Merge pull request #1772 from c9s/edwin/bybit/query-trade

FEATURE: [bybit] use fee currency of trade
This commit is contained in:
bailantaotao 2024-10-14 21:05:56 +08:00 committed by GitHub
commit 0dd1e01d4a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 53 additions and 22 deletions

View File

@ -80,6 +80,26 @@ func TestClient(t *testing.T) {
} }
}) })
t.Run("GetTrade", func(t *testing.T) {
cursor := ""
for {
req := client.NewGetExecutionListRequest().Limit(50)
if len(cursor) != 0 {
req = req.Cursor(cursor)
}
trades, err := req.Do(ctx)
assert.NoError(t, err)
for _, o := range trades.List {
t.Logf("openOrders: %+v", o)
}
if len(trades.NextPageCursor) == 0 {
break
}
cursor = trades.NextPageCursor
}
})
t.Run("PlaceOrderRequest", func(t *testing.T) { t.Run("PlaceOrderRequest", func(t *testing.T) {
req := client.NewPlaceOrderRequest(). req := client.NewPlaceOrderRequest().
Symbol("DOTUSDT"). Symbol("DOTUSDT").

View File

@ -24,12 +24,14 @@ type Trade struct {
Side Side `json:"side"` Side Side `json:"side"`
OrderType OrderType `json:"orderType"` OrderType OrderType `json:"orderType"`
// ExecFee is supported on restful API v5, but not on websocket API. // ExecFee is supported on restful API v5, but not on websocket API.
ExecFee fixedpoint.Value `json:"execFee"` ExecFee fixedpoint.Value `json:"execFee"`
ExecId string `json:"execId"` ExecId string `json:"execId"`
ExecPrice fixedpoint.Value `json:"execPrice"` ExecPrice fixedpoint.Value `json:"execPrice"`
ExecQty fixedpoint.Value `json:"execQty"` ExecQty fixedpoint.Value `json:"execQty"`
ExecTime types.MillisecondTimestamp `json:"execTime"` ExecTime types.MillisecondTimestamp `json:"execTime"`
IsMaker bool `json:"isMaker"` IsMaker bool `json:"isMaker"`
FeeRate fixedpoint.Value `json:"feeRate"`
FeeCurrency string `json:"feeCurrency"`
} }
//go:generate GetRequest -url "/v5/execution/list" -type GetExecutionListRequest -responseDataType .TradesResponse -rateLimiter 5+15/1s //go:generate GetRequest -url "/v5/execution/list" -type GetExecutionListRequest -responseDataType .TradesResponse -rateLimiter 5+15/1s
@ -38,8 +40,9 @@ type GetExecutionListRequest struct {
category Category `param:"category,query" validValues:"spot"` category Category `param:"category,query" validValues:"spot"`
symbol *string `param:"symbol,query"` symbol *string `param:"symbol,query"`
orderId *string `param:"orderId,query"` orderId *string `param:"orderId,query"`
orderLinkId *string `param:"orderLinkId,query"`
// startTime the start timestamp (ms) // startTime the start timestamp (ms)
// startTime and endTime are not passed, return 7 days by default; // startTime and endTime are not passed, return 7 days by default;

View File

@ -31,6 +31,11 @@ func (g *GetExecutionListRequest) OrderId(orderId string) *GetExecutionListReque
return g return g
} }
func (g *GetExecutionListRequest) OrderLinkId(orderLinkId string) *GetExecutionListRequest {
g.orderLinkId = &orderLinkId
return g
}
func (g *GetExecutionListRequest) StartTime(startTime time.Time) *GetExecutionListRequest { func (g *GetExecutionListRequest) StartTime(startTime time.Time) *GetExecutionListRequest {
g.startTime = &startTime g.startTime = &startTime
return g return g
@ -86,6 +91,14 @@ func (g *GetExecutionListRequest) GetQueryParameters() (url.Values, error) {
params["orderId"] = orderId params["orderId"] = orderId
} else { } else {
} }
// check orderLinkId field -> json key orderLinkId
if g.orderLinkId != nil {
orderLinkId := *g.orderLinkId
// assign parameter of orderLinkId
params["orderLinkId"] = orderLinkId
} else {
}
// check startTime field -> json key startTime // check startTime field -> json key startTime
if g.startTime != nil { if g.startTime != nil {
startTime := *g.startTime startTime := *g.startTime
@ -275,7 +288,6 @@ func (g *GetExecutionListRequest) Do(ctx context.Context) (*TradesResponse, erro
return nil, err return nil, err
} }
} }
var data TradesResponse var data TradesResponse
if err := json.Unmarshal(apiResponse.Result, &data); err != nil { if err := json.Unmarshal(apiResponse.Result, &data); err != nil {
return nil, err return nil, err

View File

@ -325,7 +325,7 @@ func v3ToGlobalTrade(trade v3.Trade) (*types.Trade, error) {
}, nil }, nil
} }
func toGlobalTrade(trade bybitapi.Trade, feeDetail SymbolFeeDetail) (*types.Trade, error) { func toGlobalTrade(trade bybitapi.Trade) (*types.Trade, error) {
side, err := toGlobalSideType(trade.Side) side, err := toGlobalSideType(trade.Side)
if err != nil { if err != nil {
return nil, fmt.Errorf("unexpected side: %s, err: %w", trade.Side, err) return nil, fmt.Errorf("unexpected side: %s, err: %w", trade.Side, err)
@ -339,8 +339,6 @@ func toGlobalTrade(trade bybitapi.Trade, feeDetail SymbolFeeDetail) (*types.Trad
return nil, fmt.Errorf("unexpected trade id: %s, err: %w", trade.ExecId, err) return nil, fmt.Errorf("unexpected trade id: %s, err: %w", trade.ExecId, err)
} }
fc, _ := calculateFee(trade, feeDetail)
return &types.Trade{ return &types.Trade{
ID: tradeIdNum, ID: tradeIdNum,
OrderID: orderIdNum, OrderID: orderIdNum,
@ -354,7 +352,7 @@ func toGlobalTrade(trade bybitapi.Trade, feeDetail SymbolFeeDetail) (*types.Trad
IsMaker: trade.IsMaker, IsMaker: trade.IsMaker,
Time: types.Time(trade.ExecTime), Time: types.Time(trade.ExecTime),
Fee: trade.ExecFee, Fee: trade.ExecFee,
FeeCurrency: fc, FeeCurrency: trade.FeeCurrency,
IsMargin: false, IsMargin: false,
IsFutures: false, IsFutures: false,
IsIsolated: false, IsIsolated: false,

View File

@ -231,15 +231,17 @@ func (e *Exchange) QueryOrder(ctx context.Context, q types.OrderQuery) (*types.O
return toGlobalOrder(res.List[0]) return toGlobalOrder(res.List[0])
} }
// QueryOrderTrades You can query by symbol, baseCoin, orderId and orderLinkId, and if you pass multiple params,
// the system will process them according to this priority: orderId > orderLinkId > symbol > baseCoin.
func (e *Exchange) QueryOrderTrades(ctx context.Context, q types.OrderQuery) (trades []types.Trade, err error) { func (e *Exchange) QueryOrderTrades(ctx context.Context, q types.OrderQuery) (trades []types.Trade, err error) {
req := e.client.NewGetExecutionListRequest()
if len(q.ClientOrderID) != 0 { if len(q.ClientOrderID) != 0 {
log.Warn("!!!BYBIT EXCHANGE API NOTICE!!! Bybit does not support searching for trades using OrderClientId.") req.OrderLinkId(q.ClientOrderID)
} }
if len(q.OrderID) == 0 { if len(q.OrderID) != 0 {
return nil, errors.New("orderID is required parameter") req.OrderLinkId(q.OrderID)
} }
req := e.client.NewGetExecutionListRequest().OrderId(q.OrderID)
if len(q.Symbol) != 0 { if len(q.Symbol) != 0 {
req.Symbol(q.Symbol) req.Symbol(q.Symbol)
@ -437,11 +439,7 @@ func (e *Exchange) queryTrades(ctx context.Context, req *bybitapi.GetExecutionLi
} }
for _, trade := range res.List { for _, trade := range res.List {
feeRate, err := pollAndGetFeeRate(ctx, trade.Symbol, e.FeeRatePoller, e.marketsInfo) trade, err := toGlobalTrade(trade)
if err != nil {
return nil, fmt.Errorf("failed to get fee rate, err: %v", err)
}
trade, err := toGlobalTrade(trade, feeRate)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to convert trade, err: %v", err) return nil, fmt.Errorf("failed to convert trade, err: %v", err)
} }