/// <summary>
        /// Cancels a pending order
        /// </summary>
        /// <param name="symbol">The symbol the order is for</param>
        /// <param name="orderId">The order id of the order</param>
        /// <param name="origClientOrderId">The client order id of the order</param>
        /// <param name="newClientOrderId">Unique identifier for this cancel</param>
        /// <param name="recvWindow">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>
        /// <returns>Id's for canceled order</returns>
        public async Task <BinanceApiResult <BinanceCanceledOrder> > CancelOrderAsync(string symbol, long?orderId = null, string origClientOrderId = null, string newClientOrderId = null, long?recvWindow = null)
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <BinanceCanceledOrder>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            var parameters = new Dictionary <string, string>()
            {
                { "symbol", symbol },
                { "timestamp", GetTimestamp() }
            };

            AddOptionalParameter(parameters, "orderId", orderId?.ToString());
            AddOptionalParameter(parameters, "origClientOrderId", origClientOrderId);
            AddOptionalParameter(parameters, "newClientOrderId", newClientOrderId);
            AddOptionalParameter(parameters, "recvWindow", recvWindow?.ToString());

            return(await ExecuteRequest <BinanceCanceledOrder>(GetUrl(CancelOrderEndpoint, Api, SignedVersion, parameters), true, DeleteMethod));
        }
Beispiel #2
0
        private BinanceApiResult <BinanceStream> CreateSocket(string url)
        {
            try
            {
                var socket = SocketFactory.CreateWebsocket(url);

                var socketObject = new BinanceStream()
                {
                    Socket = socket, StreamId = NextStreamId()
                };
                socket.SetEnabledSslProtocols(protocols);
                socket.OnClose += (obj, args) => Socket_OnClose(socketObject, args);
                socket.OnError += (obj, args) => Socket_OnError(socketObject, args);
                socket.OnOpen  += (obj, args) => Socket_OnOpen(socketObject, args);
                socket.Connect();
                lock (sockets)
                    sockets.Add(socketObject);

                return(new BinanceApiResult <BinanceStream>()
                {
                    Data = socketObject, Success = true
                });
            }
            catch (Exception e)
            {
                var errorMessage = $"Couldn't open socket stream: {e.Message}";
                log.Write(LogVerbosity.Error, errorMessage);
                return(ThrowErrorMessage <BinanceStream>(BinanceErrors.GetError(BinanceErrorKey.CantConnectToServer), errorMessage));
            }
        }
        /// <summary>
        /// Places a new test order. Test orders are not actually being executed and just test the functionality.
        /// </summary>
        /// <param name="symbol">The symbol the order is for</param>
        /// <param name="side">The order side (buy/sell)</param>
        /// <param name="type">The order type (limit/market)</param>
        /// <param name="timeInForce">Lifetime of the order (GoodTillCancel/ImmediateOrCancel)</param>
        /// <param name="quantity">The amount of the symbol</param>
        /// <param name="price">The price to use</param>
        /// <param name="newClientOrderId">Unique id for order</param>
        /// <param name="stopPrice">Used for stop orders</param>
        /// <param name="icebergQty">User for iceberg orders</param>
        /// <returns>Id's for the placed test order</returns>
        public async Task <BinanceApiResult <BinancePlacedOrder> > PlaceTestOrderAsync(string symbol, OrderSide side, OrderType type, TimeInForce timeInForce, decimal quantity, decimal price, string newClientOrderId = null, decimal?stopPrice = null, decimal?icebergQty = null)
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <BinancePlacedOrder>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            var parameters = new Dictionary <string, string>()
            {
                { "symbol", symbol },
                { "side", JsonConvert.SerializeObject(side, new OrderSideConverter(false)) },
                { "type", JsonConvert.SerializeObject(type, new OrderTypeConverter(false)) },
                { "timeInForce", JsonConvert.SerializeObject(timeInForce, new TimeInForceConverter(false)) },
                { "quantity", quantity.ToString(CultureInfo.InvariantCulture) },
                { "price", price.ToString(CultureInfo.InvariantCulture) },
                { "timestamp", GetTimestamp() }
            };

            AddOptionalParameter(parameters, "newClientOrderId", newClientOrderId);
            AddOptionalParameter(parameters, "stopPrice", stopPrice?.ToString());
            AddOptionalParameter(parameters, "icebergQty", icebergQty?.ToString());

            return(await ExecuteRequest <BinancePlacedOrder>(GetUrl(NewTestOrderEndpoint, Api, SignedVersion, parameters), true, PostMethod));
        }
        /// <summary>
        /// Subscribes to the account update stream. Prior to using this, the <see cref="BinanceClient.StartUserStream"/> method should be called.
        /// </summary>
        /// <param name="listenKey">Listen key retrieved by the StartUserStream method</param>
        /// <param name="onAccountInfoMessage">The event handler for whenever an account info update is received</param>
        /// <param name="OnOrderUpdateMessage">The event handler for whenever an order status update is received</param>
        /// <returns>A stream subscription. This stream subscription can be used to be notified when the socket is closed and can close this specific stream
        /// using the <see cref="UnsubscribeFromStream(BinanceStreamSubscription)"/> method</returns>
        public BinanceApiResult <BinanceStreamSubscription> SubscribeToUserStream(string listenKey, Action <BinanceStreamAccountInfo> onAccountInfoMessage, Action <BinanceStreamOrderUpdate> OnOrderUpdateMessage)
        {
            if (string.IsNullOrEmpty(listenKey))
            {
                return(ThrowErrorMessage <BinanceStreamSubscription>(BinanceErrors.GetError(BinanceErrorKey.NoListenKey)));
            }

            return(CreateUserStream(listenKey, onAccountInfoMessage, OnOrderUpdateMessage));
        }
