418 lines
15 KiB
MQL5
418 lines
15 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| PlaceOrders.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 <Trade\PositionInfo.mqh>
|
|
#include <Trade\Trade.mqh>
|
|
#include "..\\Includes\\CalculateBreakeven.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class OrderManager
|
|
{
|
|
private:
|
|
|
|
public:
|
|
|
|
int recoveryOrdersSell;
|
|
int recoveryOrdersBuy;
|
|
|
|
CPositionInfo m_position;
|
|
CTrade m_trade;
|
|
OrderManager();
|
|
~OrderManager();
|
|
void CloseTrades(long MagicNumber,bool buy,bool sell,double profit=0,double parttoclose=0);
|
|
void TrailTrades(long MagicNumber,bool buy,bool sell,double profit,double parttoclose, double iTrailingStart, double iTrailStep,double iTrailingStop);
|
|
int HedgePositions(long MagicNumber);
|
|
void FirstOrder(long Mymagic,double Volume);
|
|
bool PlaceOrder(ENUM_POSITION_TYPE TypeOrder, double Volume, int magic, string Comment);
|
|
double RelativeProfitOnMagic(long MyMagic,double lots,double min,double lotstobreakdown,datetime hedge,bool proces,bool forcerecover);
|
|
double RelativeProfitOnMagic2(long MyMagic,double lots,double min,double lotstobreakdown,datetime hedge,bool proces,bool forcerecover);
|
|
double TrallB ;
|
|
double LastOrderProfit();
|
|
long GetDirectionOfTheLastProfitTrade(int mtype, string symbol, int magicx);
|
|
void CloseAll();
|
|
int PositionTotalOnThis();
|
|
bool ToMuchMagic();
|
|
int GetHighestMagic();
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
OrderManager::OrderManager()
|
|
{
|
|
m_trade.SetTypeFillingBySymbol(m_position.Symbol());
|
|
TrallB = 0;
|
|
recoveryOrdersSell=0;
|
|
recoveryOrdersBuy=0;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
OrderManager::~OrderManager()
|
|
{
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OrderManager::FirstOrder(long Mymagic,double Volume)
|
|
{
|
|
MqlRates rates[];
|
|
CopyRates(Symbol(),PERIOD_M15,0,2,rates);
|
|
|
|
MqlTick tick;
|
|
if(!SymbolInfoTick(Symbol(),tick))
|
|
Print("SymbolInfoTick() failed, error = ",GetLastError());
|
|
|
|
|
|
if(GetDirectionOfTheLastProfitTrade(-99, _Symbol, -1)== DEAL_TYPE_BUY)
|
|
{
|
|
if(!PlaceOrder(POSITION_TYPE_SELL,Volume,Mymagic,NULL))
|
|
printf("error");
|
|
|
|
}
|
|
else
|
|
{
|
|
if(!PlaceOrder(POSITION_TYPE_BUY,Volume,Mymagic,NULL))
|
|
printf("error");
|
|
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
long OrderManager::GetDirectionOfTheLastProfitTrade(int mtype, string symbol, int magicx)
|
|
{
|
|
|
|
|
|
|
|
ulong ticket=0;
|
|
int cta=0;
|
|
HistorySelect(0,TimeCurrent());
|
|
for(int i=HistoryOrdersTotal(); i>=0; i--)
|
|
{
|
|
if((ticket=HistoryDealGetTicket(i))>0)
|
|
{
|
|
if(HistoryDealGetInteger(ticket,DEAL_ENTRY) == DEAL_ENTRY_OUT)
|
|
{
|
|
string s= HistoryDealGetString(ticket,DEAL_SYMBOL);
|
|
if(s==symbol || symbol=="ALL")
|
|
{
|
|
long type =HistoryDealGetInteger(ticket,DEAL_TYPE);
|
|
if(type==mtype || mtype==-99)
|
|
{
|
|
long m =HistoryDealGetInteger(ticket, DEAL_MAGIC);
|
|
if(m==magicx || magicx==-1)
|
|
{
|
|
double profit=HistoryDealGetDouble(ticket, DEAL_PROFIT);
|
|
if(profit>0)
|
|
return type;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double OrderManager::LastOrderProfit()
|
|
{
|
|
int totalPositions = PositionsTotal();
|
|
double lastPositionProfit = 0.0;
|
|
|
|
for (int i = totalPositions - 1; i >= 0; i--) {
|
|
ulong ticket = PositionGetTicket(i);
|
|
if (PositionSelectByTicket(ticket)) {
|
|
if (PositionGetString(POSITION_SYMBOL) == _Symbol) {
|
|
lastPositionProfit = PositionGetDouble(POSITION_PROFIT);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return lastPositionProfit;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
double OrderManager::RelativeProfitOnMagic(long MyMagic,double lots,double min,double lotstobreakdown,datetime hedge,bool proces,bool forcerecover)
|
|
{
|
|
MqlDateTime rightNow;
|
|
TimeCurrent(rightNow);
|
|
CalculateBreakeven breakEven;
|
|
m_trade.SetMarginMode();
|
|
BreakEvenInput breakEvenInput;
|
|
breakEvenInput.Buys=true;
|
|
breakEvenInput.Sells=true;
|
|
|
|
breakEvenInput.MagicNumber=MyMagic;
|
|
breakEvenInput.ProfitInMoney=0;
|
|
breakEvenInput.HedgeToBreakDownLots=lotstobreakdown;
|
|
BreakEvenResult breakevenResult=breakEven.GetBreakEven(breakEvenInput);
|
|
//
|
|
if((NormalizeDouble(breakevenResult.Net_Lots,2)==0) && proces && breakevenResult.Net_Trades>0 )
|
|
{
|
|
FirstOrder(MyMagic, lots);
|
|
FirstOrder(MyMagic, lots);
|
|
FirstOrder(MyMagic, lots);
|
|
FirstOrder(MyMagic, lots);
|
|
recoveryOrdersBuy=0;
|
|
recoveryOrdersSell=0;
|
|
}
|
|
|
|
//&&(hedge+=0* PeriodSeconds(PERIOD_H1))<TimeCurrent()
|
|
double relativ= (breakevenResult.Net_Result*MathAbs(lots/(breakevenResult.Net_Lots==0?lots:breakevenResult.Net_Lots)));
|
|
if((LastOrderProfit()<min) && breakevenResult.Net_Lots>0 )
|
|
{
|
|
if(recoveryOrdersBuy<(MyMagic>1?2:3))
|
|
{
|
|
PlaceOrder(POSITION_TYPE_BUY,lots,MyMagic,MyMagic);
|
|
recoveryOrdersBuy=recoveryOrdersBuy+1;
|
|
recoveryOrdersSell=0;
|
|
}
|
|
}
|
|
if((LastOrderProfit()<min) && breakevenResult.Net_Lots<0 )
|
|
{
|
|
if(recoveryOrdersSell<(MyMagic>1?2:3))
|
|
{
|
|
PlaceOrder(POSITION_TYPE_SELL,lots,MyMagic,MyMagic);
|
|
recoveryOrdersBuy=0;
|
|
recoveryOrdersSell=recoveryOrdersSell+1;
|
|
}
|
|
}
|
|
|
|
return breakevenResult.Net_Result;
|
|
}
|
|
|
|
double OrderManager::RelativeProfitOnMagic2(long MyMagic,double lots,double min,double lotstobreakdown,datetime hedge,bool proces,bool forcerecover)
|
|
|
|
{
|
|
MqlDateTime rightNow;
|
|
TimeCurrent(rightNow);
|
|
CalculateBreakeven breakEven;
|
|
m_trade.SetMarginMode();
|
|
BreakEvenInput breakEvenInput;
|
|
breakEvenInput.Buys=true;
|
|
breakEvenInput.Sells=true;
|
|
|
|
breakEvenInput.MagicNumber=MyMagic;
|
|
breakEvenInput.ProfitInMoney=0;
|
|
breakEvenInput.HedgeToBreakDownLots=lotstobreakdown;
|
|
BreakEvenResult breakevenResult=breakEven.GetBreakEven(breakEvenInput);
|
|
//
|
|
// if(((NormalizeDouble(breakevenResult.Net_Lots,2)==0)&&(hedge+=0* PeriodSeconds(PERIOD_H1))<TimeCurrent() && proces && breakevenResult.Net_Trades>0 && rightNow.hour>10)||forcerecover)
|
|
// FirstOrder(MyMagic, lots);
|
|
/*
|
|
double relativ= (breakevenResult.Net_Result*MathAbs(lots/(breakevenResult.Net_Lots==0?lots:breakevenResult.Net_Lots)));
|
|
if((LastOrderProfit()<min) && breakevenResult.Net_Lots>0 && proces){
|
|
if (recoveryOrdersBuy<4){
|
|
PlaceOrder(POSITION_TYPE_BUY,lots,MyMagic,NULL);
|
|
recoveryOrdersBuy=recoveryOrdersBuy+1;
|
|
recoveryOrdersSell=0;}
|
|
}
|
|
if((LastOrderProfit()<min) && breakevenResult.Net_Lots<0 && proces){
|
|
if (recoveryOrdersSell<4){
|
|
PlaceOrder(POSITION_TYPE_SELL,lots,MyMagic,NULL);
|
|
recoveryOrdersBuy=0;
|
|
recoveryOrdersSell=recoveryOrdersSell+1;
|
|
}}
|
|
*/
|
|
return breakevenResult.Net_Result;
|
|
}
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool OrderManager::PlaceOrder(ENUM_POSITION_TYPE TypeOrder, double Volume, int magic, string Comment)
|
|
{
|
|
m_trade.SetExpertMagicNumber(magic);
|
|
|
|
if(TypeOrder == POSITION_TYPE_BUY)
|
|
{
|
|
if(!m_trade.Buy(Volume,Symbol(),0,0,0,Comment))
|
|
return(false);
|
|
}
|
|
|
|
if(TypeOrder == POSITION_TYPE_SELL)
|
|
{
|
|
if(!m_trade.Sell(Volume,Symbol(),0,0,0,Comment))
|
|
return(false);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OrderManager::CloseAll()
|
|
{
|
|
for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions
|
|
if(m_position.SelectByIndex(i))
|
|
{
|
|
m_trade.PositionClose(m_position.Ticket());
|
|
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int OrderManager::PositionTotalOnThis()
|
|
{
|
|
int total=0;
|
|
for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions
|
|
if(m_position.SelectByIndex(i))
|
|
{
|
|
if(m_position.Symbol()==_Symbol)
|
|
total=total+1;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
bool OrderManager::ToMuchMagic()
|
|
{
|
|
MqlDateTime SDateTime;
|
|
TimeToStruct(TimeCurrent(),SDateTime);
|
|
|
|
SDateTime.hour=0;
|
|
SDateTime.min=0;
|
|
SDateTime.sec=0;
|
|
datetime from_date=StructToTime(SDateTime); // From date
|
|
|
|
SDateTime.hour=10;
|
|
SDateTime.min=59;
|
|
SDateTime.sec=59;
|
|
datetime to_date=StructToTime(SDateTime); // To date
|
|
to_date-=60*60*24;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
int OrderManager::GetHighestMagic()
|
|
{
|
|
int magic=1;
|
|
for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions
|
|
if(m_position.SelectByIndex(i))
|
|
{
|
|
if(m_position.Symbol()==_Symbol)
|
|
if (m_position.Magic()>magic)
|
|
magic=m_position.Magic();
|
|
|
|
}
|
|
return magic;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OrderManager::CloseTrades(long MagicNumber,bool buy,bool sell,double profit=0,double parttoclose=0)
|
|
{
|
|
|
|
CalculateBreakeven breakEven;
|
|
m_trade.SetMarginMode();
|
|
BreakEvenInput breakEvenInput;
|
|
breakEvenInput.Buys=true;
|
|
breakEvenInput.Sells=true;
|
|
|
|
breakEvenInput.MagicNumber=MagicNumber;
|
|
breakEvenInput.ProfitInMoney=profit;
|
|
breakEvenInput.HedgeToBreakDownLots=parttoclose;
|
|
BreakEvenResult breakevenResult=breakEven.GetBreakEven(breakEvenInput);
|
|
if((breakevenResult.Net_Lots>0 && SymbolInfoDouble(_Symbol, SYMBOL_BID)>=breakevenResult.Average_Price) || (breakevenResult.Net_Lots<0 && SymbolInfoDouble(_Symbol, SYMBOL_ASK)<=breakevenResult.Average_Price)|| profit==0 || MagicNumber==0)
|
|
for(int i=breakevenResult.TicketsToClose.Total()-1; i>=0; i--) // returns the number of current positions
|
|
if(m_position.SelectByTicket(breakevenResult.TicketsToClose.At(i))) // selects the position by index for further access to its properties
|
|
{
|
|
if(breakevenResult.TicketsLotSizeToClose.At(i)==0)
|
|
printf("error zero volume");
|
|
m_trade.PositionClosePartial(m_position.Ticket(),breakevenResult.TicketsLotSizeToClose.At(i));
|
|
recoveryOrdersSell=0;
|
|
recoveryOrdersBuy=0;
|
|
|
|
}
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void OrderManager::TrailTrades(long MagicNumber,bool buy,bool sell,double profit,double parttoclose, double iTrailingStart, double iTrailStep,double iTrailingStop)
|
|
{
|
|
|
|
CalculateBreakeven breakEven;
|
|
m_trade.SetMarginMode();
|
|
BreakEvenInput breakEvenInput;
|
|
breakEvenInput.Buys=true;
|
|
breakEvenInput.Sells=true;
|
|
|
|
breakEvenInput.MagicNumber=MagicNumber;
|
|
breakEvenInput.ProfitInMoney=profit;
|
|
breakEvenInput.HedgeToBreakDownLots=parttoclose;
|
|
BreakEvenResult breakevenResult=breakEven.GetBreakEven(breakEvenInput);
|
|
double p = breakevenResult.Net_Result;
|
|
if(breakevenResult.TicketsToClose.Total()==0)
|
|
TrallB=0;
|
|
double SL=breakevenResult.Net_Result-iTrailingStop;
|
|
|
|
if(breakevenResult.Net_Result>=iTrailingStart && (TrallB==0 || TrallB+iTrailStep<SL))
|
|
TrallB=SL;
|
|
if((breakevenResult.Net_Result<=TrallB) && (TrallB>0))
|
|
|
|
|
|
for(int i=breakevenResult.TicketsToClose.Total()-1; i>=0; i--)
|
|
if(m_position.SelectByTicket(breakevenResult.TicketsToClose.At(i)))
|
|
{
|
|
{
|
|
m_trade.PositionClosePartial(m_position.Ticket(),breakevenResult.TicketsLotSizeToClose.At(i));
|
|
recoveryOrdersSell=0;
|
|
recoveryOrdersBuy=0;
|
|
}
|
|
TrallB=0;
|
|
|
|
}
|
|
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
int OrderManager::HedgePositions(long MagicNumber)
|
|
{
|
|
CalculateBreakeven breakEven;
|
|
m_trade.SetMarginMode();
|
|
BreakEvenInput breakEvenInput;
|
|
breakEvenInput.Buys=true;
|
|
breakEvenInput.Sells=true;
|
|
BreakEvenResult breakevenResult=breakEven.GetBreakEven(breakEvenInput);
|
|
if(breakevenResult.Net_Lots<0)
|
|
{
|
|
PlaceOrder(POSITION_TYPE_BUY,NormalizeDouble(MathAbs(breakevenResult.Net_Lots),2),MagicNumber,"HEDGE");
|
|
return 1;
|
|
}
|
|
if(breakevenResult.Net_Lots>0)
|
|
{
|
|
PlaceOrder(POSITION_TYPE_SELL,NormalizeDouble(breakevenResult.Net_Lots,2),MagicNumber,"HEDGE");
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
|
|
//+------------------------------------------------------------------+
|