Ejemplo n.º 1
0
        private async Task Handle(ExecuteSpecialLiquidationOrderCommand command, IEventPublisher publisher)
        {
            var executionInfo = await _operationExecutionInfoRepository.GetAsync <SpecialLiquidationOperationData>(
                operationName : SpecialLiquidationSaga.OperationName,
                id : command.OperationId);

            if (executionInfo?.Data == null)
            {
                return;
            }

            if (executionInfo.Data.SwitchState(SpecialLiquidationOperationState.PriceReceived,
                                               SpecialLiquidationOperationState.ExternalOrderExecuted))
            {
                if (command.Volume == 0)
                {
                    publisher.PublishEvent(new SpecialLiquidationOrderExecutedEvent
                    {
                        OperationId   = command.OperationId,
                        CreationTime  = _dateService.Now(),
                        MarketMakerId = "ZeroNetVolume",
                        ExecutionTime = _dateService.Now(),
                        OrderId       = _identityGenerator.GenerateGuid(),
                    });
                }
                else
                {
                    var order = new OrderModel(
                        tradeType: command.Volume > 0 ? TradeType.Buy : TradeType.Sell,
                        orderType: OrderType.Market.ToType <Lykke.Service.ExchangeConnector.Client.Models.OrderType>(),
                        timeInForce: TimeInForce.FillOrKill,
                        volume: (double)Math.Abs(command.Volume),
                        dateTime: _dateService.Now(),
                        exchangeName: executionInfo.Data.ExternalProviderId,
                        instrument: command.Instrument,
                        price: (double?)command.Price,
                        orderId: _identityGenerator.GenerateAlphanumericId());

                    try
                    {
                        var executionResult = await _exchangeConnectorService.CreateOrderAsync(order);

                        publisher.PublishEvent(new SpecialLiquidationOrderExecutedEvent
                        {
                            OperationId   = command.OperationId,
                            CreationTime  = _dateService.Now(),
                            MarketMakerId = executionInfo.Data.ExternalProviderId,
                            ExecutionTime = executionResult.Time,
                            OrderId       = executionResult.ExchangeOrderId,
                        });
                    }
                    catch (Exception exception)
                    {
                        publisher.PublishEvent(new SpecialLiquidationOrderExecutionFailedEvent
                        {
                            OperationId  = command.OperationId,
                            CreationTime = _dateService.Now(),
                            Reason       = exception.Message
                        });
                        await _log.WriteWarningAsync(nameof(SpecialLiquidationCommandsHandler),
                                                     nameof(ExecuteSpecialLiquidationOrderCommand),
                                                     $"Failed to execute the order: {order.ToJson()}",
                                                     exception);
                    }
                }

                await _operationExecutionInfoRepository.Save(executionInfo);
            }
        }
Ejemplo 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";
            }
        }
Ejemplo 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());
        }