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);
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        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
            });
        }
コード例 #5
0
        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);
        }
コード例 #6
0
        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
            });
        }