public Alert ExitAlertCreate(Bar exitBar, Position position, double stopOrLimitPrice, string signalName,
			Direction direction, MarketLimitStop exitMarketLimitStop) {

			this.checkThrowEntryBarIsValid(exitBar);
			this.checkThrowPositionToCloseIsValid(position);

			double priceScriptOrStreaming = stopOrLimitPrice;
			OrderSpreadSide orderSpreadSide = OrderSpreadSide.Unknown;
			if (exitMarketLimitStop == MarketLimitStop.Market) {
				priceScriptOrStreaming = this.getStreamingPriceForMarketOrder(exitMarketLimitStop, direction, out orderSpreadSide);
			}

			PositionLongShort longShortFromDirection = MarketConverter.LongShortFromDirection(direction);
			double exitPriceScript = exitBar.ParentBars.SymbolInfo.RoundAlertPriceToPriceLevel(
				priceScriptOrStreaming, true, longShortFromDirection, exitMarketLimitStop);

			Alert alert = new Alert(exitBar, position.Shares, exitPriceScript, signalName,
				direction, exitMarketLimitStop, orderSpreadSide,
				//this.executor.Script,
				this.executor.Strategy);
			alert.AbsorbFromExecutor(executor);
			alert.PositionAffected = position;
			// moved to CallbackAlertFilled - we can exit by TP or SL - and position has no clue which Alert was filled!!!
			//position.ExitCopyFromAlert(alert);
			alert.PositionAffected.ExitAlertAttach(alert);

			return alert;
		}
		public Alert EntryAlertCreate(Bar entryBar, double stopOrLimitPrice, string entrySignalName,
			Direction direction, MarketLimitStop entryMarketLimitStop) {

			this.checkThrowEntryBarIsValid(entryBar);

			double priceScriptOrStreaming = stopOrLimitPrice;
			OrderSpreadSide orderSpreadSide = OrderSpreadSide.Unknown;
			if (entryMarketLimitStop == MarketLimitStop.Market) {
				priceScriptOrStreaming = this.getStreamingPriceForMarketOrder(entryMarketLimitStop, direction, out orderSpreadSide);
			}

			PositionLongShort longShortFromDirection = MarketConverter.LongShortFromDirection(direction);
			// ALREADY_ALIGNED_AFTER GetAlignedBidOrAskForTidalOrCrossMarketFromStreaming
			double entryPriceScript = entryBar.ParentBars.SymbolInfo.RoundAlertPriceToPriceLevel(
				priceScriptOrStreaming, true, longShortFromDirection, entryMarketLimitStop);

			double shares = this.executor.PositionSizeCalculate(entryBar, entryPriceScript);

			Alert alert = new Alert(entryBar, shares, entryPriceScript, entrySignalName,
				direction, entryMarketLimitStop, orderSpreadSide,
				//this.executor.Script,
				this.executor.Strategy);
			alert.AbsorbFromExecutor(executor);

			return alert;
		}
		public Alert ExitAlertCreate(Bar exitBar, Position position, double stopOrLimitPrice, string signalName,
				Direction direction, MarketLimitStop exitMarketLimitStop) {
			if (position == null) {
				string msg = "do not SellOrCover(position = null) please";
				throw new Exception(msg);
				return null;
			}
			if (position.NoExitBarOrStreaming == false) return null;

			//Bars bars = position.Bars;
			// backtest substitutes StrategyExecutor.Bars, so exit(bar+1) should point on StreamingBar, not backtested!
			//Bars backtestingOrStreamingBars = this.executor.Bars;

			Direction posDirection = MarketConverter.ExitDirectionFromLongShort(position.PositionLongShort);
			if (posDirection != direction) {
				string msg = "here is the case when you Sell a Short once again or Cover a Long, what's the matter with you?";
				throw new Exception(msg);
			}

			PositionLongShort positionDirection = PositionLongShort.Long;
			switch (direction) {
				case Direction.Sell:
					positionDirection = PositionLongShort.Long;
					break;
				case Direction.Cover:
					positionDirection = PositionLongShort.Short;
					break;
				default:
					throw new Exception("NYI direction[" + direction + "]");
			}
			if (positionDirection != position.PositionLongShort) {
				string msg = "pass positionDirection to AlignAlertPriceToPriceLevel!!! you should close with an opposite alignment";
				throw new Exception(msg);
			}

			double exitPriceScript = stopOrLimitPrice;

			int barSmallestAllowed = 0;
			OrderSpreadSide orderSpreadSide = OrderSpreadSide.Unknown;
			switch (exitMarketLimitStop) {
				case MarketLimitStop.Market:
					//if (exitBar >= this.executor.Bars.Count) {	//bar+1
					if (exitBar.IsBarStreaming) {	//bar+1
						if (this.executor.IsStreaming) {
							//basisPrice = 0;
							this.executor.DataSource.StreamingProvider.StreamingDataSnapshot.GetAlignedBidOrAskForTidalOrCrossMarketFromStreaming(
								this.executor.Bars.Symbol, posDirection, out exitPriceScript, out orderSpreadSide, false);
						} else {
							//basisPrice = this.executor.Bars[bar].Open;
							//basisPrice = this.executor.Bars.LastBar.Close;
							//if (bar > this.executor.Bars.Count) { //bar+2
//							exitPriceScript = this.executor.Bars[exitBar - 1].Close;
//							string msg = "[" + direction + "]At[" + exitMarketLimitStop + "](bar=[" + exitBar + "])"
//								+ " when LastBar[" + (this.executor.Bars.Count - 1) + "]; No way I can bring you"
//								+ " price from the future, even by executing your order right now"
//								+ "; can't do inequivalent repacement to LastBar.Open";
//							log.Fatal(msg, new Exception(msg));
							string msg = "[" + direction + "]At[" + exitMarketLimitStop + "](bar=[" + exitBar + "])";
							throw new Exception("UNABLE_TO_REFACTOR#2 " + msg);
							//}
						}
					} else {
						//exitPriceScript = this.executor.Bars[exitBar].Open;
						exitPriceScript = exitBar.Open;
					}
					barSmallestAllowed = 1;
					break;
				case MarketLimitStop.AtClose:
					//if (exitBar >= this.executor.Bars.Count) { //bar+1
					if (exitBar.IsBarStreaming) { //bar+1
						exitPriceScript = 0;
						string msg = "[" + direction + "]At[" + exitMarketLimitStop + "](bar=[" + exitBar + "])"
							+ " when LastBar[" + this.executor.Bars.BarStaticLast + "]; No way I can bring you price from the future,"
							+ " even by executing your order right now"
							+ "; can't do inequivalent repacement to LastBar.Close";
						log.Fatal(msg, new Exception(msg));
					} else {
						//exitPriceScript = this.executor.Bars[exitBar].Close;
						exitPriceScript = exitBar.Close;
					}
					barSmallestAllowed = 0;
					break;
				case MarketLimitStop.Stop:
					break;
				case MarketLimitStop.Limit:
					break;
				case MarketLimitStop.StopLimit:
					break;
				default:
					throw new Exception("no handler for exitMarketLimitStop.[" + exitMarketLimitStop + "]");
			}
			//BAR_NOT_NULL_CHECKED_UPSTACK_IN_ScriptExecutor.SellOrCoverAlertCreateRegister() this.executor._throwWhenBarOutsideInterval(exitBar, barSmallestAllowed, this.executor.Bars.Count, this.executor.Bars);
			//if (exitBar < this.executor.Bars.Count) {
			if (exitBar.IsBarStreaming == false) {
				this.basisPriceZeroCheckThrow(exitPriceScript);
			}

			//if (position == Position.AllPositions) {
			//	bool result = false;
			//	int num = this.executor.ExecutionDataSnapshot.PositionsOpenNow.Count;
			//	for (int i = this.executor.ExecutionDataSnapshot.PositionsMaster.Count - 1; i >= 0; i--) {
			//		if (num == 0) return result;
			//		bool soldOrCovered = SellOrCover(exitBar, this.executor.ExecutionDataSnapshot.PositionsMaster[i],
			//			stopOrLimitPrice, signalName, direction, exitMarketLimitStop);
			//		if (this.executor.ExecutionDataSnapshot.PositionsMaster[i].NoExitBarOrStreaming && soldOrCovered) { result = true; num--; }
			//	}
			//	return result;
			//}
			//if (exitBar < this.executor.Bars.Count) {
			if (exitBar.IsBarStreaming == false) {
				//BAR_NOT_NULL_CHECKED_UPSTACK_IN_ScriptExecutor.SellOrCoverAlertCreateRegister() this.executor._throwWhenBarOutsideInterval(exitBar, position.EntryBarIndex, position.Bars.Count, position.Bars);
				//switch (direction) {
				//	case Direction.Sell:
				//		if (this.executor._IsDayLimitedDownWithBarsBy(position.Bars, exitBar) == false) return null;
				//		if (position.PositionLongShort != PositionLongShort.Long) return null;
				//		break;
				//	case Direction.Cover:
				//		if (this.executor._IsDayLimitedUpWithBarsBy(position.Bars, exitBar) == false) return null;
				//		if (position.PositionLongShort != PositionLongShort.Short) return null;
				//		break;
				//	default:
				//		throw new Exception("NYI direction[" + direction + "]");
				//}
			}

			PositionLongShort longShortFromDirection = MarketConverter.LongShortFromDirection(direction);
			exitPriceScript = this.executor.AlignAlertPriceToPriceLevel(this.executor.Bars, exitPriceScript, true, longShortFromDirection, exitMarketLimitStop);

			Alert alert = new Alert(exitBar, position.Shares, exitPriceScript, signalName,
				direction, exitMarketLimitStop, orderSpreadSide,
				//this.executor.Script,
				this.executor.Strategy);
			alert.AbsorbFromExecutor(executor);
			alert.PositionAffected = position;
			// moved to CallbackAlertFilled - we can exit by TP or SL - and position has no clue which Alert was filled!!!
			//position.ExitCopyFromAlert(alert);

			return alert;
		}
		public Alert EntryAlertCreate(Bar entryBar, double stopOrLimitPrice, string entrySignalName,
				Direction direction, MarketLimitStop entryMarketLimitStop) {
			
			//if (direction == Direction.Buy
			//	 && this.executor._BarsLimitedUpBy(entryBar) == false) return null;
			//if (direction == Direction.Short
			//	&& this.executor._BarsLimitedDownBy(entryBar) == false) return null;

			double entryPriceScript = stopOrLimitPrice;

			int barSmallestAllowed = 0;
			OrderSpreadSide orderSpreadSide = OrderSpreadSide.Unknown;
			switch (entryMarketLimitStop) {
				case MarketLimitStop.Market:
					//if (entryBar >= this.executor.Bars.Count) {
					if (entryBar.IsBarStreaming) {
						if (this.executor.IsStreaming) {
							//basisPrice = 0;
							this.executor.DataSource.StreamingProvider.StreamingDataSnapshot.GetAlignedBidOrAskForTidalOrCrossMarketFromStreaming(
								this.executor.Bars.Symbol, direction, out entryPriceScript, out orderSpreadSide, false);
						} else {
							//basisPrice = this.executor.Bars.LastBar.Open;
							//if (bar > this.executor.Bars.Count) {
							//	throw new Exception("got LastBar.Open while MarketOrder is placed few bars further from LastBar");
							//}
//							entryPriceScript = this.executor.Bars[entryBar - 1].Close;
//							string msg = "[" + direction + "]At[" + entryMarketLimitStop + "](bar=[" + entryBar + "])"
//								+ " when LastBar[" + (this.executor.Bars.Count - 1) + "]; No way I can bring you price from the future, even by executing your order right now"
//								+ "; can't do inequivalent repacement to LastBar.Open";
//							log.Fatal(msg, new Exception(msg));
							string msg = "[" + direction + "]At[" + entryMarketLimitStop + "](bar=[" + entryBar + "])";
							throw new Exception("UNABLE_TO_REFACTOR#1 " + msg);
						}
					} else {
						//entryPriceScript = this.executor.Bars[entryBar].Open;
						entryPriceScript = entryBar.Open;
					}
					barSmallestAllowed = 1;
					break;
				case MarketLimitStop.AtClose:
					//basisPrice = this.executor.Bars[bar - 1].Close;
					//if (entryBar >= this.executor.Bars.Count) { //bar+1
					if (entryBar.IsBarStreaming) {
						entryPriceScript = 0;
						string msg = "[" + direction + "]At[" + entryMarketLimitStop + "](bar=[" + entryBar + "])"
							+ " when LastBar[" + (this.executor.Bars.Count - 1) + "]; No way I can bring you a future price,"
							+ " even by executing your order right now"
							+ "; can't do inequivalent repacement to LastBar.Close";
						log.Fatal(msg, new Exception(msg));
					} else {
						//entryPriceScript = this.executor.Bars[entryBar].Close;
						entryPriceScript = entryBar.Close;
					}
					barSmallestAllowed = 0;
					break;
				case MarketLimitStop.Stop:
					break;
				case MarketLimitStop.Limit:
					break;
				default:
					throw new Exception("no handler for Direction.[" + direction + "]");
			}
			//BAR_NOT_NULL_CHECKED_UPSTACK_IN_ScriptExecutor.BuyOrShortAlertCreateRegister() this.executor._throwWhenBarOutsideInterval(entryBar, barSmallestAllowed, this.executor.Bars.Count, this.executor.Bars);
			//if (entryBar < this.executor.Bars.Count) {
			this.basisPriceZeroCheckThrow(entryPriceScript);
			//}

			PositionLongShort longShortFromDirection = MarketConverter.LongShortFromDirection(direction);
			entryPriceScript = this.executor.AlignAlertPriceToPriceLevel(this.executor.Bars, entryPriceScript, true, longShortFromDirection, entryMarketLimitStop);
			if (entryPriceScript == 0) {
				int a = 1;
			}
			double shares = this.executor.PositionSizeCalculator.CalcPositionSize(entryBar,
				entryPriceScript, longShortFromDirection, this.executor.ScriptExecutorConfig.RiskStopLevel, true);

			Alert alert = new Alert(entryBar, shares, entryPriceScript, entrySignalName,
				direction, entryMarketLimitStop, orderSpreadSide,
				//this.executor.Script,
				this.executor.Strategy);
			alert.AbsorbFromExecutor(executor);

			return alert;
		}