예제 #1
0
        private async Task CancelOrder(string currentOrderId)
        {
            await _trader.CancelOrder(currentOrderId);

            _levelsByOrder.Remove(currentOrderId);
        }
        public async Task PlaceToMarketAsync()
        {
            var level = _levels.FirstOrDefault(l => l.Status == MarketLevelStatus.Empty);

            while (level != null)
            {
                var side =
                    (level.Side == MarketSide.Long && level.Type == MarketLevelType.Direct) ||
                    (level.Side == MarketSide.Short && level.Type == MarketLevelType.Compensate)
                        ? MarketSide.Long
                        : MarketSide.Short;

                var price = level.Type == MarketLevelType.Direct ? level.Price : level.PriceCompensate;



                var scope = _levels.Where(l => l.Status == MarketLevelStatus.Placed && l.OrderSide != side);

                var crossLevel =
                    side == MarketSide.Long
                        ? scope.Where(l => l.Price <= price).OrderBy(l => l.Price).FirstOrDefault() :
                    scope.Where(l => l.Price >= price).OrderByDescending(l => l.Price).FirstOrDefault();

                if (crossLevel != null)
                {
                    crossLevel.CurrentOrderId = string.Empty;
                    crossLevel.Status         = MarketLevelStatus.Empty;
                    crossLevel.Type           = crossLevel.Type == MarketLevelType.Direct ? MarketLevelType.Compensate : MarketLevelType.Direct;

                    if (crossLevel.Status == MarketLevelStatus.Placed)
                    {
                        await _trader.CancelOrder(crossLevel.CurrentOrderId);

                        _levelsByOrder.Remove(crossLevel.CurrentOrderId);
                    }

                    Console.WriteLine($"flip level. Price: {level.Price}, Side: {level.Side}, Type: {level.Type}, Id: {level.CurrentOrderId}");


                    level.CurrentOrderId = string.Empty;
                    level.Status         = MarketLevelStatus.Empty;
                    level.Type           = level.Type == MarketLevelType.Direct ? MarketLevelType.Compensate : MarketLevelType.Direct;
                    Console.WriteLine($"flip level. Price: {level.Price}, Side: {level.Side}, Type: {level.Type}");
                }
                else
                {
                    var orderId = await _trader.PlaceOrderAsync(
                        _symbol,
                        price,
                        level.OriginalSize,
                        side);

                    if (!string.IsNullOrEmpty(orderId))
                    {
                        level.CurrentOrderId = orderId;
                        level.Status         = MarketLevelStatus.Placed;
                        level.OrderSide      = side;
                        Console.WriteLine(
                            $"Placed. Price: {level.Price}, Type: {level.Side}/{level.Type}, O-Price: {price}, O-Side: {side}, O-Id: {level.CurrentOrderId}");

                        _levelsByOrder[orderId] = level;
                    }
                }

                level = _levels.FirstOrDefault(l => l.Status == MarketLevelStatus.Empty);
            }
        }
