Skip to content

Commit

Permalink
Shared exchange functionality (#214)
Browse files Browse the repository at this point in the history
  • Loading branch information
JKorf authored Sep 27, 2024
1 parent 5d3de52 commit b8686d6
Show file tree
Hide file tree
Showing 199 changed files with 7,219 additions and 277 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using CryptoExchange.Net.Clients;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Options;
using CryptoExchange.Net.SharedApis;
using CryptoExchange.Net.UnitTests.TestImplementations;
using Microsoft.Extensions.Logging;

Expand Down Expand Up @@ -55,7 +56,7 @@ public CallResult<T> Deserialize<T>(string data)
}

/// <inheritdoc />
public override string FormatSymbol(string baseAsset, string quoteAsset) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";
public override TimeSpan? GetTimeOffset() => null;
public override TimeSyncInfo GetTimeSyncInfo() => null;
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using CryptoExchange.Net.Objects.Options;
using Microsoft.Extensions.Logging;
using CryptoExchange.Net.Clients;
using CryptoExchange.Net.SharedApis;

namespace CryptoExchange.Net.UnitTests.TestImplementations
{
Expand Down Expand Up @@ -138,7 +139,7 @@ public TestRestApi1Client(TestClientOptions options) : base(new TraceLogger(), n
}

/// <inheritdoc />
public override string FormatSymbol(string baseAsset, string quoteAsset) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";

public async Task<CallResult<T>> Request<T>(CancellationToken ct = default) where T : class
{
Expand Down Expand Up @@ -182,7 +183,7 @@ public TestRestApi2Client(TestClientOptions options) : base(new TraceLogger(), n
}

/// <inheritdoc />
public override string FormatSymbol(string baseAsset, string quoteAsset) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";

public async Task<CallResult<T>> Request<T>(CancellationToken ct = default) where T : class
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.Extensions.Logging;
using Moq;
using CryptoExchange.Net.Testing.Implementations;
using CryptoExchange.Net.SharedApis;

namespace CryptoExchange.Net.UnitTests.TestImplementations
{
Expand Down Expand Up @@ -86,7 +87,7 @@ public TestSubSocketClient(TestSocketOptions options, SocketApiOptions apiOption
}

/// <inheritdoc />
public override string FormatSymbol(string baseAsset, string quoteAsset) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";
public override string FormatSymbol(string baseAsset, string quoteAsset, TradingMode futuresType, DateTime? deliverDate = null) => $"{baseAsset.ToUpperInvariant()}{quoteAsset.ToUpperInvariant()}";

internal IWebsocket CreateSocketInternal(string address)
{
Expand Down
4 changes: 3 additions & 1 deletion CryptoExchange.Net/Clients/BaseApiClient.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Interfaces;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Options;
using CryptoExchange.Net.SharedApis;
using Microsoft.Extensions.Logging;

namespace CryptoExchange.Net.Clients
Expand Down Expand Up @@ -76,7 +78,7 @@ protected BaseApiClient(ILogger logger, bool outputOriginalData, ApiCredentials?
protected abstract AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials);

/// <inheritdoc />
public abstract string FormatSymbol(string baseAsset, string quoteAsset);
public abstract string FormatSymbol(string baseAsset, string quoteAsset, TradingMode tradingMode, DateTime? deliverDate = null);

/// <inheritdoc />
public void SetApiCredentials<T>(T credentials) where T : ApiCredentials
Expand Down
1 change: 0 additions & 1 deletion CryptoExchange.Net/Clients/RestApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
using CryptoExchange.Net.RateLimiting.Interfaces;
using CryptoExchange.Net.Requests;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace CryptoExchange.Net.Clients
{
Expand Down
1 change: 0 additions & 1 deletion CryptoExchange.Net/Clients/SocketApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
using CryptoExchange.Net.Sockets;
using Microsoft.Extensions.Logging;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
Expand Down
3 changes: 1 addition & 2 deletions CryptoExchange.Net/Converters/JsonNet/DateTimeConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Primitives;
using System;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.Serialization;
using System.Text;
using System.Text.Json.Serialization;
using System.Text.Json;
using System.Globalization;

namespace CryptoExchange.Net.Converters.SystemTextJson
{
Expand Down
2 changes: 1 addition & 1 deletion CryptoExchange.Net/CryptoExchange.Net.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
</PropertyGroup>
<ItemGroup Label="Deterministic Build" Condition="'$(Configuration)' == 'Release'">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
Expand Down
104 changes: 100 additions & 4 deletions CryptoExchange.Net/ExchangeHelpers.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.SharedApis;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;

namespace CryptoExchange.Net
{
Expand All @@ -12,6 +16,22 @@ public static class ExchangeHelpers
{
private const string _allowedRandomChars = "ABCDEFGHIJKLMONOPQRSTUVWXYZabcdefghijklmonopqrstuvwxyz0123456789";

private static readonly Dictionary<int, string> _monthSymbols = new Dictionary<int, string>()
{
{ 1, "F" },
{ 2, "G" },
{ 3, "H" },
{ 4, "J" },
{ 5, "K" },
{ 6, "M" },
{ 7, "N" },
{ 8, "Q" },
{ 9, "U" },
{ 10, "V" },
{ 11, "X" },
{ 12, "Z" },
};

/// <summary>
/// The last used id, use NextId() to get the next id and up this
/// </summary>
Expand Down Expand Up @@ -55,6 +75,11 @@ public static decimal AdjustValueStep(decimal min, decimal max, decimal? step, R
{
value -= offset;
}
else if(roundingType == RoundingType.Up)
{
if (offset != 0)
value += (step.Value - offset);
}
else
{
if (offset < step / 2)
Expand Down Expand Up @@ -107,17 +132,23 @@ public static decimal RoundToSignificantDigits(decimal value, int digits, Roundi
}

/// <summary>
/// Rounds a value down to
/// Rounds a value down
/// </summary>
/// <param name="i"></param>
/// <param name="decimalPlaces"></param>
/// <returns></returns>
public static decimal RoundDown(decimal i, double decimalPlaces)
{
var power = Convert.ToDecimal(Math.Pow(10, decimalPlaces));
return Math.Floor(i * power) / power;
}

/// <summary>
/// Rounds a value up
/// </summary>
public static decimal RoundUp(decimal i, double decimalPlaces)
{
var power = Convert.ToDecimal(Math.Pow(10, decimalPlaces));
return Math.Ceiling(i * power) / power;
}

/// <summary>
/// Strips any trailing zero's of a decimal value, useful when converting the value to string.
/// </summary>
Expand Down Expand Up @@ -177,5 +208,70 @@ public static string AppendRandomString(string source, int totalLength)

return source + RandomString(totalLength - source.Length);
}

/// <summary>
/// Get the month representation for futures symbol based on the delivery month
/// </summary>
/// <param name="time">Delivery time</param>
/// <returns></returns>
public static string GetDeliveryMonthSymbol(DateTime time) => _monthSymbols[time.Month];

/// <summary>
/// Execute multiple requests to retrieve multiple pages of the result set
/// </summary>
/// <typeparam name="T">Type of the client</typeparam>
/// <typeparam name="U">Type of the request</typeparam>
/// <param name="paginatedFunc">The func to execute with each request</param>
/// <param name="request">The request parameters</param>
/// <param name="ct">Cancellation token</param>
/// <returns></returns>
public static async IAsyncEnumerable<ExchangeWebResult<IEnumerable<T>>> ExecutePages<T, U>(Func<U, INextPageToken?, CancellationToken, Task<ExchangeWebResult<IEnumerable<T>>>> paginatedFunc, U request, [EnumeratorCancellation]CancellationToken ct = default)
{
var result = new List<T>();
ExchangeWebResult<IEnumerable<T>> batch;
INextPageToken? nextPageToken = null;
while (true)
{
batch = await paginatedFunc(request, nextPageToken, ct).ConfigureAwait(false);
yield return batch;
if (!batch || ct.IsCancellationRequested)
break;

result.AddRange(batch.Data);
nextPageToken = batch.NextPageToken;
if (nextPageToken == null)
break;
}
}

/// <summary>
/// Apply the rules (price and quantity step size and decimals precision, min/max quantity) from the symbol to the quantity and price
/// </summary>
/// <param name="symbol">The symbol as retrieved from the exchange</param>
/// <param name="quantity">Quantity to trade</param>
/// <param name="price">Price to trade at</param>
/// <param name="adjustedQuantity">Quantity adjusted to match all trading rules</param>
/// <param name="adjustedPrice">Price adjusted to match all trading rules</param>
public static void ApplySymbolRules(SharedSpotSymbol symbol, decimal quantity, decimal? price, out decimal adjustedQuantity, out decimal? adjustedPrice)
{
adjustedPrice = price;
adjustedQuantity = quantity;
var minNotionalAdjust = false;

if (price != null)
{
adjustedPrice = AdjustValueStep(0, decimal.MaxValue, symbol.PriceStep, RoundingType.Down, price.Value);
adjustedPrice = symbol.PriceDecimals.HasValue ? RoundDown(price.Value, symbol.PriceDecimals.Value) : adjustedPrice;
if (adjustedPrice != 0 && adjustedPrice * quantity < symbol.MinNotionalValue)
{
adjustedQuantity = symbol.MinNotionalValue.Value / adjustedPrice.Value;
minNotionalAdjust = true;
}
}

adjustedQuantity = AdjustValueStep(symbol.MinTradeQuantity ?? 0, symbol.MaxTradeQuantity ?? decimal.MaxValue, symbol.QuantityStep, minNotionalAdjust ? RoundingType.Up : RoundingType.Down, adjustedQuantity);
adjustedQuantity = symbol.QuantityDecimals.HasValue ? (minNotionalAdjust ? RoundUp(adjustedQuantity, symbol.QuantityDecimals.Value) : RoundDown(adjustedQuantity, symbol.QuantityDecimals.Value)) : adjustedQuantity;

}
}
}
Loading

0 comments on commit b8686d6

Please sign in to comment.