Beispiel #5
0
        /// <summary>
        /// Subscribes to the order update stream. Prior to using this, the <see cref="BinanceClient.StartUserStream"/> method should be called.
        /// </summary>
        /// <param name="listenKey">Listen key retrieved by the StartUserStream method</param>
        /// <param name="onMessage">The event handler for the data received</param>
        /// <returns>bool indicating success</returns>
        public BinanceApiResult <bool> SubscribeToOrderUpdateStream(string listenKey, Action <BinanceStreamOrderUpdate> onMessage)
        {
            if (string.IsNullOrEmpty(listenKey))
            {
                return(ThrowErrorMessage <bool>(BinanceErrors.GetError(BinanceErrorKey.NoListenKey)));
            }

            orderUpdateCallback = onMessage;
            return(CreateUserStream(listenKey));
        }
        /// <summary>
        /// Starts a user stream by requesting a listen key. This listen key can be used in subsequent requests to <see cref="BinanceSocketClient.SubscribeToAccountUpdateStream"/> and <see cref="BinanceSocketClient.SubscribeToOrderUpdateStream"/>
        /// </summary>
        /// <returns>Listen key</returns>
        public async Task <BinanceApiResult <BinanceListenKey> > StartUserStreamAsync()
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <BinanceListenKey>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            return(await ExecuteRequest <BinanceListenKey>(GetUrl(GetListenKeyEndpoint, Api, UserDataStreamVersion), false, PostMethod));
        }
        /// <summary>
        /// Stops the current user stream
        /// </summary>
        /// <returns></returns>
        public async Task <BinanceApiResult <object> > StopUserStreamAsync(string listenKey)
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <object>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            var parameters = new Dictionary <string, string>()
            {
                { "listenKey", listenKey },
            };

            return(await ExecuteRequest <object>(GetUrl(CloseListenKeyEndpoint, Api, UserDataStreamVersion, parameters), false, DeleteMethod));
        }
        /// <summary>
        /// Gets the withdrawal history
        /// </summary>
        /// <param name="asset">Filter by asset</param>
        /// <param name="status">Filter by status</param>
        /// <param name="startTime">Filter start time from</param>
        /// <param name="endTime">Filter end time till</param>
        /// <param name="recvWindow">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>
        /// <returns>List of withdrawals</returns>
        public async Task <BinanceApiResult <BinanceWithdrawalList> > GetWithdrawHistoryAsync(string asset = null, WithdrawalStatus?status = null, DateTime?startTime = null, DateTime?endTime = null, long?recvWindow = null)
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <BinanceWithdrawalList>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            var parameters = new Dictionary <string, string>()
            {
                { "timestamp", GetTimestamp() }
            };

            AddOptionalParameter(parameters, "asset", asset);
            AddOptionalParameter(parameters, "status", status != null ? JsonConvert.SerializeObject(status, new WithdrawalStatusConverter(false)): null);
            AddOptionalParameter(parameters, "startTime", startTime != null ? ToUnixTimestamp(startTime.Value).ToString(CultureInfo.InvariantCulture) : null);
            AddOptionalParameter(parameters, "endTime", endTime != null ? ToUnixTimestamp(endTime.Value).ToString(CultureInfo.InvariantCulture) : null);
            AddOptionalParameter(parameters, "recvWindow", recvWindow?.ToString());

            var result = await ExecuteRequest <BinanceWithdrawalList>(GetUrl(WithdrawHistoryEndpoint, WithdrawalApi, WithdrawalVersion, parameters), true, PostMethod);

            if (!result.Success || result.Data == null)
            {
                return(result);
            }

            result.Success = result.Data.Success;
            if (!result.Success)
            {
                result.Error = new BinanceError()
                {
                    Message = result.Data.Message
                }
            }
            ;
            return(result);
        }
        /// <summary>
        /// Withdraw assets from Binance to an address
        /// </summary>
        /// <param name="asset">The asset to withdraw</param>
        /// <param name="address">The address to send the funds to</param>
        /// <param name="amount">The amount to withdraw</param>
        /// <param name="name">Name for the transaction</param>
        /// <param name="recvWindow">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>
        /// <returns>Withdrawal confirmation</returns>
        public async Task <BinanceApiResult <BinanceWithdrawalPlaced> > WithdrawAsync(string asset, string address, decimal amount, string name = null, long?recvWindow = null)
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <BinanceWithdrawalPlaced>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            var parameters = new Dictionary <string, string>()
            {
                { "asset", asset },
                { "address", address },
                { "amount", amount.ToString(CultureInfo.InvariantCulture) },
                { "timestamp", GetTimestamp() }
            };

            AddOptionalParameter(parameters, "name", name);
            AddOptionalParameter(parameters, "recvWindow", recvWindow?.ToString());

            var result = await ExecuteRequest <BinanceWithdrawalPlaced>(GetUrl(WithdrawEndpoint, WithdrawalApi, WithdrawalVersion, parameters), true, PostMethod);

            if (!result.Success || result.Data == null)
            {
                return(result);
            }

            result.Success = result.Data.Success;
            if (!result.Success)
            {
                result.Error = new BinanceError()
                {
                    Message = result.Data.Message
                }
            }
            ;
            return(result);
        }
