Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/shared #77

Merged
merged 50 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
23e952a
wip
JKorf Aug 9, 2024
fd18f57
wip
JKorf Aug 9, 2024
c934b90
wip
JKorf Aug 11, 2024
f664186
wip
JKorf Aug 12, 2024
f725602
wip
JKorf Aug 12, 2024
7534107
wip
JKorf Aug 13, 2024
dfdf784
wip
JKorf Aug 14, 2024
2dd74f5
wip
JKorf Aug 14, 2024
c03f533
wip
JKorf Aug 15, 2024
3845c9f
wip
JKorf Aug 15, 2024
72da8a3
wip
JKorf Aug 16, 2024
7fe16c1
wip
JKorf Aug 18, 2024
7877c93
Merge branch 'master' into feature/shared
JKorf Aug 19, 2024
cbfc488
wip
JKorf Aug 20, 2024
718484a
wip
JKorf Aug 22, 2024
2b4080e
wip
JKorf Aug 25, 2024
0f3788f
wip
JKorf Aug 25, 2024
adb0269
wip
JKorf Aug 28, 2024
653629a
wip
JKorf Sep 1, 2024
c52dcfc
Merge branch 'master' into feature/shared
JKorf Sep 2, 2024
cb9cd1d
wip
JKorf Sep 2, 2024
80ee78d
wip
JKorf Sep 3, 2024
132388e
wip
JKorf Sep 4, 2024
e79e7d5
wip
JKorf Sep 4, 2024
00db58f
wip
JKorf Sep 4, 2024
dea3c55
wip
JKorf Sep 5, 2024
3fe2998
wip
JKorf Sep 5, 2024
386e935
wip
JKorf Sep 6, 2024
05bcb0d
wip
JKorf Sep 9, 2024
35a9f22
wip
JKorf Sep 10, 2024
d0b6004
wip
JKorf Sep 10, 2024
6d07508
wip
JKorf Sep 10, 2024
6bbcdcf
Merge branch 'master' into feature/shared
JKorf Sep 11, 2024
527a18a
wip
JKorf Sep 12, 2024
3812793
wip
JKorf Sep 12, 2024
0d57cbb
wip
JKorf Sep 13, 2024
0b11d3b
wip
JKorf Sep 17, 2024
be03cca
wip
JKorf Sep 18, 2024
d8fb53a
wip
JKorf Sep 19, 2024
a020795
wip
JKorf Sep 20, 2024
4a29838
wip
JKorf Sep 22, 2024
377782e
wip
JKorf Sep 23, 2024
dcd2496
wip
JKorf Sep 23, 2024
a256563
wip
JKorf Sep 24, 2024
85d44e7
wip
JKorf Sep 25, 2024
83e283e
wip
JKorf Sep 25, 2024
4cfb1f6
wip
JKorf Sep 25, 2024
f86ae91
wip
JKorf Sep 26, 2024
b81c5e6
wip
JKorf Sep 27, 2024
50b2ab6
Update CoinEx.Net.csproj
JKorf Sep 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading