diff --git a/CryptoExchange.Net/Objects/Options.cs b/CryptoExchange.Net/Objects/Options.cs
index 525f1c8..156364f 100644
--- a/CryptoExchange.Net/Objects/Options.cs
+++ b/CryptoExchange.Net/Objects/Options.cs
@@ -26,8 +26,12 @@ namespace CryptoExchange.Net.Objects
///
/// Base for order book options
///
- public class OrderBookOptions: BaseOptions
+ public class OrderBookOptions : BaseOptions
{
+ ///
+ /// Update event raising timeout in milliseconds (to limit it at high-liquidity order books)
+ ///
+ public int UpdateEventTimeout { get; }
///
/// The name of the order book implementation
///
@@ -42,8 +46,10 @@ namespace CryptoExchange.Net.Objects
///
/// The name of the order book implementation
/// Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.
- public OrderBookOptions(string name, bool sequencesAreConsecutive)
+ /// Update event raising timeout in milliseconds (to limit it at high-liquidity order books)
+ public OrderBookOptions(string name, bool sequencesAreConsecutive, int? updateInterval)
{
+ UpdateEventTimeout = updateInterval ?? 1000;
OrderBookName = name;
SequenceNumbersAreConsecutive = sequencesAreConsecutive;
}
@@ -52,7 +58,7 @@ namespace CryptoExchange.Net.Objects
///
/// Base client options
///
- public class ClientOptions: BaseOptions
+ public class ClientOptions : BaseOptions
{
///
@@ -74,7 +80,7 @@ namespace CryptoExchange.Net.Objects
///
/// Base for rest client options
///
- public class RestClientOptions: ClientOptions
+ public class RestClientOptions : ClientOptions
{
///
/// List of rate limiters to use
@@ -96,7 +102,7 @@ namespace CryptoExchange.Net.Objects
///
///
///
- public T Copy() where T:RestClientOptions, new()
+ public T Copy() where T : RestClientOptions, new()
{
var copy = new T
{
@@ -119,7 +125,7 @@ namespace CryptoExchange.Net.Objects
///
/// Base for socket client options
///
- public class SocketClientOptions: ClientOptions
+ public class SocketClientOptions : ClientOptions
{
///
/// Whether or not the socket should automatically reconnect when losing connection
diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs
index 5edd59d..2e5f2dc 100644
--- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs
+++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs
@@ -13,7 +13,7 @@ namespace CryptoExchange.Net.OrderBook
///
/// Base for order book implementations
///
- public abstract class SymbolOrderBook: IDisposable
+ public abstract class SymbolOrderBook : IDisposable
{
///
/// The process buffer, used while syncing
@@ -27,6 +27,7 @@ namespace CryptoExchange.Net.OrderBook
///
/// The bid list
///
+
protected SortedList bids;
private OrderBookStatus status;
private UpdateSubscription subscription;
@@ -69,12 +70,19 @@ namespace CryptoExchange.Net.OrderBook
///
/// Event when the state changes
///
- public event Action OnStatusChange;
+ public event Action OnStatusChange;
///
- /// Event when orderbook was updated
- ///
+ /// Event when orderbook was updated, but not more often then timeout setted in orderbook options (1000ms by default). Be careful! with small timeout it can generate a lot of events at high-liquidity order books
+ ///
public event Action OnOrderBookUpdate;
///
+ /// Should be useful for low-liquidity order-books to monitor market activity
+ ///
+ public DateTime LastOrderBookUpdate;
+ private DateTime LastOrderBookUpdateEventTrigger;
+
+ private readonly int updateEventInterval;
+ ///
/// The number of asks in the book
///
public int AskCount { get; private set; }
@@ -141,6 +149,7 @@ namespace CryptoExchange.Net.OrderBook
id = options.OrderBookName;
processBuffer = new List();
sequencesAreConsecutive = options.SequenceNumbersAreConsecutive;
+ updateEventInterval = options.UpdateEventTimeout;
Symbol = symbol;
Status = OrderBookStatus.Disconnected;
@@ -166,7 +175,7 @@ namespace CryptoExchange.Net.OrderBook
{
Status = OrderBookStatus.Connecting;
var startResult = await DoStart().ConfigureAwait(false);
- if(!startResult.Success)
+ if (!startResult.Success)
return new CallResult(false, startResult.Error);
subscription = startResult.Data;
@@ -234,7 +243,7 @@ namespace CryptoExchange.Net.OrderBook
///
///
protected abstract Task> DoResync();
-
+
///
/// Set the initial data for the order book
///
@@ -249,7 +258,7 @@ namespace CryptoExchange.Net.OrderBook
return;
asks.Clear();
- foreach(var ask in askList)
+ foreach (var ask in askList)
asks.Add(ask.Price, new OrderBookEntry(ask.Price, ask.Quantity));
bids.Clear();
foreach (var bid in bidList)
@@ -262,7 +271,12 @@ namespace CryptoExchange.Net.OrderBook
CheckProcessBuffer();
bookSet = true;
- OnOrderBookUpdate?.Invoke();
+ LastOrderBookUpdate = DateTime.UtcNow;
+ if ((LastOrderBookUpdate - LastOrderBookUpdateEventTrigger).TotalMilliseconds >= updateEventInterval)
+ {
+ OnOrderBookUpdate?.Invoke();
+ LastOrderBookUpdateEventTrigger = DateTime.UtcNow;
+ }
log.Write(LogVerbosity.Debug, $"{id} order book {Symbol} data set: {BidCount} bids, {AskCount} asks");
}
}
@@ -299,11 +313,16 @@ namespace CryptoExchange.Net.OrderBook
}
else
{
- foreach(var entry in entries)
+ foreach (var entry in entries)
ProcessUpdate(entry.Type, entry.Entry);
LastSequenceNumber = lastSequenceNumber;
CheckProcessBuffer();
- OnOrderBookUpdate?.Invoke();
+ LastOrderBookUpdate = DateTime.UtcNow;
+ if ((LastOrderBookUpdate - LastOrderBookUpdateEventTrigger).TotalMilliseconds >= updateEventInterval)
+ {
+ OnOrderBookUpdate?.Invoke();
+ LastOrderBookUpdateEventTrigger = DateTime.UtcNow;
+ }
log.Write(LogVerbosity.Debug, $"{id} order book {Symbol} update: {entries.Count} entries processed");
}
}
@@ -316,7 +335,7 @@ namespace CryptoExchange.Net.OrderBook
{
foreach (var bufferEntry in processBuffer.OrderBy(b => b.FirstSequence).ToList())
{
- if(bufferEntry.LastSequence < LastSequenceNumber)
+ if (bufferEntry.LastSequence < LastSequenceNumber)
{
processBuffer.Remove(bufferEntry);
continue;
@@ -325,7 +344,7 @@ namespace CryptoExchange.Net.OrderBook
if (bufferEntry.FirstSequence > LastSequenceNumber + 1)
break;
- foreach(var entry in bufferEntry.Entries)
+ foreach (var entry in bufferEntry.Entries)
ProcessUpdate(entry.Type, entry.Entry);
processBuffer.Remove(bufferEntry);
LastSequenceNumber = bufferEntry.LastSequence;