Skip to content

Methods AverageDepthPrice and AverageDepthPriceByQuote #1861

@DaniilSokolyuk

Description

@DaniilSokolyuk

What do AverageDepthPrice and AverageDepthPriceByQuote methods actually do? I don't really understand I wrote a simple test and expect quite predictable results.

func Test_OrderBookPriceCalculation(t *testing.T) {
	book := NewSliceOrderBook("BTC")

	book.Update(SliceOrderBook{
		Symbol: "BTC",
		  Asks: PriceVolumeSlice{
			  {Price: fixedpoint.NewFromFloat(60000), Volume: fixedpoint.NewFromFloat(3)},
			  {Price: fixedpoint.NewFromFloat(59450), Volume: fixedpoint.NewFromFloat(0.02821)},
			  {Price: fixedpoint.NewFromFloat(59405), Volume: fixedpoint.NewFromFloat(0.0413)},
			  {Price: fixedpoint.NewFromFloat(59402), Volume: fixedpoint.NewFromFloat(0.0244)},
			  {Price: fixedpoint.NewFromFloat(59400), Volume: fixedpoint.NewFromFloat(0.5123)},
		  },
		Bids: PriceVolumeSlice{
			{Price: fixedpoint.NewFromFloat(59399), Volume: fixedpoint.NewFromFloat(0.3441)},
			{Price: fixedpoint.NewFromFloat(59398), Volume: fixedpoint.NewFromFloat(0.221)},
			{Price: fixedpoint.NewFromFloat(59395), Volume: fixedpoint.NewFromFloat(0.000123)},
			{Price: fixedpoint.NewFromFloat(59390), Volume: fixedpoint.NewFromFloat(0.03312)},
			{Price: fixedpoint.NewFromFloat(59000), Volume: fixedpoint.NewFromFloat(3)},
		},
		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.Equal(t, "59818.9699", buyPrice.String()) // 197353.9529206 ?

		// Test selling 2 BTC
		sellPrice := book.Bids.AverageDepthPrice(fixedpoint.NewFromFloat(2))
		assert.Equal(t, "59119.10964055", sellPrice.String()) //197609.43348078 ?
	})

	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.Equal(t, "59818.9699", buyPrice.String()) //59899.60091065 ?

		// Test selling with ~118238.219281 quote
		sellPrice := book.Bids.AverageDepthPriceByQuote(fixedpoint.NewFromFloat(118238.219281), 0)
		assert.Equal(t, "59119.10993609", sellPrice.String()) // 59899.60091065?
	})
}

i tried fixing these methods, could you please check

func (slice PriceVolumeSlice) AverageDepthPrice(requiredQuantity fixedpoint.Value) fixedpoint.Value {
	if len(slice) == 0 {
		return fixedpoint.Zero
	}

	// Return first price if it can fulfill entire quantity
	if slice[0].Volume.Compare(requiredQuantity) >= 0 {
		return slice[0].Price
	}

	totalAmount := fixedpoint.Zero
	totalVolume := fixedpoint.Zero

	// Calculate weighted average price
	for _, pv := range slice {
		volume := fixedpoint.Min(pv.Volume, requiredQuantity)
		totalVolume = totalVolume.Add(volume)
		totalAmount = totalAmount.Add(pv.Price.Mul(volume))

		requiredQuantity = requiredQuantity.Sub(volume)
		if requiredQuantity.IsZero() {
			break
		}
	}

	return totalAmount.Div(totalVolume)
}

func (slice PriceVolumeSlice) AverageDepthPriceByQuote(requiredDepthInQuote fixedpoint.Value, maxLevel int) fixedpoint.Value {
	if len(slice) == 0 {
		return fixedpoint.Zero
	}

	remainingQuote := requiredDepthInQuote
	totalQuoteAmount := fixedpoint.Zero
	totalQuantity := fixedpoint.Zero

	l := len(slice)
	if maxLevel > 0 && l > maxLevel {
		l = maxLevel
	}

	for i := 0; i < len(slice) && (maxLevel == 0 || i < maxLevel); i++ {
		pv := slice[i]
		quoteVolume := pv.Price.Mul(pv.Volume)

		if remainingQuote.Compare(quoteVolume) >= 0 {
			totalQuantity = totalQuantity.Add(pv.Volume)
			totalQuoteAmount = totalQuoteAmount.Add(quoteVolume)
			remainingQuote = remainingQuote.Sub(quoteVolume)
		} else {
			baseAmount := remainingQuote.Div(pv.Price)
			totalQuantity = totalQuantity.Add(baseAmount)
			totalQuoteAmount = totalQuoteAmount.Add(remainingQuote)
			remainingQuote = fixedpoint.Zero
			break
		}
	}

	if totalQuantity.IsZero() {
		return fixedpoint.Zero
	}

	return totalQuoteAmount.Div(totalQuantity)
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions