diff --git a/.gitignore b/.gitignore index 16b25513c..a204359d8 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ # Dependency directories (remove the comment below to include it) # vendor/ +/.mod /.env.local /.env.*.local diff --git a/Makefile b/Makefile index fd234a2e8..9c2105df4 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,9 @@ dist: bin-dir bbgo-linux bbgo-darwin mkdir -p $(DIST_DIR) tar -C $(BUILD_DIR) -cvzf $(DIST_DIR)/bbgo-$$(git describe --tags).tar.gz . +migrations: + rockhopper compile --config rockhopper.yaml --output pkg/migrations + docker: GOPATH=$(PWD)/.mod go mod download docker build --build-arg GO_MOD_CACHE=.mod --tag yoanlin/bbgo . @@ -36,4 +39,4 @@ docker-push: docker push yoanlin/bbgo bash -c "[[ -n $(DOCKER_TAG) ]] && docker push yoanlin/bbgo:$(DOCKER_TAG)" -.PHONY: dist +.PHONY: dist migrations diff --git a/README.md b/README.md index 734d35532..915e2e2c6 100644 --- a/README.md +++ b/README.md @@ -51,29 +51,10 @@ BINANCE_API_SECRET= MAX_API_KEY= MAX_API_SECRET= -MYSQL_HOST=127.0.0.1 -MYSQL_PORT=3306 -MYSQL_USERNAME=root -MYSQL_PASSWORD= -MYSQL_DATABASE=bbgo -# Make sure the following line is correct so you can migrate successfully -MYSQL_URL=root@tcp(127.0.0.1:3306)/bbgo +MYSQL_URL=root@tcp(127.0.0.1:3306)/bbgo?parseTime=true ``` -Make sure you have [dotenv](https://github.com/bkeepers/dotenv). Then run the `migrate` command to initialize your database: - -```sh -dotenv -f .env.local -- bbgo migrate up -``` - -There are some other commands you can run: - -```sh -dotenv -f .env.local -- bbgo migrate status -dotenv -f .env.local -- bbgo migrate redo -``` - -(It internally uses `goose` to run these migration files, see [migrations](migrations)) +Make sure you have [dotenv](https://github.com/bkeepers/dotenv) To sync remote exchange klines data for backtesting: diff --git a/go.mod b/go.mod index 460f0e183..074e2483c 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/DATA-DOG/go-sqlmock v1.5.0 github.com/adshao/go-binance/v2 v2.2.1-0.20210108025425-9a582c63144e github.com/c9s/goose v0.0.0-20200415105707-8da682162a5b + github.com/c9s/rockhopper v1.2.1-0.20210115022144-cc77e66fc34f github.com/codingconcepts/env v0.0.0-20200821220118-a8fbf8d84482 github.com/fastly/go-utils v0.0.0-20180712184237-d95a45783239 // indirect github.com/go-redis/redis/v8 v8.4.0 @@ -17,30 +18,40 @@ require ( github.com/gorilla/websocket v1.4.2 github.com/jehiah/go-strftime v0.0.0-20171201141054-1d33003b3869 // indirect github.com/jmoiron/sqlx v1.2.0 - github.com/konsorten/go-windows-terminal-sequences v1.0.2 // indirect github.com/leekchan/accounting v0.0.0-20191218023648-17a4ce5f94d4 github.com/lestrrat-go/file-rotatelogs v2.2.0+incompatible github.com/lestrrat-go/strftime v1.0.0 // indirect + github.com/magiconair/properties v1.8.4 // indirect github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-isatty v0.0.12 // indirect - github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect + github.com/pelletier/go-toml v1.8.1 // indirect github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.3.0 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/robfig/cron/v3 v3.0.0 github.com/shopspring/decimal v1.2.0 // indirect - github.com/sirupsen/logrus v1.4.2 + github.com/sirupsen/logrus v1.7.0 github.com/slack-go/slack v0.6.6-0.20200602212211-b04b8521281b - github.com/spf13/cobra v1.0.0 - github.com/spf13/pflag v1.0.3 - github.com/spf13/viper v1.7.0 + github.com/spf13/afero v1.5.1 // indirect + github.com/spf13/cast v1.3.1 // indirect + github.com/spf13/cobra v1.1.1 + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 + github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.6.1 github.com/tebeka/strftime v0.1.3 // indirect github.com/valyala/fastjson v1.5.1 github.com/x-cray/logrus-prefixed-formatter v0.5.2 + golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad // indirect + golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 // indirect + golang.org/x/text v0.3.5 // indirect golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 gonum.org/v1/gonum v0.8.1 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + gopkg.in/ini.v1 v1.62.0 // indirect gopkg.in/tucnak/telebot.v2 v2.3.5 - gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) diff --git a/go.sum b/go.sum index c49fbe5b4..da4768fd1 100644 --- a/go.sum +++ b/go.sum @@ -17,9 +17,6 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/adshao/go-binance v2.2.0+incompatible h1:aaMrsvDXYRvpcz7aDYLi5OmtWdBr5L3eVUAFwdicvW0= -github.com/adshao/go-binance/v2 v2.2.0 h1:7Yoh8MG7CaJHYIBTGj3L0duXvWD7t2hBLVfDvfmrktc= -github.com/adshao/go-binance/v2 v2.2.0/go.mod h1:o+84WK3DQxq9vEKV9ncRcQi+J7RFCGhM27osbECZiJQ= github.com/adshao/go-binance/v2 v2.2.1-0.20210108025425-9a582c63144e h1:e5AeuM0NLP6mfR6rU/9yDo9Z3yjgfwSCsuBqkqBjpvA= github.com/adshao/go-binance/v2 v2.2.1-0.20210108025425-9a582c63144e/go.mod h1:o+84WK3DQxq9vEKV9ncRcQi+J7RFCGhM27osbECZiJQ= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= @@ -28,7 +25,6 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -43,6 +39,16 @@ github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8 github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/c9s/goose v0.0.0-20200415105707-8da682162a5b h1:4qsZTw8wHHTzFnwrfs3zLwz+cU2diGBdwoKRKiWOMvc= github.com/c9s/goose v0.0.0-20200415105707-8da682162a5b/go.mod h1:RaBe6PIVbQRqwrnjjSoHhlLM601JWdT7KZ0p6rhgI7I= +github.com/c9s/rockhopper v1.2.1-0.20210114064926-84f8d06c527b h1:D4TpmOWK8GVV7bvazJiW17cwTp1ke8aADrr7BalCB4E= +github.com/c9s/rockhopper v1.2.1-0.20210114064926-84f8d06c527b/go.mod h1:KJnQjZSrWA83jjwGF/+O7Y96VCVirYTYEvXJJOc6kMU= +github.com/c9s/rockhopper v1.2.1-0.20210114070642-bde97ed28999 h1:++sXjheN0ZuQtOvzqnCx/jCs4wDSQoj2GMEbE1UvsGE= +github.com/c9s/rockhopper v1.2.1-0.20210114070642-bde97ed28999/go.mod h1:KJnQjZSrWA83jjwGF/+O7Y96VCVirYTYEvXJJOc6kMU= +github.com/c9s/rockhopper v1.2.1-0.20210115015707-d3b0b1892dfd h1:Q3MLSogx558Xnc43uBFbPnlIQvI3mThaAc/buea/mQ4= +github.com/c9s/rockhopper v1.2.1-0.20210115015707-d3b0b1892dfd/go.mod h1:KJnQjZSrWA83jjwGF/+O7Y96VCVirYTYEvXJJOc6kMU= +github.com/c9s/rockhopper v1.2.1-0.20210115020622-659f1b03767b h1:1Ixa0xWAD3KADLCEb5sHAz/3rjP47XqHRW3zK6oz1Sk= +github.com/c9s/rockhopper v1.2.1-0.20210115020622-659f1b03767b/go.mod h1:KJnQjZSrWA83jjwGF/+O7Y96VCVirYTYEvXJJOc6kMU= +github.com/c9s/rockhopper v1.2.1-0.20210115022144-cc77e66fc34f h1:n1Ly7178MJj+GQB38q4dV66QktUvzEi2rA7xCtTy6Ck= +github.com/c9s/rockhopper v1.2.1-0.20210115022144-cc77e66fc34f/go.mod h1:KJnQjZSrWA83jjwGF/+O7Y96VCVirYTYEvXJJOc6kMU= github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= @@ -53,9 +59,7 @@ github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMe github.com/codingconcepts/env v0.0.0-20200821220118-a8fbf8d84482 h1:5/aEFreBh9hH/0G+33xtczJCvMaulqsm9nDuu2BZUEo= github.com/codingconcepts/env v0.0.0-20200821220118-a8fbf8d84482/go.mod h1:TM9ug+H/2cI3EjyIDr5xKCkFGyNE59URgH1wu5NyU8E= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= @@ -64,6 +68,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisenkom/go-mssqldb v0.0.0-20191128021309-1d7a30a10f73/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= +github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk= +github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= @@ -94,6 +100,7 @@ github.com/go-test/deep v1.0.6 h1:UHSEyLZUwX9Qoi99vVwvewiMC8mM2bf7XEM2nqvzEn8= github.com/go-test/deep v1.0.6/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -131,7 +138,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= @@ -177,8 +183,7 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= @@ -197,9 +202,12 @@ github.com/lestrrat-go/strftime v1.0.0/go.mod h1:E1nN3pCbtMSu1yjSVeyuRFVm/U0xoR7 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/lib/pq v1.9.0 h1:L8nSXQQzAYByakOFMTwpjRoHsMJklur4Gi59b6VivR8= +github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.4 h1:8KGKTcQQGm0Kv7vEbKFErAoAOFyyacLStRtQSeYtvkY= +github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -209,11 +217,15 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v2.0.2+incompatible h1:qzw9c2GNT8UFrgWNDhCTqRqYUSmu/Dav/9Z58LGpk7U= github.com/mattn/go-sqlite3 v2.0.2+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= +github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= +github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -224,6 +236,8 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= @@ -244,10 +258,13 @@ github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDs github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pelletier/go-toml v1.8.1 h1:1Nf83orprkJyknT6h7zbuEGUEjcyVlCxSUGTENmNCRM= +github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= @@ -278,8 +295,8 @@ github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXY github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/slack-go/slack v0.6.6-0.20200602212211-b04b8521281b h1:4NIpokK7Rg/k6lSzNQzvGLphpHtfAAaLw9AWHxHQn0w= github.com/slack-go/slack v0.6.6-0.20200602212211-b04b8521281b/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= @@ -290,23 +307,33 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/afero v1.5.1 h1:VHu76Lk0LSP1x254maIu2bplkWpfBWI+B+6fdoZprcg= +github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.0.0 h1:6m/oheQuQ13N9ks4hubMG6BnvwOeaJrqSPLahSnczz8= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= +github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= +github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v1.1.1 h1:KfztREH0tPxJJ+geloSLaAkaPkr4ki2Er5quFV1TDo4= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1 h1:2vfRuCMp5sSVIDSqO8oNnWJq7mPa6KVP3iPIwFBuy8A= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -315,13 +342,12 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tebeka/strftime v0.1.3 h1:5HQXOqWKYRFfNyBMNVc9z5+QzuBtIXy03psIhtdJYto= github.com/tebeka/strftime v0.1.3/go.mod h1:7wJm3dZlpr4l/oVK0t1HYIc4rMzQ2XJlOMIUJUJH6XQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/valyala/fastjson v1.5.1 h1:SXaQZVSwLjZOVhDEhjiCcDtnX0Feu7Z7A1+C5atpoHM= github.com/valyala/fastjson v1.5.1/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg= github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -337,8 +363,11 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= +golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -375,7 +404,6 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -401,7 +429,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -409,18 +436,25 @@ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/ golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78 h1:nVuTkr9L6Bq62qpUqKo/RnZCFfzDBL0bYo6w9OJUqZY= +golang.org/x/sys v0.0.0-20210113181707-4bcb84eeeb78/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221 h1:/ZHdbVpdR/jk3g30/d4yUL0JU9kksj8+F/bnQUVLGDM= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 h1:Hir2P/De0WpUhtrKGGjvSb2YxUgyZ7EFOSLIcSSpiwE= @@ -474,7 +508,6 @@ google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBr google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -495,6 +528,8 @@ gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU= +gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= @@ -505,12 +540,15 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c h1:grhR+C34yXImVGp7EzNk+DTIk+323eIUWOmEevy6bDo= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/migrations/20200721225616_trades.sql b/migrations/20200721225616_trades.sql index c3c3e80ca..12d4e4c77 100644 --- a/migrations/20200721225616_trades.sql +++ b/migrations/20200721225616_trades.sql @@ -1,23 +1,23 @@ --- +goose Up -CREATE TABLE `trades` ( - `gid` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, +-- +up +CREATE TABLE `trades` +( + `gid` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, - `id` BIGINT UNSIGNED, - `exchange` VARCHAR(24) NOT NULL DEFAULT '', - `symbol` VARCHAR(8) NOT NULL, - `price` DECIMAL(16, 8) UNSIGNED NOT NULL, - `quantity` DECIMAL(16, 8) UNSIGNED NOT NULL, - `quote_quantity` DECIMAL(16, 8) UNSIGNED NOT NULL, - `fee` DECIMAL(16, 8) UNSIGNED NOT NULL, - `fee_currency` VARCHAR(4) NOT NULL, - `is_buyer` BOOLEAN NOT NULL DEFAULT FALSE, - `is_maker` BOOLEAN NOT NULL DEFAULT FALSE, - `side` VARCHAR(4) NOT NULL DEFAULT '', - `traded_at` DATETIME(3) NOT NULL, + `id` BIGINT UNSIGNED, + `exchange` VARCHAR(24) NOT NULL DEFAULT '', + `symbol` VARCHAR(8) NOT NULL, + `price` DECIMAL(16, 8) UNSIGNED NOT NULL, + `quantity` DECIMAL(16, 8) UNSIGNED NOT NULL, + `quote_quantity` DECIMAL(16, 8) UNSIGNED NOT NULL, + `fee` DECIMAL(16, 8) UNSIGNED NOT NULL, + `fee_currency` VARCHAR(4) NOT NULL, + `is_buyer` BOOLEAN NOT NULL DEFAULT FALSE, + `is_maker` BOOLEAN NOT NULL DEFAULT FALSE, + `side` VARCHAR(4) NOT NULL DEFAULT '', + `traded_at` DATETIME(3) NOT NULL, - PRIMARY KEY (`gid`), - UNIQUE KEY `id` (`id`) - -) ENGINE=InnoDB; --- +goose Down + PRIMARY KEY (`gid`), + UNIQUE KEY `id` (`id`) +); +-- +down DROP TABLE `trades`; diff --git a/migrations/20200819054742_trade_index.sql b/migrations/20200819054742_trade_index.sql index 61f8fb3fd..6ce90b1bd 100644 --- a/migrations/20200819054742_trade_index.sql +++ b/migrations/20200819054742_trade_index.sql @@ -1,9 +1,9 @@ --- +goose Up +-- +up CREATE INDEX trades_symbol ON trades(symbol); CREATE INDEX trades_symbol_fee_currency ON trades(symbol, fee_currency, traded_at); CREATE INDEX trades_traded_at_symbol ON trades(traded_at, symbol); --- +goose Down +-- +down DROP INDEX trades_symbol ON trades; DROP INDEX trades_symbol_fee_currency ON trades; DROP INDEX trades_traded_at_symbol ON trades; diff --git a/migrations/20201102222546_orders.sql b/migrations/20201102222546_orders.sql index 70f0dedb8..ec5eb0e11 100644 --- a/migrations/20201102222546_orders.sql +++ b/migrations/20201102222546_orders.sql @@ -1,4 +1,4 @@ --- +goose Up +-- +up CREATE TABLE `orders` ( `gid` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, @@ -21,7 +21,6 @@ CREATE TABLE `orders` `updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), PRIMARY KEY (`gid`) -) ENGINE = InnoDB; - --- +goose Down +); +-- +down DROP TABLE `orders`; diff --git a/migrations/20201103173342_trades_add_order_id.sql b/migrations/20201103173342_trades_add_order_id.sql index ab33542ae..6af8910fd 100644 --- a/migrations/20201103173342_trades_add_order_id.sql +++ b/migrations/20201103173342_trades_add_order_id.sql @@ -1,7 +1,7 @@ --- +goose Up +-- +up ALTER TABLE `trades` ADD COLUMN `order_id` BIGINT UNSIGNED NOT NULL; --- +goose Down +-- +down ALTER TABLE `trades` DROP COLUMN `order_id`; diff --git a/migrations/20201105092857_trades_index_fix.sql b/migrations/20201105092857_trades_index_fix.sql index 0934eb491..452f7fa8d 100644 --- a/migrations/20201105092857_trades_index_fix.sql +++ b/migrations/20201105092857_trades_index_fix.sql @@ -1,4 +1,4 @@ --- +goose Up +-- +up DROP INDEX trades_symbol ON trades; DROP INDEX trades_symbol_fee_currency ON trades; DROP INDEX trades_traded_at_symbol ON trades; @@ -7,7 +7,7 @@ CREATE INDEX trades_symbol ON trades (exchange, symbol); CREATE INDEX trades_symbol_fee_currency ON trades (exchange, symbol, fee_currency, traded_at); CREATE INDEX trades_traded_at_symbol ON trades (exchange, traded_at, symbol); --- +goose Down +-- +down DROP INDEX trades_symbol ON trades; DROP INDEX trades_symbol_fee_currency ON trades; DROP INDEX trades_traded_at_symbol ON trades; diff --git a/migrations/20201105093056_orders_add_index.sql b/migrations/20201105093056_orders_add_index.sql index 484143730..4d685d4a9 100644 --- a/migrations/20201105093056_orders_add_index.sql +++ b/migrations/20201105093056_orders_add_index.sql @@ -1,7 +1,7 @@ --- +goose Up +-- +up CREATE INDEX orders_symbol ON orders (exchange, symbol); CREATE UNIQUE INDEX orders_order_id ON orders (order_id, exchange); --- +goose Down +-- +down DROP INDEX orders_symbol ON orders; DROP INDEX orders_order_id ON orders; diff --git a/migrations/20201106114742_klines.sql b/migrations/20201106114742_klines.sql index 04c3a326f..ab1cfd749 100644 --- a/migrations/20201106114742_klines.sql +++ b/migrations/20201106114742_klines.sql @@ -1,4 +1,4 @@ --- +goose Up +-- +up CREATE TABLE `klines` ( `gid` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, @@ -18,14 +18,14 @@ CREATE TABLE `klines` PRIMARY KEY (`gid`) -) ENGINE = InnoDB; +); CREATE INDEX `klines_end_time_symbol_interval` ON klines (`end_time`, `symbol`, `interval`); CREATE TABLE `okex_klines` LIKE `klines`; CREATE TABLE `binance_klines` LIKE `klines`; CREATE TABLE `max_klines` LIKE `klines`; --- +goose Down +-- +down DROP INDEX `klines_end_time_symbol_interval` ON `klines`; DROP TABLE `binance_klines`; DROP TABLE `okex_klines`; diff --git a/migrations/20201211175751_fix_symbol_length.sql b/migrations/20201211175751_fix_symbol_length.sql index 23a05d480..e0965ee42 100644 --- a/migrations/20201211175751_fix_symbol_length.sql +++ b/migrations/20201211175751_fix_symbol_length.sql @@ -1,7 +1,7 @@ --- +goose Up +-- +up ALTER TABLE trades MODIFY COLUMN symbol VARCHAR(9); ALTER TABLE orders MODIFY COLUMN symbol VARCHAR(9); --- +goose Down +-- +down ALTER TABLE trades MODIFY COLUMN symbol VARCHAR(8); ALTER TABLE orders MODIFY COLUMN symbol VARCHAR(8); diff --git a/pkg/bbgo/config.go b/pkg/bbgo/config.go index 49a20feef..2a102fc4c 100644 --- a/pkg/bbgo/config.go +++ b/pkg/bbgo/config.go @@ -10,14 +10,15 @@ import ( "github.com/pkg/errors" "gopkg.in/yaml.v3" + "github.com/c9s/bbgo/pkg/datatype" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/types" ) type PnLReporterConfig struct { - AverageCostBySymbols StringSlice `json:"averageCostBySymbols" yaml:"averageCostBySymbols"` - Of StringSlice `json:"of" yaml:"of"` - When StringSlice `json:"when" yaml:"when"` + AverageCostBySymbols datatype.StringSlice `json:"averageCostBySymbols" yaml:"averageCostBySymbols"` + Of datatype.StringSlice `json:"of" yaml:"of"` + When datatype.StringSlice `json:"when" yaml:"when"` } // ExchangeStrategyMount wraps the SingleExchangeStrategy with the Session name for mounting @@ -105,7 +106,7 @@ type RedisPersistenceConfig struct { Host string `json:"host" env:"REDIS_HOST"` Port string `json:"port" env:"REDIS_PORT"` Password string `json:"password" env:"REDIS_PASSWORD"` - DB int `json:"db" env:"REDIS_DB"` + DB int `json:"db" env:"REDIS_DB"` } type JsonPersistenceConfig struct { @@ -189,7 +190,6 @@ func Load(configFile string, loadStrategies bool) (*Config, error) { } } - return &config, nil } diff --git a/pkg/bbgo/db.go b/pkg/bbgo/db.go new file mode 100644 index 000000000..0ff4f0d13 --- /dev/null +++ b/pkg/bbgo/db.go @@ -0,0 +1,50 @@ +package bbgo + +import ( + "context" + "database/sql" + + // register the go migrations + _ "github.com/c9s/bbgo/pkg/migrations" + + "github.com/c9s/rockhopper" + "github.com/go-sql-driver/mysql" + "github.com/jmoiron/sqlx" +) + +func ConnectMySQL(dsn string) (*sqlx.DB, error) { + config, err := mysql.ParseDSN(dsn) + if err != nil { + return nil, err + } + + config.ParseTime = true + dsn = config.FormatDSN() + return sqlx.Connect("mysql", dsn) +} + +func upgradeDB(ctx context.Context, driver string, db *sql.DB) error { + dialect, err := rockhopper.LoadDialect(driver) + if err != nil { + return err + } + + loader := &rockhopper.GoMigrationLoader{} + migrations, err := loader.Load() + if err != nil { + return err + } + + rh := rockhopper.New(driver, dialect, db) + + currentVersion, err := rh.CurrentVersion() + if err != nil { + return err + } + + if err := rockhopper.Up(ctx, rh, migrations, currentVersion, 0); err != nil { + return err + } + + return nil +} diff --git a/pkg/bbgo/environment.go b/pkg/bbgo/environment.go index 9f502f480..735b32bc6 100644 --- a/pkg/bbgo/environment.go +++ b/pkg/bbgo/environment.go @@ -24,12 +24,12 @@ var LoadedCrossExchangeStrategies = make(map[string]CrossExchangeStrategy) func RegisterStrategy(key string, s interface{}) { loaded := 0 - if d, ok := s.(SingleExchangeStrategy) ; ok { + if d, ok := s.(SingleExchangeStrategy); ok { LoadedExchangeStrategies[key] = d loaded++ } - if d, ok := s.(CrossExchangeStrategy) ; ok { + if d, ok := s.(CrossExchangeStrategy); ok { LoadedCrossExchangeStrategies[key] = d loaded++ } @@ -49,6 +49,7 @@ type Environment struct { PersistenceServiceFacade *PersistenceServiceFacade + OrderService *service.OrderService TradeService *service.TradeService TradeSync *service.SyncService @@ -70,10 +71,30 @@ func (environ *Environment) Sessions() map[string]*ExchangeSession { return environ.sessions } +func (environ *Environment) ConfigureDatabase(ctx context.Context) error { + if viper.IsSet("mysql-url") { + dsn := viper.GetString("mysql-url") + db, err := ConnectMySQL(dsn) + if err != nil { + return err + } + + if err := upgradeDB(ctx, "mysql", db.DB); err != nil { + return err + } + + environ.SetDB(db) + } + + return nil +} + func (environ *Environment) SetDB(db *sqlx.DB) *Environment { + environ.OrderService = &service.OrderService{DB: db} environ.TradeService = &service.TradeService{DB: db} environ.TradeSync = &service.SyncService{ TradeService: environ.TradeService, + OrderService: environ.OrderService, } return environ diff --git a/pkg/bbgo/string.go b/pkg/bbgo/string.go index 127215304..920078f66 100644 --- a/pkg/bbgo/string.go +++ b/pkg/bbgo/string.go @@ -1,57 +1,2 @@ package bbgo -import ( - "encoding/json" - "fmt" -) - -type StringSlice []string - -func (s *StringSlice) decode(a interface{}) error { - switch d := a.(type) { - case string: - *s = append(*s, d) - - case []string: - *s = append(*s, d...) - - case []interface{}: - for _, de := range d { - if err := s.decode(de); err != nil { - return err - } - } - - default: - return fmt.Errorf("unexpected type %T for StringSlice: %+v", d, d) - } - - return nil -} - -func (s *StringSlice) UnmarshalYAML(unmarshal func(interface{}) error) (err error) { - var ss []string - err = unmarshal(&ss) - if err == nil { - *s = ss - return - } - - var as string - err = unmarshal(&as) - if err == nil { - *s = append(*s, as) - } - - return err -} - -func (s *StringSlice) UnmarshalJSON(b []byte) error { - var a interface{} - var err = json.Unmarshal(b, &a) - if err != nil { - return err - } - - return s.decode(a) -} diff --git a/pkg/cmd/backtest.go b/pkg/cmd/backtest.go index 9b9cbaf83..4f616edcb 100644 --- a/pkg/cmd/backtest.go +++ b/pkg/cmd/backtest.go @@ -8,6 +8,7 @@ import ( "github.com/pkg/errors" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/c9s/bbgo/pkg/accounting/pnl" "github.com/c9s/bbgo/pkg/backtest" @@ -95,7 +96,7 @@ var BacktestCmd = &cobra.Command{ return err } - db, err := cmdutil.ConnectMySQL() + db, err := bbgo.ConnectMySQL(viper.GetString("mysql-url")) if err != nil { return err } @@ -114,6 +115,11 @@ var BacktestCmd = &cobra.Command{ return err } + environ := bbgo.NewEnvironment() + if err := environ.ConfigureDatabase(ctx); err != nil { + return err + } + backtestService := &service.BacktestService{DB: db} if wantSync { @@ -177,7 +183,6 @@ var BacktestCmd = &cobra.Command{ backtestExchange := backtest.NewExchange(exchangeName, backtestService, userConfig.Backtest) - environ := bbgo.NewEnvironment() environ.SetStartTime(startTime) environ.AddExchange(exchangeName.String(), backtestExchange) diff --git a/pkg/cmd/builtin.go b/pkg/cmd/builtin.go index 9609c1c97..538ab6966 100644 --- a/pkg/cmd/builtin.go +++ b/pkg/cmd/builtin.go @@ -6,8 +6,9 @@ import ( _ "github.com/c9s/bbgo/pkg/strategy/buyandhold" _ "github.com/c9s/bbgo/pkg/strategy/flashcrash" _ "github.com/c9s/bbgo/pkg/strategy/grid" - _ "github.com/c9s/bbgo/pkg/strategy/trailingstop" + _ "github.com/c9s/bbgo/pkg/strategy/mirrormaker" _ "github.com/c9s/bbgo/pkg/strategy/pricealert" _ "github.com/c9s/bbgo/pkg/strategy/swing" + _ "github.com/c9s/bbgo/pkg/strategy/trailingstop" _ "github.com/c9s/bbgo/pkg/strategy/xpuremaker" ) diff --git a/pkg/cmd/cancel.go b/pkg/cmd/cancel.go index bf17eace7..acd0cc8a8 100644 --- a/pkg/cmd/cancel.go +++ b/pkg/cmd/cancel.go @@ -10,7 +10,6 @@ import ( "github.com/spf13/viper" "github.com/c9s/bbgo/pkg/bbgo" - "github.com/c9s/bbgo/pkg/cmd/cmdutil" "github.com/c9s/bbgo/pkg/types" ) @@ -66,7 +65,7 @@ var CancelCmd = &cobra.Command{ environ := bbgo.NewEnvironment() if viper.IsSet("mysql-url") { - db, err := cmdutil.ConnectMySQL() + db, err := bbgo.ConnectMySQL(viper.GetString("mysql-url")) if err != nil { return err } diff --git a/pkg/cmd/cmdutil/db.go b/pkg/cmd/cmdutil/db.go deleted file mode 100644 index f50c3f7f2..000000000 --- a/pkg/cmd/cmdutil/db.go +++ /dev/null @@ -1,14 +0,0 @@ -package cmdutil - -import ( - "fmt" - - "github.com/jmoiron/sqlx" - "github.com/spf13/viper" -) - -func ConnectMySQL() (*sqlx.DB, error) { - mysqlURL := viper.GetString("mysql-url") - mysqlURL = fmt.Sprintf("%s?parseTime=true", mysqlURL) - return sqlx.Connect("mysql", mysqlURL) -} diff --git a/pkg/cmd/migrate.go b/pkg/cmd/migrate.go deleted file mode 100644 index 8814c5545..000000000 --- a/pkg/cmd/migrate.go +++ /dev/null @@ -1,79 +0,0 @@ -package cmd - -import ( - "context" - "fmt" - "os" - "os/exec" - "path" - - "github.com/c9s/goose" - "github.com/sirupsen/logrus" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/c9s/bbgo/pkg/bbgo" -) - -func init() { - MigrateCmd.Flags().Bool("no-update", false, "update source repository") - RootCmd.AddCommand(MigrateCmd) -} - -var MigrateCmd = &cobra.Command{ - Use: "migrate", - Short: "run database migration", - SilenceUsage: true, - Args: cobra.MinimumNArgs(1), - RunE: func(cmd *cobra.Command, args []string) error { - ctx := context.Background() - - noUpdate, err := cmd.Flags().GetBool("no-update") - if err != nil { - return err - } - - mysqlURL := viper.GetString("mysql-url") - mysqlURL = fmt.Sprintf("%s?parseTime=true", mysqlURL) - db, err := goose.OpenDBWithDriver("mysql", mysqlURL) - if err != nil { - return err - } - - dotDir := bbgo.HomeDir() - sourceDir := bbgo.SourceDir() - migrationDir := path.Join(sourceDir, "migrations") - - logrus.Infof("creating dir: %s", dotDir) - if err := os.Mkdir(dotDir, 0777); err != nil { - // return err - } - - logrus.Infof("checking %s", sourceDir) - _, err = os.Stat(sourceDir) - if err != nil { - logrus.Infof("cloning bbgo source into %s ...", sourceDir) - cmd := exec.CommandContext(ctx, "git", "clone", "https://github.com/c9s/bbgo", sourceDir) - if err := cmd.Run(); err != nil { - return err - } - } else if !noUpdate { - logrus.Infof("updating: %s ...", sourceDir) - cmd := exec.CommandContext(ctx, "git", "--work-tree", sourceDir, "pull") - if err := cmd.Run(); err != nil { - return err - } - } - - logrus.Infof("using migration file dir: %s", migrationDir) - - command := args[0] - if err := goose.Run(command, db, migrationDir); err != nil { - logrus.Fatalf("goose run: %v", err) - } - - defer db.Close() - - return nil - }, -} diff --git a/pkg/cmd/pnl.go b/pkg/cmd/pnl.go index 35fd6756a..d1d8b402e 100644 --- a/pkg/cmd/pnl.go +++ b/pkg/cmd/pnl.go @@ -8,9 +8,11 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/spf13/viper" "github.com/c9s/bbgo/pkg/accounting" "github.com/c9s/bbgo/pkg/accounting/pnl" + "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/cmd/cmdutil" "github.com/c9s/bbgo/pkg/service" "github.com/c9s/bbgo/pkg/types" @@ -50,7 +52,7 @@ var PnLCmd = &cobra.Command{ return err } - db, err := cmdutil.ConnectMySQL() + db, err := bbgo.ConnectMySQL(viper.GetString("mysql-url")) if err != nil { return err } diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go index faa5717ac..9528ccfc5 100644 --- a/pkg/cmd/run.go +++ b/pkg/cmd/run.go @@ -44,6 +44,15 @@ func init() { RootCmd.AddCommand(RunCmd) } +var RunCmd = &cobra.Command{ + Use: "run", + Short: "run strategies from config file", + + // SilenceUsage is an option to silence usage when an error occurs. + SilenceUsage: true, + RunE: run, +} + var wrapperTemplate = template.Must(template.New("main").Parse(`package main // DO NOT MODIFY THIS FILE. THIS FILE IS GENERATED FOR IMPORTING STRATEGIES import ( @@ -75,12 +84,8 @@ func runConfig(basectx context.Context, userConfig *bbgo.Config) error { environ := bbgo.NewEnvironment() - if viper.IsSet("mysql-url") { - db, err := cmdutil.ConnectMySQL() - if err != nil { - return err - } - environ.SetDB(db) + if err := environ.ConfigureDatabase(ctx) ; err != nil { + return err } if err := environ.AddExchangesFromConfig(userConfig); err != nil { @@ -253,87 +258,79 @@ func runConfig(basectx context.Context, userConfig *bbgo.Config) error { return nil } -var RunCmd = &cobra.Command{ - Use: "run", - Short: "run strategies from config file", +func run(cmd *cobra.Command, args []string) error { + configFile, err := cmd.Flags().GetString("config") + if err != nil { + return err + } - // SilenceUsage is an option to silence usage when an error occurs. - SilenceUsage: true, + if len(configFile) == 0 { + return errors.New("--config option is required") + } - RunE: func(cmd *cobra.Command, args []string) error { - configFile, err := cmd.Flags().GetString("config") + noCompile, err := cmd.Flags().GetBool("no-compile") + if err != nil { + return err + } + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + userConfig, err := bbgo.Load(configFile, false) + if err != nil { + return err + } + + shouldCompile := len(userConfig.Imports) > 0 + + // if there is no custom imports, we don't have to compile + if noCompile || !shouldCompile { + userConfig, err = bbgo.Load(configFile, true) if err != nil { return err } - if len(configFile) == 0 { - return errors.New("--config option is required") - } - - noCompile, err := cmd.Flags().GetBool("no-compile") - if err != nil { + log.Infof("running config without wrapper binary...") + if err := runConfig(ctx, userConfig); err != nil { return err } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - userConfig, err := bbgo.Load(configFile, false) - if err != nil { - return err - } - - shouldCompile := len(userConfig.Imports) > 0 - - // if there is no custom imports, we don't have to compile - if noCompile || !shouldCompile { - userConfig, err = bbgo.Load(configFile, true) - if err != nil { - return err - } - - log.Infof("running config without wrapper binary...") - if err := runConfig(ctx, userConfig); err != nil { - return err - } - - return nil - } - - var runArgs = []string{"run", "--no-compile"} - cmd.Flags().Visit(func(flag *flag.Flag) { - runArgs = append(runArgs, "--"+flag.Name, flag.Value.String()) - }) - runArgs = append(runArgs, args...) - - goOS, err := cmd.Flags().GetString("os") - if err != nil { - return err - } - - goArch, err := cmd.Flags().GetString("arch") - if err != nil { - return err - } - - runCmd, err := buildAndRun(ctx, userConfig, goOS, goArch, runArgs...) - if err != nil { - return err - } - - if sig := cmdutil.WaitForSignal(ctx, syscall.SIGTERM, syscall.SIGINT); sig != nil { - log.Infof("sending signal to the child process...") - if err := runCmd.Process.Signal(sig); err != nil { - return err - } - - if err := runCmd.Wait(); err != nil { - return err - } - } - return nil - }, + } + + var runArgs = []string{"run", "--no-compile"} + cmd.Flags().Visit(func(flag *flag.Flag) { + runArgs = append(runArgs, "--"+flag.Name, flag.Value.String()) + }) + runArgs = append(runArgs, args...) + + goOS, err := cmd.Flags().GetString("os") + if err != nil { + return err + } + + goArch, err := cmd.Flags().GetString("arch") + if err != nil { + return err + } + + runCmd, err := buildAndRun(ctx, userConfig, goOS, goArch, runArgs...) + if err != nil { + return err + } + + if sig := cmdutil.WaitForSignal(ctx, syscall.SIGTERM, syscall.SIGINT); sig != nil { + log.Infof("sending signal to the child process...") + if err := runCmd.Process.Signal(sig); err != nil { + return err + } + + if err := runCmd.Wait(); err != nil { + return err + } + } + + return nil } func compile(buildDir string, userConfig *bbgo.Config) error { diff --git a/pkg/cmd/sync.go b/pkg/cmd/sync.go index 65a175b74..3f4dd4c6d 100644 --- a/pkg/cmd/sync.go +++ b/pkg/cmd/sync.go @@ -7,8 +7,8 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" + "github.com/c9s/bbgo/pkg/bbgo" "github.com/c9s/bbgo/pkg/cmd/cmdutil" - "github.com/c9s/bbgo/pkg/service" "github.com/c9s/bbgo/pkg/types" ) @@ -46,8 +46,8 @@ var SyncCmd = &cobra.Command{ return err } - db, err := cmdutil.ConnectMySQL() - if err != nil { + environ := bbgo.NewEnvironment() + if err := environ.ConfigureDatabase(ctx); err != nil { return err } @@ -73,20 +73,13 @@ var SyncCmd = &cobra.Command{ } } - tradeService := &service.TradeService{DB: db} - orderService := &service.OrderService{DB: db} - syncService := &service.SyncService{ - TradeService: tradeService, - OrderService: orderService, - } - log.Info("syncing trades from exchange...") - if err := syncService.SyncTrades(ctx, exchange, symbol, startTime); err != nil { + if err := environ.TradeSync.SyncTrades(ctx, exchange, symbol, startTime); err != nil { return err } log.Info("syncing orders from exchange...") - if err := syncService.SyncOrders(ctx, exchange, symbol, startTime); err != nil { + if err := environ.TradeSync.SyncOrders(ctx, exchange, symbol, startTime); err != nil { return err } diff --git a/pkg/datatype/string_slice.go b/pkg/datatype/string_slice.go new file mode 100644 index 000000000..d33d2c48b --- /dev/null +++ b/pkg/datatype/string_slice.go @@ -0,0 +1,57 @@ +package datatype + +import ( + "encoding/json" + "fmt" +) + +type StringSlice []string + +func (s *StringSlice) decode(a interface{}) error { + switch d := a.(type) { + case string: + *s = append(*s, d) + + case []string: + *s = append(*s, d...) + + case []interface{}: + for _, de := range d { + if err := s.decode(de); err != nil { + return err + } + } + + default: + return fmt.Errorf("unexpected type %T for StringSlice: %+v", d, d) + } + + return nil +} + +func (s *StringSlice) UnmarshalYAML(unmarshal func(interface{}) error) (err error) { + var ss []string + err = unmarshal(&ss) + if err == nil { + *s = ss + return + } + + var as string + err = unmarshal(&as) + if err == nil { + *s = append(*s, as) + } + + return err +} + +func (s *StringSlice) UnmarshalJSON(b []byte) error { + var a interface{} + var err = json.Unmarshal(b, &a) + if err != nil { + return err + } + + return s.decode(a) +} diff --git a/pkg/migrations/20200721225616_trades.go b/pkg/migrations/20200721225616_trades.go new file mode 100644 index 000000000..12f449bbd --- /dev/null +++ b/pkg/migrations/20200721225616_trades.go @@ -0,0 +1,33 @@ +package migrations + +import ( + "context" + + "github.com/c9s/rockhopper" +) + +func init() { + rockhopper.AddMigration(upTrades, downTrades) +} + +func upTrades(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is applied. + + _, err = tx.ExecContext(ctx, "CREATE TABLE `trades`\n(\n `gid` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,\n `id` BIGINT UNSIGNED,\n `exchange` VARCHAR(24) NOT NULL DEFAULT '',\n `symbol` VARCHAR(8) NOT NULL,\n `price` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `quantity` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `quote_quantity` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `fee` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `fee_currency` VARCHAR(4) NOT NULL,\n `is_buyer` BOOLEAN NOT NULL DEFAULT FALSE,\n `is_maker` BOOLEAN NOT NULL DEFAULT FALSE,\n `side` VARCHAR(4) NOT NULL DEFAULT '',\n `traded_at` DATETIME(3) NOT NULL,\n PRIMARY KEY (`gid`),\n UNIQUE KEY `id` (`id`)\n);") + if err != nil { + return err + } + + return err +} + +func downTrades(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is rolled back. + + _, err = tx.ExecContext(ctx, "DROP TABLE `trades`;") + if err != nil { + return err + } + + return err +} diff --git a/pkg/migrations/20200819054742_trade_index.go b/pkg/migrations/20200819054742_trade_index.go new file mode 100644 index 000000000..59c7b89ef --- /dev/null +++ b/pkg/migrations/20200819054742_trade_index.go @@ -0,0 +1,53 @@ +package migrations + +import ( + "context" + + "github.com/c9s/rockhopper" +) + +func init() { + rockhopper.AddMigration(upTradeIndex, downTradeIndex) +} + +func upTradeIndex(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is applied. + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_symbol ON trades(symbol);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_symbol_fee_currency ON trades(symbol, fee_currency, traded_at);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_traded_at_symbol ON trades(traded_at, symbol);") + if err != nil { + return err + } + + return err +} + +func downTradeIndex(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is rolled back. + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_symbol ON trades;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_symbol_fee_currency ON trades;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_traded_at_symbol ON trades;") + if err != nil { + return err + } + + return err +} diff --git a/pkg/migrations/20201102222546_orders.go b/pkg/migrations/20201102222546_orders.go new file mode 100644 index 000000000..04af54150 --- /dev/null +++ b/pkg/migrations/20201102222546_orders.go @@ -0,0 +1,33 @@ +package migrations + +import ( + "context" + + "github.com/c9s/rockhopper" +) + +func init() { + rockhopper.AddMigration(upOrders, downOrders) +} + +func upOrders(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is applied. + + _, err = tx.ExecContext(ctx, "CREATE TABLE `orders`\n(\n `gid` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,\n `exchange` VARCHAR(24) NOT NULL DEFAULT '',\n -- order_id is the order id returned from the exchange\n `order_id` BIGINT UNSIGNED NOT NULL,\n `client_order_id` VARCHAR(42) NOT NULL DEFAULT '',\n `order_type` VARCHAR(16) NOT NULL,\n `symbol` VARCHAR(8) NOT NULL,\n `status` VARCHAR(12) NOT NULL,\n `time_in_force` VARCHAR(4) NOT NULL,\n `price` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `stop_price` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `quantity` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `executed_quantity` DECIMAL(16, 8) UNSIGNED NOT NULL DEFAULT 0.0,\n `side` VARCHAR(4) NOT NULL DEFAULT '',\n `is_working` BOOL NOT NULL DEFAULT FALSE,\n `created_at` DATETIME(3) NOT NULL,\n `updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),\n PRIMARY KEY (`gid`)\n);") + if err != nil { + return err + } + + return err +} + +func downOrders(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is rolled back. + + _, err = tx.ExecContext(ctx, "DROP TABLE `orders`;") + if err != nil { + return err + } + + return err +} diff --git a/pkg/migrations/20201103173342_trades_add_order_id.go b/pkg/migrations/20201103173342_trades_add_order_id.go new file mode 100644 index 000000000..596624746 --- /dev/null +++ b/pkg/migrations/20201103173342_trades_add_order_id.go @@ -0,0 +1,33 @@ +package migrations + +import ( + "context" + + "github.com/c9s/rockhopper" +) + +func init() { + rockhopper.AddMigration(upTradesAddOrderId, downTradesAddOrderId) +} + +func upTradesAddOrderId(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is applied. + + _, err = tx.ExecContext(ctx, "ALTER TABLE `trades`\n ADD COLUMN `order_id` BIGINT UNSIGNED NOT NULL;") + if err != nil { + return err + } + + return err +} + +func downTradesAddOrderId(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is rolled back. + + _, err = tx.ExecContext(ctx, "ALTER TABLE `trades`\n DROP COLUMN `order_id`;") + if err != nil { + return err + } + + return err +} diff --git a/pkg/migrations/20201105092857_trades_index_fix.go b/pkg/migrations/20201105092857_trades_index_fix.go new file mode 100644 index 000000000..72b90f321 --- /dev/null +++ b/pkg/migrations/20201105092857_trades_index_fix.go @@ -0,0 +1,83 @@ +package migrations + +import ( + "context" + + "github.com/c9s/rockhopper" +) + +func init() { + rockhopper.AddMigration(upTradesIndexFix, downTradesIndexFix) +} + +func upTradesIndexFix(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is applied. + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_symbol ON trades;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_symbol_fee_currency ON trades;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_traded_at_symbol ON trades;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_symbol ON trades (exchange, symbol);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_symbol_fee_currency ON trades (exchange, symbol, fee_currency, traded_at);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_traded_at_symbol ON trades (exchange, traded_at, symbol);") + if err != nil { + return err + } + + return err +} + +func downTradesIndexFix(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is rolled back. + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_symbol ON trades;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_symbol_fee_currency ON trades;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP INDEX trades_traded_at_symbol ON trades;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_symbol ON trades (symbol);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_symbol_fee_currency ON trades (symbol, fee_currency, traded_at);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX trades_traded_at_symbol ON trades (traded_at, symbol);") + if err != nil { + return err + } + + return err +} diff --git a/pkg/migrations/20201105093056_orders_add_index.go b/pkg/migrations/20201105093056_orders_add_index.go new file mode 100644 index 000000000..9d1251169 --- /dev/null +++ b/pkg/migrations/20201105093056_orders_add_index.go @@ -0,0 +1,43 @@ +package migrations + +import ( + "context" + + "github.com/c9s/rockhopper" +) + +func init() { + rockhopper.AddMigration(upOrdersAddIndex, downOrdersAddIndex) +} + +func upOrdersAddIndex(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is applied. + + _, err = tx.ExecContext(ctx, "CREATE INDEX orders_symbol ON orders (exchange, symbol);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE UNIQUE INDEX orders_order_id ON orders (order_id, exchange);") + if err != nil { + return err + } + + return err +} + +func downOrdersAddIndex(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is rolled back. + + _, err = tx.ExecContext(ctx, "DROP INDEX orders_symbol ON orders;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP INDEX orders_order_id ON orders;") + if err != nil { + return err + } + + return err +} diff --git a/pkg/migrations/20201106114742_klines.go b/pkg/migrations/20201106114742_klines.go new file mode 100644 index 000000000..bbb4ca9ac --- /dev/null +++ b/pkg/migrations/20201106114742_klines.go @@ -0,0 +1,73 @@ +package migrations + +import ( + "context" + + "github.com/c9s/rockhopper" +) + +func init() { + rockhopper.AddMigration(upKlines, downKlines) +} + +func upKlines(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is applied. + + _, err = tx.ExecContext(ctx, "CREATE TABLE `klines`\n(\n `gid` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,\n `exchange` VARCHAR(10) NOT NULL,\n `start_time` DATETIME(3) NOT NULL,\n `end_time` DATETIME(3) NOT NULL,\n `interval` VARCHAR(3) NOT NULL,\n `symbol` VARCHAR(7) NOT NULL,\n `open` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `high` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `low` DECIMAL(16, 8) UNSIGNED NOT NULL,\n `close` DECIMAL(16, 8) UNSIGNED NOT NULL DEFAULT 0.0,\n `volume` DECIMAL(16, 8) UNSIGNED NOT NULL DEFAULT 0.0,\n `closed` BOOL NOT NULL DEFAULT TRUE,\n `last_trade_id` INT UNSIGNED NOT NULL DEFAULT 0,\n `num_trades` INT UNSIGNED NOT NULL DEFAULT 0,\n PRIMARY KEY (`gid`)\n);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE INDEX `klines_end_time_symbol_interval` ON klines (`end_time`, `symbol`, `interval`);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE TABLE `okex_klines` LIKE `klines`;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE TABLE `binance_klines` LIKE `klines`;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "CREATE TABLE `max_klines` LIKE `klines`;") + if err != nil { + return err + } + + return err +} + +func downKlines(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is rolled back. + + _, err = tx.ExecContext(ctx, "DROP INDEX `klines_end_time_symbol_interval` ON `klines`;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP TABLE `binance_klines`;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP TABLE `okex_klines`;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP TABLE `max_klines`;") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "DROP TABLE `klines`;") + if err != nil { + return err + } + + return err +} diff --git a/pkg/migrations/20201211175751_fix_symbol_length.go b/pkg/migrations/20201211175751_fix_symbol_length.go new file mode 100644 index 000000000..6349d3763 --- /dev/null +++ b/pkg/migrations/20201211175751_fix_symbol_length.go @@ -0,0 +1,43 @@ +package migrations + +import ( + "context" + + "github.com/c9s/rockhopper" +) + +func init() { + rockhopper.AddMigration(upFixSymbolLength, downFixSymbolLength) +} + +func upFixSymbolLength(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is applied. + + _, err = tx.ExecContext(ctx, "ALTER TABLE trades MODIFY COLUMN symbol VARCHAR(9);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "ALTER TABLE orders MODIFY COLUMN symbol VARCHAR(9);") + if err != nil { + return err + } + + return err +} + +func downFixSymbolLength(ctx context.Context, tx rockhopper.SQLExecutor) (err error) { + // This code is executed when the migration is rolled back. + + _, err = tx.ExecContext(ctx, "ALTER TABLE trades MODIFY COLUMN symbol VARCHAR(8);") + if err != nil { + return err + } + + _, err = tx.ExecContext(ctx, "ALTER TABLE orders MODIFY COLUMN symbol VARCHAR(8);") + if err != nil { + return err + } + + return err +}