Example #1
0
        public async Task Handle(AssetPairChangedEvent @event)
        {
            //deduplication is not required, it's ok if an object is updated multiple times
            if (@event.AssetPair?.Id == null)
            {
                await _log.WriteWarningAsync(nameof(AssetPairProjection), nameof(Handle),
                                             "AssetPairChangedEvent contained no asset pair id");

                return;
            }

            if (IsDelete(@event))
            {
                CloseAllOrders();

                ValidatePositions(@event.AssetPair.Id);

                _assetPairsCache.Remove(@event.AssetPair.Id);
            }
            else
            {
                if (@event.AssetPair.IsDiscontinued)
                {
                    CloseAllOrders();
                }

                _assetPairsCache.AddOrUpdate(new AssetPair(
                                                 id: @event.AssetPair.Id,
                                                 name: @event.AssetPair.Name,
                                                 baseAssetId: @event.AssetPair.BaseAssetId,
                                                 quoteAssetId: @event.AssetPair.QuoteAssetId,
                                                 accuracy: @event.AssetPair.Accuracy,
                                                 legalEntity: @event.AssetPair.LegalEntity,
                                                 basePairId: @event.AssetPair.BasePairId,
                                                 matchingEngineMode: @event.AssetPair.MatchingEngineMode.ToType <MatchingEngineMode>(),
                                                 stpMultiplierMarkupBid: @event.AssetPair.StpMultiplierMarkupBid,
                                                 stpMultiplierMarkupAsk: @event.AssetPair.StpMultiplierMarkupAsk,
                                                 isSuspended: @event.AssetPair.IsSuspended,
                                                 isFrozen: @event.AssetPair.IsFrozen,
                                                 isDiscontinued: @event.AssetPair.IsDiscontinued
                                                 ));
            }

            await _scheduleSettingsCacheService.UpdateSettingsAsync();

            void CloseAllOrders()
            {
                try
                {
                    foreach (var order in _orderReader.GetPending().Where(x => x.AssetPairId == @event.AssetPair.Id))
                    {
                        _tradingEngine.CancelPendingOrder(order.Id, null, @event.OperationId,
                                                          null, OrderCancellationReason.InstrumentInvalidated);
                    }
                }
                catch (Exception exception)
                {
                    _log.WriteError(nameof(AssetPairProjection), nameof(CloseAllOrders), exception);
                    throw;
                }
            }

            void ValidatePositions(string assetPairId)
            {
                var positions = _orderReader.GetPositions(assetPairId);

                if (positions.Any())
                {
                    _log.WriteFatalError(nameof(AssetPairProjection), nameof(ValidatePositions),
                                         new Exception($"{positions.Length} positions are opened for [{assetPairId}], first: [{positions.First().Id}]."));
                }
            }
        }