/// <summary> /// Random Execution Method /// </summary> static void RandomMethod(int bar, BacktestEval eval, ref double current, bool isTopReachable, bool isBottomReachable, bool isHigherPrice, bool isLowerPrice, double priceHigher, double priceLower, Order orderHigher, Order orderLower, bool isClosingAmbiguity) { double high = High[bar]; double low = Low[bar]; double close = Close[bar]; Random random = new Random(); if (eval == BacktestEval.None) { // There is no more orders if (!session[bar].IsTopReached && !session[bar].IsBottomReached) { // Neither the top nor the bottom was reached int upRange = (int)Math.Round((high - current) / Data.InstrProperties.Point); int downRange = (int)Math.Round((current - low) / Data.InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 1; downRange = 1; } int iRandom = random.Next(upRange + downRange); bool bHitHigh = false; if (upRange > downRange) bHitHigh = iRandom > upRange; else bHitHigh = iRandom < downRange; if (bHitHigh) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } else if (!session[bar].IsTopReached) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else if (!session[bar].IsBottomReached) { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } if (eval == BacktestEval.Correct) { // Hit the order or the top/bottom Order theOrder = null; double thePrice = 0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } if (!session[bar].IsBottomReached && isBottomReachable) { // The order or the bottom int iUpRange = (int)Math.Round((thePrice - current) / Data.InstrProperties.Point); int iDnRange = (int)Math.Round((current - low) / Data.InstrProperties.Point); iUpRange = iUpRange < 0 ? 0 : iUpRange; iDnRange = iDnRange < 0 ? 0 : iDnRange; if (iDnRange + iDnRange == 0) { iUpRange = 1; iDnRange = 1; } int iRandom = random.Next(iUpRange + iDnRange); bool executeUpper = false; if (iUpRange > iDnRange) executeUpper = iRandom > iUpRange; else executeUpper = iRandom < iDnRange; if (executeUpper) { // Execute current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } else if (!session[bar].IsTopReached && isTopReachable) { // The order or the Top int upRange = (int)Math.Round((high - current) / Data.InstrProperties.Point); int downRange = (int)Math.Round((current - thePrice) / Data.InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 1; downRange = 1; } int iRandom = random.Next(upRange + downRange); bool executeUpper = false; if (upRange > downRange) executeUpper = iRandom > upRange; else executeUpper = iRandom < downRange; if (executeUpper) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Execute current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } } else { // Execute the order current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } } else if (eval == BacktestEval.Ambiguous) { // Ambiguous - two orders or order and bar closing if (!isClosingAmbiguity) { // Execute the randomly chosen order int upRange = (int)Math.Round((priceHigher - current) / Data.InstrProperties.Point); int downRange = (int)Math.Round((current - priceLower) / Data.InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 1; downRange = 1; } int iRandom = random.Next(upRange + downRange); bool executeUpper = false; if (upRange > downRange) executeUpper = iRandom > upRange; else executeUpper = iRandom < downRange; Order theOrder; double thePrice; if (executeUpper) { theOrder = orderHigher; thePrice = priceHigher; } else { theOrder = orderLower; thePrice = priceLower; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } else { // Execute or exit the bar if (isHigherPrice) { int upRange = (int)Math.Round((priceHigher - current) / Data.InstrProperties.Point); int downRange = (int)Math.Round((close - current) / Data.InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 1; downRange = 0; } int iRandom = random.Next(upRange + downRange); if (iRandom > upRange) { // Execute the order current = priceHigher; ExecOrd(bar, orderHigher, priceHigher, eval); } else { // Exit the bar current = close; orderHigher.OrdStatus = OrderStatus.Cancelled; session[bar].BacktestEval = BacktestEval.Ambiguous; } } else if (isLowerPrice) { // The priceLower or Exit the bar int upRange = (int)Math.Round((current - close) / Data.InstrProperties.Point); int downRange = (int)Math.Round((current - priceLower) / Data.InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 0; downRange = 1; } int iRandom = random.Next(upRange + downRange); if (iRandom > downRange) { // Execute the order current = priceLower; ExecOrd(bar, orderLower, priceLower, eval); } else { // Exit the bar current = close; orderLower.OrdStatus = OrderStatus.Cancelled; session[bar].BacktestEval = BacktestEval.Ambiguous; } } } } return; }
/// <summary> /// Makes a deep copy. /// </summary> public Order Copy() { Order order = new Order(); order.ordDir = this.ordDir; order.ordType = this.ordType; order.ordCond = this.ordCond; order.ordStatus = this.ordStatus; order.ordSender = this.ordSender; order.ordOrigin = this.ordOrigin; order.ordNumb = this.ordNumb; order.ordIF = this.ordIF; order.ordPos = this.ordPos; order.ordLots = this.ordLots; order.ordPrice = this.ordPrice; order.ordPrice2 = this.ordPrice2; order.ordNote = this.ordNote; return order; }
/// <summary> /// Nearest order first Method /// </summary> static void NearestMethod(int bar, BacktestEval eval, ref double current, bool isTopReachable, bool isBottomReachable, bool isHigherPrice, bool isLowerPrice, double priceHigher, double priceLower, Order orderHigher, Order orderLower, bool isClosingAmbiguity) { double open = Open[bar]; double high = High[bar]; double low = Low[bar]; double close = Close[bar]; if (eval == BacktestEval.None) { // There is no more orders if (!session[bar].IsTopReached && !session[bar].IsBottomReached) { // Neither the top nor the bottom was reached if (close < open) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } else if (!session[bar].IsTopReached) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else if (!session[bar].IsBottomReached) { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } if (eval == BacktestEval.Correct) { // Hit the order or the top/bottom Order theOrder = null; double thePrice = 0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } if (!session[bar].IsBottomReached && isBottomReachable) { // The order or the bottom double upRange = thePrice - current; double downRange = current - low; if (upRange < downRange) { // Execute current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } else if (!session[bar].IsTopReached && isTopReachable) { // The order or the bottom double upRange = high - current; double downRange = current - thePrice; if (upRange < downRange) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Execute current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } } else { // Execute the order current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } } else if (eval == BacktestEval.Ambiguous) { // Ambiguous - two orders or order and bar closing if (!isClosingAmbiguity) { // Execute the nearest order double upRange = priceHigher - current; double downRange = current - priceLower; Order theOrder; double thePrice; if (upRange < downRange) { theOrder = orderHigher; thePrice = priceHigher; } else { theOrder = orderLower; thePrice = priceLower; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } else { // Exit the bar double orderRange = isHigherPrice ? priceHigher - current : current - priceLower; double closeRange = Math.Abs(current - close); if (orderRange < closeRange) { // Execute the order Order theOrder; double thePrice; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else { theOrder = orderLower; thePrice = priceLower; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } else { // Cancel the order, go to Close current = close; session[bar].BacktestEval = BacktestEval.Ambiguous; if (isHigherPrice) orderHigher.OrdStatus = OrderStatus.Cancelled; else if (isLowerPrice) orderLower.OrdStatus = OrderStatus.Cancelled; } } } return; }
/// <summary> /// Optimistic / Pessimistic Method /// </summary> static void OptimisticPessimisticMethod(int bar, BacktestEval eval, ref double current, bool isTopReachable, bool isBottomReachable, bool isHigherPrice, bool isLowerPrice, double priceHigher, double priceLower, Order orderHigher, Order orderLower, bool isClosingAmbiguity) { double open = Open[bar]; double high = High[bar]; double low = Low[bar]; double close = Close[bar]; bool isOptimistic = interpolationMethod == InterpolationMethod.Optimistic; if (eval == BacktestEval.None) { // There is no more orders if (!session[bar].IsTopReached && !session[bar].IsBottomReached) { // Neither the top nor the bottom was reached if (close < open) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } else if (!session[bar].IsTopReached) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else if (!session[bar].IsBottomReached) { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } if (eval == BacktestEval.Correct) { // Hit the order or the top/bottom Order theOrder = null; double thePrice = 0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } if (!session[bar].IsBottomReached && isBottomReachable) { // The order or the bottom bool goUpward; if (current < low + micron) goUpward = false; else if (thePrice - current < micron) goUpward = true; else if (theOrder.OrdDir == OrderDirection.Buy) goUpward = !isOptimistic; else if (theOrder.OrdDir == OrderDirection.Sell) goUpward = isOptimistic; else goUpward = thePrice - current < current - low; if (goUpward) { // Execute order current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } else if (!session[bar].IsTopReached && isTopReachable) { // The order or the top bool goUpward; if (current > high - micron) goUpward = true; else if (current - thePrice < micron) goUpward = false; else if (theOrder.OrdDir == OrderDirection.Buy) goUpward = !isOptimistic; else if (theOrder.OrdDir == OrderDirection.Sell) goUpward = isOptimistic; else goUpward = high - current < current - thePrice; if (goUpward) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Execute order current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } } else { // Execute the order current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } } else if (eval == BacktestEval.Ambiguous) { // Ambiguous - two orders or order and bar closing if (!isClosingAmbiguity) { // Execute one of both orders bool executeUpper; if (priceHigher - current < micron) executeUpper = true; else if (current - priceLower < micron) executeUpper = false; else if (session[bar].Summary.PosDir == PosDirection.Long) executeUpper = isOptimistic; else if (session[bar].Summary.PosDir == PosDirection.Short) executeUpper = !isOptimistic; else { if (orderHigher.OrdDir == OrderDirection.Buy && orderLower.OrdDir == OrderDirection.Buy) executeUpper = !isOptimistic; else if (orderHigher.OrdDir == OrderDirection.Sell && orderLower.OrdDir == OrderDirection.Sell) executeUpper = isOptimistic; else if (orderHigher.OrdDir == OrderDirection.Buy && orderLower.OrdDir == OrderDirection.Sell) { if (current < close) executeUpper = isOptimistic; else executeUpper = !isOptimistic; if (Data.Strategy.OppSignalAction == OppositeDirSignalAction.Reverse) executeUpper = !executeUpper; } else { if (current < close) executeUpper = !isOptimistic; else executeUpper = isOptimistic; if (Data.Strategy.OppSignalAction == OppositeDirSignalAction.Reverse) executeUpper = !executeUpper; } } Order theOrder; double thePrice; if (executeUpper) { theOrder = orderHigher; thePrice = priceHigher; } else { theOrder = orderLower; thePrice = priceLower; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } else { // Execute or exit the bar if (isHigherPrice) { bool toExecute = false; if (session[bar].Summary.PosDir == PosDirection.Long) toExecute = isOptimistic; else if (session[bar].Summary.PosDir == PosDirection.Short) toExecute = !isOptimistic; else if (orderHigher.OrdDir == OrderDirection.Buy) toExecute = !isOptimistic; else if (orderHigher.OrdDir == OrderDirection.Sell) toExecute = isOptimistic; if (toExecute) { // Execute current = priceHigher; ExecOrd(bar, orderHigher, priceHigher, eval); } else { // Exit the bar current = close; orderHigher.OrdStatus = OrderStatus.Cancelled; session[bar].BacktestEval = BacktestEval.Ambiguous; } } else if (isLowerPrice) { // The priceLower or Exit the bar bool toExecute = false; if (session[bar].Summary.PosDir == PosDirection.Long) toExecute = !isOptimistic; else if (session[bar].Summary.PosDir == PosDirection.Short) toExecute = isOptimistic; else if (orderLower.OrdDir == OrderDirection.Buy) toExecute = isOptimistic; else if (orderLower.OrdDir == OrderDirection.Sell) toExecute = !isOptimistic; if (toExecute) { // Execute current = priceLower; ExecOrd(bar, orderLower, priceLower, eval); } else { // Exit the bar current = close; orderLower.OrdStatus = OrderStatus.Cancelled; session[bar].BacktestEval = BacktestEval.Ambiguous; } } } } return; }
/// <summary> /// Tick Scanning /// </summary> static bool TickScanning(int bar, BacktestEval eval, ref double current, ref int reachedTick, bool isTopReachable, bool isBottomReachable, bool isHigherPrice, bool isLowerPrice, double priceHigher, double priceLower, Order orderHigher, Order orderLower, bool isClosingAmbiguity) { double high = High[bar]; double low = Low[bar]; double close = Close[bar]; bool isScanningResult = false; if (eval == BacktestEval.None) { // There isn't any orders if (!session[bar].IsTopReached && !session[bar].IsBottomReached) { // Neither the top nor the bottom was reached int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (Data.TickData[bar][tick] + micron > high) { // Top found current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; isScanningResult = true; break; } else if (Data.TickData[bar][tick] - micron < low) { // Bottom found current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; isScanningResult = true; break; } } } else if (!session[bar].IsTopReached) { // Whether hit the Top int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (Data.TickData[bar][tick] + micron > high) { // Top found current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; isScanningResult = true; break; } } } else if (!session[bar].IsBottomReached) { // Whether hit the Bottom int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (Data.TickData[bar][tick] - micron < low) { // Bottom found current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; isScanningResult = true; break; } } } } if (eval == BacktestEval.Correct) { // Hit the order or the top / bottom Order theOrder = null; double thePrice = 0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } if (!session[bar].IsBottomReached && isBottomReachable) { // The order or the Bottom int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (Data.TickData[bar][tick] + micron > thePrice) { // The order is reached current = thePrice; ExecOrd(bar, theOrder, thePrice, BacktestEval.Correct); isScanningResult = true; break; } else if (Data.TickData[bar][tick] - micron < low) { // Bottom is reached current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; isScanningResult = true; break; } } } else if (!session[bar].IsTopReached && isTopReachable) { // The order or the Top int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (Data.TickData[bar][tick] + micron > high) { // The Top is reached current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; isScanningResult = true; break; } else if (Data.TickData[bar][tick] - micron < thePrice) { // The order is reached current = thePrice; ExecOrd(bar, theOrder, thePrice, BacktestEval.Correct); isScanningResult = true; break; } } } else { // Execute the order double priceOld = Data.TickData[bar][reachedTick]; int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (priceOld - micron < thePrice && Data.TickData[bar][tick] + micron > thePrice || priceOld + micron > thePrice && Data.TickData[bar][tick] - micron < thePrice) { // Order reached current = thePrice; ExecOrd(bar, theOrder, thePrice, BacktestEval.Correct); isScanningResult = true; break; } } } } else if (eval == BacktestEval.Ambiguous) { // Ambiguous - two orders or order and bar closing if (!isClosingAmbiguity) { // Execute the the first reached order int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (Data.TickData[bar][tick] + micron > priceHigher) { // Upper order is reached current = priceHigher; ExecOrd(bar, orderHigher, priceHigher, BacktestEval.Correct); isScanningResult = true; break; } else if (Data.TickData[bar][tick] - micron < priceLower) { // Lower order is reached current = priceLower; ExecOrd(bar, orderLower, priceLower, BacktestEval.Correct); isScanningResult = true; break; } } } else { // Execute or exit the bar Order theOrder = null; double thePrice = 0.0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } bool executeOrder = false; if (isHigherPrice) { int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (Data.TickData[bar][tick] + micron > thePrice) { // The order is reached executeOrder = true; break; } } } else if (isLowerPrice) { // The priceLower or Exit the bar int tickCount = Data.TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (Data.TickData[bar][tick] - micron < thePrice) { // The order is reached executeOrder = true; break; } } } if (executeOrder) { // Execute the order current = thePrice; ExecOrd(bar, theOrder, thePrice, BacktestEval.Correct); } else { // Exit the bar current = close; theOrder.OrdStatus = OrderStatus.Cancelled; session[bar].BacktestEval = BacktestEval.Correct; } isScanningResult = true; } } return isScanningResult; }
/// <summary> /// Intrabar Scanning /// </summary> static bool IntrabarScanning(int bar, BacktestEval eval, ref double current, ref int reachedIntrabar, ref int tradedIntrabar, bool isTopReachable, bool isBottomReachable, bool isHigherPrice, bool isLowerPrice, double priceHigher, double priceLower, Order orderHigher, Order orderLower, bool isClosingAmbiguity) { double high = High[bar]; double low = Low[bar]; double close = Close[bar]; bool isScanningResult = false; if (eval == BacktestEval.None) { // There is no more orders if (!session[bar].IsTopReached && !session[bar].IsBottomReached) { // Neither the top nor the bottom was reached bool goUpward = false; for (int intraBar = reachedIntrabar; intraBar < Data.IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (Data.IntraBarData[bar][intraBar].High + micron > high) { // Top found goUpward = true; isScanningResult = true; } if (Data.IntraBarData[bar][intraBar].Low - micron < low) { // Bottom found if (isScanningResult) { // Top and Bottom into the same intrabar isScanningResult = false; break; } goUpward = false; isScanningResult = true; } if (isScanningResult) break; } if (isScanningResult) { if (goUpward) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } } else if (!session[bar].IsTopReached) { // Whether hit the Top for (int intraBar = reachedIntrabar; intraBar < Data.IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (Data.IntraBarData[bar][intraBar].High + micron > high) { // Top found current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; isScanningResult = true; break; } } } else if (!session[bar].IsBottomReached) { // Whether hit the Bottom for (int intraBar = reachedIntrabar; intraBar < Data.IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (Data.IntraBarData[bar][intraBar].Low - micron < low) { // Bottom found current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; isScanningResult = true; break; } } } } if (eval == BacktestEval.Correct) { // Hit the order or the top / bottom Order theOrder = null; double thePrice = 0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } if (!session[bar].IsBottomReached && isBottomReachable) { // The order or the bottom bool goUpward = false; for (int intraBar = reachedIntrabar; intraBar < Data.IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (Data.IntraBarData[bar][intraBar].High + micron > thePrice) { // The order is reached goUpward = true; isScanningResult = true; } if (Data.IntraBarData[bar][intraBar].Low - micron < low) { // Bottom is reached if (isScanningResult) { // The Order and Bottom into the same intrabar isScanningResult = false; break; } goUpward = false; isScanningResult = true; } if (isScanningResult) break; } if (isScanningResult) { if (goUpward) { // Execute if (tradedIntrabar == reachedIntrabar) { isScanningResult = false; return isScanningResult; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); tradedIntrabar = reachedIntrabar; } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } } else if (!session[bar].IsTopReached && isTopReachable) { // The order or the Top bool goUpward = false; for (int intraBar = reachedIntrabar; intraBar < Data.IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (Data.IntraBarData[bar][intraBar].High + micron > high) { // The Top is reached goUpward = true; isScanningResult = true; } if (Data.IntraBarData[bar][intraBar].Low - micron < thePrice) { // The order is reached if (isScanningResult) { // The Top and the order are into the same intrabar isScanningResult = false; break; } // The order is reachable downwards goUpward = false; isScanningResult = true; } if (isScanningResult) break; } if (isScanningResult) { if (goUpward) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Execute if (tradedIntrabar == reachedIntrabar) { isScanningResult = false; return isScanningResult; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); tradedIntrabar = reachedIntrabar; } } } else { // Execute the order for (int intraBar = reachedIntrabar; intraBar < Data.IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (Data.IntraBarData[bar][intraBar].High + micron > thePrice && Data.IntraBarData[bar][intraBar].Low - micron < thePrice) { // Order reached if (tradedIntrabar == reachedIntrabar) { isScanningResult = false; return isScanningResult; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); isScanningResult = true; tradedIntrabar = reachedIntrabar; break; } } } } else if (eval == BacktestEval.Ambiguous) { // Ambiguous - two orders or order and bar closing if (!isClosingAmbiguity) { // Execute the the first reached order bool executeUpper = false; for (int intraBar = reachedIntrabar; intraBar < Data.IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (Data.IntraBarData[bar][intraBar].High + micron > priceHigher) { // Upper order is reached executeUpper = true; isScanningResult = true; } if (Data.IntraBarData[bar][intraBar].Low - micron < priceLower) { // Lower order is reached if (isScanningResult) { // Top and Bottom into the same intrabar isScanningResult = false; break; } executeUpper = false; isScanningResult = true; } if (isScanningResult) break; } if (isScanningResult) { Order theOrder; double thePrice; if (executeUpper) { theOrder = orderHigher; thePrice = priceHigher; } else { theOrder = orderLower; thePrice = priceLower; } if (tradedIntrabar == reachedIntrabar) { isScanningResult = false; return isScanningResult; } eval = BacktestEval.Correct; current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); tradedIntrabar = reachedIntrabar; } } else { // Execute or exit the bar Order theOrder = null; double thePrice = 0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } bool executeOrder = false; if (isHigherPrice) { for (int intraBar = reachedIntrabar; intraBar < Data.IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (Data.IntraBarData[bar][intraBar].High + micron > thePrice) { // The order is reached executeOrder = true; break; } } } else if (isLowerPrice) { // The priceLower or Exit the bar for (int b = reachedIntrabar; b < Data.IntraBarBars[bar]; b++) { reachedIntrabar = b; if (Data.IntraBarData[bar][b].Low - micron < thePrice) { // The order is reached executeOrder = true; break; } } } if (executeOrder) { // Execute the order if (tradedIntrabar == reachedIntrabar) { isScanningResult = false; return isScanningResult; } current = thePrice; eval = BacktestEval.Correct; ExecOrd(bar, theOrder, thePrice, eval); tradedIntrabar = reachedIntrabar; } else { // Exit the bar current = close; theOrder.OrdStatus = OrderStatus.Cancelled; session[bar].BacktestEval = BacktestEval.Correct; } isScanningResult = true; } } return isScanningResult; }
/// <summary> /// Shortest route inside the bar Method /// </summary> static void ShortestMethod(int bar, BacktestEval eval, ref double current, bool isTopReachable, bool isBottomReachable, bool isHigherPrice, bool isLowerPrice, double priceHigher, double priceLower, Order orderHigher, Order orderLower, bool isClosingAmbiguity) { double open = Open[bar]; double high = High[bar]; double low = Low[bar]; double close = Close[bar]; bool isGoUpward; if (!session[bar].IsTopReached && !session[bar].IsBottomReached) isGoUpward = open > close; else if (session[bar].IsTopReached && !session[bar].IsBottomReached) isGoUpward = false; else if (!session[bar].IsTopReached && session[bar].IsBottomReached) isGoUpward = true; else isGoUpward = open > close; if (isLowerPrice && current - priceLower < micron) isGoUpward = false; if (isHigherPrice && priceHigher - current < micron) isGoUpward = true; if (eval == BacktestEval.None) { // There is no more orders if (!session[bar].IsTopReached && !session[bar].IsBottomReached) { // Neither the top nor the bottom was reached if (isGoUpward) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } else if (!session[bar].IsTopReached) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else if (!session[bar].IsBottomReached) { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } } if (eval == BacktestEval.Correct) { // Hit the top/bottom or execute Order theOrder = null; double thePrice = 0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } if (!session[bar].IsBottomReached && isBottomReachable && !isGoUpward) { // Hit the Bottom current = low; session[bar].SetWayPoint(low, WayPointType.Low); session[bar].IsBottomReached = true; } else if (!session[bar].IsTopReached && isTopReachable && isGoUpward) { // Hit the Top current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; } else { // Execute the order current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } } else if (eval == BacktestEval.Ambiguous) { // Ambiguous - two orders or order and bar closing if (!isClosingAmbiguity) { // Execute the nearest order Order theOrder; double thePrice; if (isGoUpward) { theOrder = orderHigher; thePrice = priceHigher; } else { theOrder = orderLower; thePrice = priceLower; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); } else { // Exit the bar current = close; session[bar].BacktestEval = BacktestEval.Ambiguous; if (isHigherPrice) orderHigher.OrdStatus = OrderStatus.Cancelled; else if (isLowerPrice) orderLower.OrdStatus = OrderStatus.Cancelled; } } return; }
/// <summary> /// Makes a deep copy. /// </summary> public Order Copy() { var order = new Order { OrdDir = OrdDir, OrdType = OrdType, OrdCond = OrdCond, OrdStatus = OrdStatus, OrdSender = OrdSender, OrdOrigin = OrdOrigin, OrdNumb = OrdNumb, OrdIF = OrdIF, OrdPos = OrdPos, OrdLots = OrdLots, OrdPrice = OrdPrice, OrdPrice2 = OrdPrice2, OrdNote = OrdNote }; return order; }
/// <summary> /// Finds and cancels the exit order of an entry order /// </summary> static void FindCancelExitOrder(int bar, Order order) { for (int ord = 0; ord < session[bar].Orders; ord++) if (session[bar].Order[ord].OrdIF == order.OrdNumb) { session[bar].Order[ord].OrdStatus = OrderStatus.Cancelled; break; } }
/// <summary> /// Tunes and Executes an order /// </summary> static OrderStatus ExecOrd(int bar, Order order, double price, BacktestEval testEval) { Position position = session[bar].Summary; PosDirection posDir = position.PosDir; OrderDirection ordDir = order.OrdDir; WayPointType wayPointType = WayPointType.None; // Orders modification on a fly // Checks whether we are on the market if (posDir == PosDirection.Long || posDir == PosDirection.Short) { // We are on the market if (order.OrdSender == OrderSender.Open) { // Entry orders if (ordDir == OrderDirection.Buy && posDir == PosDirection.Long || ordDir == OrderDirection.Sell && posDir == PosDirection.Short) { // In case of a Same Dir Signal switch (Strategy.SameSignalAction) { case SameDirSignalAction.Add: order.OrdLots = TradingSize(Strategy.AddingLots, bar); if (position.PosLots + TradingSize(Strategy.AddingLots, bar) <= maximumLots) { // Adding wayPointType = WayPointType.Add; } else { // Cancel the Adding order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; FindCancelExitOrder(bar, order); // Canceling of its exit order } break; case SameDirSignalAction.Winner: order.OrdLots = TradingSize(Strategy.AddingLots, bar); if (position.PosLots + TradingSize(Strategy.AddingLots, bar) <= maximumLots && (position.PosDir == PosDirection.Long && position.PosPrice < order.OrdPrice || position.PosDir == PosDirection.Short && position.PosPrice > order.OrdPrice)) { // Adding wayPointType = WayPointType.Add; } else { // Cancel the Adding order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; FindCancelExitOrder(bar, order); // Canceling of its exit order } break; case SameDirSignalAction.Nothing: order.OrdLots = TradingSize(Strategy.AddingLots, bar); order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; FindCancelExitOrder(bar, order); // Canceling of its exit order break; default: break; } } else if (ordDir == OrderDirection.Buy && posDir == PosDirection.Short || ordDir == OrderDirection.Sell && posDir == PosDirection.Long) { // In case of an Opposite Dir Signal switch (Strategy.OppSignalAction) { case OppositeDirSignalAction.Reduce: if (position.PosLots > TradingSize(Strategy.ReducingLots, bar)) { // Reducing order.OrdLots = TradingSize(Strategy.ReducingLots, bar); wayPointType = WayPointType.Reduce; } else { // Closing order.OrdLots = position.PosLots; wayPointType = WayPointType.Exit; } break; case OppositeDirSignalAction.Close: order.OrdLots = position.PosLots; wayPointType = WayPointType.Exit; break; case OppositeDirSignalAction.Reverse: order.OrdLots = position.PosLots + TradingSize(Strategy.EntryLots, bar); wayPointType = WayPointType.Reverse; break; case OppositeDirSignalAction.Nothing: order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; FindCancelExitOrder(bar, order); // Canceling of its exit order break; default: break; } } } else { // Exit orders if (ordDir == OrderDirection.Buy && posDir == PosDirection.Short || ordDir == OrderDirection.Sell && posDir == PosDirection.Long) { // Check for Break Even Activation if (order.OrdOrigin == OrderOrigin.BreakEvenActivation) { // This is a fictive order order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; } else { // The Close orders can only close the position order.OrdLots = position.PosLots; wayPointType = WayPointType.Exit; } } else { // If the direction of the exit order is same as the position's direction // the order have to be cancelled order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; } } } else { // We are out of the market if (order.OrdSender == OrderSender.Open) { // Open a new position order.OrdLots = Math.Min(TradingSize(Strategy.EntryLots, bar), maximumLots); wayPointType = WayPointType.Entry; } else// if (order.OrdSender == OrderSender.Close) { // The Close strategy cannot do anything order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; } } // Enter Once can cancel an entry order if (hasEnterOnce && order.OrdSender == OrderSender.Open && order.OrdStatus == OrderStatus.Confirmed) { bool toCancel = false; switch (Strategy.Slot[slotEnterOnce].IndParam.ListParam[0].Text) { case "Enter no more than once a bar": toCancel = Time[bar] == lastEntryTime; break; case "Enter no more than once a day": toCancel = Time[bar].DayOfYear == lastEntryTime.DayOfYear; break; case "Enter no more than once a week": int lastEntryWeek = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear( lastEntryTime, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); int currentWeek = CultureInfo.CurrentCulture.Calendar.GetWeekOfYear( Time[bar], CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); toCancel = lastEntryWeek == currentWeek; break; case "Enter no more than once a month": toCancel = Time[bar].Month == lastEntryTime.Month; break; default: break; } if (toCancel) { // Cancel the entry order order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; FindCancelExitOrder(bar, order); // Canceling of its exit order } else lastEntryTime = Time[bar]; } // Do not trade after Margin Call or after -1000000 Loss if (order.OrdSender == OrderSender.Open && order.OrdStatus == OrderStatus.Confirmed) { if (position.FreeMargin < -1000000 || Configs.TradeUntilMarginCall && RequiredMargin(order.OrdLots, bar) > position.FreeMargin) { // Cancel the entry order order.OrdStatus = OrderStatus.Cancelled; wayPointType = WayPointType.Cancel; FindCancelExitOrder(bar, order); // Canceling of its exit order } } // Executing the order if (order.OrdStatus == OrderStatus.Confirmed) { // Executes the order SetPosition(bar, ordDir, order.OrdLots, price, order.OrdNumb); order.OrdStatus = OrderStatus.Executed; // Set the evaluation switch (testEval) { case BacktestEval.Error: session[bar].BacktestEval = BacktestEval.Error; break; case BacktestEval.None: break; case BacktestEval.Ambiguous: session[bar].BacktestEval = BacktestEval.Ambiguous; break; case BacktestEval.Unknown: if (session[bar].BacktestEval != BacktestEval.Ambiguous) session[bar].BacktestEval = BacktestEval.Unknown; break; case BacktestEval.Correct: if (session[bar].BacktestEval == BacktestEval.None) session[bar].BacktestEval = BacktestEval.Correct; break; default: break; } // If entry order closes or reverses the position the exit orders of the // initial position have to be cancelled if (order.OrdSender == OrderSender.Open && (session[bar].Summary.Transaction == Transaction.Close || session[bar].Summary.Transaction == Transaction.Reverse)) { int initialNumber = session[bar].Position[session[bar].Positions - 2].FormOrdNumb; // If the position was opened during the current bar, we can find its exit order bool isFound = false; for (int ord = 0; ord < session[bar].Orders; ord++) { if (session[bar].Order[ord].OrdIF == initialNumber && session[bar].Order[ord].OrdSender == OrderSender.Close) { session[bar].Order[ord].OrdStatus = OrderStatus.Cancelled; isFound = true; break; } } // In case when the order is not found, this means that the position is transferred // so its exit order is not conditional if (!isFound) { for (int ord = 0; ord < session[bar].Orders; ord++) { if (session[bar].Order[ord].OrdSender == OrderSender.Close && session[bar].Order[ord].OrdIF == 0) { session[bar].Order[ord].OrdStatus = OrderStatus.Cancelled; break; } } } // Setting the exit order of the current position if (session[bar].Summary.Transaction == Transaction.Close) { // In case of closing we have to cancel the exit order int number = session[bar].Summary.FormOrdNumb; for (int ord = 0; ord < session[bar].Orders; ord++) { if (session[bar].Order[ord].OrdIF == number) { session[bar].Order[ord].OrdStatus = OrderStatus.Cancelled; break; } } } else if (session[bar].Summary.Transaction == Transaction.Reduce) { // In case of reducing we have to change the direction of the exit order int number = session[bar].Summary.FormOrdNumb; for (int ord = 0; ord < session[bar].Orders; ord++) { if (session[bar].Order[ord].OrdIF == number) { if (session[bar].Summary.PosDir == PosDirection.Long) session[bar].Order[ord].OrdDir = OrderDirection.Sell; else session[bar].Order[ord].OrdDir = OrderDirection.Buy; break; } } } } } session[bar].SetWayPoint(price, wayPointType); if (order.OrdStatus == OrderStatus.Cancelled) { session[bar].WayPoint[session[bar].WayPoints - 1].OrdNumb = order.OrdNumb; } return order.OrdStatus; }
/// <summary> /// Updates the journal data from the backtester /// </summary> void UpdateJournalData() { if (!Data.IsResult) return; Order[] aOrders = new Order[orders]; aiOrderIcons = new Image[orders]; int ordIndex = 0; for (int point = 0; point < Backtester.WayPoints(selectedBar); point++) { int iOrdNumber = Backtester.WayPoint(selectedBar, point).OrdNumb; WayPointType wpType = Backtester.WayPoint(selectedBar, point).WPType; if (iOrdNumber == -1) continue; // There is no order if (iOrdNumber < Backtester.OrdNumb(selectedBar, 0)) continue; // For a transferred position if (wpType == WayPointType.Add || wpType == WayPointType.Cancel || wpType == WayPointType.Entry || wpType == WayPointType.Exit || wpType == WayPointType.Reduce || wpType == WayPointType.Reverse) { aOrders[ordIndex] = Backtester.OrdFromNumb(iOrdNumber); ordIndex++; } } for (int ord = 0; ord < orders; ord++) { int ordNumber = Backtester.OrdNumb(selectedBar, ord); bool toIncluded = true; for (int i = 0; i < ordIndex; i++) { if (ordNumber == aOrders[i].OrdNumb) { toIncluded = false; break; } } if (toIncluded) { aOrders[ordIndex] = Backtester.OrdFromNumb(ordNumber); ordIndex++; } } asJournalData = new string[orders, columns]; for (int ord = firstOrd; ord < firstOrd + shownOrd; ord++) { int row = ord - firstOrd; string ordIF = (aOrders[ord].OrdIF > 0 ? (aOrders[ord].OrdIF + 1).ToString() : "-"); string ordPrice2 = (aOrders[ord].OrdPrice2 > 0 ? aOrders[ord].OrdPrice2.ToString(Data.FF) : "-"); asJournalData[row, 0] = (aOrders[ord].OrdNumb + 1).ToString(); asJournalData[row, 1] = Language.T(aOrders[ord].OrdDir.ToString()); asJournalData[row, 2] = Language.T(aOrders[ord].OrdType.ToString()); if (Configs.AccountInMoney) { string sOrdAmount = (aOrders[ord].OrdDir == OrderDirection.Sell ? "-" : "") + (aOrders[ord].OrdLots * Data.InstrProperties.LotSize).ToString(); asJournalData[row, 3] = sOrdAmount; } else asJournalData[row, 3] = aOrders[ord].OrdLots.ToString(); asJournalData[row, 4] = aOrders[ord].OrdPrice.ToString(Data.FF); asJournalData[row, 5] = ordPrice2; asJournalData[row, 6] = Language.T(aOrders[ord].OrdStatus.ToString()); asJournalData[row, 7] = aOrders[ord].OrdNote; // Icons aiOrderIcons[row] = aOrders[ord].OrderIcon; } return; }