public override Task Execute()
        {
            var pendingOrders = _orderReader.GetPending().GroupBy(o => o.Instrument);

            foreach (var gr in pendingOrders)
            {
                if (!_assetDayOffService.ArePendingOrdersDisabled(gr.Key))
                {
                    continue;
                }

                foreach (var pendingOrder in gr)
                {
                    try
                    {
                        _tradingEngine.CancelPendingOrder(pendingOrder.Id, OrderCloseReason.CanceledBySystem);
                    }
                    catch (Exception e)
                    {
                        _log.WriteErrorAsync(nameof(PendingOrdersCleaningService),
                                             $"Cancelling pending order {pendingOrder.Id}", pendingOrder.ToJson(), e);
                    }
                }
            }

            return(Task.CompletedTask);
        }
Beispiel #2
0
        public IAssetPair GetAssetPairIfAvailableForTrading(string assetPairId, OrderType orderType,
                                                            bool shouldOpenNewPosition, bool isPreTradeValidation)
        {
            if (isPreTradeValidation || orderType == OrderType.Market)
            {
                if (_assetDayOffService.IsDayOff(assetPairId))
                {
                    throw new ValidateOrderException(OrderRejectReason.NoLiquidity,
                                                     "Trades for instrument are not available");
                }
            }
            else if (_assetDayOffService.ArePendingOrdersDisabled(assetPairId))
            {
                throw new ValidateOrderException(OrderRejectReason.NoLiquidity,
                                                 "Pending orders for instrument are not available");
            }

            var assetPair = _assetPairsCache.GetAssetPairByIdOrDefault(assetPairId);

            if (assetPair == null)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument, "Instrument not found");
            }

            if (assetPair.IsDiscontinued)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                 "Trading for the instrument is discontinued");
            }

            if (assetPair.IsSuspended)
            {
                if (isPreTradeValidation)
                {
                    throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                     "Orders execution for instrument is temporarily unavailable");
                }

                if (orderType == OrderType.Market)
                {
                    throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                     "Market orders for instrument are temporarily unavailable");
                }
            }

            if (assetPair.IsFrozen && shouldOpenNewPosition)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                 "Opening new positions is temporarily unavailable");
            }

            return(assetPair);
        }
Beispiel #3
0
        private IEnumerable <Order> GetPendingOrdersToBeExecuted(string instrument)
        {
            var pendingOrders = _ordersCache.WaitingForExecutionOrders.GetOrdersByInstrument(instrument)
                                .OrderBy(item => item.CreateDate);

            foreach (var order in pendingOrders)
            {
                InstrumentBidAskPair pair;

                if (_quoteCashService.TryGetQuoteById(order.Instrument, out pair))
                {
                    var price = pair.GetPriceForOrderType(order.GetCloseType());

                    if (order.IsSuitablePriceForPendingOrder(price) &&
                        !_assetPairDayOffService.ArePendingOrdersDisabled(order.Instrument))
                    {
                        yield return(order);
                    }
                }
            }
        }
