Example #1
0
        public void Get_Sell_Volume_From_First_Level()
        {
            // arrange

            const decimal volume = 3;

            var expectedVolumes = new[]
            {
                new ExchangeVolume {
                    Exchange = Exchange1, Price = 3100, Volume = 3
                }
            };

            // act

            IReadOnlyList <ExchangeVolume> actualVolumes =
                _defaultOrderBook.GetSellVolumes(volume, _activeLimitOrders, _excludedExchanges);

            // assert

            Assert.IsTrue(AreEqual(expectedVolumes, actualVolumes));
        }
        private async Task ExecuteMarketOrderAsync(MarketOrder marketOrder)
        {
            AggregatedOrderBook aggregatedOrderBook = _aggregatedOrderBookService.GetByAssetPair(marketOrder.AssetPair);

            if (aggregatedOrderBook == null)
            {
                _log.WarningWithDetails("Can not execute market order the aggregated order book does not exist",
                                        marketOrder);
                return;
            }

            IReadOnlyList <ExternalLimitOrder> externalLimitOrders =
                await _externalLimitOrderService.GetByParentIdAsync(marketOrder.Id);

            List <ExternalLimitOrder> activeLimitOrders = externalLimitOrders
                                                          .Where(o => o.Status == ExternalLimitOrderStatus.Active)
                                                          .ToList();

            decimal executedVolume = externalLimitOrders
                                     .Where(o => o.Status == ExternalLimitOrderStatus.Filled ||
                                            o.Status == ExternalLimitOrderStatus.PartiallyFilled)
                                     .Sum(o => o.Volume);

            decimal remainingVolume = marketOrder.Volume - executedVolume;

            bool rerouteFailedLimitOrders;

            var excludedExchanges = new List <string>();

            do
            {
                rerouteFailedLimitOrders = false;

                IReadOnlyList <ExchangeVolume> volumes;

                if (marketOrder.Type == OrderType.Sell)
                {
                    volumes = aggregatedOrderBook.GetBuyVolumes(remainingVolume, activeLimitOrders, excludedExchanges);
                }
                else
                {
                    volumes = aggregatedOrderBook.GetSellVolumes(remainingVolume, activeLimitOrders, excludedExchanges);
                }

                if (volumes.Count == 0)
                {
                    _log.WarningWithDetails("Can not execute market order no liquidity in aggregated order book",
                                            new
                    {
                        MarketOrder     = marketOrder,
                        RemainingVolume = remainingVolume,
                        ActiveVolume    = activeLimitOrders.Sum(o => o.Volume)
                    });
                    break;
                }

                foreach (ExchangeVolume exchangeVolume in volumes)
                {
                    ExchangeSettings exchangeSettings =
                        await _exchangeSettingsService.GetByNameAsync(exchangeVolume.Exchange);

                    decimal price;

                    if (marketOrder.Type == OrderType.Sell)
                    {
                        price = exchangeVolume.Price * (1 - exchangeSettings.SlippageMarkup);
                    }
                    else
                    {
                        price = exchangeVolume.Price * (1 + exchangeSettings.SlippageMarkup);
                    }

                    try
                    {
                        ExternalLimitOrder externalLimitOrder =
                            await _exchangeService.CreateLimitOrderAsync(exchangeVolume.Exchange, marketOrder.AssetPair,
                                                                         price, exchangeVolume.Volume, marketOrder.Type);

                        _log.InfoWithDetails("External limit order created", externalLimitOrder);

                        await _externalLimitOrderService.AddAsync(marketOrder.Id, externalLimitOrder);

                        activeLimitOrders.Add(externalLimitOrder);
                    }
                    catch (Exception exception)
                    {
                        rerouteFailedLimitOrders = true;

                        excludedExchanges.Add(exchangeSettings.Name);

                        _log.ErrorWithDetails(exception, "An error occurred while creating external limit order",
                                              new
                        {
                            MarketOrderId = marketOrder.Id,
                            exchangeVolume.Exchange,
                            marketOrder.AssetPair,
                            Price = price,
                            exchangeVolume.Volume,
                            OrderType = marketOrder.Type.ToString()
                        });
                    }
                }
            } while (rerouteFailedLimitOrders);
        }