Initial comit of TrendBreakouts

This commit is contained in:
CristianAlam
2025-07-11 08:43:07 +03:00
commit 2ff4d9d569
148 changed files with 61835 additions and 0 deletions
File diff suppressed because it is too large Load Diff
Binary file not shown.
+404
View File
@@ -0,0 +1,404 @@
//+------------------------------------------------------------------+
//| Breakout_Fractals.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
//#include "Algo_Skeleton_Functions.mqh"
#include "Phoenix_Functions.mqh"
bool trailWhenMarketOpensDaily = false ;
int OnInit()
{
//---
//---
for(int i=0; i<NUM_MAX_ALLOWED_TRADES ; i++)
{
BuyActiveTradesArray[i] = NULL ;
SellActiveTradesArray[i] = NULL ;
}
objectsManager.addTextTiger();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
Print("Buys Count: " + buysCount);
Print("Sells Count: " + sellsCount);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
cleanBuyTradesArr();
cleanSellTradesArr();
if(newCandleDetectorM5.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_M5){
trailAllOpenPositionsIfNeeded(PERIOD_M5);
}
if(TIME_FRAME_TO_TRADE == PERIOD_M5)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorM15.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_M15){
trailAllOpenPositionsIfNeeded(PERIOD_M15);
}
if(TIME_FRAME_TO_TRADE == PERIOD_M15)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorM30.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_M30){
trailAllOpenPositionsIfNeeded(PERIOD_M30);
}
if(TIME_FRAME_TO_TRADE == PERIOD_M30)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorH1.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_D1 && trailWhenMarketOpensDaily){
trailAllOpenPositionsIfNeeded(PERIOD_D1);
trailWhenMarketOpensDaily = false ;
}
if(APPLY_TRAIL && (TRAIL_TIME_FRAME == PERIOD_H1)){
Print("Entered the trail !");
trailAllOpenPositionsIfNeeded(PERIOD_H1);
}
if(TIME_FRAME_TO_TRADE == PERIOD_H1)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorH4.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_H4){
trailAllOpenPositionsIfNeeded(PERIOD_H4);
}
if(TIME_FRAME_TO_TRADE == PERIOD_H4)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorDaily.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_D1){
trailWhenMarketOpensDaily = true ;
trailAllOpenPositionsIfNeeded(PERIOD_D1);
}
objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
if(newCandleDetectorWeekly.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_W1){
trailAllOpenPositionsIfNeeded(PERIOD_W1);
}
objectsManager.drawVerticalLine(clrRed, TimeCurrent());;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void handleSells()
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": im taking a sell !");
if(((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1))
{
double stopLossPrice = calculateStopLossBasedOnFractalsSells(stopLossFractalsPeriod,stopLossTimeFrame) ;
stopLossPrice = stopLossPrice + stopLossAboveWickByActual ;
if(stopLossIsValidSells(stopLossPrice,maxPipsRiskAmountActual))
{
if(rrFactor != -1 && lotSize == -1) // tp based rr metehod
{
if(SELLS_ALLOWED){
double stopLossInPips = stopLossPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID) ;
double netTp = rrFactor * stopLossInPips ;
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_BID)- netTp) ;
SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge);
tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge);
SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array
sellsCount++;
}
}
else
if(rrFactor == -1 && lotSize == -1) // tp based net take profit method
{
if(SELLS_ALLOWED){
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_BID)- netTakeProfit) ;
SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge);
tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge);
SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array
sellsCount++;
}
}
else if(lotSize != -1){ // taking an entry based on fixed lot , and managing risk via trail
if(SELLS_ALLOWED){
activeTradeId = sellEntryManager.takeSellTradeTiger(lotSize,stopLossPrice) ;
SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge);
tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge);
SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array
sellsCount++;
}
}
}
else
{
Print("stop loss is not valid sells!");
}
}
else
{
Comment("i cant take a trade because the arrray is full");
}
currentSupportLowerEdge = -1;
currentSupportHighEdge = -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void handleBuys()
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": im taking a buy !");
if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1))
{
Print("indexToNewTrade:-------------------------------------------- " + indexToNewTrade);
double stopLossPrice = calculateStopLossBasedOnFractalsBuys(stopLossFractalsPeriod,stopLossTimeFrame);
stopLossPrice = stopLossPrice - stopLossUnderWickByActual ;
if(stopLossIsValidBuys(stopLossPrice,maxPipsRiskAmountActual))
{
if(rrFactor != -1 && lotSize == -1)
{
if(BUYS_ALLOWED){
double stopLossInPips = SymbolInfoDouble(_Symbol,SYMBOL_ASK) - stopLossPrice ;
double netTp = rrFactor * stopLossInPips ;
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+ netTp) ;
BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge);
tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge);
BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array
buysCount++;
}
}
else
if(rrFactor == -1 && lotSize == -1)
{
if(BUYS_ALLOWED){
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+ netTakeProfit) ;
BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge);
tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge);
BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array
buysCount++;
}
}
else if(lotSize != -1){ // taking an entry based on fixed lot , and managing risk via trail
if(BUYS_ALLOWED){
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotSize,stopLossPrice) ;
BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge);
tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge);
BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array
buysCount++;
}
}
}
else
{
Print("stop loss is not valid buys !");
}
}
else
{
Comment("i cant take a trade because the arrray is full");
}
currentResistanceHighEdge = -1;
currentResistanceLowEdge = -1;
}
//+------------------------------------------------------------------+
+113
View File
@@ -0,0 +1,113 @@
//+------------------------------------------------------------------+
//| BuyEntryManager.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "BuyRejectionDetector.mqh"
#include <Trade/Trade.mqh>
CTrade tradeLong ;
class BuyEntryManager
{
private:
bool longTradeTaken ;
bool waitingForRejectionCandle;
bool waitingForRetracement ;
public:
BuyEntryManager();
~BuyEntryManager();
BuyRejectionDetector* buyRejectionDetector ;
bool isWaitingForRejectionCandle(){return waitingForRejectionCandle ;}
void setWaitingForRejectionCandle(bool _setting){waitingForRejectionCandle = _setting ;}
bool isWaitingForRetracement(){return waitingForRetracement;}
void setWaitingForRetracement(bool _setting){waitingForRetracement = _setting ;}
bool buyTradeTaken();
void setTradeTakenStatus(bool _status){longTradeTaken = _status ; Print("long trade taken flag has been set to true");}
ulong takeBuyTrade(double _lots,double _stopLoss);
ulong takeBuyTradeTiger(double _lots,double _stopLoss,double _takeProfit);
ulong takeBuyTradeTiger(double _lots,double _stopLoss);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyEntryManager::BuyEntryManager()
{
buyRejectionDetector = new BuyRejectionDetector();
longTradeTaken = false ;
waitingForRejectionCandle = false ;
waitingForRetracement = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyEntryManager::~BuyEntryManager()
{
delete buyRejectionDetector ;
}
//+------------------------------------------------------------------+
bool BuyEntryManager:: buyTradeTaken(){
return longTradeTaken ;
}
ulong BuyEntryManager:: takeBuyTrade(double _lots, double _stopLoss){
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong BuyEntryManager:: takeBuyTradeTiger(double _lots,double _stopLoss, double _takeProft){ // first version, take the buy with fixed tp
double netTp = _takeProft - SymbolInfoDouble(_Symbol, SYMBOL_ASK) ;
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss,SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTp);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong BuyEntryManager:: takeBuyTradeTiger(double _lots,double _stopLoss){ // second version, take the buy without a fixed tp
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
+85
View File
@@ -0,0 +1,85 @@
//+------------------------------------------------------------------+
//| BuyGandalf.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade/Trade.mqh>
CTrade tradeLong ;
class BuyGandalf
{
private:
bool longTradeTaken ;
ulong longTrades[10] ;
public:
BuyGandalf();
~BuyGandalf();
bool buyTradeTaken();
void setTradeTakenStatus(bool _status){longTradeTaken = _status ; Print("long trade taken flag has been set to true");}
ulong takeBuyTrade(double _lots,double _stopLoss);
ulong takeBuyTradeGandalf(double _lots,double _stopLoss);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyGandalf::BuyGandalf()
{
longTradeTaken = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyGandalf::~BuyGandalf()
{
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
bool BuyGandalf:: buyTradeTaken(){
return longTradeTaken ;
}
ulong BuyGandalf:: takeBuyTrade(double _lots, double _stopLoss){
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong BuyGandalf:: takeBuyTradeGandalf(double _lots,double _stopLoss){
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
+53
View File
@@ -0,0 +1,53 @@
//+------------------------------------------------------------------+
//| BuyRejectionDetector.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class BuyRejectionDetector
{
private:
public:
BuyRejectionDetector();
~BuyRejectionDetector();
bool rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame);
bool rejectionByRangeFormed();
bool rejectionByWicksFormed();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyRejectionDetector::BuyRejectionDetector()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyRejectionDetector::~BuyRejectionDetector()
{
}
//+------------------------------------------------------------------+
bool BuyRejectionDetector:: rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame){
double rejectionCandleClose = iClose(_Symbol,_timeFrame,1);
double rejectionCandleOpen = iOpen(_Symbol,_timeFrame,1);
double rejectionCandleHigh = iHigh(_Symbol,_timeFrame,1) ;
double rejectionCandleHigherWickSize ;
double rejectionCandleBodySize ;
if( rejectionCandleClose > rejectionCandleOpen ){ // the previous candle closed bullish
rejectionCandleHigherWickSize = rejectionCandleHigh - rejectionCandleClose;
rejectionCandleBodySize = rejectionCandleClose - rejectionCandleOpen;
if(rejectionCandleBodySize >= rejectionCandleHigherWickSize){
return true ;
}
}
return false ;
}
+587
View File
@@ -0,0 +1,587 @@
//+------------------------------------------------------------------+
//| BuyTradeManager.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <TradeManagersAttributes.mqh>
#include <Telegram_Handler.mqh>
#include <Trade/Trade.mqh>
CTrade tradeLongInTradeManager;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class BuyTradeManager
{
private:
int tradeId;
ulong rejectionByOneCandleTradeArray[3];
string firstSecureMethod ;
bool firstSecureMethodFound;
int numberOfTakeProfits ;
bool securedFirstLevelProfit ;
bool securedSecondLevelProfit;
double partialToClose ;
bool isTradeRunning ;
public:
BuyTradeManager();
~BuyTradeManager();
void fillRejectionByOneCandleTradeArray(int _index, int _id) {rejectionByOneCandleTradeArray[_index] = _id ;}
ulong getRejectionByOneCandleTradeTicket(int _index) {return rejectionByOneCandleTradeArray[_index] ;}
void printRejectionByOneCandleTradeArray();
void checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars);
string findFirstSecureMethod();
bool reachedProfitRatio(int _indexInArr);
bool closeTrade(int _indexInArr);
bool positionBreakEven(int _indexInArr);
void addTpAtIndex(int _index, double tpPrice) {tpArray[_index] = tpPrice;}
int countRemainingTakeProfits();
bool reachedClosestTakeProfit();
void deleteClosestTp();
int findClosestTpIndex();
void cleanOrderDataStructures();
void setTradeRunning(bool _setting) {isTradeRunning = _setting ;}
bool tradeIsRunning() {return isTradeRunning ;}
double tpArray[3];
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyTradeManager::BuyTradeManager()
{
for(int i=0; i<3; i++)
{
tpArray[i] = -1;
}
securedFirstLevelProfit = false ;
securedSecondLevelProfit = false ;
firstSecureMethodFound = false ;
firstSecureMethod = "NOT_FOUND" ;
partialToClose = -1 ;
isTradeRunning = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyTradeManager::~BuyTradeManager()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BuyTradeManager:: printRejectionByOneCandleTradeArray()
{
Print("Printing the tickets :");
for(int i=0 ; i<3 ; i++)
{
Print((int)rejectionByOneCandleTradeArray[i]);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BuyTradeManager:: checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars)
{
if(securedFirstLevelProfit == false) // in this case im searching for 2 cases: either RR 1:1.5 , OR reaching the first TP , if any of them happened im gonna close half the order and updatae the remaining stop losses
{
if(!firstSecureMethodFound)
{
firstSecureMethod = findFirstSecureMethod();
if(firstSecureMethod != "FAILED")
{
firstSecureMethodFound = true ;
}
else
if(firstSecureMethod == "FAILED")
{
Print("Failed to find the first secure method, go check the function : findFirstSecureMehod() !");
}
}
if(firstSecureMethodFound == true)
{
if(firstSecureMethod == "RATIO_METHOD")
{
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(reachedProfitRatio(0))
{
ChartRedraw(); // Make sure the chart is up to date
if(closeTrade(0)) // close the half
{
rejectionByOneCandleTradeArray[0] = -1;
Print("Closed Half Of the position due to reaching the first secure Ratio!");
}
else
{
Print("Failed Closing Half of the order by reaching the first secure Ratio !");
}
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(positionBreakEven(1)) // put the first quarter at break even
{
Print(" First quarter has been put into break even due to reaching the first secure Ratio!");
}
else
{
Print("Failed to Put the first quarter into break even");
}
numberOfTakeProfits = countRemainingTakeProfits();
Print("Number of remaining tps is: " + numberOfTakeProfits);
securedFirstLevelProfit = true ;
}
}
else
if(firstSecureMethod == "FIRST_TP_METHOD")
{
if(countRemainingTakeProfits() > 1) // there is at least 2 tp in the tp Array (because if this is the last tp then we want to close the whole order and not just a part of it)
{
if(reachedClosestTakeProfit()) // 2. Check if reached the first Tp
{
ChartRedraw(); // Make sure the chart is up to date
ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
// close the first half and update remaining partials sl's and delete the closest take profit from the array
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(closeTrade(0)) // close the half
{
rejectionByOneCandleTradeArray[0] = -1;
Print("Closed Half Of the position due to reaching the first TP!");
}
else
{
Print("Failed Closing Half of the order by reaching the first TP !");
}
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(positionBreakEven(1)) // put the first quarter at break even
{
Print(" First quarter has been put into break even due to reaching the first TP!");
}
else
{
Print("Failed to Put the first quarter into break even");
}
deleteClosestTp();
numberOfTakeProfits = countRemainingTakeProfits(); // update the number of remaining take profits
// calculate the remaining tps
Print("Number of remaining tps is: " + numberOfTakeProfits);
Print("TP ARRY: " + tpArray[0] + ", " + tpArray[1] + " , " + tpArray[2]);
securedFirstLevelProfit = true ;
}
}
else
if(numberOfTakeProfits = countRemainingTakeProfits() == 1)
{
if(reachedClosestTakeProfit())
{
// close everything remained
}
}
}
}
}
else
if(securedFirstLevelProfit == true) // after securing the first level i just want to close the remaining partials by reaching the tp's
{
if(countRemainingTakeProfits() == 1)
{
if(reachedClosestTakeProfit())
{
// close everything
cleanOrderDataStructures();
for(int i=0 ; i<3 ; i++)
{
closeTrade(i);
}
Print("Closed every thing because price reached the last Take Profit !");
ChartRedraw(); // Make sure the chart is up to date
deleteClosestTp();
}
}
else
if(countRemainingTakeProfits() > 1)
{
if(reachedClosestTakeProfit())
{
cleanOrderDataStructures();
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[1])) // DEALING WITH THE FIRST QUARTER
{
double currentLot = PositionGetDouble(POSITION_VOLUME);
if(partialToClose == -1)
{
partialToClose = currentLot/numberOfTakeProfits ;
}
if(tradeLongInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[1],NormalizeDouble(partialToClose,2)))
{
uint res = tradeLongInTradeManager.ResultRetcode();
if(res == 10009)
{
Print("Closed Partials successfully on the first quarter !");
}
else
{
Print("The returned code is: " + res + " go check what it means !");
}
}
}
else
{
Print("Failed to select position by ticket! , Error: " + GetLastError());
Print("The EA tried to close partials on the first quarter, but it is closed, probably due to break even and thats why it couldnt select the order !");
}
cleanOrderDataStructures();
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[2])) // DEALING WITH THE SECOND QUARTER
{
if(PositionGetDouble(POSITION_SL) < PositionGetDouble(POSITION_PRICE_OPEN)) // this is to put the second quarter at break even if its not already at break even
{
positionBreakEven(2);
}
double currentLot = PositionGetDouble(POSITION_VOLUME);
if(partialToClose == -1)
{
partialToClose = currentLot/numberOfTakeProfits ;
}
if(tradeLongInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[2],NormalizeDouble(partialToClose,2)))
{
uint res = tradeLongInTradeManager.ResultRetcode();
if(res == 10009)
{
Print("Closed Partials successfully on the second quarter!");
}
else
{
Print("The returned code is: " + res + " go check what it means !");
}
}
}
deleteClosestTp();
Print("Number Of Remained tps is: " + countRemainingTakeProfits());
ChartRedraw(); // Make sure the chart is up to date
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string BuyTradeManager:: findFirstSecureMethod()
{
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[0]))
{
double positionStopLoss = PositionGetDouble(POSITION_SL);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double firstTakeProfit = tpArray[findClosestTpIndex()];
if(((firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) > firstSecureRatio)) // firstTp > ratio
{
Print("Found the first profit secure method !");
Print("The first TP RR is: 1:" + (firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) + "the firstSecureRatio is: 1:" + firstSecureRatio);
Print("The tp ratio is greater than the firstSecure so:");
Print("The first secure method is RATIO_METHOD");
return"RATIO_METHOD";
}
else
if((firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss)< firstSecureRatio)
{
Print("Found the first profit secure method !");
Print("The first TP RR is: 1:" + (firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) + "the firstSecureRatio is: 1:" + firstSecureRatio);
Print("The tp ratio is less than the firstSecure so:");
Print("The first secure method is FIRST_TP_METHOD");
return "FIRST_TP_METHOD" ;
}
}
else
{
Print("Failed to select position by ticket 1, Error: " + GetLastError());
}
return "FAILED" ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BuyTradeManager:: reachedProfitRatio(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket))
{
if(PositionGetDouble(POSITION_PROFIT)/(0.5*riskDollars) >= firstSecureRatio) // checking if the first half of the contract reached the ratio of first secure profit
{
Print("reached profit ratio !");
return true ;
}
}
else
{
Print("Failed to select the position by ticket 4 ,Error: " + GetLastError());
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BuyTradeManager:: closeTrade(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket))
{
// close the first half and update remaining partials sl's
if(tradeLongInTradeManager.PositionClose(_ticket))
{
return true ;
}
else
{
Print("Failed to close positon, Error:" + GetLastError());
return false;
}
}
else
{
Print("Failed to select position by ticket , Error: "+ GetLastError());
return false;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BuyTradeManager:: positionBreakEven(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket)) // select the first quarter
{
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double positionTp = PositionGetDouble(POSITION_TP);
double positionSl = PositionGetDouble(POSITION_SL);
if(tradeLongInTradeManager.PositionModify(_ticket,openPrice,positionTp))
{
return true ;
}
else
{
Print("Failed to modify oder , ERROR: " + GetLastError());
return false ;
}
}
else
{
Print("Failed to select position by ticket ");
return false ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int BuyTradeManager:: countRemainingTakeProfits()
{
int counter = 0 ;
for(int i=0; i<3 ; i++)
{
if(tpArray[i] != -1)
{
counter++ ;
}
}
return counter;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BuyTradeManager:: deleteClosestTp()
{
int closestTpIndex =findClosestTpIndex();
tpArray[closestTpIndex] = -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int BuyTradeManager:: findClosestTpIndex()
{
int closestTpIndex = 0;
int closestTpValue = 1000000 ; // dummy value
for(int i=0; i<3; i++)
{
if(tpArray[i] != -1 && tpArray[i] < closestTpValue)
{
closestTpValue = tpArray[i];
closestTpIndex = i ;
}
}
return closestTpIndex ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BuyTradeManager:: reachedClosestTakeProfit()
{
double closestTakeProfitValue = tpArray[findClosestTpIndex()];
//Print("im in reached closest take profit function ,the current price is: " + SymbolInfoDouble(_Symbol, SYMBOL_BID) + " and the tp is: " + closestTakeProfitValue);
if(SymbolInfoDouble(_Symbol, SYMBOL_BID) >= closestTakeProfitValue) // we are looking for the BID , because reaching a tp in a buy trade means we are selling, so we want our take profit value, to be at least as the BID price (because we want to find someone to buy it from us at this price)
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BuyTradeManager:: cleanOrderDataStructures()
{
// this is to make sure, that every closed order is removed from the data strucutre !
for(int i=0; i<3; i++)
{
if(!PositionSelectByTicket(rejectionByOneCandleTradeArray[i]))
{
if(GetLastError() == 4753)
{
rejectionByOneCandleTradeArray[i] = -1 ;
}
}
}
}
//+------------------------------------------------------------------+
+72
View File
@@ -0,0 +1,72 @@
//+------------------------------------------------------------------+
//| BuyTradeManagerTiger.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class BuyTradeManagerTiger
{
private:
ulong tradeId ;
string entryType ;
bool firstPartialSecured ;
bool secondPartialSecured ;
bool managedRisk ;
bool retestWickFormed ;
double retestWickLengthInPips ;
int riskManagementCandleCounter ;
double brokenResistanceLowerEdge ;
double brokenResistanceHigherEdge ;
public:
ulong getTradeId(){return tradeId ;}
bool riskAlreadyManaged(){return managedRisk ;}
void manageRisk(){managedRisk = true ;}
bool firstPartialIsSecured(){return firstPartialSecured ;}
void secureFirstPartial(){firstPartialSecured = true ;}
void setBrokenResistancetLowerEdge(double _brokenResistanceLowerEdge){brokenResistanceLowerEdge = _brokenResistanceLowerEdge ;}
void setBrokenResistanceHigherEdge(double _brokenResistanceHigherEdge){brokenResistanceHigherEdge = _brokenResistanceHigherEdge ;}
double getBrokenResistanceLowerEdge(){return brokenResistanceLowerEdge ;}
double getBrokenResistanceHigherEdge(){return brokenResistanceHigherEdge ;}
void incrementRiskManagementCandleCoutner(){riskManagementCandleCounter++ ;}
void decrementRiskManagementCandleCounter(){riskManagementCandleCounter-- ;}
int getRiskManagementCandleCounter(){return riskManagementCandleCounter ;}
void setRiskManagementCandleCounter(int count){ riskManagementCandleCounter = count ;}
BuyTradeManagerTiger(ulong _tradeId);
~BuyTradeManagerTiger();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyTradeManagerTiger::BuyTradeManagerTiger(ulong _tradeId)
{
tradeId = _tradeId ;
firstPartialSecured = false ;
secondPartialSecured = false ;
managedRisk = false ;
retestWickFormed = false ;
retestWickLengthInPips = 0 ;
riskManagementCandleCounter = 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyTradeManagerTiger::~BuyTradeManagerTiger()
{
}
//+------------------------------------------------------------------+
Binary file not shown.
+333
View File
@@ -0,0 +1,333 @@
//+------------------------------------------------------------------+
//| TigerObserver.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Algo_Skeleton_Functions.mqh"
long H4_SUPPORT_ZONE_CLR ;
long H4_RESISTANCE_ZONE_CLR ;
long H1_SUPPORT_ZONE_CLR;
long H1_RESISTANCE_ZONE_CLR;
long M30_SUPPORT_ZONE_CLR ;
long M30_RESISTANCE_ZONE_CLR ;
int OnInit()
{
//--- create timer
EventSetTimer(60);
// ONLY FOR VISULAZITAION ON STRATEGY TESTER
iClose(_Symbol,PERIOD_W1,1);
iClose(_Symbol,PERIOD_D1,1);
iClose(_Symbol,PERIOD_H4,5);
iClose(_Symbol,PERIOD_H1,5);
iClose(_Symbol,PERIOD_M30,5);
iClose(_Symbol,PERIOD_M15,5);
H4_SUPPORT_ZONE_CLR = clrBlack ;
H4_RESISTANCE_ZONE_CLR = clrBlack ;
if(ENTRY_BASED_H1_STRUCTURE == true && ENTRY_BASED_M30_STRUCTURE == false){
M30_SUPPORT_ZONE_CLR = clrBlack ;
M30_RESISTANCE_ZONE_CLR = clrBlack ;
H1_SUPPORT_ZONE_CLR = clrAliceBlue ;
H1_RESISTANCE_ZONE_CLR = clrDarkGray ;
}
else if(ENTRY_BASED_H1_STRUCTURE == false && ENTRY_BASED_M30_STRUCTURE == true){
M30_SUPPORT_ZONE_CLR = clrAliceBlue ;
M30_RESISTANCE_ZONE_CLR = clrDarkGray ;
H1_SUPPORT_ZONE_CLR = clrBlack ;
H1_RESISTANCE_ZONE_CLR = clrBlack ;
}
objectsManager.addTextTiger();
for(int i=0; i<NUM_MAX_ALLOWED_TRADES ; i++)
{
BuyActiveTradesArray[i] = NULL ;
SellActiveTradesArray[i] = NULL ;
}
//objectsManager.addMarketDescriptionTextTiger();
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
Print("Buys Count: " + buysCount);
Print("Sells Count: " + sellsCount);
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
cleanBuyTradesArr();
cleanSellTradesArr();
secureProfitIfNeeded();
if(newCandleDetectorM15.isNewCandle())
{
// UPDATING M30 ZONES
if(zoneContainerSupport_M30.getNumberOfActiveZones()>0){
updateNormalZonesSupport(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",M30_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_M30,0);
}
if(zoneContainer_M30.getNumberOfActiveZones()> 0){
updateNormalZonesResistance(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",M30_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_M30,0);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetector30M.isNewCandle())
{
if(trail_based_m30){
trailAllOpenPositionsIfNeeded(PERIOD_M30);
}
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",M30_RESISTANCE_ZONE_CLR,zoneContainer_M30,rangeDistanceBetweenZonesActual_M30,0);
detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",M30_SUPPORT_ZONE_CLR,zoneContainerSupport_M30,rangeDistanceBetweenZonesActual_M30,0);
if(ENTRY_BASED_M30_STRUCTURE){
handleBuys(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",cleanRangeUponEntryActual);
handleSells(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",cleanRangeUponEntryActual);
}
else{
handleBullishBreakouts(zoneContainer_M30,PERIOD_M30,"PERIOD_M30");
handleBearishBreakouts(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30");
}
// UPDATING H1 ZONES
if(zoneContainerSupport_H1.getNumberOfActiveZones()>0){
updateNormalZonesSupport(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",H1_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_H1,1000);
}
if(zoneContainer_H1.getNumberOfActiveZones()> 0){
updateNormalZonesResistance(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",H1_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_H1,1000);
}
zoneContainerSupport_M30.printZonesSortedArray();
zoneContainer_M30.printZonesSortedArray();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetector1H.isNewCandle()){
if(trail_based_h1){
trailAllOpenPositionsIfNeeded(PERIOD_H1);
}
detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",H1_RESISTANCE_ZONE_CLR,zoneContainer_H1,rangeDistanceBetweenZonesActual_H1,1000);
detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",H1_SUPPORT_ZONE_CLR,zoneContainerSupport_H1,rangeDistanceBetweenZonesActual_H1,1000);
if(ENTRY_BASED_H1_STRUCTURE){
handleBuys(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",cleanRangeUponEntryActual);
handleSells(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",cleanRangeUponEntryActual);
}
else{
handleBullishBreakouts(zoneContainer_H1,PERIOD_H1,"PERIOD_H1");
handleBearishBreakouts(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1");
}
// UPDATING H4 ZONES
if(zoneContainerSupport_H4.getNumberOfActiveZones()>0){
updateNormalZonesSupport(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",H4_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_H4,2000);
}
if(zoneContainer_H4.getNumberOfActiveZones()> 0){
updateNormalZonesResistance(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",H4_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_H4,2000);
}
Print("H1 zones :");
//zoneContainerSupport_H1.printZonesSortedArray();
//zoneContainer_H1.printZonesSortedArray();
}
if(newCandleDetector4H.isNewCandle()){
last_H4_candle_broke_structure = false ;
if(trail_based_h4){
trailAllOpenPositionsIfNeeded(PERIOD_H4);
}
detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",H4_RESISTANCE_ZONE_CLR,zoneContainer_H4,rangeDistanceBetweenZonesActual_H4,2000);
detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",H4_SUPPORT_ZONE_CLR,zoneContainerSupport_H4,rangeDistanceBetweenZonesActual_H4,2000);
// BREAK OF STRUCTURE HANDLING
handleBullishBreakouts(zoneContainer_H4,PERIOD_H4,"PERIOD_H4");
handleBearishBreakouts(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4");
//handleBuys(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual);
//handleSells(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual);
//Print("H4, Zones:");
//zoneContainerSupport_H4.printZonesSortedArray();
//zoneContainer_H4.printZonesSortedArray();
}
if(newCandleDetectorDaily.isNewCandle())
{
//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1);
//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1");
objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetectorWeekly.isNewCandle())
{
objectsManager.drawVerticalLine(clrRed, TimeCurrent());
weekCounter++ ;
if(weekCounter == deleteAllZonesAfter_Weeks){
//deleteAllzonesWithGUI();
weekCounter = 0;
}
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
BIN
View File
Binary file not shown.
+363
View File
@@ -0,0 +1,363 @@
//+------------------------------------------------------------------+
//| Gandalf.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "GraphicalObjectsManager.mqh"
#include "TempLineObjectAttributes.mqh"
#include "ObjectConfirmationUnit.mqh"
#include "BuyGandalf.mqh"
#include "SellGandalf.mqh"
#include "LotSizeCalculator.mqh"
LotSizeCalculator lsCalc;
GraphicalObjectsManager graphicalObjectsManager ;
ObjectConfirmationUnit objectConfUnit ;
BuyGandalf buyGandalfGray ;
SellGandalf SellGandalfGray ;
bool buyCase = false ;
bool sellCase = false ;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
TempLineObjectAttributes tempLineObjectAttr ;
int OnInit()
{
//--- create timer
EventSetTimer(60);
graphicalObjectsManager.addTotalRiskText();
graphicalObjectsManager.addTakeBuyTradeButton();
graphicalObjectsManager.addTakeSellTradeButton();
graphicalObjectsManager.addText();
graphicalObjectsManager.addConfirmButton();
//ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"the new ext is : !");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
updateOverAllRiskText();
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
switch(id)
{
case CHARTEVENT_CLICK:
{
break;
}
//--- clicking on a graphical object
case CHARTEVENT_OBJECT_CLICK:
{
if(sparam == "BUY_BTN")
{
buyCase = true ;
graphicalObjectsManager.drawStopLossLineGandalf();
objectConfUnit.setWaitingStatus(true);
}
else if(sparam == "SELL_BTN"){
sellCase = true ;
graphicalObjectsManager.drawStopLossLineGandalf();
objectConfUnit.setWaitingStatus(true);
}
else
if(sparam == "CONFIRM_BTN")
{
if(buyCase == true)
{
if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ;
string textRecieved;
graphicalObjectsManager.EditTextGet(textRecieved,0,"textName");
double riskAsDouble = StringToDouble(textRecieved);
double stopLossPrice = tempLineObjectAttr.getPrice();
if(ObjectDelete(_Symbol,"sl"))
{
}
else
{
Print("Failed to delete the stop loss line ! Error: "+ GetLastError());
}
//Print("Buy info has been set, SL price: " + stopLossPrice + " risk is: " + riskAsDouble);
double lotsToTrade = lsCalc.calculateLotSize(riskAsDouble,stopLossPrice);
buyGandalfGray.takeBuyTradeGandalf(lotsToTrade,stopLossPrice);
objectConfUnit.setWaitingStatus(false);
buyCase = false ;
// change the risk text
//updateOverAllRiskText();
}
}
else
if(sellCase == true)
{
if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
string textRecieved;
graphicalObjectsManager.EditTextGet(textRecieved,0,"textName");
double riskAsDouble = StringToDouble(textRecieved);
double stopLossPrice = tempLineObjectAttr.getPrice();
if(ObjectDelete(_Symbol,"sl")){
}
else{
Print("Failed to delete the stop loss line ! Error: "+ GetLastError());
}
double lotsToTrade = lsCalc.calculateLotSize(riskAsDouble,stopLossPrice);
SellGandalfGray.takeSellTradeGandalf(lotsToTrade,stopLossPrice);
objectConfUnit.setWaitingStatus(false);
sellCase = false ;
// change the risk text
//updateOverAllRiskText();
}
}
}
break;
}
case CHARTEVENT_OBJECT_DRAG:
{
if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE)
{
if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone)
{
double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0);
tempLineObjectAttr.setId(sparam);
tempLineObjectAttr.setPrice(stopLossPrice);
}
else
if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone)
{
double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0);
tempLineObjectAttr.setId(sparam);
tempLineObjectAttr.setPrice(takeProfitPrice);
}
}
break;
}
case CHARTEVENT_KEYDOWN:
{
}
//---
}
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
//+------------------------------------------------------------------+
void updateOverAllRiskText(){
//double pointValue = lsCalc.PointValue(_Symbol);
double pointValue = PointValueNew(_Symbol);
double overAllRisk = 0 ;
for(int i=PositionsTotal() -1 ;i >= 0 ; i--){
//Print("entered here !");
ulong ticket = PositionGetTicket(i);
int positionType = PositionGetInteger(POSITION_TYPE);
double positionStopLossPrice = PositionGetDouble(POSITION_SL);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double positionLotSize = PositionGetDouble(POSITION_VOLUME);
if(positionType == POSITION_TYPE_BUY){
double positionStopLossInPoints = (positionOpenPrice - positionStopLossPrice) * MathPow(10 , SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)) ;
double riskAmount = pointValue*positionLotSize*positionStopLossInPoints ;
overAllRisk = overAllRisk + riskAmount ;
string riskAsString = DoubleToString(overAllRisk);
ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is:" + riskAsString);
}
else if(positionType == POSITION_TYPE_SELL){
double positionStopLossInPoints = (positionStopLossPrice - positionOpenPrice) * MathPow(10 , SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)) ;
double riskAmount = pointValue*positionLotSize*positionStopLossInPoints ;
overAllRisk = overAllRisk + riskAmount ;
string riskAsString = DoubleToString(overAllRisk);
ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is:" + riskAsString);
}
}
}
double PointValueNew(string symbol){
double tickSize = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE);
double point = SymbolInfoDouble(symbol,SYMBOL_POINT);
double ticksPerPoint = tickSize/point ;
double pointValue = tickValue/ticksPerPoint ;
return (pointValue);
}
BIN
View File
Binary file not shown.
+1668
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+254
View File
@@ -0,0 +1,254 @@
//+------------------------------------------------------------------+
//| HighFractal.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class HighFractal
{
private:
double highPrice ;
int leftPeriod;
int rightPeriod;
MqlDateTime dateStruct ;
datetime date ;
double sellLimitPrice; // the fib level price , based on this fractal
double lowestPeak ; // the highest price reached, after the fractal was formed
int hour ;
int minute;
int distance ; // holds the number of candles from this fractal until the current live candle
string arrowObjName ;
double fibPrice ;
public:
HighFractal();
HighFractal(double _price, int _leftPeriod, int _rightPeriod, datetime _date,ENUM_TIMEFRAMES _tf);
~HighFractal();
// GETTERS
double getPrice();
int getLeftPeriod();
int getRightPeriod();
int getHour();
int getMinute();
double getLowestPeak();
int getDistance();
string getArrowObjName();
datetime getDate();
// SETTERS
void setPrice(double _price);
void setLeftPeriod(int _leftPeriod);
void setRightPeriod(int _rightPeriod);
void setHour(int _hour);
void setMinute(int _minute);
void setLowestPeak(double _highest);
void setArrowObjName(string _name);
void setDistance(int _dist);
void setDate(datetime _givenDate);
// OTHER FUNCTIONS
double calculateFibPrice(double _fibLevel, double _highPrice, double _lowPrice); // calculate the fibonacci price based on the given level, and saves the price in the fibPrice88 variable in the object
void updateDistance();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractal::HighFractal()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractal::HighFractal(double _price, int _leftPeriod, int _rightPeriod,datetime _date,ENUM_TIMEFRAMES _tf)
{
// the constructor sets the data to the attribues , and calculates the real time of the fractal , because the given minute and hour
// are not the real time, they are the time of when the fractal was "known to be a fractal", which is after _righPeriod amount of candles
highPrice = _price ;
leftPeriod = _leftPeriod;
rightPeriod = _rightPeriod;
sellLimitPrice = -1 ;
distance = _rightPeriod+1;
arrowObjName = " " ;
lowestPeak = -1;
date = iTime(_Symbol,_tf,_rightPeriod+1); // bring the actual date of the fractal
TimeToStruct(date,dateStruct); // convert the actual date into a struct
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractal::~HighFractal()
{
}
//+------------------------------------------------------------------+
double HighFractal:: getPrice()
{
return highPrice ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int HighFractal:: getLeftPeriod()
{
return leftPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int HighFractal:: getRightPeriod()
{
return rightPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int HighFractal:: getHour()
{
return dateStruct.hour ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int HighFractal:: getMinute()
{
return dateStruct.min ;
}
double HighFractal:: getLowestPeak(){
return lowestPeak ;
}
int HighFractal:: getDistance(){
return distance ;
}
string HighFractal:: getArrowObjName(){
return arrowObjName ;
}
datetime HighFractal:: getDate(){
return date ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setPrice(double _price)
{
highPrice = _price ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setLeftPeriod(int _leftPeriod)
{
leftPeriod = _leftPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setRightPeriod(int _rightPeriod)
{
rightPeriod = _rightPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setHour(int _hour)
{
hour = _hour ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setMinute(int _minute)
{
minute = _minute ;
}
//+------------------------------------------------------------------+
void HighFractal:: setArrowObjName(string _name){
arrowObjName = _name ;
}
void HighFractal:: setDistance(int _dist){
distance = _dist ;
}
double HighFractal:: calculateFibPrice(double _fibLevel, double _highPrice, double _lowPrice){
double difference = _lowPrice - _highPrice ;
difference = difference*-1 ;
double retracement = _fibLevel * difference ;
double _fibPrice = _lowPrice + retracement ;
fibPrice = _fibPrice ;
return fibPrice;
}
void HighFractal:: setLowestPeak(double _lowest){
lowestPeak = _lowest ;
}
void HighFractal:: setDate(datetime _givenDate){
date = _givenDate;
TimeToStruct(date,dateStruct); // convert the actual date into a struct
}
void HighFractal:: updateDistance(){
distance++ ;
}
//+------------------------------------------------------------------+
+131
View File
@@ -0,0 +1,131 @@
//+------------------------------------------------------------------+
//| HighFractalContainer.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "HighFractal.mqh"
#include <library_functions.mqh>
#define SIZE 700
double input arrowDistanceHighs ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class HighFractalContainer
{
private:
HighFractal* highFractals[SIZE];
int freeIndex ;
double range ;
ENUM_TIMEFRAMES timeFrame ;
public:
HighFractalContainer(ENUM_TIMEFRAMES _timeFrame);
~HighFractalContainer();
//GETTERS
HighFractal* getHighFractal(int _index) {return highFractals[_index] ;} // returns the fractal using its index in the array
int getFreeIndex() {return freeIndex ; }
//SETTERS
void setRange(double _range) {range = _range ;}
// OTHER FUNCTIONS
void addHighFractal(HighFractal* _highFractal); // adds high fractal to the high fractals array
void printHighFractals(); // prints the data of every high fractal in the highFractals[] array
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractalContainer::HighFractalContainer(ENUM_TIMEFRAMES _timeFrame)
{
timeFrame = _timeFrame;
freeIndex = 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractalContainer::~HighFractalContainer()
{
for(int i=0; i<SIZE; i++) // free the highFractals array
{
delete highFractals[i] ;
}
}
//+------------------------------------------------------------------+
void HighFractalContainer:: addHighFractal(HighFractal* _highFractal){
if(freeIndex == SIZE) // in this case we are adding a new fractal but the array is full so we need to do the following
{
ObjectDelete(_Symbol,highFractals[0].getArrowObjName()); // delete the object arrow of the deleted fractal
ObjectCreate(_Symbol,_highFractal.getArrowObjName(),OBJ_ARROW_DOWN,0,iTime(Symbol(),timeFrame,_highFractal.getDistance()),iHigh(Symbol(),timeFrame,_highFractal.getDistance()) + arrowDistanceHighs); // create the new object arrow of the new fractal
ObjectSetInteger(0,_highFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
delete highFractals[0]; // free the memory allocated for the fractal in the first index (because we wanna remove it from the array)
for(int i=0; i< SIZE-1 ; i++) // shift the array
{
highFractals[i] = highFractals[i+1];
}
highFractals[freeIndex - 1] = _highFractal ;
}
else
{
if(freeIndex == 0) // case of the first fractal
{
highFractals[freeIndex] = _highFractal ;
freeIndex++;
ObjectCreate(_Symbol,_highFractal.getArrowObjName(),OBJ_ARROW_DOWN,0,iTime(Symbol(),timeFrame,_highFractal.getDistance()),iHigh(Symbol(),timeFrame,_highFractal.getDistance()) + arrowDistanceHighs);
ObjectSetInteger(0,_highFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
}
else
{
highFractals[freeIndex] = _highFractal ;
freeIndex++;
ObjectCreate(_Symbol,_highFractal.getArrowObjName(),OBJ_ARROW_DOWN,0,iTime(Symbol(),timeFrame,_highFractal.getDistance()),iHigh(Symbol(),timeFrame,_highFractal.getDistance()) + arrowDistanceHighs);
ObjectSetInteger(0,_highFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
}
}
}
void HighFractalContainer:: printHighFractals()
{
if(freeIndex > 0)
{
for(int i=0 ; i<freeIndex ; i++)
{
Print(" Fractal " + i + " Time: ", highFractals[i].getHour() + ":" + highFractals[i].getMinute()+ " Price: "
+ highFractals[i].getPrice() + " Distance: " + highFractals[i].getDistance() );
}
}
}
+130
View File
@@ -0,0 +1,130 @@
//+------------------------------------------------------------------+
//| LotSizeCalculator.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class LotSizeCalculator
{
private:
public:
LotSizeCalculator();
~LotSizeCalculator();
double calculateLotSize(double riskInMoney,double stopLossPrice);
string BaseCurrency() { return (AccountInfoString(ACCOUNT_CURRENCY)); }
double Point(string symbol) { return (SymbolInfoDouble(symbol, SYMBOL_POINT)); }
double TickSize(string symbol) { return (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE)); }
double TickValue(string symbol) { return (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)); }
double PointValue(string symbol);
void Test(string symbol);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LotSizeCalculator::LotSizeCalculator()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LotSizeCalculator::~LotSizeCalculator()
{
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double LotSizeCalculator:: calculateLotSize(double riskInMoney, double stopLossPrice)
{
double difference ;
double differenceInPoints ;
if(stopLossPrice > SymbolInfoDouble(_Symbol, SYMBOL_BID)) // we are calculating for a sell
{
difference = stopLossPrice - SymbolInfoDouble(_Symbol, SYMBOL_BID) ;
differenceInPoints = difference / SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double pointValue = PointValue(_Symbol);
// Situation 3, fixed risk amount and stop loss, how many lots to trade
double riskInPoints = differenceInPoints;
double riskLots = riskInMoney / (pointValue * riskInPoints);
return riskLots;
}
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) > stopLossPrice){
difference = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossPrice ;
differenceInPoints = difference / SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double pointValue = PointValue(_Symbol);
double riskInPoints = differenceInPoints;
double riskLots = riskInMoney / (pointValue * riskInPoints);
return riskLots;
}
return 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double LotSizeCalculator:: PointValue(string symbol)
{
double tickSize = TickSize(symbol);
double tickValue = TickValue(symbol);
double point = Point(symbol);
double ticksPerPoint = tickSize / point;
double pointValue = tickValue / ticksPerPoint;
PrintFormat("tickSize=%f, tickValue=%f, point=%f, ticksPerPoint=%f, pointValue=%f",
tickSize, tickValue, point, ticksPerPoint, pointValue);
return (pointValue);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LotSizeCalculator:: Test(string symbol)
{
PrintFormat("Base currency is %s", BaseCurrency());
PrintFormat("Testing for symbol %s", symbol);
double pointValue = PointValue(symbol);
PrintFormat("ValuePerPoint for %s is %f", symbol, pointValue);
// Situation 3, fixed risk amount and stop loss, how many lots to trade
double riskAmount = 100;
double riskPoints = 5000;
double riskLots = riskAmount / (pointValue * riskPoints);
PrintFormat("Risk lots for %s value %f and stop loss at %f points is %f",
symbol, riskAmount, riskPoints, riskLots);
}
//+------------------------------------------------------------------+
+255
View File
@@ -0,0 +1,255 @@
//+------------------------------------------------------------------+
//| LowFractal.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class LowFractal
{
private:
private:
double lowPrice ;
int leftPeriod;
int rightPeriod;
MqlDateTime dateStruct ;
datetime date ;
double buyLimitPrice; // the fib level price , based on this fractal
double highestPeak ; // the highest price reached, after the fractal was formed
int hour ;
int minute;
int distance ; // holds the number of candles from this fractal until the current live candle
string arrowObjName ;
double fibPrice ;
public:
LowFractal();
LowFractal(double _price, int _leftPeriod, int _rightPeriod, datetime _date,ENUM_TIMEFRAMES _tf);
~LowFractal();
// GETTERS
double getPrice();
int getLeftPeriod();
int getRightPeriod();
int getHour();
int getMinute();
double getHighestPeak();
int getDistance();
string getArrowObjName();
datetime getDate();
// SETTERS
void setPrice(double _price);
void setLeftPeriod(int _leftPeriod);
void setRightPeriod(int _rightPeriod);
void setHour(int _hour);
void setMinute(int _minute);
void setHighestPeak(double _highest);
void setArrowObjName(string _name);
void setDistance(int _dist);
void setDate(datetime _givenDate);
// OTHER FUNCTIONS
double calculateFibPrice(double _fibLevel, double _lowPrice, double _highPrice); // calculate the fibonacci price based on the given level, and saves the price in the fibPrice88 variable in the object
void updateDistance();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractal::LowFractal()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractal::LowFractal(double _price, int _leftPeriod, int _rightPeriod,datetime _date, ENUM_TIMEFRAMES _tf)
{
// the constructor sets the data to the attribues , and calculates the real time of the fractal , because the given minute and hour
// are not the real time, they are the time of when the fractal was "known to be a fractal", which is after _righPeriod amount of candles
lowPrice = _price ;
leftPeriod = _leftPeriod;
rightPeriod = _rightPeriod;
buyLimitPrice = -1 ;
distance = _rightPeriod+1;
arrowObjName = " " ;
highestPeak = -1;
date = iTime(_Symbol,_tf,_rightPeriod+1); // bring the actual date of the fractal
TimeToStruct(date,dateStruct); // convert the actual date into a struct
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractal::~LowFractal()
{
}
//+------------------------------------------------------------------+
double LowFractal:: getPrice()
{
return lowPrice ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int LowFractal:: getLeftPeriod()
{
return leftPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int LowFractal:: getRightPeriod()
{
return rightPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int LowFractal:: getHour()
{
return dateStruct.hour ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int LowFractal:: getMinute()
{
return dateStruct.min ;
}
double LowFractal:: getHighestPeak(){
return highestPeak ;
}
int LowFractal:: getDistance(){
return distance ;
}
string LowFractal:: getArrowObjName(){
return arrowObjName ;
}
datetime LowFractal:: getDate(){
return date ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setPrice(double _price)
{
lowPrice = _price ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setLeftPeriod(int _leftPeriod)
{
leftPeriod = _leftPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setRightPeriod(int _rightPeriod)
{
rightPeriod = _rightPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setHour(int _hour)
{
hour = _hour ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setMinute(int _minute)
{
minute = _minute ;
}
//+------------------------------------------------------------------+
void LowFractal:: setArrowObjName(string _name){
arrowObjName = _name ;
}
void LowFractal:: setDistance(int _dist){
distance = _dist ;
}
double LowFractal:: calculateFibPrice(double _fibLevel, double _lowPrice, double _highPrice){
double difference = _highPrice - _lowPrice ;
double retracement = _fibLevel * difference ;
double _fibPrice = _highPrice - retracement ;
fibPrice = _fibPrice ;
return fibPrice;
}
void LowFractal:: setHighestPeak(double _highest){
highestPeak = _highest ;
}
void LowFractal:: setDate(datetime _givenDate){
date = _givenDate;
TimeToStruct(date,dateStruct); // convert the actual date into a struct
}
void LowFractal:: updateDistance(){
distance++ ;
}
+137
View File
@@ -0,0 +1,137 @@
//+------------------------------------------------------------------+
//| LowFractalContainer.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "LowFractal.mqh"
#include <library_functions.mqh>
#define SIZE 700
double input arrowDistanceLows ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class LowFractalContainer
{
private:
LowFractal* lowFractals[SIZE];
int freeIndex ;
double range ;
ENUM_TIMEFRAMES timeFrame ;
public:
LowFractalContainer(ENUM_TIMEFRAMES _timeFrame);
~LowFractalContainer();
//GETTERS
LowFractal* getLowFractal(int _index) {return lowFractals[_index] ;} // returns the fractal using its index in the array
int getFreeIndex() {return freeIndex ; }
//SETTERS
void setRange(double _range) {range = _range ;}
// OTHER FUNCTIONS
void addLowFractal(LowFractal* _lowFractal); // adds low fractal to the low fractals array
void printLowFractals(); // prints all low fractals data
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractalContainer::LowFractalContainer(ENUM_TIMEFRAMES _timeFrame)
{
timeFrame = _timeFrame ;
freeIndex = 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractalContainer::~LowFractalContainer()
{
for(int i=0; i<SIZE; i++) // free the lowFractals array
{
delete lowFractals[i] ;
}
}
//+------------------------------------------------------------------+
void LowFractalContainer:: addLowFractal(LowFractal* _lowFractal){
if(freeIndex == SIZE) // in this case we are adding a new fractal but the array is full so we need to do the following
{
ObjectDelete(_Symbol,lowFractals[0].getArrowObjName()); // delete the object arrow of the deleted fractal
ObjectCreate(_Symbol,_lowFractal.getArrowObjName(),OBJ_ARROW_UP,0,iTime(Symbol(),timeFrame,_lowFractal.getDistance()),iLow(Symbol(),timeFrame,_lowFractal.getDistance()) - arrowDistanceLows); // create the new object arrow of the new fractal
ObjectSetInteger(0,_lowFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
delete lowFractals[0]; // free the memory allocated for the fractal in the first index (because we wanna remove it from the array)
for(int i=0; i< SIZE-1 ; i++) // shift the array
{
lowFractals[i] = lowFractals[i+1];
}
lowFractals[freeIndex - 1] = _lowFractal ;
}
else
{
if(freeIndex == 0) // case of the first fractal
{
lowFractals[freeIndex] = _lowFractal ;
freeIndex++;
ObjectCreate(_Symbol,_lowFractal.getArrowObjName(),OBJ_ARROW_UP,0,iTime(Symbol(),timeFrame,_lowFractal.getDistance()),iLow(Symbol(),timeFrame,_lowFractal.getDistance()) - arrowDistanceLows);
ObjectSetInteger(0,_lowFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
}
else
{
lowFractals[freeIndex] = _lowFractal ;
freeIndex++;
ObjectCreate(_Symbol,_lowFractal.getArrowObjName(),OBJ_ARROW_UP,0,iTime(Symbol(),timeFrame,_lowFractal.getDistance()),iLow(Symbol(),timeFrame,_lowFractal.getDistance()) - arrowDistanceLows);
ObjectSetInteger(0,_lowFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
}
}
}
void LowFractalContainer:: printLowFractals()
{
if(freeIndex > 0)
{
for(int i=0 ; i<freeIndex ; i++)
{
Print(" Fractal " + i + " Time: ", lowFractals[i].getHour() + ":" + lowFractals[i].getMinute()+ " Price: "
+ lowFractals[i].getPrice() + " Distance: " + lowFractals[i].getDistance() );
}
}
}
+299
View File
@@ -0,0 +1,299 @@
//+------------------------------------------------------------------+
//| MarketObserver.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Zone.mqh"
#include "ZoneContainer.mqh"
#include "LowFractal.mqh"
#include "HighFractal.mqh"
#include "LowFractalContainer.mqh"
#include "HighFractalContainer.mqh"
// ALGORITHM CLASSES INCLUDES
#include "NewCandleDetector.mqh"
// LIVE FORMING FRACTALS HANDLER CLASS
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class MarketObserver
{
// THIS CLASS HAS ACCESS TO ZONE CONTAINER, HOWEVER IT MUST NOT CHANGE IT IT ONLY READS FROM THE ZONECONTAINER CLASS
private:
/*NewCandleDetector* newCandleDetector_H4;
NewCandleDetector* newCandleDetector_H1 ;
NewCandleDetector* newCandleDetector_M30;
NewCandleDetector* newCandleDetector_M1 ;*/
ZoneContainer* zoneContainer ; // must not be changed from this class
bool closestResistanceWaiting ;
bool closestSupportWaiting ;
public:
MarketObserver(ZoneContainer* _zoneContainer);
~MarketObserver();
string zoneReached();
Zone* getClosestResistanceZone() {return zoneContainer.getHigherPivotIndexZone();}
Zone* getClosestSupportZone() {return zoneContainer.getLowerPivotIndexZone();}
bool reachedClosestSupportZone();
bool reachedClosestResistanceZone();
bool bearishCandleClosedInsideClosestSupportZone(ENUM_TIMEFRAMES tf);
bool bullishCandleClosedInsideClosestResistanceZone(ENUM_TIMEFRAMES tf);
bool candleClosedBelowClosestSupportZone(ENUM_TIMEFRAMES tf);
bool candleClosedAboveClosestResistanceZone(ENUM_TIMEFRAMES tf);
bool candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf); // the index is a specific zone from the zones container
bool candleClosedBelowSupportByIndex(int _index,ENUM_TIMEFRAMES tf); // the index is a specific zone from the zones container
bool isClosestResistanceWaiting() {return closestResistanceWaiting;}
bool isClosestSupportWaiting() {return closestSupportWaiting;}
void setClosestResistanceWaiting(bool _state) {closestResistanceWaiting = _state ;}
void setClosestSupportWaiting(bool _state) {closestSupportWaiting = _state ;}
string giveMarketReport();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MarketObserver::MarketObserver(ZoneContainer* _zoneContainer)
{
/*newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4") ;
newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1");
newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30");
newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1");*/
zoneContainer = _zoneContainer ;
closestResistanceWaiting = false ;
closestSupportWaiting = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MarketObserver::~MarketObserver()
{
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string MarketObserver:: zoneReached()
{
int currentResistanceZoneIndex = zoneContainer.getHighZonePivot();
int currentSupportZoneIndex = zoneContainer.getLowZonePivot();
if(currentResistanceZoneIndex != -1 && currentSupportZoneIndex != -1)
{
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) >= zoneContainer.getZoneByIndex(currentResistanceZoneIndex).getLowerEdge())
{
Print("Reached the current resistance zone !");
return "TYPE_RESISTANCE" ;
}
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= zoneContainer.getZoneByIndex(currentSupportZoneIndex).getHigherEdge())
{
Print("Reached the current support zone !");
return "TYPE_SUPPORT" ;
}
}
return "" ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: reachedClosestSupportZone()
{
int currentSupportZoneIndex = zoneContainer.getLowZonePivot();
if(currentSupportZoneIndex != -1)
{
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= zoneContainer.getZoneByIndex(currentSupportZoneIndex).getHigherEdge())
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: reachedClosestResistanceZone()
{
int currentResistanceZoneIndex = zoneContainer.getHighZonePivot();
if(currentResistanceZoneIndex != -1)
{
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) >= zoneContainer.getZoneByIndex(currentResistanceZoneIndex).getLowerEdge())
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: bullishCandleClosedInsideClosestResistanceZone(ENUM_TIMEFRAMES tf)
{
double previousCandleClose = iClose(_Symbol,tf,1);
double previousCandleOpen = iOpen(_Symbol,tf,1);
if(zoneContainer.getHighZonePivot() != -1) // means if there is a pivot zone
{
if((previousCandleClose > previousCandleOpen) && (previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getLowerEdge()) && (previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getHigherEdge())) // means if previous the candle is bullish and closed inside the resistance zone
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: bearishCandleClosedInsideClosestSupportZone(ENUM_TIMEFRAMES tf)
{
double previousCandleClose = iClose(_Symbol,tf,1);
double previousCandleOpen = iOpen(_Symbol,tf,1);
if(zoneContainer.getLowZonePivot() != -1)
{
if((previousCandleClose < previousCandleOpen) && (previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getHigherEdge()) && (previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getLowerEdge())) // means if previous the candle is breaish and closed inside the support zone
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string MarketObserver:: giveMarketReport()
{
return " " ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: candleClosedBelowClosestSupportZone(ENUM_TIMEFRAMES tf)
{
double previousCandleClose = iClose(_Symbol,tf,1);
double previousCandleOpen = iOpen(_Symbol,tf,1);
if(zoneContainer.getLowZonePivot() != -1)
{
if((previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getLowerEdge())) // means if the previous candle closed below the support zone
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: candleClosedAboveClosestResistanceZone(ENUM_TIMEFRAMES tf)
{
double previousCandleClose = iClose(_Symbol,tf,1);
double previousCandleOpen = iOpen(_Symbol,tf,1);
if(zoneContainer.getHighZonePivot() != -1) // means if there is a pivot zone
{
if((previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getHigherEdge())) // means if previous the candle closed above the resistance zone
{
return true ;
}
}
return false ;
}
bool MarketObserver:: candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf){
double previousCandleClose = iClose(_Symbol,tf,1);
if((previousCandleClose > zoneContainer.getZoneByIndex(_index).getHigherEdge())){
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
+105
View File
@@ -0,0 +1,105 @@
//+------------------------------------------------------------------+
//| MarketObserverTiger.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
// #define MacrosHello "Hello, world!"
// #define MacrosYear 2010
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
// #import "user32.dll"
// int SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
// int ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
// string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+
#include "Zone.mqh"
#include "ZoneContainer.mqh"
// ALGORITHM CLASSES INCLUDES
#include "NewCandleDetector.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class MarketObserverTiger
{
// THIS CLASS HAS ACCESS TO ZONE CONTAINER, HOWEVER IT MUST NOT CHANGE IT IT ONLY READS FROM THE ZONECONTAINER CLASS
private:
public:
MarketObserverTiger();
~MarketObserverTiger();
string zoneReached();
bool candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& resistanceZoneContainer); // the index is a specific zone from the zones container
bool candleClosedBelowSupportByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& supportZoneContainer); // the index is a specific zone from the zones container
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MarketObserverTiger::MarketObserverTiger()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MarketObserverTiger::~MarketObserverTiger()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserverTiger:: candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& resistanceZoneContainer)
{
double previousCandleClose = iClose(_Symbol,tf,1);
if((previousCandleClose > resistanceZoneContainer.getZoneByIndex(_index).getHigherEdge()))
{
return true ;
}
return false ;
}
bool MarketObserverTiger:: candleClosedBelowSupportByIndex(int _index, ENUM_TIMEFRAMES tf, ZoneContainer& supportZoneContainer){
double previousCandleClose = iClose(_Symbol,tf,1);
if(previousCandleClose < supportZoneContainer.getZoneByIndex(_index).getLowerEdge()){
return true ;
}
return false ;
}
+378
View File
@@ -0,0 +1,378 @@
//+------------------------------------------------------------------+
//| NewCandleDetector.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class NewCandleDetector
{
private:
string timeFrame ;
datetime beginDate ; // this datetime gets initialized only after the first call of the isNewCandle() function
MqlDateTime currTimeStruct;
MqlDateTime beginDateStruct;
bool firstCallHappened;
public:
NewCandleDetector(string _timeFrame);
~NewCandleDetector();
// GETTERS
datetime getBeginDate() {return beginDate;}
void setTimeFrame(string _timeFrame) {timeFrame = _timeFrame;}
bool isNewCandle();
};
//+------------------------------------------------------------------+
NewCandleDetector::NewCandleDetector(string _timeFrame)
{
timeFrame = _timeFrame ;
firstCallHappened = false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
NewCandleDetector::~NewCandleDetector()
{
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool NewCandleDetector:: isNewCandle()
{
if(timeFrame == "PERIOD_M1")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_M1,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_M1,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.min == currTimeStruct.min)
{
return false;
}
else
{
//Print("in a new candle !, asset: " + _Symbol);
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_M2")
{
}
else
if(timeFrame == "PERIOD_M3")
{
}
else
if(timeFrame == "PERIOD_M4")
{
}
else
if(timeFrame == "PERIOD_M5")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_M5,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_M5,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.min == currTimeStruct.min)
{
return false;
}
else
{
Print("in a new candle !, asset: " + _Symbol);
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_M6")
{
}
else
if(timeFrame == "PERIOD_M10")
{
}
else
if(timeFrame == "PERIOD_M12")
{
}
else
if(timeFrame == "PERIOD_M15")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_M15,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_M15,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.min == currTimeStruct.min)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_M20")
{
}
else
if(timeFrame == "PERIOD_M30")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_M30,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_M30,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.min == currTimeStruct.min)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_H1")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_H1,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_H1,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.hour == currTimeStruct.hour)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_H2")
{
}
else
if(timeFrame == "PERIOD_H3")
{
}
else
if(timeFrame == "PERIOD_H4")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_H4,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_H4,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.hour == currTimeStruct.hour)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_H6")
{
}
else
if(timeFrame == "PERIOD_H8")
{
}
else
if(timeFrame == "PERIOD_H12")
{
}
else
if(timeFrame == "PERIOD_D1")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_D1,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_D1,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.day == currTimeStruct.day)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_W1")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_W1,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_W1,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.day == currTimeStruct.day)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_MN1")
{
}
return true;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
BIN
View File
Binary file not shown.
+1643
View File
File diff suppressed because it is too large Load Diff
+50
View File
@@ -0,0 +1,50 @@
//+------------------------------------------------------------------+
//| ObjectConfirmationUnit.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
/*
This class is responsible for all the proccess of confirming a new object. it prevents adding new objects if the previous was not confirmed.
*/
class ObjectConfirmationUnit
{
private:
string confirmationObjectID ;
string objectType ;
bool waitingToBeConfirmed ;
public:
ObjectConfirmationUnit();
~ObjectConfirmationUnit();
// GETTERS
string getObjectType(){ return objectType ;}
bool getWaitingStatus(){ return waitingToBeConfirmed ;}
string getConfirmationObjectId(){return confirmationObjectID;}
// SETTERS
void setObjectType(string _type){ objectType = _type ;}
void setWaitingStatus(bool _waitStatus){ waitingToBeConfirmed = _waitStatus ;}
void setConfirmationObjectId(int _Id){ confirmationObjectID = IntegerToString(_Id) ;}
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ObjectConfirmationUnit::ObjectConfirmationUnit()
{
waitingToBeConfirmed = false ; // initialize with false value
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ObjectConfirmationUnit::~ObjectConfirmationUnit()
{
}
//+------------------------------------------------------------------+
+618
View File
@@ -0,0 +1,618 @@
//+------------------------------------------------------------------+
//| Phoenix_Functions.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#define NUM_MAX_ALLOWED_TRADES 4
#include "library_functions.mqh"
#include "NewCandleDetector.mqh"
#include "GraphicalObjectsManager.mqh"
#include "Zone.mqh"
#include "ZoneContainer.mqh"
#include "LotSizeCalculator.mqh"
#include "MarketObserverTiger.mqh"
#include "BuyEntryManager.mqh"
#include "SellEntryManager.mqh"
#include "BuyTradeManagerTiger.mqh"
#include "SellTradeManagerTiger.mqh"
//input group "Range Related Variables"
//input double rangeDistanceBetweenZones ;
//input double cleanRangeUponEntry ;
//input double potentialRR;
input group "Zone Related Settings"
input double resistanceExtendAboveCandle;
input double resistanceLowerEdgeExtend ;
input double supportExtendBelowCandle ;
input double supportHigherEdgeExtend;
input int firstZoneShift ;
input datetime rightEdge ;
//input group "Zone TimeFrames"
//input bool APPLY_M30_STRUCTURE ;
//input bool APPLY_H1_STRUCTURE;
//input group "Candle Body Variables"
//input double WICK_RATIO_REJECTION;
//input double SIZE_OF_BREAKER_CANDLE_BODY;
input group "Trade Related Variables 2"
input double riskManagementPartial ;
input double firstPartialCloseFactor ;
input double firstPartialProfitInPips;
input bool BUYS_ALLOWED = true ;
input bool SELLS_ALLOWED = true ;
input double lotSize ;
input int riskManagementCandlesCount ;
input double rrFactor ;
input bool APPLY_TRAIL ;
input ENUM_TIMEFRAMES TRAIL_TIME_FRAME ;
//input group "Trading Sessions"
//input bool TRADE_NEW_YORK_ALLOWED = true ;
//input bool TRADE_LONDON_ALLOWED = true ;
input group "Fractal Related Variables"
//input int leftFractalPeriod ;
//input int rightFractalPeriod ;
input ENUM_TIMEFRAMES TIME_FRAME_TO_TRADE;
input int fractalsPeriod ;
input int stopLossFractalsPeriod ;
input ENUM_TIMEFRAMES stopLossTimeFrame ;
// GUI CLASSES INITIALIZATION
GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager();
// ALGORITHM CLASSES INITIALIZATION
MarketObserverTiger* marketObserverTiger = new MarketObserverTiger();
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
NewCandleDetector newCandleDetectorWeekly("PERIOD_W1");
NewCandleDetector newCandleDetectorDaily("PERIOD_D1");
NewCandleDetector newCandleDetectorH4("PERIOD_H4");
NewCandleDetector newCandleDetectorH1("PERIOD_H1");
NewCandleDetector newCandleDetectorM30("PERIOD_M30");
NewCandleDetector newCandleDetectorM15("PERIOD_M15");
NewCandleDetector newCandleDetectorM5("PERIOD_M5");
NewCandleDetector newCandleDetectorM1("PERIOD_M1");
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
Zone* temporaryRestestSupportZone = new Zone();
// TRADE CLASSES
BuyEntryManager buyEntryManager ;
SellEntryManager sellEntryManager ;
// LotSizeCalculator class
LotSizeCalculator lsCalc ;
// TRADE VARIABLS
bool securedRisk = false ;
ulong activeTradeId ;
BuyTradeManagerTiger* BuyActiveTradesArray[NUM_MAX_ALLOWED_TRADES];
SellTradeManagerTiger* SellActiveTradesArray[NUM_MAX_ALLOWED_TRADES];
int buysCount = 0 ;
int sellsCount = 0 ;
bool waitForBottomWick = false ;
bool bottomWickFormed = false;
bool topWickFormed = false;
bool waitForTopWick = false ;
double currentResistanceHighEdge = -1 ;
double currentResistanceLowEdge = -1 ;
double currentSupportHighEdge = -1 ;
double currentSupportLowerEdge = -1;
double currentSupportZonePrice ;
double currentResistanceZonePrice;
int indexToNewTrade ;
// DATA STRUCTURES
double lastLowFractalPrice ;
double lastHighFractalPrice ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double supportExtendBelowCandleActual = supportExtendBelowCandle * Point();
double supportHigherEdgeExtendActual = supportHigherEdgeExtend * Point();
double resistanceExtendAboveCandleActual = resistanceExtendAboveCandle * Point();
double resistanceLowerEdgeExtendActual = resistanceLowerEdgeExtend * Point();
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double stopLossAboveWickByActual = stopLossAboveWickBy * Point() ;
double stopLossUnderWickByActual = stopLossUnderWickBy * Point() ;
//double cleanRangeUponEntryActual = cleanRangeUponEntry * Point() ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//double rangeDistanceBetweenZonesActual_H4 = rangeDistanceBetweenZones_4H * Point();
//double rangeDistanceBetweenZonesActual_M30 = rangeDistanceBetweenZones_M30 * Point();
double maxPipsRiskAmountActual = maxPipsRiskAmount * Point();
double firstPartialProfitInPipsActual = firstPartialProfitInPips * Point();
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double detectSupportFromLastLowFractal(int _index)
{
double lastLowestSupportPrice = 99999;
for(int i= _index ; i > 1 ; i--)
{
if((candleClosedBearish(PERIOD_CURRENT,i) && candleClosedBullish(PERIOD_CURRENT,i-1))|| (candleClosedBearish(PERIOD_CURRENT,i) && candleClosedDoji(PERIOD_CURRENT,i-1)))
{
if(iClose(_Symbol,PERIOD_CURRENT,i) < lastLowestSupportPrice)
{
lastLowestSupportPrice = iClose(_Symbol,PERIOD_CURRENT,i);
}
}
}
return lastLowestSupportPrice ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double detectResistanceFromLastHighFractal(int _index)
{
double lastHighestResistancePrice = -1;
for(int i= _index ; i > 1 ; i--)
{
if((candleClosedBullish(PERIOD_CURRENT,i) && candleClosedBearish(PERIOD_CURRENT,i-1))|| (candleClosedBullish(PERIOD_CURRENT,i) && candleClosedDoji(PERIOD_CURRENT,i-1)))
{
if(iClose(_Symbol,PERIOD_CURRENT,i) > lastHighestResistancePrice)
{
lastHighestResistancePrice = iClose(_Symbol,PERIOD_CURRENT,i);
}
}
}
return lastHighestResistancePrice ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void findAndDrawFractalsAndZones(ENUM_TIMEFRAMES _timeFrame, string _timeFrameStr)
{
if(isLowFractalByIndex(fractalsPeriod+1,fractalsPeriod,fractalsPeriod,_timeFrame)) // SUPPORTS
{
objectsManager.drawLowFractal(fractalsPeriod+1,clrRed);
lastLowFractalPrice = iLow(_Symbol,PERIOD_CURRENT,fractalsPeriod+1);
currentSupportZonePrice = detectSupportFromLastLowFractal(fractalsPeriod+5);
datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,fractalsPeriod+1);
datetime _rightEdge =rightEdge;
double _higherEdgePrice = currentSupportZonePrice + supportHigherEdgeExtendActual;
double _lowerEdgePrice = currentSupportZonePrice - supportExtendBelowCandleActual;
currentSupportLowerEdge = _lowerEdgePrice;
currentSupportHighEdge = _higherEdgePrice ;
Zone* supportZoneObject = new Zone("support_zone",_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,_timeFrameStr,"TYPE_SUPPORT_BREAKOUT");
objectsManager.drawRectangleInStrategyTester(1,_leftEdge,_rightEdge,_higherEdgePrice,_lowerEdgePrice,clrAliceBlue);
if(candleClosedBelowSupportZone(_timeFrame))
{
Comment("Im taking a sell !");
if(((indexToNewTrade = findAvailableSpotInSellManagerArr())!= -1))
{
double stopLossPrice ;
if(currentResistanceHighEdge != -1)
{
// stopLossPrice = currentResistanceHighEdge + stopLossAboveWickByActual ;
stopLossPrice = lastHighFractalPrice + stopLossAboveWickByActual;
}
//stopLossPrice = iHigh(_Symbol,_timeFrame,1) + stopLossAboveWickByActual;
if(stopLossIsValidSells(stopLossPrice,maxPipsRiskAmountActual))
{
double stopLossInPips = stopLossPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID) ;
double netTp = rrFactor * stopLossInPips ;
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_BID)- netTp) ;
SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge);
tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge);
SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array
sellsCount++;
}
else
{
Print("stop loss is not valid sells!");
}
}
else
{
Comment("i cant take a trade because the arrray is full");
}
currentSupportLowerEdge = -1;
currentSupportHighEdge = -1 ;
}
}
if(isHighFractalByIndex(fractalsPeriod+1,fractalsPeriod,fractalsPeriod,_timeFrame)) // RESISTANCES
{
objectsManager.drawHighFractal(fractalsPeriod+1,clrAliceBlue);
lastHighFractalPrice = iHigh(_Symbol,PERIOD_CURRENT,fractalsPeriod+1);
currentResistanceZonePrice = detectResistanceFromLastHighFractal(fractalsPeriod+5);
datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,fractalsPeriod+1);
datetime _rightEdge =rightEdge;
double _higherEdgePrice = currentResistanceZonePrice + resistanceExtendAboveCandleActual;
double _lowerEdgePrice = currentResistanceZonePrice - resistanceLowerEdgeExtendActual;
currentResistanceHighEdge = _higherEdgePrice;
currentResistanceLowEdge = _lowerEdgePrice;
Zone* supportZoneObject = new Zone("resistance_zone",_higherEdgePrice,_lowerEdgePrice,_leftEdge,_rightEdge,_timeFrameStr,"TYPE_RESISTANCE_BREAKOUT");
objectsManager.drawRectangleInStrategyTester(2,_leftEdge,_rightEdge,_higherEdgePrice,_lowerEdgePrice,clrAliceBlue);
if(candleClosedAboveResistanceZone(_timeFrame))
{
Comment("Im taking a buy !");
if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1))
{
Print("indexToNewTrade:--------------------------------------- " + indexToNewTrade);
double stopLossPrice ;
if(currentSupportLowerEdge != -1)
{
// stopLossPrice = currentSupportLowerEdge - stopLossUnderWickByActual ;
stopLossPrice = lastLowFractalPrice - stopLossUnderWickByActual ;
}
//stopLossPrice = iLow(_Symbol,_timeFrame,1) - stopLossUnderWickByActual; // if there is no lower zone , take the last m30 candle's low
if(stopLossIsValidBuys(stopLossPrice,maxPipsRiskAmountActual))
{
double stopLossInPips = SymbolInfoDouble(_Symbol,SYMBOL_ASK) - stopLossPrice ;
double netTp = rrFactor * stopLossInPips ;
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+ netTp) ;
BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge);
tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge);
BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array
buysCount++;
}
else
{
Print("stop loss is not valid buys !");
}
}
else
{
Comment("i cant take a trade because the arrray is full");
}
currentResistanceHighEdge = -1;
currentResistanceLowEdge = -1 ;
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedBelowSupportZone(ENUM_TIMEFRAMES _timeFrame)
{
if(candleClosedBearish(_timeFrame,1) && (iClose(_Symbol,_timeFrame,1) < currentSupportLowerEdge) && (currentSupportLowerEdge != -1) && (currentSupportZonePrice != 99999))
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedAboveResistanceZone(ENUM_TIMEFRAMES _timeFrame)
{
if(candleClosedBullish(_timeFrame,1) && (iClose(_Symbol,_timeFrame,1) > currentResistanceHighEdge) && (currentResistanceHighEdge != -1) && (currentResistanceZonePrice != 0))
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int findAvailableSpotInBuyManagerArr() // returns the index , or -1 if all are full
{
for(int i=0 ; i < NUM_MAX_ALLOWED_TRADES ; i++)
{
if(BuyActiveTradesArray[i] == NULL)
{
return i;
}
}
return -1 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int findAvailableSpotInSellManagerArr() // returns the index , or -1 if all are full
{
for(int i=0 ; i<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)
{
if(BuyActiveTradesArray[i]!= NULL)
{
Print("Cleaned the position with the id of: "+ BuyActiveTradesArray[i].getTradeId());
}
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 manageRiskIfNeededPhoenix()
{
for(int i=0; i<NUM_MAX_ALLOWED_TRADES; i++)
{
if(BuyActiveTradesArray[i] != NULL)
{
if(candleClosedBearish(PERIOD_M5,1) && (iClose(_Symbol,PERIOD_M5,1) < BuyActiveTradesArray[i].getBrokenResistanceLowerEdge()))
{
BuyActiveTradesArray[i].incrementRiskManagementCandleCoutner();
Print("risk managment candle coutn is :" + BuyActiveTradesArray[i].getRiskManagementCandleCounter());
}
else
if((iClose(_Symbol,PERIOD_M5,1)) > BuyActiveTradesArray[i].getBrokenResistanceHigherEdge())
{
BuyActiveTradesArray[i].setRiskManagementCandleCounter(0);
}
if(BuyActiveTradesArray[i].getRiskManagementCandleCounter() >= riskManagementCandlesCount)
{
// Close the trade
tradeLong.PositionClose(BuyActiveTradesArray[i].getTradeId());
}
}
if(SellActiveTradesArray[i] != NULL)
{
if(candleClosedBullish(PERIOD_M5,1) && (iClose(_Symbol,PERIOD_M5,1) > SellActiveTradesArray[i].getBrokenSupportHigherEdge()))
{
SellActiveTradesArray[i].incrementRiskManagementCandleCoutner();
}
else
if((iClose(_Symbol,PERIOD_M5,1)) < SellActiveTradesArray[i].getBrokenSupportLowerEdge())
{
SellActiveTradesArray[i].setRiskManagementCandleCounter(0);
}
if(SellActiveTradesArray[i].getRiskManagementCandleCounter() >= riskManagementCandlesCount)
{
// Close the trade
tradeShort.PositionClose(SellActiveTradesArray[i].getTradeId());
}
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double calculateStopLossBasedOnFractalsBuys(int _fractalsPeriod, ENUM_TIMEFRAMES _timeFrame)
{
for(int i=0 ; 300 ; i++) // scan the last 200 candles
{
if(isLowFractalByIndex(i,_fractalsPeriod,_fractalsPeriod,_timeFrame))
{
return iLow(_Symbol,_timeFrame,i);
}
}
return -1 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double calculateStopLossBasedOnFractalsSells(int _fractalsPeriod,ENUM_TIMEFRAMES _timeFrame)
{
for(int i=0 ; 300 ; i++) // scan the last 200 candles
{
if(isHighFractalByIndex(i,_fractalsPeriod,_fractalsPeriod,_timeFrame))
{
return iHigh(_Symbol,_timeFrame,i);
}
}
return -1 ;
}
//+------------------------------------------------------------------+
void trailAllOpenPositionsIfNeeded(ENUM_TIMEFRAMES _timeFrame)
{
for(int i=0 ; i< NUM_MAX_ALLOWED_TRADES ; i++) // CHECK TRAIL FOR BUYS
{
if((BuyActiveTradesArray[i] != NULL))
{
double newStopLoss = iLow(_Symbol,_timeFrame,1);
newStopLoss = newStopLoss - stopLossUnderWickByActual ;
if(newStopLoss > positionStopLoss(BuyActiveTradesArray[i].getTradeId())) // if new stop loss is higher than the current position's stop loss
{
if(SymbolInfoDouble(_Symbol,SYMBOL_BID) <= newStopLoss){ // close the trade because the bid is lower than the stop loss (and the modify will fail))
tradeLong.PositionClose(BuyActiveTradesArray[i].getTradeId());
}
positionTrailStopLoss(BuyActiveTradesArray[i].getTradeId(),newStopLoss,0);
}
}
if((SellActiveTradesArray[i] != NULL)) // CHECK TRAIL FOR SELLS
{
double newStopLoss = iHigh(_Symbol,_timeFrame,1);
newStopLoss = newStopLoss + stopLossAboveWickByActual ;
if(newStopLoss < positionStopLoss(SellActiveTradesArray[i].getTradeId())) // if new stop loss is lower than the current position's stop loss
{
if(SymbolInfoDouble(_Symbol,SYMBOL_ASK) >= newStopLoss){ // close the trade because the ask is higher than the stop loss (and the modify will fail))
tradeShort.PositionClose(SellActiveTradesArray[i].getTradeId());
}
positionTrailStopLoss(SellActiveTradesArray[i].getTradeId(),newStopLoss,0);
}
}
}
}
Binary file not shown.
+201
View File
@@ -0,0 +1,201 @@
//+------------------------------------------------------------------+
//| Phoenix_Reborn.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Phoenix_Functions.mqh"
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
iOpen(_Symbol,PERIOD_M5,1);
iOpen(_Symbol,PERIOD_M15,1);
iOpen(_Symbol,PERIOD_M30,1);
iOpen(_Symbol,PERIOD_H1,1);
iOpen(_Symbol,PERIOD_H4,1);
for(int i=0; i<NUM_MAX_ALLOWED_TRADES ; i++)
{
BuyActiveTradesArray[i] = NULL ;
SellActiveTradesArray[i] = NULL ;
}
objectsManager.addTextTiger();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
Print("Buys Count: " + buysCount);
Print("Sells Count: " + sellsCount);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
cleanBuyTradesArr();
cleanSellTradesArr();
/*if(newCandleDetectorM1.isNewCandle()){
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
findAndDrawFractalsAndZones(PERIOD_M1,"PERIOD_M1");
if(candleClosedBelowSupportZone()){
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": im taking a sell !");
if(((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1 ) )
{
Print("indexToNewTrade: ----------------------------------------------" + indexToNewTrade);
double stopLossPrice ;
if(currentResistanceHighEdge != -1){
stopLossPrice = currentResistanceHighEdge + stopLossAboveWickBy ;
}
else{
stopLossPrice = iHigh(_Symbol,PERIOD_M30,1) - stopLossAboveWickBy; // if there is no higher zone , take the last m30 candle's high
}
activeTradeId = sellEntryManager.takeSellTradeTiger(lotSize,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_BID)- netTakeProfit ) ;
SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge);
tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge);
SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array
sellsCount++;
}
else
{
Comment("i cant take a trade because the arrray is full");
}
currentSupportLowerEdge = -1;
currentSupportHighEdge = -1;
}
if(candleClosedAboveResistanceZone()){
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": im taking a buy !");
if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1))
{
Print("indexToNewTrade:-------------------------------------------- " + indexToNewTrade);
double stopLossPrice ;
if(currentSupportLowerEdge != -1){
stopLossPrice = currentSupportLowerEdge - stopLossUnderWickBy ;
}
else{
stopLossPrice = iLow(_Symbol,PERIOD_M30,1) - stopLossUnderWickBy; // if there is no lower zone , take the last m30 candle's low
}
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotSize,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+ netTakeProfit ) ;
BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge);
tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge);
BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array
buysCount++;
}
else
{
Comment("i cant take a trade because the arrray is full");
}
currentResistanceHighEdge = -1;
currentResistanceLowEdge = -1;
}
} */
/*if(newCandleDetectorM5.isNewCandle()){
findAndDrawFractalsAndZones(PERIOD_M5,"PERIOD_M5");
int tradeCount = 0 ;
for(int i=0;i<NUM_MAX_ALLOWED_TRADES;i++){
if(BuyActiveTradesArray[i]!= NULL){
tradeCount++ ;
}
}
manageRiskIfNeededPhoenix();
} */
/*if(newCandleDetectorM30.isNewCandle()){
findAndDrawFractalsAndZones(PERIOD_M30,"PERIOD_M30");
int tradeCount = 0 ;
for(int i=0;i<NUM_MAX_ALLOWED_TRADES;i++){
if(BuyActiveTradesArray[i]!= NULL){
tradeCount++ ;
}
}
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
} */
if(newCandleDetectorH4.isNewCandle()){
findAndDrawFractalsAndZones(PERIOD_H4,"PERIOD_H4");
int tradeCount = 0 ;
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
}
if(newCandleDetectorDaily.isNewCandle()){
// objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
if(newCandleDetectorWeekly.isNewCandle()){
objectsManager.drawVerticalLine(clrRed, TimeCurrent());;
}
}
//+------------------------------------------------------------------+
Binary file not shown.
+51
View File
@@ -0,0 +1,51 @@
//+------------------------------------------------------------------+
//| Point_Value_Testing.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
#property script_show_inputs
//--- day of week
enum Confirmation_HTF
{
H4_Break= 0,
H4_Closure = 1,
};
//--- input parameters
input Confirmation_HTF H4_CONFIRMATION ;
input int someNumber ;
int OnInit()
{
//---
//---
if(!ChartScreenShot(0,"somefile.png",1260,720,ALIGN_CENTER)){
Print("failed to take screenshot , Error: " + GetLastError());
}
Print("Point value of this pair :" + Point());
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
}
//+------------------------------------------------------------------+
Binary file not shown.
File diff suppressed because it is too large Load Diff
+119
View File
@@ -0,0 +1,119 @@
//+------------------------------------------------------------------+
//| SellEntryManager.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "SellRejectionDetector.mqh"
#include <Trade/Trade.mqh>
CTrade tradeShort ;
class SellEntryManager
{
private:
bool shortTradeTaken ;
bool waitingForRejectionCandle ;
bool waitingForRetracement ;
bool liquiditySweepEntryTaken ;
public:
SellEntryManager();
~SellEntryManager();
SellRejectionDetector* sellRejectionDetector ;
bool isWaitingForRejectionCandle(){return waitingForRejectionCandle ;}
void setWaitingForRejectionCandle(bool _setting){waitingForRejectionCandle = _setting ; }
bool isWaitingForRetracement(){return waitingForRetracement;}
void setWaitingForRetracement(bool _setting){waitingForRetracement = _setting ;}
bool sellTradeTaken();
void setTradeTakenStatus(bool _status){shortTradeTaken = _status ;}
bool liqEntryIsTaken(){return liquiditySweepEntryTaken;}
void setLiquiditySweepEntryTaken(bool _entryStatus){liquiditySweepEntryTaken = _entryStatus ;}
ulong takeSellTrade(double _lots,double _stopLoss);
ulong takeSellTradeTiger(double _lots, double _stopLoss, double _takeProfit);
ulong takeSellTradeTiger(double _lots, double _stopLoss);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellEntryManager::SellEntryManager()
{
sellRejectionDetector = new SellRejectionDetector();
shortTradeTaken = false ;
waitingForRejectionCandle = false ;
bool waitingForRetracement = false;
liquiditySweepEntryTaken = false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellEntryManager::~SellEntryManager()
{
delete sellRejectionDetector;
}
//+------------------------------------------------------------------+
bool SellEntryManager:: sellTradeTaken(){
return shortTradeTaken ;
}
ulong SellEntryManager:: takeSellTrade(double _lots, double _stopLoss){
tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss);
ulong tradeTicket = tradeShort.ResultOrder();
Print("Sell entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong SellEntryManager:: takeSellTradeTiger(double _lots, double _stopLoss, double _takeProfit){
double netTp = SymbolInfoDouble(_Symbol, SYMBOL_BID);
netTp = netTp - _takeProfit ;
tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss,SymbolInfoDouble(_Symbol, SYMBOL_BID) - netTp);
ulong tradeTicket = tradeShort.ResultOrder();
Print("sELL entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong SellEntryManager:: takeSellTradeTiger(double _lots, double _stopLoss){
tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss);
ulong tradeTicket = tradeShort.ResultOrder();
Print("sELL entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
+79
View File
@@ -0,0 +1,79 @@
//+------------------------------------------------------------------+
//| SellGandalf.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade/Trade.mqh>
CTrade tradeShort ;
class SellGandalf
{
private:
bool shortTradeTaken ;
ulong longTrades[10] ;
public:
SellGandalf();
~SellGandalf();
bool sellTradeTaken();
void setTradeTakenStatus(bool _status){shortTradeTaken = _status ; Print("long trade taken flag has been set to true");}
ulong takeSellTrade(double _lots,double _stopLoss);
ulong takeSellTradeGandalf(double _lots,double _stopLoss);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellGandalf::SellGandalf()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellGandalf::~SellGandalf()
{
}
//+------------------------------------------------------------------+
bool SellGandalf:: sellTradeTaken(){
return shortTradeTaken ;
}
ulong SellGandalf:: takeSellTrade(double _lots, double _stopLoss){
tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss);
ulong tradeTicket = tradeShort.ResultOrder();
Print("Sell entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong SellGandalf:: takeSellTradeGandalf(double _lots,double _stopLoss){
tradeShort.Sell(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_BID),_stopLoss);
ulong tradeTicket = tradeShort.ResultOrder();
Print("Sell entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
+52
View File
@@ -0,0 +1,52 @@
//+------------------------------------------------------------------+
//| SellRejectionDetector.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class SellRejectionDetector
{
private:
public:
SellRejectionDetector();
~SellRejectionDetector();
bool rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame);
bool rejectionByRangeFormed();
bool rejectionByWicksFormed();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellRejectionDetector::SellRejectionDetector()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellRejectionDetector::~SellRejectionDetector()
{
}
//+------------------------------------------------------------------+
bool SellRejectionDetector:: rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame){
double rejectionCandleClose = iClose(_Symbol,_timeFrame,1);
double rejectionCandleOpen = iOpen(_Symbol,_timeFrame,1);
double rejectionCandleLow = iLow(_Symbol,_timeFrame,1);
double rejectionCandleLowerWickSize ;
double rejectionCandleBodySize;
if(rejectionCandleOpen > rejectionCandleClose){ // the previous candle closed bearish
rejectionCandleLowerWickSize = rejectionCandleClose - rejectionCandleLow ;
rejectionCandleBodySize = rejectionCandleOpen - rejectionCandleClose;
if(rejectionCandleBodySize >= rejectionCandleLowerWickSize){
return true ;
}
}
return false ;
}
+586
View File
@@ -0,0 +1,586 @@
//+------------------------------------------------------------------+
//| SellTradeManager.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//#include <Telegram_Handler.mqh>
#include <TradeManagersAttributes.mqh>
#include <Trade/Trade.mqh>
CTrade tradeInTradeManager;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class SellTradeManager
{
private:
int tradeId ;
ulong rejectionByOneCandleTradeArray[3]; // index 0 : half the contract , index 1 : quarter of the contract , index 2 : quarter of the contract
string firstSecureMethod ;
bool firstSecureMethodFound;
int numberOfTakeProfits ;
bool securedFirstLevelProfit ;
bool securedSecondLevelProfit;
double partialToClose ;
bool isTradeRunning ;
public:
SellTradeManager();
~SellTradeManager();
void fillRejectionByOneCandleTradeArray(int _index, ulong _id) {rejectionByOneCandleTradeArray[_index] = _id ;}
ulong getRejectionByOneCandleTradeTicket(int _index) {return rejectionByOneCandleTradeArray[_index] ;}
void printRejectionByOneCandleTradeArray();
void checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars);
string findFirstSecureMethod();
bool reachedProfitRatio(int _indexInArr);
bool closeTrade(int _indexInArr);
bool positionBreakEven(int _indexInArr);
void addTpAtIndex(int _index, double tpPrice) {tpArray[_index] = tpPrice;}
int countRemainingTakeProfits();
bool reachedClosestTakeProfit();
void deleteClosestTp();
int findClosestTpIndex();
void cleanOrderDataStructures();
void setTradeRunning(bool _setting) {isTradeRunning = _setting ;}
bool tradeIsRunning() {return isTradeRunning ;}
double tpArray[3];
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellTradeManager::SellTradeManager()
{
for(int i=0; i<3; i++)
{
tpArray[i] = -1;
}
securedFirstLevelProfit = false ;
securedSecondLevelProfit = false ;
firstSecureMethodFound = false ;
firstSecureMethod = "NOT_FOUND" ;
partialToClose = -1 ;
isTradeRunning = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellTradeManager::~SellTradeManager()
{
}
//+------------------------------------------------------------------+
void SellTradeManager:: printRejectionByOneCandleTradeArray()
{
Print("Printing the tickets :");
for(int i=0 ; i<3 ; i++)
{
Print((int)rejectionByOneCandleTradeArray[i]);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void SellTradeManager:: checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars)
{
if(securedFirstLevelProfit == false) // in this case im searching for 2 cases: either RR 1:1.5 , OR reaching the first TP , if any of them happened im gonna close half the order and updatae the remaining stop losses
{
if(!firstSecureMethodFound)
{
firstSecureMethod = findFirstSecureMethod();
if(firstSecureMethod != "FAILED")
{
firstSecureMethodFound = true ;
}
else
if(firstSecureMethod == "FAILED")
{
Print("Failed to find the first secure method, go check the function : findFirstSecureMehod() !");
}
}
if(firstSecureMethodFound == true)
{
if(firstSecureMethod == "RATIO_METHOD")
{
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(reachedProfitRatio(0))
{
ChartRedraw(); // Make sure the chart is up to date
ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,
"If you see this message it means we reached the first secure method, which is ratio method, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName);
if(closeTrade(0)) // close the half
{
rejectionByOneCandleTradeArray[0] = -1;
Print("Closed Half Of the position due to reaching the first secure Ratio!");
}
else
{
Print("Failed Closing Half of the order by reaching the first secure Ratio !");
}
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(positionBreakEven(1)) // put the first quarter at break even
{
Print(" First quarter has been put into break even due to reaching the first secure Ratio!");
}
else
{
Print("Failed to Put the first quarter into break even");
}
numberOfTakeProfits = countRemainingTakeProfits();
Print("Number of remaining tps is: " + numberOfTakeProfits);
securedFirstLevelProfit = true ;
}
}
else
if(firstSecureMethod == "FIRST_TP_METHOD")
{
if(countRemainingTakeProfits() > 1) // there is at least 2 tp in the tp Array (because if this is the last tp then we want to close the whole order and not just a part of it)
{
if(reachedClosestTakeProfit()) // 2. Check if reached the first Tp
{
ChartRedraw(); // Make sure the chart is up to date
ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,
"If you see this message it means we reached the first secure method which is tp1, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName);
// close the first half and update remaining partials sl's and delete the closest take profit from the array
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(closeTrade(0)) // close the half
{
rejectionByOneCandleTradeArray[0] = -1;
Print("Closed Half Of the position due to reaching the first TP!");
}
else
{
Print("Failed Closing Half of the order by reaching the first TP !");
}
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(positionBreakEven(1)) // put the first quarter at break even
{
Print(" First quarter has been put into break even due to reaching the first TP!");
}
else
{
Print("Failed to Put the first quarter into break even");
}
deleteClosestTp();
numberOfTakeProfits = countRemainingTakeProfits(); // update the number of remaining take profits
// calculate the remaining tps
Print("Number of remaining tps is: " + numberOfTakeProfits);
securedFirstLevelProfit = true ;
}
}
else
if(numberOfTakeProfits = countRemainingTakeProfits() == 1)
{
if(reachedClosestTakeProfit())
{
// close everything remained
}
}
}
}
}
else
if(securedFirstLevelProfit == true) // after securing the first level i just want to close the remaining partials by reaching the tp's
{
if(countRemainingTakeProfits() == 1)
{
if(reachedClosestTakeProfit())
{
// close everything
cleanOrderDataStructures();
for(int i=0 ; i<3 ; i++)
{
closeTrade(i);
}
Print("Closed every thing because price reached the last Take Profit !");
ChartRedraw(); // Make sure the chart is up to date
ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,
"If you see this message it means that all order are closed as a result of reaching the last tp " + TimeToString(TimeLocal()), fileName);
deleteClosestTp();
}
}
else
if(countRemainingTakeProfits() > 1)
{
if(reachedClosestTakeProfit())
{
cleanOrderDataStructures();
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[1])) // DEALING WITH THE FIRST QUARTER
{
double currentLot = PositionGetDouble(POSITION_VOLUME);
if(partialToClose == -1)
{
partialToClose = currentLot/numberOfTakeProfits ;
}
if(tradeInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[1],NormalizeDouble(partialToClose,2)))
{
uint res = tradeInTradeManager.ResultRetcode();
if(res == 10009)
{
Print("Closed Partials successfully on the first quarter !");
}
else
{
Print("The returned code is: " + res + " go check what it means !");
}
}
}
else
{
Print("Failed to select position by ticket, Error: " + GetLastError());
Print("The EA tried to close partials on the first quarter, but it is closed, probably due to break even and thats why it couldnt select the order !");
}
cleanOrderDataStructures();
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[2])) // DEALING WITH THE SECOND QUARTER
{
if(PositionGetDouble(POSITION_SL) > PositionGetDouble(POSITION_PRICE_OPEN)) // this is to put the second quarter at break even if its not already at break even
{
positionBreakEven(2);
}
double currentLot = PositionGetDouble(POSITION_VOLUME);
if(partialToClose == -1)
{
partialToClose = currentLot/numberOfTakeProfits ;
}
if(tradeInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[2],NormalizeDouble(partialToClose,2)))
{
uint res = tradeInTradeManager.ResultRetcode();
if(res == 10009)
{
Print("Closed Partials successfully on the second quarter!");
}
else
{
Print("The returned code is: " + res + " go check what it means !");
}
}
}
deleteClosestTp();
Print("Number Of Remained tps is: " + countRemainingTakeProfits());
ChartRedraw(); // Make sure the chart is up to date
ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,
"If you see this message it means we reached a tp level (different than the first secure level), so partial positions will be closed, and the scond quarter must be in break even!" + TimeToString(TimeLocal()), fileName);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string SellTradeManager:: findFirstSecureMethod()
{
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[0]))
{
double positionStopLoss = PositionGetDouble(POSITION_SL);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double firstTakeProfit = tpArray[findClosestTpIndex()];
if(((positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) > firstSecureRatio)) // firstTp > ratio
{
Print("Found the first profit secure method !");
Print("The first TP RR is: 1:" + (positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) + "the firstSecureRatio is: 1:" + firstSecureRatio);
Print("The tp ratio is greater than the firstSecure so:");
Print("The first secure method is RATIO_METHOD");
return"RATIO_METHOD";
}
else
if((positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice)< firstSecureRatio)
{
Print("Found the first profit secure method !");
Print("The first TP RR is: 1:" + (positionOpenPrice-firstTakeProfit)/(positionStopLoss-positionOpenPrice) + "the firstSecureRatio is: 1:" + firstSecureRatio);
Print("The tp ratio is less than the firstSecure so:");
Print("The first secure method is FIRST_TP_METHOD");
return "FIRST_TP_METHOD" ;
}
}
else
{
Print("Failed to select position by ticket 1, Error: " + GetLastError());
}
return "FAILED" ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool SellTradeManager:: reachedProfitRatio(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket))
{
if(PositionGetDouble(POSITION_PROFIT)/(0.5*riskDollars) >= firstSecureRatio) // checking if the first half of the contract reached the ratio of first secure profit
{
Print("reached profit ratio !");
return true ;
}
}
else
{
Print("Failed to select the position by ticket 4 ,Error: " + GetLastError());
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool SellTradeManager:: closeTrade(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket))
{
// close the first half and update remaining partials sl's
if(tradeInTradeManager.PositionClose(_ticket))
{
return true ;
}
else
{
Print("Failed to close positon, Error:" + GetLastError());
return false;
}
}
else
{
Print("Failed to select position by ticket 2, Error: "+ GetLastError());
return false;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool SellTradeManager:: positionBreakEven(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket)) // select the first quarter
{
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double positionTp = PositionGetDouble(POSITION_TP);
double positionSl = PositionGetDouble(POSITION_SL);
if(tradeInTradeManager.PositionModify((_ticket),openPrice,positionTp))
{
return true ;
}
else
{
Print("Failed to modify oder , ERROR: " + GetLastError());
return false ;
}
}
else
{
Print("Failed to select position by ticket 3");
return false ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int SellTradeManager:: countRemainingTakeProfits()
{
int counter = 0 ;
for(int i=0; i<3 ; i++)
{
if(tpArray[i] != -1)
{
counter++ ;
}
}
return counter;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void SellTradeManager:: deleteClosestTp()
{
int closestTpIndex =findClosestTpIndex();
tpArray[closestTpIndex] = -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int SellTradeManager:: findClosestTpIndex()
{
int closestTpIndex = 0;
for(int i=1; i<3; i++)
{
if(tpArray[i] > tpArray[closestTpIndex])
{
closestTpIndex = i ;
}
}
return closestTpIndex ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool SellTradeManager:: reachedClosestTakeProfit()
{
double closestTakeProfitValue = tpArray[findClosestTpIndex()];
//Print("im in reached closest take profit function ,the current price is: " + SymbolInfoDouble(_Symbol, SYMBOL_BID) + " and the tp is: " + closestTakeProfitValue);
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= closestTakeProfitValue) // we want the ASK because we are basically buying the asset again (in a cheaper price), and we want to buy it on the ASK (which is the price that a seller is willing to sell us)
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void SellTradeManager:: cleanOrderDataStructures()
{
// this is to make sure, that every closed order is removed from the data strucutre !
for(int i=0; i<3; i++)
{
if(!PositionSelectByTicket(rejectionByOneCandleTradeArray[i]))
{
if(GetLastError() == 4753)
{
rejectionByOneCandleTradeArray[i] = -1 ;
}
}
}
}
//+------------------------------------------------------------------+
+69
View File
@@ -0,0 +1,69 @@
//+------------------------------------------------------------------+
//| SellTradeManagerTiger.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class SellTradeManagerTiger
{
private:
ulong tradeId ;
string entryType ;
bool firstPartialSecured ;
bool secondPartialSecured ;
bool managedRisk ;
int riskManagementCandleCounter ;
double brokenSupportHigherEdge ;
double brokenSupportLowerEdge ;
public:
ulong getTradeId(){return tradeId ;}
bool riskAlreadyManaged(){return managedRisk ;}
void manageRisk(){managedRisk = true ;}
bool firstPartialIsSecured(){return firstPartialSecured ;}
void secureFirstPartial(){firstPartialSecured = true ;}
bool retestWickFormed ;
double retestWickLengthInPips ;
void setBrokenSupportHigherEdge(double _brokenSupportHigherEdge){brokenSupportHigherEdge = _brokenSupportHigherEdge ;}
void setBrokenSupportLowerEdge(double _brokenSupportLowerEdge){brokenSupportLowerEdge = _brokenSupportLowerEdge ;}
double getBrokenSupportHigherEdge(){return brokenSupportHigherEdge ;}
double getBrokenSupportLowerEdge(){return brokenSupportLowerEdge;}
void incrementRiskManagementCandleCoutner(){riskManagementCandleCounter++ ;}
void decrementRiskManagementCandleCounter(){riskManagementCandleCounter-- ;}
int getRiskManagementCandleCounter(){return riskManagementCandleCounter ;}
void setRiskManagementCandleCounter(int count){ riskManagementCandleCounter = count ;}
SellTradeManagerTiger(ulong _tradeId);
~SellTradeManagerTiger();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellTradeManagerTiger::SellTradeManagerTiger(ulong _tradeId)
{
tradeId = _tradeId ;
firstPartialSecured = false ;
secondPartialSecured = false ;
managedRisk = false ;
retestWickFormed = false ;
retestWickLengthInPips = 0 ;
riskManagementCandleCounter = 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellTradeManagerTiger::~SellTradeManagerTiger()
{
}
//+------------------------------------------------------------------+
+29
View File
@@ -0,0 +1,29 @@
//+------------------------------------------------------------------+
//| SellTradeMangerTiger.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class SellTradeMangerTiger
{
private:
public:
SellTradeMangerTiger();
~SellTradeMangerTiger();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellTradeMangerTiger::SellTradeMangerTiger()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
SellTradeMangerTiger::~SellTradeMangerTiger()
{
}
//+------------------------------------------------------------------+
+846
View File
@@ -0,0 +1,846 @@
//+------------------------------------------------------------------+
//| ZoneScanner.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
// INPUT VARIABLES
input ENUM_TIMEFRAMES inputTimeFrameFractals ;
// FRACTAL VARIABLES INITIALIZATION
input int leftPeriod;
input int rightPeriod;
input int weekPeriodToInitialize;
input int initFractalsPeriod ;
int lowFractalIndex ;
int highFractalIndex ;
// GUI CLASSES INCLUDES
#include "ZoneContainer.mqh"
#include "GraphicalObjectsManager.mqh"
#include "ObjectConfirmationUnit.mqh"
#include "TempObjectAttributes.mqh"
// DATA STRUCTURE CLASSES INCLUDES
#include "Zone.mqh"
#include "LowFractal.mqh"
#include "HighFractal.mqh"
#include "LowFractalContainer.mqh"
#include "HighFractalContainer.mqh"
// ALGORITHM CLASSES INCLUDES
#include "NewCandleDetector.mqh"
// LIBRARIES INCLUDES
#include <library_functions.mqh>
// GUI CLASSES INITIALIZATION
GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager();
ObjectConfirmationUnit* objectConfUnit = new ObjectConfirmationUnit();
TempObjectAttributes* tempObjectAttr = new TempObjectAttributes();
// CONTAINERS INITIALIZATION
ZoneContainer zoneContainer ;
LowFractalContainer* lowsContainer = new LowFractalContainer(inputTimeFrameFractals) ;
HighFractalContainer* highsContainer = new HighFractalContainer(inputTimeFrameFractals) ;
// GENERAL CHART VARIABLES INITIALIZATION
bool initialized = false ;
bool firstCandleAfterStart = true ;
// NEW CANDLE CLASSES INITIALIZATION
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
/*NewCandleDetector* newCandleDetectorM1 = new NewCandleDetector("PERIOD_M1");
NewCandleDetector* newCandleDetectorM5 = new NewCandleDetector("PERIOD_M5");
NewCandleDetector* newCandleDetectorM15 = new NewCandleDetector("PERIOD_M15");
NewCandleDetector* newCandleDetectorM30 = new NewCandleDetector("PERIOD_M30");
NewCandleDetector* newCandleDetectorH1 = new NewCandleDetector("PERIOD_H1");
NewCandleDetector* newCandleDetectorH4 = new NewCandleDetector("PERIOD_H4");
NewCandleDetector* newCandleDetectorD1 = new NewCandleDetector("PERIOD_D1"); */
// LIVE FORMING FRACTALS HANDLER CLASS
NewCandleDetector* newCandleDetectorLive ;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create timer
EventSetTimer(60);
//Print("the ask is: " + SymbolInfoDouble(_Symbol, SYMBOL_ASK));
// THIS IS FOR SETTING THE NEW CANDLE DETECTOR TIMEFRAME FOR THE LIVE FRACTALS . (IN ORDER TO KNOW WHICH TIMEFRAME OF THE LIVE FRACTALS TO TAKE)
if(inputTimeFrameFractals == PERIOD_M1)
{
newCandleDetectorLive = new NewCandleDetector("PERIOD_M1");
}
else
if(inputTimeFrameFractals == PERIOD_M5)
{
newCandleDetectorLive = new NewCandleDetector("PERIOD_M5");
}
else
if(inputTimeFrameFractals == PERIOD_M15)
{
newCandleDetectorLive = new NewCandleDetector("PERIOD_M15");
}
else
if(inputTimeFrameFractals == PERIOD_M30)
{
newCandleDetectorLive = new NewCandleDetector("PERIOD_M30");
}
else
if(inputTimeFrameFractals == PERIOD_H1)
{
newCandleDetectorLive = new NewCandleDetector("PERIOD_H1");
}
else
if(inputTimeFrameFractals == PERIOD_H4)
{
newCandleDetectorLive = new NewCandleDetector("PERIOD_H4");
}
else
if(inputTimeFrameFractals == PERIOD_D1)
{
newCandleDetectorLive = new NewCandleDetector("PERIOD_D1");
}
if(initialized == false)
{
Print("Shark Initialized successfully on " + Symbol());
// ADD THE BUTTONS TO THE SCREEN
objectsManager.addZoneButton();
objectsManager.addConfirmButton();
objectsManager.addDeleteButton();
objectsManager.addExitExperAdvisorButton();
objectsManager.addPrintFractalsButton();
objectsManager.addPrintZonesButton();
// INIT FRACTAL VARIABLES
lowFractalIndex = rightPeriod+1 ; // this is used for the fractals
highFractalIndex = rightPeriod+1; // this is used for the fractals
initLowFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals);
initHighFractalsFromIndex(initFractalsPeriod,inputTimeFrameFractals);
// INITIALIZATION FLAG
initialized = true ;
}
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
/*Print("Low Fractals:");
lowsContainer.printLowFractals();
Print(" ");
Print("High Fractals:");
highsContainer.printhighFractals();
Print(" "); */
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
if(newCandleDetectorLive.isNewCandle())
{
handleLowFractals(inputTimeFrameFractals); // scans low fractals that are forming and adds them to the container
handleHighFractals(inputTimeFrameFractals); // scans high fractals that are forming and adds them to the container
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
//--- left-clicking on a chart
switch(id)
{
case CHARTEVENT_CLICK:
{
break;
}
//--- clicking on a graphical object
case CHARTEVENT_OBJECT_CLICK:
{
if(sparam == "ZONE_ADD_BTN")
{
if(objectConfUnit.getWaitingStatus() == false) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED
{
// create a rectangle with a unique name
int currentIdCounter = zoneContainer.getZonesIdCounter();
objectsManager.drawRectangle(currentIdCounter); // create a rectangle . set its name to be the current zonesIdCounter (and that would be the id of this current zone )
objectConfUnit.setWaitingStatus(true);
objectConfUnit.setObjectType("OBJ_RECTANGLE");
objectConfUnit.setConfirmationObjectId(currentIdCounter);
zoneContainer.incrementZonesIdCounter();
}
else
{
Print("Failed to Add a new Object, Make sure to confirm the previous object first! .");
}
}
else
if(sparam == "CONFIRM_BTN")
{
if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED
{
if(objectConfUnit.getObjectType() == "OBJ_RECTANGLE") // CASE OF ZONE
{
if(zoneContainer.getZoneIndex(objectConfUnit.getConfirmationObjectId()) != -1) // means the zone already in the data structure, in this case we just need to update it
{
// update the zone attributes
// zoneContainer.UpdateZone(int id);
Zone* tempZone = new Zone();
tempZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice()) ;
tempZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice());
tempZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime());
tempZone.setRightEdge(tempObjectAttr.getRightEdgeTime());
tempZone.setTimeFrame(tempObjectAttr.getTimeFrame());
string idOfOriginalZone = objectConfUnit.getConfirmationObjectId();
// no need to set the ID here because the ID belongs to the original zone and not this new temp one (this is just a temporary zone to check if the adjustment is valid or no)
if(zoneContainer.updateZone(tempZone, idOfOriginalZone) ==1)
{
// in this case we successfully updated the zone
Print("Updated the object:" +
"\n ID: " + objectConfUnit.getConfirmationObjectId() +
"\n Type: " + objectConfUnit.getObjectType() +
"\n Asset: " + tempObjectAttr.getSymbol() +
"\n Time Frame:" + tempObjectAttr.getTimeFrame() +
"\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() +
"\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() +
"\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() +
"\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime()
);
delete tempZone;
if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it
{
}
else
{
Print("Failed to unselect the object. Error: " + GetLastError());
}
// THIS IS TO CLEAN THE objectConfUnit
objectConfUnit.setWaitingStatus(false);
ChartRedraw();
}
else
{
Print("Failed to update the zone, please reposition it");
}
}
else // means the zone is new so we need to add it
{
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(tempObjectAttr.getHigherEdgePrice());
newZone.setLowerEdgePrice(tempObjectAttr.getLowerEdgePrice());
newZone.setLeftEdge(tempObjectAttr.getLeftEdgeTime());
newZone.setRightEdge(tempObjectAttr.getRightEdgeTime());
newZone.setId(objectConfUnit.getConfirmationObjectId());
newZone.setTimeFrame(tempObjectAttr.getTimeFrame());
if(tempObjectAttr.getHigherEdgePrice() < SymbolInfoDouble(_Symbol, SYMBOL_ASK) ){ // means its a support zone
newZone.setType("TYPE_SUPPORT");
}
if(tempObjectAttr.getLowerEdgePrice() > SymbolInfoDouble(_Symbol, SYMBOL_ASK)){ // means its a resistance zone
newZone.setType("TYPE_RESISTANCE");
}
// add the zone to the data structure
if(zoneContainer.addZone(newZone) == 1)
{
zoneContainer.findOrUpdatePivotEdges(); // update the pivot edges
Print("Added the object:" +
"\n ID: " + objectConfUnit.getConfirmationObjectId() +
"\n Type: " + objectConfUnit.getObjectType() +
"\n Asset: " + tempObjectAttr.getSymbol() +
"\n Time Frame:" + tempObjectAttr.getTimeFrame() +
"\n Higher Edge Price: " + tempObjectAttr.getHigherEdgePrice() +
"\n Lower Edge Price: " + tempObjectAttr.getLowerEdgePrice() +
"\n Left Edge Date: " + tempObjectAttr.getLeftEdgeTime() +
"\n Right Edge Date: " + tempObjectAttr.getRightEdgeTime()
);
if(ObjectSetInteger(_Symbol,objectConfUnit.getConfirmationObjectId(),OBJPROP_SELECTED,false) == true) // this is to unselect the object once we finish using it
{
}
else
{
Print("Failed to unselect the object. Error: " + GetLastError());
}
// THIS IS TO CLEAN THE objectConfUnit
objectConfUnit.setWaitingStatus(false);
}
else
{
Print("Failed to add the zone, Error: 2 or more zones are crossing");
}
ChartRedraw();
}
}
else
if(objectConfUnit.getObjectType() == "OBJ_TRENDLINE") // CASE OF TRENDLINE
{
}
}
else
{
Print("Cannot confirm, Please select an object first !");
}
}
else
if(sparam == "DELETE_BTN")
{
if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE DELETED
{
if(ObjectDelete(_Symbol,objectConfUnit.getConfirmationObjectId()))
{
if(zoneContainer.deleteZone(objectConfUnit.getConfirmationObjectId()) == 1)
{ // delete from data structure
zoneContainer.findOrUpdatePivotEdges();
Print("Deleted the object: " +
"\n Type: " + objectConfUnit.getObjectType() +
"\n ID: " + objectConfUnit.getConfirmationObjectId());
objectConfUnit.setWaitingStatus(false);
objectConfUnit.setObjectType("NO_OBJECT");
objectConfUnit.setConfirmationObjectId(-2);
ChartRedraw();
}
else{
objectConfUnit.setWaitingStatus(false);
objectConfUnit.setObjectType("NO_OBJECT");
objectConfUnit.setConfirmationObjectId(-2);
}
}
}
else
{
Print("Cannot delete, Please select an object first !");
}
}
else
if(sparam == "EXIT_BTN")
{
delete objectsManager ;
delete objectConfUnit;
delete tempObjectAttr;
delete lowsContainer;
delete highsContainer;
delete newCandleDetectorLive;
zoneContainer.freeZonesSortedArray();
/*delete newCandleDetectorD1;
delete newCandleDetectorM5;
delete newCandleDetectorM30;
delete newCandleDetectorM15;
delete newCandleDetectorM1;
delete newCandleDetectorH4;
delete newCandleDetectorH1; */
ExpertRemove();
}
else
if(sparam == "PRINT_FRACTAL_BTN")
{
Print("Low Fractals:");
lowsContainer.printLowFractals();
Print("High Fractals:");
highsContainer.printHighFractals();
}
else
if(sparam == "PRINT_ZONES_BTN")
{
zoneContainer.printZonesSortedArray();
}
else // THIS is the case were we click on any object except for the 'Add Zone' and 'Confirm Object' Buttons
{
if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THERE IS NO OTHER OBJECT SELECTED
{
Print("Cannot select the object clicked, Make sure to confirm a previous selected object first !");
}
else
{
ObjectSetInteger(_Symbol,sparam,OBJPROP_SELECTED,true);
if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_RECTANGLE)
{
Print("Selected the object:" +
"\n Type: OBJ_RECTANGLE" +
"\n ID: " + sparam);
objectConfUnit.setWaitingStatus(true) ;
objectConfUnit.setConfirmationObjectId(StringToInteger(sparam));
objectConfUnit.setObjectType("OBJ_RECTANGLE");
ChartRedraw();
}
}
}
break;
}
//--- object moved or anchor point coordinates changed
case CHARTEVENT_OBJECT_DRAG:
{
double _higherEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,1);
double _lowerEdgePrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0);
datetime _leftEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,0);
datetime _rightEdgeTime = (datetime)ObjectGetInteger(_Symbol,sparam,OBJPROP_TIME,1);
if(_higherEdgePrice < _lowerEdgePrice) // this is the case were the user flips the rectangle while adjusting it.
{
tempObjectAttr.setHigherEdgePrice(_lowerEdgePrice);
tempObjectAttr.setLowerEdgePrice(_higherEdgePrice);
}
else
{
tempObjectAttr.setHigherEdgePrice(_higherEdgePrice);
tempObjectAttr.setLowerEdgePrice(_lowerEdgePrice);
}
tempObjectAttr.setLeftEdgeTime(_leftEdgeTime);
tempObjectAttr.setRightEdgeTime(_rightEdgeTime);
tempObjectAttr.setSymbol();
tempObjectAttr.setTimeFrame(getChartTimeFrameInString());
break;
}
}
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void initLowFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod)
{
for(int i=_index ; i> rightPeriod ; i--)
{
bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals
if(isLowFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true)
{
if(lowsContainer.getFreeIndex() > 0)
{
if(iLow(Symbol(),timeFramePeriod,i) == lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getPrice()) // if low fractal is equal to the previous low fractal
{
if(lowsContainer.getLowFractal(lowsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 lows are inside the range of 2 times of right period
{
accessDeniedLows = true ;
}
}
}
if(accessDeniedLows == false)
{
LowFractal* currentFractal = new LowFractal(iLow(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod);
currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i));
currentFractal.setDistance(i);
int NumberOfCandle = i-1;
string NumberOfCandleText = IntegerToString(NumberOfCandle);
currentFractal.setArrowObjName(NumberOfCandleText);
lowsContainer.addLowFractal(currentFractal);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void initHighFractalsFromIndex(int _index,ENUM_TIMEFRAMES timeFramePeriod)
{
for(int i=_index ; i> rightPeriod ; i--)
{
bool accessDeniedHighs = false ; // variable for dealing with equal consecutive fractals
if(isHighFractalByIndex(i,leftPeriod,rightPeriod,timeFramePeriod) == true)
{
if(highsContainer.getFreeIndex() > 0)
{
if(iHigh(Symbol(),timeFramePeriod,i) == highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getPrice()) // if high fractal is equal to the previous high fractal
{
if(highsContainer.getHighFractal(highsContainer.getFreeIndex()-1).getDistance() - i < 2*rightPeriod) // if the 2 highs are inside the range of 2 times of right period
{
accessDeniedHighs = true ;
}
}
}
if(accessDeniedHighs == false)
{
HighFractal* currentFractal = new HighFractal(iHigh(Symbol(),timeFramePeriod,i),leftPeriod,rightPeriod,TimeCurrent(),timeFramePeriod);
currentFractal.setDate(iTime(Symbol(),timeFramePeriod,i));
currentFractal.setDistance(i);
int NumberOfCandle = i-1;
string NumberOfCandleText = IntegerToString(NumberOfCandle);
currentFractal.setArrowObjName(NumberOfCandleText);
highsContainer.addHighFractal(currentFractal);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void handleLowFractals(ENUM_TIMEFRAMES tf)
{
bool accessDeniedLows = false ; // variable for dealing with equal consecutive fractals if its true, then the current fractal will not be added
for(int x=0 ; x<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 !");
}
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
+1191
View File
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
//+------------------------------------------------------------------+
//| TempLineObjectAttributes.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class TempLineObjectAttributes
{
private:
string id ;
double price ;
public:
TempLineObjectAttributes();
~TempLineObjectAttributes();
// GETTERS
string getId(){return id;}
double getPrice(){return price ;}
// SETTERS
void setId(string _id){id =_id ;}
void setPrice(double _price){price = _price ;}
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
TempLineObjectAttributes::TempLineObjectAttributes()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
TempLineObjectAttributes::~TempLineObjectAttributes()
{
}
//+------------------------------------------------------------------+
+81
View File
@@ -0,0 +1,81 @@
//+------------------------------------------------------------------+
//| TempObjectAttributes.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class TempObjectAttributes
{
private:
// ATTRIBUTES FOR A ZONE
string assetName;
string timeFrame ;
double higherEdgePrice ;
double lowerEdgePrice ;
datetime leftEdgeTime ;
datetime rightEdgeTime;
// ATTRIBUTES FOR TRENDLINE
// ATTRIBUTES FOR DAILY LINE
// ATTRIBUTES FOR IMBALANCE
// ATTRIBUTES FOR FIBONACCI LEVEL
public:
TempObjectAttributes();
~TempObjectAttributes();
// GETTERS FOR ZONE
double getHigherEdgePrice(){return higherEdgePrice;}
double getLowerEdgePrice(){return lowerEdgePrice;}
datetime getLeftEdgeTime(){return leftEdgeTime ;}
datetime getRightEdgeTime(){return rightEdgeTime;}
string getSymbol(){return assetName;}
string getTimeFrame(){return timeFrame;}
// SETTERS FOR ZONE
void setHigherEdgePrice(double _higherEdgePrice){higherEdgePrice = _higherEdgePrice;}
void setLowerEdgePrice(double _lowerEdgePrice){lowerEdgePrice = _lowerEdgePrice;}
void setLeftEdgeTime(datetime _leftEdgeTime){leftEdgeTime = _leftEdgeTime;}
void setRightEdgeTime(datetime _rightEdgeTime){rightEdgeTime = _rightEdgeTime;}
void setSymbol(){assetName = Symbol();}
void setTimeFrame(string _timeframe){timeFrame = _timeframe;}
// OTHER ZONE FUNCTIONS
void cleanAttributesZone(){higherEdgePrice = -1;
lowerEdgePrice = -1;
leftEdgeTime = 0;
rightEdgeTime = 0;}
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
TempObjectAttributes::TempObjectAttributes()
{
higherEdgePrice = -1;
lowerEdgePrice = -1;
leftEdgeTime = 0;
rightEdgeTime = 0;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
TempObjectAttributes::~TempObjectAttributes()
{
}
//+------------------------------------------------------------------+
BIN
View File
Binary file not shown.
+601
View File
@@ -0,0 +1,601 @@
//+------------------------------------------------------------------+
//| Tiger.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "NewCandleDetector.mqh"
#include "GraphicalObjectsManager.mqh"
#include "Zone.mqh"
#include "ZoneContainer.mqh"
#include "MarketObserver.mqh"
#include "BuyEntryManager.mqh"
#include "LotSizeCalculator.mqh"
input double rangeDistance ;
input double resistanceExtendAboveCandle;
input double supportExtendBelowCandle ;
input double stopLossLimit ;
double input riskInDollars ;
double input netTakeProfit ;
bool input allowSecondChanceStopLoss ;
double input bottomWickSize ;
double input smallBottomWickSize ;
double input buyStopPipsTrigger ;
bool input MOD_CLEAN = false ;
bool waitingForBottomWickToForm = false ;
bool waitingForSmallBottomWickToForm = false ;
bool buyStopValid = false ;
bool closedPartialOnNegativeDirection = false ;
bool securedTenPips = false ;
#include <Trade\Trade.mqh>
CTrade tradeTiger ;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
// GUI CLASSES INITIALIZATION
GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager();
// CONTAINERS INITIALIZATION
ZoneContainer* zoneContainer = new ZoneContainer() ;
// ALGORITHM CLASSES INITIALIZATION
MarketObserver* marketObserver = new MarketObserver(zoneContainer);
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
NewCandleDetector newCandleDetector("PERIOD_M30");
BuyEntryManager buyEntryMan ;
LotSizeCalculator lotSizeCalc ;
Zone* temporaryRestestSupportZone = new Zone();
int OnInit()
{
//--- create timer
EventSetTimer(60);
iClose(_Symbol,PERIOD_M15,5);
iClose(_Symbol,PERIOD_H1,5);
/*datetime d1=D'2023.09.01 00:00:00'; // Year Month Day Hours Minutes Seconds
Print("the dateTime is: " + d1);
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(1930);
newZone.setLowerEdgePrice(1925);
newZone.setLeftEdge(iTime(_Symbol,PERIOD_CURRENT,2));
newZone.setRightEdge(d1);
newZone.setId("1");
newZone.setTimeFrame("PERIOD_M30");
zoneContainer.addZone(newZone);
objectsManager.drawRectangleInStrategyTester(1,iTime(_Symbol,PERIOD_CURRENT,2),d1,1930,1925);
zoneContainer.printZonesSortedArray(); */
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
if(securedTenPips == false ){
secureTenPips(0.3);
}
if(waitingForBottomWickToForm){
if(iClose(_Symbol,PERIOD_CURRENT,1) - SymbolInfoDouble(_Symbol, SYMBOL_BID) >= bottomWickSize){
waitingForBottomWickToForm = false ;
Print("Bottom Wick in length of at least " + bottomWickSize + " was formed !");
buyStopValid = true ;
}
}
if(buyStopValid){
if( SymbolInfoDouble(_Symbol, SYMBOL_ASK) > iHigh(_Symbol,PERIOD_CURRENT,1) + buyStopPipsTrigger){ // here we take a buy entry based on break and retest wick. the Algo will first try to put the stop loss under the low of the temporary support zone
// if that stop loss was too high , then it will put it under the low of the wick that was recently made. (the wick should be at least bottomWickSize which is currently 1)
double stopLossUnderTemporarySupportZone = temporaryRestestSupportZone.getLowerEdge() - 0.5 ; // under the temporary support zone
double stopLossUnderWick = iLow(_Symbol,PERIOD_CURRENT,0) - 0.5; // the low of the current candle
if(!((SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossUnderTemporarySupportZone) > stopLossLimit)){ // on this case a wick was formed price starts to break the previous candle high, im taking a buy
//and im putting the stop loss below the whole zone (which is support now)
double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossUnderTemporarySupportZone);
buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossUnderTemporarySupportZone,2);
closedPartialOnNegativeDirection = false ;
securedTenPips = false ;
buyStopValid = false ;
Print("Took a wick retest buy type 1");
}
else if(!((SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossUnderWick) > stopLossLimit)){ // on this case a wick was formed price starts to break the previous candle high, im taking a buy
//and im putting the stop loss below the wick (which is at least bottomWickSize)
double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossUnderWick);
buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossUnderWick,2);
closedPartialOnNegativeDirection = false ;
securedTenPips = false ;
buyStopValid = false ;
Print("Took a wick retest buy type 2");
}
}
}
if(newCandleDetector.isNewCandle())
{
if(iClose(_Symbol,PERIOD_CURRENT,1) < iOpen(_Symbol,PERIOD_CURRENT,1) && closedPartialOnNegativeDirection == false){ // if the m30 candle closed bearish
closePartialsOfAllTrades(0.5);
closedPartialOnNegativeDirection = true ;
}
buyStopValid = false ;
waitingForBottomWickToForm = false ;
bool finishedDeleting = false ;
MqlDateTime mqldt ;
datetime currTime = TimeCurrent(mqldt);
if(candleClosedBelowRetestZone(PERIOD_CURRENT)){
temporaryRestestSupportZone.setType("TYPE_INVALID");
deleteZoneGuiOnly("999");
}
if(zoneContainer.getNumberOfActiveZones() != 0) // if there are zones found
{
if(marketObserver.candleClosedAboveResistanceByIndex(0,PERIOD_CURRENT)) // check if candle closed above the zone
{
datetime _leftEdgeRestestZone = iTime(_Symbol,PERIOD_CURRENT,4);
datetime _rightEdgeRetestZone = D'2023.11.01 00:00:00';
while(!finishedDeleting && zoneContainer.getNumberOfActiveZones() != 0) // this while is used in the case of a candle closing above more than 1 zone at once
{
/* temporaryRestestSupportZone.setHigherEdgePrice(zoneContainer.getZoneByIndex(0).getHigherEdge());
temporaryRestestSupportZone.setLowerEdgePrice(zoneContainer.getZoneByIndex(0).getLowerEdge());
temporaryRestestSupportZone.setLeftEdge(_leftEdgeRestestZone);
temporaryRestestSupportZone.setRightEdge(_rightEdgeRetestZone);
temporaryRestestSupportZone.setId("999"); // the + "t" stands for temporary and it is made to keep the zones id's unique
temporaryRestestSupportZone.setTimeFrame("PERIOD_M30");
temporaryRestestSupportZone.setType("TYPE_SUPPORT");
deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */
if(zoneContainer.getNumberOfActiveZones() != 0 && marketObserver.candleClosedAboveResistanceByIndex(0,PERIOD_CURRENT))
{
zoneContainer.getZoneByIndex(0).getHigherEdge();
temporaryRestestSupportZone.setHigherEdgePrice(zoneContainer.getZoneByIndex(0).getHigherEdge());
temporaryRestestSupportZone.setLowerEdgePrice(zoneContainer.getZoneByIndex(0).getLowerEdge());
temporaryRestestSupportZone.setLeftEdge(_leftEdgeRestestZone);
temporaryRestestSupportZone.setRightEdge(_rightEdgeRetestZone);
temporaryRestestSupportZone.setId("999"); // the + "t" stands for temporary and it is made to keep the zones id's unique
temporaryRestestSupportZone.setTimeFrame("PERIOD_M30");
temporaryRestestSupportZone.setType("TYPE_SUPPORT");
deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI
}
else
{
finishedDeleting = true ;
}
}
int idAsInt = StringToInteger(temporaryRestestSupportZone.getId());
if((mqldt.hour > 13 && mqldt.hour < 22) || (mqldt.hour > 3 && mqldt.hour < 7) || (mqldt.hour > 8 && mqldt.hour < 12) )
{
double stopLossPrice = iLow(_Symbol,PERIOD_CURRENT,1);
stopLossPrice = stopLossPrice -1;
double secondChanceStopLossPrice = iLow(_Symbol,PERIOD_M15,1);
secondChanceStopLossPrice = secondChanceStopLossPrice -1;
if(!(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossPrice > stopLossLimit)) // enter only if the M30 previous candle satisfied the condition of the proper stop loss
{
//Print("Entered here 2!");
double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,stopLossPrice);
buyEntryMan.takeBuyTradeTiger(lotsToEnter,stopLossPrice,netTakeProfit);
closedPartialOnNegativeDirection = false ;
securedTenPips = false ;
}
else
if(!(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - secondChanceStopLossPrice > stopLossLimit) && secondChanceStopLossPrice < temporaryRestestSupportZone.getLowerEdge() - 0.5) // if the M30 candle failed , then try the M15 candle
{
if(allowSecondChanceStopLoss == true)
{
double lotsToEnter = lotSizeCalc.calculateLotSize(riskInDollars,secondChanceStopLossPrice);
buyEntryMan.takeBuyTradeTiger(lotsToEnter,secondChanceStopLossPrice,netTakeProfit);
closedPartialOnNegativeDirection = false ;
securedTenPips = false ;
}
}
else // both M30 and M15 candles closed too far from the zone, so im gonna wait for retracement , and support to be built on the zone, or a bottom wick to form
{
objectsManager.drawRectangleInStrategyTester(idAsInt,_leftEdgeRestestZone,_rightEdgeRetestZone,
temporaryRestestSupportZone.getHigherEdge(),temporaryRestestSupportZone.getLowerEdge(),clrGray);
waitingForBottomWickToForm = true ;
}
}
}
}
if(candleClosedBullish(PERIOD_M30,2) && candleClosedBearish(PERIOD_M30,1))
{
// create a rectangle with a unique name
int currentIdCounter = zoneContainer.getZonesIdCounter();
datetime _leftEdge = iTime(_Symbol,PERIOD_CURRENT,2);
datetime _rightEdge = D'2023.11.01 00:00:00';
double resistancePrice = iOpen(_Symbol,PERIOD_CURRENT,1);
if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistance))
{
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle);
newZone.setLowerEdgePrice(resistancePrice);
newZone.setLeftEdge(_leftEdge);
newZone.setRightEdge(_rightEdge);
newZone.setId(IntegerToString(currentIdCounter));
newZone.setTimeFrame("PERIOD_M30");
newZone.setType("TYPE_RESISTANCE");
zoneContainer.addResistanceZoneTiger(newZone);
zoneContainer.incrementZonesIdCounter();
objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,clrBeige);
//Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones());
//zoneContainer.printZonesSortedArray();
}
else if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistance)){
double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above
double currentLowEdge = resistancePrice; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above
}
else
if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre
{
//Print("Entered here 2");
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle);
newZone.setLowerEdgePrice(resistancePrice);
newZone.setLeftEdge(_leftEdge);
newZone.setRightEdge(_rightEdge);
newZone.setId(IntegerToString(currentIdCounter));
newZone.setTimeFrame("PERIOD_M30");
newZone.setType("TYPE_RESISTANCE");
zoneContainer.addResistanceZoneTiger(newZone);
zoneContainer.incrementZonesIdCounter();
objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,clrBeige);
//zoneContainer.printZonesSortedArray();
}
}
Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones());
Print("Zones are : ");
zoneContainer.printZonesSortedArray();
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool resistanceIsFound()
{
//if()
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index)
{
double candleClose = iClose(_Symbol,_timeFrame,_index);
double candleOpen = iOpen(_Symbol,_timeFrame,_index);
if(candleClose >candleOpen) // the candle closed bullish
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index)
{
double candleClose = iClose(_Symbol,_timeFrame,_index);
double candleOpen = iOpen(_Symbol,_timeFrame,_index);
if(candleClose < candleOpen) // the candle closed bullish
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void deleteZoneWithGUI(string _id)
{
zoneContainer.deleteZone(_id);
if(!ObjectDelete(_Symbol,_id))
{
Print("Failed to delete object error: " + GetLastError());
}
}
void deleteZoneGuiOnly(string _id)
{
if(!ObjectDelete(_Symbol,_id))
{
Print("Failed to delete object error: " + GetLastError());
}
}
//+------------------------------------------------------------------+
bool candleClosedBelowRetestZone(ENUM_TIMEFRAMES tf){
double previousCandleClose = iClose(_Symbol,tf,1);
if(previousCandleClose < temporaryRestestSupportZone.getLowerEdge() ){
return true ;
}
return false ;
}
void closePartialsOfAllTrades(double partial){
for(int i = PositionsTotal()-1 ; i>=0 ; i--){
ulong posTicket = PositionGetTicket(i);
if(PositionSelectByTicket(posTicket)){
double positionVolum = PositionGetDouble(POSITION_VOLUME);
double partialToClose = positionVolum * partial ;
tradeTiger.PositionClosePartial(posTicket,NormalizeDouble(partialToClose,2));
}
else{
Print("Failed to select position, Error: " + GetLastError());
}
}
}
void secureTenPips(double partial){
for(int i = PositionsTotal()-1 ; i>=0 ; i--){
ulong posTicket = PositionGetTicket(i);
if(PositionSelectByTicket(posTicket)){
double positionVolume = PositionGetDouble(POSITION_VOLUME);
if((SymbolInfoDouble(_Symbol, SYMBOL_BID) - PositionGetDouble(POSITION_PRICE_OPEN)) > 1){
double partialToClose = positionVolume * partial ;
tradeTiger.PositionClosePartial(posTicket,NormalizeDouble(partialToClose,2));
securedTenPips = true ;
Print("secured 10 pips");
}
}
else{
Print("Failed to select position, Error: " + GetLastError());
}
}
}
Binary file not shown.
+1023
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+1442
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+694
View File
@@ -0,0 +1,694 @@
//+------------------------------------------------------------------+
//| TigerObserver.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "NewCandleDetector.mqh"
#include "GraphicalObjectsManager.mqh"
#include "Zone.mqh"
#include "ZoneContainer.mqh"
#include "MarketObserverTiger.mqh"
input group "Range Related Variables"
input double rangeDistanceBetweenZones ;
input double cleanRangeUponEntry ;
input double potentialRR;
input group "Zone Size Settings"
input double resistanceExtendAboveCandle;
input double resistanceLowerEdgeExtend ;
input double supportExtendBelowCandle ;
input double supportHigherEdgeExtend;
input group "Zone TimeFrames"
input bool APPLY_M30_STRUCTURE ;
input bool APPLY_H1_STRUCTURE;
// GUI CLASSES INITIALIZATION
GraphicalObjectsManager* objectsManager = new GraphicalObjectsManager();
// CONTAINERS INITIALIZATION
ZoneContainer* zoneContainer_W1 = new ZoneContainer() ;
ZoneContainer* zoneContainer_D1 = new ZoneContainer() ;
ZoneContainer* zoneContainer_H4 = new ZoneContainer() ;
ZoneContainer* zoneContainer_H1 = new ZoneContainer() ;
ZoneContainer* zoneContainer_M30 = new ZoneContainer() ;
ZoneContainer* zoneContainerSupport_W1 = new ZoneContainer() ;
ZoneContainer* zoneContainerSupport_D1 = new ZoneContainer() ;
ZoneContainer* zoneContainerSupport_H4 = new ZoneContainer() ;
ZoneContainer* zoneContainerSupport_H1 = new ZoneContainer() ;
ZoneContainer* zoneContainerSupport_M30 = new ZoneContainer() ;
// ALGORITHM CLASSES INITIALIZATION
MarketObserverTiger* marketObserverTiger = new MarketObserverTiger();
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
NewCandleDetector newCandleDetectorWeekly("PERIOD_W1");
NewCandleDetector newCandleDetectorDaily("PERIOD_D1");
NewCandleDetector newCandleDetector4H("PERIOD_H4");
NewCandleDetector newCandleDetector1H("PERIOD_H1");
NewCandleDetector newCandleDetector30M("PERIOD_M30");
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
Zone* temporaryRestestSupportZone = new Zone();
int OnInit()
{
//--- create timer
EventSetTimer(60);
// ONLY FOR VISULAZITAION ON STRATEGY TESTER
iClose(_Symbol,PERIOD_W1,1);
iClose(_Symbol,PERIOD_D1,1);
iClose(_Symbol,PERIOD_H4,5);
iClose(_Symbol,PERIOD_H1,5);
iClose(_Symbol,PERIOD_M30,5);
iClose(_Symbol,PERIOD_M15,5);
objectsManager.addTextTiger();
//objectsManager.addMarketDescriptionTextTiger();
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
/*if(newCandleDetector30M.isNewCandle())
{
detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30);
updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30");
detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30);
updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30");
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
} */
/*if(newCandleDetector1H.isNewCandle()){
MqlDateTime mqldt ;
datetime currTime = TimeCurrent(mqldt);
if(mqldt.hour == 13){
objectsManager.drawVerticalLine(clrAzure,TimeCurrent());
}
detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrGray,clrRed,zoneContainer_H1);
updateBreakAboveStructureAndDelete(zoneContainer_H1,PERIOD_H1,"PERIOD_H1");
detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",clrWhite,clrRed,zoneContainerSupport_H1);
updateBreakBelowStructureAndDelete(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1");
//zoneContainer_H1.printZonesSortedArray();
//zoneContainerSupport_H1.printZonesSortedArray();
} */
if(newCandleDetector4H.isNewCandle()){
detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPurple,clrGreen,zoneContainer_H4);
updateBreakAboveStructureAndDelete(zoneContainer_H4,PERIOD_H4,"PERIOD_H4");
detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPink,clrBlue,zoneContainer_H4);
updateBreakAboveStructureAndDelete(zoneContainer_H4,PERIOD_H4,"PERIOD_H4");
detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrYellow,clrGreen,zoneContainerSupport_H4);
updateBreakBelowStructureAndDelete(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4");
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
}
if(newCandleDetectorDaily.isNewCandle()){
//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1);
//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1");
objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
if(newCandleDetectorWeekly.isNewCandle()){
objectsManager.drawVerticalLine(clrRed, TimeCurrent());;
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool detectAndDrawResistanceOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer )
{
if(candleClosedBullish(timeFrame,2) && candleClosedBearish(timeFrame,1)) // if resistance formed
{
// create a rectangle with a unique name
int currentIdCounter = zoneContainer.getZonesIdCounter();
datetime _leftEdge = iTime(_Symbol,timeFrame,2);
datetime _rightEdge = D'2023.11.01 00:00:00';
double resistancePrice = iOpen(_Symbol,timeFrame,1);
if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice >= rangeDistanceBetweenZones)) // check if it has a clean range above
{
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle);
newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend);
newZone.setLeftEdge(_leftEdge);
newZone.setRightEdge(_rightEdge);
newZone.setId(IntegerToString(currentIdCounter));
newZone.setTimeFrame(timeFrameStr);
newZone.setType("TYPE_RESISTANCE_BREAKOUT");
zoneContainer.addResistanceZoneTiger(newZone);
zoneContainer.incrementZonesIdCounter();
Print("current id counter of, zoneContainer is: " + currentIdCounter );
objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color);
//Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones());
//zoneContainer.printZonesSortedArray();
}
else
if((zoneContainer.getNumberOfActiveZones() != 0) && (zoneContainer.getZoneByIndex(0).getLowerEdge() - resistancePrice < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone
{
double currentHighEdge = resistancePrice + resistanceExtendAboveCandle ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above
double currentLowEdge = resistancePrice - resistanceLowerEdgeExtend; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle);
newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend);
newZone.setLeftEdge(_leftEdge);
newZone.setRightEdge(_rightEdge);
newZone.setId(IntegerToString(currentIdCounter));
newZone.setTimeFrame(timeFrameStr);
newZone.setType("TYPE_RESISTANCE_NORMAL");
zoneContainer.addResistanceZoneTiger(newZone);
zoneContainer.incrementZonesIdCounter();
//objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice,usual_zone_color);
/*if(zoneContainer.getZoneByIndex(1).getType() == "TYPE_RESISTANCE_NORMAL"){
string idOfZoneToHide = zoneContainer.getZoneByIndex(1).getId();
deleteZoneGuiOnly(idOfZoneToHide,zoneContainer);
} */
}
else
if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre
{
//Print("Entered here 2");
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(resistancePrice + resistanceExtendAboveCandle);
newZone.setLowerEdgePrice(resistancePrice - resistanceLowerEdgeExtend);
newZone.setLeftEdge(_leftEdge);
newZone.setRightEdge(_rightEdge);
newZone.setId(IntegerToString(currentIdCounter));
newZone.setTimeFrame(timeFrameStr);
newZone.setType("TYPE_RESISTANCE_BREAKOUT");
zoneContainer.addResistanceZoneTiger(newZone);
zoneContainer.incrementZonesIdCounter();
objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,resistancePrice + resistanceExtendAboveCandle,resistancePrice - resistanceLowerEdgeExtend,BOS_zone_color);
//zoneContainer.printZonesSortedArray();
}
return true ;
}
return false ;
}
bool detectAndDrawSupportOnTimeFrame(ENUM_TIMEFRAMES timeFrame, string timeFrameStr, long BOS_zone_color, long usual_zone_color,ZoneContainer& zoneContainer )
{
if(candleClosedBearish(timeFrame,2) && candleClosedBullish(timeFrame,1)) // if support formed
{
// create a rectangle with a unique name
int currentIdCounter = zoneContainer.getSupportZonesIdCounter();
datetime _leftEdge = iTime(_Symbol,timeFrame,2);
datetime _rightEdge = D'2023.11.01 00:00:00';
double supportPrice = iOpen(_Symbol,timeFrame,1);
if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() >= rangeDistanceBetweenZones)) // check if it has a clean range down
{
Zone* newZone = new Zone() ;
newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle);
newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend);
newZone.setLeftEdge(_leftEdge);
newZone.setRightEdge(_rightEdge);
newZone.setId(IntegerToString(currentIdCounter));
newZone.setTimeFrame(timeFrameStr);
newZone.setType("TYPE_SUPPORT_BREAKOUT");
zoneContainer.addSupportZoneTiger(newZone);
zoneContainer.incrementZonesIdCounterSupport();
Print("current id counter of, zoneContainer_support is: " + currentIdCounter );
objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice- supportExtendBelowCandle,BOS_zone_color);
//Print("Number of active zones is: " + zoneContainer.getNumberOfActiveZones());
//zoneContainer.printZonesSortedArray();
}
else
if((zoneContainer.getNumberOfActiveZones() != 0) && (supportPrice - zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge() < rangeDistanceBetweenZones)) // if it doesnt have a clean range, just add it as a blue zone
{
double currentHighEdge = supportPrice + supportHigherEdgeExtend ; // this is a high edge of a resistance, but its not considered as a zone, because it doesnt have clean range above
double currentLowEdge = supportPrice - supportExtendBelowCandle; // this is a low edge of a resistance, but its not considered as a zone, because it doesnt have clean range above
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend);
newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle);
newZone.setLeftEdge(_leftEdge);
newZone.setRightEdge(_rightEdge);
newZone.setId(IntegerToString(currentIdCounter));
newZone.setTimeFrame(timeFrameStr);
newZone.setType("TYPE_SUPPORT_NORMAL");
zoneContainer.addSupportZoneTiger(newZone);
zoneContainer.incrementZonesIdCounterSupport();
//objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice,supportPrice - supportExtendBelowCandle,usual_zone_color);
}
else
if(zoneContainer.getNumberOfActiveZones() == 0) // this means this is the first zone to add to the data strucutre
{
//Print("Entered here 2");
Zone* newZone = new Zone() ;
newZone.setHigherEdgePrice(supportPrice + supportHigherEdgeExtend);
newZone.setLowerEdgePrice(supportPrice - supportExtendBelowCandle);
newZone.setLeftEdge(_leftEdge);
newZone.setRightEdge(_rightEdge);
newZone.setId(IntegerToString(currentIdCounter));
newZone.setTimeFrame(timeFrameStr);
newZone.setType("TYPE_SUPPORT_BREAKOUT");
zoneContainer.addSupportZoneTiger(newZone);
zoneContainer.incrementZonesIdCounterSupport();
objectsManager.drawRectangleInStrategyTester(currentIdCounter,_leftEdge,_rightEdge,supportPrice + supportHigherEdgeExtend,supportPrice - supportExtendBelowCandle,BOS_zone_color);
//zoneContainer.printZonesSortedArray();
}
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index)
{
double candleClose = iClose(_Symbol,_timeFrame,_index);
double candleOpen = iOpen(_Symbol,_timeFrame,_index);
if(candleClose >candleOpen) // the candle closed bullish
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index)
{
double candleClose = iClose(_Symbol,_timeFrame,_index);
double candleOpen = iOpen(_Symbol,_timeFrame,_index);
if(candleClose < candleOpen) // the candle closed bullish
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
void deleteZoneWithGUI(string _id, ZoneContainer& zoneContainer)
{
zoneContainer.deleteZone(_id);
if(!ObjectDelete(_Symbol,_id))
{
Print("Failed to delete object error: " + GetLastError());
}
Print("Deleted the zone with gui!");
}
void deleteZoneGuiOnly(string _id,ZoneContainer& zoneContainer)
{
if(!ObjectDelete(_Symbol,_id))
{
Print("Failed to delete object error: " + GetLastError());
}
Print("Deleted the zone gui!");
}
void updateBreakAboveStructureAndDelete(ZoneContainer& zoneContainer, ENUM_TIMEFRAMES timeFrame, string timeFrameStr){
bool finishedDeleting = false ;
if(zoneContainer.getNumberOfActiveZones() != 0) // if there are zones found
{
if(marketObserverTiger.candleClosedAboveResistanceByIndex(0,timeFrame,zoneContainer)) // check if candle closed above the zone
{
datetime _leftEdgeRestestZone = iTime(_Symbol,timeFrame,4);
datetime _rightEdgeRetestZone = D'2023.11.01 00:00:00';
while(!finishedDeleting && zoneContainer.getNumberOfActiveZones() != 0 ) // this while is used in the case of a candle closing above more than 1 zone at once
{
/* temporaryRestestSupportZone.setHigherEdgePrice(zoneContainer.getZoneByIndex(0).getHigherEdge());
temporaryRestestSupportZone.setLowerEdgePrice(zoneContainer.getZoneByIndex(0).getLowerEdge());
temporaryRestestSupportZone.setLeftEdge(_leftEdgeRestestZone);
temporaryRestestSupportZone.setRightEdge(_rightEdgeRetestZone);
temporaryRestestSupportZone.setId("999"); // the + "t" stands for temporary and it is made to keep the zones id's unique
temporaryRestestSupportZone.setTimeFrame("PERIOD_M30");
temporaryRestestSupportZone.setType("TYPE_SUPPORT");
deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */
if(zoneContainer.getNumberOfActiveZones() != 0 && marketObserverTiger.candleClosedAboveResistanceByIndex(0,timeFrame,zoneContainer))
{
zoneContainer.getZoneByIndex(0).getHigherEdge();
temporaryRestestSupportZone.setHigherEdgePrice(zoneContainer.getZoneByIndex(0).getHigherEdge());
temporaryRestestSupportZone.setLowerEdgePrice(zoneContainer.getZoneByIndex(0).getLowerEdge());
temporaryRestestSupportZone.setLeftEdge(_leftEdgeRestestZone);
temporaryRestestSupportZone.setRightEdge(_rightEdgeRetestZone);
temporaryRestestSupportZone.setId("999"); // the + "t" stands for temporary and it is made to keep the zones id's unique
temporaryRestestSupportZone.setTimeFrame(timeFrameStr);
temporaryRestestSupportZone.setType("TYPE_SUPPORT");
deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId()),zoneContainer); // delete the zone with the GUI
}
else
{
finishedDeleting = true ;
ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"");
ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"");
ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"Candle Closed Above the zone");
}
}
/*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){
Zone* tempZone = zoneContainer.getZoneByIndex(0);
string zoneIdStr = tempZone.getId();
int zoneIdInteger = StringToInteger(zoneIdStr);
objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed);
Print("Retrieved the zone succesfully!");
} */
}
}
}
void updateBreakBelowStructureAndDelete(ZoneContainer& zoneContainer, ENUM_TIMEFRAMES timeFrame, string timeFrameStr){
bool finishedDeleting = false ;
if(zoneContainer.getNumberOfActiveZones() != 0) // if there are zones found
{
if(marketObserverTiger.candleClosedBelowSupportByIndex(zoneContainer.getNumberOfActiveZones() -1 ,timeFrame,zoneContainer)) // check if candle closed below the zone
{
datetime _leftEdgeRestestZone = iTime(_Symbol,timeFrame,4);
datetime _rightEdgeRetestZone = D'2023.11.01 00:00:00';
while(!finishedDeleting && zoneContainer.getNumberOfActiveZones() != 0 ) // this while is used in the case of a candle closing above more than 1 zone at once
{
/* temporaryRestestSupportZone.setHigherEdgePrice(zoneContainer.getZoneByIndex(0).getHigherEdge());
temporaryRestestSupportZone.setLowerEdgePrice(zoneContainer.getZoneByIndex(0).getLowerEdge());
temporaryRestestSupportZone.setLeftEdge(_leftEdgeRestestZone);
temporaryRestestSupportZone.setRightEdge(_rightEdgeRetestZone);
temporaryRestestSupportZone.setId("999"); // the + "t" stands for temporary and it is made to keep the zones id's unique
temporaryRestestSupportZone.setTimeFrame("PERIOD_M30");
temporaryRestestSupportZone.setType("TYPE_SUPPORT");
deleteZoneWithGUI((zoneContainer.getZoneByIndex(0).getId())); // delete the zone with the GUI */
if(zoneContainer.getNumberOfActiveZones() != 0 && marketObserverTiger.candleClosedBelowSupportByIndex(zoneContainer.getNumberOfActiveZones()-1,timeFrame,zoneContainer))
{
zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge();
temporaryRestestSupportZone.setHigherEdgePrice(zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getHigherEdge());
temporaryRestestSupportZone.setLowerEdgePrice(zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getLowerEdge());
temporaryRestestSupportZone.setLeftEdge(_leftEdgeRestestZone);
temporaryRestestSupportZone.setRightEdge(_rightEdgeRetestZone);
temporaryRestestSupportZone.setId("9999"); // the + "t" stands for temporary and it is made to keep the zones id's unique
temporaryRestestSupportZone.setTimeFrame(timeFrameStr);
temporaryRestestSupportZone.setType("TYPE_RESISTANCE");
deleteZoneWithGUI((zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getId()),zoneContainer); // delete the zone with the GUI
}
else
{
//Print("Lower edge is: " + zoneContainer.getZoneByIndex(zoneContainer.getNumberOfActiveZones()-1).getLowerEdge());
finishedDeleting = true ;
ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"");
ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"");
ObjectSetString(0,"marketDescriptionText",OBJPROP_TEXT,"Candle Closed Below the zone");
}
}
/*if(zoneContainer.getNumberOfActiveZones() != 0 && zoneContainer.getZoneByIndex(0).getType() == "TYPE_RESISTANCE_NORMAL"){
Zone* tempZone = zoneContainer.getZoneByIndex(0);
string zoneIdStr = tempZone.getId();
int zoneIdInteger = StringToInteger(zoneIdStr);
objectsManager.drawRectangleInStrategyTester(zoneIdInteger,tempZone.getLeftEdge(),tempZone.getRightEdge(),tempZone.getHigherEdge(),tempZone.getLowerEdge(),clrRed);
Print("Retrieved the zone succesfully!");
} */
}
}
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+443
View File
@@ -0,0 +1,443 @@
//+------------------------------------------------------------------+
//| TigerObserver.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Algo_Skeleton_Functions.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int OnInit()
{
//--- create timer
EventSetTimer(60);
// ONLY FOR VISULAZITAION ON STRATEGY TESTER
iClose(_Symbol,PERIOD_W1,1);
iClose(_Symbol,PERIOD_D1,1);
iClose(_Symbol,PERIOD_H4,5);
iClose(_Symbol,PERIOD_H1,5);
iClose(_Symbol,PERIOD_M30,5);
iClose(_Symbol,PERIOD_M15,5);
objectsManager.addTextTiger();
for(int i=0; i<NUM_MAX_ALLOWED_TRADES ; i++)
{
BuyActiveTradesArray[i] = NULL ;
SellActiveTradesArray[i] = NULL ;
}
//objectsManager.addMarketDescriptionTextTiger();
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
Print("Buys Count: " + buysCount);
Print("Sells Count: " + sellsCount);
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
cleanBuyTradesArr();
cleanSellTradesArr();
secureProfitIfNeeded();
// BUYS
if(waitForBottomWickToForm == true && wickLengthCounter == wickLengthInMinutes) // waited wickLengthInMinutes time, and now its the time to check if the wick is valid
{
bottomWickValidationState = handleBottomWickValidation();
updateBottomWickState(bottomWickValidationState);
}
if(bottomWickFormed){
datetime currTime = TimeCurrent();
if(SymbolInfoDouble(_Symbol,SYMBOL_ASK) >= buyStopPrice && !wickTradeTaken){
double stopLossPrice = iLow(_Symbol,PERIOD_CURRENT,0) - stopLossUnderWickBy;
double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1);
double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1);
double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1);
stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ;
stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ;
stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ;
if((SymbolInfoDouble(_Symbol,SYMBOL_ASK) - stopLossPrice) < minimumStopLossInPips){
stopLossPrice = stopLossBased_M30 ;
if(stopLossIsValidBuys(stopLossBased_H1,maxPipsRiskAmount)){
stopLossPrice = stopLossBased_H1 ;
}
else if(stopLossIsValidBuys(stopLossBased_M30,maxPipsRiskAmount)){
stopLossPrice = stopLossBased_M30 ;
}
else if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount)){
stopLossPrice = stopLossBased_M15 ;
}
}
else if(!stopLossIsValidBuys(stopLossPrice,maxPipsRiskAmount)){
stopLossPrice = -1 ;
}
double lotsToBuy = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
int indexToNewTrade ;
if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) && stopLossPrice != -1)
{
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToBuy,stopLossPrice) ;
BuyTradeManagerTiger* tempTigerManager= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
BuyActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array
buysCount++;
wickTradeTaken = true ;
Comment("Took a bUY. stop loss: above current wick, " + "Active trade id: " + activeTradeId);
}
else
{
Comment("i cant take a trade because the arrray is full");
}
Comment(TimeToString(currTime,TIME_MINUTES) + ": price has reached the candle high, im taking a buy");
}
}
// SELLS
if(waitForTopWickToForm == true && wickLengthCounter == wickLengthInMinutes){ // waited wickLengthInMinutes time, and now its the time to check if the wick is valid
topWickValidationState = handleTopWickValidation();
updateTopWickState(topWickValidationState);
}
if(topWickFormed){
datetime currTime = TimeCurrent();
if((SymbolInfoDouble(_Symbol,SYMBOL_BID) <= sellStopPrice) && !wickTradeTaken){
double stopLossPrice = iHigh(_Symbol,PERIOD_CURRENT,0) + stopLossAboveWickBy;
double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1);
double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1);
double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1);
stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ;
stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ;
stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ;
if((stopLossPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID)) < minimumStopLossInPips){
stopLossPrice = stopLossBased_M30 ;
if(stopLossIsValidSells(stopLossBased_H1,maxPipsRiskAmount)){
stopLossPrice = stopLossBased_H1 ;
}
else if(stopLossIsValidSells(stopLossBased_M30,maxPipsRiskAmount)){
stopLossPrice = stopLossBased_M30 ;
}
else if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount)){
stopLossPrice = stopLossBased_M15 ;
}
}
else if(!stopLossIsValidSells(stopLossPrice,maxPipsRiskAmount)){
stopLossPrice = -1 ;
}
double lotsToSell = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
int indexToNewTrade ;
if(((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1) && stopLossPrice != -1)
{
activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToSell,stopLossPrice) ;
SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array
sellsCount++;
wickTradeTaken = true ;
Comment("Took a sell. stop loss: under current wick, " + "Active trade id: " + activeTradeId);
}
else
{
Comment("i cant take a trade because the arrray is full");
}
Comment(TimeToString(currTime,TIME_MINUTES) + ": price has reached the candle low, im taking a sell");
}
}
if(newCandleDetectorM1.isNewCandle())
{
// BUY CASE
if(waitForBottomWickToForm == true && wickLengthCounter < wickLengthInMinutes)
{
wickLengthCounter++ ;
}
// SELL CASE
if(waitForTopWickToForm == true && wickLengthCounter < wickLengthInMinutes){
wickLengthCounter++;
}
}
if(newCandleDetectorM15.isNewCandle())
{
manageRiskIfNeeded();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetector30M.isNewCandle())
{
wickTradeTaken = false ;
if(bottomWickFormed){ // reset the bottomWickFormed flag. this is for the cases that bottom wick has formed, but m30 candle closed and the trade still not taken
bottomWickFormed = false ;
buyStopPrice = -1;
}
if(topWickFormed){ // reset the topWickFormed flag. this is for the cases that top wick has formed, but m30 candle closed and the trade still not taken
topWickFormed = false ;
sellStopPrice = -1;
}
trailAllOpenPositionsIfNeeded(PERIOD_M30);
// DETECTING SUPPORTS AND RESISTANCES
detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30);
detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30);
// VARIABLE PREPROCESSING FOR BOS
double brokenResistanceLowerPrice = -1 ;
string brokenZoneTypeResistance = "" ;
double brokenSupportHigherPrice = -1;
string brokenZoneTypeSupport = "" ;
// BREAK OF STRUCTURE HANDLING
if(updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",brokenResistanceLowerPrice,brokenZoneTypeResistance)
&& buyBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY)
&& ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_ALLOWED)) && BUYS_ALLOWED) // means M30 candle broke structure, and the breaker candle is valid (big enough),and time is in the sessions (ny or london or both, based on what the user chose))
{
double firstResistancePrice = findClosestResistancePrice(zoneContainer_M30);
double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK);
Print("first resistcane price is: "+ firstResistancePrice);
if(zoneContainer_M30.getNumberOfActiveZones() > 0 && firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT")
{
Comment("Price Broke and closed above resistance zone, im waiting for a bottom wick to form");
waitForBottomWickToForm = true ;
}
else if(zoneContainer_M30.getNumberOfActiveZones() == 0 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT")
{
Comment("Price Broke and closed above resistance zone, im waiting for a bottom wick to form");
waitForBottomWickToForm = true ;
}
}
if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport)
&& sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY)
&& ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_ALLOWED)) && SELLS_ALLOWED) // means M30 candle broke structure, and the breaker candle is valid (big enough),and time is in the sessions (ny or london or both, based on what the user chose))
{
double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30);
double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice;
if(zoneContainerSupport_M30.getNumberOfActiveZones() > 0 && firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT")
{
waitForTopWickToForm = true ;
Comment("Price Broke and closed below support zone, im waiting for a top wick to form");
}
else if(zoneContainerSupport_M30.getNumberOfActiveZones() == 0 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT"){
waitForTopWickToForm = true ;
Comment("Price Broke and closed below support zone, im waiting for a top wick to form");
}
}
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
zoneContainer_M30.printZonesSortedArray();
zoneContainerSupport_M30.printZonesSortedArray();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetectorDaily.isNewCandle())
{
//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1);
//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1");
objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetectorWeekly.isNewCandle())
{
objectsManager.drawVerticalLine(clrRed, TimeCurrent());
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
Binary file not shown.
+423
View File
@@ -0,0 +1,423 @@
//+------------------------------------------------------------------+
//| TigerObserver.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Algo_Skeleton_Functions.mqh"
int OnInit()
{
//--- create timer
EventSetTimer(60);
// ONLY FOR VISULAZITAION ON STRATEGY TESTER
iClose(_Symbol,PERIOD_W1,1);
iClose(_Symbol,PERIOD_D1,1);
iClose(_Symbol,PERIOD_H4,5);
iClose(_Symbol,PERIOD_H1,5);
iClose(_Symbol,PERIOD_M30,5);
iClose(_Symbol,PERIOD_M15,5);
objectsManager.addTextTiger();
for(int i=0; i<NUM_MAX_ALLOWED_TRADES ; i++)
{
BuyActiveTradesArray[i] = NULL ;
SellActiveTradesArray[i] = NULL ;
}
//objectsManager.addMarketDescriptionTextTiger();
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
Print("Buys Count: " + buysCount);
Print("Sells Count: " + sellsCount);
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
cleanBuyTradesArr();
cleanSellTradesArr();
secureProfitIfNeeded();
if(newCandleDetectorM15.isNewCandle())
{
manageRiskIfNeeded();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetector30M.isNewCandle())
{
//Print("zone coutner is: "+ zoneContainer_M30.getNumberOfActiveZones());
trailAllOpenPositionsIfNeeded(PERIOD_M30);
//Print("number of opened orders are: " + PositionsTotal());
// DETECTING SUPPORTS AND RESISTANCES
detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrPink,clrBlue,zoneContainer_M30);
detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",clrYellow,clrGreen,zoneContainerSupport_M30);
// VARIABLE PREPROCESSING FOR BOS
double brokenResistanceLowerPrice = -1 ;
string brokenZoneTypeResistance = "" ;
double brokenSupportHigherPrice = -1;
string brokenZoneTypeSupport = "" ;
// BREAK OF STRUCTURE HANDLING
if(updateBreakAboveStructureAndDelete(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",brokenResistanceLowerPrice,brokenZoneTypeResistance)
&& buyBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY)
&& ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_ALLOWED)) && BUYS_ALLOWED) // means M30 candle broke structure, and the breaker candle is valid (big enough),and time is in the sessions (ny or london or both, based on what the user chose))
{
double firstResistancePrice = findClosestResistancePrice(zoneContainer_M30);
double cleanRangeValueBuys = firstResistancePrice - SymbolInfoDouble(_Symbol, SYMBOL_ASK);
if(firstResistancePrice != -1 && brokenZoneTypeResistance == "TYPE_RESISTANCE_BREAKOUT")
{
Comment("M30 candle Broke and closed above the zone. the closest resistance price is:" + DoubleToString(firstResistancePrice));
if(cleanRangeValueBuys >= cleanRangeUponEntry)
{
double stopLossBased_H1 = iLow(_Symbol,PERIOD_H1,1);
double stopLossBased_M30 = iLow(_Symbol,PERIOD_M30,1);
double stopLossBased_M15 = iLow(_Symbol,PERIOD_M15,1);
stopLossBased_H1 = stopLossBased_H1 - stopLossUnderWickBy ;
stopLossBased_M30 = stopLossBased_M30 - stopLossUnderWickBy ;
stopLossBased_M15 = stopLossBased_M15 - stopLossUnderWickBy ;
if(stopLossIsValidBuys(stopLossBased_M30, maxPipsRiskAmount))
{
double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30);
int indexToNewTrade ;
if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result
{
Print("The free index found is: " + indexToNewTrade);
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M30) ;
BuyTradeManagerTiger* tempTigerManager= new BuyTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger
BuyActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array
buysCount++;
Comment("Took a buy. stop loss: based on M30, " + "Active trade id: " + activeTradeId);
}
else
{
Comment("I cant take a trade because the trades array is full");
}
}
else
if(stopLossIsValidBuys(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBullish(PERIOD_M15,1))
{
double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15);
int indexToNewTrade ;
if((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1) // find a spot in the trades array, and save the result
{
Print("The free index found is: " + indexToNewTrade);
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToEnter,stopLossBased_M15) ;
BuyTradeManagerTiger* tempTigerManager= new BuyTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger
BuyActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array
buysCount++;
Comment("Took a buy. stop loss: based on M15, " + "Active trade id: " + activeTradeId);
}
else
{
Comment("I cant take a trade because the trades array is full");
}
}
else
{
Comment("Failed to find a valid stop loss on both M30 and M15 !");
}
}
else
{
datetime currTime = TimeCurrent();
string timeInStr = TimeToString(currTime,TIME_MINUTES);
Comment(timeInStr + ": Price Broke the resitance zone, but not enough clean range to take a trade");
}
}
else
{
datetime currTime = TimeCurrent();
string timeInStr = TimeToString(currTime,TIME_MINUTES);
Comment(timeInStr+ ": Price broke the resistance zone but i dont see the next target zone, Or the zone price broke was not a breakout zone ");
}
}
if(updateBreakBelowStructureAndDelete(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",brokenSupportHigherPrice,brokenZoneTypeSupport)
&& sellBreakerCandleIsValid(PERIOD_M30, SIZE_OF_BREAKER_CANDLE_BODY)
&& ((sessionIsNy() && TRADE_NEW_YORK_ALLOWED) || (sessionIsLondon() && TRADE_LONDON_ALLOWED)) && SELLS_ALLOWED) // means M30 candle broke structure, and the breaker candle is valid (big enough),and time is in the sessions (ny or london or both, based on what the user chose))
{
double firstSupportPrice = findClosestSupportPrice(zoneContainerSupport_M30);
double cleanRangeValueSells = SymbolInfoDouble(_Symbol, SYMBOL_BID) - firstSupportPrice;
Print("firstSupport variable is: " + firstSupportPrice);
Print("cleanRangeValueSells :" + cleanRangeValueSells);
if(firstSupportPrice != -1 && brokenZoneTypeSupport == "TYPE_SUPPORT_BREAKOUT")
{
Comment("M30 candle Broke and closed below the zone. the closest support price is:" + DoubleToString(firstSupportPrice));
if(cleanRangeValueSells >= cleanRangeUponEntry)
{
double stopLossBased_H1 = iHigh(_Symbol,PERIOD_H1,1);
double stopLossBased_M30 = iHigh(_Symbol,PERIOD_M30,1);
double stopLossBased_M15 = iHigh(_Symbol,PERIOD_M15,1);
stopLossBased_H1 = stopLossBased_H1 + stopLossAboveWickBy ;
stopLossBased_M30 = stopLossBased_M30 + stopLossAboveWickBy ;
stopLossBased_M15 = stopLossBased_M15 + stopLossAboveWickBy ;
if(stopLossIsValidSells(stopLossBased_M30, maxPipsRiskAmount))
{
double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M30);
int indexToNewTrade ;
if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1)
{
Print("The free index found is: " + indexToNewTrade);
activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M30) ;
SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array
sellsCount++;
Comment("Took a sell. stop loss: based on M30, " + "Active trade id: " + activeTradeId);
}
else
{
Comment("i cant take a trade because the arrray is full");
}
}
else
if(stopLossIsValidSells(stopLossBased_M15,maxPipsRiskAmount) && candleClosedBearish(PERIOD_M15,1))
{
double lotsToEnter = lsCalc.calculateLotSize(riskDollars,stopLossBased_M15);
int indexToNewTrade ;
if((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1)
{
Print("The free index found is: " + indexToNewTrade);
activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToEnter,stopLossBased_M15) ;
SellTradeManagerTiger* tempTigerManager= new SellTradeManagerTiger(activeTradeId); // create an object of type buyTradeManagerTiger
SellActiveTradesArray[indexToNewTrade] = tempTigerManager ;// put the new object in the array
sellsCount++;
Comment("Took a sell. stop loss: based on M15, "+ "Active trade id: " + activeTradeId);
}
else
{
Comment("i cant take a trade since another one is running");
}
}
else
{
Comment("Failed to find a valid stop loss on both M30 and M15 !");
}
}
else
{
datetime currTime = TimeCurrent();
string timeInStr = TimeToString(currTime,TIME_MINUTES);
Comment(timeInStr + ": Price Broke the support zone, but not enough clean range to take a trade");
}
}
else
{
datetime currTime = TimeCurrent();
string timeInStr = TimeToString(currTime,TIME_MINUTES);
Comment(timeInStr+ ": Price broke the support zone but i dont see the next target zone, Or the zone price broke was not a breakout zone ");
}
}
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
zoneContainer_M30.printZonesSortedArray();
zoneContainerSupport_M30.printZonesSortedArray();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetectorDaily.isNewCandle())
{
//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1);
//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1");
objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetectorWeekly.isNewCandle())
{
objectsManager.drawVerticalLine(clrRed, TimeCurrent());
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
Binary file not shown.
+232
View File
@@ -0,0 +1,232 @@
//+------------------------------------------------------------------+
//| TigerObserver.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Algo_Skeleton_Functions.mqh"
int OnInit()
{
//--- create timer
EventSetTimer(60);
// ONLY FOR VISULAZITAION ON STRATEGY TESTER
iClose(_Symbol,PERIOD_W1,1);
iClose(_Symbol,PERIOD_D1,1);
iClose(_Symbol,PERIOD_H4,5);
iClose(_Symbol,PERIOD_H1,5);
iClose(_Symbol,PERIOD_M30,5);
iClose(_Symbol,PERIOD_M15,5);
objectsManager.addTextTiger();
for(int i=0; i<NUM_MAX_ALLOWED_TRADES ; i++)
{
BuyActiveTradesArray[i] = NULL ;
SellActiveTradesArray[i] = NULL ;
}
//objectsManager.addMarketDescriptionTextTiger();
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
Print("Buys Count: " + buysCount);
Print("Sells Count: " + sellsCount);
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
cleanBuyTradesArr();
cleanSellTradesArr();
secureProfitIfNeeded();
/*if(newCandleDetectorM15.isNewCandle())
{
} */
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetector30M.isNewCandle())
{
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetector1H.isNewCandle()){
if(zoneContainerSupport_H4.getNumberOfActiveZones()>0){
updateNormalZonesSupport(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",clrAliceBlue,rangeDistanceBetweenZonesActual_H4);
}
if(zoneContainer_H4.getNumberOfActiveZones()){
updateNormalZonesResistance(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",clrPink,rangeDistanceBetweenZonesActual_H4);
}
}
if(newCandleDetector4H.isNewCandle()){
trailAllOpenPositionsIfNeeded(PERIOD_H4);
detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrPink,zoneContainer_H4,rangeDistanceBetweenZonesActual_H4);
detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",clrAliceBlue,zoneContainerSupport_H4,rangeDistanceBetweenZonesActual_H4);
// BREAK OF STRUCTURE HANDLING
handleBuys(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual);
handleSells(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual);
zoneContainerSupport_H4.printZonesSortedArray();
zoneContainer_H4.printZonesSortedArray();
}
if(newCandleDetectorDaily.isNewCandle())
{
//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1);
//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1");
objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetectorWeekly.isNewCandle())
{
objectsManager.drawVerticalLine(clrRed, TimeCurrent());
weekCounter++ ;
if(weekCounter == deleteAllZonesAfter_Weeks){
//deleteAllzonesWithGUI();
weekCounter = 0;
}
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
Binary file not shown.
+182
View File
@@ -0,0 +1,182 @@
//+------------------------------------------------------------------+
//| TrendBreakouts.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#define NUM_WEEKS_RESEARCH 48
#include "Algo_Skeleton_Functions.mqh"
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int bullishCandlesCount = 0 ;
int conditionMetBullish = 0 ;
int secondConditionMetBullish = 0;
int bearishCandlesCount = 0;
int conditionMetBearish = 0 ;
int secondConditionMetBearish = 0 ;
input group "Conditions"
input bool firstCondition = false ;
input bool secondCondition = false ;
input bool noCondition = false ;
int OnInit()
{
//---
//---
/* string fileName = "First_Condition_Bullish.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode
int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE |FILE_CSV|FILE_ANSI);
FileSeek(fileHandle,0,SEEK_END);
FileWrite(fileHandle,"-----","Size of Week 1","Size of Week 2", "Monday", "Tuesday","Wednesday","Thursday","Friday","Retracement Measure","Low below previous close","Day of lowest point"); */
string fileName1 = "First_Condition_Bearish.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode
int fileHandle1 = FileOpen(fileName1,FILE_READ|FILE_WRITE |FILE_CSV|FILE_ANSI);
FileSeek(fileHandle1,0,SEEK_END);
FileWrite(fileHandle1,"-----","Size of Week 1","Size of Week 2", "Monday", "Tuesday","Wednesday","Thursday","Friday","Retracement Measure","High above previous close","Day of Highest point");
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
Print("Count: "+ bullishCandlesCount + " First Condition: " + conditionMetBullish + " Second Condition: " + secondConditionMetBullish);
Print("Count: "+ bearishCandlesCount + " First Condition: " + conditionMetBearish + " Second Condition: " + secondConditionMetBearish);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
if(newCandleDetectorDaily.isNewCandle())
{
//objectsManager.drawVerticalLine(clrAliceBlue, TimeCurrent());
}
int shift = 2 ;
if(newCandleDetectorWeekly.isNewCandle())
{
objectsManager.drawVerticalLine(clrRed, TimeCurrent());
if(candleClosedBullish(PERIOD_W1,shift))
{
if(!bullishCandleIsWeak(PERIOD_W1,shift,WICK_RATIO_REJECTION))
{
bullishCandlesCount++ ;
if(firstCondition){
if((iHigh(_Symbol,PERIOD_W1,1) > iHigh(_Symbol,PERIOD_W1,2)) && (iLow(_Symbol,PERIOD_W1,1) >iLow(_Symbol,PERIOD_W1,2)))
{
saveInCsv("firstCondition_Bullish.csv");
conditionMetBullish++ ;
}
}
if(secondCondition){
if((iHigh(_Symbol,PERIOD_W1,1) > iClose(_Symbol,PERIOD_W1,2)) && (iLow(_Symbol,PERIOD_W1,1) > iLow(_Symbol,PERIOD_W1,2)))
{
saveInCsv("secondCondition_Bullish.csv");
secondConditionMetBullish++ ;
}
}
if(noCondition){
saveInCsv("noCondition_Bullish.csv");
}
}
}
if(candleClosedBearish(PERIOD_W1,shift))
{
if(!bearishCandleIsWeak(PERIOD_W1,shift,WICK_RATIO_REJECTION))
{
bearishCandlesCount++ ;
if((iLow(_Symbol,PERIOD_W1,1) < iLow(_Symbol,PERIOD_W1,2)) && (iHigh(_Symbol,PERIOD_W1,1) < iHigh(_Symbol,PERIOD_W1,2)))
{
conditionMetBearish++ ;
}
if((iLow(_Symbol,PERIOD_W1,1) < iClose(_Symbol,PERIOD_W1,2)) && (iHigh(_Symbol,PERIOD_W1,1) < iHigh(_Symbol,PERIOD_W1,2)))
{
secondConditionMetBearish++ ;
}
}
}
//Print("bearish candles count: " + bearishCandlesCount);
//Print("bullish canldes count: " + bullishCandlesCount);
}
}
//+------------------------------------------------------------------+
void saveInCsv(string csvFileName){
int lastWeekDaysArr[5] ;
for(int i=0; i<5; i++)
{
lastWeekDaysArr[i]= -1;
}
for(int i=5 ; i>0 ; i--)
{
if(candleClosedBullish(PERIOD_D1,i))
{
lastWeekDaysArr[5-i] = 1 ;
}
if(candleClosedBearish(PERIOD_D1,i))
{
lastWeekDaysArr[5-i] = 0 ;
}
}
double firstWeekSize = iHigh(_Symbol,PERIOD_W1,2) - iLow(_Symbol,PERIOD_W1,2) ;
double secondWeekSize = iHigh(_Symbol,PERIOD_W1,1) - iLow(_Symbol,PERIOD_W1,1) ;
datetime time = iTime(_Symbol,PERIOD_W1,2);
string timeInStr = TimeToString(time,TIME_DATE);
string fileName = csvFileName ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode
int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/);
FileSeek(fileHandle,0,SEEK_END);
FileWrite(fileHandle,timeInStr,firstWeekSize,secondWeekSize,lastWeekDaysArr[0],lastWeekDaysArr[1],lastWeekDaysArr[2],lastWeekDaysArr[3],lastWeekDaysArr[4]);
FileClose(fileHandle);
}
+341
View File
@@ -0,0 +1,341 @@
//+------------------------------------------------------------------+
//| Zone.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "LowFractal.mqh"
#include "HighFractal.mqh"
#include "BuyEntryManager.mqh"
#include "SellEntryManager.mqh"
#include "BuyTradeManager.mqh"
#include "SellTradeManager.mqh"
#define SIZE_ATTACHED_FRACTALS
#define TP_ARR_SIZE 3
class Zone
{
private:
string id ;
string timeFrame ;
string type ; // has 2 types : TYPE_SUPPORT, TYPE_RESISTANCE
string state ; // state is one of 5 states : STATE_CLEAN , STATE_TESTED, STATE_BROKEN, STATE_BROKEN_RETESTED, STATE_WAITING(used when price breaks structure, and is waiting to confirm BOS or a liquidity sweep)
datetime leftEdge ;
datetime rightEdge;
double lowerEdgePrice ;
double higherEdgePrice ;
double stopLossPrice ;
double tpPrices[TP_ARR_SIZE] ;
public:
Zone();
Zone:: Zone(string _zoneId,double _higherEdgePrice,double _lowerEdgePrice,datetime _leftEdge,datetime _rightEdge,string _timeFrameStr,string _type);
~Zone();
BuyEntryManager* buyEntryManager ;
BuyTradeManager* buyTradeManager;
SellEntryManager* sellEntryManager ;
SellTradeManager* sellTradeManager ;
// GETTERS
double getHigherEdge();
double getLowerEdge();
datetime getLeftEdge();
datetime getRightEdge();
string getId();
string getTimeFrame();
string getState();
string getType();
double getStopLossPrice();
double getZoneHeight();
// SETTERS
void setLeftEdge(datetime _leftEdge);
void setRightEdge(datetime _rightEdge);
void setLowerEdgePrice(double _lowerPirce);
void setHigherEdgePrice(double _higherPrice);
void setTimeFrame(string _timeframe);
void setId(string _id);
void setType(string _type);
void setState(string _state);
void setStopLossPrice(double slPrice);
bool setTakeProfit(double tpVal); // returns false if there is no valid slot in the tp's array, and true on success
// OTHER FUNCTIONS
void printTpLevels();
void printTradeManagerData();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Zone:: Zone()
{
buyEntryManager = new BuyEntryManager();
buyTradeManager = new BuyTradeManager();
sellEntryManager = new SellEntryManager();
sellTradeManager = new SellTradeManager();
for(int i=0 ;i< TP_ARR_SIZE ;i++){ // initialize the tp array with -1's
tpPrices[i] = -1 ;
}
}
Zone:: Zone(string _zoneId,double _higherEdgePrice,double _lowerEdgePrice,datetime _leftEdge,datetime _rightEdge,string _timeFrameStr,string _type){
buyEntryManager = new BuyEntryManager();
buyTradeManager = new BuyTradeManager();
sellEntryManager = new SellEntryManager();
sellTradeManager = new SellTradeManager();
id = _zoneId ;
timeFrame = _timeFrameStr;
type = _type; // has 2 types : TYPE_SUPPORT, TYPE_RESISTANCE
leftEdge = _leftEdge;
rightEdge = _rightEdge;
lowerEdgePrice = _lowerEdgePrice;
higherEdgePrice = _higherEdgePrice;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Zone::~Zone()
{
delete buyEntryManager;
delete sellEntryManager;
delete buyTradeManager;
delete sellTradeManager;
}
//+------------------------------------------------------------------+
// GETTERS
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
datetime Zone:: getLeftEdge()
{
return leftEdge;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
datetime Zone:: getRightEdge()
{
return rightEdge ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Zone:: getHigherEdge()
{
return higherEdgePrice;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double Zone:: getLowerEdge()
{
return lowerEdgePrice;
}
string Zone :: getState(){
return state ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string Zone:: getId()
{
return id;
}
string Zone:: getTimeFrame() {return timeFrame ;}
string Zone:: getType(){
return type ;
}
double Zone :: getStopLossPrice(){
return stopLossPrice ;
}
// SETTERS
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void Zone:: setLeftEdge(datetime _leftEdge)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void Zone:: setRightEdge(datetime _rightEdge)
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void Zone:: setTimeFrame(string _timeframe)
{
timeFrame = _timeframe;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void Zone:: setLowerEdgePrice(double _lowerPirce)
{
lowerEdgePrice = _lowerPirce;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void Zone::setHigherEdgePrice(double _higherPrice)
{
higherEdgePrice = _higherPrice ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void Zone:: setId(string _id)
{
id = _id;
}
void Zone:: setType(string _type){
type = _type ;
}
void Zone:: setState(string _state){
state = _state ;
}
void Zone:: setStopLossPrice(double slPrice){
stopLossPrice = slPrice ;
}
bool Zone:: setTakeProfit(double tpVal){
for(int i=0; i<TP_ARR_SIZE; i++){
if(tpPrices[i] == -1){
tpPrices[i] = tpVal ;
if(type == "TYPE_SUPPORT"){
buyTradeManager.tpArray[i] = tpVal;
}
else if(type == "TYPE_RESISTANCE"){
sellTradeManager.tpArray[i] = tpVal ;
}
return true ;
}
}
return false;
}
// GUI FUNCTIONS
// ALGORITHM FUNCTIONS
//+------------------------------------------------------------------+
void Zone:: printTpLevels(){
Print("Take Profit Levels are: ");
for(int i=0 ; i< TP_ARR_SIZE;i++){
if(tpPrices[i] != -1){
Print(tpPrices[i]);
}
}
}
double Zone:: getZoneHeight(){
return higherEdgePrice - lowerEdgePrice ;
}
void Zone:: printTradeManagerData(){
if(type == "TYPE_SUPPORT"){
Print("TP array in buyTradeManager is: ");
for(int i=0;i<3;i++){
Print("TP " + i + ": " + buyTradeManager.tpArray[i]);
}
}
else if(type == "TYPE_RESISTANCE"){
Print("TP array in sellTradeManager is: ");
for(int i=0;i<3;i++){
Print("TP " + i + ": " + sellTradeManager.tpArray[i]);
}
}
}
+686
View File
@@ -0,0 +1,686 @@
//+------------------------------------------------------------------+
//| ZoneContainer.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Zone.mqh"
#define ZONES_SORTED_ARR_SIZE 400
class ZoneContainer
{
private:
int zonesIdCounter ; // number to identify each zone when we create it, it keeps adding up. if we delete a zone, we dont decrement it
int zonesIdCounterSupport ; // used for support zones. i had to make it different from the resistance because there was a problem of collision of id's between supports and resistances zones
int numberOfActiveZones ;
Zone* zonesSortedArray[ZONES_SORTED_ARR_SIZE] ;
int pivotEdges[2] ; // this array contains the indexes of the 2 zones that are closest to the current price , pivotEdges[0] = index of lower edge, pivotEdges[1] = index of higher edge
public:
ZoneContainer();
~ZoneContainer();
// GETTERS
int getZonesIdCounter();
int getSupportZonesIdCounter();
int getNumberOfActiveZones();
int getLowZonePivot();
int getHighZonePivot();
// SETTERS
// OTHER FUNCTIONS
void incrementZonesIdCounter();
void incrementZonesIdCounterSupport();
int addZone(Zone* _newZone);
void addResistanceZoneTiger(Zone* _newZone);
void addSupportZoneTiger(Zone* _newZone);
void addHistoryResistanceZoneOnTop(Zone* _newZone);
void addHistorySupportZoneAtBottom(Zone* _newZone);
int updateZone(Zone* _tempZone,string _idOfOriginalZone);
int deleteZone(string ID);
void freeZonesSortedArray();
void printZonesSortedArray();
void forwardShiftZonesSortedArrayFromIndex(int _index);
void backwardShiftZonesSortedArrayFromIndex(int _index);
void findOrUpdatePivotEdgesOnConfirm(double _ask, double _bid);
void findOrUpdatePivotEdgesOnDelete();
void printPivotEdges();
Zone* getLowerPivotIndexZone();
Zone* getHigherPivotIndexZone();
int getZoneIndex(string _id); // returns the index of the zone in the zonesSortedArray if it was found , and returns -1 if it wasnt found
int searchForTheRightPlace(Zone* _zone);
Zone* searchZoneById(string _idOfZone);
Zone* getZoneByIndex(int _index);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ZoneContainer::ZoneContainer()
{
zonesIdCounter = 0;
zonesIdCounterSupport = 100 ;
pivotEdges[0] = -1;
pivotEdges[1] = -1;
numberOfActiveZones = 0;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
ZoneContainer::~ZoneContainer()
{
}
//+------------------------------------------------------------------+
// GETTERS
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer:: getZonesIdCounter()
{
return zonesIdCounter;
}
int ZoneContainer:: getSupportZonesIdCounter(){
return zonesIdCounterSupport;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer:: getNumberOfActiveZones()
{
return numberOfActiveZones;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer:: getLowZonePivot()
{
return pivotEdges[0];
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer:: getHighZonePivot()
{
return pivotEdges[1] ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Zone* ZoneContainer:: getZoneByIndex(int _index)
{
return zonesSortedArray[_index];
}
// SETTERS
// OTHER FUNCTIONS
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer:: incrementZonesIdCounter()
{
zonesIdCounter++;
}
void ZoneContainer:: incrementZonesIdCounterSupport(){
zonesIdCounterSupport++ ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer:: addZone(Zone* _newZone)
{
int result = -1;
if(numberOfActiveZones == 0) // means the array is empty
{
zonesSortedArray[0] = _newZone;
numberOfActiveZones++;
return 1 ;
}
else
if(_newZone.getHigherEdge() < zonesSortedArray[0].getLowerEdge()) // in this case the new zone should be put in the first place in the array
{
forwardShiftZonesSortedArrayFromIndex(0); // shift all the array
zonesSortedArray[0] = _newZone ;
numberOfActiveZones++;
return 1;
}
else
if(_newZone.getLowerEdge() > zonesSortedArray[numberOfActiveZones-1].getHigherEdge()) // in this case the new zone should be in the last place in the array
{
zonesSortedArray[numberOfActiveZones] = _newZone;
numberOfActiveZones++;
return 1;
}
else // in this case, the new zone sits somewhere in the array (not the edges)
{
int indexOfNewZone = searchForTheRightPlace(_newZone);
if(indexOfNewZone != -1) // means found a place for the new zone
{
forwardShiftZonesSortedArrayFromIndex(indexOfNewZone);
zonesSortedArray[indexOfNewZone] = _newZone ;
numberOfActiveZones++;
return 1;
}
else
{
return -1;
}
}
return result;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer:: deleteZone(string ID)
{
// 1. find the index of the zone with the ID
int indexOfZoneToDelete = getZoneIndex(ID);
if(indexOfZoneToDelete == -1)
{
return -1;
}
else
if(indexOfZoneToDelete == (numberOfActiveZones-1)) // means that this is the last zone in the sorted array
{
// 2. delete the zone
// 3. its the last element so do nothing
delete zonesSortedArray[numberOfActiveZones-1] ;
numberOfActiveZones--;
return 1;
}
else
{
// 2. delete the zone
// 3. its not the last element, so shift the array 1 step backwards
delete zonesSortedArray[indexOfZoneToDelete];
backwardShiftZonesSortedArrayFromIndex(indexOfZoneToDelete);
numberOfActiveZones--;
return 1;
}
return 0 ;
}
/* int ZoneContainer:: deleteZoneTiger(string ID){
// 1. find the index of the zone with the ID
int indexOfZoneToDelete = getZoneIndex(ID);
if(indexOfZoneToDelete == -1)
{
return -1;
}
else
if(indexOfZoneToDelete == (numberOfActiveZones-1)) // means that this is the last zone in the sorted array
{
// 2. delete the zone
// 3. its the last element so do nothing
delete zonesSortedArray[numberOfActiveZones-1] ;
numberOfActiveZones--;
return 1;
}
else
{
// 2. delete the zone
// 3. its not the last element, so shift the array 1 step backwards
delete zonesSortedArray[indexOfZoneToDelete];
backwardShiftZonesSortedArrayFromIndex(indexOfZoneToDelete);
numberOfActiveZones--;
return 1;
}
return 0 ;
} */
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer:: freeZonesSortedArray()
{
for(int i=0; i<numberOfActiveZones; i++)
{
delete zonesSortedArray[i];
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer::printZonesSortedArray()
{
if(numberOfActiveZones > 0)
{
for(int i=0; i<numberOfActiveZones; i++)
{
Print("Zone "+ i + ": " + "Type: " + zonesSortedArray[i].getType() + ", Lower Edge: " + zonesSortedArray[i].getLowerEdge() + " Higher Edge: "+ zonesSortedArray[i].getHigherEdge() + " Stop Loss Price: " + zonesSortedArray[i].getStopLossPrice());
//zonesSortedArray[i].printTpLevels();
//zonesSortedArray[i].printTradeManagerData();
}
Print("Current Price is between zone " + pivotEdges[0] + " and zone "+ pivotEdges[1]);
}
else
{
Print("There is no active zones !");
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer:: getZoneIndex(string _id)
{
int indexOfZone = -1;
for(int i=0 ; i <numberOfActiveZones ; i++)
{
if(zonesSortedArray[i].getId() == _id)
{
indexOfZone = i ;
return indexOfZone ;
}
}
return indexOfZone ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer::forwardShiftZonesSortedArrayFromIndex(int _index) // used for adding
{
for(int x = numberOfActiveZones ; x > _index ; x--)
{
zonesSortedArray[x] = zonesSortedArray[x-1] ;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer:: backwardShiftZonesSortedArrayFromIndex(int _index) // used for deleting
{
for(int i= _index ; i<numberOfActiveZones ; i++)
{
zonesSortedArray[i] = zonesSortedArray[i+1];
}
zonesSortedArray[numberOfActiveZones-1] = NULL ; // empty the last element in the sorted array
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer:: searchForTheRightPlace(Zone* _zone)
{
int index = -1;
for(int i=0; i<numberOfActiveZones-1; i++)
{
if((_zone.getLowerEdge() > zonesSortedArray[i].getHigherEdge()) && (_zone.getHigherEdge() < zonesSortedArray[i+1].getLowerEdge()))
{
index = i+1;
return index;
}
}
return index ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int ZoneContainer :: updateZone(Zone* _tempZone, string _idOfOriginalZone)
{
Zone* zoneToUpdate = searchZoneById(_idOfOriginalZone);
zoneToUpdate.setHigherEdgePrice(_tempZone.getHigherEdge());
zoneToUpdate.setLowerEdgePrice(_tempZone.getLowerEdge());
zoneToUpdate.setLeftEdge(_tempZone.getLeftEdge());
zoneToUpdate.setRightEdge(_tempZone.getRightEdge());
zoneToUpdate.setTimeFrame(_tempZone.getTimeFrame());
return 1 ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Zone* ZoneContainer:: searchZoneById(string _idOfZone)
{
Zone* result ;
for(int i=0 ; i< numberOfActiveZones ; i++)
{
if(zonesSortedArray[i].getId() == _idOfZone)
{
result = zonesSortedArray[i] ;
}
}
return result ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer:: findOrUpdatePivotEdgesOnConfirm(double _ask,double _bid)
{
bool foundSupport = false ;
bool foundResistance = false ;
for(int i=0 ; i<numberOfActiveZones ; i++) // FIND LOWER PIVOT EDGE
{
if(zonesSortedArray[i].getState() != "STATE_WAITING")
{
if((zonesSortedArray[i].getHigherEdge() < _ask) && (zonesSortedArray[i].getType() == "TYPE_SUPPORT"))
{
pivotEdges[0] = i;
foundSupport = true ;
}
}
}
for(int i= numberOfActiveZones-1 ; i >=0 ; i--) // FIND HIGHER PIVOT EDGE
{
if(zonesSortedArray[i].getState()!= "STATE_WAITING")
{
if((zonesSortedArray[i].getLowerEdge() > _bid) && (zonesSortedArray[i].getType() == "TYPE_RESISTANCE"))
{
pivotEdges[1] = i;
foundResistance = true ;
}
}
}
if(foundSupport == false)
{
pivotEdges[0] = -1;
}
if(foundResistance == false)
{
pivotEdges[1] = -1;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer:: findOrUpdatePivotEdgesOnDelete()
{
bool foundSupport = false ;
bool foundResistance = false ;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ;
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
for(int i=0 ; i<numberOfActiveZones ; i++) // FIND LOWER PIVOT EDGE
{
if(zonesSortedArray[i].getState() != "STATE_WAITING")
{
if(zonesSortedArray[i].getHigherEdge() < ask)
{
pivotEdges[0] = i;
foundSupport = true ;
}
}
}
for(int i= numberOfActiveZones-1 ; i >=0 ; i--) // FIND HIGHER PIVOT EDGE
{
if(zonesSortedArray[i].getState()!= "STATE_WAITING")
{
if(zonesSortedArray[i].getLowerEdge() > bid)
{
pivotEdges[1] = i;
foundResistance = true ;
}
}
}
if(foundSupport == false)
{
pivotEdges[0] = -1;
}
if(foundResistance == false)
{
pivotEdges[1] = -1;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer:: printPivotEdges()
{
Print("Lower Edge Index: " + pivotEdges[0]);
Print("Higher Edge Index: " + pivotEdges[1]);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Zone* ZoneContainer:: getLowerPivotIndexZone()
{
if(pivotEdges[0] != -1)
{
return getZoneByIndex(pivotEdges[0]);
}
return NULL ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Zone* ZoneContainer:: getHigherPivotIndexZone()
{
if(pivotEdges[1] != -1)
{
return getZoneByIndex(pivotEdges[1]);
}
return NULL;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void ZoneContainer:: addResistanceZoneTiger(Zone* _newZone)
{
if((numberOfActiveZones != 0 ) && (_newZone.getLowerEdge() >= zonesSortedArray[0].getHigherEdge())) // this is the case, where the new zone shouldnt be placed at the beggining (gap case for instance)
{
int indexOfNewZone = searchForTheRightPlace(_newZone);
if(indexOfNewZone != -1) // means found a place for the new zone
{
forwardShiftZonesSortedArrayFromIndex(indexOfNewZone);
zonesSortedArray[indexOfNewZone] = _newZone ;
numberOfActiveZones++;
}
else
{
Print("Couldnt find an index to place the new zone !");
}
}
else
{
forwardShiftZonesSortedArrayFromIndex(0);
zonesSortedArray[0] = _newZone ;
if(_newZone.getType() == "TYPE_RESISTANCE_BREAKOUT")
{
numberOfActiveZones++;
}
else
if(_newZone.getType() == "TYPE_RESISTANCE_NORMAL")
{
numberOfActiveZones++ ;
}
}
}
void ZoneContainer:: addHistoryResistanceZoneOnTop(Zone* _newZone){
zonesSortedArray[numberOfActiveZones] = _newZone ;
numberOfActiveZones++;
}
void ZoneContainer:: addSupportZoneTiger(Zone* _newZone)
{
/* if((numberOfActiveZones != 0 ) && (_newZone.getHigherEdge() <= zonesSortedArray[numberOfActiveZones-1].getLowerEdge())) // this is the case, where the new zone shouldnt be placed at the beggining (gap case for instance)
{
int indexOfNewZone = searchForTheRightPlace(_newZone);
if(indexOfNewZone != -1) // means found a place for the new zone
{
forwardShiftZonesSortedArrayFromIndex(indexOfNewZone);
zonesSortedArray[indexOfNewZone] = _newZone ;
numberOfActiveZones++;
}
else
{
Print("Couldnt find an index to place the new zone !");
}
} */
zonesSortedArray[numberOfActiveZones] = _newZone ;
if(_newZone.getType() == "TYPE_SUPPORT_BREAKOUT")
{
numberOfActiveZones++;
}
else
if(_newZone.getType() == "TYPE_SUPPORT_NORMAL")
{
numberOfActiveZones++ ;
}
}
//+------------------------------------------------------------------+
void ZoneContainer:: addHistorySupportZoneAtBottom(Zone* _newZone){
forwardShiftZonesSortedArrayFromIndex(0);
zonesSortedArray[0] = _newZone ;
numberOfActiveZones++;
}
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+98
View File
@@ -0,0 +1,98 @@
//+------------------------------------------------------------------+
//| candleStringDetector.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
#include "Algo_Skeleton_Functions.mqh"
int last_Color_candle = -1 ;
int daily_streak_counter = 0 ;
string timeInStr = "--" ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int OnInit()
{
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
if(newCandleDetectorDaily.isNewCandle())
{
//objectsManager.drawVerticalLine(clrAliceBlue, TimeCurrent());
if(candleClosedBullish(PERIOD_D1,1) && last_Color_candle != 1) // this is the first daily bullish candle
{
// save the timeInStr and the daily streak counter in a row in excel
string fileName = "daily_candle_streak.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode
int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/);
FileSeek(fileHandle,0,SEEK_END);
FileWrite(fileHandle,timeInStr,daily_streak_counter);
FileClose(fileHandle);
datetime time = TimeCurrent(); // save the date of this day
timeInStr = TimeToString(time,TIME_DATE);
last_Color_candle = 1 ; // convert the flag to bullish
daily_streak_counter = 0 ; // reset the counter
}
else if(candleClosedBullish(PERIOD_D1,1) && last_Color_candle == 1)
{
daily_streak_counter++ ;
}
if(candleClosedBearish(PERIOD_D1,1) && last_Color_candle != 0) // this is the first daily bearish candle
{
// save the timeInStr and the daily streak counter in a row in excel
string fileName = "daily_candle_streak.csv" ; // if you want to find the csv file, go to file -> open data folder -> mql5 -> files . all from the visual mode
int fileHandle = FileOpen(fileName,FILE_READ|FILE_WRITE/* |FILE_CSV|FILE_ANSI*/);
FileSeek(fileHandle,0,SEEK_END);
FileWrite(fileHandle,timeInStr,daily_streak_counter);
FileClose(fileHandle);
datetime time = TimeCurrent();
timeInStr = TimeToString(time,TIME_DATE);
last_Color_candle = 0 ;
daily_streak_counter = 0;
}
else if(candleClosedBearish(PERIOD_D1,1) && last_Color_candle == 0){
daily_streak_counter++ ;
}
}
}
//+------------------------------------------------------------------+
+765
View File
@@ -0,0 +1,765 @@
//+------------------------------------------------------------------+
//| library_functions.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#include <Trade/Trade.mqh>
int findMondayFromLastPeriodWeeks(int _period);
// FRACTALS RELATED FUNCTIONS
bool isLowFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame); // checks if the given index candle is, a low fractal of the left, right periods
bool isHighFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame); // checks if the given index candle is, a high fractal of the left, right periods
// TIME FRAME RELATED FUNCTIONS
string getChartTimeFrameInString() ; // gets the chart time frame in string format
string timeFrameToString(ENUM_TIMEFRAMES _timeFrame);
// SESSIONS RELATED FUNCTIONS
bool sessionIsNy(); // checks if the session is ny
bool sessionIsLondon(); // checks if the session is london
bool sessionIsTokyo();
// TRADE RELATED FUNCTIONS
bool closePartialFromAllPositions(double partialAmount) ; // closes partial of all open positions the partial is partialAmount (parameter)
bool closePartialFromSpecificPosition(ulong posTicket, double partialToClose) ; // closes a partial from the given position ticket
bool stopLossIsValidBuys(double stopLoss, double _maxPipsRiskAmount);
bool stopLossIsValidSells(double stopLoss,double _maxPipsRiskAmount);
double positionProfitInPips(ulong posTicket); // returns the position profit in pips
double positionStopLoss(ulong posTicket);
void positionTrailStopLoss(ulong posTicket, double newStopLoss, double takeProfit);
// CANDLE ANATOMY RELATED FUNCTIONS
bool buyBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody); // checks if the buy breaker candle is big enough
bool sellBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody); // checks if the sell breaker candle is big enough
bool bearishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection); // this function assumes that the previous candle is bearish
bool bullishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection); // this function assumes that the previous candle is bullish
double retestWickFormedOnTheFirstHalfOfCandle(ENUM_TIMEFRAMES _mainTimeFrame, ENUM_TIMEFRAMES _secondaryTimeFrame);
bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index);
bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index);
bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index);
bool candleBodyIsValid(ENUM_TIMEFRAMES _timeFrame, int _index); // this function is used for enhancing the detection of supports/resistances
// SUPPORT AND RESISTANCE RELATED FUNCTIONS
bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index=0); // _index = 0 is the default state which is a specific case of the general function with _index = i
bool resistancePatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index=0);// _index = 0 is the default state which is a specific case of the general function with _index = i
/* WARNING FOR THE NEXT FUNCTION*/
/* IF A FRIDAY WAS NOT ON THE BROKER, THE FUNCTION WILL NOT COUNT THE WEEK. MAKE SURE BEFORE APPLYING IT TO SEE VISUALLY THAT IT WAS LAUNCHED RIGHT */
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int findMondayFromLastPeriodWeeks(int _period) { // _period = 1 means the previous week. _period = 2 means 2 weeks ago. and so on ...
int startCountFromIndex = 0 ;
datetime localTime = TimeLocal();
MqlDateTime dateTimeStructure ;
TimeToStruct(localTime,dateTimeStructure);
int dayOfTheWeek = dateTimeStructure.day_of_week;
int hourOfTheDay = dateTimeStructure.hour;
if(dayOfTheWeek == 5) { // means if we called the function on friday , start counting from the candle of index 25, because our goal is to reach the pervious week friday, so we know we are in the previous week
startCountFromIndex = 25 ;
}
if(dayOfTheWeek == 6 || dayOfTheWeek == 7) {
Alert("Its saturday/sunday start next week !");
}
MqlDateTime shiftedBarTimeStruct ;
int weeksPassed = 0 ; // count of how many weeks we passed. it starts with 0 since we start at week 0. and will end in _period
int lockCounter = 0;
int i = startCountFromIndex ; // i represents the distance from the moment we started. by the end of the function it will point to the first monday of the desired week that we want
while(weeksPassed < _period) {
datetime shiftedBarTime=iTime(_Symbol,PERIOD_CURRENT,i); // take the date of the current candle
TimeToStruct(shiftedBarTime,shiftedBarTimeStruct); // change the date to a struct
if(shiftedBarTimeStruct.day_of_week == 5 && lockCounter == 0) { // if we reached friday, add the weeksPassed by 1 and lock the block for the next friday
weeksPassed++; // each time we reach a friday this means we are in a previous week. (we are counting the weeks starting from the current moment and going back in time)
lockCounter++;
} else if(shiftedBarTimeStruct.day_of_week == 5 && lockCounter > 0) { // stay locked until we pass the current friday
lockCounter++ ;
} else if(shiftedBarTimeStruct.day_of_week == 4) { // if reached thursday , then release the lock
lockCounter = 0;
}
i++;
}
Print("weeks passed value is: "+ weeksPassed);
return i-2 ;
}
// ************************ FRACTALS FUNCTIONS ************************
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool isLowFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame) { // checks if the given index candle is, a low fractal of the left, right periods
for(int i = index+1 ; i < (index + leftPeriod + 1) ; i++) {
if(!(iLow(Symbol(),timeFrame,index) <= iLow(Symbol(),timeFrame,i))) {
return false;
}
}
if(index > rightPeriod) { // this means we have enough candles to the right
for(int j = index-1 ; (j > index - rightPeriod - 1) ; j--) {
if(!(iLow(Symbol(),timeFrame,index) <= iLow(Symbol(),timeFrame,j))) {
return false ;
}
}
}
else{
return false ;
}
return true ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool isHighFractalByIndex(int index, int leftPeriod, int rightPeriod, ENUM_TIMEFRAMES timeFrame) { // checks if the given index candle is, a high fractal of the left, right periods
for(int i = index+1 ; i < (index + leftPeriod + 1) ; i++) {
if(!(iHigh(Symbol(),timeFrame,index) >= iHigh(Symbol(),timeFrame,i))) {
return false;
}
}
if(index > rightPeriod) { // this means we have enough candles to the right
for(int j = index-1 ; (j > index - rightPeriod - 1) ; j--) {
if(!(iHigh(Symbol(),timeFrame,index) >= iHigh(Symbol(),timeFrame,j))) {
return false ;
}
}
}
else{
return false ;
}
return true ;
}
// ************************ TIME FRAMES FUNCTIONS ************************
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string getChartTimeFrameInString() {
ENUM_TIMEFRAMES period = Period();
switch(period) {
case PERIOD_M1:
return "PERIOD_M1" ;
break;
case PERIOD_M2:
return "PERIOD_M2" ;
break;
case PERIOD_M3:
return "PERIOD_M3" ;
break;
case PERIOD_M4:
return "PERIOD_M4" ;
break;
case PERIOD_M5:
return "PERIOD_M5" ;
break;
case PERIOD_M6:
return "PERIOD_M6" ;
break;
case PERIOD_M10:
return "PERIOD_M10" ;
break;
case PERIOD_M12:
return "PERIOD_M12" ;
break;
case PERIOD_M15:
return "PERIOD_M15" ;
break;
case PERIOD_M20:
return "PERIOD_M20" ;
break;
case PERIOD_M30:
return "PERIOD_M30" ;
break;
case PERIOD_H1:
return "PERIOD_H1" ;
break;
case PERIOD_H2:
return "PERIOD_H2" ;
break;
case PERIOD_H3:
return "PERIOD_H3" ;
break;
case PERIOD_H4:
return "PERIOD_H4" ;
break;
case PERIOD_H6:
return "PERIOD_H6" ;
break;
case PERIOD_H8:
return "PERIOD_H8" ;
break;
case PERIOD_H12:
return "PERIOD_H12" ;
break;
case PERIOD_D1:
return "PERIOD_D1" ;
break;
case PERIOD_W1:
return "PERIOD_W1" ;
break;
case PERIOD_MN1:
return "PERIOD_MN1" ;
break;
}
return "" ;
}
string timeFrameToString(ENUM_TIMEFRAMES _timeFrame){
switch(_timeFrame) {
case PERIOD_M1:
return "PERIOD_M1" ;
break;
case PERIOD_M2:
return "PERIOD_M2" ;
break;
case PERIOD_M3:
return "PERIOD_M3" ;
break;
case PERIOD_M4:
return "PERIOD_M4" ;
break;
case PERIOD_M5:
return "PERIOD_M5" ;
break;
case PERIOD_M6:
return "PERIOD_M6" ;
break;
case PERIOD_M10:
return "PERIOD_M10" ;
break;
case PERIOD_M12:
return "PERIOD_M12" ;
break;
case PERIOD_M15:
return "PERIOD_M15" ;
break;
case PERIOD_M20:
return "PERIOD_M20" ;
break;
case PERIOD_M30:
return "PERIOD_M30" ;
break;
case PERIOD_H1:
return "PERIOD_H1" ;
break;
case PERIOD_H2:
return "PERIOD_H2" ;
break;
case PERIOD_H3:
return "PERIOD_H3" ;
break;
case PERIOD_H4:
return "PERIOD_H4" ;
break;
case PERIOD_H6:
return "PERIOD_H6" ;
break;
case PERIOD_H8:
return "PERIOD_H8" ;
break;
case PERIOD_H12:
return "PERIOD_H12" ;
break;
case PERIOD_D1:
return "PERIOD_D1" ;
break;
case PERIOD_W1:
return "PERIOD_W1" ;
break;
case PERIOD_MN1:
return "PERIOD_MN1" ;
break;
}
return "" ;
}
// ************************ SESSIONS FUNCTIONS ************************
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool sessionIsNy() {
MqlDateTime mqldt ;
datetime currTime = TimeCurrent(mqldt);
if(mqldt.hour >= 12 && mqldt.hour <= 20) {
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool sessionIsLondon() {
MqlDateTime mqldt ;
datetime currTime = TimeCurrent(mqldt);
if(mqldt.hour >= 8 && mqldt.hour <= 12) {
return true ;
}
return false ;
}
bool sessionIsTokyo(){
MqlDateTime mqldt ;
datetime currTime = TimeCurrent(mqldt);
if(mqldt.hour >= 4 && mqldt.hour <= 8) {
return true ;
}
return false ;
}
// ************************ TRADE FUNCTIONS ************************
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool closePartialFromAllPositions(double partialAmount) {
CTrade trade ;
for(uint i=0 ; i< PositionsTotal() ; i++) {
ulong positionTicket = PositionGetTicket(i);
if(PositionSelectByTicket(positionTicket)) {
double positionVolume = PositionGetDouble(POSITION_VOLUME);
double lotsToClose = positionVolume * partialAmount ;
if(trade.PositionClosePartial(positionTicket,NormalizeDouble(lotsToClose,2))) {
Print("Closed partials succesffully");
return true ;
} else {
Print("Failed to close partials, Error: " + GetLastError());
return false ;
}
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool closePartialFromSpecificPosition(ulong posTicket, double partialToClose) {
CTrade trade ;
double positionVolume = PositionGetDouble(POSITION_VOLUME);
double lotsToClose = positionVolume * partialToClose ;
if(trade.PositionClosePartial(posTicket,NormalizeDouble(lotsToClose,2))) {
return true ;
} else {
return false ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool stopLossIsValidBuys(double stopLoss, double _maxPipsRiskAmount) {
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLoss < _maxPipsRiskAmount) {
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double positionProfitInPips(ulong posTicket) {
double currentProfitInPips = -1 ;
if(PositionSelectByTicket(posTicket)) {
double currentPrice = PositionGetDouble(POSITION_PRICE_CURRENT) ;
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) {
currentProfitInPips = currentPrice - positionOpenPrice ;
}
else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) {
currentProfitInPips = positionOpenPrice - currentPrice ;
}
} else {
Comment("Error from positionProfitInPips() function: Failed to select position, Error " + GetLastError());
}
return currentProfitInPips ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double positionStopLoss(ulong posTicket) {
double posStopLoss = -1 ;
if(PositionSelectByTicket(posTicket)) {
posStopLoss = PositionGetDouble(POSITION_SL) ;
} else {
Comment("Error from positionStopLoss() function: Failed to select position, Error " + GetLastError());
}
return posStopLoss;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool stopLossIsValidSells(double stopLoss,double _maxPipsRiskAmount) {
if(stopLoss - SymbolInfoDouble(_Symbol, SYMBOL_BID) < _maxPipsRiskAmount) {
return true ;
}
return false ;
}
void positionTrailStopLoss(ulong posTicket, double newStopLoss, double takeProfit) {
CTrade trade ;
trade.PositionModify(posTicket,newStopLoss,takeProfit);
}
// ************************ CANDLE ANATOMY FUNCTIONS ************************
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool buyBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody) {
if((iClose(_Symbol,_timeFrame,1) - iOpen(_Symbol,_timeFrame,1)) >= _sizeOfBreakerCandleBody) {
return true ;
} else {
datetime currTime = TimeCurrent();
string timeInStr = TimeToString(currTime,TIME_MINUTES);
Comment(timeInStr + " Bullish Breaker candle body is too small to take a trade !");
return false ;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool sellBreakerCandleIsValid(ENUM_TIMEFRAMES _timeFrame, double _sizeOfBreakerCandleBody) {
if((iOpen(_Symbol,_timeFrame,1) - iClose(_Symbol,_timeFrame,1)) >= _sizeOfBreakerCandleBody) {
return true ;
} else {
datetime currTime = TimeCurrent();
string timeInStr = TimeToString(currTime,TIME_MINUTES);
Comment(timeInStr + " Bearish Breaker candle body is too small to take a trade !");
return false ;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool bearishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection) { // this function assumes that the previous candle is bearish
double upperWickLength = iHigh(_Symbol,_timeFrame,index) - iOpen(_Symbol,_timeFrame,index) ;
double totalCandleLength = iHigh(_Symbol,_timeFrame,index) - iClose(_Symbol,_timeFrame,index);
if((upperWickLength / totalCandleLength) >= wickRatioRejection) { // this means the candle is weak
Comment("Bearish Candle Is Weak");
return true ;
} else {
return false ;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool bullishCandleIsWeak(ENUM_TIMEFRAMES _timeFrame, int index, double wickRatioRejection) { // this function assumes that the previous candle is bullish
double lowerWickLength = iOpen(_Symbol,_timeFrame,index) - iLow(_Symbol,_timeFrame,index) ;
double totalCandleLength = iClose(_Symbol,_timeFrame,index) - iLow(_Symbol,_timeFrame,index) ;
if((lowerWickLength/totalCandleLength) >= wickRatioRejection) { // this means the candle is weak
Comment("Bullish Candle is weak");
return true ;
} else {
return false ;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedBullish(ENUM_TIMEFRAMES _timeFrame, int _index) {
double candleClose = iClose(_Symbol,_timeFrame,_index);
double candleOpen = iOpen(_Symbol,_timeFrame,_index);
if(candleClose >candleOpen) { // the candle closed bullish
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedBearish(ENUM_TIMEFRAMES _timeFrame,int _index) {
double candleClose = iClose(_Symbol,_timeFrame,_index);
double candleOpen = iOpen(_Symbol,_timeFrame,_index);
if(candleClose < candleOpen) { // the candle closed bullish
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleClosedDoji(ENUM_TIMEFRAMES _timeFrame, int _index) {
double candleClose = iClose(_Symbol,_timeFrame,_index);
double candleOpen = iOpen(_Symbol,_timeFrame,_index);
if(candleClose == candleOpen) {
return true;
} else {
return false;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool candleBodyIsValid(ENUM_TIMEFRAMES _timeFrame, int _index) {
double candleClose = iClose(_Symbol,_timeFrame,_index);
double candleOpen = iOpen(_Symbol,_timeFrame,_index);
double candleHigh = iHigh(_Symbol,_timeFrame,_index);
double candleLow = iLow(_Symbol,_timeFrame,_index);
double topWickSize ;
double bottomWickSize ;
double candleBodySize ;
if(candleClosedBearish(_timeFrame,_index)) {
topWickSize = candleHigh - candleOpen ;
bottomWickSize = candleClose - candleLow ;
candleBodySize = candleOpen - candleClose ;
} else if(candleClosedBullish(_timeFrame,_index)) {
topWickSize = candleHigh - candleClose ;
bottomWickSize = candleOpen - candleLow ;
candleBodySize = candleClose - candleOpen ;
} else if(candleClosedDoji(_timeFrame,_index)) {
return false ;
}
if((topWickSize >= (15*candleBodySize)) || (bottomWickSize >= (15* candleBodySize))) { // 8 is fixed number ,
//which means that if i find a candle's wick that is 15 times bigger than the body then i dont want to consider it when detecting a support or resistance, this is for the cases that the candle looks almost like a doji but not an actual doji
return false ;
}
return true ;
}
/*double retestWickFormedOnTheFirstHalfOfCandle(ENUM_TIMEFRAMES _mainTimeFrame, ENUM_TIMEFRAMES _secondaryTimeFrame){
if(candleClosedBullish(_mainTimeFrame,1)){ // previous candle closed bullish, this means checking a wick on a bullish candle on the main timeframe
if(candleClosedBearish(_secondaryTimeFrame)){
}
}
if(candleClosedBearish(_mainTimeFrame)){ // previous candle closed bullish, this means checking a wick on a bearish candle on the main timeframe
}
} */
// ************************ SUPPORT AND RESISTANCE RELATED FUNCTIONS ************************
/*bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame){ // this is a spicific case of the next function, the _index parameter here is 0
if((candleClosedBearish(_timeFrame,2) && candleClosedBullish(_timeFrame,1) && candleBodyIsValid(_timeFrame,1)&& candleBodyIsValid(_timeFrame,2))
|| (candleClosedBearish(_timeFrame,3) && candleClosedDoji(_timeFrame,2) && candleClosedBullish(_timeFrame,1))
|| candleClosedBearish(_timeFrame,3) && candleBodyIsValid(_timeFrame,3) && !candleBodyIsValid(_timeFrame,2) && candleClosedBullish(_timeFrame,1) && candleBodyIsValid(_timeFrame,1)) {
return true ;
}
return false ;
}*/
bool supportPatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index = 0){ // this is the same previous function but with geniric index to detect the support on . its used for detecing old supports (that are not currently happeneing)
if((candleClosedBearish(_timeFrame,_index+2) && candleClosedBullish(_timeFrame,_index+1) && candleBodyIsValid(_timeFrame,_index+1)&& candleBodyIsValid(_timeFrame,_index+2))
|| (candleClosedBearish(_timeFrame,_index+3) && candleClosedDoji(_timeFrame,_index+2) && candleClosedBullish(_timeFrame,_index+1))
|| candleClosedBearish(_timeFrame,_index+3) && candleBodyIsValid(_timeFrame,_index+3) && !candleBodyIsValid(_timeFrame,_index + 2) && candleClosedBullish(_timeFrame,_index+1)
&& candleBodyIsValid(_timeFrame,_index+1) ){
return true ;
}
return false ;
}
bool resistancePatternFormed(ENUM_TIMEFRAMES _timeFrame, int _index = 0){ // this is a spicific case of the next function
if((candleClosedBullish(_timeFrame,_index+2) && candleClosedBearish(_timeFrame,_index+1) && candleBodyIsValid(_timeFrame,_index+2) && candleBodyIsValid(_timeFrame,_index+1))
|| (candleClosedBullish(_timeFrame,3) && candleClosedDoji(_timeFrame,2) && candleClosedBearish(_timeFrame,1) )){
return true ;
}
return false ;
}
File diff suppressed because it is too large Load Diff
Binary file not shown.
+404
View File
@@ -0,0 +1,404 @@
//+------------------------------------------------------------------+
//| Breakout_Fractals.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
//#include "Algo_Skeleton_Functions.mqh"
#include "Phoenix_Functions.mqh"
bool trailWhenMarketOpensDaily = false ;
int OnInit()
{
//---
//---
for(int i=0; i<NUM_MAX_ALLOWED_TRADES ; i++)
{
BuyActiveTradesArray[i] = NULL ;
SellActiveTradesArray[i] = NULL ;
}
objectsManager.addTextTiger();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
Print("Buys Count: " + buysCount);
Print("Sells Count: " + sellsCount);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
cleanBuyTradesArr();
cleanSellTradesArr();
if(newCandleDetectorM5.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_M5){
trailAllOpenPositionsIfNeeded(PERIOD_M5);
}
if(TIME_FRAME_TO_TRADE == PERIOD_M5)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorM15.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_M15){
trailAllOpenPositionsIfNeeded(PERIOD_M15);
}
if(TIME_FRAME_TO_TRADE == PERIOD_M15)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorM30.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_M30){
trailAllOpenPositionsIfNeeded(PERIOD_M30);
}
if(TIME_FRAME_TO_TRADE == PERIOD_M30)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorH1.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_D1 && trailWhenMarketOpensDaily){
trailAllOpenPositionsIfNeeded(PERIOD_D1);
trailWhenMarketOpensDaily = false ;
}
if(APPLY_TRAIL && (TRAIL_TIME_FRAME == PERIOD_H1)){
Print("Entered the trail !");
trailAllOpenPositionsIfNeeded(PERIOD_H1);
}
if(TIME_FRAME_TO_TRADE == PERIOD_H1)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorH4.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_H4){
trailAllOpenPositionsIfNeeded(PERIOD_H4);
}
if(TIME_FRAME_TO_TRADE == PERIOD_H4)
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": Sell Below: " + currentSupportLowerEdge + " Buy Above: "+ currentResistanceHighEdge);
string timeFrameStr = timeFrameToString(TIME_FRAME_TO_TRADE);
findAndDrawFractalsAndZones(TIME_FRAME_TO_TRADE,timeFrameStr);
if(candleClosedBelowSupportZone(TIME_FRAME_TO_TRADE)) // SELL CASE
{
handleSells();
}
if(candleClosedAboveResistanceZone(TIME_FRAME_TO_TRADE)) // BUY CASE
{
handleBuys();
}
}
}
if(newCandleDetectorDaily.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_D1){
trailWhenMarketOpensDaily = true ;
trailAllOpenPositionsIfNeeded(PERIOD_D1);
}
objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
if(newCandleDetectorWeekly.isNewCandle())
{
if(APPLY_TRAIL && TRAIL_TIME_FRAME == PERIOD_W1){
trailAllOpenPositionsIfNeeded(PERIOD_W1);
}
objectsManager.drawVerticalLine(clrRed, TimeCurrent());;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void handleSells()
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": im taking a sell !");
if(((indexToNewTrade = findAvailableSpotInSellManagerArr()) != -1))
{
double stopLossPrice = calculateStopLossBasedOnFractalsSells(stopLossFractalsPeriod,stopLossTimeFrame) ;
stopLossPrice = stopLossPrice + stopLossAboveWickByActual ;
if(stopLossIsValidSells(stopLossPrice,maxPipsRiskAmountActual))
{
if(rrFactor != -1 && lotSize == -1) // tp based rr metehod
{
if(SELLS_ALLOWED){
double stopLossInPips = stopLossPrice - SymbolInfoDouble(_Symbol,SYMBOL_BID) ;
double netTp = rrFactor * stopLossInPips ;
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_BID)- netTp) ;
SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge);
tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge);
SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array
sellsCount++;
}
}
else
if(rrFactor == -1 && lotSize == -1) // tp based net take profit method
{
if(SELLS_ALLOWED){
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = sellEntryManager.takeSellTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_BID)- netTakeProfit) ;
SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge);
tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge);
SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array
sellsCount++;
}
}
else if(lotSize != -1){ // taking an entry based on fixed lot , and managing risk via trail
if(SELLS_ALLOWED){
activeTradeId = sellEntryManager.takeSellTradeTiger(lotSize,stopLossPrice) ;
SellTradeManagerTiger* tempTigerManagerSell= new SellTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerSell.setBrokenSupportHigherEdge(currentSupportHighEdge);
tempTigerManagerSell.setBrokenSupportLowerEdge(currentSupportLowerEdge);
SellActiveTradesArray[indexToNewTrade] = tempTigerManagerSell ;// put the new object in the array
sellsCount++;
}
}
}
else
{
Print("stop loss is not valid sells!");
}
}
else
{
Comment("i cant take a trade because the arrray is full");
}
currentSupportLowerEdge = -1;
currentSupportHighEdge = -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void handleBuys()
{
datetime currTime = TimeCurrent();
Comment(TimeToString(currTime,TIME_MINUTES) + ": im taking a buy !");
if(((indexToNewTrade = findAvailableSpotInBuyManagerArr()) != -1))
{
Print("indexToNewTrade:-------------------------------------------- " + indexToNewTrade);
double stopLossPrice = calculateStopLossBasedOnFractalsBuys(stopLossFractalsPeriod,stopLossTimeFrame);
stopLossPrice = stopLossPrice - stopLossUnderWickByActual ;
if(stopLossIsValidBuys(stopLossPrice,maxPipsRiskAmountActual))
{
if(rrFactor != -1 && lotSize == -1)
{
if(BUYS_ALLOWED){
double stopLossInPips = SymbolInfoDouble(_Symbol,SYMBOL_ASK) - stopLossPrice ;
double netTp = rrFactor * stopLossInPips ;
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+ netTp) ;
BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge);
tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge);
BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array
buysCount++;
}
}
else
if(rrFactor == -1 && lotSize == -1)
{
if(BUYS_ALLOWED){
double lotsToTrade = lsCalc.calculateLotSize(riskDollars,stopLossPrice);
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotsToTrade,stopLossPrice,SymbolInfoDouble(_Symbol,SYMBOL_ASK)+ netTakeProfit) ;
BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge);
tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge);
BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array
buysCount++;
}
}
else if(lotSize != -1){ // taking an entry based on fixed lot , and managing risk via trail
if(BUYS_ALLOWED){
activeTradeId = buyEntryManager.takeBuyTradeTiger(lotSize,stopLossPrice) ;
BuyTradeManagerTiger* tempTigerManagerBuy= new BuyTradeManagerTiger(activeTradeId); // create an object of type sellTradeManagerTiger
tempTigerManagerBuy.setBrokenResistanceHigherEdge(currentResistanceHighEdge);
tempTigerManagerBuy.setBrokenResistancetLowerEdge(currentResistanceLowEdge);
BuyActiveTradesArray[indexToNewTrade] = tempTigerManagerBuy ;// put the new object in the array
buysCount++;
}
}
}
else
{
Print("stop loss is not valid buys !");
}
}
else
{
Comment("i cant take a trade because the arrray is full");
}
currentResistanceHighEdge = -1;
currentResistanceLowEdge = -1;
}
//+------------------------------------------------------------------+
+113
View File
@@ -0,0 +1,113 @@
//+------------------------------------------------------------------+
//| BuyEntryManager.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "BuyRejectionDetector.mqh"
#include <Trade/Trade.mqh>
CTrade tradeLong ;
class BuyEntryManager
{
private:
bool longTradeTaken ;
bool waitingForRejectionCandle;
bool waitingForRetracement ;
public:
BuyEntryManager();
~BuyEntryManager();
BuyRejectionDetector* buyRejectionDetector ;
bool isWaitingForRejectionCandle(){return waitingForRejectionCandle ;}
void setWaitingForRejectionCandle(bool _setting){waitingForRejectionCandle = _setting ;}
bool isWaitingForRetracement(){return waitingForRetracement;}
void setWaitingForRetracement(bool _setting){waitingForRetracement = _setting ;}
bool buyTradeTaken();
void setTradeTakenStatus(bool _status){longTradeTaken = _status ; Print("long trade taken flag has been set to true");}
ulong takeBuyTrade(double _lots,double _stopLoss);
ulong takeBuyTradeTiger(double _lots,double _stopLoss,double _takeProfit);
ulong takeBuyTradeTiger(double _lots,double _stopLoss);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyEntryManager::BuyEntryManager()
{
buyRejectionDetector = new BuyRejectionDetector();
longTradeTaken = false ;
waitingForRejectionCandle = false ;
waitingForRetracement = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyEntryManager::~BuyEntryManager()
{
delete buyRejectionDetector ;
}
//+------------------------------------------------------------------+
bool BuyEntryManager:: buyTradeTaken(){
return longTradeTaken ;
}
ulong BuyEntryManager:: takeBuyTrade(double _lots, double _stopLoss){
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong BuyEntryManager:: takeBuyTradeTiger(double _lots,double _stopLoss, double _takeProft){ // first version, take the buy with fixed tp
double netTp = _takeProft - SymbolInfoDouble(_Symbol, SYMBOL_ASK) ;
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss,SymbolInfoDouble(_Symbol, SYMBOL_ASK) + netTp);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong BuyEntryManager:: takeBuyTradeTiger(double _lots,double _stopLoss){ // second version, take the buy without a fixed tp
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
+85
View File
@@ -0,0 +1,85 @@
//+------------------------------------------------------------------+
//| BuyGandalf.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Trade/Trade.mqh>
CTrade tradeLong ;
class BuyGandalf
{
private:
bool longTradeTaken ;
ulong longTrades[10] ;
public:
BuyGandalf();
~BuyGandalf();
bool buyTradeTaken();
void setTradeTakenStatus(bool _status){longTradeTaken = _status ; Print("long trade taken flag has been set to true");}
ulong takeBuyTrade(double _lots,double _stopLoss);
ulong takeBuyTradeGandalf(double _lots,double _stopLoss);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyGandalf::BuyGandalf()
{
longTradeTaken = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyGandalf::~BuyGandalf()
{
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
bool BuyGandalf:: buyTradeTaken(){
return longTradeTaken ;
}
ulong BuyGandalf:: takeBuyTrade(double _lots, double _stopLoss){
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
ulong BuyGandalf:: takeBuyTradeGandalf(double _lots,double _stopLoss){
tradeLong.Buy(NormalizeDouble(_lots,2),_Symbol,SymbolInfoDouble(_Symbol, SYMBOL_ASK),_stopLoss);
ulong tradeTicket = tradeLong.ResultOrder();
Print("Buy entry manager has taken a trade, ticket: " + tradeTicket);
return tradeTicket;
}
+53
View File
@@ -0,0 +1,53 @@
//+------------------------------------------------------------------+
//| BuyRejectionDetector.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class BuyRejectionDetector
{
private:
public:
BuyRejectionDetector();
~BuyRejectionDetector();
bool rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame);
bool rejectionByRangeFormed();
bool rejectionByWicksFormed();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyRejectionDetector::BuyRejectionDetector()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyRejectionDetector::~BuyRejectionDetector()
{
}
//+------------------------------------------------------------------+
bool BuyRejectionDetector:: rejectionByOneCandleFormed(ENUM_TIMEFRAMES _timeFrame){
double rejectionCandleClose = iClose(_Symbol,_timeFrame,1);
double rejectionCandleOpen = iOpen(_Symbol,_timeFrame,1);
double rejectionCandleHigh = iHigh(_Symbol,_timeFrame,1) ;
double rejectionCandleHigherWickSize ;
double rejectionCandleBodySize ;
if( rejectionCandleClose > rejectionCandleOpen ){ // the previous candle closed bullish
rejectionCandleHigherWickSize = rejectionCandleHigh - rejectionCandleClose;
rejectionCandleBodySize = rejectionCandleClose - rejectionCandleOpen;
if(rejectionCandleBodySize >= rejectionCandleHigherWickSize){
return true ;
}
}
return false ;
}
+592
View File
@@ -0,0 +1,592 @@
//+------------------------------------------------------------------+
//| BuyTradeManager.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//#include <TradeManagersAttributes.mqh>
//#include <Telegram_Handler.mqh>
#include <Trade/Trade.mqh>
CTrade tradeLongInTradeManager;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class BuyTradeManager
{
private:
int tradeId;
ulong rejectionByOneCandleTradeArray[3];
string firstSecureMethod ;
bool firstSecureMethodFound;
int numberOfTakeProfits ;
bool securedFirstLevelProfit ;
bool securedSecondLevelProfit;
double partialToClose ;
bool isTradeRunning ;
public:
BuyTradeManager();
~BuyTradeManager();
void fillRejectionByOneCandleTradeArray(int _index, int _id) {rejectionByOneCandleTradeArray[_index] = _id ;}
ulong getRejectionByOneCandleTradeTicket(int _index) {return rejectionByOneCandleTradeArray[_index] ;}
void printRejectionByOneCandleTradeArray();
void checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars);
string findFirstSecureMethod();
bool reachedProfitRatio(int _indexInArr);
bool closeTrade(int _indexInArr);
bool positionBreakEven(int _indexInArr);
void addTpAtIndex(int _index, double tpPrice) {tpArray[_index] = tpPrice;}
int countRemainingTakeProfits();
bool reachedClosestTakeProfit();
void deleteClosestTp();
int findClosestTpIndex();
void cleanOrderDataStructures();
void setTradeRunning(bool _setting) {isTradeRunning = _setting ;}
bool tradeIsRunning() {return isTradeRunning ;}
double tpArray[3];
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyTradeManager::BuyTradeManager()
{
for(int i=0; i<3; i++)
{
tpArray[i] = -1;
}
securedFirstLevelProfit = false ;
securedSecondLevelProfit = false ;
firstSecureMethodFound = false ;
firstSecureMethod = "NOT_FOUND" ;
partialToClose = -1 ;
isTradeRunning = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyTradeManager::~BuyTradeManager()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BuyTradeManager:: printRejectionByOneCandleTradeArray()
{
Print("Printing the tickets :");
for(int i=0 ; i<3 ; i++)
{
Print((int)rejectionByOneCandleTradeArray[i]);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BuyTradeManager:: checkAndSecureTradeIfNeeded(double _ratio, double _riskInDollars)
{
if(securedFirstLevelProfit == false) // in this case im searching for 2 cases: either RR 1:1.5 , OR reaching the first TP , if any of them happened im gonna close half the order and updatae the remaining stop losses
{
if(!firstSecureMethodFound)
{
firstSecureMethod = findFirstSecureMethod();
if(firstSecureMethod != "FAILED")
{
firstSecureMethodFound = true ;
}
else
if(firstSecureMethod == "FAILED")
{
Print("Failed to find the first secure method, go check the function : findFirstSecureMehod() !");
}
}
if(firstSecureMethodFound == true)
{
if(firstSecureMethod == "RATIO_METHOD")
{
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(reachedProfitRatio(0))
{
ChartRedraw(); // Make sure the chart is up to date
//ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
//SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,
//"If you see this message it means we reached the first secure method, which is ratio method, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName);
if(closeTrade(0)) // close the half
{
rejectionByOneCandleTradeArray[0] = -1;
Print("Closed Half Of the position due to reaching the first secure Ratio!");
}
else
{
Print("Failed Closing Half of the order by reaching the first secure Ratio !");
}
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(positionBreakEven(1)) // put the first quarter at break even
{
Print(" First quarter has been put into break even due to reaching the first secure Ratio!");
}
else
{
Print("Failed to Put the first quarter into break even");
}
numberOfTakeProfits = countRemainingTakeProfits();
Print("Number of remaining tps is: " + numberOfTakeProfits);
securedFirstLevelProfit = true ;
}
}
else
if(firstSecureMethod == "FIRST_TP_METHOD")
{
if(countRemainingTakeProfits() > 1) // there is at least 2 tp in the tp Array (because if this is the last tp then we want to close the whole order and not just a part of it)
{
if(reachedClosestTakeProfit()) // 2. Check if reached the first Tp
{
ChartRedraw(); // Make sure the chart is up to date
//ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
//SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,
//"If you see this message it means we reached the first secure method which is tp1, after this message, half of the order must be closed (2 trades will remain active), and the first quarter will be put into Break even " + TimeToString(TimeLocal()), fileName);
// close the first half and update remaining partials sl's and delete the closest take profit from the array
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(closeTrade(0)) // close the half
{
rejectionByOneCandleTradeArray[0] = -1;
Print("Closed Half Of the position due to reaching the first TP!");
}
else
{
Print("Failed Closing Half of the order by reaching the first TP !");
}
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(positionBreakEven(1)) // put the first quarter at break even
{
Print(" First quarter has been put into break even due to reaching the first TP!");
}
else
{
Print("Failed to Put the first quarter into break even");
}
deleteClosestTp();
numberOfTakeProfits = countRemainingTakeProfits(); // update the number of remaining take profits
// calculate the remaining tps
Print("Number of remaining tps is: " + numberOfTakeProfits);
Print("TP ARRY: " + tpArray[0] + ", " + tpArray[1] + " , " + tpArray[2]);
securedFirstLevelProfit = true ;
}
}
else
if(numberOfTakeProfits = countRemainingTakeProfits() == 1)
{
if(reachedClosestTakeProfit())
{
// close everything remained
}
}
}
}
}
else
if(securedFirstLevelProfit == true) // after securing the first level i just want to close the remaining partials by reaching the tp's
{
if(countRemainingTakeProfits() == 1)
{
if(reachedClosestTakeProfit())
{
// close everything
cleanOrderDataStructures();
for(int i=0 ; i<3 ; i++)
{
closeTrade(i);
}
Print("Closed every thing because price reached the last Take Profit !");
ChartRedraw(); // Make sure the chart is up to date
//ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
//SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,
// "If you see this message it means that all order are closed as a result of reaching the last tp " + TimeToString(TimeLocal()), fileName);
deleteClosestTp();
}
}
else
if(countRemainingTakeProfits() > 1)
{
if(reachedClosestTakeProfit())
{
cleanOrderDataStructures();
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[1])) // DEALING WITH THE FIRST QUARTER
{
double currentLot = PositionGetDouble(POSITION_VOLUME);
if(partialToClose == -1)
{
partialToClose = currentLot/numberOfTakeProfits ;
}
if(tradeLongInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[1],NormalizeDouble(partialToClose,2)))
{
uint res = tradeLongInTradeManager.ResultRetcode();
if(res == 10009)
{
Print("Closed Partials successfully on the first quarter !");
}
else
{
Print("The returned code is: " + res + " go check what it means !");
}
}
}
else
{
Print("Failed to select position by ticket! , Error: " + GetLastError());
Print("The EA tried to close partials on the first quarter, but it is closed, probably due to break even and thats why it couldnt select the order !");
}
cleanOrderDataStructures();
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[2])) // DEALING WITH THE SECOND QUARTER
{
if(PositionGetDouble(POSITION_SL) < PositionGetDouble(POSITION_PRICE_OPEN)) // this is to put the second quarter at break even if its not already at break even
{
positionBreakEven(2);
}
double currentLot = PositionGetDouble(POSITION_VOLUME);
if(partialToClose == -1)
{
partialToClose = currentLot/numberOfTakeProfits ;
}
if(tradeLongInTradeManager.PositionClosePartial(rejectionByOneCandleTradeArray[2],NormalizeDouble(partialToClose,2)))
{
uint res = tradeLongInTradeManager.ResultRetcode();
if(res == 10009)
{
Print("Closed Partials successfully on the second quarter!");
}
else
{
Print("The returned code is: " + res + " go check what it means !");
}
}
}
deleteClosestTp();
Print("Number Of Remained tps is: " + countRemainingTakeProfits());
ChartRedraw(); // Make sure the chart is up to date
//ChartScreenShot(0, fileName, 1024, 768, ALIGN_RIGHT);
//SendTelegramMessage(TelegramApiUrl, TelegramBotToken, ChatId,
// "If you see this message it means we reached a tp level (different than the first secure level), so partial positions will be closed, and the scond quarter must be in break even!" + TimeToString(TimeLocal()), fileName);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string BuyTradeManager:: findFirstSecureMethod()
{
cleanOrderDataStructures(); // this is used each time before we are choosing an order by ticket
if(PositionSelectByTicket(rejectionByOneCandleTradeArray[0]))
{
double positionStopLoss = PositionGetDouble(POSITION_SL);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double firstTakeProfit = tpArray[findClosestTpIndex()];
if(((firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) > firstSecureRatio)) // firstTp > ratio
{
Print("Found the first profit secure method !");
Print("The first TP RR is: 1:" + (firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) + "the firstSecureRatio is: 1:" + firstSecureRatio);
Print("The tp ratio is greater than the firstSecure so:");
Print("The first secure method is RATIO_METHOD");
return"RATIO_METHOD";
}
else
if((firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss)< firstSecureRatio)
{
Print("Found the first profit secure method !");
Print("The first TP RR is: 1:" + (firstTakeProfit-positionOpenPrice)/(positionOpenPrice-positionStopLoss) + "the firstSecureRatio is: 1:" + firstSecureRatio);
Print("The tp ratio is less than the firstSecure so:");
Print("The first secure method is FIRST_TP_METHOD");
return "FIRST_TP_METHOD" ;
}
}
else
{
Print("Failed to select position by ticket 1, Error: " + GetLastError());
}
return "FAILED" ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BuyTradeManager:: reachedProfitRatio(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket))
{
if(PositionGetDouble(POSITION_PROFIT)/(0.5*riskDollars) >= firstSecureRatio) // checking if the first half of the contract reached the ratio of first secure profit
{
Print("reached profit ratio !");
return true ;
}
}
else
{
Print("Failed to select the position by ticket 4 ,Error: " + GetLastError());
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BuyTradeManager:: closeTrade(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket))
{
// close the first half and update remaining partials sl's
if(tradeLongInTradeManager.PositionClose(_ticket))
{
return true ;
}
else
{
Print("Failed to close positon, Error:" + GetLastError());
return false;
}
}
else
{
Print("Failed to select position by ticket , Error: "+ GetLastError());
return false;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BuyTradeManager:: positionBreakEven(int _indexInArr)
{
ulong _ticket = rejectionByOneCandleTradeArray[_indexInArr];
if(_ticket != -1)
{
if(PositionSelectByTicket(_ticket)) // select the first quarter
{
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double positionTp = PositionGetDouble(POSITION_TP);
double positionSl = PositionGetDouble(POSITION_SL);
if(tradeLongInTradeManager.PositionModify(_ticket,openPrice,positionTp))
{
return true ;
}
else
{
Print("Failed to modify oder , ERROR: " + GetLastError());
return false ;
}
}
else
{
Print("Failed to select position by ticket ");
return false ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int BuyTradeManager:: countRemainingTakeProfits()
{
int counter = 0 ;
for(int i=0; i<3 ; i++)
{
if(tpArray[i] != -1)
{
counter++ ;
}
}
return counter;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BuyTradeManager:: deleteClosestTp()
{
int closestTpIndex =findClosestTpIndex();
tpArray[closestTpIndex] = -1;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int BuyTradeManager:: findClosestTpIndex()
{
int closestTpIndex = 0;
int closestTpValue = 1000000 ; // dummy value
for(int i=0; i<3; i++)
{
if(tpArray[i] != -1 && tpArray[i] < closestTpValue)
{
closestTpValue = tpArray[i];
closestTpIndex = i ;
}
}
return closestTpIndex ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool BuyTradeManager:: reachedClosestTakeProfit()
{
double closestTakeProfitValue = tpArray[findClosestTpIndex()];
//Print("im in reached closest take profit function ,the current price is: " + SymbolInfoDouble(_Symbol, SYMBOL_BID) + " and the tp is: " + closestTakeProfitValue);
if(SymbolInfoDouble(_Symbol, SYMBOL_BID) >= closestTakeProfitValue) // we are looking for the BID , because reaching a tp in a buy trade means we are selling, so we want our take profit value, to be at least as the BID price (because we want to find someone to buy it from us at this price)
{
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void BuyTradeManager:: cleanOrderDataStructures()
{
// this is to make sure, that every closed order is removed from the data strucutre !
for(int i=0; i<3; i++)
{
if(!PositionSelectByTicket(rejectionByOneCandleTradeArray[i]))
{
if(GetLastError() == 4753)
{
rejectionByOneCandleTradeArray[i] = -1 ;
}
}
}
}
//+------------------------------------------------------------------+
+72
View File
@@ -0,0 +1,72 @@
//+------------------------------------------------------------------+
//| BuyTradeManagerTiger.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class BuyTradeManagerTiger
{
private:
ulong tradeId ;
string entryType ;
bool firstPartialSecured ;
bool secondPartialSecured ;
bool managedRisk ;
bool retestWickFormed ;
double retestWickLengthInPips ;
int riskManagementCandleCounter ;
double brokenResistanceLowerEdge ;
double brokenResistanceHigherEdge ;
public:
ulong getTradeId(){return tradeId ;}
bool riskAlreadyManaged(){return managedRisk ;}
void manageRisk(){managedRisk = true ;}
bool firstPartialIsSecured(){return firstPartialSecured ;}
void secureFirstPartial(){firstPartialSecured = true ;}
void setBrokenResistancetLowerEdge(double _brokenResistanceLowerEdge){brokenResistanceLowerEdge = _brokenResistanceLowerEdge ;}
void setBrokenResistanceHigherEdge(double _brokenResistanceHigherEdge){brokenResistanceHigherEdge = _brokenResistanceHigherEdge ;}
double getBrokenResistanceLowerEdge(){return brokenResistanceLowerEdge ;}
double getBrokenResistanceHigherEdge(){return brokenResistanceHigherEdge ;}
void incrementRiskManagementCandleCoutner(){riskManagementCandleCounter++ ;}
void decrementRiskManagementCandleCounter(){riskManagementCandleCounter-- ;}
int getRiskManagementCandleCounter(){return riskManagementCandleCounter ;}
void setRiskManagementCandleCounter(int count){ riskManagementCandleCounter = count ;}
BuyTradeManagerTiger(ulong _tradeId);
~BuyTradeManagerTiger();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyTradeManagerTiger::BuyTradeManagerTiger(ulong _tradeId)
{
tradeId = _tradeId ;
firstPartialSecured = false ;
secondPartialSecured = false ;
managedRisk = false ;
retestWickFormed = false ;
retestWickLengthInPips = 0 ;
riskManagementCandleCounter = 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
BuyTradeManagerTiger::~BuyTradeManagerTiger()
{
}
//+------------------------------------------------------------------+
Binary file not shown.
+333
View File
@@ -0,0 +1,333 @@
//+------------------------------------------------------------------+
//| TigerObserver.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Algo_Skeleton_Functions.mqh"
long H4_SUPPORT_ZONE_CLR ;
long H4_RESISTANCE_ZONE_CLR ;
long H1_SUPPORT_ZONE_CLR;
long H1_RESISTANCE_ZONE_CLR;
long M30_SUPPORT_ZONE_CLR ;
long M30_RESISTANCE_ZONE_CLR ;
int OnInit()
{
//--- create timer
EventSetTimer(60);
// ONLY FOR VISULAZITAION ON STRATEGY TESTER
iClose(_Symbol,PERIOD_W1,1);
iClose(_Symbol,PERIOD_D1,1);
iClose(_Symbol,PERIOD_H4,5);
iClose(_Symbol,PERIOD_H1,5);
iClose(_Symbol,PERIOD_M30,5);
iClose(_Symbol,PERIOD_M15,5);
H4_SUPPORT_ZONE_CLR = clrBlack ;
H4_RESISTANCE_ZONE_CLR = clrBlack ;
if(ENTRY_BASED_H1_STRUCTURE == true && ENTRY_BASED_M30_STRUCTURE == false){
M30_SUPPORT_ZONE_CLR = clrBlack ;
M30_RESISTANCE_ZONE_CLR = clrBlack ;
H1_SUPPORT_ZONE_CLR = clrAliceBlue ;
H1_RESISTANCE_ZONE_CLR = clrDarkGray ;
}
else if(ENTRY_BASED_H1_STRUCTURE == false && ENTRY_BASED_M30_STRUCTURE == true){
M30_SUPPORT_ZONE_CLR = clrAliceBlue ;
M30_RESISTANCE_ZONE_CLR = clrDarkGray ;
H1_SUPPORT_ZONE_CLR = clrBlack ;
H1_RESISTANCE_ZONE_CLR = clrBlack ;
}
objectsManager.addTextTiger();
for(int i=0; i<NUM_MAX_ALLOWED_TRADES ; i++)
{
BuyActiveTradesArray[i] = NULL ;
SellActiveTradesArray[i] = NULL ;
}
//objectsManager.addMarketDescriptionTextTiger();
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
Print("Buys Count: " + buysCount);
Print("Sells Count: " + sellsCount);
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
cleanBuyTradesArr();
cleanSellTradesArr();
secureProfitIfNeeded();
if(newCandleDetectorM15.isNewCandle())
{
// UPDATING M30 ZONES
if(zoneContainerSupport_M30.getNumberOfActiveZones()>0){
updateNormalZonesSupport(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",M30_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_M30,0);
}
if(zoneContainer_M30.getNumberOfActiveZones()> 0){
updateNormalZonesResistance(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",M30_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_M30,0);
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetector30M.isNewCandle())
{
if(trail_based_m30){
trailAllOpenPositionsIfNeeded(PERIOD_M30);
}
datetime currTime = TimeCurrent();
ObjectSetString(0,"clockTextTiger",OBJPROP_TEXT,TimeToString(currTime,TIME_MINUTES));
detectAndDrawResistanceOnTimeFrame(PERIOD_M30,"PERIOD_M30",M30_RESISTANCE_ZONE_CLR,zoneContainer_M30,rangeDistanceBetweenZonesActual_M30,0);
detectAndDrawSupportOnTimeFrame(PERIOD_M30,"PERIOD_M30",M30_SUPPORT_ZONE_CLR,zoneContainerSupport_M30,rangeDistanceBetweenZonesActual_M30,0);
if(ENTRY_BASED_M30_STRUCTURE){
handleBuys(zoneContainer_M30,PERIOD_M30,"PERIOD_M30",cleanRangeUponEntryActual);
handleSells(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30",cleanRangeUponEntryActual);
}
else{
handleBullishBreakouts(zoneContainer_M30,PERIOD_M30,"PERIOD_M30");
handleBearishBreakouts(zoneContainerSupport_M30,PERIOD_M30,"PERIOD_M30");
}
// UPDATING H1 ZONES
if(zoneContainerSupport_H1.getNumberOfActiveZones()>0){
updateNormalZonesSupport(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",H1_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_H1,1000);
}
if(zoneContainer_H1.getNumberOfActiveZones()> 0){
updateNormalZonesResistance(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",H1_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_H1,1000);
}
zoneContainerSupport_M30.printZonesSortedArray();
zoneContainer_M30.printZonesSortedArray();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetector1H.isNewCandle()){
if(trail_based_h1){
trailAllOpenPositionsIfNeeded(PERIOD_H1);
}
detectAndDrawResistanceOnTimeFrame(PERIOD_H1,"PERIOD_H1",H1_RESISTANCE_ZONE_CLR,zoneContainer_H1,rangeDistanceBetweenZonesActual_H1,1000);
detectAndDrawSupportOnTimeFrame(PERIOD_H1,"PERIOD_H1",H1_SUPPORT_ZONE_CLR,zoneContainerSupport_H1,rangeDistanceBetweenZonesActual_H1,1000);
if(ENTRY_BASED_H1_STRUCTURE){
handleBuys(zoneContainer_H1,PERIOD_H1,"PERIOD_H1",cleanRangeUponEntryActual);
handleSells(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1",cleanRangeUponEntryActual);
}
else{
handleBullishBreakouts(zoneContainer_H1,PERIOD_H1,"PERIOD_H1");
handleBearishBreakouts(zoneContainerSupport_H1,PERIOD_H1,"PERIOD_H1");
}
// UPDATING H4 ZONES
if(zoneContainerSupport_H4.getNumberOfActiveZones()>0){
updateNormalZonesSupport(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",H4_SUPPORT_ZONE_CLR,rangeDistanceBetweenZonesActual_H4,2000);
}
if(zoneContainer_H4.getNumberOfActiveZones()> 0){
updateNormalZonesResistance(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",H4_RESISTANCE_ZONE_CLR,rangeDistanceBetweenZonesActual_H4,2000);
}
Print("H1 zones :");
//zoneContainerSupport_H1.printZonesSortedArray();
//zoneContainer_H1.printZonesSortedArray();
}
if(newCandleDetector4H.isNewCandle()){
last_H4_candle_broke_structure = false ;
if(trail_based_h4){
trailAllOpenPositionsIfNeeded(PERIOD_H4);
}
detectAndDrawResistanceOnTimeFrame(PERIOD_H4,"PERIOD_H4",H4_RESISTANCE_ZONE_CLR,zoneContainer_H4,rangeDistanceBetweenZonesActual_H4,2000);
detectAndDrawSupportOnTimeFrame(PERIOD_H4,"PERIOD_H4",H4_SUPPORT_ZONE_CLR,zoneContainerSupport_H4,rangeDistanceBetweenZonesActual_H4,2000);
// BREAK OF STRUCTURE HANDLING
handleBullishBreakouts(zoneContainer_H4,PERIOD_H4,"PERIOD_H4");
handleBearishBreakouts(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4");
//handleBuys(zoneContainer_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual);
//handleSells(zoneContainerSupport_H4,PERIOD_H4,"PERIOD_H4",cleanRangeUponEntryActual);
//Print("H4, Zones:");
//zoneContainerSupport_H4.printZonesSortedArray();
//zoneContainer_H4.printZonesSortedArray();
}
if(newCandleDetectorDaily.isNewCandle())
{
//detectAndDrawResistanceOnTimeFrame(PERIOD_D1,"PERIOD_D1",clrYellow,clrYellow,zoneContainer_D1);
//updateBreakAboveStructureAndDelete(zoneContainer_D1,PERIOD_D1,"PERIOD_D1");
objectsManager.drawVerticalLine(clrAqua, TimeCurrent());
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
if(newCandleDetectorWeekly.isNewCandle())
{
objectsManager.drawVerticalLine(clrRed, TimeCurrent());
weekCounter++ ;
if(weekCounter == deleteAllZonesAfter_Weeks){
//deleteAllzonesWithGUI();
weekCounter = 0;
}
}
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//---
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
Binary file not shown.
+363
View File
@@ -0,0 +1,363 @@
//+------------------------------------------------------------------+
//| Gandalf.mq5 |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "GraphicalObjectsManager.mqh"
#include "TempLineObjectAttributes.mqh"
#include "ObjectConfirmationUnit.mqh"
#include "BuyGandalf.mqh"
#include "SellGandalf.mqh"
#include "LotSizeCalculator.mqh"
LotSizeCalculator lsCalc;
GraphicalObjectsManager graphicalObjectsManager ;
ObjectConfirmationUnit objectConfUnit ;
BuyGandalf buyGandalfGray ;
SellGandalf SellGandalfGray ;
bool buyCase = false ;
bool sellCase = false ;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
TempLineObjectAttributes tempLineObjectAttr ;
int OnInit()
{
//--- create timer
EventSetTimer(60);
graphicalObjectsManager.addTotalRiskText();
graphicalObjectsManager.addTakeBuyTradeButton();
graphicalObjectsManager.addTakeSellTradeButton();
graphicalObjectsManager.addText();
graphicalObjectsManager.addConfirmButton();
//ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"the new ext is : !");
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- destroy timer
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
updateOverAllRiskText();
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
}
//+------------------------------------------------------------------+
//| Trade function |
//+------------------------------------------------------------------+
void OnTrade()
{
//---
}
//+------------------------------------------------------------------+
//| TradeTransaction function |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
const MqlTradeRequest& request,
const MqlTradeResult& result)
{
//---
}
//+------------------------------------------------------------------+
//| Tester function |
//+------------------------------------------------------------------+
double OnTester()
{
//---
double ret=0.0;
//---
//---
return(ret);
}
//+------------------------------------------------------------------+
//| TesterInit function |
//+------------------------------------------------------------------+
void OnTesterInit()
{
//---
}
//+------------------------------------------------------------------+
//| TesterPass function |
//+------------------------------------------------------------------+
void OnTesterPass()
{
//---
}
//+------------------------------------------------------------------+
//| TesterDeinit function |
//+------------------------------------------------------------------+
void OnTesterDeinit()
{
//---
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
switch(id)
{
case CHARTEVENT_CLICK:
{
break;
}
//--- clicking on a graphical object
case CHARTEVENT_OBJECT_CLICK:
{
if(sparam == "BUY_BTN")
{
buyCase = true ;
graphicalObjectsManager.drawStopLossLineGandalf();
objectConfUnit.setWaitingStatus(true);
}
else if(sparam == "SELL_BTN"){
sellCase = true ;
graphicalObjectsManager.drawStopLossLineGandalf();
objectConfUnit.setWaitingStatus(true);
}
else
if(sparam == "CONFIRM_BTN")
{
if(buyCase == true)
{
if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK) ;
string textRecieved;
graphicalObjectsManager.EditTextGet(textRecieved,0,"textName");
double riskAsDouble = StringToDouble(textRecieved);
double stopLossPrice = tempLineObjectAttr.getPrice();
if(ObjectDelete(_Symbol,"sl"))
{
}
else
{
Print("Failed to delete the stop loss line ! Error: "+ GetLastError());
}
//Print("Buy info has been set, SL price: " + stopLossPrice + " risk is: " + riskAsDouble);
double lotsToTrade = lsCalc.calculateLotSize(riskAsDouble,stopLossPrice);
buyGandalfGray.takeBuyTradeGandalf(lotsToTrade,stopLossPrice);
objectConfUnit.setWaitingStatus(false);
buyCase = false ;
// change the risk text
//updateOverAllRiskText();
}
}
else
if(sellCase == true)
{
if(objectConfUnit.getWaitingStatus() == true) // THIS IS TO MAKE SURE THAT THERE IS SOMETHING SELECTED TO BE CONFIRMED
{
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
string textRecieved;
graphicalObjectsManager.EditTextGet(textRecieved,0,"textName");
double riskAsDouble = StringToDouble(textRecieved);
double stopLossPrice = tempLineObjectAttr.getPrice();
if(ObjectDelete(_Symbol,"sl")){
}
else{
Print("Failed to delete the stop loss line ! Error: "+ GetLastError());
}
double lotsToTrade = lsCalc.calculateLotSize(riskAsDouble,stopLossPrice);
SellGandalfGray.takeSellTradeGandalf(lotsToTrade,stopLossPrice);
objectConfUnit.setWaitingStatus(false);
sellCase = false ;
// change the risk text
//updateOverAllRiskText();
}
}
}
break;
}
case CHARTEVENT_OBJECT_DRAG:
{
if(ObjectGetInteger(_Symbol,sparam,OBJPROP_TYPE,0) == OBJ_HLINE)
{
if(StringSubstr(sparam,0,2) == "sl") // case of sl line (attached to a zone)
{
double stopLossPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0);
tempLineObjectAttr.setId(sparam);
tempLineObjectAttr.setPrice(stopLossPrice);
}
else
if(StringSubstr(sparam,0,2) == "tp") // case of tp line (attached to a zone)
{
double takeProfitPrice = ObjectGetDouble(_Symbol,sparam,OBJPROP_PRICE,0);
tempLineObjectAttr.setId(sparam);
tempLineObjectAttr.setPrice(takeProfitPrice);
}
}
break;
}
case CHARTEVENT_KEYDOWN:
{
}
//---
}
}
//+------------------------------------------------------------------+
//| BookEvent function |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
//---
}
//+------------------------------------------------------------------+
void updateOverAllRiskText(){
//double pointValue = lsCalc.PointValue(_Symbol);
double pointValue = PointValueNew(_Symbol);
double overAllRisk = 0 ;
for(int i=PositionsTotal() -1 ;i >= 0 ; i--){
//Print("entered here !");
ulong ticket = PositionGetTicket(i);
int positionType = PositionGetInteger(POSITION_TYPE);
double positionStopLossPrice = PositionGetDouble(POSITION_SL);
double positionOpenPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double positionLotSize = PositionGetDouble(POSITION_VOLUME);
if(positionType == POSITION_TYPE_BUY){
double positionStopLossInPoints = (positionOpenPrice - positionStopLossPrice) * MathPow(10 , SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)) ;
double riskAmount = pointValue*positionLotSize*positionStopLossInPoints ;
overAllRisk = overAllRisk + riskAmount ;
string riskAsString = DoubleToString(overAllRisk);
ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is:" + riskAsString);
}
else if(positionType == POSITION_TYPE_SELL){
double positionStopLossInPoints = (positionStopLossPrice - positionOpenPrice) * MathPow(10 , SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)) ;
double riskAmount = pointValue*positionLotSize*positionStopLossInPoints ;
overAllRisk = overAllRisk + riskAmount ;
string riskAsString = DoubleToString(overAllRisk);
ObjectSetString(0,"totalRiskText",OBJPROP_TEXT,"Total Risk is:" + riskAsString);
}
}
}
double PointValueNew(string symbol){
double tickSize = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE);
double tickValue = SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE);
double point = SymbolInfoDouble(symbol,SYMBOL_POINT);
double ticksPerPoint = tickSize/point ;
double pointValue = tickValue/ticksPerPoint ;
return (pointValue);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+254
View File
@@ -0,0 +1,254 @@
//+------------------------------------------------------------------+
//| HighFractal.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class HighFractal
{
private:
double highPrice ;
int leftPeriod;
int rightPeriod;
MqlDateTime dateStruct ;
datetime date ;
double sellLimitPrice; // the fib level price , based on this fractal
double lowestPeak ; // the highest price reached, after the fractal was formed
int hour ;
int minute;
int distance ; // holds the number of candles from this fractal until the current live candle
string arrowObjName ;
double fibPrice ;
public:
HighFractal();
HighFractal(double _price, int _leftPeriod, int _rightPeriod, datetime _date,ENUM_TIMEFRAMES _tf);
~HighFractal();
// GETTERS
double getPrice();
int getLeftPeriod();
int getRightPeriod();
int getHour();
int getMinute();
double getLowestPeak();
int getDistance();
string getArrowObjName();
datetime getDate();
// SETTERS
void setPrice(double _price);
void setLeftPeriod(int _leftPeriod);
void setRightPeriod(int _rightPeriod);
void setHour(int _hour);
void setMinute(int _minute);
void setLowestPeak(double _highest);
void setArrowObjName(string _name);
void setDistance(int _dist);
void setDate(datetime _givenDate);
// OTHER FUNCTIONS
double calculateFibPrice(double _fibLevel, double _highPrice, double _lowPrice); // calculate the fibonacci price based on the given level, and saves the price in the fibPrice88 variable in the object
void updateDistance();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractal::HighFractal()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractal::HighFractal(double _price, int _leftPeriod, int _rightPeriod,datetime _date,ENUM_TIMEFRAMES _tf)
{
// the constructor sets the data to the attribues , and calculates the real time of the fractal , because the given minute and hour
// are not the real time, they are the time of when the fractal was "known to be a fractal", which is after _righPeriod amount of candles
highPrice = _price ;
leftPeriod = _leftPeriod;
rightPeriod = _rightPeriod;
sellLimitPrice = -1 ;
distance = _rightPeriod+1;
arrowObjName = " " ;
lowestPeak = -1;
date = iTime(_Symbol,_tf,_rightPeriod+1); // bring the actual date of the fractal
TimeToStruct(date,dateStruct); // convert the actual date into a struct
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractal::~HighFractal()
{
}
//+------------------------------------------------------------------+
double HighFractal:: getPrice()
{
return highPrice ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int HighFractal:: getLeftPeriod()
{
return leftPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int HighFractal:: getRightPeriod()
{
return rightPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int HighFractal:: getHour()
{
return dateStruct.hour ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int HighFractal:: getMinute()
{
return dateStruct.min ;
}
double HighFractal:: getLowestPeak(){
return lowestPeak ;
}
int HighFractal:: getDistance(){
return distance ;
}
string HighFractal:: getArrowObjName(){
return arrowObjName ;
}
datetime HighFractal:: getDate(){
return date ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setPrice(double _price)
{
highPrice = _price ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setLeftPeriod(int _leftPeriod)
{
leftPeriod = _leftPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setRightPeriod(int _rightPeriod)
{
rightPeriod = _rightPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setHour(int _hour)
{
hour = _hour ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void HighFractal:: setMinute(int _minute)
{
minute = _minute ;
}
//+------------------------------------------------------------------+
void HighFractal:: setArrowObjName(string _name){
arrowObjName = _name ;
}
void HighFractal:: setDistance(int _dist){
distance = _dist ;
}
double HighFractal:: calculateFibPrice(double _fibLevel, double _highPrice, double _lowPrice){
double difference = _lowPrice - _highPrice ;
difference = difference*-1 ;
double retracement = _fibLevel * difference ;
double _fibPrice = _lowPrice + retracement ;
fibPrice = _fibPrice ;
return fibPrice;
}
void HighFractal:: setLowestPeak(double _lowest){
lowestPeak = _lowest ;
}
void HighFractal:: setDate(datetime _givenDate){
date = _givenDate;
TimeToStruct(date,dateStruct); // convert the actual date into a struct
}
void HighFractal:: updateDistance(){
distance++ ;
}
//+------------------------------------------------------------------+
+131
View File
@@ -0,0 +1,131 @@
//+------------------------------------------------------------------+
//| HighFractalContainer.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "HighFractal.mqh"
#include <library_functions.mqh>
#define SIZE 700
double input arrowDistanceHighs ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class HighFractalContainer
{
private:
HighFractal* highFractals[SIZE];
int freeIndex ;
double range ;
ENUM_TIMEFRAMES timeFrame ;
public:
HighFractalContainer(ENUM_TIMEFRAMES _timeFrame);
~HighFractalContainer();
//GETTERS
HighFractal* getHighFractal(int _index) {return highFractals[_index] ;} // returns the fractal using its index in the array
int getFreeIndex() {return freeIndex ; }
//SETTERS
void setRange(double _range) {range = _range ;}
// OTHER FUNCTIONS
void addHighFractal(HighFractal* _highFractal); // adds high fractal to the high fractals array
void printHighFractals(); // prints the data of every high fractal in the highFractals[] array
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractalContainer::HighFractalContainer(ENUM_TIMEFRAMES _timeFrame)
{
timeFrame = _timeFrame;
freeIndex = 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
HighFractalContainer::~HighFractalContainer()
{
for(int i=0; i<SIZE; i++) // free the highFractals array
{
delete highFractals[i] ;
}
}
//+------------------------------------------------------------------+
void HighFractalContainer:: addHighFractal(HighFractal* _highFractal){
if(freeIndex == SIZE) // in this case we are adding a new fractal but the array is full so we need to do the following
{
ObjectDelete(_Symbol,highFractals[0].getArrowObjName()); // delete the object arrow of the deleted fractal
ObjectCreate(_Symbol,_highFractal.getArrowObjName(),OBJ_ARROW_DOWN,0,iTime(Symbol(),timeFrame,_highFractal.getDistance()),iHigh(Symbol(),timeFrame,_highFractal.getDistance()) + arrowDistanceHighs); // create the new object arrow of the new fractal
ObjectSetInteger(0,_highFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
delete highFractals[0]; // free the memory allocated for the fractal in the first index (because we wanna remove it from the array)
for(int i=0; i< SIZE-1 ; i++) // shift the array
{
highFractals[i] = highFractals[i+1];
}
highFractals[freeIndex - 1] = _highFractal ;
}
else
{
if(freeIndex == 0) // case of the first fractal
{
highFractals[freeIndex] = _highFractal ;
freeIndex++;
ObjectCreate(_Symbol,_highFractal.getArrowObjName(),OBJ_ARROW_DOWN,0,iTime(Symbol(),timeFrame,_highFractal.getDistance()),iHigh(Symbol(),timeFrame,_highFractal.getDistance()) + arrowDistanceHighs);
ObjectSetInteger(0,_highFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
}
else
{
highFractals[freeIndex] = _highFractal ;
freeIndex++;
ObjectCreate(_Symbol,_highFractal.getArrowObjName(),OBJ_ARROW_DOWN,0,iTime(Symbol(),timeFrame,_highFractal.getDistance()),iHigh(Symbol(),timeFrame,_highFractal.getDistance()) + arrowDistanceHighs);
ObjectSetInteger(0,_highFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
}
}
}
void HighFractalContainer:: printHighFractals()
{
if(freeIndex > 0)
{
for(int i=0 ; i<freeIndex ; i++)
{
Print(" Fractal " + i + " Time: ", highFractals[i].getHour() + ":" + highFractals[i].getMinute()+ " Price: "
+ highFractals[i].getPrice() + " Distance: " + highFractals[i].getDistance() );
}
}
}
+130
View File
@@ -0,0 +1,130 @@
//+------------------------------------------------------------------+
//| LotSizeCalculator.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class LotSizeCalculator
{
private:
public:
LotSizeCalculator();
~LotSizeCalculator();
double calculateLotSize(double riskInMoney,double stopLossPrice);
string BaseCurrency() { return (AccountInfoString(ACCOUNT_CURRENCY)); }
double Point(string symbol) { return (SymbolInfoDouble(symbol, SYMBOL_POINT)); }
double TickSize(string symbol) { return (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE)); }
double TickValue(string symbol) { return (SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE)); }
double PointValue(string symbol);
void Test(string symbol);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LotSizeCalculator::LotSizeCalculator()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LotSizeCalculator::~LotSizeCalculator()
{
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double LotSizeCalculator:: calculateLotSize(double riskInMoney, double stopLossPrice)
{
double difference ;
double differenceInPoints ;
if(stopLossPrice > SymbolInfoDouble(_Symbol, SYMBOL_BID)) // we are calculating for a sell
{
difference = stopLossPrice - SymbolInfoDouble(_Symbol, SYMBOL_BID) ;
differenceInPoints = difference / SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double pointValue = PointValue(_Symbol);
// Situation 3, fixed risk amount and stop loss, how many lots to trade
double riskInPoints = differenceInPoints;
double riskLots = riskInMoney / (pointValue * riskInPoints);
return riskLots;
}
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) > stopLossPrice){
difference = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - stopLossPrice ;
differenceInPoints = difference / SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double pointValue = PointValue(_Symbol);
double riskInPoints = differenceInPoints;
double riskLots = riskInMoney / (pointValue * riskInPoints);
return riskLots;
}
return 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
double LotSizeCalculator:: PointValue(string symbol)
{
double tickSize = TickSize(symbol);
double tickValue = TickValue(symbol);
double point = Point(symbol);
double ticksPerPoint = tickSize / point;
double pointValue = tickValue / ticksPerPoint;
PrintFormat("tickSize=%f, tickValue=%f, point=%f, ticksPerPoint=%f, pointValue=%f",
tickSize, tickValue, point, ticksPerPoint, pointValue);
return (pointValue);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LotSizeCalculator:: Test(string symbol)
{
PrintFormat("Base currency is %s", BaseCurrency());
PrintFormat("Testing for symbol %s", symbol);
double pointValue = PointValue(symbol);
PrintFormat("ValuePerPoint for %s is %f", symbol, pointValue);
// Situation 3, fixed risk amount and stop loss, how many lots to trade
double riskAmount = 100;
double riskPoints = 5000;
double riskLots = riskAmount / (pointValue * riskPoints);
PrintFormat("Risk lots for %s value %f and stop loss at %f points is %f",
symbol, riskAmount, riskPoints, riskLots);
}
//+------------------------------------------------------------------+
+255
View File
@@ -0,0 +1,255 @@
//+------------------------------------------------------------------+
//| LowFractal.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class LowFractal
{
private:
private:
double lowPrice ;
int leftPeriod;
int rightPeriod;
MqlDateTime dateStruct ;
datetime date ;
double buyLimitPrice; // the fib level price , based on this fractal
double highestPeak ; // the highest price reached, after the fractal was formed
int hour ;
int minute;
int distance ; // holds the number of candles from this fractal until the current live candle
string arrowObjName ;
double fibPrice ;
public:
LowFractal();
LowFractal(double _price, int _leftPeriod, int _rightPeriod, datetime _date,ENUM_TIMEFRAMES _tf);
~LowFractal();
// GETTERS
double getPrice();
int getLeftPeriod();
int getRightPeriod();
int getHour();
int getMinute();
double getHighestPeak();
int getDistance();
string getArrowObjName();
datetime getDate();
// SETTERS
void setPrice(double _price);
void setLeftPeriod(int _leftPeriod);
void setRightPeriod(int _rightPeriod);
void setHour(int _hour);
void setMinute(int _minute);
void setHighestPeak(double _highest);
void setArrowObjName(string _name);
void setDistance(int _dist);
void setDate(datetime _givenDate);
// OTHER FUNCTIONS
double calculateFibPrice(double _fibLevel, double _lowPrice, double _highPrice); // calculate the fibonacci price based on the given level, and saves the price in the fibPrice88 variable in the object
void updateDistance();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractal::LowFractal()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractal::LowFractal(double _price, int _leftPeriod, int _rightPeriod,datetime _date, ENUM_TIMEFRAMES _tf)
{
// the constructor sets the data to the attribues , and calculates the real time of the fractal , because the given minute and hour
// are not the real time, they are the time of when the fractal was "known to be a fractal", which is after _righPeriod amount of candles
lowPrice = _price ;
leftPeriod = _leftPeriod;
rightPeriod = _rightPeriod;
buyLimitPrice = -1 ;
distance = _rightPeriod+1;
arrowObjName = " " ;
highestPeak = -1;
date = iTime(_Symbol,_tf,_rightPeriod+1); // bring the actual date of the fractal
TimeToStruct(date,dateStruct); // convert the actual date into a struct
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractal::~LowFractal()
{
}
//+------------------------------------------------------------------+
double LowFractal:: getPrice()
{
return lowPrice ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int LowFractal:: getLeftPeriod()
{
return leftPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int LowFractal:: getRightPeriod()
{
return rightPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int LowFractal:: getHour()
{
return dateStruct.hour ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int LowFractal:: getMinute()
{
return dateStruct.min ;
}
double LowFractal:: getHighestPeak(){
return highestPeak ;
}
int LowFractal:: getDistance(){
return distance ;
}
string LowFractal:: getArrowObjName(){
return arrowObjName ;
}
datetime LowFractal:: getDate(){
return date ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setPrice(double _price)
{
lowPrice = _price ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setLeftPeriod(int _leftPeriod)
{
leftPeriod = _leftPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setRightPeriod(int _rightPeriod)
{
rightPeriod = _rightPeriod ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setHour(int _hour)
{
hour = _hour ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void LowFractal:: setMinute(int _minute)
{
minute = _minute ;
}
//+------------------------------------------------------------------+
void LowFractal:: setArrowObjName(string _name){
arrowObjName = _name ;
}
void LowFractal:: setDistance(int _dist){
distance = _dist ;
}
double LowFractal:: calculateFibPrice(double _fibLevel, double _lowPrice, double _highPrice){
double difference = _highPrice - _lowPrice ;
double retracement = _fibLevel * difference ;
double _fibPrice = _highPrice - retracement ;
fibPrice = _fibPrice ;
return fibPrice;
}
void LowFractal:: setHighestPeak(double _highest){
highestPeak = _highest ;
}
void LowFractal:: setDate(datetime _givenDate){
date = _givenDate;
TimeToStruct(date,dateStruct); // convert the actual date into a struct
}
void LowFractal:: updateDistance(){
distance++ ;
}
+137
View File
@@ -0,0 +1,137 @@
//+------------------------------------------------------------------+
//| LowFractalContainer.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "LowFractal.mqh"
#include <library_functions.mqh>
#define SIZE 700
double input arrowDistanceLows ;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class LowFractalContainer
{
private:
LowFractal* lowFractals[SIZE];
int freeIndex ;
double range ;
ENUM_TIMEFRAMES timeFrame ;
public:
LowFractalContainer(ENUM_TIMEFRAMES _timeFrame);
~LowFractalContainer();
//GETTERS
LowFractal* getLowFractal(int _index) {return lowFractals[_index] ;} // returns the fractal using its index in the array
int getFreeIndex() {return freeIndex ; }
//SETTERS
void setRange(double _range) {range = _range ;}
// OTHER FUNCTIONS
void addLowFractal(LowFractal* _lowFractal); // adds low fractal to the low fractals array
void printLowFractals(); // prints all low fractals data
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractalContainer::LowFractalContainer(ENUM_TIMEFRAMES _timeFrame)
{
timeFrame = _timeFrame ;
freeIndex = 0 ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
LowFractalContainer::~LowFractalContainer()
{
for(int i=0; i<SIZE; i++) // free the lowFractals array
{
delete lowFractals[i] ;
}
}
//+------------------------------------------------------------------+
void LowFractalContainer:: addLowFractal(LowFractal* _lowFractal){
if(freeIndex == SIZE) // in this case we are adding a new fractal but the array is full so we need to do the following
{
ObjectDelete(_Symbol,lowFractals[0].getArrowObjName()); // delete the object arrow of the deleted fractal
ObjectCreate(_Symbol,_lowFractal.getArrowObjName(),OBJ_ARROW_UP,0,iTime(Symbol(),timeFrame,_lowFractal.getDistance()),iLow(Symbol(),timeFrame,_lowFractal.getDistance()) - arrowDistanceLows); // create the new object arrow of the new fractal
ObjectSetInteger(0,_lowFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
delete lowFractals[0]; // free the memory allocated for the fractal in the first index (because we wanna remove it from the array)
for(int i=0; i< SIZE-1 ; i++) // shift the array
{
lowFractals[i] = lowFractals[i+1];
}
lowFractals[freeIndex - 1] = _lowFractal ;
}
else
{
if(freeIndex == 0) // case of the first fractal
{
lowFractals[freeIndex] = _lowFractal ;
freeIndex++;
ObjectCreate(_Symbol,_lowFractal.getArrowObjName(),OBJ_ARROW_UP,0,iTime(Symbol(),timeFrame,_lowFractal.getDistance()),iLow(Symbol(),timeFrame,_lowFractal.getDistance()) - arrowDistanceLows);
ObjectSetInteger(0,_lowFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
}
else
{
lowFractals[freeIndex] = _lowFractal ;
freeIndex++;
ObjectCreate(_Symbol,_lowFractal.getArrowObjName(),OBJ_ARROW_UP,0,iTime(Symbol(),timeFrame,_lowFractal.getDistance()),iLow(Symbol(),timeFrame,_lowFractal.getDistance()) - arrowDistanceLows);
ObjectSetInteger(0,_lowFractal.getArrowObjName(),OBJPROP_COLOR,clrWhite);
}
}
}
void LowFractalContainer:: printLowFractals()
{
if(freeIndex > 0)
{
for(int i=0 ; i<freeIndex ; i++)
{
Print(" Fractal " + i + " Time: ", lowFractals[i].getHour() + ":" + lowFractals[i].getMinute()+ " Price: "
+ lowFractals[i].getPrice() + " Distance: " + lowFractals[i].getDistance() );
}
}
}
+299
View File
@@ -0,0 +1,299 @@
//+------------------------------------------------------------------+
//| MarketObserver.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include "Zone.mqh"
#include "ZoneContainer.mqh"
#include "LowFractal.mqh"
#include "HighFractal.mqh"
#include "LowFractalContainer.mqh"
#include "HighFractalContainer.mqh"
// ALGORITHM CLASSES INCLUDES
#include "NewCandleDetector.mqh"
// LIVE FORMING FRACTALS HANDLER CLASS
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class MarketObserver
{
// THIS CLASS HAS ACCESS TO ZONE CONTAINER, HOWEVER IT MUST NOT CHANGE IT IT ONLY READS FROM THE ZONECONTAINER CLASS
private:
/*NewCandleDetector* newCandleDetector_H4;
NewCandleDetector* newCandleDetector_H1 ;
NewCandleDetector* newCandleDetector_M30;
NewCandleDetector* newCandleDetector_M1 ;*/
ZoneContainer* zoneContainer ; // must not be changed from this class
bool closestResistanceWaiting ;
bool closestSupportWaiting ;
public:
MarketObserver(ZoneContainer* _zoneContainer);
~MarketObserver();
string zoneReached();
Zone* getClosestResistanceZone() {return zoneContainer.getHigherPivotIndexZone();}
Zone* getClosestSupportZone() {return zoneContainer.getLowerPivotIndexZone();}
bool reachedClosestSupportZone();
bool reachedClosestResistanceZone();
bool bearishCandleClosedInsideClosestSupportZone(ENUM_TIMEFRAMES tf);
bool bullishCandleClosedInsideClosestResistanceZone(ENUM_TIMEFRAMES tf);
bool candleClosedBelowClosestSupportZone(ENUM_TIMEFRAMES tf);
bool candleClosedAboveClosestResistanceZone(ENUM_TIMEFRAMES tf);
bool candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf); // the index is a specific zone from the zones container
bool candleClosedBelowSupportByIndex(int _index,ENUM_TIMEFRAMES tf); // the index is a specific zone from the zones container
bool isClosestResistanceWaiting() {return closestResistanceWaiting;}
bool isClosestSupportWaiting() {return closestSupportWaiting;}
void setClosestResistanceWaiting(bool _state) {closestResistanceWaiting = _state ;}
void setClosestSupportWaiting(bool _state) {closestSupportWaiting = _state ;}
string giveMarketReport();
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MarketObserver::MarketObserver(ZoneContainer* _zoneContainer)
{
/*newCandleDetector_H4 = new NewCandleDetector("PERIOD_H4") ;
newCandleDetector_H1 = new NewCandleDetector("PERIOD_H1");
newCandleDetector_M30 = new NewCandleDetector("PERIOD_M30");
newCandleDetector_M1 = new NewCandleDetector("PERIOD_M1");*/
zoneContainer = _zoneContainer ;
closestResistanceWaiting = false ;
closestSupportWaiting = false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MarketObserver::~MarketObserver()
{
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string MarketObserver:: zoneReached()
{
int currentResistanceZoneIndex = zoneContainer.getHighZonePivot();
int currentSupportZoneIndex = zoneContainer.getLowZonePivot();
if(currentResistanceZoneIndex != -1 && currentSupportZoneIndex != -1)
{
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) >= zoneContainer.getZoneByIndex(currentResistanceZoneIndex).getLowerEdge())
{
Print("Reached the current resistance zone !");
return "TYPE_RESISTANCE" ;
}
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= zoneContainer.getZoneByIndex(currentSupportZoneIndex).getHigherEdge())
{
Print("Reached the current support zone !");
return "TYPE_SUPPORT" ;
}
}
return "" ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: reachedClosestSupportZone()
{
int currentSupportZoneIndex = zoneContainer.getLowZonePivot();
if(currentSupportZoneIndex != -1)
{
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) <= zoneContainer.getZoneByIndex(currentSupportZoneIndex).getHigherEdge())
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: reachedClosestResistanceZone()
{
int currentResistanceZoneIndex = zoneContainer.getHighZonePivot();
if(currentResistanceZoneIndex != -1)
{
if(SymbolInfoDouble(_Symbol, SYMBOL_ASK) >= zoneContainer.getZoneByIndex(currentResistanceZoneIndex).getLowerEdge())
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: bullishCandleClosedInsideClosestResistanceZone(ENUM_TIMEFRAMES tf)
{
double previousCandleClose = iClose(_Symbol,tf,1);
double previousCandleOpen = iOpen(_Symbol,tf,1);
if(zoneContainer.getHighZonePivot() != -1) // means if there is a pivot zone
{
if((previousCandleClose > previousCandleOpen) && (previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getLowerEdge()) && (previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getHigherEdge())) // means if previous the candle is bullish and closed inside the resistance zone
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: bearishCandleClosedInsideClosestSupportZone(ENUM_TIMEFRAMES tf)
{
double previousCandleClose = iClose(_Symbol,tf,1);
double previousCandleOpen = iOpen(_Symbol,tf,1);
if(zoneContainer.getLowZonePivot() != -1)
{
if((previousCandleClose < previousCandleOpen) && (previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getHigherEdge()) && (previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getLowerEdge())) // means if previous the candle is breaish and closed inside the support zone
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string MarketObserver:: giveMarketReport()
{
return " " ;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: candleClosedBelowClosestSupportZone(ENUM_TIMEFRAMES tf)
{
double previousCandleClose = iClose(_Symbol,tf,1);
double previousCandleOpen = iOpen(_Symbol,tf,1);
if(zoneContainer.getLowZonePivot() != -1)
{
if((previousCandleClose < zoneContainer.getZoneByIndex(zoneContainer.getLowZonePivot()).getLowerEdge())) // means if the previous candle closed below the support zone
{
return true ;
}
}
return false ;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserver:: candleClosedAboveClosestResistanceZone(ENUM_TIMEFRAMES tf)
{
double previousCandleClose = iClose(_Symbol,tf,1);
double previousCandleOpen = iOpen(_Symbol,tf,1);
if(zoneContainer.getHighZonePivot() != -1) // means if there is a pivot zone
{
if((previousCandleClose > zoneContainer.getZoneByIndex(zoneContainer.getHighZonePivot()).getHigherEdge())) // means if previous the candle closed above the resistance zone
{
return true ;
}
}
return false ;
}
bool MarketObserver:: candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf){
double previousCandleClose = iClose(_Symbol,tf,1);
if((previousCandleClose > zoneContainer.getZoneByIndex(_index).getHigherEdge())){
return true ;
}
return false ;
}
//+------------------------------------------------------------------+
+105
View File
@@ -0,0 +1,105 @@
//+------------------------------------------------------------------+
//| MarketObserverTiger.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
//+------------------------------------------------------------------+
//| defines |
//+------------------------------------------------------------------+
// #define MacrosHello "Hello, world!"
// #define MacrosYear 2010
//+------------------------------------------------------------------+
//| DLL imports |
//+------------------------------------------------------------------+
// #import "user32.dll"
// int SendMessageA(int hWnd,int Msg,int wParam,int lParam);
// #import "my_expert.dll"
// int ExpertRecalculate(int wParam,int lParam);
// #import
//+------------------------------------------------------------------+
//| EX5 imports |
//+------------------------------------------------------------------+
// #import "stdlib.ex5"
// string ErrorDescription(int error_code);
// #import
//+------------------------------------------------------------------+
#include "Zone.mqh"
#include "ZoneContainer.mqh"
// ALGORITHM CLASSES INCLUDES
#include "NewCandleDetector.mqh"
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class MarketObserverTiger
{
// THIS CLASS HAS ACCESS TO ZONE CONTAINER, HOWEVER IT MUST NOT CHANGE IT IT ONLY READS FROM THE ZONECONTAINER CLASS
private:
public:
MarketObserverTiger();
~MarketObserverTiger();
string zoneReached();
bool candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& resistanceZoneContainer); // the index is a specific zone from the zones container
bool candleClosedBelowSupportByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& supportZoneContainer); // the index is a specific zone from the zones container
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MarketObserverTiger::MarketObserverTiger()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
MarketObserverTiger::~MarketObserverTiger()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool MarketObserverTiger:: candleClosedAboveResistanceByIndex(int _index,ENUM_TIMEFRAMES tf,ZoneContainer& resistanceZoneContainer)
{
double previousCandleClose = iClose(_Symbol,tf,1);
if((previousCandleClose > resistanceZoneContainer.getZoneByIndex(_index).getHigherEdge()))
{
return true ;
}
return false ;
}
bool MarketObserverTiger:: candleClosedBelowSupportByIndex(int _index, ENUM_TIMEFRAMES tf, ZoneContainer& supportZoneContainer){
double previousCandleClose = iClose(_Symbol,tf,1);
if(previousCandleClose < supportZoneContainer.getZoneByIndex(_index).getLowerEdge()){
return true ;
}
return false ;
}
+378
View File
@@ -0,0 +1,378 @@
//+------------------------------------------------------------------+
//| NewCandleDetector.mqh |
//| Copyright 2023, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
class NewCandleDetector
{
private:
string timeFrame ;
datetime beginDate ; // this datetime gets initialized only after the first call of the isNewCandle() function
MqlDateTime currTimeStruct;
MqlDateTime beginDateStruct;
bool firstCallHappened;
public:
NewCandleDetector(string _timeFrame);
~NewCandleDetector();
// GETTERS
datetime getBeginDate() {return beginDate;}
void setTimeFrame(string _timeFrame) {timeFrame = _timeFrame;}
bool isNewCandle();
};
//+------------------------------------------------------------------+
NewCandleDetector::NewCandleDetector(string _timeFrame)
{
timeFrame = _timeFrame ;
firstCallHappened = false;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
NewCandleDetector::~NewCandleDetector()
{
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool NewCandleDetector:: isNewCandle()
{
if(timeFrame == "PERIOD_M1")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_M1,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_M1,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.min == currTimeStruct.min)
{
return false;
}
else
{
//Print("in a new candle !, asset: " + _Symbol);
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_M2")
{
}
else
if(timeFrame == "PERIOD_M3")
{
}
else
if(timeFrame == "PERIOD_M4")
{
}
else
if(timeFrame == "PERIOD_M5")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_M5,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_M5,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.min == currTimeStruct.min)
{
return false;
}
else
{
Print("in a new candle !, asset: " + _Symbol);
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_M6")
{
}
else
if(timeFrame == "PERIOD_M10")
{
}
else
if(timeFrame == "PERIOD_M12")
{
}
else
if(timeFrame == "PERIOD_M15")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_M15,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_M15,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.min == currTimeStruct.min)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_M20")
{
}
else
if(timeFrame == "PERIOD_M30")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_M30,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_M30,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.min == currTimeStruct.min)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_H1")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_H1,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_H1,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.hour == currTimeStruct.hour)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_H2")
{
}
else
if(timeFrame == "PERIOD_H3")
{
}
else
if(timeFrame == "PERIOD_H4")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_H4,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_H4,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.hour == currTimeStruct.hour)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_H6")
{
}
else
if(timeFrame == "PERIOD_H8")
{
}
else
if(timeFrame == "PERIOD_H12")
{
}
else
if(timeFrame == "PERIOD_D1")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_D1,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_D1,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.day == currTimeStruct.day)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_W1")
{
if(firstCallHappened == false)
{
beginDate = iTime(_Symbol,PERIOD_W1,0);
firstCallHappened = true;
}
if(firstCallHappened == true)
{
datetime currTime = iTime(_Symbol,PERIOD_W1,0);
TimeToStruct(beginDate,beginDateStruct);
TimeToStruct(currTime,currTimeStruct);
if(beginDateStruct.day == currTimeStruct.day)
{
return false;
}
else
{
beginDate = currTime;
return true ;
}
}
}
else
if(timeFrame == "PERIOD_MN1")
{
}
return true;
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
Binary file not shown.
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More