Beispiel #4
0
        //has to be beyond global lock
        public void Validate(Order order)
        {
            #region Validate input params

            if (_assetDayOffService.IsDayOff(order.Instrument))
            {
                throw new ValidateOrderException(OrderRejectReason.NoLiquidity, "Trades for instrument are not available");
            }

            if (order.Volume == 0)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidVolume, "Volume cannot be 0");
            }

            var asset = _assetPairsCache.TryGetAssetPairById(order.Instrument);

            if (asset == null)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument, "Instrument not found");
            }

            var account = _accountsCacheService.TryGet(order.ClientId, order.AccountId);

            if (account == null)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidAccount, "Account not found");
            }

            if (!_quoteCashService.TryGetQuoteById(order.Instrument, out var quote))
            {
                throw new ValidateOrderException(OrderRejectReason.NoLiquidity, "Quote not found");
            }

            #endregion

            order.AssetAccuracy      = asset.Accuracy;
            order.AccountAssetId     = account.BaseAssetId;
            order.TradingConditionId = account.TradingConditionId;

            //check ExpectedOpenPrice for pending order
            if (order.ExpectedOpenPrice.HasValue)
            {
                if (_assetDayOffService.ArePendingOrdersDisabled(order.Instrument))
                {
                    throw new ValidateOrderException(OrderRejectReason.NoLiquidity, "Trades for instrument are not available");
                }

                if (order.ExpectedOpenPrice <= 0)
                {
                    throw new ValidateOrderException(OrderRejectReason.InvalidExpectedOpenPrice, "Incorrect expected open price");
                }

                order.ExpectedOpenPrice = Math.Round(order.ExpectedOpenPrice ?? 0, order.AssetAccuracy);

                if (order.GetOrderType() == OrderDirection.Buy && order.ExpectedOpenPrice > quote.Ask ||
                    order.GetOrderType() == OrderDirection.Sell && order.ExpectedOpenPrice < quote.Bid)
                {
                    var reasonText = order.GetOrderType() == OrderDirection.Buy
                        ? string.Format(MtMessages.Validation_PriceAboveAsk, order.ExpectedOpenPrice, quote.Ask)
                        : string.Format(MtMessages.Validation_PriceBelowBid, order.ExpectedOpenPrice, quote.Bid);

                    throw new ValidateOrderException(OrderRejectReason.InvalidExpectedOpenPrice, reasonText, $"{order.Instrument} quote (bid/ask): {quote.Bid}/{quote.Ask}");
                }
            }

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

            if (accountAsset.DealLimit > 0 && Math.Abs(order.Volume) > accountAsset.DealLimit)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidVolume,
                                                 $"Margin Trading is in beta testing. The volume of a single order is temporarily limited to {accountAsset.DealLimit} {accountAsset.Instrument}. Thank you for using Lykke Margin Trading, the limit will be cancelled soon!");
            }

            //check TP/SL
            if (order.TakeProfit.HasValue)
            {
                order.TakeProfit = Math.Round(order.TakeProfit.Value, order.AssetAccuracy);
            }

            if (order.StopLoss.HasValue)
            {
                order.StopLoss = Math.Round(order.StopLoss.Value, order.AssetAccuracy);
            }

            ValidateOrderStops(order.GetOrderType(), quote, accountAsset.DeltaBid, accountAsset.DeltaAsk, order.TakeProfit, order.StopLoss, order.ExpectedOpenPrice, order.AssetAccuracy);

            ValidateInstrumentPositionVolume(accountAsset, order);

            if (!_accountUpdateService.IsEnoughBalance(order))
            {
                throw new ValidateOrderException(OrderRejectReason.NotEnoughBalance, MtMessages.Validation_NotEnoughBalance, $"Account available balance is {account.GetTotalCapital()}");
            }
        }
Beispiel #5
0
        public IAssetPair GetAssetPairIfAvailableForTrading(string assetPairId, OrderType orderType,
                                                            bool shouldOpenNewPosition, bool isPreTradeValidation, bool validateForEdit = false)
        {
            if (isPreTradeValidation || orderType == OrderType.Market)
            {
                var tradingStatus = _assetDayOffService.IsAssetTradingDisabled(assetPairId);
                if (tradingStatus)
                {
                    if (tradingStatus.Reason == InstrumentTradingDisabledReason.InstrumentTradingDisabled)
                    {
                        throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                         $"Trading for the instrument {assetPairId} is disabled. Error code: {CommonErrorCodes.InstrumentTradingDisabled}");
                    }
                    throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                     $"Trades for instrument {assetPairId} are not available due to trading is closed");
                }
            }
            else if (_assetDayOffService.ArePendingOrdersDisabled(assetPairId))
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                 $"Pending orders for instrument {assetPairId} are not available");
            }

            var assetPair = _assetPairsCache.GetAssetPairByIdOrDefault(assetPairId);

            if (assetPair == null)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument, $"Instrument {assetPairId} not found");
            }

            if (assetPair.IsDiscontinued)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                 $"Trading for the instrument {assetPairId} is discontinued");
            }

            if (assetPair.IsTradingDisabled && !validateForEdit)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                 $"Trading for the instrument {assetPairId} is disabled. Error code: {CommonErrorCodes.InstrumentTradingDisabled}");
            }

            if (assetPair.IsSuspended && shouldOpenNewPosition)
            {
                if (isPreTradeValidation)
                {
                    throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                     $"Orders execution for instrument {assetPairId} is temporarily unavailable (instrument is suspended)");
                }

                if (orderType == OrderType.Market)
                {
                    throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                     $"Market orders for instrument {assetPairId} are temporarily unavailable (instrument is suspended)");
                }
            }

            if (assetPair.IsFrozen && shouldOpenNewPosition)
            {
                throw new ValidateOrderException(OrderRejectReason.InvalidInstrument,
                                                 $"Opening new positions for instrument {assetPairId} is temporarily unavailable (instrument is frozen)");
            }

            return(assetPair);
        }