golangでSQLiteを使いデータを蓄積してみましょう。

2021-04-25

golangでSQLiteを使いデータを蓄積してみましょう

Androidのアプリとかでもよく使われるSQLiteです。 その名前の通り軽量で、手軽に使えるのが魅力的なデータベースですね。

今回は、Golangから使ってみます。 モチベーションとしては、過去作ってきた仮想通貨トレード判断に使痛いと思っています。 まずはデータがないと始まらないですからね。ガンガン溜めていきましょう。

sqlite3 をインストール

SQLite このサイトのDownloadからダウンロードします。

Windowsであれば、Precompiled Binaries for Windowsから、sqlite-tools-win32-x86を選べばまずはOKです。 ダウンロートしたzipファイルの中にあるexeファイルを環境変数に追加することで使い始めることができます。

このSQLiteこれから、Golangで作るDBの動作確認に使います。

GolangでSQLiteを使うやり方

SQLiteのパッケージを追加

いつものようにパッケージを追加します。

go get github.com/mattn/go-sqlite3

これで準備はOKです。

Config.ini

golangでiniファイルを読み込むとき用テンプレートプロジェクト 過去記事で作り方は詳細に記載していますので割愛します。

Config.iniに使用するデータベースとデータベース名を追加します。

[db]
name = stockData.sql
driver = sqlite3

config.go

過去記事で作成したConfigList構造体に、今回追加した記述に対応する箇所を追加します。

type ConfigList struct {
    ApiKey      string
    ApiSecret   string
    LogFile     string
    ProductCode string

+   TradeDuration time.Duration
+   Durations     map[string]time.Duration
+   DbName        string
+   SQLDriver     string
+   Port          int
}

DBManage.go

DBManage.goは app/modelsというフォルダを作りその中に置きます。 このファイルではデータベース操作を書きます。

コードの全体像はこちら

package db

import (
    "SystemTrade/config"
    "database/sql"
    "fmt"
    "log"
    "time"

    _ "github.com/mattn/go-sqlite3"
)

var DbConnection *sql.DB

func GetCandleTableName(productCode string, duration time.Duration) string {
    return fmt.Sprintf("%s_%s", productCode, duration)
}

func init() {
    var err error
    DbConnection, err = sql.Open(config.Config.SQLDriver, config.Config.DbName)
    if err != nil {
        log.Fatalln(err)
    }
    // CREATE DB TABLE
    cmd := fmt.Sprintf(`
    CREATE TABLE IF NOT EXISTS %s(
        time DATETIME PRIMARY KEY NOT NULL,
        product_code STRING,
        side STRING,
        price FLOAT,
        size FLOAT)`, "tableNameSignalEvents")
    DbConnection.Exec(cmd)

    // CREATE DB TABLE
    for _, duration := range config.Config.Durations {
        // example BTC_USD_1m
        tableName := GetCandleTableName(config.Config.ProductCode, duration)
        c := fmt.Sprintf(`
        CREATE TABLE IF NOT EXISTS %s(
            time DATETIME PRIMARY KEY NOT NULL,
            open FLOAT,
            close FLOAT,
            high FLOAT,
            low open FLOAT,
            volume FLOAT)`, tableName)
        DbConnection.Exec(c)
    }

}

過去記事を参考にしない場合の修正箇所

先程の記事で作成したiniファイルを読み出していますが、このように書き換えればとりあえず動くはずです。(試してないですが…)

-DbConnection, err = sql.Open(config.Config.SQLDriver, config.Config.DbName)
+DbConnection, err = sql.Open("stockData.sql", "sqlite3")
-tableName := GetCandleTableName(config.Config.ProductCode, duration)
+tableName := GetCandleTableName("XLM_JPY", duration)

DB Connectorを作成する

sqlを操作するのに変数を用意します。 そして、仮想通貨を詰め込む前提なので、通貨ペア(例Bitcoinと円)ごとにDBで使う値を返す関数を用意します。

var DbConnection *sql.DB

func GetCandleTableName(productCode string, duration time.Duration) string {
    return fmt.Sprintf("%s_%s", productCode, duration)
}

データベースの作成

初期化関数を実装していきます。

func init() {
    var err error
    DbConnection, err = sql.Open(config.Config.SQLDriver, config.Config.DbName)
    if err != nil {
        log.Fatalln(err)
    }
    // CREATE DB TABLE
    cmd := fmt.Sprintf(`
    CREATE TABLE IF NOT EXISTS %s(
        time DATETIME PRIMARY KEY NOT NULL,
        product_code STRING,
        side STRING,
        price FLOAT,
        size FLOAT)`, "tableNameSignalEvents")
    DbConnection.Exec(cmd)

    // CREATE DB TABLE
    for _, duration := range config.Config.Durations {
        tableName := GetCandleTableName(config.Config.ProductCode, duration)
        c := fmt.Sprintf(`
        CREATE TABLE IF NOT EXISTS %s(
            time DATETIME PRIMARY KEY NOT NULL,
            open FLOAT,
            close FLOAT,
            high FLOAT,
            low open FLOAT,
            volume FLOAT)`, tableName)
        DbConnection.Exec(c)
    }

}

sql.openでDBのファイルを開き(作成)します。

DbConnection, err = sql.Open(config.Config.SQLDriver, config.Config.DbName)

DBファイルの中にTableを作っていきます。 コマンドは、SQL操作構文なので調べると沢山出てきます。 cmdとして作り、Exexで実行しています。

CREATE TABLE IF NOT EXISTS はテーブルが無いと追加コマンドです。 ()の中身はテーブル要素を作り込んでいきます。

SignalEventを作ります。

    cmd := fmt.Sprintf(`
    CREATE TABLE IF NOT EXISTS %s(
        time DATETIME PRIMARY KEY NOT NULL,
        product_code STRING,
        side STRING,
        price FLOAT,
        size FLOAT)`, "tableNameSignalEvents")
    DbConnection.Exec(cmd)

仮想通貨のペアごとにテーブルを作ります。 読み取りやすさなどを考えると多分こうするのが良いと思います。

    // CREATE DB TABLE
    for _, duration := range config.Config.Durations {
        tableName := GetCandleTableName(config.Config.ProductCode, duration)
        c := fmt.Sprintf(`
        CREATE TABLE IF NOT EXISTS %s(
            time DATETIME PRIMARY KEY NOT NULL,
            open FLOAT,
            close FLOAT,
            high FLOAT,
            low open FLOAT,
            volume FLOAT)`, tableName)
        DbConnection.Exec(c)
    }

Trade.go

メイン関数を書いていきます。

package main

import (
    "SystemTrade/app/models"
    "SystemTrade/config"
    "SystemTrade/utils"
    "fmt"
)

func main() {
    utils.LoggingSetting(config.Config.LogFile)
    fmt.Println(models.DbConnection)
}

動作確認

実行するとstockData.sqlというファイルが出来上がります。

sqlite3 .\stockData.sql

データベース開いて.tableで作成したテーブルの一覧を表示できます。

.table

こんな感じのものがでます。

XLM_JPY_1h0m0s         XLM_JPY_1s
XLM_JPY_1m0s           tableNameSignalEvents

まとめ

DBを使えるようになりましたね。 Androidのアプリ開発やっていたときにもお世話になったのですが、ライブラリのおかげもあって簡単ですね。 こうやって少しずつできることを増やしていきましょう。