/// <summary> /// Get older (non-compressed) trades. /// </summary> /// <param name="client"></param> /// <param name="apiKey"></param> /// <param name="symbol"></param> /// <param name="fromId">TradeId to fetch from. Default gets most recent trades.</param> /// <param name="limit">Default 500; max 500.</param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetTradesAsync(this IBinanceHttpClient client, string apiKey, string symbol, long fromId = BinanceApi.NullId, int limit = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(5, token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/api/v1/historicalTrades") { ApiKey = apiKey }; request.AddParameter("symbol", symbol.FormatSymbol()); if (fromId >= 0) { request.AddParameter("fromId", fromId); } if (limit > 0) { request.AddParameter("limit", limit); } return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get current account information. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetAccountInfoAsync(this IBinanceHttpClient client, IBinanceApiUser user, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); if (recvWindow <= 0) { recvWindow = client.Options.RecvWindowDefault ?? 0; } if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(5, token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/api/v3/account") { ApiKey = user.ApiKey }; if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } await client.SignAsync(request, user, token) .ConfigureAwait(false); return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Constructor. /// </summary> /// <param name="client"></param> /// <param name="orderBookSerializer"></param> /// <param name="orderBookTopSerializer"></param> /// <param name="aggregateTradeSerializer"></param> /// <param name="candlestickSerializer"></param> /// <param name="symbolPriceSerializer"></param> /// <param name="symbolStatisticsSerializer"></param> /// <param name="accountTradeSerializer"></param> /// <param name="tradeSerializer"></param> /// <param name="orderSerializer"></param> /// <param name="logger"></param> public BinanceApi( IBinanceHttpClient client, IOrderBookSerializer orderBookSerializer = null, IOrderBookTopSerializer orderBookTopSerializer = null, IAggregateTradeSerializer aggregateTradeSerializer = null, ICandlestickSerializer candlestickSerializer = null, ISymbolPriceSerializer symbolPriceSerializer = null, ISymbolStatisticsSerializer symbolStatisticsSerializer = null, IAccountTradeSerializer accountTradeSerializer = null, ITradeSerializer tradeSerializer = null, IOrderSerializer orderSerializer = null, ILogger <BinanceApi> logger = null) { Throw.IfNull(client, nameof(client)); HttpClient = client; _orderBookSerializer = orderBookSerializer ?? new OrderBookSerializer(); _orderBookTopSerializer = orderBookTopSerializer ?? new OrderBookTopSerializer(); _aggregateTradeSerializer = aggregateTradeSerializer ?? new AggregateTradeSerializer(); _candlestickSerializer = candlestickSerializer ?? new CandlestickSerializer(); _symbolPriceSerializer = symbolPriceSerializer ?? new SymbolPriceSerializer(); _symbolStatisticsSerializer = symbolStatisticsSerializer ?? new SymbolStatisticsSerializer(); _accountTradeSerializer = accountTradeSerializer ?? new AccountTradeSerializer(); _tradeSerializer = tradeSerializer ?? new TradeSerializer(); _orderSerializer = orderSerializer ?? new OrderSerializer(); _logger = logger; }
/// <summary> /// Get current account information. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetAccountInfoAsync(this IBinanceHttpClient client, IBinanceApiUser user, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); if (recvWindow <= 0) { recvWindow = client.Options.RecvWindowDefault ?? 0; } var request = new BinanceHttpRequest($"/api/v3/account") { ApiKey = user.ApiKey }; var timestamp = await client.GetTimestampAsync(token) .ConfigureAwait(false); request.AddParameter("timestamp", timestamp); if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } var signature = user.Sign(request.QueryString); request.AddParameter("signature", signature); return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get candlesticks for a symbol. Candlesticks/K-Lines are uniquely identified by their open time. /// If startTime and endTime are not sent, the most recent candlesticks are returned. /// </summary> /// <param name="client"></param> /// <param name="symbol"></param> /// <param name="interval"></param> /// <param name="limit">Default 500; max 500.</param> /// <param name="startTime"></param> /// <param name="endTime"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetCandlesticksAsync(this IBinanceHttpClient client, string symbol, CandlestickInterval interval, int limit = default, long startTime = default, long endTime = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/api/v1/klines"); request.AddParameter("symbol", symbol.FormatSymbol()); request.AddParameter("interval", interval.AsString()); if (limit > 0) { request.AddParameter("limit", limit); } if (startTime > 0) { request.AddParameter("startTime", startTime); } if (endTime > 0) { request.AddParameter("endTime", endTime); } return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
public BinanceHttpClientExtensionsTest() { // Configure services. var serviceProvider = new ServiceCollection() .AddBinance().BuildServiceProvider(); // Get IBinanceHttpClient service. _client = serviceProvider.GetService <IBinanceHttpClient>(); }
/// <summary> /// Cancel an active order. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="symbol"></param> /// <param name="orderId"></param> /// <param name="origClientOrderId"></param> /// <param name="newClientOrderId">Used to uniquely identify this cancel. Automatically generated by default.</param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> CancelOrderAsync(this IBinanceHttpClient client, IBinanceApiUser user, string symbol, long orderId = BinanceApi.NullId, string origClientOrderId = null, string newClientOrderId = null, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); if (orderId < 0 && string.IsNullOrWhiteSpace(origClientOrderId)) { throw new ArgumentException($"Either '{nameof(orderId)}' or '{nameof(origClientOrderId)}' must be provided, but both were invalid."); } if (recvWindow == default) { recvWindow = client.DefaultRecvWindow; } if (user.RateLimiter != null) { await user.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/api/v3/order") { ApiKey = user.ApiKey }; request.AddParameter("symbol", symbol.FormatSymbol()); if (orderId >= 0) { request.AddParameter("orderId", orderId); } if (!string.IsNullOrWhiteSpace(origClientOrderId)) { request.AddParameter("origClientOrderId", origClientOrderId); } if (!string.IsNullOrWhiteSpace(newClientOrderId)) { request.AddParameter("newClientOrderId", newClientOrderId); } if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } await client.SignAsync(request, user, token) .ConfigureAwait(false); return(await client.DeleteAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get best price/quantity on the order book for a symbol. /// </summary> /// <param name="client"></param> /// <param name="symbol"></param> /// <param name="token"></param> /// <returns></returns> public static Task <string> GetOrderBookTopAsync(this IBinanceHttpClient client, string symbol, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); var request = new BinanceHttpRequest("/api/v1/ticker/bookTicker"); request.AddParameter("symbol", symbol.FormatSymbol()); return(client.GetAsync(request, token)); }
/// <summary> /// Start a new user data stream. /// </summary> /// <param name="client"></param> /// <param name="apiKey"></param> /// <param name="token"></param> /// <returns></returns> public static Task <string> UserStreamStartAsync(this IBinanceHttpClient client, string apiKey, CancellationToken token = default) { Throw.IfNullOrWhiteSpace(apiKey, nameof(apiKey)); var request = new BinanceHttpRequest("/api/v1/userDataStream") { ApiKey = apiKey }; return(client.PostAsync(request, token)); }
/// <summary> /// Submit a withdraw request. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="asset"></param> /// <param name="address"></param> /// <param name="addressTag"></param> /// <param name="amount"></param> /// <param name="name">A description of the address (optional).</param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> WithdrawAsync(this IBinanceHttpClient client, IBinanceApiUser user, string asset, string address, string addressTag, decimal amount, string name = null, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); Throw.IfNullOrWhiteSpace(asset, nameof(asset)); Throw.IfNullOrWhiteSpace(address, nameof(address)); if (amount <= 0) { throw new ArgumentException("Withdraw amount must be greater than 0.", nameof(amount)); } if (recvWindow == default) { recvWindow = client.DefaultRecvWindow; } if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/wapi/v3/withdraw.html") { ApiKey = user.ApiKey }; request.AddParameter("asset", asset.FormatSymbol()); request.AddParameter("address", address); request.AddParameter("amount", amount); if (!string.IsNullOrWhiteSpace(addressTag)) { request.AddParameter("addressTag", addressTag); } if (!string.IsNullOrWhiteSpace(name)) { request.AddParameter("name", name); } if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } await client.SignAsync(request, user, token) .ConfigureAwait(false); return(await client.PostAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get the deposit history. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="asset"></param> /// <param name="status"></param> /// <param name="startTime"></param> /// <param name="endTime"></param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetDepositsAsync(this IBinanceHttpClient client, IBinanceApiUser user, string asset = null, DepositStatus?status = null, long startTime = default, long endTime = default, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); if (recvWindow <= 0) { recvWindow = client.Options.RecvWindowDefault ?? 0; } if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/wapi/v3/depositHistory.html") { ApiKey = user.ApiKey }; if (!string.IsNullOrWhiteSpace(asset)) { request.AddParameter("asset", asset.FormatSymbol()); } if (status.HasValue) { request.AddParameter("status", (int)status); } if (startTime > 0) { request.AddParameter("startTime", startTime); } if (endTime > 0) { request.AddParameter("endTime", endTime); } if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } await client.SignAsync(request, user, token) .ConfigureAwait(false); return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get the withdrawal history. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="asset"></param> /// <param name="status"></param> /// <param name="startTime"></param> /// <param name="endTime"></param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetWithdrawalsAsync(this IBinanceHttpClient client, IBinanceApiUser user, string asset = null, WithdrawalStatus?status = null, long startTime = default, long endTime = default, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); if (recvWindow <= 0) { recvWindow = client.Options.RecvWindowDefault ?? 0; } var request = new BinanceHttpRequest($"/wapi/v3/withdrawHistory.html") { ApiKey = user.ApiKey }; var timestamp = await client.GetTimestampAsync(token) .ConfigureAwait(false); request.AddParameter("timestamp", timestamp); if (!string.IsNullOrWhiteSpace(asset)) { request.AddParameter("asset", asset.FormatSymbol()); } if (status.HasValue) { request.AddParameter("status", (int)status); } if (startTime > 0) { request.AddParameter("startTime", startTime); } if (endTime > 0) { request.AddParameter("endTime", endTime); } if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } var signature = user.Sign(request.QueryString); request.AddParameter("signature", signature); return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Extension allowing candlestick interval as a string. /// </summary> /// <param name="client"></param> /// <param name="symbol"></param> /// <param name="interval"></param> /// <param name="limit"></param> /// <param name="startTime"></param> /// <param name="endTime"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetCandlesticksAsync(this IBinanceHttpClient client, string symbol, string interval, int limit = default, DateTime startTime = default, DateTime endTime = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } return(await client.GetCandlesticksAsync(symbol, interval.ToCandlestickInterval(), limit, startTime, endTime, token) .ConfigureAwait(false)); }
/// <summary> /// Get system status. /// </summary> /// <param name="client"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetSystemStatusAsync(this IBinanceHttpClient client, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } return(await client.GetAsync("/wapi/v3/systemStatus.html", token) .ConfigureAwait(false)); }
/// <summary> /// Get latest price for a symbol or all symbols. /// </summary> /// <param name="client"></param> /// <param name="symbol"></param> /// <param name="token"></param> /// <returns></returns> public static Task <string> GetPriceAsync(this IBinanceHttpClient client, string symbol = null, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); var request = new BinanceHttpRequest("/api/v3/ticker/price"); if (!string.IsNullOrWhiteSpace(symbol)) { request.AddParameter("symbol", symbol.FormatSymbol()); } return(client.GetAsync(request, token)); }
/// <summary> /// Get best price/quantity on the order book for all symbols. /// </summary> /// <param name="client"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetOrderBookTopsAsync(this IBinanceHttpClient client, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } return(await client.GetAsync("/api/v1/ticker/bookTicker", token) .ConfigureAwait(false)); }
/// <summary> /// Get compressed, aggregate trades. Trades that fill at the time, from the same order, with the same price will have the quantity aggregated. /// If fromdId, startTime, and endTime are not sent, the most recent aggregate trades will be returned. /// </summary> /// <param name="client"></param> /// <param name="symbol"></param> /// <param name="fromId">ID to get aggregate trades from INCLUSIVE.</param> /// <param name="limit">Default 500; max 500.</param> /// <param name="startTime">Timestamp in ms to get aggregate trades from INCLUSIVE.</param> /// <param name="endTime">Timestamp in ms to get aggregate trades until INCLUSIVE.</param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetAggregateTradesAsync(this IBinanceHttpClient client, string symbol, long fromId = BinanceApi.NullId, int limit = default, long startTime = default, long endTime = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/api/v1/aggTrades"); request.AddParameter("symbol", symbol.FormatSymbol()); if (fromId >= 0) { request.AddParameter("fromId", fromId); } if (startTime > 0) { request.AddParameter("startTime", startTime); } if (endTime > 0) { request.AddParameter("endTime", endTime); } if (startTime <= 0 || endTime <= 0) { if (limit > 0) { request.AddParameter("limit", limit); } } else { var start = DateTimeOffset.FromUnixTimeMilliseconds(startTime); var end = DateTimeOffset.FromUnixTimeMilliseconds(endTime); if ((end - start).Duration() >= TimeSpan.FromHours(24)) { throw new ArgumentException($"The interval between {nameof(startTime)} and {nameof(endTime)} must be less than 24 hours.", nameof(endTime)); } } return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get 24 hour price change statistics for a symbol or all symbols. /// </summary> /// <param name="client"></param> /// <param name="symbol"></param> /// <param name="token"></param> /// <returns></returns> public static Task <string> Get24HourStatisticsAsync(this IBinanceHttpClient client, string symbol = null, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); // When symbol is not provided use number of symbols that are TRADING for weight. var request = new BinanceHttpRequest("/api/v1/ticker/24hr", string.IsNullOrWhiteSpace(symbol) ? Symbol.Cache.Values.Count(s => s.Status == SymbolStatus.Trading) : 1); if (!string.IsNullOrWhiteSpace(symbol)) { request.AddParameter("symbol", symbol.FormatSymbol()); } return(client.GetAsync(request, token)); }
/// <summary> /// Close out a user data stream. /// </summary> /// <param name="client"></param> /// <param name="apiKey"></param> /// <param name="listenKey"></param> /// <param name="token"></param> /// <returns></returns> public static Task <string> UserStreamCloseAsync(this IBinanceHttpClient client, string apiKey, string listenKey, CancellationToken token = default) { Throw.IfNullOrWhiteSpace(apiKey, nameof(apiKey)); Throw.IfNullOrWhiteSpace(listenKey, nameof(listenKey)); var request = new BinanceHttpRequest("/api/v1/userDataStream") { ApiKey = apiKey }; request.AddParameter("listenKey", listenKey); return(client.DeleteAsync(request, token)); }
/// <summary> /// Check an order's status. Either orderId or origClientOrderId must be sent. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="symbol"></param> /// <param name="orderId"></param> /// <param name="origClientOrderId"></param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetOrderAsync(this IBinanceHttpClient client, IBinanceApiUser user, string symbol, long orderId = BinanceApi.NullId, string origClientOrderId = null, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); if (orderId < 0 && string.IsNullOrWhiteSpace(origClientOrderId)) { throw new ArgumentException($"Either '{nameof(orderId)}' or '{nameof(origClientOrderId)}' must be provided, but both were invalid."); } if (recvWindow <= 0) { recvWindow = client.Options.RecvWindowDefault ?? 0; } var request = new BinanceHttpRequest($"/api/v3/order") { ApiKey = user.ApiKey }; request.AddParameter("symbol", symbol.FormatSymbol()); if (orderId >= 0) { request.AddParameter("orderId", orderId); } if (!string.IsNullOrWhiteSpace(origClientOrderId)) { request.AddParameter("origClientOrderId", origClientOrderId); } if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } var timestamp = await client.GetTimestampAsync(token) .ConfigureAwait(false); request.AddParameter("timestamp", timestamp); var signature = user.Sign(request.QueryString); request.AddParameter("signature", signature); return(await client.GetAsync(request, token, user.RateLimiter) .ConfigureAwait(false)); }
/// <summary> /// Get the account status. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetAccountStatusAsync(this IBinanceHttpClient client, IBinanceApiUser user, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); var request = new BinanceHttpRequest("/wapi/v3/accountStatus.html") { ApiKey = user.ApiKey }; await client.SignAsync(request, user, token) .ConfigureAwait(false); return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
public async Task <long> GetTimestampAsync(IBinanceHttpClient client, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); // Acquire synchronization lock. await _syncLock.WaitAsync(token) .ConfigureAwait(false); try { if (DateTime.UtcNow - _offsetLastUpdate > TimestampOffsetRefreshPeriod) { const long n = 3; long sum = 0; var count = n; do { var systemTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var json = await client.GetServerTimeAsync(token) .ConfigureAwait(false); systemTime = (systemTime + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) / 2; // Calculate timestamp offset to account for time differences. sum += JObject.Parse(json)["serverTime"].Value <long>() - systemTime; await Task.Delay(100, token) .ConfigureAwait(false); } while (--count > 0); // Calculate average offset. TimestampOffset = sum / n; // Record the current system time to determine when to refresh offset. _offsetLastUpdate = DateTime.UtcNow; } } catch (Exception) { /* ignore */ } finally { // Release synchronization lock. _syncLock.Release(); } return(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + TimestampOffset); }
/// <summary> /// Get latest (non-compressed) trades. /// </summary> /// <param name="client"></param> /// <param name="symbol"></param> /// <param name="limit"></param> /// <param name="token"></param> /// <returns></returns> public static Task <string> GetTradesAsync(this IBinanceHttpClient client, string symbol, int limit = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); var request = new BinanceHttpRequest("/api/v1/trades"); request.AddParameter("symbol", symbol.FormatSymbol()); if (limit > 0) { request.AddParameter("limit", limit); } return(client.GetAsync(request, token)); }
/// <summary> /// Ping a user data stream to prevent a time out. /// </summary> /// <param name="client"></param> /// <param name="apiKey"></param> /// <param name="listenKey"></param> /// <param name="token"></param> /// <returns></returns> public static Task <string> UserStreamKeepAliveAsync(this IBinanceHttpClient client, string apiKey, string listenKey, CancellationToken token = default) { Throw.IfNullOrWhiteSpace(apiKey, nameof(apiKey)); Throw.IfNullOrWhiteSpace(listenKey, nameof(listenKey)); var request = new BinanceHttpRequest("/api/v1/userDataStream") { ApiKey = apiKey }; request.AddParameter("listenKey", listenKey); // TODO // A POST will either get back your current stream (and effectively do a PUT) or get back a new stream. //return client.PostAsync(request, token); return(client.PutAsync(request, token)); }
/// <summary> /// Constructor. /// </summary> /// <param name="client"></param> /// <param name="orderBookSerializer"></param> /// <param name="logger"></param> public BinanceApi( IBinanceHttpClient client, IOrderBookSerializer orderBookSerializer = null, ITradeSerializer tradeSerializer = null, IOrderSerializer orderSerializer = null, ILogger <BinanceApi> logger = null) { Throw.IfNull(client, nameof(client)); HttpClient = client; _orderBookSerializer = orderBookSerializer ?? new OrderBookSerializer(); _tradeSerializer = tradeSerializer ?? new TradeSerializer(); _orderSerializer = orderSerializer ?? new OrderSerializer(); _logger = logger; }
/// <summary> /// Get local system timestamp synchronized with server time. /// </summary> /// <param name="token"></param> /// <returns></returns> public static async Task <long> GetTimestampAsync(this IBinanceHttpClient client, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); // Acquire synchronization lock. await _timestampOffsetSync.WaitAsync(token) .ConfigureAwait(false); try { if (DateTime.UtcNow - _timestampOffsetUpdatedAt > TimeSpan.FromMinutes(client.Options.TimestampOffsetRefreshPeriodMinutes)) { const long N = 3; long sum = 0; var count = N; do { var systemTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var json = await GetServerTimeAsync(client, token) .ConfigureAwait(false); systemTime = (systemTime + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) / 2; // Calculate timestamp offset to account for time differences and delays. sum += JObject.Parse(json)["serverTime"].Value <long>() - systemTime; } while (--count > 0); // Calculate average offset. _timestampOffset = sum / N; // Record the current system time to determine when to refresh offset. _timestampOffsetUpdatedAt = DateTime.UtcNow; } } catch (Exception) { /* ignore */ } finally { // Release synchronization lock. _timestampOffsetSync.Release(); } return(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() + _timestampOffset); }
/// <summary> /// Get trades for a specific account and symbol. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="symbol"></param> /// <param name="fromId">TradeId to fetch from. Default gets most recent trades.</param> /// <param name="limit">Default 500; max 500.</param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetAccountTradesAsync(this IBinanceHttpClient client, IBinanceApiUser user, string symbol, long fromId = BinanceApi.NullId, int limit = default, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); if (recvWindow <= 0) { recvWindow = client.Options.RecvWindowDefault ?? 0; } var request = new BinanceHttpRequest($"/api/v3/myTrades") { ApiKey = user.ApiKey }; request.AddParameter("symbol", symbol.FormatSymbol()); if (fromId >= 0) { request.AddParameter("fromId", fromId); } if (limit > 0) { request.AddParameter("limit", limit); } if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } var timestamp = await client.GetTimestampAsync(token) .ConfigureAwait(false); request.AddParameter("timestamp", timestamp); var signature = user.Sign(request.QueryString); request.AddParameter("signature", signature); return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get trades for a specific account and symbol. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="symbol"></param> /// <param name="fromId">TradeId to fetch from. Default gets most recent trades.</param> /// <param name="limit">Default 500; max 500.</param> /// <param name="recvWindow"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetAccountTradesAsync(this IBinanceHttpClient client, IBinanceApiUser user, string symbol, long fromId = BinanceApi.NullId, int limit = default, long recvWindow = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNull(user, nameof(user)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); if (recvWindow == default) { recvWindow = client.DefaultRecvWindow; } if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(5, token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/api/v3/myTrades") { ApiKey = user.ApiKey }; request.AddParameter("symbol", symbol.FormatSymbol()); if (fromId >= 0) { request.AddParameter("fromId", fromId); } if (limit > 0) { request.AddParameter("limit", limit); } if (recvWindow > 0) { request.AddParameter("recvWindow", recvWindow); } await client.SignAsync(request, user, token) .ConfigureAwait(false); return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get candlesticks for a symbol. Candlesticks/K-Lines are uniquely identified by their open time. /// If startTime and endTime are not sent, the most recent candlesticks are returned. /// </summary> /// <param name="client"></param> /// <param name="symbol"></param> /// <param name="interval"></param> /// <param name="limit">Default 500; max 500.</param> /// <param name="startTime"></param> /// <param name="endTime"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetCandlesticksAsync(this IBinanceHttpClient client, string symbol, CandlestickInterval interval, int limit = default, DateTime startTime = default, DateTime endTime = default, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNullOrWhiteSpace(symbol, nameof(symbol)); if (client.RateLimiter != null) { await client.RateLimiter.DelayAsync(token : token) .ConfigureAwait(false); } var request = new BinanceHttpRequest("/api/v1/klines"); request.AddParameter("symbol", symbol.FormatSymbol()); request.AddParameter("interval", interval.AsString()); if (limit > 0) { request.AddParameter("limit", limit); } if (startTime != default) { if (startTime.Kind != DateTimeKind.Utc) { throw new ArgumentException("Date/Time must be UTC.", nameof(startTime)); } request.AddParameter("startTime", startTime.ToTimestamp()); } // ReSharper disable once InvertIf if (endTime != default) { if (endTime.Kind != DateTimeKind.Utc) { throw new ArgumentException("Date/Time must be UTC.", nameof(endTime)); } request.AddParameter("endTime", endTime.ToTimestamp()); } return(await client.GetAsync(request, token) .ConfigureAwait(false)); }
/// <summary> /// Get the deposit address for an asset. /// </summary> /// <param name="client"></param> /// <param name="user"></param> /// <param name="asset"></param> /// <param name="token"></param> /// <returns></returns> public static async Task <string> GetDepositAddressAsync(this IBinanceHttpClient client, IBinanceApiUser user, string asset, CancellationToken token = default) { Throw.IfNull(client, nameof(client)); Throw.IfNullOrWhiteSpace(asset, nameof(asset)); var request = new BinanceHttpRequest("/wapi/v3/depositAddress.html") { ApiKey = user.ApiKey }; request.AddParameter("asset", asset.FormatSymbol()); await client.SignAsync(request, user, token) .ConfigureAwait(false); return(await client.GetAsync(request, token) .ConfigureAwait(false)); }