diff --git a/exchanges/binance/binance_test.go b/exchanges/binance/binance_test.go index d2ed5262..227d0973 100644 --- a/exchanges/binance/binance_test.go +++ b/exchanges/binance/binance_test.go @@ -2266,9 +2266,11 @@ func TestExecutionTypeToOrderStatus(t *testing.T) { } testCases := []TestCases{ {Case: "NEW", Result: order.New}, + {Case: "PARTIALLY_FILLED", Result: order.PartiallyFilled}, + {Case: "FILLED", Result: order.Filled}, {Case: "CANCELED", Result: order.Cancelled}, + {Case: "PENDING_CANCEL", Result: order.PendingCancel}, {Case: "REJECTED", Result: order.Rejected}, - {Case: "TRADE", Result: order.PartiallyFilled}, {Case: "EXPIRED", Result: order.Expired}, {Case: "LOL", Result: order.UnknownStatus}, } @@ -2491,20 +2493,26 @@ func TestWsOrderExecutionReport(t *testing.T) { payload := []byte(`{"stream":"jTfvpakT2yT0hVIo5gYWVihZhdM2PrBgJUZ5PyfZ4EVpCkx4Uoxk5timcrQc","data":{"e":"executionReport","E":1616627567900,"s":"BTCUSDT","c":"c4wyKsIhoAaittTYlIVLqk","S":"BUY","o":"LIMIT","f":"GTC","q":"0.00028400","p":"52789.10000000","P":"0.00000000","F":"0.00000000","g":-1,"C":"","x":"NEW","X":"NEW","r":"NONE","i":5340845958,"l":"0.00000000","z":"0.00000000","L":"0.00000000","n":"0","N":"BTC","T":1616627567900,"t":-1,"I":11388173160,"w":true,"m":false,"M":false,"O":1616627567900,"Z":"0.00000000","Y":"0.00000000","Q":"0.00000000"}}`) // this is a buy BTC order, normally commission is charged in BTC, vice versa. expRes := order.Detail{ - Price: 52789.1, - Amount: 0.00028400, - Exchange: "Binance", - ID: "5340845958", - ClientOrderID: "c4wyKsIhoAaittTYlIVLqk", - Side: order.Buy, - Type: order.Limit, - Status: order.New, - AssetType: asset.Spot, - Pair: currency.NewPair(currency.BTC, currency.USDT), - RemainingAmount: 0.000284, - Date: time.Unix(0, 1616627567900*int64(time.Millisecond)), - Cost: 0, - CostAsset: currency.BTC, + Price: 52789.1, + Amount: 0.00028400, + AverageExecutedPrice: 0, + TargetAmount: 0, + ExecutedAmount: 0, + RemainingAmount: 0.00028400, + Cost: 0, + CostAsset: currency.USDT, + Fee: 0, + FeeAsset: currency.BTC, + Exchange: "Binance", + ID: "5340845958", + ClientOrderID: "c4wyKsIhoAaittTYlIVLqk", + Type: order.Limit, + Side: order.Buy, + Status: order.New, + AssetType: asset.Spot, + Date: time.Unix(0, 1616627567900*int64(time.Millisecond)), + LastUpdated: time.Unix(0, 1616627567900*int64(time.Millisecond)), + Pair: currency.NewPair(currency.BTC, currency.USDT), } // empty the channel. otherwise mock_test will fail for len(b.Websocket.DataHandler) > 0 { diff --git a/exchanges/binance/binance_types.go b/exchanges/binance/binance_types.go index 4581f28f..cf7b9176 100644 --- a/exchanges/binance/binance_types.go +++ b/exchanges/binance/binance_types.go @@ -736,37 +736,38 @@ type wsOrderUpdate struct { // WsOrderUpdateData defines websocket account order update data type WsOrderUpdateData struct { - ClientOrderID string `json:"c"` - EventTime time.Time `json:"E"` - IcebergQuantity float64 `json:"F,string"` - LastExecutedPrice float64 `json:"L,string"` - CommissionAsset string `json:"N"` - OrderCreationTime time.Time `json:"O"` - StopPrice float64 `json:"P,string"` - QuoteOrderQuantity float64 `json:"Q,string"` - Side string `json:"S"` - TransactionTime time.Time `json:"T"` - OrderStatus string `json:"X"` - LastQuoteAssetTransactedQuantity float64 `json:"Y,string"` - CumulativeQuoteTransactedQuantity float64 `json:"Z,string"` - CancelledClientOrderID string `json:"C"` EventType string `json:"e"` + EventTime time.Time `json:"E"` + Symbol string `json:"s"` + ClientOrderID string `json:"c"` + Side string `json:"S"` + OrderType string `json:"o"` TimeInForce string `json:"f"` + Quantity float64 `json:"q,string"` + Price float64 `json:"p,string"` + StopPrice float64 `json:"P,string"` + IcebergQuantity float64 `json:"F,string"` OrderListID int64 `json:"g"` + CancelledClientOrderID string `json:"C"` + CurrentExecutionType string `json:"x"` + OrderStatus string `json:"X"` + RejectionReason string `json:"r"` OrderID int64 `json:"i"` LastExecutedQuantity float64 `json:"l,string"` - IsMaker bool `json:"m"` - Commission float64 `json:"n,string"` - OrderType string `json:"o"` - Price float64 `json:"p,string"` - Quantity float64 `json:"q,string"` - RejectionReason string `json:"r"` - Symbol string `json:"s"` - TradeID int64 `json:"t"` - Ignored int64 `json:"I"` // must be ignored explicitly, otherwise it overwrites 'i' - IsOnOrderBook bool `json:"w"` - CurrentExecutionType string `json:"x"` CumulativeFilledQuantity float64 `json:"z,string"` + LastExecutedPrice float64 `json:"L,string"` + Commission float64 `json:"n,string"` + CommissionAsset string `json:"N"` + TransactionTime time.Time `json:"T"` + TradeID int64 `json:"t"` + Ignored int64 `json:"I"` // Must be ignored explicitly, otherwise it overwrites 'i'. + IsOnOrderBook bool `json:"w"` + IsMaker bool `json:"m"` + Ignored2 bool `json:"M"` // See the comment for "I". + OrderCreationTime time.Time `json:"O"` + CumulativeQuoteTransactedQuantity float64 `json:"Z,string"` + LastQuoteAssetTransactedQuantity float64 `json:"Y,string"` + QuoteOrderQuantity float64 `json:"Q,string"` } type wsListStatus struct { diff --git a/exchanges/binance/binance_websocket.go b/exchanges/binance/binance_websocket.go index 446ecf42..e5058e17 100644 --- a/exchanges/binance/binance_websocket.go +++ b/exchanges/binance/binance_websocket.go @@ -207,66 +207,68 @@ func (b *Binance) wsHandleData(respRaw []byte) error { b.Name, err) } - var orderID = strconv.FormatInt(data.Data.OrderID, 10) - oType, err := order.StringToOrderType(data.Data.OrderType) - if err != nil { - b.Websocket.DataHandler <- order.ClassificationError{ - Exchange: b.Name, - OrderID: orderID, - Err: err, - } + averagePrice := 0.0 + if data.Data.CumulativeFilledQuantity != 0 { + averagePrice = data.Data.CumulativeQuoteTransactedQuantity / data.Data.CumulativeFilledQuantity } - var oSide order.Side - oSide, err = order.StringToOrderSide(data.Data.Side) - if err != nil { - b.Websocket.DataHandler <- order.ClassificationError{ - Exchange: b.Name, - OrderID: orderID, - Err: err, - } - } - var oStatus order.Status - oStatus, err = stringToOrderStatus(data.Data.CurrentExecutionType) - if err != nil { - b.Websocket.DataHandler <- order.ClassificationError{ - Exchange: b.Name, - OrderID: orderID, - Err: err, - } - } - if oStatus == order.PartiallyFilled && data.Data.CumulativeFilledQuantity == data.Data.Quantity { - oStatus = order.Filled - } - var p currency.Pair - var a asset.Item - p, a, err = b.GetRequestFormattedPairAndAssetType(data.Data.Symbol) + remainingAmount := data.Data.Quantity - data.Data.CumulativeFilledQuantity + pair, assetType, err := b.GetRequestFormattedPairAndAssetType(data.Data.Symbol) if err != nil { return err } + var feeAsset currency.Code + if data.Data.CommissionAsset != "" { + feeAsset = currency.NewCode(data.Data.CommissionAsset) + } + orderID := strconv.FormatInt(data.Data.OrderID, 10) + orderStatus, err := stringToOrderStatus(data.Data.OrderStatus) + if err != nil { + b.Websocket.DataHandler <- order.ClassificationError{ + Exchange: b.Name, + OrderID: orderID, + Err: err, + } + } clientOrderID := data.Data.ClientOrderID - if oStatus == order.Cancelled { + if orderStatus == order.Cancelled { clientOrderID = data.Data.CancelledClientOrderID } - var costAsset currency.Code - if data.Data.CommissionAsset != "" { - costAsset = currency.NewCode(data.Data.CommissionAsset) + orderType, err := order.StringToOrderType(data.Data.OrderType) + if err != nil { + b.Websocket.DataHandler <- order.ClassificationError{ + Exchange: b.Name, + OrderID: orderID, + Err: err, + } + } + orderSide, err := order.StringToOrderSide(data.Data.Side) + if err != nil { + b.Websocket.DataHandler <- order.ClassificationError{ + Exchange: b.Name, + OrderID: orderID, + Err: err, + } } b.Websocket.DataHandler <- &order.Detail{ - Price: data.Data.Price, - Amount: data.Data.Quantity, - ExecutedAmount: data.Data.CumulativeFilledQuantity, - RemainingAmount: data.Data.Quantity - data.Data.CumulativeFilledQuantity, - Exchange: b.Name, - ID: orderID, - Type: oType, - Side: oSide, - Status: oStatus, - AssetType: a, - Date: data.Data.OrderCreationTime, - Pair: p, - ClientOrderID: clientOrderID, - Cost: data.Data.Commission, - CostAsset: costAsset, + Price: data.Data.Price, + Amount: data.Data.Quantity, + AverageExecutedPrice: averagePrice, + ExecutedAmount: data.Data.CumulativeFilledQuantity, + RemainingAmount: remainingAmount, + Cost: data.Data.CumulativeQuoteTransactedQuantity, + CostAsset: pair.Quote, + Fee: data.Data.Commission, + FeeAsset: feeAsset, + Exchange: b.Name, + ID: orderID, + ClientOrderID: clientOrderID, + Type: orderType, + Side: orderSide, + Status: orderStatus, + AssetType: assetType, + Date: data.Data.OrderCreationTime, + LastUpdated: data.Data.TransactionTime, + Pair: pair, } return nil case "listStatus": @@ -435,12 +437,16 @@ func stringToOrderStatus(status string) (order.Status, error) { switch status { case "NEW": return order.New, nil + case "PARTIALLY_FILLED": + return order.PartiallyFilled, nil + case "FILLED": + return order.Filled, nil case "CANCELED": return order.Cancelled, nil + case "PENDING_CANCEL": + return order.PendingCancel, nil case "REJECTED": return order.Rejected, nil - case "TRADE": - return order.PartiallyFilled, nil case "EXPIRED": return order.Expired, nil default: diff --git a/exchanges/ftx/ftx_websocket.go b/exchanges/ftx/ftx_websocket.go index eed2939c..dd004ab4 100644 --- a/exchanges/ftx/ftx_websocket.go +++ b/exchanges/ftx/ftx_websocket.go @@ -353,7 +353,7 @@ func (f *FTX) wsHandleData(respRaw []byte) error { resp.AverageExecutedPrice = resultData.OrderData.AvgFillPrice resp.ExecutedAmount = resultData.OrderData.FilledSize resp.RemainingAmount = resultData.OrderData.Size - resultData.OrderData.FilledSize - resp.Cost = resp.AverageExecutedPrice * resp.Amount + resp.Cost = resp.AverageExecutedPrice * resultData.OrderData.FilledSize // Fee: orderVars.Fee is incorrect. resp.Exchange = f.Name resp.ID = strconv.FormatInt(resultData.OrderData.ID, 10) @@ -363,6 +363,8 @@ func (f *FTX) wsHandleData(respRaw []byte) error { resp.Status = orderVars.Status resp.AssetType = assetType resp.Date = resultData.OrderData.CreatedAt + // There's no current timestamp, so this is the best we can get. + resp.LastUpdated = resultData.OrderData.CreatedAt resp.Pair = pair f.Websocket.DataHandler <- &resp case wsFills: diff --git a/exchanges/order/order_types.go b/exchanges/order/order_types.go index 686f5ade..0d395bd8 100644 --- a/exchanges/order/order_types.go +++ b/exchanges/order/order_types.go @@ -135,6 +135,7 @@ type Detail struct { Cost float64 CostAsset currency.Code Fee float64 + FeeAsset currency.Code Exchange string InternalOrderID string ID string