Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
JKorf committed Oct 9, 2024
1 parent a381152 commit d36ff8d
Show file tree
Hide file tree
Showing 9 changed files with 510 additions and 21 deletions.
162 changes: 159 additions & 3 deletions Binance.Net/Binance.Net.xml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Binance.Net.Objects;
using Binance.Net.Objects.Internal;
using Binance.Net.Objects.Models;
using Binance.Net.Objects.Models.Futures;
using Binance.Net.Objects.Models.Futures.Socket;
using Binance.Net.Objects.Models.Spot.Socket;
using Binance.Net.Objects.Options;
Expand All @@ -32,6 +33,10 @@ internal partial class BinanceSocketClientUsdFuturesApi : SocketApiClient, IBina
#region fields
private static readonly MessagePath _idPath = MessagePath.Get().Property("id");
private static readonly MessagePath _streamPath = MessagePath.Get().Property("stream");

internal BinanceFuturesUsdtExchangeInfo? _exchangeInfo;
internal DateTime? _lastExchangeInfoUpdate;
internal readonly string _brokerId;
#endregion

/// <inheritdoc />
Expand All @@ -53,6 +58,8 @@ internal BinanceSocketClientUsdFuturesApi(ILogger logger, BinanceSocketOptions o
ExchangeData = new BinanceSocketClientUsdFuturesApiExchangeData(logger, this);
Trading = new BinanceSocketClientUsdFuturesApiTrading(logger, this);

_brokerId = !string.IsNullOrEmpty(options.UsdFuturesOptions.BrokerId) ? options.UsdFuturesOptions.BrokerId! : "x-d63tKbx3";

// When sending more than 4000 bytes the server responds very delayed (somehow connected to the websocket keep alive interval on framework level)
// See https://dev.binance.vision/t/socket-live-subscribing-server-delay/9645/2
// To prevent issues we keep below this
Expand Down Expand Up @@ -137,7 +144,6 @@ internal async Task<CallResult<BinanceResponse<T>>> QueryAsync<T>(string url, st
return result;
}


/// <inheritdoc />
protected override Query? GetAuthenticationRequest(SocketConnection connection) => null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Binance.Net.Clients.SpotApi;
using Binance.Net.Interfaces.Clients.UsdFuturesApi;
using Binance.Net.Objects;
using Binance.Net.Objects.Models;
using Binance.Net.Objects.Models.Futures;
using Binance.Net.Objects.Models.Futures.Socket;
using Binance.Net.Objects.Sockets;
using CryptoExchange.Net.Objects.Sockets;
Expand All @@ -23,6 +25,32 @@ internal BinanceSocketClientUsdFuturesApiAccount(ILogger logger, BinanceSocketCl

#region Queries


#region Future Account Balance

/// <inheritdoc />
public async Task<CallResult<BinanceResponse<IEnumerable<BinanceUsdFuturesAccountBalance>>>> GetBalancesAsync(long? receiveWindow = null, CancellationToken ct = default)
{
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("recvWindow", receiveWindow?.ToString(CultureInfo.InvariantCulture));

return await _client.QueryAsync<IEnumerable<BinanceUsdFuturesAccountBalance>>(_client.ClientOptions.Environment.UsdFuturesSocketApiAddress!.AppendPath("ws-fapi/v1"), $"v2/account.balance", parameters, true, true, weight: 5, ct: ct).ConfigureAwait(false);
}

#endregion

#region Get Account Info

/// <inheritdoc />
public async Task<CallResult<BinanceResponse<BinanceFuturesAccountInfoV3>>> GetAccountInfoAsync(long? receiveWindow = null, CancellationToken ct = default)
{
var parameters = new ParameterCollection();
parameters.AddOptionalParameter("recvWindow", receiveWindow?.ToString(CultureInfo.InvariantCulture));
return await _client.QueryAsync<BinanceFuturesAccountInfoV3>(_client.ClientOptions.Environment.UsdFuturesSocketApiAddress!.AppendPath("ws-fapi/v1"), $"v2/account.status", parameters, true, true, weight: 5, ct: ct).ConfigureAwait(false);
}

#endregion

#endregion

#region Streams
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Binance.Net.Interfaces.Clients.UsdFuturesApi;
using Binance.Net.Enums;
using Binance.Net.Interfaces.Clients.UsdFuturesApi;
using Binance.Net.Objects;
using Binance.Net.Objects.Models.Futures;
using System;
using System.Collections.Generic;
using System.Text;
Expand All @@ -18,6 +21,152 @@ internal BinanceSocketClientUsdFuturesApiTrading(ILogger logger, BinanceSocketCl

#region Queries

#region Place Order

/// <inheritdoc />
public async Task<CallResult<BinanceResponse<BinanceUsdFuturesOrder>>> PlaceOrderAsync(string symbol,
Enums.OrderSide side,
FuturesOrderType type,
decimal? quantity,
decimal? price = null,
Enums.PositionSide? positionSide = null,
TimeInForce? timeInForce = null,
bool? reduceOnly = null,
string? newClientOrderId = null,
decimal? stopPrice = null,
decimal? activationPrice = null,
decimal? callbackRate = null,
WorkingType? workingType = null,
bool? closePosition = null,
OrderResponseType? orderResponseType = null,
bool? priceProtect = null,
PriceMatch? priceMatch = null,
SelfTradePreventionMode? selfTradePreventionMode = null,
DateTime? goodTillDate = null,
int? receiveWindow = null,
CancellationToken ct = default)
{
if (closePosition == true && positionSide != null)
{
if (positionSide == Enums.PositionSide.Short && side == Enums.OrderSide.Sell)
throw new ArgumentException("Can't close short position with order side sell");
if (positionSide == Enums.PositionSide.Long && side == Enums.OrderSide.Buy)
throw new ArgumentException("Can't close long position with order side buy");
}

if (orderResponseType == OrderResponseType.Full)
throw new ArgumentException("OrderResponseType.Full is not supported in Futures");

string clientOrderId = newClientOrderId ?? ExchangeHelpers.AppendRandomString(_client._brokerId, 32);

var parameters = new ParameterCollection();
parameters.AddParameter("symbol", symbol);
parameters.AddEnum("side", side);
parameters.AddEnum("type", type);
parameters.AddOptionalParameter("quantity", quantity?.ToString(CultureInfo.InvariantCulture));
parameters.AddOptionalParameter("newClientOrderId", clientOrderId);
parameters.AddOptionalParameter("price", price?.ToString(CultureInfo.InvariantCulture));
parameters.AddOptionalEnum("timeInForce", timeInForce);
parameters.AddOptionalEnum("positionSide", positionSide);
parameters.AddOptionalParameter("stopPrice", stopPrice?.ToString(CultureInfo.InvariantCulture));
parameters.AddOptionalParameter("activationPrice", activationPrice?.ToString(CultureInfo.InvariantCulture));
parameters.AddOptionalParameter("callbackRate", callbackRate?.ToString(CultureInfo.InvariantCulture));
parameters.AddOptionalEnum("workingType", workingType);
parameters.AddOptionalParameter("reduceOnly", reduceOnly?.ToString().ToLower());
parameters.AddOptionalParameter("closePosition", closePosition?.ToString().ToLower());
parameters.AddOptionalEnum("newOrderRespType", orderResponseType);
parameters.AddOptionalParameter("priceProtect", priceProtect?.ToString().ToUpper());
parameters.AddOptionalEnum("priceMatch", priceMatch);
parameters.AddOptionalEnum("selfTradePreventionMode", selfTradePreventionMode);
parameters.AddOptionalMilliseconds("goodTillDate", goodTillDate);
parameters.AddOptionalParameter("recvWindow", receiveWindow?.ToString(CultureInfo.InvariantCulture));

return await _client.QueryAsync<BinanceUsdFuturesOrder>(_client.ClientOptions.Environment.UsdFuturesSocketApiAddress!.AppendPath("ws-fapi/v1"), $"order.place", parameters, true, true, weight: 0, ct: ct).ConfigureAwait(false);
}

#endregion

#region Edit Order

/// <inheritdoc />
public async Task<CallResult<BinanceResponse<BinanceUsdFuturesOrder>>> EditOrderAsync(string symbol, OrderSide side, decimal quantity, decimal price, long? orderId = null, string? origClientOrderId = null, long? receiveWindow = null, CancellationToken ct = default)
{
if (!orderId.HasValue && string.IsNullOrEmpty(origClientOrderId))
throw new ArgumentException("Either orderId or origClientOrderId must be sent");

var parameters = new ParameterCollection
{
{ "symbol", symbol },
{ "side", EnumConverter.GetString(side) },
{ "quantity", quantity.ToString(CultureInfo.InvariantCulture) },
{ "price", price.ToString(CultureInfo.InvariantCulture) },
};
parameters.AddOptionalParameter("orderId", orderId?.ToString(CultureInfo.InvariantCulture));
parameters.AddOptionalParameter("origClientOrderId", origClientOrderId);
parameters.AddOptionalParameter("recvWindow", receiveWindow?.ToString(CultureInfo.InvariantCulture));

return await _client.QueryAsync<BinanceUsdFuturesOrder>(_client.ClientOptions.Environment.UsdFuturesSocketApiAddress!.AppendPath("ws-fapi/v1"), $"order.modify", parameters, true, true, weight: 1, ct: ct).ConfigureAwait(false);

}

#endregion

#region Cancel Order

/// <inheritdoc />
public async Task<CallResult<BinanceResponse<BinanceUsdFuturesOrder>>> CancelOrderAsync(string symbol, long? orderId = null, string? origClientOrderId = null, long? receiveWindow = null, CancellationToken ct = default)
{
if (!orderId.HasValue && string.IsNullOrEmpty(origClientOrderId))
throw new ArgumentException("Either orderId or origClientOrderId must be sent");

var parameters = new ParameterCollection
{
{ "symbol", symbol }
};
parameters.AddOptionalParameter("orderId", orderId?.ToString(CultureInfo.InvariantCulture));
parameters.AddOptionalParameter("origClientOrderId", origClientOrderId);
parameters.AddOptionalParameter("recvWindow", receiveWindow?.ToString(CultureInfo.InvariantCulture));

return await _client.QueryAsync<BinanceUsdFuturesOrder>(_client.ClientOptions.Environment.UsdFuturesSocketApiAddress!.AppendPath("ws-fapi/v1"), $"order.cancel", parameters, true, true, weight: 1, ct: ct).ConfigureAwait(false);
}

#endregion

#region Get Order

/// <inheritdoc />
public async Task<CallResult<BinanceResponse<BinanceUsdFuturesOrder>>> GetOrderAsync(string symbol, long? orderId = null, string? origClientOrderId = null, long? receiveWindow = null, CancellationToken ct = default)
{
if (orderId == null && origClientOrderId == null)
throw new ArgumentException("Either orderId or origClientOrderId must be sent");

var parameters = new ParameterCollection
{
{ "symbol", symbol }
};
parameters.AddOptionalParameter("orderId", orderId?.ToString(CultureInfo.InvariantCulture));
parameters.AddOptionalParameter("origClientOrderId", origClientOrderId);
parameters.AddOptionalParameter("recvWindow", receiveWindow?.ToString(CultureInfo.InvariantCulture));

return await _client.QueryAsync<BinanceUsdFuturesOrder>(_client.ClientOptions.Environment.UsdFuturesSocketApiAddress!.AppendPath("ws-fapi/v1"), $"order.status", parameters, true, true, weight: 1, ct: ct).ConfigureAwait(false);
}

#endregion

#region Get Positions

/// <inheritdoc />
public async Task<CallResult<BinanceResponse<IEnumerable<BinancePositionV3>>>> GetPositionsAsync(string? symbol = null, long? receiveWindow = null, CancellationToken ct = default)
{
var parameters = new ParameterCollection();
parameters.AddOptional("symbol", symbol);
parameters.AddOptionalParameter("recvWindow", receiveWindow?.ToString(CultureInfo.InvariantCulture));

return await _client.QueryAsync<IEnumerable<BinancePositionV3>>(_client.ClientOptions.Environment.UsdFuturesSocketApiAddress!.AppendPath("ws-fapi/v1"), $"v2/account.position", parameters, true, true, weight: 5, ct: ct).ConfigureAwait(false);
}

#endregion

#endregion

#region Streams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ Task<WebCallResult<IEnumerable<BinanceFuturesQuantileEstimation>>> GetPositionAd
/// <param name="ct">Cancellation token</param>
Task<WebCallResult<BinanceFuturesAccountInfoV3>> GetAccountInfoV3Async(long? receiveWindow = null, CancellationToken ct = default);

/// <summary>.
/// <summary>
/// Gets account balances
/// <para><a href="https://binance-docs.github.io/apidocs/futures/en/#futures-account-balance-v2-user_data" /></para>
/// </summary>
Expand All @@ -149,7 +149,7 @@ Task<WebCallResult<IEnumerable<BinanceFuturesQuantileEstimation>>> GetPositionAd
/// <returns>The account information</returns>
Task<WebCallResult<IEnumerable<BinanceUsdFuturesAccountBalance>>> GetBalancesAsync(long? receiveWindow = null, CancellationToken ct = default);

/// <summary>.
/// <summary>
/// Get user's Multi-Assets mode (Multi-Assets Mode or Single-Asset Mode) on Every symbol
/// <para><a href="https://binance-docs.github.io/apidocs/futures/en/#get-current-multi-assets-mode-user_data" /></para>
/// </summary>
Expand All @@ -158,7 +158,7 @@ Task<WebCallResult<IEnumerable<BinanceFuturesQuantileEstimation>>> GetPositionAd
/// <returns>Multi asset mode</returns>
Task<WebCallResult<BinanceFuturesMultiAssetMode>> GetMultiAssetsModeAsync(long? receiveWindow = null, CancellationToken ct = default);

/// <summary>.
/// <summary>
/// Set user's Multi-Assets mode (Multi-Assets Mode or Single-Asset Mode) on Every symbol
/// <para><a href="https://binance-docs.github.io/apidocs/futures/en/#change-multi-assets-mode-trade" /></para>
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Binance.Net.Enums;
using Binance.Net.Objects;
using Binance.Net.Objects.Models;
using Binance.Net.Objects.Models.Futures;
using Binance.Net.Objects.Models.Futures.Socket;
using Binance.Net.Objects.Models.Spot.Socket;
using CryptoExchange.Net.Objects.Sockets;
Expand All @@ -11,6 +13,23 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi
/// </summary>
public interface IBinanceSocketClientUsdFuturesApiAccount
{
/// <summary>
/// Gets account balances
/// <para><a href="https://binance-docs.github.io/apidocs/futures/en/#futures-account-balance-v2-user_data" /></para>
/// </summary>
/// <param name="receiveWindow">The receive window for which this request is active. When the request takes longer than this to complete the server will reject the request</param>
/// <param name="ct">Cancellation token</param>
/// <returns>The account information</returns>
Task<CallResult<BinanceResponse<IEnumerable<BinanceUsdFuturesAccountBalance>>>> GetBalancesAsync(long? receiveWindow = null, CancellationToken ct = default);

/// <summary>
/// Get account information, including position and balances
/// <para><a href="https://developers.binance.com/docs/derivatives/usds-margined-futures/account/rest-api/Account-Information-V3" /></para>
/// </summary>
/// <param name="receiveWindow">The receive window for which this request is active. When the request takes longer than this to complete the server will reject the request</param>
/// <param name="ct">Cancellation token</param>
Task<CallResult<BinanceResponse<BinanceFuturesAccountInfoV3>>> GetAccountInfoAsync(long? receiveWindow = null, CancellationToken ct = default);

/// <summary>
/// Subscribes to the account update stream. Prior to using this, the <see cref="IBinanceRestClientUsdFuturesApiAccount.StartUserStreamAsync(CancellationToken)">restClient.UsdFuturesApi.Account.StartUserStreamAsync</see> method should be called to start the stream and obtaining a listen key.
/// <para><a href="https://binance-docs.github.io/apidocs/futures/en/#user-data-streams" /></para>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,47 @@ namespace Binance.Net.Interfaces.Clients.UsdFuturesApi
/// </summary>
public interface IBinanceSocketClientUsdFuturesApiExchangeData
{
/// <summary>
/// Gets the order book for the provided symbol
/// <para><a href="https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/websocket-api" /></para>
/// </summary>
/// <param name="symbol">The symbol to get the order book for, for example `ETHUSDT`</param>
/// <param name="limit">Max number of results</param>
/// <param name="ct">Cancellation token</param>
Task<CallResult<BinanceResponse<BinanceFuturesOrderBook>>> GetOrderBookAsync(string symbol, int? limit = null, CancellationToken ct = default);

/// <summary>
/// Gets the price of a symbol
/// <para><a href="https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/websocket-api/Symbol-Price-Ticker" /></para>
/// </summary>
/// <param name="symbol">The symbol to get the price for, for example `ETHUSDT`</param>
/// <param name="ct">Cancellation token</param>
/// <returns>Price of symbol</returns>
Task<CallResult<BinanceResponse<BinancePrice>>> GetPriceAsync(string symbol, CancellationToken ct = default);

/// <summary>
/// Gets the price of all symbols
/// <para><a href="https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/websocket-api/Symbol-Price-Ticker" /></para>
/// </summary>
/// <param name="ct">Cancellation token</param>
/// <returns>Price of symbol</returns>
Task<CallResult<BinanceResponse<IEnumerable<BinancePrice>>>> GetPricesAsync(CancellationToken ct = default);

/// <summary>
/// Gets the best price/quantity on the order book for a symbol.
/// <para><a href="https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/websocket-api/Symbol-Order-Book-Ticker" /></para>
/// </summary>
/// <param name="symbol">Symbol to get book price for, for example `ETHUSDT`</param>
/// <param name="ct">Cancellation token</param>
/// <returns>List of book prices</returns>
Task<CallResult<BinanceResponse<BinanceBookPrice>>> GetBookPriceAsync(string symbol, CancellationToken ct = default);

/// <summary>
/// Gets the best price/quantity on the order book for all symbols.
/// <para><a href="https://developers.binance.com/docs/derivatives/usds-margined-futures/market-data/websocket-api/Symbol-Order-Book-Ticker" /></para>
/// </summary>
/// <param name="ct">Cancellation token</param>
/// <returns>List of book prices</returns>
Task<CallResult<BinanceResponse<IEnumerable<BinanceBookPrice>>>> GetBookPricesAsync(CancellationToken ct = default);

/// <summary>
Expand Down
Loading

0 comments on commit d36ff8d

Please sign in to comment.