public async Task <bool> CancelLimitOrderAsync(ExternalLimitOrder externalLimitOrder) { IExchange exchange = GetExchange(externalLimitOrder.Exchange); ExternalLimitOrderInfo externalLimitOrderInfo = await exchange.GetLimitOrderInfoAsync(externalLimitOrder.Id); switch (externalLimitOrderInfo.Status) { case ExternalLimitOrderStatus.Filled: case ExternalLimitOrderStatus.PartiallyFilled: externalLimitOrder.Execute(externalLimitOrderInfo); return(true); case ExternalLimitOrderStatus.Cancelled: externalLimitOrder.Cancel(); return(true); case ExternalLimitOrderStatus.Active: return(false); default: throw new InvalidEnumArgumentException(nameof(externalLimitOrderInfo.Status), (int)externalLimitOrderInfo.Status, typeof(ExternalLimitOrderStatus)); } }
public async Task <ExternalLimitOrder> CreateLimitOrderAsync(string exchangeName, string assetPair, decimal price, decimal volume, OrderType orderType) { IExchange exchange = GetExchange(exchangeName); AssetPairModel assetPairModel = _marketInstrumentService.GetAssetPair(assetPair, exchange.Name); if (assetPairModel == null) { throw new FailedOperationException("Asset pair settings does not exist"); } price = price.TruncateDecimalPlaces(assetPairModel.PriceAccuracy, orderType == OrderType.Sell); volume = Math.Round(volume, assetPairModel.VolumeAccuracy); if (volume < assetPairModel.MinVolume) { throw new FailedOperationException("The volume is too small"); } string orderId = await exchange.CreateLimitOrderAsync(assetPair, price, volume, orderType); var externalLimitOrder = new ExternalLimitOrder(orderId, exchange.Name, assetPair, price, volume, orderType); return(externalLimitOrder); }
public Task UpdateAsync(ExternalLimitOrder externalLimitOrder) { return(_storage.MergeAsync(GetPartitionKey(externalLimitOrder.Id), GetRowKey(externalLimitOrder.Id), entity => { Mapper.Map(externalLimitOrder, entity); return entity; })); }
public async Task InsertAsync(string parentId, ExternalLimitOrder externalLimitOrder) { var entity = new ExternalLimitOrderEntity(GetPartitionKey(externalLimitOrder.Id), GetRowKey(externalLimitOrder.Id)); Mapper.Map(externalLimitOrder, entity); await _storage.InsertAsync(entity); var index = new AzureIndex(GetIndexPartitionKey(parentId), GetIndexRowKey(externalLimitOrder.Id), entity); await _indices.InsertAsync(index); }
public Task UpdateAsync(ExternalLimitOrder externalLimitOrder) { return(_externalLimitOrderRepository.UpdateAsync(externalLimitOrder)); }
public Task AddAsync(string parentId, ExternalLimitOrder externalLimitOrder) { return(_externalLimitOrderRepository.InsertAsync(parentId, externalLimitOrder)); }
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); }