diff --git a/pkg/strategy/xdepthmaker/strategy_test.go b/pkg/strategy/xdepthmaker/strategy_test.go index 6eb247a2b3..9880d75c4a 100644 --- a/pkg/strategy/xdepthmaker/strategy_test.go +++ b/pkg/strategy/xdepthmaker/strategy_test.go @@ -75,3 +75,49 @@ func TestStrategy_generateMakerOrders(t *testing.T) { {Side: types.SideTypeSell, Price: Number("25300"), Quantity: Number("0.275845")}, }, orders) } + +func TestPriceVolumeSlice_AverageDepthPrice(t *testing.T) { + book := types.NewSliceOrderBook("BTCUSDT") + book.Update(types.SliceOrderBook{ + Symbol: "BTCUSDT", + Asks: PriceVolumeSliceFromText(` + 59400,0.5123 + 59402,0.0244 + 59405,0.0413 + 59450,0.02821 + 60000,3 + `), + Bids: PriceVolumeSliceFromText(` + 59399,0.3441 // = 20,439.1959 + 59398,0.221 // = 13,126.958 + 59395,0.000123 // = 7.305585 + 59390,0.03312 // = 1,966.9968 + 59000,3 // = 177,000 + // sum = 212,540.456285 + `), + Time: time.Now(), + LastUpdateId: 0, + }) + + t.Run("test average price by base quantity", func(t *testing.T) { + // Test buying 2 BTC + buyPrice := book.Asks.AverageDepthPrice(fixedpoint.NewFromFloat(2)) + assert.InDelta(t, 59818.9699, 0.001, buyPrice.Float64()) + + // Test selling 2 BTC + sellPrice := book.Bids.AverageDepthPrice(fixedpoint.NewFromFloat(2)) + assert.InDelta(t, 59119.1096, 0.001, sellPrice.Float64()) + }) + + t.Run("test average price by quote quantity", func(t *testing.T) { + // Test buying with ~119637.9398 quote + buyPrice := book.Asks.AverageDepthPriceByQuote(fixedpoint.NewFromFloat(119637.9398), 0) + assert.InDelta(t, 59899.6009, buyPrice.Float64(), 0.001) + + // Test selling with ~118238.219281 quote + sellPrice := book.Bids.AverageDepthPriceByQuote(fixedpoint.NewFromFloat(118238.219281), 0) + assert.InDelta(t, 59066.2024, sellPrice.Float64(), 0.001) + + assert.Less(t, sellPrice.Float64(), buyPrice.Float64(), "the sell price should be lower than the buy price") + }) +} diff --git a/pkg/testing/testhelper/pricevolumeslice.go b/pkg/testing/testhelper/pricevolumeslice.go index ea78380637..31087301fe 100644 --- a/pkg/testing/testhelper/pricevolumeslice.go +++ b/pkg/testing/testhelper/pricevolumeslice.go @@ -12,6 +12,13 @@ func PriceVolumeSliceFromText(str string) (slice types.PriceVolumeSlice) { lines := strings.Split(str, "\n") for _, line := range lines { line = strings.TrimSpace(line) + + // strip comments + commentIdx := strings.Index(line, "//") + if commentIdx >= 0 { + line = line[:commentIdx] + } + if len(line) == 0 { continue } diff --git a/pkg/types/price_volume_slice.go b/pkg/types/price_volume_slice.go index 092c652a5d..47ebcebacc 100644 --- a/pkg/types/price_volume_slice.go +++ b/pkg/types/price_volume_slice.go @@ -265,13 +265,16 @@ func (slice PriceVolumeSlice) AverageDepthPriceByQuote(requiredDepthInQuote fixe totalQuantity := fixedpoint.Zero l := len(slice) - if maxLevel > 0 && l > maxLevel { - l = maxLevel + if maxLevel > 0 { + l = min(l, maxLevel) } for i := 0; i < l; i++ { pv := slice[i] - quoteAmount := fixedpoint.Mul(pv.Volume, pv.Price) + + // quoteAmount is the total quote amount of the current price level + quoteAmount := pv.Volume.Mul(pv.Price) + totalQuoteAmount = totalQuoteAmount.Add(quoteAmount) totalQuantity = totalQuantity.Add(pv.Volume) @@ -321,11 +324,12 @@ func (slice PriceVolumeSlice) AverageDepthPrice(requiredQuantity fixedpoint.Valu pv := slice[i] if pv.Volume.Compare(rq) >= 0 { totalAmount = totalAmount.Add(rq.Mul(pv.Price)) + rq = fixedpoint.Zero break } - rq = rq.Sub(pv.Volume) totalAmount = totalAmount.Add(pv.Volume.Mul(pv.Price)) + rq = rq.Sub(pv.Volume) } return totalAmount.Div(requiredQuantity.Sub(rq))