commit 2ff4d9d5691e2d4867b061e7320a60557a72f25d Author: CristianAlam <91946810+CristianAlam@users.noreply.github.com> Date: Fri Jul 11 08:43:07 2025 +0300 Initial comit of TrendBreakouts diff --git a/Algo_Skeleton_Functions.mqh b/Algo_Skeleton_Functions.mqh new file mode 100644 index 0000000..c4c345a --- /dev/null +++ b/Algo_Skeleton_Functions.mqh @@ -0,0 +1,1958 @@ +//+------------------------------------------------------------------+ +//| 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 ; + } + + + + +//+------------------------------------------------------------------+ diff --git a/Breakout_Fractals.ex5 b/Breakout_Fractals.ex5 new file mode 100644 index 0000000..db3bad1 Binary files /dev/null and b/Breakout_Fractals.ex5 differ diff --git a/Breakout_Fractals.mq5 b/Breakout_Fractals.mq5 new file mode 100644 index 0000000..faad5b5 --- /dev/null +++ b/Breakout_Fractals.mq5 @@ -0,0 +1,404 @@ +//+------------------------------------------------------------------+ +//| Breakout_Fractals.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +//#include "Algo_Skeleton_Functions.mqh" +#include "Phoenix_Functions.mqh" + +bool trailWhenMarketOpensDaily = false ; +int OnInit() + { +//--- + +//--- + for(int i=0; i + +CTrade tradeLong ; +class BuyEntryManager + { +private: + + bool longTradeTaken ; + bool waitingForRejectionCandle; + bool waitingForRetracement ; + + + +public: + BuyEntryManager(); + ~BuyEntryManager(); + + BuyRejectionDetector* buyRejectionDetector ; + + bool isWaitingForRejectionCandle(){return waitingForRejectionCandle ;} + void setWaitingForRejectionCandle(bool _setting){waitingForRejectionCandle = _setting ;} + + bool isWaitingForRetracement(){return waitingForRetracement;} + void setWaitingForRetracement(bool _setting){waitingForRetracement = _setting ;} + + bool buyTradeTaken(); + void setTradeTakenStatus(bool _status){longTradeTaken = _status ; Print("long trade taken flag has been set to true");} + + + ulong takeBuyTrade(double _lots,double _stopLoss); + ulong takeBuyTradeTiger(double _lots,double _stopLoss,double _takeProfit); + ulong takeBuyTradeTiger(double _lots,double _stopLoss); + + + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyEntryManager::BuyEntryManager() + { + buyRejectionDetector = new BuyRejectionDetector(); + longTradeTaken = false ; + waitingForRejectionCandle = false ; + waitingForRetracement = false ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyEntryManager::~BuyEntryManager() + { + delete buyRejectionDetector ; + } +//+------------------------------------------------------------------+ + + +bool BuyEntryManager:: buyTradeTaken(){ + + +return longTradeTaken ; +} + + +ulong BuyEntryManager:: takeBuyTrade(double _lots, double _stopLoss){ + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + + +} + + +ulong BuyEntryManager:: takeBuyTradeTiger(double _lots,double _stopLoss, double _takeProft){ // first version, take the buy with fixed tp + + double netTp = _takeProft - SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss,SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTp); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} + + +ulong BuyEntryManager:: takeBuyTradeTiger(double _lots,double _stopLoss){ // second version, take the buy without a fixed tp + + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} + diff --git a/BuyGandalf.mqh b/BuyGandalf.mqh new file mode 100644 index 0000000..f802a88 --- /dev/null +++ b/BuyGandalf.mqh @@ -0,0 +1,85 @@ +//+------------------------------------------------------------------+ +//| BuyGandalf.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include + +CTrade tradeLong ; +class BuyGandalf + { +private: + + bool longTradeTaken ; + ulong longTrades[10] ; + + +public: + BuyGandalf(); + ~BuyGandalf(); + + + + bool buyTradeTaken(); + void setTradeTakenStatus(bool _status){longTradeTaken = _status ; Print("long trade taken flag has been set to true");} + + + ulong takeBuyTrade(double _lots,double _stopLoss); + ulong takeBuyTradeGandalf(double _lots,double _stopLoss); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyGandalf::BuyGandalf() + { + + longTradeTaken = false ; + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyGandalf::~BuyGandalf() + { + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ + + +bool BuyGandalf:: buyTradeTaken(){ + + +return longTradeTaken ; +} + + +ulong BuyGandalf:: takeBuyTrade(double _lots, double _stopLoss){ + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + + +} + + +ulong BuyGandalf:: takeBuyTradeGandalf(double _lots,double _stopLoss){ + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} diff --git a/BuyRejectionDetector.mqh b/BuyRejectionDetector.mqh new file mode 100644 index 0000000..91f0fc3 --- /dev/null +++ b/BuyRejectionDetector.mqh @@ -0,0 +1,53 @@ +//+------------------------------------------------------------------+ +//| BuyRejectionDetector.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class BuyRejectionDetector + { +private: + +public: + BuyRejectionDetector(); + ~BuyRejectionDetector(); + + bool rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame); + bool rejectionByRangeFormed(); + bool rejectionByWicksFormed(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyRejectionDetector::BuyRejectionDetector() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyRejectionDetector::~BuyRejectionDetector() + { + } +//+------------------------------------------------------------------+ + + +bool BuyRejectionDetector:: rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame){ + + double rejectionCandleClose = iClose(_Symbol,_timeFrame,1); + double rejectionCandleOpen = iOpen(_Symbol,_timeFrame,1); + double rejectionCandleHigh = iHigh(_Symbol,_timeFrame,1) ; + double rejectionCandleHigherWickSize ; + double rejectionCandleBodySize ; + + if( rejectionCandleClose > rejectionCandleOpen ){ // the previous candle closed bullish + rejectionCandleHigherWickSize = rejectionCandleHigh - rejectionCandleClose; + rejectionCandleBodySize = rejectionCandleClose - rejectionCandleOpen; + if(rejectionCandleBodySize >= rejectionCandleHigherWickSize){ + return true ; + } + + } + return false ; +} \ No newline at end of file diff --git a/BuyTradeManager.mqh b/BuyTradeManager.mqh new file mode 100644 index 0000000..70e16d4 --- /dev/null +++ b/BuyTradeManager.mqh @@ -0,0 +1,587 @@ +//+------------------------------------------------------------------+ +//| BuyTradeManager.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include +#include +#include +CTrade tradeLongInTradeManager; + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class BuyTradeManager + { +private: + int tradeId; + ulong rejectionByOneCandleTradeArray[3]; + + string firstSecureMethod ; + bool firstSecureMethodFound; + int numberOfTakeProfits ; + bool securedFirstLevelProfit ; + bool securedSecondLevelProfit; + double partialToClose ; + bool isTradeRunning ; + + +public: + BuyTradeManager(); + ~BuyTradeManager(); + + void fillRejectionByOneCandleTradeArray(int _index, int _id) {rejectionByOneCandleTradeArray[_index] = _id ;} + ulong getRejectionByOneCandleTradeTicket(int _index) {return rejectionByOneCandleTradeArray[_index] ;} + void printRejectionByOneCandleTradeArray(); + + void checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars); + string findFirstSecureMethod(); + + bool reachedProfitRatio(int _indexInArr); + bool closeTrade(int _indexInArr); + bool positionBreakEven(int _indexInArr); + + + void addTpAtIndex(int _index, double tpPrice) {tpArray[_index] = tpPrice;} + int countRemainingTakeProfits(); + bool reachedClosestTakeProfit(); + void deleteClosestTp(); + int findClosestTpIndex(); + + + void cleanOrderDataStructures(); + + void setTradeRunning(bool _setting) {isTradeRunning = _setting ;} + bool tradeIsRunning() {return isTradeRunning ;} + + double tpArray[3]; + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyTradeManager::BuyTradeManager() + { + + for(int i=0; i<3; i++) + { + tpArray[i] = -1; + } + securedFirstLevelProfit = false ; + securedSecondLevelProfit = false ; + firstSecureMethodFound = false ; + firstSecureMethod = "NOT_FOUND" ; + partialToClose = -1 ; + isTradeRunning = false ; + + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyTradeManager::~BuyTradeManager() + { + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void BuyTradeManager:: printRejectionByOneCandleTradeArray() + { + + Print("Printing the tickets :"); + for(int i=0 ; i<3 ; i++) + { + Print((int)rejectionByOneCandleTradeArray[i]); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void BuyTradeManager:: checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars) + { + if(securedFirstLevelProfit == false) // in this case im searching for 2 cases: either RR 1:1.5 , OR reaching the first TP , if any of them happened im gonna close half the order and updatae the remaining stop losses + { + + + if(!firstSecureMethodFound) + { + + firstSecureMethod = findFirstSecureMethod(); + if(firstSecureMethod != "FAILED") + { + + firstSecureMethodFound = true ; + } + else + if(firstSecureMethod == "FAILED") + { + Print("Failed to find the first secure method, go check the function : findFirstSecureMehod() !"); + } + + } + + if(firstSecureMethodFound == true) + { + + if(firstSecureMethod == "RATIO_METHOD") + { + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(reachedProfitRatio(0)) + { + ChartRedraw(); // Make sure the chart is up to date + + if(closeTrade(0)) // close the half + { + + rejectionByOneCandleTradeArray[0] = -1; + Print("Closed Half Of the position due to reaching the first secure Ratio!"); + } + else + { + Print("Failed Closing Half of the order by reaching the first secure Ratio !"); + } + + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(positionBreakEven(1)) // put the first quarter at break even + { + + Print(" First quarter has been put into break even due to reaching the first secure Ratio!"); + } + else + { + Print("Failed to Put the first quarter into break even"); + } + + numberOfTakeProfits = countRemainingTakeProfits(); + + Print("Number of remaining tps is: " + numberOfTakeProfits); + + securedFirstLevelProfit = true ; + } + + + + + + } + else + if(firstSecureMethod == "FIRST_TP_METHOD") + { + if(countRemainingTakeProfits() > 1) // there is at least 2 tp in the tp Array (because if this is the last tp then we want to close the whole order and not just a part of it) + { + if(reachedClosestTakeProfit()) // 2. Check if reached the first Tp + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + + // close the first half and update remaining partials sl's and delete the closest take profit from the array + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(closeTrade(0)) // close the half + { + + rejectionByOneCandleTradeArray[0] = -1; + Print("Closed Half Of the position due to reaching the first TP!"); + + } + else + { + Print("Failed Closing Half of the order by reaching the first TP !"); + } + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(positionBreakEven(1)) // put the first quarter at break even + { + + Print(" First quarter has been put into break even due to reaching the first TP!"); + } + else + { + Print("Failed to Put the first quarter into break even"); + } + deleteClosestTp(); + numberOfTakeProfits = countRemainingTakeProfits(); // update the number of remaining take profits + // calculate the remaining tps + + Print("Number of remaining tps is: " + numberOfTakeProfits); + Print("TP ARRY: " + tpArray[0] + ", " + tpArray[1] + " , " + tpArray[2]); + + securedFirstLevelProfit = true ; + + + } + } + else + if(numberOfTakeProfits = countRemainingTakeProfits() == 1) + { + if(reachedClosestTakeProfit()) + { + // close everything remained + } + } + } + + } + + + + } + else + if(securedFirstLevelProfit == true) // after securing the first level i just want to close the remaining partials by reaching the tp's + { + + if(countRemainingTakeProfits() == 1) + { + if(reachedClosestTakeProfit()) + { + // close everything + cleanOrderDataStructures(); + for(int i=0 ; i<3 ; i++) + { + closeTrade(i); + } + Print("Closed every thing because price reached the last Take Profit !"); + + ChartRedraw(); // Make sure the chart is up to date + + + deleteClosestTp(); + } + } + else + if(countRemainingTakeProfits() > 1) + { + if(reachedClosestTakeProfit()) + { + cleanOrderDataStructures(); + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[1])) // DEALING WITH THE FIRST QUARTER + { + double currentLot = PositionGetDouble(POSITION_VOLUME); + if(partialToClose == -1) + { + partialToClose = currentLot/numberOfTakeProfits ; + } + if(tradeLongInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[1],NormalizeDouble(partialToClose,2))) + { + uint res = tradeLongInTradeManager.ResultRetcode(); + if(res == 10009) + { + Print("Closed Partials successfully on the first quarter !"); + } + else + { + Print("The returned code is: " + res + " go check what it means !"); + } + + } + } + else + { + Print("Failed to select position by ticket! , Error: " + GetLastError()); + Print("The EA tried to close partials on the first quarter, but it is closed, probably due to break even and thats why it couldnt select the order !"); + } + + + cleanOrderDataStructures(); + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[2])) // DEALING WITH THE SECOND QUARTER + { + if(PositionGetDouble(POSITION_SL) < PositionGetDouble(POSITION_PRICE_OPEN)) // this is to put the second quarter at break even if its not already at break even + { + positionBreakEven(2); + + } + double currentLot = PositionGetDouble(POSITION_VOLUME); + if(partialToClose == -1) + { + partialToClose = currentLot/numberOfTakeProfits ; + } + if(tradeLongInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[2],NormalizeDouble(partialToClose,2))) + { + uint res = tradeLongInTradeManager.ResultRetcode(); + if(res == 10009) + { + Print("Closed Partials successfully on the second quarter!"); + } + else + { + Print("The returned code is: " + res + " go check what it means !"); + } + + } + + } + deleteClosestTp(); + Print("Number Of Remained tps is: " + countRemainingTakeProfits()); + + ChartRedraw(); // Make sure the chart is up to date + + + } + + } + + + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string BuyTradeManager:: findFirstSecureMethod() + { + + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[0])) + { + double positionStopLoss = PositionGetDouble(POSITION_SL); + double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double firstTakeProfit = tpArray[findClosestTpIndex()]; + if(((firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) > firstSecureRatio)) // firstTp > ratio + { + Print("Found the first profit secure method !"); + Print("The first TP RR is: 1:" + (firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) + "the firstSecureRatio is: 1:" + firstSecureRatio); + Print("The tp ratio is greater than the firstSecure so:"); + Print("The first secure method is RATIO_METHOD"); + return"RATIO_METHOD"; + } + else + if((firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss)< firstSecureRatio) + { + Print("Found the first profit secure method !"); + Print("The first TP RR is: 1:" + (firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) + "the firstSecureRatio is: 1:" + firstSecureRatio); + Print("The tp ratio is less than the firstSecure so:"); + Print("The first secure method is FIRST_TP_METHOD"); + return "FIRST_TP_METHOD" ; + } + } + else + { + Print("Failed to select position by ticket 1, Error: " + GetLastError()); + } + + return "FAILED" ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool BuyTradeManager:: reachedProfitRatio(int _indexInArr) + { + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) + { + if(PositionGetDouble(POSITION_PROFIT)/(0.5*riskDollars) >= firstSecureRatio) // checking if the first half of the contract reached the ratio of first secure profit + { + Print("reached profit ratio !"); + return true ; + } + } + else + { + Print("Failed to select the position by ticket 4 ,Error: " + GetLastError()); + + } + + } + + return false ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool BuyTradeManager:: closeTrade(int _indexInArr) + { + + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) + { + + // close the first half and update remaining partials sl's + if(tradeLongInTradeManager.PositionClose(_ticket)) + { + return true ; + + } + else + { + + Print("Failed to close positon, Error:" + GetLastError()); + return false; + } + + } + else + { + + Print("Failed to select position by ticket , Error: "+ GetLastError()); + return false; + } + + } + + + return false ; + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool BuyTradeManager:: positionBreakEven(int _indexInArr) + { + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) // select the first quarter + { + double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double positionTp = PositionGetDouble(POSITION_TP); + double positionSl = PositionGetDouble(POSITION_SL); + + if(tradeLongInTradeManager.PositionModify(_ticket,openPrice,positionTp)) + { + + + return true ; + } + else + { + Print("Failed to modify oder , ERROR: " + GetLastError()); + return false ; + } + + } + else + { + Print("Failed to select position by ticket "); + return false ; + } + } + + + return false ; + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int BuyTradeManager:: countRemainingTakeProfits() + { + + int counter = 0 ; + for(int i=0; i<3 ; i++) + { + if(tpArray[i] != -1) + { + counter++ ; + } + } + + return counter; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void BuyTradeManager:: deleteClosestTp() + { + + int closestTpIndex =findClosestTpIndex(); + tpArray[closestTpIndex] = -1; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int BuyTradeManager:: findClosestTpIndex() + { + int closestTpIndex = 0; + int closestTpValue = 1000000 ; // dummy value + + for(int i=0; i<3; i++) + { + if(tpArray[i] != -1 && tpArray[i] < closestTpValue) + { + closestTpValue = tpArray[i]; + closestTpIndex = i ; + } + + } + + return closestTpIndex ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool BuyTradeManager:: reachedClosestTakeProfit() + { + + + double closestTakeProfitValue = tpArray[findClosestTpIndex()]; + //Print("im in reached closest take profit function ,the current price is: " + SymbolInfoDouble(_Symbol, SYMBOL_BID) + " and the tp is: " + closestTakeProfitValue); + if(SymbolInfoDouble(_Symbol, SYMBOL_BID) >= closestTakeProfitValue) // we are looking for the BID , because reaching a tp in a buy trade means we are selling, so we want our take profit value, to be at least as the BID price (because we want to find someone to buy it from us at this price) + { + return true ; + } + return false ; + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void BuyTradeManager:: cleanOrderDataStructures() + { +// this is to make sure, that every closed order is removed from the data strucutre ! + + for(int i=0; i<3; i++) + { + if(!PositionSelectByTicket(rejectionByOneCandleTradeArray[i])) + { + if(GetLastError() == 4753) + { + rejectionByOneCandleTradeArray[i] = -1 ; + } + } + } + + } +//+------------------------------------------------------------------+ + + diff --git a/BuyTradeManagerTiger.mqh b/BuyTradeManagerTiger.mqh new file mode 100644 index 0000000..d9295ba --- /dev/null +++ b/BuyTradeManagerTiger.mqh @@ -0,0 +1,72 @@ +//+------------------------------------------------------------------+ +//| BuyTradeManagerTiger.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class BuyTradeManagerTiger + { +private: + + ulong tradeId ; + string entryType ; + bool firstPartialSecured ; + bool secondPartialSecured ; + bool managedRisk ; + bool retestWickFormed ; + double retestWickLengthInPips ; + + int riskManagementCandleCounter ; + double brokenResistanceLowerEdge ; + double brokenResistanceHigherEdge ; +public: + + ulong getTradeId(){return tradeId ;} + + bool riskAlreadyManaged(){return managedRisk ;} + void manageRisk(){managedRisk = true ;} + + bool firstPartialIsSecured(){return firstPartialSecured ;} + void secureFirstPartial(){firstPartialSecured = true ;} + + void setBrokenResistancetLowerEdge(double _brokenResistanceLowerEdge){brokenResistanceLowerEdge = _brokenResistanceLowerEdge ;} + void setBrokenResistanceHigherEdge(double _brokenResistanceHigherEdge){brokenResistanceHigherEdge = _brokenResistanceHigherEdge ;} + + double getBrokenResistanceLowerEdge(){return brokenResistanceLowerEdge ;} + double getBrokenResistanceHigherEdge(){return brokenResistanceHigherEdge ;} + + void incrementRiskManagementCandleCoutner(){riskManagementCandleCounter++ ;} + void decrementRiskManagementCandleCounter(){riskManagementCandleCounter-- ;} + + int getRiskManagementCandleCounter(){return riskManagementCandleCounter ;} + + void setRiskManagementCandleCounter(int count){ riskManagementCandleCounter = count ;} + + BuyTradeManagerTiger(ulong _tradeId); + ~BuyTradeManagerTiger(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyTradeManagerTiger::BuyTradeManagerTiger(ulong _tradeId) + { + + tradeId = _tradeId ; + firstPartialSecured = false ; + secondPartialSecured = false ; + managedRisk = false ; + retestWickFormed = false ; + retestWickLengthInPips = 0 ; + + riskManagementCandleCounter = 0 ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyTradeManagerTiger::~BuyTradeManagerTiger() + { + } +//+------------------------------------------------------------------+ + diff --git a/Entries_Newest.ex5 b/Entries_Newest.ex5 new file mode 100644 index 0000000..33fa53c Binary files /dev/null and b/Entries_Newest.ex5 differ diff --git a/Entries_Newest.mq5 b/Entries_Newest.mq5 new file mode 100644 index 0000000..1b205b9 --- /dev/null +++ b/Entries_Newest.mq5 @@ -0,0 +1,333 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include "Algo_Skeleton_Functions.mqh" + +long H4_SUPPORT_ZONE_CLR ; +long H4_RESISTANCE_ZONE_CLR ; +long H1_SUPPORT_ZONE_CLR; +long H1_RESISTANCE_ZONE_CLR; +long M30_SUPPORT_ZONE_CLR ; +long M30_RESISTANCE_ZONE_CLR ; + +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + H4_SUPPORT_ZONE_CLR = clrBlack ; + H4_RESISTANCE_ZONE_CLR = clrBlack ; + + if(ENTRY_BASED_H1_STRUCTURE == true && ENTRY_BASED_M30_STRUCTURE == false){ + M30_SUPPORT_ZONE_CLR = clrBlack ; + M30_RESISTANCE_ZONE_CLR = clrBlack ; + + H1_SUPPORT_ZONE_CLR = clrAliceBlue ; + H1_RESISTANCE_ZONE_CLR = clrDarkGray ; + + } + else if(ENTRY_BASED_H1_STRUCTURE == false && ENTRY_BASED_M30_STRUCTURE == true){ + M30_SUPPORT_ZONE_CLR = clrAliceBlue ; + M30_RESISTANCE_ZONE_CLR = clrDarkGray ; + + H1_SUPPORT_ZONE_CLR = clrBlack ; + H1_RESISTANCE_ZONE_CLR = clrBlack ; + + } + + + objectsManager.addTextTiger(); + + for(int i=0; i0){ + updateNormalZonesSupport(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",M30_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_M30,0); + } + + if(zoneContainer_M30.getNumberOfActiveZones()> 0){ + updateNormalZonesResistance(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",M30_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_M30,0); + } + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetector30M.isNewCandle()) + { + + if(trail_based_m30){ + trailAllOpenPositionsIfNeeded(PERIOD_M30); + } + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",M30_RESISTANCE_ZONE_CLR,zoneContainer_M30,rangeDistanceBetweenZonesActual_M30,0); + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",M30_SUPPORT_ZONE_CLR,zoneContainerSupport_M30,rangeDistanceBetweenZonesActual_M30,0); + if(ENTRY_BASED_M30_STRUCTURE){ + + handleBuys(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",cleanRangeUponEntryActual); + handleSells(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",cleanRangeUponEntryActual); + } + else{ + + handleBullishBreakouts(zoneContainer_M30,PERIOD_M30,"PERIOD_M30"); + handleBearishBreakouts(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30"); + } + + + + // UPDATING H1 ZONES + if(zoneContainerSupport_H1.getNumberOfActiveZones()>0){ + updateNormalZonesSupport(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",H1_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_H1,1000); + } + + if(zoneContainer_H1.getNumberOfActiveZones()> 0){ + updateNormalZonesResistance(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",H1_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_H1,1000); + } + + + + zoneContainerSupport_M30.printZonesSortedArray(); + zoneContainer_M30.printZonesSortedArray(); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + if(newCandleDetector1H.isNewCandle()){ + + if(trail_based_h1){ + trailAllOpenPositionsIfNeeded(PERIOD_H1); + } + + + detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",H1_RESISTANCE_ZONE_CLR,zoneContainer_H1,rangeDistanceBetweenZonesActual_H1,1000); + detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",H1_SUPPORT_ZONE_CLR,zoneContainerSupport_H1,rangeDistanceBetweenZonesActual_H1,1000); + + if(ENTRY_BASED_H1_STRUCTURE){ + + handleBuys(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",cleanRangeUponEntryActual); + handleSells(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",cleanRangeUponEntryActual); + } + + else{ + handleBullishBreakouts(zoneContainer_H1,PERIOD_H1,"PERIOD_H1"); + handleBearishBreakouts(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1"); + + } + + + // UPDATING H4 ZONES + if(zoneContainerSupport_H4.getNumberOfActiveZones()>0){ + updateNormalZonesSupport(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",H4_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_H4,2000); + } + + if(zoneContainer_H4.getNumberOfActiveZones()> 0){ + updateNormalZonesResistance(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",H4_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_H4,2000); + } + + Print("H1 zones :"); + //zoneContainerSupport_H1.printZonesSortedArray(); + //zoneContainer_H1.printZonesSortedArray(); + + } + + + + + if(newCandleDetector4H.isNewCandle()){ + last_H4_candle_broke_structure = false ; + + if(trail_based_h4){ + trailAllOpenPositionsIfNeeded(PERIOD_H4); + } + + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",H4_RESISTANCE_ZONE_CLR,zoneContainer_H4,rangeDistanceBetweenZonesActual_H4,2000); + detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",H4_SUPPORT_ZONE_CLR,zoneContainerSupport_H4,rangeDistanceBetweenZonesActual_H4,2000); + + // BREAK OF STRUCTURE HANDLING + + + handleBullishBreakouts(zoneContainer_H4,PERIOD_H4,"PERIOD_H4"); + handleBearishBreakouts(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4"); + + //handleBuys(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual); + //handleSells(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual); + + //Print("H4, Zones:"); + //zoneContainerSupport_H4.printZonesSortedArray(); + //zoneContainer_H4.printZonesSortedArray(); + } + + + + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + + weekCounter++ ; + + if(weekCounter == deleteAllZonesAfter_Weeks){ + + //deleteAllzonesWithGUI(); + weekCounter = 0; + } + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } + diff --git a/Gandalf.ex5 b/Gandalf.ex5 new file mode 100644 index 0000000..86bde9f Binary files /dev/null and b/Gandalf.ex5 differ diff --git a/Gandalf.mq5 b/Gandalf.mq5 new file mode 100644 index 0000000..189f720 --- /dev/null +++ b/Gandalf.mq5 @@ -0,0 +1,363 @@ +//+------------------------------------------------------------------+ +//| Gandalf.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "GraphicalObjectsManager.mqh" +#include "TempLineObjectAttributes.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "BuyGandalf.mqh" +#include "SellGandalf.mqh" +#include "LotSizeCalculator.mqh" + + + +LotSizeCalculator lsCalc; +GraphicalObjectsManager graphicalObjectsManager ; +ObjectConfirmationUnit objectConfUnit ; +BuyGandalf buyGandalfGray ; +SellGandalf SellGandalfGray ; + +bool buyCase = false ; +bool sellCase = false ; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +TempLineObjectAttributes tempLineObjectAttr ; +int OnInit() + { +//--- create timer + EventSetTimer(60); + + + graphicalObjectsManager.addTotalRiskText(); + graphicalObjectsManager.addTakeBuyTradeButton(); + graphicalObjectsManager.addTakeSellTradeButton(); + graphicalObjectsManager.addText(); + graphicalObjectsManager.addConfirmButton(); + + //ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"the new ext is : !"); + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + updateOverAllRiskText(); + + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { + + + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + + + if(sparam == "BUY_BTN") + { + buyCase = true ; + + graphicalObjectsManager.drawStopLossLineGandalf(); + objectConfUnit.setWaitingStatus(true); + + } + + else if(sparam == "SELL_BTN"){ + sellCase = true ; + graphicalObjectsManager.drawStopLossLineGandalf(); + objectConfUnit.setWaitingStatus(true); + + + } + + else + if(sparam == "CONFIRM_BTN") + { + if(buyCase == true) + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + string textRecieved; + graphicalObjectsManager.EditTextGet(textRecieved,0,"textName"); + double riskAsDouble = StringToDouble(textRecieved); + + double stopLossPrice = tempLineObjectAttr.getPrice(); + + + + if(ObjectDelete(_Symbol,"sl")) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + //Print("Buy info has been set, SL price: " + stopLossPrice + " risk is: " + riskAsDouble); + + double lotsToTrade = lsCalc.calculateLotSize(riskAsDouble,stopLossPrice); + + buyGandalfGray.takeBuyTradeGandalf(lotsToTrade,stopLossPrice); + + objectConfUnit.setWaitingStatus(false); + buyCase = false ; + + // change the risk text + //updateOverAllRiskText(); + + + } + + } + else + if(sellCase == true) + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + string textRecieved; + graphicalObjectsManager.EditTextGet(textRecieved,0,"textName"); + double riskAsDouble = StringToDouble(textRecieved); + + double stopLossPrice = tempLineObjectAttr.getPrice(); + + if(ObjectDelete(_Symbol,"sl")){ + + + } + else{ + + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + double lotsToTrade = lsCalc.calculateLotSize(riskAsDouble,stopLossPrice); + SellGandalfGray.takeSellTradeGandalf(lotsToTrade,stopLossPrice); + + objectConfUnit.setWaitingStatus(false); + sellCase = false ; + + + // change the risk text + //updateOverAllRiskText(); + + + } + + } + + + + + } + break; + } + + + case CHARTEVENT_OBJECT_DRAG: + { + + + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + + + } + + + break; + } + + + case CHARTEVENT_KEYDOWN: + { + + } + + + + //--- + + } + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + +void updateOverAllRiskText(){ + + + + //double pointValue = lsCalc.PointValue(_Symbol); + + double pointValue = PointValueNew(_Symbol); + double overAllRisk = 0 ; + for(int i=PositionsTotal() -1 ;i >= 0 ; i--){ + //Print("entered here !"); + ulong ticket = PositionGetTicket(i); + int positionType = PositionGetInteger(POSITION_TYPE); + double positionStopLossPrice = PositionGetDouble(POSITION_SL); + double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double positionLotSize = PositionGetDouble(POSITION_VOLUME); + + + if(positionType == POSITION_TYPE_BUY){ + double positionStopLossInPoints = (positionOpenPrice - positionStopLossPrice) * MathPow(10 , SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)) ; + double riskAmount = pointValue*positionLotSize*positionStopLossInPoints ; + overAllRisk = overAllRisk + riskAmount ; + string riskAsString = DoubleToString(overAllRisk); + ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is:" + riskAsString); + } + else if(positionType == POSITION_TYPE_SELL){ + double positionStopLossInPoints = (positionStopLossPrice - positionOpenPrice) * MathPow(10 , SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)) ; + double riskAmount = pointValue*positionLotSize*positionStopLossInPoints ; + overAllRisk = overAllRisk + riskAmount ; + string riskAsString = DoubleToString(overAllRisk); + ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is:" + riskAsString); + + } + } + +} + + + +double PointValueNew(string symbol){ + + + double tickSize = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE); + double tickValue = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE); + double point = SymbolInfoDouble(symbol,SYMBOL_POINT); + double ticksPerPoint = tickSize/point ; + double pointValue = tickValue/ticksPerPoint ; + + return (pointValue); +} \ No newline at end of file diff --git a/GeneralTests.ex5 b/GeneralTests.ex5 new file mode 100644 index 0000000..baec73c Binary files /dev/null and b/GeneralTests.ex5 differ diff --git a/GeneralTests.mq5 b/GeneralTests.mq5 new file mode 100644 index 0000000..c57d650 --- /dev/null +++ b/GeneralTests.mq5 @@ -0,0 +1,1668 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +//input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTALS DATA + +//input int leftPeriod; +//input int rightPeriod; +//input int weekPeriodToInitialize; +//input int initFractalsPeriod ; +//int lowFractalIndex ; +//int highFractalIndex ; +//#include "LowFractal.mqh" +//#include "HighFractal.mqh" +//#include "LowFractalContainer.mqh" +//#include "HighFractalContainer.mqh" + + + +#property script_show_inputs + +input datetime InpStartTime = __DATETIME__; +input bool REJECTION_M1_ONLY ; + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" + + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" +#include "LotSizeCalculator.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + +// Telegram Connection include +#include + +// SCRIPTS INCLUDES + + + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +// NEW CANDLE CLASSES INITIALIZATION +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + +bool telegramTested = false ; +input bool testTelegram ; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +// Added because bmp files seem to have stopped working, possibly a file format issue +//fileType = "png"; +//fileName = "MyScreenshot." + fileType; + + + if(telegramTested == false && testTelegram == true) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"This is just a test ! " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + telegramTested = true ; + } + + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + + + + + /* if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } */ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + + //lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + //highFractalIndex = rightPeriod+1; // this is used for the fractals + //initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + //initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + /*if(newCandleDetector_M1.isNewCandle()) + { + + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + }*/ + + + if(REJECTION_M1_ONLY == true) + { + if(newCandleDetector_M1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + Print("Im in new candle !"); + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + } + } + else + { + + if(newCandleDetector_H1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + handleBuys(PERIOD_H1); + handleSells(PERIOD_H1); + } + + } + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bearish candle closed inside the closest support zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bullish candle closed inside the resistance zone on " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+------------------------------------------------------------------+ diff --git a/GraphicalObjectsManager.mqh b/GraphicalObjectsManager.mqh new file mode 100644 index 0000000..73c2cc8 --- /dev/null +++ b/GraphicalObjectsManager.mqh @@ -0,0 +1,1076 @@ +//+------------------------------------------------------------------+ +//| GraphicalObjectsManager.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class GraphicalObjectsManager + { +private: + int verticalLineCounter ; +public: + GraphicalObjectsManager(); + ~GraphicalObjectsManager(); + + + void addZoneButton(); + void addStopLossButton(); + void addTakeProfitButton(); + void addSetTakeProfitButton(); + void addConfirmButton(); + void addDeleteButton(); + void addPrintFractalsButton(); + void addPrintZonesButton(); + void addTakeBuyTradeButton(); + void addTakeSellTradeButton(); + void addExitExperAdvisorButton(); + void drawRectangle(int _zoneId); + void drawRectangleInStrategyTester(int _zone_Id,datetime leftEdge, datetime rightEdge, double highEdgePrice, double lowEdgePrice,long _color); + void drawStopLossLine(string _zoneId); + void drawStopLossLineGandalf(); + void drawTakeProfitLine(string _zoneId); + void drawVerticalLine(long _color, datetime _time); + void drawHorizontalLine(long _color, string nameOfLine,double price); + void drawLowFractal(int _index,long _color); + void drawHighFractal(int _index,long _color); + + void addText (); + void addTextTiger(); + void addMarketDescriptionTextTiger(); + void addTotalRiskText (); + + bool EditTextGet(string &text, const long chart_ID=0, string name = "" ) ; + + + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +GraphicalObjectsManager::GraphicalObjectsManager() + { + verticalLineCounter = 0; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +GraphicalObjectsManager::~GraphicalObjectsManager() + { + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addZoneButton() + { + + + if(!ObjectCreate(0,"ZONE_ADD_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_XDISTANCE,30); + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"ZONE_ADD_BTN",OBJPROP_TEXT,"Add Zone"); + //--- set text font + ObjectSetString(0,"ZONE_ADD_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BORDER_COLOR,clrGray); + //--- display in the foreground (false) or background (true) + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BACK,back); + + //--- set button state + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_STATE,state); + + //--- enable (true) or disable (false) the mode of moving the button by mouse + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTABLE,selection); + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTED,selection); + + //--- hide (true) or display (false) graphical object name in the object list + + // ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_HIDDEN,hidden); + + //--- set the priority for receiving the event of a mouse click in the chart + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_ZORDER,z_order); + + } + } + + + +void GraphicalObjectsManager:: addTakeBuyTradeButton(){ + + + + if(!ObjectCreate(0,"BUY_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"BUY_BTN",OBJPROP_XDISTANCE,30); + ObjectSetInteger(0,"BUY_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"BUY_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"BUY_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"BUY_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"BUY_BTN",OBJPROP_TEXT,"Buy"); + //--- set text font + ObjectSetString(0,"BUY_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"BUY_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"BUY_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"BUY_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"BUY_BTN",OBJPROP_BORDER_COLOR,clrGray); + //--- display in the foreground (false) or background (true) + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BACK,back); + + //--- set button state + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_STATE,state); + + //--- enable (true) or disable (false) the mode of moving the button by mouse + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTABLE,selection); + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTED,selection); + + //--- hide (true) or display (false) graphical object name in the object list + + // ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_HIDDEN,hidden); + + //--- set the priority for receiving the event of a mouse click in the chart + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_ZORDER,z_order); + + } + + +} + + + + + +void GraphicalObjectsManager:: addTakeSellTradeButton(){ + + + + if(!ObjectCreate(0,"SELL_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"SELL_BTN",OBJPROP_XDISTANCE,170); + ObjectSetInteger(0,"SELL_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"SELL_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"SELL_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"SELL_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"SELL_BTN",OBJPROP_TEXT,"Sell"); + //--- set text font + ObjectSetString(0,"SELL_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"SELL_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"SELL_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"SELL_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"SELL_BTN",OBJPROP_BORDER_COLOR,clrGray); + //--- display in the foreground (false) or background (true) + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BACK,back); + + //--- set button state + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_STATE,state); + + //--- enable (true) or disable (false) the mode of moving the button by mouse + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTABLE,selection); + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTED,selection); + + //--- hide (true) or display (false) graphical object name in the object list + + // ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_HIDDEN,hidden); + + //--- set the priority for receiving the event of a mouse click in the chart + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_ZORDER,z_order); + + } + + +} + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addConfirmButton() + { + + if(!ObjectCreate(0,"CONFIRM_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the confirm button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_XDISTANCE,470); + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"CONFIRM_BTN",OBJPROP_TEXT,"Confirm Object"); + //--- set text font + ObjectSetString(0,"CONFIRM_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addDeleteButton() + { + if(!ObjectCreate(0,"DELETE_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the delete button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_XDISTANCE,310); + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"DELETE_BTN",OBJPROP_TEXT,"Delete Object"); + //--- set text font + ObjectSetString(0,"DELETE_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addExitExperAdvisorButton() + { + if(!ObjectCreate(0,"EXIT_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the exit button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_XDISTANCE,450); + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"EXIT_BTN",OBJPROP_TEXT,"Remove Expert"); + //--- set text font + ObjectSetString(0,"EXIT_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_FONTSIZE,9); + //--- set text color + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addPrintFractalsButton() + { + + if(!ObjectCreate(0,"PRINT_FRACTAL_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the print fractals button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_XDISTANCE,590); + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"PRINT_FRACTAL_BTN",OBJPROP_TEXT,"Print Fractals"); + //--- set text font + ObjectSetString(0,"PRINT_FRACTAL_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addPrintZonesButton() + { + if(!ObjectCreate(0,"PRINT_ZONES_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the print fractals button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_XDISTANCE,730); + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"PRINT_ZONES_BTN",OBJPROP_TEXT,"Print Zones"); + //--- set text font + ObjectSetString(0,"PRINT_ZONES_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addStopLossButton() + { + if(!ObjectCreate(0,"ADD_SL_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the stop loss button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_XDISTANCE,30); + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_YDISTANCE,100); + //--- set button size + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"ADD_SL_BTN",OBJPROP_TEXT,"Add SL"); + //--- set text font + ObjectSetString(0,"ADD_SL_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addTakeProfitButton() + { + + if(!ObjectCreate(0,"ADD_TP_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the take profit button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_XDISTANCE,170); + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_YDISTANCE,100); + //--- set button size + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"ADD_TP_BTN",OBJPROP_TEXT,"Add TP"); + //--- set text font + ObjectSetString(0,"ADD_TP_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + } + + + +void GraphicalObjectsManager:: addSetTakeProfitButton(){ + if(!ObjectCreate(0,"SET_TP_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the take profit button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_XDISTANCE,310); + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_YDISTANCE,100); + //--- set button size + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"SET_TP_BTN",OBJPROP_TEXT,"Set TP"); + //--- set text font + ObjectSetString(0,"SET_TP_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + +} +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: drawRectangle(int _zoneId) + { + + string nameInString = IntegerToString(_zoneId); + + + if(!ObjectCreate(_Symbol,nameInString,OBJ_RECTANGLE,0,iTime(_Symbol,PERIOD_CURRENT,20),iLow(_Symbol,PERIOD_CURRENT,20),iTime(_Symbol,PERIOD_CURRENT,10), iOpen(_Symbol,PERIOD_CURRENT,20))) + { + + Print(__FUNCTION__, + ": Failed to create a Zone! Error code = ",GetLastError()); + + } + + else + { + ChartRedraw(); + Print("Rectangle created successfully!"); + //--- set rectangle color + ObjectSetInteger(0,nameInString,OBJPROP_COLOR,clrDimGray); + ObjectSetInteger(0,nameInString,OBJPROP_FILL,clrDimGray); + + ObjectSetInteger(0,nameInString,OBJPROP_SELECTABLE,true); + + ObjectSetInteger(0,nameInString,OBJPROP_SELECTED,true); + + + ObjectSetInteger(0,nameInString,OBJPROP_XDISTANCE,700); + ObjectSetInteger(0,nameInString,OBJPROP_YDISTANCE,700); + + + } + + } + + + +void GraphicalObjectsManager:: drawRectangleInStrategyTester(int _zoneId,datetime leftEdge, datetime rightEdge, double highEdgePrice, double lowEdgePrice, long _color){ + + string nameInString = IntegerToString(_zoneId); + + + if(!ObjectCreate(_Symbol,nameInString,OBJ_RECTANGLE,0,leftEdge,lowEdgePrice,rightEdge, highEdgePrice)) + { + + Print(__FUNCTION__, + ": Failed to create a Zone! Error code = ",GetLastError()); + + } + + else + { + ChartRedraw(); + Print("Rectangle created successfully!"); + //--- set rectangle color + ObjectSetInteger(0,nameInString,OBJPROP_COLOR,_color); + ObjectSetInteger(0,nameInString,OBJPROP_FILL,_color); + ObjectSetInteger(0,nameInString,OBJPROP_BORDER_TYPE,0); + ObjectSetInteger(0,nameInString,OBJPROP_BACK,true); + + ObjectSetInteger(0,nameInString,OBJPROP_SELECTABLE,true); + + ObjectSetInteger(0,nameInString,OBJPROP_SELECTED,false); + + + ObjectSetInteger(0,nameInString,OBJPROP_XDISTANCE,700); + ObjectSetInteger(0,nameInString,OBJPROP_YDISTANCE,700); + + + + } + +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: drawStopLossLine(string _zoneId) + { + + string lineName = "sl" + _zoneId ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,lineName,OBJ_HLINE,0,0,SymbolInfoDouble(_Symbol, SYMBOL_ASK))) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,clrRed); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,1); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + +//--- successful execution + } + + + void GraphicalObjectsManager:: drawTakeProfitLine(string _zoneId) + { + + string lineName = "tp" + _zoneId ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,lineName,OBJ_HLINE,0,0,SymbolInfoDouble(_Symbol, SYMBOL_ASK))) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,clrAqua); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,0.5); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + +//--- successful execution + } + + + +void GraphicalObjectsManager:: drawVerticalLine(long _color, datetime _time){ + Print("entered the drawvertical line function"); + string lineName = "vline" + IntegerToString(verticalLineCounter) ; + verticalLineCounter++; + + + + + if(!ObjectCreate(_Symbol,lineName,OBJ_VLINE,0,_time,0)) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,_color); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,0.5); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + + +} + + + +void GraphicalObjectsManager:: drawHorizontalLine(long _color, string nameOfLine,double price){ + + string lineName = nameOfLine; + + + + if(!ObjectCreate(_Symbol,lineName,OBJ_HLINE,0,TimeCurrent(),price)) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,_color); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,0.5); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + +} + +void GraphicalObjectsManager:: addText (){ + + if(!ObjectCreate(0,"textName",OBJ_EDIT,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create a text! Error code = ",GetLastError()); + + } + + else{ + + + + ChartRedraw(); + + + //--- set button coordinates + ObjectSetInteger(0,"textName",OBJPROP_XDISTANCE,300); + ObjectSetInteger(0,"textName",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"textName",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"textName",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"textName",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"textName",OBJPROP_TEXT," Risk Amount"); + //--- set text font + ObjectSetString(0,"textName",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"textName",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"textName",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"textName",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"textName",OBJPROP_BORDER_COLOR,clrGray); + } + + + +} + + +void GraphicalObjectsManager:: addTextTiger (){ + + if(!ObjectCreate(0,"clockTextTiger",OBJ_EDIT,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create a text! Error code = ",GetLastError()); + + } + + else{ + + + + ChartRedraw(); + + + //--- set button coordinates + ObjectSetInteger(0,"clockTextTiger",OBJPROP_XDISTANCE,300); + ObjectSetInteger(0,"clockTextTiger",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"clockTextTiger",OBJPROP_XSIZE,150); + ObjectSetInteger(0,"clockTextTiger",OBJPROP_YSIZE,100); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"clockTextTiger",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT," "); + //--- set text font + ObjectSetString(0,"clockTextTiger",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"clockTextTiger",OBJPROP_FONTSIZE,20); + //--- set text color + ObjectSetInteger(0,"clockTextTiger",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"clockTextTiger",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"clockTextTiger",OBJPROP_BORDER_COLOR,clrGray); + } + + + +} + + + +void GraphicalObjectsManager:: addMarketDescriptionTextTiger(){ + + if(!ObjectCreate(0,"marketDescriptionText",OBJ_EDIT,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create a text! Error code = ",GetLastError()); + + } + + else{ + + + + ChartRedraw(); + + + //--- set button coordinates + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_XDISTANCE,50); + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_YDISTANCE,150); + //--- set button size + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_XSIZE,600); + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_YSIZE,100); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT," "); + //--- set text font + ObjectSetString(0,"marketDescriptionText",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_BORDER_COLOR,clrGray); + } + + +} + + +void GraphicalObjectsManager:: addTotalRiskText (){ + + if(!ObjectCreate(0,"totalRiskText",OBJ_EDIT,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create a text! Error code = ",GetLastError()); + + } + + else{ + + + + ChartRedraw(); + + + //--- set button coordinates + ObjectSetInteger(0,"totalRiskText",OBJPROP_XDISTANCE,700); + ObjectSetInteger(0,"totalRiskText",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"totalRiskText",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"totalRiskText",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"totalRiskText",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is: 0"); + //--- set text font + ObjectSetString(0,"totalRiskText",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"totalRiskText",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"totalRiskText",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"totalRiskText",OBJPROP_BGCOLOR,clrBlack); + //--- set border color + ObjectSetInteger(0,"totalRiskText",OBJPROP_BORDER_COLOR,clrBlack); + + ObjectSetInteger(_Symbol,"totalRiskText",OBJPROP_SELECTABLE,false); + + + } + + + +} + + +bool GraphicalObjectsManager:: EditTextGet(string &text, const long chart_ID=0, string name = "") + { +//--- reset the error value + ResetLastError(); +//--- get object text + if(!ObjectGetString(chart_ID,name,OBJPROP_TEXT,0,text)) + { + Print(__FUNCTION__, + ": failed to get the text! Error code = ",GetLastError()); + return(false); + } +//--- successful execution + return(true); + } + + + +void GraphicalObjectsManager:: drawStopLossLineGandalf() + { + + string lineName = "sl" ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,lineName,OBJ_HLINE,0,0,SymbolInfoDouble(_Symbol, SYMBOL_ASK))) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,clrRed); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,1); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + +//--- successful execution + } + + + + +void GraphicalObjectsManager:: drawLowFractal(int _index,long _color){ + + string fractalName = "low_fractal" ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,fractalName,OBJ_ARROW_UP,0,iTime(_Symbol,PERIOD_CURRENT,_index),iLow(_Symbol,PERIOD_CURRENT,_index) - 0.25)) + { + + Print(__FUNCTION__, + ": failed to create an arrow object! Error code = ",GetLastError()); + + } + + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,fractalName,OBJPROP_COLOR,_color); +//--- set line display style + ObjectSetInteger(_Symbol,fractalName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + // ObjectSetInteger(_Symbol,fractalName,OBJPROP_WIDTH,1); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,fractalName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + //ObjectSetInteger(_Symbol,fractalName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,fractalName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,fractalName,OBJPROP_HIDDEN,false); +} + + + +void GraphicalObjectsManager:: drawHighFractal(int _index,long _color){ + + string fractalName = "high_fractal" ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,fractalName,OBJ_ARROW_DOWN,0,iTime(_Symbol,PERIOD_CURRENT,_index),iHigh(_Symbol,PERIOD_CURRENT,_index) + 0.25)) + { + + Print(__FUNCTION__, + ": failed to create an arrow object! Error code = ",GetLastError()); + + } + + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,fractalName,OBJPROP_COLOR,_color); +//--- set line display style + ObjectSetInteger(_Symbol,fractalName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + // ObjectSetInteger(_Symbol,fractalName,OBJPROP_WIDTH,1); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,fractalName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + //ObjectSetInteger(_Symbol,fractalName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,fractalName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,fractalName,OBJPROP_HIDDEN,false); +} \ No newline at end of file diff --git a/HighFractal.mqh b/HighFractal.mqh new file mode 100644 index 0000000..8fea724 --- /dev/null +++ b/HighFractal.mqh @@ -0,0 +1,254 @@ +//+------------------------------------------------------------------+ +//| HighFractal.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class HighFractal + { + +private: + + double highPrice ; + int leftPeriod; + int rightPeriod; + + MqlDateTime dateStruct ; + datetime date ; + + double sellLimitPrice; // the fib level price , based on this fractal + double lowestPeak ; // the highest price reached, after the fractal was formed + int hour ; + int minute; + int distance ; // holds the number of candles from this fractal until the current live candle + string arrowObjName ; + double fibPrice ; + +public: + HighFractal(); + HighFractal(double _price, int _leftPeriod, int _rightPeriod, datetime _date,ENUM_TIMEFRAMES _tf); + ~HighFractal(); + + + + // GETTERS + + double getPrice(); + int getLeftPeriod(); + int getRightPeriod(); + int getHour(); + int getMinute(); + double getLowestPeak(); + int getDistance(); + string getArrowObjName(); + datetime getDate(); + // SETTERS + + void setPrice(double _price); + void setLeftPeriod(int _leftPeriod); + void setRightPeriod(int _rightPeriod); + void setHour(int _hour); + void setMinute(int _minute); + void setLowestPeak(double _highest); + void setArrowObjName(string _name); + void setDistance(int _dist); + void setDate(datetime _givenDate); + + + // OTHER FUNCTIONS + + double calculateFibPrice(double _fibLevel, double _highPrice, double _lowPrice); // calculate the fibonacci price based on the given level, and saves the price in the fibPrice88 variable in the object + void updateDistance(); + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractal::HighFractal() + { + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractal::HighFractal(double _price, int _leftPeriod, int _rightPeriod,datetime _date,ENUM_TIMEFRAMES _tf) + { +// the constructor sets the data to the attribues , and calculates the real time of the fractal , because the given minute and hour +// are not the real time, they are the time of when the fractal was "known to be a fractal", which is after _righPeriod amount of candles + + highPrice = _price ; + leftPeriod = _leftPeriod; + rightPeriod = _rightPeriod; + sellLimitPrice = -1 ; + distance = _rightPeriod+1; + arrowObjName = " " ; + lowestPeak = -1; + + + date = iTime(_Symbol,_tf,_rightPeriod+1); // bring the actual date of the fractal + TimeToStruct(date,dateStruct); // convert the actual date into a struct + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractal::~HighFractal() + { + } +//+------------------------------------------------------------------+ + + + +double HighFractal:: getPrice() + { + + return highPrice ; + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int HighFractal:: getLeftPeriod() + { + + return leftPeriod ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int HighFractal:: getRightPeriod() + { + + return rightPeriod ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int HighFractal:: getHour() + { + + return dateStruct.hour ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int HighFractal:: getMinute() + { + return dateStruct.min ; + } + + +double HighFractal:: getLowestPeak(){ + + return lowestPeak ; +} + + + +int HighFractal:: getDistance(){ + + return distance ; +} + + +string HighFractal:: getArrowObjName(){ + return arrowObjName ; + +} + + +datetime HighFractal:: getDate(){ + + return date ; +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setPrice(double _price) + { + highPrice = _price ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setLeftPeriod(int _leftPeriod) + { + leftPeriod = _leftPeriod ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setRightPeriod(int _rightPeriod) + { + rightPeriod = _rightPeriod ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setHour(int _hour) + { + hour = _hour ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setMinute(int _minute) + { + minute = _minute ; + } + +//+------------------------------------------------------------------+ + +void HighFractal:: setArrowObjName(string _name){ + arrowObjName = _name ; + +} + + void HighFractal:: setDistance(int _dist){ + distance = _dist ; + } + + + +double HighFractal:: calculateFibPrice(double _fibLevel, double _highPrice, double _lowPrice){ + + double difference = _lowPrice - _highPrice ; + difference = difference*-1 ; + double retracement = _fibLevel * difference ; + double _fibPrice = _lowPrice + retracement ; + fibPrice = _fibPrice ; + return fibPrice; +} + + + +void HighFractal:: setLowestPeak(double _lowest){ + + lowestPeak = _lowest ; + +} + +void HighFractal:: setDate(datetime _givenDate){ + date = _givenDate; + TimeToStruct(date,dateStruct); // convert the actual date into a struct +} + +void HighFractal:: updateDistance(){ + + distance++ ; +} +//+------------------------------------------------------------------+ diff --git a/HighFractalContainer.mqh b/HighFractalContainer.mqh new file mode 100644 index 0000000..07321ae --- /dev/null +++ b/HighFractalContainer.mqh @@ -0,0 +1,131 @@ +//+------------------------------------------------------------------+ +//| HighFractalContainer.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "HighFractal.mqh" +#include +#define SIZE 700 + +double input arrowDistanceHighs ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class HighFractalContainer + { +private: + HighFractal* highFractals[SIZE]; + int freeIndex ; + double range ; + ENUM_TIMEFRAMES timeFrame ; +public: + HighFractalContainer(ENUM_TIMEFRAMES _timeFrame); + ~HighFractalContainer(); + + //GETTERS + + HighFractal* getHighFractal(int _index) {return highFractals[_index] ;} // returns the fractal using its index in the array + int getFreeIndex() {return freeIndex ; } + + //SETTERS + void setRange(double _range) {range = _range ;} + + // OTHER FUNCTIONS + void addHighFractal(HighFractal* _highFractal); // adds high fractal to the high fractals array + void printHighFractals(); // prints the data of every high fractal in the highFractals[] array + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractalContainer::HighFractalContainer(ENUM_TIMEFRAMES _timeFrame) + { + timeFrame = _timeFrame; + freeIndex = 0 ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractalContainer::~HighFractalContainer() + { + + for(int i=0; i 0) + { + for(int i=0 ; i SymbolInfoDouble(_Symbol, SYMBOL_BID)) // we are calculating for a sell + { + difference = stopLossPrice - SymbolInfoDouble(_Symbol, SYMBOL_BID) ; + differenceInPoints = difference / SymbolInfoDouble(_Symbol, SYMBOL_POINT); + double pointValue = PointValue(_Symbol); + + // Situation 3, fixed risk amount and stop loss, how many lots to trade + double riskInPoints = differenceInPoints; + double riskLots = riskInMoney / (pointValue * riskInPoints); + + return riskLots; + } + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) > stopLossPrice){ + difference = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossPrice ; + differenceInPoints = difference / SymbolInfoDouble(_Symbol, SYMBOL_POINT); + double pointValue = PointValue(_Symbol); + double riskInPoints = differenceInPoints; + double riskLots = riskInMoney / (pointValue * riskInPoints); + return riskLots; + } + + + return 0 ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double LotSizeCalculator:: PointValue(string symbol) + { + + double tickSize = TickSize(symbol); + double tickValue = TickValue(symbol); + double point = Point(symbol); + double ticksPerPoint = tickSize / point; + double pointValue = tickValue / ticksPerPoint; + + PrintFormat("tickSize=%f, tickValue=%f, point=%f, ticksPerPoint=%f, pointValue=%f", + tickSize, tickValue, point, ticksPerPoint, pointValue); + + return (pointValue); + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LotSizeCalculator:: Test(string symbol) + { + + PrintFormat("Base currency is %s", BaseCurrency()); + PrintFormat("Testing for symbol %s", symbol); + + double pointValue = PointValue(symbol); + + PrintFormat("ValuePerPoint for %s is %f", symbol, pointValue); + +// Situation 3, fixed risk amount and stop loss, how many lots to trade + double riskAmount = 100; + double riskPoints = 5000; + double riskLots = riskAmount / (pointValue * riskPoints); + PrintFormat("Risk lots for %s value %f and stop loss at %f points is %f", + symbol, riskAmount, riskPoints, riskLots); + } +//+------------------------------------------------------------------+ diff --git a/LowFractal.mqh b/LowFractal.mqh new file mode 100644 index 0000000..96244f9 --- /dev/null +++ b/LowFractal.mqh @@ -0,0 +1,255 @@ +//+------------------------------------------------------------------+ +//| LowFractal.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class LowFractal + { +private: + +private: + + double lowPrice ; + int leftPeriod; + int rightPeriod; + + MqlDateTime dateStruct ; + datetime date ; + + double buyLimitPrice; // the fib level price , based on this fractal + double highestPeak ; // the highest price reached, after the fractal was formed + int hour ; + int minute; + int distance ; // holds the number of candles from this fractal until the current live candle + string arrowObjName ; + double fibPrice ; + +public: + LowFractal(); + LowFractal(double _price, int _leftPeriod, int _rightPeriod, datetime _date,ENUM_TIMEFRAMES _tf); + ~LowFractal(); + + + + // GETTERS + + double getPrice(); + int getLeftPeriod(); + int getRightPeriod(); + int getHour(); + int getMinute(); + double getHighestPeak(); + int getDistance(); + string getArrowObjName(); + datetime getDate(); + // SETTERS + + void setPrice(double _price); + void setLeftPeriod(int _leftPeriod); + void setRightPeriod(int _rightPeriod); + void setHour(int _hour); + void setMinute(int _minute); + void setHighestPeak(double _highest); + void setArrowObjName(string _name); + void setDistance(int _dist); + void setDate(datetime _givenDate); + + + // OTHER FUNCTIONS + + double calculateFibPrice(double _fibLevel, double _lowPrice, double _highPrice); // calculate the fibonacci price based on the given level, and saves the price in the fibPrice88 variable in the object + void updateDistance(); + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractal::LowFractal() + { + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractal::LowFractal(double _price, int _leftPeriod, int _rightPeriod,datetime _date, ENUM_TIMEFRAMES _tf) + { +// the constructor sets the data to the attribues , and calculates the real time of the fractal , because the given minute and hour +// are not the real time, they are the time of when the fractal was "known to be a fractal", which is after _righPeriod amount of candles + + lowPrice = _price ; + leftPeriod = _leftPeriod; + rightPeriod = _rightPeriod; + buyLimitPrice = -1 ; + distance = _rightPeriod+1; + arrowObjName = " " ; + highestPeak = -1; + + + date = iTime(_Symbol,_tf,_rightPeriod+1); // bring the actual date of the fractal + TimeToStruct(date,dateStruct); // convert the actual date into a struct + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractal::~LowFractal() + { + } +//+------------------------------------------------------------------+ + + + +double LowFractal:: getPrice() + { + + return lowPrice ; + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int LowFractal:: getLeftPeriod() + { + + return leftPeriod ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int LowFractal:: getRightPeriod() + { + + return rightPeriod ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int LowFractal:: getHour() + { + + return dateStruct.hour ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int LowFractal:: getMinute() + { + return dateStruct.min ; + } + + +double LowFractal:: getHighestPeak(){ + + return highestPeak ; +} + + + +int LowFractal:: getDistance(){ + + return distance ; +} + + +string LowFractal:: getArrowObjName(){ + return arrowObjName ; + +} + + +datetime LowFractal:: getDate(){ + + return date ; +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setPrice(double _price) + { + lowPrice = _price ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setLeftPeriod(int _leftPeriod) + { + leftPeriod = _leftPeriod ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setRightPeriod(int _rightPeriod) + { + rightPeriod = _rightPeriod ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setHour(int _hour) + { + hour = _hour ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setMinute(int _minute) + { + minute = _minute ; + } + +//+------------------------------------------------------------------+ + +void LowFractal:: setArrowObjName(string _name){ + arrowObjName = _name ; + +} + + void LowFractal:: setDistance(int _dist){ + distance = _dist ; + } + + + +double LowFractal:: calculateFibPrice(double _fibLevel, double _lowPrice, double _highPrice){ + + double difference = _highPrice - _lowPrice ; + double retracement = _fibLevel * difference ; + double _fibPrice = _highPrice - retracement ; + fibPrice = _fibPrice ; + return fibPrice; +} + + + +void LowFractal:: setHighestPeak(double _highest){ + + highestPeak = _highest ; + +} + +void LowFractal:: setDate(datetime _givenDate){ + date = _givenDate; + TimeToStruct(date,dateStruct); // convert the actual date into a struct +} + +void LowFractal:: updateDistance(){ + + distance++ ; +} + + diff --git a/LowFractalContainer.mqh b/LowFractalContainer.mqh new file mode 100644 index 0000000..e343409 --- /dev/null +++ b/LowFractalContainer.mqh @@ -0,0 +1,137 @@ +//+------------------------------------------------------------------+ +//| LowFractalContainer.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "LowFractal.mqh" +#include +#define SIZE 700 + +double input arrowDistanceLows ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class LowFractalContainer + { +private: + LowFractal* lowFractals[SIZE]; + int freeIndex ; + double range ; + ENUM_TIMEFRAMES timeFrame ; +public: + LowFractalContainer(ENUM_TIMEFRAMES _timeFrame); + ~LowFractalContainer(); + + //GETTERS + + LowFractal* getLowFractal(int _index) {return lowFractals[_index] ;} // returns the fractal using its index in the array + int getFreeIndex() {return freeIndex ; } + + //SETTERS + void setRange(double _range) {range = _range ;} + + // OTHER FUNCTIONS + void addLowFractal(LowFractal* _lowFractal); // adds low fractal to the low fractals array + void printLowFractals(); // prints all low fractals data + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractalContainer::LowFractalContainer(ENUM_TIMEFRAMES _timeFrame) + { + timeFrame = _timeFrame ; + freeIndex = 0 ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractalContainer::~LowFractalContainer() + { + + for(int i=0; i 0) + { + + for(int i=0 ; i= zoneContainer.getZoneByIndex(currentResistanceZoneIndex).getLowerEdge()) + { + + Print("Reached the current resistance zone !"); + return "TYPE_RESISTANCE" ; + + } + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= zoneContainer.getZoneByIndex(currentSupportZoneIndex).getHigherEdge()) + { + Print("Reached the current support zone !"); + return "TYPE_SUPPORT" ; + + } + } + + + return "" ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: reachedClosestSupportZone() + { + + int currentSupportZoneIndex = zoneContainer.getLowZonePivot(); + + if(currentSupportZoneIndex != -1) + { + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= zoneContainer.getZoneByIndex(currentSupportZoneIndex).getHigherEdge()) + { + return true ; + + } + + } + + return false ; + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: reachedClosestResistanceZone() + { + + int currentResistanceZoneIndex = zoneContainer.getHighZonePivot(); + + if(currentResistanceZoneIndex != -1) + { + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) >= zoneContainer.getZoneByIndex(currentResistanceZoneIndex).getLowerEdge()) + { + return true ; + + } + } + + + return false ; + + } + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: bullishCandleClosedInsideClosestResistanceZone(ENUM_TIMEFRAMES tf) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + double previousCandleOpen = iOpen(_Symbol,tf,1); + + if(zoneContainer.getHighZonePivot() != -1) // means if there is a pivot zone + { + + if((previousCandleClose > previousCandleOpen) && (previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getLowerEdge()) && (previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getHigherEdge())) // means if previous the candle is bullish and closed inside the resistance zone + { + + return true ; + } + } + + return false ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: bearishCandleClosedInsideClosestSupportZone(ENUM_TIMEFRAMES tf) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + double previousCandleOpen = iOpen(_Symbol,tf,1); + + if(zoneContainer.getLowZonePivot() != -1) + { + if((previousCandleClose < previousCandleOpen) && (previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getHigherEdge()) && (previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getLowerEdge())) // means if previous the candle is breaish and closed inside the support zone + { + return true ; + } + + } + return false ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketObserver:: giveMarketReport() + { + + + return " " ; + } + +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: candleClosedBelowClosestSupportZone(ENUM_TIMEFRAMES tf) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + double previousCandleOpen = iOpen(_Symbol,tf,1); + + + if(zoneContainer.getLowZonePivot() != -1) + { + if((previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getLowerEdge())) // means if the previous candle closed below the support zone + { + + return true ; + } + + } + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: candleClosedAboveClosestResistanceZone(ENUM_TIMEFRAMES tf) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + double previousCandleOpen = iOpen(_Symbol,tf,1); + + if(zoneContainer.getHighZonePivot() != -1) // means if there is a pivot zone + { + + if((previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getHigherEdge())) // means if previous the candle closed above the resistance zone + { + + return true ; + } + } + return false ; + + } + + + bool MarketObserver:: candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf){ + + double previousCandleClose = iClose(_Symbol,tf,1); + + if((previousCandleClose > zoneContainer.getZoneByIndex(_index).getHigherEdge())){ + + return true ; + } + + return false ; + } +//+------------------------------------------------------------------+ diff --git a/MarketObserverTiger.mqh b/MarketObserverTiger.mqh new file mode 100644 index 0000000..17a709b --- /dev/null +++ b/MarketObserverTiger.mqh @@ -0,0 +1,105 @@ +//+------------------------------------------------------------------+ +//| MarketObserverTiger.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +//+------------------------------------------------------------------+ +//| defines | +//+------------------------------------------------------------------+ +// #define MacrosHello "Hello, world!" +// #define MacrosYear 2010 +//+------------------------------------------------------------------+ +//| DLL imports | +//+------------------------------------------------------------------+ +// #import "user32.dll" +// int SendMessageA(int hWnd,int Msg,int wParam,int lParam); +// #import "my_expert.dll" +// int ExpertRecalculate(int wParam,int lParam); +// #import +//+------------------------------------------------------------------+ +//| EX5 imports | +//+------------------------------------------------------------------+ +// #import "stdlib.ex5" +// string ErrorDescription(int error_code); +// #import +//+------------------------------------------------------------------+ +#include "Zone.mqh" +#include "ZoneContainer.mqh" + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class MarketObserverTiger + { + // THIS CLASS HAS ACCESS TO ZONE CONTAINER, HOWEVER IT MUST NOT CHANGE IT IT ONLY READS FROM THE ZONECONTAINER CLASS +private: + + + +public: + MarketObserverTiger(); + ~MarketObserverTiger(); + + string zoneReached(); + bool candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& resistanceZoneContainer); // the index is a specific zone from the zones container + bool candleClosedBelowSupportByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& supportZoneContainer); // the index is a specific zone from the zones container + + + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +MarketObserverTiger::MarketObserverTiger() + { + + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +MarketObserverTiger::~MarketObserverTiger() + { + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserverTiger:: candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& resistanceZoneContainer) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + + if((previousCandleClose > resistanceZoneContainer.getZoneByIndex(_index).getHigherEdge())) + { + + return true ; + } + + return false ; + } + + + +bool MarketObserverTiger:: candleClosedBelowSupportByIndex(int _index, ENUM_TIMEFRAMES tf, ZoneContainer& supportZoneContainer){ + + + double previousCandleClose = iClose(_Symbol,tf,1); + if(previousCandleClose < supportZoneContainer.getZoneByIndex(_index).getLowerEdge()){ + return true ; + } + + return false ; +} diff --git a/NewCandleDetector.mqh b/NewCandleDetector.mqh new file mode 100644 index 0000000..678a7b4 --- /dev/null +++ b/NewCandleDetector.mqh @@ -0,0 +1,378 @@ +//+------------------------------------------------------------------+ +//| NewCandleDetector.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class NewCandleDetector + { +private: + string timeFrame ; + datetime beginDate ; // this datetime gets initialized only after the first call of the isNewCandle() function + MqlDateTime currTimeStruct; + MqlDateTime beginDateStruct; + bool firstCallHappened; +public: + NewCandleDetector(string _timeFrame); + + ~NewCandleDetector(); + + // GETTERS + datetime getBeginDate() {return beginDate;} + + void setTimeFrame(string _timeFrame) {timeFrame = _timeFrame;} + bool isNewCandle(); + + }; +//+------------------------------------------------------------------+ + +NewCandleDetector::NewCandleDetector(string _timeFrame) + { + + timeFrame = _timeFrame ; + firstCallHappened = false; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +NewCandleDetector::~NewCandleDetector() + { + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool NewCandleDetector:: isNewCandle() + { + + + + if(timeFrame == "PERIOD_M1") + { + + if(firstCallHappened == false) + { + + beginDate = iTime(_Symbol,PERIOD_M1,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_M1,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.min == currTimeStruct.min) + { + + return false; + } + else + { + //Print("in a new candle !, asset: " + _Symbol); + beginDate = currTime; + return true ; + + } + } + + + + } + else + if(timeFrame == "PERIOD_M2") + { + + } + + else + if(timeFrame == "PERIOD_M3") + { + + } + else + if(timeFrame == "PERIOD_M4") + { + + } + else + if(timeFrame == "PERIOD_M5") + { + + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_M5,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_M5,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.min == currTimeStruct.min) + { + + return false; + } + else + { + Print("in a new candle !, asset: " + _Symbol); + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_M6") + { + + } + else + if(timeFrame == "PERIOD_M10") + { + + } + else + if(timeFrame == "PERIOD_M12") + { + + } + else + if(timeFrame == "PERIOD_M15") + { + + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_M15,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_M15,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.min == currTimeStruct.min) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_M20") + { + + } + else + if(timeFrame == "PERIOD_M30") + { + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_M30,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_M30,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.min == currTimeStruct.min) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + } + else + if(timeFrame == "PERIOD_H1") + { + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_H1,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_H1,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.hour == currTimeStruct.hour) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_H2") + { + + } + else + if(timeFrame == "PERIOD_H3") + { + + } + else + if(timeFrame == "PERIOD_H4") + { + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_H4,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_H4,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.hour == currTimeStruct.hour) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + } + else + if(timeFrame == "PERIOD_H6") + { + + } + else + if(timeFrame == "PERIOD_H8") + { + + } + else + if(timeFrame == "PERIOD_H12") + { + + } + else + if(timeFrame == "PERIOD_D1") + { + + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_D1,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_D1,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.day == currTimeStruct.day) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_W1") + { + + + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_W1,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_W1,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.day == currTimeStruct.day) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_MN1") + { + + } + + + + return true; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/NewGenTest.ex5 b/NewGenTest.ex5 new file mode 100644 index 0000000..26600d1 Binary files /dev/null and b/NewGenTest.ex5 differ diff --git a/NewGenTest.mq5 b/NewGenTest.mq5 new file mode 100644 index 0000000..49d1571 --- /dev/null +++ b/NewGenTest.mq5 @@ -0,0 +1,1643 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +//input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTALS DATA + +//input int leftPeriod; +//input int rightPeriod; +//input int weekPeriodToInitialize; +//input int initFractalsPeriod ; +//int lowFractalIndex ; +//int highFractalIndex ; +//#include "LowFractal.mqh" +//#include "HighFractal.mqh" +//#include "LowFractalContainer.mqh" +//#include "HighFractalContainer.mqh" + + + +#property script_show_inputs + +input datetime InpStartTime = __DATETIME__; +input bool REJECTION_M1_ONLY ; + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" + + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" +#include "LotSizeCalculator.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + +// Telegram Connection include +#include + +// SCRIPTS INCLUDES + + + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +// NEW CANDLE CLASSES INITIALIZATION +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + +bool telegramTested = false ; +input bool testTelegram ; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +// Added because bmp files seem to have stopped working, possibly a file format issue +//fileType = "png"; +//fileName = "MyScreenshot." + fileType; + + + if(telegramTested == false && testTelegram == true) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"This is just a test ! " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + telegramTested = true ; + } + + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + + + + + /* if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } */ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + + //lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + //highFractalIndex = rightPeriod+1; // this is used for the fractals + //initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + //initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + /*if(newCandleDetector_M1.isNewCandle()) + { + + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + }*/ + + + if(REJECTION_M1_ONLY == true) + { + if(newCandleDetector_M1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + Print("Im in new candle !"); + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + } + } + else + { + + if(newCandleDetector_H1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + handleBuys(PERIOD_H1); + handleSells(PERIOD_H1); + } + + } + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + Print("Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol); + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + Print(" Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + Print("Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + Print("A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + Print("A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + Print("Bullish candle closed inside the resistance zone on " + _Symbol); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + Print("Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + Print("Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + Print("Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + Print("A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + Print("A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+------------------------------------------------------------------+ diff --git a/ObjectConfirmationUnit.mqh b/ObjectConfirmationUnit.mqh new file mode 100644 index 0000000..7ffdd76 --- /dev/null +++ b/ObjectConfirmationUnit.mqh @@ -0,0 +1,50 @@ +//+------------------------------------------------------------------+ +//| ObjectConfirmationUnit.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +/* + This class is responsible for all the proccess of confirming a new object. it prevents adding new objects if the previous was not confirmed. +*/ + +class ObjectConfirmationUnit + { +private: + string confirmationObjectID ; + string objectType ; + bool waitingToBeConfirmed ; + + +public: + ObjectConfirmationUnit(); + ~ObjectConfirmationUnit(); + + // GETTERS + string getObjectType(){ return objectType ;} + bool getWaitingStatus(){ return waitingToBeConfirmed ;} + string getConfirmationObjectId(){return confirmationObjectID;} + + // SETTERS + void setObjectType(string _type){ objectType = _type ;} + void setWaitingStatus(bool _waitStatus){ waitingToBeConfirmed = _waitStatus ;} + void setConfirmationObjectId(int _Id){ confirmationObjectID = IntegerToString(_Id) ;} + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +ObjectConfirmationUnit::ObjectConfirmationUnit() + { + waitingToBeConfirmed = false ; // initialize with false value + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +ObjectConfirmationUnit::~ObjectConfirmationUnit() + { + } +//+------------------------------------------------------------------+ diff --git a/Phoenix_Functions.mqh b/Phoenix_Functions.mqh new file mode 100644 index 0000000..ba50e5c --- /dev/null +++ b/Phoenix_Functions.mqh @@ -0,0 +1,618 @@ +//+------------------------------------------------------------------+ +//| Phoenix_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 "Range Related Variables" +//input double rangeDistanceBetweenZones ; +//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 group "Zone TimeFrames" +//input bool APPLY_M30_STRUCTURE ; +//input bool APPLY_H1_STRUCTURE; + + + +//input group "Candle Body Variables" +//input double WICK_RATIO_REJECTION; +//input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables 2" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; +input bool BUYS_ALLOWED = true ; +input bool SELLS_ALLOWED = true ; +input double lotSize ; +input int riskManagementCandlesCount ; +input double rrFactor ; +input bool APPLY_TRAIL ; +input ENUM_TIMEFRAMES TRAIL_TIME_FRAME ; + + +//input group "Trading Sessions" +//input bool TRADE_NEW_YORK_ALLOWED = true ; +//input bool TRADE_LONDON_ALLOWED = true ; + +input group "Fractal Related Variables" +//input int leftFractalPeriod ; +//input int rightFractalPeriod ; +input ENUM_TIMEFRAMES TIME_FRAME_TO_TRADE; +input int fractalsPeriod ; +input int stopLossFractalsPeriod ; +input ENUM_TIMEFRAMES stopLossTimeFrame ; + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); + + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserverTiger* marketObserverTiger = new MarketObserverTiger(); + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +NewCandleDetector newCandleDetectorWeekly("PERIOD_W1"); +NewCandleDetector newCandleDetectorDaily("PERIOD_D1"); +NewCandleDetector newCandleDetectorH4("PERIOD_H4"); +NewCandleDetector newCandleDetectorH1("PERIOD_H1"); +NewCandleDetector newCandleDetectorM30("PERIOD_M30"); +NewCandleDetector newCandleDetectorM15("PERIOD_M15"); +NewCandleDetector newCandleDetectorM5("PERIOD_M5"); +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 waitForBottomWick = false ; +bool bottomWickFormed = false; +bool topWickFormed = false; +bool waitForTopWick = false ; + + +double currentResistanceHighEdge = -1 ; +double currentResistanceLowEdge = -1 ; +double currentSupportHighEdge = -1 ; +double currentSupportLowerEdge = -1; + + +double currentSupportZonePrice ; +double currentResistanceZonePrice; + +int indexToNewTrade ; + + +// DATA STRUCTURES + +double lastLowFractalPrice ; +double lastHighFractalPrice ; + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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_M30 = rangeDistanceBetweenZones_M30 * Point(); + +double maxPipsRiskAmountActual = maxPipsRiskAmount * Point(); + +double firstPartialProfitInPipsActual = firstPartialProfitInPips * Point(); + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double detectSupportFromLastLowFractal(int _index) + { + double lastLowestSupportPrice = 99999; + for(int i= _index ; i > 1 ; i--) + { + if((candleClosedBearish(PERIOD_CURRENT,i) && candleClosedBullish(PERIOD_CURRENT,i-1))|| (candleClosedBearish(PERIOD_CURRENT,i) && candleClosedDoji(PERIOD_CURRENT,i-1))) + { + if(iClose(_Symbol,PERIOD_CURRENT,i) < lastLowestSupportPrice) + { + lastLowestSupportPrice = iClose(_Symbol,PERIOD_CURRENT,i); + + } + } + } + + return lastLowestSupportPrice ; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double detectResistanceFromLastHighFractal(int _index) + { + + + double lastHighestResistancePrice = -1; + for(int i= _index ; i > 1 ; i--) + { + if((candleClosedBullish(PERIOD_CURRENT,i) && candleClosedBearish(PERIOD_CURRENT,i-1))|| (candleClosedBullish(PERIOD_CURRENT,i) && candleClosedDoji(PERIOD_CURRENT,i-1))) + { + if(iClose(_Symbol,PERIOD_CURRENT,i) > lastHighestResistancePrice) + { + lastHighestResistancePrice = iClose(_Symbol,PERIOD_CURRENT,i); + + } + } + } + + return lastHighestResistancePrice ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void findAndDrawFractalsAndZones(ENUM_TIMEFRAMES _timeFrame, string _timeFrameStr) + { + if(isLowFractalByIndex(fractalsPeriod+1,fractalsPeriod,fractalsPeriod,_timeFrame)) // SUPPORTS + { + objectsManager.drawLowFractal(fractalsPeriod+1,clrRed); + lastLowFractalPrice = iLow(_Symbol,PERIOD_CURRENT,fractalsPeriod+1); + currentSupportZonePrice = detectSupportFromLastLowFractal(fractalsPeriod+5); + + datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,fractalsPeriod+1); + datetime _rightEdge =rightEdge; + double _higherEdgePrice = currentSupportZonePrice + supportHigherEdgeExtendActual; + double _lowerEdgePrice = currentSupportZonePrice - supportExtendBelowCandleActual; + + currentSupportLowerEdge = _lowerEdgePrice; + currentSupportHighEdge = _higherEdgePrice ; + + Zone* supportZoneObject = new Zone("support_zone",_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,_timeFrameStr,"TYPE_SUPPORT_BREAKOUT"); + objectsManager.drawRectangleInStrategyTester(1,_leftEdge,_rightEdge,_higherEdgePrice,_lowerEdgePrice,clrAliceBlue); + + if(candleClosedBelowSupportZone(_timeFrame)) + { + Comment("Im taking a sell !"); + if(((indexToNewTrade = findAvailableSpotInSellManagerArr())!= -1)) + { + + + double stopLossPrice ; + if(currentResistanceHighEdge != -1) + { + // stopLossPrice = currentResistanceHighEdge + stopLossAboveWickByActual ; + stopLossPrice = lastHighFractalPrice + stopLossAboveWickByActual; + } + //stopLossPrice = iHigh(_Symbol,_timeFrame,1) + stopLossAboveWickByActual; + + if(stopLossIsValidSells(stopLossPrice,maxPipsRiskAmountActual)) + { + double stopLossInPips = stopLossPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID) ; + double netTp = rrFactor * stopLossInPips ; + double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_BID)- netTp) ; + + SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger + + tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge); + tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge); + SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array + + sellsCount++; + } + else + { + Print("stop loss is not valid sells!"); + } + + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + currentSupportLowerEdge = -1; + currentSupportHighEdge = -1 ; + } + + + + } + + if(isHighFractalByIndex(fractalsPeriod+1,fractalsPeriod,fractalsPeriod,_timeFrame)) // RESISTANCES + { + objectsManager.drawHighFractal(fractalsPeriod+1,clrAliceBlue); + lastHighFractalPrice = iHigh(_Symbol,PERIOD_CURRENT,fractalsPeriod+1); + currentResistanceZonePrice = detectResistanceFromLastHighFractal(fractalsPeriod+5); + + datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,fractalsPeriod+1); + datetime _rightEdge =rightEdge; + double _higherEdgePrice = currentResistanceZonePrice + resistanceExtendAboveCandleActual; + double _lowerEdgePrice = currentResistanceZonePrice - resistanceLowerEdgeExtendActual; + + currentResistanceHighEdge = _higherEdgePrice; + currentResistanceLowEdge = _lowerEdgePrice; + Zone* supportZoneObject = new Zone("resistance_zone",_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,_timeFrameStr,"TYPE_RESISTANCE_BREAKOUT"); + objectsManager.drawRectangleInStrategyTester(2,_leftEdge,_rightEdge,_higherEdgePrice,_lowerEdgePrice,clrAliceBlue); + + if(candleClosedAboveResistanceZone(_timeFrame)) + { + Comment("Im taking a buy !"); + + if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1)) + { + + Print("indexToNewTrade:--------------------------------------- " + indexToNewTrade); + double stopLossPrice ; + if(currentSupportLowerEdge != -1) + { + // stopLossPrice = currentSupportLowerEdge - stopLossUnderWickByActual ; + stopLossPrice = lastLowFractalPrice - stopLossUnderWickByActual ; + } + + //stopLossPrice = iLow(_Symbol,_timeFrame,1) - stopLossUnderWickByActual; // if there is no lower zone , take the last m30 candle's low + + if(stopLossIsValidBuys(stopLossPrice,maxPipsRiskAmountActual)) + { + double stopLossInPips = SymbolInfoDouble(_Symbol,SYMBOL_ASK) - stopLossPrice ; + double netTp = rrFactor * stopLossInPips ; + double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+ netTp) ; + + BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger + tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge); + tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge); + BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array + + buysCount++; + } + else + { + Print("stop loss is not valid buys !"); + } + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + currentResistanceHighEdge = -1; + currentResistanceLowEdge = -1 ; + } + + } + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBelowSupportZone(ENUM_TIMEFRAMES _timeFrame) + { + if(candleClosedBearish(_timeFrame,1) && (iClose(_Symbol,_timeFrame,1) < currentSupportLowerEdge) && (currentSupportLowerEdge != -1) && (currentSupportZonePrice != 99999)) + { + return true ; + } + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedAboveResistanceZone(ENUM_TIMEFRAMES _timeFrame) + { + + if(candleClosedBullish(_timeFrame,1) && (iClose(_Symbol,_timeFrame,1) > currentResistanceHighEdge) && (currentResistanceHighEdge != -1) && (currentResistanceZonePrice != 0)) + { + + return true ; + } + return false ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 BuyActiveTradesArray[i].getBrokenResistanceHigherEdge()) + { + BuyActiveTradesArray[i].setRiskManagementCandleCounter(0); + } + + if(BuyActiveTradesArray[i].getRiskManagementCandleCounter() >= riskManagementCandlesCount) + { + // Close the trade + tradeLong.PositionClose(BuyActiveTradesArray[i].getTradeId()); + } + } + + + + + if(SellActiveTradesArray[i] != NULL) + { + if(candleClosedBullish(PERIOD_M5,1) && (iClose(_Symbol,PERIOD_M5,1) > SellActiveTradesArray[i].getBrokenSupportHigherEdge())) + { + SellActiveTradesArray[i].incrementRiskManagementCandleCoutner(); + + } + else + if((iClose(_Symbol,PERIOD_M5,1)) < SellActiveTradesArray[i].getBrokenSupportLowerEdge()) + { + SellActiveTradesArray[i].setRiskManagementCandleCounter(0); + } + + if(SellActiveTradesArray[i].getRiskManagementCandleCounter() >= riskManagementCandlesCount) + { + // Close the trade + tradeShort.PositionClose(SellActiveTradesArray[i].getTradeId()); + } + } + } + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double calculateStopLossBasedOnFractalsBuys(int _fractalsPeriod, ENUM_TIMEFRAMES _timeFrame) + { + + + + for(int i=0 ; 300 ; i++) // scan the last 200 candles + { + if(isLowFractalByIndex(i,_fractalsPeriod,_fractalsPeriod,_timeFrame)) + { + + return iLow(_Symbol,_timeFrame,i); + } + } + + return -1 ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double calculateStopLossBasedOnFractalsSells(int _fractalsPeriod,ENUM_TIMEFRAMES _timeFrame) + { + for(int i=0 ; 300 ; i++) // scan the last 200 candles + { + if(isHighFractalByIndex(i,_fractalsPeriod,_fractalsPeriod,_timeFrame)) + { + return iHigh(_Symbol,_timeFrame,i); + } + } + + return -1 ; + } +//+------------------------------------------------------------------+ + + +void trailAllOpenPositionsIfNeeded(ENUM_TIMEFRAMES _timeFrame) + { + + for(int i=0 ; i< NUM_MAX_ALLOWED_TRADES ; i++) // CHECK TRAIL FOR BUYS + { + if((BuyActiveTradesArray[i] != NULL)) + { + double newStopLoss = iLow(_Symbol,_timeFrame,1); + newStopLoss = newStopLoss - stopLossUnderWickByActual ; + if(newStopLoss > 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); + } + } + + + } + } \ No newline at end of file diff --git a/Phoenix_Reborn.ex5 b/Phoenix_Reborn.ex5 new file mode 100644 index 0000000..fb05022 Binary files /dev/null and b/Phoenix_Reborn.ex5 differ diff --git a/Phoenix_Reborn.mq5 b/Phoenix_Reborn.mq5 new file mode 100644 index 0000000..6f1cb9b --- /dev/null +++ b/Phoenix_Reborn.mq5 @@ -0,0 +1,201 @@ +//+------------------------------------------------------------------+ +//| Phoenix_Reborn.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include "Phoenix_Functions.mqh" + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + + + + +int OnInit() + { +//--- + +//--- + iOpen(_Symbol,PERIOD_M5,1); + iOpen(_Symbol,PERIOD_M15,1); + iOpen(_Symbol,PERIOD_M30,1); + iOpen(_Symbol,PERIOD_H1,1); + iOpen(_Symbol,PERIOD_H4,1); + + for(int i=0; i + + + +// SCRIPTS INCLUDES +//#include "Telegram_Exporter.mq5" + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + +// TRADE RELATED CLASSES INITIALIZATION +//BuyEntryManager* buyEntryManager = new BuyEntryManager(); +//BuyTradeManager* buyTradeManager = new BuyTradeManager(); + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +//SellEntryManager* sellEntryManager = new SellEntryManager(); +//SellTradeManager* sellTradeManager = new SellTradeManager(); + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + +// NEW CANDLE CLASSES INITIALIZATION + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*NewCandleDetector* newCandleDetectorM1 = new NewCandleDetector("PERIOD_M1"); +NewCandleDetector* newCandleDetectorM5 = new NewCandleDetector("PERIOD_M5"); +NewCandleDetector* newCandleDetectorM15 = new NewCandleDetector("PERIOD_M15"); +NewCandleDetector* newCandleDetectorM30 = new NewCandleDetector("PERIOD_M30"); +NewCandleDetector* newCandleDetectorH1 = new NewCandleDetector("PERIOD_H1"); +NewCandleDetector* newCandleDetectorH4 = new NewCandleDetector("PERIOD_H4"); +NewCandleDetector* newCandleDetectorD1 = new NewCandleDetector("PERIOD_D1"); */ + + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + +NewCandleDetector* newCandleDetectorTest ; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + +input datetime zoneLeftEdge ; +input double zoneHighEdge; +input double zoneLowEdge; +input double stopLosssPrice; +input double takeProfittPrice ; +input double takeProfittPrice2; + + + +//#property copyright "Copyright 2022, Orchard Forex" +//#property link "https://www.orchardforex.com" + +//#property script_show_inputs +//#property script_show_confirm + +//const string TelegramBotToken = "6245008777:AAHfUg-t4vhPPX6MioVSaZYB2Hc_QCm4acI"; +//const string ChatId = "-1001943701147"; +//const string TelegramApiUrl = "https://api.telegram.org"; // Add this to Allow URLs + +//const int UrlDefinedErrorMt4 = 4066 ; // this url defined error is for MT4 +//const int UrlDefinedError = 4014; // Because MT4 and MT5 are different + + + + +// VARIABLES FOR TELEGRAM PUBLISHER +//string fileType ; +//string fileName; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + + + objectsManager.drawRectangleInStrategyTester(1,iTime(Symbol(),PERIOD_CURRENT,130),iTime(Symbol(),PERIOD_CURRENT,0),zoneHighEdge,zoneLowEdge); + zoneContainer.incrementZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(zoneHighEdge); + newZone.setLowerEdgePrice(zoneLowEdge); + newZone.setLeftEdge(iTime(Symbol(),PERIOD_CURRENT,130)); + newZone.setRightEdge(iTime(Symbol(),PERIOD_CURRENT,0)); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(getChartTimeFrameInString()); + + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(zoneHighEdge < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(zoneLowEdge > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } +// add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + newZone.setStopLossPrice(stopLosssPrice); + newZone.setTakeProfit(takeProfittPrice); + newZone.setTakeProfit(takeProfittPrice2); + + newZone.printTradeManagerData(); + zoneContainer.printZonesSortedArray(); + +// ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + /*if(newCandleDetector_M1.isNewCandle()) + { + + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + }*/ + + + if(newCandleDetector_H1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + handleBuys(PERIOD_H1); + handleSells(PERIOD_H1); + } + + + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bearish candle closed inside the closest support zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bullish candle closed inside the resistance zone on " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+----------------------- diff --git a/SellEntryManager.mqh b/SellEntryManager.mqh new file mode 100644 index 0000000..85f3e8d --- /dev/null +++ b/SellEntryManager.mqh @@ -0,0 +1,119 @@ +//+------------------------------------------------------------------+ +//| SellEntryManager.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include "SellRejectionDetector.mqh" +#include + + + + + +CTrade tradeShort ; + +class SellEntryManager + { +private: + + bool shortTradeTaken ; + bool waitingForRejectionCandle ; + bool waitingForRetracement ; + bool liquiditySweepEntryTaken ; + +public: + SellEntryManager(); + ~SellEntryManager(); + + SellRejectionDetector* sellRejectionDetector ; + + bool isWaitingForRejectionCandle(){return waitingForRejectionCandle ;} + void setWaitingForRejectionCandle(bool _setting){waitingForRejectionCandle = _setting ; } + + bool isWaitingForRetracement(){return waitingForRetracement;} + void setWaitingForRetracement(bool _setting){waitingForRetracement = _setting ;} + + + bool sellTradeTaken(); + void setTradeTakenStatus(bool _status){shortTradeTaken = _status ;} + + bool liqEntryIsTaken(){return liquiditySweepEntryTaken;} + void setLiquiditySweepEntryTaken(bool _entryStatus){liquiditySweepEntryTaken = _entryStatus ;} + + + + + ulong takeSellTrade(double _lots,double _stopLoss); + ulong takeSellTradeTiger(double _lots, double _stopLoss, double _takeProfit); + ulong takeSellTradeTiger(double _lots, double _stopLoss); + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellEntryManager::SellEntryManager() + { + + sellRejectionDetector = new SellRejectionDetector(); + shortTradeTaken = false ; + waitingForRejectionCandle = false ; + bool waitingForRetracement = false; + liquiditySweepEntryTaken = false; + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellEntryManager::~SellEntryManager() + { + delete sellRejectionDetector; + } +//+------------------------------------------------------------------+ + +bool SellEntryManager:: sellTradeTaken(){ + + return shortTradeTaken ; +} + +ulong SellEntryManager:: takeSellTrade(double _lots, double _stopLoss){ + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss); + ulong tradeTicket = tradeShort.ResultOrder(); + + Print("Sell entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + + +} + + +ulong SellEntryManager:: takeSellTradeTiger(double _lots, double _stopLoss, double _takeProfit){ + + double netTp = SymbolInfoDouble(_Symbol, SYMBOL_BID); + netTp = netTp - _takeProfit ; + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss,SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTp); + + + ulong tradeTicket = tradeShort.ResultOrder(); + + Print("sELL entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} + + +ulong SellEntryManager:: takeSellTradeTiger(double _lots, double _stopLoss){ + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss); + ulong tradeTicket = tradeShort.ResultOrder(); + Print("sELL entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} \ No newline at end of file diff --git a/SellGandalf.mqh b/SellGandalf.mqh new file mode 100644 index 0000000..a1c0560 --- /dev/null +++ b/SellGandalf.mqh @@ -0,0 +1,79 @@ +//+------------------------------------------------------------------+ +//| SellGandalf.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include + +CTrade tradeShort ; + +class SellGandalf + { +private: + bool shortTradeTaken ; + ulong longTrades[10] ; + +public: + SellGandalf(); + ~SellGandalf(); + + bool sellTradeTaken(); + void setTradeTakenStatus(bool _status){shortTradeTaken = _status ; Print("long trade taken flag has been set to true");} + + + ulong takeSellTrade(double _lots,double _stopLoss); + ulong takeSellTradeGandalf(double _lots,double _stopLoss); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellGandalf::SellGandalf() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellGandalf::~SellGandalf() + { + } +//+------------------------------------------------------------------+ + + +bool SellGandalf:: sellTradeTaken(){ + + +return shortTradeTaken ; +} + + + +ulong SellGandalf:: takeSellTrade(double _lots, double _stopLoss){ + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss); + + ulong tradeTicket = tradeShort.ResultOrder(); + + Print("Sell entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + + +} + + +ulong SellGandalf:: takeSellTradeGandalf(double _lots,double _stopLoss){ + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss); + + ulong tradeTicket = tradeShort.ResultOrder(); + + Print("Sell entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} + + diff --git a/SellRejectionDetector.mqh b/SellRejectionDetector.mqh new file mode 100644 index 0000000..a51b7f9 --- /dev/null +++ b/SellRejectionDetector.mqh @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| SellRejectionDetector.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class SellRejectionDetector + { +private: + +public: + SellRejectionDetector(); + ~SellRejectionDetector(); + + bool rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame); + bool rejectionByRangeFormed(); + bool rejectionByWicksFormed(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellRejectionDetector::SellRejectionDetector() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellRejectionDetector::~SellRejectionDetector() + { + } +//+------------------------------------------------------------------+ + +bool SellRejectionDetector:: rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame){ + + double rejectionCandleClose = iClose(_Symbol,_timeFrame,1); + double rejectionCandleOpen = iOpen(_Symbol,_timeFrame,1); + double rejectionCandleLow = iLow(_Symbol,_timeFrame,1); + double rejectionCandleLowerWickSize ; + double rejectionCandleBodySize; + + if(rejectionCandleOpen > rejectionCandleClose){ // the previous candle closed bearish + rejectionCandleLowerWickSize = rejectionCandleClose - rejectionCandleLow ; + rejectionCandleBodySize = rejectionCandleOpen - rejectionCandleClose; + if(rejectionCandleBodySize >= rejectionCandleLowerWickSize){ + return true ; + } + + } + return false ; +} \ No newline at end of file diff --git a/SellTradeManager.mqh b/SellTradeManager.mqh new file mode 100644 index 0000000..8ab5681 --- /dev/null +++ b/SellTradeManager.mqh @@ -0,0 +1,586 @@ +//+------------------------------------------------------------------+ +//| SellTradeManager.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//#include +#include +#include +CTrade tradeInTradeManager; + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class SellTradeManager + { +private: + int tradeId ; + ulong rejectionByOneCandleTradeArray[3]; // index 0 : half the contract , index 1 : quarter of the contract , index 2 : quarter of the contract + + + string firstSecureMethod ; + bool firstSecureMethodFound; + int numberOfTakeProfits ; + bool securedFirstLevelProfit ; + bool securedSecondLevelProfit; + double partialToClose ; + bool isTradeRunning ; + + +public: + SellTradeManager(); + ~SellTradeManager(); + + + void fillRejectionByOneCandleTradeArray(int _index, ulong _id) {rejectionByOneCandleTradeArray[_index] = _id ;} + ulong getRejectionByOneCandleTradeTicket(int _index) {return rejectionByOneCandleTradeArray[_index] ;} + void printRejectionByOneCandleTradeArray(); + + void checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars); + string findFirstSecureMethod(); + + bool reachedProfitRatio(int _indexInArr); + bool closeTrade(int _indexInArr); + bool positionBreakEven(int _indexInArr); + + void addTpAtIndex(int _index, double tpPrice) {tpArray[_index] = tpPrice;} + int countRemainingTakeProfits(); + bool reachedClosestTakeProfit(); + void deleteClosestTp(); + int findClosestTpIndex(); + + void cleanOrderDataStructures(); + + void setTradeRunning(bool _setting) {isTradeRunning = _setting ;} + bool tradeIsRunning() {return isTradeRunning ;} + + double tpArray[3]; + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeManager::SellTradeManager() + { + for(int i=0; i<3; i++) + { + tpArray[i] = -1; + } + securedFirstLevelProfit = false ; + securedSecondLevelProfit = false ; + firstSecureMethodFound = false ; + firstSecureMethod = "NOT_FOUND" ; + partialToClose = -1 ; + isTradeRunning = false ; + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeManager::~SellTradeManager() + { + } + +//+------------------------------------------------------------------+ +void SellTradeManager:: printRejectionByOneCandleTradeArray() + { + + Print("Printing the tickets :"); + for(int i=0 ; i<3 ; i++) + { + Print((int)rejectionByOneCandleTradeArray[i]); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void SellTradeManager:: checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars) + { + + + if(securedFirstLevelProfit == false) // in this case im searching for 2 cases: either RR 1:1.5 , OR reaching the first TP , if any of them happened im gonna close half the order and updatae the remaining stop losses + { + + + if(!firstSecureMethodFound) + { + + firstSecureMethod = findFirstSecureMethod(); + if(firstSecureMethod != "FAILED") + { + firstSecureMethodFound = true ; + } + else + if(firstSecureMethod == "FAILED") + { + Print("Failed to find the first secure method, go check the function : findFirstSecureMehod() !"); + } + + } + + if(firstSecureMethodFound == true) + { + + if(firstSecureMethod == "RATIO_METHOD") + { + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(reachedProfitRatio(0)) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + "If you see this message it means we reached the first secure method, which is ratio method, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName); + if(closeTrade(0)) // close the half + { + + rejectionByOneCandleTradeArray[0] = -1; + Print("Closed Half Of the position due to reaching the first secure Ratio!"); + } + else + { + Print("Failed Closing Half of the order by reaching the first secure Ratio !"); + } + + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(positionBreakEven(1)) // put the first quarter at break even + { + + Print(" First quarter has been put into break even due to reaching the first secure Ratio!"); + } + else + { + Print("Failed to Put the first quarter into break even"); + } + + numberOfTakeProfits = countRemainingTakeProfits(); + + Print("Number of remaining tps is: " + numberOfTakeProfits); + + securedFirstLevelProfit = true ; + } + + + + + + } + else + if(firstSecureMethod == "FIRST_TP_METHOD") + { + if(countRemainingTakeProfits() > 1) // there is at least 2 tp in the tp Array (because if this is the last tp then we want to close the whole order and not just a part of it) + { + if(reachedClosestTakeProfit()) // 2. Check if reached the first Tp + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + "If you see this message it means we reached the first secure method which is tp1, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName); + // close the first half and update remaining partials sl's and delete the closest take profit from the array + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(closeTrade(0)) // close the half + { + + rejectionByOneCandleTradeArray[0] = -1; + Print("Closed Half Of the position due to reaching the first TP!"); + + } + else + { + Print("Failed Closing Half of the order by reaching the first TP !"); + } + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(positionBreakEven(1)) // put the first quarter at break even + { + + Print(" First quarter has been put into break even due to reaching the first TP!"); + } + else + { + Print("Failed to Put the first quarter into break even"); + } + deleteClosestTp(); + numberOfTakeProfits = countRemainingTakeProfits(); // update the number of remaining take profits + // calculate the remaining tps + + Print("Number of remaining tps is: " + numberOfTakeProfits); + + securedFirstLevelProfit = true ; + + + } + } + else + if(numberOfTakeProfits = countRemainingTakeProfits() == 1) + { + if(reachedClosestTakeProfit()) + { + // close everything remained + } + } + } + + } + + + + } + else + if(securedFirstLevelProfit == true) // after securing the first level i just want to close the remaining partials by reaching the tp's + { + + if(countRemainingTakeProfits() == 1) + { + if(reachedClosestTakeProfit()) + { + // close everything + cleanOrderDataStructures(); + for(int i=0 ; i<3 ; i++) + { + closeTrade(i); + } + Print("Closed every thing because price reached the last Take Profit !"); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + "If you see this message it means that all order are closed as a result of reaching the last tp " + TimeToString(TimeLocal()), fileName); + deleteClosestTp(); + } + } + else + if(countRemainingTakeProfits() > 1) + { + if(reachedClosestTakeProfit()) + { + cleanOrderDataStructures(); + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[1])) // DEALING WITH THE FIRST QUARTER + { + double currentLot = PositionGetDouble(POSITION_VOLUME); + if(partialToClose == -1) + { + partialToClose = currentLot/numberOfTakeProfits ; + } + if(tradeInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[1],NormalizeDouble(partialToClose,2))) + { + uint res = tradeInTradeManager.ResultRetcode(); + if(res == 10009) + { + Print("Closed Partials successfully on the first quarter !"); + } + else + { + Print("The returned code is: " + res + " go check what it means !"); + } + + } + } + else + { + Print("Failed to select position by ticket, Error: " + GetLastError()); + Print("The EA tried to close partials on the first quarter, but it is closed, probably due to break even and thats why it couldnt select the order !"); + } + + + cleanOrderDataStructures(); + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[2])) // DEALING WITH THE SECOND QUARTER + { + if(PositionGetDouble(POSITION_SL) > PositionGetDouble(POSITION_PRICE_OPEN)) // this is to put the second quarter at break even if its not already at break even + { + positionBreakEven(2); + + } + double currentLot = PositionGetDouble(POSITION_VOLUME); + if(partialToClose == -1) + { + partialToClose = currentLot/numberOfTakeProfits ; + } + if(tradeInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[2],NormalizeDouble(partialToClose,2))) + { + uint res = tradeInTradeManager.ResultRetcode(); + if(res == 10009) + { + Print("Closed Partials successfully on the second quarter!"); + } + else + { + Print("The returned code is: " + res + " go check what it means !"); + } + + } + + } + deleteClosestTp(); + Print("Number Of Remained tps is: " + countRemainingTakeProfits()); + + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + "If you see this message it means we reached a tp level (different than the first secure level), so partial positions will be closed, and the scond quarter must be in break even!" + TimeToString(TimeLocal()), fileName); + } + + } + + + } + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string SellTradeManager:: findFirstSecureMethod() + { + + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[0])) + { + double positionStopLoss = PositionGetDouble(POSITION_SL); + double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double firstTakeProfit = tpArray[findClosestTpIndex()]; + if(((positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) > firstSecureRatio)) // firstTp > ratio + { + Print("Found the first profit secure method !"); + Print("The first TP RR is: 1:" + (positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) + "the firstSecureRatio is: 1:" + firstSecureRatio); + Print("The tp ratio is greater than the firstSecure so:"); + Print("The first secure method is RATIO_METHOD"); + return"RATIO_METHOD"; + } + else + if((positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice)< firstSecureRatio) + { + Print("Found the first profit secure method !"); + Print("The first TP RR is: 1:" + (positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) + "the firstSecureRatio is: 1:" + firstSecureRatio); + Print("The tp ratio is less than the firstSecure so:"); + Print("The first secure method is FIRST_TP_METHOD"); + return "FIRST_TP_METHOD" ; + } + } + else + { + Print("Failed to select position by ticket 1, Error: " + GetLastError()); + } + + return "FAILED" ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool SellTradeManager:: reachedProfitRatio(int _indexInArr) + { + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) + { + if(PositionGetDouble(POSITION_PROFIT)/(0.5*riskDollars) >= firstSecureRatio) // checking if the first half of the contract reached the ratio of first secure profit + { + Print("reached profit ratio !"); + return true ; + } + } + else + { + Print("Failed to select the position by ticket 4 ,Error: " + GetLastError()); + + } + + } + + return false ; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool SellTradeManager:: closeTrade(int _indexInArr) + { + + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) + { + + // close the first half and update remaining partials sl's + if(tradeInTradeManager.PositionClose(_ticket)) + { + return true ; + + } + else + { + + Print("Failed to close positon, Error:" + GetLastError()); + return false; + } + + } + else + { + + Print("Failed to select position by ticket 2, Error: "+ GetLastError()); + return false; + } + + } + + + return false ; + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool SellTradeManager:: positionBreakEven(int _indexInArr) + { + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) // select the first quarter + { + double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double positionTp = PositionGetDouble(POSITION_TP); + double positionSl = PositionGetDouble(POSITION_SL); + + if(tradeInTradeManager.PositionModify((_ticket),openPrice,positionTp)) + { + + + return true ; + } + else + { + Print("Failed to modify oder , ERROR: " + GetLastError()); + return false ; + } + + } + else + { + Print("Failed to select position by ticket 3"); + return false ; + } + } + + + return false ; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int SellTradeManager:: countRemainingTakeProfits() + { + + int counter = 0 ; + for(int i=0; i<3 ; i++) + { + if(tpArray[i] != -1) + { + counter++ ; + } + } + + return counter; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void SellTradeManager:: deleteClosestTp() + { + + int closestTpIndex =findClosestTpIndex(); + tpArray[closestTpIndex] = -1; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int SellTradeManager:: findClosestTpIndex() + { + int closestTpIndex = 0; + + for(int i=1; i<3; i++) + { + if(tpArray[i] > tpArray[closestTpIndex]) + { + closestTpIndex = i ; + } + } + + return closestTpIndex ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool SellTradeManager:: reachedClosestTakeProfit() + { + + + double closestTakeProfitValue = tpArray[findClosestTpIndex()]; +//Print("im in reached closest take profit function ,the current price is: " + SymbolInfoDouble(_Symbol, SYMBOL_BID) + " and the tp is: " + closestTakeProfitValue); + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= closestTakeProfitValue) // we want the ASK because we are basically buying the asset again (in a cheaper price), and we want to buy it on the ASK (which is the price that a seller is willing to sell us) + { + return true ; + } + return false ; + + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void SellTradeManager:: cleanOrderDataStructures() + { +// this is to make sure, that every closed order is removed from the data strucutre ! + + for(int i=0; i<3; i++) + { + if(!PositionSelectByTicket(rejectionByOneCandleTradeArray[i])) + { + if(GetLastError() == 4753) + { + rejectionByOneCandleTradeArray[i] = -1 ; + } + } + } + + } +//+------------------------------------------------------------------+ diff --git a/SellTradeManagerTiger.mqh b/SellTradeManagerTiger.mqh new file mode 100644 index 0000000..ce5dfdd --- /dev/null +++ b/SellTradeManagerTiger.mqh @@ -0,0 +1,69 @@ +//+------------------------------------------------------------------+ +//| SellTradeManagerTiger.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class SellTradeManagerTiger + { +private: + ulong tradeId ; + string entryType ; + bool firstPartialSecured ; + bool secondPartialSecured ; + bool managedRisk ; + int riskManagementCandleCounter ; + double brokenSupportHigherEdge ; + double brokenSupportLowerEdge ; +public: + ulong getTradeId(){return tradeId ;} + + bool riskAlreadyManaged(){return managedRisk ;} + void manageRisk(){managedRisk = true ;} + + bool firstPartialIsSecured(){return firstPartialSecured ;} + void secureFirstPartial(){firstPartialSecured = true ;} + + bool retestWickFormed ; + double retestWickLengthInPips ; + + void setBrokenSupportHigherEdge(double _brokenSupportHigherEdge){brokenSupportHigherEdge = _brokenSupportHigherEdge ;} + void setBrokenSupportLowerEdge(double _brokenSupportLowerEdge){brokenSupportLowerEdge = _brokenSupportLowerEdge ;} + + double getBrokenSupportHigherEdge(){return brokenSupportHigherEdge ;} + double getBrokenSupportLowerEdge(){return brokenSupportLowerEdge;} + + void incrementRiskManagementCandleCoutner(){riskManagementCandleCounter++ ;} + void decrementRiskManagementCandleCounter(){riskManagementCandleCounter-- ;} + + int getRiskManagementCandleCounter(){return riskManagementCandleCounter ;} + void setRiskManagementCandleCounter(int count){ riskManagementCandleCounter = count ;} + + + SellTradeManagerTiger(ulong _tradeId); + ~SellTradeManagerTiger(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeManagerTiger::SellTradeManagerTiger(ulong _tradeId) + { + + tradeId = _tradeId ; + firstPartialSecured = false ; + secondPartialSecured = false ; + managedRisk = false ; + + retestWickFormed = false ; + retestWickLengthInPips = 0 ; + riskManagementCandleCounter = 0 ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeManagerTiger::~SellTradeManagerTiger() + { + } +//+------------------------------------------------------------------+ diff --git a/SellTradeMangerTiger.mqh b/SellTradeMangerTiger.mqh new file mode 100644 index 0000000..0a82a3b --- /dev/null +++ b/SellTradeMangerTiger.mqh @@ -0,0 +1,29 @@ +//+------------------------------------------------------------------+ +//| SellTradeMangerTiger.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class SellTradeMangerTiger + { +private: + +public: + SellTradeMangerTiger(); + ~SellTradeMangerTiger(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeMangerTiger::SellTradeMangerTiger() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeMangerTiger::~SellTradeMangerTiger() + { + } +//+------------------------------------------------------------------+ diff --git a/Shark.mq5 b/Shark.mq5 new file mode 100644 index 0000000..1074547 --- /dev/null +++ b/Shark.mq5 @@ -0,0 +1,846 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTAL VARIABLES INITIALIZATION + +input int leftPeriod; +input int rightPeriod; +input int weekPeriodToInitialize; +input int initFractalsPeriod ; +int lowFractalIndex ; +int highFractalIndex ; + + + + +// GUI CLASSES INCLUDES +#include "ZoneContainer.mqh" +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "LowFractal.mqh" +#include "HighFractal.mqh" +#include "LowFractalContainer.mqh" +#include "HighFractalContainer.mqh" + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" + +// LIBRARIES INCLUDES +#include + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer zoneContainer ; +LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + + + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// NEW CANDLE CLASSES INITIALIZATION + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*NewCandleDetector* newCandleDetectorM1 = new NewCandleDetector("PERIOD_M1"); +NewCandleDetector* newCandleDetectorM5 = new NewCandleDetector("PERIOD_M5"); +NewCandleDetector* newCandleDetectorM15 = new NewCandleDetector("PERIOD_M15"); +NewCandleDetector* newCandleDetectorM30 = new NewCandleDetector("PERIOD_M30"); +NewCandleDetector* newCandleDetectorH1 = new NewCandleDetector("PERIOD_H1"); +NewCandleDetector* newCandleDetectorH4 = new NewCandleDetector("PERIOD_H4"); +NewCandleDetector* newCandleDetectorD1 = new NewCandleDetector("PERIOD_D1"); */ + + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + //Print("the ask is: " + SymbolInfoDouble(_Symbol, SYMBOL_ASK)); + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + + // INIT FRACTAL VARIABLES + lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + highFractalIndex = rightPeriod+1; // this is used for the fractals + initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + + + if(newCandleDetectorLive.isNewCandle()) + { + handleLowFractals(inputTimeFrameFractals); // scans low fractals that are forming and adds them to the container + handleHighFractals(inputTimeFrameFractals); // scans high fractals that are forming and adds them to the container + } + + + + + + + + + + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + if(tempObjectAttr.getHigherEdgePrice() < SymbolInfoDouble(_Symbol, SYMBOL_ASK) ){ // means its a support zone + newZone.setType("TYPE_SUPPORT"); + } + if(tempObjectAttr.getLowerEdgePrice() > SymbolInfoDouble(_Symbol, SYMBOL_ASK)){ // means its a resistance zone + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdges(); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + } + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { // delete from data structure + zoneContainer.findOrUpdatePivotEdges(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else{ + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + delete lowsContainer; + delete highsContainer; + + delete newCandleDetectorLive; + zoneContainer.freeZonesSortedArray(); + /*delete newCandleDetectorD1; + delete newCandleDetectorM5; + delete newCandleDetectorM30; + delete newCandleDetectorM15; + delete newCandleDetectorM1; + delete newCandleDetectorH4; + delete newCandleDetectorH1; */ + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print("High Fractals:"); + highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + else // THIS is the case were we click on any object except for the 'Add Zone' and 'Confirm Object' Buttons + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } + + + +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/Shark_tester.mq5 b/Shark_tester.mq5 new file mode 100644 index 0000000..d89ba7c --- /dev/null +++ b/Shark_tester.mq5 @@ -0,0 +1,1191 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTAL VARIABLES INITIALIZATION + +input int leftPeriod; +input int rightPeriod; +input int weekPeriodToInitialize; +input int initFractalsPeriod ; +int lowFractalIndex ; +int highFractalIndex ; + + + + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" +#include "LowFractal.mqh" +#include "HighFractal.mqh" +#include "LowFractalContainer.mqh" +#include "HighFractalContainer.mqh" + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer zoneContainer ; +LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION + MarketObserver marketObserver = new MarketObserver(); + + + +// TRADE RELATED CLASSES INITIALIZATION +BuyEntryManager buyEntryManager = new BuyEntryManager(); +BuyTradeManager buyTradeManager = new BuyTradeManager(); + +SellEntryManager sellEntryManager = new SellEntryManager(); +SellTradeManager sellTradeManager = new SellTradeManager(); + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + +// NEW CANDLE CLASSES INITIALIZATION + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*NewCandleDetector* newCandleDetectorM1 = new NewCandleDetector("PERIOD_M1"); +NewCandleDetector* newCandleDetectorM5 = new NewCandleDetector("PERIOD_M5"); +NewCandleDetector* newCandleDetectorM15 = new NewCandleDetector("PERIOD_M15"); +NewCandleDetector* newCandleDetectorM30 = new NewCandleDetector("PERIOD_M30"); +NewCandleDetector* newCandleDetectorH1 = new NewCandleDetector("PERIOD_H1"); +NewCandleDetector* newCandleDetectorH4 = new NewCandleDetector("PERIOD_H4"); +NewCandleDetector* newCandleDetectorD1 = new NewCandleDetector("PERIOD_D1"); */ + + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + + + + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +//Print("the ask is: " + SymbolInfoDouble(_Symbol, SYMBOL_ASK)); + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + highFractalIndex = rightPeriod+1; // this is used for the fractals + initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + if(newCandleDetectorLive.isNewCandle()) + { + handleLowFractals(inputTimeFrameFractals); // scans low fractals that are forming and adds them to the container + handleHighFractals(inputTimeFrameFractals); // scans high fractals that are forming and adds them to the container + } + + + + + /* if((priceInMiddle == true) && (buyOnAction == true)){ // THIS CASE MEANS WE ARE IN THE MIDDLE OF TWO ZONES , AND A BUY TRADE IS OPEN + buyTradeManager.handleTrade(); // this is responsible for exiting and taking partials + + if(marketObserver.candleClosedBelowSupportZone(&zoneContainer) == true){ + buyTradeManager.closeTrade(); + + buyOnAction = false ; + + } + else if(marketObserver.zoneReached(&zoneContainer) == "TYPE_RESISTANCE"){ + // close the buy + buyTradeManager.closeTrade(); + + buyOnAction = false ; + sellEntryManager.setLookingForSell(true) ; + } + + } */ + + /*else if((priceInMiddle == true) && (sellOnAction == true)){ // THIS CASE MEANS WE ARE IN THE MIDDLE OF TWO ZONES , AND A SELL TRADE IS OPEN + sellTradeManager.handleTrade();// this is responsible for exiting and taking partials + + if(marketObserver.candleClosedAboveResistanceZone(&zoneContainer) == true){ + sellTradeManager.closeTrade(); + + sellOnAction = false ; + } + else if(marketObserver.zoneReached(&zoneContainer) == "TYPE_SUPPORT"){ + // close the sell + sellTradeManager.closeTrade(); + + sellOnAction = false; + buyEntryManager.setLookingForBuy(true) ; + + } + + } */ + + + + + + if(priceInMiddle == true){ // THIS CASE MEANS WE ARE IN THE MIDDLE OF TWO ZONES , AND NO CURRENT TRADE IS OPEN + if(marketObserver.reachedClosestSupportZone(&zoneContainer)){ // we reached a support zone so looking for buys + Print("Reached a support zone ! i will inform you if a buy confiramtion happens "); + priceInMiddle = false; + buyEntryManager.setLookingForBuy(true) ; + sellEntryManager.setLookingForSell(false); + + + } + else if(marketObserver.reachedClosestResistanceZone(&zoneContainer)){ // we reached resistance zone so looking for sells + Print("Reached a resistance zone ! i will inform you if a sell confirmation happens "); + priceInMiddle = false; + sellEntryManager.setLookingForSell(true) ; + buyEntryManager.setLookingForBuy(false) ; + + } + else{ // we are still in the middle so do nothing + + } + + } + + + + + /*if(buyEntryManager.isLookingForBuy() == true){ + if(marketObserver.candleClosedBelowSupportZone(&zoneContainer) == true){ // trade idea is invalid , so wait the user to confirm the break of the zone + buyEntryManager.setLookingForBuy(false) ; + + } + else if(buyEntryManager.buyTaken() == true ){ + priceInMiddle = true ; + buyOnAction = true ; + buyEntryManager.setLookingForBuy(false) ; + + } + + else if(marketObserver.reachedClosestResistanceZone() == true){ + + buyEntryManager.setLookingForBuy(false); + } + } */ + + + + /*if(sellEntryManager.isLookingForSell() == true){ + if(marketObserver.candleClosedAboveResistanceZone(&zoneContainer) == true){ + sellEntryManager.setLookingForSell(false); + } + else if(sellEntryManager.sellTaken() == true){ + priceInMiddle = true ; + sellOnAction = true ; + sellEntryManager.setLookingForSell(false) ; + + } + } */ + + + + + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + if(tempObjectAttr.getHigherEdgePrice() < SymbolInfoDouble(_Symbol, SYMBOL_ASK)) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + if(tempObjectAttr.getLowerEdgePrice() > SymbolInfoDouble(_Symbol, SYMBOL_ASK)) // means its a resistance zone + { + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdges(); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdges(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + delete lowsContainer; + delete highsContainer; + + delete newCandleDetectorLive; + zoneContainer.freeZonesSortedArray(); + /*delete newCandleDetectorD1; + delete newCandleDetectorM5; + delete newCandleDetectorM30; + delete newCandleDetectorM15; + delete newCandleDetectorM1; + delete newCandleDetectorH4; + delete newCandleDetectorH1; */ + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print("High Fractals:"); + highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else if(sparam == "SET_TP_BTN"){ + if(objectConfUnit.getObjectType() != "OBJ_HLINE"){ + Print("Please select a TP line first !"); + + } + else{ + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())){ + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else{ + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } + + + +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/TempLineObjectAttributes.mqh b/TempLineObjectAttributes.mqh new file mode 100644 index 0000000..c878c48 --- /dev/null +++ b/TempLineObjectAttributes.mqh @@ -0,0 +1,40 @@ +//+------------------------------------------------------------------+ +//| TempLineObjectAttributes.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class TempLineObjectAttributes + { +private: + + string id ; + double price ; + +public: + TempLineObjectAttributes(); + ~TempLineObjectAttributes(); + + // GETTERS + string getId(){return id;} + double getPrice(){return price ;} + + // SETTERS + void setId(string _id){id =_id ;} + void setPrice(double _price){price = _price ;} + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +TempLineObjectAttributes::TempLineObjectAttributes() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +TempLineObjectAttributes::~TempLineObjectAttributes() + { + } +//+------------------------------------------------------------------+ diff --git a/TempObjectAttributes.mqh b/TempObjectAttributes.mqh new file mode 100644 index 0000000..99949d1 --- /dev/null +++ b/TempObjectAttributes.mqh @@ -0,0 +1,81 @@ +//+------------------------------------------------------------------+ +//| TempObjectAttributes.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class TempObjectAttributes + { +private: + // ATTRIBUTES FOR A ZONE + string assetName; + string timeFrame ; + double higherEdgePrice ; + double lowerEdgePrice ; + datetime leftEdgeTime ; + datetime rightEdgeTime; + + + // ATTRIBUTES FOR TRENDLINE + + + + // ATTRIBUTES FOR DAILY LINE + + + + // ATTRIBUTES FOR IMBALANCE + + + + // ATTRIBUTES FOR FIBONACCI LEVEL + + + + +public: + TempObjectAttributes(); + ~TempObjectAttributes(); + + // GETTERS FOR ZONE + double getHigherEdgePrice(){return higherEdgePrice;} + double getLowerEdgePrice(){return lowerEdgePrice;} + datetime getLeftEdgeTime(){return leftEdgeTime ;} + datetime getRightEdgeTime(){return rightEdgeTime;} + string getSymbol(){return assetName;} + string getTimeFrame(){return timeFrame;} + + // SETTERS FOR ZONE + void setHigherEdgePrice(double _higherEdgePrice){higherEdgePrice = _higherEdgePrice;} + void setLowerEdgePrice(double _lowerEdgePrice){lowerEdgePrice = _lowerEdgePrice;} + void setLeftEdgeTime(datetime _leftEdgeTime){leftEdgeTime = _leftEdgeTime;} + void setRightEdgeTime(datetime _rightEdgeTime){rightEdgeTime = _rightEdgeTime;} + void setSymbol(){assetName = Symbol();} + void setTimeFrame(string _timeframe){timeFrame = _timeframe;} + // OTHER ZONE FUNCTIONS + + void cleanAttributesZone(){higherEdgePrice = -1; + lowerEdgePrice = -1; + leftEdgeTime = 0; + rightEdgeTime = 0;} + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +TempObjectAttributes::TempObjectAttributes() + { + + higherEdgePrice = -1; + lowerEdgePrice = -1; + leftEdgeTime = 0; + rightEdgeTime = 0; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +TempObjectAttributes::~TempObjectAttributes() + { + } +//+------------------------------------------------------------------+ diff --git a/Tiger.ex5 b/Tiger.ex5 new file mode 100644 index 0000000..0c85b19 Binary files /dev/null and b/Tiger.ex5 differ diff --git a/Tiger.mq5 b/Tiger.mq5 new file mode 100644 index 0000000..d88c67c --- /dev/null +++ b/Tiger.mq5 @@ -0,0 +1,601 @@ +//+------------------------------------------------------------------+ +//| Tiger.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include "NewCandleDetector.mqh" +#include "GraphicalObjectsManager.mqh" +#include "Zone.mqh" +#include "ZoneContainer.mqh" + +#include "MarketObserver.mqh" +#include "BuyEntryManager.mqh" +#include "LotSizeCalculator.mqh" +input double rangeDistance ; +input double resistanceExtendAboveCandle; +input double supportExtendBelowCandle ; +input double stopLossLimit ; +double input riskInDollars ; +double input netTakeProfit ; +bool input allowSecondChanceStopLoss ; +double input bottomWickSize ; +double input smallBottomWickSize ; +double input buyStopPipsTrigger ; +bool input MOD_CLEAN = false ; + + +bool waitingForBottomWickToForm = false ; +bool waitingForSmallBottomWickToForm = false ; +bool buyStopValid = false ; +bool closedPartialOnNegativeDirection = false ; +bool securedTenPips = false ; + + +#include + +CTrade tradeTiger ; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; + + + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +NewCandleDetector newCandleDetector("PERIOD_M30"); +BuyEntryManager buyEntryMan ; +LotSizeCalculator lotSizeCalc ; + + +Zone* temporaryRestestSupportZone = new Zone(); +int OnInit() + { +//--- create timer + EventSetTimer(60); + iClose(_Symbol,PERIOD_M15,5); + iClose(_Symbol,PERIOD_H1,5); + + /*datetime d1=D'2023.09.01 00:00:00'; // Year Month Day Hours Minutes Seconds + Print("the dateTime is: " + d1); + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(1930); + newZone.setLowerEdgePrice(1925); + newZone.setLeftEdge(iTime(_Symbol,PERIOD_CURRENT,2)); + newZone.setRightEdge(d1); + newZone.setId("1"); + newZone.setTimeFrame("PERIOD_M30"); + + + zoneContainer.addZone(newZone); + objectsManager.drawRectangleInStrategyTester(1,iTime(_Symbol,PERIOD_CURRENT,2),d1,1930,1925); + zoneContainer.printZonesSortedArray(); */ + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + + if(securedTenPips == false ){ + secureTenPips(0.3); + } + + if(waitingForBottomWickToForm){ + if(iClose(_Symbol,PERIOD_CURRENT,1) - SymbolInfoDouble(_Symbol, SYMBOL_BID) >= bottomWickSize){ + + waitingForBottomWickToForm = false ; + Print("Bottom Wick in length of at least " + bottomWickSize + " was formed !"); + buyStopValid = true ; + + + } + + } + + + + + if(buyStopValid){ + if( SymbolInfoDouble(_Symbol, SYMBOL_ASK) > iHigh(_Symbol,PERIOD_CURRENT,1) + buyStopPipsTrigger){ // here we take a buy entry based on break and retest wick. the Algo will first try to put the stop loss under the low of the temporary support zone + // if that stop loss was too high , then it will put it under the low of the wick that was recently made. (the wick should be at least bottomWickSize which is currently 1) + + double stopLossUnderTemporarySupportZone = temporaryRestestSupportZone.getLowerEdge() - 0.5 ; // under the temporary support zone + double stopLossUnderWick = iLow(_Symbol,PERIOD_CURRENT,0) - 0.5; // the low of the current candle + + if(!((SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossUnderTemporarySupportZone) > stopLossLimit)){ // on this case a wick was formed price starts to break the previous candle high, im taking a buy + //and im putting the stop loss below the whole zone (which is support now) + double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossUnderTemporarySupportZone); + buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossUnderTemporarySupportZone,2); + closedPartialOnNegativeDirection = false ; + securedTenPips = false ; + buyStopValid = false ; + Print("Took a wick retest buy type 1"); + + + } + else if(!((SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossUnderWick) > stopLossLimit)){ // on this case a wick was formed price starts to break the previous candle high, im taking a buy + //and im putting the stop loss below the wick (which is at least bottomWickSize) + + double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossUnderWick); + buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossUnderWick,2); + closedPartialOnNegativeDirection = false ; + securedTenPips = false ; + buyStopValid = false ; + Print("Took a wick retest buy type 2"); + } + } + + } + + if(newCandleDetector.isNewCandle()) + { + + + if(iClose(_Symbol,PERIOD_CURRENT,1) < iOpen(_Symbol,PERIOD_CURRENT,1) && closedPartialOnNegativeDirection == false){ // if the m30 candle closed bearish + closePartialsOfAllTrades(0.5); + closedPartialOnNegativeDirection = true ; + } + + + buyStopValid = false ; + waitingForBottomWickToForm = false ; + bool finishedDeleting = false ; + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + + + if(candleClosedBelowRetestZone(PERIOD_CURRENT)){ + temporaryRestestSupportZone.setType("TYPE_INVALID"); + deleteZoneGuiOnly("999"); + + } + + if(zoneContainer.getNumberOfActiveZones() != 0) // if there are zones found + { + if(marketObserver.candleClosedAboveResistanceByIndex(0,PERIOD_CURRENT)) // check if candle closed above the zone + { + + + datetime _leftEdgeRestestZone = iTime(_Symbol,PERIOD_CURRENT,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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + if(zoneContainer.getNumberOfActiveZones() != 0 && marketObserver.candleClosedAboveResistanceByIndex(0,PERIOD_CURRENT)) + { + 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI + } + else + { + finishedDeleting = true ; + } + + + } + + + + int idAsInt = StringToInteger(temporaryRestestSupportZone.getId()); + + + if((mqldt.hour > 13 && mqldt.hour < 22) || (mqldt.hour > 3 && mqldt.hour < 7) || (mqldt.hour > 8 && mqldt.hour < 12) ) + { + + + double stopLossPrice = iLow(_Symbol,PERIOD_CURRENT,1); + stopLossPrice = stopLossPrice -1; + + double secondChanceStopLossPrice = iLow(_Symbol,PERIOD_M15,1); + secondChanceStopLossPrice = secondChanceStopLossPrice -1; + + if(!(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossPrice > stopLossLimit)) // enter only if the M30 previous candle satisfied the condition of the proper stop loss + { + //Print("Entered here 2!"); + double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossPrice); + buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossPrice,netTakeProfit); + closedPartialOnNegativeDirection = false ; + securedTenPips = false ; + } + else + if(!(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - secondChanceStopLossPrice > stopLossLimit) && secondChanceStopLossPrice < temporaryRestestSupportZone.getLowerEdge() - 0.5) // if the M30 candle failed , then try the M15 candle + { + + if(allowSecondChanceStopLoss == true) + { + + double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,secondChanceStopLossPrice); + buyEntryMan.takeBuyTradeTiger(lotsToEnter,secondChanceStopLossPrice,netTakeProfit); + closedPartialOnNegativeDirection = false ; + securedTenPips = false ; + + } + + + } + + else // both M30 and M15 candles closed too far from the zone, so im gonna wait for retracement , and support to be built on the zone, or a bottom wick to form + { + + objectsManager.drawRectangleInStrategyTester(idAsInt,_leftEdgeRestestZone,_rightEdgeRetestZone, + temporaryRestestSupportZone.getHigherEdge(),temporaryRestestSupportZone.getLowerEdge(),clrGray); + + + waitingForBottomWickToForm = true ; + + + } + + } + + + + } + + } + + + + if(candleClosedBullish(PERIOD_M30,2) && candleClosedBearish(PERIOD_M30,1)) + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,PERIOD_CURRENT,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistance)) + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame("PERIOD_M30"); + newZone.setType("TYPE_RESISTANCE"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,clrBeige); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistance)){ + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame("PERIOD_M30"); + newZone.setType("TYPE_RESISTANCE"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,clrBeige); + //zoneContainer.printZonesSortedArray(); + } + + + + } + + + Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + Print("Zones are : "); + zoneContainer.printZonesSortedArray(); + } + + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool resistanceIsFound() + { + +//if() + + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + zoneContainer.deleteZone(_id); + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + + + void deleteZoneGuiOnly(string _id) + { + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } +//+------------------------------------------------------------------+ + + +bool candleClosedBelowRetestZone(ENUM_TIMEFRAMES tf){ + + + double previousCandleClose = iClose(_Symbol,tf,1); + + if(previousCandleClose < temporaryRestestSupportZone.getLowerEdge() ){ + + return true ; + } + + return false ; +} + + + + +void closePartialsOfAllTrades(double partial){ + for(int i = PositionsTotal()-1 ; i>=0 ; i--){ + ulong posTicket = PositionGetTicket(i); + if(PositionSelectByTicket(posTicket)){ + double positionVolum = PositionGetDouble(POSITION_VOLUME); + double partialToClose = positionVolum * partial ; + tradeTiger.PositionClosePartial(posTicket,NormalizeDouble(partialToClose,2)); + + } + else{ + Print("Failed to select position, Error: " + GetLastError()); + } + + + + } +} + + + +void secureTenPips(double partial){ + + for(int i = PositionsTotal()-1 ; i>=0 ; i--){ + ulong posTicket = PositionGetTicket(i); + if(PositionSelectByTicket(posTicket)){ + double positionVolume = PositionGetDouble(POSITION_VOLUME); + + if((SymbolInfoDouble(_Symbol, SYMBOL_BID) - PositionGetDouble(POSITION_PRICE_OPEN)) > 1){ + double partialToClose = positionVolume * partial ; + tradeTiger.PositionClosePartial(posTicket,NormalizeDouble(partialToClose,2)); + securedTenPips = true ; + Print("secured 10 pips"); + + } + + + } + else{ + Print("Failed to select position, Error: " + GetLastError()); + } + + + + } + +} \ No newline at end of file diff --git a/TigerEntryTaker.ex5 b/TigerEntryTaker.ex5 new file mode 100644 index 0000000..5ac2f28 Binary files /dev/null and b/TigerEntryTaker.ex5 differ diff --git a/TigerEntryTaker.mq5 b/TigerEntryTaker.mq5 new file mode 100644 index 0000000..d9e0ccb --- /dev/null +++ b/TigerEntryTaker.mq5 @@ -0,0 +1,1023 @@ +//+------------------------------------------------------------------+ +//| TigerEntryTaker.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "NewCandleDetector.mqh" +#include "GraphicalObjectsManager.mqh" +#include "Zone.mqh" +#include "ZoneContainer.mqh" +#include "MarketObserverTiger.mqh" +#include "LotSizeCalculator.mqh" + +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" + + +input group "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +// 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"); +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + + +// TRADE CLASSES +BuyEntryManager buyEntryManager ; +SellEntryManager sellEntryManager ; + + +// LotSizeCalculator class + +LotSizeCalculator lsCalc ; + +Zone* temporaryRestestSupportZone = new Zone(); + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + + + //--- example of applying template, located in \MQL5\Files + /*if(FileIsExist("Default.tpl")) + { + Print("The file Default.tpl found in \Files'"); + //--- apply template + if(ChartApplyTemplate(0,"\\Files\\Default.tpl")) + { + Print("The template 'Default.tpl' applied successfully"); + //--- redraw chart + ChartRedraw(); + } + else + Print("Failed to apply 'Default.tpl', error code ",GetLastError()); + } + else + { + Print("File 'Default.tpl' not found in " + +TerminalInfoString(TERMINAL_PATH)+"\\MQL5\\Files"); + } */ + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_M15,5); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_W1,1); + + + + + //ChartOpen(_Symbol,PERIOD_W1); + //ChartOpen(_Symbol,PERIOD_D1); + //long H4_NAME = ChartOpen(_Symbol,PERIOD_H4); + //long H1_NAME = ChartOpen(_Symbol,PERIOD_H1); + //if(!ChartOpen(_Symbol,PERIOD_M30)){ + // Print("Failed to open chart Error, " + GetLastError()); + //} + + //Print(H1_NAME); + //Print(M30_NAME); + //Print(H4_NAME); + + + + + objectsManager.addTextTiger(); +//objectsManager.addMarketDescriptionTextTiger(); + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + //Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + if(newCandleDetector30M.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrBeige,clrBlue,zoneContainer_M30); + //updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30"); + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + } + + + if(newCandleDetector1H.isNewCandle()) + { + + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + if(mqldt.hour == 13){ + + objectsManager.drawVerticalLine(clrAzure,TimeCurrent()); + + } + + detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrGray,clrRed,zoneContainer_H1); + double brokenResistanceLowerPrice = -1 ; + string brokenZoneTypeResistance = "" ; + if(updateBreakAboveStructureAndDelete(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",brokenResistanceLowerPrice,brokenZoneTypeResistance)) // means price broke the zone on an h1 candle + { + + + double firstResistancePrice = findClosestResistancePrice(zoneContainer_H1); + double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + if(cleanRangeValueBuys >= cleanRangeUponEntry) + { + + + + if(firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + + Print("H1 candle Broke and closed above the zone. the closest resistance price is: " + DoubleToString(firstResistancePrice)); + Print("The lower edge of the recently broken resistance zone is: " + brokenResistanceLowerPrice); + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_H1)) + { + + //if((mqldt.hour > 13 && mqldt.hour < 20) || (mqldt.hour > 8 && mqldt.hour < 12)){ + + //buyEntryManager.takeBuyTradeTiger(0.1,stopLossBased_H1,firstResistancePrice); + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_H1); + Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_H1, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + Print("Took a buy. stop loss: based on 1 hour"); + //} + + + + } + else + if(stopLossIsValidBuys(stopLossBased_M30)) + { + //if((mqldt.hour > 13 && mqldt.hour < 20) || (mqldt.hour > 8 && mqldt.hour < 12)){ + + //buyEntryManager.takeBuyTradeTiger(0.1,stopLossBased_H1,firstResistancePrice) ; + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + + Print("Took a buy. stop loss: based on 30 min"); + + // } + + } + + else + { + + Print("Failed to find a valid stop loss on both H1 and M30 !"); + } + } + + else + { + + Print("H1 candle Broke and closed above the zone, but im not taking a buy because i dont see a next zone target!"); + } + + + + + } + + else + { + + Print("Price Broke the zone but not enough range to take the trade !"); + + } + + + } + + + detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrWhite,clrRed,zoneContainerSupport_H1); + double brokenSupportHigherPrice = -1 ; + string brokenZoneTypeSupport= "" ; + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",brokenSupportHigherPrice,brokenZoneTypeSupport)) + { + //MqlDateTime mqldt ; + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_H1); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + + Print("H1 candle Broke and closed below the zone. the closest support price is: " + DoubleToString(firstSupportPrice)); + Print("The higher edge of the recently broken support zone is: " + brokenSupportHigherPrice); + + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_H1)) + { + //if((mqldt.hour > 13 && mqldt.hour < 20) || (mqldt.hour > 8 && mqldt.hour < 12)){ + + //sellEntryManager.takeSellTradeTiger(0.1,stopLossBased_H1,firstSupportPrice); + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_H1); + Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_H1,SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit); + Print("Took a sell. stop loss: based on 1 hour"); + //} + + + } + else + if(stopLossIsValidSells(stopLossBased_M30)) + { + + //if((mqldt.hour > 13 && mqldt.hour < 20) || (mqldt.hour > 8 && mqldt.hour < 12)){ + //sellEntryManager.takeSellTradeTiger(0.1,stopLossBased_H1,firstSupportPrice); + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30,SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit); + + Print("Took a sell. stop loss: based on 30 min"); + + //} + + + } + + else + { + + Print("Failed to find a valid stop loss on both H1 and M30 !"); + } + } + + else + { + + Print("H1 candle Broke and closed below the zone. but im not taking a sell because i dont see a target zone !"); + } + + + + + } + else{ + Print("Price broke the support zone but not enough range to take the trade"); + + } + + } + + + + } + + /*if(newCandleDetector4H.isNewCandle()){ + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPurple,clrGreen,zoneContainer_H4); + updateBreakAboveStructureAndDelete(zoneContainer_H4,PERIOD_H4,"PERIOD_H4"); + }*/ + + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + + } + + + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed,TimeCurrent()); + } + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if(candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - 0.1); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if(candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + 0.1); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 stopLossIsValidBuys(double stopLoss) + { + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLoss < maxPipsRiskAmount) + { + return true ; + } + + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool stopLossIsValidSells(double stopLoss) + { + if(stopLoss - SymbolInfoDouble(_Symbol, SYMBOL_BID) < maxPipsRiskAmount) + { + return true ; + } + return false ; + + } +//+------------------------------------------------------------------+ + + +bool sessionIsNy(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 14 && mqldt.hour <= 17){ + return true ; + } + + return false ; + +} + + +bool sessionIsLondon(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 8 && mqldt.hour <= 11){ + return true ; + } + + return false ; + +} \ No newline at end of file diff --git a/TigerEntryTakerNew.ex5 b/TigerEntryTakerNew.ex5 new file mode 100644 index 0000000..711e298 Binary files /dev/null and b/TigerEntryTakerNew.ex5 differ diff --git a/TigerEntryTakerNew.mq5 b/TigerEntryTakerNew.mq5 new file mode 100644 index 0000000..1ac3a87 --- /dev/null +++ b/TigerEntryTakerNew.mq5 @@ -0,0 +1,1161 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#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 "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + + +input group "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK = true ; +input bool TRADE_LONDON = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +Zone* temporaryRestestSupportZone = new Zone(); + + + +// TRADE CLASSES +BuyEntryManager buyEntryManager ; +SellEntryManager sellEntryManager ; + + +// LotSizeCalculator class + +LotSizeCalculator lsCalc ; + + +string activeTradeType ; // its either , "BUY" , or "SELL" +bool securedRisk = false ; + +CTrade trade ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + +//objectsManager.addMarketDescriptionTextTiger(); + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + if(newCandleDetectorM15.isNewCandle()) + { + Print("new Candle on m15"); + if(PositionsTotal()!= 0) // There is an active trade + { + if(activeTradeType == "BUY") + { + + if(candleClosedBearish(PERIOD_M15,1) && !bearishCandleIsWeak(PERIOD_M15,1)){ + Print("M15 , closed against my direction, we should close half"); + if(securedRisk == false && closePartialFromAllPositions(riskManagementPartial)){ + securedRisk = true ; + } + } + + } + else + if(activeTradeType == "SELL") + { + if(candleClosedBullish(PERIOD_M15,1) && !bullishCandleIsWeak(PERIOD_M15,1)){ + Print("M15 , closed against my direction, we should close half"); + if(securedRisk == false && closePartialFromAllPositions(riskManagementPartial)){ + securedRisk = true ; + } + } + + } + + } + else{ + securedRisk = false ; // return the risk secure flag to false , to be ready for the next trade + + } + + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetector30M.isNewCandle()) + { +//Print("number of opened orders are: " + PositionsTotal()); +// DETECTING SUPPORTS AND RESISTANCES + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30); + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30); + +// VARIABLE PREPROCESSING FOR BOS + double brokenResistanceLowerPrice = -1 ; + string brokenZoneTypeResistance = "" ; + + double brokenSupportHigherPrice = -1; + string brokenZoneTypeSupport = "" ; + +// BREAK OF STRUCTURE HANDLING + + if(updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",brokenResistanceLowerPrice,brokenZoneTypeResistance) + && buyBreakerCandleIsValid(PERIOD_M30) + && ((sessionIsNy() && TRADE_NEW_YORK) || (sessionIsLondon() && TRADE_LONDON) )) // 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)) + { + + double firstResistancePrice = findClosestResistancePrice(zoneContainer_M30); + double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + Print("firstResistance variable is: " + firstResistancePrice); + Print("cleanRangeVlaueBuys :" + cleanRangeValueBuys); + + + if(firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + Comment("M30 candle Broke and closed above the zone. the closest resistance price is:" + DoubleToString(firstResistancePrice)); + if(cleanRangeValueBuys >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + if(PositionsTotal() == 0) // there are no active trades + { + + buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + activeTradeType = "BUY" ; + Comment("Took a buy. stop loss: based on M30"); + } + else + { + + Comment("I cant take a trade because another trade is running"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + if(PositionsTotal() == 0) + { + buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + activeTradeType = "BUY" ; + Comment("Took a buy. stop loss: based on M15"); + } + else + { + + Comment("I cant take a trade because another trade is running"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30) + && ((sessionIsNy() && TRADE_NEW_YORK) || (sessionIsLondon() && TRADE_LONDON) )) // 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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + if(PositionsTotal() == 0) + { + sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit) ; + activeTradeType = "SELL"; + Comment("Took a sell. stop loss: based on M30"); + + } + else + { + + Comment("i cant take a trade since another one is running"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + + if(PositionsTotal() == 0) + { + sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15, SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit) ; + activeTradeType = "SELL"; + Comment("Took a sell. stop loss: based on M15"); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetectorDaily.isNewCandle()) + { + +//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); +//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent());; + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) || (candleClosedBullish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBearish(timeFrame,1))) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) || (candleClosedBearish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBullish(timeFrame,1))) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + if(candleClose == candleOpen) + { + return true; + } + else + { + return false; + } + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 stopLossIsValidBuys(double stopLoss) + { + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLoss < maxPipsRiskAmount) + { + return true ; + } + + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool stopLossIsValidSells(double stopLoss) + { + if(stopLoss - SymbolInfoDouble(_Symbol, SYMBOL_BID) < maxPipsRiskAmount) + { + return true ; + } + return false ; + + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ + +bool bearishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index){ // this function assumes that the previous candle is bearish + + double upperWickLength = iHigh(_Symbol,_timeFrame,1) - iOpen(_Symbol,_timeFrame,1) ; + double totalCandleLength = iHigh(_Symbol,_timeFrame,1) - iClose(_Symbol,_timeFrame,1); + if((upperWickLength / totalCandleLength) >= WICK_RATIO_REJECTION ){ // this means the candle is not weak + return true ; + } + else{ + return false ; + } +} + +bool bullishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index){ // this function assumes that the previous candle is bullish + double lowerWickLength = iOpen(_Symbol,_timeFrame,1) - iLow(_Symbol,_timeFrame,1) ; + double totalCandleLength = iClose(_Symbol,_timeFrame,1) - iLow(_Symbol,_timeFrame,1) ; + + if((lowerWickLength/totalCandleLength) >= WICK_RATIO_REJECTION){ // this means the candle is not weak + return true ; + } + else{ + return false ; + } +} + + +bool buyBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame){ + + if((iClose(_Symbol,_timeFrame,1) - iOpen(_Symbol,_timeFrame,1)) >= SIZE_OF_BREAKER_CANDLE_BODY) { + return true ; + } + else{ + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr + " Bullish Breaker candle body is too small to take a trade !"); + return false ; + + } + +} + +bool sellBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame){ + if((iOpen(_Symbol,_timeFrame,1) - iClose(_Symbol,_timeFrame,1)) >= SIZE_OF_BREAKER_CANDLE_BODY) { + return true ; + } + else{ + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr + " Bearish Breaker candle body is too small to take a trade !"); + return false ; + + } + +} + +bool closePartialFromAllPositions(double partialAmount){ + + for(uint i=0 ; i< PositionsTotal() ; i++){ + + ulong positionTicket = PositionGetTicket(i); + if(PositionSelectByTicket(positionTicket)){ + + double positionVolume = PositionGetDouble(POSITION_VOLUME); + double lotsToClose = positionVolume * partialAmount ; + if(trade.PositionClosePartial(positionTicket,NormalizeDouble(lotsToClose,2))){ + Print("Closed partials succesffully"); + return true ; + } + else{ + Print("Failed to close partials, Error: " + GetLastError()); + return false ; + } + + } + + + + } + return false ; + +} + + +bool sessionIsNy(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 14 && mqldt.hour <= 18){ + return true ; + } + + return false ; + +} + + +bool sessionIsLondon(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 8 && mqldt.hour <= 11){ + return true ; + } + + return false ; + +} \ No newline at end of file diff --git a/TigerEntryTakerNewGen.ex5 b/TigerEntryTakerNewGen.ex5 new file mode 100644 index 0000000..c99f2ca Binary files /dev/null and b/TigerEntryTakerNewGen.ex5 differ diff --git a/TigerEntryTakerNewGen.mq5 b/TigerEntryTakerNewGen.mq5 new file mode 100644 index 0000000..d9e330a --- /dev/null +++ b/TigerEntryTakerNewGen.mq5 @@ -0,0 +1,1060 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#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 "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + + +input group "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK_ALLOWED = true ; +input bool TRADE_LONDON_ALLOWED = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +Zone* temporaryRestestSupportZone = new Zone(); + + + +// TRADE CLASSES +BuyEntryManager buyEntryManager ; +SellEntryManager sellEntryManager ; + + +// LotSizeCalculator class + +LotSizeCalculator lsCalc ; + + +string activeTradeType ; // its either , "BUY" , or "SELL" +bool securedRisk = false ; + +ulong activeTradeId ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + +//objectsManager.addMarketDescriptionTextTiger(); + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + + + if(newCandleDetectorM15.isNewCandle()) + { + + + manageRiskIfNeeded(); + for(int i=0 ;i< PositionsTotal() ; i++){ + + Print("active trade id is : " + PositionGetTicket(i)); + + } + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetector30M.isNewCandle()) + { +//Print("number of opened orders are: " + PositionsTotal()); +// DETECTING SUPPORTS AND RESISTANCES + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30); + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30); + +// VARIABLE PREPROCESSING FOR BOS + double brokenResistanceLowerPrice = -1 ; + string brokenZoneTypeResistance = "" ; + + double brokenSupportHigherPrice = -1; + string brokenZoneTypeSupport = "" ; + +// BREAK OF STRUCTURE HANDLING + + if(updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",brokenResistanceLowerPrice,brokenZoneTypeResistance) + && buyBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + double firstResistancePrice = findClosestResistancePrice(zoneContainer_M30); + double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + + if(firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + Comment("M30 candle Broke and closed above the zone. the closest resistance price is:" + DoubleToString(firstResistancePrice)); + if(cleanRangeValueBuys >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + if(PositionsTotal() == 0) // there are no active trades + { + + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + activeTradeType = "BUY" ; + Comment("Took a buy. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because another trade is running"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + if(PositionsTotal() == 0) + { + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + activeTradeType = "BUY" ; + Comment("Took a buy. stop loss: based on M15, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because another trade is running"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + if(PositionsTotal() == 0) + { + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit) ; + activeTradeType = "SELL"; + Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade since another one is running"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + + if(PositionsTotal() == 0) + { + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15, SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit) ; + activeTradeType = "SELL"; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetectorDaily.isNewCandle()) + { + +//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); +//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent());; + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) || (candleClosedBullish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBearish(timeFrame,1))) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) || (candleClosedBearish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBullish(timeFrame,1))) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + if(candleClose == candleOpen) + { + return true; + } + else + { + return false; + } + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 + { + if(activeTradeType == "BUY") + { + + if(candleClosedBearish(PERIOD_M15,1) && !bearishCandleIsWeak(PERIOD_M15,1, WICK_RATIO_REJECTION)){ + Print("M15 , closed against my direction, we should close half"); + if(securedRisk == false && closePartialFromAllPositions(riskManagementPartial)){ + securedRisk = true ; + } + } + + } + else + if(activeTradeType == "SELL") + { + if(candleClosedBullish(PERIOD_M15,1) && !bullishCandleIsWeak(PERIOD_M15,1, WICK_RATIO_REJECTION)){ + Print("M15 , closed against my direction, we should close half"); + if(securedRisk == false && closePartialFromAllPositions(riskManagementPartial)){ + securedRisk = true ; + } + } + + } + + } + else{ + securedRisk = false ; // return the risk secure flag to false , to be ready for the next trade + + } + +} \ No newline at end of file diff --git a/TigerEntryTakerNewGenNext.ex5 b/TigerEntryTakerNewGenNext.ex5 new file mode 100644 index 0000000..555326b Binary files /dev/null and b/TigerEntryTakerNewGenNext.ex5 differ diff --git a/TigerEntryTakerNewGenNext.mq5 b/TigerEntryTakerNewGenNext.mq5 new file mode 100644 index 0000000..1ac04eb --- /dev/null +++ b/TigerEntryTakerNewGenNext.mq5 @@ -0,0 +1,1274 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#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 "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; +input bool BUYS_ALLOWED = true ; +input bool SELLS_ALLOWED = true ; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK_ALLOWED = true ; +input bool TRADE_LONDON_ALLOWED = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| 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 ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ; + + 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 M15, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) || (candleClosedBullish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBearish(timeFrame,1))) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) || (candleClosedBearish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBullish(timeFrame,1))) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 >= firstPartialProfitInPips){ + 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 >= firstPartialProfitInPips){ + 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 + positionTrailStopLoss(BuyActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + if((SellActiveTradesArray[i] != NULL)){ // CHECK TRAIL FOR SELLS + double newStopLoss = iHigh(_Symbol,_timeFrame,1); + newStopLoss = newStopLoss + stopLossAboveWickBy ; + if(newStopLoss < positionStopLoss(SellActiveTradesArray[i].getTradeId())){ // if new stop loss is lower than the current position's stop loss + positionTrailStopLoss(SellActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + + } +} diff --git a/TigerNewFeature.ex5 b/TigerNewFeature.ex5 new file mode 100644 index 0000000..7618eab Binary files /dev/null and b/TigerNewFeature.ex5 differ diff --git a/TigerNewFeature.mq5 b/TigerNewFeature.mq5 new file mode 100644 index 0000000..ee879ee --- /dev/null +++ b/TigerNewFeature.mq5 @@ -0,0 +1,1442 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#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 "Range Related Variables" +input double rangeDistanceBetweenZones ; +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 group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; +input bool BUYS_ALLOWED = true ; +input bool SELLS_ALLOWED = true ; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK_ALLOWED = true ; +input bool TRADE_LONDON_ALLOWED = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| 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 ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= cleanRangeUponEntry) { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) { // find a spot in the trades array, and save the result + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + } else { + + Comment("I cant take a trade because the trades array is full"); + } + + + } else if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) { // find a spot in the trades array, and save the result + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ; + + 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 M15, " + "Active trade id: " + activeTradeId); + } else { + + Comment("I cant take a trade because the trades array is full"); + + } + + } + + else { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) { + + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + + } else { + + Comment("i cant take a trade because the arrray is full"); + } + + + } else if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } else { + Comment("i cant take a trade since another one is running"); + } + } + + else { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + zoneContainer_M30.printZonesSortedArray(); + zoneContainerSupport_M30.printZonesSortedArray(); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + +} + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() { +//--- + +} +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() { +//--- + +} +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) { +//--- + +} +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() { +//--- + double ret=0.0; +//--- + +//--- + return(ret); +} +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() { +//--- + +} +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() { +//--- + +} +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() { +//--- + +} +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) { +//--- + +} +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) { +//--- + +} +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) { + + + if(resistancePatternFormed(timeFrame)) { // if resistance formed + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) { // check if it has a clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) { // if it doesnt have a clean range, just add it as a blue zone + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else if(zoneContainer.getNumberOfActiveZones() == 0) { // this means this is the first zone to add to the data strucutre + int result = detectAndDrawFirstResistanceZoneHigherThan(resistancePrice + resistanceExtendAboveCandle, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color); + if(result == 1) { + + Print("reached here !"); + int currentIdCounter = zoneContainer.getZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + + + + } + else if(result == 0){ + int currentIdCounter = zoneContainer.getZonesIdCounter(); + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + } + else if(result == 2){ + int currentIdCounter = zoneContainer.getZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,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); + + + + 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); + } + + } + + } + + return true ; + + } + return false ; +} + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) { + + + if(supportPatternFormed(timeFrame)) { // if support formed + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) { // check if it has a clean range down + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) { // if it doesnt have a clean range, just add it as a blue zone + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + 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. + //detectAndDrawFirstSupportZoneLowerThan(supportPrice - supportExtendBelowCandle, timeFrame, firstZoneShift,timeFrameStr, BOS_zone_color); + int result = detectAndDrawFirstSupportZoneLowerThan(supportPrice - supportExtendBelowCandle, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color); + if(result == 1) { + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + + } + else if(result == 0){ + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + } + else if(result == 2){ + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,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) == 1 ; + + 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); + } + + } + + } + + + return true ; + + } + return false ; +} + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int detectAndDrawFirstResistanceZoneHigherThan(double currentHigherResistancePrice, ENUM_TIMEFRAMES timeFrame,int _firstZoneShift,ZoneContainer& zoneContainer,string timeFrameStr, long BOS_zone_color) { + + 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(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,i+1); + + if((resistancePrice > currentHigherResistancePrice) && ((resistancePrice - currentHigherResistancePrice) > rangeDistanceBetweenZones)) { // this means the range is valid + Print("tthe range is valid between the newly formed RESISTANCE zone, and the first higher old zone"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addHistoryResistanceZoneOnTop(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("the zone counter is: "+ currentIdCounter); + 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) > rangeDistanceBetweenZones)) { // the range is not valid, this means draw only the old one + Print("the range is not valid between the newly formed RESISTANCE zone, and the first higher old zone"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + + zoneContainer.addHistoryResistanceZoneOnTop(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("the zone counter is: "+ currentIdCounter); + 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) { + + 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(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,i+1); + Print("supportPrice is:" + supportPrice); + + if((supportPrice < currentLowerSupportPrice) && ((currentLowerSupportPrice - supportPrice) > rangeDistanceBetweenZones)) { // this means the range is valid + Print("tthe range is valid between the newly formed SUPPORT zone, and the first higher old zone"); + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addHistorySupportZoneAtBottom(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("Higher edge of created zone is: "+ newZone.getHigherEdge()); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); + + return 1 ; + } else if((supportPrice < currentLowerSupportPrice) && !((currentLowerSupportPrice - supportPrice) > rangeDistanceBetweenZones)) { // the range is not valid, this means draw only the old one + Print("the range is not valid between the newly formed SUPPORT zone, and the first higher old zone"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addHistorySupportZoneAtBottom(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("Higher edge of created zone is: "+ newZone.getHigherEdge()); + 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 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 + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 >= firstPartialProfitInPips) { + 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 >= firstPartialProfitInPips) { + 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 + positionTrailStopLoss(BuyActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + if((SellActiveTradesArray[i] != NULL)) { // CHECK TRAIL FOR SELLS + double newStopLoss = iHigh(_Symbol,_timeFrame,1); + newStopLoss = newStopLoss + stopLossAboveWickBy ; + if(newStopLoss < positionStopLoss(SellActiveTradesArray[i].getTradeId())) { // if new stop loss is lower than the current position's stop loss + positionTrailStopLoss(SellActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + + } +} +//+------------------------------------------------------------------+ diff --git a/TigerObserver.ex5 b/TigerObserver.ex5 new file mode 100644 index 0000000..2f57dcf Binary files /dev/null and b/TigerObserver.ex5 differ diff --git a/TigerObserver.mq5 b/TigerObserver.mq5 new file mode 100644 index 0000000..8205be0 --- /dev/null +++ b/TigerObserver.mq5 @@ -0,0 +1,694 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include "NewCandleDetector.mqh" +#include "GraphicalObjectsManager.mqh" +#include "Zone.mqh" +#include "ZoneContainer.mqh" + +#include "MarketObserverTiger.mqh" + + +input group "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + + +// 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"); +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +Zone* temporaryRestestSupportZone = new Zone(); + +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + //objectsManager.addMarketDescriptionTextTiger(); + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + /*if(newCandleDetector30M.isNewCandle()) + { + + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30); + updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30"); + + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30); + updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30"); + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + } */ + + + /*if(newCandleDetector1H.isNewCandle()){ + + + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + if(mqldt.hour == 13){ + + objectsManager.drawVerticalLine(clrAzure,TimeCurrent()); + + } + detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrGray,clrRed,zoneContainer_H1); + updateBreakAboveStructureAndDelete(zoneContainer_H1,PERIOD_H1,"PERIOD_H1"); + + detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrWhite,clrRed,zoneContainerSupport_H1); + updateBreakBelowStructureAndDelete(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1"); + + + //zoneContainer_H1.printZonesSortedArray(); + //zoneContainerSupport_H1.printZonesSortedArray(); + + } */ + + + + if(newCandleDetector4H.isNewCandle()){ + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPurple,clrGreen,zoneContainer_H4); + updateBreakAboveStructureAndDelete(zoneContainer_H4,PERIOD_H4,"PERIOD_H4"); + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPink,clrBlue,zoneContainer_H4); + updateBreakAboveStructureAndDelete(zoneContainer_H4,PERIOD_H4,"PERIOD_H4"); + + detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrYellow,clrGreen,zoneContainerSupport_H4); + updateBreakBelowStructureAndDelete(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4"); + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + } + + if(newCandleDetectorDaily.isNewCandle()){ + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + + } + + + if(newCandleDetectorWeekly.isNewCandle()){ + + objectsManager.drawVerticalLine(clrRed, TimeCurrent());; + } + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer ) + { + + + if(candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter ); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + + bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer ) + { + + + if(candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter ); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + + +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!"); + + } + + + + + + + +void updateBreakAboveStructureAndDelete(ZoneContainer& zoneContainer, ENUM_TIMEFRAMES timeFrame, string timeFrameStr){ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId()),zoneContainer); // delete the zone with the GUI + } + else + { + finishedDeleting = true ; + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,""); + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,""); + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"Candle Closed Above the zone"); + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + } + + + } + +} + + + + + +void updateBreakBelowStructureAndDelete(ZoneContainer& zoneContainer, ENUM_TIMEFRAMES timeFrame, string timeFrameStr){ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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); + temporaryRestestSupportZone.setType("TYPE_RESISTANCE"); + + deleteZoneWithGUI((zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getId()),zoneContainer); // delete the zone with the GUI + + } + else + { + //Print("Lower edge is: " + zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getLowerEdge()); + finishedDeleting = true ; + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,""); + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,""); + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"Candle Closed Below the zone"); + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + } + + + } + +} \ No newline at end of file diff --git a/TigerWicksIncluded.ex5 b/TigerWicksIncluded.ex5 new file mode 100644 index 0000000..9e798a6 Binary files /dev/null and b/TigerWicksIncluded.ex5 differ diff --git a/TigerWicksIncluded.mq5 b/TigerWicksIncluded.mq5 new file mode 100644 index 0000000..c4709b3 --- /dev/null +++ b/TigerWicksIncluded.mq5 @@ -0,0 +1,1465 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#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 "Range Related Variables" +input double rangeDistanceBetweenZones ; +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 group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; +input bool BUYS_ALLOWED = true ; +input bool SELLS_ALLOWED = true ; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK_ALLOWED = true ; +input bool TRADE_LONDON_ALLOWED = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| 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 ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ; + + 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 M15, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + zoneContainer_M30.printZonesSortedArray(); + zoneContainerSupport_M30.printZonesSortedArray(); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if(resistancePatternFormed(timeFrame)) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + 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 + resistanceExtendAboveCandle; + double _lowerEdgePrice = resistancePrice - resistanceLowerEdgeExtend ; + string _zoneId = IntegerToString(currentIdCounter); + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // 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 + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // 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 + resistanceExtendAboveCandle, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color); + if(result == 1) + { + + string currentIdCounter = IntegerToString(zoneContainer.getZonesIdCounter()); + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + + + + } + else + if(result == 0) + { + string currentIdCounter = IntegerToString(zoneContainer.getZonesIdCounter()); + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_NORMAL") ; + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + } + else + if(result == 2) + { + string currentIdCounter = IntegerToString(zoneContainer.getZonesIdCounter()); + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,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); + + + + 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); + } + + } + + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if(supportPatternFormed(timeFrame)) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge =rightEdge; + double supportPrice = iOpen(_Symbol,timeFrame,1); + double _higherEdgePrice = supportPrice + supportHigherEdgeExtend; + double _lowerEdgePrice = supportPrice - supportExtendBelowCandle; + string _zoneId = IntegerToString(currentIdCounter); + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + Zone* newZone = new Zone(currentIdCounter,_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 - supportExtendBelowCandle, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color); + if(result == 1) // means if found a lower zone and the range is clean + { + string currentIdCounter = IntegerToString(zoneContainer.getSupportZonesIdCounter()); + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + + } + else + if(result == 0) // means found a lower zone but the range is not clean + { + + string currentIdCounter = IntegerToString(zoneContainer.getSupportZonesIdCounter()); + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_NORMAL") ; + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + } + else + if(result == 2) // means didnt find a lower zone + { + + string currentIdCounter = IntegerToString(zoneContainer.getSupportZonesIdCounter()); + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,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) == 1 ; + + 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); + } + + } + + } + + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int detectAndDrawFirstResistanceZoneHigherThan(double currentHigherResistancePrice, ENUM_TIMEFRAMES timeFrame,int _firstZoneShift,ZoneContainer& zoneContainer,string timeFrameStr, long BOS_zone_color) + { + + for(int i=3 ; i< _firstZoneShift; i++) + { + if(resistancePatternFormed(timeFrame,i)) // if old resistance found + { + + // create a rectangle with a unique name + string currentIdCounter = IntegerToString(zoneContainer.getZonesIdCounter()); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); + datetime _rightEdge = rightEdge; + double resistancePrice = iOpen(_Symbol,timeFrame,i+1); + double _higherEdgePrice = resistancePrice + resistanceExtendAboveCandle; + double _lowerEdgePrice = resistancePrice - resistanceLowerEdgeExtend ; + + if((resistancePrice > currentHigherResistancePrice) && ((resistancePrice - currentHigherResistancePrice) > rangeDistanceBetweenZones)) // this means the range is valid + { + + Zone* newZone = new Zone(currentIdCounter,_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) > rangeDistanceBetweenZones)) // the range is not valid, this means draw only the old one + { + + Zone* newZone = new Zone(currentIdCounter,_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) + { + + 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 + string currentIdCounter = IntegerToString(zoneContainer.getSupportZonesIdCounter()); + datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); + datetime _rightEdge = rightEdge; + double supportPrice = iOpen(_Symbol,timeFrame,i+1); + double _higherEdgePrice = supportPrice + supportHigherEdgeExtend; + double _lowerEdgePrice = supportPrice - supportExtendBelowCandle ; + + if((supportPrice < currentLowerSupportPrice) && ((currentLowerSupportPrice - supportPrice) > rangeDistanceBetweenZones)) // this means the range is valid + { + + Zone* newZone = new Zone(currentIdCounter,_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) > rangeDistanceBetweenZones)) // the range is not valid, this means draw only the old one + { + + Zone* newZone = new Zone(currentIdCounter,_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 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 >= firstPartialProfitInPips) + { + 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 >= firstPartialProfitInPips) + { + 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 + { + positionTrailStopLoss(BuyActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + if((SellActiveTradesArray[i] != NULL)) // CHECK TRAIL FOR SELLS + { + double newStopLoss = iHigh(_Symbol,_timeFrame,1); + newStopLoss = newStopLoss + stopLossAboveWickBy ; + if(newStopLoss < positionStopLoss(SellActiveTradesArray[i].getTradeId())) // if new stop loss is lower than the current position's stop loss + { + positionTrailStopLoss(SellActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + + } + } +//+------------------------------------------------------------------+ diff --git a/TigerWicksOnly.ex5 b/TigerWicksOnly.ex5 new file mode 100644 index 0000000..a35b8ce Binary files /dev/null and b/TigerWicksOnly.ex5 differ diff --git a/TigerWicksOnly.mq5 b/TigerWicksOnly.mq5 new file mode 100644 index 0000000..d6707bf --- /dev/null +++ b/TigerWicksOnly.mq5 @@ -0,0 +1,443 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "Algo_Skeleton_Functions.mqh" + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= buyStopPrice && !wickTradeTaken){ + double stopLossPrice = iLow(_Symbol,PERIOD_CURRENT,0) - stopLossUnderWickBy; + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + + if((SymbolInfoDouble(_Symbol,SYMBOL_ASK) - stopLossPrice) < minimumStopLossInPips){ + stopLossPrice = stopLossBased_M30 ; + if(stopLossIsValidBuys(stopLossBased_H1,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_H1 ; + } + else if(stopLossIsValidBuys(stopLossBased_M30,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_M30 ; + } + + else if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_M15 ; + } + } + else if(!stopLossIsValidBuys(stopLossPrice,maxPipsRiskAmount)){ + stopLossPrice = -1 ; + } + double lotsToBuy = lsCalc.calculateLotSize(riskDollars,stopLossPrice); + int indexToNewTrade ; + if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) && stopLossPrice != -1) + { + + + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToBuy,stopLossPrice) ; + + BuyTradeManagerTiger* tempTigerManager= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger + BuyActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + buysCount++; + wickTradeTaken = true ; + Comment("Took a bUY. stop loss: above current wick, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + Comment(TimeToString(currTime,TIME_MINUTES) + ": price has reached the candle high, im taking a buy"); + } + + } + + + // SELLS + + if(waitForTopWickToForm == true && wickLengthCounter == wickLengthInMinutes){ // waited wickLengthInMinutes time, and now its the time to check if the wick is valid + topWickValidationState = handleTopWickValidation(); + updateTopWickState(topWickValidationState); + } + + if(topWickFormed){ + datetime currTime = TimeCurrent(); + if((SymbolInfoDouble(_Symbol,SYMBOL_BID) <= sellStopPrice) && !wickTradeTaken){ + double stopLossPrice = iHigh(_Symbol,PERIOD_CURRENT,0) + stopLossAboveWickBy; + + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if((stopLossPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID)) < minimumStopLossInPips){ + stopLossPrice = stopLossBased_M30 ; + if(stopLossIsValidSells(stopLossBased_H1,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_H1 ; + } + else if(stopLossIsValidSells(stopLossBased_M30,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_M30 ; + } + + else if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_M15 ; + } + } + else if(!stopLossIsValidSells(stopLossPrice,maxPipsRiskAmount)){ + stopLossPrice = -1 ; + } + + + + double lotsToSell = lsCalc.calculateLotSize(riskDollars,stopLossPrice); + + int indexToNewTrade ; + + if(((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) && stopLossPrice != -1) + { + + + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToSell,stopLossPrice) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + wickTradeTaken = true ; + Comment("Took a sell. stop loss: under current wick, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + + Comment(TimeToString(currTime,TIME_MINUTES) + ": price has reached the candle low, im taking a sell"); + } + } + + + + + + if(newCandleDetectorM1.isNewCandle()) + { + + // BUY CASE + if(waitForBottomWickToForm == true && wickLengthCounter < wickLengthInMinutes) + { + wickLengthCounter++ ; + } + + // SELL CASE + + if(waitForTopWickToForm == true && wickLengthCounter < wickLengthInMinutes){ + wickLengthCounter++; + } + } + + + + + if(newCandleDetectorM15.isNewCandle()) + { + + manageRiskIfNeeded(); + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetector30M.isNewCandle()) + { + wickTradeTaken = false ; + if(bottomWickFormed){ // reset the bottomWickFormed flag. this is for the cases that bottom wick has formed, but m30 candle closed and the trade still not taken + bottomWickFormed = false ; + buyStopPrice = -1; + } + + if(topWickFormed){ // reset the topWickFormed flag. this is for the cases that top wick has formed, but m30 candle closed and the trade still not taken + topWickFormed = false ; + sellStopPrice = -1; + } + trailAllOpenPositionsIfNeeded(PERIOD_M30); + + // DETECTING SUPPORTS AND RESISTANCES + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30); + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30); + + + // VARIABLE PREPROCESSING FOR BOS + double brokenResistanceLowerPrice = -1 ; + string brokenZoneTypeResistance = "" ; + + double brokenSupportHigherPrice = -1; + string brokenZoneTypeSupport = "" ; + + + + + // BREAK OF STRUCTURE HANDLING + + if(updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",brokenResistanceLowerPrice,brokenZoneTypeResistance) + && buyBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + + double firstResistancePrice = findClosestResistancePrice(zoneContainer_M30); + double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + Print("first resistcane price is: "+ firstResistancePrice); + if(zoneContainer_M30.getNumberOfActiveZones() > 0 && firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + + + Comment("Price Broke and closed above resistance zone, im waiting for a bottom wick to form"); + waitForBottomWickToForm = true ; + + } + + else if(zoneContainer_M30.getNumberOfActiveZones() == 0 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + + + Comment("Price Broke and closed above resistance zone, im waiting for a bottom wick to form"); + waitForBottomWickToForm = true ; + + } + + + } + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + if(zoneContainerSupport_M30.getNumberOfActiveZones() > 0 && firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + waitForTopWickToForm = true ; + Comment("Price Broke and closed below support zone, im waiting for a top wick to form"); + + + } + + else if(zoneContainerSupport_M30.getNumberOfActiveZones() == 0 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT"){ + waitForTopWickToForm = true ; + Comment("Price Broke and closed below support zone, im waiting for a top wick to form"); + + } + } + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + zoneContainer_M30.printZonesSortedArray(); + zoneContainerSupport_M30.printZonesSortedArray(); + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } + + + +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/TigerZonesComplete.ex5 b/TigerZonesComplete.ex5 new file mode 100644 index 0000000..f61c533 Binary files /dev/null and b/TigerZonesComplete.ex5 differ diff --git a/TigerZonesComplete.mq5 b/TigerZonesComplete.mq5 new file mode 100644 index 0000000..1ff8728 --- /dev/null +++ b/TigerZonesComplete.mq5 @@ -0,0 +1,423 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include "Algo_Skeleton_Functions.mqh" + +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ; + + 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 M15, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + zoneContainer_M30.printZonesSortedArray(); + zoneContainerSupport_M30.printZonesSortedArray(); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } + diff --git a/Tiger_Entries_4H.ex5 b/Tiger_Entries_4H.ex5 new file mode 100644 index 0000000..20f8c31 Binary files /dev/null and b/Tiger_Entries_4H.ex5 differ diff --git a/Tiger_Entries_4H.mq5 b/Tiger_Entries_4H.mq5 new file mode 100644 index 0000000..d62c190 --- /dev/null +++ b/Tiger_Entries_4H.mq5 @@ -0,0 +1,232 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include "Algo_Skeleton_Functions.mqh" + +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + + + objectsManager.addTextTiger(); + + for(int i=0; i0){ + updateNormalZonesSupport(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",clrAliceBlue,rangeDistanceBetweenZonesActual_H4); + } + + if(zoneContainer_H4.getNumberOfActiveZones()){ + updateNormalZonesResistance(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",clrPink,rangeDistanceBetweenZonesActual_H4); + } + + } + + + if(newCandleDetector4H.isNewCandle()){ + trailAllOpenPositionsIfNeeded(PERIOD_H4); + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPink,zoneContainer_H4,rangeDistanceBetweenZonesActual_H4); + detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrAliceBlue,zoneContainerSupport_H4,rangeDistanceBetweenZonesActual_H4); + + // BREAK OF STRUCTURE HANDLING + handleBuys(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual); + handleSells(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual); + + + zoneContainerSupport_H4.printZonesSortedArray(); + zoneContainer_H4.printZonesSortedArray(); + } + + + + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + + weekCounter++ ; + + if(weekCounter == deleteAllZonesAfter_Weeks){ + + //deleteAllzonesWithGUI(); + weekCounter = 0; + } + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } + diff --git a/TrendBreakouts.ex5 b/TrendBreakouts.ex5 new file mode 100644 index 0000000..77d8054 Binary files /dev/null and b/TrendBreakouts.ex5 differ diff --git a/TrendBreakouts.mq5 b/TrendBreakouts.mq5 new file mode 100644 index 0000000..986dc2b --- /dev/null +++ b/TrendBreakouts.mq5 @@ -0,0 +1,182 @@ +//+------------------------------------------------------------------+ +//| TrendBreakouts.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#define NUM_WEEKS_RESEARCH 48 +#include "Algo_Skeleton_Functions.mqh" +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int bullishCandlesCount = 0 ; +int conditionMetBullish = 0 ; +int secondConditionMetBullish = 0; +int bearishCandlesCount = 0; +int conditionMetBearish = 0 ; +int secondConditionMetBearish = 0 ; + +input group "Conditions" +input bool firstCondition = false ; +input bool secondCondition = false ; +input bool noCondition = false ; + +int OnInit() + { +//--- + +//--- + /* string fileName = "First_Condition_Bullish.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE |FILE_CSV|FILE_ANSI); + + FileSeek(fileHandle,0,SEEK_END); + FileWrite(fileHandle,"-----","Size of Week 1","Size of Week 2", "Monday", "Tuesday","Wednesday","Thursday","Friday","Retracement Measure","Low below previous close","Day of lowest point"); */ + + + string fileName1 = "First_Condition_Bearish.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle1 = FileOpen(fileName1,FILE_READ|FILE_WRITE |FILE_CSV|FILE_ANSI); + + FileSeek(fileHandle1,0,SEEK_END); + FileWrite(fileHandle1,"-----","Size of Week 1","Size of Week 2", "Monday", "Tuesday","Wednesday","Thursday","Friday","Retracement Measure","High above previous close","Day of Highest point"); + + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + Print("Count: "+ bullishCandlesCount + " First Condition: " + conditionMetBullish + " Second Condition: " + secondConditionMetBullish); + Print("Count: "+ bearishCandlesCount + " First Condition: " + conditionMetBearish + " Second Condition: " + secondConditionMetBearish); + + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + + + if(newCandleDetectorDaily.isNewCandle()) + { + //objectsManager.drawVerticalLine(clrAliceBlue, TimeCurrent()); + + + + + } + + int shift = 2 ; + if(newCandleDetectorWeekly.isNewCandle()) + { + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + + if(candleClosedBullish(PERIOD_W1,shift)) + { + if(!bullishCandleIsWeak(PERIOD_W1,shift,WICK_RATIO_REJECTION)) + { + + bullishCandlesCount++ ; + + if(firstCondition){ + if((iHigh(_Symbol,PERIOD_W1,1) > iHigh(_Symbol,PERIOD_W1,2)) && (iLow(_Symbol,PERIOD_W1,1) >iLow(_Symbol,PERIOD_W1,2))) + { + saveInCsv("firstCondition_Bullish.csv"); + conditionMetBullish++ ; + } + } + + if(secondCondition){ + if((iHigh(_Symbol,PERIOD_W1,1) > iClose(_Symbol,PERIOD_W1,2)) && (iLow(_Symbol,PERIOD_W1,1) > iLow(_Symbol,PERIOD_W1,2))) + { + saveInCsv("secondCondition_Bullish.csv"); + secondConditionMetBullish++ ; + } + } + + if(noCondition){ + saveInCsv("noCondition_Bullish.csv"); + + } + + + } + + } + + if(candleClosedBearish(PERIOD_W1,shift)) + { + + if(!bearishCandleIsWeak(PERIOD_W1,shift,WICK_RATIO_REJECTION)) + { + + bearishCandlesCount++ ; + if((iLow(_Symbol,PERIOD_W1,1) < iLow(_Symbol,PERIOD_W1,2)) && (iHigh(_Symbol,PERIOD_W1,1) < iHigh(_Symbol,PERIOD_W1,2))) + { + conditionMetBearish++ ; + } + + + if((iLow(_Symbol,PERIOD_W1,1) < iClose(_Symbol,PERIOD_W1,2)) && (iHigh(_Symbol,PERIOD_W1,1) < iHigh(_Symbol,PERIOD_W1,2))) + { + secondConditionMetBearish++ ; + } + + + + } + + } + + //Print("bearish candles count: " + bearishCandlesCount); + //Print("bullish canldes count: " + bullishCandlesCount); + + } + + } +//+------------------------------------------------------------------+ + + +void saveInCsv(string csvFileName){ +int lastWeekDaysArr[5] ; + for(int i=0; i<5; i++) + { + lastWeekDaysArr[i]= -1; + } + for(int i=5 ; i>0 ; i--) + { + if(candleClosedBullish(PERIOD_D1,i)) + { + lastWeekDaysArr[5-i] = 1 ; + } + if(candleClosedBearish(PERIOD_D1,i)) + { + lastWeekDaysArr[5-i] = 0 ; + } + } + + double firstWeekSize = iHigh(_Symbol,PERIOD_W1,2) - iLow(_Symbol,PERIOD_W1,2) ; + double secondWeekSize = iHigh(_Symbol,PERIOD_W1,1) - iLow(_Symbol,PERIOD_W1,1) ; + + + datetime time = iTime(_Symbol,PERIOD_W1,2); + string timeInStr = TimeToString(time,TIME_DATE); + + string fileName = csvFileName ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/); + + + + FileSeek(fileHandle,0,SEEK_END); + FileWrite(fileHandle,timeInStr,firstWeekSize,secondWeekSize,lastWeekDaysArr[0],lastWeekDaysArr[1],lastWeekDaysArr[2],lastWeekDaysArr[3],lastWeekDaysArr[4]); + + FileClose(fileHandle); +} \ No newline at end of file diff --git a/Zone.mqh b/Zone.mqh new file mode 100644 index 0000000..95a5f02 --- /dev/null +++ b/Zone.mqh @@ -0,0 +1,341 @@ +//+------------------------------------------------------------------+ +//| Zone.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "LowFractal.mqh" +#include "HighFractal.mqh" +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +#define SIZE_ATTACHED_FRACTALS +#define TP_ARR_SIZE 3 +class Zone + { +private: + string id ; + string timeFrame ; + string type ; // has 2 types : TYPE_SUPPORT, TYPE_RESISTANCE + string state ; // state is one of 5 states : STATE_CLEAN , STATE_TESTED, STATE_BROKEN, STATE_BROKEN_RETESTED, STATE_WAITING(used when price breaks structure, and is waiting to confirm BOS or a liquidity sweep) + datetime leftEdge ; + datetime rightEdge; + double lowerEdgePrice ; + double higherEdgePrice ; + double stopLossPrice ; + double tpPrices[TP_ARR_SIZE] ; + + + + + +public: + Zone(); + Zone:: Zone(string _zoneId,double _higherEdgePrice,double _lowerEdgePrice,datetime _leftEdge,datetime _rightEdge,string _timeFrameStr,string _type); + ~Zone(); + BuyEntryManager* buyEntryManager ; + BuyTradeManager* buyTradeManager; + + SellEntryManager* sellEntryManager ; + SellTradeManager* sellTradeManager ; + + + + // GETTERS + double getHigherEdge(); + double getLowerEdge(); + datetime getLeftEdge(); + datetime getRightEdge(); + string getId(); + string getTimeFrame(); + string getState(); + string getType(); + double getStopLossPrice(); + double getZoneHeight(); + + + // SETTERS + void setLeftEdge(datetime _leftEdge); + void setRightEdge(datetime _rightEdge); + void setLowerEdgePrice(double _lowerPirce); + void setHigherEdgePrice(double _higherPrice); + void setTimeFrame(string _timeframe); + void setId(string _id); + void setType(string _type); + void setState(string _state); + void setStopLossPrice(double slPrice); + bool setTakeProfit(double tpVal); // returns false if there is no valid slot in the tp's array, and true on success + + + // OTHER FUNCTIONS + void printTpLevels(); + void printTradeManagerData(); + + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone:: Zone() + { + + buyEntryManager = new BuyEntryManager(); + buyTradeManager = new BuyTradeManager(); + sellEntryManager = new SellEntryManager(); + sellTradeManager = new SellTradeManager(); + + + + + + for(int i=0 ;i< TP_ARR_SIZE ;i++){ // initialize the tp array with -1's + tpPrices[i] = -1 ; + } + + } + + +Zone:: Zone(string _zoneId,double _higherEdgePrice,double _lowerEdgePrice,datetime _leftEdge,datetime _rightEdge,string _timeFrameStr,string _type){ + + buyEntryManager = new BuyEntryManager(); + buyTradeManager = new BuyTradeManager(); + sellEntryManager = new SellEntryManager(); + sellTradeManager = new SellTradeManager(); + + id = _zoneId ; + + timeFrame = _timeFrameStr; + type = _type; // has 2 types : TYPE_SUPPORT, TYPE_RESISTANCE + leftEdge = _leftEdge; + rightEdge = _rightEdge; + lowerEdgePrice = _lowerEdgePrice; + higherEdgePrice = _higherEdgePrice; + + +} +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone::~Zone() + { + delete buyEntryManager; + delete sellEntryManager; + delete buyTradeManager; + delete sellTradeManager; + } +//+------------------------------------------------------------------+ + + +// GETTERS + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +datetime Zone:: getLeftEdge() + { + + return leftEdge; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +datetime Zone:: getRightEdge() + { + + return rightEdge ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double Zone:: getHigherEdge() + { + + return higherEdgePrice; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double Zone:: getLowerEdge() + { + + return lowerEdgePrice; + } + +string Zone :: getState(){ + + return state ; +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string Zone:: getId() + { + + return id; + } + +string Zone:: getTimeFrame() {return timeFrame ;} + + + +string Zone:: getType(){ + + return type ; +} + + +double Zone :: getStopLossPrice(){ + return stopLossPrice ; +} + +// SETTERS + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setLeftEdge(datetime _leftEdge) + { + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setRightEdge(datetime _rightEdge) + { + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setTimeFrame(string _timeframe) + { + + timeFrame = _timeframe; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setLowerEdgePrice(double _lowerPirce) + { + + lowerEdgePrice = _lowerPirce; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone::setHigherEdgePrice(double _higherPrice) + { + + higherEdgePrice = _higherPrice ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setId(string _id) + { + + id = _id; + } + + + +void Zone:: setType(string _type){ + + type = _type ; +} + + +void Zone:: setState(string _state){ + + state = _state ; +} + + +void Zone:: setStopLossPrice(double slPrice){ + + stopLossPrice = slPrice ; + +} + + +bool Zone:: setTakeProfit(double tpVal){ + for(int i=0; i zonesSortedArray[numberOfActiveZones-1].getHigherEdge()) // in this case the new zone should be in the last place in the array + { + zonesSortedArray[numberOfActiveZones] = _newZone; + numberOfActiveZones++; + + return 1; + } + else // in this case, the new zone sits somewhere in the array (not the edges) + { + int indexOfNewZone = searchForTheRightPlace(_newZone); + if(indexOfNewZone != -1) // means found a place for the new zone + { + forwardShiftZonesSortedArrayFromIndex(indexOfNewZone); + zonesSortedArray[indexOfNewZone] = _newZone ; + numberOfActiveZones++; + + return 1; + } + else + { + return -1; + } + + + } + return result; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int ZoneContainer:: deleteZone(string ID) + { + +// 1. find the index of the zone with the ID + int indexOfZoneToDelete = getZoneIndex(ID); + if(indexOfZoneToDelete == -1) + { + return -1; + } + else + if(indexOfZoneToDelete == (numberOfActiveZones-1)) // means that this is the last zone in the sorted array + { + // 2. delete the zone + // 3. its the last element so do nothing + delete zonesSortedArray[numberOfActiveZones-1] ; + numberOfActiveZones--; + return 1; + } + else + { + // 2. delete the zone + // 3. its not the last element, so shift the array 1 step backwards + delete zonesSortedArray[indexOfZoneToDelete]; + backwardShiftZonesSortedArrayFromIndex(indexOfZoneToDelete); + numberOfActiveZones--; + return 1; + } + return 0 ; + } + + + + + + +/* int ZoneContainer:: deleteZoneTiger(string ID){ + +// 1. find the index of the zone with the ID + int indexOfZoneToDelete = getZoneIndex(ID); + if(indexOfZoneToDelete == -1) + { + return -1; + } + else + if(indexOfZoneToDelete == (numberOfActiveZones-1)) // means that this is the last zone in the sorted array + { + // 2. delete the zone + // 3. its the last element so do nothing + delete zonesSortedArray[numberOfActiveZones-1] ; + numberOfActiveZones--; + return 1; + } + else + { + // 2. delete the zone + // 3. its not the last element, so shift the array 1 step backwards + delete zonesSortedArray[indexOfZoneToDelete]; + backwardShiftZonesSortedArrayFromIndex(indexOfZoneToDelete); + numberOfActiveZones--; + return 1; + } + return 0 ; + + + + +} */ +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: freeZonesSortedArray() + { + + for(int i=0; i 0) + { + for(int i=0; i _index ; x--) + { + zonesSortedArray[x] = zonesSortedArray[x-1] ; + } + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: backwardShiftZonesSortedArrayFromIndex(int _index) // used for deleting + { + for(int i= _index ; i zonesSortedArray[i].getHigherEdge()) && (_zone.getHigherEdge() < zonesSortedArray[i+1].getLowerEdge())) + { + index = i+1; + + return index; + } + } + return index ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int ZoneContainer :: updateZone(Zone* _tempZone, string _idOfOriginalZone) + { + + + Zone* zoneToUpdate = searchZoneById(_idOfOriginalZone); + + zoneToUpdate.setHigherEdgePrice(_tempZone.getHigherEdge()); + zoneToUpdate.setLowerEdgePrice(_tempZone.getLowerEdge()); + zoneToUpdate.setLeftEdge(_tempZone.getLeftEdge()); + zoneToUpdate.setRightEdge(_tempZone.getRightEdge()); + zoneToUpdate.setTimeFrame(_tempZone.getTimeFrame()); + + return 1 ; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone* ZoneContainer:: searchZoneById(string _idOfZone) + { + Zone* result ; + for(int i=0 ; i< numberOfActiveZones ; i++) + { + if(zonesSortedArray[i].getId() == _idOfZone) + { + result = zonesSortedArray[i] ; + + } + } + + return result ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: findOrUpdatePivotEdgesOnConfirm(double _ask,double _bid) + { + + bool foundSupport = false ; + bool foundResistance = false ; + + + for(int i=0 ; i=0 ; i--) // FIND HIGHER PIVOT EDGE + { + if(zonesSortedArray[i].getState()!= "STATE_WAITING") + { + if((zonesSortedArray[i].getLowerEdge() > _bid) && (zonesSortedArray[i].getType() == "TYPE_RESISTANCE")) + { + pivotEdges[1] = i; + foundResistance = true ; + } + } + + } + + if(foundSupport == false) + { + pivotEdges[0] = -1; + } + if(foundResistance == false) + { + pivotEdges[1] = -1; + } + + } + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: findOrUpdatePivotEdgesOnDelete() + { + bool foundSupport = false ; + bool foundResistance = false ; + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + + for(int i=0 ; i=0 ; i--) // FIND HIGHER PIVOT EDGE + { + if(zonesSortedArray[i].getState()!= "STATE_WAITING") + { + if(zonesSortedArray[i].getLowerEdge() > bid) + { + pivotEdges[1] = i; + foundResistance = true ; + } + } + + } + + if(foundSupport == false) + { + pivotEdges[0] = -1; + } + if(foundResistance == false) + { + pivotEdges[1] = -1; + } + + + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: printPivotEdges() + { + + Print("Lower Edge Index: " + pivotEdges[0]); + Print("Higher Edge Index: " + pivotEdges[1]); + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone* ZoneContainer:: getLowerPivotIndexZone() + { + + if(pivotEdges[0] != -1) + { + return getZoneByIndex(pivotEdges[0]); + } + + return NULL ; + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone* ZoneContainer:: getHigherPivotIndexZone() + { + + if(pivotEdges[1] != -1) + { + return getZoneByIndex(pivotEdges[1]); + } + + return NULL; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: addResistanceZoneTiger(Zone* _newZone) + { + + + if((numberOfActiveZones != 0 ) && (_newZone.getLowerEdge() >= zonesSortedArray[0].getHigherEdge())) // this is the case, where the new zone shouldnt be placed at the beggining (gap case for instance) + { + + + int indexOfNewZone = searchForTheRightPlace(_newZone); + if(indexOfNewZone != -1) // means found a place for the new zone + { + forwardShiftZonesSortedArrayFromIndex(indexOfNewZone); + zonesSortedArray[indexOfNewZone] = _newZone ; + numberOfActiveZones++; + + } + else + { + Print("Couldnt find an index to place the new zone !"); + } + + + } + + else + { + + forwardShiftZonesSortedArrayFromIndex(0); + zonesSortedArray[0] = _newZone ; + + if(_newZone.getType() == "TYPE_RESISTANCE_BREAKOUT") + { + numberOfActiveZones++; + } + else + if(_newZone.getType() == "TYPE_RESISTANCE_NORMAL") + { + + numberOfActiveZones++ ; + } + } + + + + + } + + + void ZoneContainer:: addHistoryResistanceZoneOnTop(Zone* _newZone){ + zonesSortedArray[numberOfActiveZones] = _newZone ; + numberOfActiveZones++; + } + + + + +void ZoneContainer:: addSupportZoneTiger(Zone* _newZone) + { + + + /* if((numberOfActiveZones != 0 ) && (_newZone.getHigherEdge() <= zonesSortedArray[numberOfActiveZones-1].getLowerEdge())) // this is the case, where the new zone shouldnt be placed at the beggining (gap case for instance) + { + + + int indexOfNewZone = searchForTheRightPlace(_newZone); + if(indexOfNewZone != -1) // means found a place for the new zone + { + forwardShiftZonesSortedArrayFromIndex(indexOfNewZone); + zonesSortedArray[indexOfNewZone] = _newZone ; + numberOfActiveZones++; + + } + else + { + Print("Couldnt find an index to place the new zone !"); + } + + + } */ + + + + + zonesSortedArray[numberOfActiveZones] = _newZone ; + + if(_newZone.getType() == "TYPE_SUPPORT_BREAKOUT") + { + numberOfActiveZones++; + } + else + if(_newZone.getType() == "TYPE_SUPPORT_NORMAL") + { + + numberOfActiveZones++ ; + } + + + + + + } + +//+------------------------------------------------------------------+ + void ZoneContainer:: addHistorySupportZoneAtBottom(Zone* _newZone){ + + + forwardShiftZonesSortedArrayFromIndex(0); + zonesSortedArray[0] = _newZone ; + numberOfActiveZones++; + } \ No newline at end of file diff --git a/ZoneRejectionOneCandle.ex5 b/ZoneRejectionOneCandle.ex5 new file mode 100644 index 0000000..7f8d3b5 Binary files /dev/null and b/ZoneRejectionOneCandle.ex5 differ diff --git a/ZoneRejectionOneCandle.mq5 b/ZoneRejectionOneCandle.mq5 new file mode 100644 index 0000000..9630a59 --- /dev/null +++ b/ZoneRejectionOneCandle.mq5 @@ -0,0 +1,1651 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +//input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTALS DATA + +//input int leftPeriod; +//input int rightPeriod; +//input int weekPeriodToInitialize; +//input int initFractalsPeriod ; +//int lowFractalIndex ; +//int highFractalIndex ; +//#include "LowFractal.mqh" +//#include "HighFractal.mqh" +//#include "LowFractalContainer.mqh" +//#include "HighFractalContainer.mqh" + + + +#property script_show_inputs + +input datetime InpStartTime = __DATETIME__; + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" + + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" +#include "LotSizeCalculator.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + +// Telegram Connection include +#include + +// SCRIPTS INCLUDES + + + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +// NEW CANDLE CLASSES INITIALIZATION +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + +bool telegramTested = false ; +input bool testTelegram ; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +// Added because bmp files seem to have stopped working, possibly a file format issue +//fileType = "png"; +//fileName = "MyScreenshot." + fileType; + + + if(telegramTested == false && testTelegram == true) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"This is just a test ! " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + telegramTested = true ; + } + + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + + + + + /* if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } */ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + + //lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + //highFractalIndex = rightPeriod+1; // this is used for the fractals + //initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + //initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + /*if(newCandleDetector_M1.isNewCandle()) + { + + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + }*/ + + + if(newCandleDetector_H1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + handleBuys(PERIOD_H1); + handleSells(PERIOD_H1); + } + + + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bearish candle closed inside the closest support zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bullish candle closed inside the resistance zone on " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+------------------------------------------------------------------+ diff --git a/ZoneRjectionTest4H.ex5 b/ZoneRjectionTest4H.ex5 new file mode 100644 index 0000000..4b72b66 Binary files /dev/null and b/ZoneRjectionTest4H.ex5 differ diff --git a/ZoneRjectionTest4H.mq5 b/ZoneRjectionTest4H.mq5 new file mode 100644 index 0000000..3ba7fe3 --- /dev/null +++ b/ZoneRjectionTest4H.mq5 @@ -0,0 +1,1642 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +//input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTAL VARIABLES INITIALIZATION + +//input int leftPeriod; +//input int rightPeriod; +//input int weekPeriodToInitialize; +//input int initFractalsPeriod ; +//int lowFractalIndex ; +//int highFractalIndex ; + + +#property script_show_inputs + +input datetime InpStartTime = __DATETIME__; + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" +//#include "LowFractal.mqh" +//#include "HighFractal.mqh" +//#include "LowFractalContainer.mqh" +//#include "HighFractalContainer.mqh" + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" +#include "LotSizeCalculator.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + +// Telegram Connection include +#include + +// SCRIPTS INCLUDES +//#include "Telegram_Exporter.mq5" + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + +// TRADE RELATED CLASSES INITIALIZATION +//BuyEntryManager* buyEntryManager = new BuyEntryManager(); +//BuyTradeManager* buyTradeManager = new BuyTradeManager(); + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +//SellEntryManager* sellEntryManager = new SellEntryManager(); +//SellTradeManager* sellTradeManager = new SellTradeManager(); + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +// NEW CANDLE CLASSES INITIALIZATION +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +// Added because bmp files seem to have stopped working, possibly a file format issue +//fileType = "png"; +//fileName = "MyScreenshot." + fileType; + + + + + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + + + + + /* if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } */ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + + //lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + //highFractalIndex = rightPeriod+1; // this is used for the fractals + //initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + //initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + if(newCandleDetector_M1.isNewCandle()) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + } + + + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bearish candle closed inside the closest support zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bullish candle closed inside the resistance zone on " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+------------------------------------------------------------------+ diff --git a/candleStringDetector.ex5 b/candleStringDetector.ex5 new file mode 100644 index 0000000..cd1a5fe Binary files /dev/null and b/candleStringDetector.ex5 differ diff --git a/candleStringDetector.mq5 b/candleStringDetector.mq5 new file mode 100644 index 0000000..79f5850 --- /dev/null +++ b/candleStringDetector.mq5 @@ -0,0 +1,98 @@ +//+------------------------------------------------------------------+ +//| candleStringDetector.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +#include "Algo_Skeleton_Functions.mqh" + +int last_Color_candle = -1 ; +int daily_streak_counter = 0 ; + +string timeInStr = "--" ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + + + + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + if(newCandleDetectorDaily.isNewCandle()) + { + //objectsManager.drawVerticalLine(clrAliceBlue, TimeCurrent()); + if(candleClosedBullish(PERIOD_D1,1) && last_Color_candle != 1) // this is the first daily bullish candle + { + + // save the timeInStr and the daily streak counter in a row in excel + string fileName = "daily_candle_streak.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/); + FileSeek(fileHandle,0,SEEK_END); + FileWrite(fileHandle,timeInStr,daily_streak_counter); + + FileClose(fileHandle); + + datetime time = TimeCurrent(); // save the date of this day + timeInStr = TimeToString(time,TIME_DATE); + last_Color_candle = 1 ; // convert the flag to bullish + daily_streak_counter = 0 ; // reset the counter + + } + else if(candleClosedBullish(PERIOD_D1,1) && last_Color_candle == 1) + { + + daily_streak_counter++ ; + } + + + if(candleClosedBearish(PERIOD_D1,1) && last_Color_candle != 0) // this is the first daily bearish candle + { + + // save the timeInStr and the daily streak counter in a row in excel + string fileName = "daily_candle_streak.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/); + FileSeek(fileHandle,0,SEEK_END); + FileWrite(fileHandle,timeInStr,daily_streak_counter); + + FileClose(fileHandle); + + datetime time = TimeCurrent(); + timeInStr = TimeToString(time,TIME_DATE); + last_Color_candle = 0 ; + daily_streak_counter = 0; + } + + else if(candleClosedBearish(PERIOD_D1,1) && last_Color_candle == 0){ + daily_streak_counter++ ; + } + + + } + + } +//+------------------------------------------------------------------+ diff --git a/library_functions.mqh b/library_functions.mqh new file mode 100644 index 0000000..11c94bb --- /dev/null +++ b/library_functions.mqh @@ -0,0 +1,765 @@ +//+------------------------------------------------------------------+ +//| library_functions.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" + + + +#include + + + +int findMondayFromLastPeriodWeeks(int _period); + +// FRACTALS RELATED FUNCTIONS +bool isLowFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame); // checks if the given index candle is, a low fractal of the left, right periods +bool isHighFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame); // checks if the given index candle is, a high fractal of the left, right periods + +// TIME FRAME RELATED FUNCTIONS +string getChartTimeFrameInString() ; // gets the chart time frame in string format +string timeFrameToString(ENUM_TIMEFRAMES _timeFrame); + +// SESSIONS RELATED FUNCTIONS +bool sessionIsNy(); // checks if the session is ny +bool sessionIsLondon(); // checks if the session is london +bool sessionIsTokyo(); + + + +// TRADE RELATED FUNCTIONS +bool closePartialFromAllPositions(double partialAmount) ; // closes partial of all open positions the partial is partialAmount (parameter) +bool closePartialFromSpecificPosition(ulong posTicket, double partialToClose) ; // closes a partial from the given position ticket +bool stopLossIsValidBuys(double stopLoss, double _maxPipsRiskAmount); +bool stopLossIsValidSells(double stopLoss,double _maxPipsRiskAmount); +double positionProfitInPips(ulong posTicket); // returns the position profit in pips +double positionStopLoss(ulong posTicket); +void positionTrailStopLoss(ulong posTicket, double newStopLoss, double takeProfit); + + + +// CANDLE ANATOMY RELATED FUNCTIONS +bool buyBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody); // checks if the buy breaker candle is big enough +bool sellBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody); // checks if the sell breaker candle is big enough +bool bearishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection); // this function assumes that the previous candle is bearish +bool bullishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection); // this function assumes that the previous candle is bullish +double retestWickFormedOnTheFirstHalfOfCandle(ENUM_TIMEFRAMES _mainTimeFrame, ENUM_TIMEFRAMES _secondaryTimeFrame); +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index); +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index); +bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index); +bool candleBodyIsValid(ENUM_TIMEFRAMES _timeFrame, int _index); // this function is used for enhancing the detection of supports/resistances + + +// SUPPORT AND RESISTANCE RELATED FUNCTIONS +bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index=0); // _index = 0 is the default state which is a specific case of the general function with _index = i +bool resistancePatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index=0);// _index = 0 is the default state which is a specific case of the general function with _index = i + + + + + + +/* WARNING FOR THE NEXT FUNCTION*/ +/* IF A FRIDAY WAS NOT ON THE BROKER, THE FUNCTION WILL NOT COUNT THE WEEK. MAKE SURE BEFORE APPLYING IT TO SEE VISUALLY THAT IT WAS LAUNCHED RIGHT */ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int findMondayFromLastPeriodWeeks(int _period) { // _period = 1 means the previous week. _period = 2 means 2 weeks ago. and so on ... + + int startCountFromIndex = 0 ; + datetime localTime = TimeLocal(); + MqlDateTime dateTimeStructure ; + TimeToStruct(localTime,dateTimeStructure); + int dayOfTheWeek = dateTimeStructure.day_of_week; + int hourOfTheDay = dateTimeStructure.hour; + + if(dayOfTheWeek == 5) { // means if we called the function on friday , start counting from the candle of index 25, because our goal is to reach the pervious week friday, so we know we are in the previous week + startCountFromIndex = 25 ; + } + if(dayOfTheWeek == 6 || dayOfTheWeek == 7) { + Alert("Its saturday/sunday start next week !"); + } + + MqlDateTime shiftedBarTimeStruct ; + int weeksPassed = 0 ; // count of how many weeks we passed. it starts with 0 since we start at week 0. and will end in _period + int lockCounter = 0; + int i = startCountFromIndex ; // i represents the distance from the moment we started. by the end of the function it will point to the first monday of the desired week that we want + while(weeksPassed < _period) { + datetime shiftedBarTime=iTime(_Symbol,PERIOD_CURRENT,i); // take the date of the current candle + TimeToStruct(shiftedBarTime,shiftedBarTimeStruct); // change the date to a struct + + if(shiftedBarTimeStruct.day_of_week == 5 && lockCounter == 0) { // if we reached friday, add the weeksPassed by 1 and lock the block for the next friday + weeksPassed++; // each time we reach a friday this means we are in a previous week. (we are counting the weeks starting from the current moment and going back in time) + lockCounter++; + + } else if(shiftedBarTimeStruct.day_of_week == 5 && lockCounter > 0) { // stay locked until we pass the current friday + lockCounter++ ; + } else if(shiftedBarTimeStruct.day_of_week == 4) { // if reached thursday , then release the lock + lockCounter = 0; + } + i++; + } + + Print("weeks passed value is: "+ weeksPassed); + return i-2 ; + +} + + +// ************************ FRACTALS FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool isLowFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame) { // checks if the given index candle is, a low fractal of the left, right periods + + for(int i = index+1 ; i < (index + leftPeriod + 1) ; i++) { + if(!(iLow(Symbol(),timeFrame,index) <= iLow(Symbol(),timeFrame,i))) { + return false; + } + } + + + if(index > rightPeriod) { // this means we have enough candles to the right + + for(int j = index-1 ; (j > index - rightPeriod - 1) ; j--) { + if(!(iLow(Symbol(),timeFrame,index) <= iLow(Symbol(),timeFrame,j))) { + return false ; + } + } + } + else{ + return false ; + } + + + return true ; +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool isHighFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame) { // checks if the given index candle is, a high fractal of the left, right periods + + for(int i = index+1 ; i < (index + leftPeriod + 1) ; i++) { + if(!(iHigh(Symbol(),timeFrame,index) >= iHigh(Symbol(),timeFrame,i))) { + return false; + } + } + + if(index > rightPeriod) { // this means we have enough candles to the right + + for(int j = index-1 ; (j > index - rightPeriod - 1) ; j--) { + if(!(iHigh(Symbol(),timeFrame,index) >= iHigh(Symbol(),timeFrame,j))) { + return false ; + } + } + } + else{ + return false ; + } + + return true ; +} + + + + + + +// ************************ TIME FRAMES FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string getChartTimeFrameInString() { + + ENUM_TIMEFRAMES period = Period(); + + switch(period) { + + case PERIOD_M1: + return "PERIOD_M1" ; + break; + + case PERIOD_M2: + return "PERIOD_M2" ; + break; + + case PERIOD_M3: + return "PERIOD_M3" ; + break; + + case PERIOD_M4: + return "PERIOD_M4" ; + break; + + case PERIOD_M5: + return "PERIOD_M5" ; + break; + + case PERIOD_M6: + return "PERIOD_M6" ; + break; + case PERIOD_M10: + return "PERIOD_M10" ; + break; + + case PERIOD_M12: + return "PERIOD_M12" ; + break; + + case PERIOD_M15: + return "PERIOD_M15" ; + break; + + case PERIOD_M20: + return "PERIOD_M20" ; + break; + + case PERIOD_M30: + return "PERIOD_M30" ; + break; + case PERIOD_H1: + return "PERIOD_H1" ; + break; + + case PERIOD_H2: + return "PERIOD_H2" ; + break; + + case PERIOD_H3: + return "PERIOD_H3" ; + break; + + case PERIOD_H4: + return "PERIOD_H4" ; + break; + + case PERIOD_H6: + return "PERIOD_H6" ; + break; + + case PERIOD_H8: + return "PERIOD_H8" ; + break; + case PERIOD_H12: + return "PERIOD_H12" ; + break; + + case PERIOD_D1: + return "PERIOD_D1" ; + break; + case PERIOD_W1: + return "PERIOD_W1" ; + break; + + case PERIOD_MN1: + return "PERIOD_MN1" ; + break; + + } + + return "" ; +} + + +string timeFrameToString(ENUM_TIMEFRAMES _timeFrame){ + switch(_timeFrame) { + + case PERIOD_M1: + return "PERIOD_M1" ; + break; + + case PERIOD_M2: + return "PERIOD_M2" ; + break; + + case PERIOD_M3: + return "PERIOD_M3" ; + break; + + case PERIOD_M4: + return "PERIOD_M4" ; + break; + + case PERIOD_M5: + return "PERIOD_M5" ; + break; + + case PERIOD_M6: + return "PERIOD_M6" ; + break; + case PERIOD_M10: + return "PERIOD_M10" ; + break; + + case PERIOD_M12: + return "PERIOD_M12" ; + break; + + case PERIOD_M15: + return "PERIOD_M15" ; + break; + + case PERIOD_M20: + return "PERIOD_M20" ; + break; + + case PERIOD_M30: + return "PERIOD_M30" ; + break; + case PERIOD_H1: + return "PERIOD_H1" ; + break; + + case PERIOD_H2: + return "PERIOD_H2" ; + break; + + case PERIOD_H3: + return "PERIOD_H3" ; + break; + + case PERIOD_H4: + return "PERIOD_H4" ; + break; + + case PERIOD_H6: + return "PERIOD_H6" ; + break; + + case PERIOD_H8: + return "PERIOD_H8" ; + break; + case PERIOD_H12: + return "PERIOD_H12" ; + break; + + case PERIOD_D1: + return "PERIOD_D1" ; + break; + case PERIOD_W1: + return "PERIOD_W1" ; + break; + + case PERIOD_MN1: + return "PERIOD_MN1" ; + break; + + } + + return "" ; + +} + + + + + +// ************************ SESSIONS FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool sessionIsNy() { + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 12 && mqldt.hour <= 20) { + return true ; + } + + return false ; + +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool sessionIsLondon() { + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 8 && mqldt.hour <= 12) { + return true ; + } + + return false ; + +} + + +bool sessionIsTokyo(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 4 && mqldt.hour <= 8) { + return true ; + } + + return false ; +} + + +// ************************ TRADE FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool closePartialFromAllPositions(double partialAmount) { + CTrade trade ; + for(uint i=0 ; i< PositionsTotal() ; i++) { + + ulong positionTicket = PositionGetTicket(i); + if(PositionSelectByTicket(positionTicket)) { + + double positionVolume = PositionGetDouble(POSITION_VOLUME); + double lotsToClose = positionVolume * partialAmount ; + if(trade.PositionClosePartial(positionTicket,NormalizeDouble(lotsToClose,2))) { + Print("Closed partials succesffully"); + return true ; + } else { + Print("Failed to close partials, Error: " + GetLastError()); + return false ; + } + + } + + + + } + return false ; + +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool closePartialFromSpecificPosition(ulong posTicket, double partialToClose) { + + CTrade trade ; + double positionVolume = PositionGetDouble(POSITION_VOLUME); + double lotsToClose = positionVolume * partialToClose ; + if(trade.PositionClosePartial(posTicket,NormalizeDouble(lotsToClose,2))) { + + return true ; + + } else { + return false ; + } + + + return false ; + +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool stopLossIsValidBuys(double stopLoss, double _maxPipsRiskAmount) { + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLoss < _maxPipsRiskAmount) { + return true ; + } + + return false ; +} + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double positionProfitInPips(ulong posTicket) { + + double currentProfitInPips = -1 ; + if(PositionSelectByTicket(posTicket)) { + + double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT) ; + double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); + + + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { + currentProfitInPips = currentPrice - positionOpenPrice ; + } + + else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { + + currentProfitInPips = positionOpenPrice - currentPrice ; + } + } else { + + Comment("Error from positionProfitInPips() function: Failed to select position, Error " + GetLastError()); + } + + + + return currentProfitInPips ; + +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +double positionStopLoss(ulong posTicket) { + + double posStopLoss = -1 ; + if(PositionSelectByTicket(posTicket)) { + posStopLoss = PositionGetDouble(POSITION_SL) ; + + } else { + Comment("Error from positionStopLoss() function: Failed to select position, Error " + GetLastError()); + } + + return posStopLoss; + +} + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool stopLossIsValidSells(double stopLoss,double _maxPipsRiskAmount) { + if(stopLoss - SymbolInfoDouble(_Symbol, SYMBOL_BID) < _maxPipsRiskAmount) { + return true ; + } + return false ; + +} + + + + +void positionTrailStopLoss(ulong posTicket, double newStopLoss, double takeProfit) { + + CTrade trade ; + trade.PositionModify(posTicket,newStopLoss,takeProfit); + + + +} + + +// ************************ CANDLE ANATOMY FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool buyBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody) { + + if((iClose(_Symbol,_timeFrame,1) - iOpen(_Symbol,_timeFrame,1)) >= _sizeOfBreakerCandleBody) { + return true ; + } else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr + " Bullish Breaker candle body is too small to take a trade !"); + return false ; + + } + +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool sellBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody) { + if((iOpen(_Symbol,_timeFrame,1) - iClose(_Symbol,_timeFrame,1)) >= _sizeOfBreakerCandleBody) { + return true ; + } else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr + " Bearish Breaker candle body is too small to take a trade !"); + return false ; + + } + +} + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool bearishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection) { // this function assumes that the previous candle is bearish + + double upperWickLength = iHigh(_Symbol,_timeFrame,index) - iOpen(_Symbol,_timeFrame,index) ; + double totalCandleLength = iHigh(_Symbol,_timeFrame,index) - iClose(_Symbol,_timeFrame,index); + if((upperWickLength / totalCandleLength) >= wickRatioRejection) { // this means the candle is weak + Comment("Bearish Candle Is Weak"); + return true ; + } else { + return false ; + } +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool bullishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection) { // this function assumes that the previous candle is bullish + double lowerWickLength = iOpen(_Symbol,_timeFrame,index) - iLow(_Symbol,_timeFrame,index) ; + double totalCandleLength = iClose(_Symbol,_timeFrame,index) - iLow(_Symbol,_timeFrame,index) ; + + if((lowerWickLength/totalCandleLength) >= wickRatioRejection) { // this means the candle is weak + Comment("Bullish Candle is weak"); + return true ; + } else { + return false ; + } +} +//+------------------------------------------------------------------+ + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) { // the candle closed bullish + + return true ; + } + return false ; +} + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) { // the candle closed bullish + + return true ; + } + return false ; +} +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index) { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + if(candleClose == candleOpen) { + return true; + } else { + return false; + } + +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleBodyIsValid(ENUM_TIMEFRAMES _timeFrame, int _index) { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + double candleHigh = iHigh(_Symbol,_timeFrame,_index); + double candleLow = iLow(_Symbol,_timeFrame,_index); + double topWickSize ; + double bottomWickSize ; + double candleBodySize ; + + if(candleClosedBearish(_timeFrame,_index)) { + topWickSize = candleHigh - candleOpen ; + bottomWickSize = candleClose - candleLow ; + candleBodySize = candleOpen - candleClose ; + + } else if(candleClosedBullish(_timeFrame,_index)) { + topWickSize = candleHigh - candleClose ; + bottomWickSize = candleOpen - candleLow ; + candleBodySize = candleClose - candleOpen ; + } else if(candleClosedDoji(_timeFrame,_index)) { + + return false ; + } + + + if((topWickSize >= (15*candleBodySize)) || (bottomWickSize >= (15* candleBodySize))) { // 8 is fixed number , + //which means that if i find a candle's wick that is 15 times bigger than the body then i dont want to consider it when detecting a support or resistance, this is for the cases that the candle looks almost like a doji but not an actual doji + return false ; + } + + return true ; +} + +/*double retestWickFormedOnTheFirstHalfOfCandle(ENUM_TIMEFRAMES _mainTimeFrame, ENUM_TIMEFRAMES _secondaryTimeFrame){ + + if(candleClosedBullish(_mainTimeFrame,1)){ // previous candle closed bullish, this means checking a wick on a bullish candle on the main timeframe + if(candleClosedBearish(_secondaryTimeFrame)){ + + } + } + + + if(candleClosedBearish(_mainTimeFrame)){ // previous candle closed bullish, this means checking a wick on a bearish candle on the main timeframe + + } + +} */ + + +// ************************ SUPPORT AND RESISTANCE RELATED FUNCTIONS ************************ + + +/*bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame){ // this is a spicific case of the next function, the _index parameter here is 0 + if((candleClosedBearish(_timeFrame,2) && candleClosedBullish(_timeFrame,1) && candleBodyIsValid(_timeFrame,1)&& candleBodyIsValid(_timeFrame,2)) + || (candleClosedBearish(_timeFrame,3) && candleClosedDoji(_timeFrame,2) && candleClosedBullish(_timeFrame,1)) + || candleClosedBearish(_timeFrame,3) && candleBodyIsValid(_timeFrame,3) && !candleBodyIsValid(_timeFrame,2) && candleClosedBullish(_timeFrame,1) && candleBodyIsValid(_timeFrame,1)) { + return true ; + + } + return false ; +}*/ + + +bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index = 0){ // this is the same previous function but with geniric index to detect the support on . its used for detecing old supports (that are not currently happeneing) + + +if((candleClosedBearish(_timeFrame,_index+2) && candleClosedBullish(_timeFrame,_index+1) && candleBodyIsValid(_timeFrame,_index+1)&& candleBodyIsValid(_timeFrame,_index+2)) + || (candleClosedBearish(_timeFrame,_index+3) && candleClosedDoji(_timeFrame,_index+2) && candleClosedBullish(_timeFrame,_index+1)) + || candleClosedBearish(_timeFrame,_index+3) && candleBodyIsValid(_timeFrame,_index+3) && !candleBodyIsValid(_timeFrame,_index + 2) && candleClosedBullish(_timeFrame,_index+1) + && candleBodyIsValid(_timeFrame,_index+1) ){ + return true ; + + } + return false ; + +} +bool resistancePatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index = 0){ // this is a spicific case of the next function + + if((candleClosedBullish(_timeFrame,_index+2) && candleClosedBearish(_timeFrame,_index+1) && candleBodyIsValid(_timeFrame,_index+2) && candleBodyIsValid(_timeFrame,_index+1)) + || (candleClosedBullish(_timeFrame,3) && candleClosedDoji(_timeFrame,2) && candleClosedBearish(_timeFrame,1) )){ + + return true ; + } + + return false ; +} + diff --git a/shark_tiger/Algo_Skeleton_Functions.mqh b/shark_tiger/Algo_Skeleton_Functions.mqh new file mode 100644 index 0000000..c4c345a --- /dev/null +++ b/shark_tiger/Algo_Skeleton_Functions.mqh @@ -0,0 +1,1958 @@ +//+------------------------------------------------------------------+ +//| 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 ; + } + + + + +//+------------------------------------------------------------------+ diff --git a/shark_tiger/Breakout_Fractals.ex5 b/shark_tiger/Breakout_Fractals.ex5 new file mode 100644 index 0000000..5c267c4 Binary files /dev/null and b/shark_tiger/Breakout_Fractals.ex5 differ diff --git a/shark_tiger/Breakout_Fractals.mq5 b/shark_tiger/Breakout_Fractals.mq5 new file mode 100644 index 0000000..faad5b5 --- /dev/null +++ b/shark_tiger/Breakout_Fractals.mq5 @@ -0,0 +1,404 @@ +//+------------------------------------------------------------------+ +//| Breakout_Fractals.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +//#include "Algo_Skeleton_Functions.mqh" +#include "Phoenix_Functions.mqh" + +bool trailWhenMarketOpensDaily = false ; +int OnInit() + { +//--- + +//--- + for(int i=0; i + +CTrade tradeLong ; +class BuyEntryManager + { +private: + + bool longTradeTaken ; + bool waitingForRejectionCandle; + bool waitingForRetracement ; + + + +public: + BuyEntryManager(); + ~BuyEntryManager(); + + BuyRejectionDetector* buyRejectionDetector ; + + bool isWaitingForRejectionCandle(){return waitingForRejectionCandle ;} + void setWaitingForRejectionCandle(bool _setting){waitingForRejectionCandle = _setting ;} + + bool isWaitingForRetracement(){return waitingForRetracement;} + void setWaitingForRetracement(bool _setting){waitingForRetracement = _setting ;} + + bool buyTradeTaken(); + void setTradeTakenStatus(bool _status){longTradeTaken = _status ; Print("long trade taken flag has been set to true");} + + + ulong takeBuyTrade(double _lots,double _stopLoss); + ulong takeBuyTradeTiger(double _lots,double _stopLoss,double _takeProfit); + ulong takeBuyTradeTiger(double _lots,double _stopLoss); + + + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyEntryManager::BuyEntryManager() + { + buyRejectionDetector = new BuyRejectionDetector(); + longTradeTaken = false ; + waitingForRejectionCandle = false ; + waitingForRetracement = false ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyEntryManager::~BuyEntryManager() + { + delete buyRejectionDetector ; + } +//+------------------------------------------------------------------+ + + +bool BuyEntryManager:: buyTradeTaken(){ + + +return longTradeTaken ; +} + + +ulong BuyEntryManager:: takeBuyTrade(double _lots, double _stopLoss){ + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + + +} + + +ulong BuyEntryManager:: takeBuyTradeTiger(double _lots,double _stopLoss, double _takeProft){ // first version, take the buy with fixed tp + + double netTp = _takeProft - SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss,SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTp); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} + + +ulong BuyEntryManager:: takeBuyTradeTiger(double _lots,double _stopLoss){ // second version, take the buy without a fixed tp + + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} + diff --git a/shark_tiger/BuyGandalf.mqh b/shark_tiger/BuyGandalf.mqh new file mode 100644 index 0000000..f802a88 --- /dev/null +++ b/shark_tiger/BuyGandalf.mqh @@ -0,0 +1,85 @@ +//+------------------------------------------------------------------+ +//| BuyGandalf.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include + +CTrade tradeLong ; +class BuyGandalf + { +private: + + bool longTradeTaken ; + ulong longTrades[10] ; + + +public: + BuyGandalf(); + ~BuyGandalf(); + + + + bool buyTradeTaken(); + void setTradeTakenStatus(bool _status){longTradeTaken = _status ; Print("long trade taken flag has been set to true");} + + + ulong takeBuyTrade(double _lots,double _stopLoss); + ulong takeBuyTradeGandalf(double _lots,double _stopLoss); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyGandalf::BuyGandalf() + { + + longTradeTaken = false ; + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyGandalf::~BuyGandalf() + { + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ + + +bool BuyGandalf:: buyTradeTaken(){ + + +return longTradeTaken ; +} + + +ulong BuyGandalf:: takeBuyTrade(double _lots, double _stopLoss){ + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + + +} + + +ulong BuyGandalf:: takeBuyTradeGandalf(double _lots,double _stopLoss){ + + tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss); + + ulong tradeTicket = tradeLong.ResultOrder(); + + Print("Buy entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} diff --git a/shark_tiger/BuyRejectionDetector.mqh b/shark_tiger/BuyRejectionDetector.mqh new file mode 100644 index 0000000..91f0fc3 --- /dev/null +++ b/shark_tiger/BuyRejectionDetector.mqh @@ -0,0 +1,53 @@ +//+------------------------------------------------------------------+ +//| BuyRejectionDetector.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class BuyRejectionDetector + { +private: + +public: + BuyRejectionDetector(); + ~BuyRejectionDetector(); + + bool rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame); + bool rejectionByRangeFormed(); + bool rejectionByWicksFormed(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyRejectionDetector::BuyRejectionDetector() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyRejectionDetector::~BuyRejectionDetector() + { + } +//+------------------------------------------------------------------+ + + +bool BuyRejectionDetector:: rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame){ + + double rejectionCandleClose = iClose(_Symbol,_timeFrame,1); + double rejectionCandleOpen = iOpen(_Symbol,_timeFrame,1); + double rejectionCandleHigh = iHigh(_Symbol,_timeFrame,1) ; + double rejectionCandleHigherWickSize ; + double rejectionCandleBodySize ; + + if( rejectionCandleClose > rejectionCandleOpen ){ // the previous candle closed bullish + rejectionCandleHigherWickSize = rejectionCandleHigh - rejectionCandleClose; + rejectionCandleBodySize = rejectionCandleClose - rejectionCandleOpen; + if(rejectionCandleBodySize >= rejectionCandleHigherWickSize){ + return true ; + } + + } + return false ; +} \ No newline at end of file diff --git a/shark_tiger/BuyTradeManager.mqh b/shark_tiger/BuyTradeManager.mqh new file mode 100644 index 0000000..9ff3bc9 --- /dev/null +++ b/shark_tiger/BuyTradeManager.mqh @@ -0,0 +1,592 @@ +//+------------------------------------------------------------------+ +//| BuyTradeManager.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//#include +//#include +#include +CTrade tradeLongInTradeManager; + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class BuyTradeManager + { +private: + int tradeId; + ulong rejectionByOneCandleTradeArray[3]; + + string firstSecureMethod ; + bool firstSecureMethodFound; + int numberOfTakeProfits ; + bool securedFirstLevelProfit ; + bool securedSecondLevelProfit; + double partialToClose ; + bool isTradeRunning ; + + +public: + BuyTradeManager(); + ~BuyTradeManager(); + + void fillRejectionByOneCandleTradeArray(int _index, int _id) {rejectionByOneCandleTradeArray[_index] = _id ;} + ulong getRejectionByOneCandleTradeTicket(int _index) {return rejectionByOneCandleTradeArray[_index] ;} + void printRejectionByOneCandleTradeArray(); + + void checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars); + string findFirstSecureMethod(); + + bool reachedProfitRatio(int _indexInArr); + bool closeTrade(int _indexInArr); + bool positionBreakEven(int _indexInArr); + + + void addTpAtIndex(int _index, double tpPrice) {tpArray[_index] = tpPrice;} + int countRemainingTakeProfits(); + bool reachedClosestTakeProfit(); + void deleteClosestTp(); + int findClosestTpIndex(); + + + void cleanOrderDataStructures(); + + void setTradeRunning(bool _setting) {isTradeRunning = _setting ;} + bool tradeIsRunning() {return isTradeRunning ;} + + double tpArray[3]; + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyTradeManager::BuyTradeManager() + { + + for(int i=0; i<3; i++) + { + tpArray[i] = -1; + } + securedFirstLevelProfit = false ; + securedSecondLevelProfit = false ; + firstSecureMethodFound = false ; + firstSecureMethod = "NOT_FOUND" ; + partialToClose = -1 ; + isTradeRunning = false ; + + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyTradeManager::~BuyTradeManager() + { + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void BuyTradeManager:: printRejectionByOneCandleTradeArray() + { + + Print("Printing the tickets :"); + for(int i=0 ; i<3 ; i++) + { + Print((int)rejectionByOneCandleTradeArray[i]); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void BuyTradeManager:: checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars) + { + if(securedFirstLevelProfit == false) // in this case im searching for 2 cases: either RR 1:1.5 , OR reaching the first TP , if any of them happened im gonna close half the order and updatae the remaining stop losses + { + + + if(!firstSecureMethodFound) + { + + firstSecureMethod = findFirstSecureMethod(); + if(firstSecureMethod != "FAILED") + { + + firstSecureMethodFound = true ; + } + else + if(firstSecureMethod == "FAILED") + { + Print("Failed to find the first secure method, go check the function : findFirstSecureMehod() !"); + } + + } + + if(firstSecureMethodFound == true) + { + + if(firstSecureMethod == "RATIO_METHOD") + { + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(reachedProfitRatio(0)) + { + ChartRedraw(); // Make sure the chart is up to date + //ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + //SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + //"If you see this message it means we reached the first secure method, which is ratio method, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName); + if(closeTrade(0)) // close the half + { + + rejectionByOneCandleTradeArray[0] = -1; + Print("Closed Half Of the position due to reaching the first secure Ratio!"); + } + else + { + Print("Failed Closing Half of the order by reaching the first secure Ratio !"); + } + + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(positionBreakEven(1)) // put the first quarter at break even + { + + Print(" First quarter has been put into break even due to reaching the first secure Ratio!"); + } + else + { + Print("Failed to Put the first quarter into break even"); + } + + numberOfTakeProfits = countRemainingTakeProfits(); + + Print("Number of remaining tps is: " + numberOfTakeProfits); + + securedFirstLevelProfit = true ; + } + + + + + + } + else + if(firstSecureMethod == "FIRST_TP_METHOD") + { + if(countRemainingTakeProfits() > 1) // there is at least 2 tp in the tp Array (because if this is the last tp then we want to close the whole order and not just a part of it) + { + if(reachedClosestTakeProfit()) // 2. Check if reached the first Tp + { + ChartRedraw(); // Make sure the chart is up to date + //ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + //SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + //"If you see this message it means we reached the first secure method which is tp1, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName); + // close the first half and update remaining partials sl's and delete the closest take profit from the array + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(closeTrade(0)) // close the half + { + + rejectionByOneCandleTradeArray[0] = -1; + Print("Closed Half Of the position due to reaching the first TP!"); + + } + else + { + Print("Failed Closing Half of the order by reaching the first TP !"); + } + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(positionBreakEven(1)) // put the first quarter at break even + { + + Print(" First quarter has been put into break even due to reaching the first TP!"); + } + else + { + Print("Failed to Put the first quarter into break even"); + } + deleteClosestTp(); + numberOfTakeProfits = countRemainingTakeProfits(); // update the number of remaining take profits + // calculate the remaining tps + + Print("Number of remaining tps is: " + numberOfTakeProfits); + Print("TP ARRY: " + tpArray[0] + ", " + tpArray[1] + " , " + tpArray[2]); + + securedFirstLevelProfit = true ; + + + } + } + else + if(numberOfTakeProfits = countRemainingTakeProfits() == 1) + { + if(reachedClosestTakeProfit()) + { + // close everything remained + } + } + } + + } + + + + } + else + if(securedFirstLevelProfit == true) // after securing the first level i just want to close the remaining partials by reaching the tp's + { + + if(countRemainingTakeProfits() == 1) + { + if(reachedClosestTakeProfit()) + { + // close everything + cleanOrderDataStructures(); + for(int i=0 ; i<3 ; i++) + { + closeTrade(i); + } + Print("Closed every thing because price reached the last Take Profit !"); + + ChartRedraw(); // Make sure the chart is up to date + //ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + //SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + // "If you see this message it means that all order are closed as a result of reaching the last tp " + TimeToString(TimeLocal()), fileName); + deleteClosestTp(); + } + } + else + if(countRemainingTakeProfits() > 1) + { + if(reachedClosestTakeProfit()) + { + cleanOrderDataStructures(); + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[1])) // DEALING WITH THE FIRST QUARTER + { + double currentLot = PositionGetDouble(POSITION_VOLUME); + if(partialToClose == -1) + { + partialToClose = currentLot/numberOfTakeProfits ; + } + if(tradeLongInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[1],NormalizeDouble(partialToClose,2))) + { + uint res = tradeLongInTradeManager.ResultRetcode(); + if(res == 10009) + { + Print("Closed Partials successfully on the first quarter !"); + } + else + { + Print("The returned code is: " + res + " go check what it means !"); + } + + } + } + else + { + Print("Failed to select position by ticket! , Error: " + GetLastError()); + Print("The EA tried to close partials on the first quarter, but it is closed, probably due to break even and thats why it couldnt select the order !"); + } + + + cleanOrderDataStructures(); + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[2])) // DEALING WITH THE SECOND QUARTER + { + if(PositionGetDouble(POSITION_SL) < PositionGetDouble(POSITION_PRICE_OPEN)) // this is to put the second quarter at break even if its not already at break even + { + positionBreakEven(2); + + } + double currentLot = PositionGetDouble(POSITION_VOLUME); + if(partialToClose == -1) + { + partialToClose = currentLot/numberOfTakeProfits ; + } + if(tradeLongInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[2],NormalizeDouble(partialToClose,2))) + { + uint res = tradeLongInTradeManager.ResultRetcode(); + if(res == 10009) + { + Print("Closed Partials successfully on the second quarter!"); + } + else + { + Print("The returned code is: " + res + " go check what it means !"); + } + + } + + } + deleteClosestTp(); + Print("Number Of Remained tps is: " + countRemainingTakeProfits()); + + ChartRedraw(); // Make sure the chart is up to date + //ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + //SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + // "If you see this message it means we reached a tp level (different than the first secure level), so partial positions will be closed, and the scond quarter must be in break even!" + TimeToString(TimeLocal()), fileName); + } + + } + + + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string BuyTradeManager:: findFirstSecureMethod() + { + + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[0])) + { + double positionStopLoss = PositionGetDouble(POSITION_SL); + double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double firstTakeProfit = tpArray[findClosestTpIndex()]; + if(((firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) > firstSecureRatio)) // firstTp > ratio + { + Print("Found the first profit secure method !"); + Print("The first TP RR is: 1:" + (firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) + "the firstSecureRatio is: 1:" + firstSecureRatio); + Print("The tp ratio is greater than the firstSecure so:"); + Print("The first secure method is RATIO_METHOD"); + return"RATIO_METHOD"; + } + else + if((firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss)< firstSecureRatio) + { + Print("Found the first profit secure method !"); + Print("The first TP RR is: 1:" + (firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) + "the firstSecureRatio is: 1:" + firstSecureRatio); + Print("The tp ratio is less than the firstSecure so:"); + Print("The first secure method is FIRST_TP_METHOD"); + return "FIRST_TP_METHOD" ; + } + } + else + { + Print("Failed to select position by ticket 1, Error: " + GetLastError()); + } + + return "FAILED" ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool BuyTradeManager:: reachedProfitRatio(int _indexInArr) + { + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) + { + if(PositionGetDouble(POSITION_PROFIT)/(0.5*riskDollars) >= firstSecureRatio) // checking if the first half of the contract reached the ratio of first secure profit + { + Print("reached profit ratio !"); + return true ; + } + } + else + { + Print("Failed to select the position by ticket 4 ,Error: " + GetLastError()); + + } + + } + + return false ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool BuyTradeManager:: closeTrade(int _indexInArr) + { + + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) + { + + // close the first half and update remaining partials sl's + if(tradeLongInTradeManager.PositionClose(_ticket)) + { + return true ; + + } + else + { + + Print("Failed to close positon, Error:" + GetLastError()); + return false; + } + + } + else + { + + Print("Failed to select position by ticket , Error: "+ GetLastError()); + return false; + } + + } + + + return false ; + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool BuyTradeManager:: positionBreakEven(int _indexInArr) + { + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) // select the first quarter + { + double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double positionTp = PositionGetDouble(POSITION_TP); + double positionSl = PositionGetDouble(POSITION_SL); + + if(tradeLongInTradeManager.PositionModify(_ticket,openPrice,positionTp)) + { + + + return true ; + } + else + { + Print("Failed to modify oder , ERROR: " + GetLastError()); + return false ; + } + + } + else + { + Print("Failed to select position by ticket "); + return false ; + } + } + + + return false ; + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int BuyTradeManager:: countRemainingTakeProfits() + { + + int counter = 0 ; + for(int i=0; i<3 ; i++) + { + if(tpArray[i] != -1) + { + counter++ ; + } + } + + return counter; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void BuyTradeManager:: deleteClosestTp() + { + + int closestTpIndex =findClosestTpIndex(); + tpArray[closestTpIndex] = -1; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int BuyTradeManager:: findClosestTpIndex() + { + int closestTpIndex = 0; + int closestTpValue = 1000000 ; // dummy value + + for(int i=0; i<3; i++) + { + if(tpArray[i] != -1 && tpArray[i] < closestTpValue) + { + closestTpValue = tpArray[i]; + closestTpIndex = i ; + } + + } + + return closestTpIndex ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool BuyTradeManager:: reachedClosestTakeProfit() + { + + + double closestTakeProfitValue = tpArray[findClosestTpIndex()]; + //Print("im in reached closest take profit function ,the current price is: " + SymbolInfoDouble(_Symbol, SYMBOL_BID) + " and the tp is: " + closestTakeProfitValue); + if(SymbolInfoDouble(_Symbol, SYMBOL_BID) >= closestTakeProfitValue) // we are looking for the BID , because reaching a tp in a buy trade means we are selling, so we want our take profit value, to be at least as the BID price (because we want to find someone to buy it from us at this price) + { + return true ; + } + return false ; + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void BuyTradeManager:: cleanOrderDataStructures() + { +// this is to make sure, that every closed order is removed from the data strucutre ! + + for(int i=0; i<3; i++) + { + if(!PositionSelectByTicket(rejectionByOneCandleTradeArray[i])) + { + if(GetLastError() == 4753) + { + rejectionByOneCandleTradeArray[i] = -1 ; + } + } + } + + } +//+------------------------------------------------------------------+ + + diff --git a/shark_tiger/BuyTradeManagerTiger.mqh b/shark_tiger/BuyTradeManagerTiger.mqh new file mode 100644 index 0000000..d9295ba --- /dev/null +++ b/shark_tiger/BuyTradeManagerTiger.mqh @@ -0,0 +1,72 @@ +//+------------------------------------------------------------------+ +//| BuyTradeManagerTiger.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class BuyTradeManagerTiger + { +private: + + ulong tradeId ; + string entryType ; + bool firstPartialSecured ; + bool secondPartialSecured ; + bool managedRisk ; + bool retestWickFormed ; + double retestWickLengthInPips ; + + int riskManagementCandleCounter ; + double brokenResistanceLowerEdge ; + double brokenResistanceHigherEdge ; +public: + + ulong getTradeId(){return tradeId ;} + + bool riskAlreadyManaged(){return managedRisk ;} + void manageRisk(){managedRisk = true ;} + + bool firstPartialIsSecured(){return firstPartialSecured ;} + void secureFirstPartial(){firstPartialSecured = true ;} + + void setBrokenResistancetLowerEdge(double _brokenResistanceLowerEdge){brokenResistanceLowerEdge = _brokenResistanceLowerEdge ;} + void setBrokenResistanceHigherEdge(double _brokenResistanceHigherEdge){brokenResistanceHigherEdge = _brokenResistanceHigherEdge ;} + + double getBrokenResistanceLowerEdge(){return brokenResistanceLowerEdge ;} + double getBrokenResistanceHigherEdge(){return brokenResistanceHigherEdge ;} + + void incrementRiskManagementCandleCoutner(){riskManagementCandleCounter++ ;} + void decrementRiskManagementCandleCounter(){riskManagementCandleCounter-- ;} + + int getRiskManagementCandleCounter(){return riskManagementCandleCounter ;} + + void setRiskManagementCandleCounter(int count){ riskManagementCandleCounter = count ;} + + BuyTradeManagerTiger(ulong _tradeId); + ~BuyTradeManagerTiger(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyTradeManagerTiger::BuyTradeManagerTiger(ulong _tradeId) + { + + tradeId = _tradeId ; + firstPartialSecured = false ; + secondPartialSecured = false ; + managedRisk = false ; + retestWickFormed = false ; + retestWickLengthInPips = 0 ; + + riskManagementCandleCounter = 0 ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +BuyTradeManagerTiger::~BuyTradeManagerTiger() + { + } +//+------------------------------------------------------------------+ + diff --git a/shark_tiger/Entries_Newest.ex5 b/shark_tiger/Entries_Newest.ex5 new file mode 100644 index 0000000..33fa53c Binary files /dev/null and b/shark_tiger/Entries_Newest.ex5 differ diff --git a/shark_tiger/Entries_Newest.mq5 b/shark_tiger/Entries_Newest.mq5 new file mode 100644 index 0000000..1b205b9 --- /dev/null +++ b/shark_tiger/Entries_Newest.mq5 @@ -0,0 +1,333 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include "Algo_Skeleton_Functions.mqh" + +long H4_SUPPORT_ZONE_CLR ; +long H4_RESISTANCE_ZONE_CLR ; +long H1_SUPPORT_ZONE_CLR; +long H1_RESISTANCE_ZONE_CLR; +long M30_SUPPORT_ZONE_CLR ; +long M30_RESISTANCE_ZONE_CLR ; + +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + H4_SUPPORT_ZONE_CLR = clrBlack ; + H4_RESISTANCE_ZONE_CLR = clrBlack ; + + if(ENTRY_BASED_H1_STRUCTURE == true && ENTRY_BASED_M30_STRUCTURE == false){ + M30_SUPPORT_ZONE_CLR = clrBlack ; + M30_RESISTANCE_ZONE_CLR = clrBlack ; + + H1_SUPPORT_ZONE_CLR = clrAliceBlue ; + H1_RESISTANCE_ZONE_CLR = clrDarkGray ; + + } + else if(ENTRY_BASED_H1_STRUCTURE == false && ENTRY_BASED_M30_STRUCTURE == true){ + M30_SUPPORT_ZONE_CLR = clrAliceBlue ; + M30_RESISTANCE_ZONE_CLR = clrDarkGray ; + + H1_SUPPORT_ZONE_CLR = clrBlack ; + H1_RESISTANCE_ZONE_CLR = clrBlack ; + + } + + + objectsManager.addTextTiger(); + + for(int i=0; i0){ + updateNormalZonesSupport(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",M30_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_M30,0); + } + + if(zoneContainer_M30.getNumberOfActiveZones()> 0){ + updateNormalZonesResistance(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",M30_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_M30,0); + } + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetector30M.isNewCandle()) + { + + if(trail_based_m30){ + trailAllOpenPositionsIfNeeded(PERIOD_M30); + } + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",M30_RESISTANCE_ZONE_CLR,zoneContainer_M30,rangeDistanceBetweenZonesActual_M30,0); + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",M30_SUPPORT_ZONE_CLR,zoneContainerSupport_M30,rangeDistanceBetweenZonesActual_M30,0); + if(ENTRY_BASED_M30_STRUCTURE){ + + handleBuys(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",cleanRangeUponEntryActual); + handleSells(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",cleanRangeUponEntryActual); + } + else{ + + handleBullishBreakouts(zoneContainer_M30,PERIOD_M30,"PERIOD_M30"); + handleBearishBreakouts(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30"); + } + + + + // UPDATING H1 ZONES + if(zoneContainerSupport_H1.getNumberOfActiveZones()>0){ + updateNormalZonesSupport(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",H1_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_H1,1000); + } + + if(zoneContainer_H1.getNumberOfActiveZones()> 0){ + updateNormalZonesResistance(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",H1_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_H1,1000); + } + + + + zoneContainerSupport_M30.printZonesSortedArray(); + zoneContainer_M30.printZonesSortedArray(); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + if(newCandleDetector1H.isNewCandle()){ + + if(trail_based_h1){ + trailAllOpenPositionsIfNeeded(PERIOD_H1); + } + + + detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",H1_RESISTANCE_ZONE_CLR,zoneContainer_H1,rangeDistanceBetweenZonesActual_H1,1000); + detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",H1_SUPPORT_ZONE_CLR,zoneContainerSupport_H1,rangeDistanceBetweenZonesActual_H1,1000); + + if(ENTRY_BASED_H1_STRUCTURE){ + + handleBuys(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",cleanRangeUponEntryActual); + handleSells(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",cleanRangeUponEntryActual); + } + + else{ + handleBullishBreakouts(zoneContainer_H1,PERIOD_H1,"PERIOD_H1"); + handleBearishBreakouts(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1"); + + } + + + // UPDATING H4 ZONES + if(zoneContainerSupport_H4.getNumberOfActiveZones()>0){ + updateNormalZonesSupport(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",H4_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_H4,2000); + } + + if(zoneContainer_H4.getNumberOfActiveZones()> 0){ + updateNormalZonesResistance(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",H4_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_H4,2000); + } + + Print("H1 zones :"); + //zoneContainerSupport_H1.printZonesSortedArray(); + //zoneContainer_H1.printZonesSortedArray(); + + } + + + + + if(newCandleDetector4H.isNewCandle()){ + last_H4_candle_broke_structure = false ; + + if(trail_based_h4){ + trailAllOpenPositionsIfNeeded(PERIOD_H4); + } + + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",H4_RESISTANCE_ZONE_CLR,zoneContainer_H4,rangeDistanceBetweenZonesActual_H4,2000); + detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",H4_SUPPORT_ZONE_CLR,zoneContainerSupport_H4,rangeDistanceBetweenZonesActual_H4,2000); + + // BREAK OF STRUCTURE HANDLING + + + handleBullishBreakouts(zoneContainer_H4,PERIOD_H4,"PERIOD_H4"); + handleBearishBreakouts(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4"); + + //handleBuys(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual); + //handleSells(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual); + + //Print("H4, Zones:"); + //zoneContainerSupport_H4.printZonesSortedArray(); + //zoneContainer_H4.printZonesSortedArray(); + } + + + + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + + weekCounter++ ; + + if(weekCounter == deleteAllZonesAfter_Weeks){ + + //deleteAllzonesWithGUI(); + weekCounter = 0; + } + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } + diff --git a/shark_tiger/Gandalf.ex5 b/shark_tiger/Gandalf.ex5 new file mode 100644 index 0000000..cc7a2bc Binary files /dev/null and b/shark_tiger/Gandalf.ex5 differ diff --git a/shark_tiger/Gandalf.mq5 b/shark_tiger/Gandalf.mq5 new file mode 100644 index 0000000..189f720 --- /dev/null +++ b/shark_tiger/Gandalf.mq5 @@ -0,0 +1,363 @@ +//+------------------------------------------------------------------+ +//| Gandalf.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "GraphicalObjectsManager.mqh" +#include "TempLineObjectAttributes.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "BuyGandalf.mqh" +#include "SellGandalf.mqh" +#include "LotSizeCalculator.mqh" + + + +LotSizeCalculator lsCalc; +GraphicalObjectsManager graphicalObjectsManager ; +ObjectConfirmationUnit objectConfUnit ; +BuyGandalf buyGandalfGray ; +SellGandalf SellGandalfGray ; + +bool buyCase = false ; +bool sellCase = false ; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +TempLineObjectAttributes tempLineObjectAttr ; +int OnInit() + { +//--- create timer + EventSetTimer(60); + + + graphicalObjectsManager.addTotalRiskText(); + graphicalObjectsManager.addTakeBuyTradeButton(); + graphicalObjectsManager.addTakeSellTradeButton(); + graphicalObjectsManager.addText(); + graphicalObjectsManager.addConfirmButton(); + + //ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"the new ext is : !"); + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + updateOverAllRiskText(); + + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { + + + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + + + if(sparam == "BUY_BTN") + { + buyCase = true ; + + graphicalObjectsManager.drawStopLossLineGandalf(); + objectConfUnit.setWaitingStatus(true); + + } + + else if(sparam == "SELL_BTN"){ + sellCase = true ; + graphicalObjectsManager.drawStopLossLineGandalf(); + objectConfUnit.setWaitingStatus(true); + + + } + + else + if(sparam == "CONFIRM_BTN") + { + if(buyCase == true) + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + string textRecieved; + graphicalObjectsManager.EditTextGet(textRecieved,0,"textName"); + double riskAsDouble = StringToDouble(textRecieved); + + double stopLossPrice = tempLineObjectAttr.getPrice(); + + + + if(ObjectDelete(_Symbol,"sl")) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + //Print("Buy info has been set, SL price: " + stopLossPrice + " risk is: " + riskAsDouble); + + double lotsToTrade = lsCalc.calculateLotSize(riskAsDouble,stopLossPrice); + + buyGandalfGray.takeBuyTradeGandalf(lotsToTrade,stopLossPrice); + + objectConfUnit.setWaitingStatus(false); + buyCase = false ; + + // change the risk text + //updateOverAllRiskText(); + + + } + + } + else + if(sellCase == true) + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + string textRecieved; + graphicalObjectsManager.EditTextGet(textRecieved,0,"textName"); + double riskAsDouble = StringToDouble(textRecieved); + + double stopLossPrice = tempLineObjectAttr.getPrice(); + + if(ObjectDelete(_Symbol,"sl")){ + + + } + else{ + + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + double lotsToTrade = lsCalc.calculateLotSize(riskAsDouble,stopLossPrice); + SellGandalfGray.takeSellTradeGandalf(lotsToTrade,stopLossPrice); + + objectConfUnit.setWaitingStatus(false); + sellCase = false ; + + + // change the risk text + //updateOverAllRiskText(); + + + } + + } + + + + + } + break; + } + + + case CHARTEVENT_OBJECT_DRAG: + { + + + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + + + } + + + break; + } + + + case CHARTEVENT_KEYDOWN: + { + + } + + + + //--- + + } + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + +void updateOverAllRiskText(){ + + + + //double pointValue = lsCalc.PointValue(_Symbol); + + double pointValue = PointValueNew(_Symbol); + double overAllRisk = 0 ; + for(int i=PositionsTotal() -1 ;i >= 0 ; i--){ + //Print("entered here !"); + ulong ticket = PositionGetTicket(i); + int positionType = PositionGetInteger(POSITION_TYPE); + double positionStopLossPrice = PositionGetDouble(POSITION_SL); + double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double positionLotSize = PositionGetDouble(POSITION_VOLUME); + + + if(positionType == POSITION_TYPE_BUY){ + double positionStopLossInPoints = (positionOpenPrice - positionStopLossPrice) * MathPow(10 , SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)) ; + double riskAmount = pointValue*positionLotSize*positionStopLossInPoints ; + overAllRisk = overAllRisk + riskAmount ; + string riskAsString = DoubleToString(overAllRisk); + ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is:" + riskAsString); + } + else if(positionType == POSITION_TYPE_SELL){ + double positionStopLossInPoints = (positionStopLossPrice - positionOpenPrice) * MathPow(10 , SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)) ; + double riskAmount = pointValue*positionLotSize*positionStopLossInPoints ; + overAllRisk = overAllRisk + riskAmount ; + string riskAsString = DoubleToString(overAllRisk); + ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is:" + riskAsString); + + } + } + +} + + + +double PointValueNew(string symbol){ + + + double tickSize = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE); + double tickValue = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE); + double point = SymbolInfoDouble(symbol,SYMBOL_POINT); + double ticksPerPoint = tickSize/point ; + double pointValue = tickValue/ticksPerPoint ; + + return (pointValue); +} \ No newline at end of file diff --git a/shark_tiger/GeneralTests.mq5 b/shark_tiger/GeneralTests.mq5 new file mode 100644 index 0000000..c57d650 --- /dev/null +++ b/shark_tiger/GeneralTests.mq5 @@ -0,0 +1,1668 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +//input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTALS DATA + +//input int leftPeriod; +//input int rightPeriod; +//input int weekPeriodToInitialize; +//input int initFractalsPeriod ; +//int lowFractalIndex ; +//int highFractalIndex ; +//#include "LowFractal.mqh" +//#include "HighFractal.mqh" +//#include "LowFractalContainer.mqh" +//#include "HighFractalContainer.mqh" + + + +#property script_show_inputs + +input datetime InpStartTime = __DATETIME__; +input bool REJECTION_M1_ONLY ; + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" + + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" +#include "LotSizeCalculator.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + +// Telegram Connection include +#include + +// SCRIPTS INCLUDES + + + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +// NEW CANDLE CLASSES INITIALIZATION +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + +bool telegramTested = false ; +input bool testTelegram ; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +// Added because bmp files seem to have stopped working, possibly a file format issue +//fileType = "png"; +//fileName = "MyScreenshot." + fileType; + + + if(telegramTested == false && testTelegram == true) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"This is just a test ! " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + telegramTested = true ; + } + + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + + + + + /* if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } */ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + + //lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + //highFractalIndex = rightPeriod+1; // this is used for the fractals + //initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + //initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + /*if(newCandleDetector_M1.isNewCandle()) + { + + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + }*/ + + + if(REJECTION_M1_ONLY == true) + { + if(newCandleDetector_M1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + Print("Im in new candle !"); + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + } + } + else + { + + if(newCandleDetector_H1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + handleBuys(PERIOD_H1); + handleSells(PERIOD_H1); + } + + } + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bearish candle closed inside the closest support zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bullish candle closed inside the resistance zone on " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/GraphicalObjectsManager.mqh b/shark_tiger/GraphicalObjectsManager.mqh new file mode 100644 index 0000000..73c2cc8 --- /dev/null +++ b/shark_tiger/GraphicalObjectsManager.mqh @@ -0,0 +1,1076 @@ +//+------------------------------------------------------------------+ +//| GraphicalObjectsManager.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class GraphicalObjectsManager + { +private: + int verticalLineCounter ; +public: + GraphicalObjectsManager(); + ~GraphicalObjectsManager(); + + + void addZoneButton(); + void addStopLossButton(); + void addTakeProfitButton(); + void addSetTakeProfitButton(); + void addConfirmButton(); + void addDeleteButton(); + void addPrintFractalsButton(); + void addPrintZonesButton(); + void addTakeBuyTradeButton(); + void addTakeSellTradeButton(); + void addExitExperAdvisorButton(); + void drawRectangle(int _zoneId); + void drawRectangleInStrategyTester(int _zone_Id,datetime leftEdge, datetime rightEdge, double highEdgePrice, double lowEdgePrice,long _color); + void drawStopLossLine(string _zoneId); + void drawStopLossLineGandalf(); + void drawTakeProfitLine(string _zoneId); + void drawVerticalLine(long _color, datetime _time); + void drawHorizontalLine(long _color, string nameOfLine,double price); + void drawLowFractal(int _index,long _color); + void drawHighFractal(int _index,long _color); + + void addText (); + void addTextTiger(); + void addMarketDescriptionTextTiger(); + void addTotalRiskText (); + + bool EditTextGet(string &text, const long chart_ID=0, string name = "" ) ; + + + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +GraphicalObjectsManager::GraphicalObjectsManager() + { + verticalLineCounter = 0; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +GraphicalObjectsManager::~GraphicalObjectsManager() + { + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addZoneButton() + { + + + if(!ObjectCreate(0,"ZONE_ADD_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_XDISTANCE,30); + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"ZONE_ADD_BTN",OBJPROP_TEXT,"Add Zone"); + //--- set text font + ObjectSetString(0,"ZONE_ADD_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BORDER_COLOR,clrGray); + //--- display in the foreground (false) or background (true) + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BACK,back); + + //--- set button state + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_STATE,state); + + //--- enable (true) or disable (false) the mode of moving the button by mouse + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTABLE,selection); + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTED,selection); + + //--- hide (true) or display (false) graphical object name in the object list + + // ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_HIDDEN,hidden); + + //--- set the priority for receiving the event of a mouse click in the chart + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_ZORDER,z_order); + + } + } + + + +void GraphicalObjectsManager:: addTakeBuyTradeButton(){ + + + + if(!ObjectCreate(0,"BUY_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"BUY_BTN",OBJPROP_XDISTANCE,30); + ObjectSetInteger(0,"BUY_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"BUY_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"BUY_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"BUY_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"BUY_BTN",OBJPROP_TEXT,"Buy"); + //--- set text font + ObjectSetString(0,"BUY_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"BUY_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"BUY_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"BUY_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"BUY_BTN",OBJPROP_BORDER_COLOR,clrGray); + //--- display in the foreground (false) or background (true) + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BACK,back); + + //--- set button state + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_STATE,state); + + //--- enable (true) or disable (false) the mode of moving the button by mouse + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTABLE,selection); + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTED,selection); + + //--- hide (true) or display (false) graphical object name in the object list + + // ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_HIDDEN,hidden); + + //--- set the priority for receiving the event of a mouse click in the chart + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_ZORDER,z_order); + + } + + +} + + + + + +void GraphicalObjectsManager:: addTakeSellTradeButton(){ + + + + if(!ObjectCreate(0,"SELL_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"SELL_BTN",OBJPROP_XDISTANCE,170); + ObjectSetInteger(0,"SELL_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"SELL_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"SELL_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"SELL_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"SELL_BTN",OBJPROP_TEXT,"Sell"); + //--- set text font + ObjectSetString(0,"SELL_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"SELL_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"SELL_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"SELL_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"SELL_BTN",OBJPROP_BORDER_COLOR,clrGray); + //--- display in the foreground (false) or background (true) + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_BACK,back); + + //--- set button state + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_STATE,state); + + //--- enable (true) or disable (false) the mode of moving the button by mouse + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTABLE,selection); + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_SELECTED,selection); + + //--- hide (true) or display (false) graphical object name in the object list + + // ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_HIDDEN,hidden); + + //--- set the priority for receiving the event of a mouse click in the chart + + //ObjectSetInteger(0,"ZONE_ADD_BTN",OBJPROP_ZORDER,z_order); + + } + + +} + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addConfirmButton() + { + + if(!ObjectCreate(0,"CONFIRM_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the confirm button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_XDISTANCE,470); + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"CONFIRM_BTN",OBJPROP_TEXT,"Confirm Object"); + //--- set text font + ObjectSetString(0,"CONFIRM_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"CONFIRM_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addDeleteButton() + { + if(!ObjectCreate(0,"DELETE_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the delete button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_XDISTANCE,310); + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"DELETE_BTN",OBJPROP_TEXT,"Delete Object"); + //--- set text font + ObjectSetString(0,"DELETE_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"DELETE_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addExitExperAdvisorButton() + { + if(!ObjectCreate(0,"EXIT_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the exit button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_XDISTANCE,450); + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"EXIT_BTN",OBJPROP_TEXT,"Remove Expert"); + //--- set text font + ObjectSetString(0,"EXIT_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_FONTSIZE,9); + //--- set text color + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"EXIT_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addPrintFractalsButton() + { + + if(!ObjectCreate(0,"PRINT_FRACTAL_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the print fractals button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_XDISTANCE,590); + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"PRINT_FRACTAL_BTN",OBJPROP_TEXT,"Print Fractals"); + //--- set text font + ObjectSetString(0,"PRINT_FRACTAL_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"PRINT_FRACTAL_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addPrintZonesButton() + { + if(!ObjectCreate(0,"PRINT_ZONES_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the print fractals button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_XDISTANCE,730); + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"PRINT_ZONES_BTN",OBJPROP_TEXT,"Print Zones"); + //--- set text font + ObjectSetString(0,"PRINT_ZONES_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"PRINT_ZONES_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addStopLossButton() + { + if(!ObjectCreate(0,"ADD_SL_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the stop loss button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_XDISTANCE,30); + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_YDISTANCE,100); + //--- set button size + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"ADD_SL_BTN",OBJPROP_TEXT,"Add SL"); + //--- set text font + ObjectSetString(0,"ADD_SL_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"ADD_SL_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: addTakeProfitButton() + { + + if(!ObjectCreate(0,"ADD_TP_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the take profit button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_XDISTANCE,170); + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_YDISTANCE,100); + //--- set button size + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"ADD_TP_BTN",OBJPROP_TEXT,"Add TP"); + //--- set text font + ObjectSetString(0,"ADD_TP_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"ADD_TP_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + } + + + +void GraphicalObjectsManager:: addSetTakeProfitButton(){ + if(!ObjectCreate(0,"SET_TP_BTN",OBJ_BUTTON,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create the take profit button! Error code = ",GetLastError()); + + } + else + { + ChartRedraw(); + //--- set button coordinates + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_XDISTANCE,310); + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_YDISTANCE,100); + //--- set button size + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"SET_TP_BTN",OBJPROP_TEXT,"Set TP"); + //--- set text font + ObjectSetString(0,"SET_TP_BTN",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"SET_TP_BTN",OBJPROP_BORDER_COLOR,clrGray); + + } + +} +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: drawRectangle(int _zoneId) + { + + string nameInString = IntegerToString(_zoneId); + + + if(!ObjectCreate(_Symbol,nameInString,OBJ_RECTANGLE,0,iTime(_Symbol,PERIOD_CURRENT,20),iLow(_Symbol,PERIOD_CURRENT,20),iTime(_Symbol,PERIOD_CURRENT,10), iOpen(_Symbol,PERIOD_CURRENT,20))) + { + + Print(__FUNCTION__, + ": Failed to create a Zone! Error code = ",GetLastError()); + + } + + else + { + ChartRedraw(); + Print("Rectangle created successfully!"); + //--- set rectangle color + ObjectSetInteger(0,nameInString,OBJPROP_COLOR,clrDimGray); + ObjectSetInteger(0,nameInString,OBJPROP_FILL,clrDimGray); + + ObjectSetInteger(0,nameInString,OBJPROP_SELECTABLE,true); + + ObjectSetInteger(0,nameInString,OBJPROP_SELECTED,true); + + + ObjectSetInteger(0,nameInString,OBJPROP_XDISTANCE,700); + ObjectSetInteger(0,nameInString,OBJPROP_YDISTANCE,700); + + + } + + } + + + +void GraphicalObjectsManager:: drawRectangleInStrategyTester(int _zoneId,datetime leftEdge, datetime rightEdge, double highEdgePrice, double lowEdgePrice, long _color){ + + string nameInString = IntegerToString(_zoneId); + + + if(!ObjectCreate(_Symbol,nameInString,OBJ_RECTANGLE,0,leftEdge,lowEdgePrice,rightEdge, highEdgePrice)) + { + + Print(__FUNCTION__, + ": Failed to create a Zone! Error code = ",GetLastError()); + + } + + else + { + ChartRedraw(); + Print("Rectangle created successfully!"); + //--- set rectangle color + ObjectSetInteger(0,nameInString,OBJPROP_COLOR,_color); + ObjectSetInteger(0,nameInString,OBJPROP_FILL,_color); + ObjectSetInteger(0,nameInString,OBJPROP_BORDER_TYPE,0); + ObjectSetInteger(0,nameInString,OBJPROP_BACK,true); + + ObjectSetInteger(0,nameInString,OBJPROP_SELECTABLE,true); + + ObjectSetInteger(0,nameInString,OBJPROP_SELECTED,false); + + + ObjectSetInteger(0,nameInString,OBJPROP_XDISTANCE,700); + ObjectSetInteger(0,nameInString,OBJPROP_YDISTANCE,700); + + + + } + +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void GraphicalObjectsManager:: drawStopLossLine(string _zoneId) + { + + string lineName = "sl" + _zoneId ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,lineName,OBJ_HLINE,0,0,SymbolInfoDouble(_Symbol, SYMBOL_ASK))) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,clrRed); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,1); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + +//--- successful execution + } + + + void GraphicalObjectsManager:: drawTakeProfitLine(string _zoneId) + { + + string lineName = "tp" + _zoneId ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,lineName,OBJ_HLINE,0,0,SymbolInfoDouble(_Symbol, SYMBOL_ASK))) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,clrAqua); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,0.5); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + +//--- successful execution + } + + + +void GraphicalObjectsManager:: drawVerticalLine(long _color, datetime _time){ + Print("entered the drawvertical line function"); + string lineName = "vline" + IntegerToString(verticalLineCounter) ; + verticalLineCounter++; + + + + + if(!ObjectCreate(_Symbol,lineName,OBJ_VLINE,0,_time,0)) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,_color); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,0.5); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + + +} + + + +void GraphicalObjectsManager:: drawHorizontalLine(long _color, string nameOfLine,double price){ + + string lineName = nameOfLine; + + + + if(!ObjectCreate(_Symbol,lineName,OBJ_HLINE,0,TimeCurrent(),price)) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,_color); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,0.5); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + +} + +void GraphicalObjectsManager:: addText (){ + + if(!ObjectCreate(0,"textName",OBJ_EDIT,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create a text! Error code = ",GetLastError()); + + } + + else{ + + + + ChartRedraw(); + + + //--- set button coordinates + ObjectSetInteger(0,"textName",OBJPROP_XDISTANCE,300); + ObjectSetInteger(0,"textName",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"textName",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"textName",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"textName",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"textName",OBJPROP_TEXT," Risk Amount"); + //--- set text font + ObjectSetString(0,"textName",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"textName",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"textName",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"textName",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"textName",OBJPROP_BORDER_COLOR,clrGray); + } + + + +} + + +void GraphicalObjectsManager:: addTextTiger (){ + + if(!ObjectCreate(0,"clockTextTiger",OBJ_EDIT,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create a text! Error code = ",GetLastError()); + + } + + else{ + + + + ChartRedraw(); + + + //--- set button coordinates + ObjectSetInteger(0,"clockTextTiger",OBJPROP_XDISTANCE,300); + ObjectSetInteger(0,"clockTextTiger",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"clockTextTiger",OBJPROP_XSIZE,150); + ObjectSetInteger(0,"clockTextTiger",OBJPROP_YSIZE,100); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"clockTextTiger",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT," "); + //--- set text font + ObjectSetString(0,"clockTextTiger",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"clockTextTiger",OBJPROP_FONTSIZE,20); + //--- set text color + ObjectSetInteger(0,"clockTextTiger",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"clockTextTiger",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"clockTextTiger",OBJPROP_BORDER_COLOR,clrGray); + } + + + +} + + + +void GraphicalObjectsManager:: addMarketDescriptionTextTiger(){ + + if(!ObjectCreate(0,"marketDescriptionText",OBJ_EDIT,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create a text! Error code = ",GetLastError()); + + } + + else{ + + + + ChartRedraw(); + + + //--- set button coordinates + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_XDISTANCE,50); + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_YDISTANCE,150); + //--- set button size + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_XSIZE,600); + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_YSIZE,100); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT," "); + //--- set text font + ObjectSetString(0,"marketDescriptionText",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_BGCOLOR,clrGray); + //--- set border color + ObjectSetInteger(0,"marketDescriptionText",OBJPROP_BORDER_COLOR,clrGray); + } + + +} + + +void GraphicalObjectsManager:: addTotalRiskText (){ + + if(!ObjectCreate(0,"totalRiskText",OBJ_EDIT,0,0,0)) + { + Print(__FUNCTION__, + ": failed to create a text! Error code = ",GetLastError()); + + } + + else{ + + + + ChartRedraw(); + + + //--- set button coordinates + ObjectSetInteger(0,"totalRiskText",OBJPROP_XDISTANCE,700); + ObjectSetInteger(0,"totalRiskText",OBJPROP_YDISTANCE,40); + //--- set button size + ObjectSetInteger(0,"totalRiskText",OBJPROP_XSIZE,120); + ObjectSetInteger(0,"totalRiskText",OBJPROP_YSIZE,50); + //--- set the chart's corner, relative to which point coordinates are defined + ObjectSetInteger(0,"totalRiskText",OBJPROP_CORNER,CORNER_LEFT_UPPER); + //--- set the text + ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is: 0"); + //--- set text font + ObjectSetString(0,"totalRiskText",OBJPROP_FONT,"Arial"); + //--- set font size + ObjectSetInteger(0,"totalRiskText",OBJPROP_FONTSIZE,10); + //--- set text color + ObjectSetInteger(0,"totalRiskText",OBJPROP_COLOR,clrWhite); + //--- set background color + ObjectSetInteger(0,"totalRiskText",OBJPROP_BGCOLOR,clrBlack); + //--- set border color + ObjectSetInteger(0,"totalRiskText",OBJPROP_BORDER_COLOR,clrBlack); + + ObjectSetInteger(_Symbol,"totalRiskText",OBJPROP_SELECTABLE,false); + + + } + + + +} + + +bool GraphicalObjectsManager:: EditTextGet(string &text, const long chart_ID=0, string name = "") + { +//--- reset the error value + ResetLastError(); +//--- get object text + if(!ObjectGetString(chart_ID,name,OBJPROP_TEXT,0,text)) + { + Print(__FUNCTION__, + ": failed to get the text! Error code = ",GetLastError()); + return(false); + } +//--- successful execution + return(true); + } + + + +void GraphicalObjectsManager:: drawStopLossLineGandalf() + { + + string lineName = "sl" ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,lineName,OBJ_HLINE,0,0,SymbolInfoDouble(_Symbol, SYMBOL_ASK))) + { + Print(__FUNCTION__, + ": failed to create a horizontal line! Error code = ",GetLastError()); + + } + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,lineName,OBJPROP_COLOR,clrRed); +//--- set line display style + ObjectSetInteger(_Symbol,lineName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + ObjectSetInteger(_Symbol,lineName,OBJPROP_WIDTH,1); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,lineName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,lineName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,lineName,OBJPROP_HIDDEN,false); + +//--- successful execution + } + + + + +void GraphicalObjectsManager:: drawLowFractal(int _index,long _color){ + + string fractalName = "low_fractal" ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,fractalName,OBJ_ARROW_UP,0,iTime(_Symbol,PERIOD_CURRENT,_index),iLow(_Symbol,PERIOD_CURRENT,_index) - 0.25)) + { + + Print(__FUNCTION__, + ": failed to create an arrow object! Error code = ",GetLastError()); + + } + + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,fractalName,OBJPROP_COLOR,_color); +//--- set line display style + ObjectSetInteger(_Symbol,fractalName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + // ObjectSetInteger(_Symbol,fractalName,OBJPROP_WIDTH,1); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,fractalName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + //ObjectSetInteger(_Symbol,fractalName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,fractalName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,fractalName,OBJPROP_HIDDEN,false); +} + + + +void GraphicalObjectsManager:: drawHighFractal(int _index,long _color){ + + string fractalName = "high_fractal" ; +//--- create a horizontal line + if(!ObjectCreate(_Symbol,fractalName,OBJ_ARROW_DOWN,0,iTime(_Symbol,PERIOD_CURRENT,_index),iHigh(_Symbol,PERIOD_CURRENT,_index) + 0.25)) + { + + Print(__FUNCTION__, + ": failed to create an arrow object! Error code = ",GetLastError()); + + } + + ChartRedraw(); +//--- set line color + ObjectSetInteger(_Symbol,fractalName,OBJPROP_COLOR,_color); +//--- set line display style + ObjectSetInteger(_Symbol,fractalName,OBJPROP_STYLE,STYLE_SOLID); +//--- set line width + // ObjectSetInteger(_Symbol,fractalName,OBJPROP_WIDTH,1); +//--- display in the foreground (false) or background (true) + ObjectSetInteger(_Symbol,fractalName,OBJPROP_BACK,true); +//--- enable (true) or disable (false) the mode of moving the line by mouse +//--- when creating a graphical object using ObjectCreate function, the object cannot be +//--- highlighted and moved by default. Inside this method, selection parameter +//--- is true by default making it possible to highlight and move the object + //ObjectSetInteger(_Symbol,fractalName,OBJPROP_SELECTABLE,true); + ObjectSetInteger(_Symbol,fractalName,OBJPROP_SELECTED,false); +//--- hide (true) or display (false) graphical object name in the object list + ObjectSetInteger(_Symbol,fractalName,OBJPROP_HIDDEN,false); +} \ No newline at end of file diff --git a/shark_tiger/HighFractal.mqh b/shark_tiger/HighFractal.mqh new file mode 100644 index 0000000..8fea724 --- /dev/null +++ b/shark_tiger/HighFractal.mqh @@ -0,0 +1,254 @@ +//+------------------------------------------------------------------+ +//| HighFractal.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class HighFractal + { + +private: + + double highPrice ; + int leftPeriod; + int rightPeriod; + + MqlDateTime dateStruct ; + datetime date ; + + double sellLimitPrice; // the fib level price , based on this fractal + double lowestPeak ; // the highest price reached, after the fractal was formed + int hour ; + int minute; + int distance ; // holds the number of candles from this fractal until the current live candle + string arrowObjName ; + double fibPrice ; + +public: + HighFractal(); + HighFractal(double _price, int _leftPeriod, int _rightPeriod, datetime _date,ENUM_TIMEFRAMES _tf); + ~HighFractal(); + + + + // GETTERS + + double getPrice(); + int getLeftPeriod(); + int getRightPeriod(); + int getHour(); + int getMinute(); + double getLowestPeak(); + int getDistance(); + string getArrowObjName(); + datetime getDate(); + // SETTERS + + void setPrice(double _price); + void setLeftPeriod(int _leftPeriod); + void setRightPeriod(int _rightPeriod); + void setHour(int _hour); + void setMinute(int _minute); + void setLowestPeak(double _highest); + void setArrowObjName(string _name); + void setDistance(int _dist); + void setDate(datetime _givenDate); + + + // OTHER FUNCTIONS + + double calculateFibPrice(double _fibLevel, double _highPrice, double _lowPrice); // calculate the fibonacci price based on the given level, and saves the price in the fibPrice88 variable in the object + void updateDistance(); + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractal::HighFractal() + { + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractal::HighFractal(double _price, int _leftPeriod, int _rightPeriod,datetime _date,ENUM_TIMEFRAMES _tf) + { +// the constructor sets the data to the attribues , and calculates the real time of the fractal , because the given minute and hour +// are not the real time, they are the time of when the fractal was "known to be a fractal", which is after _righPeriod amount of candles + + highPrice = _price ; + leftPeriod = _leftPeriod; + rightPeriod = _rightPeriod; + sellLimitPrice = -1 ; + distance = _rightPeriod+1; + arrowObjName = " " ; + lowestPeak = -1; + + + date = iTime(_Symbol,_tf,_rightPeriod+1); // bring the actual date of the fractal + TimeToStruct(date,dateStruct); // convert the actual date into a struct + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractal::~HighFractal() + { + } +//+------------------------------------------------------------------+ + + + +double HighFractal:: getPrice() + { + + return highPrice ; + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int HighFractal:: getLeftPeriod() + { + + return leftPeriod ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int HighFractal:: getRightPeriod() + { + + return rightPeriod ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int HighFractal:: getHour() + { + + return dateStruct.hour ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int HighFractal:: getMinute() + { + return dateStruct.min ; + } + + +double HighFractal:: getLowestPeak(){ + + return lowestPeak ; +} + + + +int HighFractal:: getDistance(){ + + return distance ; +} + + +string HighFractal:: getArrowObjName(){ + return arrowObjName ; + +} + + +datetime HighFractal:: getDate(){ + + return date ; +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setPrice(double _price) + { + highPrice = _price ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setLeftPeriod(int _leftPeriod) + { + leftPeriod = _leftPeriod ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setRightPeriod(int _rightPeriod) + { + rightPeriod = _rightPeriod ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setHour(int _hour) + { + hour = _hour ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void HighFractal:: setMinute(int _minute) + { + minute = _minute ; + } + +//+------------------------------------------------------------------+ + +void HighFractal:: setArrowObjName(string _name){ + arrowObjName = _name ; + +} + + void HighFractal:: setDistance(int _dist){ + distance = _dist ; + } + + + +double HighFractal:: calculateFibPrice(double _fibLevel, double _highPrice, double _lowPrice){ + + double difference = _lowPrice - _highPrice ; + difference = difference*-1 ; + double retracement = _fibLevel * difference ; + double _fibPrice = _lowPrice + retracement ; + fibPrice = _fibPrice ; + return fibPrice; +} + + + +void HighFractal:: setLowestPeak(double _lowest){ + + lowestPeak = _lowest ; + +} + +void HighFractal:: setDate(datetime _givenDate){ + date = _givenDate; + TimeToStruct(date,dateStruct); // convert the actual date into a struct +} + +void HighFractal:: updateDistance(){ + + distance++ ; +} +//+------------------------------------------------------------------+ diff --git a/shark_tiger/HighFractalContainer.mqh b/shark_tiger/HighFractalContainer.mqh new file mode 100644 index 0000000..07321ae --- /dev/null +++ b/shark_tiger/HighFractalContainer.mqh @@ -0,0 +1,131 @@ +//+------------------------------------------------------------------+ +//| HighFractalContainer.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "HighFractal.mqh" +#include +#define SIZE 700 + +double input arrowDistanceHighs ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class HighFractalContainer + { +private: + HighFractal* highFractals[SIZE]; + int freeIndex ; + double range ; + ENUM_TIMEFRAMES timeFrame ; +public: + HighFractalContainer(ENUM_TIMEFRAMES _timeFrame); + ~HighFractalContainer(); + + //GETTERS + + HighFractal* getHighFractal(int _index) {return highFractals[_index] ;} // returns the fractal using its index in the array + int getFreeIndex() {return freeIndex ; } + + //SETTERS + void setRange(double _range) {range = _range ;} + + // OTHER FUNCTIONS + void addHighFractal(HighFractal* _highFractal); // adds high fractal to the high fractals array + void printHighFractals(); // prints the data of every high fractal in the highFractals[] array + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractalContainer::HighFractalContainer(ENUM_TIMEFRAMES _timeFrame) + { + timeFrame = _timeFrame; + freeIndex = 0 ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +HighFractalContainer::~HighFractalContainer() + { + + for(int i=0; i 0) + { + for(int i=0 ; i SymbolInfoDouble(_Symbol, SYMBOL_BID)) // we are calculating for a sell + { + difference = stopLossPrice - SymbolInfoDouble(_Symbol, SYMBOL_BID) ; + differenceInPoints = difference / SymbolInfoDouble(_Symbol, SYMBOL_POINT); + double pointValue = PointValue(_Symbol); + + // Situation 3, fixed risk amount and stop loss, how many lots to trade + double riskInPoints = differenceInPoints; + double riskLots = riskInMoney / (pointValue * riskInPoints); + + return riskLots; + } + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) > stopLossPrice){ + difference = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossPrice ; + differenceInPoints = difference / SymbolInfoDouble(_Symbol, SYMBOL_POINT); + double pointValue = PointValue(_Symbol); + double riskInPoints = differenceInPoints; + double riskLots = riskInMoney / (pointValue * riskInPoints); + return riskLots; + } + + + return 0 ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double LotSizeCalculator:: PointValue(string symbol) + { + + double tickSize = TickSize(symbol); + double tickValue = TickValue(symbol); + double point = Point(symbol); + double ticksPerPoint = tickSize / point; + double pointValue = tickValue / ticksPerPoint; + + PrintFormat("tickSize=%f, tickValue=%f, point=%f, ticksPerPoint=%f, pointValue=%f", + tickSize, tickValue, point, ticksPerPoint, pointValue); + + return (pointValue); + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LotSizeCalculator:: Test(string symbol) + { + + PrintFormat("Base currency is %s", BaseCurrency()); + PrintFormat("Testing for symbol %s", symbol); + + double pointValue = PointValue(symbol); + + PrintFormat("ValuePerPoint for %s is %f", symbol, pointValue); + +// Situation 3, fixed risk amount and stop loss, how many lots to trade + double riskAmount = 100; + double riskPoints = 5000; + double riskLots = riskAmount / (pointValue * riskPoints); + PrintFormat("Risk lots for %s value %f and stop loss at %f points is %f", + symbol, riskAmount, riskPoints, riskLots); + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/LowFractal.mqh b/shark_tiger/LowFractal.mqh new file mode 100644 index 0000000..96244f9 --- /dev/null +++ b/shark_tiger/LowFractal.mqh @@ -0,0 +1,255 @@ +//+------------------------------------------------------------------+ +//| LowFractal.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class LowFractal + { +private: + +private: + + double lowPrice ; + int leftPeriod; + int rightPeriod; + + MqlDateTime dateStruct ; + datetime date ; + + double buyLimitPrice; // the fib level price , based on this fractal + double highestPeak ; // the highest price reached, after the fractal was formed + int hour ; + int minute; + int distance ; // holds the number of candles from this fractal until the current live candle + string arrowObjName ; + double fibPrice ; + +public: + LowFractal(); + LowFractal(double _price, int _leftPeriod, int _rightPeriod, datetime _date,ENUM_TIMEFRAMES _tf); + ~LowFractal(); + + + + // GETTERS + + double getPrice(); + int getLeftPeriod(); + int getRightPeriod(); + int getHour(); + int getMinute(); + double getHighestPeak(); + int getDistance(); + string getArrowObjName(); + datetime getDate(); + // SETTERS + + void setPrice(double _price); + void setLeftPeriod(int _leftPeriod); + void setRightPeriod(int _rightPeriod); + void setHour(int _hour); + void setMinute(int _minute); + void setHighestPeak(double _highest); + void setArrowObjName(string _name); + void setDistance(int _dist); + void setDate(datetime _givenDate); + + + // OTHER FUNCTIONS + + double calculateFibPrice(double _fibLevel, double _lowPrice, double _highPrice); // calculate the fibonacci price based on the given level, and saves the price in the fibPrice88 variable in the object + void updateDistance(); + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractal::LowFractal() + { + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractal::LowFractal(double _price, int _leftPeriod, int _rightPeriod,datetime _date, ENUM_TIMEFRAMES _tf) + { +// the constructor sets the data to the attribues , and calculates the real time of the fractal , because the given minute and hour +// are not the real time, they are the time of when the fractal was "known to be a fractal", which is after _righPeriod amount of candles + + lowPrice = _price ; + leftPeriod = _leftPeriod; + rightPeriod = _rightPeriod; + buyLimitPrice = -1 ; + distance = _rightPeriod+1; + arrowObjName = " " ; + highestPeak = -1; + + + date = iTime(_Symbol,_tf,_rightPeriod+1); // bring the actual date of the fractal + TimeToStruct(date,dateStruct); // convert the actual date into a struct + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractal::~LowFractal() + { + } +//+------------------------------------------------------------------+ + + + +double LowFractal:: getPrice() + { + + return lowPrice ; + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int LowFractal:: getLeftPeriod() + { + + return leftPeriod ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int LowFractal:: getRightPeriod() + { + + return rightPeriod ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int LowFractal:: getHour() + { + + return dateStruct.hour ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int LowFractal:: getMinute() + { + return dateStruct.min ; + } + + +double LowFractal:: getHighestPeak(){ + + return highestPeak ; +} + + + +int LowFractal:: getDistance(){ + + return distance ; +} + + +string LowFractal:: getArrowObjName(){ + return arrowObjName ; + +} + + +datetime LowFractal:: getDate(){ + + return date ; +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setPrice(double _price) + { + lowPrice = _price ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setLeftPeriod(int _leftPeriod) + { + leftPeriod = _leftPeriod ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setRightPeriod(int _rightPeriod) + { + rightPeriod = _rightPeriod ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setHour(int _hour) + { + hour = _hour ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void LowFractal:: setMinute(int _minute) + { + minute = _minute ; + } + +//+------------------------------------------------------------------+ + +void LowFractal:: setArrowObjName(string _name){ + arrowObjName = _name ; + +} + + void LowFractal:: setDistance(int _dist){ + distance = _dist ; + } + + + +double LowFractal:: calculateFibPrice(double _fibLevel, double _lowPrice, double _highPrice){ + + double difference = _highPrice - _lowPrice ; + double retracement = _fibLevel * difference ; + double _fibPrice = _highPrice - retracement ; + fibPrice = _fibPrice ; + return fibPrice; +} + + + +void LowFractal:: setHighestPeak(double _highest){ + + highestPeak = _highest ; + +} + +void LowFractal:: setDate(datetime _givenDate){ + date = _givenDate; + TimeToStruct(date,dateStruct); // convert the actual date into a struct +} + +void LowFractal:: updateDistance(){ + + distance++ ; +} + + diff --git a/shark_tiger/LowFractalContainer.mqh b/shark_tiger/LowFractalContainer.mqh new file mode 100644 index 0000000..e343409 --- /dev/null +++ b/shark_tiger/LowFractalContainer.mqh @@ -0,0 +1,137 @@ +//+------------------------------------------------------------------+ +//| LowFractalContainer.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "LowFractal.mqh" +#include +#define SIZE 700 + +double input arrowDistanceLows ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class LowFractalContainer + { +private: + LowFractal* lowFractals[SIZE]; + int freeIndex ; + double range ; + ENUM_TIMEFRAMES timeFrame ; +public: + LowFractalContainer(ENUM_TIMEFRAMES _timeFrame); + ~LowFractalContainer(); + + //GETTERS + + LowFractal* getLowFractal(int _index) {return lowFractals[_index] ;} // returns the fractal using its index in the array + int getFreeIndex() {return freeIndex ; } + + //SETTERS + void setRange(double _range) {range = _range ;} + + // OTHER FUNCTIONS + void addLowFractal(LowFractal* _lowFractal); // adds low fractal to the low fractals array + void printLowFractals(); // prints all low fractals data + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractalContainer::LowFractalContainer(ENUM_TIMEFRAMES _timeFrame) + { + timeFrame = _timeFrame ; + freeIndex = 0 ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +LowFractalContainer::~LowFractalContainer() + { + + for(int i=0; i 0) + { + + for(int i=0 ; i= zoneContainer.getZoneByIndex(currentResistanceZoneIndex).getLowerEdge()) + { + + Print("Reached the current resistance zone !"); + return "TYPE_RESISTANCE" ; + + } + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= zoneContainer.getZoneByIndex(currentSupportZoneIndex).getHigherEdge()) + { + Print("Reached the current support zone !"); + return "TYPE_SUPPORT" ; + + } + } + + + return "" ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: reachedClosestSupportZone() + { + + int currentSupportZoneIndex = zoneContainer.getLowZonePivot(); + + if(currentSupportZoneIndex != -1) + { + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= zoneContainer.getZoneByIndex(currentSupportZoneIndex).getHigherEdge()) + { + return true ; + + } + + } + + return false ; + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: reachedClosestResistanceZone() + { + + int currentResistanceZoneIndex = zoneContainer.getHighZonePivot(); + + if(currentResistanceZoneIndex != -1) + { + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) >= zoneContainer.getZoneByIndex(currentResistanceZoneIndex).getLowerEdge()) + { + return true ; + + } + } + + + return false ; + + } + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: bullishCandleClosedInsideClosestResistanceZone(ENUM_TIMEFRAMES tf) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + double previousCandleOpen = iOpen(_Symbol,tf,1); + + if(zoneContainer.getHighZonePivot() != -1) // means if there is a pivot zone + { + + if((previousCandleClose > previousCandleOpen) && (previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getLowerEdge()) && (previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getHigherEdge())) // means if previous the candle is bullish and closed inside the resistance zone + { + + return true ; + } + } + + return false ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: bearishCandleClosedInsideClosestSupportZone(ENUM_TIMEFRAMES tf) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + double previousCandleOpen = iOpen(_Symbol,tf,1); + + if(zoneContainer.getLowZonePivot() != -1) + { + if((previousCandleClose < previousCandleOpen) && (previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getHigherEdge()) && (previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getLowerEdge())) // means if previous the candle is breaish and closed inside the support zone + { + return true ; + } + + } + return false ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketObserver:: giveMarketReport() + { + + + return " " ; + } + +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: candleClosedBelowClosestSupportZone(ENUM_TIMEFRAMES tf) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + double previousCandleOpen = iOpen(_Symbol,tf,1); + + + if(zoneContainer.getLowZonePivot() != -1) + { + if((previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getLowerEdge())) // means if the previous candle closed below the support zone + { + + return true ; + } + + } + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserver:: candleClosedAboveClosestResistanceZone(ENUM_TIMEFRAMES tf) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + double previousCandleOpen = iOpen(_Symbol,tf,1); + + if(zoneContainer.getHighZonePivot() != -1) // means if there is a pivot zone + { + + if((previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getHigherEdge())) // means if previous the candle closed above the resistance zone + { + + return true ; + } + } + return false ; + + } + + + bool MarketObserver:: candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf){ + + double previousCandleClose = iClose(_Symbol,tf,1); + + if((previousCandleClose > zoneContainer.getZoneByIndex(_index).getHigherEdge())){ + + return true ; + } + + return false ; + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/MarketObserverTiger.mqh b/shark_tiger/MarketObserverTiger.mqh new file mode 100644 index 0000000..17a709b --- /dev/null +++ b/shark_tiger/MarketObserverTiger.mqh @@ -0,0 +1,105 @@ +//+------------------------------------------------------------------+ +//| MarketObserverTiger.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +//+------------------------------------------------------------------+ +//| defines | +//+------------------------------------------------------------------+ +// #define MacrosHello "Hello, world!" +// #define MacrosYear 2010 +//+------------------------------------------------------------------+ +//| DLL imports | +//+------------------------------------------------------------------+ +// #import "user32.dll" +// int SendMessageA(int hWnd,int Msg,int wParam,int lParam); +// #import "my_expert.dll" +// int ExpertRecalculate(int wParam,int lParam); +// #import +//+------------------------------------------------------------------+ +//| EX5 imports | +//+------------------------------------------------------------------+ +// #import "stdlib.ex5" +// string ErrorDescription(int error_code); +// #import +//+------------------------------------------------------------------+ +#include "Zone.mqh" +#include "ZoneContainer.mqh" + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class MarketObserverTiger + { + // THIS CLASS HAS ACCESS TO ZONE CONTAINER, HOWEVER IT MUST NOT CHANGE IT IT ONLY READS FROM THE ZONECONTAINER CLASS +private: + + + +public: + MarketObserverTiger(); + ~MarketObserverTiger(); + + string zoneReached(); + bool candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& resistanceZoneContainer); // the index is a specific zone from the zones container + bool candleClosedBelowSupportByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& supportZoneContainer); // the index is a specific zone from the zones container + + + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +MarketObserverTiger::MarketObserverTiger() + { + + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +MarketObserverTiger::~MarketObserverTiger() + { + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool MarketObserverTiger:: candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& resistanceZoneContainer) + { + + double previousCandleClose = iClose(_Symbol,tf,1); + + if((previousCandleClose > resistanceZoneContainer.getZoneByIndex(_index).getHigherEdge())) + { + + return true ; + } + + return false ; + } + + + +bool MarketObserverTiger:: candleClosedBelowSupportByIndex(int _index, ENUM_TIMEFRAMES tf, ZoneContainer& supportZoneContainer){ + + + double previousCandleClose = iClose(_Symbol,tf,1); + if(previousCandleClose < supportZoneContainer.getZoneByIndex(_index).getLowerEdge()){ + return true ; + } + + return false ; +} diff --git a/shark_tiger/NewCandleDetector.mqh b/shark_tiger/NewCandleDetector.mqh new file mode 100644 index 0000000..678a7b4 --- /dev/null +++ b/shark_tiger/NewCandleDetector.mqh @@ -0,0 +1,378 @@ +//+------------------------------------------------------------------+ +//| NewCandleDetector.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class NewCandleDetector + { +private: + string timeFrame ; + datetime beginDate ; // this datetime gets initialized only after the first call of the isNewCandle() function + MqlDateTime currTimeStruct; + MqlDateTime beginDateStruct; + bool firstCallHappened; +public: + NewCandleDetector(string _timeFrame); + + ~NewCandleDetector(); + + // GETTERS + datetime getBeginDate() {return beginDate;} + + void setTimeFrame(string _timeFrame) {timeFrame = _timeFrame;} + bool isNewCandle(); + + }; +//+------------------------------------------------------------------+ + +NewCandleDetector::NewCandleDetector(string _timeFrame) + { + + timeFrame = _timeFrame ; + firstCallHappened = false; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +NewCandleDetector::~NewCandleDetector() + { + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool NewCandleDetector:: isNewCandle() + { + + + + if(timeFrame == "PERIOD_M1") + { + + if(firstCallHappened == false) + { + + beginDate = iTime(_Symbol,PERIOD_M1,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_M1,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.min == currTimeStruct.min) + { + + return false; + } + else + { + //Print("in a new candle !, asset: " + _Symbol); + beginDate = currTime; + return true ; + + } + } + + + + } + else + if(timeFrame == "PERIOD_M2") + { + + } + + else + if(timeFrame == "PERIOD_M3") + { + + } + else + if(timeFrame == "PERIOD_M4") + { + + } + else + if(timeFrame == "PERIOD_M5") + { + + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_M5,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_M5,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.min == currTimeStruct.min) + { + + return false; + } + else + { + Print("in a new candle !, asset: " + _Symbol); + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_M6") + { + + } + else + if(timeFrame == "PERIOD_M10") + { + + } + else + if(timeFrame == "PERIOD_M12") + { + + } + else + if(timeFrame == "PERIOD_M15") + { + + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_M15,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_M15,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.min == currTimeStruct.min) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_M20") + { + + } + else + if(timeFrame == "PERIOD_M30") + { + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_M30,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_M30,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.min == currTimeStruct.min) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + } + else + if(timeFrame == "PERIOD_H1") + { + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_H1,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_H1,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.hour == currTimeStruct.hour) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_H2") + { + + } + else + if(timeFrame == "PERIOD_H3") + { + + } + else + if(timeFrame == "PERIOD_H4") + { + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_H4,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_H4,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.hour == currTimeStruct.hour) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + } + else + if(timeFrame == "PERIOD_H6") + { + + } + else + if(timeFrame == "PERIOD_H8") + { + + } + else + if(timeFrame == "PERIOD_H12") + { + + } + else + if(timeFrame == "PERIOD_D1") + { + + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_D1,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_D1,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.day == currTimeStruct.day) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_W1") + { + + + if(firstCallHappened == false) + { + beginDate = iTime(_Symbol,PERIOD_W1,0); + firstCallHappened = true; + } + + if(firstCallHappened == true) + { + datetime currTime = iTime(_Symbol,PERIOD_W1,0); + TimeToStruct(beginDate,beginDateStruct); + TimeToStruct(currTime,currTimeStruct); + + if(beginDateStruct.day == currTimeStruct.day) + { + + return false; + } + else + { + + beginDate = currTime; + return true ; + + } + } + + } + else + if(timeFrame == "PERIOD_MN1") + { + + } + + + + return true; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/shark_tiger/NewGenTest.ex5 b/shark_tiger/NewGenTest.ex5 new file mode 100644 index 0000000..26600d1 Binary files /dev/null and b/shark_tiger/NewGenTest.ex5 differ diff --git a/shark_tiger/NewGenTest.mq5 b/shark_tiger/NewGenTest.mq5 new file mode 100644 index 0000000..49d1571 --- /dev/null +++ b/shark_tiger/NewGenTest.mq5 @@ -0,0 +1,1643 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +//input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTALS DATA + +//input int leftPeriod; +//input int rightPeriod; +//input int weekPeriodToInitialize; +//input int initFractalsPeriod ; +//int lowFractalIndex ; +//int highFractalIndex ; +//#include "LowFractal.mqh" +//#include "HighFractal.mqh" +//#include "LowFractalContainer.mqh" +//#include "HighFractalContainer.mqh" + + + +#property script_show_inputs + +input datetime InpStartTime = __DATETIME__; +input bool REJECTION_M1_ONLY ; + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" + + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" +#include "LotSizeCalculator.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + +// Telegram Connection include +#include + +// SCRIPTS INCLUDES + + + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +// NEW CANDLE CLASSES INITIALIZATION +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + +bool telegramTested = false ; +input bool testTelegram ; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +// Added because bmp files seem to have stopped working, possibly a file format issue +//fileType = "png"; +//fileName = "MyScreenshot." + fileType; + + + if(telegramTested == false && testTelegram == true) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"This is just a test ! " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + telegramTested = true ; + } + + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + + + + + /* if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } */ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + + //lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + //highFractalIndex = rightPeriod+1; // this is used for the fractals + //initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + //initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + /*if(newCandleDetector_M1.isNewCandle()) + { + + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + }*/ + + + if(REJECTION_M1_ONLY == true) + { + if(newCandleDetector_M1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + Print("Im in new candle !"); + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + } + } + else + { + + if(newCandleDetector_H1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + handleBuys(PERIOD_H1); + handleSells(PERIOD_H1); + } + + } + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + Print("Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol); + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + Print(" Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + Print("Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + Print("A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + Print("A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + Print("Bullish candle closed inside the resistance zone on " + _Symbol); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + Print("Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + Print("Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + Print("Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + Print("A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + Print("A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/ObjectConfirmationUnit.mqh b/shark_tiger/ObjectConfirmationUnit.mqh new file mode 100644 index 0000000..7ffdd76 --- /dev/null +++ b/shark_tiger/ObjectConfirmationUnit.mqh @@ -0,0 +1,50 @@ +//+------------------------------------------------------------------+ +//| ObjectConfirmationUnit.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +/* + This class is responsible for all the proccess of confirming a new object. it prevents adding new objects if the previous was not confirmed. +*/ + +class ObjectConfirmationUnit + { +private: + string confirmationObjectID ; + string objectType ; + bool waitingToBeConfirmed ; + + +public: + ObjectConfirmationUnit(); + ~ObjectConfirmationUnit(); + + // GETTERS + string getObjectType(){ return objectType ;} + bool getWaitingStatus(){ return waitingToBeConfirmed ;} + string getConfirmationObjectId(){return confirmationObjectID;} + + // SETTERS + void setObjectType(string _type){ objectType = _type ;} + void setWaitingStatus(bool _waitStatus){ waitingToBeConfirmed = _waitStatus ;} + void setConfirmationObjectId(int _Id){ confirmationObjectID = IntegerToString(_Id) ;} + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +ObjectConfirmationUnit::ObjectConfirmationUnit() + { + waitingToBeConfirmed = false ; // initialize with false value + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +ObjectConfirmationUnit::~ObjectConfirmationUnit() + { + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/Phoenix_Functions.mqh b/shark_tiger/Phoenix_Functions.mqh new file mode 100644 index 0000000..ba50e5c --- /dev/null +++ b/shark_tiger/Phoenix_Functions.mqh @@ -0,0 +1,618 @@ +//+------------------------------------------------------------------+ +//| Phoenix_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 "Range Related Variables" +//input double rangeDistanceBetweenZones ; +//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 group "Zone TimeFrames" +//input bool APPLY_M30_STRUCTURE ; +//input bool APPLY_H1_STRUCTURE; + + + +//input group "Candle Body Variables" +//input double WICK_RATIO_REJECTION; +//input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables 2" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; +input bool BUYS_ALLOWED = true ; +input bool SELLS_ALLOWED = true ; +input double lotSize ; +input int riskManagementCandlesCount ; +input double rrFactor ; +input bool APPLY_TRAIL ; +input ENUM_TIMEFRAMES TRAIL_TIME_FRAME ; + + +//input group "Trading Sessions" +//input bool TRADE_NEW_YORK_ALLOWED = true ; +//input bool TRADE_LONDON_ALLOWED = true ; + +input group "Fractal Related Variables" +//input int leftFractalPeriod ; +//input int rightFractalPeriod ; +input ENUM_TIMEFRAMES TIME_FRAME_TO_TRADE; +input int fractalsPeriod ; +input int stopLossFractalsPeriod ; +input ENUM_TIMEFRAMES stopLossTimeFrame ; + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); + + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserverTiger* marketObserverTiger = new MarketObserverTiger(); + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +NewCandleDetector newCandleDetectorWeekly("PERIOD_W1"); +NewCandleDetector newCandleDetectorDaily("PERIOD_D1"); +NewCandleDetector newCandleDetectorH4("PERIOD_H4"); +NewCandleDetector newCandleDetectorH1("PERIOD_H1"); +NewCandleDetector newCandleDetectorM30("PERIOD_M30"); +NewCandleDetector newCandleDetectorM15("PERIOD_M15"); +NewCandleDetector newCandleDetectorM5("PERIOD_M5"); +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 waitForBottomWick = false ; +bool bottomWickFormed = false; +bool topWickFormed = false; +bool waitForTopWick = false ; + + +double currentResistanceHighEdge = -1 ; +double currentResistanceLowEdge = -1 ; +double currentSupportHighEdge = -1 ; +double currentSupportLowerEdge = -1; + + +double currentSupportZonePrice ; +double currentResistanceZonePrice; + +int indexToNewTrade ; + + +// DATA STRUCTURES + +double lastLowFractalPrice ; +double lastHighFractalPrice ; + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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_M30 = rangeDistanceBetweenZones_M30 * Point(); + +double maxPipsRiskAmountActual = maxPipsRiskAmount * Point(); + +double firstPartialProfitInPipsActual = firstPartialProfitInPips * Point(); + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double detectSupportFromLastLowFractal(int _index) + { + double lastLowestSupportPrice = 99999; + for(int i= _index ; i > 1 ; i--) + { + if((candleClosedBearish(PERIOD_CURRENT,i) && candleClosedBullish(PERIOD_CURRENT,i-1))|| (candleClosedBearish(PERIOD_CURRENT,i) && candleClosedDoji(PERIOD_CURRENT,i-1))) + { + if(iClose(_Symbol,PERIOD_CURRENT,i) < lastLowestSupportPrice) + { + lastLowestSupportPrice = iClose(_Symbol,PERIOD_CURRENT,i); + + } + } + } + + return lastLowestSupportPrice ; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double detectResistanceFromLastHighFractal(int _index) + { + + + double lastHighestResistancePrice = -1; + for(int i= _index ; i > 1 ; i--) + { + if((candleClosedBullish(PERIOD_CURRENT,i) && candleClosedBearish(PERIOD_CURRENT,i-1))|| (candleClosedBullish(PERIOD_CURRENT,i) && candleClosedDoji(PERIOD_CURRENT,i-1))) + { + if(iClose(_Symbol,PERIOD_CURRENT,i) > lastHighestResistancePrice) + { + lastHighestResistancePrice = iClose(_Symbol,PERIOD_CURRENT,i); + + } + } + } + + return lastHighestResistancePrice ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void findAndDrawFractalsAndZones(ENUM_TIMEFRAMES _timeFrame, string _timeFrameStr) + { + if(isLowFractalByIndex(fractalsPeriod+1,fractalsPeriod,fractalsPeriod,_timeFrame)) // SUPPORTS + { + objectsManager.drawLowFractal(fractalsPeriod+1,clrRed); + lastLowFractalPrice = iLow(_Symbol,PERIOD_CURRENT,fractalsPeriod+1); + currentSupportZonePrice = detectSupportFromLastLowFractal(fractalsPeriod+5); + + datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,fractalsPeriod+1); + datetime _rightEdge =rightEdge; + double _higherEdgePrice = currentSupportZonePrice + supportHigherEdgeExtendActual; + double _lowerEdgePrice = currentSupportZonePrice - supportExtendBelowCandleActual; + + currentSupportLowerEdge = _lowerEdgePrice; + currentSupportHighEdge = _higherEdgePrice ; + + Zone* supportZoneObject = new Zone("support_zone",_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,_timeFrameStr,"TYPE_SUPPORT_BREAKOUT"); + objectsManager.drawRectangleInStrategyTester(1,_leftEdge,_rightEdge,_higherEdgePrice,_lowerEdgePrice,clrAliceBlue); + + if(candleClosedBelowSupportZone(_timeFrame)) + { + Comment("Im taking a sell !"); + if(((indexToNewTrade = findAvailableSpotInSellManagerArr())!= -1)) + { + + + double stopLossPrice ; + if(currentResistanceHighEdge != -1) + { + // stopLossPrice = currentResistanceHighEdge + stopLossAboveWickByActual ; + stopLossPrice = lastHighFractalPrice + stopLossAboveWickByActual; + } + //stopLossPrice = iHigh(_Symbol,_timeFrame,1) + stopLossAboveWickByActual; + + if(stopLossIsValidSells(stopLossPrice,maxPipsRiskAmountActual)) + { + double stopLossInPips = stopLossPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID) ; + double netTp = rrFactor * stopLossInPips ; + double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_BID)- netTp) ; + + SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger + + tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge); + tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge); + SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array + + sellsCount++; + } + else + { + Print("stop loss is not valid sells!"); + } + + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + currentSupportLowerEdge = -1; + currentSupportHighEdge = -1 ; + } + + + + } + + if(isHighFractalByIndex(fractalsPeriod+1,fractalsPeriod,fractalsPeriod,_timeFrame)) // RESISTANCES + { + objectsManager.drawHighFractal(fractalsPeriod+1,clrAliceBlue); + lastHighFractalPrice = iHigh(_Symbol,PERIOD_CURRENT,fractalsPeriod+1); + currentResistanceZonePrice = detectResistanceFromLastHighFractal(fractalsPeriod+5); + + datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,fractalsPeriod+1); + datetime _rightEdge =rightEdge; + double _higherEdgePrice = currentResistanceZonePrice + resistanceExtendAboveCandleActual; + double _lowerEdgePrice = currentResistanceZonePrice - resistanceLowerEdgeExtendActual; + + currentResistanceHighEdge = _higherEdgePrice; + currentResistanceLowEdge = _lowerEdgePrice; + Zone* supportZoneObject = new Zone("resistance_zone",_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,_timeFrameStr,"TYPE_RESISTANCE_BREAKOUT"); + objectsManager.drawRectangleInStrategyTester(2,_leftEdge,_rightEdge,_higherEdgePrice,_lowerEdgePrice,clrAliceBlue); + + if(candleClosedAboveResistanceZone(_timeFrame)) + { + Comment("Im taking a buy !"); + + if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1)) + { + + Print("indexToNewTrade:--------------------------------------- " + indexToNewTrade); + double stopLossPrice ; + if(currentSupportLowerEdge != -1) + { + // stopLossPrice = currentSupportLowerEdge - stopLossUnderWickByActual ; + stopLossPrice = lastLowFractalPrice - stopLossUnderWickByActual ; + } + + //stopLossPrice = iLow(_Symbol,_timeFrame,1) - stopLossUnderWickByActual; // if there is no lower zone , take the last m30 candle's low + + if(stopLossIsValidBuys(stopLossPrice,maxPipsRiskAmountActual)) + { + double stopLossInPips = SymbolInfoDouble(_Symbol,SYMBOL_ASK) - stopLossPrice ; + double netTp = rrFactor * stopLossInPips ; + double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+ netTp) ; + + BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger + tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge); + tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge); + BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array + + buysCount++; + } + else + { + Print("stop loss is not valid buys !"); + } + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + currentResistanceHighEdge = -1; + currentResistanceLowEdge = -1 ; + } + + } + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBelowSupportZone(ENUM_TIMEFRAMES _timeFrame) + { + if(candleClosedBearish(_timeFrame,1) && (iClose(_Symbol,_timeFrame,1) < currentSupportLowerEdge) && (currentSupportLowerEdge != -1) && (currentSupportZonePrice != 99999)) + { + return true ; + } + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedAboveResistanceZone(ENUM_TIMEFRAMES _timeFrame) + { + + if(candleClosedBullish(_timeFrame,1) && (iClose(_Symbol,_timeFrame,1) > currentResistanceHighEdge) && (currentResistanceHighEdge != -1) && (currentResistanceZonePrice != 0)) + { + + return true ; + } + return false ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 BuyActiveTradesArray[i].getBrokenResistanceHigherEdge()) + { + BuyActiveTradesArray[i].setRiskManagementCandleCounter(0); + } + + if(BuyActiveTradesArray[i].getRiskManagementCandleCounter() >= riskManagementCandlesCount) + { + // Close the trade + tradeLong.PositionClose(BuyActiveTradesArray[i].getTradeId()); + } + } + + + + + if(SellActiveTradesArray[i] != NULL) + { + if(candleClosedBullish(PERIOD_M5,1) && (iClose(_Symbol,PERIOD_M5,1) > SellActiveTradesArray[i].getBrokenSupportHigherEdge())) + { + SellActiveTradesArray[i].incrementRiskManagementCandleCoutner(); + + } + else + if((iClose(_Symbol,PERIOD_M5,1)) < SellActiveTradesArray[i].getBrokenSupportLowerEdge()) + { + SellActiveTradesArray[i].setRiskManagementCandleCounter(0); + } + + if(SellActiveTradesArray[i].getRiskManagementCandleCounter() >= riskManagementCandlesCount) + { + // Close the trade + tradeShort.PositionClose(SellActiveTradesArray[i].getTradeId()); + } + } + } + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double calculateStopLossBasedOnFractalsBuys(int _fractalsPeriod, ENUM_TIMEFRAMES _timeFrame) + { + + + + for(int i=0 ; 300 ; i++) // scan the last 200 candles + { + if(isLowFractalByIndex(i,_fractalsPeriod,_fractalsPeriod,_timeFrame)) + { + + return iLow(_Symbol,_timeFrame,i); + } + } + + return -1 ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double calculateStopLossBasedOnFractalsSells(int _fractalsPeriod,ENUM_TIMEFRAMES _timeFrame) + { + for(int i=0 ; 300 ; i++) // scan the last 200 candles + { + if(isHighFractalByIndex(i,_fractalsPeriod,_fractalsPeriod,_timeFrame)) + { + return iHigh(_Symbol,_timeFrame,i); + } + } + + return -1 ; + } +//+------------------------------------------------------------------+ + + +void trailAllOpenPositionsIfNeeded(ENUM_TIMEFRAMES _timeFrame) + { + + for(int i=0 ; i< NUM_MAX_ALLOWED_TRADES ; i++) // CHECK TRAIL FOR BUYS + { + if((BuyActiveTradesArray[i] != NULL)) + { + double newStopLoss = iLow(_Symbol,_timeFrame,1); + newStopLoss = newStopLoss - stopLossUnderWickByActual ; + if(newStopLoss > 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); + } + } + + + } + } \ No newline at end of file diff --git a/shark_tiger/Phoenix_Reborn.ex5 b/shark_tiger/Phoenix_Reborn.ex5 new file mode 100644 index 0000000..fb05022 Binary files /dev/null and b/shark_tiger/Phoenix_Reborn.ex5 differ diff --git a/shark_tiger/Phoenix_Reborn.mq5 b/shark_tiger/Phoenix_Reborn.mq5 new file mode 100644 index 0000000..6f1cb9b --- /dev/null +++ b/shark_tiger/Phoenix_Reborn.mq5 @@ -0,0 +1,201 @@ +//+------------------------------------------------------------------+ +//| Phoenix_Reborn.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include "Phoenix_Functions.mqh" + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + + + + +int OnInit() + { +//--- + +//--- + iOpen(_Symbol,PERIOD_M5,1); + iOpen(_Symbol,PERIOD_M15,1); + iOpen(_Symbol,PERIOD_M30,1); + iOpen(_Symbol,PERIOD_H1,1); + iOpen(_Symbol,PERIOD_H4,1); + + for(int i=0; i + + + +// SCRIPTS INCLUDES +//#include "Telegram_Exporter.mq5" + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + +// TRADE RELATED CLASSES INITIALIZATION +//BuyEntryManager* buyEntryManager = new BuyEntryManager(); +//BuyTradeManager* buyTradeManager = new BuyTradeManager(); + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +//SellEntryManager* sellEntryManager = new SellEntryManager(); +//SellTradeManager* sellTradeManager = new SellTradeManager(); + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + +// NEW CANDLE CLASSES INITIALIZATION + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*NewCandleDetector* newCandleDetectorM1 = new NewCandleDetector("PERIOD_M1"); +NewCandleDetector* newCandleDetectorM5 = new NewCandleDetector("PERIOD_M5"); +NewCandleDetector* newCandleDetectorM15 = new NewCandleDetector("PERIOD_M15"); +NewCandleDetector* newCandleDetectorM30 = new NewCandleDetector("PERIOD_M30"); +NewCandleDetector* newCandleDetectorH1 = new NewCandleDetector("PERIOD_H1"); +NewCandleDetector* newCandleDetectorH4 = new NewCandleDetector("PERIOD_H4"); +NewCandleDetector* newCandleDetectorD1 = new NewCandleDetector("PERIOD_D1"); */ + + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + +NewCandleDetector* newCandleDetectorTest ; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + +input datetime zoneLeftEdge ; +input double zoneHighEdge; +input double zoneLowEdge; +input double stopLosssPrice; +input double takeProfittPrice ; +input double takeProfittPrice2; + + + +//#property copyright "Copyright 2022, Orchard Forex" +//#property link "https://www.orchardforex.com" + +//#property script_show_inputs +//#property script_show_confirm + +//const string TelegramBotToken = "6245008777:AAHfUg-t4vhPPX6MioVSaZYB2Hc_QCm4acI"; +//const string ChatId = "-1001943701147"; +//const string TelegramApiUrl = "https://api.telegram.org"; // Add this to Allow URLs + +//const int UrlDefinedErrorMt4 = 4066 ; // this url defined error is for MT4 +//const int UrlDefinedError = 4014; // Because MT4 and MT5 are different + + + + +// VARIABLES FOR TELEGRAM PUBLISHER +//string fileType ; +//string fileName; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + + + objectsManager.drawRectangleInStrategyTester(1,iTime(Symbol(),PERIOD_CURRENT,130),iTime(Symbol(),PERIOD_CURRENT,0),zoneHighEdge,zoneLowEdge); + zoneContainer.incrementZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(zoneHighEdge); + newZone.setLowerEdgePrice(zoneLowEdge); + newZone.setLeftEdge(iTime(Symbol(),PERIOD_CURRENT,130)); + newZone.setRightEdge(iTime(Symbol(),PERIOD_CURRENT,0)); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(getChartTimeFrameInString()); + + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(zoneHighEdge < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(zoneLowEdge > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } +// add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + newZone.setStopLossPrice(stopLosssPrice); + newZone.setTakeProfit(takeProfittPrice); + newZone.setTakeProfit(takeProfittPrice2); + + newZone.printTradeManagerData(); + zoneContainer.printZonesSortedArray(); + +// ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + /*if(newCandleDetector_M1.isNewCandle()) + { + + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + }*/ + + + if(newCandleDetector_H1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + handleBuys(PERIOD_H1); + handleSells(PERIOD_H1); + } + + + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bearish candle closed inside the closest support zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bullish candle closed inside the resistance zone on " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+----------------------- diff --git a/shark_tiger/SellEntryManager.mqh b/shark_tiger/SellEntryManager.mqh new file mode 100644 index 0000000..85f3e8d --- /dev/null +++ b/shark_tiger/SellEntryManager.mqh @@ -0,0 +1,119 @@ +//+------------------------------------------------------------------+ +//| SellEntryManager.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include "SellRejectionDetector.mqh" +#include + + + + + +CTrade tradeShort ; + +class SellEntryManager + { +private: + + bool shortTradeTaken ; + bool waitingForRejectionCandle ; + bool waitingForRetracement ; + bool liquiditySweepEntryTaken ; + +public: + SellEntryManager(); + ~SellEntryManager(); + + SellRejectionDetector* sellRejectionDetector ; + + bool isWaitingForRejectionCandle(){return waitingForRejectionCandle ;} + void setWaitingForRejectionCandle(bool _setting){waitingForRejectionCandle = _setting ; } + + bool isWaitingForRetracement(){return waitingForRetracement;} + void setWaitingForRetracement(bool _setting){waitingForRetracement = _setting ;} + + + bool sellTradeTaken(); + void setTradeTakenStatus(bool _status){shortTradeTaken = _status ;} + + bool liqEntryIsTaken(){return liquiditySweepEntryTaken;} + void setLiquiditySweepEntryTaken(bool _entryStatus){liquiditySweepEntryTaken = _entryStatus ;} + + + + + ulong takeSellTrade(double _lots,double _stopLoss); + ulong takeSellTradeTiger(double _lots, double _stopLoss, double _takeProfit); + ulong takeSellTradeTiger(double _lots, double _stopLoss); + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellEntryManager::SellEntryManager() + { + + sellRejectionDetector = new SellRejectionDetector(); + shortTradeTaken = false ; + waitingForRejectionCandle = false ; + bool waitingForRetracement = false; + liquiditySweepEntryTaken = false; + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellEntryManager::~SellEntryManager() + { + delete sellRejectionDetector; + } +//+------------------------------------------------------------------+ + +bool SellEntryManager:: sellTradeTaken(){ + + return shortTradeTaken ; +} + +ulong SellEntryManager:: takeSellTrade(double _lots, double _stopLoss){ + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss); + ulong tradeTicket = tradeShort.ResultOrder(); + + Print("Sell entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + + +} + + +ulong SellEntryManager:: takeSellTradeTiger(double _lots, double _stopLoss, double _takeProfit){ + + double netTp = SymbolInfoDouble(_Symbol, SYMBOL_BID); + netTp = netTp - _takeProfit ; + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss,SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTp); + + + ulong tradeTicket = tradeShort.ResultOrder(); + + Print("sELL entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} + + +ulong SellEntryManager:: takeSellTradeTiger(double _lots, double _stopLoss){ + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss); + ulong tradeTicket = tradeShort.ResultOrder(); + Print("sELL entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} \ No newline at end of file diff --git a/shark_tiger/SellGandalf.mqh b/shark_tiger/SellGandalf.mqh new file mode 100644 index 0000000..a1c0560 --- /dev/null +++ b/shark_tiger/SellGandalf.mqh @@ -0,0 +1,79 @@ +//+------------------------------------------------------------------+ +//| SellGandalf.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include + +CTrade tradeShort ; + +class SellGandalf + { +private: + bool shortTradeTaken ; + ulong longTrades[10] ; + +public: + SellGandalf(); + ~SellGandalf(); + + bool sellTradeTaken(); + void setTradeTakenStatus(bool _status){shortTradeTaken = _status ; Print("long trade taken flag has been set to true");} + + + ulong takeSellTrade(double _lots,double _stopLoss); + ulong takeSellTradeGandalf(double _lots,double _stopLoss); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellGandalf::SellGandalf() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellGandalf::~SellGandalf() + { + } +//+------------------------------------------------------------------+ + + +bool SellGandalf:: sellTradeTaken(){ + + +return shortTradeTaken ; +} + + + +ulong SellGandalf:: takeSellTrade(double _lots, double _stopLoss){ + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss); + + ulong tradeTicket = tradeShort.ResultOrder(); + + Print("Sell entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + + +} + + +ulong SellGandalf:: takeSellTradeGandalf(double _lots,double _stopLoss){ + + tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss); + + ulong tradeTicket = tradeShort.ResultOrder(); + + Print("Sell entry manager has taken a trade, ticket: " + tradeTicket); + return tradeTicket; + +} + + diff --git a/shark_tiger/SellRejectionDetector.mqh b/shark_tiger/SellRejectionDetector.mqh new file mode 100644 index 0000000..a51b7f9 --- /dev/null +++ b/shark_tiger/SellRejectionDetector.mqh @@ -0,0 +1,52 @@ +//+------------------------------------------------------------------+ +//| SellRejectionDetector.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class SellRejectionDetector + { +private: + +public: + SellRejectionDetector(); + ~SellRejectionDetector(); + + bool rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame); + bool rejectionByRangeFormed(); + bool rejectionByWicksFormed(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellRejectionDetector::SellRejectionDetector() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellRejectionDetector::~SellRejectionDetector() + { + } +//+------------------------------------------------------------------+ + +bool SellRejectionDetector:: rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame){ + + double rejectionCandleClose = iClose(_Symbol,_timeFrame,1); + double rejectionCandleOpen = iOpen(_Symbol,_timeFrame,1); + double rejectionCandleLow = iLow(_Symbol,_timeFrame,1); + double rejectionCandleLowerWickSize ; + double rejectionCandleBodySize; + + if(rejectionCandleOpen > rejectionCandleClose){ // the previous candle closed bearish + rejectionCandleLowerWickSize = rejectionCandleClose - rejectionCandleLow ; + rejectionCandleBodySize = rejectionCandleOpen - rejectionCandleClose; + if(rejectionCandleBodySize >= rejectionCandleLowerWickSize){ + return true ; + } + + } + return false ; +} \ No newline at end of file diff --git a/shark_tiger/SellTradeManager.mqh b/shark_tiger/SellTradeManager.mqh new file mode 100644 index 0000000..8ab5681 --- /dev/null +++ b/shark_tiger/SellTradeManager.mqh @@ -0,0 +1,586 @@ +//+------------------------------------------------------------------+ +//| SellTradeManager.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//#include +#include +#include +CTrade tradeInTradeManager; + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +class SellTradeManager + { +private: + int tradeId ; + ulong rejectionByOneCandleTradeArray[3]; // index 0 : half the contract , index 1 : quarter of the contract , index 2 : quarter of the contract + + + string firstSecureMethod ; + bool firstSecureMethodFound; + int numberOfTakeProfits ; + bool securedFirstLevelProfit ; + bool securedSecondLevelProfit; + double partialToClose ; + bool isTradeRunning ; + + +public: + SellTradeManager(); + ~SellTradeManager(); + + + void fillRejectionByOneCandleTradeArray(int _index, ulong _id) {rejectionByOneCandleTradeArray[_index] = _id ;} + ulong getRejectionByOneCandleTradeTicket(int _index) {return rejectionByOneCandleTradeArray[_index] ;} + void printRejectionByOneCandleTradeArray(); + + void checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars); + string findFirstSecureMethod(); + + bool reachedProfitRatio(int _indexInArr); + bool closeTrade(int _indexInArr); + bool positionBreakEven(int _indexInArr); + + void addTpAtIndex(int _index, double tpPrice) {tpArray[_index] = tpPrice;} + int countRemainingTakeProfits(); + bool reachedClosestTakeProfit(); + void deleteClosestTp(); + int findClosestTpIndex(); + + void cleanOrderDataStructures(); + + void setTradeRunning(bool _setting) {isTradeRunning = _setting ;} + bool tradeIsRunning() {return isTradeRunning ;} + + double tpArray[3]; + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeManager::SellTradeManager() + { + for(int i=0; i<3; i++) + { + tpArray[i] = -1; + } + securedFirstLevelProfit = false ; + securedSecondLevelProfit = false ; + firstSecureMethodFound = false ; + firstSecureMethod = "NOT_FOUND" ; + partialToClose = -1 ; + isTradeRunning = false ; + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeManager::~SellTradeManager() + { + } + +//+------------------------------------------------------------------+ +void SellTradeManager:: printRejectionByOneCandleTradeArray() + { + + Print("Printing the tickets :"); + for(int i=0 ; i<3 ; i++) + { + Print((int)rejectionByOneCandleTradeArray[i]); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void SellTradeManager:: checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars) + { + + + if(securedFirstLevelProfit == false) // in this case im searching for 2 cases: either RR 1:1.5 , OR reaching the first TP , if any of them happened im gonna close half the order and updatae the remaining stop losses + { + + + if(!firstSecureMethodFound) + { + + firstSecureMethod = findFirstSecureMethod(); + if(firstSecureMethod != "FAILED") + { + firstSecureMethodFound = true ; + } + else + if(firstSecureMethod == "FAILED") + { + Print("Failed to find the first secure method, go check the function : findFirstSecureMehod() !"); + } + + } + + if(firstSecureMethodFound == true) + { + + if(firstSecureMethod == "RATIO_METHOD") + { + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(reachedProfitRatio(0)) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + "If you see this message it means we reached the first secure method, which is ratio method, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName); + if(closeTrade(0)) // close the half + { + + rejectionByOneCandleTradeArray[0] = -1; + Print("Closed Half Of the position due to reaching the first secure Ratio!"); + } + else + { + Print("Failed Closing Half of the order by reaching the first secure Ratio !"); + } + + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(positionBreakEven(1)) // put the first quarter at break even + { + + Print(" First quarter has been put into break even due to reaching the first secure Ratio!"); + } + else + { + Print("Failed to Put the first quarter into break even"); + } + + numberOfTakeProfits = countRemainingTakeProfits(); + + Print("Number of remaining tps is: " + numberOfTakeProfits); + + securedFirstLevelProfit = true ; + } + + + + + + } + else + if(firstSecureMethod == "FIRST_TP_METHOD") + { + if(countRemainingTakeProfits() > 1) // there is at least 2 tp in the tp Array (because if this is the last tp then we want to close the whole order and not just a part of it) + { + if(reachedClosestTakeProfit()) // 2. Check if reached the first Tp + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + "If you see this message it means we reached the first secure method which is tp1, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName); + // close the first half and update remaining partials sl's and delete the closest take profit from the array + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(closeTrade(0)) // close the half + { + + rejectionByOneCandleTradeArray[0] = -1; + Print("Closed Half Of the position due to reaching the first TP!"); + + } + else + { + Print("Failed Closing Half of the order by reaching the first TP !"); + } + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(positionBreakEven(1)) // put the first quarter at break even + { + + Print(" First quarter has been put into break even due to reaching the first TP!"); + } + else + { + Print("Failed to Put the first quarter into break even"); + } + deleteClosestTp(); + numberOfTakeProfits = countRemainingTakeProfits(); // update the number of remaining take profits + // calculate the remaining tps + + Print("Number of remaining tps is: " + numberOfTakeProfits); + + securedFirstLevelProfit = true ; + + + } + } + else + if(numberOfTakeProfits = countRemainingTakeProfits() == 1) + { + if(reachedClosestTakeProfit()) + { + // close everything remained + } + } + } + + } + + + + } + else + if(securedFirstLevelProfit == true) // after securing the first level i just want to close the remaining partials by reaching the tp's + { + + if(countRemainingTakeProfits() == 1) + { + if(reachedClosestTakeProfit()) + { + // close everything + cleanOrderDataStructures(); + for(int i=0 ; i<3 ; i++) + { + closeTrade(i); + } + Print("Closed every thing because price reached the last Take Profit !"); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + "If you see this message it means that all order are closed as a result of reaching the last tp " + TimeToString(TimeLocal()), fileName); + deleteClosestTp(); + } + } + else + if(countRemainingTakeProfits() > 1) + { + if(reachedClosestTakeProfit()) + { + cleanOrderDataStructures(); + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[1])) // DEALING WITH THE FIRST QUARTER + { + double currentLot = PositionGetDouble(POSITION_VOLUME); + if(partialToClose == -1) + { + partialToClose = currentLot/numberOfTakeProfits ; + } + if(tradeInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[1],NormalizeDouble(partialToClose,2))) + { + uint res = tradeInTradeManager.ResultRetcode(); + if(res == 10009) + { + Print("Closed Partials successfully on the first quarter !"); + } + else + { + Print("The returned code is: " + res + " go check what it means !"); + } + + } + } + else + { + Print("Failed to select position by ticket, Error: " + GetLastError()); + Print("The EA tried to close partials on the first quarter, but it is closed, probably due to break even and thats why it couldnt select the order !"); + } + + + cleanOrderDataStructures(); + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[2])) // DEALING WITH THE SECOND QUARTER + { + if(PositionGetDouble(POSITION_SL) > PositionGetDouble(POSITION_PRICE_OPEN)) // this is to put the second quarter at break even if its not already at break even + { + positionBreakEven(2); + + } + double currentLot = PositionGetDouble(POSITION_VOLUME); + if(partialToClose == -1) + { + partialToClose = currentLot/numberOfTakeProfits ; + } + if(tradeInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[2],NormalizeDouble(partialToClose,2))) + { + uint res = tradeInTradeManager.ResultRetcode(); + if(res == 10009) + { + Print("Closed Partials successfully on the second quarter!"); + } + else + { + Print("The returned code is: " + res + " go check what it means !"); + } + + } + + } + deleteClosestTp(); + Print("Number Of Remained tps is: " + countRemainingTakeProfits()); + + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId, + "If you see this message it means we reached a tp level (different than the first secure level), so partial positions will be closed, and the scond quarter must be in break even!" + TimeToString(TimeLocal()), fileName); + } + + } + + + } + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string SellTradeManager:: findFirstSecureMethod() + { + + cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket + if(PositionSelectByTicket(rejectionByOneCandleTradeArray[0])) + { + double positionStopLoss = PositionGetDouble(POSITION_SL); + double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double firstTakeProfit = tpArray[findClosestTpIndex()]; + if(((positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) > firstSecureRatio)) // firstTp > ratio + { + Print("Found the first profit secure method !"); + Print("The first TP RR is: 1:" + (positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) + "the firstSecureRatio is: 1:" + firstSecureRatio); + Print("The tp ratio is greater than the firstSecure so:"); + Print("The first secure method is RATIO_METHOD"); + return"RATIO_METHOD"; + } + else + if((positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice)< firstSecureRatio) + { + Print("Found the first profit secure method !"); + Print("The first TP RR is: 1:" + (positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) + "the firstSecureRatio is: 1:" + firstSecureRatio); + Print("The tp ratio is less than the firstSecure so:"); + Print("The first secure method is FIRST_TP_METHOD"); + return "FIRST_TP_METHOD" ; + } + } + else + { + Print("Failed to select position by ticket 1, Error: " + GetLastError()); + } + + return "FAILED" ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool SellTradeManager:: reachedProfitRatio(int _indexInArr) + { + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) + { + if(PositionGetDouble(POSITION_PROFIT)/(0.5*riskDollars) >= firstSecureRatio) // checking if the first half of the contract reached the ratio of first secure profit + { + Print("reached profit ratio !"); + return true ; + } + } + else + { + Print("Failed to select the position by ticket 4 ,Error: " + GetLastError()); + + } + + } + + return false ; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool SellTradeManager:: closeTrade(int _indexInArr) + { + + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) + { + + // close the first half and update remaining partials sl's + if(tradeInTradeManager.PositionClose(_ticket)) + { + return true ; + + } + else + { + + Print("Failed to close positon, Error:" + GetLastError()); + return false; + } + + } + else + { + + Print("Failed to select position by ticket 2, Error: "+ GetLastError()); + return false; + } + + } + + + return false ; + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool SellTradeManager:: positionBreakEven(int _indexInArr) + { + + ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr]; + if(_ticket != -1) + { + if(PositionSelectByTicket(_ticket)) // select the first quarter + { + double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); + double positionTp = PositionGetDouble(POSITION_TP); + double positionSl = PositionGetDouble(POSITION_SL); + + if(tradeInTradeManager.PositionModify((_ticket),openPrice,positionTp)) + { + + + return true ; + } + else + { + Print("Failed to modify oder , ERROR: " + GetLastError()); + return false ; + } + + } + else + { + Print("Failed to select position by ticket 3"); + return false ; + } + } + + + return false ; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int SellTradeManager:: countRemainingTakeProfits() + { + + int counter = 0 ; + for(int i=0; i<3 ; i++) + { + if(tpArray[i] != -1) + { + counter++ ; + } + } + + return counter; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void SellTradeManager:: deleteClosestTp() + { + + int closestTpIndex =findClosestTpIndex(); + tpArray[closestTpIndex] = -1; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int SellTradeManager:: findClosestTpIndex() + { + int closestTpIndex = 0; + + for(int i=1; i<3; i++) + { + if(tpArray[i] > tpArray[closestTpIndex]) + { + closestTpIndex = i ; + } + } + + return closestTpIndex ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool SellTradeManager:: reachedClosestTakeProfit() + { + + + double closestTakeProfitValue = tpArray[findClosestTpIndex()]; +//Print("im in reached closest take profit function ,the current price is: " + SymbolInfoDouble(_Symbol, SYMBOL_BID) + " and the tp is: " + closestTakeProfitValue); + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= closestTakeProfitValue) // we want the ASK because we are basically buying the asset again (in a cheaper price), and we want to buy it on the ASK (which is the price that a seller is willing to sell us) + { + return true ; + } + return false ; + + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void SellTradeManager:: cleanOrderDataStructures() + { +// this is to make sure, that every closed order is removed from the data strucutre ! + + for(int i=0; i<3; i++) + { + if(!PositionSelectByTicket(rejectionByOneCandleTradeArray[i])) + { + if(GetLastError() == 4753) + { + rejectionByOneCandleTradeArray[i] = -1 ; + } + } + } + + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/SellTradeManagerTiger.mqh b/shark_tiger/SellTradeManagerTiger.mqh new file mode 100644 index 0000000..ce5dfdd --- /dev/null +++ b/shark_tiger/SellTradeManagerTiger.mqh @@ -0,0 +1,69 @@ +//+------------------------------------------------------------------+ +//| SellTradeManagerTiger.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class SellTradeManagerTiger + { +private: + ulong tradeId ; + string entryType ; + bool firstPartialSecured ; + bool secondPartialSecured ; + bool managedRisk ; + int riskManagementCandleCounter ; + double brokenSupportHigherEdge ; + double brokenSupportLowerEdge ; +public: + ulong getTradeId(){return tradeId ;} + + bool riskAlreadyManaged(){return managedRisk ;} + void manageRisk(){managedRisk = true ;} + + bool firstPartialIsSecured(){return firstPartialSecured ;} + void secureFirstPartial(){firstPartialSecured = true ;} + + bool retestWickFormed ; + double retestWickLengthInPips ; + + void setBrokenSupportHigherEdge(double _brokenSupportHigherEdge){brokenSupportHigherEdge = _brokenSupportHigherEdge ;} + void setBrokenSupportLowerEdge(double _brokenSupportLowerEdge){brokenSupportLowerEdge = _brokenSupportLowerEdge ;} + + double getBrokenSupportHigherEdge(){return brokenSupportHigherEdge ;} + double getBrokenSupportLowerEdge(){return brokenSupportLowerEdge;} + + void incrementRiskManagementCandleCoutner(){riskManagementCandleCounter++ ;} + void decrementRiskManagementCandleCounter(){riskManagementCandleCounter-- ;} + + int getRiskManagementCandleCounter(){return riskManagementCandleCounter ;} + void setRiskManagementCandleCounter(int count){ riskManagementCandleCounter = count ;} + + + SellTradeManagerTiger(ulong _tradeId); + ~SellTradeManagerTiger(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeManagerTiger::SellTradeManagerTiger(ulong _tradeId) + { + + tradeId = _tradeId ; + firstPartialSecured = false ; + secondPartialSecured = false ; + managedRisk = false ; + + retestWickFormed = false ; + retestWickLengthInPips = 0 ; + riskManagementCandleCounter = 0 ; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeManagerTiger::~SellTradeManagerTiger() + { + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/SellTradeMangerTiger.mqh b/shark_tiger/SellTradeMangerTiger.mqh new file mode 100644 index 0000000..0a82a3b --- /dev/null +++ b/shark_tiger/SellTradeMangerTiger.mqh @@ -0,0 +1,29 @@ +//+------------------------------------------------------------------+ +//| SellTradeMangerTiger.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class SellTradeMangerTiger + { +private: + +public: + SellTradeMangerTiger(); + ~SellTradeMangerTiger(); + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeMangerTiger::SellTradeMangerTiger() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +SellTradeMangerTiger::~SellTradeMangerTiger() + { + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/Shark.mq5 b/shark_tiger/Shark.mq5 new file mode 100644 index 0000000..1074547 --- /dev/null +++ b/shark_tiger/Shark.mq5 @@ -0,0 +1,846 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTAL VARIABLES INITIALIZATION + +input int leftPeriod; +input int rightPeriod; +input int weekPeriodToInitialize; +input int initFractalsPeriod ; +int lowFractalIndex ; +int highFractalIndex ; + + + + +// GUI CLASSES INCLUDES +#include "ZoneContainer.mqh" +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "LowFractal.mqh" +#include "HighFractal.mqh" +#include "LowFractalContainer.mqh" +#include "HighFractalContainer.mqh" + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" + +// LIBRARIES INCLUDES +#include + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer zoneContainer ; +LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + + + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// NEW CANDLE CLASSES INITIALIZATION + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*NewCandleDetector* newCandleDetectorM1 = new NewCandleDetector("PERIOD_M1"); +NewCandleDetector* newCandleDetectorM5 = new NewCandleDetector("PERIOD_M5"); +NewCandleDetector* newCandleDetectorM15 = new NewCandleDetector("PERIOD_M15"); +NewCandleDetector* newCandleDetectorM30 = new NewCandleDetector("PERIOD_M30"); +NewCandleDetector* newCandleDetectorH1 = new NewCandleDetector("PERIOD_H1"); +NewCandleDetector* newCandleDetectorH4 = new NewCandleDetector("PERIOD_H4"); +NewCandleDetector* newCandleDetectorD1 = new NewCandleDetector("PERIOD_D1"); */ + + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + //Print("the ask is: " + SymbolInfoDouble(_Symbol, SYMBOL_ASK)); + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + + // INIT FRACTAL VARIABLES + lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + highFractalIndex = rightPeriod+1; // this is used for the fractals + initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + + + if(newCandleDetectorLive.isNewCandle()) + { + handleLowFractals(inputTimeFrameFractals); // scans low fractals that are forming and adds them to the container + handleHighFractals(inputTimeFrameFractals); // scans high fractals that are forming and adds them to the container + } + + + + + + + + + + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + if(tempObjectAttr.getHigherEdgePrice() < SymbolInfoDouble(_Symbol, SYMBOL_ASK) ){ // means its a support zone + newZone.setType("TYPE_SUPPORT"); + } + if(tempObjectAttr.getLowerEdgePrice() > SymbolInfoDouble(_Symbol, SYMBOL_ASK)){ // means its a resistance zone + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdges(); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + } + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { // delete from data structure + zoneContainer.findOrUpdatePivotEdges(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else{ + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + delete lowsContainer; + delete highsContainer; + + delete newCandleDetectorLive; + zoneContainer.freeZonesSortedArray(); + /*delete newCandleDetectorD1; + delete newCandleDetectorM5; + delete newCandleDetectorM30; + delete newCandleDetectorM15; + delete newCandleDetectorM1; + delete newCandleDetectorH4; + delete newCandleDetectorH1; */ + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print("High Fractals:"); + highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + else // THIS is the case were we click on any object except for the 'Add Zone' and 'Confirm Object' Buttons + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } + + + +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/shark_tiger/Shark_tester.mq5 b/shark_tiger/Shark_tester.mq5 new file mode 100644 index 0000000..d89ba7c --- /dev/null +++ b/shark_tiger/Shark_tester.mq5 @@ -0,0 +1,1191 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTAL VARIABLES INITIALIZATION + +input int leftPeriod; +input int rightPeriod; +input int weekPeriodToInitialize; +input int initFractalsPeriod ; +int lowFractalIndex ; +int highFractalIndex ; + + + + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" +#include "LowFractal.mqh" +#include "HighFractal.mqh" +#include "LowFractalContainer.mqh" +#include "HighFractalContainer.mqh" + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer zoneContainer ; +LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION + MarketObserver marketObserver = new MarketObserver(); + + + +// TRADE RELATED CLASSES INITIALIZATION +BuyEntryManager buyEntryManager = new BuyEntryManager(); +BuyTradeManager buyTradeManager = new BuyTradeManager(); + +SellEntryManager sellEntryManager = new SellEntryManager(); +SellTradeManager sellTradeManager = new SellTradeManager(); + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + +// NEW CANDLE CLASSES INITIALIZATION + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*NewCandleDetector* newCandleDetectorM1 = new NewCandleDetector("PERIOD_M1"); +NewCandleDetector* newCandleDetectorM5 = new NewCandleDetector("PERIOD_M5"); +NewCandleDetector* newCandleDetectorM15 = new NewCandleDetector("PERIOD_M15"); +NewCandleDetector* newCandleDetectorM30 = new NewCandleDetector("PERIOD_M30"); +NewCandleDetector* newCandleDetectorH1 = new NewCandleDetector("PERIOD_H1"); +NewCandleDetector* newCandleDetectorH4 = new NewCandleDetector("PERIOD_H4"); +NewCandleDetector* newCandleDetectorD1 = new NewCandleDetector("PERIOD_D1"); */ + + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + + + + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +//Print("the ask is: " + SymbolInfoDouble(_Symbol, SYMBOL_ASK)); + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + highFractalIndex = rightPeriod+1; // this is used for the fractals + initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + if(newCandleDetectorLive.isNewCandle()) + { + handleLowFractals(inputTimeFrameFractals); // scans low fractals that are forming and adds them to the container + handleHighFractals(inputTimeFrameFractals); // scans high fractals that are forming and adds them to the container + } + + + + + /* if((priceInMiddle == true) && (buyOnAction == true)){ // THIS CASE MEANS WE ARE IN THE MIDDLE OF TWO ZONES , AND A BUY TRADE IS OPEN + buyTradeManager.handleTrade(); // this is responsible for exiting and taking partials + + if(marketObserver.candleClosedBelowSupportZone(&zoneContainer) == true){ + buyTradeManager.closeTrade(); + + buyOnAction = false ; + + } + else if(marketObserver.zoneReached(&zoneContainer) == "TYPE_RESISTANCE"){ + // close the buy + buyTradeManager.closeTrade(); + + buyOnAction = false ; + sellEntryManager.setLookingForSell(true) ; + } + + } */ + + /*else if((priceInMiddle == true) && (sellOnAction == true)){ // THIS CASE MEANS WE ARE IN THE MIDDLE OF TWO ZONES , AND A SELL TRADE IS OPEN + sellTradeManager.handleTrade();// this is responsible for exiting and taking partials + + if(marketObserver.candleClosedAboveResistanceZone(&zoneContainer) == true){ + sellTradeManager.closeTrade(); + + sellOnAction = false ; + } + else if(marketObserver.zoneReached(&zoneContainer) == "TYPE_SUPPORT"){ + // close the sell + sellTradeManager.closeTrade(); + + sellOnAction = false; + buyEntryManager.setLookingForBuy(true) ; + + } + + } */ + + + + + + if(priceInMiddle == true){ // THIS CASE MEANS WE ARE IN THE MIDDLE OF TWO ZONES , AND NO CURRENT TRADE IS OPEN + if(marketObserver.reachedClosestSupportZone(&zoneContainer)){ // we reached a support zone so looking for buys + Print("Reached a support zone ! i will inform you if a buy confiramtion happens "); + priceInMiddle = false; + buyEntryManager.setLookingForBuy(true) ; + sellEntryManager.setLookingForSell(false); + + + } + else if(marketObserver.reachedClosestResistanceZone(&zoneContainer)){ // we reached resistance zone so looking for sells + Print("Reached a resistance zone ! i will inform you if a sell confirmation happens "); + priceInMiddle = false; + sellEntryManager.setLookingForSell(true) ; + buyEntryManager.setLookingForBuy(false) ; + + } + else{ // we are still in the middle so do nothing + + } + + } + + + + + /*if(buyEntryManager.isLookingForBuy() == true){ + if(marketObserver.candleClosedBelowSupportZone(&zoneContainer) == true){ // trade idea is invalid , so wait the user to confirm the break of the zone + buyEntryManager.setLookingForBuy(false) ; + + } + else if(buyEntryManager.buyTaken() == true ){ + priceInMiddle = true ; + buyOnAction = true ; + buyEntryManager.setLookingForBuy(false) ; + + } + + else if(marketObserver.reachedClosestResistanceZone() == true){ + + buyEntryManager.setLookingForBuy(false); + } + } */ + + + + /*if(sellEntryManager.isLookingForSell() == true){ + if(marketObserver.candleClosedAboveResistanceZone(&zoneContainer) == true){ + sellEntryManager.setLookingForSell(false); + } + else if(sellEntryManager.sellTaken() == true){ + priceInMiddle = true ; + sellOnAction = true ; + sellEntryManager.setLookingForSell(false) ; + + } + } */ + + + + + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + if(tempObjectAttr.getHigherEdgePrice() < SymbolInfoDouble(_Symbol, SYMBOL_ASK)) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + if(tempObjectAttr.getLowerEdgePrice() > SymbolInfoDouble(_Symbol, SYMBOL_ASK)) // means its a resistance zone + { + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdges(); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdges(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + delete lowsContainer; + delete highsContainer; + + delete newCandleDetectorLive; + zoneContainer.freeZonesSortedArray(); + /*delete newCandleDetectorD1; + delete newCandleDetectorM5; + delete newCandleDetectorM30; + delete newCandleDetectorM15; + delete newCandleDetectorM1; + delete newCandleDetectorH4; + delete newCandleDetectorH1; */ + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print("High Fractals:"); + highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else if(sparam == "SET_TP_BTN"){ + if(objectConfUnit.getObjectType() != "OBJ_HLINE"){ + Print("Please select a TP line first !"); + + } + else{ + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())){ + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else{ + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } + + + +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/shark_tiger/TempLineObjectAttributes.mqh b/shark_tiger/TempLineObjectAttributes.mqh new file mode 100644 index 0000000..c878c48 --- /dev/null +++ b/shark_tiger/TempLineObjectAttributes.mqh @@ -0,0 +1,40 @@ +//+------------------------------------------------------------------+ +//| TempLineObjectAttributes.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class TempLineObjectAttributes + { +private: + + string id ; + double price ; + +public: + TempLineObjectAttributes(); + ~TempLineObjectAttributes(); + + // GETTERS + string getId(){return id;} + double getPrice(){return price ;} + + // SETTERS + void setId(string _id){id =_id ;} + void setPrice(double _price){price = _price ;} + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +TempLineObjectAttributes::TempLineObjectAttributes() + { + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +TempLineObjectAttributes::~TempLineObjectAttributes() + { + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/TempObjectAttributes.mqh b/shark_tiger/TempObjectAttributes.mqh new file mode 100644 index 0000000..99949d1 --- /dev/null +++ b/shark_tiger/TempObjectAttributes.mqh @@ -0,0 +1,81 @@ +//+------------------------------------------------------------------+ +//| TempObjectAttributes.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +class TempObjectAttributes + { +private: + // ATTRIBUTES FOR A ZONE + string assetName; + string timeFrame ; + double higherEdgePrice ; + double lowerEdgePrice ; + datetime leftEdgeTime ; + datetime rightEdgeTime; + + + // ATTRIBUTES FOR TRENDLINE + + + + // ATTRIBUTES FOR DAILY LINE + + + + // ATTRIBUTES FOR IMBALANCE + + + + // ATTRIBUTES FOR FIBONACCI LEVEL + + + + +public: + TempObjectAttributes(); + ~TempObjectAttributes(); + + // GETTERS FOR ZONE + double getHigherEdgePrice(){return higherEdgePrice;} + double getLowerEdgePrice(){return lowerEdgePrice;} + datetime getLeftEdgeTime(){return leftEdgeTime ;} + datetime getRightEdgeTime(){return rightEdgeTime;} + string getSymbol(){return assetName;} + string getTimeFrame(){return timeFrame;} + + // SETTERS FOR ZONE + void setHigherEdgePrice(double _higherEdgePrice){higherEdgePrice = _higherEdgePrice;} + void setLowerEdgePrice(double _lowerEdgePrice){lowerEdgePrice = _lowerEdgePrice;} + void setLeftEdgeTime(datetime _leftEdgeTime){leftEdgeTime = _leftEdgeTime;} + void setRightEdgeTime(datetime _rightEdgeTime){rightEdgeTime = _rightEdgeTime;} + void setSymbol(){assetName = Symbol();} + void setTimeFrame(string _timeframe){timeFrame = _timeframe;} + // OTHER ZONE FUNCTIONS + + void cleanAttributesZone(){higherEdgePrice = -1; + lowerEdgePrice = -1; + leftEdgeTime = 0; + rightEdgeTime = 0;} + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +TempObjectAttributes::TempObjectAttributes() + { + + higherEdgePrice = -1; + lowerEdgePrice = -1; + leftEdgeTime = 0; + rightEdgeTime = 0; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +TempObjectAttributes::~TempObjectAttributes() + { + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/Tiger.ex5 b/shark_tiger/Tiger.ex5 new file mode 100644 index 0000000..0c85b19 Binary files /dev/null and b/shark_tiger/Tiger.ex5 differ diff --git a/shark_tiger/Tiger.mq5 b/shark_tiger/Tiger.mq5 new file mode 100644 index 0000000..d88c67c --- /dev/null +++ b/shark_tiger/Tiger.mq5 @@ -0,0 +1,601 @@ +//+------------------------------------------------------------------+ +//| Tiger.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include "NewCandleDetector.mqh" +#include "GraphicalObjectsManager.mqh" +#include "Zone.mqh" +#include "ZoneContainer.mqh" + +#include "MarketObserver.mqh" +#include "BuyEntryManager.mqh" +#include "LotSizeCalculator.mqh" +input double rangeDistance ; +input double resistanceExtendAboveCandle; +input double supportExtendBelowCandle ; +input double stopLossLimit ; +double input riskInDollars ; +double input netTakeProfit ; +bool input allowSecondChanceStopLoss ; +double input bottomWickSize ; +double input smallBottomWickSize ; +double input buyStopPipsTrigger ; +bool input MOD_CLEAN = false ; + + +bool waitingForBottomWickToForm = false ; +bool waitingForSmallBottomWickToForm = false ; +bool buyStopValid = false ; +bool closedPartialOnNegativeDirection = false ; +bool securedTenPips = false ; + + +#include + +CTrade tradeTiger ; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; + + + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +NewCandleDetector newCandleDetector("PERIOD_M30"); +BuyEntryManager buyEntryMan ; +LotSizeCalculator lotSizeCalc ; + + +Zone* temporaryRestestSupportZone = new Zone(); +int OnInit() + { +//--- create timer + EventSetTimer(60); + iClose(_Symbol,PERIOD_M15,5); + iClose(_Symbol,PERIOD_H1,5); + + /*datetime d1=D'2023.09.01 00:00:00'; // Year Month Day Hours Minutes Seconds + Print("the dateTime is: " + d1); + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(1930); + newZone.setLowerEdgePrice(1925); + newZone.setLeftEdge(iTime(_Symbol,PERIOD_CURRENT,2)); + newZone.setRightEdge(d1); + newZone.setId("1"); + newZone.setTimeFrame("PERIOD_M30"); + + + zoneContainer.addZone(newZone); + objectsManager.drawRectangleInStrategyTester(1,iTime(_Symbol,PERIOD_CURRENT,2),d1,1930,1925); + zoneContainer.printZonesSortedArray(); */ + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + + if(securedTenPips == false ){ + secureTenPips(0.3); + } + + if(waitingForBottomWickToForm){ + if(iClose(_Symbol,PERIOD_CURRENT,1) - SymbolInfoDouble(_Symbol, SYMBOL_BID) >= bottomWickSize){ + + waitingForBottomWickToForm = false ; + Print("Bottom Wick in length of at least " + bottomWickSize + " was formed !"); + buyStopValid = true ; + + + } + + } + + + + + if(buyStopValid){ + if( SymbolInfoDouble(_Symbol, SYMBOL_ASK) > iHigh(_Symbol,PERIOD_CURRENT,1) + buyStopPipsTrigger){ // here we take a buy entry based on break and retest wick. the Algo will first try to put the stop loss under the low of the temporary support zone + // if that stop loss was too high , then it will put it under the low of the wick that was recently made. (the wick should be at least bottomWickSize which is currently 1) + + double stopLossUnderTemporarySupportZone = temporaryRestestSupportZone.getLowerEdge() - 0.5 ; // under the temporary support zone + double stopLossUnderWick = iLow(_Symbol,PERIOD_CURRENT,0) - 0.5; // the low of the current candle + + if(!((SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossUnderTemporarySupportZone) > stopLossLimit)){ // on this case a wick was formed price starts to break the previous candle high, im taking a buy + //and im putting the stop loss below the whole zone (which is support now) + double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossUnderTemporarySupportZone); + buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossUnderTemporarySupportZone,2); + closedPartialOnNegativeDirection = false ; + securedTenPips = false ; + buyStopValid = false ; + Print("Took a wick retest buy type 1"); + + + } + else if(!((SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossUnderWick) > stopLossLimit)){ // on this case a wick was formed price starts to break the previous candle high, im taking a buy + //and im putting the stop loss below the wick (which is at least bottomWickSize) + + double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossUnderWick); + buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossUnderWick,2); + closedPartialOnNegativeDirection = false ; + securedTenPips = false ; + buyStopValid = false ; + Print("Took a wick retest buy type 2"); + } + } + + } + + if(newCandleDetector.isNewCandle()) + { + + + if(iClose(_Symbol,PERIOD_CURRENT,1) < iOpen(_Symbol,PERIOD_CURRENT,1) && closedPartialOnNegativeDirection == false){ // if the m30 candle closed bearish + closePartialsOfAllTrades(0.5); + closedPartialOnNegativeDirection = true ; + } + + + buyStopValid = false ; + waitingForBottomWickToForm = false ; + bool finishedDeleting = false ; + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + + + if(candleClosedBelowRetestZone(PERIOD_CURRENT)){ + temporaryRestestSupportZone.setType("TYPE_INVALID"); + deleteZoneGuiOnly("999"); + + } + + if(zoneContainer.getNumberOfActiveZones() != 0) // if there are zones found + { + if(marketObserver.candleClosedAboveResistanceByIndex(0,PERIOD_CURRENT)) // check if candle closed above the zone + { + + + datetime _leftEdgeRestestZone = iTime(_Symbol,PERIOD_CURRENT,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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + if(zoneContainer.getNumberOfActiveZones() != 0 && marketObserver.candleClosedAboveResistanceByIndex(0,PERIOD_CURRENT)) + { + 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI + } + else + { + finishedDeleting = true ; + } + + + } + + + + int idAsInt = StringToInteger(temporaryRestestSupportZone.getId()); + + + if((mqldt.hour > 13 && mqldt.hour < 22) || (mqldt.hour > 3 && mqldt.hour < 7) || (mqldt.hour > 8 && mqldt.hour < 12) ) + { + + + double stopLossPrice = iLow(_Symbol,PERIOD_CURRENT,1); + stopLossPrice = stopLossPrice -1; + + double secondChanceStopLossPrice = iLow(_Symbol,PERIOD_M15,1); + secondChanceStopLossPrice = secondChanceStopLossPrice -1; + + if(!(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossPrice > stopLossLimit)) // enter only if the M30 previous candle satisfied the condition of the proper stop loss + { + //Print("Entered here 2!"); + double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossPrice); + buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossPrice,netTakeProfit); + closedPartialOnNegativeDirection = false ; + securedTenPips = false ; + } + else + if(!(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - secondChanceStopLossPrice > stopLossLimit) && secondChanceStopLossPrice < temporaryRestestSupportZone.getLowerEdge() - 0.5) // if the M30 candle failed , then try the M15 candle + { + + if(allowSecondChanceStopLoss == true) + { + + double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,secondChanceStopLossPrice); + buyEntryMan.takeBuyTradeTiger(lotsToEnter,secondChanceStopLossPrice,netTakeProfit); + closedPartialOnNegativeDirection = false ; + securedTenPips = false ; + + } + + + } + + else // both M30 and M15 candles closed too far from the zone, so im gonna wait for retracement , and support to be built on the zone, or a bottom wick to form + { + + objectsManager.drawRectangleInStrategyTester(idAsInt,_leftEdgeRestestZone,_rightEdgeRetestZone, + temporaryRestestSupportZone.getHigherEdge(),temporaryRestestSupportZone.getLowerEdge(),clrGray); + + + waitingForBottomWickToForm = true ; + + + } + + } + + + + } + + } + + + + if(candleClosedBullish(PERIOD_M30,2) && candleClosedBearish(PERIOD_M30,1)) + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,PERIOD_CURRENT,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistance)) + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame("PERIOD_M30"); + newZone.setType("TYPE_RESISTANCE"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,clrBeige); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistance)){ + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame("PERIOD_M30"); + newZone.setType("TYPE_RESISTANCE"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,clrBeige); + //zoneContainer.printZonesSortedArray(); + } + + + + } + + + Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + Print("Zones are : "); + zoneContainer.printZonesSortedArray(); + } + + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool resistanceIsFound() + { + +//if() + + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + zoneContainer.deleteZone(_id); + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + + + void deleteZoneGuiOnly(string _id) + { + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } +//+------------------------------------------------------------------+ + + +bool candleClosedBelowRetestZone(ENUM_TIMEFRAMES tf){ + + + double previousCandleClose = iClose(_Symbol,tf,1); + + if(previousCandleClose < temporaryRestestSupportZone.getLowerEdge() ){ + + return true ; + } + + return false ; +} + + + + +void closePartialsOfAllTrades(double partial){ + for(int i = PositionsTotal()-1 ; i>=0 ; i--){ + ulong posTicket = PositionGetTicket(i); + if(PositionSelectByTicket(posTicket)){ + double positionVolum = PositionGetDouble(POSITION_VOLUME); + double partialToClose = positionVolum * partial ; + tradeTiger.PositionClosePartial(posTicket,NormalizeDouble(partialToClose,2)); + + } + else{ + Print("Failed to select position, Error: " + GetLastError()); + } + + + + } +} + + + +void secureTenPips(double partial){ + + for(int i = PositionsTotal()-1 ; i>=0 ; i--){ + ulong posTicket = PositionGetTicket(i); + if(PositionSelectByTicket(posTicket)){ + double positionVolume = PositionGetDouble(POSITION_VOLUME); + + if((SymbolInfoDouble(_Symbol, SYMBOL_BID) - PositionGetDouble(POSITION_PRICE_OPEN)) > 1){ + double partialToClose = positionVolume * partial ; + tradeTiger.PositionClosePartial(posTicket,NormalizeDouble(partialToClose,2)); + securedTenPips = true ; + Print("secured 10 pips"); + + } + + + } + else{ + Print("Failed to select position, Error: " + GetLastError()); + } + + + + } + +} \ No newline at end of file diff --git a/shark_tiger/TigerEntryTaker.ex5 b/shark_tiger/TigerEntryTaker.ex5 new file mode 100644 index 0000000..5ac2f28 Binary files /dev/null and b/shark_tiger/TigerEntryTaker.ex5 differ diff --git a/shark_tiger/TigerEntryTaker.mq5 b/shark_tiger/TigerEntryTaker.mq5 new file mode 100644 index 0000000..d9e0ccb --- /dev/null +++ b/shark_tiger/TigerEntryTaker.mq5 @@ -0,0 +1,1023 @@ +//+------------------------------------------------------------------+ +//| TigerEntryTaker.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "NewCandleDetector.mqh" +#include "GraphicalObjectsManager.mqh" +#include "Zone.mqh" +#include "ZoneContainer.mqh" +#include "MarketObserverTiger.mqh" +#include "LotSizeCalculator.mqh" + +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" + + +input group "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +// 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"); +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + + +// TRADE CLASSES +BuyEntryManager buyEntryManager ; +SellEntryManager sellEntryManager ; + + +// LotSizeCalculator class + +LotSizeCalculator lsCalc ; + +Zone* temporaryRestestSupportZone = new Zone(); + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + + + //--- example of applying template, located in \MQL5\Files + /*if(FileIsExist("Default.tpl")) + { + Print("The file Default.tpl found in \Files'"); + //--- apply template + if(ChartApplyTemplate(0,"\\Files\\Default.tpl")) + { + Print("The template 'Default.tpl' applied successfully"); + //--- redraw chart + ChartRedraw(); + } + else + Print("Failed to apply 'Default.tpl', error code ",GetLastError()); + } + else + { + Print("File 'Default.tpl' not found in " + +TerminalInfoString(TERMINAL_PATH)+"\\MQL5\\Files"); + } */ + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_M15,5); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_W1,1); + + + + + //ChartOpen(_Symbol,PERIOD_W1); + //ChartOpen(_Symbol,PERIOD_D1); + //long H4_NAME = ChartOpen(_Symbol,PERIOD_H4); + //long H1_NAME = ChartOpen(_Symbol,PERIOD_H1); + //if(!ChartOpen(_Symbol,PERIOD_M30)){ + // Print("Failed to open chart Error, " + GetLastError()); + //} + + //Print(H1_NAME); + //Print(M30_NAME); + //Print(H4_NAME); + + + + + objectsManager.addTextTiger(); +//objectsManager.addMarketDescriptionTextTiger(); + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + //Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + if(newCandleDetector30M.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrBeige,clrBlue,zoneContainer_M30); + //updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30"); + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + } + + + if(newCandleDetector1H.isNewCandle()) + { + + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + if(mqldt.hour == 13){ + + objectsManager.drawVerticalLine(clrAzure,TimeCurrent()); + + } + + detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrGray,clrRed,zoneContainer_H1); + double brokenResistanceLowerPrice = -1 ; + string brokenZoneTypeResistance = "" ; + if(updateBreakAboveStructureAndDelete(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",brokenResistanceLowerPrice,brokenZoneTypeResistance)) // means price broke the zone on an h1 candle + { + + + double firstResistancePrice = findClosestResistancePrice(zoneContainer_H1); + double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + if(cleanRangeValueBuys >= cleanRangeUponEntry) + { + + + + if(firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + + Print("H1 candle Broke and closed above the zone. the closest resistance price is: " + DoubleToString(firstResistancePrice)); + Print("The lower edge of the recently broken resistance zone is: " + brokenResistanceLowerPrice); + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_H1)) + { + + //if((mqldt.hour > 13 && mqldt.hour < 20) || (mqldt.hour > 8 && mqldt.hour < 12)){ + + //buyEntryManager.takeBuyTradeTiger(0.1,stopLossBased_H1,firstResistancePrice); + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_H1); + Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_H1, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + Print("Took a buy. stop loss: based on 1 hour"); + //} + + + + } + else + if(stopLossIsValidBuys(stopLossBased_M30)) + { + //if((mqldt.hour > 13 && mqldt.hour < 20) || (mqldt.hour > 8 && mqldt.hour < 12)){ + + //buyEntryManager.takeBuyTradeTiger(0.1,stopLossBased_H1,firstResistancePrice) ; + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + + Print("Took a buy. stop loss: based on 30 min"); + + // } + + } + + else + { + + Print("Failed to find a valid stop loss on both H1 and M30 !"); + } + } + + else + { + + Print("H1 candle Broke and closed above the zone, but im not taking a buy because i dont see a next zone target!"); + } + + + + + } + + else + { + + Print("Price Broke the zone but not enough range to take the trade !"); + + } + + + } + + + detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrWhite,clrRed,zoneContainerSupport_H1); + double brokenSupportHigherPrice = -1 ; + string brokenZoneTypeSupport= "" ; + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",brokenSupportHigherPrice,brokenZoneTypeSupport)) + { + //MqlDateTime mqldt ; + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_H1); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + + Print("H1 candle Broke and closed below the zone. the closest support price is: " + DoubleToString(firstSupportPrice)); + Print("The higher edge of the recently broken support zone is: " + brokenSupportHigherPrice); + + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_H1)) + { + //if((mqldt.hour > 13 && mqldt.hour < 20) || (mqldt.hour > 8 && mqldt.hour < 12)){ + + //sellEntryManager.takeSellTradeTiger(0.1,stopLossBased_H1,firstSupportPrice); + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_H1); + Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_H1,SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit); + Print("Took a sell. stop loss: based on 1 hour"); + //} + + + } + else + if(stopLossIsValidSells(stopLossBased_M30)) + { + + //if((mqldt.hour > 13 && mqldt.hour < 20) || (mqldt.hour > 8 && mqldt.hour < 12)){ + //sellEntryManager.takeSellTradeTiger(0.1,stopLossBased_H1,firstSupportPrice); + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + Comment("Spread is: + " + SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); + sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30,SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit); + + Print("Took a sell. stop loss: based on 30 min"); + + //} + + + } + + else + { + + Print("Failed to find a valid stop loss on both H1 and M30 !"); + } + } + + else + { + + Print("H1 candle Broke and closed below the zone. but im not taking a sell because i dont see a target zone !"); + } + + + + + } + else{ + Print("Price broke the support zone but not enough range to take the trade"); + + } + + } + + + + } + + /*if(newCandleDetector4H.isNewCandle()){ + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPurple,clrGreen,zoneContainer_H4); + updateBreakAboveStructureAndDelete(zoneContainer_H4,PERIOD_H4,"PERIOD_H4"); + }*/ + + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + + } + + + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed,TimeCurrent()); + } + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if(candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - 0.1); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if(candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + 0.1); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 stopLossIsValidBuys(double stopLoss) + { + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLoss < maxPipsRiskAmount) + { + return true ; + } + + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool stopLossIsValidSells(double stopLoss) + { + if(stopLoss - SymbolInfoDouble(_Symbol, SYMBOL_BID) < maxPipsRiskAmount) + { + return true ; + } + return false ; + + } +//+------------------------------------------------------------------+ + + +bool sessionIsNy(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 14 && mqldt.hour <= 17){ + return true ; + } + + return false ; + +} + + +bool sessionIsLondon(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 8 && mqldt.hour <= 11){ + return true ; + } + + return false ; + +} \ No newline at end of file diff --git a/shark_tiger/TigerEntryTakerNew.ex5 b/shark_tiger/TigerEntryTakerNew.ex5 new file mode 100644 index 0000000..711e298 Binary files /dev/null and b/shark_tiger/TigerEntryTakerNew.ex5 differ diff --git a/shark_tiger/TigerEntryTakerNew.mq5 b/shark_tiger/TigerEntryTakerNew.mq5 new file mode 100644 index 0000000..1ac3a87 --- /dev/null +++ b/shark_tiger/TigerEntryTakerNew.mq5 @@ -0,0 +1,1161 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#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 "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + + +input group "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK = true ; +input bool TRADE_LONDON = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +Zone* temporaryRestestSupportZone = new Zone(); + + + +// TRADE CLASSES +BuyEntryManager buyEntryManager ; +SellEntryManager sellEntryManager ; + + +// LotSizeCalculator class + +LotSizeCalculator lsCalc ; + + +string activeTradeType ; // its either , "BUY" , or "SELL" +bool securedRisk = false ; + +CTrade trade ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + +//objectsManager.addMarketDescriptionTextTiger(); + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + if(newCandleDetectorM15.isNewCandle()) + { + Print("new Candle on m15"); + if(PositionsTotal()!= 0) // There is an active trade + { + if(activeTradeType == "BUY") + { + + if(candleClosedBearish(PERIOD_M15,1) && !bearishCandleIsWeak(PERIOD_M15,1)){ + Print("M15 , closed against my direction, we should close half"); + if(securedRisk == false && closePartialFromAllPositions(riskManagementPartial)){ + securedRisk = true ; + } + } + + } + else + if(activeTradeType == "SELL") + { + if(candleClosedBullish(PERIOD_M15,1) && !bullishCandleIsWeak(PERIOD_M15,1)){ + Print("M15 , closed against my direction, we should close half"); + if(securedRisk == false && closePartialFromAllPositions(riskManagementPartial)){ + securedRisk = true ; + } + } + + } + + } + else{ + securedRisk = false ; // return the risk secure flag to false , to be ready for the next trade + + } + + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetector30M.isNewCandle()) + { +//Print("number of opened orders are: " + PositionsTotal()); +// DETECTING SUPPORTS AND RESISTANCES + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30); + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30); + +// VARIABLE PREPROCESSING FOR BOS + double brokenResistanceLowerPrice = -1 ; + string brokenZoneTypeResistance = "" ; + + double brokenSupportHigherPrice = -1; + string brokenZoneTypeSupport = "" ; + +// BREAK OF STRUCTURE HANDLING + + if(updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",brokenResistanceLowerPrice,brokenZoneTypeResistance) + && buyBreakerCandleIsValid(PERIOD_M30) + && ((sessionIsNy() && TRADE_NEW_YORK) || (sessionIsLondon() && TRADE_LONDON) )) // 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)) + { + + double firstResistancePrice = findClosestResistancePrice(zoneContainer_M30); + double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + Print("firstResistance variable is: " + firstResistancePrice); + Print("cleanRangeVlaueBuys :" + cleanRangeValueBuys); + + + if(firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + Comment("M30 candle Broke and closed above the zone. the closest resistance price is:" + DoubleToString(firstResistancePrice)); + if(cleanRangeValueBuys >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + if(PositionsTotal() == 0) // there are no active trades + { + + buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + activeTradeType = "BUY" ; + Comment("Took a buy. stop loss: based on M30"); + } + else + { + + Comment("I cant take a trade because another trade is running"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + if(PositionsTotal() == 0) + { + buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + activeTradeType = "BUY" ; + Comment("Took a buy. stop loss: based on M15"); + } + else + { + + Comment("I cant take a trade because another trade is running"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30) + && ((sessionIsNy() && TRADE_NEW_YORK) || (sessionIsLondon() && TRADE_LONDON) )) // 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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + if(PositionsTotal() == 0) + { + sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit) ; + activeTradeType = "SELL"; + Comment("Took a sell. stop loss: based on M30"); + + } + else + { + + Comment("i cant take a trade since another one is running"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + + if(PositionsTotal() == 0) + { + sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15, SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit) ; + activeTradeType = "SELL"; + Comment("Took a sell. stop loss: based on M15"); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetectorDaily.isNewCandle()) + { + +//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); +//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent());; + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) || (candleClosedBullish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBearish(timeFrame,1))) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) || (candleClosedBearish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBullish(timeFrame,1))) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + if(candleClose == candleOpen) + { + return true; + } + else + { + return false; + } + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 stopLossIsValidBuys(double stopLoss) + { + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLoss < maxPipsRiskAmount) + { + return true ; + } + + return false ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool stopLossIsValidSells(double stopLoss) + { + if(stopLoss - SymbolInfoDouble(_Symbol, SYMBOL_BID) < maxPipsRiskAmount) + { + return true ; + } + return false ; + + } +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ + +bool bearishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index){ // this function assumes that the previous candle is bearish + + double upperWickLength = iHigh(_Symbol,_timeFrame,1) - iOpen(_Symbol,_timeFrame,1) ; + double totalCandleLength = iHigh(_Symbol,_timeFrame,1) - iClose(_Symbol,_timeFrame,1); + if((upperWickLength / totalCandleLength) >= WICK_RATIO_REJECTION ){ // this means the candle is not weak + return true ; + } + else{ + return false ; + } +} + +bool bullishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index){ // this function assumes that the previous candle is bullish + double lowerWickLength = iOpen(_Symbol,_timeFrame,1) - iLow(_Symbol,_timeFrame,1) ; + double totalCandleLength = iClose(_Symbol,_timeFrame,1) - iLow(_Symbol,_timeFrame,1) ; + + if((lowerWickLength/totalCandleLength) >= WICK_RATIO_REJECTION){ // this means the candle is not weak + return true ; + } + else{ + return false ; + } +} + + +bool buyBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame){ + + if((iClose(_Symbol,_timeFrame,1) - iOpen(_Symbol,_timeFrame,1)) >= SIZE_OF_BREAKER_CANDLE_BODY) { + return true ; + } + else{ + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr + " Bullish Breaker candle body is too small to take a trade !"); + return false ; + + } + +} + +bool sellBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame){ + if((iOpen(_Symbol,_timeFrame,1) - iClose(_Symbol,_timeFrame,1)) >= SIZE_OF_BREAKER_CANDLE_BODY) { + return true ; + } + else{ + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr + " Bearish Breaker candle body is too small to take a trade !"); + return false ; + + } + +} + +bool closePartialFromAllPositions(double partialAmount){ + + for(uint i=0 ; i< PositionsTotal() ; i++){ + + ulong positionTicket = PositionGetTicket(i); + if(PositionSelectByTicket(positionTicket)){ + + double positionVolume = PositionGetDouble(POSITION_VOLUME); + double lotsToClose = positionVolume * partialAmount ; + if(trade.PositionClosePartial(positionTicket,NormalizeDouble(lotsToClose,2))){ + Print("Closed partials succesffully"); + return true ; + } + else{ + Print("Failed to close partials, Error: " + GetLastError()); + return false ; + } + + } + + + + } + return false ; + +} + + +bool sessionIsNy(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 14 && mqldt.hour <= 18){ + return true ; + } + + return false ; + +} + + +bool sessionIsLondon(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 8 && mqldt.hour <= 11){ + return true ; + } + + return false ; + +} \ No newline at end of file diff --git a/shark_tiger/TigerEntryTakerNewGen.ex5 b/shark_tiger/TigerEntryTakerNewGen.ex5 new file mode 100644 index 0000000..c99f2ca Binary files /dev/null and b/shark_tiger/TigerEntryTakerNewGen.ex5 differ diff --git a/shark_tiger/TigerEntryTakerNewGen.mq5 b/shark_tiger/TigerEntryTakerNewGen.mq5 new file mode 100644 index 0000000..d9e330a --- /dev/null +++ b/shark_tiger/TigerEntryTakerNewGen.mq5 @@ -0,0 +1,1060 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#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 "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + + +input group "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK_ALLOWED = true ; +input bool TRADE_LONDON_ALLOWED = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +Zone* temporaryRestestSupportZone = new Zone(); + + + +// TRADE CLASSES +BuyEntryManager buyEntryManager ; +SellEntryManager sellEntryManager ; + + +// LotSizeCalculator class + +LotSizeCalculator lsCalc ; + + +string activeTradeType ; // its either , "BUY" , or "SELL" +bool securedRisk = false ; + +ulong activeTradeId ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + +//objectsManager.addMarketDescriptionTextTiger(); + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + + + if(newCandleDetectorM15.isNewCandle()) + { + + + manageRiskIfNeeded(); + for(int i=0 ;i< PositionsTotal() ; i++){ + + Print("active trade id is : " + PositionGetTicket(i)); + + } + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetector30M.isNewCandle()) + { +//Print("number of opened orders are: " + PositionsTotal()); +// DETECTING SUPPORTS AND RESISTANCES + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30); + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30); + +// VARIABLE PREPROCESSING FOR BOS + double brokenResistanceLowerPrice = -1 ; + string brokenZoneTypeResistance = "" ; + + double brokenSupportHigherPrice = -1; + string brokenZoneTypeSupport = "" ; + +// BREAK OF STRUCTURE HANDLING + + if(updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",brokenResistanceLowerPrice,brokenZoneTypeResistance) + && buyBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + double firstResistancePrice = findClosestResistancePrice(zoneContainer_M30); + double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + + if(firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + Comment("M30 candle Broke and closed above the zone. the closest resistance price is:" + DoubleToString(firstResistancePrice)); + if(cleanRangeValueBuys >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + if(PositionsTotal() == 0) // there are no active trades + { + + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + activeTradeType = "BUY" ; + Comment("Took a buy. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because another trade is running"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + if(PositionsTotal() == 0) + { + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15, SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTakeProfit) ; + activeTradeType = "BUY" ; + Comment("Took a buy. stop loss: based on M15, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because another trade is running"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + if(PositionsTotal() == 0) + { + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30, SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit) ; + activeTradeType = "SELL"; + Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade since another one is running"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + + if(PositionsTotal() == 0) + { + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15, SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTakeProfit) ; + activeTradeType = "SELL"; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetectorDaily.isNewCandle()) + { + +//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); +//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent());; + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) || (candleClosedBullish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBearish(timeFrame,1))) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) || (candleClosedBearish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBullish(timeFrame,1))) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + if(candleClose == candleOpen) + { + return true; + } + else + { + return false; + } + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 + { + if(activeTradeType == "BUY") + { + + if(candleClosedBearish(PERIOD_M15,1) && !bearishCandleIsWeak(PERIOD_M15,1, WICK_RATIO_REJECTION)){ + Print("M15 , closed against my direction, we should close half"); + if(securedRisk == false && closePartialFromAllPositions(riskManagementPartial)){ + securedRisk = true ; + } + } + + } + else + if(activeTradeType == "SELL") + { + if(candleClosedBullish(PERIOD_M15,1) && !bullishCandleIsWeak(PERIOD_M15,1, WICK_RATIO_REJECTION)){ + Print("M15 , closed against my direction, we should close half"); + if(securedRisk == false && closePartialFromAllPositions(riskManagementPartial)){ + securedRisk = true ; + } + } + + } + + } + else{ + securedRisk = false ; // return the risk secure flag to false , to be ready for the next trade + + } + +} \ No newline at end of file diff --git a/shark_tiger/TigerEntryTakerNewGenNext.mq5 b/shark_tiger/TigerEntryTakerNewGenNext.mq5 new file mode 100644 index 0000000..1ac04eb --- /dev/null +++ b/shark_tiger/TigerEntryTakerNewGenNext.mq5 @@ -0,0 +1,1274 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#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 "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; +input bool BUYS_ALLOWED = true ; +input bool SELLS_ALLOWED = true ; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK_ALLOWED = true ; +input bool TRADE_LONDON_ALLOWED = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| 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 ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ; + + 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 M15, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) || (candleClosedBullish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBearish(timeFrame,1))) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if((candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) || (candleClosedBearish(timeFrame,3) && candleClosedDoji(timeFrame,2) && candleClosedBullish(timeFrame,1))) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 >= firstPartialProfitInPips){ + 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 >= firstPartialProfitInPips){ + 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 + positionTrailStopLoss(BuyActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + if((SellActiveTradesArray[i] != NULL)){ // CHECK TRAIL FOR SELLS + double newStopLoss = iHigh(_Symbol,_timeFrame,1); + newStopLoss = newStopLoss + stopLossAboveWickBy ; + if(newStopLoss < positionStopLoss(SellActiveTradesArray[i].getTradeId())){ // if new stop loss is lower than the current position's stop loss + positionTrailStopLoss(SellActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + + } +} diff --git a/shark_tiger/TigerNewFeature.ex5 b/shark_tiger/TigerNewFeature.ex5 new file mode 100644 index 0000000..7618eab Binary files /dev/null and b/shark_tiger/TigerNewFeature.ex5 differ diff --git a/shark_tiger/TigerNewFeature.mq5 b/shark_tiger/TigerNewFeature.mq5 new file mode 100644 index 0000000..ee879ee --- /dev/null +++ b/shark_tiger/TigerNewFeature.mq5 @@ -0,0 +1,1442 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#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 "Range Related Variables" +input double rangeDistanceBetweenZones ; +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 group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; +input bool BUYS_ALLOWED = true ; +input bool SELLS_ALLOWED = true ; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK_ALLOWED = true ; +input bool TRADE_LONDON_ALLOWED = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| 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 ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= cleanRangeUponEntry) { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) { // find a spot in the trades array, and save the result + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + } else { + + Comment("I cant take a trade because the trades array is full"); + } + + + } else if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) { // find a spot in the trades array, and save the result + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ; + + 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 M15, " + "Active trade id: " + activeTradeId); + } else { + + Comment("I cant take a trade because the trades array is full"); + + } + + } + + else { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) { + + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + + } else { + + Comment("i cant take a trade because the arrray is full"); + } + + + } else if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } else { + Comment("i cant take a trade since another one is running"); + } + } + + else { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + zoneContainer_M30.printZonesSortedArray(); + zoneContainerSupport_M30.printZonesSortedArray(); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + +} + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() { +//--- + +} +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() { +//--- + +} +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) { +//--- + +} +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() { +//--- + double ret=0.0; +//--- + +//--- + return(ret); +} +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() { +//--- + +} +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() { +//--- + +} +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() { +//--- + +} +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) { +//--- + +} +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) { +//--- + +} +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) { + + + if(resistancePatternFormed(timeFrame)) { // if resistance formed + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) { // check if it has a clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) { // if it doesnt have a clean range, just add it as a blue zone + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else if(zoneContainer.getNumberOfActiveZones() == 0) { // this means this is the first zone to add to the data strucutre + int result = detectAndDrawFirstResistanceZoneHigherThan(resistancePrice + resistanceExtendAboveCandle, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color); + if(result == 1) { + + Print("reached here !"); + int currentIdCounter = zoneContainer.getZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + + + + } + else if(result == 0){ + int currentIdCounter = zoneContainer.getZonesIdCounter(); + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + } + else if(result == 2){ + int currentIdCounter = zoneContainer.getZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,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); + + + + 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); + } + + } + + } + + return true ; + + } + return false ; +} + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) { + + + if(supportPatternFormed(timeFrame)) { // if support formed + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) { // check if it has a clean range down + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) { // if it doesnt have a clean range, just add it as a blue zone + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + 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. + //detectAndDrawFirstSupportZoneLowerThan(supportPrice - supportExtendBelowCandle, timeFrame, firstZoneShift,timeFrameStr, BOS_zone_color); + int result = detectAndDrawFirstSupportZoneLowerThan(supportPrice - supportExtendBelowCandle, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color); + if(result == 1) { + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + + } + else if(result == 0){ + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + } + else if(result == 2){ + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,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) == 1 ; + + 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); + } + + } + + } + + + return true ; + + } + return false ; +} + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int detectAndDrawFirstResistanceZoneHigherThan(double currentHigherResistancePrice, ENUM_TIMEFRAMES timeFrame,int _firstZoneShift,ZoneContainer& zoneContainer,string timeFrameStr, long BOS_zone_color) { + + 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(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,i+1); + + if((resistancePrice > currentHigherResistancePrice) && ((resistancePrice - currentHigherResistancePrice) > rangeDistanceBetweenZones)) { // this means the range is valid + Print("tthe range is valid between the newly formed RESISTANCE zone, and the first higher old zone"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addHistoryResistanceZoneOnTop(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("the zone counter is: "+ currentIdCounter); + 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) > rangeDistanceBetweenZones)) { // the range is not valid, this means draw only the old one + Print("the range is not valid between the newly formed RESISTANCE zone, and the first higher old zone"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + + zoneContainer.addHistoryResistanceZoneOnTop(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("the zone counter is: "+ currentIdCounter); + 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) { + + 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(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,i+1); + Print("supportPrice is:" + supportPrice); + + if((supportPrice < currentLowerSupportPrice) && ((currentLowerSupportPrice - supportPrice) > rangeDistanceBetweenZones)) { // this means the range is valid + Print("tthe range is valid between the newly formed SUPPORT zone, and the first higher old zone"); + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addHistorySupportZoneAtBottom(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("Higher edge of created zone is: "+ newZone.getHigherEdge()); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,newZone.getHigherEdge(),newZone.getLowerEdge(),BOS_zone_color); + + return 1 ; + } else if((supportPrice < currentLowerSupportPrice) && !((currentLowerSupportPrice - supportPrice) > rangeDistanceBetweenZones)) { // the range is not valid, this means draw only the old one + Print("the range is not valid between the newly formed SUPPORT zone, and the first higher old zone"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addHistorySupportZoneAtBottom(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("Higher edge of created zone is: "+ newZone.getHigherEdge()); + 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 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 + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + 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 + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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 ; + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + 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 >= firstPartialProfitInPips) { + 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 >= firstPartialProfitInPips) { + 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 + positionTrailStopLoss(BuyActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + if((SellActiveTradesArray[i] != NULL)) { // CHECK TRAIL FOR SELLS + double newStopLoss = iHigh(_Symbol,_timeFrame,1); + newStopLoss = newStopLoss + stopLossAboveWickBy ; + if(newStopLoss < positionStopLoss(SellActiveTradesArray[i].getTradeId())) { // if new stop loss is lower than the current position's stop loss + positionTrailStopLoss(SellActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + + } +} +//+------------------------------------------------------------------+ diff --git a/shark_tiger/TigerObserver.ex5 b/shark_tiger/TigerObserver.ex5 new file mode 100644 index 0000000..2f57dcf Binary files /dev/null and b/shark_tiger/TigerObserver.ex5 differ diff --git a/shark_tiger/TigerObserver.mq5 b/shark_tiger/TigerObserver.mq5 new file mode 100644 index 0000000..8205be0 --- /dev/null +++ b/shark_tiger/TigerObserver.mq5 @@ -0,0 +1,694 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#include "NewCandleDetector.mqh" +#include "GraphicalObjectsManager.mqh" +#include "Zone.mqh" +#include "ZoneContainer.mqh" + +#include "MarketObserverTiger.mqh" + + +input group "Range Related Variables" +input double rangeDistanceBetweenZones ; +input double cleanRangeUponEntry ; +input double potentialRR; + +input group "Zone Size Settings" +input double resistanceExtendAboveCandle; +input double resistanceLowerEdgeExtend ; +input double supportExtendBelowCandle ; +input double supportHigherEdgeExtend; + +input group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + + +// 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"); +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +Zone* temporaryRestestSupportZone = new Zone(); + +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + //objectsManager.addMarketDescriptionTextTiger(); + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + /*if(newCandleDetector30M.isNewCandle()) + { + + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30); + updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30"); + + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30); + updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30"); + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + } */ + + + /*if(newCandleDetector1H.isNewCandle()){ + + + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + if(mqldt.hour == 13){ + + objectsManager.drawVerticalLine(clrAzure,TimeCurrent()); + + } + detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrGray,clrRed,zoneContainer_H1); + updateBreakAboveStructureAndDelete(zoneContainer_H1,PERIOD_H1,"PERIOD_H1"); + + detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrWhite,clrRed,zoneContainerSupport_H1); + updateBreakBelowStructureAndDelete(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1"); + + + //zoneContainer_H1.printZonesSortedArray(); + //zoneContainerSupport_H1.printZonesSortedArray(); + + } */ + + + + if(newCandleDetector4H.isNewCandle()){ + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPurple,clrGreen,zoneContainer_H4); + updateBreakAboveStructureAndDelete(zoneContainer_H4,PERIOD_H4,"PERIOD_H4"); + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPink,clrBlue,zoneContainer_H4); + updateBreakAboveStructureAndDelete(zoneContainer_H4,PERIOD_H4,"PERIOD_H4"); + + detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrYellow,clrGreen,zoneContainerSupport_H4); + updateBreakBelowStructureAndDelete(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4"); + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + } + + if(newCandleDetectorDaily.isNewCandle()){ + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + + } + + + if(newCandleDetectorWeekly.isNewCandle()){ + + objectsManager.drawVerticalLine(clrRed, TimeCurrent());; + } + } +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer ) + { + + + if(candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double resistancePrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above + { + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + Print("current id counter of, zoneContainer is: " + currentIdCounter ); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_NORMAL"); + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color); + + /*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){ + string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId(); + deleteZoneGuiOnly(idOfZoneToHide,zoneContainer); + } */ + + + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle); + newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_RESISTANCE_BREAKOUT"); + + + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + return true ; + + } + return false ; + } + + + + + bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer ) + { + + + if(candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge = D'2023.11.01 00:00:00'; + double supportPrice = iOpen(_Symbol,timeFrame,1); + + + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone() ; + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + Print("current id counter of, zoneContainer_support is: " + currentIdCounter ); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + //Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones()); + //zoneContainer.printZonesSortedArray(); + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above + + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_NORMAL"); + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + //objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color); + + } + + else + if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre + { + + //Print("Entered here 2"); + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend); + newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle); + newZone.setLeftEdge(_leftEdge); + newZone.setRightEdge(_rightEdge); + newZone.setId(IntegerToString(currentIdCounter)); + newZone.setTimeFrame(timeFrameStr); + newZone.setType("TYPE_SUPPORT_BREAKOUT"); + + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + //zoneContainer.printZonesSortedArray(); + } + + + return true ; + + } + return false ; + } + + + + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) + { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) + { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) // the candle closed bullish + { + + return true ; + } + return false ; + } +//+------------------------------------------------------------------+ + + + +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!"); + + } + + + + + + + +void updateBreakAboveStructureAndDelete(ZoneContainer& zoneContainer, ENUM_TIMEFRAMES timeFrame, string timeFrameStr){ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId()),zoneContainer); // delete the zone with the GUI + } + else + { + finishedDeleting = true ; + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,""); + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,""); + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"Candle Closed Above the zone"); + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + } + + + } + +} + + + + + +void updateBreakBelowStructureAndDelete(ZoneContainer& zoneContainer, ENUM_TIMEFRAMES timeFrame, string timeFrameStr){ + 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 + { + /* 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("PERIOD_M30"); + temporaryRestestSupportZone.setType("TYPE_SUPPORT"); + deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */ + + 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); + temporaryRestestSupportZone.setType("TYPE_RESISTANCE"); + + deleteZoneWithGUI((zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getId()),zoneContainer); // delete the zone with the GUI + + } + else + { + //Print("Lower edge is: " + zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getLowerEdge()); + finishedDeleting = true ; + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,""); + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,""); + ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"Candle Closed Below the zone"); + } + + + } + + /*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){ + + Zone* tempZone = zoneContainer.getZoneByIndex(0); + string zoneIdStr = tempZone.getId(); + int zoneIdInteger = StringToInteger(zoneIdStr); + + objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed); + Print("Retrieved the zone succesfully!"); + + + } */ + + + } + + + } + +} \ No newline at end of file diff --git a/shark_tiger/TigerWicksIncluded.ex5 b/shark_tiger/TigerWicksIncluded.ex5 new file mode 100644 index 0000000..9e798a6 Binary files /dev/null and b/shark_tiger/TigerWicksIncluded.ex5 differ diff --git a/shark_tiger/TigerWicksIncluded.mq5 b/shark_tiger/TigerWicksIncluded.mq5 new file mode 100644 index 0000000..c4709b3 --- /dev/null +++ b/shark_tiger/TigerWicksIncluded.mq5 @@ -0,0 +1,1465 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + +#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 "Range Related Variables" +input double rangeDistanceBetweenZones ; +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 group "Zone TimeFrames" +input bool APPLY_M30_STRUCTURE ; +input bool APPLY_H1_STRUCTURE; + +input group "Candle Body Variables" +input double WICK_RATIO_REJECTION; +input double SIZE_OF_BREAKER_CANDLE_BODY; + +input group "Trade Related Variables" +input double riskManagementPartial ; +input double firstPartialCloseFactor ; +input double firstPartialProfitInPips; +input bool BUYS_ALLOWED = true ; +input bool SELLS_ALLOWED = true ; + +input group "Trading Sessions" +input bool TRADE_NEW_YORK_ALLOWED = true ; +input bool TRADE_LONDON_ALLOWED = true ; + +// 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"); +//+------------------------------------------------------------------+ +//| 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 ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ; + + 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 M15, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + zoneContainer_M30.printZonesSortedArray(); + zoneContainerSupport_M30.printZonesSortedArray(); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if(resistancePatternFormed(timeFrame)) // if resistance formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + + + 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 + resistanceExtendAboveCandle; + double _lowerEdgePrice = resistancePrice - resistanceLowerEdgeExtend ; + string _zoneId = IntegerToString(currentIdCounter); + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // 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 + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // 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 + resistanceExtendAboveCandle, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color); + if(result == 1) + { + + string currentIdCounter = IntegerToString(zoneContainer.getZonesIdCounter()); + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color); + + + + } + else + if(result == 0) + { + string currentIdCounter = IntegerToString(zoneContainer.getZonesIdCounter()); + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_NORMAL") ; + + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + } + else + if(result == 2) + { + string currentIdCounter = IntegerToString(zoneContainer.getZonesIdCounter()); + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_RESISTANCE_BREAKOUT") ; + zoneContainer.addResistanceZoneTiger(newZone); + zoneContainer.incrementZonesIdCounter(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,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); + + + + 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); + } + + } + + } + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer) + { + + + if(supportPatternFormed(timeFrame)) // if support formed + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getSupportZonesIdCounter(); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,2); + datetime _rightEdge =rightEdge; + double supportPrice = iOpen(_Symbol,timeFrame,1); + double _higherEdgePrice = supportPrice + supportHigherEdgeExtend; + double _lowerEdgePrice = supportPrice - supportExtendBelowCandle; + string _zoneId = IntegerToString(currentIdCounter); + + + + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down + { + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; + + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color); + + } + + else + if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone + { + Zone* newZone = new Zone(currentIdCounter,_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 - supportExtendBelowCandle, timeFrame,firstZoneShift, zoneContainer, timeFrameStr,BOS_zone_color); + if(result == 1) // means if found a lower zone and the range is clean + { + string currentIdCounter = IntegerToString(zoneContainer.getSupportZonesIdCounter()); + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color); + + } + else + if(result == 0) // means found a lower zone but the range is not clean + { + + string currentIdCounter = IntegerToString(zoneContainer.getSupportZonesIdCounter()); + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_NORMAL") ; + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + } + else + if(result == 2) // means didnt find a lower zone + { + + string currentIdCounter = IntegerToString(zoneContainer.getSupportZonesIdCounter()); + + Zone* newZone = new Zone(currentIdCounter,_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,timeFrameStr,"TYPE_SUPPORT_BREAKOUT") ; + zoneContainer.addSupportZoneTiger(newZone); + zoneContainer.incrementZonesIdCounterSupport(); + + objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,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) == 1 ; + + 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); + } + + } + + } + + + return true ; + + } + return false ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int detectAndDrawFirstResistanceZoneHigherThan(double currentHigherResistancePrice, ENUM_TIMEFRAMES timeFrame,int _firstZoneShift,ZoneContainer& zoneContainer,string timeFrameStr, long BOS_zone_color) + { + + for(int i=3 ; i< _firstZoneShift; i++) + { + if(resistancePatternFormed(timeFrame,i)) // if old resistance found + { + + // create a rectangle with a unique name + string currentIdCounter = IntegerToString(zoneContainer.getZonesIdCounter()); + + + datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); + datetime _rightEdge = rightEdge; + double resistancePrice = iOpen(_Symbol,timeFrame,i+1); + double _higherEdgePrice = resistancePrice + resistanceExtendAboveCandle; + double _lowerEdgePrice = resistancePrice - resistanceLowerEdgeExtend ; + + if((resistancePrice > currentHigherResistancePrice) && ((resistancePrice - currentHigherResistancePrice) > rangeDistanceBetweenZones)) // this means the range is valid + { + + Zone* newZone = new Zone(currentIdCounter,_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) > rangeDistanceBetweenZones)) // the range is not valid, this means draw only the old one + { + + Zone* newZone = new Zone(currentIdCounter,_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) + { + + 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 + string currentIdCounter = IntegerToString(zoneContainer.getSupportZonesIdCounter()); + datetime _leftEdge = iTime(_Symbol,timeFrame,i+2); + datetime _rightEdge = rightEdge; + double supportPrice = iOpen(_Symbol,timeFrame,i+1); + double _higherEdgePrice = supportPrice + supportHigherEdgeExtend; + double _lowerEdgePrice = supportPrice - supportExtendBelowCandle ; + + if((supportPrice < currentLowerSupportPrice) && ((currentLowerSupportPrice - supportPrice) > rangeDistanceBetweenZones)) // this means the range is valid + { + + Zone* newZone = new Zone(currentIdCounter,_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) > rangeDistanceBetweenZones)) // the range is not valid, this means draw only the old one + { + + Zone* newZone = new Zone(currentIdCounter,_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 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 >= firstPartialProfitInPips) + { + 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 >= firstPartialProfitInPips) + { + 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 + { + positionTrailStopLoss(BuyActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + if((SellActiveTradesArray[i] != NULL)) // CHECK TRAIL FOR SELLS + { + double newStopLoss = iHigh(_Symbol,_timeFrame,1); + newStopLoss = newStopLoss + stopLossAboveWickBy ; + if(newStopLoss < positionStopLoss(SellActiveTradesArray[i].getTradeId())) // if new stop loss is lower than the current position's stop loss + { + positionTrailStopLoss(SellActiveTradesArray[i].getTradeId(),newStopLoss,0); + } + } + + + + + } + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/TigerWicksOnly.ex5 b/shark_tiger/TigerWicksOnly.ex5 new file mode 100644 index 0000000..a35b8ce Binary files /dev/null and b/shark_tiger/TigerWicksOnly.ex5 differ diff --git a/shark_tiger/TigerWicksOnly.mq5 b/shark_tiger/TigerWicksOnly.mq5 new file mode 100644 index 0000000..d6707bf --- /dev/null +++ b/shark_tiger/TigerWicksOnly.mq5 @@ -0,0 +1,443 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "Algo_Skeleton_Functions.mqh" + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= buyStopPrice && !wickTradeTaken){ + double stopLossPrice = iLow(_Symbol,PERIOD_CURRENT,0) - stopLossUnderWickBy; + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + + if((SymbolInfoDouble(_Symbol,SYMBOL_ASK) - stopLossPrice) < minimumStopLossInPips){ + stopLossPrice = stopLossBased_M30 ; + if(stopLossIsValidBuys(stopLossBased_H1,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_H1 ; + } + else if(stopLossIsValidBuys(stopLossBased_M30,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_M30 ; + } + + else if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_M15 ; + } + } + else if(!stopLossIsValidBuys(stopLossPrice,maxPipsRiskAmount)){ + stopLossPrice = -1 ; + } + double lotsToBuy = lsCalc.calculateLotSize(riskDollars,stopLossPrice); + int indexToNewTrade ; + if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) && stopLossPrice != -1) + { + + + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToBuy,stopLossPrice) ; + + BuyTradeManagerTiger* tempTigerManager= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger + BuyActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + buysCount++; + wickTradeTaken = true ; + Comment("Took a bUY. stop loss: above current wick, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + Comment(TimeToString(currTime,TIME_MINUTES) + ": price has reached the candle high, im taking a buy"); + } + + } + + + // SELLS + + if(waitForTopWickToForm == true && wickLengthCounter == wickLengthInMinutes){ // waited wickLengthInMinutes time, and now its the time to check if the wick is valid + topWickValidationState = handleTopWickValidation(); + updateTopWickState(topWickValidationState); + } + + if(topWickFormed){ + datetime currTime = TimeCurrent(); + if((SymbolInfoDouble(_Symbol,SYMBOL_BID) <= sellStopPrice) && !wickTradeTaken){ + double stopLossPrice = iHigh(_Symbol,PERIOD_CURRENT,0) + stopLossAboveWickBy; + + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if((stopLossPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID)) < minimumStopLossInPips){ + stopLossPrice = stopLossBased_M30 ; + if(stopLossIsValidSells(stopLossBased_H1,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_H1 ; + } + else if(stopLossIsValidSells(stopLossBased_M30,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_M30 ; + } + + else if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount)){ + stopLossPrice = stopLossBased_M15 ; + } + } + else if(!stopLossIsValidSells(stopLossPrice,maxPipsRiskAmount)){ + stopLossPrice = -1 ; + } + + + + double lotsToSell = lsCalc.calculateLotSize(riskDollars,stopLossPrice); + + int indexToNewTrade ; + + if(((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) && stopLossPrice != -1) + { + + + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToSell,stopLossPrice) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + wickTradeTaken = true ; + Comment("Took a sell. stop loss: under current wick, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + + Comment(TimeToString(currTime,TIME_MINUTES) + ": price has reached the candle low, im taking a sell"); + } + } + + + + + + if(newCandleDetectorM1.isNewCandle()) + { + + // BUY CASE + if(waitForBottomWickToForm == true && wickLengthCounter < wickLengthInMinutes) + { + wickLengthCounter++ ; + } + + // SELL CASE + + if(waitForTopWickToForm == true && wickLengthCounter < wickLengthInMinutes){ + wickLengthCounter++; + } + } + + + + + if(newCandleDetectorM15.isNewCandle()) + { + + manageRiskIfNeeded(); + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetector30M.isNewCandle()) + { + wickTradeTaken = false ; + if(bottomWickFormed){ // reset the bottomWickFormed flag. this is for the cases that bottom wick has formed, but m30 candle closed and the trade still not taken + bottomWickFormed = false ; + buyStopPrice = -1; + } + + if(topWickFormed){ // reset the topWickFormed flag. this is for the cases that top wick has formed, but m30 candle closed and the trade still not taken + topWickFormed = false ; + sellStopPrice = -1; + } + trailAllOpenPositionsIfNeeded(PERIOD_M30); + + // DETECTING SUPPORTS AND RESISTANCES + detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30); + detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30); + + + // VARIABLE PREPROCESSING FOR BOS + double brokenResistanceLowerPrice = -1 ; + string brokenZoneTypeResistance = "" ; + + double brokenSupportHigherPrice = -1; + string brokenZoneTypeSupport = "" ; + + + + + // BREAK OF STRUCTURE HANDLING + + if(updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",brokenResistanceLowerPrice,brokenZoneTypeResistance) + && buyBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + + double firstResistancePrice = findClosestResistancePrice(zoneContainer_M30); + double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK); + + Print("first resistcane price is: "+ firstResistancePrice); + if(zoneContainer_M30.getNumberOfActiveZones() > 0 && firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + + + Comment("Price Broke and closed above resistance zone, im waiting for a bottom wick to form"); + waitForBottomWickToForm = true ; + + } + + else if(zoneContainer_M30.getNumberOfActiveZones() == 0 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT") + { + + + Comment("Price Broke and closed above resistance zone, im waiting for a bottom wick to form"); + waitForBottomWickToForm = true ; + + } + + + } + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + if(zoneContainerSupport_M30.getNumberOfActiveZones() > 0 && firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + waitForTopWickToForm = true ; + Comment("Price Broke and closed below support zone, im waiting for a top wick to form"); + + + } + + else if(zoneContainerSupport_M30.getNumberOfActiveZones() == 0 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT"){ + waitForTopWickToForm = true ; + Comment("Price Broke and closed below support zone, im waiting for a top wick to form"); + + } + } + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + zoneContainer_M30.printZonesSortedArray(); + zoneContainerSupport_M30.printZonesSortedArray(); + + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } + + + +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ diff --git a/shark_tiger/TigerZonesComplete.mq5 b/shark_tiger/TigerZonesComplete.mq5 new file mode 100644 index 0000000..1ff8728 --- /dev/null +++ b/shark_tiger/TigerZonesComplete.mq5 @@ -0,0 +1,423 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include "Algo_Skeleton_Functions.mqh" + +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + objectsManager.addTextTiger(); + + for(int i=0; i= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ; + stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ; + stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ; + + if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + } + + + } + else + if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ; + + 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 M15, " + "Active trade id: " + activeTradeId); + } + else + { + + Comment("I cant take a trade because the trades array is full"); + + } + + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + } + + + if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport) + && sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY) + && ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_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)) + { + + + double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30); + + double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice; + + Print("firstSupport variable is: " + firstSupportPrice); + Print("cleanRangeValueSells :" + cleanRangeValueSells); + + + if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT") + { + Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice)); + if(cleanRangeValueSells >= cleanRangeUponEntry) + { + + double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1); + double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1); + double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1); + + stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ; + stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ; + stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ; + + if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount)) + { + + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30); + int indexToNewTrade ; + + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ; + + 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 M30, " + "Active trade id: " + activeTradeId); + + } + else + { + + Comment("i cant take a trade because the arrray is full"); + } + + + } + else + if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1)) + { + double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15); + int indexToNewTrade ; + if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) + { + Print("The free index found is: " + indexToNewTrade); + activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ; + + SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger + SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array + sellsCount++; + Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId); + } + else + { + Comment("i cant take a trade since another one is running"); + } + } + + else + { + + + Comment("Failed to find a valid stop loss on both M30 and M15 !"); + } + + } + + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + + + Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade"); + + } + + } + else + { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone "); + + } + + + + } + + + datetime currTime = TimeCurrent(); + ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES)); + + + zoneContainer_M30.printZonesSortedArray(); + zoneContainerSupport_M30.printZonesSortedArray(); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } + diff --git a/shark_tiger/Tiger_Entries_4H.ex5 b/shark_tiger/Tiger_Entries_4H.ex5 new file mode 100644 index 0000000..20f8c31 Binary files /dev/null and b/shark_tiger/Tiger_Entries_4H.ex5 differ diff --git a/shark_tiger/Tiger_Entries_4H.mq5 b/shark_tiger/Tiger_Entries_4H.mq5 new file mode 100644 index 0000000..d62c190 --- /dev/null +++ b/shark_tiger/Tiger_Entries_4H.mq5 @@ -0,0 +1,232 @@ +//+------------------------------------------------------------------+ +//| TigerObserver.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#include "Algo_Skeleton_Functions.mqh" + +int OnInit() + { +//--- create timer + EventSetTimer(60); + +// ONLY FOR VISULAZITAION ON STRATEGY TESTER + iClose(_Symbol,PERIOD_W1,1); + iClose(_Symbol,PERIOD_D1,1); + iClose(_Symbol,PERIOD_H4,5); + iClose(_Symbol,PERIOD_H1,5); + iClose(_Symbol,PERIOD_M30,5); + iClose(_Symbol,PERIOD_M15,5); + + + + objectsManager.addTextTiger(); + + for(int i=0; i0){ + updateNormalZonesSupport(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",clrAliceBlue,rangeDistanceBetweenZonesActual_H4); + } + + if(zoneContainer_H4.getNumberOfActiveZones()){ + updateNormalZonesResistance(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",clrPink,rangeDistanceBetweenZonesActual_H4); + } + + } + + + if(newCandleDetector4H.isNewCandle()){ + trailAllOpenPositionsIfNeeded(PERIOD_H4); + + detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPink,zoneContainer_H4,rangeDistanceBetweenZonesActual_H4); + detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrAliceBlue,zoneContainerSupport_H4,rangeDistanceBetweenZonesActual_H4); + + // BREAK OF STRUCTURE HANDLING + handleBuys(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual); + handleSells(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual); + + + zoneContainerSupport_H4.printZonesSortedArray(); + zoneContainer_H4.printZonesSortedArray(); + } + + + + if(newCandleDetectorDaily.isNewCandle()) + { + + //detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1); + //updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1"); + objectsManager.drawVerticalLine(clrAqua, TimeCurrent()); + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + if(newCandleDetectorWeekly.isNewCandle()) + { + + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + + weekCounter++ ; + + if(weekCounter == deleteAllZonesAfter_Weeks){ + + //deleteAllzonesWithGUI(); + weekCounter = 0; + } + } + + } + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- + + } +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } + diff --git a/shark_tiger/TrendBreakouts.ex5 b/shark_tiger/TrendBreakouts.ex5 new file mode 100644 index 0000000..5ba1b04 Binary files /dev/null and b/shark_tiger/TrendBreakouts.ex5 differ diff --git a/shark_tiger/TrendBreakouts.mq5 b/shark_tiger/TrendBreakouts.mq5 new file mode 100644 index 0000000..986dc2b --- /dev/null +++ b/shark_tiger/TrendBreakouts.mq5 @@ -0,0 +1,182 @@ +//+------------------------------------------------------------------+ +//| TrendBreakouts.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +#define NUM_WEEKS_RESEARCH 48 +#include "Algo_Skeleton_Functions.mqh" +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int bullishCandlesCount = 0 ; +int conditionMetBullish = 0 ; +int secondConditionMetBullish = 0; +int bearishCandlesCount = 0; +int conditionMetBearish = 0 ; +int secondConditionMetBearish = 0 ; + +input group "Conditions" +input bool firstCondition = false ; +input bool secondCondition = false ; +input bool noCondition = false ; + +int OnInit() + { +//--- + +//--- + /* string fileName = "First_Condition_Bullish.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE |FILE_CSV|FILE_ANSI); + + FileSeek(fileHandle,0,SEEK_END); + FileWrite(fileHandle,"-----","Size of Week 1","Size of Week 2", "Monday", "Tuesday","Wednesday","Thursday","Friday","Retracement Measure","Low below previous close","Day of lowest point"); */ + + + string fileName1 = "First_Condition_Bearish.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle1 = FileOpen(fileName1,FILE_READ|FILE_WRITE |FILE_CSV|FILE_ANSI); + + FileSeek(fileHandle1,0,SEEK_END); + FileWrite(fileHandle1,"-----","Size of Week 1","Size of Week 2", "Monday", "Tuesday","Wednesday","Thursday","Friday","Retracement Measure","High above previous close","Day of Highest point"); + + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + Print("Count: "+ bullishCandlesCount + " First Condition: " + conditionMetBullish + " Second Condition: " + secondConditionMetBullish); + Print("Count: "+ bearishCandlesCount + " First Condition: " + conditionMetBearish + " Second Condition: " + secondConditionMetBearish); + + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + + + if(newCandleDetectorDaily.isNewCandle()) + { + //objectsManager.drawVerticalLine(clrAliceBlue, TimeCurrent()); + + + + + } + + int shift = 2 ; + if(newCandleDetectorWeekly.isNewCandle()) + { + objectsManager.drawVerticalLine(clrRed, TimeCurrent()); + + if(candleClosedBullish(PERIOD_W1,shift)) + { + if(!bullishCandleIsWeak(PERIOD_W1,shift,WICK_RATIO_REJECTION)) + { + + bullishCandlesCount++ ; + + if(firstCondition){ + if((iHigh(_Symbol,PERIOD_W1,1) > iHigh(_Symbol,PERIOD_W1,2)) && (iLow(_Symbol,PERIOD_W1,1) >iLow(_Symbol,PERIOD_W1,2))) + { + saveInCsv("firstCondition_Bullish.csv"); + conditionMetBullish++ ; + } + } + + if(secondCondition){ + if((iHigh(_Symbol,PERIOD_W1,1) > iClose(_Symbol,PERIOD_W1,2)) && (iLow(_Symbol,PERIOD_W1,1) > iLow(_Symbol,PERIOD_W1,2))) + { + saveInCsv("secondCondition_Bullish.csv"); + secondConditionMetBullish++ ; + } + } + + if(noCondition){ + saveInCsv("noCondition_Bullish.csv"); + + } + + + } + + } + + if(candleClosedBearish(PERIOD_W1,shift)) + { + + if(!bearishCandleIsWeak(PERIOD_W1,shift,WICK_RATIO_REJECTION)) + { + + bearishCandlesCount++ ; + if((iLow(_Symbol,PERIOD_W1,1) < iLow(_Symbol,PERIOD_W1,2)) && (iHigh(_Symbol,PERIOD_W1,1) < iHigh(_Symbol,PERIOD_W1,2))) + { + conditionMetBearish++ ; + } + + + if((iLow(_Symbol,PERIOD_W1,1) < iClose(_Symbol,PERIOD_W1,2)) && (iHigh(_Symbol,PERIOD_W1,1) < iHigh(_Symbol,PERIOD_W1,2))) + { + secondConditionMetBearish++ ; + } + + + + } + + } + + //Print("bearish candles count: " + bearishCandlesCount); + //Print("bullish canldes count: " + bullishCandlesCount); + + } + + } +//+------------------------------------------------------------------+ + + +void saveInCsv(string csvFileName){ +int lastWeekDaysArr[5] ; + for(int i=0; i<5; i++) + { + lastWeekDaysArr[i]= -1; + } + for(int i=5 ; i>0 ; i--) + { + if(candleClosedBullish(PERIOD_D1,i)) + { + lastWeekDaysArr[5-i] = 1 ; + } + if(candleClosedBearish(PERIOD_D1,i)) + { + lastWeekDaysArr[5-i] = 0 ; + } + } + + double firstWeekSize = iHigh(_Symbol,PERIOD_W1,2) - iLow(_Symbol,PERIOD_W1,2) ; + double secondWeekSize = iHigh(_Symbol,PERIOD_W1,1) - iLow(_Symbol,PERIOD_W1,1) ; + + + datetime time = iTime(_Symbol,PERIOD_W1,2); + string timeInStr = TimeToString(time,TIME_DATE); + + string fileName = csvFileName ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/); + + + + FileSeek(fileHandle,0,SEEK_END); + FileWrite(fileHandle,timeInStr,firstWeekSize,secondWeekSize,lastWeekDaysArr[0],lastWeekDaysArr[1],lastWeekDaysArr[2],lastWeekDaysArr[3],lastWeekDaysArr[4]); + + FileClose(fileHandle); +} \ No newline at end of file diff --git a/shark_tiger/Zone.mqh b/shark_tiger/Zone.mqh new file mode 100644 index 0000000..95a5f02 --- /dev/null +++ b/shark_tiger/Zone.mqh @@ -0,0 +1,341 @@ +//+------------------------------------------------------------------+ +//| Zone.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +#include "LowFractal.mqh" +#include "HighFractal.mqh" +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +#define SIZE_ATTACHED_FRACTALS +#define TP_ARR_SIZE 3 +class Zone + { +private: + string id ; + string timeFrame ; + string type ; // has 2 types : TYPE_SUPPORT, TYPE_RESISTANCE + string state ; // state is one of 5 states : STATE_CLEAN , STATE_TESTED, STATE_BROKEN, STATE_BROKEN_RETESTED, STATE_WAITING(used when price breaks structure, and is waiting to confirm BOS or a liquidity sweep) + datetime leftEdge ; + datetime rightEdge; + double lowerEdgePrice ; + double higherEdgePrice ; + double stopLossPrice ; + double tpPrices[TP_ARR_SIZE] ; + + + + + +public: + Zone(); + Zone:: Zone(string _zoneId,double _higherEdgePrice,double _lowerEdgePrice,datetime _leftEdge,datetime _rightEdge,string _timeFrameStr,string _type); + ~Zone(); + BuyEntryManager* buyEntryManager ; + BuyTradeManager* buyTradeManager; + + SellEntryManager* sellEntryManager ; + SellTradeManager* sellTradeManager ; + + + + // GETTERS + double getHigherEdge(); + double getLowerEdge(); + datetime getLeftEdge(); + datetime getRightEdge(); + string getId(); + string getTimeFrame(); + string getState(); + string getType(); + double getStopLossPrice(); + double getZoneHeight(); + + + // SETTERS + void setLeftEdge(datetime _leftEdge); + void setRightEdge(datetime _rightEdge); + void setLowerEdgePrice(double _lowerPirce); + void setHigherEdgePrice(double _higherPrice); + void setTimeFrame(string _timeframe); + void setId(string _id); + void setType(string _type); + void setState(string _state); + void setStopLossPrice(double slPrice); + bool setTakeProfit(double tpVal); // returns false if there is no valid slot in the tp's array, and true on success + + + // OTHER FUNCTIONS + void printTpLevels(); + void printTradeManagerData(); + + + + }; +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone:: Zone() + { + + buyEntryManager = new BuyEntryManager(); + buyTradeManager = new BuyTradeManager(); + sellEntryManager = new SellEntryManager(); + sellTradeManager = new SellTradeManager(); + + + + + + for(int i=0 ;i< TP_ARR_SIZE ;i++){ // initialize the tp array with -1's + tpPrices[i] = -1 ; + } + + } + + +Zone:: Zone(string _zoneId,double _higherEdgePrice,double _lowerEdgePrice,datetime _leftEdge,datetime _rightEdge,string _timeFrameStr,string _type){ + + buyEntryManager = new BuyEntryManager(); + buyTradeManager = new BuyTradeManager(); + sellEntryManager = new SellEntryManager(); + sellTradeManager = new SellTradeManager(); + + id = _zoneId ; + + timeFrame = _timeFrameStr; + type = _type; // has 2 types : TYPE_SUPPORT, TYPE_RESISTANCE + leftEdge = _leftEdge; + rightEdge = _rightEdge; + lowerEdgePrice = _lowerEdgePrice; + higherEdgePrice = _higherEdgePrice; + + +} +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone::~Zone() + { + delete buyEntryManager; + delete sellEntryManager; + delete buyTradeManager; + delete sellTradeManager; + } +//+------------------------------------------------------------------+ + + +// GETTERS + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +datetime Zone:: getLeftEdge() + { + + return leftEdge; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +datetime Zone:: getRightEdge() + { + + return rightEdge ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double Zone:: getHigherEdge() + { + + return higherEdgePrice; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double Zone:: getLowerEdge() + { + + return lowerEdgePrice; + } + +string Zone :: getState(){ + + return state ; +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string Zone:: getId() + { + + return id; + } + +string Zone:: getTimeFrame() {return timeFrame ;} + + + +string Zone:: getType(){ + + return type ; +} + + +double Zone :: getStopLossPrice(){ + return stopLossPrice ; +} + +// SETTERS + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setLeftEdge(datetime _leftEdge) + { + + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setRightEdge(datetime _rightEdge) + { + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setTimeFrame(string _timeframe) + { + + timeFrame = _timeframe; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setLowerEdgePrice(double _lowerPirce) + { + + lowerEdgePrice = _lowerPirce; + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone::setHigherEdgePrice(double _higherPrice) + { + + higherEdgePrice = _higherPrice ; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void Zone:: setId(string _id) + { + + id = _id; + } + + + +void Zone:: setType(string _type){ + + type = _type ; +} + + +void Zone:: setState(string _state){ + + state = _state ; +} + + +void Zone:: setStopLossPrice(double slPrice){ + + stopLossPrice = slPrice ; + +} + + +bool Zone:: setTakeProfit(double tpVal){ + for(int i=0; i zonesSortedArray[numberOfActiveZones-1].getHigherEdge()) // in this case the new zone should be in the last place in the array + { + zonesSortedArray[numberOfActiveZones] = _newZone; + numberOfActiveZones++; + + return 1; + } + else // in this case, the new zone sits somewhere in the array (not the edges) + { + int indexOfNewZone = searchForTheRightPlace(_newZone); + if(indexOfNewZone != -1) // means found a place for the new zone + { + forwardShiftZonesSortedArrayFromIndex(indexOfNewZone); + zonesSortedArray[indexOfNewZone] = _newZone ; + numberOfActiveZones++; + + return 1; + } + else + { + return -1; + } + + + } + return result; + } +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int ZoneContainer:: deleteZone(string ID) + { + +// 1. find the index of the zone with the ID + int indexOfZoneToDelete = getZoneIndex(ID); + if(indexOfZoneToDelete == -1) + { + return -1; + } + else + if(indexOfZoneToDelete == (numberOfActiveZones-1)) // means that this is the last zone in the sorted array + { + // 2. delete the zone + // 3. its the last element so do nothing + delete zonesSortedArray[numberOfActiveZones-1] ; + numberOfActiveZones--; + return 1; + } + else + { + // 2. delete the zone + // 3. its not the last element, so shift the array 1 step backwards + delete zonesSortedArray[indexOfZoneToDelete]; + backwardShiftZonesSortedArrayFromIndex(indexOfZoneToDelete); + numberOfActiveZones--; + return 1; + } + return 0 ; + } + + + + + + +/* int ZoneContainer:: deleteZoneTiger(string ID){ + +// 1. find the index of the zone with the ID + int indexOfZoneToDelete = getZoneIndex(ID); + if(indexOfZoneToDelete == -1) + { + return -1; + } + else + if(indexOfZoneToDelete == (numberOfActiveZones-1)) // means that this is the last zone in the sorted array + { + // 2. delete the zone + // 3. its the last element so do nothing + delete zonesSortedArray[numberOfActiveZones-1] ; + numberOfActiveZones--; + return 1; + } + else + { + // 2. delete the zone + // 3. its not the last element, so shift the array 1 step backwards + delete zonesSortedArray[indexOfZoneToDelete]; + backwardShiftZonesSortedArrayFromIndex(indexOfZoneToDelete); + numberOfActiveZones--; + return 1; + } + return 0 ; + + + + +} */ +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: freeZonesSortedArray() + { + + for(int i=0; i 0) + { + for(int i=0; i _index ; x--) + { + zonesSortedArray[x] = zonesSortedArray[x-1] ; + } + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: backwardShiftZonesSortedArrayFromIndex(int _index) // used for deleting + { + for(int i= _index ; i zonesSortedArray[i].getHigherEdge()) && (_zone.getHigherEdge() < zonesSortedArray[i+1].getLowerEdge())) + { + index = i+1; + + return index; + } + } + return index ; + } + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int ZoneContainer :: updateZone(Zone* _tempZone, string _idOfOriginalZone) + { + + + Zone* zoneToUpdate = searchZoneById(_idOfOriginalZone); + + zoneToUpdate.setHigherEdgePrice(_tempZone.getHigherEdge()); + zoneToUpdate.setLowerEdgePrice(_tempZone.getLowerEdge()); + zoneToUpdate.setLeftEdge(_tempZone.getLeftEdge()); + zoneToUpdate.setRightEdge(_tempZone.getRightEdge()); + zoneToUpdate.setTimeFrame(_tempZone.getTimeFrame()); + + return 1 ; + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone* ZoneContainer:: searchZoneById(string _idOfZone) + { + Zone* result ; + for(int i=0 ; i< numberOfActiveZones ; i++) + { + if(zonesSortedArray[i].getId() == _idOfZone) + { + result = zonesSortedArray[i] ; + + } + } + + return result ; + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: findOrUpdatePivotEdgesOnConfirm(double _ask,double _bid) + { + + bool foundSupport = false ; + bool foundResistance = false ; + + + for(int i=0 ; i=0 ; i--) // FIND HIGHER PIVOT EDGE + { + if(zonesSortedArray[i].getState()!= "STATE_WAITING") + { + if((zonesSortedArray[i].getLowerEdge() > _bid) && (zonesSortedArray[i].getType() == "TYPE_RESISTANCE")) + { + pivotEdges[1] = i; + foundResistance = true ; + } + } + + } + + if(foundSupport == false) + { + pivotEdges[0] = -1; + } + if(foundResistance == false) + { + pivotEdges[1] = -1; + } + + } + + + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: findOrUpdatePivotEdgesOnDelete() + { + bool foundSupport = false ; + bool foundResistance = false ; + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + + for(int i=0 ; i=0 ; i--) // FIND HIGHER PIVOT EDGE + { + if(zonesSortedArray[i].getState()!= "STATE_WAITING") + { + if(zonesSortedArray[i].getLowerEdge() > bid) + { + pivotEdges[1] = i; + foundResistance = true ; + } + } + + } + + if(foundSupport == false) + { + pivotEdges[0] = -1; + } + if(foundResistance == false) + { + pivotEdges[1] = -1; + } + + + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: printPivotEdges() + { + + Print("Lower Edge Index: " + pivotEdges[0]); + Print("Higher Edge Index: " + pivotEdges[1]); + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone* ZoneContainer:: getLowerPivotIndexZone() + { + + if(pivotEdges[0] != -1) + { + return getZoneByIndex(pivotEdges[0]); + } + + return NULL ; + + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +Zone* ZoneContainer:: getHigherPivotIndexZone() + { + + if(pivotEdges[1] != -1) + { + return getZoneByIndex(pivotEdges[1]); + } + + return NULL; + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void ZoneContainer:: addResistanceZoneTiger(Zone* _newZone) + { + + + if((numberOfActiveZones != 0 ) && (_newZone.getLowerEdge() >= zonesSortedArray[0].getHigherEdge())) // this is the case, where the new zone shouldnt be placed at the beggining (gap case for instance) + { + + + int indexOfNewZone = searchForTheRightPlace(_newZone); + if(indexOfNewZone != -1) // means found a place for the new zone + { + forwardShiftZonesSortedArrayFromIndex(indexOfNewZone); + zonesSortedArray[indexOfNewZone] = _newZone ; + numberOfActiveZones++; + + } + else + { + Print("Couldnt find an index to place the new zone !"); + } + + + } + + else + { + + forwardShiftZonesSortedArrayFromIndex(0); + zonesSortedArray[0] = _newZone ; + + if(_newZone.getType() == "TYPE_RESISTANCE_BREAKOUT") + { + numberOfActiveZones++; + } + else + if(_newZone.getType() == "TYPE_RESISTANCE_NORMAL") + { + + numberOfActiveZones++ ; + } + } + + + + + } + + + void ZoneContainer:: addHistoryResistanceZoneOnTop(Zone* _newZone){ + zonesSortedArray[numberOfActiveZones] = _newZone ; + numberOfActiveZones++; + } + + + + +void ZoneContainer:: addSupportZoneTiger(Zone* _newZone) + { + + + /* if((numberOfActiveZones != 0 ) && (_newZone.getHigherEdge() <= zonesSortedArray[numberOfActiveZones-1].getLowerEdge())) // this is the case, where the new zone shouldnt be placed at the beggining (gap case for instance) + { + + + int indexOfNewZone = searchForTheRightPlace(_newZone); + if(indexOfNewZone != -1) // means found a place for the new zone + { + forwardShiftZonesSortedArrayFromIndex(indexOfNewZone); + zonesSortedArray[indexOfNewZone] = _newZone ; + numberOfActiveZones++; + + } + else + { + Print("Couldnt find an index to place the new zone !"); + } + + + } */ + + + + + zonesSortedArray[numberOfActiveZones] = _newZone ; + + if(_newZone.getType() == "TYPE_SUPPORT_BREAKOUT") + { + numberOfActiveZones++; + } + else + if(_newZone.getType() == "TYPE_SUPPORT_NORMAL") + { + + numberOfActiveZones++ ; + } + + + + + + } + +//+------------------------------------------------------------------+ + void ZoneContainer:: addHistorySupportZoneAtBottom(Zone* _newZone){ + + + forwardShiftZonesSortedArrayFromIndex(0); + zonesSortedArray[0] = _newZone ; + numberOfActiveZones++; + } \ No newline at end of file diff --git a/shark_tiger/ZoneRejectionOneCandle.ex5 b/shark_tiger/ZoneRejectionOneCandle.ex5 new file mode 100644 index 0000000..7f8d3b5 Binary files /dev/null and b/shark_tiger/ZoneRejectionOneCandle.ex5 differ diff --git a/shark_tiger/ZoneRejectionOneCandle.mq5 b/shark_tiger/ZoneRejectionOneCandle.mq5 new file mode 100644 index 0000000..9630a59 --- /dev/null +++ b/shark_tiger/ZoneRejectionOneCandle.mq5 @@ -0,0 +1,1651 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +//input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTALS DATA + +//input int leftPeriod; +//input int rightPeriod; +//input int weekPeriodToInitialize; +//input int initFractalsPeriod ; +//int lowFractalIndex ; +//int highFractalIndex ; +//#include "LowFractal.mqh" +//#include "HighFractal.mqh" +//#include "LowFractalContainer.mqh" +//#include "HighFractalContainer.mqh" + + + +#property script_show_inputs + +input datetime InpStartTime = __DATETIME__; + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" + + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" +#include "LotSizeCalculator.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + +// Telegram Connection include +#include + +// SCRIPTS INCLUDES + + + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +// NEW CANDLE CLASSES INITIALIZATION +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + +bool telegramTested = false ; +input bool testTelegram ; +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +// Added because bmp files seem to have stopped working, possibly a file format issue +//fileType = "png"; +//fileName = "MyScreenshot." + fileType; + + + if(telegramTested == false && testTelegram == true) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"This is just a test ! " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + telegramTested = true ; + } + + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + + + + + /* if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } */ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + + //lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + //highFractalIndex = rightPeriod+1; // this is used for the fractals + //initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + //initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + /*if(newCandleDetector_M1.isNewCandle()) + { + + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + }*/ + + + if(newCandleDetector_H1.isNewCandle()) + { + + /* ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); */ + handleBuys(PERIOD_H1); + handleSells(PERIOD_H1); + } + + + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bearish candle closed inside the closest support zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bullish candle closed inside the resistance zone on " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/ZoneRjectionTest4H.ex5 b/shark_tiger/ZoneRjectionTest4H.ex5 new file mode 100644 index 0000000..4b72b66 Binary files /dev/null and b/shark_tiger/ZoneRjectionTest4H.ex5 differ diff --git a/shark_tiger/ZoneRjectionTest4H.mq5 b/shark_tiger/ZoneRjectionTest4H.mq5 new file mode 100644 index 0000000..3ba7fe3 --- /dev/null +++ b/shark_tiger/ZoneRjectionTest4H.mq5 @@ -0,0 +1,1642 @@ +//+------------------------------------------------------------------+ +//| ZoneScanner.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" + + +// INPUT VARIABLES +//input ENUM_TIMEFRAMES inputTimeFrameFractals ; + + + +// FRACTAL VARIABLES INITIALIZATION + +//input int leftPeriod; +//input int rightPeriod; +//input int weekPeriodToInitialize; +//input int initFractalsPeriod ; +//int lowFractalIndex ; +//int highFractalIndex ; + + +#property script_show_inputs + +input datetime InpStartTime = __DATETIME__; + +// GUI CLASSES INCLUDES +#include "GraphicalObjectsManager.mqh" +#include "ObjectConfirmationUnit.mqh" +#include "TempObjectAttributes.mqh" +#include "TempLineObjectAttributes.mqh" + + +// DATA STRUCTURE CLASSES INCLUDES +#include "Zone.mqh" +#include "ZoneContainer.mqh" +//#include "LowFractal.mqh" +//#include "HighFractal.mqh" +//#include "LowFractalContainer.mqh" +//#include "HighFractalContainer.mqh" + + +// ALGORITHM CLASSES INCLUDES + +#include "NewCandleDetector.mqh" +#include "MarketObserver.mqh" +#include "LotSizeCalculator.mqh" + + +// TRADE RELATED CLASSES INCLUDES +#include "BuyEntryManager.mqh" +#include "SellEntryManager.mqh" +#include "BuyTradeManager.mqh" +#include "SellTradeManager.mqh" + +// LIBRARIES INCLUDES +#include + +// Telegram Connection include +#include + +// SCRIPTS INCLUDES +//#include "Telegram_Exporter.mq5" + + +// GUI CLASSES INITIALIZATION +GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager(); +ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit(); +TempObjectAttributes* tempObjectAttr = new TempObjectAttributes(); +TempLineObjectAttributes* tempLineObjectAttr = new TempLineObjectAttributes(); + + +// CONTAINERS INITIALIZATION +ZoneContainer* zoneContainer = new ZoneContainer() ; +//LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ; + +//HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ; + + +// ALGORITHM CLASSES INITIALIZATION +MarketObserver* marketObserver = new MarketObserver(zoneContainer); +LotSizeCalculator lotSizeCalculator ; + + +// TRADE RELATED CLASSES INITIALIZATION +//BuyEntryManager* buyEntryManager = new BuyEntryManager(); +//BuyTradeManager* buyTradeManager = new BuyTradeManager(); + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +//SellEntryManager* sellEntryManager = new SellEntryManager(); +//SellTradeManager* sellTradeManager = new SellTradeManager(); + + +// GENERAL CHART VARIABLES INITIALIZATION +bool initialized = false ; +bool firstCandleAfterStart = true ; + + +// ENTRY VARIABLES +string entryZoneType ; +bool lookForBuy = false ; +bool lookForSell = false ; + + +// LIVE FORMING FRACTALS HANDLER CLASS +NewCandleDetector* newCandleDetectorLive ; + + +// NEW CANDLE CLASSES INITIALIZATION +NewCandleDetector* newCandleDetector_H4; +NewCandleDetector* newCandleDetector_H1; +NewCandleDetector* newCandleDetector_M30; +NewCandleDetector* newCandleDetector_M15; +NewCandleDetector* newCandleDetector_M5; +NewCandleDetector* newCandleDetector_M1; + + + +// Trade MANAGING VARIABLES +bool priceInMiddle = true ; +bool buyOnWait = false ; +bool buyOnAction = false; +bool sellOnWait = false; +bool sellOnAction = false ; + + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- create timer + EventSetTimer(60); +// Added because bmp files seem to have stopped working, possibly a file format issue +//fileType = "png"; +//fileName = "MyScreenshot." + fileType; + + + + + +// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE) + + + + + + /* if(inputTimeFrameFractals == PERIOD_M1) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M1"); + + } + else + if(inputTimeFrameFractals == PERIOD_M5) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M5"); + } + else + if(inputTimeFrameFractals == PERIOD_M15) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_M15"); + + } + else + if(inputTimeFrameFractals == PERIOD_M30) + { + + newCandleDetectorLive = new NewCandleDetector("PERIOD_M30"); + } + else + if(inputTimeFrameFractals == PERIOD_H1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H1"); + + } + else + if(inputTimeFrameFractals == PERIOD_H4) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_H4"); + + } + else + if(inputTimeFrameFractals == PERIOD_D1) + { + newCandleDetectorLive = new NewCandleDetector("PERIOD_D1"); + + } */ + + + if(initialized == false) + { + Print("Shark Initialized successfully on " + Symbol()); + + // ADD THE BUTTONS TO THE SCREEN + objectsManager.addZoneButton(); + objectsManager.addConfirmButton(); + objectsManager.addDeleteButton(); + objectsManager.addExitExperAdvisorButton(); + objectsManager.addPrintFractalsButton(); + objectsManager.addPrintZonesButton(); + objectsManager.addStopLossButton(); + objectsManager.addTakeProfitButton(); + objectsManager.addSetTakeProfitButton(); + + // INIT FRACTAL VARIABLES + + //lowFractalIndex = rightPeriod+1 ; // this is used for the fractals + //highFractalIndex = rightPeriod+1; // this is used for the fractals + //initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + //initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals); + + // INITIALIZATION FLAG + + + newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4"); + newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1"); + newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30"); + newCandleDetector_M15 = new NewCandleDetector("PERIOD_M15"); + newCandleDetector_M5 = new NewCandleDetector("PERIOD_M5"); + newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1"); + + initialized = true ; + + + } + + + + +//--- + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- destroy timer + /*Print("Low Fractals:"); + lowsContainer.printLowFractals(); + Print(" "); + Print("High Fractals:"); + highsContainer.printhighFractals(); + Print(" "); */ + + + + + + + + + + EventKillTimer(); + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { + + + if(!IsTradeAllowed()) + { + + return ; + } + + if(!IsMarketOpen2(Symbol(),TimeCurrent())) + { + + return ; + } + + + + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) + { + marketObserver.getClosestResistanceZone().sellTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) + { + marketObserver.getClosestSupportZone().buyTradeManager.checkAndSecureTradeIfNeeded(firstSecureRatio,riskDollars); + } + + + + + if(newCandleDetector_M1.isNewCandle()) + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"this is just a test " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + handleBuys(PERIOD_M1); + handleSells(PERIOD_M1); + } + + + } + + + +//+------------------------------------------------------------------+ +//| Timer function | +//+------------------------------------------------------------------+ +void OnTimer() + { +//--- + + } +//+------------------------------------------------------------------+ +//| Trade function | +//+------------------------------------------------------------------+ +void OnTrade() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TradeTransaction function | +//+------------------------------------------------------------------+ +void OnTradeTransaction(const MqlTradeTransaction& trans, + const MqlTradeRequest& request, + const MqlTradeResult& result) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Tester function | +//+------------------------------------------------------------------+ +double OnTester() + { +//--- + double ret=0.0; +//--- + +//--- + return(ret); + } +//+------------------------------------------------------------------+ +//| TesterInit function | +//+------------------------------------------------------------------+ +void OnTesterInit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterPass function | +//+------------------------------------------------------------------+ +void OnTesterPass() + { +//--- + + } +//+------------------------------------------------------------------+ +//| TesterDeinit function | +//+------------------------------------------------------------------+ +void OnTesterDeinit() + { +//--- + + } +//+------------------------------------------------------------------+ +//| ChartEvent function | +//+------------------------------------------------------------------+ +void OnChartEvent(const int id, + const long &lparam, + const double &dparam, + const string &sparam) + { +//--- +//--- left-clicking on a chart + + switch(id) + { + + case CHARTEVENT_CLICK: + { + + break; + } + + + + + //--- clicking on a graphical object + case CHARTEVENT_OBJECT_CLICK: + { + if(sparam == "ZONE_ADD_BTN") + { + + if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + + // create a rectangle with a unique name + int currentIdCounter = zoneContainer.getZonesIdCounter(); + objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone ) + objectConfUnit.setWaitingStatus(true); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + objectConfUnit.setConfirmationObjectId(currentIdCounter); + zoneContainer.incrementZonesIdCounter(); + + + + } + else + { + + Print("Failed to Add a new Object, Make sure to confirm the previous object first! ."); + } + + + + } + + else + if(sparam == "ADD_SL_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawStopLossLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + + } + else + if(sparam == "ADD_TP_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS A ZONE SELECTED TO ADD STOP LOSS TO + { + + if(objectConfUnit.getObjectType() != "OBJ_RECTANGLE") + { + Print("Please select a zone object only !"); + } + else + { + + objectsManager.drawTakeProfitLine(objectConfUnit.getConfirmationObjectId()); + } + + } + else + { + + Print("Please select a zone in order to add a stop loss line !"); + } + + } + else + if(sparam == "CONFIRM_BTN") + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED + { + + + if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE + { + + if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it + { + + // update the zone attributes + // zoneContainer.UpdateZone(int id); + Zone* tempZone = new Zone(); + + + + tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ; + tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + tempZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + string idOfOriginalZone = objectConfUnit.getConfirmationObjectId(); + // no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no) + + if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1) + { + // in this case we successfully updated the zone + + Print("Updated the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + delete tempZone; + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + { + + Print("Failed to update the zone, please reposition it"); + } + + } + + else // means the zone is new so we need to add it + { + Zone* newZone = new Zone() ; + newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()); + newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice()); + newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime()); + newZone.setRightEdge(tempObjectAttr.getRightEdgeTime()); + newZone.setId(objectConfUnit.getConfirmationObjectId()); + newZone.setTimeFrame(tempObjectAttr.getTimeFrame()); + + + double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ; + double higherEdge = tempObjectAttr.getHigherEdgePrice(); + + Print("higher edge is: " + higherEdge + " ask is: " + ask); + if(tempObjectAttr.getHigherEdgePrice() < ask) // means its a support zone + { + newZone.setType("TYPE_SUPPORT"); + } + + + double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); + double lowerEdge = tempObjectAttr.getLowerEdgePrice(); + Print("lower edge is: "+lowerEdge + " bidd i: " + bid); + if(tempObjectAttr.getLowerEdgePrice() > bid) // means its a resistance zone + { + + newZone.setType("TYPE_RESISTANCE"); + } + // add the zone to the data structure + if(zoneContainer.addZone(newZone) == 1) + { + zoneContainer.findOrUpdatePivotEdgesOnConfirm(ask,bid); // update the pivot edges + Print("Added the object:" + + "\n ID: " + objectConfUnit.getConfirmationObjectId() + + "\n Type: " + objectConfUnit.getObjectType() + + "\n Asset: " + tempObjectAttr.getSymbol() + + "\n Time Frame:" + tempObjectAttr.getTimeFrame() + + "\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() + + "\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() + + "\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() + + "\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime() + ); + + + + if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it + { + } + else + { + Print("Failed to unselect the object. Error: " + GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + } + else + { + Print("Failed to add the zone, Error: 2 or more zones are crossing"); + } + + ChartRedraw(); + } + + + + + + } + + else + if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE + { + + + + + } + else + if(objectConfUnit.getObjectType() == "OBJ_HLINE") // CASE OF HORIZNOTAL LINE + { + + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "sl") + { + + zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setStopLossPrice(tempLineObjectAttr.getPrice()); + Print("Stop loss for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "tp") + { + + + if(ObjectDelete(_Symbol,tempLineObjectAttr.getId())) + { + + } + else + { + Print("Failed to delete the stop loss line ! Error: "+ GetLastError()); + } + + // THIS IS TO CLEAN THE objectConfUnit + objectConfUnit.setWaitingStatus(false); + ChartRedraw(); + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "rl") + { + + Print("Relational level line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,2) == "dl") + { + + Print("Daily indecision line for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + else + if(StringSubstr(tempLineObjectAttr.getId(),0,3) == "bos") + { + + Print("Break of structure line for zone: " + StringSubstr(tempLineObjectAttr.getId(),3,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + ChartRedraw(); + + } + + } + + + + } + else + { + + Print("Cannot confirm, Please select an object first !"); + } + + } + + else + if(sparam == "DELETE_BTN") + { + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED + { + if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId())) + { + if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + "\n Type: " + objectConfUnit.getObjectType() + + "\n ID: " + objectConfUnit.getConfirmationObjectId()); + + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + + ChartRedraw(); + } + else + { + objectConfUnit.setWaitingStatus(false); + objectConfUnit.setObjectType("NO_OBJECT"); + objectConfUnit.setConfirmationObjectId(-2); + } + } + + } + else + { + + Print("Cannot delete, Please select an object first !"); + } + + } + else + if(sparam == "EXIT_BTN") + { + delete objectsManager ; + delete objectConfUnit; + delete tempObjectAttr; + //delete lowsContainer; + //delete highsContainer; + + delete newCandleDetectorLive; + delete tempLineObjectAttr; + delete marketObserver; + + + zoneContainer.freeZonesSortedArray(); + delete zoneContainer ; + + delete newCandleDetector_H4; + delete newCandleDetector_H1; + delete newCandleDetector_M30; + delete newCandleDetector_M15; + delete newCandleDetector_M5 ; + delete newCandleDetector_M1; + + + + + + + ExpertRemove(); + } + else + if(sparam == "PRINT_FRACTAL_BTN") + { + Print("Low Fractals:"); + //lowsContainer.printLowFractals(); + Print("High Fractals:"); + //highsContainer.printHighFractals(); + } + + else + if(sparam == "PRINT_ZONES_BTN") + { + + zoneContainer.printZonesSortedArray(); + } + + else + if(sparam == "SET_TP_BTN") + { + if(objectConfUnit.getObjectType() != "OBJ_HLINE") + { + Print("Please select a TP line first !"); + + } + else + { + if(zoneContainer.searchZoneById(StringSubstr(tempLineObjectAttr.getId(),2,-1)).setTakeProfit(tempLineObjectAttr.getPrice())) + { + Print("TP for zone: " + StringSubstr(tempLineObjectAttr.getId(),2,-1) + " has been set at: " + tempLineObjectAttr.getPrice()); + } + else + { + Print("You have reached the max take profit lines !"); + } + + } + + + } + else // THIS is the case were we click on any object except for main Buttons on screen + { + + if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED + { + Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !"); + } + + + else + { + ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true); + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) // CASE OF SELECTING A RECTANGLE + { + Print("Selected the object:" + + "\n Type: OBJ_RECTANGLE" + + "\n ID: " + sparam); + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_RECTANGLE"); + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + + + + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + ChartRedraw(); + } + + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) // CASE OF SELECTING A HORIZONTAL LINE + { + + objectConfUnit.setWaitingStatus(true) ; + objectConfUnit.setConfirmationObjectId(StringToInteger(sparam)); + objectConfUnit.setObjectType("OBJ_HLINE"); + + //tempLineObjectAttr.setId(sparam); + //tempLineObjectAttr.setPrice( ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0)); + ChartRedraw(); + } + + + + + + } + + } + + + break; + } + + + //--- object moved or anchor point coordinates changed + case CHARTEVENT_OBJECT_DRAG: + { + + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE) + { + + + double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1); + double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + + datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0); + datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1); + + if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it. + { + tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice); + tempObjectAttr.setLowerEdgePrice(_higherEdgePrice); + } + else + { + tempObjectAttr.setHigherEdgePrice(_higherEdgePrice); + tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice); + } + + tempObjectAttr.setLeftEdgeTime(_leftEdgeTime); + tempObjectAttr.setRightEdgeTime(_rightEdgeTime); + tempObjectAttr.setSymbol(); + tempObjectAttr.setTimeFrame(getChartTimeFrameInString()); + break; + } + + else + if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE) + { + + if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone) + { + double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(stopLossPrice); + } + else + if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone) + { + double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0); + tempLineObjectAttr.setId(sparam); + tempLineObjectAttr.setPrice(takeProfitPrice); + } + else + if(StringSubstr(sparam,0,2) == "rl") // case of relational point line (attached to a zone) + { + Print("dragging a relational point line"); + } + else + if(StringSubstr(sparam,0,2) == "dl") // case of daily line + { + Print("dragging a daily line"); + } + else + if(StringSubstr(sparam,0,3) == "bos") // case of break of structure line + { + Print("dragging a break of structure line"); + } + + } + } + } + + } + + +//+------------------------------------------------------------------+ +//| BookEvent function | +//+------------------------------------------------------------------+ +void OnBookEvent(const string &symbol) + { +//--- + + } +//+------------------------------------------------------------------+ + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals + + + + if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(lowsContainer.getFreeIndex() > 0) + { + + if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + + } + + + } + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +/*void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod) + { + + for(int i=_index ; i> rightPeriod ; i--) + { + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + + + if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true) + { + + if(highsContainer.getFreeIndex() > 0) + { + + if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod); + currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i)); + currentFractal.setDistance(i); + int NumberOfCandle = i-1; + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + + } + + + } + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleLowFractals(ENUM_TIMEFRAMES tf) + { + + bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added + + for(int x=0 ; x 0) + { + + if(iLow(Symbol(),tf,lowFractalIndex) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal + { + + if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period + { + + accessDeniedLows = true ; + } + + } + } + + if(accessDeniedLows == false) + { + + LowFractal* currentFractal = new LowFractal(iLow(Symbol(),tf,lowFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + lowsContainer.addLowFractal(currentFractal); + Print("added a new low fractal !"); + + } + + + } + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +/*void handleHighFractals(ENUM_TIMEFRAMES tf) + { + + + bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals + + for(int x=0 ; x 0) + { + + if(iHigh(Symbol(),tf,highFractalIndex) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal + { + if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() <= 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period + { + accessDeniedHighs = true ; + } + + } + } + + if(accessDeniedHighs == false) + { + + + HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),tf,highFractalIndex),leftPeriod,rightPeriod,TimeCurrent(),tf); + + int NumberOfCandle = Bars(Symbol(),tf); + string NumberOfCandleText = IntegerToString(NumberOfCandle); + currentFractal.setArrowObjName(NumberOfCandleText); + highsContainer.addHighFractal(currentFractal); + Print("added a new high fractal !"); + } + + + } + + + } */ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string MarketTest(string symbol, datetime testTime) + { + + return symbol + " " + TimeToString(testTime, TIME_DATE|TIME_MINUTES|TIME_SECONDS) + " " + IsMarketOpen(symbol, testTime) + " " + IsMarketOpen2(symbol, testTime); + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsTradeAllowed() + { + + return ((bool)MQLInfoInteger(MQL_TRADE_ALLOWED) // Trading allowed in input dialog + && (bool)TerminalInfoInteger(TERMINAL_TRADE_ALLOWED) // Trading allowed in terminal + && (bool)AccountInfoInteger(ACCOUNT_TRADE_ALLOWED) // Is account able to trade, not locked out + && (bool)AccountInfoInteger(ACCOUNT_TRADE_EXPERT) // Is account able to auto trade + ); + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen(string symbol, datetime time) + { + + MqlDateTime mtime; + TimeToStruct(time, mtime); + datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec; + + datetime fromTime; + datetime toTime; + + for(int session = 0;; session++) + { + if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime)) + return false; + if(fromTime<=seconds && seconds<=toTime) + return true; + } + + } + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool IsMarketOpen2(string symbol, datetime time) + { + + static string lastSymbol = ""; + static bool isOpen = false; + static datetime sessionStart = 0; + static datetime sessionEnd = 0; + + if(lastSymbol==symbol && sessionEnd>sessionStart) + { + if((isOpen && time>=sessionStart && time<=sessionEnd) + || (!isOpen && time>sessionStart && timetoTime) // maybe a later session + { + sessionStart = dayStart + toTime; + continue; + } + + // at this point must be inside a session + sessionStart = dayStart + fromTime; + sessionEnd = dayStart + toTime; + isOpen = true; + return isOpen; + + } + + return false; + + } +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void deleteZoneWithGUI(string _id) + { + + + if(zoneContainer.deleteZone(_id) == 1) + { + // delete from data structure + zoneContainer.findOrUpdatePivotEdgesOnDelete(); + Print("Deleted the object: " + + + "\n ID: " + _id); + + ChartRedraw(); + } + else + { + + } + + + if(!ObjectDelete(_Symbol,_id)) + { + Print("Failed to delete object error: " + GetLastError()); + } + + } + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + +//+------------------------------------------------------------------+ +void handleBuys(ENUM_TIMEFRAMES _timeFrame) + { + +// BUY CASE + + if((marketObserver.getClosestSupportZone() != NULL) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken()) && !(marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bearishCandleClosedInsideClosestSupportZone(_timeFrame)) + { + Print("Bearish Candle closed inside closest support zone !"); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bearish candle closed inside the closest support zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + } + + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + if(marketObserver.getClosestSupportZone().buyEntryManager.buyRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRejectionCandle(false); + double lastBullishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + + if(lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getHigherEdge()) // closed above the zone + { + + // now we need to check if closed twice as the zone height + + + if(lastBullishCandleClosePrice - marketObserver.getClosestSupportZone().getHigherEdge() > marketObserver.getClosestSupportZone().getZoneHeight()) + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price closed above the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setWaitingForRetracement(true); + } + else + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish rejection candle was formed, Price Closed above the zone in a distance less than the height of the zone, im taking a buy now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + } + else + if(lastBullishCandleClosePrice < marketObserver.getClosestSupportZone().getHigherEdge() && lastBullishCandleClosePrice > marketObserver.getClosestSupportZone().getLowerEdge()) // closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bullish Rejection Candle Closed inside the zone, im taking a buy now !, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestSupportZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestSupportZone().buyEntryManager.takeBuyTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestSupportZone().buyTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + } + + else + if((marketObserver.getClosestSupportZone() != NULL) && (marketObserver.getClosestSupportZone().buyEntryManager.isWaitingForRetracement())) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && !(marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FOURTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS STILL NOT TAKEN , SO WE DONT WANT TO ENTER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, the trade is still not taken and im not gonna take it, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + + } + else + if((marketObserver.getClosestSupportZone() != NULL) && marketObserver.candleClosedBelowClosestSupportZone(_timeFrame) && (marketObserver.getClosestSupportZone().buyEntryManager.buyTradeTaken())) // FIFTH CASE: PRICE CLOSED UNDER THE ZONE, AND THE BUY IS TAKEN , SO WE WANNA CLOSE THE ORDER + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THIS ZONE ** A candle closed below the support zone, i am in a buy trade and im gonna close the position and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestSupportZone().buyEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestSupportZone().buyTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestSupportZone().buyTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestSupportZone().getId(); + deleteZoneWithGUI(_idToDelete); + } + } + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +void handleSells(ENUM_TIMEFRAMES _timeFrame) + { + + + + +// SELL CASE + + if((marketObserver.getClosestResistanceZone() != NULL) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement())) // FIRST CASE : PRICE IS IN THE MIDDLE + { + if(marketObserver.bullishCandleClosedInsideClosestResistanceZone(_timeFrame)) + { + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** M1 Bullish candle closed inside the resistance zone on " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && (marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRejectionCandle()) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // SECOND CASE : PRICE HAS CLOSED IN THE ZONE AND WAITING FOR REJECTION, AND THE TRADE HAS NOT BEEN TAKEN YET + { + + if(marketObserver.getClosestResistanceZone().sellEntryManager.sellRejectionDetector.rejectionByOneCandleFormed(_timeFrame)) + { + + + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRejectionCandle(false); + // let the market observer check where the rejection candle closed, was it inside the zone ? or outside ? if outside the zone was it too close to the zone? if too + double lastBearishCandleClosePrice = iClose(_Symbol,_timeFrame,1); + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed under the zone + { + + // now we need to check if closed twice as the zone height + + if((marketObserver.getClosestResistanceZone().getLowerEdge() - lastBearishCandleClosePrice) > marketObserver.getClosestResistanceZone().getZoneHeight()) // rejection candle closed in a distance more than the height of the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance more than the height of the zone, in these cases i take an entry on imbalance fill or a retracement but at the moment im not trading these cases , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setWaitingForRetracement(true); + } + else // previous candle closed in a distance less than the height of the zone + { + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish rejection candle was formed, Price closed under the zone in a distance less than the height of the zone, im taking a sell now , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled, and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + + + } + + } + else + if(lastBearishCandleClosePrice < marketObserver.getClosestResistanceZone().getHigherEdge() && lastBearishCandleClosePrice > marketObserver.getClosestResistanceZone().getLowerEdge()) // rejection candle closed inside the zone + { + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** Bearish Rejection Candle Closed inside the zone, im taking a sell now ! , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + double stopLossPrice = marketObserver.getClosestResistanceZone().getStopLossPrice(); + double lotsToTrade = lotSizeCalculator.calculateLotSize(riskDollars,stopLossPrice); + for(int i=0 ; i<3 ; i++) // after this loop, the trade id's array will be filled , and the 3 trades will be taken + { + double partialLotPercent ; + if(i == 0) + { + partialLotPercent = 0.5 ; + } + if(i == 1 || i == 2) + { + partialLotPercent = 0.25; + } + ulong currentEntryId = marketObserver.getClosestResistanceZone().sellEntryManager.takeSellTrade(partialLotPercent * lotsToTrade,stopLossPrice); + marketObserver.getClosestResistanceZone().sellTradeManager.fillRejectionByOneCandleTradeArray(i,currentEntryId); + } + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(true); + } + + // call trade manager + } + + } + + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.getClosestResistanceZone().sellEntryManager.isWaitingForRetracement()) // THIRD CASE: WAITING FOR A RETRACEMENT BECAUSE THE REJECTION CANDLE CLOSED MORE THAN THE HEIGHT OF THE ZONE + { + + Print("Im waiting for retracement because the rejection candle closed more than the height of the zone, ** this messaage is just for testing, because i still do not take trades on these kind of setups **"); + + } + + + + + + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && !(marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FOURTH CASE: PRICE CLOSED ABOVE THE ZONE, WE STILL HAVNT TOOK A TRADE, AND WE ARE NOT GONNA TAKE IT + { + + + + marketObserver.setClosestResistanceWaiting(true); + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone i havnet took a trade, im gonna delete the zone , Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + else + if((marketObserver.getClosestResistanceZone() != NULL) && marketObserver.candleClosedAboveClosestResistanceZone(_timeFrame) && (marketObserver.getClosestResistanceZone().sellEntryManager.sellTradeTaken())) // FIFTH CASE: PRICE CLOSED ABOVE THE ZONE, WE TOOK THE TRADE, AND WE NEED TO CLOSE IT + { + marketObserver.setClosestResistanceWaiting(true); + + ChartRedraw(); // Make sure the chart is up to date + ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT); + SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,"** THIS MESSAGE SHOULD BE SEEN ONCE FOR THE CURRENT ZONE ** A candle closed above the resistance zone im in a sell and im gonna close it, and delete the zone, Symbol: " + _Symbol + " " + TimeToString(TimeLocal()), fileName); + marketObserver.getClosestResistanceZone().sellEntryManager.setTradeTakenStatus(false); + + // Make sure that the trades didnt hit the stop loss first + marketObserver.getClosestResistanceZone().sellTradeManager.cleanOrderDataStructures(); + for(int i=0; i<3; i++) + { + marketObserver.getClosestResistanceZone().sellTradeManager.closeTrade(i); + } + + string _idToDelete = marketObserver.getClosestResistanceZone().getId(); + deleteZoneWithGUI(_idToDelete); + + + } + + + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/candleStringDetector.ex5 b/shark_tiger/candleStringDetector.ex5 new file mode 100644 index 0000000..cd1a5fe Binary files /dev/null and b/shark_tiger/candleStringDetector.ex5 differ diff --git a/shark_tiger/candleStringDetector.mq5 b/shark_tiger/candleStringDetector.mq5 new file mode 100644 index 0000000..79f5850 --- /dev/null +++ b/shark_tiger/candleStringDetector.mq5 @@ -0,0 +1,98 @@ +//+------------------------------------------------------------------+ +//| candleStringDetector.mq5 | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" +#property version "1.00" +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ + +#include "Algo_Skeleton_Functions.mqh" + +int last_Color_candle = -1 ; +int daily_streak_counter = 0 ; + +string timeInStr = "--" ; + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int OnInit() + { +//--- + + + + return(INIT_SUCCEEDED); + } +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) + { +//--- + + } +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() + { +//--- + + if(newCandleDetectorDaily.isNewCandle()) + { + //objectsManager.drawVerticalLine(clrAliceBlue, TimeCurrent()); + if(candleClosedBullish(PERIOD_D1,1) && last_Color_candle != 1) // this is the first daily bullish candle + { + + // save the timeInStr and the daily streak counter in a row in excel + string fileName = "daily_candle_streak.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/); + FileSeek(fileHandle,0,SEEK_END); + FileWrite(fileHandle,timeInStr,daily_streak_counter); + + FileClose(fileHandle); + + datetime time = TimeCurrent(); // save the date of this day + timeInStr = TimeToString(time,TIME_DATE); + last_Color_candle = 1 ; // convert the flag to bullish + daily_streak_counter = 0 ; // reset the counter + + } + else if(candleClosedBullish(PERIOD_D1,1) && last_Color_candle == 1) + { + + daily_streak_counter++ ; + } + + + if(candleClosedBearish(PERIOD_D1,1) && last_Color_candle != 0) // this is the first daily bearish candle + { + + // save the timeInStr and the daily streak counter in a row in excel + string fileName = "daily_candle_streak.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode + int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/); + FileSeek(fileHandle,0,SEEK_END); + FileWrite(fileHandle,timeInStr,daily_streak_counter); + + FileClose(fileHandle); + + datetime time = TimeCurrent(); + timeInStr = TimeToString(time,TIME_DATE); + last_Color_candle = 0 ; + daily_streak_counter = 0; + } + + else if(candleClosedBearish(PERIOD_D1,1) && last_Color_candle == 0){ + daily_streak_counter++ ; + } + + + } + + } +//+------------------------------------------------------------------+ diff --git a/shark_tiger/library_functions.mqh b/shark_tiger/library_functions.mqh new file mode 100644 index 0000000..11c94bb --- /dev/null +++ b/shark_tiger/library_functions.mqh @@ -0,0 +1,765 @@ +//+------------------------------------------------------------------+ +//| library_functions.mqh | +//| Copyright 2023, MetaQuotes Ltd. | +//| https://www.mql5.com | +//+------------------------------------------------------------------+ +#property copyright "Copyright 2023, MetaQuotes Ltd." +#property link "https://www.mql5.com" + + + +#include + + + +int findMondayFromLastPeriodWeeks(int _period); + +// FRACTALS RELATED FUNCTIONS +bool isLowFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame); // checks if the given index candle is, a low fractal of the left, right periods +bool isHighFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame); // checks if the given index candle is, a high fractal of the left, right periods + +// TIME FRAME RELATED FUNCTIONS +string getChartTimeFrameInString() ; // gets the chart time frame in string format +string timeFrameToString(ENUM_TIMEFRAMES _timeFrame); + +// SESSIONS RELATED FUNCTIONS +bool sessionIsNy(); // checks if the session is ny +bool sessionIsLondon(); // checks if the session is london +bool sessionIsTokyo(); + + + +// TRADE RELATED FUNCTIONS +bool closePartialFromAllPositions(double partialAmount) ; // closes partial of all open positions the partial is partialAmount (parameter) +bool closePartialFromSpecificPosition(ulong posTicket, double partialToClose) ; // closes a partial from the given position ticket +bool stopLossIsValidBuys(double stopLoss, double _maxPipsRiskAmount); +bool stopLossIsValidSells(double stopLoss,double _maxPipsRiskAmount); +double positionProfitInPips(ulong posTicket); // returns the position profit in pips +double positionStopLoss(ulong posTicket); +void positionTrailStopLoss(ulong posTicket, double newStopLoss, double takeProfit); + + + +// CANDLE ANATOMY RELATED FUNCTIONS +bool buyBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody); // checks if the buy breaker candle is big enough +bool sellBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody); // checks if the sell breaker candle is big enough +bool bearishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection); // this function assumes that the previous candle is bearish +bool bullishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection); // this function assumes that the previous candle is bullish +double retestWickFormedOnTheFirstHalfOfCandle(ENUM_TIMEFRAMES _mainTimeFrame, ENUM_TIMEFRAMES _secondaryTimeFrame); +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index); +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index); +bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index); +bool candleBodyIsValid(ENUM_TIMEFRAMES _timeFrame, int _index); // this function is used for enhancing the detection of supports/resistances + + +// SUPPORT AND RESISTANCE RELATED FUNCTIONS +bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index=0); // _index = 0 is the default state which is a specific case of the general function with _index = i +bool resistancePatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index=0);// _index = 0 is the default state which is a specific case of the general function with _index = i + + + + + + +/* WARNING FOR THE NEXT FUNCTION*/ +/* IF A FRIDAY WAS NOT ON THE BROKER, THE FUNCTION WILL NOT COUNT THE WEEK. MAKE SURE BEFORE APPLYING IT TO SEE VISUALLY THAT IT WAS LAUNCHED RIGHT */ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +int findMondayFromLastPeriodWeeks(int _period) { // _period = 1 means the previous week. _period = 2 means 2 weeks ago. and so on ... + + int startCountFromIndex = 0 ; + datetime localTime = TimeLocal(); + MqlDateTime dateTimeStructure ; + TimeToStruct(localTime,dateTimeStructure); + int dayOfTheWeek = dateTimeStructure.day_of_week; + int hourOfTheDay = dateTimeStructure.hour; + + if(dayOfTheWeek == 5) { // means if we called the function on friday , start counting from the candle of index 25, because our goal is to reach the pervious week friday, so we know we are in the previous week + startCountFromIndex = 25 ; + } + if(dayOfTheWeek == 6 || dayOfTheWeek == 7) { + Alert("Its saturday/sunday start next week !"); + } + + MqlDateTime shiftedBarTimeStruct ; + int weeksPassed = 0 ; // count of how many weeks we passed. it starts with 0 since we start at week 0. and will end in _period + int lockCounter = 0; + int i = startCountFromIndex ; // i represents the distance from the moment we started. by the end of the function it will point to the first monday of the desired week that we want + while(weeksPassed < _period) { + datetime shiftedBarTime=iTime(_Symbol,PERIOD_CURRENT,i); // take the date of the current candle + TimeToStruct(shiftedBarTime,shiftedBarTimeStruct); // change the date to a struct + + if(shiftedBarTimeStruct.day_of_week == 5 && lockCounter == 0) { // if we reached friday, add the weeksPassed by 1 and lock the block for the next friday + weeksPassed++; // each time we reach a friday this means we are in a previous week. (we are counting the weeks starting from the current moment and going back in time) + lockCounter++; + + } else if(shiftedBarTimeStruct.day_of_week == 5 && lockCounter > 0) { // stay locked until we pass the current friday + lockCounter++ ; + } else if(shiftedBarTimeStruct.day_of_week == 4) { // if reached thursday , then release the lock + lockCounter = 0; + } + i++; + } + + Print("weeks passed value is: "+ weeksPassed); + return i-2 ; + +} + + +// ************************ FRACTALS FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool isLowFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame) { // checks if the given index candle is, a low fractal of the left, right periods + + for(int i = index+1 ; i < (index + leftPeriod + 1) ; i++) { + if(!(iLow(Symbol(),timeFrame,index) <= iLow(Symbol(),timeFrame,i))) { + return false; + } + } + + + if(index > rightPeriod) { // this means we have enough candles to the right + + for(int j = index-1 ; (j > index - rightPeriod - 1) ; j--) { + if(!(iLow(Symbol(),timeFrame,index) <= iLow(Symbol(),timeFrame,j))) { + return false ; + } + } + } + else{ + return false ; + } + + + return true ; +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool isHighFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame) { // checks if the given index candle is, a high fractal of the left, right periods + + for(int i = index+1 ; i < (index + leftPeriod + 1) ; i++) { + if(!(iHigh(Symbol(),timeFrame,index) >= iHigh(Symbol(),timeFrame,i))) { + return false; + } + } + + if(index > rightPeriod) { // this means we have enough candles to the right + + for(int j = index-1 ; (j > index - rightPeriod - 1) ; j--) { + if(!(iHigh(Symbol(),timeFrame,index) >= iHigh(Symbol(),timeFrame,j))) { + return false ; + } + } + } + else{ + return false ; + } + + return true ; +} + + + + + + +// ************************ TIME FRAMES FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +string getChartTimeFrameInString() { + + ENUM_TIMEFRAMES period = Period(); + + switch(period) { + + case PERIOD_M1: + return "PERIOD_M1" ; + break; + + case PERIOD_M2: + return "PERIOD_M2" ; + break; + + case PERIOD_M3: + return "PERIOD_M3" ; + break; + + case PERIOD_M4: + return "PERIOD_M4" ; + break; + + case PERIOD_M5: + return "PERIOD_M5" ; + break; + + case PERIOD_M6: + return "PERIOD_M6" ; + break; + case PERIOD_M10: + return "PERIOD_M10" ; + break; + + case PERIOD_M12: + return "PERIOD_M12" ; + break; + + case PERIOD_M15: + return "PERIOD_M15" ; + break; + + case PERIOD_M20: + return "PERIOD_M20" ; + break; + + case PERIOD_M30: + return "PERIOD_M30" ; + break; + case PERIOD_H1: + return "PERIOD_H1" ; + break; + + case PERIOD_H2: + return "PERIOD_H2" ; + break; + + case PERIOD_H3: + return "PERIOD_H3" ; + break; + + case PERIOD_H4: + return "PERIOD_H4" ; + break; + + case PERIOD_H6: + return "PERIOD_H6" ; + break; + + case PERIOD_H8: + return "PERIOD_H8" ; + break; + case PERIOD_H12: + return "PERIOD_H12" ; + break; + + case PERIOD_D1: + return "PERIOD_D1" ; + break; + case PERIOD_W1: + return "PERIOD_W1" ; + break; + + case PERIOD_MN1: + return "PERIOD_MN1" ; + break; + + } + + return "" ; +} + + +string timeFrameToString(ENUM_TIMEFRAMES _timeFrame){ + switch(_timeFrame) { + + case PERIOD_M1: + return "PERIOD_M1" ; + break; + + case PERIOD_M2: + return "PERIOD_M2" ; + break; + + case PERIOD_M3: + return "PERIOD_M3" ; + break; + + case PERIOD_M4: + return "PERIOD_M4" ; + break; + + case PERIOD_M5: + return "PERIOD_M5" ; + break; + + case PERIOD_M6: + return "PERIOD_M6" ; + break; + case PERIOD_M10: + return "PERIOD_M10" ; + break; + + case PERIOD_M12: + return "PERIOD_M12" ; + break; + + case PERIOD_M15: + return "PERIOD_M15" ; + break; + + case PERIOD_M20: + return "PERIOD_M20" ; + break; + + case PERIOD_M30: + return "PERIOD_M30" ; + break; + case PERIOD_H1: + return "PERIOD_H1" ; + break; + + case PERIOD_H2: + return "PERIOD_H2" ; + break; + + case PERIOD_H3: + return "PERIOD_H3" ; + break; + + case PERIOD_H4: + return "PERIOD_H4" ; + break; + + case PERIOD_H6: + return "PERIOD_H6" ; + break; + + case PERIOD_H8: + return "PERIOD_H8" ; + break; + case PERIOD_H12: + return "PERIOD_H12" ; + break; + + case PERIOD_D1: + return "PERIOD_D1" ; + break; + case PERIOD_W1: + return "PERIOD_W1" ; + break; + + case PERIOD_MN1: + return "PERIOD_MN1" ; + break; + + } + + return "" ; + +} + + + + + +// ************************ SESSIONS FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool sessionIsNy() { + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 12 && mqldt.hour <= 20) { + return true ; + } + + return false ; + +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool sessionIsLondon() { + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 8 && mqldt.hour <= 12) { + return true ; + } + + return false ; + +} + + +bool sessionIsTokyo(){ + MqlDateTime mqldt ; + datetime currTime = TimeCurrent(mqldt); + + if(mqldt.hour >= 4 && mqldt.hour <= 8) { + return true ; + } + + return false ; +} + + +// ************************ TRADE FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool closePartialFromAllPositions(double partialAmount) { + CTrade trade ; + for(uint i=0 ; i< PositionsTotal() ; i++) { + + ulong positionTicket = PositionGetTicket(i); + if(PositionSelectByTicket(positionTicket)) { + + double positionVolume = PositionGetDouble(POSITION_VOLUME); + double lotsToClose = positionVolume * partialAmount ; + if(trade.PositionClosePartial(positionTicket,NormalizeDouble(lotsToClose,2))) { + Print("Closed partials succesffully"); + return true ; + } else { + Print("Failed to close partials, Error: " + GetLastError()); + return false ; + } + + } + + + + } + return false ; + +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool closePartialFromSpecificPosition(ulong posTicket, double partialToClose) { + + CTrade trade ; + double positionVolume = PositionGetDouble(POSITION_VOLUME); + double lotsToClose = positionVolume * partialToClose ; + if(trade.PositionClosePartial(posTicket,NormalizeDouble(lotsToClose,2))) { + + return true ; + + } else { + return false ; + } + + + return false ; + +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool stopLossIsValidBuys(double stopLoss, double _maxPipsRiskAmount) { + + if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLoss < _maxPipsRiskAmount) { + return true ; + } + + return false ; +} + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +double positionProfitInPips(ulong posTicket) { + + double currentProfitInPips = -1 ; + if(PositionSelectByTicket(posTicket)) { + + double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT) ; + double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN); + + + if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { + currentProfitInPips = currentPrice - positionOpenPrice ; + } + + else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { + + currentProfitInPips = positionOpenPrice - currentPrice ; + } + } else { + + Comment("Error from positionProfitInPips() function: Failed to select position, Error " + GetLastError()); + } + + + + return currentProfitInPips ; + +} + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ + + +double positionStopLoss(ulong posTicket) { + + double posStopLoss = -1 ; + if(PositionSelectByTicket(posTicket)) { + posStopLoss = PositionGetDouble(POSITION_SL) ; + + } else { + Comment("Error from positionStopLoss() function: Failed to select position, Error " + GetLastError()); + } + + return posStopLoss; + +} + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool stopLossIsValidSells(double stopLoss,double _maxPipsRiskAmount) { + if(stopLoss - SymbolInfoDouble(_Symbol, SYMBOL_BID) < _maxPipsRiskAmount) { + return true ; + } + return false ; + +} + + + + +void positionTrailStopLoss(ulong posTicket, double newStopLoss, double takeProfit) { + + CTrade trade ; + trade.PositionModify(posTicket,newStopLoss,takeProfit); + + + +} + + +// ************************ CANDLE ANATOMY FUNCTIONS ************************ + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool buyBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody) { + + if((iClose(_Symbol,_timeFrame,1) - iOpen(_Symbol,_timeFrame,1)) >= _sizeOfBreakerCandleBody) { + return true ; + } else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr + " Bullish Breaker candle body is too small to take a trade !"); + return false ; + + } + +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool sellBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody) { + if((iOpen(_Symbol,_timeFrame,1) - iClose(_Symbol,_timeFrame,1)) >= _sizeOfBreakerCandleBody) { + return true ; + } else { + datetime currTime = TimeCurrent(); + string timeInStr = TimeToString(currTime,TIME_MINUTES); + Comment(timeInStr + " Bearish Breaker candle body is too small to take a trade !"); + return false ; + + } + +} + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool bearishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection) { // this function assumes that the previous candle is bearish + + double upperWickLength = iHigh(_Symbol,_timeFrame,index) - iOpen(_Symbol,_timeFrame,index) ; + double totalCandleLength = iHigh(_Symbol,_timeFrame,index) - iClose(_Symbol,_timeFrame,index); + if((upperWickLength / totalCandleLength) >= wickRatioRejection) { // this means the candle is weak + Comment("Bearish Candle Is Weak"); + return true ; + } else { + return false ; + } +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool bullishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection) { // this function assumes that the previous candle is bullish + double lowerWickLength = iOpen(_Symbol,_timeFrame,index) - iLow(_Symbol,_timeFrame,index) ; + double totalCandleLength = iClose(_Symbol,_timeFrame,index) - iLow(_Symbol,_timeFrame,index) ; + + if((lowerWickLength/totalCandleLength) >= wickRatioRejection) { // this means the candle is weak + Comment("Bullish Candle is weak"); + return true ; + } else { + return false ; + } +} +//+------------------------------------------------------------------+ + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose >candleOpen) { // the candle closed bullish + + return true ; + } + return false ; +} + + + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) { + + + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + + if(candleClose < candleOpen) { // the candle closed bullish + + return true ; + } + return false ; +} +//+------------------------------------------------------------------+ + + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index) { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + + if(candleClose == candleOpen) { + return true; + } else { + return false; + } + +} + +//+------------------------------------------------------------------+ +//| | +//+------------------------------------------------------------------+ +bool candleBodyIsValid(ENUM_TIMEFRAMES _timeFrame, int _index) { + double candleClose = iClose(_Symbol,_timeFrame,_index); + double candleOpen = iOpen(_Symbol,_timeFrame,_index); + double candleHigh = iHigh(_Symbol,_timeFrame,_index); + double candleLow = iLow(_Symbol,_timeFrame,_index); + double topWickSize ; + double bottomWickSize ; + double candleBodySize ; + + if(candleClosedBearish(_timeFrame,_index)) { + topWickSize = candleHigh - candleOpen ; + bottomWickSize = candleClose - candleLow ; + candleBodySize = candleOpen - candleClose ; + + } else if(candleClosedBullish(_timeFrame,_index)) { + topWickSize = candleHigh - candleClose ; + bottomWickSize = candleOpen - candleLow ; + candleBodySize = candleClose - candleOpen ; + } else if(candleClosedDoji(_timeFrame,_index)) { + + return false ; + } + + + if((topWickSize >= (15*candleBodySize)) || (bottomWickSize >= (15* candleBodySize))) { // 8 is fixed number , + //which means that if i find a candle's wick that is 15 times bigger than the body then i dont want to consider it when detecting a support or resistance, this is for the cases that the candle looks almost like a doji but not an actual doji + return false ; + } + + return true ; +} + +/*double retestWickFormedOnTheFirstHalfOfCandle(ENUM_TIMEFRAMES _mainTimeFrame, ENUM_TIMEFRAMES _secondaryTimeFrame){ + + if(candleClosedBullish(_mainTimeFrame,1)){ // previous candle closed bullish, this means checking a wick on a bullish candle on the main timeframe + if(candleClosedBearish(_secondaryTimeFrame)){ + + } + } + + + if(candleClosedBearish(_mainTimeFrame)){ // previous candle closed bullish, this means checking a wick on a bearish candle on the main timeframe + + } + +} */ + + +// ************************ SUPPORT AND RESISTANCE RELATED FUNCTIONS ************************ + + +/*bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame){ // this is a spicific case of the next function, the _index parameter here is 0 + if((candleClosedBearish(_timeFrame,2) && candleClosedBullish(_timeFrame,1) && candleBodyIsValid(_timeFrame,1)&& candleBodyIsValid(_timeFrame,2)) + || (candleClosedBearish(_timeFrame,3) && candleClosedDoji(_timeFrame,2) && candleClosedBullish(_timeFrame,1)) + || candleClosedBearish(_timeFrame,3) && candleBodyIsValid(_timeFrame,3) && !candleBodyIsValid(_timeFrame,2) && candleClosedBullish(_timeFrame,1) && candleBodyIsValid(_timeFrame,1)) { + return true ; + + } + return false ; +}*/ + + +bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index = 0){ // this is the same previous function but with geniric index to detect the support on . its used for detecing old supports (that are not currently happeneing) + + +if((candleClosedBearish(_timeFrame,_index+2) && candleClosedBullish(_timeFrame,_index+1) && candleBodyIsValid(_timeFrame,_index+1)&& candleBodyIsValid(_timeFrame,_index+2)) + || (candleClosedBearish(_timeFrame,_index+3) && candleClosedDoji(_timeFrame,_index+2) && candleClosedBullish(_timeFrame,_index+1)) + || candleClosedBearish(_timeFrame,_index+3) && candleBodyIsValid(_timeFrame,_index+3) && !candleBodyIsValid(_timeFrame,_index + 2) && candleClosedBullish(_timeFrame,_index+1) + && candleBodyIsValid(_timeFrame,_index+1) ){ + return true ; + + } + return false ; + +} +bool resistancePatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index = 0){ // this is a spicific case of the next function + + if((candleClosedBullish(_timeFrame,_index+2) && candleClosedBearish(_timeFrame,_index+1) && candleBodyIsValid(_timeFrame,_index+2) && candleBodyIsValid(_timeFrame,_index+1)) + || (candleClosedBullish(_timeFrame,3) && candleClosedDoji(_timeFrame,2) && candleClosedBearish(_timeFrame,1) )){ + + return true ; + } + + return false ; +} +