diff --git a/CryptoExchange.Net.UnitTests/BaseClientTests.cs b/CryptoExchange.Net.UnitTests/BaseClientTests.cs index a27fbda..bf43577 100644 --- a/CryptoExchange.Net.UnitTests/BaseClientTests.cs +++ b/CryptoExchange.Net.UnitTests/BaseClientTests.cs @@ -23,7 +23,7 @@ namespace CryptoExchange.Net.UnitTests // arrange // act // assert - Assert.Throws(typeof(ArgumentException), () => new TestBaseClient(new ClientOptions() { ApiCredentials = new ApiCredentials(key, secret) })); + Assert.Throws(typeof(ArgumentException), () => new TestBaseClient(new RestClientOptions() { ApiCredentials = new ApiCredentials(key, secret) })); } [TestCase] @@ -31,7 +31,7 @@ namespace CryptoExchange.Net.UnitTests { // arrange var stringBuilder = new StringBuilder(); - var client = new TestBaseClient(new ClientOptions() + var client = new TestBaseClient(new RestClientOptions() { LogWriters = new List { new StringWriter(stringBuilder) } }); @@ -67,7 +67,7 @@ namespace CryptoExchange.Net.UnitTests { // arrange var stringBuilder = new StringBuilder(); - var client = new TestBaseClient(new ClientOptions() + var client = new TestBaseClient(new RestClientOptions() { LogWriters = new List { new StringWriter(stringBuilder) }, LogVerbosity = verbosity diff --git a/CryptoExchange.Net.UnitTests/RestClientTests.cs b/CryptoExchange.Net.UnitTests/RestClientTests.cs index d171427..78fa402 100644 --- a/CryptoExchange.Net.UnitTests/RestClientTests.cs +++ b/CryptoExchange.Net.UnitTests/RestClientTests.cs @@ -105,7 +105,7 @@ namespace CryptoExchange.Net.UnitTests { // arrange // act - var client = new TestRestClient(new ClientOptions() + var client = new TestRestClient(new RestClientOptions() { BaseAddress = "http://test.address.com", RateLimiters = new List{new RateLimiterTotal(1, TimeSpan.FromSeconds(1))}, @@ -123,7 +123,7 @@ namespace CryptoExchange.Net.UnitTests public void SettingRateLimitingBehaviourToFail_Should_FailLimitedRequests() { // arrange - var client = new TestRestClient(new ClientOptions() + var client = new TestRestClient(new RestClientOptions() { RateLimiters = new List { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) }, RateLimitingBehaviour = RateLimitingBehaviour.Fail @@ -146,7 +146,7 @@ namespace CryptoExchange.Net.UnitTests public void SettingRateLimitingBehaviourToWait_Should_DelayLimitedRequests() { // arrange - var client = new TestRestClient(new ClientOptions() + var client = new TestRestClient(new RestClientOptions() { RateLimiters = new List { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) }, RateLimitingBehaviour = RateLimitingBehaviour.Wait @@ -171,7 +171,7 @@ namespace CryptoExchange.Net.UnitTests public void SettingApiKeyRateLimiter_Should_DelayRequestsFromSameKey() { // arrange - var client = new TestRestClient(new ClientOptions() + var client = new TestRestClient(new RestClientOptions() { RateLimiters = new List { new RateLimiterAPIKey(1, TimeSpan.FromSeconds(1)) }, RateLimitingBehaviour = RateLimitingBehaviour.Wait, diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs index 9357401..dc0cd25 100644 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestBaseClient.cs @@ -7,11 +7,11 @@ namespace CryptoExchange.Net.UnitTests { public class TestBaseClient: BaseClient { - public TestBaseClient(): base(new ClientOptions(), null) + public TestBaseClient(): base(new RestClientOptions(), null) { } - public TestBaseClient(ClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) + public TestBaseClient(RestClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) { } diff --git a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs b/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs index f9e8782..e8bf674 100644 --- a/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs +++ b/CryptoExchange.Net.UnitTests/TestImplementations/TestRestClient.cs @@ -16,12 +16,12 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations { public class TestRestClient: RestClient { - public TestRestClient() : base(new ClientOptions(), null) + public TestRestClient() : base(new RestClientOptions(), null) { RequestFactory = new Mock().Object; } - public TestRestClient(ClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) + public TestRestClient(RestClientOptions exchangeOptions) : base(exchangeOptions, exchangeOptions.ApiCredentials == null ? null : new TestAuthProvider(exchangeOptions.ApiCredentials)) { RequestFactory = new Mock().Object; } @@ -108,7 +108,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations public class ParseErrorTestRestClient: TestRestClient { public ParseErrorTestRestClient() { } - public ParseErrorTestRestClient(ClientOptions exchangeOptions) : base(exchangeOptions) { } + public ParseErrorTestRestClient(RestClientOptions exchangeOptions) : base(exchangeOptions) { } protected override Error ParseErrorResponse(JToken error) { diff --git a/CryptoExchange.Net/BaseClient.cs b/CryptoExchange.Net/BaseClient.cs index f99db21..7adf435 100644 --- a/CryptoExchange.Net/BaseClient.cs +++ b/CryptoExchange.Net/BaseClient.cs @@ -30,7 +30,7 @@ namespace CryptoExchange.Net public static int LastId => lastId; - protected BaseClient(ExchangeOptions options, AuthenticationProvider authenticationProvider) + protected BaseClient(ClientOptions options, AuthenticationProvider authenticationProvider) { log = new Log(); authProvider = authenticationProvider; @@ -40,16 +40,16 @@ namespace CryptoExchange.Net /// /// Configure the client using the provided options /// - /// Options - protected void Configure(ExchangeOptions exchangeOptions) + /// Options + protected void Configure(ClientOptions clientOptions) { - log.UpdateWriters(exchangeOptions.LogWriters); - log.Level = exchangeOptions.LogVerbosity; + log.UpdateWriters(clientOptions.LogWriters); + log.Level = clientOptions.LogVerbosity; - BaseAddress = exchangeOptions.BaseAddress; - apiProxy = exchangeOptions.Proxy; + BaseAddress = clientOptions.BaseAddress; + apiProxy = clientOptions.Proxy; if (apiProxy != null) - log.Write(LogVerbosity.Info, $"Setting api proxy to {exchangeOptions.Proxy.Host}:{exchangeOptions.Proxy.Port}"); + log.Write(LogVerbosity.Info, $"Setting api proxy to {clientOptions.Proxy.Host}:{clientOptions.Proxy.Port}"); } /// diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index 427e647..c3aef77 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -7,7 +7,7 @@ CryptoExchange.Net JKorf - 2.1.4 + 2.1.5 false https://github.com/JKorf/CryptoExchange.Net https://github.com/JKorf/CryptoExchange.Net/blob/master/LICENSE diff --git a/CryptoExchange.Net/Objects/ExchangeOptions.cs b/CryptoExchange.Net/Objects/Options.cs similarity index 72% rename from CryptoExchange.Net/Objects/ExchangeOptions.cs rename to CryptoExchange.Net/Objects/Options.cs index 01fc26f..aae859d 100644 --- a/CryptoExchange.Net/Objects/ExchangeOptions.cs +++ b/CryptoExchange.Net/Objects/Options.cs @@ -8,9 +8,51 @@ using CryptoExchange.Net.Logging; namespace CryptoExchange.Net.Objects { /// - /// Options + /// Base options /// - public class ExchangeOptions + public class BaseOptions + { + /// + /// The log verbosity + /// + public LogVerbosity LogVerbosity { get; set; } = LogVerbosity.Info; + + /// + /// The log writers + /// + public List LogWriters { get; set; } = new List { new DebugTextWriter() }; + } + + /// + /// Base for order book options + /// + public class OrderBookOptions: BaseOptions + { + /// + /// The name of the order book implementation + /// + public string OrderBookName { get; } + + /// + /// Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped. + /// + public bool SequenceNumbersAreConsecutive { get; } + + /// + /// + /// 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) + { + OrderBookName = name; + SequenceNumbersAreConsecutive = sequencesAreConsecutive; + } + } + + /// + /// Base client options + /// + public class ClientOptions: BaseOptions { /// @@ -27,19 +69,12 @@ namespace CryptoExchange.Net.Objects /// Proxy to use /// public ApiProxy Proxy { get; set; } - - /// - /// The log verbosity - /// - public LogVerbosity LogVerbosity { get; set; } = LogVerbosity.Info; - - /// - /// The log writers - /// - public List LogWriters { get; set; } = new List { new DebugTextWriter() }; } - public class ClientOptions: ExchangeOptions + /// + /// Base for rest client options + /// + public class RestClientOptions: ClientOptions { /// /// List of rate limiters to use @@ -56,7 +91,7 @@ namespace CryptoExchange.Net.Objects /// public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30); - public T Copy() where T:ClientOptions, new() + public T Copy() where T:RestClientOptions, new() { var copy = new T { @@ -76,7 +111,10 @@ namespace CryptoExchange.Net.Objects } } - public class SocketClientOptions: ExchangeOptions + /// + /// Base for socket client options + /// + 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 2399980..9418129 100644 --- a/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs +++ b/CryptoExchange.Net/OrderBook/SymbolOrderBook.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -9,6 +10,9 @@ using CryptoExchange.Net.Sockets; namespace CryptoExchange.Net.OrderBook { + /// + /// Base for order book implementations + /// public abstract class SymbolOrderBook: IDisposable { protected readonly List processBuffer; @@ -112,21 +116,20 @@ namespace CryptoExchange.Net.OrderBook } } - protected SymbolOrderBook(string id, string symbol, bool sequencesAreConsecutive, LogVerbosity logVerbosity, IEnumerable logWriters) + protected SymbolOrderBook(string symbol, OrderBookOptions options) { - this.id = id; + id = options.OrderBookName; processBuffer = new List(); - this.sequencesAreConsecutive = sequencesAreConsecutive; + sequencesAreConsecutive = options.SequenceNumbersAreConsecutive; Symbol = symbol; Status = OrderBookStatus.Disconnected; asks = new SortedList(); bids = new SortedList(new DescComparer()); - log = new Log { Level = logVerbosity }; - if (logWriters == null) - logWriters = new List { new DebugTextWriter() }; - log.UpdateWriters(logWriters.ToList()); + log = new Log { Level = options.LogVerbosity }; + var writers = options.LogWriters ?? new List { new DebugTextWriter() }; + log.UpdateWriters(writers.ToList()); } /// @@ -222,7 +225,7 @@ namespace CryptoExchange.Net.OrderBook CheckProcessBuffer(); bookSet = true; - log.Write(LogVerbosity.Debug, $"{id} order book {Symbol} initial order book set"); + log.Write(LogVerbosity.Debug, $"{id} order book {Symbol} data set: {BidCount} bids, {AskCount} asks"); } } @@ -309,6 +312,24 @@ namespace CryptoExchange.Net.OrderBook } public abstract void Dispose(); + + public override string ToString() + { + return ToString(3); + } + + public string ToString(int numberOfEntries) + { + var result = ""; + result += $"Asks ({AskCount}): {Environment.NewLine}"; + foreach (var entry in Asks.Take(numberOfEntries).Reverse()) + result += $" {entry.Price.ToString(CultureInfo.InvariantCulture).PadLeft(8)} | {entry.Quantity.ToString(CultureInfo.InvariantCulture).PadRight(8)}{Environment.NewLine}"; + + result += $"Bids ({BidCount}): {Environment.NewLine}"; + foreach (var entry in Bids.Take(numberOfEntries)) + result += $" {entry.Price.ToString(CultureInfo.InvariantCulture).PadLeft(8)} | {entry.Quantity.ToString(CultureInfo.InvariantCulture).PadRight(8)}{Environment.NewLine}"; + return result; + } } internal class DescComparer : IComparer diff --git a/CryptoExchange.Net/RestClient.cs b/CryptoExchange.Net/RestClient.cs index d21d105..85511c7 100644 --- a/CryptoExchange.Net/RestClient.cs +++ b/CryptoExchange.Net/RestClient.cs @@ -35,7 +35,7 @@ namespace CryptoExchange.Net public IEnumerable RateLimiters { get; private set; } public int TotalRequestsMade { get; private set; } - protected RestClient(ClientOptions exchangeOptions, AuthenticationProvider authenticationProvider): base(exchangeOptions, authenticationProvider) + protected RestClient(RestClientOptions exchangeOptions, AuthenticationProvider authenticationProvider): base(exchangeOptions, authenticationProvider) { Configure(exchangeOptions); } @@ -44,7 +44,7 @@ namespace CryptoExchange.Net /// Configure the client using the provided options /// /// Options - protected void Configure(ClientOptions exchangeOptions) + protected void Configure(RestClientOptions exchangeOptions) { RequestTimeout = exchangeOptions.RequestTimeout; RateLimitBehaviour = exchangeOptions.RateLimitingBehaviour; diff --git a/README.md b/README.md index fde3bf6..1f22a22 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,10 @@ 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 2.1.4 - 24 june 201 +* Version 2.1.5 - 09 jul 2019 + * Updated SymbolOrderBook + +* Version 2.1.4 - 24 jun 2019 * Added checks for json deserialization issues * Version 2.1.3 - 16 may 2019