예제 #3
0
        private async void HandleNonFilledOrder(ExchangeOrderResult orderResult, Candle candle)
        {
            ExchangeOrderResult result = null;

            Ticker ticker;

            switch (orderResult.Result)
            {
            case ExchangeAPIOrderResult.FilledPartially:

                Log($"Partially filled order quantity filled {orderResult.AmountFilled} of {orderResult.Amount}");

                /*
                 *
                 * PARTIALLY FILLED
                 *
                 * 1. Save the initial order and what was filled
                 * 2. Check in thrity seconds for any more filling of it
                 * 3. Add a new order against this position
                 * 4. If not filled after two more queries, cancel it
                 *
                 */

                // 1. Save

                SavePosition(SaveOrder(orderResult, GetTimeStamp(candle.Timestamp)));

                // 2. Check in 30 seconds twice

                int counter = 0;

                while (counter < 3)
                {
                    Log("Waiting 30 seconds..");

                    Pause(30);
                    ++counter;

                    result = await CheckOrderStatus(orderResult.OrderId);

                    if (result.Result == ExchangeAPIOrderResult.Filled)     // if status now is now filled great
                    {
                        Log($"Remaining quanity of order filled");
                        SaveOrder(orderResult, GetTimeStamp(candle.Timestamp));
                        UpdatePositionQuantity();
                        return;
                    }
                    else
                    {
                        if (counter == 2)     // this is the last time & it wasn't filled
                        {
                            Log($"Remaining quanity of order not filled after waiting 90 seconds, cancelling the order, exchange order id {orderResult.OrderId}, message: {orderResult.Message}");

                            _trader.CancelOrder(orderResult.OrderId);

                            // TODO: Could look at putting in another order for the outstanding quantity
                            // Get the minimum quantity for the currency
                            // if the outstanding quantity is more than the minimum quantity
                            // get the current price
                            // create a new order for the remaining quantity
                            // update the position with the new quantity received
                        }
                    }
                }


                break;

            case ExchangeAPIOrderResult.Canceled:

                /*
                 *
                 * CANCELLED by exchange
                 *
                 * 1. Wait 10 seconds
                 * 3. Check price now
                 * 4. Issue a new Buy
                 *
                 */

                Log($"Order cancelled by exchange for orderId {orderResult.OrderId}, waiting 10 seconds and retrying, message: {orderResult.Message}");

                Log("Waiting 10 seconds");
                Pause(10);

                ticker = _trader.GetLatestTicker(_inMemoryBot.BaseCoin, _inMemoryBot.Coin);

                if (orderResult.IsBuy)
                {
                    Buy(new Candle()
                    {
                        Timestamp = DateTime.Now, ClosePrice = ticker.Ask
                    });
                }
                else
                {
                    Sell(new Candle()
                    {
                        Timestamp = DateTime.Now, ClosePrice = ticker.Bid
                    });
                }

                break;


            case ExchangeAPIOrderResult.Error:

                /*
                 *
                 * ERROR
                 *
                 * 1. Wait 10 seconds and check again
                 * 2. If still error, cancel it
                 * 3. Check price now
                 * 4. Issue a new Buy
                 *
                 */

                Log($"Error reported on exchange for orderId {orderResult.OrderId}, message: {orderResult.Message}");
                Log("Waiting 10 seconds to check again");
                Pause(10);

                result = await CheckOrderStatus(orderResult.OrderId);

                Log($"Result.. {result.Result}");

                // 2. If not filled, cancel it

                if (result.Result != ExchangeAPIOrderResult.Filled)
                {
                    Log($"Not filled, cancelling order {orderResult.OrderId}");
                    _trader.CancelOrder(orderResult.OrderId);

                    // 3. Check the price now
                    ticker = _trader.GetLatestTicker(_inMemoryBot.BaseCoin, _inMemoryBot.Coin);
                    Log($"Going to order again, latest ticker {JsonConvert.SerializeObject(ticker)} ");

                    if (orderResult.IsBuy)
                    {
                        Buy(new Candle()
                        {
                            Timestamp = DateTime.Now, ClosePrice = ticker.Ask
                        });
                    }
                    else
                    {
                        Sell(new Candle()
                        {
                            Timestamp = DateTime.Now, ClosePrice = ticker.Bid
                        });
                    }
                }

                break;


            case ExchangeAPIOrderResult.Pending:

                /*
                 *
                 * PENDING
                 *
                 * 1. Wait 30 seconds and check again
                 * 2. If still pending, cancel it
                 * 3. Check price now
                 * 4. Issue a new Buy
                 *
                 */

                Log($"Pending reported on exchange for orderId {orderResult.OrderId}, message: {orderResult.Message}");

                // 1. Wait thirty seconds & check

                Pause(30);

                result = await CheckOrderStatus(orderResult.OrderId);

                // 2. If not filled, cancel it

                if (result.Result == ExchangeAPIOrderResult.Pending)
                {
                    _trader.CancelOrder(orderResult.OrderId);

                    // 3. Check the price now
                    ticker = _trader.GetLatestTicker(_inMemoryBot.BaseCoin, _inMemoryBot.Coin);

                    Log($"Order still pending after 30 seconds for orderId {orderResult.OrderId}, cancelling and re-ordering at new price {ticker.Ask}");

                    if (orderResult.IsBuy)
                    {
                        Buy(new Candle()
                        {
                            Timestamp = DateTime.Now, ClosePrice = ticker.Ask
                        });
                    }
                    else
                    {
                        Sell(new Candle()
                        {
                            Timestamp = DateTime.Now, ClosePrice = ticker.Bid
                        });
                    }
                }


                break;


            case ExchangeAPIOrderResult.Unknown:

                /*
                 *
                 * UNKNOWN
                 *
                 * 1. Wait thirty seconds and check again
                 * 2. If still unknow, cancel it
                 * 3. Check price now
                 * 4. Issue a new Buy
                 *
                 */

                Log($"UNKNOWN reported by exchange for orderId {orderResult.OrderId}, message: {orderResult.Message}. Waiting 30 seconds to try again");

                // 1. Wait thirty seconds & check

                Pause(30);

                result = await CheckOrderStatus(orderResult.OrderId);

                // 2. If not filled, cancel it

                if (result.Result == ExchangeAPIOrderResult.Unknown)
                {
                    _trader.CancelOrder(orderResult.OrderId);

                    // 3. Check the price now
                    ticker = _trader.GetLatestTicker(_inMemoryBot.BaseCoin, _inMemoryBot.Coin);

                    Log($"Order still UNKNOWN after 30 seconds for orderId {orderResult.OrderId}, cancelling and re-ordering at new price {ticker.Ask}");

                    if (orderResult.IsBuy)
                    {
                        Buy(new Candle()
                        {
                            Timestamp = DateTime.Now, ClosePrice = ticker.Ask
                        });
                    }
                    else
                    {
                        Sell(new Candle()
                        {
                            Timestamp = DateTime.Now, ClosePrice = ticker.Bid
                        });
                    }
                }

                break;
            }
        }