Example #1
0
        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);
        }
Example #2
0
        /// <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);
        }