Files
2025-07-11 08:43:07 +03:00

588 lines
20 KiB
Plaintext

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