//+------------------------------------------------------------------+ //| 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 // 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); } } //+-----------------------