示例#1
0
        public void Is_Quote_Returned()
        {
            const string instrument = "EURUSD";

            _bestPriceConsumer.SendEvent(this, new BestPriceChangeEventArgs(new InstrumentBidAskPair {
                Instrument = instrument, Ask = 1.05M, Bid = 1.04M
            }));

            var quote = _quoteCacheService.GetQuote(instrument);

            Assert.IsNotNull(quote);
            Assert.AreEqual(1.04, quote.Bid);
            Assert.AreEqual(1.05, quote.Ask);
        }
示例#2
0
        public void ChangeOrderLimits(string orderId, decimal?stopLoss, decimal?takeProfit, decimal?expectedOpenPrice)
        {
            using (_contextFactory.GetWriteSyncContext($"{nameof(TradingEngine)}.{nameof(ChangeOrderLimits)}"))
            {
                var order = _ordersCache.GetOrderById(orderId);

                if (order.Status != OrderStatus.WaitingForExecution && expectedOpenPrice > 0)
                {
                    return;
                }

                var quote        = _quoteCashService.GetQuote(order.Instrument);
                var tp           = takeProfit == 0 ? null : takeProfit;
                var sl           = stopLoss == 0 ? null : stopLoss;
                var expOpenPrice = expectedOpenPrice == 0 ? null : expectedOpenPrice;

                var accountAsset = _accountAssetsCacheService.GetAccountAsset(order.TradingConditionId,
                                                                              order.AccountAssetId, order.Instrument);

                _validateOrderService.ValidateOrderStops(order.GetOrderType(), quote,
                                                         accountAsset.DeltaBid, accountAsset.DeltaAsk, tp, sl, expOpenPrice, order.AssetAccuracy);

                order.TakeProfit        = tp.HasValue ? Math.Round(tp.Value, order.AssetAccuracy) : (decimal?)null;
                order.StopLoss          = sl.HasValue ? Math.Round(sl.Value, order.AssetAccuracy) : (decimal?)null;
                order.ExpectedOpenPrice = expOpenPrice.HasValue ? Math.Round(expOpenPrice.Value, order.AssetAccuracy) : (decimal?)null;
                _orderLimitsChangesEventChannel.SendEvent(this, new OrderLimitsChangedEventArgs(order));
            }
        }
示例#3
0
        public decimal GetQuoteRateForBaseAsset(string accountAssetId, string assetPairId, string legalEntity,
                                                bool useAsk)
        {
            var assetPair = _assetPairsCache.GetAssetPairById(assetPairId);

            // two step transform: base -> quote from QuoteCache, quote -> account from FxCache
            // if accountAssetId == assetPair.BaseAssetId, rate != 1, because trading and fx rates can be different

            var assetPairQuote = _quoteCacheService.GetQuote(assetPairId);
            var tradingRate    = useAsk ? assetPairQuote.Ask : assetPairQuote.Bid;

            if (assetPair.QuoteAssetId == accountAssetId)
            {
                return(tradingRate);
            }

            var fxPair =
                _assetPairsCache.FindAssetPair(assetPair.QuoteAssetId, accountAssetId, legalEntity);
            var fxQuote = _fxRateCacheService.GetQuote(fxPair.Id);

            var rate = fxPair.BaseAssetId == assetPair.QuoteAssetId
                ? fxQuote.Ask * tradingRate
                : 1 / fxQuote.Bid * tradingRate;

            return(rate);
        }
示例#4
0
        public void ApprovePriceRequest(string operationId, decimal?price)
        {
            if (_specialLiquidationSettings.FakePriceRequestAutoApproval)
            {
                _log.WriteWarning(nameof(ManualRfqService),
                                  nameof(ApprovePriceRequest),
                                  $"Most probably, the price request for {operationId} has already been automatically approved according to configuration");
            }

            if (!_requests.TryGetValue(operationId, out var command))
            {
                throw new InvalidOperationException($"Command with operation ID {operationId} does not exist");
            }

            if (price == null)
            {
                var quote = _quoteCacheService.GetQuote(command.Instrument);

                price = (command.Volume > 0 ? quote.Ask : quote.Bid) * _specialLiquidationSettings.FakePriceMultiplier;
            }

            _cqrsSender.PublishEvent(new PriceForSpecialLiquidationCalculatedEvent
            {
                OperationId  = operationId,
                CreationTime = _dateService.Now(),
                Price        = price.Value,
            }, _cqrsContextNamesSettings.Gavel);

            _requests.TryRemove(operationId, out _);
        }
