diff --git a/exchanges/alphapoint/alphapoint_wrapper.go b/exchanges/alphapoint/alphapoint_wrapper.go index 5f38b53f..1e84e1be 100644 --- a/exchanges/alphapoint/alphapoint_wrapper.go +++ b/exchanges/alphapoint/alphapoint_wrapper.go @@ -376,6 +376,7 @@ func (a *Alphapoint) GetActiveOrders(ctx context.Context, req *order.GetOrdersRe orderDetail := order.Detail{ Amount: resp[x].OpenOrders[y].QtyTotal, Exchange: a.Name, + ExecutedAmount: resp[x].OpenOrders[y].QtyTotal - resp[x].OpenOrders[y].QtyRemaining, AccountID: strconv.FormatInt(int64(resp[x].OpenOrders[y].AccountID), 10), ID: strconv.FormatInt(int64(resp[x].OpenOrders[y].ServerOrderID), 10), Price: resp[x].OpenOrders[y].Price, @@ -423,6 +424,7 @@ func (a *Alphapoint) GetOrderHistory(ctx context.Context, req *order.GetOrdersRe Amount: resp[x].OpenOrders[y].QtyTotal, AccountID: strconv.FormatInt(int64(resp[x].OpenOrders[y].AccountID), 10), Exchange: a.Name, + ExecutedAmount: resp[x].OpenOrders[y].QtyTotal - resp[x].OpenOrders[y].QtyRemaining, ID: strconv.FormatInt(int64(resp[x].OpenOrders[y].ServerOrderID), 10), Price: resp[x].OpenOrders[y].Price, RemainingAmount: resp[x].OpenOrders[y].QtyRemaining, diff --git a/exchanges/binance/binance_wrapper.go b/exchanges/binance/binance_wrapper.go index 140bc44f..b8dc00c7 100644 --- a/exchanges/binance/binance_wrapper.go +++ b/exchanges/binance/binance_wrapper.go @@ -1130,7 +1130,7 @@ func (b *Binance) GetOrderInfo(ctx context.Context, orderID string, pair currenc orderSide := order.Side(resp.Side) status, err := order.StringToOrderStatus(resp.Status) if err != nil { - return respData, err + log.Errorf(log.ExchangeSys, "%s %v", b.Name, err) } orderType := order.Limit if resp.Type == "MARKET" { @@ -1295,6 +1295,10 @@ func (b *Binance) GetActiveOrders(ctx context.Context, req *order.GetOrdersReque for x := range resp { orderSide := order.Side(strings.ToUpper(resp[x].Side)) orderType := order.Type(strings.ToUpper(resp[x].Type)) + orderStatus, err := order.StringToOrderStatus(resp[i].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", b.Name, err) + } orders = append(orders, order.Detail{ Amount: resp[x].OrigQty, Date: resp[x].Time, @@ -1304,7 +1308,7 @@ func (b *Binance) GetActiveOrders(ctx context.Context, req *order.GetOrdersReque Side: orderSide, Type: orderType, Price: resp[x].Price, - Status: order.Status(resp[x].Status), + Status: orderStatus, Pair: req.Pairs[i], AssetType: req.AssetType, LastUpdated: resp[x].UpdateTime, @@ -1411,22 +1415,39 @@ func (b *Binance) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque for i := range resp { orderSide := order.Side(strings.ToUpper(resp[i].Side)) orderType := order.Type(strings.ToUpper(resp[i].Type)) + orderStatus, err := order.StringToOrderStatus(resp[i].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", b.Name, err) + } // New orders are covered in GetOpenOrders - if resp[i].Status == "NEW" { + if orderStatus == order.New { continue } - orders = append(orders, order.Detail{ - Amount: resp[i].OrigQty, - Date: resp[i].Time, - Exchange: b.Name, - ID: strconv.FormatInt(resp[i].OrderID, 10), - Side: orderSide, - Type: orderType, - Price: resp[i].Price, - Pair: req.Pairs[x], - Status: order.Status(resp[i].Status), - }) + var cost float64 + // For some historical orders cummulativeQuoteQty will be < 0, + // meaning the data is not available at this time. + if resp[i].CummulativeQuoteQty > 0 { + cost = resp[i].CummulativeQuoteQty + } + detail := order.Detail{ + Amount: resp[i].OrigQty, + ExecutedAmount: resp[i].ExecutedQty, + RemainingAmount: resp[i].OrigQty - resp[i].ExecutedQty, + Cost: cost, + CostAsset: req.Pairs[x].Quote, + Date: resp[i].Time, + LastUpdated: resp[i].UpdateTime, + Exchange: b.Name, + ID: strconv.FormatInt(resp[i].OrderID, 10), + Side: orderSide, + Type: orderType, + Price: resp[i].Price, + Pair: req.Pairs[x], + Status: orderStatus, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } } case asset.CoinMarginedFutures: diff --git a/exchanges/bitfinex/bitfinex_wrapper.go b/exchanges/bitfinex/bitfinex_wrapper.go index 4cc78b53..62b36480 100644 --- a/exchanges/bitfinex/bitfinex_wrapper.go +++ b/exchanges/bitfinex/bitfinex_wrapper.go @@ -956,16 +956,18 @@ func (b *Bitfinex) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequ } orderDetail := order.Detail{ - Amount: resp[i].OriginalAmount, - Date: orderDate, - Exchange: b.Name, - ID: strconv.FormatInt(resp[i].ID, 10), - Side: orderSide, - Price: resp[i].Price, - RemainingAmount: resp[i].RemainingAmount, - ExecutedAmount: resp[i].ExecutedAmount, - Pair: pair, + Amount: resp[i].OriginalAmount, + Date: orderDate, + Exchange: b.Name, + ID: strconv.FormatInt(resp[i].ID, 10), + Side: orderSide, + Price: resp[i].Price, + AverageExecutedPrice: resp[i].AverageExecutionPrice, + RemainingAmount: resp[i].RemainingAmount, + ExecutedAmount: resp[i].ExecutedAmount, + Pair: pair, } + orderDetail.InferCostsAndTimes() switch { case resp[i].IsLive: diff --git a/exchanges/bithumb/bithumb_types.go b/exchanges/bithumb/bithumb_types.go index a7889954..0fc88a60 100644 --- a/exchanges/bithumb/bithumb_types.go +++ b/exchanges/bithumb/bithumb_types.go @@ -127,18 +127,17 @@ type Orders struct { // OrderData contains all individual order details type OrderData struct { - OrderID string `json:"order_id"` - OrderCurrency string `json:"order_currency"` - OrderDate int64 `json:"order_date"` - PaymentCurrency string `json:"payment_currency"` - Type string `json:"type"` - Status string `json:"status"` - Units float64 `json:"units,string"` - UnitsRemaining float64 `json:"units_remaining,string"` - Price float64 `json:"price,string"` - Fee float64 `json:"fee,string"` - Total float64 `json:"total,string"` - DateCompleted int64 `json:"date_completed"` + OrderID string `json:"order_id"` + OrderCurrency string `json:"order_currency"` + OrderDate bithumbTime `json:"order_date"` + PaymentCurrency string `json:"payment_currency"` + Type string `json:"type"` + Status string `json:"status"` + Units float64 `json:"units,string"` + UnitsRemaining float64 `json:"units_remaining,string"` + Price float64 `json:"price,string"` + Fee float64 `json:"fee,string"` + Total float64 `json:"total,string"` } // UserTransactions holds users full transaction list diff --git a/exchanges/bithumb/bithumb_wrapper.go b/exchanges/bithumb/bithumb_wrapper.go index d1cfe62e..ae131466 100644 --- a/exchanges/bithumb/bithumb_wrapper.go +++ b/exchanges/bithumb/bithumb_wrapper.go @@ -692,12 +692,12 @@ func (b *Bithumb) GetActiveOrders(ctx context.Context, req *order.GetOrdersReque continue } - orderDate := time.Unix(resp.Data[i].OrderDate, 0) orderDetail := order.Detail{ Amount: resp.Data[i].Units, Exchange: b.Name, + ExecutedAmount: resp.Data[i].Units - resp.Data[i].UnitsRemaining, ID: resp.Data[i].OrderID, - Date: orderDate, + Date: resp.Data[i].OrderDate.Time(), Price: resp.Data[i].Price, RemainingAmount: resp.Data[i].UnitsRemaining, Status: order.Active, @@ -750,14 +750,14 @@ func (b *Bithumb) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque continue } - orderDate := time.Unix(resp.Data[i].OrderDate, 0) orderDetail := order.Detail{ Amount: resp.Data[i].Units, + ExecutedAmount: resp.Data[i].Units - resp.Data[i].UnitsRemaining, + RemainingAmount: resp.Data[i].UnitsRemaining, Exchange: b.Name, ID: resp.Data[i].OrderID, - Date: orderDate, + Date: resp.Data[i].OrderDate.Time(), Price: resp.Data[i].Price, - RemainingAmount: resp.Data[i].UnitsRemaining, Pair: currency.NewPairWithDelimiter(resp.Data[i].OrderCurrency, resp.Data[i].PaymentCurrency, format.Delimiter), @@ -769,6 +769,7 @@ func (b *Bithumb) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque orderDetail.Side = order.Sell } + orderDetail.InferCostsAndTimes() orders = append(orders, orderDetail) } } diff --git a/exchanges/bitmex/bitmex_types.go b/exchanges/bitmex/bitmex_types.go index 1877a6ee..33e8a95a 100644 --- a/exchanges/bitmex/bitmex_types.go +++ b/exchanges/bitmex/bitmex_types.go @@ -291,18 +291,18 @@ type Order struct { ClOrdID string `json:"clOrdID"` ClOrdLinkID string `json:"clOrdLinkID"` ContingencyType string `json:"contingencyType"` - CumQty int64 `json:"cumQty"` + CumQty float64 `json:"cumQty"` Currency string `json:"currency"` DisplayQuantity int64 `json:"displayQty"` ExDestination string `json:"exDestination"` ExecInst string `json:"execInst"` - LeavesQty int64 `json:"leavesQty"` + LeavesQty float64 `json:"leavesQty"` MultiLegReportingType string `json:"multiLegReportingType"` OrdRejReason string `json:"ordRejReason"` OrdStatus string `json:"ordStatus"` OrdType int64 `json:"ordType,string"` OrderID string `json:"orderID"` - OrderQty int64 `json:"orderQty"` + OrderQty float64 `json:"orderQty"` PegOffsetValue float64 `json:"pegOffsetValue"` PegPriceType string `json:"pegPriceType"` Price float64 `json:"price"` @@ -316,7 +316,7 @@ type Order struct { Text string `json:"text"` TimeInForce string `json:"timeInForce"` Timestamp time.Time `json:"timestamp"` - TransactTime string `json:"transactTime"` + TransactTime time.Time `json:"transactTime"` Triggered string `json:"triggered"` WorkingIndicator bool `json:"workingIndicator"` } diff --git a/exchanges/bitmex/bitmex_wrapper.go b/exchanges/bitmex/bitmex_wrapper.go index 89fefbeb..c127a01b 100644 --- a/exchanges/bitmex/bitmex_wrapper.go +++ b/exchanges/bitmex/bitmex_wrapper.go @@ -748,20 +748,26 @@ func (b *Bitmex) GetActiveOrders(ctx context.Context, req *order.GetOrdersReques for i := range resp { orderSide := orderSideMap[resp[i].Side] + orderStatus, err := order.StringToOrderStatus(resp[i].OrdStatus) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", b.Name, err) + } orderType := orderTypeMap[resp[i].OrdType] if orderType == "" { orderType = order.UnknownType } orderDetail := order.Detail{ - Date: resp[i].Timestamp, - Price: resp[i].Price, - Amount: float64(resp[i].OrderQty), - Exchange: b.Name, - ID: resp[i].OrderID, - Side: orderSide, - Type: orderType, - Status: order.Status(resp[i].OrdStatus), + Date: resp[i].Timestamp, + Price: resp[i].Price, + Amount: resp[i].OrderQty, + ExecutedAmount: resp[i].CumQty, + RemainingAmount: resp[i].LeavesQty, + Exchange: b.Name, + ID: resp[i].OrderID, + Side: orderSide, + Status: orderStatus, + Type: orderType, Pair: currency.NewPairWithDelimiter(resp[i].Symbol, resp[i].SettlCurrency, format.Delimiter), @@ -799,23 +805,32 @@ func (b *Bitmex) GetOrderHistory(ctx context.Context, req *order.GetOrdersReques for i := range resp { orderSide := orderSideMap[resp[i].Side] + orderStatus, err := order.StringToOrderStatus(resp[i].OrdStatus) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", b.Name, err) + } orderType := orderTypeMap[resp[i].OrdType] if orderType == "" { orderType = order.UnknownType } + pair := currency.NewPairWithDelimiter(resp[i].Symbol, resp[i].SettlCurrency, format.Delimiter) orderDetail := order.Detail{ - Price: resp[i].Price, - Amount: float64(resp[i].OrderQty), - Exchange: b.Name, - ID: resp[i].OrderID, - Side: orderSide, - Type: orderType, - Status: order.Status(resp[i].OrdStatus), - Pair: currency.NewPairWithDelimiter(resp[i].Symbol, - resp[i].SettlCurrency, - format.Delimiter), + Price: resp[i].Price, + AverageExecutedPrice: resp[i].AvgPx, + Amount: resp[i].OrderQty, + ExecutedAmount: resp[i].CumQty, + RemainingAmount: resp[i].LeavesQty, + Date: resp[i].TransactTime, + CloseTime: resp[i].Timestamp, + Exchange: b.Name, + ID: resp[i].OrderID, + Side: orderSide, + Status: orderStatus, + Type: orderType, + Pair: pair, } + orderDetail.InferCostsAndTimes() orders = append(orders, orderDetail) } diff --git a/exchanges/bittrex/bittrex_wrapper.go b/exchanges/bittrex/bittrex_wrapper.go index 7dbd55b7..9a3f6823 100644 --- a/exchanges/bittrex/bittrex_wrapper.go +++ b/exchanges/bittrex/bittrex_wrapper.go @@ -856,12 +856,13 @@ func (b *Bittrex) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque continue } - resp = append(resp, order.Detail{ + detail := order.Detail{ Amount: orderData[i].Quantity, - RemainingAmount: orderData[i].Quantity - orderData[i].FillQuantity, ExecutedAmount: orderData[i].FillQuantity, + RemainingAmount: orderData[i].Quantity - orderData[i].FillQuantity, Price: orderData[i].Limit, Date: orderData[i].CreatedAt, + CloseTime: orderData[i].ClosedAt, ID: orderData[i].ID, Exchange: b.Name, Type: orderType, @@ -869,7 +870,9 @@ func (b *Bittrex) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque Status: orderStatus, Fee: orderData[i].Commission, Pair: pair, - }) + } + detail.InferCostsAndTimes() + resp = append(resp, detail) } order.FilterOrdersByType(&resp, req.Type) diff --git a/exchanges/btcmarkets/btcmarkets_wrapper.go b/exchanges/btcmarkets/btcmarkets_wrapper.go index 464d626c..1bf7b36f 100644 --- a/exchanges/btcmarkets/btcmarkets_wrapper.go +++ b/exchanges/btcmarkets/btcmarkets_wrapper.go @@ -864,7 +864,10 @@ func (b *BTCMarkets) GetOrderHistory(ctx context.Context, req *order.GetOrdersRe tempResp.ID = tempData.Orders[c].OrderID tempResp.Date = tempData.Orders[c].CreationTime tempResp.Price = tempData.Orders[c].Price - tempResp.ExecutedAmount = tempData.Orders[c].Amount + tempResp.Amount = tempData.Orders[c].Amount + tempResp.ExecutedAmount = tempData.Orders[c].Amount - tempData.Orders[c].OpenAmount + tempResp.RemainingAmount = tempData.Orders[c].OpenAmount + tempResp.InferCostsAndTimes() resp = append(resp, tempResp) } } diff --git a/exchanges/btse/btse_wrapper.go b/exchanges/btse/btse_wrapper.go index 8e0bf7ea..0047961d 100644 --- a/exchanges/btse/btse_wrapper.go +++ b/exchanges/btse/btse_wrapper.go @@ -648,7 +648,9 @@ func (b *BTSE) GetOrderInfo(ctx context.Context, orderID string, pair currency.P od.Type = orderIntToType(o[i].OrderType) od.Price = o[i].Price - od.Status = order.Status(o[i].OrderState) + if od.Status, err = order.StringToOrderStatus(o[i].OrderState); err != nil { + log.Errorf(log.ExchangeSys, "%s %v", b.Name, err) + } th, err := b.TradeHistory(ctx, "", @@ -782,6 +784,11 @@ func (b *BTSE) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest) side = order.Sell } + status, err := order.StringToOrderStatus(resp[i].OrderState) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", b.Name, err) + } + p, err := currency.NewPairDelimiter(resp[i].Symbol, format.Delimiter) if err != nil { @@ -792,14 +799,16 @@ func (b *BTSE) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest) } openOrder := order.Detail{ - Pair: p, - Exchange: b.Name, - Amount: resp[i].Size, - ID: resp[i].OrderID, - Date: time.Unix(resp[i].Timestamp, 0), - Side: side, - Price: resp[i].Price, - Status: order.Status(resp[i].OrderState), + Pair: p, + Exchange: b.Name, + Amount: resp[i].Size, + ExecutedAmount: resp[i].FilledSize, + RemainingAmount: resp[i].Size - resp[i].FilledSize, + ID: resp[i].OrderID, + Date: time.Unix(resp[i].Timestamp, 0), + Side: side, + Price: resp[i].Price, + Status: status, } if resp[i].OrderType == 77 { @@ -886,24 +895,26 @@ func (b *BTSE) GetOrderHistory(ctx context.Context, getOrdersRequest *order.GetO if !matchType(currentOrder[y].OrderType, orderDeref.Type) { continue } + orderStatus, err := order.StringToOrderStatus(currentOrder[x].OrderState) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", b.Name, err) + } + orderTime := time.UnixMilli(currentOrder[y].Timestamp) tempOrder := order.Detail{ - Price: currentOrder[y].Price, - Amount: currentOrder[y].Size, - Side: order.Side(currentOrder[y].Side), - Pair: orderDeref.Pairs[x], - } - switch currentOrder[x].OrderState { - case "STATUS_ACTIVE": - tempOrder.Status = order.Active - case "ORDER_CANCELLED": - tempOrder.Status = order.Cancelled - case "ORDER_FULLY_TRANSACTED": - tempOrder.Status = order.Filled - case "ORDER_PARTIALLY_TRANSACTED": - tempOrder.Status = order.PartiallyFilled - default: - tempOrder.Status = order.UnknownStatus + ID: currentOrder[y].OrderID, + ClientID: currentOrder[y].ClOrderID, + Exchange: b.Name, + Price: currentOrder[y].Price, + AverageExecutedPrice: currentOrder[y].AverageFillPrice, + Amount: currentOrder[y].Size, + ExecutedAmount: currentOrder[y].FilledSize, + RemainingAmount: currentOrder[y].Size - currentOrder[y].FilledSize, + Date: orderTime, + Side: order.Side(currentOrder[y].Side), + Status: orderStatus, + Pair: orderDeref.Pairs[x], } + tempOrder.InferCostsAndTimes() resp = append(resp, tempOrder) } } diff --git a/exchanges/coinbasepro/coinbasepro_types.go b/exchanges/coinbasepro/coinbasepro_types.go index 552b2d28..b4d72422 100644 --- a/exchanges/coinbasepro/coinbasepro_types.go +++ b/exchanges/coinbasepro/coinbasepro_types.go @@ -125,7 +125,7 @@ type GeneralizedOrderResponse struct { Funds float64 `json:"funds,string"` SpecifiedFunds float64 `json:"specified_funds,string"` DoneReason string `json:"done_reason"` - DoneAt string `json:"done_at"` + DoneAt time.Time `json:"done_at"` } // Funding holds funding data diff --git a/exchanges/coinbasepro/coinbasepro_wrapper.go b/exchanges/coinbasepro/coinbasepro_wrapper.go index 46d5d008..3b26c83f 100644 --- a/exchanges/coinbasepro/coinbasepro_wrapper.go +++ b/exchanges/coinbasepro/coinbasepro_wrapper.go @@ -588,10 +588,6 @@ func (c *CoinbasePro) GetOrderInfo(ctx context.Context, orderID string, pair cur if errGo != nil { return order.Detail{}, fmt.Errorf("error retrieving order %s : %s", orderID, errGo) } - od, errOd := time.Parse(time.RFC3339, genOrderDetail.DoneAt) - if errOd != nil { - return order.Detail{}, fmt.Errorf("error parsing order done at time: %s", errOd) - } os, errOs := order.StringToOrderStatus(genOrderDetail.Status) if errOs != nil { return order.Detail{}, fmt.Errorf("error parsing order status: %s", errOs) @@ -615,7 +611,7 @@ func (c *CoinbasePro) GetOrderInfo(ctx context.Context, orderID string, pair cur Pair: p, Side: ss, Type: tt, - Date: od, + Date: genOrderDetail.DoneAt, Status: os, Price: genOrderDetail.Price, Amount: genOrderDetail.Size, @@ -828,20 +824,31 @@ func (c *CoinbasePro) GetOrderHistory(ctx context.Context, req *order.GetOrdersR return nil, err } orderSide := order.Side(strings.ToUpper(respOrders[i].Side)) + orderStatus, err := order.StringToOrderStatus(respOrders[i].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", c.Name, err) + } orderType := order.Type(strings.ToUpper(respOrders[i].Type)) - orders = append(orders, order.Detail{ - ID: respOrders[i].ID, - Amount: respOrders[i].Size, - ExecutedAmount: respOrders[i].FilledSize, - Type: orderType, - Date: respOrders[i].CreatedAt, - Fee: respOrders[i].FillFees, - FeeAsset: curr.Quote, - Side: orderSide, - Pair: curr, - Price: respOrders[i].Price, - Exchange: c.Name, - }) + detail := order.Detail{ + ID: respOrders[i].ID, + Amount: respOrders[i].Size, + ExecutedAmount: respOrders[i].FilledSize, + RemainingAmount: respOrders[i].Size - respOrders[i].FilledSize, + Cost: respOrders[i].ExecutedValue, + CostAsset: curr.Quote, + Type: orderType, + Date: respOrders[i].CreatedAt, + CloseTime: respOrders[i].DoneAt, + Fee: respOrders[i].FillFees, + FeeAsset: curr.Quote, + Side: orderSide, + Status: orderStatus, + Pair: curr, + Price: respOrders[i].Price, + Exchange: c.Name, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } order.FilterOrdersByType(&orders, req.Type) diff --git a/exchanges/coinbene/coinbene_wrapper.go b/exchanges/coinbene/coinbene_wrapper.go index f5c7b0c3..3a898ae5 100644 --- a/exchanges/coinbene/coinbene_wrapper.go +++ b/exchanges/coinbene/coinbene_wrapper.go @@ -774,7 +774,9 @@ func (c *Coinbene) GetActiveOrders(ctx context.Context, getOrdersRequest *order. tempResp.Side = order.Sell } tempResp.Date = tempData[y].OrderTime - tempResp.Status = order.Status(tempData[y].OrderStatus) + if tempResp.Status, err = order.StringToOrderStatus(tempData[y].OrderStatus); err != nil { + log.Errorf(log.ExchangeSys, "%s %v", c.Name, err) + } tempResp.Price = tempData[y].OrderPrice tempResp.Amount = tempData[y].Amount tempResp.ExecutedAmount = tempData[y].FilledAmount @@ -831,12 +833,18 @@ func (c *Coinbene) GetOrderHistory(ctx context.Context, getOrdersRequest *order. tempResp.Side = order.Sell } tempResp.Date = tempData[y].OrderTime - tempResp.Status = order.Status(tempData[y].OrderStatus) + if tempResp.Status, err = order.StringToOrderStatus(tempData[y].OrderStatus); err != nil { + log.Errorf(log.ExchangeSys, "%s %v", c.Name, err) + } tempResp.Price = tempData[y].OrderPrice + tempResp.AverageExecutedPrice = tempData[y].AvgPrice tempResp.Amount = tempData[y].Amount tempResp.ExecutedAmount = tempData[y].FilledAmount tempResp.RemainingAmount = tempData[y].Amount - tempData[y].FilledAmount + tempResp.Cost = tempData[y].Quantity + tempResp.CostAsset = tempResp.Pair.Quote tempResp.Fee = tempData[y].TotalFee + tempResp.InferCostsAndTimes() resp = append(resp, tempResp) } } diff --git a/exchanges/coinut/coinut_wrapper.go b/exchanges/coinut/coinut_wrapper.go index 0d1f295b..f47d5787 100644 --- a/exchanges/coinut/coinut_wrapper.go +++ b/exchanges/coinut/coinut_wrapper.go @@ -977,7 +977,7 @@ func (c *COINUT) GetOrderHistory(ctx context.Context, req *order.GetOrdersReques return nil, err } - allOrders = append(allOrders, order.Detail{ + detail := order.Detail{ Exchange: c.Name, ID: strconv.FormatInt(trades.Trades[x].OrderID, 10), Pair: p, @@ -986,9 +986,11 @@ func (c *COINUT) GetOrderHistory(ctx context.Context, req *order.GetOrdersReques Status: order.Filled, Price: trades.Trades[x].Price, Amount: trades.Trades[x].Quantity, - ExecutedAmount: trades.Trades[x].Quantity, + ExecutedAmount: trades.Trades[x].Quantity - trades.Trades[x].OpenQuantity, RemainingAmount: trades.Trades[x].OpenQuantity, - }) + } + detail.InferCostsAndTimes() + allOrders = append(allOrders, detail) } if len(trades.Trades) < 100 { break diff --git a/exchanges/exmo/exmo_wrapper.go b/exchanges/exmo/exmo_wrapper.go index b7367054..838f1054 100644 --- a/exchanges/exmo/exmo_wrapper.go +++ b/exchanges/exmo/exmo_wrapper.go @@ -670,21 +670,26 @@ func (e *EXMO) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest) var orders []order.Detail for i := range allTrades { - symbol, err := currency.NewPairDelimiter(allTrades[i].Pair, "_") + pair, err := currency.NewPairDelimiter(allTrades[i].Pair, "_") if err != nil { return nil, err } orderDate := time.Unix(allTrades[i].Date, 0) orderSide := order.Side(strings.ToUpper(allTrades[i].Type)) - orders = append(orders, order.Detail{ - ID: strconv.FormatInt(allTrades[i].TradeID, 10), - Amount: allTrades[i].Quantity, - Date: orderDate, - Price: allTrades[i].Price, - Side: orderSide, - Exchange: e.Name, - Pair: symbol, - }) + detail := order.Detail{ + ID: strconv.FormatInt(allTrades[i].TradeID, 10), + Amount: allTrades[i].Quantity, + ExecutedAmount: allTrades[i].Quantity, + Cost: allTrades[i].Amount, + CostAsset: pair.Quote, + Date: orderDate, + Price: allTrades[i].Price, + Side: orderSide, + Exchange: e.Name, + Pair: pair, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } order.FilterOrdersByTimeRange(&orders, req.StartTime, req.EndTime) diff --git a/exchanges/ftx/ftx_wrapper.go b/exchanges/ftx/ftx_wrapper.go index 5c491d3e..b7697be0 100644 --- a/exchanges/ftx/ftx_wrapper.go +++ b/exchanges/ftx/ftx_wrapper.go @@ -1016,6 +1016,7 @@ func (f *FTX) GetOrderHistory(ctx context.Context, getOrdersRequest *order.GetOr tempResp.ID = strconv.FormatInt(orderData[y].ID, 10) tempResp.Amount = orderData[y].Size tempResp.AssetType = assetType + tempResp.AverageExecutedPrice = orderData[y].AvgFillPrice tempResp.ClientOrderID = orderData[y].ClientID tempResp.Date = orderData[y].CreatedAt tempResp.Exchange = f.Name @@ -1080,6 +1081,7 @@ func (f *FTX) GetOrderHistory(ctx context.Context, getOrdersRequest *order.GetOr tempResp.Side = orderVars.Side tempResp.Type = orderVars.OrderType tempResp.Fee = orderVars.Fee + tempResp.InferCostsAndTimes() resp = append(resp, tempResp) } } diff --git a/exchanges/gateio/gateio_wrapper.go b/exchanges/gateio/gateio_wrapper.go index 206f3cf2..e565668a 100644 --- a/exchanges/gateio/gateio_wrapper.go +++ b/exchanges/gateio/gateio_wrapper.go @@ -605,7 +605,9 @@ func (g *Gateio) GetOrderInfo(ctx context.Context, orderID string, pair currency orderDetail.ExecutedAmount = orders.Orders[x].FilledAmount orderDetail.Amount = orders.Orders[x].InitialAmount orderDetail.Date = time.Unix(orders.Orders[x].Timestamp, 0) - orderDetail.Status = order.Status(orders.Orders[x].Status) + if orderDetail.Status, err = order.StringToOrderStatus(orders.Orders[x].Status); err != nil { + log.Errorf(log.ExchangeSys, "%s %v", g.Name, err) + } orderDetail.Price = orders.Orders[x].Rate orderDetail.Pair, err = currency.NewPairDelimiter(orders.Orders[x].CurrencyPair, format.Delimiter) @@ -763,17 +765,22 @@ func (g *Gateio) GetActiveOrders(ctx context.Context, req *order.GetOrdersReques return nil, err } side := order.Side(strings.ToUpper(resp.Orders[i].Type)) + status, err := order.StringToOrderStatus(resp.Orders[i].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", g.Name, err) + } orderDate := time.Unix(resp.Orders[i].Timestamp, 0) orders = append(orders, order.Detail{ ID: resp.Orders[i].OrderNumber, Amount: resp.Orders[i].Amount, - Price: resp.Orders[i].Rate, + ExecutedAmount: resp.Orders[i].Amount - resp.Orders[i].FilledAmount, RemainingAmount: resp.Orders[i].FilledAmount, + Price: resp.Orders[i].Rate, Date: orderDate, Side: side, Exchange: g.Name, Pair: symbol, - Status: order.Status(resp.Orders[i].Status), + Status: status, }) } } @@ -805,22 +812,26 @@ func (g *Gateio) GetOrderHistory(ctx context.Context, req *order.GetOrdersReques var orders []order.Detail for i := range trades { - var symbol currency.Pair - symbol, err = currency.NewPairDelimiter(trades[i].Pair, format.Delimiter) + var pair currency.Pair + pair, err = currency.NewPairDelimiter(trades[i].Pair, format.Delimiter) if err != nil { return nil, err } side := order.Side(strings.ToUpper(trades[i].Type)) orderDate := time.Unix(trades[i].TimeUnix, 0) - orders = append(orders, order.Detail{ - ID: strconv.FormatInt(trades[i].OrderID, 10), - Amount: trades[i].Amount, - Price: trades[i].Rate, - Date: orderDate, - Side: side, - Exchange: g.Name, - Pair: symbol, - }) + detail := order.Detail{ + ID: strconv.FormatInt(trades[i].OrderID, 10), + Amount: trades[i].Amount, + ExecutedAmount: trades[i].Amount, + Price: trades[i].Rate, + AverageExecutedPrice: trades[i].Rate, + Date: orderDate, + Side: side, + Exchange: g.Name, + Pair: pair, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } order.FilterOrdersByTimeRange(&orders, req.StartTime, req.EndTime) diff --git a/exchanges/gemini/gemini_wrapper.go b/exchanges/gemini/gemini_wrapper.go index bb68bcf8..469c43c6 100644 --- a/exchanges/gemini/gemini_wrapper.go +++ b/exchanges/gemini/gemini_wrapper.go @@ -757,18 +757,24 @@ func (g *Gemini) GetOrderHistory(ctx context.Context, req *order.GetOrdersReques side := order.Side(strings.ToUpper(trades[i].Type)) orderDate := time.Unix(trades[i].Timestamp, 0) - orders = append(orders, order.Detail{ - Amount: trades[i].Amount, - ID: strconv.FormatInt(trades[i].OrderID, 10), - Exchange: g.Name, - Date: orderDate, - Side: side, - Fee: trades[i].FeeAmount, - Price: trades[i].Price, - Pair: currency.NewPairWithDelimiter(trades[i].BaseCurrency, + detail := order.Detail{ + ID: strconv.FormatInt(trades[i].OrderID, 10), + Amount: trades[i].Amount, + ExecutedAmount: trades[i].Amount, + Exchange: g.Name, + Date: orderDate, + Side: side, + Fee: trades[i].FeeAmount, + Price: trades[i].Price, + AverageExecutedPrice: trades[i].Price, + Pair: currency.NewPairWithDelimiter( + trades[i].BaseCurrency, trades[i].QuoteCurrency, - format.Delimiter), - }) + format.Delimiter, + ), + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } order.FilterOrdersByTimeRange(&orders, req.StartTime, req.EndTime) diff --git a/exchanges/hitbtc/hitbtc_types.go b/exchanges/hitbtc/hitbtc_types.go index 38eb426a..df7bcd27 100644 --- a/exchanges/hitbtc/hitbtc_types.go +++ b/exchanges/hitbtc/hitbtc_types.go @@ -184,6 +184,7 @@ type OrderHistoryResponse struct { Type string `json:"type"` TimeInForce string `json:"timeInForce"` Price float64 `json:"price,string"` + AvgPrice float64 `json:"avgPrice,string"` Quantity float64 `json:"quantity,string"` PostOnly bool `json:"postOnly"` CumQuantity float64 `json:"cumQuantity,string"` diff --git a/exchanges/hitbtc/hitbtc_wrapper.go b/exchanges/hitbtc/hitbtc_wrapper.go index 1e93d72f..4d10a435 100644 --- a/exchanges/hitbtc/hitbtc_wrapper.go +++ b/exchanges/hitbtc/hitbtc_wrapper.go @@ -768,22 +768,33 @@ func (h *HitBTC) GetOrderHistory(ctx context.Context, req *order.GetOrdersReques var orders []order.Detail for i := range allOrders { - var symbol currency.Pair - symbol, err = currency.NewPairDelimiter(allOrders[i].Symbol, + var pair currency.Pair + pair, err = currency.NewPairDelimiter(allOrders[i].Symbol, format.Delimiter) if err != nil { return nil, err } side := order.Side(strings.ToUpper(allOrders[i].Side)) - orders = append(orders, order.Detail{ - ID: allOrders[i].ID, - Amount: allOrders[i].Quantity, - Exchange: h.Name, - Price: allOrders[i].Price, - Date: allOrders[i].CreatedAt, - Side: side, - Pair: symbol, - }) + status, err := order.StringToOrderStatus(allOrders[i].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", h.Name, err) + } + detail := order.Detail{ + ID: allOrders[i].ID, + Amount: allOrders[i].Quantity, + ExecutedAmount: allOrders[i].CumQuantity, + RemainingAmount: allOrders[i].Quantity - allOrders[i].CumQuantity, + Exchange: h.Name, + Price: allOrders[i].Price, + AverageExecutedPrice: allOrders[i].AvgPrice, + Date: allOrders[i].CreatedAt, + LastUpdated: allOrders[i].UpdatedAt, + Side: side, + Status: status, + Pair: pair, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } order.FilterOrdersByTimeRange(&orders, req.StartTime, req.EndTime) diff --git a/exchanges/huobi/huobi_wrapper.go b/exchanges/huobi/huobi_wrapper.go index 8d05065c..50da1d79 100644 --- a/exchanges/huobi/huobi_wrapper.go +++ b/exchanges/huobi/huobi_wrapper.go @@ -1384,18 +1384,18 @@ func (h *HUOBI) GetActiveOrders(ctx context.Context, req *order.GetOrdersRequest } for x := range resp { orderDetail := order.Detail{ - ID: strconv.FormatInt(resp[x].ID, 10), - Price: resp[x].Price, - Amount: resp[x].Amount, - Pair: req.Pairs[i], - Exchange: h.Name, - ExecutedAmount: resp[x].FilledAmount, - Date: time.UnixMilli(resp[x].CreatedAt), - Status: order.Status(resp[x].State), - AccountID: strconv.FormatInt(resp[x].AccountID, 10), - Fee: resp[x].FilledFees, + ID: strconv.FormatInt(resp[x].ID, 10), + Price: resp[x].Price, + Amount: resp[x].Amount, + ExecutedAmount: resp[x].FilledAmount, + RemainingAmount: resp[x].Amount - resp[x].FilledAmount, + Pair: req.Pairs[i], + Exchange: h.Name, + Date: time.UnixMilli(resp[x].CreatedAt), + AccountID: strconv.FormatInt(resp[x].AccountID, 10), + Fee: resp[x].FilledFees, } - setOrderSideAndType(resp[x].Type, &orderDetail) + setOrderSideStatusAndType(resp[x].State, resp[x].Type, &orderDetail) orders = append(orders, orderDetail) } } @@ -1520,18 +1520,22 @@ func (h *HUOBI) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest } for x := range resp { orderDetail := order.Detail{ - ID: strconv.FormatInt(resp[x].ID, 10), - Price: resp[x].Price, - Amount: resp[x].Amount, - Pair: req.Pairs[i], - Exchange: h.Name, - ExecutedAmount: resp[x].FilledAmount, - Date: time.UnixMilli(resp[x].CreatedAt), - Status: order.Status(resp[x].State), - AccountID: strconv.FormatInt(resp[x].AccountID, 10), - Fee: resp[x].FilledFees, + ID: strconv.FormatInt(resp[x].ID, 10), + Price: resp[x].Price, + Amount: resp[x].Amount, + ExecutedAmount: resp[x].FilledAmount, + RemainingAmount: resp[x].Amount - resp[x].FilledAmount, + Cost: resp[x].FilledCashAmount, + CostAsset: req.Pairs[i].Quote, + Pair: req.Pairs[i], + Exchange: h.Name, + Date: time.UnixMilli(resp[x].CreatedAt), + CloseTime: time.UnixMilli(resp[x].FinishedAt), + AccountID: strconv.FormatInt(resp[x].AccountID, 10), + Fee: resp[x].FilledFees, } - setOrderSideAndType(resp[x].Type, &orderDetail) + setOrderSideStatusAndType(resp[x].State, resp[x].Type, &orderDetail) + orderDetail.InferCostsAndTimes() orders = append(orders, orderDetail) } } @@ -1648,7 +1652,12 @@ func (h *HUOBI) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest return orders, nil } -func setOrderSideAndType(requestType string, orderDetail *order.Detail) { +func setOrderSideStatusAndType(orderState, requestType string, orderDetail *order.Detail) { + var err error + if orderDetail.Status, err = order.StringToOrderStatus(orderState); err != nil { + log.Errorf(log.ExchangeSys, "%s %v", orderDetail.Exchange, err) + } + switch SpotNewOrderRequestParamsType(requestType) { case SpotNewOrderRequestTypeBuyMarket: orderDetail.Side = order.Buy diff --git a/exchanges/itbit/itbit_wrapper.go b/exchanges/itbit/itbit_wrapper.go index ecaacd4f..d38430f0 100644 --- a/exchanges/itbit/itbit_wrapper.go +++ b/exchanges/itbit/itbit_wrapper.go @@ -614,6 +614,10 @@ func (i *ItBit) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest } side := order.Side(strings.ToUpper(allOrders[j].Side)) + status, err := order.StringToOrderStatus(allOrders[j].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", i.Name, err) + } orderDate, err := time.Parse(time.RFC3339, allOrders[j].CreatedTime) if err != nil { log.Errorf(log.ExchangeSys, @@ -624,16 +628,21 @@ func (i *ItBit) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest allOrders[j].CreatedTime) } - orders = append(orders, order.Detail{ - ID: allOrders[j].ID, - Side: side, - Amount: allOrders[j].Amount, - ExecutedAmount: allOrders[j].AmountFilled, - RemainingAmount: (allOrders[j].Amount - allOrders[j].AmountFilled), - Exchange: i.Name, - Date: orderDate, - Pair: symbol, - }) + detail := order.Detail{ + ID: allOrders[j].ID, + Side: side, + Status: status, + Amount: allOrders[j].Amount, + ExecutedAmount: allOrders[j].AmountFilled, + RemainingAmount: allOrders[j].Amount - allOrders[j].AmountFilled, + Price: allOrders[j].Price, + AverageExecutedPrice: allOrders[j].VolumeWeightedAveragePrice, + Exchange: i.Name, + Date: orderDate, + Pair: symbol, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } order.FilterOrdersByTimeRange(&orders, req.StartTime, req.EndTime) diff --git a/exchanges/kraken/kraken_wrapper.go b/exchanges/kraken/kraken_wrapper.go index 626eb2c0..0a838876 100644 --- a/exchanges/kraken/kraken_wrapper.go +++ b/exchanges/kraken/kraken_wrapper.go @@ -904,7 +904,7 @@ func (k *Kraken) GetOrderInfo(ctx context.Context, orderID string, pair currency } status, err := order.StringToOrderStatus(orderInfo.Status) if err != nil { - return orderDetail, err + log.Errorf(log.ExchangeSys, "%s %v", k.Name, err) } oType, err := order.StringToOrderType(orderInfo.Description.OrderType) if err != nil { @@ -1225,20 +1225,29 @@ func (k *Kraken) GetOrderHistory(ctx context.Context, getOrdersRequest *order.Ge } side := order.Side(strings.ToUpper(resp.Closed[i].Description.Type)) + status, err := order.StringToOrderStatus(resp.Closed[i].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", k.Name, err) + } orderType := order.Type(strings.ToUpper(resp.Closed[i].Description.OrderType)) - orders = append(orders, order.Detail{ + detail := order.Detail{ ID: i, Amount: resp.Closed[i].Volume, - RemainingAmount: (resp.Closed[i].Volume - resp.Closed[i].VolumeExecuted), ExecutedAmount: resp.Closed[i].VolumeExecuted, + RemainingAmount: resp.Closed[i].Volume - resp.Closed[i].VolumeExecuted, + Cost: resp.Closed[i].Cost, + CostAsset: p.Quote, Exchange: k.Name, Date: convert.TimeFromUnixTimestampDecimal(resp.Closed[i].OpenTime), CloseTime: convert.TimeFromUnixTimestampDecimal(resp.Closed[i].CloseTime), Price: resp.Closed[i].Description.Price, Side: side, + Status: status, Type: orderType, Pair: p, - }) + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } case asset.Futures: var orderHistory FuturesRecentOrdersData diff --git a/exchanges/lbank/lbank_wrapper.go b/exchanges/lbank/lbank_wrapper.go index 1a681333..8402d883 100644 --- a/exchanges/lbank/lbank_wrapper.go +++ b/exchanges/lbank/lbank_wrapper.go @@ -790,10 +790,11 @@ func (l *Lbank) GetOrderHistory(ctx context.Context, getOrdersRequest *order.Get resp.Status = "Invalid Order Status" } resp.Price = tempResp.Orders[x].Price + resp.AverageExecutedPrice = tempResp.Orders[x].AvgPrice resp.Amount = tempResp.Orders[x].Amount resp.Date = time.Unix(tempResp.Orders[x].CreateTime, 0) resp.ExecutedAmount = tempResp.Orders[x].DealAmount - resp.RemainingAmount = tempResp.Orders[x].Price - tempResp.Orders[x].DealAmount + resp.RemainingAmount = tempResp.Orders[x].Amount - tempResp.Orders[x].DealAmount resp.Fee, err = l.GetFeeByType(ctx, &exchange.FeeBuilder{ FeeType: exchange.CryptocurrencyTradeFee, @@ -802,6 +803,7 @@ func (l *Lbank) GetOrderHistory(ctx context.Context, getOrdersRequest *order.Get if err != nil { resp.Fee = lbankFeeNotFound } + resp.InferCostsAndTimes() finalResp = append(finalResp, resp) b++ } diff --git a/exchanges/localbitcoins/localbitcoins_wrapper.go b/exchanges/localbitcoins/localbitcoins_wrapper.go index e79a0842..79a9f594 100644 --- a/exchanges/localbitcoins/localbitcoins_wrapper.go +++ b/exchanges/localbitcoins/localbitcoins_wrapper.go @@ -638,6 +638,11 @@ func (l *LocalBitcoins) GetOrderHistory(ctx context.Context, getOrdersRequest *o status = "Closed" } + orderStatus, err := order.StringToOrderStatus(status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", l.Name, err) + } + orders = append(orders, order.Detail{ Amount: allTrades[i].Data.AmountBTC, Price: allTrades[i].Data.Amount, @@ -645,7 +650,7 @@ func (l *LocalBitcoins) GetOrderHistory(ctx context.Context, getOrdersRequest *o Date: orderDate, Fee: allTrades[i].Data.FeeBTC, Side: side, - Status: order.Status(status), + Status: orderStatus, Pair: currency.NewPairWithDelimiter(currency.BTC.String(), allTrades[i].Data.Currency, format.Delimiter), diff --git a/exchanges/okgroup/okgroup_types.go b/exchanges/okgroup/okgroup_types.go index f3c2560b..345db811 100644 --- a/exchanges/okgroup/okgroup_types.go +++ b/exchanges/okgroup/okgroup_types.go @@ -319,6 +319,7 @@ type GetSpotOrderResponse struct { Notional string `json:"notional"` OrderID string `json:"order_id"` Price float64 `json:"price,string"` + PriceAvg float64 `json:"price_avg,string"` Side string `json:"side"` Size float64 `json:"size,string"` Status string `json:"status"` diff --git a/exchanges/okgroup/okgroup_wrapper.go b/exchanges/okgroup/okgroup_wrapper.go index 4557bf81..30a8ddc8 100644 --- a/exchanges/okgroup/okgroup_wrapper.go +++ b/exchanges/okgroup/okgroup_wrapper.go @@ -408,16 +408,20 @@ func (o *OKGroup) GetOrderInfo(ctx context.Context, orderID string, pair currenc return resp, err } + status, err := order.StringToOrderStatus(mOrder.Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", o.Name, err) + } resp = order.Detail{ Amount: mOrder.Size, Pair: p, Exchange: o.Name, Date: mOrder.Timestamp, ExecutedAmount: mOrder.FilledSize, - Status: order.Status(mOrder.Status), + Status: status, Side: order.Side(mOrder.Side), } - return + return resp, nil } // GetDepositAddress returns a deposit address for a specified currency @@ -501,6 +505,11 @@ func (o *OKGroup) GetActiveOrders(ctx context.Context, req *order.GetOrdersReque return resp, err } for i := range spotOpenOrders { + var status order.Status + status, err = order.StringToOrderStatus(spotOpenOrders[i].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", o.Name, err) + } resp = append(resp, order.Detail{ ID: spotOpenOrders[i].OrderID, Price: spotOpenOrders[i].Price, @@ -511,7 +520,7 @@ func (o *OKGroup) GetActiveOrders(ctx context.Context, req *order.GetOrdersReque Type: order.Type(spotOpenOrders[i].Type), ExecutedAmount: spotOpenOrders[i].FilledSize, Date: spotOpenOrders[i].Timestamp, - Status: order.Status(spotOpenOrders[i].Status), + Status: status, }) } } @@ -532,8 +541,8 @@ func (o *OKGroup) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque if err != nil { return nil, err } - var spotOpenOrders []GetSpotOrderResponse - spotOpenOrders, err = o.GetSpotOrders(ctx, + var spotOrders []GetSpotOrderResponse + spotOrders, err = o.GetSpotOrders(ctx, GetSpotOrdersRequest{ Status: strings.Join([]string{"filled", "cancelled", "failure"}, "|"), InstrumentID: fPair.String(), @@ -541,19 +550,28 @@ func (o *OKGroup) GetOrderHistory(ctx context.Context, req *order.GetOrdersReque if err != nil { return resp, err } - for i := range spotOpenOrders { - resp = append(resp, order.Detail{ - ID: spotOpenOrders[i].OrderID, - Price: spotOpenOrders[i].Price, - Amount: spotOpenOrders[i].Size, - Pair: req.Pairs[x], - Exchange: o.Name, - Side: order.Side(spotOpenOrders[i].Side), - Type: order.Type(spotOpenOrders[i].Type), - ExecutedAmount: spotOpenOrders[i].FilledSize, - Date: spotOpenOrders[i].Timestamp, - Status: order.Status(spotOpenOrders[i].Status), - }) + for i := range spotOrders { + var status order.Status + status, err = order.StringToOrderStatus(spotOrders[i].Status) + if err != nil { + log.Errorf(log.ExchangeSys, "%s %v", o.Name, err) + } + detail := order.Detail{ + ID: spotOrders[i].OrderID, + Price: spotOrders[i].Price, + AverageExecutedPrice: spotOrders[i].PriceAvg, + Amount: spotOrders[i].Size, + ExecutedAmount: spotOrders[i].FilledSize, + RemainingAmount: spotOrders[i].Size - spotOrders[i].FilledSize, + Pair: req.Pairs[x], + Exchange: o.Name, + Side: order.Side(spotOrders[i].Side), + Type: order.Type(spotOrders[i].Type), + Date: spotOrders[i].Timestamp, + Status: status, + } + detail.InferCostsAndTimes() + resp = append(resp, detail) } } return resp, err diff --git a/exchanges/order/order_test.go b/exchanges/order/order_test.go index ea917751..76e587eb 100644 --- a/exchanges/order/order_test.go +++ b/exchanges/order/order_test.go @@ -144,6 +144,90 @@ func TestOrderTypes(t *testing.T) { } } +func TestInferCostsAndTimes(t *testing.T) { + t.Parallel() + + var detail Detail + detail.InferCostsAndTimes() + if detail.Amount != detail.ExecutedAmount+detail.RemainingAmount { + t.Errorf( + "Order detail amounts not equals. Expected 0, received %f", + detail.Amount-(detail.ExecutedAmount+detail.RemainingAmount), + ) + } + + detail.CloseTime = time.Now() + detail.InferCostsAndTimes() + if detail.LastUpdated != detail.CloseTime { + t.Errorf( + "Order last updated not equals close time. Expected %s, received %s", + detail.CloseTime, + detail.LastUpdated, + ) + } + + detail.Amount = 1 + detail.ExecutedAmount = 1 + detail.InferCostsAndTimes() + if detail.AverageExecutedPrice != 0 { + t.Errorf( + "Unexpected AverageExecutedPrice. Expected 0, received %f", + detail.AverageExecutedPrice, + ) + } + + detail.Amount = 1 + detail.ExecutedAmount = 1 + detail.InferCostsAndTimes() + if detail.Cost != 0 { + t.Errorf( + "Unexpected Cost. Expected 0, received %f", + detail.Cost, + ) + } + detail.ExecutedAmount = 0 + + detail.Amount = 1 + detail.RemainingAmount = 1 + detail.InferCostsAndTimes() + if detail.Amount != detail.ExecutedAmount+detail.RemainingAmount { + t.Errorf( + "Order detail amounts not equals. Expected 0, received %f", + detail.Amount-(detail.ExecutedAmount+detail.RemainingAmount), + ) + } + detail.RemainingAmount = 0 + + detail.Amount = 1 + detail.ExecutedAmount = 1 + detail.Price = 2 + detail.InferCostsAndTimes() + if detail.AverageExecutedPrice != 2 { + t.Errorf( + "Unexpected AverageExecutedPrice. Expected 2, received %f", + detail.AverageExecutedPrice, + ) + } + + detail = Detail{Amount: 1, ExecutedAmount: 2, Cost: 3, Price: 0} + detail.InferCostsAndTimes() + if detail.AverageExecutedPrice != 1.5 { + t.Errorf( + "Unexpected AverageExecutedPrice. Expected 1.5, received %f", + detail.AverageExecutedPrice, + ) + } + + detail = Detail{Amount: 1, ExecutedAmount: 2, AverageExecutedPrice: 3} + detail.InferCostsAndTimes() + if detail.Cost != 6 { + t.Errorf( + "Unexpected Cost. Expected 6, received %f", + detail.Cost, + ) + } +} + func TestFilterOrdersByType(t *testing.T) { t.Parallel() diff --git a/exchanges/order/orders.go b/exchanges/order/orders.go index 72a27fd4..c3519379 100644 --- a/exchanges/order/orders.go +++ b/exchanges/order/orders.go @@ -488,6 +488,36 @@ func (s Status) String() string { return string(s) } +// InferCostsAndTimes infer order costs using execution information and times when available +func (d *Detail) InferCostsAndTimes() { + if d.CostAsset.IsEmpty() { + d.CostAsset = d.Pair.Quote + } + + if d.LastUpdated.IsZero() { + if d.CloseTime.IsZero() { + d.LastUpdated = d.Date + } else { + d.LastUpdated = d.CloseTime + } + } + + if d.ExecutedAmount <= 0 { + return + } + + if d.AverageExecutedPrice == 0 { + if d.Cost != 0 { + d.AverageExecutedPrice = d.Cost / d.ExecutedAmount + } else { + d.AverageExecutedPrice = d.Price + } + } + if d.Cost == 0 { + d.Cost = d.AverageExecutedPrice * d.ExecutedAmount + } +} + // FilterOrdersBySide removes any order details that don't match the // order status provided func FilterOrdersBySide(orders *[]Detail, side Side) { @@ -743,7 +773,8 @@ func StringToOrderStatus(status string) (Status, error) { case strings.EqualFold(status, New.String()), strings.EqualFold(status, "placed"): return New, nil - case strings.EqualFold(status, Active.String()): + case strings.EqualFold(status, Active.String()), + strings.EqualFold(status, "STATUS_ACTIVE"): // BTSE case return Active, nil case strings.EqualFold(status, PartiallyFilled.String()), strings.EqualFold(status, "partially matched"), @@ -751,18 +782,20 @@ func StringToOrderStatus(status string) (Status, error) { return PartiallyFilled, nil case strings.EqualFold(status, Filled.String()), strings.EqualFold(status, "fully matched"), - strings.EqualFold(status, "fully filled"): + strings.EqualFold(status, "fully filled"), + strings.EqualFold(status, "ORDER_FULLY_TRANSACTED"): // BTSE case return Filled, nil case strings.EqualFold(status, PartiallyCancelled.String()), - strings.EqualFold(status, "partially cancelled"): + strings.EqualFold(status, "partially cancelled"), + strings.EqualFold(status, "ORDER_PARTIALLY_TRANSACTED"): // BTSE case return PartiallyCancelled, nil case strings.EqualFold(status, Open.String()): return Open, nil case strings.EqualFold(status, Closed.String()): return Closed, nil - case strings.EqualFold(status, Cancelled.String()): - return Cancelled, nil - case strings.EqualFold(status, "CANCELED"): // Kraken case + case strings.EqualFold(status, Cancelled.String()), + strings.EqualFold(status, "CANCELED"), // Binance and Kraken case + strings.EqualFold(status, "ORDER_CANCELLED"): // BTSE case return Cancelled, nil case strings.EqualFold(status, PendingCancel.String()), strings.EqualFold(status, "pending cancel"), diff --git a/exchanges/poloniex/poloniex_wrapper.go b/exchanges/poloniex/poloniex_wrapper.go index f3381bd8..a766361d 100644 --- a/exchanges/poloniex/poloniex_wrapper.go +++ b/exchanges/poloniex/poloniex_wrapper.go @@ -668,7 +668,9 @@ func (p *Poloniex) GetOrderInfo(ctx context.Context, orderID string, pair curren return orderInfo, err } - orderInfo.Status, _ = order.StringToOrderStatus(resp.Status) + if orderInfo.Status, err = order.StringToOrderStatus(resp.Status); err != nil { + log.Errorf(log.ExchangeSys, "%s %v", p.Name, err) + } orderInfo.Price = resp.Rate orderInfo.Amount = resp.Amount orderInfo.Cost = resp.Total @@ -874,8 +876,8 @@ func (p *Poloniex) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequ var orders []order.Detail for key := range resp.Data { - var symbol currency.Pair - symbol, err = currency.NewPairDelimiter(key, format.Delimiter) + var pair currency.Pair + pair, err = currency.NewPairDelimiter(key, format.Delimiter) if err != nil { return nil, err } @@ -893,15 +895,20 @@ func (p *Poloniex) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequ resp.Data[key][i].Date) } - orders = append(orders, order.Detail{ - ID: strconv.FormatInt(resp.Data[key][i].GlobalTradeID, 10), - Side: orderSide, - Amount: resp.Data[key][i].Amount, - Date: orderDate, - Price: resp.Data[key][i].Rate, - Pair: symbol, - Exchange: p.Name, - }) + detail := order.Detail{ + ID: strconv.FormatInt(resp.Data[key][i].GlobalTradeID, 10), + Side: orderSide, + Amount: resp.Data[key][i].Amount, + ExecutedAmount: resp.Data[key][i].Amount, + Date: orderDate, + Price: resp.Data[key][i].Rate, + AverageExecutedPrice: resp.Data[key][i].Rate, + Pair: pair, + Status: order.Filled, + Exchange: p.Name, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } } diff --git a/exchanges/yobit/yobit_wrapper.go b/exchanges/yobit/yobit_wrapper.go index f7db2ad5..35a6f9c3 100644 --- a/exchanges/yobit/yobit_wrapper.go +++ b/exchanges/yobit/yobit_wrapper.go @@ -635,22 +635,27 @@ func (y *Yobit) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest var orders []order.Detail for i := range allOrders { - var symbol currency.Pair - symbol, err = currency.NewPairDelimiter(allOrders[i].Pair, format.Delimiter) + var pair currency.Pair + pair, err = currency.NewPairDelimiter(allOrders[i].Pair, format.Delimiter) if err != nil { return nil, err } orderDate := time.Unix(int64(allOrders[i].Timestamp), 0) side := order.Side(strings.ToUpper(allOrders[i].Type)) - orders = append(orders, order.Detail{ - ID: strconv.FormatFloat(allOrders[i].OrderID, 'f', -1, 64), - Amount: allOrders[i].Amount, - Price: allOrders[i].Rate, - Side: side, - Date: orderDate, - Pair: symbol, - Exchange: y.Name, - }) + detail := order.Detail{ + ID: strconv.FormatFloat(allOrders[i].OrderID, 'f', -1, 64), + Amount: allOrders[i].Amount, + ExecutedAmount: allOrders[i].Amount, + Price: allOrders[i].Rate, + AverageExecutedPrice: allOrders[i].Rate, + Side: side, + Status: order.Filled, + Date: orderDate, + Pair: pair, + Exchange: y.Name, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } order.FilterOrdersBySide(&orders, req.Side) diff --git a/exchanges/zb/zb_types.go b/exchanges/zb/zb_types.go index 7dd6d1b3..a5c1a91a 100644 --- a/exchanges/zb/zb_types.go +++ b/exchanges/zb/zb_types.go @@ -40,7 +40,7 @@ type Order struct { Price float64 `json:"price"` Status int `json:"status"` TotalAmount float64 `json:"total_amount"` - TradeAmount int `json:"trade_amount"` + TradeAmount float64 `json:"trade_amount"` TradeDate int `json:"trade_date"` TradeMoney float64 `json:"trade_money"` Type int64 `json:"type"` diff --git a/exchanges/zb/zb_wrapper.go b/exchanges/zb/zb_wrapper.go index 2954f55b..af4c0c6d 100644 --- a/exchanges/zb/zb_wrapper.go +++ b/exchanges/zb/zb_wrapper.go @@ -812,23 +812,28 @@ func (z *ZB) GetOrderHistory(ctx context.Context, req *order.GetOrdersRequest) ( } for i := range allOrders { - var symbol currency.Pair - symbol, err = currency.NewPairDelimiter(allOrders[i].Currency, + var pair currency.Pair + pair, err = currency.NewPairDelimiter(allOrders[i].Currency, format.Delimiter) if err != nil { return nil, err } orderDate := time.Unix(int64(allOrders[i].TradeDate), 0) orderSide := orderSideMap[allOrders[i].Type] - orders = append(orders, order.Detail{ - ID: strconv.FormatInt(allOrders[i].ID, 10), - Amount: allOrders[i].TotalAmount, - Exchange: z.Name, - Date: orderDate, - Price: allOrders[i].Price, - Side: orderSide, - Pair: symbol, - }) + detail := order.Detail{ + ID: strconv.FormatInt(allOrders[i].ID, 10), + Amount: allOrders[i].TotalAmount, + ExecutedAmount: allOrders[i].TradeAmount, + RemainingAmount: allOrders[i].TotalAmount - allOrders[i].TradeAmount, + Exchange: z.Name, + Date: orderDate, + Price: allOrders[i].Price, + AverageExecutedPrice: allOrders[i].TradePrice, + Side: orderSide, + Pair: pair, + } + detail.InferCostsAndTimes() + orders = append(orders, detail) } order.FilterOrdersByTimeRange(&orders, req.StartTime, req.EndTime)