Skip to content

Commit fbcf152

Browse files
authored
Merge pull request #2460 from anywhy/binanca-algo-order
FEATURE: [binance] add the normal order ID for the algo order
2 parents 9127d1e + 83e2476 commit fbcf152

9 files changed

Lines changed: 144 additions & 4 deletions
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- +up
2+
-- +begin
3+
ALTER TABLE `orders` ADD COLUMN `actual_order_id` BIGINT UNSIGNED NOT NULL DEFAULT 0;
4+
-- +end
5+
6+
-- +down
7+
-- +begin
8+
ALTER TABLE `orders` DROP COLUMN `actual_order_id`;
9+
-- +end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-- +up
2+
-- +begin
3+
ALTER TABLE orders ADD COLUMN actual_order_id INTEGER NOT NULL DEFAULT 0;
4+
-- +end
5+
6+
-- +down
7+
-- +begin
8+
ALTER TABLE orders DROP COLUMN actual_order_id;
9+
-- +end

pkg/exchange/binance/convert_futures.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package binance
22

33
import (
44
"fmt"
5+
"strconv"
56

67
"github.com/adshao/go-binance/v2/futures"
78
"github.com/c9s/bbgo/pkg/exchange/binance/binanceapi"
@@ -163,6 +164,7 @@ func toGlobalFuturesOrder[T FuturesOrderConstraint](orderSource T, isIsolated bo
163164
avgPrice string
164165
timeInForce futures.TimeInForceType
165166
orderID int64
167+
actualOrderId uint64
166168
status futures.OrderStatusType
167169
executedQuantity string
168170
time int64
@@ -220,6 +222,7 @@ func toGlobalFuturesOrder[T FuturesOrderConstraint](orderSource T, isIsolated bo
220222
avgPrice = "" // GetAlgoOrderResp doesn't have AvgPrice
221223
timeInForce = o.TimeInForce
222224
orderID = o.AlgoId
225+
actualOrderId, _ = strconv.ParseUint(o.ActualOrderId, 10, 64)
223226
status = futures.OrderStatusType(o.AlgoStatus)
224227
executedQuantity = "0" // GetAlgoOrderResp doesn't have ExecutedQuantity
225228
time = o.CreateTime
@@ -260,6 +263,7 @@ func toGlobalFuturesOrder[T FuturesOrderConstraint](orderSource T, isIsolated bo
260263
},
261264
Exchange: types.ExchangeBinance,
262265
OrderID: uint64(orderID),
266+
ActualOrderId: actualOrderId,
263267
Status: toGlobalFuturesOrderStatus(status),
264268
ExecutedQuantity: fixedpoint.MustNewFromString(executedQuantity),
265269
CreationTime: types.Time(millisecondTime(time)),

pkg/exchange/binance/parse.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7+
"strconv"
78
"time"
89

910
"github.com/adshao/go-binance/v2/futures"
@@ -1349,6 +1350,11 @@ func (e *AlgoOrderUpdateEvent) OrderFutures() (*types.Order, error) {
13491350
return nil, errors.New("algo update event type is not for futures order")
13501351
}
13511352

1353+
var actualOrderId uint64
1354+
if e.AlgoOrder.OrderId != "" {
1355+
actualOrderId, _ = strconv.ParseUint(e.AlgoOrder.OrderId, 10, 64)
1356+
}
1357+
13521358
return &types.Order{
13531359
Exchange: types.ExchangeBinance,
13541360
SubmitOrder: types.SubmitOrder{
@@ -1362,6 +1368,7 @@ func (e *AlgoOrderUpdateEvent) OrderFutures() (*types.Order, error) {
13621368
TimeInForce: types.TimeInForce(e.AlgoOrder.TimeInForce),
13631369
},
13641370
OrderID: uint64(e.AlgoOrder.AlgoId),
1371+
ActualOrderId: actualOrderId,
13651372
Status: toGlobalFuturesOrderStatus(futures.OrderStatusType(e.AlgoOrder.Status)),
13661373
ExecutedQuantity: e.AlgoOrder.ExecutedQuantity,
13671374
UpdateTime: types.Time(e.TransactionTime.Time()),

pkg/exchange/binance/parse_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,4 +756,54 @@ func TestAlgoOrderUpdateEvent_OrderFutures(t *testing.T) {
756756
})
757757
}
758758
})
759+
760+
t.Run("parses numeric actual order id", func(t *testing.T) {
761+
event := &AlgoOrderUpdateEvent{
762+
TransactionTime: transactionTime,
763+
AlgoOrder: AlgoOrder{
764+
ClientAlgoId: "test-actual-order-id",
765+
AlgoId: 112233,
766+
OrderType: "TAKE_PROFIT",
767+
Symbol: "BNBUSDT",
768+
Side: "SELL",
769+
TimeInForce: "GTC",
770+
Quantity: fixedpoint.MustNewFromString("0.5"),
771+
Price: fixedpoint.MustNewFromString("700"),
772+
TriggerPrice: fixedpoint.MustNewFromString("680"),
773+
Status: "TRIGGERED",
774+
OrderId: "987654321",
775+
ExecutedQuantity: fixedpoint.MustNewFromString("0.1"),
776+
},
777+
}
778+
779+
order, err := event.OrderFutures()
780+
assert.NoError(t, err)
781+
assert.NotNil(t, order)
782+
assert.Equal(t, uint64(987654321), order.ActualOrderId)
783+
})
784+
785+
t.Run("invalid actual order id string falls back to zero", func(t *testing.T) {
786+
event := &AlgoOrderUpdateEvent{
787+
TransactionTime: transactionTime,
788+
AlgoOrder: AlgoOrder{
789+
ClientAlgoId: "test-invalid-actual-order-id",
790+
AlgoId: 445566,
791+
OrderType: "STOP",
792+
Symbol: "BTCUSDT",
793+
Side: "BUY",
794+
TimeInForce: "GTC",
795+
Quantity: fixedpoint.MustNewFromString("1.0"),
796+
Price: fixedpoint.MustNewFromString("50000"),
797+
TriggerPrice: fixedpoint.MustNewFromString("49000"),
798+
Status: "TRIGGERED",
799+
OrderId: "not-a-number",
800+
ExecutedQuantity: fixedpoint.MustNewFromString("0"),
801+
},
802+
}
803+
804+
order, err := event.OrderFutures()
805+
assert.NoError(t, err)
806+
assert.NotNil(t, order)
807+
assert.Zero(t, order.ActualOrderId)
808+
})
759809
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package mysql
2+
3+
import (
4+
"context"
5+
6+
"github.com/c9s/rockhopper/v2"
7+
)
8+
9+
func init() {
10+
AddMigration("main", up_main_ordersAddActualOrderId, down_main_ordersAddActualOrderId)
11+
}
12+
13+
func up_main_ordersAddActualOrderId(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
14+
// This code is executed when the migration is applied.
15+
_, err = tx.ExecContext(ctx, "ALTER TABLE `orders` ADD COLUMN `actual_order_id` BIGINT UNSIGNED NOT NULL DEFAULT 0;")
16+
if err != nil {
17+
return err
18+
}
19+
return err
20+
}
21+
22+
func down_main_ordersAddActualOrderId(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
23+
// This code is executed when the migration is rolled back.
24+
_, err = tx.ExecContext(ctx, "ALTER TABLE `orders` DROP COLUMN `actual_order_id`;")
25+
if err != nil {
26+
return err
27+
}
28+
return err
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package sqlite3
2+
3+
import (
4+
"context"
5+
6+
"github.com/c9s/rockhopper/v2"
7+
)
8+
9+
func init() {
10+
AddMigration("main", up_main_ordersAddActualOrderId, down_main_ordersAddActualOrderId)
11+
}
12+
13+
func up_main_ordersAddActualOrderId(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
14+
// This code is executed when the migration is applied.
15+
_, err = tx.ExecContext(ctx, "ALTER TABLE orders ADD COLUMN actual_order_id INTEGER NOT NULL DEFAULT 0;")
16+
if err != nil {
17+
return err
18+
}
19+
return err
20+
}
21+
22+
func down_main_ordersAddActualOrderId(ctx context.Context, tx rockhopper.SQLExecutor) (err error) {
23+
// This code is executed when the migration is rolled back.
24+
_, err = tx.ExecContext(ctx, "ALTER TABLE orders DROP COLUMN actual_order_id;")
25+
if err != nil {
26+
return err
27+
}
28+
return err
29+
}

pkg/service/order.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,15 @@ func (s *OrderService) scanRows(rows *sqlx.Rows) (orders []types.Order, err erro
225225
func (s *OrderService) Insert(order types.Order) (err error) {
226226
if s.DB.DriverName() == "mysql" {
227227
_, err = s.DB.NamedExec(`
228-
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, uuid)
229-
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, IF(:uuid != '', UUID_TO_BIN(:uuid, true), ''))
228+
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, uuid, actual_order_id)
229+
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, IF(:uuid != '', UUID_TO_BIN(:uuid, true), ''), :actual_order_id)
230230
ON DUPLICATE KEY UPDATE status=:status, executed_quantity=:executed_quantity, is_working=:is_working, updated_at=:updated_at`, order)
231231
return err
232232
}
233233

234234
_, err = s.DB.NamedExec(`
235-
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, uuid)
236-
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, :uuid)
235+
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, uuid, actual_order_id)
236+
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, :uuid, :actual_order_id)
237237
`, order)
238238

239239
return err

pkg/types/order.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,9 @@ type Order struct {
339339
// ExecutedQuantity is how much quantity has been executed
340340
ExecutedQuantity fixedpoint.Value `json:"executedQuantity" db:"executed_quantity"`
341341

342+
// ActualOrderId is the order id of the executed normal order on exchange for algo order
343+
ActualOrderId uint64 `json:"actualOrderId,omitempty" db:"actual_order_id"`
344+
342345
// IsWorking means if the order is still on the order book (active order)
343346
IsWorking bool `json:"isWorking" db:"is_working"`
344347

0 commit comments

Comments
 (0)