Files
Financial-Markets-research/Algo_Skeleton_Functions.mqh
2025-07-11 08:43:07 +03:00

1959 lines
75 KiB
Plaintext

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