From e7ec10e98d58da16c0f12f334884840bd233f989 Mon Sep 17 00:00:00 2001 From: Ben Davison Date: Wed, 11 Dec 2019 13:26:13 +0000 Subject: [PATCH 1/8] Ticking price event --- CryptoExchange.Net/CryptoExchange.Net.xml | 153 ++++++++++++++++++ .../Interfaces/ISymbolOrderBook.cs | 4 + .../OrderBook/SymbolOrderBook.cs | 32 +++- 3 files changed, 186 insertions(+), 3 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index 800ba58..eb9478e 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -797,6 +797,11 @@ Event when order book was updated. Be careful! It can generate a lot of events at high-liquidity markets + + + Event when the BestBid or BestAsk changes ie a Pricing Tick + + Timestamp of the last update @@ -1769,6 +1774,11 @@ Event when the state changes + + + Event when the BestBid or BestAsk changes ie a Pricing Tick + + Event when order book was updated, containing the changed bids and asks. Be careful! It can generate a lot of events at high-liquidity markets @@ -2888,5 +2898,148 @@ + + + Specifies that is allowed as an input even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that is disallowed as an input even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that a method that will never return under any circumstance. + + + + + Initializes a new instance of the class. + + + + + Specifies that the method will not return if the associated + parameter is passed the specified value. + + + + + Gets the condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Initializes a new instance of the + class with the specified parameter value. + + + The condition parameter value. + Code after the method is considered unreachable by diagnostics if the argument + to the associated parameter matches this value. + + + + + Specifies that an output may be even if the + corresponding type disallows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that when a method returns , + the parameter may be even if the corresponding type disallows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter may be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter may be . + + + + + Specifies that an output is not even if the + corresponding type allows it. + + + + + Initializes a new instance of the class. + + + + + Specifies that the output will be non- if the + named parameter is non-. + + + + + Gets the associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Initializes the attribute with the associated parameter name. + + + The associated parameter name. + The output will be non- if the argument to the + parameter specified is non-. + + + + + Specifies that when a method returns , + the parameter will not be even if the corresponding type allows it. + + + + + Gets the return value condition. + If the method returns this value, the associated parameter will not be . + + + + + Initializes the attribute with the specified return value condition. + + + The return value condition. + If the method returns this value, the associated parameter will not be . + + diff --git a/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs b/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs index 1571feb..1800689 100644 --- a/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs +++ b/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs @@ -33,6 +33,10 @@ namespace CryptoExchange.Net.Interfaces /// event Action, IEnumerable> OnOrderBookUpdate; /// + /// Event when the BestBid or BestAsk changes ie a Pricing Tick + /// + event Action OnPriceChanged; + /// /// Timestamp of the last update /// DateTime LastOrderBookUpdate { get; } diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index cc890c8..b33512d 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -51,7 +51,7 @@ namespace CryptoExchange.Net.OrderBook /// /// The status of the order book. Order book is up to date when the status is `Synced` /// - public OrderBookStatus Status + public OrderBookStatus Status { get => status; set @@ -79,6 +79,12 @@ namespace CryptoExchange.Net.OrderBook /// Event when the state changes /// public event Action? OnStatusChange; + + /// + /// Event when the BestBid or BestAsk changes ie a Pricing Tick + /// + public event Action? OnPriceChanged; + /// /// Event when order book was updated, containing the changed bids and asks. Be careful! It can generate a lot of events at high-liquidity markets /// @@ -112,7 +118,7 @@ namespace CryptoExchange.Net.OrderBook /// /// The list of bids /// - public IEnumerable Bids + public IEnumerable Bids { get { @@ -136,7 +142,7 @@ namespace CryptoExchange.Net.OrderBook /// /// The best ask currently in the order book /// - public ISymbolOrderBookEntry BestAsk + public ISymbolOrderBookEntry BestAsk { get { @@ -286,9 +292,16 @@ namespace CryptoExchange.Net.OrderBook log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} data set: {BidCount} bids, {AskCount} asks. #{orderBookSequenceNumber}"); CheckProcessBuffer(); OnOrderBookUpdate?.Invoke(bidList, askList); + OnPriceChanged?.Invoke(BestBid, BestAsk); } } + private bool BestPricingUpdated(ISymbolOrderBookEntry prevBestBid, ISymbolOrderBookEntry prevBestAsk) + { + return BestBid.Price != prevBestBid.Price || BestBid.Quantity != prevBestBid.Quantity || + BestAsk.Price != prevBestAsk.Price || BestAsk.Quantity != prevBestAsk.Quantity; + } + /// /// Update the order book using a single id for an update /// @@ -315,8 +328,12 @@ namespace CryptoExchange.Net.OrderBook else { CheckProcessBuffer(); + var prevBestBid = BestBid; + var prevBestAsk = BestAsk; ProcessSingleSequenceUpdates(rangeUpdateId, bids, asks); OnOrderBookUpdate?.Invoke(bids, asks); + if (BestPricingUpdated(prevBestBid, prevBestAsk)) + OnPriceChanged?.Invoke(BestBid, BestAsk); } } } @@ -349,8 +366,12 @@ namespace CryptoExchange.Net.OrderBook else { CheckProcessBuffer(); + var prevBestBid = BestBid; + var prevBestAsk = BestAsk; ProcessRangeUpdates(firstUpdateId, lastUpdateId, bids, asks); OnOrderBookUpdate?.Invoke(bids, asks); + if (BestPricingUpdated(prevBestBid, prevBestAsk)) + OnPriceChanged?.Invoke(BestBid, BestAsk); } } } @@ -376,8 +397,13 @@ namespace CryptoExchange.Net.OrderBook else { CheckProcessBuffer(); + var prevBestBid = BestBid; + var prevBestAsk = BestAsk; ProcessUpdates(bids, asks); OnOrderBookUpdate?.Invoke(bids, asks); + if (BestPricingUpdated(prevBestBid, prevBestAsk)) + OnPriceChanged?.Invoke(BestBid, BestAsk); + } } } From c870370ebbe180e3a2955fe7001d05a8c07994fc Mon Sep 17 00:00:00 2001 From: Mykyta Kochetkov Date: Tue, 17 Dec 2019 14:22:20 +0100 Subject: [PATCH 2/8] fix log with request body --- CryptoExchange.Net/RestClient.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index 521f9b9..048cf6c 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -181,7 +181,7 @@ namespace CryptoExchange.Net } string? paramString = null; - if (parameters != null && method == HttpMethod.Post) + if (method == HttpMethod.Post) paramString = " with request body " + request.Content; log.Write(LogVerbosity.Debug, $"Sending {method}{(signed ? " signed" : "")} request to {request.Uri}{paramString ?? " "}{(apiProxy == null? "": $" via proxy {apiProxy.Host}")}"); From a5a7c4ed1d28a43fb8a4360e6827ca5f125695ad Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 23 Jan 2020 13:52:04 +0100 Subject: [PATCH 3/8] used async await for tasks instead of WaitAll --- CryptoExchange.Net/SocketClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CryptoExchange.Net/SocketClient.cs b/CryptoExchange.Net/SocketClient.cs index b416553..c1848ef 100644 --- a/CryptoExchange.Net/SocketClient.cs +++ b/CryptoExchange.Net/SocketClient.cs @@ -552,7 +552,7 @@ namespace CryptoExchange.Net { log.Write(LogVerbosity.Debug, $"Closing all {sockets.Sum(s => s.Value.HandlerCount)} subscriptions"); - await Task.Run(() => + await Task.Run(async () => { var tasks = new List(); { @@ -561,7 +561,7 @@ namespace CryptoExchange.Net tasks.Add(sub.Close()); } - Task.WaitAll(tasks.ToArray()); + await Task.WhenAll(tasks.ToArray()).ConfigureAwait(false); }).ConfigureAwait(false); } From ccaf1da5c9ed319eb1ca853191b61b4fc0505315 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 23 Jan 2020 14:00:58 +0100 Subject: [PATCH 4/8] Renamed OnPriceChanged to OnBestOffersChanged --- CryptoExchange.Net/CryptoExchange.Net.xml | 4 ++-- .../Interfaces/ISymbolOrderBook.cs | 2 +- .../OrderBook/SymbolOrderBook.cs | 21 ++++++++----------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index eb9478e..a29cf01 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -797,7 +797,7 @@ Event when order book was updated. Be careful! It can generate a lot of events at high-liquidity markets - + Event when the BestBid or BestAsk changes ie a Pricing Tick @@ -1774,7 +1774,7 @@ Event when the state changes - + Event when the BestBid or BestAsk changes ie a Pricing Tick diff --git a/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs b/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs index 1800689..9d0b502 100644 --- a/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs +++ b/CryptoExchange.Net/Interfaces/ISymbolOrderBook.cs @@ -35,7 +35,7 @@ namespace CryptoExchange.Net.Interfaces /// /// Event when the BestBid or BestAsk changes ie a Pricing Tick /// - event Action OnPriceChanged; + event Action OnBestOffersChanged; /// /// Timestamp of the last update /// diff --git a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs index b33512d..36e94b8 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -83,7 +83,7 @@ namespace CryptoExchange.Net.OrderBook /// /// Event when the BestBid or BestAsk changes ie a Pricing Tick /// - public event Action? OnPriceChanged; + public event Action? OnBestOffersChanged; /// /// Event when order book was updated, containing the changed bids and asks. Be careful! It can generate a lot of events at high-liquidity markets @@ -292,14 +292,15 @@ namespace CryptoExchange.Net.OrderBook log.Write(LogVerbosity.Debug, $"{Id} order book {Symbol} data set: {BidCount} bids, {AskCount} asks. #{orderBookSequenceNumber}"); CheckProcessBuffer(); OnOrderBookUpdate?.Invoke(bidList, askList); - OnPriceChanged?.Invoke(BestBid, BestAsk); + OnBestOffersChanged?.Invoke(BestBid, BestAsk); } } - private bool BestPricingUpdated(ISymbolOrderBookEntry prevBestBid, ISymbolOrderBookEntry prevBestAsk) + private void CheckBestOffersChanged(ISymbolOrderBookEntry prevBestBid, ISymbolOrderBookEntry prevBestAsk) { - return BestBid.Price != prevBestBid.Price || BestBid.Quantity != prevBestBid.Quantity || - BestAsk.Price != prevBestAsk.Price || BestAsk.Quantity != prevBestAsk.Quantity; + if (BestBid.Price != prevBestBid.Price || BestBid.Quantity != prevBestBid.Quantity || + BestAsk.Price != prevBestAsk.Price || BestAsk.Quantity != prevBestAsk.Quantity) + OnBestOffersChanged?.Invoke(BestBid, BestAsk); } /// @@ -332,8 +333,7 @@ namespace CryptoExchange.Net.OrderBook var prevBestAsk = BestAsk; ProcessSingleSequenceUpdates(rangeUpdateId, bids, asks); OnOrderBookUpdate?.Invoke(bids, asks); - if (BestPricingUpdated(prevBestBid, prevBestAsk)) - OnPriceChanged?.Invoke(BestBid, BestAsk); + CheckBestOffersChanged(prevBestBid, prevBestAsk); } } } @@ -370,8 +370,7 @@ namespace CryptoExchange.Net.OrderBook var prevBestAsk = BestAsk; ProcessRangeUpdates(firstUpdateId, lastUpdateId, bids, asks); OnOrderBookUpdate?.Invoke(bids, asks); - if (BestPricingUpdated(prevBestBid, prevBestAsk)) - OnPriceChanged?.Invoke(BestBid, BestAsk); + CheckBestOffersChanged(prevBestBid, prevBestAsk); } } } @@ -401,9 +400,7 @@ namespace CryptoExchange.Net.OrderBook var prevBestAsk = BestAsk; ProcessUpdates(bids, asks); OnOrderBookUpdate?.Invoke(bids, asks); - if (BestPricingUpdated(prevBestBid, prevBestAsk)) - OnPriceChanged?.Invoke(BestBid, BestAsk); - + CheckBestOffersChanged(prevBestBid, prevBestAsk); } } } From 400259c0a1dd08e5ed2f51a8c15d0f7bf988fa21 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 23 Jan 2020 14:14:28 +0100 Subject: [PATCH 5/8] Moved error logging so no error are logged when error response is being parsed --- CryptoExchange.Net/BaseClient.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index 8c32f2b..a4bbc98 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -106,19 +106,16 @@ namespace CryptoExchange.Net catch (JsonReaderException jre) { var info = $"Deserialize JsonReaderException: {jre.Message}, Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}. Data: {data}"; - log.Write(LogVerbosity.Error, info); return new CallResult(null, new DeserializeError(info)); } catch (JsonSerializationException jse) { var info = $"Deserialize JsonSerializationException: {jse.Message}. Data: {data}"; - log.Write(LogVerbosity.Error, info); return new CallResult(null, new DeserializeError(info)); } catch (Exception ex) { var info = $"Deserialize Unknown Exception: {ex.Message}. Data: {data}"; - log.Write(LogVerbosity.Error, info); return new CallResult(null, new DeserializeError(info)); } } @@ -134,7 +131,13 @@ namespace CryptoExchange.Net protected CallResult Deserialize(string data, bool checkObject = true, JsonSerializer? serializer = null) { var tokenResult = ValidateJson(data); - return !tokenResult ? new CallResult(default, tokenResult.Error) : Deserialize(tokenResult.Data, checkObject, serializer); + if (!tokenResult) + { + log.Write(LogVerbosity.Error, tokenResult.Error!.Message); + return new CallResult(default, tokenResult.Error); + } + + return Deserialize(tokenResult.Data, checkObject, serializer); } /// From 649860b4d8cb7a85d0956c97deb08dc436d13566 Mon Sep 17 00:00:00 2001 From: JKorf Date: Thu, 23 Jan 2020 15:18:05 +0100 Subject: [PATCH 6/8] Updated version --- CryptoExchange.Net/CryptoExchange.Net.csproj | 4 ++-- README.md | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index b772e21..188bc11 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -5,12 +5,12 @@ CryptoExchange.Net JKorf - 3.0.2 + 3.0.3 false https://github.com/JKorf/CryptoExchange.Net en true - 3.0.2 - Removed invalid check for unauthenticated proxy + 3.0.3 - Added OnBestOffersChanged event to order book implementations enable 8.0 MIT diff --git a/README.md b/README.md index 970fd4b..4dfa2ed 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,9 @@ The order book will automatically reconnect when the connection is lost and resy To stop synchronizing an order book use the `Stop` method. ## Release notes +* Version 3.0.3 - 23 Jan 2020 + * Added OnBestOffersChanged event to order book implementations + * Version 3.0.2 - 10 Dec 2019 * Removed invalid check for unauthenticated proxy From 82ff1aebafea43874db51f4e1c5796da6f828cc3 Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 29 Jan 2020 17:05:28 +0100 Subject: [PATCH 7/8] SocketConnection.Send check if object is string, if so it doesn't deserialize again --- CryptoExchange.Net/CryptoExchange.Net.csproj | 1 + CryptoExchange.Net/CryptoExchange.Net.xml | 143 ------------------ .../Sockets/SocketConnection.cs | 5 +- 3 files changed, 5 insertions(+), 144 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index 188bc11..ac224ad 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -5,6 +5,7 @@ CryptoExchange.Net JKorf + A base package for implementing cryptocurrency exchange API's 3.0.3 false https://github.com/JKorf/CryptoExchange.Net diff --git a/CryptoExchange.Net/CryptoExchange.Net.xml b/CryptoExchange.Net/CryptoExchange.Net.xml index a29cf01..62e5487 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.xml +++ b/CryptoExchange.Net/CryptoExchange.Net.xml @@ -2898,148 +2898,5 @@ - - - Specifies that is allowed as an input even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that is disallowed as an input even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that a method that will never return under any circumstance. - - - - - Initializes a new instance of the class. - - - - - Specifies that the method will not return if the associated - parameter is passed the specified value. - - - - - Gets the condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Initializes a new instance of the - class with the specified parameter value. - - - The condition parameter value. - Code after the method is considered unreachable by diagnostics if the argument - to the associated parameter matches this value. - - - - - Specifies that an output may be even if the - corresponding type disallows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that when a method returns , - the parameter may be even if the corresponding type disallows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter may be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter may be . - - - - - Specifies that an output is not even if the - corresponding type allows it. - - - - - Initializes a new instance of the class. - - - - - Specifies that the output will be non- if the - named parameter is non-. - - - - - Gets the associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Initializes the attribute with the associated parameter name. - - - The associated parameter name. - The output will be non- if the argument to the - parameter specified is non-. - - - - - Specifies that when a method returns , - the parameter will not be even if the corresponding type allows it. - - - - - Gets the return value condition. - If the method returns this value, the associated parameter will not be . - - - - - Initializes the attribute with the specified return value condition. - - - The return value condition. - If the method returns this value, the associated parameter will not be . - - diff --git a/CryptoExchange.Net/Sockets/SocketConnection.cs b/CryptoExchange.Net/Sockets/SocketConnection.cs index b7e8b9a..e1704e0 100644 --- a/CryptoExchange.Net/Sockets/SocketConnection.cs +++ b/CryptoExchange.Net/Sockets/SocketConnection.cs @@ -216,7 +216,10 @@ namespace CryptoExchange.Net.Sockets /// How null values should be serialized public virtual void Send(T obj, NullValueHandling nullValueHandling = NullValueHandling.Ignore) { - Send(JsonConvert.SerializeObject(obj, Formatting.None, new JsonSerializerSettings { NullValueHandling = nullValueHandling })); + if(obj is string str) + Send(str); + else + Send(JsonConvert.SerializeObject(obj, Formatting.None, new JsonSerializerSettings { NullValueHandling = nullValueHandling })); } /// From d4591023236cafd1c6ef2d77bbed79d5c3e6458e Mon Sep 17 00:00:00 2001 From: JKorf Date: Wed, 29 Jan 2020 17:06:46 +0100 Subject: [PATCH 8/8] Updated version --- CryptoExchange.Net/CryptoExchange.Net.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index ac224ad..841462b 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -6,12 +6,12 @@ CryptoExchange.Net JKorf A base package for implementing cryptocurrency exchange API's - 3.0.3 + 3.0.4 false https://github.com/JKorf/CryptoExchange.Net en true - 3.0.3 - Added OnBestOffersChanged event to order book implementations + 3.0.4 - Removed unnecessary json serialization when sending string data enable 8.0 MIT