Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Filter out old trade data and don't emit invalid quotes #17

Merged
merged 2 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion QuantConnect.CoinbaseBrokerage/CoinbaseBrokerage.Messaging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ public partial class CoinbaseBrokerage
/// </example>
private readonly ConcurrentDictionary<Symbol, List<DefaultOrderBook>> _orderBooks = new();

/// <summary>
/// Sometimes coinbase likes to duplicate the trades, let's ignore old trade ids
/// </summary>
private readonly ConcurrentDictionary<Symbol, Tuple<long, DateTime>> _tradeIds = new();

/// <summary>
/// Represents a rate limiter for controlling the frequency of WebSocket operations.
/// </summary>
Expand Down Expand Up @@ -273,6 +278,11 @@ private void Level2Snapshot(CoinbaseLevel2Event snapshotData)

orderBook.BestBidAskUpdated += OnBestBidAskUpdated;

if (orderBook.BestBidPrice == 0 && orderBook.BestAskPrice == 0)
{
// nothing to emit, can happen with illiquid assets
return;
}
EmitQuoteTick(orderBook.Symbol, orderBook.BestBidPrice, orderBook.BestBidSize, orderBook.BestAskPrice, orderBook.BestAskSize);
}
}
Expand Down Expand Up @@ -325,10 +335,21 @@ private void Level2Update(CoinbaseLevel2Event updateData)

private void EmitTradeTick(CoinbaseMarketTradesEvent tradeUpdates)
{
foreach (var trade in tradeUpdates.Trades)
// coinbase sends older data, as an update, seems they send the last 100 trades, so let's filter it out
// also order by time since they return in descending time and we want ascending
var dataFrontier = DateTime.UtcNow - TimeSpan.FromMinutes(5);
foreach (var trade in tradeUpdates.Trades.Where(x => x.Time.UtcDateTime > dataFrontier).OrderBy(x => x.Time))
{
var symbol = _symbolMapper.GetLeanSymbol(trade.ProductId, SecurityType.Crypto, MarketName);

if (_tradeIds.TryGetValue(symbol, out var lastTradeData)
// ignore old trade ids as long as they have an old timestamp too, just in case it restarted
&& lastTradeData.Item1 > trade.TradeId && lastTradeData.Item2 > trade.Time.UtcDateTime)
{
continue;
}
_tradeIds[symbol] = new (trade.TradeId, trade.Time.UtcDateTime);

var tick = new Tick
{
Value = trade.Price.Value,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public class CoinbaseMarketTradesEvent : WebSocketEvent
public class Trade
{
[JsonProperty("trade_id")]
public string TradeId { get; set; }
public long TradeId { get; set; }

[JsonProperty("product_id")]
public string ProductId { get; set; }
Expand Down
Loading