qbtrade/pkg/backtest/priceorder.go

78 lines
2.1 KiB
Go
Raw Normal View History

2024-06-27 14:42:38 +00:00
package backtest
import (
"sort"
"git.qtrade.icu/lychiyu/qbtrade/pkg/fixedpoint"
"git.qtrade.icu/lychiyu/qbtrade/pkg/types"
)
type PriceOrder struct {
Price fixedpoint.Value
Order types.Order
}
type PriceOrderSlice []PriceOrder
func (slice PriceOrderSlice) Len() int { return len(slice) }
func (slice PriceOrderSlice) Less(i, j int) bool { return slice[i].Price.Compare(slice[j].Price) < 0 }
func (slice PriceOrderSlice) Swap(i, j int) { slice[i], slice[j] = slice[j], slice[i] }
func (slice PriceOrderSlice) InsertAt(idx int, po PriceOrder) PriceOrderSlice {
rear := append([]PriceOrder{}, slice[idx:]...)
newSlice := append(slice[:idx], po)
return append(newSlice, rear...)
}
func (slice PriceOrderSlice) Remove(price fixedpoint.Value, descending bool) PriceOrderSlice {
matched, idx := slice.Find(price, descending)
if matched.Price != price {
return slice
}
return append(slice[:idx], slice[idx+1:]...)
}
func (slice PriceOrderSlice) First() (PriceOrder, bool) {
if len(slice) > 0 {
return slice[0], true
}
return PriceOrder{}, false
}
// FindPriceVolumePair finds the pair by the given price, this function is a read-only
// operation, so we use the value receiver to avoid copy value from the pointer
// If the price is not found, it will return the index where the price can be inserted at.
// true for descending (bid orders), false for ascending (ask orders)
func (slice PriceOrderSlice) Find(price fixedpoint.Value, descending bool) (pv PriceOrder, idx int) {
idx = sort.Search(len(slice), func(i int) bool {
if descending {
return slice[i].Price.Compare(price) <= 0
}
return slice[i].Price.Compare(price) >= 0
})
if idx >= len(slice) || slice[idx].Price != price {
return pv, idx
}
pv = slice[idx]
return pv, idx
}
func (slice PriceOrderSlice) Upsert(po PriceOrder, descending bool) PriceOrderSlice {
if len(slice) == 0 {
return append(slice, po)
}
price := po.Price
_, idx := slice.Find(price, descending)
if idx >= len(slice) || slice[idx].Price != price {
return slice.InsertAt(idx, po)
}
slice[idx].Order = po.Order
return slice
}