示例#5
0
        public decimal GetQuoteRateForBaseAsset(string accountAssetId, string instrument)
        {
            var asset = _assetPairsCache.GetAssetPairById(instrument);

            var baseAssetId = asset.BaseAssetId;

            if (accountAssetId == baseAssetId)
            {
                return(1);
            }

            var inst  = _assetPairsCache.FindAssetPair(baseAssetId, accountAssetId);
            var quote = _quoteCacheService.GetQuote(inst.Id);

            if (inst.BaseAssetId == baseAssetId)
            {
                return(quote.Ask);
            }

            return(1.0M / quote.Bid);
        }
示例#6
0
        public decimal GetQuoteRateForBaseAsset(string accountAssetId, string assetPairId, string legalEntity,
                                                bool metricIsPositive = true)
        {
            var assetPair = _assetPairsCache.GetAssetPairById(assetPairId);

            if (accountAssetId == assetPair.BaseAssetId)
            {
                return(1);
            }

            var assetPairSubst = _assetPairsCache.FindAssetPair(assetPair.BaseAssetId, accountAssetId, legalEntity);

            var rate = metricIsPositive
                ? assetPairSubst.BaseAssetId == assetPair.BaseAssetId
                    ? _quoteCacheService.GetQuote(assetPairSubst.Id).Ask
                    : 1 / _quoteCacheService.GetQuote(assetPairSubst.Id).Bid
                : assetPairSubst.BaseAssetId == assetPair.BaseAssetId
                    ? _quoteCacheService.GetQuote(assetPairSubst.Id).Bid
                    : 1 / _quoteCacheService.GetQuote(assetPairSubst.Id).Ask;

            return(rate);
        }
示例#7
0
        public void CheckIsEnoughBalance(Order order, IMatchingEngineBase matchingEngine)
        {
            var orderMargin            = _fplService.GetInitMarginForOrder(order);
            var accountMarginAvailable = _accountsCacheService.Get(order.AccountId).GetMarginAvailable();

            var quote = _quoteCacheService.GetQuote(order.AssetPairId);

            var openPrice         = order.Price ?? 0;
            var closePrice        = 0m;
            var directionForClose = order.Volume.GetClosePositionOrderDirection();

            if (quote.GetVolumeForOrderDirection(order.Direction) >= Math.Abs(order.Volume) &&
                quote.GetVolumeForOrderDirection(directionForClose) >= Math.Abs(order.Volume))
            {
                closePrice = quote.GetPriceForOrderDirection(directionForClose);

                if (openPrice == 0)
                {
                    openPrice = quote.GetPriceForOrderDirection(order.Direction);
                }
            }
            else
            {
                var openPriceInfo  = matchingEngine.GetBestPriceForOpen(order.AssetPairId, order.Volume);
                var closePriceInfo =
                    matchingEngine.GetPriceForClose(order.AssetPairId, order.Volume, openPriceInfo.externalProviderId);

                if (openPriceInfo.price == null || closePriceInfo == null)
                {
                    throw new ValidateOrderException(OrderRejectReason.NoLiquidity,
                                                     "Price for open/close can not be calculated");
                }

                closePrice = closePriceInfo.Value;

                if (openPrice == 0)
                {
                    openPrice = openPriceInfo.price.Value;
                }
            }

            var pnlInTradingCurrency = (closePrice - openPrice) * order.Volume;
            var fxRate = _cfdCalculatorService.GetQuoteRateForQuoteAsset(order.AccountAssetId,
                                                                         order.AssetPairId, order.LegalEntity,
                                                                         pnlInTradingCurrency > 0);
            var pnl = pnlInTradingCurrency * fxRate;

            // just in case... is should be always negative
            if (pnl > 0)
            {
                _log.WriteWarning(nameof(CheckIsEnoughBalance), order.ToJson(),
                                  $"Theoretical PnL at the moment of order execution is positive");
                pnl = 0;
            }

            if (accountMarginAvailable + pnl < orderMargin)
            {
                throw new ValidateOrderException(OrderRejectReason.NotEnoughBalance,
                                                 MtMessages.Validation_NotEnoughBalance,
                                                 $"Account available margin: {accountMarginAvailable}, order margin: {orderMargin}, pnl: {pnl} " +
                                                 $"(open price: {openPrice}, close price: {closePrice}, fx rate: {fxRate})");
            }
        }
