1
0
mirror of https://github.com/JKorf/CryptoExchange.Net synced 2025-06-12 10:26:27 +00:00

Updated SymbolOrderBook

This commit is contained in:
Jan Korf 2019-07-09 12:00:03 +02:00
parent e89df592f5
commit 0d4707f6a5
10 changed files with 109 additions and 47 deletions

View File

@ -23,7 +23,7 @@ namespace CryptoExchange.Net.UnitTests
// arrange // arrange
// act // act
// assert // 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] [TestCase]
@ -31,7 +31,7 @@ namespace CryptoExchange.Net.UnitTests
{ {
// arrange // arrange
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
var client = new TestBaseClient(new ClientOptions() var client = new TestBaseClient(new RestClientOptions()
{ {
LogWriters = new List<TextWriter> { new StringWriter(stringBuilder) } LogWriters = new List<TextWriter> { new StringWriter(stringBuilder) }
}); });
@ -67,7 +67,7 @@ namespace CryptoExchange.Net.UnitTests
{ {
// arrange // arrange
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
var client = new TestBaseClient(new ClientOptions() var client = new TestBaseClient(new RestClientOptions()
{ {
LogWriters = new List<TextWriter> { new StringWriter(stringBuilder) }, LogWriters = new List<TextWriter> { new StringWriter(stringBuilder) },
LogVerbosity = verbosity LogVerbosity = verbosity

View File

@ -105,7 +105,7 @@ namespace CryptoExchange.Net.UnitTests
{ {
// arrange // arrange
// act // act
var client = new TestRestClient(new ClientOptions() var client = new TestRestClient(new RestClientOptions()
{ {
BaseAddress = "http://test.address.com", BaseAddress = "http://test.address.com",
RateLimiters = new List<IRateLimiter>{new RateLimiterTotal(1, TimeSpan.FromSeconds(1))}, RateLimiters = new List<IRateLimiter>{new RateLimiterTotal(1, TimeSpan.FromSeconds(1))},
@ -123,7 +123,7 @@ namespace CryptoExchange.Net.UnitTests
public void SettingRateLimitingBehaviourToFail_Should_FailLimitedRequests() public void SettingRateLimitingBehaviourToFail_Should_FailLimitedRequests()
{ {
// arrange // arrange
var client = new TestRestClient(new ClientOptions() var client = new TestRestClient(new RestClientOptions()
{ {
RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) }, RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) },
RateLimitingBehaviour = RateLimitingBehaviour.Fail RateLimitingBehaviour = RateLimitingBehaviour.Fail
@ -146,7 +146,7 @@ namespace CryptoExchange.Net.UnitTests
public void SettingRateLimitingBehaviourToWait_Should_DelayLimitedRequests() public void SettingRateLimitingBehaviourToWait_Should_DelayLimitedRequests()
{ {
// arrange // arrange
var client = new TestRestClient(new ClientOptions() var client = new TestRestClient(new RestClientOptions()
{ {
RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) }, RateLimiters = new List<IRateLimiter> { new RateLimiterTotal(1, TimeSpan.FromSeconds(1)) },
RateLimitingBehaviour = RateLimitingBehaviour.Wait RateLimitingBehaviour = RateLimitingBehaviour.Wait
@ -171,7 +171,7 @@ namespace CryptoExchange.Net.UnitTests
public void SettingApiKeyRateLimiter_Should_DelayRequestsFromSameKey() public void SettingApiKeyRateLimiter_Should_DelayRequestsFromSameKey()
{ {
// arrange // arrange
var client = new TestRestClient(new ClientOptions() var client = new TestRestClient(new RestClientOptions()
{ {
RateLimiters = new List<IRateLimiter> { new RateLimiterAPIKey(1, TimeSpan.FromSeconds(1)) }, RateLimiters = new List<IRateLimiter> { new RateLimiterAPIKey(1, TimeSpan.FromSeconds(1)) },
RateLimitingBehaviour = RateLimitingBehaviour.Wait, RateLimitingBehaviour = RateLimitingBehaviour.Wait,

View File

@ -7,11 +7,11 @@ namespace CryptoExchange.Net.UnitTests
{ {
public class TestBaseClient: BaseClient 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))
{ {
} }

View File

@ -16,12 +16,12 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
{ {
public class TestRestClient: RestClient public class TestRestClient: RestClient
{ {
public TestRestClient() : base(new ClientOptions(), null) public TestRestClient() : base(new RestClientOptions(), null)
{ {
RequestFactory = new Mock<IRequestFactory>().Object; RequestFactory = new Mock<IRequestFactory>().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<IRequestFactory>().Object; RequestFactory = new Mock<IRequestFactory>().Object;
} }
@ -108,7 +108,7 @@ namespace CryptoExchange.Net.UnitTests.TestImplementations
public class ParseErrorTestRestClient: TestRestClient public class ParseErrorTestRestClient: TestRestClient
{ {
public ParseErrorTestRestClient() { } public ParseErrorTestRestClient() { }
public ParseErrorTestRestClient(ClientOptions exchangeOptions) : base(exchangeOptions) { } public ParseErrorTestRestClient(RestClientOptions exchangeOptions) : base(exchangeOptions) { }
protected override Error ParseErrorResponse(JToken error) protected override Error ParseErrorResponse(JToken error)
{ {

View File

@ -30,7 +30,7 @@ namespace CryptoExchange.Net
public static int LastId => lastId; public static int LastId => lastId;
protected BaseClient(ExchangeOptions options, AuthenticationProvider authenticationProvider) protected BaseClient(ClientOptions options, AuthenticationProvider authenticationProvider)
{ {
log = new Log(); log = new Log();
authProvider = authenticationProvider; authProvider = authenticationProvider;
@ -40,16 +40,16 @@ namespace CryptoExchange.Net
/// <summary> /// <summary>
/// Configure the client using the provided options /// Configure the client using the provided options
/// </summary> /// </summary>
/// <param name="exchangeOptions">Options</param> /// <param name="clientOptionsns">Options</param>
protected void Configure(ExchangeOptions exchangeOptions) protected void Configure(ClientOptions clientOptions)
{ {
log.UpdateWriters(exchangeOptions.LogWriters); log.UpdateWriters(clientOptions.LogWriters);
log.Level = exchangeOptions.LogVerbosity; log.Level = clientOptions.LogVerbosity;
BaseAddress = exchangeOptions.BaseAddress; BaseAddress = clientOptions.BaseAddress;
apiProxy = exchangeOptions.Proxy; apiProxy = clientOptions.Proxy;
if (apiProxy != null) 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}");
} }
/// <summary> /// <summary>

View File

@ -7,7 +7,7 @@
<PropertyGroup> <PropertyGroup>
<PackageId>CryptoExchange.Net</PackageId> <PackageId>CryptoExchange.Net</PackageId>
<Authors>JKorf</Authors> <Authors>JKorf</Authors>
<PackageVersion>2.1.4</PackageVersion> <PackageVersion>2.1.5</PackageVersion>
<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance> <PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
<PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl> <PackageProjectUrl>https://github.com/JKorf/CryptoExchange.Net</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/JKorf/CryptoExchange.Net/blob/master/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/JKorf/CryptoExchange.Net/blob/master/LICENSE</PackageLicenseUrl>

View File

@ -8,9 +8,51 @@ using CryptoExchange.Net.Logging;
namespace CryptoExchange.Net.Objects namespace CryptoExchange.Net.Objects
{ {
/// <summary> /// <summary>
/// Options /// Base options
/// </summary> /// </summary>
public class ExchangeOptions public class BaseOptions
{
/// <summary>
/// The log verbosity
/// </summary>
public LogVerbosity LogVerbosity { get; set; } = LogVerbosity.Info;
/// <summary>
/// The log writers
/// </summary>
public List<TextWriter> LogWriters { get; set; } = new List<TextWriter> { new DebugTextWriter() };
}
/// <summary>
/// Base for order book options
/// </summary>
public class OrderBookOptions: BaseOptions
{
/// <summary>
/// The name of the order book implementation
/// </summary>
public string OrderBookName { get; }
/// <summary>
/// Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.
/// </summary>
public bool SequenceNumbersAreConsecutive { get; }
/// <summary>
/// </summary>
/// <param name="name">The name of the order book implementation</param>
/// <param name="sequencesAreConsecutive">Whether each update should have a consecutive id number. Used to identify and reconnect when numbers are skipped.</param>
public OrderBookOptions(string name, bool sequencesAreConsecutive)
{
OrderBookName = name;
SequenceNumbersAreConsecutive = sequencesAreConsecutive;
}
}
/// <summary>
/// Base client options
/// </summary>
public class ClientOptions: BaseOptions
{ {
/// <summary> /// <summary>
@ -27,19 +69,12 @@ namespace CryptoExchange.Net.Objects
/// Proxy to use /// Proxy to use
/// </summary> /// </summary>
public ApiProxy Proxy { get; set; } public ApiProxy Proxy { get; set; }
/// <summary>
/// The log verbosity
/// </summary>
public LogVerbosity LogVerbosity { get; set; } = LogVerbosity.Info;
/// <summary>
/// The log writers
/// </summary>
public List<TextWriter> LogWriters { get; set; } = new List<TextWriter> { new DebugTextWriter() };
} }
public class ClientOptions: ExchangeOptions /// <summary>
/// Base for rest client options
/// </summary>
public class RestClientOptions: ClientOptions
{ {
/// <summary> /// <summary>
/// List of rate limiters to use /// List of rate limiters to use
@ -56,7 +91,7 @@ namespace CryptoExchange.Net.Objects
/// </summary> /// </summary>
public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30); public TimeSpan RequestTimeout { get; set; } = TimeSpan.FromSeconds(30);
public T Copy<T>() where T:ClientOptions, new() public T Copy<T>() where T:RestClientOptions, new()
{ {
var copy = new T var copy = new T
{ {
@ -76,7 +111,10 @@ namespace CryptoExchange.Net.Objects
} }
} }
public class SocketClientOptions: ExchangeOptions /// <summary>
/// Base for socket client options
/// </summary>
public class SocketClientOptions: ClientOptions
{ {
/// <summary> /// <summary>
/// Whether or not the socket should automatically reconnect when losing connection /// Whether or not the socket should automatically reconnect when losing connection

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -9,6 +10,9 @@ using CryptoExchange.Net.Sockets;
namespace CryptoExchange.Net.OrderBook namespace CryptoExchange.Net.OrderBook
{ {
/// <summary>
/// Base for order book implementations
/// </summary>
public abstract class SymbolOrderBook: IDisposable public abstract class SymbolOrderBook: IDisposable
{ {
protected readonly List<ProcessBufferEntry> processBuffer; protected readonly List<ProcessBufferEntry> processBuffer;
@ -112,21 +116,20 @@ namespace CryptoExchange.Net.OrderBook
} }
} }
protected SymbolOrderBook(string id, string symbol, bool sequencesAreConsecutive, LogVerbosity logVerbosity, IEnumerable<TextWriter> logWriters) protected SymbolOrderBook(string symbol, OrderBookOptions options)
{ {
this.id = id; id = options.OrderBookName;
processBuffer = new List<ProcessBufferEntry>(); processBuffer = new List<ProcessBufferEntry>();
this.sequencesAreConsecutive = sequencesAreConsecutive; sequencesAreConsecutive = options.SequenceNumbersAreConsecutive;
Symbol = symbol; Symbol = symbol;
Status = OrderBookStatus.Disconnected; Status = OrderBookStatus.Disconnected;
asks = new SortedList<decimal, OrderBookEntry>(); asks = new SortedList<decimal, OrderBookEntry>();
bids = new SortedList<decimal, OrderBookEntry>(new DescComparer<decimal>()); bids = new SortedList<decimal, OrderBookEntry>(new DescComparer<decimal>());
log = new Log { Level = logVerbosity }; log = new Log { Level = options.LogVerbosity };
if (logWriters == null) var writers = options.LogWriters ?? new List<TextWriter> { new DebugTextWriter() };
logWriters = new List<TextWriter> { new DebugTextWriter() }; log.UpdateWriters(writers.ToList());
log.UpdateWriters(logWriters.ToList());
} }
/// <summary> /// <summary>
@ -222,7 +225,7 @@ namespace CryptoExchange.Net.OrderBook
CheckProcessBuffer(); CheckProcessBuffer();
bookSet = true; 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 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<T> : IComparer<T> internal class DescComparer<T> : IComparer<T>

View File

@ -35,7 +35,7 @@ namespace CryptoExchange.Net
public IEnumerable<IRateLimiter> RateLimiters { get; private set; } public IEnumerable<IRateLimiter> RateLimiters { get; private set; }
public int TotalRequestsMade { 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); Configure(exchangeOptions);
} }
@ -44,7 +44,7 @@ namespace CryptoExchange.Net
/// Configure the client using the provided options /// Configure the client using the provided options
/// </summary> /// </summary>
/// <param name="exchangeOptions">Options</param> /// <param name="exchangeOptions">Options</param>
protected void Configure(ClientOptions exchangeOptions) protected void Configure(RestClientOptions exchangeOptions)
{ {
RequestTimeout = exchangeOptions.RequestTimeout; RequestTimeout = exchangeOptions.RequestTimeout;
RateLimitBehaviour = exchangeOptions.RateLimitingBehaviour; RateLimitBehaviour = exchangeOptions.RateLimitingBehaviour;

View File

@ -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. To stop synchronizing an order book use the `Stop` method.
## Release notes ## 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 * Added checks for json deserialization issues
* Version 2.1.3 - 16 may 2019 * Version 2.1.3 - 16 may 2019