xdepthmaker: support partial maker order replenish

This commit is contained in:
c9s 2023-11-30 17:10:09 +08:00
parent f21170aa5d
commit 888a550c80
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
5 changed files with 82 additions and 10 deletions

View File

@ -2,6 +2,7 @@ package xdepthmaker
import (
"context"
stderrors "errors"
"fmt"
"sync"
"time"
@ -381,8 +382,10 @@ func (s *Strategy) CrossRun(
switch sig.Type {
case types.BookSignalSnapshot:
case types.BookSignalUpdate:
s.updateQuote(ctx, 0)
case types.BookSignalUpdate:
s.updateQuote(ctx, 5)
}
case <-posTicker.C:
@ -581,7 +584,7 @@ func (s *Strategy) runTradeRecover(ctx context.Context) {
}
}
func (s *Strategy) generateMakerOrders(pricingBook *types.StreamOrderBook) ([]types.SubmitOrder, error) {
func (s *Strategy) generateMakerOrders(pricingBook *types.StreamOrderBook, maxLayer int) ([]types.SubmitOrder, error) {
bestBid, bestAsk, hasPrice := pricingBook.BestBidAndAsk()
if !hasPrice {
return nil, nil
@ -600,8 +603,12 @@ func (s *Strategy) generateMakerOrders(pricingBook *types.StreamOrderBook) ([]ty
dupPricingBook := pricingBook.CopyDepth(0)
if maxLayer == 0 || maxLayer > s.NumLayers {
maxLayer = s.NumLayers
}
for _, side := range []types.SideType{types.SideTypeBuy, types.SideTypeSell} {
for i := 1; i <= s.NumLayers; i++ {
for i := 1; i <= maxLayer; i++ {
requiredDepthFloat, err := s.DepthScale.Scale(i)
if err != nil {
return nil, errors.Wrapf(err, "depthScale scale error")
@ -679,12 +686,32 @@ func (s *Strategy) generateMakerOrders(pricingBook *types.StreamOrderBook) ([]ty
return submitOrders, nil
}
func (s *Strategy) updateQuote(ctx context.Context) {
func (s *Strategy) partiallyCancelOrders(ctx context.Context, maxLayer int) error {
buyOrders, sellOrders := s.MakerOrderExecutor.ActiveMakerOrders().Orders().SeparateBySide()
buyOrders = types.SortOrdersByPrice(buyOrders, true)
sellOrders = types.SortOrdersByPrice(sellOrders, false)
buyOrdersToCancel := buyOrders[0:min(maxLayer, len(buyOrders))]
sellOrdersToCancel := sellOrders[0:min(maxLayer, len(sellOrders))]
err1 := s.MakerOrderExecutor.GracefulCancel(ctx, buyOrdersToCancel...)
err2 := s.MakerOrderExecutor.GracefulCancel(ctx, sellOrdersToCancel...)
return stderrors.Join(err1, err2)
}
func (s *Strategy) updateQuote(ctx context.Context, maxLayer int) {
if maxLayer == 0 {
if err := s.MakerOrderExecutor.GracefulCancel(ctx); err != nil {
log.Warnf("there are some %s orders not canceled, skipping placing maker orders", s.Symbol)
log.WithError(err).Warnf("there are some %s orders not canceled, skipping placing maker orders", s.Symbol)
s.MakerOrderExecutor.ActiveMakerOrders().Print()
return
}
} else {
if err := s.partiallyCancelOrders(ctx, maxLayer); err != nil {
log.WithError(err).Warnf("%s partial order cancel failed", s.Symbol)
return
}
}
numOfMakerOrders := s.MakerOrderExecutor.ActiveMakerOrders().NumOfOrders()
if numOfMakerOrders > 0 {
@ -719,7 +746,7 @@ func (s *Strategy) updateQuote(ctx context.Context) {
return
}
submitOrders, err := s.generateMakerOrders(s.pricingBook)
submitOrders, err := s.generateMakerOrders(s.pricingBook, maxLayer)
if err != nil {
log.WithError(err).Errorf("generate order error")
return
@ -771,3 +798,11 @@ func averageDepthPrice(pvs types.PriceVolumeSlice) (price fixedpoint.Value, err
price = totalQuoteAmount.Div(totalQuantity)
return price, nil
}
func min(a, b int) int {
if a < b {
return a
}
return b
}

View File

@ -59,7 +59,7 @@ func TestStrategy_generateMakerOrders(t *testing.T) {
Time: time.Now(),
})
orders, err := s.generateMakerOrders(pricingBook)
orders, err := s.generateMakerOrders(pricingBook, 0)
assert.NoError(t, err)
AssertOrdersPriceSideQuantity(t, []PriceSideQuantityAssert{
{Side: types.SideTypeBuy, Price: Number("25000"), Quantity: Number("0.04")}, // =~ $1000.00

View File

@ -243,3 +243,16 @@ func (m *SyncOrderMap) Orders() (slice OrderSlice) {
}
type OrderSlice []Order
func (s OrderSlice) SeparateBySide() (buyOrders, sellOrders []Order) {
for _, o := range s {
switch o.Side {
case SideTypeBuy:
buyOrders = append(buyOrders, o)
case SideTypeSell:
sellOrders = append(sellOrders, o)
}
}
return buyOrders, sellOrders
}

View File

@ -18,6 +18,10 @@ func NewPriceHeartBeat(timeout time.Duration) *PriceHeartBeat {
}
}
func (b *PriceHeartBeat) Last() PriceVolume {
return b.last
}
// Update updates the price volume object and the last update time
// It returns (bool, error), when the price is successfully updated, it returns true.
// If the price is not updated (same price) and the last time exceeded the timeout,

View File

@ -82,6 +82,26 @@ func (slice PriceVolumeSlice) IndexByQuoteVolumeDepth(requiredQuoteVolume fixedp
return -1
}
func (slice PriceVolumeSlice) SumDepth() fixedpoint.Value {
var total = fixedpoint.Zero
for _, pv := range slice {
total = total.Add(pv.Volume)
}
return total
}
func (slice PriceVolumeSlice) SumDepthInQuote() fixedpoint.Value {
var total = fixedpoint.Zero
for _, pv := range slice {
quoteVolume := fixedpoint.Mul(pv.Price, pv.Volume)
total = total.Add(quoteVolume)
}
return total
}
func (slice PriceVolumeSlice) IndexByVolumeDepth(requiredVolume fixedpoint.Value) int {
var tv = fixedpoint.Zero
for x, el := range slice {