public async Task UpdateAsync(string assetPairId, CrossInstrument crossInstrument) { await _storage.MergeAsync(GetPartitionKey(assetPairId), GetRowKey(crossInstrument.AssetPairId), entity => { Mapper.Map(crossInstrument, entity); return(entity); }); }
public async Task AddAsync(string assetPairId, CrossInstrument crossInstrument) { var entity = new CrossInstrumentEntity(GetPartitionKey(assetPairId), GetRowKey(crossInstrument.AssetPairId)); Mapper.Map(crossInstrument, entity); await _storage.InsertAsync(entity); }
public async Task UpdateCrossInstrumentAsync(string assetPairId, CrossInstrument crossInstrument) { Instrument instrument = await GetByAssetPairIdAsync(assetPairId); instrument.UpdateCrossInstrument(crossInstrument); await _crossInstrumentRepository.UpdateAsync(assetPairId, crossInstrument); _cache.Set(instrument); _log.InfoWithDetails("Cross instrument was updated of the instrument", instrument); }
private async Task <OrderBook> CalculateCrossOrderBookAsync(OrderBook directOrderBook, CrossInstrument crossInstrument) { Quote quote = await _quoteService .GetAsync(crossInstrument.QuoteSource, crossInstrument.ExternalAssetPairId); if (quote == null) { _log.WarningWithDetails("No quote for instrument", new { Source = crossInstrument.QuoteSource, AssetPair = crossInstrument.ExternalAssetPairId }); return(null); } LimitOrder[] validDirectLimitOrders = directOrderBook.LimitOrders .Where(o => o.Error == LimitOrderError.None) .ToArray(); if (validDirectLimitOrders.Length == 0) { return(null); } AssetPair assetPair = await _assetsServiceWithCache.TryGetAssetPairAsync(crossInstrument.AssetPairId); Asset baseAsset = await _assetsServiceWithCache.TryGetAssetAsync(assetPair.BaseAssetId); IReadOnlyCollection <LimitOrder> crossLimitOrders = Calculator.CalculateCrossLimitOrders(quote, validDirectLimitOrders, crossInstrument.IsInverse, assetPair.Accuracy, baseAsset.Accuracy); await ValidateQuoteTimeoutAsync(crossLimitOrders, quote); ValidateMinVolume(crossLimitOrders, (decimal)assetPair.MinVolume); await ValidateBalanceAsync(crossLimitOrders, assetPair); WriteInfoLog(crossInstrument.AssetPairId, directOrderBook.AssetPairId, quote, crossLimitOrders, "Cross limit orders calculated"); return(new OrderBook { AssetPairId = crossInstrument.AssetPairId, Time = DateTime.UtcNow, LimitOrders = crossLimitOrders, IsDirect = false, BaseAssetPairId = directOrderBook.AssetPairId, CrossQuote = quote }); }
public async Task AddCrossInstrumentAsync(string assetPairId, CrossInstrument crossInstrument) { IReadOnlyCollection <Instrument> instruments = await GetAllAsync(); if (instruments.Any(o => o.AssetPairId == crossInstrument.AssetPairId || o.CrossInstruments?.Any(p => p.AssetPairId == crossInstrument.AssetPairId) == true)) { throw new InvalidOperationException("The instrument already used"); } Instrument instrument = await GetByAssetPairIdAsync(assetPairId); instrument.AddCrossInstrument(crossInstrument); await _crossInstrumentRepository.AddAsync(assetPairId, crossInstrument); _cache.Set(instrument); _log.InfoWithDetails("Cross instrument was added to the instrument", instrument); }
public async Task OpenAsync(IReadOnlyCollection <InternalTrade> internalTrades) { var startedAt = DateTime.UtcNow; var positions = new List <Position>(); foreach (InternalTrade internalTrade in internalTrades) { Instrument instrument = await _instrumentService.FindAsync(internalTrade.AssetPairId); if (instrument == null) { _log.WarningWithDetails("Can not open position. Unknown instrument.", internalTrade); continue; } if (internalTrade.AssetPairId != instrument.AssetPairId) { CrossInstrument crossInstrument = instrument.CrossInstruments .Single(o => o.AssetPairId == internalTrade.AssetPairId); Quote quote = await _quoteService.GetAsync(crossInstrument.QuoteSource, crossInstrument.ExternalAssetPairId); if (quote != null) { decimal price = internalTrade.Type == TradeType.Sell ? Calculator.CalculateDirectSellPrice(internalTrade.Price, quote, crossInstrument.IsInverse) : Calculator.CalculateDirectBuyPrice(internalTrade.Price, quote, crossInstrument.IsInverse); var position = Position.Open(instrument.AssetPairId, price, internalTrade.Price, internalTrade.Volume, quote, crossInstrument.AssetPairId, internalTrade.Type, internalTrade.Id); positions.Add(position); } else { _log.WarningWithDetails("Can not open position. No quote.", internalTrade); } } else { var position = Position.Open(instrument.AssetPairId, internalTrade.Price, internalTrade.Volume, internalTrade.Type, internalTrade.Id); positions.Add(position); } } await _tradeService.RegisterAsync(internalTrades); foreach (Position position in positions) { await TraceWrapper.TraceExecutionTimeAsync("Inserting position to the Azure storage", () => _positionRepository.InsertAsync(position), _log); await TraceWrapper.TraceExecutionTimeAsync("Inserting open position to the Azure storage", () => _openPositionRepository.InsertAsync(position), _log); try { await TraceWrapper.TraceExecutionTimeAsync("Inserting position to the Postgres storage", () => _positionRepositoryPostgres.InsertAsync(position), _log); } catch (Exception exception) { _log.ErrorWithDetails(exception, "An error occurred while inserting position to the Postgres DB", position); } await TraceWrapper.TraceExecutionTimeAsync("Updating summary report in the Azure storage", () => _summaryReportService.RegisterOpenPositionAsync(position, internalTrades.Where(o => o.Id == position.TradeId).ToArray()), _log); _log.InfoWithDetails("Position opened", position); } var finishedAt = DateTime.UtcNow; _log.Info("PositionService.OpenAsync() completed.", new { PositionsCount = positions.Count, TradeIds = positions.Select(x => x.TradeId).ToList(), StartedAt = startedAt, FinishedAt = finishedAt, Latency = (finishedAt - startedAt).TotalMilliseconds }); }