//+------------------------------------------------------------------+ //| CalculateBreakeven.mqh | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2024, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" #include #include "BreakEvenResult.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CalculateBreakeven { private: int Total_Buy_Trades; double Total_Buy_Size; double Total_Buy_Price; double Buy_Profit; //--- int Total_Sell_Trades; double Total_Sell_Size; double Total_Sell_Price; double Sell_Profit; int PipAdjust,NrOfDigits; double point; public: CalculateBreakeven(); ~CalculateBreakeven(); BreakEvenHedgeTicketsResult GetHedge(double lotsize,long magicnumber); BreakEvenResult GetBreakEven(const BreakEvenInput &breakEvenInput); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CalculateBreakeven::CalculateBreakeven() { if(NrOfDigits==5 || NrOfDigits==3) PipAdjust=10; else if(NrOfDigits==4 || NrOfDigits==2) PipAdjust=1; //--- point=Point()*PipAdjust; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CalculateBreakeven::~CalculateBreakeven() { } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ BreakEvenHedgeTicketsResult CalculateBreakeven::GetHedge(double lotsize,long magicnumber) { CPositionInfo m_position; BreakEvenHedgeTicketsResult result; int total=PositionsTotal(); if(magicnumber==0) return result; //--- datetime oldestbuy=TimeCurrent(); datetime oldestsell=TimeCurrent(); double oldestbuylotsize=0; double oldestsellLotsize=0; ulong oldestBuyTicket=0; ulong oldestSellTicket=0; double lotSizeFilledBuy=0; double lotSizeFilledSell=0; lotsize=NormalizeDouble(lotsize,2); for(int i=0;i(lotsize-lotSizeFilledBuy) && ((lotsize-lotSizeFilledBuy)>0)) { result.lotsizes.Add(lotsize-lotSizeFilledBuy); result.ticketnumbers.Add(m_position.Ticket()); result.Buy.Add(1); lotSizeFilledBuy=lotsize; } } } if(m_position.PositionType()==POSITION_TYPE_SELL && m_position.Symbol()==Symbol() && magicnumber!=m_position.Magic()) { if(lotSizeFilledSell(lotsize-lotSizeFilledSell) && ((lotsize-lotSizeFilledSell)>0)) { result.lotsizes.Add(lotsize-lotSizeFilledSell); result.ticketnumbers.Add(m_position.Ticket()); result.Buy.Add(0); lotSizeFilledSell=lotsize; } } } } return result; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ BreakEvenResult CalculateBreakeven::GetBreakEven(const BreakEvenInput &breakEvenInput) { Total_Buy_Trades=0; Total_Buy_Size=0; Total_Buy_Price=0; Buy_Profit=0; //--- Total_Sell_Trades=0; Total_Sell_Size=0; Total_Sell_Price=0; Sell_Profit=0; BreakEvenResult result; BreakEvenHedgeTicketsResult hedges=GetHedge(breakEvenInput.HedgeToBreakDownLots,breakEvenInput.MagicNumber); CPositionInfo m_position; double Pip_Value=SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE)*PipAdjust; double Pip_Size=SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE)*PipAdjust; //--- int total=PositionsTotal(); //--- for(int i=0;i-1) { double portionvolume=hedges.lotsizes.At(index); Total_Buy_Trades++; Total_Buy_Price+=m_position.PriceOpen()*portionvolume; Total_Buy_Size += portionvolume; Buy_Profit+=(m_position.Profit()*portionvolume)/m_position.Volume()+(m_position.Swap()*portionvolume)/m_position.Volume()+(m_position.Commission()*portionvolume)/m_position.Volume(); result.TicketsToClose.Add(m_position.Ticket()); result.TicketsLotSizeToClose.Add(portionvolume); } } if(m_position.PositionType()==POSITION_TYPE_SELL && m_position.Symbol()==Symbol() && breakEvenInput.Sells==true && ((breakEvenInput.MagicNumber==0)||(m_position.Magic()==breakEvenInput.MagicNumber))) { Total_Sell_Trades++; Total_Sell_Size+=m_position.Volume(); Total_Sell_Price+=m_position.PriceOpen()*m_position.Volume(); Sell_Profit+=m_position.Profit()+m_position.Swap()+m_position.Commission(); result.TicketsToClose.Add(m_position.Ticket()); result.TicketsLotSizeToClose.Add(m_position.Volume()); } if(m_position.PositionType()==POSITION_TYPE_SELL && m_position.Symbol()==Symbol() && breakEvenInput.Sells==true && ((breakEvenInput.MagicNumber!=0)&&(m_position.Magic()!=breakEvenInput.MagicNumber))) { long temptic=m_position.Ticket(); int index=-1; for(int y=0;y-1) { double portionvolume=hedges.lotsizes.At(index); Total_Sell_Trades++; Total_Sell_Size+=portionvolume; Total_Sell_Price+=m_position.PriceOpen()*portionvolume; Sell_Profit+=(m_position.Profit()*portionvolume)/m_position.Volume()+(m_position.Swap()*portionvolume)/m_position.Volume()+(m_position.Commission()*portionvolume)/m_position.Volume(); result.TicketsToClose.Add(m_position.Ticket()); result.TicketsLotSizeToClose.Add(portionvolume); } } } } if(Total_Buy_Price>0) { Total_Buy_Price/=Total_Buy_Size; } if(Total_Sell_Price>0) { Total_Sell_Price/=Total_Sell_Size; } result.Net_Trades=Total_Buy_Trades+Total_Sell_Trades; result.Net_Lots=Total_Buy_Size-Total_Sell_Size; result.Net_Result=Buy_Profit+Sell_Profit; if(result.Net_Trades>0 && result.Net_Lots!=0) { result.distance=(((result.Net_Result-breakEvenInput.ProfitInMoney)/(MathAbs(result.Net_Lots*SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE))))*SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE)); if(result.Net_Lots>0) { result.Average_Price= SymbolInfoDouble(_Symbol, SYMBOL_BID)- result.distance; } if(result.Net_Lots<0) { result.Average_Price= SymbolInfoDouble(_Symbol, SYMBOL_ASK)+ result.distance; } } if(result.Net_Trades>0 && result.Net_Lots==0) { result.distance=(result.Net_Result/((SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE)))*SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE)); result.Average_Price=SymbolInfoDouble(_Symbol, SYMBOL_BID)-result.distance; } return(result); } //+------------------------------------------------------------------+