xmaker: pull out getLayerPrice and add test against the method

This commit is contained in:
c9s 2024-09-09 14:41:41 +08:00
parent 960ea89d8c
commit 77dfe213e5
No known key found for this signature in database
GPG Key ID: 7385E7E464CB0A54
2 changed files with 130 additions and 32 deletions

View File

@ -444,6 +444,53 @@ func (s *Strategy) getInitialLayerQuantity(i int) (fixedpoint.Value, error) {
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 {
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)
@ -710,7 +757,6 @@ func (s *Strategy) updateQuote(ctx context.Context) error {
var submitOrders []types.SubmitOrder
var accumulativeBidQuantity, accumulativeAskQuantity fixedpoint.Value
var askQuantity = s.Quantity
var quote = &Quote{
BestBidPrice: bestBidPrice,
@ -798,26 +844,17 @@ func (s *Strategy) updateQuote(ctx context.Context) error {
hedgeQuota.Rollback()
}
if s.QuantityMultiplier.Sign() > 0 {
bidQuantity = bidQuantity.Mul(s.QuantityMultiplier)
}
}
}
for i := 0; i < s.NumLayers; i++ {
// for maker ask orders
if !disableMakerAsk {
if s.QuantityScale != nil {
qf, err := s.QuantityScale.Scale(i + 1)
if err != nil {
return fmt.Errorf("quantityScale error: %w", err)
}
log.Infof("%s scaling ask #%d quantity to %f", s.Symbol, i+1, qf)
// override the default bid quantity
askQuantity = fixedpoint.NewFromFloat(qf)
// for maker ask orders
if !disableMakerAsk {
for i := 0; i < s.NumLayers; i++ {
askQuantity, err := s.getInitialLayerQuantity(i)
if err != nil {
return err
}
accumulativeAskQuantity = accumulativeAskQuantity.Add(askQuantity)
if s.UseDepthPrice {

View File

@ -2,28 +2,89 @@ package xmaker
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/c9s/bbgo/pkg/fixedpoint"
"github.com/c9s/bbgo/pkg/types"
"github.com/stretchr/testify/assert"
. "github.com/c9s/bbgo/pkg/testing/testhelper"
)
func Test_aggregatePrice(t *testing.T) {
bids := types.PriceVolumeSlice{
{
Price: fixedpoint.NewFromFloat(1000.0),
Volume: fixedpoint.NewFromFloat(1.0),
},
{
Price: fixedpoint.NewFromFloat(1200.0),
Volume: fixedpoint.NewFromFloat(1.0),
},
{
Price: fixedpoint.NewFromFloat(1400.0),
Volume: fixedpoint.NewFromFloat(1.0),
},
func TestStrategy_getLayerPrice(t *testing.T) {
symbol := "BTCUSDT"
market := Market(symbol)
s := &Strategy{
UseDepthPrice: true,
DepthQuantity: Number(3.0),
makerMarket: market,
}
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))
assert.Equal(t, fixedpoint.NewFromFloat(1000.0), aggregatedPrice1)