Skip to content

Commit d0cbc83

Browse files
authored
Merge pull request #2299 from c9s/c9s/fix-backtest
FIX: [backtest] fix stop market order matching
2 parents c9ab41f + 0d455cb commit d0cbc83

File tree

1 file changed

+76
-77
lines changed

1 file changed

+76
-77
lines changed

pkg/backtest/matching.go

Lines changed: 76 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -366,19 +366,19 @@ func (m *SimplePriceMatching) buyToPrice(price fixedpoint.Value) (closedOrders [
366366
switch o.Type {
367367

368368
case types.OrderTypeStopMarket:
369-
// the price is still lower than the stop price, we will put the order back to the list
370-
if price.Compare(o.StopPrice) < 0 {
369+
// if the stop price is higher than last price, and the current price is higher than stop price
370+
if o.StopPrice.Compare(m.lastPrice) > 0 && o.StopPrice.Compare(price) <= 0 {
371+
o.Type = types.OrderTypeMarket
372+
o.ExecutedQuantity = o.Quantity
373+
o.Price = price
374+
o.Status = types.OrderStatusFilled
375+
closedOrders = append(closedOrders, o)
376+
} else {
371377
// not triggering it, put it back
372378
bidOrders = append(bidOrders, o)
373379
break
374380
}
375381

376-
o.Type = types.OrderTypeMarket
377-
o.ExecutedQuantity = o.Quantity
378-
o.Price = price
379-
o.Status = types.OrderStatusFilled
380-
closedOrders = append(closedOrders, o)
381-
382382
case types.OrderTypeStopLimit:
383383
// the price is still lower than the stop price, we will put the order back to the list
384384
if price.Compare(o.StopPrice) < 0 {
@@ -414,41 +414,41 @@ func (m *SimplePriceMatching) buyToPrice(price fixedpoint.Value) (closedOrders [
414414
switch o.Type {
415415

416416
case types.OrderTypeStopMarket:
417-
// should we trigger the order
418-
if price.Compare(o.StopPrice) < 0 {
417+
// if the stop price is higher than last price, and the current price is higher than stop price
418+
if o.StopPrice.Compare(m.lastPrice) > 0 && o.StopPrice.Compare(price) <= 0 {
419+
o.Type = types.OrderTypeMarket
420+
o.ExecutedQuantity = o.Quantity
421+
o.Price = price
422+
o.Status = types.OrderStatusFilled
423+
closedOrders = append(closedOrders, o)
424+
} else {
419425
// not triggering it, put it back
420426
askOrders = append(askOrders, o)
421427
break
422428
}
423429

424-
o.Type = types.OrderTypeMarket
425-
o.ExecutedQuantity = o.Quantity
426-
o.Price = price
427-
o.Status = types.OrderStatusFilled
428-
closedOrders = append(closedOrders, o)
429-
430430
case types.OrderTypeStopLimit:
431431
// should we trigger the order?
432-
if price.Compare(o.StopPrice) < 0 {
433-
askOrders = append(askOrders, o)
434-
break
435-
}
436-
437-
o.Type = types.OrderTypeLimit
438-
439-
// is it a taker order?
440-
// higher than the current price, then it's a taker order
441-
if o.Price.Compare(price) <= 0 {
442-
// limit sell order as taker, move it to the closed order
443-
// we assume that we have no price slippage here, so the latest price will be the executed price
444-
// TODO: simulate slippage here
445-
o.AveragePrice = price
446-
o.ExecutedQuantity = o.Quantity
447-
o.Status = types.OrderStatusFilled
448-
closedOrders = append(closedOrders, o)
432+
if o.StopPrice.Compare(m.lastPrice) > 0 && o.StopPrice.Compare(price) <= 0 {
433+
o.Type = types.OrderTypeLimit
434+
435+
// is it a taker order?
436+
// higher than the current price, then it's a taker order
437+
if o.Price.Compare(price) <= 0 {
438+
// limit sell order as taker, move it to the closed order
439+
// we assume that we have no price slippage here, so the latest price will be the executed price
440+
// TODO: simulate slippage here
441+
o.AveragePrice = price
442+
o.ExecutedQuantity = o.Quantity
443+
o.Status = types.OrderStatusFilled
444+
closedOrders = append(closedOrders, o)
445+
} else {
446+
// maker order
447+
askOrders = append(askOrders, o)
448+
}
449449
} else {
450-
// maker order
451450
askOrders = append(askOrders, o)
451+
break
452452
}
453453

454454
case types.OrderTypeLimit, types.OrderTypeLimitMaker:
@@ -501,38 +501,37 @@ func (m *SimplePriceMatching) sellToPrice(price fixedpoint.Value) (closedOrders
501501
switch o.Type {
502502

503503
case types.OrderTypeStopMarket:
504-
// should we trigger the order
505-
if price.Compare(o.StopPrice) > 0 {
504+
if o.StopPrice.Compare(m.lastPrice) < 0 && o.StopPrice.Compare(price) >= 0 {
505+
o.Type = types.OrderTypeMarket
506+
o.ExecutedQuantity = o.Quantity
507+
o.Price = price
508+
o.Status = types.OrderStatusFilled
509+
closedOrders = append(closedOrders, o)
510+
} else {
506511
askOrders = append(askOrders, o)
507512
break
508513
}
509514

510-
o.Type = types.OrderTypeMarket
511-
o.ExecutedQuantity = o.Quantity
512-
o.Price = price
513-
o.Status = types.OrderStatusFilled
514-
closedOrders = append(closedOrders, o)
515-
516515
case types.OrderTypeStopLimit:
517516
// if the price is lower than the stop price
518517
// we should trigger the stop sell order
519-
if price.Compare(o.StopPrice) > 0 {
520-
askOrders = append(askOrders, o)
521-
break
522-
}
523-
524-
o.Type = types.OrderTypeLimit
525-
526-
// handle TAKER SELL
527-
// if the order price is lower than the current price
528-
// it's a taker order
529-
if o.Price.Compare(price) <= 0 {
530-
o.AveragePrice = price
531-
o.ExecutedQuantity = o.Quantity
532-
o.Status = types.OrderStatusFilled
533-
closedOrders = append(closedOrders, o)
518+
if o.StopPrice.Compare(m.lastPrice) < 0 && o.StopPrice.Compare(price) >= 0 {
519+
o.Type = types.OrderTypeLimit
520+
521+
// handle TAKER SELL
522+
// if the order price is lower than the current price
523+
// it's a taker order
524+
if o.Price.Compare(price) <= 0 {
525+
o.AveragePrice = price
526+
o.ExecutedQuantity = o.Quantity
527+
o.Status = types.OrderStatusFilled
528+
closedOrders = append(closedOrders, o)
529+
} else {
530+
askOrders = append(askOrders, o)
531+
}
534532
} else {
535533
askOrders = append(askOrders, o)
534+
break
536535
}
537536

538537
default:
@@ -549,36 +548,36 @@ func (m *SimplePriceMatching) sellToPrice(price fixedpoint.Value) (closedOrders
549548
// price goes down and if the stop price is still lower than the current price
550549
// or the stop price is not touched
551550
// then we should skip this order
552-
if price.Compare(o.StopPrice) > 0 {
551+
if o.StopPrice.Compare(m.lastPrice) < 0 && o.StopPrice.Compare(price) >= 0 {
552+
o.Type = types.OrderTypeMarket
553+
o.ExecutedQuantity = o.Quantity
554+
o.Price = price
555+
o.Status = types.OrderStatusFilled
556+
closedOrders = append(closedOrders, o)
557+
} else {
553558
bidOrders = append(bidOrders, o)
554559
break
555560
}
556561

557-
o.Type = types.OrderTypeMarket
558-
o.ExecutedQuantity = o.Quantity
559-
o.Price = price
560-
o.Status = types.OrderStatusFilled
561-
closedOrders = append(closedOrders, o)
562-
563562
case types.OrderTypeStopLimit:
564563
// price goes down and if the stop price is still lower than the current price
565564
// or the stop price is not touched
566565
// then we should skip this order
567-
if price.Compare(o.StopPrice) > 0 {
568-
bidOrders = append(bidOrders, o)
569-
break
570-
}
571-
572-
o.Type = types.OrderTypeLimit
573-
574-
// handle TAKER order
575-
if o.Price.Compare(price) >= 0 {
576-
o.AveragePrice = price
577-
o.ExecutedQuantity = o.Quantity
578-
o.Status = types.OrderStatusFilled
579-
closedOrders = append(closedOrders, o)
566+
if o.StopPrice.Compare(m.lastPrice) < 0 && o.StopPrice.Compare(price) >= 0 {
567+
o.Type = types.OrderTypeLimit
568+
569+
// handle TAKER order
570+
if o.Price.Compare(price) >= 0 {
571+
o.AveragePrice = price
572+
o.ExecutedQuantity = o.Quantity
573+
o.Status = types.OrderStatusFilled
574+
closedOrders = append(closedOrders, o)
575+
} else {
576+
bidOrders = append(bidOrders, o)
577+
}
580578
} else {
581579
bidOrders = append(bidOrders, o)
580+
break
582581
}
583582

584583
case types.OrderTypeLimit, types.OrderTypeLimitMaker:

0 commit comments

Comments
 (0)