1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-08-11 16:32:57 +00:00

Updated SharedTrade to use SharedOrderQuantity for quantities

This commit is contained in:
Jkorf
2026-07-28 11:47:59 +02:00
parent 20bddd5c37
commit 4803ed91cd
4 changed files with 74 additions and 10 deletions
@@ -12,7 +12,12 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// Quantity of the trade /// Quantity of the trade
/// </summary> /// </summary>
public decimal Quantity { get; set; } [Obsolete("Use `Quantities` instead")]
public decimal Quantity => Quantities.QuantityInBaseAsset ?? Quantities.QuantityInContracts ?? 0;
/// <summary>
/// The quantities of the trade
/// </summary>
public SharedOrderQuantity Quantities { get; set; }
/// <summary> /// <summary>
/// Price of the trade /// Price of the trade
/// </summary> /// </summary>
@@ -29,9 +34,9 @@ namespace CryptoExchange.Net.SharedApis
/// <summary> /// <summary>
/// ctor /// ctor
/// </summary> /// </summary>
public SharedTrade(SharedSymbol? sharedSymbol, string symbol, decimal quantity, decimal price, DateTime timestamp) : base(sharedSymbol, symbol) public SharedTrade(SharedSymbol? sharedSymbol, string symbol, SharedOrderQuantity quantities, decimal price, DateTime timestamp) : base(sharedSymbol, symbol)
{ {
Quantity = quantity; Quantities = quantities;
Price = price; Price = price;
Timestamp = timestamp; Timestamp = timestamp;
} }
@@ -160,6 +160,22 @@ namespace CryptoExchange.Net.SharedApis
{ {
} }
/// <summary>
/// Get the quantity in quote asset. Will use the set `QuantityInQuoteAsset` property if it has a value, or `QuantityInBaseAsset` * `price` if not. Null otherwise.
/// </summary>
/// <param name="price">The price to use for the QuantityInBaseAsset to quote asset quantity calculation</param>
/// <returns>Quantity in quote asset if it's available or can be calculated, null otherwise</returns>
public decimal? GetQuantityInQuoteAsset(decimal? price)
{
if (QuantityInQuoteAsset != null)
return QuantityInQuoteAsset;
if (QuantityInBaseAsset != null && price != null)
return QuantityInBaseAsset * price;
return null;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() => base.ToString(); public override string ToString() => base.ToString();
} }
@@ -284,8 +284,10 @@ namespace CryptoExchange.Net.Trackers.Klines
LastOpenTime = klines.Last().OpenTime, LastOpenTime = klines.Last().OpenTime,
HighPrice = klines.Select(d => d.LowPrice).Max(), HighPrice = klines.Select(d => d.LowPrice).Max(),
LowPrice = klines.Select(d => d.HighPrice).Min(), LowPrice = klines.Select(d => d.HighPrice).Min(),
#pragma warning disable CS0618 // Type or member is obsolete | Temporary to maintain previous behavior
Volume = klines.Select(d => d.Volume).Sum(), Volume = klines.Select(d => d.Volume).Sum(),
AverageVolume = Math.Round(klines.OrderByDescending(d => d.OpenTime).Skip(1).Select(d => d.Volume).DefaultIfEmpty().Average(), 8) AverageVolume = Math.Round(klines.OrderByDescending(d => d.OpenTime).Skip(1).Select(d => d.Volume).DefaultIfEmpty().Average(), 8)
#pragma warning restore
}; };
} }
@@ -138,6 +138,11 @@ namespace CryptoExchange.Net.Trackers.Trades
} }
} }
/// <summary>
/// The type of quantity the trades and stats are denoted in
/// </summary>
public TradeQuantityType QuantityType { get; }
/// <inheritdoc /> /// <inheritdoc />
public event Func<SharedTrade, Task>? OnAdded; public event Func<SharedTrade, Task>? OnAdded;
/// <inheritdoc /> /// <inheritdoc />
@@ -156,12 +161,14 @@ namespace CryptoExchange.Net.Trackers.Trades
SharedSymbol symbol, SharedSymbol symbol,
int? limit = null, int? limit = null,
TimeSpan? period = null, TimeSpan? period = null,
TradeQuantityType tradeQuantityType = TradeQuantityType.BaseAsset,
ExchangeParameters? exchangeParameters = null) ExchangeParameters? exchangeParameters = null)
{ {
_logger = logger ?? new NullLogger<TradeTracker>(); _logger = logger ?? new NullLogger<TradeTracker>();
_recentRestClient = recentRestClient; _recentRestClient = recentRestClient;
_historyRestClient = historyRestClient; _historyRestClient = historyRestClient;
_socketClient = socketClient; _socketClient = socketClient;
QuantityType = tradeQuantityType;
_exchangeParameters = exchangeParameters; _exchangeParameters = exchangeParameters;
Exchange = socketClient.Exchange; Exchange = socketClient.Exchange;
Symbol = symbol; Symbol = symbol;
@@ -170,22 +177,41 @@ namespace CryptoExchange.Net.Trackers.Trades
Period = period; Period = period;
} }
private static TradesStats GetStats(IEnumerable<SharedTrade> trades) private TradesStats GetStats(IEnumerable<SharedTrade> trades)
{ {
if (!trades.Any()) if (!trades.Any())
return new TradesStats(); return new TradesStats();
return new TradesStats
var stats = new TradesStats
{ {
TradeCount = trades.Count(), TradeCount = trades.Count(),
FirstTradeTime = trades.First().Timestamp, FirstTradeTime = trades.First().Timestamp,
LastTradeTime = trades.Last().Timestamp, LastTradeTime = trades.Last().Timestamp,
AveragePrice = Math.Round(trades.Select(d => d.Price).DefaultIfEmpty().Average(), 8), AveragePrice = Math.Round(trades.Select(d => d.Price).DefaultIfEmpty().Average(), 8),
VolumeWeightedAveragePrice = trades.Any() ? Math.Round(trades.Select(d => d.Price * d.Quantity).DefaultIfEmpty().Sum() / trades.Select(d => d.Quantity).DefaultIfEmpty().Sum(), 8) : null, QuoteVolume = Math.Round(trades.Sum(d => d.Quantities.GetQuantityInQuoteAsset(d.Price) ?? 0), 8),
Volume = Math.Round(trades.Sum(d => d.Quantity), 8),
QuoteVolume = Math.Round(trades.Sum(d => d.Quantity * d.Price), 8),
BuySellRatio = Math.Round(trades.Where(x => x.Side == SharedOrderSide.Buy).Sum(x => x.Quantity) / trades.Sum(x => x.Quantity), 8)
}; };
if (QuantityType == TradeQuantityType.BaseAsset)
{
stats.VolumeWeightedAveragePrice =
trades.Any()
? Math.Round(trades.Select(d => d.Quantities.GetQuantityInQuoteAsset(d.Price) ?? 0).DefaultIfEmpty().Sum() / trades.Select(d => d.Quantities.QuantityInBaseAsset!.Value).DefaultIfEmpty().Sum(), 8)
: null;
stats.Volume = Math.Round(trades.Sum(d => d.Quantities.QuantityInBaseAsset!.Value), 8);
stats.BuySellRatio = Math.Round(trades.Where(x => x.Side == SharedOrderSide.Buy).Sum(x => x.Quantities.QuantityInBaseAsset!.Value) / trades.Sum(x => x.Quantities.QuantityInBaseAsset!.Value), 8);
}
else
{
stats.VolumeWeightedAveragePrice =
trades.Any()
? Math.Round(trades.Select(d => d.Quantities.GetQuantityInQuoteAsset(d.Price) ?? 0).DefaultIfEmpty().Sum() / trades.Select(d => d.Quantities.QuantityInContracts!.Value).DefaultIfEmpty().Sum(), 8)
: null;
stats.Volume = Math.Round(trades.Sum(d => d.Quantities.QuantityInContracts!.Value), 8);
stats.BuySellRatio = Math.Round(trades.Where(x => x.Side == SharedOrderSide.Buy).Sum(x => x.Quantities.QuantityInContracts!.Value) / trades.Sum(x => x.Quantities.QuantityInContracts!.Value), 8);
}
return stats;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -498,4 +524,19 @@ namespace CryptoExchange.Net.Trackers.Trades
Status = SyncStatus.Synced; Status = SyncStatus.Synced;
} }
} }
/// <summary>
/// The quantities to use for trade tracking
/// </summary>
public enum TradeQuantityType
{
/// <summary>
/// Base asset
/// </summary>
BaseAsset,
/// <summary>
/// Contracts
/// </summary>
Contracts
}
} }