1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-07 07:56:12 +00:00

Added CalculateTradableAmount to SymbolOrderBook

This commit is contained in:
JKorf 2023-03-18 10:01:38 +01:00
parent 1c33e297e7
commit da6ed580f1
3 changed files with 69 additions and 3 deletions

View File

@ -108,5 +108,33 @@ namespace CryptoExchange.Net.UnitTests
Assert.AreEqual(1.06666667m, resultBids2.Data);
Assert.AreEqual(1.23333333m, resultAsks2.Data);
}
[TestCase]
public void CalculateTradableAmount()
{
var orderbook = new TestableSymbolOrderBook();
orderbook.SetData(new List<ISymbolOrderBookEntry>
{
new BookEntry{ Price = 1, Quantity = 1 },
new BookEntry{ Price = 1.1m, Quantity = 1 },
},
new List<ISymbolOrderBookEntry>()
{
new BookEntry{ Price = 1.2m, Quantity = 1 },
new BookEntry{ Price = 1.3m, Quantity = 1 },
});
var resultBids = orderbook.CalculateTradableAmount(2, OrderBookEntryType.Bid);
var resultAsks = orderbook.CalculateTradableAmount(2, OrderBookEntryType.Ask);
var resultBids2 = orderbook.CalculateTradableAmount(1.5m, OrderBookEntryType.Bid);
var resultAsks2 = orderbook.CalculateTradableAmount(1.5m, OrderBookEntryType.Ask);
Assert.True(resultBids.Success);
Assert.True(resultAsks.Success);
Assert.AreEqual(1.9m, resultBids.Data);
Assert.AreEqual(1.61538462m, resultAsks.Data);
Assert.AreEqual(1.4m, resultBids2.Data);
Assert.AreEqual(1.23076923m, resultAsks2.Data);
}
}
}

View File

@ -101,13 +101,22 @@ namespace CryptoExchange.Net.Interfaces
/// <summary>
/// Get the average price that a market order would fill at at the current order book state. This is no guarentee that an order of that quantity would actually be filled
/// at that price since between this calculation and the order placement the book can have changed.
/// at that price since between this calculation and the order placement the book might have changed.
/// </summary>
/// <param name="quantity">The quantity in base asset to fill</param>
/// <param name="type">The type</param>
/// <returns>Average fill price</returns>
CallResult<decimal> CalculateAverageFillPrice(decimal quantity, OrderBookEntryType type);
/// <summary>
/// Get the amount of base asset which can be traded with the quote quantity when placing a market order at at the current order book state.
/// This is no guarentee that an order of that quantity would actually be fill the quantity returned by this since between this calculation and the order placement the book might have changed.
/// </summary>
/// <param name="quoteQuantity">The quantity in quote asset looking to trade</param>
/// <param name="type">The type</param>
/// <returns>Amount of base asset tradable with the specified amount of quote asset</returns>
CallResult<decimal> CalculateTradableAmount(decimal quoteQuantity, OrderBookEntryType type);
/// <summary>
/// String representation of the top x entries
/// </summary>

View File

@ -304,14 +304,14 @@ namespace CryptoExchange.Net.OrderBook
}
/// <inheritdoc/>
public CallResult<decimal> CalculateAverageFillPrice(decimal quantity, OrderBookEntryType type)
public CallResult<decimal> CalculateAverageFillPrice(decimal baseQuantity, OrderBookEntryType type)
{
if (Status != OrderBookStatus.Synced)
return new CallResult<decimal>(new InvalidOperationError($"{nameof(CalculateAverageFillPrice)} is not available when book is not in Synced state"));
var totalCost = 0m;
var totalAmount = 0m;
var amountLeft = quantity;
var amountLeft = baseQuantity;
lock (_bookLock)
{
var list = type == OrderBookEntryType.Ask ? asks : bids;
@ -334,6 +334,35 @@ namespace CryptoExchange.Net.OrderBook
return new CallResult<decimal>(Math.Round(totalCost / totalAmount, 8));
}
/// <inheritdoc/>
public CallResult<decimal> CalculateTradableAmount(decimal quoteQuantity, OrderBookEntryType type)
{
if (Status != OrderBookStatus.Synced)
return new CallResult<decimal>(new InvalidOperationError($"{nameof(CalculateTradableAmount)} is not available when book is not in Synced state"));
var quoteQuantityLeft = quoteQuantity;
var totalBaseQuantity = 0m;
lock (_bookLock)
{
var list = type == OrderBookEntryType.Ask ? asks : bids;
var step = 0;
while (quoteQuantityLeft > 0)
{
if (step == list.Count)
return new CallResult<decimal>(new InvalidOperationError("Quantity is larger than order in the order book"));
var element = list.ElementAt(step);
var stepAmount = Math.Min(element.Value.Quantity * element.Value.Price, quoteQuantityLeft);
quoteQuantityLeft -= stepAmount;
totalBaseQuantity += stepAmount / element.Value.Price;
step++;
}
}
return new CallResult<decimal>(Math.Round(totalBaseQuantity, 8));
}
/// <summary>
/// Implementation for starting the order book. Should typically have logic for subscribing to the update stream and retrieving
/// and setting the initial order book