xmaker: pull out getLayerPrice and add test against the method
This commit is contained in:
parent
0e4f7b366a
commit
4d3af3a6bc
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user