1677 lines
67 KiB
Plaintext
1677 lines
67 KiB
Plaintext
//+------------------------------------------------------------------+
|
|
//| 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 <library_functions.mqh>
|
|
|
|
|
|
|
|
// 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<lowsContainer.getFreeIndex(); x++)
|
|
{
|
|
|
|
lowsContainer.getLowFractal(x).updateDistance(); // update the distance for every fractal in the container
|
|
|
|
}
|
|
|
|
|
|
if(isLowFractalByIndex(lowFractalIndex,leftPeriod,rightPeriod,tf) == true)
|
|
{
|
|
|
|
if(lowsContainer.getFreeIndex() > 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<highsContainer.getFreeIndex(); x++)
|
|
{
|
|
|
|
highsContainer.getHighFractal(x).updateDistance(); // update the distance for every fractal in the container
|
|
|
|
}
|
|
|
|
|
|
if(isHighFractalByIndex(highFractalIndex,leftPeriod,rightPeriod,tf) == true)
|
|
{
|
|
|
|
if(highsContainer.getFreeIndex() > 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 && time<sessionEnd))
|
|
return isOpen;
|
|
}
|
|
|
|
lastSymbol = symbol;
|
|
|
|
MqlDateTime mtime;
|
|
TimeToStruct(time, mtime);
|
|
datetime seconds = mtime.hour*3600+mtime.min*60+mtime.sec;
|
|
|
|
mtime.hour = 0;
|
|
mtime.min = 0;
|
|
mtime.sec = 0;
|
|
datetime dayStart = StructToTime(mtime);
|
|
datetime dayEnd = dayStart + 86400;
|
|
|
|
datetime fromTime;
|
|
datetime toTime;
|
|
|
|
sessionStart = dayStart;
|
|
sessionEnd = dayEnd;
|
|
|
|
for(int session = 0;; session++)
|
|
{
|
|
|
|
if(!SymbolInfoSessionTrade(symbol, (ENUM_DAY_OF_WEEK)mtime.day_of_week, session, fromTime, toTime))
|
|
{
|
|
sessionEnd = dayEnd;
|
|
isOpen = false;
|
|
return isOpen;
|
|
}
|
|
|
|
if(seconds<fromTime) // not inside a session
|
|
{
|
|
sessionEnd = dayStart + fromTime;
|
|
isOpen = false;
|
|
return isOpen;
|
|
}
|
|
|
|
if(seconds>toTime) // 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
//+-----------------------
|