mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-22 14:55:16 +00:00
backtest: fix stop order backtest, add more test cases and assertions
This commit is contained in:
parent
09e98eed82
commit
abee61cdc4
|
@ -311,8 +311,8 @@ func (m *SimplePriceMatching) BuyToPrice(price fixedpoint.Value) (closedOrders [
|
||||||
switch o.Type {
|
switch o.Type {
|
||||||
|
|
||||||
case types.OrderTypeStopMarket:
|
case types.OrderTypeStopMarket:
|
||||||
// should we trigger the order
|
// the price is still lower than the stop price, we will put the order back to the list
|
||||||
if o.StopPrice.Compare(price) <= 0 {
|
if price.Compare(o.StopPrice) < 0 {
|
||||||
// not triggering it, put it back
|
// not triggering it, put it back
|
||||||
bidOrders = append(bidOrders, o)
|
bidOrders = append(bidOrders, o)
|
||||||
break
|
break
|
||||||
|
@ -325,8 +325,8 @@ func (m *SimplePriceMatching) BuyToPrice(price fixedpoint.Value) (closedOrders [
|
||||||
closedOrders = append(closedOrders, o)
|
closedOrders = append(closedOrders, o)
|
||||||
|
|
||||||
case types.OrderTypeStopLimit:
|
case types.OrderTypeStopLimit:
|
||||||
// should we trigger the order?
|
// the price is still lower than the stop price, we will put the order back to the list
|
||||||
if price.Compare(o.StopPrice) <= 0 {
|
if price.Compare(o.StopPrice) < 0 {
|
||||||
bidOrders = append(bidOrders, o)
|
bidOrders = append(bidOrders, o)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -338,7 +338,10 @@ func (m *SimplePriceMatching) BuyToPrice(price fixedpoint.Value) (closedOrders [
|
||||||
// is it a taker order?
|
// is it a taker order?
|
||||||
// higher than the current price, then it's a taker order
|
// higher than the current price, then it's a taker order
|
||||||
if o.Price.Compare(price) >= 0 {
|
if o.Price.Compare(price) >= 0 {
|
||||||
// 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
|
||||||
|
// TODO: simulate slippage here
|
||||||
|
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)
|
||||||
|
@ -358,7 +361,7 @@ func (m *SimplePriceMatching) BuyToPrice(price fixedpoint.Value) (closedOrders [
|
||||||
|
|
||||||
case types.OrderTypeStopMarket:
|
case types.OrderTypeStopMarket:
|
||||||
// should we trigger the order
|
// should we trigger the order
|
||||||
if price.Compare(o.StopPrice) <= 0 {
|
if price.Compare(o.StopPrice) < 0 {
|
||||||
// not triggering it, put it back
|
// not triggering it, put it back
|
||||||
askOrders = append(askOrders, o)
|
askOrders = append(askOrders, o)
|
||||||
break
|
break
|
||||||
|
@ -372,7 +375,7 @@ func (m *SimplePriceMatching) BuyToPrice(price fixedpoint.Value) (closedOrders [
|
||||||
|
|
||||||
case types.OrderTypeStopLimit:
|
case types.OrderTypeStopLimit:
|
||||||
// should we trigger the order?
|
// should we trigger the order?
|
||||||
if price.Compare(o.StopPrice) <= 0 {
|
if price.Compare(o.StopPrice) < 0 {
|
||||||
askOrders = append(askOrders, o)
|
askOrders = append(askOrders, o)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -381,11 +384,11 @@ func (m *SimplePriceMatching) BuyToPrice(price fixedpoint.Value) (closedOrders [
|
||||||
|
|
||||||
// is it a taker order?
|
// is it a taker order?
|
||||||
// higher than the current price, then it's a taker order
|
// higher than the current price, then it's a taker order
|
||||||
if o.Price.Compare(price) >= 0 {
|
if o.Price.Compare(price) <= 0 {
|
||||||
// price protection, added by @zenix
|
// limit sell order as taker, move it to the closed order
|
||||||
if o.Price.Compare(m.LastKLine.Low) < 0 {
|
// we assume that we have no price slippage here, so the latest price will be the executed price
|
||||||
o.Price = m.LastKLine.Low
|
// TODO: simulate slippage here
|
||||||
}
|
o.Price = price
|
||||||
|
|
||||||
o.ExecutedQuantity = o.Quantity
|
o.ExecutedQuantity = o.Quantity
|
||||||
o.Status = types.OrderStatusFilled
|
o.Status = types.OrderStatusFilled
|
||||||
|
@ -397,9 +400,6 @@ func (m *SimplePriceMatching) BuyToPrice(price fixedpoint.Value) (closedOrders [
|
||||||
|
|
||||||
case types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
case types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
||||||
if price.Compare(o.Price) >= 0 {
|
if price.Compare(o.Price) >= 0 {
|
||||||
if o.Price.Compare(m.LastKLine.Low) < 0 {
|
|
||||||
o.Price = m.LastKLine.Low
|
|
||||||
}
|
|
||||||
o.ExecutedQuantity = o.Quantity
|
o.ExecutedQuantity = o.Quantity
|
||||||
o.Status = types.OrderStatusFilled
|
o.Status = types.OrderStatusFilled
|
||||||
closedOrders = append(closedOrders, o)
|
closedOrders = append(closedOrders, o)
|
||||||
|
@ -432,40 +432,44 @@ func (m *SimplePriceMatching) BuyToPrice(price fixedpoint.Value) (closedOrders [
|
||||||
return closedOrders, trades
|
return closedOrders, trades
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SellToPrice simulates the price trend in down direction.
|
||||||
|
// When price goes down, buy orders should be executed, and the stop orders should be triggered.
|
||||||
func (m *SimplePriceMatching) SellToPrice(price fixedpoint.Value) (closedOrders []types.Order, trades []types.Trade) {
|
func (m *SimplePriceMatching) SellToPrice(price fixedpoint.Value) (closedOrders []types.Order, trades []types.Trade) {
|
||||||
klineMatchingLogger.Debugf("kline sell to price %s", price.String())
|
klineMatchingLogger.Debugf("kline sell to price %s", price.String())
|
||||||
|
|
||||||
var sellPrice = price
|
// in this section we handle --- the price goes lower, and we trigger the stop sell
|
||||||
|
|
||||||
var askOrders []types.Order
|
var askOrders []types.Order
|
||||||
for _, o := range m.askOrders {
|
for _, o := range m.askOrders {
|
||||||
switch o.Type {
|
switch o.Type {
|
||||||
|
|
||||||
case types.OrderTypeStopMarket:
|
case types.OrderTypeStopMarket:
|
||||||
// should we trigger the order
|
// should we trigger the order
|
||||||
if o.StopPrice.Compare(sellPrice) >= 0 {
|
if price.Compare(o.StopPrice) > 0 {
|
||||||
o.Type = types.OrderTypeMarket
|
|
||||||
o.ExecutedQuantity = o.Quantity
|
|
||||||
o.Price = sellPrice
|
|
||||||
o.Status = types.OrderStatusFilled
|
|
||||||
closedOrders = append(closedOrders, o)
|
|
||||||
} else {
|
|
||||||
askOrders = append(askOrders, o)
|
askOrders = append(askOrders, o)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o.Type = types.OrderTypeMarket
|
||||||
|
o.ExecutedQuantity = o.Quantity
|
||||||
|
o.Price = price
|
||||||
|
o.Status = types.OrderStatusFilled
|
||||||
|
closedOrders = append(closedOrders, o)
|
||||||
|
|
||||||
case types.OrderTypeStopLimit:
|
case types.OrderTypeStopLimit:
|
||||||
// if the price is lower than the stop price
|
// if the price is lower than the stop price
|
||||||
// we should trigger the stop sell order
|
// we should trigger the stop sell order
|
||||||
if sellPrice.Compare(o.StopPrice) > 0 {
|
if price.Compare(o.StopPrice) > 0 {
|
||||||
askOrders = append(askOrders, o)
|
askOrders = append(askOrders, o)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
o.Type = types.OrderTypeLimit
|
o.Type = types.OrderTypeLimit
|
||||||
|
|
||||||
|
// handle TAKER SELL
|
||||||
// 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(sellPrice) <= 0 {
|
if o.Price.Compare(price) <= 0 {
|
||||||
|
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)
|
||||||
|
@ -485,38 +489,39 @@ func (m *SimplePriceMatching) SellToPrice(price fixedpoint.Value) (closedOrders
|
||||||
|
|
||||||
case types.OrderTypeStopMarket:
|
case types.OrderTypeStopMarket:
|
||||||
// should we trigger the order
|
// should we trigger the order
|
||||||
if o.StopPrice.Compare(sellPrice) >= 0 {
|
if o.StopPrice.Compare(price) < 0 {
|
||||||
o.Type = types.OrderTypeMarket
|
bidOrders = append(bidOrders, o)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
o.Type = types.OrderTypeMarket
|
||||||
|
o.ExecutedQuantity = o.Quantity
|
||||||
|
o.Price = price
|
||||||
|
o.Status = types.OrderStatusFilled
|
||||||
|
closedOrders = append(closedOrders, o)
|
||||||
|
|
||||||
|
case types.OrderTypeStopLimit:
|
||||||
|
// if the price is lower than the stop order price
|
||||||
|
// we should trigger the stop order
|
||||||
|
if o.StopPrice.Compare(price) < 0 {
|
||||||
|
bidOrders = append(bidOrders, o)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
o.Type = types.OrderTypeLimit
|
||||||
|
|
||||||
|
// taker order?
|
||||||
|
if o.Price.Compare(price) >= 0 {
|
||||||
|
o.Price = price
|
||||||
o.ExecutedQuantity = o.Quantity
|
o.ExecutedQuantity = o.Quantity
|
||||||
o.Price = sellPrice
|
|
||||||
o.Status = types.OrderStatusFilled
|
o.Status = types.OrderStatusFilled
|
||||||
closedOrders = append(closedOrders, o)
|
closedOrders = append(closedOrders, o)
|
||||||
} else {
|
} else {
|
||||||
bidOrders = append(bidOrders, o)
|
bidOrders = append(bidOrders, o)
|
||||||
}
|
}
|
||||||
|
|
||||||
case types.OrderTypeStopLimit:
|
|
||||||
// if the price is lower than the stop price
|
|
||||||
// we should trigger the stop order
|
|
||||||
if sellPrice.Compare(o.StopPrice) <= 0 {
|
|
||||||
o.Type = types.OrderTypeLimit
|
|
||||||
|
|
||||||
if o.Price.Compare(sellPrice) <= 0 {
|
|
||||||
if o.Price.Compare(m.LastKLine.High) > 0 {
|
|
||||||
o.Price = m.LastKLine.High
|
|
||||||
}
|
|
||||||
o.ExecutedQuantity = o.Quantity
|
|
||||||
o.Status = types.OrderStatusFilled
|
|
||||||
closedOrders = append(closedOrders, o)
|
|
||||||
} else {
|
|
||||||
bidOrders = append(bidOrders, o)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bidOrders = append(bidOrders, o)
|
|
||||||
}
|
|
||||||
|
|
||||||
case types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
case types.OrderTypeLimit, types.OrderTypeLimitMaker:
|
||||||
if sellPrice.Compare(o.Price) <= 0 {
|
if price.Compare(o.Price) <= 0 {
|
||||||
o.ExecutedQuantity = o.Quantity
|
o.ExecutedQuantity = o.Quantity
|
||||||
o.Status = types.OrderStatusFilled
|
o.Status = types.OrderStatusFilled
|
||||||
closedOrders = append(closedOrders, o)
|
closedOrders = append(closedOrders, o)
|
||||||
|
@ -570,7 +575,6 @@ func (m *SimplePriceMatching) getOrder(orderID uint64) (types.Order, bool) {
|
||||||
|
|
||||||
func (m *SimplePriceMatching) processKLine(kline types.KLine) {
|
func (m *SimplePriceMatching) processKLine(kline types.KLine) {
|
||||||
m.CurrentTime = kline.EndTime.Time()
|
m.CurrentTime = kline.EndTime.Time()
|
||||||
m.LastKLine = kline
|
|
||||||
if m.LastPrice.IsZero() {
|
if m.LastPrice.IsZero() {
|
||||||
m.LastPrice = kline.Open
|
m.LastPrice = kline.Open
|
||||||
} else {
|
} else {
|
||||||
|
@ -610,8 +614,9 @@ func (m *SimplePriceMatching) processKLine(kline types.KLine) {
|
||||||
if m.LastPrice.IsZero() {
|
if m.LastPrice.IsZero() {
|
||||||
m.BuyToPrice(kline.Close)
|
m.BuyToPrice(kline.Close)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.LastKLine = kline
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *SimplePriceMatching) newOrder(o types.SubmitOrder, orderID uint64) types.Order {
|
func (m *SimplePriceMatching) newOrder(o types.SubmitOrder, orderID uint64) types.Order {
|
||||||
|
|
|
@ -187,7 +187,7 @@ func TestSimplePriceMatching_StopLimitOrderBuy(t *testing.T) {
|
||||||
LastPrice: fixedpoint.NewFromFloat(19000.0),
|
LastPrice: fixedpoint.NewFromFloat(19000.0),
|
||||||
}
|
}
|
||||||
|
|
||||||
stopOrder := types.SubmitOrder{
|
stopBuyOrder := types.SubmitOrder{
|
||||||
Symbol: market.Symbol,
|
Symbol: market.Symbol,
|
||||||
Side: types.SideTypeBuy,
|
Side: types.SideTypeBuy,
|
||||||
Type: types.OrderTypeStopLimit,
|
Type: types.OrderTypeStopLimit,
|
||||||
|
@ -196,14 +196,24 @@ func TestSimplePriceMatching_StopLimitOrderBuy(t *testing.T) {
|
||||||
StopPrice: fixedpoint.NewFromFloat(21000.0),
|
StopPrice: fixedpoint.NewFromFloat(21000.0),
|
||||||
TimeInForce: types.TimeInForceGTC,
|
TimeInForce: types.TimeInForceGTC,
|
||||||
}
|
}
|
||||||
createdOrder, trade, err := engine.PlaceOrder(stopOrder)
|
createdOrder, trade, err := engine.PlaceOrder(stopBuyOrder)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, trade, "place stop order should not trigger the stop buy")
|
assert.Nil(t, trade, "place stop order should not trigger the stop buy")
|
||||||
assert.NotNil(t, createdOrder, "place stop order should not trigger the stop buy")
|
assert.NotNil(t, createdOrder, "place stop order should not trigger the stop buy")
|
||||||
|
|
||||||
|
// place some limit orders, so we ensure that the remaining orders are not removed.
|
||||||
|
_, _, err = engine.PlaceOrder(newLimitOrder(market.Symbol, types.SideTypeBuy, 18000, 0.01))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, _, err = engine.PlaceOrder(newLimitOrder(market.Symbol, types.SideTypeSell, 32000, 0.01))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 2, len(engine.bidOrders))
|
||||||
|
assert.Equal(t, 1, len(engine.askOrders))
|
||||||
|
|
||||||
closedOrders, trades := engine.BuyToPrice(fixedpoint.NewFromFloat(20000.0))
|
closedOrders, trades := engine.BuyToPrice(fixedpoint.NewFromFloat(20000.0))
|
||||||
assert.Len(t, closedOrders, 0, "price change far from the price should not trigger the stop buy")
|
assert.Len(t, closedOrders, 0, "price change far from the price should not trigger the stop buy")
|
||||||
assert.Len(t, trades, 0, "price change far from the price should not trigger the stop buy")
|
assert.Len(t, trades, 0, "price change far from the price should not trigger the stop buy")
|
||||||
|
assert.Equal(t, 2, len(engine.bidOrders), "bid orders should be the same")
|
||||||
|
assert.Equal(t, 1, len(engine.askOrders), "ask orders should be the same")
|
||||||
|
|
||||||
closedOrders, trades = engine.BuyToPrice(fixedpoint.NewFromFloat(21001.0))
|
closedOrders, trades = engine.BuyToPrice(fixedpoint.NewFromFloat(21001.0))
|
||||||
assert.Len(t, closedOrders, 1, "should trigger the stop buy order")
|
assert.Len(t, closedOrders, 1, "should trigger the stop buy order")
|
||||||
|
@ -211,7 +221,30 @@ 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, stopOrder.Price, trades[0].Price)
|
assert.Equal(t, "21001", trades[0].Price.String())
|
||||||
|
assert.Equal(t, "21001", closedOrders[0].Price.String(), "order.Price should be adjusted")
|
||||||
|
|
||||||
|
assert.Equal(t, fixedpoint.NewFromFloat(21001.0).String(), engine.LastPrice.String())
|
||||||
|
|
||||||
|
stopOrder2 := types.SubmitOrder{
|
||||||
|
Symbol: market.Symbol,
|
||||||
|
Side: types.SideTypeBuy,
|
||||||
|
Type: types.OrderTypeStopLimit,
|
||||||
|
Quantity: fixedpoint.NewFromFloat(0.1),
|
||||||
|
Price: fixedpoint.NewFromFloat(22000.0),
|
||||||
|
StopPrice: fixedpoint.NewFromFloat(21000.0),
|
||||||
|
TimeInForce: types.TimeInForceGTC,
|
||||||
|
}
|
||||||
|
createdOrder, trade, err = engine.PlaceOrder(stopOrder2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, trade, "place stop order should not trigger the stop buy")
|
||||||
|
assert.NotNil(t, createdOrder, "place stop order should not trigger the stop buy")
|
||||||
|
assert.Len(t, engine.bidOrders, 2)
|
||||||
|
|
||||||
|
closedOrders, trades = engine.SellToPrice(fixedpoint.NewFromFloat(20500.0))
|
||||||
|
assert.Len(t, closedOrders, 1, "should trigger the stop buy order")
|
||||||
|
assert.Len(t, trades, 1, "should have stop order trade executed")
|
||||||
|
assert.Len(t, engine.bidOrders, 1, "should left one bid order")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSimplePriceMatching_StopLimitOrderSell(t *testing.T) {
|
func TestSimplePriceMatching_StopLimitOrderSell(t *testing.T) {
|
||||||
|
@ -224,7 +257,7 @@ func TestSimplePriceMatching_StopLimitOrderSell(t *testing.T) {
|
||||||
LastPrice: fixedpoint.NewFromFloat(22000.0),
|
LastPrice: fixedpoint.NewFromFloat(22000.0),
|
||||||
}
|
}
|
||||||
|
|
||||||
stopOrder := types.SubmitOrder{
|
stopSellOrder := types.SubmitOrder{
|
||||||
Symbol: market.Symbol,
|
Symbol: market.Symbol,
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
Type: types.OrderTypeStopLimit,
|
Type: types.OrderTypeStopLimit,
|
||||||
|
@ -233,22 +266,62 @@ func TestSimplePriceMatching_StopLimitOrderSell(t *testing.T) {
|
||||||
StopPrice: fixedpoint.NewFromFloat(21000.0),
|
StopPrice: fixedpoint.NewFromFloat(21000.0),
|
||||||
TimeInForce: types.TimeInForceGTC,
|
TimeInForce: types.TimeInForceGTC,
|
||||||
}
|
}
|
||||||
createdOrder, trade, err := engine.PlaceOrder(stopOrder)
|
createdOrder, trade, err := engine.PlaceOrder(stopSellOrder)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Nil(t, trade, "place stop order should not trigger the stop sell")
|
assert.Nil(t, trade, "place stop order should not trigger the stop sell")
|
||||||
assert.NotNil(t, createdOrder, "place stop order should not trigger the stop sell")
|
assert.NotNil(t, createdOrder, "place stop order should not trigger the stop sell")
|
||||||
|
|
||||||
|
// place some limit orders, so we ensure that the remaining orders are not removed.
|
||||||
|
_, _, err = engine.PlaceOrder(newLimitOrder(market.Symbol, types.SideTypeBuy, 18000, 0.01))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
_, _, err = engine.PlaceOrder(newLimitOrder(market.Symbol, types.SideTypeSell, 32000, 0.01))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, 1, len(engine.bidOrders))
|
||||||
|
assert.Equal(t, 2, len(engine.askOrders))
|
||||||
|
|
||||||
closedOrders, trades := engine.SellToPrice(fixedpoint.NewFromFloat(21500.0))
|
closedOrders, trades := engine.SellToPrice(fixedpoint.NewFromFloat(21500.0))
|
||||||
assert.Len(t, closedOrders, 0, "price change far from the price should not trigger the stop buy")
|
assert.Len(t, closedOrders, 0, "price change far from the price should not trigger the stop buy")
|
||||||
assert.Len(t, trades, 0, "price change far from the price should not trigger the stop buy")
|
assert.Len(t, trades, 0, "price change far from the price should not trigger the stop buy")
|
||||||
|
assert.Equal(t, 1, len(engine.bidOrders))
|
||||||
|
assert.Equal(t, 2, len(engine.askOrders))
|
||||||
|
|
||||||
closedOrders, trades = engine.SellToPrice(fixedpoint.NewFromFloat(20990.0))
|
closedOrders, trades = engine.SellToPrice(fixedpoint.NewFromFloat(20990.0))
|
||||||
assert.Len(t, closedOrders, 1, "should trigger the stop sell order")
|
assert.Len(t, closedOrders, 1, "should trigger the stop sell order")
|
||||||
assert.Len(t, trades, 1, "should have stop order trade executed")
|
assert.Len(t, trades, 1, "should have stop order trade executed")
|
||||||
|
assert.Equal(t, 1, len(engine.bidOrders))
|
||||||
|
assert.Equal(t, 1, len(engine.askOrders))
|
||||||
|
|
||||||
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, stopOrder.Price, trades[0].Price)
|
assert.Equal(t, "20990", closedOrders[0].Price.String())
|
||||||
|
assert.Equal(t, "20990", trades[0].Price.String())
|
||||||
|
assert.Equal(t, "20990", engine.LastPrice.String())
|
||||||
|
|
||||||
|
// place a stop limit sell order with a higher price than the current price
|
||||||
|
stopOrder2 := types.SubmitOrder{
|
||||||
|
Symbol: market.Symbol,
|
||||||
|
Side: types.SideTypeSell,
|
||||||
|
Type: types.OrderTypeStopLimit,
|
||||||
|
Quantity: fixedpoint.NewFromFloat(0.1),
|
||||||
|
Price: fixedpoint.NewFromFloat(20000.0),
|
||||||
|
StopPrice: fixedpoint.NewFromFloat(21000.0),
|
||||||
|
TimeInForce: types.TimeInForceGTC,
|
||||||
|
}
|
||||||
|
|
||||||
|
createdOrder, trade, err = engine.PlaceOrder(stopOrder2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, trade, "place stop order should not trigger the stop sell")
|
||||||
|
assert.NotNil(t, createdOrder, "place stop order should not trigger the stop sell")
|
||||||
|
|
||||||
|
closedOrders, trades = engine.BuyToPrice(fixedpoint.NewFromFloat(21000.0))
|
||||||
|
if assert.Len(t, closedOrders, 1, "should trigger the stop sell order") {
|
||||||
|
assert.Len(t, trades, 1, "should have stop order trade executed")
|
||||||
|
assert.Equal(t, types.SideTypeSell, closedOrders[0].Side)
|
||||||
|
assert.Equal(t, types.OrderStatusFilled, closedOrders[0].Status)
|
||||||
|
assert.Equal(t, types.OrderTypeLimit, closedOrders[0].Type)
|
||||||
|
assert.Equal(t, "21000", trades[0].Price.String(), "trade price should be the kline price not the order price")
|
||||||
|
assert.Equal(t, "21000", engine.LastPrice.String(), "engine last price should be updated correctly")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSimplePriceMatching_StopMarketOrderSell(t *testing.T) {
|
func TestSimplePriceMatching_StopMarketOrderSell(t *testing.T) {
|
||||||
|
@ -285,7 +358,7 @@ func TestSimplePriceMatching_StopMarketOrderSell(t *testing.T) {
|
||||||
|
|
||||||
assert.Equal(t, types.OrderStatusFilled, closedOrders[0].Status)
|
assert.Equal(t, types.OrderStatusFilled, closedOrders[0].Status)
|
||||||
assert.Equal(t, types.OrderTypeMarket, closedOrders[0].Type)
|
assert.Equal(t, types.OrderTypeMarket, closedOrders[0].Type)
|
||||||
assert.Equal(t, fixedpoint.NewFromFloat(20990.0), trades[0].Price)
|
assert.Equal(t, fixedpoint.NewFromFloat(20990.0), trades[0].Price, "trade price should be adjusted to the last price")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSimplePriceMatching_PlaceLimitOrder(t *testing.T) {
|
func TestSimplePriceMatching_PlaceLimitOrder(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user