//+------------------------------------------------------------------+ //| Algo_Skeleton_Functions.mqh | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #define NUM_MAX_ALLOWED_TRADES 4 #include "library_functions.mqh" #include "NewCandleDetector.mqh" #include "GraphicalObjectsManager.mqh" #include "Zone.mqh" #include "ZoneContainer.mqh" #include "LotSizeCalculator.mqh" #include "MarketObserverTiger.mqh" #include "BuyEntryManager.mqh" #include "SellEntryManager.mqh" #include "BuyTradeManagerTiger.mqh" #include "SellTradeManagerTiger.mqh" input group "Risk Management Related Variables" input double riskManagementPartial ; input double firstPartialCloseFactor ; input double firstPartialProfitInPips; input bool trail_based_m30 ; input bool trail_based_h1 ; input bool trail_based_h4 ; input group "Entry Time Frame" input bool ENTRY_BASED_M30_STRUCTURE ; input bool ENTRY_BASED_H1_STRUCTURE ; input group "Range Related Variables" input double rangeDistanceBetweenZones_4H ; input double rangeDistanceBetweenZones_H1; input double rangeDistanceBetweenZones_M30 ; input double breakoutMinDist_H4 ; input double breakoutMinDist_H1 ; input double breakoutMinDist_M30 ; input double cleanRangeUponEntry ; input double potentialRR; input group "Zone Related Settings" input double resistanceExtendAboveCandle; input double resistanceLowerEdgeExtend ; input double supportExtendBelowCandle ; input double supportHigherEdgeExtend; input int firstZoneShift ; input datetime rightEdge ; input int deleteAllZonesAfter_Weeks ; input group "Candle Body Variables" input double WICK_RATIO_REJECTION; input double SIZE_OF_BREAKER_CANDLE_BODY; input group "Trade Restrictions" input bool BUYS_ALLOWED = true ; input bool SELLS_ALLOWED = true ; /* input int wickLengthInMinutes ; input double preWickPush ; input double stopOrderFactor ; input double retracementWickSize ; input double retracementWickFibMeasure ; input double minimumStopLossInPips ; */ input group "Trading Sessions" input bool TRADE_NEW_YORK_ALLOWED = true ; input bool TRADE_LONDON_ALLOWED = true ; input bool TRADE_TOKYO_ALLOWED = true ; input group "Modes" input bool MODE_WICKS_INCLUDED ; input group "HTF Confirmations" input bool H4_Break_Confirmation ; input bool H4_Closure_Confirmation ; // GUI CLASSES INITIALIZATION GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); // CONTAINERS INITIALIZATION //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ZoneContainer* zoneContainer_W1 = new ZoneContainer() ; ZoneContainer* zoneContainer_D1 = new ZoneContainer() ; ZoneContainer* zoneContainer_H4 = new ZoneContainer() ; ZoneContainer* zoneContainer_H1 = new ZoneContainer() ; ZoneContainer* zoneContainer_M30 = new ZoneContainer() ; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ZoneContainer* zoneContainerSupport_W1 = new ZoneContainer() ; ZoneContainer* zoneContainerSupport_D1 = new ZoneContainer() ; ZoneContainer* zoneContainerSupport_H4 = new ZoneContainer() ; ZoneContainer* zoneContainerSupport_H1 = new ZoneContainer() ; ZoneContainer* zoneContainerSupport_M30 = new ZoneContainer() ; // ALGORITHM CLASSES INITIALIZATION MarketObserverTiger* marketObserverTiger = new MarketObserverTiger(); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ NewCandleDetector newCandleDetectorWeekly("PERIOD_W1"); NewCandleDetector newCandleDetectorDaily("PERIOD_D1"); NewCandleDetector newCandleDetector4H("PERIOD_H4"); NewCandleDetector newCandleDetector1H("PERIOD_H1"); NewCandleDetector newCandleDetector30M("PERIOD_M30"); NewCandleDetector newCandleDetectorM15("PERIOD_M15"); NewCandleDetector newCandleDetectorM1("PERIOD_M1"); //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ Zone* temporaryRestestSupportZone = new Zone(); // TRADE CLASSES BuyEntryManager buyEntryManager ; SellEntryManager sellEntryManager ; // LotSizeCalculator class LotSizeCalculator lsCalc ; // TRADE VARIABLS bool securedRisk = false ; ulong activeTradeId ; BuyTradeManagerTiger* BuyActiveTradesArray[NUM_MAX_ALLOWED_TRADES]; SellTradeManagerTiger* SellActiveTradesArray[NUM_MAX_ALLOWED_TRADES]; int buysCount = 0 ; int sellsCount = 0 ; bool waitForBottomWickToForm = false ; bool bottomWickFormed = false; bool topWickFormed = false; int bottomWickValidationState = -2 ; int topWickValidationState = -2; bool waitForTopWickToForm = false ; int wickLengthCounter = 0 ; double buyStopPrice = -1 ; double sellStopPrice = -1 ; bool wickTradeTaken = false ; // Zone variables int weekCounter = 0 ; // HTF Variables bool last_H4_candle_broke_structure = false ; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double supportExtendBelowCandleActual = supportExtendBelowCandle * Point(); double supportHigherEdgeExtendActual = supportHigherEdgeExtend * Point(); double resistanceExtendAboveCandleActual = resistanceExtendAboveCandle * Point(); double resistanceLowerEdgeExtendActual = resistanceLowerEdgeExtend * Point(); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double stopLossAboveWickByActual = stopLossAboveWickBy * Point() ; double stopLossUnderWickByActual = stopLossUnderWickBy * Point() ; double cleanRangeUponEntryActual = cleanRangeUponEntry * Point() ; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double rangeDistanceBetweenZonesActual_H4 = rangeDistanceBetweenZones_4H * Point(); double rangeDistanceBetweenZonesActual_H1 = rangeDistanceBetweenZones_H1 * Point(); double rangeDistanceBetweenZonesActual_M30 = rangeDistanceBetweenZones_M30 * Point(); double maxPipsRiskAmountActual = maxPipsRiskAmount * Point(); double firstPartialProfitInPipsActual = firstPartialProfitInPips * Point(); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color,ZoneContainer& zoneContainer, double _rangeDistanceBetweenZonesActual, int _timeFrameZoneCounterFactor) { if(resistancePatternFormed(timeFrame)) // if resistance formed { // create a rectangle with a unique name int currentIdCounter = zoneContainer.getZonesIdCounter() + _timeFrameZoneCounterFactor; datetime _leftEdge = iTime(_Symbol,timeFrame,2); //datetime _rightEdge = D'2023.11.01 00:00:00'; datetime _rightEdge = rightEdge; double resistancePrice = iOpen(_Symbol,timeFrame,1); double _higherEdgePrice = resistancePrice + resistanceExtendAboveCandleActual; double _lowerEdgePrice = resistancePrice - resistanceLowerEdgeExtendActual ; string _zoneId = IntegerToString(currentIdCounter); if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= _rangeDistanceBetweenZonesActual)) // check if it has a clean range above { Zone* newZone = new Zone(_zoneId,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; zoneContainer.addResistanceZoneTiger(newZone); zoneContainer.incrementZonesIdCounter(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandleActual,resistancePrice - resistanceLowerEdgeExtendActual,BOS_zone_color); } else if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < _rangeDistanceBetweenZonesActual)) // if it doesnt have a clean range, just add it as a blue zone { Zone* newZone = new Zone(_zoneId,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_NORMAL") ; zoneContainer.addResistanceZoneTiger(newZone); zoneContainer.incrementZonesIdCounter(); } else if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre { int result = detectAndDrawFirstResistanceZoneHigherThan(resistancePrice + resistanceExtendAboveCandleActual, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color,_rangeDistanceBetweenZonesActual,_timeFrameZoneCounterFactor); if(result == 1) { int currentIdCounter = zoneContainer.getZonesIdCounter() + _timeFrameZoneCounterFactor ; string currentIdCounterStr = IntegerToString(currentIdCounter); Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; zoneContainer.addResistanceZoneTiger(newZone); zoneContainer.incrementZonesIdCounter(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandleActual,resistancePrice - resistanceLowerEdgeExtendActual,BOS_zone_color); } else if(result == 0) { int currentIdCounter = zoneContainer.getZonesIdCounter() + _timeFrameZoneCounterFactor ; string currentIdCounterStr = IntegerToString(currentIdCounter); Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_NORMAL") ; zoneContainer.addResistanceZoneTiger(newZone); zoneContainer.incrementZonesIdCounter(); } else if(result == 2) { int currentIdCounter = zoneContainer.getZonesIdCounter() + _timeFrameZoneCounterFactor ; string currentIdCounterStr = IntegerToString(currentIdCounter); Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; zoneContainer.addResistanceZoneTiger(newZone); zoneContainer.incrementZonesIdCounter(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandleActual,resistancePrice - resistanceLowerEdgeExtendActual,BOS_zone_color); } } if(allResistancesAreNormalType(zoneContainer)) // if all resistances are type normal , then find the first resistance higher than the current highest resistance { double highestResistanceZonePrice = zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() ; int res = detectAndDrawFirstResistanceZoneHigherThan(highestResistanceZonePrice, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color,_rangeDistanceBetweenZonesActual,_timeFrameZoneCounterFactor); if(res == 1) { if((zoneContainer.getNumberOfActiveZones()-2) >= 0) { zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-2).setType("TYPE_RESISTANCE_BREAKOUT"); // we choose the second cell from the end, because in the last index now sits the new higher zone created by the previous function call. } } else if(res == 0) { if((zoneContainer.getNumberOfActiveZones()-2) >= 0) { deleteZoneGuiOnly(zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-2).getId(),zoneContainer); } } else if(res == 2) { zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).setType("TYPE_RESISTANCE_BREAKOUT"); } } return true ; } return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color,ZoneContainer& zoneContainer, double _rangeDistanceBetweenZonesAcual, int _timeFrameZoneCounterFactor) { if(supportPatternFormed(timeFrame)) // if support formed { // create a rectangle with a unique name int currentIdCounter = zoneContainer.getSupportZonesIdCounter() + _timeFrameZoneCounterFactor; datetime _leftEdge = iTime(_Symbol,timeFrame,2); datetime _rightEdge =rightEdge; double supportPrice = iOpen(_Symbol,timeFrame,1); double _higherEdgePrice = supportPrice + supportHigherEdgeExtendActual; double _lowerEdgePrice = supportPrice - supportExtendBelowCandleActual; string _zoneId = IntegerToString(currentIdCounter); if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= _rangeDistanceBetweenZonesAcual)) // check if it has a clean range down { Zone* newZone = new Zone(_zoneId,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; zoneContainer.addSupportZoneTiger(newZone); zoneContainer.incrementZonesIdCounterSupport(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtendActual,supportPrice- supportExtendBelowCandleActual,BOS_zone_color); } else if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < _rangeDistanceBetweenZonesAcual)) // if it doesnt have a clean range, just add it as a blue zone { Zone* newZone = new Zone(_zoneId,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_NORMAL") ; zoneContainer.addSupportZoneTiger(newZone); zoneContainer.incrementZonesIdCounterSupport(); } else if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre { // Add the old lower support zone before adding the new support zone. int result = detectAndDrawFirstSupportZoneLowerThan(supportPrice - supportExtendBelowCandleActual, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color,_rangeDistanceBetweenZonesAcual,_timeFrameZoneCounterFactor); if(result == 1) // means if found a lower zone and the range is clean { int currentIdCounter = zoneContainer.getSupportZonesIdCounter() + _timeFrameZoneCounterFactor; string currentIdCounterStr = IntegerToString(currentIdCounter); Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; zoneContainer.addSupportZoneTiger(newZone); zoneContainer.incrementZonesIdCounterSupport(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtendActual,supportPrice - supportExtendBelowCandleActual,BOS_zone_color); } else if(result == 0) // means found a lower zone but the range is not clean { int currentIdCounter = zoneContainer.getSupportZonesIdCounter() + _timeFrameZoneCounterFactor; string currentIdCounterStr = IntegerToString(currentIdCounter); Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_NORMAL") ; zoneContainer.addSupportZoneTiger(newZone); zoneContainer.incrementZonesIdCounterSupport(); } else if(result == 2) // means didnt find a lower zone { int currentIdCounter = zoneContainer.getSupportZonesIdCounter() + _timeFrameZoneCounterFactor; string currentIdCounterStr = IntegerToString(currentIdCounter); Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; zoneContainer.addSupportZoneTiger(newZone); zoneContainer.incrementZonesIdCounterSupport(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtendActual,supportPrice - supportExtendBelowCandleActual,BOS_zone_color); } } if(allSupportsAreNormalType(zoneContainer)) // if all supports are type normal , then find the first support lower than the current lowest. { double lowestSupportPrice = zoneContainer.getZoneByIndex(0).getLowerEdge() ; int res = detectAndDrawFirstSupportZoneLowerThan(lowestSupportPrice, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color,_rangeDistanceBetweenZonesAcual,_timeFrameZoneCounterFactor) ; if(res == 1) // if we found lower support than the current lower, and the range is valid, then keep both { zoneContainer.getZoneByIndex(1).setType("TYPE_SUPPORT_BREAKOUT"); // we choose index 1, because in index 0 now sits the new lower zone created by the previous function call. } else if(res == 0) // if we found a lower support than the current lowest but the range is not valid, then keep only the lower one { if(zoneContainer.getNumberOfActiveZones() > 1) { zoneContainer.getZoneByIndex(1).setType("TYPE_SUPPORT_NORMAL"); deleteZoneGuiOnly(zoneContainer.getZoneByIndex(1).getId(),zoneContainer); } } else if(res == 0) { zoneContainer.getZoneByIndex(0).setType("TYPE_SUPPORT_NORMAL"); } } return true ; } return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int detectAndDrawFirstResistanceZoneHigherThan(double currentHigherResistancePrice, ENUM_TIMEFRAMES timeFrame,int _firstZoneShift,ZoneContainer& zoneContainer,string timeFrameStr, long BOS_zone_color,double _rangeDistanceBetweenZonesAcual, int _timeFrameZoneCounterFactor) { for(int i=3 ; i< _firstZoneShift; i++) { if(resistancePatternFormed(timeFrame,i)) // if old resistance found { // create a rectangle with a unique name int currentIdCounter = zoneContainer.getZonesIdCounter() + _timeFrameZoneCounterFactor ; string currentIdCounterStr = IntegerToString(currentIdCounter); datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); datetime _rightEdge = rightEdge; double resistancePrice = iOpen(_Symbol,timeFrame,i+1); double _higherEdgePrice = resistancePrice + resistanceExtendAboveCandleActual; double _lowerEdgePrice = resistancePrice - resistanceLowerEdgeExtendActual ; if((resistancePrice > currentHigherResistancePrice) && ((resistancePrice - currentHigherResistancePrice) > _rangeDistanceBetweenZonesAcual)) // this means the range is valid { if(MODE_WICKS_INCLUDED) { Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; zoneContainer.addHistoryResistanceZoneOnTop(newZone); zoneContainer.incrementZonesIdCounter(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); } else { Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_NORMAL") ; zoneContainer.addHistoryResistanceZoneOnTop(newZone); zoneContainer.incrementZonesIdCounter(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); } return 1 ; // range is valid so return 1 } else if((resistancePrice > currentHigherResistancePrice) && !((resistancePrice - currentHigherResistancePrice) > _rangeDistanceBetweenZonesAcual)) // the range is not valid, this means draw only the old one { if(MODE_WICKS_INCLUDED) { Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; zoneContainer.addHistoryResistanceZoneOnTop(newZone); zoneContainer.incrementZonesIdCounter(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); } else { Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_NORMAL") ; zoneContainer.addHistoryResistanceZoneOnTop(newZone); zoneContainer.incrementZonesIdCounter(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); } return 0 ; // range is not valid , so return 0 } } } return 2; // this is the case that we didnt find a zone above the current highest zone, which means the current highest zone now, will be breakout zone } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int detectAndDrawFirstSupportZoneLowerThan(double currentLowerSupportPrice, ENUM_TIMEFRAMES timeFrame,int _firstZoneShift,ZoneContainer& zoneContainer,string timeFrameStr, long BOS_zone_color, double _rangeDistanceBetweenZonesAcual, int _timeFrameZoneCounterFactor) { int result = 2 ; for(int i=3 ; i< _firstZoneShift; i++) { if(supportPatternFormed(timeFrame,i)) // if old support found { // create a rectangle with a unique name int currentIdCounter = zoneContainer.getSupportZonesIdCounter() + _timeFrameZoneCounterFactor ; string currentIdCounterStr = IntegerToString(currentIdCounter); datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); datetime _rightEdge = rightEdge; double supportPrice = iOpen(_Symbol,timeFrame,i+1); double _higherEdgePrice = supportPrice + supportHigherEdgeExtendActual; double _lowerEdgePrice = supportPrice - supportExtendBelowCandleActual ; if((supportPrice < currentLowerSupportPrice) && ((currentLowerSupportPrice - supportPrice) > _rangeDistanceBetweenZonesAcual)) // this means the range is valid { if(MODE_WICKS_INCLUDED) { Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; zoneContainer.addHistorySupportZoneAtBottom(newZone); zoneContainer.incrementZonesIdCounterSupport(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); } else { Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_NORMAL") ; zoneContainer.addHistorySupportZoneAtBottom(newZone); zoneContainer.incrementZonesIdCounterSupport(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); } return 1 ; } else if((supportPrice < currentLowerSupportPrice) && !((currentLowerSupportPrice - supportPrice) > _rangeDistanceBetweenZonesAcual)) // the range is not valid, this means draw only the old one { if(MODE_WICKS_INCLUDED) { Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; zoneContainer.addHistorySupportZoneAtBottom(newZone); zoneContainer.incrementZonesIdCounterSupport(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); } else { Zone* newZone = new Zone(currentIdCounterStr,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_NORMAL") ; zoneContainer.addHistorySupportZoneAtBottom(newZone); zoneContainer.incrementZonesIdCounterSupport(); objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); } return 0 ; } } } return 2 ; // this is the case that we didnt find a zone below the current lowest zone, which means the lowest zone now, will be breakout zone } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool allSupportsAreNormalType(ZoneContainer& zoneContainer) { for(int i=0 ; i< zoneContainer.getNumberOfActiveZones() ; i++) { if(zoneContainer.getZoneByIndex(i).getType() == "TYPE_SUPPORT_BREAKOUT") { return false ; } } return true ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool allResistancesAreNormalType(ZoneContainer& zoneContainer) { for(int i=0 ; i< zoneContainer.getNumberOfActiveZones() ; i++) { if(zoneContainer.getZoneByIndex(i).getType() == "TYPE_RESISTANCE_BREAKOUT") { return false ; } } return true ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void updateNormalZonesSupport(ZoneContainer& zoneContainer_Support,ENUM_TIMEFRAMES timeFrame,string timeFrameStr, long _color, double _rangeDistanceBetweenZonesAcual, int _timeFrameZoneCounterFactor) { if(allSupportsAreNormalType(zoneContainer_Support)) // if all supports are type normal , then find the first support lower than the current lowest. { double lowestSupportPrice = zoneContainer_Support.getZoneByIndex(0).getLowerEdge() ; int res = detectAndDrawFirstSupportZoneLowerThan(lowestSupportPrice, timeFrame,firstZoneShift, zoneContainer_Support, timeFrameStr,_color,_rangeDistanceBetweenZonesAcual,_timeFrameZoneCounterFactor) ; if(res == 1) // if we found lower support than the current lower, and the range is valid, then keep both { zoneContainer_Support.getZoneByIndex(1).setType("TYPE_SUPPORT_BREAKOUT"); // we choose index 1, because in index 0 now sits the new lower zone created by the previous function call. } else if(res == 0) // if we found a lower support than the current lowest but the range is not valid, then keep only the lower one { if(zoneContainer_Support.getNumberOfActiveZones() > 1) { zoneContainer_Support.getZoneByIndex(1).setType("TYPE_SUPPORT_NORMAL"); deleteZoneGuiOnly(zoneContainer_Support.getZoneByIndex(1).getId(),zoneContainer_Support); } } else if(res == 2) { zoneContainer_Support.getZoneByIndex(0).setType("TYPE_SUPPORT_BREAKOUT"); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void updateNormalZonesResistance(ZoneContainer& zoneContainer_Resistance,ENUM_TIMEFRAMES timeFrame,string timeFrameStr, long _color, double _rangeDistanceBetweenZonesAcual, int _timeFrameZoneCounterFactor) { if(allResistancesAreNormalType(zoneContainer_Resistance)) // if all resistances are type normal , then find the first resistance higher than the current highest resistance { double highestResistanceZonePrice = zoneContainer_Resistance.getZoneByIndex(zoneContainer_Resistance.getNumberOfActiveZones()-1).getHigherEdge() ; int res = detectAndDrawFirstResistanceZoneHigherThan(highestResistanceZonePrice, timeFrame,firstZoneShift, zoneContainer_Resistance, timeFrameStr,_color,_rangeDistanceBetweenZonesAcual,_timeFrameZoneCounterFactor); if(res == 1) { if((zoneContainer_Resistance.getNumberOfActiveZones()-2) >= 0) { zoneContainer_Resistance.getZoneByIndex(zoneContainer_Resistance.getNumberOfActiveZones()-2).setType("TYPE_RESISTANCE_BREAKOUT"); // we choose the second cell from the end, because in the last index now sits the new higher zone created by the previous function call. } } else if(res == 0) { if((zoneContainer_Resistance.getNumberOfActiveZones()-2) >= 0) { deleteZoneGuiOnly(zoneContainer_Resistance.getZoneByIndex(zoneContainer_Resistance.getNumberOfActiveZones()-2).getId(),zoneContainer_Resistance); } } else if(res == 2) { zoneContainer_Resistance.getZoneByIndex(zoneContainer_Resistance.getNumberOfActiveZones()-1).setType("TYPE_RESISTANCE_BREAKOUT"); } } } //+------------------------------------------------------------------+ void deleteZoneWithGUI(string _id, ZoneContainer& zoneContainer) { zoneContainer.deleteZone(_id); if(!ObjectDelete(_Symbol,_id)) { Print("Failed to delete object error: " + GetLastError()); } Print("Deleted the zone with gui!"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void deleteZoneGuiOnly(string _id,ZoneContainer& zoneContainer) { if(!ObjectDelete(_Symbol,_id)) { Print("Failed to delete object error: " + GetLastError()); } Print("Deleted the zone gui!"); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool updateBreakAboveStructureAndDelete(ZoneContainer& zoneContainer, ENUM_TIMEFRAMES timeFrame, string timeFrameStr, double& brokenResistanceLowerEdge, string& type) { bool finishedDeleting = false ; if(zoneContainer.getNumberOfActiveZones() != 0) // if there are zones found { if(marketObserverTiger.candleClosedAboveResistanceByIndex(0,timeFrame,zoneContainer)) // check if candle closed above the zone { datetime _leftEdgeRestestZone = iTime(_Symbol,timeFrame,4); datetime _rightEdgeRetestZone = D'2023.11.01 00:00:00'; while(!finishedDeleting && zoneContainer.getNumberOfActiveZones() != 0) // this while is used in the case of a candle closing above more than 1 zone at once { if(zoneContainer.getNumberOfActiveZones() != 0 && marketObserverTiger.candleClosedAboveResistanceByIndex(0,timeFrame,zoneContainer)) { zoneContainer.getZoneByIndex(0).getHigherEdge(); temporaryRestestSupportZone.setHigherEdgePrice(zoneContainer.getZoneByIndex(0).getHigherEdge()); temporaryRestestSupportZone.setLowerEdgePrice(zoneContainer.getZoneByIndex(0).getLowerEdge()); temporaryRestestSupportZone.setLeftEdge(_leftEdgeRestestZone); temporaryRestestSupportZone.setRightEdge(_rightEdgeRetestZone); temporaryRestestSupportZone.setId("999"); // the + "t" stands for temporary and it is made to keep the zones id's unique temporaryRestestSupportZone.setTimeFrame(timeFrameStr); type = zoneContainer.getZoneByIndex(0).getType(); temporaryRestestSupportZone.setType("TYPE_SUPPORT_TEMPORARY"); brokenResistanceLowerEdge = zoneContainer.getZoneByIndex(0).getLowerEdge(); // save the lower edge of the broken zone, in order to return it in the parameter deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId()),zoneContainer); // delete the zone with the GUI } else { finishedDeleting = true ; } } return true ; } } return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool updateBreakBelowStructureAndDelete(ZoneContainer& zoneContainer, ENUM_TIMEFRAMES timeFrame, string timeFrameStr, double& brokenSupportHigherEdge, string& type) { bool finishedDeleting = false ; if(zoneContainer.getNumberOfActiveZones() != 0) // if there are zones found { if(marketObserverTiger.candleClosedBelowSupportByIndex(zoneContainer.getNumberOfActiveZones() -1,timeFrame,zoneContainer)) // check if candle closed below the zone { datetime _leftEdgeRestestZone = iTime(_Symbol,timeFrame,4); datetime _rightEdgeRetestZone = D'2023.11.01 00:00:00'; while(!finishedDeleting && zoneContainer.getNumberOfActiveZones() != 0) // this while is used in the case of a candle closing above more than 1 zone at once { if(zoneContainer.getNumberOfActiveZones() != 0 && marketObserverTiger.candleClosedBelowSupportByIndex(zoneContainer.getNumberOfActiveZones()-1,timeFrame,zoneContainer)) { zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge(); temporaryRestestSupportZone.setHigherEdgePrice(zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge()); temporaryRestestSupportZone.setLowerEdgePrice(zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getLowerEdge()); temporaryRestestSupportZone.setLeftEdge(_leftEdgeRestestZone); temporaryRestestSupportZone.setRightEdge(_rightEdgeRetestZone); temporaryRestestSupportZone.setId("9999"); // the + "t" stands for temporary and it is made to keep the zones id's unique temporaryRestestSupportZone.setTimeFrame(timeFrameStr); type = zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getType(); temporaryRestestSupportZone.setType("TYPE_RESISTANCE_TEMPORARY"); brokenSupportHigherEdge = zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge(); deleteZoneWithGUI((zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getId()),zoneContainer); // delete the zone with the GUI } else { finishedDeleting = true ; } } return true ; } } return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double findClosestResistancePrice(ZoneContainer& zoneContainer) { double closestResistancePrice = -1; if(zoneContainer.getNumberOfActiveZones() != 0) { closestResistancePrice = zoneContainer.getZoneByIndex(0).getLowerEdge(); } return closestResistancePrice ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double findClosestSupportPrice(ZoneContainer& zoneContainer) { double closestSupportPrice = -1 ; if(zoneContainer.getNumberOfActiveZones() != 0) { closestSupportPrice = zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getLowerEdge(); } return closestSupportPrice ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool buyStopLossUnderZone(double resistanceZoneLowerEdge, double stopLossValue) { if(stopLossValue < resistanceZoneLowerEdge) { return true ; } else { Comment("stop loss is not under the zone im not taking a buy"); return false ; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool sellStopLossAboveZone(double supportZoneHigherEdge, double stopLossValue) { if(stopLossValue > supportZoneHigherEdge) { return true ; } else { Comment("stop loss is not above the zone, so im not taking a sell"); return false ; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void manageRiskIfNeeded() { if(PositionsTotal()!= 0) // There is an active trade { manageRiskOnBuysIfNeeded(); manageRiskOnSellsIfNeeded(); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void manageRiskOnBuysIfNeeded() { if(candleClosedBearish(PERIOD_M15,1) && !bearishCandleIsWeak(PERIOD_M15,1, WICK_RATIO_REJECTION)) { for(int i = 0 ; i < NUM_MAX_ALLOWED_TRADES ; i++) { if((BuyActiveTradesArray[i] != NULL) && !(BuyActiveTradesArray[i].riskAlreadyManaged())) // if the trade still hasnt managead risk , then do it now. { closePartialFromSpecificPosition(BuyActiveTradesArray[i].getTradeId(),riskManagementPartial); BuyActiveTradesArray[i].manageRisk(); } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void manageRiskOnSellsIfNeeded() { if(candleClosedBullish(PERIOD_M15,1) && !bullishCandleIsWeak(PERIOD_M15,1, WICK_RATIO_REJECTION)) { for(int i = 0 ; i < NUM_MAX_ALLOWED_TRADES ; i++) { if((SellActiveTradesArray[i] != NULL) && !(SellActiveTradesArray[i].riskAlreadyManaged())) // if the trade still hasnt managead risk , then do it now. { closePartialFromSpecificPosition(SellActiveTradesArray[i].getTradeId(),riskManagementPartial); SellActiveTradesArray[i].manageRisk(); } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void secureProfitIfNeeded() { if(PositionsTotal() != 0) // if there are active trades { secureProfitOnBuysIfNeeded(); secureProfitOnSellsIfNeeded(); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void secureProfitOnBuysIfNeeded() { for(int i=0 ; i< NUM_MAX_ALLOWED_TRADES ; i++) { if((BuyActiveTradesArray[i] != NULL) && !(BuyActiveTradesArray[i].firstPartialIsSecured())) // if first partial is not yet secured for the current position { double currentProfit = positionProfitInPips(BuyActiveTradesArray[i].getTradeId()); if(currentProfit >= firstPartialProfitInPipsActual) { closePartialFromSpecificPosition(BuyActiveTradesArray[i].getTradeId(),firstPartialCloseFactor) ; BuyActiveTradesArray[i].secureFirstPartial(); } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void secureProfitOnSellsIfNeeded() { for(int i=0 ; i< NUM_MAX_ALLOWED_TRADES ; i++) { if((SellActiveTradesArray[i] != NULL) && !(SellActiveTradesArray[i].firstPartialIsSecured())) // if first partial is not yet secured for the current position { double currentProfit = positionProfitInPips(SellActiveTradesArray[i].getTradeId()); if(currentProfit >= firstPartialProfitInPipsActual) { closePartialFromSpecificPosition(SellActiveTradesArray[i].getTradeId(),firstPartialCloseFactor) ; SellActiveTradesArray[i].secureFirstPartial(); } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int findAvailableSpotInBuyManagerArr() // returns the index , or -1 if all are full { for(int i=0 ; i < NUM_MAX_ALLOWED_TRADES ; i++) { if(BuyActiveTradesArray[i] == NULL) { return i; } } return -1 ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int findAvailableSpotInSellManagerArr() // returns the index , or -1 if all are full { for(int i=0 ; i positionStopLoss(BuyActiveTradesArray[i].getTradeId())) // if new stop loss is higher than the current position's stop loss { if(SymbolInfoDouble(_Symbol,SYMBOL_BID) <= newStopLoss){ // close the trade because the bid is lower than the stop loss (and the modify will fail)) tradeLong.PositionClose(BuyActiveTradesArray[i].getTradeId()); } positionTrailStopLoss(BuyActiveTradesArray[i].getTradeId(),newStopLoss,0); } } if((SellActiveTradesArray[i] != NULL)) // CHECK TRAIL FOR SELLS { double newStopLoss = iHigh(_Symbol,_timeFrame,1); newStopLoss = newStopLoss + stopLossAboveWickByActual ; if(newStopLoss < positionStopLoss(SellActiveTradesArray[i].getTradeId())) // if new stop loss is lower than the current position's stop loss { if(SymbolInfoDouble(_Symbol,SYMBOL_ASK) >= newStopLoss){ // close the trade because the ask is higher than the stop loss (and the modify will fail)) tradeShort.PositionClose(SellActiveTradesArray[i].getTradeId()); } positionTrailStopLoss(SellActiveTradesArray[i].getTradeId(),newStopLoss,0); } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ /*int bottomWickIsValid() { double previousCandleBodySize = iClose(_Symbol,PERIOD_M30,1) - iOpen(_Symbol,PERIOD_M30,1) ; double currentWickSize = iOpen(_Symbol,PERIOD_M30,0) - iLow(_Symbol,PERIOD_M30,0); if((iHigh(_Symbol,PERIOD_M30,0) - iOpen(_Symbol,PERIOD_M30,0)) > preWickPush) // this case we would not take the trade at all, because pushed too much in the beggining of the candle { return 0; } else if(currentWickSize < previousCandleBodySize * retracementWickFibMeasure) // this case we would wait until the wick size becomes valid { return 1 ; } else if(SymbolInfoDouble(_Symbol,SYMBOL_ASK) > iOpen(_Symbol,PERIOD_M30,0)) { return -1 ; } return 2 ; // this case means the wick that was formed is healthy and we only need the price to reach the candle open in order to check the trade and execute } */ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ /* int handleBottomWickValidation() { int result = bottomWickIsValid() ; if(result == 0) // not considering the trade { Comment("not considering the trade"); } else if(result == 1) // the wick was formed however its not big enough, so we need to wait more (call bottomWickIsValid() again)) { Comment("bottom wick is too small, lets wait to see if it becomes valid"); } else if(result == 2) // the wick was formed and it satisfies the conditions, so now just wait for the price to reach the candle open { Comment("bottom wick is valid, im waiting the price to reach the candle open in order to consider executing"); } else if(result == -1) { Comment("Price has already moved !"); } return result ; } */ /*void updateBottomWickState(int bottomWickValidationState) { datetime currTime = TimeCurrent(); switch(bottomWickValidationState) { case -1 : // not considering the trade because price already moved Comment(TimeToString(currTime,TIME_MINUTES) + ": not considering the trade because price already moved"); waitForBottomWickToForm = false ; wickLengthCounter = 0; break; case 0 : // not considering the trade because price pushed too much upwards before the wick formed Comment(TimeToString(currTime,TIME_MINUTES) + ": not considering the trade because price pushed too much upwards before the wick formed"); waitForBottomWickToForm = false ; wickLengthCounter = 0; break; case 1: // bottom wick has formed but its too small, lets wait for it to become valid Comment(TimeToString(currTime,TIME_MINUTES) + ": bottom wick has formed but its too small, lets wait for it to become valid"); break; case 2 : // bottom wick has formed and its healthy, lets wait for price to reach candle entry, in order to check sl Comment(TimeToString(currTime,TIME_MINUTES) + ": bottom wick has formed and its healthy, lets wait for price to reach candle entry, in order to check sl"); waitForBottomWickToForm = false ; wickLengthCounter = 0; bottomWickFormed = true ; buyStopPrice = iHigh(_Symbol,PERIOD_CURRENT,0) + stopOrderFactor ; break; } } */ /*int topWickIsValid() { double previousCandleBodySize = iOpen(_Symbol,PERIOD_M30,1) - iClose(_Symbol,PERIOD_M30,1); double currentWickSize = iHigh(_Symbol,PERIOD_M30,0) - iOpen(_Symbol,PERIOD_M30,0); if((iOpen(_Symbol,PERIOD_M30,0) - iLow(_Symbol,PERIOD_M30,0)) > preWickPush) // this case we would not take the trade at all { return 0; } else if(currentWickSize < retracementWickFibMeasure * previousCandleBodySize) // this case we would wait until the wick size becomes valid { return 1 ; } else if(SymbolInfoDouble(_Symbol,SYMBOL_BID) < iOpen(_Symbol,PERIOD_M30,0)) { return -1 ; } return 2 ; // this case means the wick that was formed is healthy and we only need the price to reach the candle open in order to check the trade and execute } */ //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ /* int handleTopWickValidation() { int result = topWickIsValid() ; if(result == 0) // not considering the trade { Comment("not considering the trade"); } else if(result == 1) // the wick was formed however its not big enough, so we need to wait more { Comment("top wick is too small, lets wait to see if it becomes valid"); } else if(result == 2) // the wick was formed and it satisfies the conditions, so now just wait for the price to reach the candle open { Comment("top wick is valid, im waiting the price to reach the candle open in order to consider executing"); } else if(result == -1) { Comment("Price has already moved !"); } return result ; } */ //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ /* void updateTopWickState(int topWickValidationState) { datetime currTime = TimeCurrent(); switch(topWickValidationState) { case -1 : // not considering the trade because price already moved Comment(TimeToString(currTime,TIME_MINUTES) + ": not considering the trade because price already moved"); waitForTopWickToForm = false ; wickLengthCounter = 0; break; case 0 : // not considering the trade because price pushed too much downwards before the wick formed Comment(TimeToString(currTime,TIME_MINUTES) + ": not considering the trade because price pushed too much downwards before the wick formed"); waitForTopWickToForm = false ; wickLengthCounter = 0; break; case 1: // top wick has formed but its too small, lets wait for it to become valid Comment(TimeToString(currTime,TIME_MINUTES) + ": top wick has formed but its too small, lets wait for it to become valid"); break; case 2 : // top wick has formed and its healthy, lets wait for price to reach candle low, in order to check sl Comment(TimeToString(currTime,TIME_MINUTES) + ": top wick has formed and its healthy, lets wait for price to reach candle low, in order to check sl"); waitForTopWickToForm = false ; wickLengthCounter = 0; topWickFormed = true ; sellStopPrice = iLow(_Symbol,PERIOD_CURRENT,0) - stopOrderFactor ; break; } } */ //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void handleBullishBreakouts(ZoneContainer& _zoneContainer, ENUM_TIMEFRAMES _timeFrame,string _timeFrameStr) { double brokenResistanceLowerPrice = -1 ; string brokenZoneTypeResistance = "" ; if(updateBreakAboveStructureAndDelete(_zoneContainer,_timeFrame,_timeFrameStr,brokenResistanceLowerPrice,brokenZoneTypeResistance)) { if(_timeFrameStr == "PERIOD_H4") { last_H4_candle_broke_structure = true ; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void handleBearishBreakouts(ZoneContainer& _zoneContainer, ENUM_TIMEFRAMES _timeFrame,string _timeFrameStr) { double brokenSupportHigherPrice = -1; string brokenZoneTypeSupport = "" ; if(updateBreakBelowStructureAndDelete(_zoneContainer,_timeFrame,_timeFrameStr,brokenSupportHigherPrice,brokenZoneTypeSupport)) { if(_timeFrameStr == "PERIOD_H4") { last_H4_candle_broke_structure = true ; } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void handleBuys(ZoneContainer& _zoneContainer, ENUM_TIMEFRAMES _timeFrame,string _timeFrameStr, double _cleanRangeUponEntryActual) { double brokenResistanceLowerPrice = -1 ; string brokenZoneTypeResistance = "" ; if(updateBreakAboveStructureAndDelete(_zoneContainer,_timeFrame,_timeFrameStr,brokenResistanceLowerPrice,brokenZoneTypeResistance) && buyBreakerCandleIsValid(_timeFrame, SIZE_OF_BREAKER_CANDLE_BODY) && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_ALLOWED) || (sessionIsTokyo() && TRADE_TOKYO_ALLOWED)) && BUYS_ALLOWED) // means M30 candle broke structure, and the breaker candle is valid (big enough),and time is in the sessions (ny or london or both, based on what the user chose)) { if(brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") { int indexToNewTrade ; if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result { if(H4TimeFrameConfirmedBuys() && validateCleanRangeBuys_H4() && validateCleanRangeBuys_H1() && validateCleanRangeBuys_M30()) { double stopLossPrice ; if((stopLossPrice = findAndValidateStopLossBuys(_timeFrameStr,maxPipsRiskAmountActual))!= -1) { double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossPrice); activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossPrice) ; BuyTradeManagerTiger* tempTigerManager= new BuyTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger BuyActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array buysCount++; Comment("Took a buy. stop loss: based on "+ _timeFrameStr + " Active trade id: " + activeTradeId); } } } else { Comment("I cant take a buy because the trades array is full"); } } else { datetime currTime = TimeCurrent(); string timeInStr = TimeToString(currTime,TIME_MINUTES); Comment(timeInStr+ ": Cant take a buy, because the broken resistance zone is not a break out zone !"); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double findAndValidateStopLossBuys(string _timeFrameStr,double _maxPipsRiskAmountActual) { if(_timeFrameStr == "PERIOD_H4") { double stopLossBased_H4 = iLow(_Symbol,PERIOD_H4,1); stopLossBased_H4 = stopLossBased_H4 - stopLossUnderWickByActual ; if(stopLossIsValidBuys(stopLossBased_H4,_maxPipsRiskAmountActual)) { return stopLossBased_H4 ; } Comment("Cant take a buy, because stop loss is not valid"); return -1 ; } else if(_timeFrameStr == "PERIOD_H1") { double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickByActual ; double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickByActual ; if(stopLossIsValidBuys(stopLossBased_H1,_maxPipsRiskAmountActual)) { return stopLossBased_H1 ; } else if(stopLossIsValidBuys(stopLossBased_M30,_maxPipsRiskAmountActual)) { return stopLossBased_M30 ; } Comment("Cant take a buy, because stop loss is not valid"); return -1 ; } else if(_timeFrameStr == "PERIOD_M30") { double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickByActual ; double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickByActual ; if(stopLossIsValidBuys(stopLossBased_M30,_maxPipsRiskAmountActual)) { return stopLossBased_M30 ; } else if(stopLossIsValidBuys(stopLossBased_M15,_maxPipsRiskAmountActual)) { return stopLossBased_M15 ; } Comment("Cant take a buy, because stop loss is not valid"); return -1 ; } Comment("Cant take a buy, because stop loss is not valid"); return -1 ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void handleSells(ZoneContainer& _zoneContainer, ENUM_TIMEFRAMES _timeFrame,string _timeFrameStr, double _cleanRangeUponEntryActual) { double brokenSupportHigherPrice = -1; string brokenZoneTypeSupport = "" ; if(updateBreakBelowStructureAndDelete(_zoneContainer,_timeFrame,_timeFrameStr,brokenSupportHigherPrice,brokenZoneTypeSupport) && sellBreakerCandleIsValid(_timeFrame, SIZE_OF_BREAKER_CANDLE_BODY) && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_ALLOWED) || (sessionIsTokyo() && TRADE_TOKYO_ALLOWED)) && SELLS_ALLOWED) // means M30 candle broke structure, and the breaker candle is valid (big enough),and time is in the sessions (ny or london or both, based on what the user chose)) { if(brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") { int indexToNewTrade ; if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) // find a spot in the trades array, and save the result { if(H4TimeFrameConfirmedSells() && validateCleanRangesSells_H4() && validateCleanRangeSells_H1() && validateCleanRangeSells_M30()) { double stopLossPrice ; if((stopLossPrice = findAndValidateStopLossSells(_timeFrameStr,maxPipsRiskAmountActual))!= -1) { double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossPrice); activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossPrice) ; SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array sellsCount++; Comment("Took a sell. stop loss: based on "+ _timeFrameStr + " Active trade id: " + activeTradeId); } } } else { Comment("I cant take a sell because the trades array is full"); } } else { datetime currTime = TimeCurrent(); string timeInStr = TimeToString(currTime,TIME_MINUTES); Comment(timeInStr+ ": Cant take a sell, because the broken resistance zone is not a break out zone !"); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double findAndValidateStopLossSells(string _timeFrameStr,double _maxPipsRiskAmountActual) { if(_timeFrameStr == "PERIOD_H4") { double stopLossBased_H4 = iHigh(_Symbol,PERIOD_H4,1); stopLossBased_H4 = stopLossBased_H4 + stopLossUnderWickByActual ; if(stopLossIsValidSells(stopLossBased_H4,_maxPipsRiskAmountActual)) { return stopLossBased_H4 ; } Comment("Cant take a sell because stop loss is not valid !"); return -1 ; } else if(_timeFrameStr == "PERIOD_H1") { double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickByActual ; double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickByActual ; if(stopLossIsValidSells(stopLossBased_H1,_maxPipsRiskAmountActual)) { return stopLossBased_H1 ; } else if(stopLossIsValidSells(stopLossBased_M30,_maxPipsRiskAmountActual)) { return stopLossBased_M30 ; } Comment("Cant take a sell because stop loss is not valid !"); return -1 ; } else if(_timeFrameStr == "PERIOD_M30") { double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); stopLossBased_M30 = stopLossBased_M30 + stopLossUnderWickByActual ; double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); stopLossBased_M15 = stopLossBased_M15 + stopLossUnderWickByActual ; if(stopLossIsValidSells(stopLossBased_M30,_maxPipsRiskAmountActual)) { return stopLossBased_M30 ; } else if(stopLossIsValidSells(stopLossBased_M15,_maxPipsRiskAmountActual)) { return stopLossBased_M15 ; } Comment("Cant take a sell because stop loss is not valid !"); return -1 ; } Comment("Cant take a sell because stop loss is not valid !"); return -1 ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool H4TimeFrameConfirmedBuys() { if(!H4_Break_Confirmation && !H4_Closure_Confirmation) // if the user doesnt want any 4H confirmation, return true . now the code understands that its not necessecary to look at the 4H confirmation. { return true ; } if((H4_Closure_Confirmation && candleClosedBullish(PERIOD_H4,1)) && !H4_Break_Confirmation) // if the user wants only 4H closure confirmation { return true ; } else if(candleClosedBullish(PERIOD_H4,1) && (H4_Break_Confirmation && last_H4_candle_broke_structure)) // if the user wants a 4H breakout confirmation (which includes the closure confirmation too) { Print("Price broke structure on H4"); return true ; } return false ; // all other cases return false, which means the 4H confirmation conditon wast not satisfied. } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool H4TimeFrameConfirmedSells() { if(!H4_Break_Confirmation && !H4_Closure_Confirmation) // if the user doesnt want any 4H confirmation, return true . now the code understands that its not necessecary to look at the 4H confirmation. { return true ; } if((H4_Closure_Confirmation && candleClosedBearish(PERIOD_H4,1)) && !H4_Break_Confirmation) // if the user wants only 4H closure confirmation { return true ; } else if(candleClosedBearish(PERIOD_H4,1) && (H4_Break_Confirmation && last_H4_candle_broke_structure)) // if the user wants a 4H breakout confirmation (which includes the closure confirmation too) { Print("Price broke structure on H4"); return true ; } return false ; // all other cases return false, which means the 4H confirmation conditon wast not satisfied. } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool validateCleanRangesBuys() { double nearest_H4_Resistance = findClosestResistancePrice(zoneContainer_H4); double nearest_H1_Resistance = findClosestResistancePrice(zoneContainer_H1); double nearest_M30_Resistance = findClosestResistancePrice(zoneContainer_M30); if((nearest_H4_Resistance >= cleanRangeUponEntryActual) && (nearest_H1_Resistance >= cleanRangeUponEntryActual) && (nearest_M30_Resistance >= cleanRangeUponEntryActual)) { return true ; } return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool validateCleanRangeBuys_H4() { double nearest_H4_Resistance = findClosestResistancePrice(zoneContainer_H4); double cleanRangeValue_H4 = nearest_H4_Resistance - SymbolInfoDouble(_Symbol,SYMBOL_ASK) ; if(((cleanRangeValue_H4 >= cleanRangeUponEntryActual) && (cleanRangeValue_H4 > 0))|| (nearest_H4_Resistance == -1)) { return true ; } datetime currTime = TimeCurrent(); string timeInStr = TimeToString(currTime,TIME_MINUTES); Comment(timeInStr + ": Cant Take a buy, Reason: No Clean Range on H4"); return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool validateCleanRangeBuys_H1() { double nearest_H1_Resistance = findClosestResistancePrice(zoneContainer_H1); double cleanRangeValue_H1 = nearest_H1_Resistance - SymbolInfoDouble(_Symbol,SYMBOL_ASK) ; if(((cleanRangeValue_H1 >= cleanRangeUponEntryActual) && (cleanRangeValue_H1 > 0))|| (nearest_H1_Resistance == -1)) { return true ; } datetime currTime = TimeCurrent(); string timeInStr = TimeToString(currTime,TIME_MINUTES); Comment(timeInStr + ": Cant Take a buy, Reason: No Clean Range on H1"); return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool validateCleanRangeBuys_M30() { double nearest_M30_Resistance = findClosestResistancePrice(zoneContainer_M30); double cleanRangeValue_M30 = nearest_M30_Resistance - SymbolInfoDouble(_Symbol,SYMBOL_ASK) ; if(((cleanRangeValue_M30 >= cleanRangeUponEntryActual) && (cleanRangeValue_M30 > 0))|| (nearest_M30_Resistance == -1)) { return true ; } datetime currTime = TimeCurrent(); string timeInStr = TimeToString(currTime,TIME_MINUTES); Comment(timeInStr + ": Cant Take a buy, Reason: No Clean Range on M30"); return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool validateCleanRangesSells_H4() { double nearest_H4_Support = findClosestSupportPrice(zoneContainerSupport_H4); double cleanRangeValue_H4 = SymbolInfoDouble(_Symbol,SYMBOL_BID) - nearest_H4_Support ; if(((cleanRangeValue_H4 >= cleanRangeUponEntryActual) && (cleanRangeValue_H4 > 0))|| (nearest_H4_Support == -1)) { return true ; } datetime currTime = TimeCurrent(); string timeInStr = TimeToString(currTime,TIME_MINUTES); Comment(timeInStr + ": Cant Take a sell, Reason: No Clean Range on H4"); return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool validateCleanRangeSells_H1() { double nearest_H1_Support = findClosestSupportPrice(zoneContainerSupport_H1); double cleanRangeValue_H1 = SymbolInfoDouble(_Symbol,SYMBOL_BID) - nearest_H1_Support ; if(((cleanRangeValue_H1 >= cleanRangeUponEntryActual) && (cleanRangeValue_H1 > 0))|| (nearest_H1_Support == -1)) { return true ; } datetime currTime = TimeCurrent(); string timeInStr = TimeToString(currTime,TIME_MINUTES); Comment(timeInStr + ": Cant Take a sell, Reason: No Clean Range on H1"); return false ; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool validateCleanRangeSells_M30() { double nearest_M30_Support = findClosestSupportPrice(zoneContainerSupport_M30); double cleanRangeValue_M30 = SymbolInfoDouble(_Symbol,SYMBOL_BID) - nearest_M30_Support ; if(((cleanRangeValue_M30 >= cleanRangeUponEntryActual) && (cleanRangeValue_M30 > 0))|| (nearest_M30_Support == -1)) { Print("Closest support is: "+ nearest_M30_Support); return true ; } datetime currTime = TimeCurrent(); string timeInStr = TimeToString(currTime,TIME_MINUTES); Comment(timeInStr + ": Cant Take a sell, Reason: No Clean Range on M30"); return false ; } //+------------------------------------------------------------------+