Quote modelQuoteThatCouldFillAlert(Alert alert) { string err; Quote quoteModel = new Quote(); quoteModel.Source = "GENERATED_TO_FILL_" + alert.ToString(); quoteModel.Size = alert.Qty; double priceScriptAligned = this.backtester.Executor.AlignAlertPriceToPriceLevel(alert.Bars, alert.PriceScript, true, alert.PositionLongShortFromDirection, alert.MarketLimitStop); Quote quotePrev = this.backtester.BacktestDataSource.BacktestStreamingProvider.StreamingDataSnapshot .LastQuoteGetForSymbol(alert.Symbol); switch (alert.MarketLimitStop) { case MarketLimitStop.Limit: switch (alert.Direction) { case Direction.Buy: case Direction.Cover: if (priceScriptAligned > quotePrev.Ask) { err = "INVALID_PRICESCRIPT_FOR_LIMIT_BUY_MUST_NOT_BE_ABOVE_CURRENT_ASK"; return null; } this.backtester.BacktestDataSource.BacktestStreamingProvider.SpreadModeler .GenerateFillBidBasedOnAsk(quoteModel, priceScriptAligned); break; case Direction.Short: case Direction.Sell: if (priceScriptAligned < quotePrev.Bid) { err = "INVALID_PRICESCRIPT_FOR_LIMIT_SELL_MUST_NOT_BE_BELOW_CURRENT_BID"; return null; } this.backtester.BacktestDataSource.BacktestStreamingProvider.SpreadModeler .GenerateFillAskBasedOnBid(quoteModel, priceScriptAligned); break; default: throw new Exception("ALERT_LIMIT_DIRECTION_UNKNOWN direction[" + alert.Direction + "] is not Buy/Cover/Short/Sell modelQuoteThatCouldFillAlert()"); } break; case MarketLimitStop.Stop: switch (alert.Direction) { case Direction.Buy: case Direction.Cover: if (priceScriptAligned < quotePrev.Ask) { err = "INVALID_PRICESCRIPT_FOR_STOP_BUY_MUST_NOT_BE_BELOW_CURRENT_ASK"; return null; } this.backtester.BacktestDataSource.BacktestStreamingProvider.SpreadModeler .GenerateFillBidBasedOnAsk(quoteModel, priceScriptAligned); break; case Direction.Short: case Direction.Sell: if (priceScriptAligned > quotePrev.Bid) { err = "INVALID_PRICESCRIPT_FOR_STOP_SELL_MUST_NOT_BE_ABOVE_CURRENT_BID"; return null; } this.backtester.BacktestDataSource.BacktestStreamingProvider.SpreadModeler .GenerateFillAskBasedOnBid(quoteModel, priceScriptAligned); break; default: throw new Exception("ALERT_STOP_DIRECTION_UNKNOWN direction[" + alert.Direction + "] is not Buy/Cover/Short/Sell modelQuoteThatCouldFillAlert()"); } break; case MarketLimitStop.Market: switch (alert.Direction) { case Direction.Buy: case Direction.Cover: quoteModel.Ask = quotePrev.Ask; this.backtester.BacktestDataSource.BacktestStreamingProvider.SpreadModeler .GenerateFillBidBasedOnAsk(quoteModel, quotePrev.Ask); break; case Direction.Short: case Direction.Sell: quoteModel.Bid = quotePrev.Bid; this.backtester.BacktestDataSource.BacktestStreamingProvider.SpreadModeler .GenerateFillAskBasedOnBid(quoteModel, quotePrev.Bid); break; default: throw new Exception("ALERT_MARKET_DIRECTION_UNKNOWN direction[" + alert.Direction + "] is not Buy/Cover/Short/Sell modelQuoteThatCouldFillAlert()"); } break; case MarketLimitStop.StopLimit: // HACK one quote might satisfy SLactivation, the other one might fill it; time to introduce state of SL into Alert??? string msg = "STOP_LIMIT_QUOTE_FILLING_GENERATION_REQUIRES_TWO_STEPS_NYI" + "; pass SLActivation=0 to PositionPrototypeActivator so that it generates STOP instead of STOPLOSS which I can't generate yet"; //Debugger.Break(); break; case MarketLimitStop.AtClose: default: throw new Exception("ALERT_TYPE_UNKNOWN MarketLimitStop[" + alert.MarketLimitStop + "] is not Market/Limit/Stop modelQuoteThatCouldFillAlert()"); } return quoteModel; }