示例#8
0
        public void CheckIsEnoughBalance(Order order, IMatchingEngineBase matchingEngine, decimal additionalMargin)
        {
            _log.WriteInfo(nameof(CheckIsEnoughBalance), new { Order = order, additionalMargin }.ToJson(),
                           "Start checking if account balance is enough ...");

            var orderMargin = _fplService.GetInitMarginForOrder(order);

            _log.WriteInfo(nameof(CheckIsEnoughBalance), new { Order = order, orderMargin }.ToJson(),
                           "Order margin calculated");

            var account = _accountsProvider.GetAccountById(order.AccountId);
            var accountMarginAvailable = account.GetMarginAvailable() + additionalMargin;

            _log.WriteInfo(nameof(CheckIsEnoughBalance), new { Order = order, Account = account, accountMarginAvailable }.ToJson(),
                           "Account margin available calculated");

            var quote = _quoteCacheService.GetQuote(order.AssetPairId);

            decimal openPrice;
            decimal closePrice;
            var     directionForClose = order.Volume.GetClosePositionOrderDirection();

            if (quote.GetVolumeForOrderDirection(order.Direction) >= Math.Abs(order.Volume) &&
                quote.GetVolumeForOrderDirection(directionForClose) >= Math.Abs(order.Volume))
            {
                closePrice = quote.GetPriceForOrderDirection(directionForClose);
                openPrice  = quote.GetPriceForOrderDirection(order.Direction);
            }
            else
            {
                var openPriceInfo  = matchingEngine.GetBestPriceForOpen(order.AssetPairId, order.Volume);
                var closePriceInfo =
                    matchingEngine.GetPriceForClose(order.AssetPairId, order.Volume, openPriceInfo.externalProviderId);

                if (openPriceInfo.price == null || closePriceInfo == null)
                {
                    throw new ValidateOrderException(OrderRejectReason.NoLiquidity,
                                                     "Price for open/close can not be calculated");
                }

                closePrice = closePriceInfo.Value;
                openPrice  = openPriceInfo.price.Value;
            }
            _log.WriteInfo(nameof(CheckIsEnoughBalance), new { Order = order, Quote = quote, openPrice, closePrice }.ToJson(),
                           "Open and close prices calculated");


            var pnlInTradingCurrency = (closePrice - openPrice) * order.Volume;
            var fxRate = _cfdCalculatorService.GetQuoteRateForQuoteAsset(order.AccountAssetId,
                                                                         order.AssetPairId, order.LegalEntity,
                                                                         pnlInTradingCurrency > 0);
            var pnl = pnlInTradingCurrency * fxRate;

            // just in case... is should be always negative
            if (pnl > 0)
            {
                _log.WriteWarning(nameof(CheckIsEnoughBalance), order.ToJson(),
                                  $"Theoretical PnL at the moment of order execution is positive");
                pnl = 0;
            }
            _log.WriteInfo(nameof(CheckIsEnoughBalance), new { Order = order, pnlInTradingCurrency, fxRate, pnl }.ToJson(),
                           "PNL calculated");

            var assetType = _assetPairsCache.GetAssetPairById(order.AssetPairId).AssetType;

            if (!_clientProfileSettingsCache.TryGetValue(account.TradingConditionId, assetType, out var clientProfileSettings))
            {
                throw new InvalidOperationException($"Client profile settings for [{account.TradingConditionId}] and asset type [{assetType}] were not found in cache");
            }

            var tradingInstrument =
                _tradingInstrumentsCache.GetTradingInstrument(account.TradingConditionId, order.AssetPairId);

            var entryCost = CostHelper.CalculateEntryCost(
                order.Price,
                order.Direction == OrderDirection.Buy ? Lykke.Snow.Common.Costs.OrderDirection.Buy : Lykke.Snow.Common.Costs.OrderDirection.Sell,
                quote.Ask,
                quote.Bid,
                fxRate,
                tradingInstrument.Spread,
                tradingInstrument.HedgeCost,
                _marginTradingSettings.BrokerDefaultCcVolume,
                _marginTradingSettings.BrokerDonationShare);

            _log.WriteInfo(nameof(CheckIsEnoughBalance),
                           new
            {
                OrderPrice = order.Price, OrderDirection = order.Direction, quote.Ask, quote.Bid, fxRate,
                tradingInstrument.Spread, tradingInstrument.HedgeCost, _marginTradingSettings.BrokerDefaultCcVolume,
                _marginTradingSettings.BrokerDonationShare, CalculatedEntryCost = entryCost
            }.ToJson(),
                           "Entry cost calculated");

            var exitCost = CostHelper.CalculateExitCost(
                order.Price,
                order.Direction == OrderDirection.Buy ? Lykke.Snow.Common.Costs.OrderDirection.Buy : Lykke.Snow.Common.Costs.OrderDirection.Sell,
                quote.Ask,
                quote.Bid,
                fxRate,
                tradingInstrument.Spread,
                tradingInstrument.HedgeCost,
                _marginTradingSettings.BrokerDefaultCcVolume,
                _marginTradingSettings.BrokerDonationShare);

            _log.WriteInfo(nameof(CheckIsEnoughBalance),
                           new
            {
                OrderPrice = order.Price, OrderDirection = order.Direction, quote.Ask, quote.Bid, fxRate,
                tradingInstrument.Spread, tradingInstrument.HedgeCost, _marginTradingSettings.BrokerDefaultCcVolume,
                _marginTradingSettings.BrokerDonationShare, CalculatedExitCost = exitCost
            }.ToJson(),
                           "Exit cost calculated");

            if (accountMarginAvailable + pnl - entryCost - exitCost < orderMargin)
            {
                throw new ValidateOrderException(OrderRejectReason.NotEnoughBalance,
                                                 MtMessages.Validation_NotEnoughBalance,
                                                 $"Account available margin: {accountMarginAvailable}, order margin: {orderMargin}, pnl: {pnl}, entry cost: {entryCost}, exit cost: {exitCost} " +
                                                 $"(open price: {openPrice}, close price: {closePrice}, fx rate: {fxRate})");
            }

            _log.WriteInfo(nameof(CheckIsEnoughBalance), new { Order = order, accountMarginAvailable, pnl, entryCost, exitCost, orderMargin }.ToJson(),
                           "Account balance is enough, validation succeeded.");
        }
