Esempio n. 1
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());
        }
Esempio n. 2
0
        //TODO: remove orderProcessed function and make all validations before match
        public void MatchMarketOrderForOpen(Order order, Func <MatchedOrderCollection, bool> orderProcessed)
        {
            var prices = _externalOrderBooksList.GetPricesForOpen(order);

            if (prices == null)
            {
                orderProcessed(new MatchedOrderCollection());
                return;
            }

            prices = order.GetOrderType() == OrderDirection.Buy
                ? prices.OrderBy(tuple => tuple.price).ToList()
                : prices.OrderByDescending(tuple => tuple.price).ToList();

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

            foreach (var sourcePrice in prices)
            {
                var externalOrderModel = new OrderModel();

                try
                {
                    externalOrderModel = new OrderModel(
                        order.GetOrderType().ToType <TradeType>(),
                        OrderType.Market,
                        TimeInForce.FillOrKill,
                        (double)Math.Abs(order.Volume),
                        _dateService.Now(),
                        sourcePrice.source,
                        externalAssetPair);

                    var executionResult = _exchangeConnectorService.CreateOrderAsync(externalOrderModel).GetAwaiter()
                                          .GetResult();

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

                    var matchedOrders = new MatchedOrderCollection
                    {
                        new MatchedOrder
                        {
                            ClientId      = order.ClientId,
                            MarketMakerId = sourcePrice.source,
                            MatchedDate   = _dateService.Now(),
                            OrderId       = executionResult.ClientOrderId,
                            Price         = CalculatePriceWithMarkups(assetPair, order.GetOrderType(), executedPrice),
                            Volume        = (decimal)executionResult.Volume
                        }
                    };

                    order.OpenExternalProviderId = sourcePrice.source;
                    order.OpenExternalOrderId    = executionResult.ClientOrderId;

                    _rabbitMqNotifyService.ExternalOrder(executionResult).GetAwaiter().GetResult();

                    if (orderProcessed(matchedOrders))
                    {
                        return;
                    }
                    else
                    {
                        var cancelOrderModel = new OrderModel(
                            order.GetCloseType().ToType <TradeType>(),
                            OrderType.Market,
                            TimeInForce.FillOrKill,
                            (double)Math.Abs(order.Volume),
                            _dateService.Now(),
                            sourcePrice.source,
                            externalAssetPair);

                        var cancelOrderResult = _exchangeConnectorService.CreateOrderAsync(cancelOrderModel).GetAwaiter().GetResult();

                        _rabbitMqNotifyService.ExternalOrder(cancelOrderResult).GetAwaiter().GetResult();
                    }

                    return;
                }
                catch (Exception e)
                {
                    _log.WriteErrorAsync(nameof(StpMatchingEngine), nameof(MatchMarketOrderForOpen),
                                         $"Internal order: {order.ToJson()}, External order model: {externalOrderModel.ToJson()}", e);
                }
            }

            if (string.IsNullOrEmpty(order.OpenExternalProviderId) ||
                string.IsNullOrEmpty(order.OpenExternalOrderId))
            {
                order.Status           = OrderStatus.Rejected;
                order.RejectReason     = OrderRejectReason.NoLiquidity;
                order.RejectReasonText = "Error executing external order";
            }
        }
Esempio n. 3
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());
        }