private async Task ProcessInstrumentAsync(Instrument instrument) { try { OrderBook directOrderBook = await CalculateDirectOrderBookAsync(instrument); if (directOrderBook == null) { return; } var orderBooks = new List <OrderBook> { directOrderBook }; if (instrument.CrossInstruments != null) { foreach (CrossInstrument crossInstrument in instrument.CrossInstruments) { OrderBook crossOrderBook = await CalculateCrossOrderBookAsync(directOrderBook, crossInstrument); if (crossOrderBook == null) { continue; } orderBooks.Add(crossOrderBook); } } await ValidatePnLThresholdAsync(orderBooks, instrument); await ValidateInventoryThresholdAsync(orderBooks, instrument); await ValidateMarketMakerStateAsync(orderBooks); ValidateInstrumentMode(orderBooks, instrument.Mode); foreach (OrderBook orderBook in orderBooks) { await _orderBookService.UpdateAsync(orderBook); } foreach (OrderBook orderBook in orderBooks) { LimitOrder[] allowedLimitOrders = orderBook.LimitOrders .Where(o => o.Error == LimitOrderError.None) .ToArray(); await _lykkeExchangeService.ApplyAsync(orderBook.AssetPairId, allowedLimitOrders); } } catch (Exception exception) { _log.WarningWithDetails("An error occured while processing instrument", exception, instrument); } }
private async Task ProcessInstrumentAsync(Instrument instrument) { Quote quote = _quoteService.Get(instrument.QuoteSource, instrument.AssetPairId); if (quote == null) { _log.WarningWithDetails("No quote for instrument", new { instrument.AssetPairId }); return; } AssetPair assetPair = _assetPairsReadModelRepository.TryGetIfEnabled(instrument.AssetPairId); if (assetPair == null) { _log.WarningWithDetails("Asset pair not found", new { instrument.AssetPairId }); return; } Balance balance = await _balanceService.GetByAssetIdAsync(assetPair.BaseAssetId); IReadOnlyCollection <LimitOrder> limitOrders = EvenlyDistributedVolumeTrader.Calculate(quote, instrument, balance.Amount, assetPair.Accuracy, assetPair.InvertedAccuracy); await ValidateQuoteAsync(limitOrders, quote); ValidateMinVolume(limitOrders, assetPair.MinVolume); await _orderBookService.UpdateAsync(new OrderBook { AssetPairId = instrument.AssetPairId, Time = DateTime.UtcNow, LimitOrders = limitOrders }); if (instrument.Mode != InstrumentMode.Active) { SetError(limitOrders, LimitOrderError.Idle); } limitOrders = limitOrders .Where(o => o.Error == LimitOrderError.None) .ToArray(); try { await _lykkeExchangeService.ApplyAsync(instrument.AssetPairId, limitOrders); } catch (Exception exception) { _log.WarningWithDetails("An error occurred while processing limit orders", exception, limitOrders); SetError(limitOrders, LimitOrderError.Unknown, "ME error"); } }
public async Task ExecuteLimitOrderAsync(HedgeLimitOrder hedgeLimitOrder) { await _hedgeLimitOrderService.AddAsync(hedgeLimitOrder); AssetPairSettings assetPairSettings = await _instrumentService.GetAssetPairAsync(hedgeLimitOrder.AssetPairId, Name); if (assetPairSettings == null) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = "Instrument not configured"; _log.WarningWithDetails("No settings for instrument", hedgeLimitOrder); return; } decimal price = hedgeLimitOrder.Price .TruncateDecimalPlaces(assetPairSettings.PriceAccuracy, hedgeLimitOrder.Type == LimitOrderType.Sell); decimal volume = Math.Round(hedgeLimitOrder.Volume, assetPairSettings.VolumeAccuracy); if (volume < assetPairSettings.MinVolume) { hedgeLimitOrder.Error = LimitOrderError.TooSmallVolume; return; } var limitOrder = new LimitOrder { Id = hedgeLimitOrder.Id, Price = price, Volume = volume, Type = hedgeLimitOrder.Type }; try { await _lykkeExchangeService.ApplyAsync(hedgeLimitOrder.AssetPairId, limitOrder); if (limitOrder.Error == LimitOrderError.None) { _hedgeLimitOrders[hedgeLimitOrder.AssetId] = hedgeLimitOrder; } hedgeLimitOrder.Error = limitOrder.Error; hedgeLimitOrder.ErrorMessage = limitOrder.ErrorMessage; } catch (ExchangeException exception) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = exception.Message; } catch (Exception exception) { hedgeLimitOrder.Error = LimitOrderError.Unknown; hedgeLimitOrder.ErrorMessage = "Cannot create limit orders an unexpected error occurred"; _log.WarningWithDetails("An error occurred during creating limit orders", exception, hedgeLimitOrder); } }
private async Task ProcessInstrumentAsync(Instrument instrument, DateTime iterationDateTime) { try { var startedAt = DateTime.UtcNow; OrderBook directOrderBook = await CalculateDirectOrderBookAsync(instrument, iterationDateTime); var finishedObCalculationAt = DateTime.UtcNow; //_log.Info("MarketMakerService.CalculateDirectOrderBookAsync() completed.", new //{ // AssetPairId = instrument.AssetPairId, // StartedAt = startedAt, // FinishedAt = finishedObCalculationAt, // Latency = (finishedObCalculationAt - startedAt).TotalMilliseconds //}); if (directOrderBook == null) { return; } var orderBooks = new List <OrderBook> { directOrderBook }; if (instrument.CrossInstruments != null) { foreach (CrossInstrument crossInstrument in instrument.CrossInstruments) { OrderBook crossOrderBook = await CalculateCrossOrderBookAsync(directOrderBook, crossInstrument); if (crossOrderBook == null) { continue; } orderBooks.Add(crossOrderBook); } } await ValidatePnLThresholdAsync(orderBooks, instrument); await ValidateInventoryThresholdAsync(orderBooks, instrument); await ValidateMarketMakerStateAsync(orderBooks); ValidateInstrumentMode(orderBooks, instrument.Mode); foreach (OrderBook orderBook in orderBooks) { await _orderBookService.UpdateAsync(orderBook); } foreach (OrderBook orderBook in orderBooks) { LimitOrder[] allowedLimitOrders = orderBook.LimitOrders .Where(o => o.Error == LimitOrderError.None) .ToArray(); await _lykkeExchangeService.ApplyAsync(orderBook.AssetPairId, allowedLimitOrders); } var finishedAt = DateTime.UtcNow; //_log.Info("MarketMakerService.ProcessInstrumentAsync() completed.", new //{ // AssetPairId = instrument.AssetPairId, // StartedAt = startedAt, // FinishedAt = finishedAt, // Latency = (finishedAt - startedAt).TotalMilliseconds //}); PrometheusMetrics.MarketMakingAssetPairLatency.Inc((finishedAt - startedAt).TotalMilliseconds); } catch (Exception exception) { _log.WarningWithDetails("An error occured while processing instrument", exception, instrument); } }
public async Task UpdateLimitOrdersAsync(string indexName) { IndexPrice indexPrice = await _indexPriceService.GetByIndexAsync(indexName); if (indexPrice == null) { throw new InvalidOperationException("Index price not found"); } IndexSettings indexSettings = await _indexSettingsService.GetByIndexAsync(indexName); if (indexSettings == null) { throw new InvalidOperationException("Index settings not found"); } AssetPairSettings assetPairSettings = await _instrumentService.GetAssetPairAsync(indexSettings.AssetPairId, Exchange); if (assetPairSettings == null) { throw new InvalidOperationException("Asset pair settings not found"); } AssetSettings baseAssetSettings = await _instrumentService.GetAssetAsync(assetPairSettings.BaseAsset, ExchangeNames.Lykke); if (baseAssetSettings == null) { throw new InvalidOperationException("Base asset settings not found"); } AssetSettings quoteAssetSettings = await _instrumentService.GetAssetAsync(assetPairSettings.QuoteAsset, ExchangeNames.Lykke); if (quoteAssetSettings == null) { throw new InvalidOperationException("Quote asset settings not found"); } decimal sellPrice = (indexPrice.Price + indexSettings.SellMarkup) .TruncateDecimalPlaces(assetPairSettings.PriceAccuracy, true); decimal buyPrice = indexPrice.Price.TruncateDecimalPlaces(assetPairSettings.PriceAccuracy); IReadOnlyCollection <LimitOrder> limitOrders = CreateLimitOrders(indexSettings, assetPairSettings, sellPrice, buyPrice); ValidateBalance(limitOrders, baseAssetSettings, quoteAssetSettings); ValidateMinVolume(limitOrders, assetPairSettings.MinVolume); LimitOrder[] allowedLimitOrders = limitOrders .Where(o => o.Error == LimitOrderError.None) .ToArray(); _log.InfoWithDetails("Limit orders created", limitOrders); _limitOrderService.Update(indexSettings.AssetPairId, limitOrders); await _lykkeExchangeService.ApplyAsync(indexSettings.AssetPairId, allowedLimitOrders); _traceWriter.LimitOrders(indexSettings.AssetPairId, limitOrders); }