示例#9
0
        public async Task <MatchedOrderCollection> MatchOrderAsync(Order order, bool shouldOpenNewPosition,
                                                                   OrderModality modality = OrderModality.Regular)
        {
            List <(string source, decimal?price)> prices = null;

            if (!string.IsNullOrEmpty(_marginTradingSettings.DefaultExternalExchangeId))
            {
                var quote = _quoteCacheService.GetQuote(order.AssetPairId);

                if (quote.GetVolumeForOrderDirection(order.Direction) >= Math.Abs(order.Volume))
                {
                    prices = new List <(string source, decimal?price)>
                    {
                        (_marginTradingSettings
                         .DefaultExternalExchangeId, quote.GetPriceForOrderDirection(order.Direction))
                    };
                }
            }

            if (prices == null)
            {
                prices = _externalOrderbookService.GetOrderedPricesForExecution(order.AssetPairId, order.Volume, shouldOpenNewPosition);

                if (prices == null || !prices.Any())
                {
                    return(new MatchedOrderCollection());
                }
            }

            var assetPair         = _assetPairsCache.GetAssetPairByIdOrDefault(order.AssetPairId);
            var externalAssetPair = assetPair?.BasePairId ?? order.AssetPairId;

            foreach (var(source, price) in prices
                     .Where(x => string.IsNullOrEmpty(order.ExternalProviderId) || x.source == order.ExternalProviderId))
            {
                var externalOrderModel = new OrderModel();

                var orderType = order.OrderType == Core.Orders.OrderType.Limit ||
                                order.OrderType == Core.Orders.OrderType.TakeProfit
                    ? Core.Orders.OrderType.Limit
                    : Core.Orders.OrderType.Market;

                var isCancellationTrade = order.AdditionalInfo.IsCancellationTrade(out var cancellationTradeExternalId);

                var targetPrice = order.OrderType != Core.Orders.OrderType.Market || isCancellationTrade
                    ? (double?)order.Price
                    : (double?)price;

                try
                {
                    externalOrderModel = new OrderModel(
                        tradeType: order.Direction.ToType <TradeType>(),
                        orderType: orderType.ToType <OrderType>(),
                        timeInForce: TimeInForce.FillOrKill,
                        volume: (double)Math.Abs(order.Volume),
                        dateTime: _dateService.Now(),
                        exchangeName: source,
                        instrument: externalAssetPair,
                        price: targetPrice,
                        orderId: order.Id,
                        modality: modality.ToType <TradeRequestModality>(),
                        isCancellationTrade: isCancellationTrade,
                        cancellationTradeExternalId: cancellationTradeExternalId);

                    var cts = new CancellationTokenSource();
                    cts.CancelAfter(_marginTradingSettings.GavelTimeout);

                    var executionResult = await _exchangeConnectorClient.ExecuteOrder(externalOrderModel, cts.Token);

                    if (!executionResult.Success)
                    {
                        var ex = new Exception(
                            $"External order was not executed. Status: {executionResult.ExecutionStatus}. Failure: {executionResult.FailureType}");
                        LogOrderExecutionException(order, externalOrderModel, ex);
                    }
                    else
                    {
                        var executedPrice = Math.Abs(executionResult.Price) > 0
                            ? (decimal)executionResult.Price
                            : price.Value;

                        if (executedPrice.EqualsZero())
                        {
                            var ex = new Exception($"Have got execution price from Gavel equal to 0. Ignoring.");
                            LogOrderExecutionException(order, externalOrderModel, ex);
                        }
                        else
                        {
                            var matchedOrders = new MatchedOrderCollection
                            {
                                new MatchedOrder
                                {
                                    MarketMakerId = source,
                                    MatchedDate   = _dateService.Now(),
                                    OrderId       = executionResult.ExchangeOrderId,
                                    Price         = CalculatePriceWithMarkups(assetPair, order.Direction, executedPrice),
                                    Volume        = (decimal)executionResult.Volume,
                                    IsExternal    = true
                                }
                            };

                            await _rabbitMqNotifyService.ExternalOrder(executionResult);

                            _operationsLogService.AddLog("external order executed", order.AccountId,
                                                         externalOrderModel.ToJson(), executionResult.ToJson());

                            return(matchedOrders);
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogOrderExecutionException(order, externalOrderModel, ex);
                    throw new OrderExecutionTechnicalException();
                }
            }

            return(new MatchedOrderCollection());
        }
示例#10
0
        public async Task <MatchedOrderCollection> MatchOrderAsync(Order order, bool shouldOpenNewPosition,
                                                                   OrderModality modality = OrderModality.Regular)
        {
            List <(string source, decimal?price)> prices = null;

            if (!string.IsNullOrEmpty(_marginTradingSettings.DefaultExternalExchangeId))
            {
                var quote = _quoteCacheService.GetQuote(order.AssetPairId);

                if (quote.GetVolumeForOrderDirection(order.Direction) >= Math.Abs(order.Volume))
                {
                    prices = new List <(string source, decimal?price)>
                    {
                        (_marginTradingSettings
                         .DefaultExternalExchangeId, quote.GetPriceForOrderDirection(order.Direction))
                    };
                }
            }

            if (prices == null)
            {
                prices = _externalOrderbookService.GetOrderedPricesForExecution(order.AssetPairId, order.Volume, shouldOpenNewPosition);

                if (prices == null || !prices.Any())
                {
                    return(new MatchedOrderCollection());
                }
            }

            var assetPair         = _assetPairsCache.GetAssetPairByIdOrDefault(order.AssetPairId);
            var externalAssetPair = assetPair?.BasePairId ?? order.AssetPairId;

            foreach (var(source, price) in prices
                     .Where(x => string.IsNullOrEmpty(order.ExternalProviderId) || x.source == order.ExternalProviderId))
            {
                var externalOrderModel = new OrderModel();

                var orderType = order.OrderType == Core.Orders.OrderType.Limit ||
                                order.OrderType == Core.Orders.OrderType.TakeProfit
                    ? OrderType.Limit
                    : OrderType.Market;

                var targetPrice = order.OrderType == Core.Orders.OrderType.Market
                    ? (double?)price
                    : (double?)order.Price;

                try
                {
                    externalOrderModel = new OrderModel(
                        tradeType: order.Direction.ToType <TradeType>(),
                        orderType: orderType,
                        timeInForce: TimeInForce.FillOrKill,
                        volume: (double)Math.Abs(order.Volume),
                        dateTime: _dateService.Now(),
                        exchangeName: source,
                        instrument: externalAssetPair,
                        price: targetPrice,
                        orderId: order.Id,
                        modality: modality.ToType <TradeRequestModality>());

                    var cts = new CancellationTokenSource();
                    cts.CancelAfter(_marginTradingSettings.GavelTimeout);
                    var executionResult = await _exchangeConnectorService.CreateOrderAsync(externalOrderModel, cts.Token);

                    if (!executionResult.Success)
                    {
                        throw new Exception(
                                  $"External order was not executed. Status: {executionResult.ExecutionStatus}. Failure: {executionResult.FailureType}");
                    }

                    var executedPrice = Math.Abs(executionResult.Price) > 0
                        ? (decimal)executionResult.Price
                        : price.Value;

                    var matchedOrders = new MatchedOrderCollection
                    {
                        new MatchedOrder
                        {
                            MarketMakerId = source,
                            MatchedDate   = _dateService.Now(),
                            OrderId       = executionResult.ExchangeOrderId,
                            Price         = CalculatePriceWithMarkups(assetPair, order.Direction, executedPrice),
                            Volume        = (decimal)executionResult.Volume,
                            IsExternal    = true
                        }
                    };

                    await _rabbitMqNotifyService.ExternalOrder(executionResult);

                    _operationsLogService.AddLog("external order executed", order.AccountId,
                                                 externalOrderModel.ToJson(), executionResult.ToJson());

                    return(matchedOrders);
                }
                catch (Exception e)
                {
                    var connector =
                        _marginTradingSettings.ExchangeConnector == ExchangeConnectorType.FakeExchangeConnector
                            ? "Fake"
                            : _exchangeConnectorService.BaseUri.OriginalString;

                    _log.WriteError(
                        $"{nameof(StpMatchingEngine)}:{nameof(MatchOrderAsync)}:{connector}",
                        $"Internal order: {order.ToJson()}, External order model: {externalOrderModel.ToJson()}", e);
                }
            }

            return(new MatchedOrderCollection());
        }
示例#11
0
        public Task <HttpOperationResponse <ExecutionReport> > CreateOrderWithHttpMessagesAsync(OrderModel orderModel = null, Dictionary <string, List <string> > customHeaders = null,
                                                                                                CancellationToken cancellationToken = new CancellationToken())
        {
            if (orderModel == null || orderModel.Volume == 0)
            {
                var report = new HttpOperationResponse <ExecutionReport>
                {
                    Response = new HttpResponseMessage()
                    {
                        Content    = new StringContent("Bad model"),
                        StatusCode = HttpStatusCode.BadRequest,
                    }
                };

                return(Task.FromResult(report));
            }

            var quote = _quoteService.GetQuote(orderModel.Instrument);

            var result = new HttpOperationResponse <ExecutionReport>();

            try
            {
                _chaosKitty.Meow(nameof(FakeExchangeConnectorService));

                result.Body = new ExecutionReport(
                    type: orderModel.TradeType.ToType <TradeType>(),
                    time: DateTime.UtcNow,
                    price: orderModel.Price ??
                    (double?)(orderModel.TradeType == TradeType.Buy ? quote?.Ask : quote?.Bid)
                    ?? throw new Exception("No price"),
                    volume: orderModel.Volume,
                    fee: 0,
                    success: true,
                    executionStatus: OrderExecutionStatus.Fill,
                    failureType: OrderStatusUpdateFailureType.None,
                    orderType: orderModel.OrderType,
                    execType: ExecType.Trade,
                    clientOrderId: Guid.NewGuid().ToString(),
                    exchangeOrderId: Guid.NewGuid().ToString(),
                    instrument: new Instrument(orderModel.Instrument, orderModel.ExchangeName));
            }
            catch
            {
                result.Body = new ExecutionReport(
                    type: orderModel.TradeType.ToType <TradeType>(),
                    time: DateTime.UtcNow,
                    price: 0,
                    volume: 0,
                    fee: 0,
                    success: false,
                    executionStatus: OrderExecutionStatus.Rejected,
                    failureType: OrderStatusUpdateFailureType.ExchangeError,
                    orderType: orderModel.OrderType,
                    execType: ExecType.Trade,
                    clientOrderId: null,
                    exchangeOrderId: null,
                    instrument: new Instrument(orderModel.Instrument, orderModel.ExchangeName));
            }

            return(Task.FromResult(result));
        }