mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-06-06 15:10:59 +00:00
Exchanges: enrich order history with avg executed price, cost, and more (#792)
* Exchanges: enrich order history with avg executed price, cost, and more * Fix division by zero in order detail enrichment * Remove DateCompleted from Bithumb OrderData and fix OrderDate parsing * Fixes on order detail fields and rename EnrichOrderDetail to CalculateCostsAndAmounts * BTSE order history populate name and id * Calculate average executed price for market order or when order amount is zero * Minor fixes on infer order amounts, costs, and times * Attach InferAmountsCostsAndTimes to Order.Detail * Binance: fix order status * Always use order.StringToOrderStatus() and ensure order has at least one of executed/remaining amount set
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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"),
|
||||
|
||||
Reference in New Issue
Block a user