/// <summary> /// Subscribes to updates on a specific market /// </summary> /// <param name="marketName">The name of the market to subscribe on</param> /// <param name="onUpdate">The update event handler</param> /// <returns></returns> public BittrexApiResult <int> SubscribeToMarketDeltaStream(string marketName, Action <BittrexMarketSummary> onUpdate) { log.Write(LogVerbosity.Debug, $"Going to subscribe to {marketName}"); lock (connectionLock) { if (connection == null || connection.State == ConnectionState.Disconnected) { log.Write(LogVerbosity.Debug, "Starting connection to bittrex server"); if (!WaitForConnection()) { return(ThrowErrorMessage <int>(BittrexErrors.GetError(BittrexErrorKey.CantConnectToServer))); } } } var registration = new BittrexStreamRegistration() { Callback = onUpdate, MarketName = marketName, StreamId = NextStreamId }; lock (registrationLock) { registrations.Add(registration); localRegistrations.Add(registration); } return(new BittrexApiResult <int>() { Result = registration.StreamId, Success = true }); }
/// <summary> /// Subscribes to updates of all markets /// </summary> /// <param name="onUpdate">The update event handler</param> /// <returns>ApiResult whether subscription was successful. The Result property contains the Stream Id which can be used to unsubscribe the stream again</returns> public async Task <BittrexApiResult <int> > SubscribeToAllMarketDeltaStreamAsync(Action <List <BittrexMarketSummary> > onUpdate) { return(await Task.Run(() => { log.Write(LogVerbosity.Debug, $"Going to subscribe to all markets"); if (!CheckConnection()) { return ThrowErrorMessage <int>(BittrexErrors.GetError(BittrexErrorKey.CantConnectToServer)); } var registration = new BittrexMarketsAllRegistration() { Callback = onUpdate, StreamId = NextStreamId }; lock (registrationLock) { registrations.Add(registration); localRegistrations.Add(registration); } return new BittrexApiResult <int>() { Result = registration.StreamId, Success = true }; }).ConfigureAwait(false)); }
/// <summary> /// Subscribes to updates on a specific market /// </summary> /// <param name="marketName">The name of the market to subscribe on</param> /// <param name="onUpdate">The update event handler</param> /// <returns>ApiResult whether subscription was successful. The Result property contains the Stream Id which can be used to unsubscribe the stream again</returns> public async Task <BittrexApiResult <int> > SubscribeToExchangeDeltasAsync(string marketName, Action <BittrexStreamExchangeState> onUpdate) { return(await Task.Run(() => { if (!CheckConnection()) { return ThrowErrorMessage <int>(BittrexErrors.GetError(BittrexErrorKey.CantConnectToServer)); } // send subscribe to bittrex SubscribeToExchangeDeltas(marketName); var registration = new BittrexExchangeDeltasRegistration() { Callback = onUpdate, MarketName = marketName, StreamId = NextStreamId }; lock (registrationLock) { registrations.Add(registration); localRegistrations.Add(registration); } return new BittrexApiResult <int>() { Result = registration.StreamId, Success = true }; }).ConfigureAwait(false)); }
/// <summary> /// Gets a list of all balances for the current account /// </summary> /// <returns>List of balances</returns> public async Task <BittrexApiResult <BittrexBalance[]> > GetBalancesAsync() { if (apiKey == null || encryptor == null) { return(ThrowErrorMessage <BittrexBalance[]>(BittrexErrors.GetError(BittrexErrorKey.NoApiCredentialsProvided))); } return(await ExecuteRequest <BittrexBalance[]>(GetUrl(BalancesEndpoint, Api, ApiVersion), true)); }
/// <summary> /// Gets the deposit history of the current account /// </summary> /// <param name="currency">Filter on currency</param> /// <returns>List of deposits</returns> public async Task <BittrexApiResult <BittrexDeposit[]> > GetDepositHistoryAsync(string currency = null) { if (apiKey == null || encryptor == null) { return(ThrowErrorMessage <BittrexDeposit[]>(BittrexErrors.GetError(BittrexErrorKey.NoApiCredentialsProvided))); } var parameters = new Dictionary <string, string>(); AddOptionalParameter(parameters, "currency", currency); return(await ExecuteRequest <BittrexDeposit[]>(GetUrl(DepositHistoryEndpoint, Api, ApiVersion, parameters), true)); }
/// <summary> /// Gets the order history for the current account /// </summary> /// <param name="market">Filter on market</param> /// <returns>List of orders</returns> public async Task <BittrexApiResult <BittrexOrderHistoryOrder[]> > GetOrderHistoryAsync(string market = null) { if (apiKey == null || encryptor == null) { return(ThrowErrorMessage <BittrexOrderHistoryOrder[]>(BittrexErrors.GetError(BittrexErrorKey.NoApiCredentialsProvided))); } var parameters = new Dictionary <string, string>(); AddOptionalParameter(parameters, "market", market); return(await ExecuteRequest <BittrexOrderHistoryOrder[]>(GetUrl(OrderHistoryEndpoint, Api, ApiVersion, parameters), true).ConfigureAwait(false)); }
/// <summary> /// Gets an order by it's guid /// </summary> /// <param name="guid">The guid of the order</param> /// <returns>The requested order</returns> public async Task <BittrexApiResult <BittrexAccountOrder> > GetOrderAsync(Guid guid) { if (apiKey == null || encryptor == null) { return(ThrowErrorMessage <BittrexAccountOrder>(BittrexErrors.GetError(BittrexErrorKey.NoApiCredentialsProvided))); } var parameters = new Dictionary <string, string>() { { "uuid", guid.ToString() } }; return(await ExecuteRequest <BittrexAccountOrder>(GetUrl(OrderEndpoint, Api, ApiVersion, parameters), true)); }
/// <summary> /// Gets the balance of a single currency /// </summary> /// <param name="currency">Currency to get the balance for</param> /// <returns>The balance of the currency</returns> public async Task <BittrexApiResult <BittrexBalance> > GetBalanceAsync(string currency) { if (apiKey == null || encryptor == null) { return(ThrowErrorMessage <BittrexBalance>(BittrexErrors.GetError(BittrexErrorKey.NoApiCredentialsProvided))); } var parameters = new Dictionary <string, string>() { { "currency", currency } }; return(await ExecuteRequest <BittrexBalance>(GetUrl(BalanceEndpoint, Api, ApiVersion, parameters), true)); }
/// <summary> /// Places a withdraw request on Bittrex /// </summary> /// <param name="currency">The currency to withdraw</param> /// <param name="quantity">The quantity to withdraw</param> /// <param name="address">The address to withdraw to</param> /// <param name="paymentId">Optional string identifier to add to the withdraw</param> /// <returns>Guid of the withdrawal</returns> public async Task <BittrexApiResult <BittrexGuid> > WithdrawAsync(string currency, decimal quantity, string address, string paymentId = null) { if (apiKey == null || encryptor == null) { return(ThrowErrorMessage <BittrexGuid>(BittrexErrors.GetError(BittrexErrorKey.NoApiCredentialsProvided))); } var parameters = new Dictionary <string, string>() { { "currency", currency }, { "quantity", quantity.ToString(CultureInfo.InvariantCulture) }, { "address", address }, }; AddOptionalParameter(parameters, "paymentid", paymentId); return(await ExecuteRequest <BittrexGuid>(GetUrl(WithdrawEndpoint, Api, ApiVersion, parameters), true)); }
/// <summary> /// Places an order /// </summary> /// <param name="type">Type of the order</param> /// <param name="market">Market to place the order on</param> /// <param name="quantity">The quantity of the order</param> /// <param name="rate">The rate per unit of the order</param> /// <returns></returns> public async Task <BittrexApiResult <BittrexGuid> > PlaceOrderAsync(OrderType type, string market, decimal quantity, decimal rate) { if (apiKey == null || encryptor == null) { return(ThrowErrorMessage <BittrexGuid>(BittrexErrors.GetError(BittrexErrorKey.NoApiCredentialsProvided))); } var parameters = new Dictionary <string, string>() { { "market", market }, { "quantity", quantity.ToString(CultureInfo.InvariantCulture) }, { "rate", rate.ToString(CultureInfo.InvariantCulture) } }; var uri = GetUrl(type == OrderType.Buy ? BuyLimitEndpoint : SellLimitEndpoint, Api, ApiVersion, parameters); return(await ExecuteRequest <BittrexGuid>(uri, true)); }
/// <summary> /// get basic/initial info of a specific market /// 500 Buys /// 100 Fills /// 500 Sells /// </summary> /// <param name="marketName">The name of the market to subscribe on</param> /// <param name="onUpdate">The update event handler</param> /// <returns>ApiResult whether subscription was successful. The Result property contains the Stream Id which can be used to unsubscribe the stream again</returns> public async Task <BittrexApiResult <int> > QueryExchangeStateAsync(string marketName, Action <BittrexExchangeState> onUpdate) { return(await Task.Run(() => { log.Write(LogVerbosity.Debug, $"Going to call QueryExchangeState for market: {marketName}"); if (!CheckConnection()) { return ThrowErrorMessage <int>(BittrexErrors.GetError(BittrexErrorKey.CantConnectToServer)); } // gives direkt return -> no subscription // https://stackoverflow.com/questions/11140164/signalr-console-app-example proxy.Invoke <JObject>("QueryExchangeState", marketName).ContinueWith(task => { if (task.IsFaulted) { log.Write(LogVerbosity.Error, String.Format("There was an error calling send: {0}", task.Exception.GetBaseException())); } else { string json = ""; try { json = task.Result.ToString(); BittrexExchangeState StreamData = JsonConvert.DeserializeObject <BittrexExchangeState>(json); onUpdate(StreamData); } catch (Exception e) { log.Write(LogVerbosity.Warning, $"Received an event but an unknown error occured. Message: {e.Message}, Received data: {json}"); } } }); return new BittrexApiResult <int>() { Success = true }; }).ConfigureAwait(false)); }
private async Task <BittrexApiResult <T> > ExecuteRequest <T>(Uri uri, bool signed = false, int currentTry = 0) { string returnedData = ""; try { var uriString = uri.ToString(); if (signed) { if (!uriString.EndsWith("?")) { uriString += "&"; } uriString += $"apiKey={apiKey}&nonce={nonce}"; } var request = RequestFactory.Create(uriString); if (signed) { request.Headers.Add("apisign", ByteToString(encryptor.ComputeHash(Encoding.UTF8.GetBytes(uriString)))); } foreach (var limiter in rateLimiters) { double limitedBy = limiter.LimitRequest(uri.AbsolutePath); if (limitedBy > 0) { log.Write(LogVerbosity.Debug, $"Request {uri.AbsolutePath} was limited by {limitedBy}ms by {limiter.GetType().Name}"); } } log.Write(LogVerbosity.Debug, $"Sending request to {uriString}"); var response = request.GetResponse(); using (var reader = new StreamReader(response.GetResponseStream())) { returnedData = await reader.ReadToEndAsync(); var result = JsonConvert.DeserializeObject <BittrexApiResult <T> >(returnedData); if (!result.Success) { log.Write(LogVerbosity.Debug, $"Call failed to {uri}, Error message: {result.Message}"); result.Error = new BittrexError(6000, result.Message); result.Message = null; } return(result); } } catch (WebException we) { var response = (HttpWebResponse)we.Response; if (currentTry < MaxRetries) { return(await ExecuteRequest <T>(uri, signed, ++currentTry)); } return(ThrowErrorMessage <T>(BittrexErrors.GetError(BittrexErrorKey.ErrorWeb), $"Status: {response.StatusCode}-{response.StatusDescription}, Message: {we.Message}")); } catch (JsonReaderException jre) { return(ThrowErrorMessage <T>(BittrexErrors.GetError(BittrexErrorKey.ParseErrorReader), $"Error occured at Path: {jre.Path}, LineNumber: {jre.LineNumber}, LinePosition: {jre.LinePosition}. Received data: {returnedData}")); } catch (JsonSerializationException jse) { return(ThrowErrorMessage <T>(BittrexErrors.GetError(BittrexErrorKey.ParseErrorSerialization), $"Message: {jse.Message}. Received data: {returnedData}")); } catch (Exception e) { return(ThrowErrorMessage <T>(BittrexErrors.GetError(BittrexErrorKey.UnknownError), $"Message: {e.Message}")); } }