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); }