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); }
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); }
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); } } } }
//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()}"); } }
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); }