diff --git a/Binance.API.Csharp.Client.Domain/Abstract/ApiClientAbstract.cs b/Binance.API.Csharp.Client.Domain/Abstract/ApiClientAbstract.cs
index 03868dd..a0c0c60 100644
--- a/Binance.API.Csharp.Client.Domain/Abstract/ApiClientAbstract.cs
+++ b/Binance.API.Csharp.Client.Domain/Abstract/ApiClientAbstract.cs
@@ -50,7 +50,7 @@ public abstract class ApiClientAbstract
/// Key used to authenticate within the API.
/// API secret used to signed API calls.
/// API based url.
- public ApiClientAbstract(string apiKey, string apiSecret, string apiUrl = @"https://www.binance.com", string webSocketEndpoint = @"wss://stream.binance.com:9443/ws/", bool addDefaultHeaders = true)
+ public ApiClientAbstract(string apiKey, string apiSecret, string apiUrl = @"https://us.binance.com", string webSocketEndpoint = @"wss://stream.binance.com:9443/ws/", bool addDefaultHeaders = true)
{
_apiUrl = apiUrl;
_apiKey = apiKey;
diff --git a/Binance.API.Csharp.Client.Domain/Interfaces/IApiClient.cs b/Binance.API.Csharp.Client.Domain/Interfaces/IApiClient.cs
index 65dc01f..b9461db 100644
--- a/Binance.API.Csharp.Client.Domain/Interfaces/IApiClient.cs
+++ b/Binance.API.Csharp.Client.Domain/Interfaces/IApiClient.cs
@@ -1,6 +1,8 @@
using Binance.API.Csharp.Client.Models.Enums;
using Binance.API.Csharp.Client.Models.WebSocket;
+using System;
using System.Threading.Tasks;
+using WebSocketSharp;
using static Binance.API.Csharp.Client.Domain.Abstract.ApiClientAbstract;
namespace Binance.API.Csharp.Client.Domain.Interfaces
@@ -18,22 +20,30 @@ public interface IApiClient
///
Task CallAsync(ApiMethod method, string endpoint, bool isSigned = false, string parameters = null);
- ///
- /// Connects to a Websocket endpoint.
- ///
- /// Type used to parsed the response message.
- /// Paremeters to send to the Websocket.
- /// Deletage to callback after receive a message.
- /// Specifies if needs to use a custom parser for the response message.
- void ConnectToWebSocket(string parameters, MessageHandler messageDelegate, bool useCustomParser = false);
+ ///
+ /// Connects to a Websocket endpoint.
+ ///
+ /// Type used to parsed the response message.
+ /// Paremeters to send to the Websocket.
+ /// Deletage to callback after receive a message.
+ /// Specifies if needs to use a custom parser for the response message.
+ WebSocket ConnectToWebSocket(
+ string parameters,
+ MessageHandler messageDelegate,
+ Action onClose,
+ bool useCustomParser = false);
- ///
- /// Connects to a UserData Websocket endpoint.
- ///
- /// Paremeters to send to the Websocket.
- /// Deletage to callback after receive a account info message.
- /// Deletage to callback after receive a trade message.
- /// Deletage to callback after receive a order message.
- void ConnectToUserDataWebSocket(string parameters, MessageHandler accountHandler, MessageHandler tradeHandler, MessageHandler orderHandler);
+ ///
+ /// Connects to a UserData Websocket endpoint.
+ ///
+ /// Paremeters to send to the Websocket.
+ /// Deletage to callback after receive a account info message.
+ /// Deletage to callback after receive a trade message.
+ /// Deletage to callback after receive a order message.
+ WebSocket ConnectToUserDataWebSocket(string parameters,
+ MessageHandler accountHandler,
+ MessageHandler tradeHandler,
+ MessageHandler orderHandler,
+ Action onClose);
}
}
\ No newline at end of file
diff --git a/Binance.API.Csharp.Client.Domain/Interfaces/IBinanceClient.cs b/Binance.API.Csharp.Client.Domain/Interfaces/IBinanceClient.cs
index 5312215..a33f67c 100644
--- a/Binance.API.Csharp.Client.Domain/Interfaces/IBinanceClient.cs
+++ b/Binance.API.Csharp.Client.Domain/Interfaces/IBinanceClient.cs
@@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using WebSocketSharp;
using static Binance.API.Csharp.Client.Domain.Abstract.ApiClientAbstract;
namespace Binance.API.Csharp.Client.Domain.Interfaces
@@ -85,8 +86,7 @@ public interface IBinanceClient
/// Indicates how long an order will remain active before it is executed or expires.
/// Specific number of milliseconds the request is valid for.
///
- Task PostNewOrder(string symbol, decimal quantity, decimal price, OrderSide side, OrderType orderType = OrderType.LIMIT, TimeInForce timeInForce = TimeInForce.GTC, decimal icebergQty = 0m, long recvWindow = 6000000);
-
+ Task PostNewOrder(string symbol, decimal quantity, decimal price, OrderSide side, OrderType orderType = OrderType.LIMIT, TimeInForce timeInForce = TimeInForce.GTC, string clientOrderId = null, decimal icebergQty = 0m, long recvWindow = 5000);
///
/// Test new order creation and signature/recvWindow long. Creates and validates a new order but does not send it into the matching engine.
///
@@ -98,8 +98,7 @@ public interface IBinanceClient
/// Indicates how long an order will remain active before it is executed or expires.
/// Specific number of milliseconds the request is valid for.
///
- Task PostNewOrderTest(string symbol, decimal quantity, decimal price, OrderSide side, OrderType orderType = OrderType.LIMIT, TimeInForce timeInForce = TimeInForce.GTC, decimal icebergQty = 0m, long recvWindow = 6000000);
-
+ Task PostNewOrderTest(string symbol, decimal quantity, decimal price, OrderSide side, OrderType orderType = OrderType.LIMIT, TimeInForce timeInForce = TimeInForce.GTC, string clientOrderId = null, decimal icebergQty = 0m, long recvWindow = 5000);
///
/// Check an order's status.
///
@@ -151,7 +150,7 @@ public interface IBinanceClient
/// Ticker symbol.
/// Specific number of milliseconds the request is valid for.
///
- Task> GetTradeList(string symbol, long recvWindow = 6000000);
+ Task> GetTradeList(string symbol, int limit, long fromId, long recvWindow = 5000);
///
/// Submit a withdraw request.
@@ -210,27 +209,31 @@ public interface IBinanceClient
#endregion
#region WebSocket
+
///
/// Listen to the Depth endpoint.
///
/// Ticker symbol.
+ ///
/// Handler to be used when a message is received.
- void ListenDepthEndpoint(string symbol, MessageHandler messageHandler);
+ WebSocket ListenDepthEndpoint(string symbol, MessageHandler messageHandler, Action onClose);
///
/// Listen to the Kline endpoint.
///
/// Ticker symbol.
/// Time interval to retreive.
+ ///
/// Handler to be used when a message is received.
- void ListenKlineEndpoint(string symbol, TimeInterval interval, MessageHandler messageHandler);
+ WebSocket ListenKlineEndpoint(string symbol, TimeInterval interval, MessageHandler messageHandler, Action onClose);
///
/// Listen to the Trades endpoint.
///
/// Ticker symbol.
+ ///
/// Handler to be used when a message is received.
- void ListenTradeEndpoint(string symbol, MessageHandler messageHandler);
+ WebSocket ListenTradeEndpoint(string symbol, MessageHandler messageHandler, Action onClose);
///
/// Listen to the User Data endpoint.
@@ -239,7 +242,7 @@ public interface IBinanceClient
/// Handler to be used when a trade message is received.
/// Handler to be used when a order message is received.
///
- string ListenUserDataEndpoint(MessageHandler accountInfoHandler, MessageHandler tradesHandler, MessageHandler ordersHandler);
+ string ListenUserDataEndpoint(MessageHandler accountInfoHandler, MessageHandler tradesHandler, MessageHandler ordersHandler, Action onClose);
#endregion
}
}
diff --git a/Binance.API.Csharp.Client.Models/Account/Trade.cs b/Binance.API.Csharp.Client.Models/Account/Trade.cs
index f01c9fd..bec3ddb 100644
--- a/Binance.API.Csharp.Client.Models/Account/Trade.cs
+++ b/Binance.API.Csharp.Client.Models/Account/Trade.cs
@@ -6,6 +6,8 @@ public class Trade
{
[JsonProperty("id")]
public int Id { get; set; }
+ [JsonProperty("orderId")]
+ public int OrderId { get; set; }
[JsonProperty("price")]
public decimal Price { get; set; }
[JsonProperty("qty")]
diff --git a/Binance.API.Csharp.Client.Models/WebSocket/AccountUpdatedMessage.cs b/Binance.API.Csharp.Client.Models/WebSocket/AccountUpdatedMessage.cs
index ba0997b..1b7d0fc 100644
--- a/Binance.API.Csharp.Client.Models/WebSocket/AccountUpdatedMessage.cs
+++ b/Binance.API.Csharp.Client.Models/WebSocket/AccountUpdatedMessage.cs
@@ -17,12 +17,14 @@ public class AccountUpdatedMessage
public int BuyerCommission { get; set; }
[JsonProperty("s")]
public int SellerCommission { get; set; }
- [JsonProperty("t")]
+ [JsonProperty("T")]
public bool CanTrade { get; set; }
- [JsonProperty("w")]
+ [JsonProperty("W")]
public bool CanWithdraw { get; set; }
- [JsonProperty("d")]
+ [JsonProperty("D")]
public bool CanDeposit { get; set; }
+ [JsonProperty("u")]
+ public long TimeLastAccountUpdate { get; set; }
[JsonProperty("B")]
public IEnumerable Balances { get; set; }
}
diff --git a/Binance.API.Csharp.Client.Models/WebSocket/DepthMessage.cs b/Binance.API.Csharp.Client.Models/WebSocket/DepthMessage.cs
index 4598ad4..3f4c8a7 100644
--- a/Binance.API.Csharp.Client.Models/WebSocket/DepthMessage.cs
+++ b/Binance.API.Csharp.Client.Models/WebSocket/DepthMessage.cs
@@ -12,4 +12,10 @@ public class DepthMessage
public IEnumerable Bids { get; set; }
public IEnumerable Asks { get; set; }
}
+ public class DepthPartialMessage
+ {
+ public int UpdateId { get; set; }
+ public IEnumerable Bids { get; set; }
+ public IEnumerable Asks { get; set; }
+ }
}
diff --git a/Binance.API.Csharp.Client.Models/WebSocket/OrderOrTradeUpdatedMessage.cs b/Binance.API.Csharp.Client.Models/WebSocket/OrderOrTradeUpdatedMessage.cs
index dabe14d..0a3a450 100644
--- a/Binance.API.Csharp.Client.Models/WebSocket/OrderOrTradeUpdatedMessage.cs
+++ b/Binance.API.Csharp.Client.Models/WebSocket/OrderOrTradeUpdatedMessage.cs
@@ -11,7 +11,7 @@ public class OrderOrTradeUpdatedMessage
[JsonProperty("s")]
public string Symbol { get; set; }
[JsonProperty("c")]
- public string NewClientOrderId { get; set; }
+ public string NewClientOrderId { get; set; }
[JsonProperty("S")]
public string Side { get; set; }
[JsonProperty("o")]
@@ -22,6 +22,15 @@ public class OrderOrTradeUpdatedMessage
public decimal OriginalQuantity { get; set; }
[JsonProperty("p")]
public decimal Price { get; set; }
+ [JsonProperty("P")]
+ public decimal StopPrice { get; set; }
+ [JsonProperty("F")]
+ public decimal IcebergQuantity { get; set; }
+ [JsonProperty("g")]
+ public int g { get; set; }
+
+ [JsonProperty("C")]
+ public string OriginalClientOrderId { get; set; }
[JsonProperty("x")]
public string ExecutionType { get; set; }
[JsonProperty("X")]
@@ -29,7 +38,7 @@ public class OrderOrTradeUpdatedMessage
[JsonProperty("r")]
public string RejectReason { get; set; }
[JsonProperty("i")]
- public int Orderid { get; set; }
+ public int OrderId { get; set; }
[JsonProperty("l")]
public decimal LastFilledTradeQuantity { get; set; }
[JsonProperty("z")]
@@ -44,7 +53,22 @@ public class OrderOrTradeUpdatedMessage
public long TradeTime { get; set; }
[JsonProperty("t")]
public int TradeId { get; set; }
+ [JsonProperty("I")]
+ public int I { get; set; }
+ [JsonProperty("w")]
+ public bool IsOrderWorking { get; set; }
[JsonProperty("m")]
public bool BuyerIsMaker { get; set; }
+ [JsonProperty("M")]
+ public bool M { get; set; }
+ [JsonProperty("O")]
+ public int O { get; set; }
+ [JsonProperty("Z")]
+ public decimal Z { get; set; }
+
+ public override string ToString()
+ {
+ return JsonConvert.SerializeObject(this, Formatting.Indented);
+ }
}
}
diff --git a/Binance.API.Csharp.Client.Test/Binance.API.Csharp.Client.Test.csproj b/Binance.API.Csharp.Client.Test/Binance.API.Csharp.Client.Test.csproj
index 4757297..0b646ed 100644
--- a/Binance.API.Csharp.Client.Test/Binance.API.Csharp.Client.Test.csproj
+++ b/Binance.API.Csharp.Client.Test/Binance.API.Csharp.Client.Test.csproj
@@ -51,6 +51,9 @@
+
+ ..\packages\WebSocketSharp-NonPreRelease.1.0.0\lib\net35\websocket-sharp.dll
+
diff --git a/Binance.API.Csharp.Client.Test/BinanceTest.cs b/Binance.API.Csharp.Client.Test/BinanceTest.cs
index 03d6216..350fbac 100644
--- a/Binance.API.Csharp.Client.Test/BinanceTest.cs
+++ b/Binance.API.Csharp.Client.Test/BinanceTest.cs
@@ -23,6 +23,13 @@ public void GetServerTime()
{
var serverTime = binanceClient.GetServerTime().Result;
}
+
+ [TestMethod]
+ public void ExchangeInfo()
+ {
+ var rules = binanceClient.GetTradingRulesAsync().Result;
+ Thread.Sleep(1000);
+ }
#endregion
#region Market Data
diff --git a/Binance.API.Csharp.Client.Test/packages.config b/Binance.API.Csharp.Client.Test/packages.config
index 213bc4b..7a4429d 100644
--- a/Binance.API.Csharp.Client.Test/packages.config
+++ b/Binance.API.Csharp.Client.Test/packages.config
@@ -3,4 +3,5 @@
+
\ No newline at end of file
diff --git a/Binance.API.Csharp.Client/ApiClient.cs b/Binance.API.Csharp.Client/ApiClient.cs
index 7601abe..856a8f2 100644
--- a/Binance.API.Csharp.Client/ApiClient.cs
+++ b/Binance.API.Csharp.Client/ApiClient.cs
@@ -22,10 +22,11 @@ public class ApiClient : ApiClientAbstract, IApiClient
/// Key used to authenticate within the API.
/// API secret used to signed API calls.
/// API base url.
- public ApiClient(string apiKey, string apiSecret, string apiUrl = @"https://www.binance.com", string webSocketEndpoint = @"wss://stream.binance.com:9443/ws/", bool addDefaultHeaders = true) : base(apiKey, apiSecret, apiUrl, webSocketEndpoint, addDefaultHeaders)
+ public ApiClient(string apiKey, string apiSecret, string apiUrl = @"https://us.binance.com", string webSocketEndpoint = @"wss://stream.binance.com:9443/ws/", bool addDefaultHeaders = true) : base(apiKey, apiSecret, apiUrl, webSocketEndpoint, addDefaultHeaders)
{
}
+
///
/// Calls API Methods.
///
@@ -42,7 +43,7 @@ public async Task CallAsync(ApiMethod method, string endpoint, bool isSign
if (isSigned)
{
// Joining provided parameters
- parameters += (!string.IsNullOrWhiteSpace(parameters) ? "×tamp=" : "timestamp=") + Utilities.GenerateTimeStamp(DateTime.Now.ToUniversalTime());
+ parameters += (!string.IsNullOrWhiteSpace(parameters) ? "×tamp=" : "timestamp=") + (Utilities.GenerateTimeStamp(DateTime.Now.ToUniversalTime()));
// Creating request signature
var signature = Utilities.GenerateSignature(_apiSecret, parameters);
@@ -86,7 +87,6 @@ public async Task CallAsync(ApiMethod method, string endpoint, bool isSign
}
catch { }
}
-
throw new Exception(string.Format("Api Error Code: {0} Message: {1}", eCode, eMsg));
}
@@ -97,7 +97,7 @@ public async Task CallAsync(ApiMethod method, string endpoint, bool isSign
/// Paremeters to send to the Websocket.
/// Deletage to callback after receive a message.
/// Specifies if needs to use a custom parser for the response message.
- public void ConnectToWebSocket(string parameters, MessageHandler messageHandler, bool useCustomParser = false)
+ public WebSocket ConnectToWebSocket(string parameters, MessageHandler messageHandler, Action onClose = null, bool useCustomParser = false)
{
var finalEndpoint = _webSocketEndpoint + parameters;
@@ -105,12 +105,19 @@ public void ConnectToWebSocket(string parameters, MessageHandler messageHa
ws.OnMessage += (sender, e) =>
{
- dynamic eventData;
+ dynamic eventData = null;
if (useCustomParser)
{
var customParser = new CustomParser();
- eventData = customParser.GetParsedDepthMessage(JsonConvert.DeserializeObject(e.Data));
+ var datum = JsonConvert.DeserializeObject(e.Data);
+ if (datum is JObject jobject)
+ {
+ if (jobject["lastUpdateId"] != null)
+ eventData = customParser.GetParsedDepthPartialMessage(jobject);
+ else
+ eventData = customParser.GetParsedDepthMessage(jobject);
+ }
}
else
{
@@ -123,15 +130,17 @@ public void ConnectToWebSocket(string parameters, MessageHandler messageHa
ws.OnClose += (sender, e) =>
{
_openSockets.Remove(ws);
+ onClose?.Invoke(e);
};
ws.OnError += (sender, e) =>
- {
- _openSockets.Remove(ws);
+ {
+ if (ws.ReadyState != WebSocketState.Open)
+ _openSockets.Remove(ws);
};
-
+ ws.OnOpen += (s, e) => _openSockets.Add(ws);
ws.Connect();
- _openSockets.Add(ws);
+ return ws;
}
///
@@ -141,7 +150,7 @@ public void ConnectToWebSocket(string parameters, MessageHandler messageHa
/// Deletage to callback after receive a account info message.
/// Deletage to callback after receive a trade message.
/// Deletage to callback after receive a order message.
- public void ConnectToUserDataWebSocket(string parameters, MessageHandler accountHandler, MessageHandler tradeHandler, MessageHandler orderHandler)
+ public WebSocket ConnectToUserDataWebSocket(string parameters, MessageHandler accountHandler, MessageHandler tradeHandler, MessageHandler orderHandler, Action onClose = null)
{
var finalEndpoint = _webSocketEndpoint + parameters;
@@ -151,7 +160,7 @@ public void ConnectToUserDataWebSocket(string parameters, MessageHandler(e.Data);
- switch (eventData.e)
+ switch ((string)eventData.e.Value)
{
case "outboundAccountInfo":
accountHandler(JsonConvert.DeserializeObject(e.Data));
@@ -174,15 +183,17 @@ public void ConnectToUserDataWebSocket(string parameters, MessageHandler
{
_openSockets.Remove(ws);
+ onClose?.Invoke(e);
};
ws.OnError += (sender, e) =>
{
- _openSockets.Remove(ws);
+ if (ws.ReadyState != WebSocketState.Open)
+ _openSockets.Remove(ws);
};
-
+ ws.OnOpen += (s, e) => _openSockets.Add(ws);
ws.Connect();
- _openSockets.Add(ws);
+ return ws;
}
}
}
diff --git a/Binance.API.Csharp.Client/Binance.API.Csharp.Client.csproj b/Binance.API.Csharp.Client/Binance.API.Csharp.Client.csproj
index d0d89bd..4088a05 100644
--- a/Binance.API.Csharp.Client/Binance.API.Csharp.Client.csproj
+++ b/Binance.API.Csharp.Client/Binance.API.Csharp.Client.csproj
@@ -72,5 +72,6 @@
Binance.API.Csharp.Client.Models
+
\ No newline at end of file
diff --git a/Binance.API.Csharp.Client/BinanceClient.cs b/Binance.API.Csharp.Client/BinanceClient.cs
index c37503a..b204c71 100644
--- a/Binance.API.Csharp.Client/BinanceClient.cs
+++ b/Binance.API.Csharp.Client/BinanceClient.cs
@@ -12,6 +12,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using WebSocketSharp;
namespace Binance.API.Csharp.Client
{
@@ -58,6 +59,12 @@ private void ValidateOrderValue(string symbol, OrderType orderType, decimal unit
}
}
+ //quantity needs to be conform to this regex "^([0-9]{1,20})(\.[0-9]{1,20})?$" -> 20 decimal digits
+ if (quantity != decimal.Round(quantity, 20))
+ {
+ throw new ArgumentException("Quantity parameter should have no mora than 20 decimal digits.");
+ }
+
// Validating Trading Rules
if (_tradingRules != null)
{
@@ -88,11 +95,22 @@ private void ValidateOrderValue(string symbol, OrderType orderType, decimal unit
}
}
- private void LoadTradingRules()
+ public void LoadTradingRules()
{
var apiClient = new ApiClient("", "", EndPoints.TradingRules, addDefaultHeaders: false);
_tradingRules = apiClient.CallAsync(ApiMethod.GET, "").Result;
}
+
+ public async Task GetTradingRulesAsync()
+ {
+ if (_tradingRules != null)
+ return _tradingRules;
+ var result = await _apiClient.CallAsync(ApiMethod.GET, EndPoints.TradingRules, false);
+
+ _tradingRules = result;
+
+ return _tradingRules;
+ }
#endregion
#region General
@@ -243,16 +261,22 @@ public async Task> GetOrderBookTicker()
/// Indicates how long an order will remain active before it is executed or expires.
/// Specific number of milliseconds the request is valid for.
///
- public async Task PostNewOrder(string symbol, decimal quantity, decimal price, OrderSide side, OrderType orderType = OrderType.LIMIT, TimeInForce timeInForce = TimeInForce.GTC, decimal icebergQty = 0m, long recvWindow = 5000)
+ public async Task PostNewOrder(string symbol, decimal quantity, decimal price, OrderSide side, OrderType orderType = OrderType.LIMIT, TimeInForce timeInForce = TimeInForce.GTC, string clientOrderId = null, decimal icebergQty = 0m, long recvWindow = 5000)
{
//Validates that the order is valid.
ValidateOrderValue(symbol, orderType, price, quantity, icebergQty);
-
- var args = $"symbol={symbol.ToUpper()}&side={side}&type={orderType}&quantity={quantity}"
+ //quantity needs to be conform to this regex ^([0-9]{1,20})(\.[0-9]{1,20})?$ -> 20 decimal digits
+ //remove trailing zeros from quantity and price
+ quantity = quantity / 1.000000000000000000000000000000m;
+ price = price / 1.000000000000000000000000000000m;
+ var args = $"symbol={symbol.ToUpper()}&side={side}&type={orderType}"
+ + $"&quantity={quantity}"
+ (orderType == OrderType.LIMIT ? $"&timeInForce={timeInForce}" : "")
+ (orderType == OrderType.LIMIT ? $"&price={price}" : "")
+ + (clientOrderId != null ? $"&newClientOrderId={clientOrderId}" : "")
+ (icebergQty > 0m ? $"&icebergQty={icebergQty}" : "")
+ $"&recvWindow={recvWindow}";
+
var result = await _apiClient.CallAsync(ApiMethod.POST, EndPoints.NewOrder, true, args);
return result;
@@ -269,16 +293,21 @@ public async Task PostNewOrder(string symbol, decimal quantity, decima
/// Indicates how long an order will remain active before it is executed or expires.
/// Specific number of milliseconds the request is valid for.
///
- public async Task PostNewOrderTest(string symbol, decimal quantity, decimal price, OrderSide side, OrderType orderType = OrderType.LIMIT, TimeInForce timeInForce = TimeInForce.GTC, decimal icebergQty = 0m, long recvWindow = 5000)
+ public async Task PostNewOrderTest(string symbol, decimal quantity, decimal price, OrderSide side, OrderType orderType = OrderType.LIMIT, TimeInForce timeInForce = TimeInForce.GTC, string clientOrderId = null, decimal icebergQty = 0m, long recvWindow = 5000)
{
//Validates that the order is valid.
ValidateOrderValue(symbol, orderType, price, quantity, icebergQty);
+ //quantity needs to be conform to this regex ^([0-9]{1,20})(\.[0-9]{1,20})?$ -> 20 decimal digits
+ quantity = quantity / 1.000000000000000000000000000000m;
+ price = price / 1.000000000000000000000000000000m;
+ var args = $"symbol={symbol.ToUpper()}&side={side}&type={orderType}"
+ + $"&quantity={quantity}"
+ + (orderType == OrderType.LIMIT ? $"&timeInForce={timeInForce}" : "")
+ + (orderType == OrderType.LIMIT ? $"&price={price}" : "")
+ + (clientOrderId != null ? $"&newClientOrderId ={clientOrderId}" : "")
+ + (icebergQty > 0m ? $"&icebergQty={icebergQty}" : "")
+ + $"&recvWindow={recvWindow}";
- var args = $"symbol={symbol.ToUpper()}&side={side}&type={orderType}&quantity={quantity}"
- + (orderType == OrderType.LIMIT ? $"&timeInForce={timeInForce}" : "")
- + (orderType == OrderType.LIMIT ? $"&price={price}" : "")
- + (icebergQty > 0m ? $"&icebergQty={icebergQty}" : "")
- + $"&recvWindow={recvWindow}";
var result = await _apiClient.CallAsync(ApiMethod.POST, EndPoints.NewOrderTest, true, args);
return result;
@@ -360,14 +389,12 @@ public async Task CancelOrder(string symbol, long? orderId = null
/// Ticker symbol.
/// Specific number of milliseconds the request is valid for.
///
- public async Task> GetCurrentOpenOrders(string symbol, long recvWindow = 5000)
+ public async Task> GetCurrentOpenOrders(string symbol = null, long recvWindow = 5000)
{
- if (string.IsNullOrWhiteSpace(symbol))
- {
- throw new ArgumentException("symbol cannot be empty. ", "symbol");
- }
- var result = await _apiClient.CallAsync>(ApiMethod.GET, EndPoints.CurrentOpenOrders, true, $"symbol={symbol.ToUpper()}&recvWindow={recvWindow}");
+ var args = $"recvWindow={recvWindow}" +
+ (!string.IsNullOrEmpty(symbol) ? $"&symbol={symbol.ToUpper()}" : "");
+ var result = await _apiClient.CallAsync>(ApiMethod.GET, EndPoints.CurrentOpenOrders, true, args);
return result;
}
@@ -410,18 +437,34 @@ public async Task GetAccountInfo(long recvWindow = 5000)
/// Ticker symbol.
/// Specific number of milliseconds the request is valid for.
///
- public async Task> GetTradeList(string symbol, long recvWindow = 5000)
+ public async Task> GetTradeList(string symbol, int limit, long fromId, long recvWindow = 5000)
{
if (string.IsNullOrWhiteSpace(symbol))
{
throw new ArgumentException("symbol cannot be empty. ", "symbol");
}
-
- var result = await _apiClient.CallAsync>(ApiMethod.GET, EndPoints.TradeList, true, $"symbol={symbol.ToUpper()}&recvWindow={recvWindow}");
+ var para = $"symbol={symbol.ToUpper()}&limit={limit}&fromId={fromId}&recvWindow={recvWindow}";
+ var result = await _apiClient.CallAsync>(ApiMethod.GET, EndPoints.TradeList, true, para);
return result;
}
+ ///
+ /// Get trades for a specific account and symbol.
+ ///
+ /// Ticker symbol.
+ /// Specific number of milliseconds the request is valid for.
+ ///
+ public async Task> GetTradeList(string symbol, int limit, long recvWindow = 5000)
+ {
+ if (string.IsNullOrWhiteSpace(symbol))
+ {
+ throw new ArgumentException("symbol cannot be empty. ", "symbol");
+ }
+ var para = $"symbol={symbol.ToUpper()}&limit={limit}&recvWindow={recvWindow}";
+ var result = await _apiClient.CallAsync>(ApiMethod.GET, EndPoints.TradeList, true, para);
+ return result;
+ }
///
/// Submit a withdraw request.
///
@@ -558,12 +601,13 @@ public async Task CloseUserStream(string listenKey)
#endregion
#region Web Socket Client
+
///
/// Listen to the Depth endpoint.
///
/// Ticker symbol.
/// Handler to be used when a message is received.
- public void ListenDepthEndpoint(string symbol, ApiClientAbstract.MessageHandler depthHandler)
+ public WebSocket ListenDepthEndpoint(string symbol, ApiClientAbstract.MessageHandler depthHandler, Action onClose = null)
{
if (string.IsNullOrWhiteSpace(symbol))
{
@@ -571,7 +615,19 @@ public void ListenDepthEndpoint(string symbol, ApiClientAbstract.MessageHandler<
}
var param = symbol + "@depth";
- _apiClient.ConnectToWebSocket(param, depthHandler, true);
+ return _apiClient.ConnectToWebSocket(param, depthHandler, onClose, true);
+ }
+
+ public WebSocket ListenPartialDepthEndPoint(string symbol, int levels, ApiClientAbstract.MessageHandler depthHandler, Action onClose = null)
+ {
+ if (string.IsNullOrWhiteSpace(symbol))
+ {
+ throw new ArgumentException("symbol cannot be empty. ", "symbol");
+ }
+ if (levels != 5 && levels != 10 && levels != 20)
+ throw new ArgumentException("Valid values for level are 5,10 or 20");
+ var param = symbol.ToLower() + "@depth" + levels;
+ return _apiClient.ConnectToWebSocket(param, depthHandler, onClose, true);
}
///
@@ -580,7 +636,7 @@ public void ListenDepthEndpoint(string symbol, ApiClientAbstract.MessageHandler<
/// Ticker symbol.
/// Time interval to retreive.
/// Handler to be used when a message is received.
- public void ListenKlineEndpoint(string symbol, TimeInterval interval, ApiClientAbstract.MessageHandler klineHandler)
+ public WebSocket ListenKlineEndpoint(string symbol, TimeInterval interval, ApiClientAbstract.MessageHandler klineHandler, Action onClose = null)
{
if (string.IsNullOrWhiteSpace(symbol))
{
@@ -588,7 +644,7 @@ public void ListenKlineEndpoint(string symbol, TimeInterval interval, ApiClientA
}
var param = symbol + $"@kline_{interval.GetDescription()}";
- _apiClient.ConnectToWebSocket(param, klineHandler);
+ return _apiClient.ConnectToWebSocket(param, klineHandler, onClose);
}
///
@@ -596,7 +652,7 @@ public void ListenKlineEndpoint(string symbol, TimeInterval interval, ApiClientA
///
/// Ticker symbol.
/// Handler to be used when a message is received.
- public void ListenTradeEndpoint(string symbol, ApiClientAbstract.MessageHandler tradeHandler)
+ public WebSocket ListenTradeEndpoint(string symbol, ApiClientAbstract.MessageHandler tradeHandler, Action onClose = null)
{
if (string.IsNullOrWhiteSpace(symbol))
{
@@ -604,7 +660,7 @@ public void ListenTradeEndpoint(string symbol, ApiClientAbstract.MessageHandler<
}
var param = symbol + "@aggTrade";
- _apiClient.ConnectToWebSocket(param, tradeHandler);
+ return _apiClient.ConnectToWebSocket(param, tradeHandler, onClose);
}
///
@@ -614,11 +670,11 @@ public void ListenTradeEndpoint(string symbol, ApiClientAbstract.MessageHandler<
/// Handler to be used when a trade message is received.
/// Handler to be used when a order message is received.
///
- public string ListenUserDataEndpoint(ApiClientAbstract.MessageHandler accountInfoHandler, ApiClientAbstract.MessageHandler tradesHandler, ApiClientAbstract.MessageHandler ordersHandler)
+ public string ListenUserDataEndpoint(ApiClientAbstract.MessageHandler accountInfoHandler, ApiClientAbstract.MessageHandler tradesHandler, ApiClientAbstract.MessageHandler ordersHandler, Action onClose = null)
{
var listenKey = StartUserStream().Result.ListenKey;
- _apiClient.ConnectToUserDataWebSocket(listenKey, accountInfoHandler, tradesHandler, ordersHandler);
+ _apiClient.ConnectToUserDataWebSocket(listenKey, accountInfoHandler, tradesHandler, ordersHandler, onClose);
return listenKey;
}
diff --git a/Binance.API.Csharp.Client/Utils/CustomParser.cs b/Binance.API.Csharp.Client/Utils/CustomParser.cs
index fb96404..f32e577 100644
--- a/Binance.API.Csharp.Client/Utils/CustomParser.cs
+++ b/Binance.API.Csharp.Client/Utils/CustomParser.cs
@@ -2,6 +2,7 @@
using Binance.API.Csharp.Client.Models.WebSocket;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
namespace Binance.API.Csharp.Client.Utils
@@ -28,12 +29,20 @@ public OrderBook GetParsedOrderBook(dynamic orderBookData)
foreach (JToken item in ((JArray)orderBookData.bids).ToArray())
{
- bids.Add(new OrderBookOffer() { Price = decimal.Parse(item[0].ToString()), Quantity = decimal.Parse(item[1].ToString()) });
+ bids.Add(new OrderBookOffer
+ {
+ Price = decimal.Parse(item[0].ToString(), CultureInfo.InvariantCulture),
+ Quantity = decimal.Parse(item[1].ToString(), CultureInfo.InvariantCulture)
+ });
}
foreach (JToken item in ((JArray)orderBookData.asks).ToArray())
{
- asks.Add(new OrderBookOffer() { Price = decimal.Parse(item[0].ToString()), Quantity = decimal.Parse(item[1].ToString()) });
+ asks.Add(new OrderBookOffer
+ {
+ Price = decimal.Parse(item[0].ToString(), CultureInfo.InvariantCulture),
+ Quantity = decimal.Parse(item[1].ToString(), CultureInfo.InvariantCulture)
+ });
}
result.Bids = bids;
@@ -56,16 +65,16 @@ public IEnumerable GetParsedCandlestick(dynamic candlestickData)
result.Add(new Candlestick()
{
OpenTime = long.Parse(item[0].ToString()),
- Open = decimal.Parse(item[1].ToString()),
- High = decimal.Parse(item[2].ToString()),
- Low = decimal.Parse(item[3].ToString()),
- Close = decimal.Parse(item[4].ToString()),
- Volume = decimal.Parse(item[5].ToString()),
+ Open = decimal.Parse(item[1].ToString(), CultureInfo.InvariantCulture),
+ High = decimal.Parse(item[2].ToString(), CultureInfo.InvariantCulture),
+ Low = decimal.Parse(item[3].ToString(), CultureInfo.InvariantCulture),
+ Close = decimal.Parse(item[4].ToString(), CultureInfo.InvariantCulture),
+ Volume = decimal.Parse(item[5].ToString(), CultureInfo.InvariantCulture),
CloseTime = long.Parse(item[6].ToString()),
- QuoteAssetVolume = decimal.Parse(item[7].ToString()),
+ QuoteAssetVolume = decimal.Parse(item[7].ToString(), CultureInfo.InvariantCulture),
NumberOfTrades = int.Parse(item[8].ToString()),
- TakerBuyBaseAssetVolume = decimal.Parse(item[9].ToString()),
- TakerBuyQuoteAssetVolume = decimal.Parse(item[10].ToString())
+ TakerBuyBaseAssetVolume = decimal.Parse(item[9].ToString(), CultureInfo.InvariantCulture),
+ TakerBuyQuoteAssetVolume = decimal.Parse(item[10].ToString(), CultureInfo.InvariantCulture)
});
}
@@ -87,12 +96,54 @@ public DepthMessage GetParsedDepthMessage(dynamic messageData)
foreach (JToken item in ((JArray)messageData.b).ToArray())
{
- bids.Add(new OrderBookOffer() { Price = decimal.Parse(item[0].ToString()), Quantity = decimal.Parse(item[1].ToString()) });
+ bids.Add(new OrderBookOffer
+ {
+ Price = decimal.Parse(item[0].ToString(), CultureInfo.InvariantCulture),
+ Quantity = decimal.Parse(item[1].ToString(), CultureInfo.InvariantCulture)
+ });
}
foreach (JToken item in ((JArray)messageData.a).ToArray())
{
- asks.Add(new OrderBookOffer() { Price = decimal.Parse(item[0].ToString()), Quantity = decimal.Parse(item[1].ToString()) });
+ asks.Add(new OrderBookOffer
+ {
+ Price = decimal.Parse(item[0].ToString(), CultureInfo.InvariantCulture),
+ Quantity = decimal.Parse(item[1].ToString(), CultureInfo.InvariantCulture)
+ });
+ }
+
+ result.Bids = bids;
+ result.Asks = asks;
+
+ return result;
+ }
+
+ public DepthPartialMessage GetParsedDepthPartialMessage(dynamic messageData)
+ {
+ var result = new DepthPartialMessage
+ {
+ UpdateId = messageData.lastUpdateId
+ };
+
+ var bids = new List();
+ var asks = new List();
+
+ foreach (JToken item in ((JArray)messageData.bids).ToArray())
+ {
+ bids.Add(new OrderBookOffer()
+ {
+ Price = decimal.Parse(item[0].ToString(), CultureInfo.InvariantCulture),
+ Quantity = decimal.Parse(item[1].ToString(), CultureInfo.InvariantCulture)
+ });
+ }
+
+ foreach (JToken item in ((JArray)messageData.asks).ToArray())
+ {
+ asks.Add(new OrderBookOffer()
+ {
+ Price = decimal.Parse(item[0].ToString(), CultureInfo.InvariantCulture),
+ Quantity = decimal.Parse(item[1].ToString(), CultureInfo.InvariantCulture)
+ });
}
result.Bids = bids;
diff --git a/Binance.API.Csharp.Client/Utils/EndPoints.cs b/Binance.API.Csharp.Client/Utils/EndPoints.cs
index 681a066..75ef8b5 100644
--- a/Binance.API.Csharp.Client/Utils/EndPoints.cs
+++ b/Binance.API.Csharp.Client/Utils/EndPoints.cs
@@ -17,7 +17,7 @@ public static class EndPoints
public static readonly string TickerPriceChange24H = "/api/v1/ticker/24hr";
public static readonly string AllPrices = "/api/v1/ticker/allPrices";
public static readonly string OrderBookTicker = "/api/v1/ticker/allBookTickers";
- public static readonly string TradingRules = "https://gist.githubusercontent.com/Ninj0r/3029b9d635f8f81f5ffab9cc9df5cc61/raw/810530a2118e5d8cdcfcc4d220349976a0acf131/tradingRules_20171022.json";
+ public static readonly string TradingRules = "/api/v1/exchangeInfo";
#endregion
#region Account Endpoints
diff --git a/Binance.API.Csharp.Client/Utils/Utilities.cs b/Binance.API.Csharp.Client/Utils/Utilities.cs
index ef4159a..c56ff64 100644
--- a/Binance.API.Csharp.Client/Utils/Utilities.cs
+++ b/Binance.API.Csharp.Client/Utils/Utilities.cs
@@ -10,6 +10,7 @@ namespace Binance.API.Csharp.Client.Utils
///
public static class Utilities
{
+ public static long DeltaTimeAdjustment { get; set; } = 0;
///
/// Gets a HMACSHA256 signature based on the API Secret.
///
@@ -36,7 +37,7 @@ public static string GenerateSignature(string apiSecret, string message)
public static string GenerateTimeStamp(DateTime baseDateTime)
{
var dtOffset = new DateTimeOffset(baseDateTime);
- return dtOffset.ToUnixTimeMilliseconds().ToString();
+ return (dtOffset.ToUnixTimeMilliseconds() + DeltaTimeAdjustment).ToString();
}
///