Skip to content

Commit

Permalink
CryptoExchange.Net v8.0.0, shared interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
JKorf authored Sep 27, 2024
1 parent 0a75c41 commit 37123db
Show file tree
Hide file tree
Showing 27 changed files with 2,120 additions and 36 deletions.
7 changes: 5 additions & 2 deletions CoinEx.Net/Clients/FuturesApi/CoinExRestClientFuturesApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
using CryptoExchange.Net.Converters.SystemTextJson;
using CoinEx.Net.Objects.Models.V2;
using CoinEx.Net.Interfaces.Clients.FuturesApi;
using CryptoExchange.Net.SharedApis;

namespace CoinEx.Net.Clients.FuturesApi
{
/// <inheritdoc cref="ICoinExRestClientFuturesApi" />
internal class CoinExRestClientFuturesApi : RestApiClient, ICoinExRestClientFuturesApi
internal partial class CoinExRestClientFuturesApi : RestApiClient, ICoinExRestClientFuturesApi
{
#region fields
internal TimeSyncState _timeSyncState = new TimeSyncState("CoinEx V2 API");
Expand Down Expand Up @@ -58,13 +59,15 @@ internal CoinExRestClientFuturesApi(ILogger logger, HttpClient? httpClient, Coin
#endregion

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

/// <inheritdoc />
protected override IStreamMessageAccessor CreateAccessor() => new SystemTextJsonStreamMessageAccessor();
/// <inheritdoc />
protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer();

public ICoinExRestClientFuturesApiShared SharedClient => this;

/// <inheritdoc />
protected override AuthenticationProvider CreateAuthenticationProvider(ApiCredentials credentials)
=> new CoinExV2AuthenticationProvider(credentials);
Expand Down
769 changes: 769 additions & 0 deletions CoinEx.Net/Clients/FuturesApi/CoinExRestClientFuturesApiShared.cs

Large diffs are not rendered by default.

10 changes: 7 additions & 3 deletions CoinEx.Net/Clients/FuturesApi/CoinExSocketClientFuturesApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@
using CoinEx.Net.Objects.Sockets.V2.Queries;
using System.Linq;
using CoinEx.Net.Interfaces.Clients.FuturesApi;
using CryptoExchange.Net.SharedApis;

namespace CoinEx.Net.Clients.FuturesApi
{
/// <inheritdoc cref="ICoinExSocketClientFuturesApi" />
internal class CoinExSocketClientFuturesApi : SocketApiClient, ICoinExSocketClientFuturesApi
internal partial class CoinExSocketClientFuturesApi : SocketApiClient, ICoinExSocketClientFuturesApi
{
#region fields
/// <inheritdoc />
Expand Down Expand Up @@ -51,14 +52,17 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden
=> new CoinExV2AuthenticationProvider(credentials);

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

#region methods

/// <inheritdoc />
protected override IByteMessageAccessor CreateAccessor() => new SystemTextJsonByteMessageAccessor();
/// <inheritdoc />
protected override IMessageSerializer CreateSerializer() => new SystemTextJsonMessageSerializer();

public ICoinExSocketClientFuturesApiShared SharedClient => this;

/// <inheritdoc />
public override string? GetListenerIdentifier(IMessageAccessor messageAccessor)
{
Expand Down Expand Up @@ -95,7 +99,7 @@ public override ReadOnlyMemory<byte> PreprocessStreamMessage(SocketConnection co
/// <inheritdoc />
public async Task<CallResult<UpdateSubscription>> SubscribeToTickerUpdatesAsync(IEnumerable<string> symbols, Action<DataEvent<IEnumerable<CoinExFuturesTickerUpdate>>> onMessage, CancellationToken ct = default)
{
var subscription = new CoinExFuturesTickerSubscription(_logger, null, new Dictionary<string, object>
var subscription = new CoinExFuturesTickerSubscription(_logger, symbols, new Dictionary<string, object>
{
{ "market_list", symbols }
}, onMessage);
Expand Down
225 changes: 225 additions & 0 deletions CoinEx.Net/Clients/FuturesApi/CoinExSocketClientFuturesApiShared.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
using CoinEx.Net.Enums;
using CoinEx.Net.Interfaces.Clients.FuturesApi;
using CoinEx.Net.Objects.Models.V2;
using CryptoExchange.Net.Objects;
using CryptoExchange.Net.Objects.Sockets;
using CryptoExchange.Net.SharedApis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace CoinEx.Net.Clients.FuturesApi
{
internal partial class CoinExSocketClientFuturesApi : ICoinExSocketClientFuturesApiShared
{
public string Exchange => CoinExExchange.ExchangeName;
public TradingMode[] SupportedTradingModes { get; } = new[] { TradingMode.PerpetualLinear, TradingMode.PerpetualInverse };
public void SetDefaultExchangeParameter(string key, object value) => ExchangeParameters.SetStaticParameter(Exchange, key, value);
public void ResetDefaultExchangeParameters() => ExchangeParameters.ResetStaticParameters();

#region Tickers client
EndpointOptions<SubscribeAllTickersRequest> ITickersSocketClient.SubscribeAllTickersOptions { get; } = new EndpointOptions<SubscribeAllTickersRequest>(false);
async Task<ExchangeResult<UpdateSubscription>> ITickersSocketClient.SubscribeToAllTickersUpdatesAsync(SubscribeAllTickersRequest request, Action<ExchangeEvent<IEnumerable<SharedSpotTicker>>> handler, CancellationToken ct)
{
var validationError = ((ITickersSocketClient)this).SubscribeAllTickersOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var result = await SubscribeToTickerUpdatesAsync(update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedSpotTicker(x.Symbol, x.LastPrice, x.HighPrice, x.LowPrice, x.Volume, x.OpenPrice == 0 ? null : Math.Round(x.LastPrice / x.OpenPrice * 100 - 100, 2))))), ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}

#endregion

#region Ticker client
EndpointOptions<SubscribeTickerRequest> ITickerSocketClient.SubscribeTickerOptions { get; } = new EndpointOptions<SubscribeTickerRequest>(false);
async Task<ExchangeResult<UpdateSubscription>> ITickerSocketClient.SubscribeToTickerUpdatesAsync(SubscribeTickerRequest request, Action<ExchangeEvent<SharedSpotTicker>> handler, CancellationToken ct)
{
var validationError = ((ITickerSocketClient)this).SubscribeTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var symbol = request.Symbol.GetSymbol(FormatSymbol);
var result = await SubscribeToTickerUpdatesAsync(new[] { symbol }, update =>
{
var ticker = update.Data.Single();
handler(update.AsExchangeEvent(Exchange, new SharedSpotTicker(symbol, ticker.LastPrice, ticker.HighPrice, ticker.LowPrice, ticker.Volume, Math.Round(ticker.LastPrice / ticker.OpenPrice * 100 - 100, 2))));
}, ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region Trade client

EndpointOptions<SubscribeTradeRequest> ITradeSocketClient.SubscribeTradeOptions { get; } = new EndpointOptions<SubscribeTradeRequest>(false);
async Task<ExchangeResult<UpdateSubscription>> ITradeSocketClient.SubscribeToTradeUpdatesAsync(SubscribeTradeRequest request, Action<ExchangeEvent<IEnumerable<SharedTrade>>> handler, CancellationToken ct)
{
var validationError = ((ITradeSocketClient)this).SubscribeTradeOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var symbol = request.Symbol.GetSymbol(FormatSymbol);
var result = await SubscribeToTradeUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedTrade(x.Quantity, x.Price, x.Timestamp)))), ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region Book Ticker client

EndpointOptions<SubscribeBookTickerRequest> IBookTickerSocketClient.SubscribeBookTickerOptions { get; } = new EndpointOptions<SubscribeBookTickerRequest>(false);
async Task<ExchangeResult<UpdateSubscription>> IBookTickerSocketClient.SubscribeToBookTickerUpdatesAsync(SubscribeBookTickerRequest request, Action<ExchangeEvent<SharedBookTicker>> handler, CancellationToken ct)
{
var validationError = ((IBookTickerSocketClient)this).SubscribeBookTickerOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var symbol = request.Symbol.GetSymbol(FormatSymbol);
var result = await SubscribeToBookPriceUpdatesAsync(symbol, update => handler(update.AsExchangeEvent(Exchange, new SharedBookTicker(update.Data.BestAskPrice, update.Data.BestAskQuantity, update.Data.BestBidPrice, update.Data.BestBidQuantity))), ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region Order Book client
SubscribeOrderBookOptions IOrderBookSocketClient.SubscribeOrderBookOptions { get; } = new SubscribeOrderBookOptions(false, new[] { 5, 10, 20, 50 });
async Task<ExchangeResult<UpdateSubscription>> IOrderBookSocketClient.SubscribeToOrderBookUpdatesAsync(SubscribeOrderBookRequest request, Action<ExchangeEvent<SharedOrderBook>> handler, CancellationToken ct)
{
var validationError = ((IOrderBookSocketClient)this).SubscribeOrderBookOptions.ValidateRequest(Exchange, request, request.Symbol.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var symbol = request.Symbol.GetSymbol(FormatSymbol);
var result = await SubscribeToOrderBookUpdatesAsync(symbol, request.Limit ?? 20, null, true, update => handler(update.AsExchangeEvent(Exchange, new SharedOrderBook(update.Data.Data.Asks, update.Data.Data.Bids))), ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region Balance client
EndpointOptions<SubscribeBalancesRequest> IBalanceSocketClient.SubscribeBalanceOptions { get; } = new EndpointOptions<SubscribeBalancesRequest>(false);
async Task<ExchangeResult<UpdateSubscription>> IBalanceSocketClient.SubscribeToBalanceUpdatesAsync(SubscribeBalancesRequest request, Action<ExchangeEvent<IEnumerable<SharedBalance>>> handler, CancellationToken ct)
{
var validationError = ((IBalanceSocketClient)this).SubscribeBalanceOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);
var result = await SubscribeToBalanceUpdatesAsync(
update => handler(update.AsExchangeEvent(Exchange, update.Data.Select(x => new SharedBalance(x.Asset, x.Available, x.Available + x.Frozen)))),
ct: ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region Spot Order client

EndpointOptions<SubscribeFuturesOrderRequest> IFuturesOrderSocketClient.SubscribeFuturesOrderOptions { get; } = new EndpointOptions<SubscribeFuturesOrderRequest>(false);
async Task<ExchangeResult<UpdateSubscription>> IFuturesOrderSocketClient.SubscribeToFuturesOrderUpdatesAsync(SubscribeFuturesOrderRequest request, Action<ExchangeEvent<IEnumerable<SharedFuturesOrder>>> handler, CancellationToken ct)
{
var validationError = ((IFuturesOrderSocketClient)this).SubscribeFuturesOrderOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var result = await SubscribeToOrderUpdatesAsync(
update => handler(update.AsExchangeEvent<IEnumerable<SharedFuturesOrder>>(Exchange, new[] {
new SharedFuturesOrder(
update.Data.Order.Symbol,
update.Data.Order.Id.ToString(),
update.Data.Order.OrderType == Enums.OrderTypeV2.Limit ? SharedOrderType.Limit : update.Data.Order.OrderType == Enums.OrderTypeV2.Market ? SharedOrderType.Market : SharedOrderType.Other,
update.Data.Order.Side == Enums.OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell,
GetOrderStatus(update.Data),
update.Data.Order.CreateTime)
{
ClientOrderId = update.Data.Order.ClientOrderId?.ToString(),
Quantity = update.Data.Order.Quantity,
QuantityFilled = update.Data.Order.QuantityFilled,
QuoteQuantityFilled = update.Data.Order.ValueFilled,
UpdateTime = update.Data.Order.UpdateTime,
OrderPrice = update.Data.Order.Price,
Fee = update.Data.Order.Fee,
FeeAsset = update.Data.Order.FeeAsset
}
})),
ct: ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region User Trade client
EndpointOptions<SubscribeUserTradeRequest> IUserTradeSocketClient.SubscribeUserTradeOptions { get; } = new EndpointOptions<SubscribeUserTradeRequest>(false);
async Task<ExchangeResult<UpdateSubscription>> IUserTradeSocketClient.SubscribeToUserTradeUpdatesAsync(SubscribeUserTradeRequest request, Action<ExchangeEvent<IEnumerable<SharedUserTrade>>> handler, CancellationToken ct)
{
var validationError = ((IUserTradeSocketClient)this).SubscribeUserTradeOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var result = await SubscribeToUserTradeUpdatesAsync(
update => handler(update.AsExchangeEvent<IEnumerable<SharedUserTrade>>(Exchange, new[] {
new SharedUserTrade(
update.Data.Symbol,
update.Data.OrderId.ToString(),
update.Data.Id.ToString(),
update.Data.Side == OrderSide.Buy ? SharedOrderSide.Buy : SharedOrderSide.Sell,
update.Data.Quantity,
update.Data.Price,
update.Data.CreateTime)
{
Fee = update.Data.Fee,
FeeAsset = update.Data.FeeAsset,
Role = update.Data.Role == Enums.TransactionRole.Maker ? SharedRole.Maker : SharedRole.Taker
}
})),
ct: ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}
#endregion

#region Position client
EndpointOptions<SubscribePositionRequest> IPositionSocketClient.SubscribePositionOptions { get; } = new EndpointOptions<SubscribePositionRequest>(true);
async Task<ExchangeResult<UpdateSubscription>> IPositionSocketClient.SubscribeToPositionUpdatesAsync(SubscribePositionRequest request, Action<ExchangeEvent<IEnumerable<SharedPosition>>> handler, CancellationToken ct)
{
var validationError = ((IPositionSocketClient)this).SubscribePositionOptions.ValidateRequest(Exchange, request, request.TradingMode, SupportedTradingModes);
if (validationError != null)
return new ExchangeResult<UpdateSubscription>(Exchange, validationError);

var result = await SubscribeToPositionUpdatesAsync(
update => handler(update.AsExchangeEvent<IEnumerable<SharedPosition>>(Exchange, new[] { new SharedPosition(update.Data.Position.Symbol, update.Data.Position.OpenInterest, update.Data.Position.UpdateTime)
{
AverageOpenPrice = update.Data.Position.AverageEntryPrice,
PositionSide = update.Data.Position.Side == Enums.PositionSide.Short ? SharedPositionSide.Short : SharedPositionSide.Long,
LiquidationPrice = update.Data.Position.LiquidationPrice,
Leverage = update.Data.Position.Leverage,
UnrealizedPnl = update.Data.Position.UnrealizedPnl
} })),
ct: ct).ConfigureAwait(false);

return new ExchangeResult<UpdateSubscription>(Exchange, result);
}

#endregion

private SharedOrderStatus GetOrderStatus(CoinExFuturesOrderUpdate update)
{
if (update.Order.QuantityFilled == update.Order.Quantity)
return SharedOrderStatus.Filled;

if (update.Event != Enums.OrderUpdateType.Finish)
{
return SharedOrderStatus.Open;
}
else
{
if (update.Order.QuantityFilled != update.Order.Quantity)
return SharedOrderStatus.Canceled;

return SharedOrderStatus.Filled;
}
}
}
}
3 changes: 2 additions & 1 deletion CoinEx.Net/Clients/SpotApiV1/CoinExRestClientSpotApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
using CryptoExchange.Net.Converters.MessageParsing;
using CryptoExchange.Net.Clients;
using CoinEx.Net.Interfaces.Clients.SpotApiV1;
using CryptoExchange.Net.SharedApis;

namespace CoinEx.Net.Clients.SpotApiV1
{
Expand Down Expand Up @@ -73,7 +74,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden
=> new CoinExAuthenticationProvider(credentials, ClientOptions.NonceProvider ?? new CoinExNonceProvider());

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

#region methods
#region private
Expand Down
3 changes: 2 additions & 1 deletion CoinEx.Net/Clients/SpotApiV1/CoinExSocketClientSpotApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
using CryptoExchange.Net.Converters.MessageParsing;
using CryptoExchange.Net.Clients;
using CoinEx.Net.Interfaces.Clients.SpotApiV1;
using CryptoExchange.Net.SharedApis;

namespace CoinEx.Net.Clients.SpotApiV1
{
Expand Down Expand Up @@ -59,7 +60,7 @@ protected override AuthenticationProvider CreateAuthenticationProvider(ApiCreden
=> new CoinExAuthenticationProvider(credentials, ClientOptions.NonceProvider ?? new CoinExNonceProvider());

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

#region methods

Expand Down
Loading

0 comments on commit 37123db

Please sign in to comment.