mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 09:11:55 +00:00
Merge branch 'main' into feature/336-kline-table
This commit is contained in:
commit
776f82fcd5
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
|
@ -27,7 +27,6 @@ jobs:
|
|||
- name: Build
|
||||
run: |
|
||||
npm install --global yarn
|
||||
(cd frontend && yarn install)
|
||||
make dist VERSION=${{ steps.get_version.outputs.VERSION }}
|
||||
shell: bash
|
||||
- name: Create Release
|
||||
|
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -34,3 +34,5 @@
|
|||
/pkg/server/assets.go
|
||||
|
||||
bbgo.sqlite3
|
||||
node_modules
|
||||
|
||||
|
|
19
Makefile
19
Makefile
|
@ -24,8 +24,8 @@ $(BIN_DIR):
|
|||
|
||||
|
||||
# build native bbgo
|
||||
bbgo:
|
||||
go build -tags web,release -o $(BIN_DIR)/$@ ./cmd/bbgo
|
||||
bbgo: static
|
||||
go build -tags web,release -o $(BIN_DIR)/bbgo ./cmd/bbgo
|
||||
|
||||
# build native bbgo (slim version)
|
||||
bbgo-slim:
|
||||
|
@ -124,12 +124,16 @@ dist: static dist-bbgo-linux dist-bbgo-darwin desktop
|
|||
|
||||
pkg/version/version.go: .FORCE
|
||||
bash utils/generate-version-file.sh > $@
|
||||
git commit $@ -m "bump version to $(VERSION)" || true
|
||||
|
||||
version: pkg/version/version.go migrations
|
||||
pkg/version/dev.go: .FORCE
|
||||
VERSION_SUFFIX="-dev" bash utils/generate-version-file.sh > $@
|
||||
|
||||
version: pkg/version/version.go pkg/version/dev.go migrations
|
||||
git commit $< $(word 2,$^) -m "bump version to $(VERSION)" || true
|
||||
[[ -e doc/release/$(VERSION).md ]] || (echo "file doc/release/$(VERSION).md does not exist" ; exit 1)
|
||||
git add -v doc/release/$(VERSION).md && git commit doc/release/$(VERSION).md -m "add release note" || true
|
||||
git tag -f $(VERSION)
|
||||
git push origin HEAD
|
||||
git push origin $(VERSION)
|
||||
|
||||
migrations:
|
||||
|
@ -146,8 +150,11 @@ docker-push:
|
|||
docker push yoanlin/bbgo
|
||||
bash -c "[[ -n $(DOCKER_TAG) ]] && docker push yoanlin/bbgo:$(DOCKER_TAG)"
|
||||
|
||||
frontend/out/index.html:
|
||||
(cd frontend && yarn export)
|
||||
frontend/node_modules:
|
||||
cd frontend && yarn install
|
||||
|
||||
frontend/out/index.html: frontend/node_modules
|
||||
cd frontend && yarn export
|
||||
|
||||
pkg/server/assets.go: frontend/out/index.html
|
||||
go run ./util/embed -package server -output $@ $(FRONTEND_EXPORT_DIR)
|
||||
|
|
29
README.md
29
README.md
|
@ -32,9 +32,10 @@ A trading bot framework written in Go. The name bbgo comes from the BB8 bot in t
|
|||
|
||||
Get your exchange API key and secret after you register the accounts (you can choose one or more exchanges):
|
||||
|
||||
- For MAX: <https://max.maicoin.com/signup?r=c7982718>
|
||||
- For Binance: <https://www.binancezh.com/en/register?ref=VGDGLT80>
|
||||
- For FTX: <https://ftx.com/#a=7710474>
|
||||
- MAX: <https://max.maicoin.com/signup?r=c7982718>
|
||||
- Binance: <https://www.binancezh.com/en/register?ref=VGDGLT80>
|
||||
- FTX: <https://ftx.com/#a=7710474>
|
||||
- OKEx: <https://www.okex.com/join/2412712?src=from:ios-share>
|
||||
|
||||
Since the exchange implementation and support are done by a small team, if you like the work they've done for you, It
|
||||
would be great if you can use their referral code as your support to them. :-D
|
||||
|
@ -125,6 +126,8 @@ bbgo pnl --exchange binance --asset BTC --since "2019-01-01"
|
|||
|
||||
## Advanced Configuration
|
||||
|
||||
### Notification
|
||||
|
||||
- [Setting up Telegram notification](./doc/configuration/telegram.md)
|
||||
- [Setting up Slack notification](./doc/configuration/slack.md)
|
||||
|
||||
|
@ -184,7 +187,8 @@ bbgo sync --session binance
|
|||
|
||||
Check out the strategy directory [strategy](pkg/strategy) for all built-in strategies:
|
||||
|
||||
- `pricealert` strategy demonstrates how to use the notification system [pricealert](pkg/strategy/pricealert)
|
||||
- `pricealert` strategy demonstrates how to use the notification system [pricealert](pkg/strategy/pricealert). See
|
||||
[document](./doc/strategy/pricealert.md).
|
||||
- `xpuremaker` strategy demonstrates how to maintain the orderbook and submit maker
|
||||
orders [xpuremaker](pkg/strategy/xpuremaker)
|
||||
- `buyandhold` strategy demonstrates how to subscribe kline events and submit market
|
||||
|
@ -535,7 +539,7 @@ rockhopper --config rockhopper_sqlite.yaml create --type sql add_pnl_column
|
|||
rockhopper --config rockhopper_mysql.yaml create --type sql add_pnl_column
|
||||
```
|
||||
|
||||
or
|
||||
or you can use the util script:
|
||||
|
||||
```
|
||||
bash utils/generate-new-migration.sh add_pnl_column
|
||||
|
@ -558,6 +562,21 @@ Then run the following command to compile the migration files into go files:
|
|||
make migrations
|
||||
```
|
||||
|
||||
|
||||
If you want to override the DSN and the Driver defined in the YAML config file, you can add some env vars in your dotenv file like this:
|
||||
|
||||
```shell
|
||||
ROCKHOPPER_DRIVER=mysql
|
||||
ROCKHOPPER_DIALECT=mysql
|
||||
ROCKHOPPER_DSN="root:123123@unix(/opt/local/var/run/mysql57/mysqld.sock)/bbgo"
|
||||
```
|
||||
|
||||
And then, run:
|
||||
|
||||
```shell
|
||||
dotenv -f .env.local -- rockhopper --config rockhopper_mysql.yaml up
|
||||
```
|
||||
|
||||
### Setup frontend development environment
|
||||
|
||||
```sh
|
||||
|
|
20
config/pricealert-tg.yaml
Normal file
20
config/pricealert-tg.yaml
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
notifications:
|
||||
# object routing rules
|
||||
routing:
|
||||
trade: "$symbol"
|
||||
order: "$symbol"
|
||||
submitOrder: "$session" # not supported yet
|
||||
pnL: "bbgo-pnl"
|
||||
|
||||
sessions:
|
||||
binance:
|
||||
exchange: binance
|
||||
envVarPrefix: binance
|
||||
|
||||
exchangeStrategies:
|
||||
- on: binance
|
||||
pricealert:
|
||||
symbol: "BTCUSDT"
|
||||
interval: "1m"
|
||||
minChange: 300
|
|
@ -1,5 +1,7 @@
|
|||
# Build From Source
|
||||
|
||||
## Install Go SDK
|
||||
|
||||
Go to the Go official website to download the Go SDK <https://go.dev/dl/>.
|
||||
|
||||
An example installation looks like this:
|
||||
|
@ -28,12 +30,18 @@ Make sure your `go` is successfully installed:
|
|||
go version
|
||||
```
|
||||
|
||||
## Install go-sqlite
|
||||
|
||||
If you need to use go-sqlite, you will need to enable CGO first:
|
||||
|
||||
```
|
||||
CGO_ENABLED=1 go get github.com/mattn/go-sqlite3
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
### Install bbgo via go install
|
||||
|
||||
Install bbgo:
|
||||
|
||||
```sh
|
||||
|
@ -64,6 +72,41 @@ export GOPATH=~/mygo
|
|||
|
||||
Then your bbgo will be installed at `~/mygo/bin/bbgo`.
|
||||
|
||||
### Install via git clone
|
||||
|
||||
Since the default GOPATH is located at `~/go`, you can clone the bbgo repo into the folder `~/go/src/github.com/c9s/bbgo`:
|
||||
|
||||
```shell
|
||||
mkdir -p ~/go/src/github.com/c9s
|
||||
git clone git@github.com:c9s/bbgo.git ~/go/src/github.com/c9s/bbgo
|
||||
cd ~/go/src/github.com/c9s/bbgo
|
||||
```
|
||||
|
||||
Download the go modules:
|
||||
|
||||
```shell
|
||||
go mod download
|
||||
```
|
||||
|
||||
And then you should be able to run bbgo with `go run`
|
||||
|
||||
```shell
|
||||
go run ./cmd/bbgo run
|
||||
```
|
||||
|
||||
You can also use the makefile to build bbgo:
|
||||
|
||||
```shell
|
||||
cd frontend && yarn install
|
||||
make bbgo
|
||||
```
|
||||
|
||||
If you don't need the web interface, you can build the slim version of bbgo:
|
||||
|
||||
```shell
|
||||
make bbgo-slim
|
||||
```
|
||||
|
||||
## Build inside a Alpine container
|
||||
|
||||
Starts a docker container with the alpine image:
|
||||
|
|
|
@ -23,6 +23,20 @@ you can set `TELEGRAM_AUTH_TOKEN` in the `.env.local` file, e.g.,
|
|||
TELEGRAM_BOT_AUTH_TOKEN=itsme55667788
|
||||
```
|
||||
|
||||
The alerting strategies use Telegram bot notification without further configuration. You can check the [pricealert
|
||||
yaml file](../../config/pricealert-tg.yaml) in the `config/` directory for example.
|
||||
|
||||
If you want the order submitting/filling notification, add the following to your `bbgo.yaml`:
|
||||
|
||||
```yaml
|
||||
notifications:
|
||||
routing:
|
||||
trade: "$symbol"
|
||||
order: "$symbol"
|
||||
submitOrder: "$session"
|
||||
pnL: "bbgo-pnl"
|
||||
```
|
||||
|
||||
Run your bbgo.
|
||||
|
||||
Open your Telegram app, search your bot `bbgo_bot_711222333`
|
||||
|
|
57
doc/development/new-exchange.md
Normal file
57
doc/development/new-exchange.md
Normal file
|
@ -0,0 +1,57 @@
|
|||
# Adding New Exchange
|
||||
|
||||
Open an issue and paste the following checklist to that issue.
|
||||
|
||||
You should send multiple small pull request to implement them.
|
||||
|
||||
**Please avoid sending a pull request with huge changes**
|
||||
|
||||
## Checklist
|
||||
|
||||
Exchange Interface (minimum)
|
||||
|
||||
- [ ] QueryMarkets
|
||||
- [ ] QueryKLines
|
||||
- [ ] QueryTickers
|
||||
- [ ] QueryOrders
|
||||
- [ ] QueryTrades
|
||||
- [ ] SubmitOrders
|
||||
|
||||
Convert functions:
|
||||
|
||||
- [ ] MarketData convert functions
|
||||
- [ ] toGlobalMarket
|
||||
- [ ] toGlobalTicker
|
||||
- [ ] toGlobalKLine
|
||||
- [ ] UserData convert functions
|
||||
- [ ] toGlobalOrder
|
||||
- [ ] toGlobalTrade
|
||||
- [ ] toGlobalAccount
|
||||
- [ ] toGlobalBalance
|
||||
|
||||
Stream
|
||||
|
||||
- [ ] UserDataStream
|
||||
- [ ] Trade message parser
|
||||
- [ ] Order message parser
|
||||
- [ ] Account message parser
|
||||
- [ ] Balance message parser
|
||||
- [ ] MarketDataStream
|
||||
- [ ] OrderBook message parser (or depth)
|
||||
- [ ] KLine message parser (required for backtesting)
|
||||
- [ ] Public trade message parser (optional)
|
||||
- [ ] Ticker message parser (optional)
|
||||
- [ ] ping/pong handling.
|
||||
- [ ] heart-beat hanlding or keep-alive handling.
|
||||
- [ ] handling reconnect
|
||||
|
||||
Database
|
||||
|
||||
- [ ] Add a new kline table for the exchange (this is required for back-testing)
|
||||
- [ ] Add MySQL migration SQL
|
||||
- [ ] Add SQLite migration SQL
|
||||
|
||||
Exchange Factory
|
||||
|
||||
- [ ] Add the exchange constructor to the exchange instance factory function.
|
||||
- [ ] Add extended fields to the ExchangeSession struct. (optional)
|
|
@ -1,7 +1,7 @@
|
|||
## Fixes
|
||||
|
||||
-
|
||||
- ftx: fixed FTX OnKLineClosed event
|
||||
|
||||
## Features
|
||||
## Migrations
|
||||
|
||||
-
|
||||
- add `is_futures` fields to orders and trades table
|
||||
|
|
25
doc/strategy/pricealert.md
Normal file
25
doc/strategy/pricealert.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
### Price Alert Strategy
|
||||
|
||||
This strategy will send notifications to specified channels when the price change of the specified trading pairs is
|
||||
larger than the threshold.
|
||||
|
||||
|
||||
### Prerequisite
|
||||
Setup Telegram/Slack notification before using Price Alert Strategy. See [Setting up Telegram Bot Notification
|
||||
](../configuration/telegram.md) and [Setting up Slack Notification](../configuration/slack.md).
|
||||
|
||||
|
||||
#### Parameters
|
||||
|
||||
- `symbol`
|
||||
- The trading pair symbol, e.g., `BTCUSDT`, `ETHUSDT`
|
||||
- `interval`
|
||||
- The K-line interval, e.g., `5m`, `1h`
|
||||
- `minChange`
|
||||
- Alert threshold, e.g., `100`, `500`. This is a fixed value of price change. Any price change in a single K-line
|
||||
larger than this value will trigger the alert.
|
||||
|
||||
|
||||
#### Examples
|
||||
|
||||
See [pricealert.yaml](../../config/pricealert.yaml) and [pricealert-tg.yaml](../../config/pricealert-tg.yaml)
|
18
migrations/mysql/20211205162043_add_is_futures_column.sql
Normal file
18
migrations/mysql/20211205162043_add_is_futures_column.sql
Normal file
|
@ -0,0 +1,18 @@
|
|||
-- +up
|
||||
-- +begin
|
||||
ALTER TABLE `trades` ADD COLUMN `is_futures` BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
-- +end
|
||||
|
||||
-- +begin
|
||||
ALTER TABLE `orders` ADD COLUMN `is_futures` BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
-- +end
|
||||
|
||||
-- +down
|
||||
|
||||
-- +begin
|
||||
ALTER TABLE `trades` DROP COLUMN `is_futures`;
|
||||
-- +end
|
||||
|
||||
-- +begin
|
||||
ALTER TABLE `orders` DROP COLUMN `is_futures`;
|
||||
-- +end
|
18
migrations/sqlite3/20211205162302_add_is_futures_column.sql
Normal file
18
migrations/sqlite3/20211205162302_add_is_futures_column.sql
Normal file
|
@ -0,0 +1,18 @@
|
|||
-- +up
|
||||
-- +begin
|
||||
ALTER TABLE `trades` ADD COLUMN `is_futures` BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
-- +end
|
||||
|
||||
-- +begin
|
||||
ALTER TABLE `orders` ADD COLUMN `is_futures` BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
-- +end
|
||||
|
||||
-- +down
|
||||
|
||||
-- +begin
|
||||
ALTER TABLE `trades` RENAME COLUMN `is_futures` TO `is_futures_deleted`;
|
||||
-- +end
|
||||
|
||||
-- +begin
|
||||
ALTER TABLE `orders` RENAME COLUMN `is_futures` TO `is_futures_deleted`;
|
||||
-- +end
|
|
@ -33,6 +33,8 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/exchange/ftx"
|
||||
"github.com/c9s/bbgo/pkg/exchange/okex"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
|
@ -68,29 +70,29 @@ type Exchange struct {
|
|||
doneC chan struct{}
|
||||
}
|
||||
|
||||
func NewExchange(sourceName types.ExchangeName, srv *service.BacktestService, config *bbgo.Backtest) *Exchange {
|
||||
func NewExchange(sourceName types.ExchangeName, srv *service.BacktestService, config *bbgo.Backtest) (*Exchange, error) {
|
||||
ex, err := newPublicExchange(sourceName)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
panic(errors.New("backtest config can not be nil"))
|
||||
return nil, errors.New("backtest config can not be nil")
|
||||
}
|
||||
|
||||
markets, err := bbgo.LoadExchangeMarketsWithCache(context.Background(), ex)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
startTime, err := config.ParseStartTime()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endTime, err := config.ParseEndTime()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
account := &types.Account{
|
||||
|
@ -117,7 +119,7 @@ func NewExchange(sourceName types.ExchangeName, srv *service.BacktestService, co
|
|||
}
|
||||
|
||||
e.resetMatchingBooks()
|
||||
return e
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) addTrade(trade types.Trade) {
|
||||
|
@ -313,7 +315,11 @@ func newPublicExchange(sourceExchange types.ExchangeName) (types.Exchange, error
|
|||
return binance.New("", ""), nil
|
||||
case types.ExchangeMax:
|
||||
return max.New("", ""), nil
|
||||
case types.ExchangeFTX:
|
||||
return ftx.NewExchange("", "", ""), nil
|
||||
case types.ExchangeOKEx:
|
||||
return okex.New("", "", ""), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("exchange %s is not supported", sourceExchange)
|
||||
return nil, fmt.Errorf("public data from exchange %s is not supported", sourceExchange)
|
||||
}
|
||||
|
|
|
@ -179,11 +179,11 @@ func (m *SimplePriceMatching) executeTrade(trade types.Trade) {
|
|||
if trade.IsBuyer {
|
||||
err = m.Account.UseLockedBalance(m.Market.QuoteCurrency, fixedpoint.NewFromFloat(trade.Price*trade.Quantity))
|
||||
|
||||
_ = m.Account.AddBalance(m.Market.BaseCurrency, fixedpoint.NewFromFloat(trade.Quantity))
|
||||
m.Account.AddBalance(m.Market.BaseCurrency, fixedpoint.NewFromFloat(trade.Quantity))
|
||||
} else {
|
||||
err = m.Account.UseLockedBalance(m.Market.BaseCurrency, fixedpoint.NewFromFloat(trade.Quantity))
|
||||
|
||||
_ = m.Account.AddBalance(m.Market.QuoteCurrency, fixedpoint.NewFromFloat(trade.Quantity*trade.Price))
|
||||
m.Account.AddBalance(m.Market.QuoteCurrency, fixedpoint.NewFromFloat(trade.Quantity*trade.Price))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -180,7 +180,7 @@ var BacktestCmd = &cobra.Command{
|
|||
|
||||
// if we don't have klines before the start time endpoint, the back-test will fail.
|
||||
// because the last price will be missing.
|
||||
if firstKLine != nil && syncFromTime.Before(firstKLine.EndTime) {
|
||||
if firstKLine != nil && syncFromTime.Before(firstKLine.StartTime) {
|
||||
return fmt.Errorf("the sync-from-time you gave %s is earlier than the previous sync-start-time %s. "+
|
||||
"re-syncing data from the earlier date before your first sync is not support,"+
|
||||
"please clean up the kline table and restart a new sync",
|
||||
|
@ -261,7 +261,11 @@ var BacktestCmd = &cobra.Command{
|
|||
}
|
||||
}
|
||||
|
||||
backtestExchange := backtest.NewExchange(exchangeName, backtestService, userConfig.Backtest)
|
||||
backtestExchange, err := backtest.NewExchange(exchangeName, backtestService, userConfig.Backtest)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to create backtest exchange")
|
||||
}
|
||||
|
||||
environ.SetStartTime(startTime)
|
||||
environ.AddExchange(exchangeName.String(), backtestExchange)
|
||||
|
||||
|
@ -338,11 +342,15 @@ var BacktestCmd = &cobra.Command{
|
|||
if jsonOutputEnabled {
|
||||
result := struct {
|
||||
Symbol string `json:"symbol,omitempty"`
|
||||
LastPrice float64 `json:"lastPrice,omitempty"`
|
||||
StartPrice float64 `json:"startPrice,omitempty"`
|
||||
PnLReport *pnl.AverageCostPnlReport `json:"pnlReport,omitempty"`
|
||||
InitialBalances types.BalanceMap `json:"initialBalances,omitempty"`
|
||||
FinalBalances types.BalanceMap `json:"finalBalances,omitempty"`
|
||||
}{
|
||||
Symbol: symbol,
|
||||
LastPrice: lastPrice,
|
||||
StartPrice: startPrice,
|
||||
PnLReport: report,
|
||||
InitialBalances: initBalances,
|
||||
FinalBalances: finalBalances,
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/adshao/go-binance/v2"
|
||||
"github.com/adshao/go-binance/v2/futures"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
|
@ -14,6 +15,42 @@ import (
|
|||
"github.com/c9s/bbgo/pkg/util"
|
||||
)
|
||||
|
||||
func toGlobalMarket(symbol binance.Symbol) types.Market {
|
||||
market := types.Market{
|
||||
Symbol: symbol.Symbol,
|
||||
LocalSymbol: symbol.Symbol,
|
||||
PricePrecision: symbol.QuotePrecision,
|
||||
VolumePrecision: symbol.BaseAssetPrecision,
|
||||
QuoteCurrency: symbol.QuoteAsset,
|
||||
BaseCurrency: symbol.BaseAsset,
|
||||
}
|
||||
|
||||
if f := symbol.MinNotionalFilter(); f != nil {
|
||||
market.MinNotional = util.MustParseFloat(f.MinNotional)
|
||||
market.MinAmount = util.MustParseFloat(f.MinNotional)
|
||||
}
|
||||
|
||||
// The LOT_SIZE filter defines the quantity (aka "lots" in auction terms) rules for a symbol.
|
||||
// There are 3 parts:
|
||||
// minQty defines the minimum quantity/icebergQty allowed.
|
||||
// maxQty defines the maximum quantity/icebergQty allowed.
|
||||
// stepSize defines the intervals that a quantity/icebergQty can be increased/decreased by.
|
||||
if f := symbol.LotSizeFilter(); f != nil {
|
||||
market.MinQuantity = util.MustParseFloat(f.MinQuantity)
|
||||
market.MaxQuantity = util.MustParseFloat(f.MaxQuantity)
|
||||
market.StepSize = util.MustParseFloat(f.StepSize)
|
||||
}
|
||||
|
||||
if f := symbol.PriceFilter(); f != nil {
|
||||
market.MaxPrice = util.MustParseFloat(f.MaxPrice)
|
||||
market.MinPrice = util.MustParseFloat(f.MinPrice)
|
||||
market.TickSize = util.MustParseFloat(f.TickSize)
|
||||
}
|
||||
|
||||
return market
|
||||
}
|
||||
|
||||
|
||||
func toGlobalIsolatedUserAsset(userAsset binance.IsolatedUserAsset) types.IsolatedUserAsset {
|
||||
return types.IsolatedUserAsset{
|
||||
Asset: userAsset.Asset,
|
||||
|
@ -90,8 +127,8 @@ func toGlobalMarginAccount(account *binance.MarginAccount) *types.MarginAccount
|
|||
}
|
||||
}
|
||||
|
||||
func toGlobalTicker(stats *binance.PriceChangeStats) types.Ticker {
|
||||
return types.Ticker{
|
||||
func toGlobalTicker(stats *binance.PriceChangeStats) (*types.Ticker, error) {
|
||||
return &types.Ticker{
|
||||
Volume: util.MustParseFloat(stats.Volume),
|
||||
Last: util.MustParseFloat(stats.LastPrice),
|
||||
Open: util.MustParseFloat(stats.OpenPrice),
|
||||
|
@ -100,8 +137,9 @@ func toGlobalTicker(stats *binance.PriceChangeStats) types.Ticker {
|
|||
Buy: util.MustParseFloat(stats.BidPrice),
|
||||
Sell: util.MustParseFloat(stats.AskPrice),
|
||||
Time: time.Unix(0, stats.CloseTime*int64(time.Millisecond)),
|
||||
},nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func toLocalOrderType(orderType types.OrderType) (binance.OrderType, error) {
|
||||
switch orderType {
|
||||
|
@ -303,3 +341,27 @@ func convertSubscription(s types.Subscription) string {
|
|||
|
||||
return fmt.Sprintf("%s@%s", strings.ToLower(s.Symbol), s.Channel)
|
||||
}
|
||||
|
||||
func convertPremiumIndex(index *futures.PremiumIndex) (*types.PremiumIndex, error) {
|
||||
markPrice, err := fixedpoint.NewFromString(index.MarkPrice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lastFundingRate, err := fixedpoint.NewFromString(index.LastFundingRate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nextFundingTime := time.Unix(0, index.NextFundingTime*int64(time.Millisecond))
|
||||
t := time.Unix(0, index.Time*int64(time.Millisecond))
|
||||
|
||||
return &types.PremiumIndex{
|
||||
Symbol: index.Symbol,
|
||||
MarkPrice: markPrice,
|
||||
NextFundingTime: nextFundingTime,
|
||||
LastFundingRate: lastFundingRate,
|
||||
Time: t,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -3,14 +3,14 @@ package binance
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/adshao/go-binance/v2/futures"
|
||||
"golang.org/x/time/rate"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
|
||||
"github.com/adshao/go-binance/v2"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -36,6 +36,7 @@ func init() {
|
|||
_ = types.Exchange(&Exchange{})
|
||||
_ = types.MarginExchange(&Exchange{})
|
||||
|
||||
// FIXME: this is not effected since dotenv is loaded in the rootCmd, not in the init function
|
||||
if ok, _ := strconv.ParseBool(os.Getenv("DEBUG_BINANCE_STREAM")); ok {
|
||||
log.Level = logrus.DebugLevel
|
||||
}
|
||||
|
@ -74,8 +75,7 @@ func (e *Exchange) QueryTicker(ctx context.Context, symbol string) (*types.Ticke
|
|||
return nil, err
|
||||
}
|
||||
|
||||
ticker := toGlobalTicker(stats[0])
|
||||
return &ticker, nil
|
||||
return toGlobalTicker(stats[0])
|
||||
}
|
||||
|
||||
func (e *Exchange) QueryTickers(ctx context.Context, symbol ...string) (map[string]types.Ticker, error) {
|
||||
|
@ -136,38 +136,7 @@ func (e *Exchange) QueryMarkets(ctx context.Context) (types.MarketMap, error) {
|
|||
|
||||
markets := types.MarketMap{}
|
||||
for _, symbol := range exchangeInfo.Symbols {
|
||||
market := types.Market{
|
||||
Symbol: symbol.Symbol,
|
||||
LocalSymbol: symbol.Symbol,
|
||||
PricePrecision: symbol.QuotePrecision,
|
||||
VolumePrecision: symbol.BaseAssetPrecision,
|
||||
QuoteCurrency: symbol.QuoteAsset,
|
||||
BaseCurrency: symbol.BaseAsset,
|
||||
}
|
||||
|
||||
if f := symbol.MinNotionalFilter(); f != nil {
|
||||
market.MinNotional = util.MustParseFloat(f.MinNotional)
|
||||
market.MinAmount = util.MustParseFloat(f.MinNotional)
|
||||
}
|
||||
|
||||
// The LOT_SIZE filter defines the quantity (aka "lots" in auction terms) rules for a symbol.
|
||||
// There are 3 parts:
|
||||
// minQty defines the minimum quantity/icebergQty allowed.
|
||||
// maxQty defines the maximum quantity/icebergQty allowed.
|
||||
// stepSize defines the intervals that a quantity/icebergQty can be increased/decreased by.
|
||||
if f := symbol.LotSizeFilter(); f != nil {
|
||||
market.MinQuantity = util.MustParseFloat(f.MinQuantity)
|
||||
market.MaxQuantity = util.MustParseFloat(f.MaxQuantity)
|
||||
market.StepSize = util.MustParseFloat(f.StepSize)
|
||||
}
|
||||
|
||||
if f := symbol.PriceFilter(); f != nil {
|
||||
market.MaxPrice = util.MustParseFloat(f.MaxPrice)
|
||||
market.MinPrice = util.MustParseFloat(f.MinPrice)
|
||||
market.TickSize = util.MustParseFloat(f.TickSize)
|
||||
}
|
||||
|
||||
markets[symbol.Symbol] = market
|
||||
markets[symbol.Symbol] = toGlobalMarket(symbol)
|
||||
}
|
||||
|
||||
return markets, nil
|
||||
|
@ -211,15 +180,6 @@ func (e *Exchange) QueryIsolatedMarginAccount(ctx context.Context, symbols ...st
|
|||
return toGlobalIsolatedMarginAccount(account), nil
|
||||
}
|
||||
|
||||
func (e *Exchange) getLaunchDate() (time.Time, error) {
|
||||
// binance launch date 12:00 July 14th, 2017
|
||||
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
return time.Date(2017, time.July, 14, 0, 0, 0, 0, loc), nil
|
||||
}
|
||||
|
||||
func (e *Exchange) Withdrawal(ctx context.Context, asset string, amount fixedpoint.Value, address string, options *types.WithdrawalOptions) error {
|
||||
req := e.Client.NewCreateWithdrawService()
|
||||
|
@ -250,7 +210,7 @@ func (e *Exchange) QueryWithdrawHistory(ctx context.Context, asset string, since
|
|||
|
||||
var emptyTime = time.Time{}
|
||||
if startTime == emptyTime {
|
||||
startTime, err = e.getLaunchDate()
|
||||
startTime, err = getLaunchDate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -338,7 +298,7 @@ func (e *Exchange) QueryDepositHistory(ctx context.Context, asset string, since,
|
|||
|
||||
var emptyTime = time.Time{}
|
||||
if startTime == emptyTime {
|
||||
startTime, err = e.getLaunchDate()
|
||||
startTime, err = getLaunchDate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -925,44 +885,7 @@ func (e *Exchange) BatchQueryKLines(ctx context.Context, symbol string, interval
|
|||
return allKLines, nil
|
||||
}
|
||||
|
||||
type FundingRate struct {
|
||||
FundingRate fixedpoint.Value
|
||||
FundingTime time.Time
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
type PremiumIndex struct {
|
||||
Symbol string `json:"symbol"`
|
||||
MarkPrice fixedpoint.Value `json:"markPrice"`
|
||||
LastFundingRate fixedpoint.Value `json:"lastFundingRate"`
|
||||
NextFundingTime time.Time `json:"nextFundingTime"`
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
func convertPremiumIndex(index *futures.PremiumIndex) (*PremiumIndex, error) {
|
||||
markPrice, err := fixedpoint.NewFromString(index.MarkPrice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lastFundingRate, err := fixedpoint.NewFromString(index.LastFundingRate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nextFundingTime := time.Unix(0, index.NextFundingTime*int64(time.Millisecond))
|
||||
t := time.Unix(0, index.Time*int64(time.Millisecond))
|
||||
|
||||
return &PremiumIndex{
|
||||
Symbol: index.Symbol,
|
||||
MarkPrice: markPrice,
|
||||
NextFundingTime: nextFundingTime,
|
||||
LastFundingRate: lastFundingRate,
|
||||
Time: t,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (e *Exchange) QueryPremiumIndex(ctx context.Context, symbol string) (*PremiumIndex, error) {
|
||||
func (e *Exchange) QueryPremiumIndex(ctx context.Context, symbol string) (*types.PremiumIndex, error) {
|
||||
futuresClient := binance.NewFuturesClient(e.key, e.secret)
|
||||
|
||||
// when symbol is set, only one index will be returned.
|
||||
|
@ -974,7 +897,7 @@ func (e *Exchange) QueryPremiumIndex(ctx context.Context, symbol string) (*Premi
|
|||
return convertPremiumIndex(indexes[0])
|
||||
}
|
||||
|
||||
func (e *Exchange) QueryFundingRateHistory(ctx context.Context, symbol string) (*FundingRate, error) {
|
||||
func (e *Exchange) QueryFundingRateHistory(ctx context.Context, symbol string) (*types.FundingRate, error) {
|
||||
futuresClient := binance.NewFuturesClient(e.key, e.secret)
|
||||
rates, err := futuresClient.NewFundingRateService().
|
||||
Symbol(symbol).
|
||||
|
@ -994,9 +917,19 @@ func (e *Exchange) QueryFundingRateHistory(ctx context.Context, symbol string) (
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &FundingRate{
|
||||
return &types.FundingRate{
|
||||
FundingRate: fundingRate,
|
||||
FundingTime: time.Unix(0, rate.FundingTime*int64(time.Millisecond)),
|
||||
Time: time.Unix(0, rate.Time*int64(time.Millisecond)),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getLaunchDate() (time.Time, error) {
|
||||
// binance launch date 12:00 July 14th, 2017
|
||||
loc, err := time.LoadLocation("Asia/Shanghai")
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
|
||||
return time.Date(2017, time.July, 14, 0, 0, 0, 0, loc), nil
|
||||
}
|
|
@ -3,6 +3,7 @@ package ftx
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"golang.org/x/time/rate"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
@ -23,6 +24,9 @@ const (
|
|||
|
||||
var logger = logrus.WithField("exchange", "ftx")
|
||||
|
||||
// POST https://ftx.com/api/orders 429, Success: false, err: Do not send more than 2 orders on this market per 200ms
|
||||
var requestLimit = rate.NewLimiter(rate.Every(220*time.Millisecond), 2)
|
||||
|
||||
//go:generate go run generate_symbol_map.go
|
||||
|
||||
type Exchange struct {
|
||||
|
@ -338,6 +342,9 @@ func (e *Exchange) SubmitOrders(ctx context.Context, orders ...types.SubmitOrder
|
|||
if so.TimeInForce != "GTC" && so.TimeInForce != "" {
|
||||
return createdOrders, fmt.Errorf("unsupported TimeInForce %s. only support GTC", so.TimeInForce)
|
||||
}
|
||||
if err := requestLimit.Wait(ctx); err != nil {
|
||||
logrus.WithError(err).Error("rate limit error")
|
||||
}
|
||||
or, err := e.newRest().PlaceOrder(ctx, PlaceOrderPayload{
|
||||
Market: toLocalSymbol(TrimUpperString(so.Symbol)),
|
||||
Side: TrimLowerString(string(so.Side)),
|
||||
|
@ -437,6 +444,9 @@ func sortByCreatedASC(orders []order) {
|
|||
func (e *Exchange) CancelOrders(ctx context.Context, orders ...types.Order) error {
|
||||
for _, o := range orders {
|
||||
rest := e.newRest()
|
||||
if err := requestLimit.Wait(ctx); err != nil {
|
||||
logrus.WithError(err).Error("rate limit error")
|
||||
}
|
||||
if len(o.ClientOrderID) > 0 {
|
||||
if _, err := rest.CancelOrderByClientID(ctx, o.ClientOrderID); err != nil {
|
||||
return err
|
||||
|
|
|
@ -141,7 +141,9 @@ func (s *Stream) pollKLines(ctx context.Context) {
|
|||
|
||||
if len(klines) > 0 {
|
||||
// handle mutiple klines, get the latest one
|
||||
s.EmitKLineClosed(klines[len(klines)-1])
|
||||
kline := klines[len(klines)-1]
|
||||
s.EmitKLine(kline)
|
||||
s.EmitKLineClosed(kline)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,58 +1,62 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
package ftx
|
||||
var symbolMap = map[string]string{
|
||||
"1INCH-0625": "1INCH-0625",
|
||||
"1INCH-1231": "1INCH-1231",
|
||||
"1INCH-PERP": "1INCH-PERP",
|
||||
"1INCHUSD": "1INCH/USD",
|
||||
"AAPL-0625": "AAPL-0625",
|
||||
"AAPL-1231": "AAPL-1231",
|
||||
"AAPLUSD": "AAPL/USD",
|
||||
"AAVE-0625": "AAVE-0625",
|
||||
"AAVE-1231": "AAVE-1231",
|
||||
"AAVE-PERP": "AAVE-PERP",
|
||||
"AAVEUSD": "AAVE/USD",
|
||||
"AAVEUSDT": "AAVE/USDT",
|
||||
"ABNB-0625": "ABNB-0625",
|
||||
"ABNB-1231": "ABNB-1231",
|
||||
"ABNBUSD": "ABNB/USD",
|
||||
"ACB-0625": "ACB-0625",
|
||||
"ACB-1231": "ACB-1231",
|
||||
"ACBUSD": "ACB/USD",
|
||||
"ADA-0625": "ADA-0625",
|
||||
"ADA-1231": "ADA-1231",
|
||||
"ADA-PERP": "ADA-PERP",
|
||||
"ADABEARUSD": "ADABEAR/USD",
|
||||
"ADABULLUSD": "ADABULL/USD",
|
||||
"ADAHALFUSD": "ADAHALF/USD",
|
||||
"ADAHEDGEUSD": "ADAHEDGE/USD",
|
||||
"AGLD-PERP": "AGLD-PERP",
|
||||
"AGLDUSD": "AGLD/USD",
|
||||
"AKROUSD": "AKRO/USD",
|
||||
"AKROUSDT": "AKRO/USDT",
|
||||
"ALCX-PERP": "ALCX-PERP",
|
||||
"ALCXUSD": "ALCX/USD",
|
||||
"ALGO-0625": "ALGO-0625",
|
||||
"ALEPHUSD": "ALEPH/USD",
|
||||
"ALGO-1231": "ALGO-1231",
|
||||
"ALGO-PERP": "ALGO-PERP",
|
||||
"ALGOBEARUSD": "ALGOBEAR/USD",
|
||||
"ALGOBULLUSD": "ALGOBULL/USD",
|
||||
"ALGOHALFUSD": "ALGOHALF/USD",
|
||||
"ALGOHEDGEUSD": "ALGOHEDGE/USD",
|
||||
"ALICE-PERP": "ALICE-PERP",
|
||||
"ALICEUSD": "ALICE/USD",
|
||||
"ALPHA-PERP": "ALPHA-PERP",
|
||||
"ALPHAUSD": "ALPHA/USD",
|
||||
"ALT-0625": "ALT-0625",
|
||||
"ALT-1231": "ALT-1231",
|
||||
"ALT-PERP": "ALT-PERP",
|
||||
"ALTBEARUSD": "ALTBEAR/USD",
|
||||
"ALTBULLUSD": "ALTBULL/USD",
|
||||
"ALTHALFUSD": "ALTHALF/USD",
|
||||
"ALTHEDGEUSD": "ALTHEDGE/USD",
|
||||
"AMC-0625": "AMC-0625",
|
||||
"AMC-1231": "AMC-1231",
|
||||
"AMCUSD": "AMC/USD",
|
||||
"AMD-0625": "AMD-0625",
|
||||
"AMD-1231": "AMD-1231",
|
||||
"AMDUSD": "AMD/USD",
|
||||
"AMPL-PERP": "AMPL-PERP",
|
||||
"AMPLUSD": "AMPL/USD",
|
||||
"AMPLUSDT": "AMPL/USDT",
|
||||
"AMZN-0625": "AMZN-0625",
|
||||
"AMZN-1231": "AMZN-1231",
|
||||
"AMZNUSD": "AMZN/USD",
|
||||
"APHA-0625": "APHA-0625",
|
||||
"APHA-1231": "APHA-1231",
|
||||
"APHAUSD": "APHA/USD",
|
||||
"AR-PERP": "AR-PERP",
|
||||
"ARKK-0625": "ARKK-0625",
|
||||
"ARKK-1231": "ARKK-1231",
|
||||
"ARKKUSD": "ARKK/USD",
|
||||
"ASD-0625": "ASD-0625",
|
||||
"ASD-PERP": "ASD-PERP",
|
||||
"ASDBEARUSD": "ASDBEAR/USD",
|
||||
"ASDBEARUSDT": "ASDBEAR/USDT",
|
||||
|
@ -61,7 +65,9 @@ var symbolMap = map[string]string{
|
|||
"ASDHALFUSD": "ASDHALF/USD",
|
||||
"ASDHEDGEUSD": "ASDHEDGE/USD",
|
||||
"ASDUSD": "ASD/USD",
|
||||
"ATOM-0625": "ATOM-0625",
|
||||
"ATLAS-PERP": "ATLAS-PERP",
|
||||
"ATLASUSD": "ATLAS/USD",
|
||||
"ATOM-1231": "ATOM-1231",
|
||||
"ATOM-PERP": "ATOM-PERP",
|
||||
"ATOMBEARUSD": "ATOMBEAR/USD",
|
||||
"ATOMBULLUSD": "ATOMBULL/USD",
|
||||
|
@ -70,16 +76,16 @@ var symbolMap = map[string]string{
|
|||
"AUDIO-PERP": "AUDIO-PERP",
|
||||
"AUDIOUSD": "AUDIO/USD",
|
||||
"AUDIOUSDT": "AUDIO/USDT",
|
||||
"AUDUSD": "AUD/USD",
|
||||
"AVAX-0625": "AVAX-0625",
|
||||
"AURYUSD": "AURY/USD",
|
||||
"AVAX-1231": "AVAX-1231",
|
||||
"AVAX-PERP": "AVAX-PERP",
|
||||
"AXS-PERP": "AXS-PERP",
|
||||
"AXSUSD": "AXS/USD",
|
||||
"BABA-0625": "BABA-0625",
|
||||
"BABA-1231": "BABA-1231",
|
||||
"BABAUSD": "BABA/USD",
|
||||
"BADGER-PERP": "BADGER-PERP",
|
||||
"BADGERUSD": "BADGER/USD",
|
||||
"BAL-0625": "BAL-0625",
|
||||
"BAL-1231": "BAL-1231",
|
||||
"BAL-PERP": "BAL-PERP",
|
||||
"BALBEARUSD": "BALBEAR/USD",
|
||||
"BALBEARUSDT": "BALBEAR/USDT",
|
||||
|
@ -93,11 +99,12 @@ var symbolMap = map[string]string{
|
|||
"BANDUSD": "BAND/USD",
|
||||
"BAO-PERP": "BAO-PERP",
|
||||
"BAOUSD": "BAO/USD",
|
||||
"BARUSD": "BAR/USD",
|
||||
"BAT-PERP": "BAT-PERP",
|
||||
"BATUSD": "BAT/USD",
|
||||
"BB-0625": "BB-0625",
|
||||
"BB-1231": "BB-1231",
|
||||
"BBUSD": "BB/USD",
|
||||
"BCH-0625": "BCH-0625",
|
||||
"BCH-1231": "BCH-1231",
|
||||
"BCH-PERP": "BCH-PERP",
|
||||
"BCHBEARUSD": "BCHBEAR/USD",
|
||||
"BCHBEARUSDT": "BCHBEAR/USDT",
|
||||
|
@ -111,11 +118,17 @@ var symbolMap = map[string]string{
|
|||
"BEARSHITUSD": "BEARSHIT/USD",
|
||||
"BEARUSD": "BEAR/USD",
|
||||
"BEARUSDT": "BEAR/USDT",
|
||||
"BILI-0625": "BILI-0625",
|
||||
"BICOUSD": "BICO/USD",
|
||||
"BILI-1231": "BILI-1231",
|
||||
"BILIUSD": "BILI/USD",
|
||||
"BITW-0625": "BITW-0625",
|
||||
"BIT-PERP": "BIT-PERP",
|
||||
"BITO-1231": "BITO-1231",
|
||||
"BITOUSD": "BITO/USD",
|
||||
"BITUSD": "BIT/USD",
|
||||
"BITW-1231": "BITW-1231",
|
||||
"BITWUSD": "BITW/USD",
|
||||
"BNB-0625": "BNB-0625",
|
||||
"BLTUSD": "BLT/USD",
|
||||
"BNB-1231": "BNB-1231",
|
||||
"BNB-PERP": "BNB-PERP",
|
||||
"BNBBEARUSD": "BNBBEAR/USD",
|
||||
"BNBBEARUSDT": "BNBBEAR/USDT",
|
||||
|
@ -128,14 +141,15 @@ var symbolMap = map[string]string{
|
|||
"BNBUSDT": "BNB/USDT",
|
||||
"BNT-PERP": "BNT-PERP",
|
||||
"BNTUSD": "BNT/USD",
|
||||
"BNTX-0625": "BNTX-0625",
|
||||
"BNTX-1231": "BNTX-1231",
|
||||
"BNTXUSD": "BNTX/USD",
|
||||
"BOBA-PERP": "BOBA-PERP",
|
||||
"BOBAUSD": "BOBA/USD",
|
||||
"BOLSONARO2022": "BOLSONARO2022",
|
||||
"BRZ-0625": "BRZ-0625",
|
||||
"BRZ-PERP": "BRZ-PERP",
|
||||
"BRZUSD": "BRZ/USD",
|
||||
"BRZUSDT": "BRZ/USDT",
|
||||
"BSV-0625": "BSV-0625",
|
||||
"BSV-1231": "BSV-1231",
|
||||
"BSV-PERP": "BSV-PERP",
|
||||
"BSVBEARUSD": "BSVBEAR/USD",
|
||||
"BSVBEARUSDT": "BSVBEAR/USDT",
|
||||
|
@ -143,20 +157,18 @@ var symbolMap = map[string]string{
|
|||
"BSVBULLUSDT": "BSVBULL/USDT",
|
||||
"BSVHALFUSD": "BSVHALF/USD",
|
||||
"BSVHEDGEUSD": "BSVHEDGE/USD",
|
||||
"BTC-0625": "BTC-0625",
|
||||
"BTC-0924": "BTC-0924",
|
||||
"BTC-0325": "BTC-0325",
|
||||
"BTC-1231": "BTC-1231",
|
||||
"BTC-MOVE-0526": "BTC-MOVE-0526",
|
||||
"BTC-MOVE-0527": "BTC-MOVE-0527",
|
||||
"BTC-MOVE-2021Q2": "BTC-MOVE-2021Q2",
|
||||
"BTC-MOVE-2021Q3": "BTC-MOVE-2021Q3",
|
||||
"BTC-MOVE-1209": "BTC-MOVE-1209",
|
||||
"BTC-MOVE-1210": "BTC-MOVE-1210",
|
||||
"BTC-MOVE-2021Q4": "BTC-MOVE-2021Q4",
|
||||
"BTC-MOVE-WK-0528": "BTC-MOVE-WK-0528",
|
||||
"BTC-MOVE-WK-0604": "BTC-MOVE-WK-0604",
|
||||
"BTC-MOVE-WK-0611": "BTC-MOVE-WK-0611",
|
||||
"BTC-MOVE-WK-0618": "BTC-MOVE-WK-0618",
|
||||
"BTC-MOVE-2022Q1": "BTC-MOVE-2022Q1",
|
||||
"BTC-MOVE-2022Q2": "BTC-MOVE-2022Q2",
|
||||
"BTC-MOVE-WK-1210": "BTC-MOVE-WK-1210",
|
||||
"BTC-MOVE-WK-1217": "BTC-MOVE-WK-1217",
|
||||
"BTC-MOVE-WK-1224": "BTC-MOVE-WK-1224",
|
||||
"BTC-MOVE-WK-1231": "BTC-MOVE-WK-1231",
|
||||
"BTC-PERP": "BTC-PERP",
|
||||
"BTCAUD": "BTC/AUD",
|
||||
"BTCBRZ": "BTC/BRZ",
|
||||
"BTCEUR": "BTC/EUR",
|
||||
"BTCTRYB": "BTC/TRYB",
|
||||
|
@ -169,20 +181,30 @@ var symbolMap = map[string]string{
|
|||
"BVOLBTC": "BVOL/BTC",
|
||||
"BVOLUSD": "BVOL/USD",
|
||||
"BVOLUSDT": "BVOL/USDT",
|
||||
"BYND-0625": "BYND-0625",
|
||||
"BYND-1231": "BYND-1231",
|
||||
"BYNDUSD": "BYND/USD",
|
||||
"C98-PERP": "C98-PERP",
|
||||
"C98USD": "C98/USD",
|
||||
"CADUSD": "CAD/USD",
|
||||
"CAKE-PERP": "CAKE-PERP",
|
||||
"CEL-0625": "CEL-0625",
|
||||
"CEL-1231": "CEL-1231",
|
||||
"CEL-PERP": "CEL-PERP",
|
||||
"CELBTC": "CEL/BTC",
|
||||
"CELO-PERP": "CELO-PERP",
|
||||
"CELUSD": "CEL/USD",
|
||||
"CGC-0625": "CGC-0625",
|
||||
"CGC-1231": "CGC-1231",
|
||||
"CGCUSD": "CGC/USD",
|
||||
"CHZ-0625": "CHZ-0625",
|
||||
"CHR-PERP": "CHR-PERP",
|
||||
"CHRUSD": "CHR/USD",
|
||||
"CHZ-1231": "CHZ-1231",
|
||||
"CHZ-PERP": "CHZ-PERP",
|
||||
"CHZUSD": "CHZ/USD",
|
||||
"CHZUSDT": "CHZ/USDT",
|
||||
"CITYUSD": "CITY/USD",
|
||||
"CLV-PERP": "CLV-PERP",
|
||||
"CLVUSD": "CLV/USD",
|
||||
"COINUSD": "COIN/USD",
|
||||
"COMP-0625": "COMP-0625",
|
||||
"COMP-1231": "COMP-1231",
|
||||
"COMP-PERP": "COMP-PERP",
|
||||
"COMPBEARUSD": "COMPBEAR/USD",
|
||||
"COMPBEARUSDT": "COMPBEAR/USDT",
|
||||
|
@ -195,12 +217,12 @@ var symbolMap = map[string]string{
|
|||
"CONV-PERP": "CONV-PERP",
|
||||
"CONVUSD": "CONV/USD",
|
||||
"COPEUSD": "COPE/USD",
|
||||
"CREAM-0625": "CREAM-0625",
|
||||
"CQTUSD": "CQT/USD",
|
||||
"CREAM-PERP": "CREAM-PERP",
|
||||
"CREAMUSD": "CREAM/USD",
|
||||
"CREAMUSDT": "CREAM/USDT",
|
||||
"CRO-PERP": "CRO-PERP",
|
||||
"CRON-0625": "CRON-0625",
|
||||
"CRON-1231": "CRON-1231",
|
||||
"CRONUSD": "CRON/USD",
|
||||
"CROUSD": "CRO/USD",
|
||||
"CRV-PERP": "CRV-PERP",
|
||||
|
@ -214,12 +236,14 @@ var symbolMap = map[string]string{
|
|||
"CUSDTHEDGEUSD": "CUSDTHEDGE/USD",
|
||||
"CUSDTUSD": "CUSDT/USD",
|
||||
"CUSDTUSDT": "CUSDT/USDT",
|
||||
"CVC-PERP": "CVC-PERP",
|
||||
"CVCUSD": "CVC/USD",
|
||||
"DAIUSD": "DAI/USD",
|
||||
"DAIUSDT": "DAI/USDT",
|
||||
"DASH-PERP": "DASH-PERP",
|
||||
"DAWN-PERP": "DAWN-PERP",
|
||||
"DAWNUSD": "DAWN/USD",
|
||||
"DEFI-0625": "DEFI-0625",
|
||||
"DEFI-1231": "DEFI-1231",
|
||||
"DEFI-PERP": "DEFI-PERP",
|
||||
"DEFIBEARUSD": "DEFIBEAR/USD",
|
||||
"DEFIBEARUSDT": "DEFIBEAR/USDT",
|
||||
|
@ -229,12 +253,14 @@ var symbolMap = map[string]string{
|
|||
"DEFIHEDGEUSD": "DEFIHEDGE/USD",
|
||||
"DENT-PERP": "DENT-PERP",
|
||||
"DENTUSD": "DENT/USD",
|
||||
"DMG-PERP": "DMG-PERP",
|
||||
"DFLUSD": "DFL/USD",
|
||||
"DKNG-1231": "DKNG-1231",
|
||||
"DKNGUSD": "DKNG/USD",
|
||||
"DMGUSD": "DMG/USD",
|
||||
"DMGUSDT": "DMG/USDT",
|
||||
"DODO-PERP": "DODO-PERP",
|
||||
"DODOUSD": "DODO/USD",
|
||||
"DOGE-0625": "DOGE-0625",
|
||||
"DOGE-1231": "DOGE-1231",
|
||||
"DOGE-PERP": "DOGE-PERP",
|
||||
"DOGEBEAR2021USD": "DOGEBEAR2021/USD",
|
||||
"DOGEBTC": "DOGE/BTC",
|
||||
|
@ -243,19 +269,26 @@ var symbolMap = map[string]string{
|
|||
"DOGEHEDGEUSD": "DOGEHEDGE/USD",
|
||||
"DOGEUSD": "DOGE/USD",
|
||||
"DOGEUSDT": "DOGE/USDT",
|
||||
"DOT-0625": "DOT-0625",
|
||||
"DOT-1231": "DOT-1231",
|
||||
"DOT-PERP": "DOT-PERP",
|
||||
"DRGN-0625": "DRGN-0625",
|
||||
"DRGN-1231": "DRGN-1231",
|
||||
"DRGN-PERP": "DRGN-PERP",
|
||||
"DRGNBEARUSD": "DRGNBEAR/USD",
|
||||
"DRGNBULLUSD": "DRGNBULL/USD",
|
||||
"DRGNHALFUSD": "DRGNHALF/USD",
|
||||
"DRGNHEDGEUSD": "DRGNHEDGE/USD",
|
||||
"DYDX-PERP": "DYDX-PERP",
|
||||
"DYDXUSD": "DYDX/USD",
|
||||
"EDEN-1231": "EDEN-1231",
|
||||
"EDEN-PERP": "EDEN-PERP",
|
||||
"EDENUSD": "EDEN/USD",
|
||||
"EGLD-PERP": "EGLD-PERP",
|
||||
"EMBUSD": "EMB/USD",
|
||||
"ENJ-PERP": "ENJ-PERP",
|
||||
"ENJUSD": "ENJ/USD",
|
||||
"EOS-0625": "EOS-0625",
|
||||
"ENS-PERP": "ENS-PERP",
|
||||
"ENSUSD": "ENS/USD",
|
||||
"EOS-1231": "EOS-1231",
|
||||
"EOS-PERP": "EOS-PERP",
|
||||
"EOSBEARUSD": "EOSBEAR/USD",
|
||||
"EOSBEARUSDT": "EOSBEAR/USDT",
|
||||
|
@ -268,18 +301,16 @@ var symbolMap = map[string]string{
|
|||
"ETCBULLUSD": "ETCBULL/USD",
|
||||
"ETCHALFUSD": "ETCHALF/USD",
|
||||
"ETCHEDGEUSD": "ETCHEDGE/USD",
|
||||
"ETH-0625": "ETH-0625",
|
||||
"ETH-0924": "ETH-0924",
|
||||
"ETH-0325": "ETH-0325",
|
||||
"ETH-1231": "ETH-1231",
|
||||
"ETH-PERP": "ETH-PERP",
|
||||
"ETHAUD": "ETH/AUD",
|
||||
"ETHBEARUSD": "ETHBEAR/USD",
|
||||
"ETHBEARUSDT": "ETHBEAR/USDT",
|
||||
"ETHBRZ": "ETH/BRZ",
|
||||
"ETHBTC": "ETH/BTC",
|
||||
"ETHBULLUSD": "ETHBULL/USD",
|
||||
"ETHBULLUSDT": "ETHBULL/USDT",
|
||||
"ETHE-0625": "ETHE-0625",
|
||||
"ETHE-1231": "ETHE-1231",
|
||||
"ETHEUR": "ETH/EUR",
|
||||
"ETHEUSD": "ETHE/USD",
|
||||
"ETHHALFUSD": "ETHHALF/USD",
|
||||
|
@ -287,18 +318,18 @@ var symbolMap = map[string]string{
|
|||
"ETHUSD": "ETH/USD",
|
||||
"ETHUSDT": "ETH/USDT",
|
||||
"EURUSD": "EUR/USD",
|
||||
"EXCH-0625": "EXCH-0625",
|
||||
"EXCH-1231": "EXCH-1231",
|
||||
"EXCH-PERP": "EXCH-PERP",
|
||||
"EXCHBEARUSD": "EXCHBEAR/USD",
|
||||
"EXCHBULLUSD": "EXCHBULL/USD",
|
||||
"EXCHHALFUSD": "EXCHHALF/USD",
|
||||
"EXCHHEDGEUSD": "EXCHHEDGE/USD",
|
||||
"FB-0625": "FB-0625",
|
||||
"FB-1231": "FB-1231",
|
||||
"FBUSD": "FB/USD",
|
||||
"FIDA-PERP": "FIDA-PERP",
|
||||
"FIDAUSD": "FIDA/USD",
|
||||
"FIDAUSDT": "FIDA/USDT",
|
||||
"FIL-0625": "FIL-0625",
|
||||
"FIL-1231": "FIL-1231",
|
||||
"FIL-PERP": "FIL-PERP",
|
||||
"FLM-PERP": "FLM-PERP",
|
||||
"FLOW-PERP": "FLOW-PERP",
|
||||
|
@ -310,21 +341,26 @@ var symbolMap = map[string]string{
|
|||
"FTTBTC": "FTT/BTC",
|
||||
"FTTUSD": "FTT/USD",
|
||||
"FTTUSDT": "FTT/USDT",
|
||||
"GALA-PERP": "GALA-PERP",
|
||||
"GALAUSD": "GALA/USD",
|
||||
"GALUSD": "GAL/USD",
|
||||
"GBPUSD": "GBP/USD",
|
||||
"GBTC-0625": "GBTC-0625",
|
||||
"GBTC-1231": "GBTC-1231",
|
||||
"GBTCUSD": "GBTC/USD",
|
||||
"GDX-0625": "GDX-0625",
|
||||
"GDXJ-0625": "GDXJ-0625",
|
||||
"GDX-1231": "GDX-1231",
|
||||
"GDXJ-1231": "GDXJ-1231",
|
||||
"GDXJUSD": "GDXJ/USD",
|
||||
"GDXUSD": "GDX/USD",
|
||||
"GLD-0625": "GLD-0625",
|
||||
"GENEUSD": "GENE/USD",
|
||||
"GLD-1231": "GLD-1231",
|
||||
"GLDUSD": "GLD/USD",
|
||||
"GLXYUSD": "GLXY/USD",
|
||||
"GME-0625": "GME-0625",
|
||||
"GME-1231": "GME-1231",
|
||||
"GMEUSD": "GME/USD",
|
||||
"GOOGL-0625": "GOOGL-0625",
|
||||
"GODSUSD": "GODS/USD",
|
||||
"GOOGL-1231": "GOOGL-1231",
|
||||
"GOOGLUSD": "GOOGL/USD",
|
||||
"GRT-0625": "GRT-0625",
|
||||
"GRT-1231": "GRT-1231",
|
||||
"GRT-PERP": "GRT-PERP",
|
||||
"GRTBEARUSD": "GRTBEAR/USD",
|
||||
"GRTBULLUSD": "GRTBULL/USD",
|
||||
|
@ -337,6 +373,7 @@ var symbolMap = map[string]string{
|
|||
"HEDGEUSD": "HEDGE/USD",
|
||||
"HGETUSD": "HGET/USD",
|
||||
"HGETUSDT": "HGET/USDT",
|
||||
"HMTUSD": "HMT/USD",
|
||||
"HNT-PERP": "HNT-PERP",
|
||||
"HNTUSD": "HNT/USD",
|
||||
"HNTUSDT": "HNT/USDT",
|
||||
|
@ -358,7 +395,11 @@ var symbolMap = map[string]string{
|
|||
"IBVOLUSD": "IBVOL/USD",
|
||||
"IBVOLUSDT": "IBVOL/USDT",
|
||||
"ICP-PERP": "ICP-PERP",
|
||||
"ICX-PERP": "ICX-PERP",
|
||||
"IMXUSD": "IMX/USD",
|
||||
"INTERUSD": "INTER/USD",
|
||||
"IOTA-PERP": "IOTA-PERP",
|
||||
"JETUSD": "JET/USD",
|
||||
"JSTUSD": "JST/USD",
|
||||
"KAVA-PERP": "KAVA-PERP",
|
||||
"KIN-PERP": "KIN-PERP",
|
||||
|
@ -372,8 +413,9 @@ var symbolMap = map[string]string{
|
|||
"KNCHEDGEUSD": "KNCHEDGE/USD",
|
||||
"KNCUSD": "KNC/USD",
|
||||
"KNCUSDT": "KNC/USDT",
|
||||
"KSHIB-PERP": "KSHIB-PERP",
|
||||
"KSHIBUSD": "KSHIB/USD",
|
||||
"KSM-PERP": "KSM-PERP",
|
||||
"LB-0812": "LB-0812",
|
||||
"LEO-PERP": "LEO-PERP",
|
||||
"LEOBEARUSD": "LEOBEAR/USD",
|
||||
"LEOBULLUSD": "LEOBULL/USD",
|
||||
|
@ -382,7 +424,7 @@ var symbolMap = map[string]string{
|
|||
"LEOUSD": "LEO/USD",
|
||||
"LINA-PERP": "LINA-PERP",
|
||||
"LINAUSD": "LINA/USD",
|
||||
"LINK-0625": "LINK-0625",
|
||||
"LINK-1231": "LINK-1231",
|
||||
"LINK-PERP": "LINK-PERP",
|
||||
"LINKBEARUSD": "LINKBEAR/USD",
|
||||
"LINKBEARUSDT": "LINKBEAR/USDT",
|
||||
|
@ -395,7 +437,7 @@ var symbolMap = map[string]string{
|
|||
"LINKUSDT": "LINK/USDT",
|
||||
"LRC-PERP": "LRC-PERP",
|
||||
"LRCUSD": "LRC/USD",
|
||||
"LTC-0625": "LTC-0625",
|
||||
"LTC-1231": "LTC-1231",
|
||||
"LTC-PERP": "LTC-PERP",
|
||||
"LTCBEARUSD": "LTCBEAR/USD",
|
||||
"LTCBEARUSDT": "LTCBEAR/USDT",
|
||||
|
@ -409,6 +451,8 @@ var symbolMap = map[string]string{
|
|||
"LUAUSD": "LUA/USD",
|
||||
"LUAUSDT": "LUA/USDT",
|
||||
"LUNA-PERP": "LUNA-PERP",
|
||||
"MANA-PERP": "MANA-PERP",
|
||||
"MANAUSD": "MANA/USD",
|
||||
"MAPS-PERP": "MAPS-PERP",
|
||||
"MAPSUSD": "MAPS/USD",
|
||||
"MAPSUSDT": "MAPS/USDT",
|
||||
|
@ -416,15 +460,18 @@ var symbolMap = map[string]string{
|
|||
"MATHUSDT": "MATH/USDT",
|
||||
"MATIC-PERP": "MATIC-PERP",
|
||||
"MATICBEAR2021USD": "MATICBEAR2021/USD",
|
||||
"MATICBTC": "MATIC/BTC",
|
||||
"MATICBULLUSD": "MATICBULL/USD",
|
||||
"MATICHALFUSD": "MATICHALF/USD",
|
||||
"MATICHEDGEUSD": "MATICHEDGE/USD",
|
||||
"MATICUSD": "MATIC/USD",
|
||||
"MCB-PERP": "MCB-PERP",
|
||||
"MCBUSD": "MCB/USD",
|
||||
"MEDIA-PERP": "MEDIA-PERP",
|
||||
"MEDIAUSD": "MEDIA/USD",
|
||||
"MER-PERP": "MER-PERP",
|
||||
"MERUSD": "MER/USD",
|
||||
"MID-0625": "MID-0625",
|
||||
"MID-1231": "MID-1231",
|
||||
"MID-PERP": "MID-PERP",
|
||||
"MIDBEARUSD": "MIDBEAR/USD",
|
||||
"MIDBULLUSD": "MIDBULL/USD",
|
||||
|
@ -435,45 +482,49 @@ var symbolMap = map[string]string{
|
|||
"MKRBULLUSD": "MKRBULL/USD",
|
||||
"MKRUSD": "MKR/USD",
|
||||
"MKRUSDT": "MKR/USDT",
|
||||
"MNGO-PERP": "MNGO-PERP",
|
||||
"MNGOUSD": "MNGO/USD",
|
||||
"MOBUSD": "MOB/USD",
|
||||
"MOBUSDT": "MOB/USDT",
|
||||
"MRNA-0625": "MRNA-0625",
|
||||
"MRNA-1231": "MRNA-1231",
|
||||
"MRNAUSD": "MRNA/USD",
|
||||
"MSTR-0625": "MSTR-0625",
|
||||
"MSOLUSD": "MSOL/USD",
|
||||
"MSTR-1231": "MSTR-1231",
|
||||
"MSTRUSD": "MSTR/USD",
|
||||
"MTA-PERP": "MTA-PERP",
|
||||
"MTAUSD": "MTA/USD",
|
||||
"MTAUSDT": "MTA/USDT",
|
||||
"MTL-PERP": "MTL-PERP",
|
||||
"MTLUSD": "MTL/USD",
|
||||
"MVDA10-PERP": "MVDA10-PERP",
|
||||
"MVDA25-PERP": "MVDA25-PERP",
|
||||
"NEAR-PERP": "NEAR-PERP",
|
||||
"NEO-PERP": "NEO-PERP",
|
||||
"NFLX-0625": "NFLX-0625",
|
||||
"NFLX-1231": "NFLX-1231",
|
||||
"NFLXUSD": "NFLX/USD",
|
||||
"NIO-0625": "NIO-0625",
|
||||
"NIO-1231": "NIO-1231",
|
||||
"NIOUSD": "NIO/USD",
|
||||
"NOK-0625": "NOK-0625",
|
||||
"NOK-1231": "NOK-1231",
|
||||
"NOKUSD": "NOK/USD",
|
||||
"NVDA-0625": "NVDA-0625",
|
||||
"NVDA-1231": "NVDA-1231",
|
||||
"NVDAUSD": "NVDA/USD",
|
||||
"OKB-0625": "OKB-0625",
|
||||
"OKB-1231": "OKB-1231",
|
||||
"OKB-PERP": "OKB-PERP",
|
||||
"OKBBEARUSD": "OKBBEAR/USD",
|
||||
"OKBBULLUSD": "OKBBULL/USD",
|
||||
"OKBHALFUSD": "OKBHALF/USD",
|
||||
"OKBHEDGEUSD": "OKBHEDGE/USD",
|
||||
"OKBUSD": "OKB/USD",
|
||||
"OLY2021": "OLY2021",
|
||||
"OMG-0625": "OMG-0625",
|
||||
"OMG-1231": "OMG-1231",
|
||||
"OMG-PERP": "OMG-PERP",
|
||||
"OMGUSD": "OMG/USD",
|
||||
"ONE-PERP": "ONE-PERP",
|
||||
"ONT-PERP": "ONT-PERP",
|
||||
"ORBS-PERP": "ORBS-PERP",
|
||||
"ORBSUSD": "ORBS/USD",
|
||||
"OXY-PERP": "OXY-PERP",
|
||||
"OXYUSD": "OXY/USD",
|
||||
"OXYUSDT": "OXY/USDT",
|
||||
"PAXG-0625": "PAXG-0625",
|
||||
"PAXG-PERP": "PAXG-PERP",
|
||||
"PAXGBEARUSD": "PAXGBEAR/USD",
|
||||
"PAXGBULLUSD": "PAXGBULL/USD",
|
||||
|
@ -481,13 +532,16 @@ var symbolMap = map[string]string{
|
|||
"PAXGHEDGEUSD": "PAXGHEDGE/USD",
|
||||
"PAXGUSD": "PAXG/USD",
|
||||
"PAXGUSDT": "PAXG/USDT",
|
||||
"PENN-0625": "PENN-0625",
|
||||
"PENN-1231": "PENN-1231",
|
||||
"PENNUSD": "PENN/USD",
|
||||
"PERP-PERP": "PERP-PERP",
|
||||
"PERPUSD": "PERP/USD",
|
||||
"PFE-0625": "PFE-0625",
|
||||
"PFE-1231": "PFE-1231",
|
||||
"PFEUSD": "PFE/USD",
|
||||
"PRIV-0625": "PRIV-0625",
|
||||
"POLIS-PERP": "POLIS-PERP",
|
||||
"POLISUSD": "POLIS/USD",
|
||||
"PORTUSD": "PORT/USD",
|
||||
"PRIV-1231": "PRIV-1231",
|
||||
"PRIV-PERP": "PRIV-PERP",
|
||||
"PRIVBEARUSD": "PRIVBEAR/USD",
|
||||
"PRIVBULLUSD": "PRIVBULL/USD",
|
||||
|
@ -495,20 +549,24 @@ var symbolMap = map[string]string{
|
|||
"PRIVHEDGEUSD": "PRIVHEDGE/USD",
|
||||
"PROM-PERP": "PROM-PERP",
|
||||
"PROMUSD": "PROM/USD",
|
||||
"PSGUSD": "PSG/USD",
|
||||
"PTUUSD": "PTU/USD",
|
||||
"PUNDIX-PERP": "PUNDIX-PERP",
|
||||
"PUNDIXUSD": "PUNDIX/USD",
|
||||
"PYPL-0625": "PYPL-0625",
|
||||
"PYPL-1231": "PYPL-1231",
|
||||
"PYPLUSD": "PYPL/USD",
|
||||
"QTUM-PERP": "QTUM-PERP",
|
||||
"RAMP-PERP": "RAMP-PERP",
|
||||
"RAMPUSD": "RAMP/USD",
|
||||
"RAY-PERP": "RAY-PERP",
|
||||
"RAYUSD": "RAY/USD",
|
||||
"REEF-0625": "REEF-0625",
|
||||
"REEF-1231": "REEF-1231",
|
||||
"REEF-PERP": "REEF-PERP",
|
||||
"REEFUSD": "REEF/USD",
|
||||
"REN-PERP": "REN-PERP",
|
||||
"RENUSD": "REN/USD",
|
||||
"RNDR-PERP": "RNDR-PERP",
|
||||
"RNDRUSD": "RNDR/USD",
|
||||
"ROOK-PERP": "ROOK-PERP",
|
||||
"ROOKUSD": "ROOK/USD",
|
||||
"ROOKUSDT": "ROOK/USDT",
|
||||
|
@ -522,61 +580,73 @@ var symbolMap = map[string]string{
|
|||
"SC-PERP": "SC-PERP",
|
||||
"SECO-PERP": "SECO-PERP",
|
||||
"SECOUSD": "SECO/USD",
|
||||
"SGDUSD": "SGD/USD",
|
||||
"SHIB-PERP": "SHIB-PERP",
|
||||
"SHIBUSD": "SHIB/USD",
|
||||
"SHIT-0625": "SHIT-0625",
|
||||
"SHIT-1231": "SHIT-1231",
|
||||
"SHIT-PERP": "SHIT-PERP",
|
||||
"SKL-PERP": "SKL-PERP",
|
||||
"SKLUSD": "SKL/USD",
|
||||
"SLV-0625": "SLV-0625",
|
||||
"SLNDUSD": "SLND/USD",
|
||||
"SLP-PERP": "SLP-PERP",
|
||||
"SLPUSD": "SLP/USD",
|
||||
"SLRSUSD": "SLRS/USD",
|
||||
"SLV-1231": "SLV-1231",
|
||||
"SLVUSD": "SLV/USD",
|
||||
"SNX-PERP": "SNX-PERP",
|
||||
"SNXUSD": "SNX/USD",
|
||||
"SOL-0625": "SOL-0625",
|
||||
"SNYUSD": "SNY/USD",
|
||||
"SOL-1231": "SOL-1231",
|
||||
"SOL-PERP": "SOL-PERP",
|
||||
"SOLBTC": "SOL/BTC",
|
||||
"SOLUSD": "SOL/USD",
|
||||
"SOLUSDT": "SOL/USDT",
|
||||
"SPY-0625": "SPY-0625",
|
||||
"SPELL-PERP": "SPELL-PERP",
|
||||
"SPELLUSD": "SPELL/USD",
|
||||
"SPY-1231": "SPY-1231",
|
||||
"SPYUSD": "SPY/USD",
|
||||
"SQ-0625": "SQ-0625",
|
||||
"SQ-1231": "SQ-1231",
|
||||
"SQUSD": "SQ/USD",
|
||||
"SRM-PERP": "SRM-PERP",
|
||||
"SRMUSD": "SRM/USD",
|
||||
"SRMUSDT": "SRM/USDT",
|
||||
"SRN-PERP": "SRN-PERP",
|
||||
"STARSUSD": "STARS/USD",
|
||||
"STEP-PERP": "STEP-PERP",
|
||||
"STEPUSD": "STEP/USD",
|
||||
"STETHUSD": "STETH/USD",
|
||||
"STMX-PERP": "STMX-PERP",
|
||||
"STMXUSD": "STMX/USD",
|
||||
"STORJ-PERP": "STORJ-PERP",
|
||||
"STORJUSD": "STORJ/USD",
|
||||
"STSOLUSD": "STSOL/USD",
|
||||
"STX-PERP": "STX-PERP",
|
||||
"SUNUSD": "SUN/USD",
|
||||
"SUSHI-0625": "SUSHI-0625",
|
||||
"SUSHI-1231": "SUSHI-1231",
|
||||
"SUSHI-PERP": "SUSHI-PERP",
|
||||
"SUSHIBEARUSD": "SUSHIBEAR/USD",
|
||||
"SUSHIBTC": "SUSHI/BTC",
|
||||
"SUSHIBULLUSD": "SUSHIBULL/USD",
|
||||
"SUSHIUSD": "SUSHI/USD",
|
||||
"SUSHIUSDT": "SUSHI/USDT",
|
||||
"SXP-0625": "SXP-0625",
|
||||
"SXP-1231": "SXP-1231",
|
||||
"SXP-PERP": "SXP-PERP",
|
||||
"SXPBEARUSD": "SXPBEAR/USD",
|
||||
"SXPBTC": "SXP/BTC",
|
||||
"SXPBULLUSD": "SXPBULL/USD",
|
||||
"SXPHALFUSD": "SXPHALF/USD",
|
||||
"SXPHALFUSDT": "SXPHALF/USDT",
|
||||
"SXPHEDGEUSD": "SXPHEDGE/USD",
|
||||
"SXPUSD": "SXP/USD",
|
||||
"SXPUSDT": "SXP/USDT",
|
||||
"THETA-0625": "THETA-0625",
|
||||
"THETA-1231": "THETA-1231",
|
||||
"THETA-PERP": "THETA-PERP",
|
||||
"THETABEARUSD": "THETABEAR/USD",
|
||||
"THETABULLUSD": "THETABULL/USD",
|
||||
"THETAHALFUSD": "THETAHALF/USD",
|
||||
"THETAHEDGEUSD": "THETAHEDGE/USD",
|
||||
"TLRY-0625": "TLRY-0625",
|
||||
"TLM-PERP": "TLM-PERP",
|
||||
"TLMUSD": "TLM/USD",
|
||||
"TLRY-1231": "TLRY-1231",
|
||||
"TLRYUSD": "TLRY/USD",
|
||||
"TOMO-PERP": "TOMO-PERP",
|
||||
"TOMOBEAR2021USD": "TOMOBEAR2021/USD",
|
||||
|
@ -585,55 +655,58 @@ var symbolMap = map[string]string{
|
|||
"TOMOHEDGEUSD": "TOMOHEDGE/USD",
|
||||
"TOMOUSD": "TOMO/USD",
|
||||
"TOMOUSDT": "TOMO/USDT",
|
||||
"TRU-0625": "TRU-0625",
|
||||
"TONCOIN-PERP": "TONCOIN-PERP",
|
||||
"TONCOINUSD": "TONCOIN/USD",
|
||||
"TRU-PERP": "TRU-PERP",
|
||||
"TRUMP2024": "TRUMP2024",
|
||||
"TRUUSD": "TRU/USD",
|
||||
"TRUUSDT": "TRU/USDT",
|
||||
"TRX-0625": "TRX-0625",
|
||||
"TRX-1231": "TRX-1231",
|
||||
"TRX-PERP": "TRX-PERP",
|
||||
"TRXBEARUSD": "TRXBEAR/USD",
|
||||
"TRXBTC": "TRX/BTC",
|
||||
"TRXBULLUSD": "TRXBULL/USD",
|
||||
"TRXHALFUSD": "TRXHALF/USD",
|
||||
"TRXHEDGEUSD": "TRXHEDGE/USD",
|
||||
"TRXUSD": "TRX/USD",
|
||||
"TRXUSDT": "TRX/USDT",
|
||||
"TRYB-0625": "TRYB-0625",
|
||||
"TRYB-PERP": "TRYB-PERP",
|
||||
"TRYBBEARUSD": "TRYBBEAR/USD",
|
||||
"TRYBBULLUSD": "TRYBBULL/USD",
|
||||
"TRYBHALFUSD": "TRYBHALF/USD",
|
||||
"TRYBHEDGEUSD": "TRYBHEDGE/USD",
|
||||
"TRYBUSD": "TRYB/USD",
|
||||
"TSLA-0625": "TSLA-0625",
|
||||
"TSLA-1231": "TSLA-1231",
|
||||
"TSLABTC": "TSLA/BTC",
|
||||
"TSLADOGE": "TSLA/DOGE",
|
||||
"TSLAUSD": "TSLA/USD",
|
||||
"TSM-0625": "TSM-0625",
|
||||
"TSM-1231": "TSM-1231",
|
||||
"TSMUSD": "TSM/USD",
|
||||
"TWTR-0625": "TWTR-0625",
|
||||
"TULIP-PERP": "TULIP-PERP",
|
||||
"TULIPUSD": "TULIP/USD",
|
||||
"TWTR-1231": "TWTR-1231",
|
||||
"TWTRUSD": "TWTR/USD",
|
||||
"UBER-0625": "UBER-0625",
|
||||
"UBER-1231": "UBER-1231",
|
||||
"UBERUSD": "UBER/USD",
|
||||
"UBXTUSD": "UBXT/USD",
|
||||
"UBXTUSDT": "UBXT/USDT",
|
||||
"UNI-0625": "UNI-0625",
|
||||
"UNI-1231": "UNI-1231",
|
||||
"UNI-PERP": "UNI-PERP",
|
||||
"UNIBTC": "UNI/BTC",
|
||||
"UNISWAP-0625": "UNISWAP-0625",
|
||||
"UNISWAP-1231": "UNISWAP-1231",
|
||||
"UNISWAP-PERP": "UNISWAP-PERP",
|
||||
"UNISWAPBEARUSD": "UNISWAPBEAR/USD",
|
||||
"UNISWAPBULLUSD": "UNISWAPBULL/USD",
|
||||
"UNIUSD": "UNI/USD",
|
||||
"UNIUSDT": "UNI/USDT",
|
||||
"USDT-0625": "USDT-0625",
|
||||
"USDT-1231": "USDT-1231",
|
||||
"USDT-PERP": "USDT-PERP",
|
||||
"USDTBEARUSD": "USDTBEAR/USD",
|
||||
"USDTBULLUSD": "USDTBULL/USD",
|
||||
"USDTHALFUSD": "USDTHALF/USD",
|
||||
"USDTHEDGEUSD": "USDTHEDGE/USD",
|
||||
"USDTUSD": "USDT/USD",
|
||||
"USO-0625": "USO-0625",
|
||||
"USO-1231": "USO-1231",
|
||||
"USOUSD": "USO/USD",
|
||||
"VET-PERP": "VET-PERP",
|
||||
"VETBEARUSD": "VETBEAR/USD",
|
||||
|
@ -641,14 +714,17 @@ var symbolMap = map[string]string{
|
|||
"VETBULLUSD": "VETBULL/USD",
|
||||
"VETBULLUSDT": "VETBULL/USDT",
|
||||
"VETHEDGEUSD": "VETHEDGE/USD",
|
||||
"WAVES-0625": "WAVES-0625",
|
||||
"VGXUSD": "VGX/USD",
|
||||
"WAVES-1231": "WAVES-1231",
|
||||
"WAVES-PERP": "WAVES-PERP",
|
||||
"WAVESUSD": "WAVES/USD",
|
||||
"WBTCBTC": "WBTC/BTC",
|
||||
"WBTCUSD": "WBTC/USD",
|
||||
"WNDRUSD": "WNDR/USD",
|
||||
"WRXUSD": "WRX/USD",
|
||||
"WRXUSDT": "WRX/USDT",
|
||||
"WSB-0625": "WSB-0625",
|
||||
"XAUT-0625": "XAUT-0625",
|
||||
"WSB-1231": "WSB-1231",
|
||||
"XAUT-1231": "XAUT-1231",
|
||||
"XAUT-PERP": "XAUT-PERP",
|
||||
"XAUTBEARUSD": "XAUTBEAR/USD",
|
||||
"XAUTBULLUSD": "XAUTBULL/USD",
|
||||
|
@ -661,7 +737,7 @@ var symbolMap = map[string]string{
|
|||
"XLMBEARUSD": "XLMBEAR/USD",
|
||||
"XLMBULLUSD": "XLMBULL/USD",
|
||||
"XMR-PERP": "XMR-PERP",
|
||||
"XRP-0625": "XRP-0625",
|
||||
"XRP-1231": "XRP-1231",
|
||||
"XRP-PERP": "XRP-PERP",
|
||||
"XRPBEARUSD": "XRPBEAR/USD",
|
||||
"XRPBEARUSDT": "XRPBEAR/USDT",
|
||||
|
@ -672,7 +748,7 @@ var symbolMap = map[string]string{
|
|||
"XRPHEDGEUSD": "XRPHEDGE/USD",
|
||||
"XRPUSD": "XRP/USD",
|
||||
"XRPUSDT": "XRP/USDT",
|
||||
"XTZ-0625": "XTZ-0625",
|
||||
"XTZ-1231": "XTZ-1231",
|
||||
"XTZ-PERP": "XTZ-PERP",
|
||||
"XTZBEARUSD": "XTZBEAR/USD",
|
||||
"XTZBEARUSDT": "XTZBEAR/USDT",
|
||||
|
@ -680,7 +756,7 @@ var symbolMap = map[string]string{
|
|||
"XTZBULLUSDT": "XTZBULL/USDT",
|
||||
"XTZHALFUSD": "XTZHALF/USD",
|
||||
"XTZHEDGEUSD": "XTZHEDGE/USD",
|
||||
"YFI-0625": "YFI-0625",
|
||||
"YFI-1231": "YFI-1231",
|
||||
"YFI-PERP": "YFI-PERP",
|
||||
"YFIBTC": "YFI/BTC",
|
||||
"YFII-PERP": "YFII-PERP",
|
||||
|
@ -691,7 +767,7 @@ var symbolMap = map[string]string{
|
|||
"ZECBEARUSD": "ZECBEAR/USD",
|
||||
"ZECBULLUSD": "ZECBULL/USD",
|
||||
"ZIL-PERP": "ZIL-PERP",
|
||||
"ZM-0625": "ZM-0625",
|
||||
"ZM-1231": "ZM-1231",
|
||||
"ZMUSD": "ZM/USD",
|
||||
"ZRX-PERP": "ZRX-PERP",
|
||||
"ZRXUSD": "ZRX/USD",
|
||||
|
|
|
@ -28,7 +28,10 @@ type Exchange struct {
|
|||
|
||||
func New(key, secret, passphrase string) *Exchange {
|
||||
client := okexapi.NewClient()
|
||||
|
||||
if len(key) > 0 && len(secret) > 0 {
|
||||
client.Auth(key, secret, passphrase)
|
||||
}
|
||||
|
||||
return &Exchange{
|
||||
key: key,
|
||||
|
|
44
pkg/migrations/mysql/20211205162043_add_is_futures_column.go
Normal file
44
pkg/migrations/mysql/20211205162043_add_is_futures_column.go
Normal file
|
@ -0,0 +1,44 @@
|
|||
package mysql
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/c9s/rockhopper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
AddMigration(upAddIsFuturesColumn, downAddIsFuturesColumn)
|
||||
|
||||
}
|
||||
|
||||
func upAddIsFuturesColumn(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
|
||||
// This code is executed when the migration is applied.
|
||||
|
||||
_, err = tx.ExecContext(ctx, "ALTER TABLE `trades` ADD COLUMN `is_futures` BOOLEAN NOT NULL DEFAULT FALSE;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, "ALTER TABLE `orders` ADD COLUMN `is_futures` BOOLEAN NOT NULL DEFAULT FALSE;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddIsFuturesColumn(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` DROP COLUMN `is_futures`;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, "ALTER TABLE `orders` DROP COLUMN `is_futures`;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package sqlite3
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/c9s/rockhopper"
|
||||
)
|
||||
|
||||
func init() {
|
||||
AddMigration(upAddIsFuturesColumn, downAddIsFuturesColumn)
|
||||
|
||||
}
|
||||
|
||||
func upAddIsFuturesColumn(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
|
||||
// This code is executed when the migration is applied.
|
||||
|
||||
_, err = tx.ExecContext(ctx, "ALTER TABLE `trades` ADD COLUMN `is_futures` BOOLEAN NOT NULL DEFAULT FALSE;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, "ALTER TABLE `orders` ADD COLUMN `is_futures` BOOLEAN NOT NULL DEFAULT FALSE;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func downAddIsFuturesColumn(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` RENAME COLUMN `is_futures` TO `is_futures_deleted`;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.ExecContext(ctx, "ALTER TABLE `orders` RENAME COLUMN `is_futures` TO `is_futures_deleted`;")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
|
@ -20,7 +20,9 @@ type OrderService struct {
|
|||
|
||||
func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol string, startTime time.Time) error {
|
||||
isMargin := false
|
||||
isFutures := false
|
||||
isIsolated := false
|
||||
|
||||
if marginExchange, ok := exchange.(types.MarginExchange); ok {
|
||||
marginSettings := marginExchange.GetMarginSettings()
|
||||
isMargin = marginSettings.IsMargin
|
||||
|
@ -30,7 +32,17 @@ func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol
|
|||
}
|
||||
}
|
||||
|
||||
records, err := s.QueryLast(exchange.Name(), symbol, isMargin, isIsolated, 50)
|
||||
if futuresExchange, ok := exchange.(types.FuturesExchange); ok {
|
||||
futuresSettings := futuresExchange.GetFuturesSettings()
|
||||
isFutures = futuresSettings.IsFutures
|
||||
isIsolated = futuresSettings.IsIsolatedFutures
|
||||
if futuresSettings.IsIsolatedFutures {
|
||||
symbol = futuresSettings.IsolatedFuturesSymbol
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
records, err := s.QueryLast(exchange.Name(), symbol, isMargin, isFutures, isIsolated, 50)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -78,14 +90,15 @@ func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol
|
|||
|
||||
|
||||
// QueryLast queries the last order from the database
|
||||
func (s *OrderService) QueryLast(ex types.ExchangeName, symbol string, isMargin, isIsolated bool, limit int) ([]types.Order, error) {
|
||||
log.Infof("querying last order exchange = %s AND symbol = %s AND is_margin = %v AND is_isolated = %v", ex, symbol, isMargin, isIsolated)
|
||||
func (s *OrderService) QueryLast(ex types.ExchangeName, symbol string, isMargin, isFutures, isIsolated bool, limit int) ([]types.Order, error) {
|
||||
log.Infof("querying last order exchange = %s AND symbol = %s AND is_margin = %v AND is_futures = %v AND is_isolated = %v", ex, symbol, isMargin, isFutures, isIsolated)
|
||||
|
||||
sql := `SELECT * FROM orders WHERE exchange = :exchange AND symbol = :symbol AND is_margin = :is_margin AND is_isolated = :is_isolated ORDER BY gid DESC LIMIT :limit`
|
||||
sql := `SELECT * FROM orders WHERE exchange = :exchange AND symbol = :symbol AND is_margin = :is_margin AND is_futures = :is_futures AND is_isolated = :is_isolated ORDER BY gid DESC LIMIT :limit`
|
||||
rows, err := s.DB.NamedQuery(sql, map[string]interface{}{
|
||||
"exchange": ex,
|
||||
"symbol": symbol,
|
||||
"is_margin": isMargin,
|
||||
"is_futures": isFutures,
|
||||
"is_isolated": isIsolated,
|
||||
"limit": limit,
|
||||
})
|
||||
|
@ -195,15 +208,15 @@ func (s *OrderService) scanRows(rows *sqlx.Rows) (orders []types.Order, err erro
|
|||
func (s *OrderService) Insert(order types.Order) (err error) {
|
||||
if s.DB.DriverName() == "mysql" {
|
||||
_, err = s.DB.NamedExec(`
|
||||
INSERT INTO orders (exchange, order_id, client_order_id, order_type, status, symbol, price, stop_price, quantity, executed_quantity, side, is_working, time_in_force, created_at, updated_at, is_margin, is_isolated)
|
||||
VALUES (:exchange, :order_id, :client_order_id, :order_type, :status, :symbol, :price, :stop_price, :quantity, :executed_quantity, :side, :is_working, :time_in_force, :created_at, :updated_at, :is_margin, :is_isolated)
|
||||
INSERT INTO orders (exchange, order_id, client_order_id, order_type, status, symbol, price, stop_price, quantity, executed_quantity, side, is_working, time_in_force, created_at, updated_at, is_margin, is_futures, is_isolated)
|
||||
VALUES (:exchange, :order_id, :client_order_id, :order_type, :status, :symbol, :price, :stop_price, :quantity, :executed_quantity, :side, :is_working, :time_in_force, :created_at, :updated_at, :is_margin, :is_futures, :is_isolated)
|
||||
ON DUPLICATE KEY UPDATE status=:status, executed_quantity=:executed_quantity, is_working=:is_working, updated_at=:updated_at`, order)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = s.DB.NamedExec(`
|
||||
INSERT INTO orders (exchange, order_id, client_order_id, order_type, status, symbol, price, stop_price, quantity, executed_quantity, side, is_working, time_in_force, created_at, updated_at, is_margin, is_isolated)
|
||||
VALUES (:exchange, :order_id, :client_order_id, :order_type, :status, :symbol, :price, :stop_price, :quantity, :executed_quantity, :side, :is_working, :time_in_force, :created_at, :updated_at, :is_margin, :is_isolated)
|
||||
INSERT INTO orders (exchange, order_id, client_order_id, order_type, status, symbol, price, stop_price, quantity, executed_quantity, side, is_working, time_in_force, created_at, updated_at, is_margin, is_futures, is_isolated)
|
||||
VALUES (:exchange, :order_id, :client_order_id, :order_type, :status, :symbol, :price, :stop_price, :quantity, :executed_quantity, :side, :is_working, :time_in_force, :created_at, :updated_at, :is_margin, :is_futures, :is_isolated)
|
||||
`, order)
|
||||
|
||||
return err
|
||||
|
|
|
@ -52,7 +52,9 @@ func NewTradeService(db *sqlx.DB) *TradeService {
|
|||
|
||||
func (s *TradeService) Sync(ctx context.Context, exchange types.Exchange, symbol string) error {
|
||||
isMargin := false
|
||||
isFutures := false
|
||||
isIsolated := false
|
||||
|
||||
if marginExchange, ok := exchange.(types.MarginExchange); ok {
|
||||
marginSettings := marginExchange.GetMarginSettings()
|
||||
isMargin = marginSettings.IsMargin
|
||||
|
@ -62,8 +64,18 @@ func (s *TradeService) Sync(ctx context.Context, exchange types.Exchange, symbol
|
|||
}
|
||||
}
|
||||
|
||||
if futuresExchange, ok := exchange.(types.FuturesExchange); ok {
|
||||
futuresSettings := futuresExchange.GetFuturesSettings()
|
||||
isFutures = futuresSettings.IsFutures
|
||||
isIsolated = futuresSettings.IsIsolatedFutures
|
||||
if futuresSettings.IsIsolatedFutures {
|
||||
symbol = futuresSettings.IsolatedFuturesSymbol
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// records descending ordered
|
||||
records, err := s.QueryLast(exchange.Name(), symbol, isMargin, isIsolated, 50)
|
||||
records, err := s.QueryLast(exchange.Name(), symbol, isMargin, isFutures, isIsolated, 50)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -265,14 +277,15 @@ func generateMysqlTradingVolumeQuerySQL(options TradingVolumeQueryOptions) strin
|
|||
}
|
||||
|
||||
// QueryLast queries the last trade from the database
|
||||
func (s *TradeService) QueryLast(ex types.ExchangeName, symbol string, isMargin, isIsolated bool, limit int) ([]types.Trade, error) {
|
||||
log.Debugf("querying last trade exchange = %s AND symbol = %s AND is_margin = %v AND is_isolated = %v", ex, symbol, isMargin, isIsolated)
|
||||
func (s *TradeService) QueryLast(ex types.ExchangeName, symbol string, isMargin, isFutures, isIsolated bool, limit int) ([]types.Trade, error) {
|
||||
log.Debugf("querying last trade exchange = %s AND symbol = %s AND is_margin = %v AND is_futures = %v AND is_isolated = %v", ex, symbol, isMargin, isFutures, isIsolated)
|
||||
|
||||
sql := "SELECT * FROM trades WHERE exchange = :exchange AND symbol = :symbol AND is_margin = :is_margin AND is_isolated = :is_isolated ORDER BY gid DESC LIMIT :limit"
|
||||
sql := "SELECT * FROM trades WHERE exchange = :exchange AND symbol = :symbol AND is_margin = :is_margin AND is_futures = :is_futures AND is_isolated = :is_isolated ORDER BY gid DESC LIMIT :limit"
|
||||
rows, err := s.DB.NamedQuery(sql, map[string]interface{}{
|
||||
"symbol": symbol,
|
||||
"exchange": ex,
|
||||
"is_margin": isMargin,
|
||||
"is_futures": isFutures,
|
||||
"is_isolated": isIsolated,
|
||||
"limit": limit,
|
||||
})
|
||||
|
@ -439,8 +452,8 @@ func (s *TradeService) scanRows(rows *sqlx.Rows) (trades []types.Trade, err erro
|
|||
|
||||
func (s *TradeService) Insert(trade types.Trade) error {
|
||||
_, err := s.DB.NamedExec(`
|
||||
INSERT INTO trades (id, exchange, order_id, symbol, price, quantity, quote_quantity, side, is_buyer, is_maker, fee, fee_currency, traded_at, is_margin, is_isolated)
|
||||
VALUES (:id, :exchange, :order_id, :symbol, :price, :quantity, :quote_quantity, :side, :is_buyer, :is_maker, :fee, :fee_currency, :traded_at, :is_margin, :is_isolated)`,
|
||||
INSERT INTO trades (id, exchange, order_id, symbol, price, quantity, quote_quantity, side, is_buyer, is_maker, fee, fee_currency, traded_at, is_margin, is_futures, is_isolated)
|
||||
VALUES (:id, :exchange, :order_id, :symbol, :price, :quantity, :quote_quantity, :side, :is_buyer, :is_maker, :fee, :fee_currency, :traded_at, :is_margin, :is_futures, :is_isolated)`,
|
||||
trade)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,13 +4,14 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/c9s/bbgo/pkg/exchange/binance"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/sirupsen/logrus"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/exchange/binance"
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/bbgo"
|
||||
"github.com/c9s/bbgo/pkg/types"
|
||||
)
|
||||
|
@ -87,7 +88,7 @@ func (s *Strategy) Validate() error {
|
|||
}
|
||||
|
||||
func (s *Strategy) listenToFundingRate(ctx context.Context, exchange *binance.Exchange) {
|
||||
var previousIndex, fundingRate24HoursLowIndex *binance.PremiumIndex
|
||||
var previousIndex, fundingRate24HoursLowIndex *types.PremiumIndex
|
||||
|
||||
fundingRateTicker := time.NewTicker(1 * time.Hour)
|
||||
defer fundingRateTicker.Stop()
|
||||
|
|
|
@ -225,7 +225,7 @@ func (a *Account) Balance(currency string) (balance Balance, ok bool) {
|
|||
return balance, ok
|
||||
}
|
||||
|
||||
func (a *Account) AddBalance(currency string, fund fixedpoint.Value) error {
|
||||
func (a *Account) AddBalance(currency string, fund fixedpoint.Value) {
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
|
@ -233,7 +233,7 @@ func (a *Account) AddBalance(currency string, fund fixedpoint.Value) error {
|
|||
if ok {
|
||||
balance.Available += fund
|
||||
a.balances[currency] = balance
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
a.balances[currency] = Balance{
|
||||
|
@ -241,7 +241,6 @@ func (a *Account) AddBalance(currency string, fund fixedpoint.Value) error {
|
|||
Available: fund,
|
||||
Locked: 0,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Account) UseLockedBalance(currency string, fund fixedpoint.Value) error {
|
||||
|
|
|
@ -10,9 +10,9 @@ import (
|
|||
|
||||
func TestAccountLockAndUnlock(t *testing.T) {
|
||||
a := NewAccount()
|
||||
err := a.AddBalance("USDT", 1000)
|
||||
assert.NoError(t, err)
|
||||
a.AddBalance("USDT", 1000)
|
||||
|
||||
var err error
|
||||
balance, ok := a.Balance("USDT")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, balance.Available, fixedpoint.Value(1000))
|
||||
|
@ -36,9 +36,9 @@ func TestAccountLockAndUnlock(t *testing.T) {
|
|||
|
||||
func TestAccountLockAndUse(t *testing.T) {
|
||||
a := NewAccount()
|
||||
err := a.AddBalance("USDT", 1000)
|
||||
assert.NoError(t, err)
|
||||
a.AddBalance("USDT", 1000)
|
||||
|
||||
var err error
|
||||
balance, ok := a.Balance("USDT")
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, balance.Available, fixedpoint.Value(1000))
|
||||
|
|
13
pkg/types/fundingrate.go
Normal file
13
pkg/types/fundingrate.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
)
|
||||
|
||||
type FundingRate struct {
|
||||
FundingRate fixedpoint.Value
|
||||
FundingTime time.Time
|
||||
Time time.Time
|
||||
}
|
|
@ -114,6 +114,10 @@ type SubmitOrder struct {
|
|||
GroupID uint32 `json:"groupID,omitempty"`
|
||||
|
||||
MarginSideEffect MarginOrderSideEffectType `json:"marginSideEffect,omitempty"` // AUTO_REPAY = repay, MARGIN_BUY = borrow, defaults to NO_SIDE_EFFECT
|
||||
|
||||
// futures order fields
|
||||
ReduceOnly bool `json:"reduceOnly" db:"reduce_only"`
|
||||
ClosePosition bool `json:"closePosition" db:"close_position"`
|
||||
}
|
||||
|
||||
func (o *SubmitOrder) String() string {
|
||||
|
|
15
pkg/types/premiumindex.go
Normal file
15
pkg/types/premiumindex.go
Normal file
|
@ -0,0 +1,15 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||
)
|
||||
|
||||
type PremiumIndex struct {
|
||||
Symbol string `json:"symbol"`
|
||||
MarkPrice fixedpoint.Value `json:"markPrice"`
|
||||
LastFundingRate fixedpoint.Value `json:"lastFundingRate"`
|
||||
NextFundingTime time.Time `json:"nextFundingTime"`
|
||||
Time time.Time `json:"time"`
|
||||
}
|
|
@ -66,6 +66,7 @@ type Trade struct {
|
|||
FeeCurrency string `json:"feeCurrency" db:"fee_currency"`
|
||||
|
||||
IsMargin bool `json:"isMargin" db:"is_margin"`
|
||||
IsFutures bool `json:"isFutures" db:"is_futures"`
|
||||
IsIsolated bool `json:"isIsolated" db:"is_isolated"`
|
||||
|
||||
StrategyID sql.NullString `json:"strategyID" db:"strategy"`
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
package version
|
||||
|
||||
const Version = "v1.19.4-5b11ef81"
|
||||
const Version = "v1.20.0-c1e69194"
|
||||
|
||||
const VersionGitRef = "5b11ef81"
|
||||
const VersionGitRef = "c1e69194"
|
||||
|
||||
|
|
|
@ -7,6 +7,10 @@ if [[ -z $VERSION ]] ; then
|
|||
VERSION=$(git describe --tags)
|
||||
fi
|
||||
|
||||
if [[ -n $VERSION_SUFFIX ]] ; then
|
||||
VERSION=${VERSION}${VERSION_SUFFIX}
|
||||
fi
|
||||
|
||||
cat <<END
|
||||
// +build release
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user