/// <summary> /// Intrabar Scanning /// </summary> private 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 < IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (IntraBarData[bar][intraBar].High + sigma > high) { // Top found goUpward = true; isScanningResult = true; } if (IntraBarData[bar][intraBar].Low - sigma < low) { // Bottom found if (isScanningResult) { // Top and Bottom into the same intrabar isScanningResult = false; break; } 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 < IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (IntraBarData[bar][intraBar].High + sigma > 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 < IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (IntraBarData[bar][intraBar].Low - sigma < 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 < IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (IntraBarData[bar][intraBar].High + sigma > thePrice) { // The order is reached goUpward = true; isScanningResult = true; } if (IntraBarData[bar][intraBar].Low - sigma < low) { // Bottom is reached if (isScanningResult) { // The Order and Bottom into the same intrabar isScanningResult = false; break; } isScanningResult = true; } if (isScanningResult) break; } if (isScanningResult) { if (goUpward) { // Execute if (tradedIntrabar == reachedIntrabar) { return false; } 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 < IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (IntraBarData[bar][intraBar].High + sigma > high) { // The Top is reached goUpward = true; isScanningResult = true; } if (IntraBarData[bar][intraBar].Low - sigma < 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 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) { return false; } current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); tradedIntrabar = reachedIntrabar; } } } else { // Execute the order for (int intraBar = reachedIntrabar; intraBar < IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (IntraBarData[bar][intraBar].High + sigma > thePrice && IntraBarData[bar][intraBar].Low - sigma < thePrice) { // Order reached if (tradedIntrabar == reachedIntrabar) { return false; } 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 < IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (IntraBarData[bar][intraBar].High + sigma > priceHigher) { // Upper order is reached executeUpper = true; isScanningResult = true; } if (IntraBarData[bar][intraBar].Low - sigma < priceLower) { // Lower order is reached if (isScanningResult) { // Top and Bottom into the same intrabar isScanningResult = false; break; } 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) { return false; } eval = BacktestEval.Correct; current = thePrice; ExecOrd(bar, theOrder, thePrice, eval); tradedIntrabar = reachedIntrabar; } } else { // Execute or exit the bar var theOrder = new Order(); 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 < IntraBarBars[bar]; intraBar++) { reachedIntrabar = intraBar; if (IntraBarData[bar][intraBar].High + sigma > thePrice) { // The order is reached executeOrder = true; break; } } } else if (isLowerPrice) { // The priceLower or Exit the bar for (int b = reachedIntrabar; b < IntraBarBars[bar]; b++) { reachedIntrabar = b; if (IntraBarData[bar][b].Low - sigma < thePrice) { // The order is reached executeOrder = true; break; } } } if (executeOrder) { // Execute the order if (tradedIntrabar == reachedIntrabar) { return false; } 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> /// Random Execution Method /// </summary> private 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]; var 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 var upRange = (int) Math.Round((high - current)/InstrProperties.Point); var downRange = (int) Math.Round((current - low)/InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 1; downRange = 1; } int rand = random.Next(upRange + downRange); bool isHitHigh; if (upRange > downRange) isHitHigh = rand > upRange; else isHitHigh = rand < downRange; if (isHitHigh) { // 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 var iUpRange = (int) Math.Round((thePrice - current)/InstrProperties.Point); var iDnRange = (int) Math.Round((current - low)/InstrProperties.Point); iUpRange = iUpRange < 0 ? 0 : iUpRange; iDnRange = iDnRange < 0 ? 0 : iDnRange; if (iDnRange + iDnRange == 0) { iUpRange = 1; iDnRange = 1; } int rand = random.Next(iUpRange + iDnRange); bool executeUpper; if (iUpRange > iDnRange) executeUpper = rand > iUpRange; else executeUpper = rand < 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 var upRange = (int) Math.Round((high - current)/InstrProperties.Point); var downRange = (int) Math.Round((current - thePrice)/InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 1; downRange = 1; } int rand = random.Next(upRange + downRange); bool executeUpper; if (upRange > downRange) executeUpper = rand > upRange; else executeUpper = rand < 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 var upRange = (int) Math.Round((priceHigher - current)/InstrProperties.Point); var downRange = (int) Math.Round((current - priceLower)/InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 1; downRange = 1; } int rand = random.Next(upRange + downRange); bool executeUpper; if (upRange > downRange) executeUpper = rand > upRange; else executeUpper = rand < 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) { var upRange = (int) Math.Round((priceHigher - current)/InstrProperties.Point); var downRange = (int) Math.Round((close - current)/InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 1; downRange = 0; } int rand = random.Next(upRange + downRange); if (rand > 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 var upRange = (int) Math.Round((current - close)/InstrProperties.Point); var downRange = (int) Math.Round((current - priceLower)/InstrProperties.Point); upRange = upRange < 0 ? 0 : upRange; downRange = downRange < 0 ? 0 : downRange; if (downRange + downRange == 0) { upRange = 0; downRange = 1; } int rand = random.Next(upRange + downRange); if (rand > 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; } } } } }
/// <summary> /// Optimistic / Pessimistic Method /// </summary> private 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 var theOrder = new Order(); 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 + sigma) goUpward = false; else if (thePrice - current < sigma) 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 - sigma) goUpward = true; else if (current - thePrice < sigma) 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 < sigma) executeUpper = true; else if (current - priceLower < sigma) 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 (Strategy.OppSignalAction == OppositeDirSignalAction.Reverse) executeUpper = !executeUpper; } else { if (current < close) executeUpper = !isOptimistic; else executeUpper = isOptimistic; if (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; } } } } }
/// <summary> /// Tick Scanning /// </summary> private 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 = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (TickData[bar][tick] + sigma > high) { // Top found current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; isScanningResult = true; break; } if (TickData[bar][tick] - sigma < 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 = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (TickData[bar][tick] + sigma > 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 = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (TickData[bar][tick] - sigma < 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 = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (TickData[bar][tick] + sigma > thePrice) { // The order is reached current = thePrice; ExecOrd(bar, theOrder, thePrice, BacktestEval.Correct); isScanningResult = true; break; } if (TickData[bar][tick] - sigma < 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 = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (TickData[bar][tick] + sigma > high) { // The Top is reached current = high; session[bar].SetWayPoint(high, WayPointType.High); session[bar].IsTopReached = true; isScanningResult = true; break; } if (TickData[bar][tick] - sigma < thePrice) { // The order is reached current = thePrice; ExecOrd(bar, theOrder, thePrice, BacktestEval.Correct); isScanningResult = true; break; } } } else { // Execute the order double priceOld = TickData[bar][reachedTick]; int tickCount = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (priceOld - sigma < thePrice && TickData[bar][tick] + sigma > thePrice || priceOld + sigma > thePrice && TickData[bar][tick] - sigma < 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 = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (TickData[bar][tick] + sigma > priceHigher) { // Upper order is reached current = priceHigher; ExecOrd(bar, orderHigher, priceHigher, BacktestEval.Correct); isScanningResult = true; break; } if (TickData[bar][tick] - sigma < priceLower) { // Lower order is reached current = priceLower; ExecOrd(bar, orderLower, priceLower, BacktestEval.Correct); isScanningResult = true; break; } } } else { // Execute or exit the bar var theOrder = new Order(); double thePrice = 0.0; if (isHigherPrice) { theOrder = orderHigher; thePrice = priceHigher; } else if (isLowerPrice) { theOrder = orderLower; thePrice = priceLower; } bool executeOrder = false; if (isHigherPrice) { int tickCount = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (TickData[bar][tick] + sigma > thePrice) { // The order is reached executeOrder = true; break; } } } else if (isLowerPrice) { // The priceLower or Exit the bar int tickCount = TickData[bar].Length; for (int tick = reachedTick; tick < tickCount; tick++) { reachedTick = tick; if (TickData[bar][tick] - sigma < 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> /// Shortest route inside the bar Method /// </summary> private 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 < sigma) isGoUpward = false; if (isHigherPrice && priceHigher - current < sigma) 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; } } }
/// <summary> /// Nearest order first Method /// </summary> private 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; } } } }
/// <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> private 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> private static void ExecOrd(int bar, Order order, double price, BacktestEval testEval) { Position position = session[bar].Summary; PosDirection posDir = position.PosDir; OrderDirection ordDir = order.OrdDir; var 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; } } 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; } } } 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 double entryAmount = TradingSize(Strategy.EntryLots, bar); if (Strategy.UseMartingale && consecutiveLosses > 0) { entryAmount = entryAmount*Math.Pow(Strategy.MartingaleMultiplier, consecutiveLosses); entryAmount = NormalizeEntryLots(entryAmount); } order.OrdLots = Math.Min(entryAmount, 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; } 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; } // 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 switch (session[bar].Summary.Transaction) { case 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) continue; session[bar].Order[ord].OrdStatus = OrderStatus.Cancelled; break; } } break; case 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) continue; session[bar].Order[ord].OrdDir = session[bar].Summary.PosDir == PosDirection.Long ? OrderDirection.Sell : OrderDirection.Buy; break; } } break; } } } session[bar].SetWayPoint(price, wayPointType); if (order.OrdStatus == OrderStatus.Cancelled) { session[bar].WayPoint[session[bar].WayPoints - 1].OrdNumb = order.OrdNumb; } }