Beispiel #10
0
        /// <summary>
        /// Gets account information, including balances
        /// </summary>
        /// <param name="recvWindow">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>
        /// <returns>The account information</returns>
        public async Task <BinanceApiResult <BinanceAccountInfo> > GetAccountInfoAsync(long?recvWindow = null)
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <BinanceAccountInfo>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            var parameters = new Dictionary <string, string>()
            {
                { "timestamp", GetTimestamp() }
            };

            AddOptionalParameter(parameters, "recvWindow", recvWindow?.ToString());

            return(await ExecuteRequest <BinanceAccountInfo>(GetUrl(AccountInfoEndpoint, Api, SignedVersion, parameters), true, GetMethod));
        }
Beispiel #11
0
        /// <summary>
        /// Gets a list of open orders for the provided symbol
        /// </summary>
        /// <param name="symbol">The symbol to get open orders for</param>
        /// <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>
        /// <returns>List of open orders</returns>
        public async Task <BinanceApiResult <BinanceOrder[]> > GetOpenOrdersAsync(string symbol, int?receiveWindow = null)
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <BinanceOrder[]>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            var parameters = new Dictionary <string, string>()
            {
                { "symbol", symbol },
                { "timestamp", GetTimestamp() }
            };

            AddOptionalParameter(parameters, "recvWindow", receiveWindow?.ToString());

            return(await ExecuteRequest <BinanceOrder[]>(GetUrl(OpenOrdersEndpoint, Api, SignedVersion, parameters), true));
        }
