public void ConsumeQuoteOfStreamingBar(Quote quote) {
			//Bar barLastFormed = quoteToReach.ParentStreamingBar;
			ExecutionDataSnapshot snap = this.backtester.Executor.ExecutionDataSnapshot;

			foreach (Indicator indicator in snap.Indicators.Values) {
				try {
					indicator.OnNewStreamingQuote(quote);
				} catch (Exception ex) {
					Debugger.Break();
				}
			}

			if (snap.AlertsPending.Count > 0) {
				var dumped = snap.DumpPendingAlertsIntoPendingHistoryByBar();
				if (dumped > 0) {
					//string msg = "here is at least one reason why dumping on fresh quoteToReach makes sense"
					//    + " if we never reach this breakpoint the remove dump() from here"
					//    + " but I don't see a need to invoke it since we dumped pendings already after OnNewBarCallback";
					string msg = "DUMPED_BEFORE_SCRIPT_EXECUTION_ON_NEW_BAR_OR_QUOTE";
				}
				int pendingCountPre = this.backtester.Executor.ExecutionDataSnapshot.AlertsPending.Count;
				int pendingFilled = this.backtester.Executor.MarketSimStreaming.SimulatePendingFill(quote);
				int pendingCountNow = this.backtester.Executor.ExecutionDataSnapshot.AlertsPending.Count;
				if (pendingCountNow != pendingCountPre - pendingFilled) {
					string msg = "NOT_ONLY it looks like AnnihilateCounterparty worked out!";
				}
				if (pendingCountNow > 0) {
					string msg = "pending=[" + pendingCountNow + "], it must be prototype-induced 2 closing TP & SL";
				}
			}
			//this.backtester.Executor.Script.OnNewQuoteCallback(quoteToReach);
			ReporterPokeUnit pokeUnit = this.backtester.Executor.ExecuteOnNewBarOrNewQuote(quote);
		}
		public virtual int InjectQuotesToFillPendingAlerts(Quote quoteToReach) {
			int quotesInjected = 0;
			int pendingsToFillInitially = this.backtester.Executor.ExecutionDataSnapshot.AlertsPending.Count;
			if (pendingsToFillInitially == 0) return quotesInjected;

			int iterationsLimit = 5;
			// hard to debug but I hate while(){} loops
			//for (Quote closestOnOurWay  = this.generateClosestQuoteForEachPendingAlertOnOurWayTo(quoteToReach);
			//           closestOnOurWay != null;
			//           closestOnOurWay  = this.generateClosestQuoteForEachPendingAlertOnOurWayTo(quoteToReach)) {
			Quote closestOnOurWay  = this.generateClosestQuoteForEachPendingAlertOnOurWayTo(quoteToReach);
			while (closestOnOurWay != null) {
				quotesInjected++;
				closestOnOurWay.IntraBarSerno += quotesInjected;
				this.backtester.BacktestDataSource.BacktestStreamingProvider.PushQuoteReceived(closestOnOurWay);
				int pendingAfterInjected = this.backtester.Executor.ExecutionDataSnapshot.AlertsPending.Count;
				if (pendingsToFillInitially != pendingAfterInjected) {
					string msg = "it looks like the quoteInjected triggered something";
					//Debugger.Break();
				}
				if (quotesInjected > iterationsLimit) {
					string msg = "InjectQuotesToFillPendingAlerts(): quotesInjected["
						+ quotesInjected + "] > iterationsLimit[" + iterationsLimit + "]"
						+ " pendingNow[" + this.backtester.Executor.ExecutionDataSnapshot.AlertsPending.Count + "]"
						+ " quoteToReach[" + quoteToReach + "]";
					//throw new Exception(msg);
					break;
				}
				if (this.backtester.BacktestAborted.WaitOne(0)) break;
				if (this.backtester.RequestingBacktestAbort.WaitOne(0)) break;
				closestOnOurWay = this.generateClosestQuoteForEachPendingAlertOnOurWayTo(quoteToReach);
			}
			return quotesInjected;
		}
		protected void LastQuoteUpdate(Quote quote) {
			if (this.LastQuotesReceived[quote.Symbol] == quote) {
				string msg = "How come you update twice to the same quote?";
				return;
			}
			this.LastQuotesReceived[quote.Symbol] = quote;
		}
		public void GeneratedQuoteEnrichSymmetricallyAndPush(Quote quote) {
			if (this.SpreadModeler == null) {
				string msg = "Don't leave quoteToReach.Bid and quoteToReach.Ask uninitialized!!!";
				throw new Exception(msg);
			}
			this.SpreadModeler.GenerateFillBidAskSymmetricallyFromLastPrice(quote);
			base.PushQuoteReceived(quote);
		}
		public virtual void UpdateLastBidAskSnapFromQuote(Quote quote) {
			this.LastQuoteUpdate(quote);

			if (double.IsNaN(quote.Bid) || double.IsNaN(quote.Ask)) {
				if (false) throw new Exception("You seem to process Bars.LastBar with Partials=NaN");
				return;
			}
			if (quote.Bid != 0 && quote.Ask != 0) {
				this.BestBidAskPutForSymbol(quote.Symbol, quote.Bid, quote.Ask);
			}
		}
		public Quote DeriveIdenticalButFresh() {
			Quote identicalButFresh = new Quote();
			identicalButFresh.Symbol = this.Symbol;
			identicalButFresh.SymbolClass = this.SymbolClass;
			identicalButFresh.Source = this.Source;
			identicalButFresh.ServerTime = this.ServerTime.AddMilliseconds(911);
			identicalButFresh.LocalTimeCreatedMillis = this.LocalTimeCreatedMillis.AddMilliseconds(911);
			identicalButFresh.PriceLastDeal = this.PriceLastDeal;
			identicalButFresh.Bid = this.Bid;
			identicalButFresh.Ask = this.Ask;
			identicalButFresh.Size = this.Size;
			identicalButFresh.IntraBarSerno = this.IntraBarSerno + Quote.IntraBarSernoShiftForGeneratedTowardsPendingFill;
			identicalButFresh.ParentStreamingBar = this.ParentStreamingBar;
			return identicalButFresh;
		}
		protected Quote generateNewQuoteChildrenHelper(int intraBarSerno, string source, string symbol, DateTime serverTime, double price, int volume) {
			Quote quote = new Quote();
			quote.Absno = ++this.QuoteAbsno;
			quote.ServerTime = serverTime;
			quote.IntraBarSerno = intraBarSerno;
			quote.Source = source;
			quote.Symbol = symbol;
			quote.SymbolClass = this.backtester.BarsOriginal.SymbolInfo.SymbolClass;
			quote.Size = volume;
			quote.PriceLastDeal = price;
			// moved to BacktestQuoteModeler
			//quote.Bid = quote.PriceLastDeal - 10;
			//quote.Ask = quote.PriceLastDeal + 10;
			return quote;
		}
		public Quote BindStreamingBarForQuote(Quote quoteSernoEnrichedWithStreamingBarUnattached) {
			if (consumer.ConsumerBarsToAppendInto == null) {
				// StreamingSolidifier will attach the Bar itself
				return quoteSernoEnrichedWithStreamingBarUnattached;
			}
//			if (consumer.ConsumerBarsToAppendInto.BarStreaming != null) {
//				// first four quotes there is no BarStreaming?.../
//				return quoteSernoEnrichedWithStreamingBarUnattached;
//			}
			
			//v1 consumer.ConsumerBarsToAppendInto.OverrideStreamingDOHLCVwith(quoteSernoEnrichedWithStreamingBarUnattached.ParentStreamingBar);
			consumer.ConsumerBarsToAppendInto.CreateNewOrAbsorbIntoStreaming(quoteSernoEnrichedWithStreamingBarUnattached.ParentStreamingBar);
			Quote quoteAttached = quoteSernoEnrichedWithStreamingBarUnattached.Clone();
			quoteAttached.SetParentBar(consumer.ConsumerBarsToAppendInto.BarStreaming);
			return quoteAttached;
		}
		public virtual Quote EnrichQuoteWithSernoUpdateStreamingBarCreateNewBar(Quote quoteClone) {
			if (quoteClone.PriceLastDeal == 0) {
				string msg = "quote.PriceLastDeal[" + quoteClone.PriceLastDeal + "] == 0;"
					+ "what kind of quote is that?... (" + quoteClone + ")";
				throw new Exception(msg);
				//return;
			}

			if (StreamingBar.Symbol != quoteClone.Symbol) {
				string msg = "StreamingBar.Symbol=[" + StreamingBar.Symbol + "]!=quote.Symbol["
					+ quoteClone.Symbol + "] (" + quoteClone + ")";
				throw new Exception(msg);
				//return;
			}

			// included in if (quoteClone.ServerTime >= StreamingBar.DateTimeNextBarOpenUnconditional) !!!
			// on very first quote StreamingBar.DateTimeNextBarOpenUnconditional = DateTime.MinValue
			//SEE_BELOW if (StreamingBar.DateTimeOpen == DateTime.MinValue)
			//SEE_BELOW 	this.initStreamingBarResetIntraBarSerno(quoteClone.ServerTime, quoteClone.PriceLastDeal, quoteClone.Size);
			//SEE_BELOW }

			if (quoteClone.ServerTime >= StreamingBar.DateTimeNextBarOpenUnconditional) {
				LastBarFormedUnattached = StreamingBar.Clone();	//beware! on very first quote LastBarFormed.DateTimeOpen == DateTime.MinValue
				initStreamingBarResetIntraBarSerno(quoteClone.ServerTime, quoteClone.PriceLastDeal, quoteClone.Size);
			} else {
				if (Double.IsNaN(StreamingBar.Open) || StreamingBar.Open == 0.0) {
					throw new Exception("nonsense! we should've had StreamingBar already initialized with first quote of a bar");
					//log.Warn("Initializing OHL as quote.PriceLastDeal[" + quoteClone.PriceLastDeal + "];"
					//	+ " following previous InitWithStreamingBarInsteadOfEmpty message"
					//	+ " (if absent then never initialized)");
					//StreamingBar.Open = quoteClone.PriceLastDeal;
					//StreamingBar.High = quoteClone.PriceLastDeal;
					//StreamingBar.Low = quoteClone.PriceLastDeal;
				}
				if (quoteClone.PriceLastDeal > StreamingBar.High) StreamingBar.High = quoteClone.PriceLastDeal;
				if (quoteClone.PriceLastDeal < StreamingBar.Low) StreamingBar.Low = quoteClone.PriceLastDeal;
				StreamingBar.Close = quoteClone.PriceLastDeal;
				StreamingBar.Volume += quoteClone.Size;
				IntraBarSerno++;
			}
			quoteClone.IntraBarSerno = IntraBarSerno;
			quoteClone.SetParentBar(StreamingBar);
			return quoteClone;
		}
		public override void OnNewQuoteOfStreamingBarCallback(Quote quote) {
			//double slowStreaming = this.MAslow.BarClosesProxied.StreamingValue;
			double slowStatic = this.MAslow.ClosesProxyEffective.LastStaticValue;
			DateTime slowStaticDate = this.MAslow.ClosesProxyEffective.LastStaticDate;

			if (this.Executor.Backtester.IsBacktestingNow == false) {
				Bar bar = quote.ParentStreamingBar;
				int barNo = bar.ParentBarsIndex;
				if (barNo == -1) return;
				DateTime lastStaticBarDateTime = bar.ParentBars.BarStaticLast.DateTimeOpen;
				DateTime streamingBarDateTime = bar.DateTimeOpen;
				Bar barNormalizedDateTimes = new Bar(bar.Symbol, bar.ScaleInterval, quote.ServerTime);
				DateTime thisBarDateTimeOpen = barNormalizedDateTimes.DateTimeOpen;
				int a = 1;
			}
			//log("OnNewQuoteCallback(): [" + quote.ToString() + "]"); 
			string msg = "OnNewQuoteCallback(): [" + quote.ToString() + "]";
			log("EnterEveryBar.cs now=[" + DateTime.Now.ToString("ddd dd-MMM-yyyy HH:mm:ss.fff" + "]: " + msg));

			if (quote.IntraBarSerno == 0) {
				return;
			}
		}
		public void PrintQuoteTimestampsOnStreamingButtonBeforeExecution(Quote quote) {
			if (quote == null) return;
			if (InvokeRequired) {
				base.BeginInvoke((MethodInvoker)delegate { this.PrintQuoteTimestampsOnStreamingButtonBeforeExecution(quote); });
				return;
			}
			StringBuilder sb = new StringBuilder(
				"StreamingOn #" + quote.IntraBarSerno.ToString("000") + " "
				+ quote.ServerTime.ToString("HH:mm:ss.fff"));
			bool quoteTimesDifferMoreThanOneMicroSecond = quote.ServerTime.ToString("HH:mm:ss.f") != quote.LocalTimeCreatedMillis.ToString("HH:mm:ss.f");
			if (quoteTimesDifferMoreThanOneMicroSecond) {
				sb.Append(" :: " + quote.LocalTimeCreatedMillis.ToString("HH:mm:ss.fff"));
			}
			if (quote.HasParentBar) {
				TimeSpan timeLeft = (quote.ParentStreamingBar.DateTimeNextBarOpenUnconditional > quote.ServerTime)
					? quote.ParentStreamingBar.DateTimeNextBarOpenUnconditional.Subtract(quote.ServerTime)
					: quote.ServerTime.Subtract(quote.ParentStreamingBar.DateTimeNextBarOpenUnconditional);
				string format = ":ss";
				if (timeLeft.Minutes > 0) format = "mm:ss";
				if (timeLeft.Hours > 0) format = "HH:mm:ss";
				sb.Append(" " + new DateTime(timeLeft.Ticks).ToString(format));
			}
			this.btnStreaming.Text = sb.ToString();
		}
		public void PushQuoteToConsumers(Quote quote2bClonedForEachConsumer) {
			if (String.IsNullOrEmpty(quote2bClonedForEachConsumer.Symbol)) {
				Assembler.PopupException("quote.Symbol[" + quote2bClonedForEachConsumer.Symbol + "] is null or empty, returning");
				return;
			}
			if (quote2bClonedForEachConsumer.Symbol != this.Symbol) {
				Assembler.PopupException("quote.Symbol[" + quote2bClonedForEachConsumer.Symbol + "] != this.Symbol[" + this.Symbol + "], returning");
				return;
			}

			Quote quoteSernoEnrichedWithUnboundStreamingBar = StreamingBarFactoryUnattached.
				EnrichQuoteWithSernoUpdateStreamingBarCreateNewBar(quote2bClonedForEachConsumer);
			if (quoteSernoEnrichedWithUnboundStreamingBar.IntraBarSerno == 0) {
				if (StreamingBarFactoryUnattached.LastBarFormedUnattached != null
						//&& Double.IsNaN(StreamingBarFactoryUnattached.LastBarFormedUnattached.Close) == true
						&& StreamingBarFactoryUnattached.LastBarFormedUnattached.DateTimeOpen != DateTime.MinValue
					) {
					lock (lockConsumersBar) {
						//try {
						this.bindNewStreamingBarAppendPokeConsumersStaticFormed();
						//} catch (Exception e) {
						//	string msg = "is this why barsSimulated.Count=6 while barOriginal=31/50??";
						//	throw new Exception(msg);
						//}
					}
				} else {
					string msg = "I won't push LastStaticBar(DateTime.MinValue, NaN*5) on first quote2bClonedForEachConsumer[" + quote2bClonedForEachConsumer + "]"
						+ " because it has initialized LastStaticBar=StreamingBar.Clone()"
						+ " for " + StreamingBarFactoryUnattached;
					//Assembler.PopupException(msg);
				}
			}
			lock (lockConsumersQuote) {
				this.bindStreamingBarForQuoteAndPushQuoteToConsumers(quoteSernoEnrichedWithUnboundStreamingBar.Clone());
			}
		}
		public virtual void OnNewQuoteOfStreamingBarCallback(Quote quoteNewArrived) {
		}
 void IStreamingConsumer.ConsumeQuoteOfStreamingBar(Sq1.Core.DataTypes.Quote quote)
 {
 }
		public virtual Quote EnrichQuoteWithSernoUpdateStreamingBarCreateNewBar(Quote quoteClone) {
			if (quoteClone.PriceLastDeal == 0) {
				string msg = "quote.PriceLastDeal[" + quoteClone.PriceLastDeal + "] == 0;"
					+ "what kind of quote is that?... (" + quoteClone + ")";
				throw new Exception(msg);
				//return;
			}

			if (this.StreamingBarUnattached.Symbol != quoteClone.Symbol) {
				string msg = "StreamingBar.Symbol=[" + this.StreamingBarUnattached.Symbol + "]!=quote.Symbol["
					+ quoteClone.Symbol + "] (" + quoteClone + ")";
				throw new Exception(msg);
				//return;
			}

			// included in if (quoteClone.ServerTime >= StreamingBar.DateTimeNextBarOpenUnconditional) !!!
			// on very first quote StreamingBar.DateTimeNextBarOpenUnconditional = DateTime.MinValue
			//SEE_BELOW if (StreamingBar.DateTimeOpen == DateTime.MinValue)
			//SEE_BELOW 	this.initStreamingBarResetIntraBarSerno(quoteClone.ServerTime, quoteClone.PriceLastDeal, quoteClone.Size);
			//SEE_BELOW }

			if (quoteClone.ServerTime >= this.StreamingBarUnattached.DateTimeNextBarOpenUnconditional) {
				this.LastBarFormedUnattached = this.StreamingBarUnattached.Clone();	//beware! on very first quote LastBarFormed.DateTimeOpen == DateTime.MinValue
				this.initStreamingBarResetIntraBarSerno(quoteClone.ServerTime, quoteClone.PriceLastDeal, quoteClone.Size);

				// quoteClone.IntraBarSerno doesn't feel new Bar; can contain 100004 for generatedQuotes;
				// I only want to reset to 0 when it's attributed to a new Bar; it's unlikely to face a new bar here for generatedQuotes;
				if (this.IntraBarSerno != 0) {
					string msg = "STREAMING_JUST_INITED_TO_ZERO WHY_NOW_IT_IS_NOT?";
					Debugger.Break();
				}
				if (quoteClone.IntraBarSerno != 0) {
					if (quoteClone.IntraBarSerno >= Quote.IntraBarSernoShiftForGeneratedTowardsPendingFill) {
						string msg = "GENERATED_QUOTES_ARENT_SUPPOSED_TO_GO_TO_NEXT_BAR";
						Debugger.Break();
					}
					quoteClone.IntraBarSerno = this.IntraBarSerno;
				}
				if (this.IntraBarSerno >= Quote.IntraBarSernoShiftForGeneratedTowardsPendingFill) {
					string msg = "BAR_FACTORY_INTRABAR_SERNO_NEVER_GOES_TO_SYNTHETIC_ZONE";
					Debugger.Break();
				}
			} else {
				if (Double.IsNaN(this.StreamingBarUnattached.Open) || this.StreamingBarUnattached.Open == 0.0) {
					throw new Exception("nonsense! we should've had StreamingBar already initialized with first quote of a bar");
					//log.Warn("Initializing OHL as quote.PriceLastDeal[" + quoteClone.PriceLastDeal + "];"
					//	+ " following previous InitWithStreamingBarInsteadOfEmpty message"
					//	+ " (if absent then never initialized)");
					//StreamingBar.Open = quoteClone.PriceLastDeal;
					//StreamingBar.High = quoteClone.PriceLastDeal;
					//StreamingBar.Low = quoteClone.PriceLastDeal;
				}
				this.StreamingBarUnattached.MergeExpandHLCVforStreamingBarUnattached(quoteClone);
				this.IntraBarSerno++;
			}
			if (quoteClone.ParentStreamingBar != null) {
				string msg = "QUOTE_ALREADY_ENRICHED_WITH_PARENT_STREAMING_BAR; I think it's a pre- bindStreamingBarForQueue() atavism";
				//Assembler.PopupException(msg);
			} else {
				quoteClone.SetParentBar(this.StreamingBarUnattached);
			}
			return quoteClone;
		}
		public override void GenerateFillAskBasedOnBid(Quote quote, double bidPrice) {
			quote.Ask = bidPrice + this.constant;
			quote.Bid = bidPrice;
		}
		public Quote generateClosestQuoteForEachPendingAlertOnOurWayTo(Quote quoteToReach) {
			if (this.backtester.Executor.ExecutionDataSnapshot.AlertsPending.Count == 0) {
				string msg = "it looks like no Pending alerts are left anymore";
				return null;
			}

			Quote quotePrev = this.backtester.BacktestDataSource.BacktestStreamingProvider.StreamingDataSnapshot
				.LastQuoteGetForSymbol(quoteToReach.Symbol);

			// assuming both quotes generated using same SpreadModeler and their spreads are equal
			//v1 if (quoteToReach.Bid == quotePrev.Bid || quoteToReach.Ask == quotePrev.Ask) {
			if (quoteToReach.SameBidAsk(quotePrev)) {
				string msg = "WE_REACHED_QUOTE_TO_REACH_SAME_BIDASK_NOTHING_ELSE_TO_GENERATE";
				return null;
			}
			if (quotePrev.ServerTime >= quoteToReach.ServerTime) {
				string msg = "WE_REACHED_QUOTE_TO_REACH_SAME_SERVERTIME_NOTHING_ELSE_TO_GENERATE";
				return null;
			}

			bool scanningDown = quoteToReach.Bid < quotePrev.Bid;
			Quote quoteClosest = null;

			List<Alert> alertsPendingSafeCopy = new List<Alert>(this.backtester.Executor.ExecutionDataSnapshot.AlertsPending);
			foreach (Alert alert in alertsPendingSafeCopy) {
				// DONT_EXPECT_THEM_TO_BE_FILLED_YOU_SHOULD_FILL_ALL_RELEVANT_NOW
				//if (scanningDown) {
				//    // while GEN'ing down, all BUY/COVER STOPs pending were already triggered & executed
				//    bool executedAtAsk = alert.Direction == Direction.Buy || alert.Direction == Direction.Cover;
				//    if (executedAtAsk && alert.MarketLimitStop == MarketLimitStop.Stop) continue;
				//} else {
				//    // while GEN'ing up, all SHORT/SELL STOPs pending were already triggered & executed
				//    bool executedAtBid = alert.Direction == Direction.Short || alert.Direction == Direction.Sell;
				//    if (executedAtBid && alert.MarketLimitStop == MarketLimitStop.Stop) continue;
				//}
				Quote quoteThatWillFillAlert = this.modelQuoteThatCouldFillAlert(alert);
				if (quoteThatWillFillAlert == null) continue;

				if (scanningDown) {
					if (quoteThatWillFillAlert.Bid > quotePrev.Bid) {
						string msg = "IGNORING_QUOTE_HIGHER_THAN_PREVIOUS_WHILE_SCANNING_DOWN";
						continue;
					}
					if (quoteThatWillFillAlert.Bid < quoteToReach.Bid) {
						string msg = "IGNORING_QUOTE_LOWER_THAN_TARGET_WHILE_SCANNING_DOWN";
						continue;
					}
				} else {
					if (quoteThatWillFillAlert.Ask < quotePrev.Ask) {
						string msg = "IGNORING_QUOTE_LOWER_THAN_PREVIOUS_WHILE_SCANNING_UP";
						continue;
					}
					if (quoteThatWillFillAlert.Ask > quoteToReach.Ask) {
						string msg = "IGNORING_QUOTE_HIGHER_THAN_TARGET_WHILE_SCANNING_UP";
						continue;
					}
				}

				if (quoteClosest == null) {
					quoteClosest = quoteThatWillFillAlert;
				} else {
					if (scanningDown) {
						// while GEN'ing closest to the top, pick the highest possible
						// while scanning down, I'm looking for the quote with highest Ask that will trigger the closest pending
						if (quoteThatWillFillAlert.Bid < quoteClosest.Bid) continue;
						quoteClosest = quoteThatWillFillAlert;
					} else {
						// while GEN'ing closest to the bottom, pick the lowest possible
						if (quoteThatWillFillAlert.Ask > quoteClosest.Ask) continue;
						quoteClosest = quoteThatWillFillAlert;
					}
				}
			}

			if (quoteClosest == null) return quoteClosest;

			if (scanningDown) {
				if (quoteClosest.Bid > quotePrev.Bid) {
					string msg = "WHILE_SCANNING_DOWN_RETURNING_QUOTE_HIGHER_THAN_PREVIOUS_IS_WRONG";
				}
				if (quoteClosest.Bid < quoteToReach.Bid) {
					string msg = "WHILE_SCANNING_DOWN_RETURNING_QUOTE_LOWER_THAN_TARGET_IS_WRONG";
				}
			} else {
				if (quoteClosest.Ask < quotePrev.Ask) {
					string msg = "WHILE_SCANNING_UP_RETURNING_QUOTE_LOWER_THAN_PREVIOUS_IS_WRONG";
				}
				if (quoteClosest.Ask > quoteToReach.Ask) {
					string msg = "WHILE_SCANNING_UP_RETURNING_QUOTE_HIGHER_THAN_TARGET_IS_WRONG";
				}
			}

			//if (quotePrev.ParentStreamingBar.ParentBarsIndex == 185) {
			if (this.backtester.Executor.Bars.Count == 185) {
				//Debugger.Break();
				int q = 1;
			}

			//I_WILL_SPOIL_STREAMING_BAR_IF_I_ATTACH_LIKE_THIS Quote quoteNextAttached = this.backtester.BacktestDataSource.BacktestStreamingProvider.(quoteToReach.Clone());
			Quote ret = quotePrev.DeriveIdenticalButFresh();
			ret.Bid = quoteClosest.Bid;
			ret.Ask = quoteClosest.Ask;
			ret.Size = quoteClosest.Size;
			ret.Source = quoteClosest.Source;
			return ret;
		}
		public bool CheckEntryAlertWillBeFilledByQuote(Alert entryAlert, Quote quote, out double entryPriceOut, out double entrySlippageOutNotUsed) {
			// if entry is triggered, call position.EnterFinalize(entryPrice, entrySlippage, entryCommission);
			entryPriceOut = this.executor.AlignAlertPriceToPriceLevel(entryAlert.Bars, entryAlert.PriceScript, true,
				entryAlert.PositionLongShortFromDirection, entryAlert.MarketLimitStop);
			entrySlippageOutNotUsed = 0;

			//Direction directionPositionClose = MarketConverter.ExitDirectionFromLongShort(alert.PositionLongShortFromDirection);
			//double slippageLimit = this.executor.getSlippage(
			//	alert.PriceScript, alert.Direction, 0, this.executor.IsStreaming, true);
			//double slippageNonLimit = this.executor.getSlippage(
			//	alert.PriceScript, alert.Direction, 0, this.executor.IsStreaming, false);
			//double slippageMarketForClosingPosition = this.executor.getSlippage(
			//	alert.PriceScript, directionPositionClose, 0, this.executor.IsStreaming, false);

			int barIndexTested = entryAlert.Bars.Count - 1;
			switch (entryAlert.MarketLimitStop) {
				case MarketLimitStop.Limit:
					switch (entryAlert.Direction) {
						case Direction.Buy:
							//dont check if (slippage >= 0) throw new Exception("BuyAtLimit: slippage[" + slippage + "] should be negative -");
							//if (priceScriptAligned + slippageLimit < quoteToReach.Bid) return false;
							if (entryPriceOut < quote.Bid) return false;
							break;
						case Direction.Short:
							//dont check if (slippage <= 0) throw new Exception("ShortAtLimit: slippage[" + slippage + "] should be positive +");
							//if (priceScriptAligned + slippageLimit > quoteToReach.Ask) return false;
							if (entryPriceOut > quote.Ask) return false;
							break;
						default:
							throw new Exception("NYI: direction[" + entryAlert.Direction + "] is not Long or Short");
					}
					break;
				case MarketLimitStop.Stop:
					switch (entryAlert.Direction) {
						case Direction.Buy:
							if (entryPriceOut > quote.Ask) return false;
							//entrySlippageOutNotUsed = slippageNonLimit;
							//priceScriptAligned += entrySlippageOutNotUsed;
							break;
						case Direction.Short:
							if (entryPriceOut < quote.Bid) return false;
							//entrySlippageOutNotUsed = -slippageNonLimit;
							//priceScriptAligned += entrySlippageOutNotUsed;
							break;
						default:
							throw new Exception("NYI: direction[" + entryAlert.Direction + "] is not Long or Short");
					}
					entryPriceOut = this.executor.AlignAlertPriceToPriceLevel(entryAlert.Bars, entryPriceOut, true,
						entryAlert.PositionLongShortFromDirection, entryAlert.MarketLimitStop);
					break;
				case MarketLimitStop.Market:
				case MarketLimitStop.AtClose:
					switch (entryAlert.Direction) {
						case Direction.Buy:
							if (entryPriceOut > quote.Ask) {
								entryPriceOut = quote.Ask;
								string msg = "BuyAtMarket/BuyAtClose(bar[" + barIndexTested
									+ "], signalName[" + entryAlert.PositionAffected.EntrySignal + "]) "
									+ "entryPrice[" + entryPriceOut + "] > := quoteToReach.Ask["
									+ barIndexTested + "]=[" + quote.Ask + "]"
									+ " while basisPrice=[" + entryAlert.PositionAffected.LastQuoteForMarketOrStopLimitImplicitPrice + "]";
							}
							//entrySlippageOutNotUsed = slippageNonLimit;
							//priceScriptAligned += entrySlippageOutNotUsed;
							break;
						case Direction.Short:
							if (entryAlert.PriceScript < quote.Bid) {
								entryPriceOut = quote.Bid;
								string msg = "ShortAtMarket/ShortAtClose(bar[" + barIndexTested
									+ "], signalName[" + entryAlert.PositionAffected.EntrySignal + "]) "
									+ "entryPrice[" + entryPriceOut + "] < := quoteToReach.Bid["
									+ barIndexTested + "]=[" + quote.Bid + "]"
									+ " while basisPrice=[" + entryAlert.PositionAffected.LastQuoteForMarketOrStopLimitImplicitPrice + "]";
							}
							//entrySlippageOutNotUsed = -slippageNonLimit;
							//priceScriptAligned += entrySlippageOutNotUsed;
							break;
						default:
							throw new Exception("CheckEntry() NYI direction[" + entryAlert.Direction + "] for [" + entryAlert + "]");
					}
					break;
				default:
					throw new Exception("NYI: marketLimitStop[" + entryAlert.MarketLimitStop + "] is not Limit or Stop");
			}
			entryPriceOut = this.executor.AlignAlertPriceToPriceLevel(entryAlert.Bars, entryPriceOut, true,
				entryAlert.PositionLongShortFromDirection, entryAlert.MarketLimitStop);
			if (entryPriceOut <= 0) {
				string msg = "entryPrice[" + entryPriceOut + "]<=0 what do you mean??? get Bars.LastBar.Close for Market...";
				throw new Exception(msg);
			}
			// v1 BarStreaming with 1 quoteToReach (=> 0px height) won't contain any price you may check here;
			// v1 REMOVED because MarketLimitStop.Market haven't been filled immediately and behaved like stop/limit entries/exits;
			// v1 for Stop/Limit you already hit "return false" above; market should get whatever crazy bid/ask and get the fill at first attempt now
			//if (alert.Bars.BarStreaming.ContainsPrice(priceScriptAligned) == false) {		// earlier version of same checkup as Position.FillEntryWith() 
			//    string msg = "QUOTE_UNFILLABLE_ON_BAR_STREAMING quoteToReach[" + quoteToReach + "] => priceScriptAligned["
			//        + priceScriptAligned + "] at alert.Bars.BarStreaming[" + alert.Bars.BarStreaming + "]";
			//    //throw new Exception(msg);
			//    return false;
			//}
			// /v1
			return true;
		}
		public ReporterPokeUnit ExecuteOnNewBarOrNewQuote(Quote quote) {
			if (this.Strategy.Script == null) return null;
			ReporterPokeUnit pokeUnit = new ReporterPokeUnit(quote);
			this.ExecutionDataSnapshot.PreExecutionClear();
			int alertsDumpedForStreamingBar = -1;

			if (quote != null) {
				try {
					this.Strategy.Script.OnNewQuoteOfStreamingBarCallback(quote);
					//alertsDumpedForStreamingBar = this.ExecutionDataSnapshot.DumpPendingAlertsIntoPendingHistoryByBar();
					//if (alertsDumpedForStreamingBar > 0) {
					//	string msg = "ITS OK HERE since prev quote has created prototype-based alerts"
					//		+ "I WANT DUMP TO BE VALID ONLY IN onNewBar case only!!!"
					//		+ " " + alertsDumpedForStreamingBar + " alerts Dumped for " + quote;
					//}
				} catch (Exception ex) {
					string msig = " Script[" + this.Strategy.Script.GetType().Name + "].OnNewQuoteCallback(" + quote + "): ";
					this.PopupException(ex.Message + msig, ex);
				}
			} else {
				try {
					this.Strategy.Script.OnBarStaticLastFormedWhileStreamingBarWithOneQuoteAlreadyAppendedCallback(this.Bars.BarStaticLast);
				} catch (Exception ex) {
					string msig = " Script[" + this.Strategy.Script.GetType().Name + "].OnNewBarCallback(" + quote + "): ";
					this.PopupException(ex.Message + msig, ex);
				}
			}
			string msg = "DONT_REMOVE_ALERT_SHOULD_LEAVE_ITS_TRAIL_DURING_LIFETIME_TO_PUT_UNFILLED_DOTS_ON_CHART";
			alertsDumpedForStreamingBar = this.ExecutionDataSnapshot.DumpPendingAlertsIntoPendingHistoryByBar();
			if (alertsDumpedForStreamingBar > 0) {
				msg += " DUMPED_AFTER_SCRIPT_EXECUTION_ON_NEW_BAR_OR_QUOTE";
			}


			// what's updated after Exec: non-volatile, kept un-reset until executor.Initialize():
			//this.ExecutionDataSnapshot.PositionsMasterByEntryBar (unique)
			//this.ExecutionDataSnapshot.PositionsMaster
			//this.PositionsOnlyActive
			//this.AlertsMaster
			//this.AlertsNewAfterExec

			// what's new for this iteration: volatile, cleared before next Exec):
			//this.AlertsNewAfterExec
			//this.ExecutionDataSnapshot.PositionsOpenedAfterExec
			//this.ExecutionDataSnapshot.PositionsClosedAfterExec

			bool willPlace = this.Backtester.IsBacktestingNow == false && this.OrderProcessor != null && this.IsAutoSubmitting;
			bool setStatusSubmitting = this.IsStreaming && this.IsAutoSubmitting;

			List<Alert> alertsNewAfterExecCopy = this.ExecutionDataSnapshot.AlertsNewAfterExecSafeCopy;
			if (alertsNewAfterExecCopy.Count > 0) {
				this.enrichAlertsWithQuoteCreated(alertsNewAfterExecCopy, quote);
				if (willPlace) {
					this.OrderProcessor.CreateOrdersSubmitToBrokerProviderInNewThreadGroups(alertsNewAfterExecCopy, setStatusSubmitting, true);
				}
			}

			if (this.Backtester.IsBacktestingNow && this.Backtester.WasBacktestAborted) return null;

			pokeUnit.AlertsNew = alertsNewAfterExecCopy;
			pokeUnit.PositionsOpened = this.ExecutionDataSnapshot.PositionsOpenedAfterExecSafeCopy;
			pokeUnit.PositionsClosed = this.ExecutionDataSnapshot.PositionsClosedAfterExecSafeCopy;
			return pokeUnit;
		}
		void enrichAlertsWithQuoteCreated(List<Alert> alertsAfterStrategy, Quote quote) {
			if (quote == null) return;
			foreach (Alert alert in alertsAfterStrategy) {
				if (alert.PlacedBarIndex != this.Bars.Count - 1) {
					string msg = "skipping enriching: alertsNewAfterExec should contain only lastBar alerts"
						+ "; got alertAfterStrategy.BarRelnoPlaced[" + alert.PlacedBarIndex + "]"
						+ "!= this.Bars.Count[" + this.Bars.Count + "] for alert[" + alert + "]";
					this.PopupException(msg);
					continue;
				}
				//log.Debug("quote!=null => setting for TradeHistory:" +
				//	" 1) alert.BrokerQuoteDateTime=quote.ServerTime[" + quote.ServerTime + "]" +
				//	" 2) alert.PriceDeposited=[" + priceDeposited + "] quote.DepositBuy[" + quote.FortsDepositBuy + "] quote.DepositSell[" + quote.FortsDepositSell + "] ");
				//if (alertAfterStrategy.DataRange == null) alertAfterStrategy.DataRange = this.BarDataRange;
				//alertAfterStrategy.PositionSize = this.PositionSize;
				alert.QuoteCreatedThisAlertServerTime = quote.ServerTime;
				alert.QuoteCreatedThisAlert = quote;
			}
		}
		public override void GenerateFillBidAskSymmetrically(Quote quote, double medianPrice) {
			if (quote == null) return;
			quote.Ask = medianPrice + this.constant / 2;
			quote.Bid = medianPrice - this.constant / 2;
		}
		public override void GenerateFillBidBasedOnAsk(Quote quote, double askPrice) {
			quote.Ask = askPrice;
			quote.Bid = askPrice - this.constant;
		}
		public void ConsumeQuoteOfStreamingBar(Quote quote) {
			this.msigForNpExceptions = "ConsumeFreshQuote(): ";
			var barsSafe = this.Bars;
			var streamingSafe = this.StreamingProvider;
			var chartFormSafe = this.ChartForm;
			var executorSafe = this.Executor;
			//var rendererSafe = this.Renderer;

			try {
				streamingSafe.InitializeStreamingOHLCVfromStreamingProvider(ConsumerBarsToAppendInto);
			} catch (Exception e) {
				Assembler.PopupException("didn't merge with Partial, continuing", e);
			}

			//this.ChartForm.Chart.UpdatePartialAndHorizontalScrollMaximum(qd.BarFactory.CurrentBar);
			if (quote.ParentStreamingBar.ParentBarsIndex > quote.ParentStreamingBar.ParentBars.Count) {
				string msg = "should I add a bar into Chart.Bars?... NO !!! already added";
			}
			//if (this.NewQuote != null) this.NewQuote(this, new QuoteEventArgs(quote));
			//this.chartFormsManager.Executor.onNewQuoteEnqueueExecuteStrategyInNewThread(this, new QuoteEventArgs(quote));
			
			// launch update in GUI thread
			chartFormSafe.PrintQuoteTimestampsOnStreamingButtonBeforeExecution(quote);
			// execute strategy in the thread of a StreamingProvider (DDE server for MockQuickProvider)
			executorSafe.ExecuteOnNewBarOrNewQuote(quote);
			// trigger GUI to repaint the chart with new positions and bid/ask lines
			chartFormSafe.ChartControl.InvalidateAllPanelsFolding();
			//rendererSafe.DrawBidAskLines = true;
		}
		public override void OnNewQuoteOfStreamingBarCallback(Quote quoteNewArrived) {
			this.placePrototypeOncePositionClosed(quoteNewArrived.ParentStreamingBar);
		}
		public abstract void GenerateFillBidAskSymmetrically(Quote quote, double medianPrice);
		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;
		}
		public abstract void GenerateFillAskBasedOnBid(Quote quote, double bidPrice);
		public abstract void GenerateFillBidBasedOnAsk(Quote quote, double askPrice);
		public void GenerateFillBidAskSymmetricallyFromLastPrice(Quote quote) {
			if (quote == null) return;
			this.GenerateFillBidAskSymmetrically(quote, quote.PriceLastDeal);
		}
		public DateTime getThisDayClose(Quote quote) {
			return new DateTime(quote.ServerTime.Date.Year, quote.ServerTime.Date.Month, quote.ServerTime.Date.Day,
				this.MarketCloseServerTime.Hour, this.MarketCloseServerTime.Minute, this.MarketCloseServerTime.Second);
		}
		public void CallbackAlertFilledMoveAroundInvokeScript(Alert alertFilled, Quote quote,
					 int barFillRelno, double priceFill, double qtyFill, double slippageFill, double commissionFill) {
			string msig = " CallbackAlertFilledMoveAroundInvokeScript(" + alertFilled + ", " + quote + ")";
			List<Alert> alertsNewAfterAlertFilled = new List<Alert>();
			List<Position> positionsOpenedAfterAlertFilled = new List<Position>();
			List<Position> positionsClosedAfterAlertFilled = new List<Position>();

			//"Excuse me, what bar is it now?" I'm just guessing! does BrokerProvider knows to pass Bar here?...
			Bar barFill = (this.IsStreaming) ? alertFilled.Bars.BarStreamingCloneReadonly : alertFilled.Bars.BarStaticLast;
			if (barFillRelno != barFill.ParentBarsIndex) {
				string msg = "barFillRelno[" + barFillRelno + "] != barFill.ParentBarsIndex["
					+ barFill.ParentBarsIndex + "]; barFill=[" + barFill + "]";
				Assembler.PopupException(msg);
			}
			if (priceFill == -1) {
				string msg = "won't set priceFill=-1 for alert [" + alertFilled + "]";
				throw new Exception(msg);
			}
			if (alertFilled.PositionAffected == null) {
				string msg = "CallbackAlertFilled can't do its job: alert.PositionAffected=null for alert [" + alertFilled + "]";
				throw new Exception(msg);
			}
			if (alertFilled.IsEntryAlert) {
				if (alertFilled.PositionAffected.EntryFilledBarIndex != -1) {
					string msg = "DUPE: CallbackAlertFilled can't do its job: alert.PositionAffected.EntryBar!=-1 for alert [" + alertFilled + "]";
					throw new Exception(msg);
				} else {
					string msg = "initializing EntryBar=[" + barFill + "] on AlertFilled";
				}
			} else {
				if (alertFilled.PositionAffected.ExitFilledBarIndex != -1) {
					string msg = "DUPE: CallbackAlertFilled can't do its job: alert.PositionAffected.ExitBar!=-1 for alert [" + alertFilled + "]";
					throw new Exception(msg);
					return;
				} else {
					string msg = "initializing ExitBar=[" + barFill + "] on AlertFilled";
				}
			}

			if (quote == null) {
				quote = this.DataSource.StreamingProvider.StreamingDataSnapshot.LastQuoteGetForSymbol(alertFilled.Symbol);
				// TODO: here quote will have NO_PARENT_BARS, since StreamingDataSnapshot contains anonymous quote;
				// I should keep per-timeframe / per-distributionChannel LastQuote to have ParentBar= different StreamingBar 's
				// bindStreamingBarForQuoteAndPushQuoteToConsumers(quoteSernoEnrichedWithUnboundStreamingBar.Clone());
			}
			alertFilled.QuoteLastWhenThisAlertFilled = quote;
			try {
				alertFilled.FillPositionAffectedEntryOrExitRespectively(barFill, barFillRelno, priceFill, qtyFill, slippageFill, commissionFill);
			} catch (Exception ex) {
				string msg = "REMOVE_FILLED_FROM_PENDING? DONT_USE_Bar.ContainsPrice()?";
				Assembler.PopupException(msg + msig, ex);
				//Debugger.Break();
			}
			bool removed = this.ExecutionDataSnapshot.AlertsPendingRemove(alertFilled);
			if (removed == false) {
				Debugger.Break();
			}
			if (alertFilled.IsEntryAlert) {
				// position has its parent alert in Position.ctor()
				//// REFACTORED_POSITION_HAS_AN_ALERT_AFTER_ALERTS_CONSTRUCTOR
				//alert.PositionAffected.EntryCopyFromAlert(alert);
				this.ExecutionDataSnapshot.PositionsMasterOpenNewAdd(alertFilled.PositionAffected);
				positionsOpenedAfterAlertFilled.Add(alertFilled.PositionAffected);
			} else {
				//// REFACTORED_POSITION_HAS_AN_ALERT_AFTER_ALERTS_CONSTRUCTOR we can exit by TP or SL - position doesn't have an ExitAlert assigned until Alert was filled!!!
				//alertFilled.PositionAffected.ExitAlertAttach(alertFilled);
				this.ExecutionDataSnapshot.MovePositionOpenToClosed(alertFilled.PositionAffected);
				positionsClosedAfterAlertFilled.Add(alertFilled.PositionAffected);
			}

			bool willPlace = this.Backtester.IsBacktestingNow == false && this.OrderProcessor != null && this.IsAutoSubmitting;
			bool setStatusSubmitting = this.IsStreaming && this.IsAutoSubmitting;

			PositionPrototype proto = alertFilled.PositionAffected.Prototype;
			if (proto != null) {
				// 0. once again, set ExitAlert to What was actually filled, because prototypeEntry created SL & TP, which were both written into ExitAlert;
				// so if we caught the Loss and SL was executed, position.ExitAlert will still contain TP if we don't set it here
				bool exitIsDifferent = alertFilled.PositionAffected.ExitAlert != null && alertFilled.PositionAffected.ExitAlert != alertFilled;
				if (alertFilled.IsExitAlert && exitIsDifferent) {
					alertFilled.PositionAffected.ExitAlertAttach(alertFilled);
				}
				// 1. alert.PositionAffected.Prototype.StopLossAlertForAnnihilation and TP will get assigned
				alertsNewAfterAlertFilled = this.PositionPrototypeActivator.AlertFilledCreateSlTpOrAnnihilateCounterparty(alertFilled);
				// quick check: there must be {SL+TP} OR Annihilator
				//this.BacktesterFacade.IsBacktestingNow == false &&
				if (alertFilled.IsEntryAlert) {
					if (proto.StopLossAlertForAnnihilation == null) {
						string msg = "NONSENSE@Entry: proto.StopLossAlert is NULL???..";
						throw new Exception(msg);
					}
					if (proto.TakeProfitAlertForAnnihilation == null) {
						string msg = "NONSENSE@Entry: proto.TakeProfitAlert is NULL???..";
						throw new Exception(msg);
					}
					if (alertsNewAfterAlertFilled.Count == 0) {
						string msg = "NONSENSE@Entry: alertsNewSlAndTp.Count=0"
							+ "; this.PositionPrototypeActivator.AlertFilledCreateSlTpOrAnnihilateCounterparty(alertFilled)"
							+ " should return 2 alerts; I don't want to create new list from {proto.SL, proto.TP}";
						throw new Exception(msg);
					}
				}
				if (alertFilled.IsExitAlert) {
					if (alertsNewAfterAlertFilled.Count > 0) {
						string msg = "NONSENSE@Exit: there must be no alerts (got " + alertsNewAfterAlertFilled.Count + "): killer works silently";
						throw new Exception(msg);
					}
				}

				if (alertsNewAfterAlertFilled.Count > 0 && willPlace) {
					this.OrderProcessor.CreateOrdersSubmitToBrokerProviderInNewThreadGroups(alertsNewAfterAlertFilled, setStatusSubmitting, true);

					// 3. Script using proto might move SL and TP which require ORDERS to be moved, not NULLs
					int twoMinutes = 120000;
					if (alertFilled.IsEntryAlert) {
						// there must be SL.OrderFollowed!=null and TP.OrderFollowed!=null
						if (proto.StopLossAlertForAnnihilation.OrderFollowed == null) {
							string msg = "StopLossAlert.OrderFollowed is NULL!!! engaging ManualResetEvent.WaitOne()";
							this.PopupException(msg);
							Stopwatch waitedForStopLossOrder = new Stopwatch();
							waitedForStopLossOrder.Start();
							proto.StopLossAlertForAnnihilation.MreOrderFollowedIsNotNull.WaitOne(twoMinutes);
							waitedForStopLossOrder.Stop();
							msg = "waited " + waitedForStopLossOrder.ElapsedMilliseconds + "ms for StopLossAlert.OrderFollowed";
							if (proto.StopLossAlertForAnnihilation.OrderFollowed == null) {
								msg += ": NO_SUCCESS still null!!!";
								this.PopupException(msg);
							} else {
								proto.StopLossAlertForAnnihilation.OrderFollowed.AppendMessage(msg);
								this.PopupException(msg);
							}
						} else {
							string msg = "you are definitely crazy, StopLossAlert.OrderFollowed is a single-threaded assignment";
							//this.ThrowPopup(new Exception(msg));
						}

						if (proto.TakeProfitAlertForAnnihilation.OrderFollowed == null) {
							string msg = "TakeProfitAlert.OrderFollowed is NULL!!! engaging ManualResetEvent.WaitOne()";
							this.PopupException(msg);
							Stopwatch waitedForTakeProfitOrder = new Stopwatch();
							waitedForTakeProfitOrder.Start();
							proto.TakeProfitAlertForAnnihilation.MreOrderFollowedIsNotNull.WaitOne();
							waitedForTakeProfitOrder.Stop();
							msg = "waited " + waitedForTakeProfitOrder.ElapsedMilliseconds + "ms for TakeProfitAlert.OrderFollowed";
							if (proto.TakeProfitAlertForAnnihilation.OrderFollowed == null) {
								msg += ": NO_SUCCESS still null!!!";
								this.PopupException(msg);
							} else {
								proto.TakeProfitAlertForAnnihilation.OrderFollowed.AppendMessage(msg);
								this.PopupException(msg);
							}
						} else {
							string msg = "you are definitely crazy, TakeProfitAlert.OrderFollowed is a single-threaded assignment";
							//this.ThrowPopup(new Exception(msg));
						}
					}
				}
			}

			if (this.Backtester.IsBacktestingNow == false) {
				ReporterPokeUnit pokeUnit = new ReporterPokeUnit(quote);
				pokeUnit.AlertsNew = alertsNewAfterAlertFilled;
				pokeUnit.PositionsOpened = positionsOpenedAfterAlertFilled;
				pokeUnit.PositionsClosed = positionsClosedAfterAlertFilled;
				this.PushPositionsOpenedClosedToReportersAsyncUnsafe(pokeUnit);
			}

			// 4. Script event will generate a StopLossMove PostponedHook
			this.invokeScriptEvents(alertFilled);

			// reasons for (alertsNewAfterExec.Count > 0) include:
			// 2.1. PrototypeActivator::AlertFilledPlaceSlTpOrAnnihilateCounterparty
			// 2.2. Script.OnAlertFilledCallback(alert)
			// 2.3. Script.OnPositionOpenedPrototypeSlTpPlacedCallback(alert.PositionAffected)
			// 2.4. Script.OnPositionClosedCallback(alert.PositionAffected)
		}