MQLArticles/RM/RM_Hooks.mqh

705 lines
51 KiB
MQL5

2025-12-21 12:44:08 -05:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Modificators.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372/news |
//+------------------------------------------------------------------+
2025-12-21 12:46:48 -05:00
#property copyright "Copyright 2025, Niquel Mendoza."
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
#property link "https://www.mql5.com/es/users/nique_372/news"
#property strict
2026-01-28 12:21:11 -05:00
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
#ifndef MQLARTICLES_RM_HOOKS_MQH
2025-12-21 12:44:08 -05:00
#define MQLARTICLES_RM_HOOKS_MQH
2026-03-05 12:10:29 -05:00
//+------------------------------------------------------------------+
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
//| |
//+------------------------------------------------------------------+
#include "LossProfit\\Manager.mqh"
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
//---
2025-12-21 12:44:08 -05:00
#define RISK_MANAGEMENT_EVENT_ON_OPEN_POSITION (1)
2026-03-05 12:10:29 -05:00
#define RISK_MANAGEMENT_EVENT_ON_CLOSE_POSITION (2)
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
//+------------------------------------------------------------------+
2026-03-05 12:10:29 -05:00
//| |
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
//+------------------------------------------------------------------+
2025-12-21 12:44:08 -05:00
class IRiskManagementHook : public CAllClassEventsBasic
2026-03-05 12:10:29 -05:00
{
2025-12-21 12:44:08 -05:00
private:
const uint8_t m_events_flags;
protected:
2026-01-28 12:21:11 -05:00
const string m_hook_name;
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
public:
2025-12-21 12:44:08 -05:00
IRiskManagementHook(uint8_t f, const string& name) : m_events_flags(f), m_hook_name(name) {}
~IRiskManagementHook() {}
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
//--- Virtual functions
// Function that will be executed each time a position is closed
virtual void OnClosePosition(const ModifierOnOpenCloseStruct &on_open_close_struct) { }
// Function that will be executed each time an operation is opened
virtual void OnOpenPosition(const ModifierOnOpenCloseStruct &on_open_close_struct) { }
2026-01-28 12:21:11 -05:00
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
// Function that will be executed only once (at the moment of creating the m_modifier)
virtual void OnInitModifier(const ModfierInitInfo &on_init) { }
2026-01-28 12:21:11 -05:00
2025-12-21 12:44:08 -05:00
// Name
2026-01-28 12:21:11 -05:00
__forceinline string Name() const { return m_hook_name; }
2025-12-21 12:44:08 -05:00
//---
__forceinline uint8_t EventsFlags() const { return m_events_flags; }
};
//+--------------------------------------------------------------------+
//| Class to integrate external modifications to risk management |
//+--------------------------------------------------------------------+
class CExtraModifications : public IRiskManagementHook
{
protected:
const CLossProfit* m_modifier;
const int m_property_to_modify;
public:
2026-03-05 12:10:29 -05:00
// WRONG_VALUE si no se busca modificar nada,
CExtraModifications(int _property_to_modify, uint8_t flags_events, const string& name)
2025-12-21 12:44:08 -05:00
: IRiskManagementHook(flags_events, name), m_property_to_modify(_property_to_modify) { }
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
//--- Non-modifiable functions
// Function that returns the type of "maximum loss or profit" that this class is modifying
__forceinline int MaximumProfitOrLossAModify() const { return m_property_to_modify; };
// Function that will be used in CRiskManagement to assign the "maximum loss or profit" based on the type of "maximum loss or profit" chosen
// in the constructor.
void SetPointer(const CLossProfit* const _modifier);
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
};
//+------------------------------------------------------------------+
2026-03-05 12:10:29 -05:00
//| Set pointer |
2025-12-21 12:44:08 -05:00
//+------------------------------------------------------------------+
void CExtraModifications::SetPointer(const CLossProfit* const _modifier)
{
//---
if(!CheckPointer(_modifier))
{
LogFatalError(StringFormat("The pointer to CLossProfit* for m_modifier %s is invalid", m_hook_name), FUNCION_ACTUAL);
Remover();
return;
}
//---
if(_modifier.Type() != MaximumProfitOrLossAModify())
{
LogFatalError(StringFormat("The type of the maximum loss/gain = %d, is different from the property to be modified = %d",
_modifier.Type(), m_property_to_modify), FUNCION_ACTUAL);
Remover();
return;
}
//---
m_modifier = _modifier;
}
//+------------------------------------------------------------------+
//| Clase para aumentar el riesgo |
//+------------------------------------------------------------------+
2026-03-05 12:10:29 -05:00
enum ENUM_MULTIPLIER_METHOD_DR
2025-12-21 12:44:08 -05:00
{
2026-03-05 12:10:29 -05:00
DR_MULTIPLIER = 0, // Multiplier
2025-12-21 12:44:08 -05:00
DR_EXPONECIAL = 1, // Exponential
DR_SUMATORIO = 2 // Additive (Summation)
};
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
//--- Clase
class CDynamicRisk : public CExtraModifications
2026-03-05 12:10:29 -05:00
{
private:
double paso;
double val;
double percentage_a_empezar_modfiicacioneS;
2025-12-21 12:44:08 -05:00
ENUM_MULTIPLIER_METHOD_DR metod;
void Aumentar();
bool is_set;
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
public:
CDynamicRisk(double step, double percentage_to_empezar, ENUM_TYPE_LOSS_PROFIT property_to_modify, ENUM_MULTIPLIER_METHOD_DR multiplier_);
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
//---
void OnClosePosition(const ModifierOnOpenCloseStruct &on_open_close_struct) override final;
void OnInitModifier(const ModfierInitInfo &on_init) override final;
};
2026-03-05 12:10:29 -05:00
//+------------------------------------------------------------------+
2025-12-21 12:44:08 -05:00
CDynamicRisk::CDynamicRisk(double step, double percentage_to_empezar, ENUM_TYPE_LOSS_PROFIT property_to_modify, ENUM_MULTIPLIER_METHOD_DR multiplier_)
: CExtraModifications(property_to_modify, RISK_MANAGEMENT_EVENT_ON_CLOSE_POSITION, "Risk enhancer by default")
{
paso = step;
percentage_a_empezar_modfiicacioneS = percentage_to_empezar;
metod = multiplier_;
is_set = false;
if((int)metod > 2 || metod < 0)
{
LogFatalError(StringFormat("The method %s is invalid", EnumToString(metod)), FUNCION_ACTUAL);
Remover();
}
}
//+------------------------------------------------------------------+
void CDynamicRisk::OnInitModifier(const ModfierInitInfo & on_init)
{
percentage_a_empezar_modfiicacioneS /= 100.0;
percentage_a_empezar_modfiicacioneS *= on_init.balance;
Print("Balance to increase risk: ", percentage_a_empezar_modfiicacioneS);
val = m_modifier.GetCalcValue();
//Print("Valor del porcentaje: ", val);
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
}
//+------------------------------------------------------------------+
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
void CDynamicRisk::OnClosePosition(const ModifierOnOpenCloseStruct & on_open_close_struct)
{
if(on_open_close_struct.position.profit > 0 && on_open_close_struct.profit_total > percentage_a_empezar_modfiicacioneS)
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
{
LogInfo(StringFormat("By increasing the risk, a profit of %.2f has been obtained. The initial balance has been exceeded by %.2f.",
on_open_close_struct.position.profit, percentage_a_empezar_modfiicacioneS), FUNCION_ACTUAL);
Aumentar();
m_modifier.SetCalcValue(val);
}
else
{
val = m_modifier.SetInitialCalcValue();
}
}
//+------------------------------------------------------------------+
void CDynamicRisk::Aumentar(void)
{
switch(metod)
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
{
2026-03-05 12:10:29 -05:00
case DR_MULTIPLIER:
2025-12-21 12:44:08 -05:00
val *= paso;
break;
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
case DR_EXPONECIAL:
val *= MathExp(paso);
break;
case DR_SUMATORIO:
val += paso;
break;
default:
Remover();
break;
}
}
2026-03-05 12:10:29 -05:00
//+------------------------------------------------------------------+
2025-12-21 12:44:08 -05:00
//| |
2026-03-05 12:10:29 -05:00
//+------------------------------------------------------------------+
2025-12-21 12:44:08 -05:00
class CModificatorOscar : public CExtraModifications
2026-03-05 12:10:29 -05:00
{
2025-12-21 12:44:08 -05:00
private:
double max_risk;
2026-03-05 12:10:29 -05:00
double riesgo_inciial;
2025-12-21 12:44:08 -05:00
double fat_mul;
double prev_risk;
int hora_ny_init;
int min_ny_inti;
datetime hora_pa;
datetime hora_pd;
public:
CModificatorOscar(double max_risk_percent, double risk_init_percent, double multiplicator_, int init_ny_h, int init_ny_min);
~CModificatorOscar();
//---
void OnNewDay(const datetime curr_time) override final;
void OnInitModifier(const ModfierInitInfo &on_init) override final;
void OnClosePosition(const ModifierOnOpenCloseStruct &on_open_close_struct) override final;
};
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
//+------------------------------------------------------------------+
CModificatorOscar::CModificatorOscar(double max_risk_percent, double risk_init_percent, double multiplicator_, int init_ny_h, int init_ny_min)
: CExtraModifications(LP_GMLPO, RISK_MANAGEMENT_EVENT_ON_CLOSE_POSITION, "Modifier by oscar")
{
max_risk = max_risk_percent;
riesgo_inciial = risk_init_percent;
fat_mul = multiplicator_;
hora_ny_init = init_ny_h;
min_ny_inti = init_ny_min;
//--- Registrar evento de nuevo dia
CBasicEvents::RegisterEvent(GetPointer(this), BASICEVENT_REG_FLAG_ON_NEW_DAY);
}
//+------------------------------------------------------------------+
CModificatorOscar::~CModificatorOscar()
{
if(CBasicEvents::IsActive())
CBasicEvents::UnregisterEvent(GetPointer(this), BASICEVENT_REG_FLAG_ON_NEW_DAY);
}
2026-03-05 12:10:29 -05:00
//+------------------------------------------------------------------+
2025-12-21 12:44:08 -05:00
//| |
//+------------------------------------------------------------------+
void CModificatorOscar::OnNewDay(const datetime curr_time)
{
datetime hora_ny = HoraYMinutoADatetime(hora_ny_init, min_ny_inti, curr_time);
hora_pa = hora_ny - 60;
hora_pd = hora_ny + 60;
}
//+------------------------------------------------------------------+
void CModificatorOscar::OnInitModifier(const ModfierInitInfo &on_init)
{
riesgo_inciial /= 100.0;
riesgo_inciial *= on_init.balance;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CModificatorOscar::OnClosePosition(const ModifierOnOpenCloseStruct &on_open_close_struct)
{
bool es_perdida = on_open_close_struct.position.profit < 0.00;
bool cerro_por_sl = on_open_close_struct.deal_reason == DEAL_REASON_SL;
bool cerro_por_tp = on_open_close_struct.deal_reason == DEAL_REASON_TP;
bool cerrado_en_ny = TimeCurrent() >= hora_pa && TimeCurrent() <= hora_pd;
2026-03-05 12:10:29 -05:00
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
//---
if(cerrado_en_ny)
{
LogInfo("Operation closed during NY hours - current risk remains", FUNCION_ACTUAL);
return;
2025-12-21 12:44:08 -05:00
}
2026-03-05 12:10:29 -05:00
//---
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
if(es_perdida && cerro_por_sl)
{
LogInfo(StringFormat("SL reached - increasing risk. Loss: %.2f", on_open_close_struct.position.profit), FUNCION_ACTUAL);
double new_risk = m_modifier.GetCalcValue() * fat_mul;
if(new_risk <= max_risk)
2025-12-21 12:44:08 -05:00
m_modifier.SetCalcValue(new_risk);
else
2026-03-05 12:10:29 -05:00
m_modifier.SetCalcValue(max_risk);
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
}
2025-12-21 12:44:08 -05:00
else
2026-03-05 12:10:29 -05:00
if(!es_perdida && cerro_por_tp)
{
LogInfo("TP reached - resetting to initial risk", FUNCION_ACTUAL);
m_modifier.SetInitialCalcValue();
}
}
//+--------------------------------------------------------------------------------------+
//| Clase para modificar el riesgo en base a la estrategia de 2.0 |
2025-12-21 12:44:08 -05:00
//+--------------------------------------------------------------------------------------+
2026-03-05 12:10:29 -05:00
class CModifierDynamicRisk : public CExtraModifications
2025-12-21 12:44:08 -05:00
{
2026-03-05 12:10:29 -05:00
private:
double to_applied[];
int index_gmlpo;
public:
CModifierDynamicRisk(string percentages_to_applied);
2025-12-21 12:44:08 -05:00
//---
2026-03-05 12:10:29 -05:00
void OnClosePosition(const ModifierOnOpenCloseStruct &on_open_close_struct) override final;
2025-12-21 12:44:08 -05:00
};
2026-03-05 12:10:29 -05:00
//+------------------------------------------------------------------+
CModifierDynamicRisk::CModifierDynamicRisk(string percentages_to_applied)
: CExtraModifications(LP_GMLPO, RISK_MANAGEMENT_EVENT_ON_CLOSE_POSITION, "Dynamic Risk 2.0")
{
StrTo::CstArray(to_applied, percentages_to_applied, ',');
index_gmlpo = 0;
}
//+------------------------------------------------------------------+
void CModifierDynamicRisk::OnClosePosition(const ModifierOnOpenCloseStruct & on_open_close_struct)
{
if(on_open_close_struct.position.profit < 0.00) //La posicion salio SL
{
// Print(__FUNCTION__, "Se a obtenido un sl modificando el riesgo...");
m_modifier.SetCalcValue(to_applied[index_gmlpo]);
2025-12-21 12:44:08 -05:00
2026-03-05 12:10:29 -05:00
if(index_gmlpo < (int)to_applied.Size() - 1)
index_gmlpo++;
}
else //La posicion salio TP
{
//Print(__FUNCTION__, "Se a obtenido un tp modificando el riesgo...");
index_gmlpo = 0;
m_modifier.SetInitialCalcValue(); //Modificar al riesgo inicial
}
}
//+------------------------------------------------------------------+
//| Modificador de riesgo 2 |
//+------------------------------------------------------------------+
class CDynamicRiskAlma : public CExtraModifications
{
private:
double multiplier;
public:
CDynamicRiskAlma(double mul)
: CExtraModifications(LP_GMLPO, RISK_MANAGEMENT_EVENT_ON_CLOSE_POSITION, "Dynamic Risk Alma v2") { multiplier = mul; }
2025-12-21 12:44:08 -05:00
//---
void OnClosePosition(const ModifierOnOpenCloseStruct &on_open_close_struct) override final;
2025-12-21 12:46:48 -05:00
2025-12-21 12:44:08 -05:00
};