Beispiel #12
0
        /// <summary>
        /// Gets all user trades for provided symbol
        /// </summary>
        /// <param name="symbol">Symbol to get trades for</param>
        /// <param name="limit">The max number of results</param>
        /// <param name="fromId">TradeId to fetch from. Default gets most recent trades</param>
        /// <param name="recvWindow">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>
        /// <returns>List of trades</returns>
        public async Task <BinanceApiResult <BinanceTrade[]> > GetMyTradesAsync(string symbol, int?limit = null, long?fromId = null, long?recvWindow = null)
        {
            if (key == null || encryptor == null)
            {
                return(ThrowErrorMessage <BinanceTrade[]>(BinanceErrors.GetError(BinanceErrorKey.NoApiCredentialsProvided)));
            }

            if (AutoTimestamp && !timeSynced)
            {
                await GetServerTimeAsync();
            }

            var parameters = new Dictionary <string, string>()
            {
                { "symbol", symbol },
                { "timestamp", GetTimestamp() }
            };

            AddOptionalParameter(parameters, "limit", limit?.ToString(CultureInfo.InvariantCulture));
            AddOptionalParameter(parameters, "fromId", fromId?.ToString(CultureInfo.InvariantCulture));
            AddOptionalParameter(parameters, "recvWindow", recvWindow?.ToString(CultureInfo.InvariantCulture));

            return(await ExecuteRequest <BinanceTrade[]>(GetUrl(MyTradesEndpoint, Api, SignedVersion, parameters), true, GetMethod));
        }
Beispiel #13
0
        private async Task <BinanceApiResult <T> > ExecuteRequest <T>(Uri uri, bool signed = false, string method = GetMethod, int currentTry = 0)
        {
            var    apiResult    = (BinanceApiResult <T>)Activator.CreateInstance(typeof(BinanceApiResult <T>));
            string returnedData = "";

            try
            {
                var uriString = uri.ToString();
                if (signed)
                {
                    uriString +=
                        $"&signature={ByteToString(encryptor.ComputeHash(Encoding.UTF8.GetBytes(uri.Query.Replace("?", ""))))}";
                }

                var request = RequestFactory.Create(uriString);
                request.Headers.Add("X-MBX-APIKEY", key);
                request.Method = method;

                log.Write(LogVerbosity.Debug, $"Sending {method} request to {uriString}");
                var response = request.GetResponse();
                using (var reader = new StreamReader(response.GetResponseStream()))
                {
                    returnedData = await reader.ReadToEndAsync();

                    var result = JsonConvert.DeserializeObject <T>(returnedData);
                    apiResult.Success = true;
                    apiResult.Data    = result;
                    return(apiResult);
                }
            }
            catch (WebException we)
            {
                var response = (HttpWebResponse)we.Response;
                if ((int)response.StatusCode >= 400)
                {
                    try
                    {
                        using (var reader = new StreamReader(response.GetResponseStream()))
                        {
                            var error = JsonConvert.DeserializeObject <BinanceError>(await reader.ReadToEndAsync());
                            apiResult.Success = false;
                            apiResult.Error   = error;
                            log.Write(LogVerbosity.Warning,
                                      $"Request to {uri} returned an error: {apiResult.Error?.Code} - {apiResult.Error?.Message}");
                            return(apiResult);
                        }
                    }
                    catch (Exception)
                    {
                        log.Write(LogVerbosity.Warning, $"Couldn't parse error response for status code {response.StatusCode}");
                    }
                }

                if (currentTry < MaxRetries)
                {
                    return(await ExecuteRequest <T>(uri, signed, method, ++currentTry));
                }

                return(ThrowErrorMessage <T>(BinanceErrors.GetError(BinanceErrorKey.ErrorWeb), $"Status: {response.StatusCode}-{response.StatusDescription}, Message: {we.Message}"));
            }
            catch (JsonSerializationException jse)
            {
                return(ThrowErrorMessage <T>(BinanceErrors.GetError(BinanceErrorKey.ParseErrorSerialization), $"Message: {jse.Message}. Received data: {returnedData}"));
            }
            catch (JsonReaderException jre)
            {
                return(ThrowErrorMessage <T>(BinanceErrors.GetError(BinanceErrorKey.ParseErrorReader), $"Error occured at Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}. Received data: {returnedData}"));
            }
            catch (Exception e)
            {
                return(ThrowErrorMessage <T>(BinanceErrors.GetError(BinanceErrorKey.UnknownError), $"Message: {e.Message}"));
            }
        }