backtest: fix execution price for stop limit taker orders

This commit is contained in:
c9s 2022-08-18 15:26:09 +08:00
parent 9f9fc098f4
commit 3a24a48cde
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
2 changed files with 35 additions and 11 deletions

View File

@ -366,8 +366,7 @@ func (m *SimplePriceMatching) buyToPrice(price fixedpoint.Value) (closedOrders [
if o.Price.Compare(price) >= 0 { if o.Price.Compare(price) >= 0 {
// limit buy taker order, move it to the closed order // limit buy taker order, move it to the closed order
// we assume that we have no price slippage here, so the latest price will be the executed price // we assume that we have no price slippage here, so the latest price will be the executed price
// TODO: simulate slippage here o.AveragePrice = price
o.Price = price
o.ExecutedQuantity = o.Quantity o.ExecutedQuantity = o.Quantity
o.Status = types.OrderStatusFilled o.Status = types.OrderStatusFilled
closedOrders = append(closedOrders, o) closedOrders = append(closedOrders, o)
@ -414,8 +413,7 @@ func (m *SimplePriceMatching) buyToPrice(price fixedpoint.Value) (closedOrders [
// limit sell order as taker, move it to the closed order // limit sell order as taker, move it to the closed order
// we assume that we have no price slippage here, so the latest price will be the executed price // we assume that we have no price slippage here, so the latest price will be the executed price
// TODO: simulate slippage here // TODO: simulate slippage here
o.Price = price o.AveragePrice = price
o.ExecutedQuantity = o.Quantity o.ExecutedQuantity = o.Quantity
o.Status = types.OrderStatusFilled o.Status = types.OrderStatusFilled
closedOrders = append(closedOrders, o) closedOrders = append(closedOrders, o)
@ -444,7 +442,12 @@ func (m *SimplePriceMatching) buyToPrice(price fixedpoint.Value) (closedOrders [
for i := range closedOrders { for i := range closedOrders {
o := closedOrders[i] o := closedOrders[i]
trade := m.newTradeFromOrder(&o, true, o.Price) executedPrice := o.Price
if !o.AveragePrice.IsZero() {
executedPrice = o.AveragePrice
}
trade := m.newTradeFromOrder(&o, !isTakerOrder(o), executedPrice)
m.executeTrade(trade) m.executeTrade(trade)
closedOrders[i] = o closedOrders[i] = o
@ -495,7 +498,7 @@ func (m *SimplePriceMatching) sellToPrice(price fixedpoint.Value) (closedOrders
// if the order price is lower than the current price // if the order price is lower than the current price
// it's a taker order // it's a taker order
if o.Price.Compare(price) <= 0 { if o.Price.Compare(price) <= 0 {
o.Price = price o.AveragePrice = price
o.ExecutedQuantity = o.Quantity o.ExecutedQuantity = o.Quantity
o.Status = types.OrderStatusFilled o.Status = types.OrderStatusFilled
closedOrders = append(closedOrders, o) closedOrders = append(closedOrders, o)
@ -539,9 +542,9 @@ func (m *SimplePriceMatching) sellToPrice(price fixedpoint.Value) (closedOrders
o.Type = types.OrderTypeLimit o.Type = types.OrderTypeLimit
// taker order? // handle TAKER order
if o.Price.Compare(price) >= 0 { if o.Price.Compare(price) >= 0 {
o.Price = price o.AveragePrice = price
o.ExecutedQuantity = o.Quantity o.ExecutedQuantity = o.Quantity
o.Status = types.OrderStatusFilled o.Status = types.OrderStatusFilled
closedOrders = append(closedOrders, o) closedOrders = append(closedOrders, o)
@ -568,7 +571,12 @@ func (m *SimplePriceMatching) sellToPrice(price fixedpoint.Value) (closedOrders
for i := range closedOrders { for i := range closedOrders {
o := closedOrders[i] o := closedOrders[i]
trade := m.newTradeFromOrder(&o, true, o.Price) executedPrice := o.Price
if !o.AveragePrice.IsZero() {
executedPrice = o.AveragePrice
}
trade := m.newTradeFromOrder(&o, !isTakerOrder(o), executedPrice)
m.executeTrade(trade) m.executeTrade(trade)
closedOrders[i] = o closedOrders[i] = o
@ -678,6 +686,22 @@ func calculateNativeOrderFee(order *types.Order, market types.Market, feeRate fi
return fee, feeCurrency return fee, feeCurrency
} }
func isTakerOrder(o types.Order) bool {
if o.AveragePrice.IsZero() {
return false
}
switch o.Side {
case types.SideTypeBuy:
return o.AveragePrice.Compare(o.Price) < 0
case types.SideTypeSell:
return o.AveragePrice.Compare(o.Price) > 0
}
return false
}
func isLimitTakerOrder(o types.SubmitOrder, currentPrice fixedpoint.Value) bool { func isLimitTakerOrder(o types.SubmitOrder, currentPrice fixedpoint.Value) bool {
if currentPrice.IsZero() { if currentPrice.IsZero() {
return false return false

View File

@ -293,7 +293,7 @@ func TestSimplePriceMatching_StopLimitOrderBuy(t *testing.T) {
assert.Equal(t, types.OrderStatusFilled, closedOrders[0].Status) assert.Equal(t, types.OrderStatusFilled, closedOrders[0].Status)
assert.Equal(t, types.OrderTypeLimit, closedOrders[0].Type) assert.Equal(t, types.OrderTypeLimit, closedOrders[0].Type)
assert.Equal(t, "21001", trades[0].Price.String()) assert.Equal(t, "21001", trades[0].Price.String())
assert.Equal(t, "21001", closedOrders[0].Price.String(), "order.Price should be adjusted") assert.Equal(t, "22000", closedOrders[0].Price.String(), "order.Price should not be adjusted")
assert.Equal(t, fixedpoint.NewFromFloat(21001.0).String(), engine.LastPrice.String()) assert.Equal(t, fixedpoint.NewFromFloat(21001.0).String(), engine.LastPrice.String())
@ -364,7 +364,7 @@ func TestSimplePriceMatching_StopLimitOrderSell(t *testing.T) {
assert.Equal(t, types.OrderStatusFilled, closedOrders[0].Status) assert.Equal(t, types.OrderStatusFilled, closedOrders[0].Status)
assert.Equal(t, types.OrderTypeLimit, closedOrders[0].Type) assert.Equal(t, types.OrderTypeLimit, closedOrders[0].Type)
assert.Equal(t, "20990", closedOrders[0].Price.String()) assert.Equal(t, "20000", closedOrders[0].Price.String(), "limit order price should not be changed")
assert.Equal(t, "20990", trades[0].Price.String()) assert.Equal(t, "20990", trades[0].Price.String())
assert.Equal(t, "20990", engine.LastPrice.String()) assert.Equal(t, "20990", engine.LastPrice.String())