mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-26 00:35:15 +00:00
Merge pull request #320 from c9s/minor/integrate-binance-future-types
feature: integrate binance future types
This commit is contained in:
commit
cf0cdf5b83
17
README.md
17
README.md
|
@ -535,7 +535,7 @@ rockhopper --config rockhopper_sqlite.yaml create --type sql add_pnl_column
|
||||||
rockhopper --config rockhopper_mysql.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
|
bash utils/generate-new-migration.sh add_pnl_column
|
||||||
|
@ -558,6 +558,21 @@ Then run the following command to compile the migration files into go files:
|
||||||
make migrations
|
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
|
### Setup frontend development environment
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
|
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
|
|
@ -20,7 +20,9 @@ type OrderService struct {
|
||||||
|
|
||||||
func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol string, startTime time.Time) error {
|
func (s *OrderService) Sync(ctx context.Context, exchange types.Exchange, symbol string, startTime time.Time) error {
|
||||||
isMargin := false
|
isMargin := false
|
||||||
|
isFutures := false
|
||||||
isIsolated := false
|
isIsolated := false
|
||||||
|
|
||||||
if marginExchange, ok := exchange.(types.MarginExchange); ok {
|
if marginExchange, ok := exchange.(types.MarginExchange); ok {
|
||||||
marginSettings := marginExchange.GetMarginSettings()
|
marginSettings := marginExchange.GetMarginSettings()
|
||||||
isMargin = marginSettings.IsMargin
|
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 {
|
if err != nil {
|
||||||
return err
|
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
|
// 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) {
|
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_isolated = %v", ex, symbol, isMargin, isIsolated)
|
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{}{
|
rows, err := s.DB.NamedQuery(sql, map[string]interface{}{
|
||||||
"exchange": ex,
|
"exchange": ex,
|
||||||
"symbol": symbol,
|
"symbol": symbol,
|
||||||
"is_margin": isMargin,
|
"is_margin": isMargin,
|
||||||
|
"is_futures": isFutures,
|
||||||
"is_isolated": isIsolated,
|
"is_isolated": isIsolated,
|
||||||
"limit": limit,
|
"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) {
|
func (s *OrderService) Insert(order types.Order) (err error) {
|
||||||
if s.DB.DriverName() == "mysql" {
|
if s.DB.DriverName() == "mysql" {
|
||||||
_, err = s.DB.NamedExec(`
|
_, 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)
|
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_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)
|
ON DUPLICATE KEY UPDATE status=:status, executed_quantity=:executed_quantity, is_working=:is_working, updated_at=:updated_at`, order)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = s.DB.NamedExec(`
|
_, 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)
|
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_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)
|
`, order)
|
||||||
|
|
||||||
return err
|
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 {
|
func (s *TradeService) Sync(ctx context.Context, exchange types.Exchange, symbol string) error {
|
||||||
isMargin := false
|
isMargin := false
|
||||||
|
isFutures := false
|
||||||
isIsolated := false
|
isIsolated := false
|
||||||
|
|
||||||
if marginExchange, ok := exchange.(types.MarginExchange); ok {
|
if marginExchange, ok := exchange.(types.MarginExchange); ok {
|
||||||
marginSettings := marginExchange.GetMarginSettings()
|
marginSettings := marginExchange.GetMarginSettings()
|
||||||
isMargin = marginSettings.IsMargin
|
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 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -265,14 +277,15 @@ func generateMysqlTradingVolumeQuerySQL(options TradingVolumeQueryOptions) strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueryLast queries the last trade from the database
|
// 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) {
|
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_isolated = %v", ex, symbol, isMargin, isIsolated)
|
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{}{
|
rows, err := s.DB.NamedQuery(sql, map[string]interface{}{
|
||||||
"symbol": symbol,
|
"symbol": symbol,
|
||||||
"exchange": ex,
|
"exchange": ex,
|
||||||
"is_margin": isMargin,
|
"is_margin": isMargin,
|
||||||
|
"is_futures": isFutures,
|
||||||
"is_isolated": isIsolated,
|
"is_isolated": isIsolated,
|
||||||
"limit": limit,
|
"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 {
|
func (s *TradeService) Insert(trade types.Trade) error {
|
||||||
_, err := s.DB.NamedExec(`
|
_, 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)
|
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_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)
|
trade)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -114,6 +114,10 @@ type SubmitOrder struct {
|
||||||
GroupID uint32 `json:"groupID,omitempty"`
|
GroupID uint32 `json:"groupID,omitempty"`
|
||||||
|
|
||||||
MarginSideEffect MarginOrderSideEffectType `json:"marginSideEffect,omitempty"` // AUTO_REPAY = repay, MARGIN_BUY = borrow, defaults to NO_SIDE_EFFECT
|
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 {
|
func (o *SubmitOrder) String() string {
|
||||||
|
|
|
@ -66,6 +66,7 @@ type Trade struct {
|
||||||
FeeCurrency string `json:"feeCurrency" db:"fee_currency"`
|
FeeCurrency string `json:"feeCurrency" db:"fee_currency"`
|
||||||
|
|
||||||
IsMargin bool `json:"isMargin" db:"is_margin"`
|
IsMargin bool `json:"isMargin" db:"is_margin"`
|
||||||
|
IsFutures bool `json:"isFutures" db:"is_futures"`
|
||||||
IsIsolated bool `json:"isIsolated" db:"is_isolated"`
|
IsIsolated bool `json:"isIsolated" db:"is_isolated"`
|
||||||
|
|
||||||
StrategyID sql.NullString `json:"strategyID" db:"strategy"`
|
StrategyID sql.NullString `json:"strategyID" db:"strategy"`
|
||||||
|
|
Loading…
Reference in New Issue
Block a user