xmaker: pull out getLayerPrice and add test against the method

This commit is contained in:
c9s 2024-09-09 14:41:41 +08:00 committed by lychiyu
parent 0e4f7b366a
commit 4d3af3a6bc
2 changed files with 127 additions and 31 deletions

View File

@ -444,6 +444,53 @@ func (s *Strategy) getInitialLayerQuantity(i int) (fixedpoint.Value, error) {
return q, nil return q, nil
} }
func (s *Strategy) getLayerPrice(
i int,
side types.SideType,
sourceBook *types.StreamOrderBook,
quote *Quote,
requiredDepth fixedpoint.Value,
) (price fixedpoint.Value) {
var margin, delta, pips fixedpoint.Value
switch side {
case types.SideTypeSell:
margin = quote.AskMargin
delta = margin
if quote.AskLayerPips.Sign() > 0 {
pips = quote.AskLayerPips
} else {
pips = fixedpoint.One
}
case types.SideTypeBuy:
margin = quote.BidMargin
delta = margin.Neg()
if quote.BidLayerPips.Sign() > 0 {
pips = quote.BidLayerPips.Neg()
} else {
pips = fixedpoint.One.Neg()
}
}
if s.UseDepthPrice {
price = aggregatePrice(sourceBook.SideBook(side), requiredDepth)
price = price.Mul(fixedpoint.One.Add(delta))
if i > 0 {
price = price.Add(pips.Mul(s.makerMarket.TickSize))
}
} else {
price = price.Mul(fixedpoint.One.Add(delta))
if i > 0 {
price = price.Add(pips.Mul(s.makerMarket.TickSize))
}
}
return price
}
func (s *Strategy) updateQuote(ctx context.Context) error { func (s *Strategy) updateQuote(ctx context.Context) error {
if err := s.activeMakerOrders.GracefulCancel(ctx, s.makerSession.Exchange); err != nil { if err := s.activeMakerOrders.GracefulCancel(ctx, s.makerSession.Exchange); err != nil {
s.logger.Warnf("there are some %s orders not canceled, skipping placing maker orders", s.Symbol) s.logger.Warnf("there are some %s orders not canceled, skipping placing maker orders", s.Symbol)
@ -710,7 +757,6 @@ func (s *Strategy) updateQuote(ctx context.Context) error {
var submitOrders []types.SubmitOrder var submitOrders []types.SubmitOrder
var accumulativeBidQuantity, accumulativeAskQuantity fixedpoint.Value var accumulativeBidQuantity, accumulativeAskQuantity fixedpoint.Value
var askQuantity = s.Quantity
var quote = &Quote{ var quote = &Quote{
BestBidPrice: bestBidPrice, BestBidPrice: bestBidPrice,
@ -798,26 +844,17 @@ func (s *Strategy) updateQuote(ctx context.Context) error {
hedgeQuota.Rollback() hedgeQuota.Rollback()
} }
if s.QuantityMultiplier.Sign() > 0 {
bidQuantity = bidQuantity.Mul(s.QuantityMultiplier)
}
} }
} }
for i := 0; i < s.NumLayers; i++ {
// for maker ask orders // for maker ask orders
if !disableMakerAsk { if !disableMakerAsk {
if s.QuantityScale != nil { for i := 0; i < s.NumLayers; i++ {
qf, err := s.QuantityScale.Scale(i + 1) askQuantity, err := s.getInitialLayerQuantity(i)
if err != nil { if err != nil {
return fmt.Errorf("quantityScale error: %w", err) return err
} }
log.Infof("%s scaling ask #%d quantity to %f", s.Symbol, i+1, qf)
// override the default bid quantity
askQuantity = fixedpoint.NewFromFloat(qf)
}
accumulativeAskQuantity = accumulativeAskQuantity.Add(askQuantity) accumulativeAskQuantity = accumulativeAskQuantity.Add(askQuantity)
if s.UseDepthPrice { if s.UseDepthPrice {

View File

@ -2,28 +2,87 @@ package xmaker
import ( import (
"testing" "testing"
"time"
"git.qtrade.icu/lychiyu/bbgo/pkg/fixedpoint" "git.qtrade.icu/lychiyu/bbgo/pkg/fixedpoint"
. "git.qtrade.icu/lychiyu/bbgo/pkg/testing/testhelper"
"git.qtrade.icu/lychiyu/bbgo/pkg/types" "git.qtrade.icu/lychiyu/bbgo/pkg/types"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func Test_aggregatePrice(t *testing.T) { func TestStrategy_getLayerPrice(t *testing.T) {
bids := types.PriceVolumeSlice{ symbol := "BTCUSDT"
{ market := Market(symbol)
Price: fixedpoint.NewFromFloat(1000.0),
Volume: fixedpoint.NewFromFloat(1.0), s := &Strategy{
}, UseDepthPrice: true,
{ DepthQuantity: Number(3.0),
Price: fixedpoint.NewFromFloat(1200.0), makerMarket: market,
Volume: fixedpoint.NewFromFloat(1.0),
},
{
Price: fixedpoint.NewFromFloat(1400.0),
Volume: fixedpoint.NewFromFloat(1.0),
},
} }
sourceBook := types.NewStreamBook(symbol, types.ExchangeBinance)
sourceBook.Load(types.SliceOrderBook{
Symbol: symbol,
Bids: PriceVolumeSlice(
Number(1300.0), Number(1.0),
Number(1200.0), Number(2.0),
Number(1100.0), Number(3.0),
),
Asks: PriceVolumeSlice(
Number(1301.0), Number(1.0),
Number(1400.0), Number(2.0),
Number(1500.0), Number(3.0),
),
Time: time.Time{},
LastUpdateId: 1,
})
quote := &Quote{
BestBidPrice: Number(1300.0),
BestAskPrice: Number(1301.0),
BidMargin: Number(0.001),
AskMargin: Number(0.001),
BidLayerPips: Number(100.0),
AskLayerPips: Number(100.0),
}
t.Run("depthPrice bid price at 0", func(t *testing.T) {
price := s.getLayerPrice(0, types.SideTypeBuy, sourceBook, quote, s.DepthQuantity)
// (1300 + 1200*2)/3 * (1 - 0.001)
assert.InDelta(t, 1232.10, price.Float64(), 0.01)
})
t.Run("depthPrice bid price at 1", func(t *testing.T) {
price := s.getLayerPrice(1, types.SideTypeBuy, sourceBook, quote, s.DepthQuantity)
// (1300 + 1200*2)/3 * (1 - 0.001) - 100 * 0.01
assert.InDelta(t, 1231.10, price.Float64(), 0.01)
})
t.Run("depthPrice ask price at 0", func(t *testing.T) {
price := s.getLayerPrice(0, types.SideTypeSell, sourceBook, quote, s.DepthQuantity)
// (1301 + 1400*2)/3 * (1 + 0.001)
assert.InDelta(t, 1368.367, price.Float64(), 0.01)
})
t.Run("depthPrice ask price at 1", func(t *testing.T) {
price := s.getLayerPrice(1, types.SideTypeSell, sourceBook, quote, s.DepthQuantity)
// (1301 + 1400*2)/3 * (1 + 0.001) + 100 * 0.01
assert.InDelta(t, 1369.367, price.Float64(), 0.01)
})
}
func Test_aggregatePrice(t *testing.T) {
bids := PriceVolumeSliceFromText(`
1000.0, 1.0
1200.0, 1.0
1400.0, 1.0
`)
aggregatedPrice1 := aggregatePrice(bids, fixedpoint.NewFromFloat(0.5)) aggregatedPrice1 := aggregatePrice(bids, fixedpoint.NewFromFloat(0.5))
assert.Equal(t, fixedpoint.NewFromFloat(1000.0), aggregatedPrice1) assert.Equal(t, fixedpoint.NewFromFloat(1000.0), aggregatedPrice1)