private ExchangeOrderResult ParsePlaceOrder(JToken token, ExchangeOrderRequest order) { /* * {"result":true,"order_id":123456} */ ExchangeOrderResult result = new ExchangeOrderResult { Amount = order.Amount, Price = order.Price, IsBuy = order.IsBuy, OrderId = token["order_id"].ToStringInvariant(), //Symbol = order.Symbol.OriginSymbol }; result.Result = ExchangeAPIOrderResult.Pending; return(result); }
/// <summary> /// Place a limit order by first querying the order book and then placing the order for a threshold below the bid or /// above the ask that would fully fulfill the amount. /// The order book is scanned until an amount of bids or asks that will fulfill the order is found and then the order /// is placed at the lowest bid or highest ask price multiplied /// by priceThreshold. /// </summary> /// <param name="api"></param> /// <param name="symbol">Symbol to sell</param> /// <param name="amount">Amount to sell</param> /// <param name="isBuy">True for buy, false for sell</param> /// <param name="orderBookCount">Amount of bids/asks to request in the order book</param> /// <param name="priceThreshold"> /// Threshold below the lowest bid or above the highest ask to set the limit order price at. For buys, this is /// converted to 1 / priceThreshold. /// This can be set to 0 if you want to set the price like a market order. /// </param> /// <param name="thresholdToAbort"> /// If the lowest bid/highest ask price divided by the highest bid/lowest ask price is below this threshold, throw an /// exception. /// This ensures that your order does not buy or sell at an extreme margin. /// </param> /// <param name="abortIfOrderBookTooSmall"> /// Whether to abort if the order book does not have enough bids or ask amounts to /// fulfill the order. /// </param> /// <returns>Order result</returns> public static async Task <List <ExchangeOrderResult> > PlaceSafeMarketOrderAsync( this ExchangeAPI api, string symbol, decimal amount, bool isBuy, int orderBookCount = 100, decimal priceThreshold = 0.9m, decimal thresholdToAbort = 0.75m, bool abortIfOrderBookTooSmall = false) { if (priceThreshold > 0.9m) { throw new APIException( "You cannot specify a price threshold above 0.9m, otherwise there is a chance your order will never be fulfilled. For buys, this is " + "converted to 1.0m / priceThreshold, so always specify the value below 0.9m"); } if (priceThreshold <= 0m) { priceThreshold = 1m; } else if (isBuy && priceThreshold > 0m) { priceThreshold = 1.0m / priceThreshold; } ExchangeDepth book = null; //todo await api.GetDepthAsync(symbol, orderBookCount); if (book == null || isBuy && book.Asks.Count == 0 || !isBuy && book.Bids.Count == 0) { throw new APIException($"Error getting order book for {symbol}"); } var counter = 0m; var highPrice = decimal.MinValue; var lowPrice = decimal.MaxValue; if (isBuy) { foreach (var ask in book.Asks.Values) { counter += ask.Amount; highPrice = Math.Max(highPrice, ask.Price); lowPrice = Math.Min(lowPrice, ask.Price); if (counter >= amount) { break; } } } else { foreach (var bid in book.Bids.Values) { counter += bid.Amount; highPrice = Math.Max(highPrice, bid.Price); lowPrice = Math.Min(lowPrice, bid.Price); if (counter >= amount) { break; } } } if (abortIfOrderBookTooSmall && counter < amount) { throw new APIException( $"{(isBuy ? "Buy" : "Sell")} order for {symbol} and amount {amount} cannot be fulfilled because the order book is too thin."); } if (lowPrice / highPrice < thresholdToAbort) { throw new APIException( $"{(isBuy ? "Buy" : "Sell")} order for {symbol} and amount {amount} would place for a price below threshold of {thresholdToAbort}, aborting."); } var request = new ExchangeOrderRequest { Amount = amount, OrderType = OrderType.Limit, Price = CryptoUtility.RoundAmount((isBuy ? highPrice : lowPrice) * priceThreshold), ShouldRoundAmount = true, Symbol = null //todo symbol }; var result = await api.PlaceOrdersAsync(request); // wait about 10 seconds until the order is fulfilled var i = 0; const int maxTries = 20; // 500 ms for each try for (; i < maxTries; i++) { await Task.Delay(500); } //TODO //result = await api.GetCanceledOrdersAsync(result.OrderId, symbol); //switch (result.Result) //{ // case ExchangeAPIOrderResult.Filled: // case ExchangeAPIOrderResult.Canceled: // case ExchangeAPIOrderResult.Error: // break; //} if (i == maxTries) { throw new APIException( $"{(isBuy ? "Buy" : "Sell")} order for {symbol} and amount {amount} timed out and may not have been fulfilled"); } return(result); }