427 lines
38 KiB
MQL5
427 lines
38 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| Ea.mq5 |
|
|
//| Copyright 2025, Niquel Mendoza. |
|
|
//| https://www.mql5.com/es/users/nique_372 |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright 2025, Niquel Mendoza."
|
|
#property link "https://www.mql5.com/es/users/nique_372"
|
|
#property version "1.00"
|
|
#property strict
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Include |
|
|
//+------------------------------------------------------------------+
|
|
#include "Main.mqh"
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Input |
|
|
//+------------------------------------------------------------------+
|
|
sinput group "----------| General |----------"
|
|
input ulong InpMagic = 35465; // Magic Number
|
|
input bool InpModifiedChart = true; // Modificar el grafico?
|
|
|
|
sinput group ""
|
|
sinput group "-------| Strategy |-------"
|
|
input ENUM_VERBOSE_LOG_LEVEL InpStrategyLogLevel = VERBOSE_LOG_LEVEL_CAUTION; // Strategy log level
|
|
|
|
sinput group "-----| TP/SL |-----"
|
|
input ENUM_TYPE_TP_SL_FIXED InpStrategyTypeTpSl = TP_SL_ATR; // Tipo de TP/SL
|
|
|
|
sinput group "-- TP SL by Point"
|
|
input long InpStrategySlPoint = 250; // Stop Loss en puntos
|
|
input long InpStrategyTpPoint = 500; // Take Profit en puntos
|
|
|
|
sinput group "-- TP SL by ATR"
|
|
input double InpStrategyAtrMultiplierTp = 2.0; // Multiplicador del ATR para el TP
|
|
input double InpStrategyAtrMultiplierSl = 2.0; // Multiplicador del ATR para el SL
|
|
|
|
|
|
sinput group "-----| Ordenes |-----"
|
|
input ulong InpStrategyMaxDeviationOrders = 100; //Maxima desviacion/slípagge de las ordenes en puntos
|
|
|
|
sinput group ""
|
|
sinput group "-------| Account Status |-------"
|
|
input ENUM_VERBOSE_LOG_LEVEL InpAccountStatusLogLevel = VERBOSE_LOG_LEVEL_ERROR_ONLY; //(Account Status|Ticket Mangement) log level:
|
|
|
|
|
|
sinput group ""
|
|
sinput group "-------| Risk Management |-------"
|
|
input ENUM_LOTE_TYPE InpRmLoteType = Dinamico; //Lote Type:
|
|
input double InpRmLote = 0.1; //Lot size (only for fixed lot)
|
|
input ENUM_MODE_RISK_MANAGEMENT InpRmRiskMode = risk_mode_personal_account; //type of g_risk management mode
|
|
input ENUM_GET_LOT InpRmGetMode = GET_LOT_BY_STOPLOSS_AND_RISK_PER_OPERATION; //How to get the lot
|
|
input double InpRmPropFirmBalance = 0; //If g_risk mode is Prop Firm FTMO, then put your ftmo account balance
|
|
input ENUM_VERBOSE_LOG_LEVEL InpRmLogLevel = VERBOSE_LOG_LEVEL_ERROR_ONLY; //Risk Management log level:
|
|
|
|
sinput group "- ML/Maximum loss/Maximum loss -"
|
|
input double InpRmPercentageOrMoneyMl = 0; //percentage or money (0 => not used ML)
|
|
input ENUM_RISK_CALCULATION_MODE InpRmModeCalculationMl = percentage; //Mode calculation Max Loss
|
|
input ENUM_APPLIED_PERCENTAGES InpRmAppliedPercentagesMl = Balance; //ML percentage applies to:
|
|
|
|
sinput group "- MWL/Maximum weekly loss/Maximum weekly loss -"
|
|
input double InpRmPercentageOrMoneyMwl = 0; //percentage or money (0 => not used MWL)
|
|
input ENUM_RISK_CALCULATION_MODE InpRmModeCalculationMwl = percentage; //Mode calculation Max weekly Loss
|
|
input ENUM_APPLIED_PERCENTAGES InpRmAppliedPercentagesMwl = Balance;//MWL percentage applies to:
|
|
|
|
sinput group "- MDL/Maximum daily loss/Maximum daily loss -"
|
|
input double InpRmPercentageOrMoneyMdl = 3.0; //percentage or money (0 => not used MDL)
|
|
input ENUM_RISK_CALCULATION_MODE InpRmModeCalculationMdl = percentage; //Mode calculation Max daily loss
|
|
input ENUM_APPLIED_PERCENTAGES InpRmAppliedPercentagesMdl = Balance;//MDL percentage applies to:
|
|
|
|
sinput group "- GMLPO/Gross maximum loss per CanTradetion/Percentage to g_risk per CanTradetion -"
|
|
input ENUM_OF_DYNAMIC_MODES_OF_GMLPO InpRmModeGmlpo = NO_DYNAMIC_GMLPO; //Select GMLPO mode:
|
|
input double InpRmPercentageOrMoneyGmlpo = 2.0; //percentage or money (0 => not used GMLPO)
|
|
input ENUM_RISK_CALCULATION_MODE InpRmModeCalculationGmlpo = percentage; //Mode calculation Max Loss per CanTradetion
|
|
input ENUM_APPLIED_PERCENTAGES InpRmAppliedPercentagesGmlpo = Balance;//GMPLO percentage applies to:
|
|
|
|
sinput group "-- Optional GMLPO settings, Dynamic GMLPO"
|
|
sinput group "--- Full customizable dynamic GMLPO"
|
|
input string InpRmNote1 = "subtracted from your total balance to establish a threshold."; //This parameter determines a specific percentage that will be
|
|
input string InpRmStrPercentagesToBeReviewed = "15,30,50"; //percentages separated by commas.
|
|
input string InpRmNote2 = "a new g_risk level will be triggered on your future trades: "; //When the current balance (equity) falls below this threshold
|
|
input string InpRmStrPercentagesToApply = "10,20,25"; //percentages separated by commas.
|
|
input string InpRmNote3 = "0 in both parameters => do not use dynamic g_risk in gmlpo"; //Note:
|
|
|
|
sinput group "--- Fixed dynamic GMLPO with parameters"
|
|
sinput group "- 1 -"
|
|
input string InpRmNote11 = "subtracted from your total balance to establish a threshold."; //This parameter determines a specific percentage that will be
|
|
input double InpRmBalancePercentageToActivateTheRisk1 = 2.0; //percentage 1 that will be exceeded to modify the g_risk separated by commas
|
|
input string InpRmNote21 = "a new g_risk level will be triggered on your future trades: "; //When the current balance (equity) falls below this threshold
|
|
input double InpRmPercentageToBeModified1 = 1.0;//new percentage 1 to which the gmlpo is modified
|
|
sinput group "- 2 -"
|
|
input double InpRmBalancePercentageToActivateTheRisk2 = 5.0;//percentage 2 that will be exceeded to modify the g_risk separated by commas
|
|
input double InpRmPercentageToBeModified2 = 0.7;//new percentage 2 to which the gmlpo is modified
|
|
sinput group "- 3 -"
|
|
input double InpRmBalancePercentageToActivateTheRisk3 = 7.0;//percentage 3 that will be exceeded to modify the g_risk separated by commas
|
|
input double InpRmPercentageToBeModified3 = 0.5;//new percentage 3 to which the gmlpo is modified
|
|
sinput group "- 4 -"
|
|
input double InpRmBalancePercentageToActivateTheRisk4 = 9.0;//percentage 4 that will be exceeded to modify the g_risk separated by commas
|
|
input double InpRmPercentageToBeModified4 = 0.33;//new percentage 4 1 to which the gmlpo is modified
|
|
|
|
sinput group "-- MDP/Maximum daily profit/Maximum daily profit --"
|
|
input bool InpRmMdpIsStrict = true; //MDP is strict?
|
|
input double InpRmPercentageOrMoneyMdp = 11.0; //percentage or money (0 => not used MDP)
|
|
input ENUM_RISK_CALCULATION_MODE InpRmModeCalculationMdp = percentage; //Mode calculation Max Daily Profit
|
|
input ENUM_APPLIED_PERCENTAGES InpRmAppliedPercentagesMdp = Balance;//MDP percentage applies to:
|
|
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Global variables |
|
|
//+------------------------------------------------------------------+
|
|
CEstrategia g_strategy(InpMagic, _Symbol, _Period, 0, 0, InpStrategyMaxDeviationOrders);
|
|
|
|
//---
|
|
int8_t g_idx_controler_w1 = INVALID_INDEX;
|
|
int8_t g_idx_controler_curr = INVALID_INDEX;
|
|
int8_t g_idx_bar_controlerd1 = INVALID_INDEX;
|
|
int8_t g_idx_bar_mn1 = INVALID_INDEX;
|
|
|
|
//---
|
|
bool g_new_day = false;
|
|
bool g_can_trade = true;
|
|
|
|
//---
|
|
const CLossProfitManager* g_loss_profit_manager;
|
|
//+------------------------------------------------------------------+
|
|
//| Expert initialization function |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Registramos timeframes
|
|
g_new_bar_manager.GetPosExecute(PERIOD_D1, g_idx_bar_controlerd1);
|
|
g_new_bar_manager.GetPosExecute(_Period, g_idx_controler_curr);
|
|
g_new_bar_manager.GetPosExecute(PERIOD_W1, g_idx_controler_w1);
|
|
g_new_bar_manager.GetPosExecute(PERIOD_MN1, g_idx_bar_mn1);
|
|
|
|
//--- Modifamos el grafico si se permite
|
|
if(InpModifiedChart)
|
|
{
|
|
long chart_id = ChartID(); // Obtén el ID del gráfico actual
|
|
|
|
// Ocultar la cuadrícula
|
|
ChartSetInteger(chart_id, CHART_SHOW_GRID, false);
|
|
ChartSetInteger(chart_id, CHART_COLOR_BACKGROUND, C'255,255,255'); // Fondo blanco
|
|
ChartSetInteger(chart_id, CHART_COLOR_FOREGROUND, clrBlack); // Texto y escalas negras
|
|
ChartSetInteger(chart_id, CHART_COLOR_CHART_UP, C'38,166,154'); // Velas alcistas color verde azulado
|
|
ChartSetInteger(chart_id, CHART_COLOR_CHART_DOWN, C'239,83,80'); // Velas bajistas color rojo
|
|
ChartSetInteger(chart_id, CHART_COLOR_CANDLE_BULL, C'38,166,154'); // Cuerpo de las velas alcistas
|
|
ChartSetInteger(chart_id, CHART_COLOR_CANDLE_BEAR, C'239,83,80'); // Cuerpo de las velas bajistas
|
|
ChartSetInteger(chart_id, CHART_COLOR_CHART_LINE, clrDarkSeaGreen); // Línea de tendencia
|
|
ChartSetInteger(chart_id, CHART_COLOR_VOLUME, C'38,166,154'); // Color de los volúmenes
|
|
ChartSetInteger(chart_id, CHART_COLOR_BID, C'38,166,154'); // Línea de oferta
|
|
ChartSetInteger(chart_id, CHART_COLOR_ASK, C'239,83,80'); // Línea de demanda
|
|
ChartSetInteger(chart_id, CHART_COLOR_LAST, C'156,186,240'); // Último precio
|
|
ChartSetInteger(chart_id, CHART_COLOR_STOP_LEVEL, C'239,83,80'); // Líneas de stop
|
|
ChartSetInteger(chart_id, CHART_SHOW_VOLUMES, true);
|
|
// Actualizar el gráfico
|
|
ChartRedraw(chart_id);
|
|
}
|
|
|
|
//--- Conceptos
|
|
// Order block
|
|
g_fvg.Create(_Symbol, _Period);
|
|
g_fvg.SetGrapich(clrGreen, clrRed, clrGreen, clrRed, STYLE_SOLID, true, 1, true, 15, 1, STYLE_DASHDOT);
|
|
g_fvg.Set(250, defined_pattern, fvg_1_vela, CreateDiffInstance(MODE_DIFF_BY_FIXED_POITNS, _Symbol, NULL, 1, 0.00));
|
|
|
|
//--- Estrategia
|
|
// Atr Ultra
|
|
CAtrUltraOptimized* atr_ultra = new CAtrUltraOptimized();
|
|
atr_ultra.SetVariables(PERIOD_CURRENT, _Symbol, 0, 14);
|
|
atr_ultra.SetInternalPointer();
|
|
|
|
// Strategy
|
|
g_strategy.AddLogFlags(InpStrategyLogLevel);
|
|
g_strategy.SetAtrTP_SL(atr_ultra, InpStrategyAtrMultiplierTp, InpStrategyAtrMultiplierSl);
|
|
g_strategy.SetOperateMode(TR_BUY_SELL, InpStrategyTypeTpSl);
|
|
g_strategy.SetTP_SL(InpStrategySlPoint, InpStrategyTpPoint);
|
|
account_status.AddItemFast(&g_strategy);
|
|
if(InpRmLoteType == Fijo)
|
|
g_strategy.FixedLotSize(InpRmLote);
|
|
|
|
//--- Gestion de riesgo
|
|
CRiskPointer* manager = new CRiskPointer(InpMagic, InpRmGetMode);
|
|
manager.SetPropirm(InpRmPropFirmBalance);
|
|
g_risk = manager.GetRiskPointer(InpRmRiskMode);
|
|
g_risk.AddLogFlags(InpRmLogLevel);
|
|
g_risk.SetLote(CreateLotePtr(_Symbol));
|
|
|
|
|
|
// We set the parameters
|
|
string to_apply = InpRmStrPercentagesToApply, to_modfied = InpRmStrPercentagesToBeReviewed;
|
|
|
|
if(InpRmModeGmlpo == DYNAMIC_GMLPO_FIXED_PARAMETERS)
|
|
SetDynamicUsingFixedParameters(InpRmBalancePercentageToActivateTheRisk1, InpRmBalancePercentageToActivateTheRisk2, InpRmBalancePercentageToActivateTheRisk3
|
|
, InpRmBalancePercentageToActivateTheRisk4, InpRmPercentageToBeModified1, InpRmPercentageToBeModified2, InpRmPercentageToBeModified3, InpRmPercentageToBeModified4
|
|
, to_modfied, to_apply);
|
|
|
|
g_risk.AddLoss(InpRmPercentageOrMoneyMdl, InpRmAppliedPercentagesMdl, InpRmModeCalculationMdl, LP_MDL, true);
|
|
g_risk.AddLoss(InpRmPercentageOrMoneyGmlpo, InpRmAppliedPercentagesGmlpo, InpRmModeCalculationGmlpo, LP_GMLPO, true, (InpRmModeGmlpo != NO_DYNAMIC_GMLPO), to_modfied, to_apply);
|
|
g_risk.AddLoss(InpRmPercentageOrMoneyMl, InpRmAppliedPercentagesMl, InpRmModeCalculationMl, LP_ML, true);
|
|
g_risk.AddLoss(InpRmPercentageOrMoneyMwl, InpRmAppliedPercentagesMwl, InpRmModeCalculationMwl, LP_MWL, true);
|
|
g_risk.AddProfit(InpRmPercentageOrMoneyMdp, InpRmAppliedPercentagesMdp, InpRmModeCalculationMdp, LP_MDP, InpRmMdpIsStrict);
|
|
g_risk.EndAddProfitLoss(); // Execute this every time we finish setting the maximum losses and profits
|
|
g_loss_profit_manager = g_risk.GetLossProfitManager();
|
|
|
|
// We finish by adding it
|
|
account_status.AddItemFast(g_risk);
|
|
|
|
// We delete the temporary pointer
|
|
delete manager;
|
|
|
|
//--- We initialize the account
|
|
account_status.AddLogFlagTicket(InpAccountStatusLogLevel);
|
|
account_status.AddLogFlags(InpAccountStatusLogLevel);
|
|
account_status.OnInitEvent();
|
|
|
|
|
|
//---
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert deinitialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int reason)
|
|
{
|
|
//---
|
|
ICTGen_OnDeinitEvent(); // IMPORTANTE: Siempre llamar a esta fucnion en OnDeinit
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Expert tick function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTick()
|
|
{
|
|
//---
|
|
const datetime time_curr = TimeCurrent();
|
|
g_new_day = false;
|
|
g_new_bar_manager.Execute(time_curr);
|
|
|
|
|
|
//--- Bloque 1 | Control Diario/Semanal/Mensual
|
|
if(CNewBarManager_IsNewBarM1(g_new_bar_manager))
|
|
{
|
|
if(CNewBarManager_IsNewBar(g_new_bar_manager, g_idx_bar_controlerd1))
|
|
{
|
|
account_status.OnNewDay(time_curr);
|
|
|
|
//---
|
|
if(CNewBarManager_IsNewBar(g_new_bar_manager, g_idx_controler_w1)) //Limpiar para no acomular mucha memoria
|
|
{
|
|
account_status.OnNewWeek(time_curr);
|
|
}
|
|
|
|
//--- Nuevo mes, eliminacion de liquidez
|
|
if(CNewBarManager_IsNewBar(g_new_bar_manager, g_idx_bar_mn1))
|
|
account_status.OnNewMonth(time_curr);
|
|
|
|
//---
|
|
g_can_trade = true;
|
|
g_new_day = true;
|
|
}
|
|
}
|
|
|
|
//--- Bloque 2 | Control de MDL\MDP.. etc
|
|
if(account_status_positions_open)
|
|
{
|
|
CAccountStatus_OnTickEvent
|
|
if(g_can_trade)
|
|
{
|
|
if(g_loss_profit_manager.MaxLossIsSuperated())
|
|
{
|
|
const ENUM_TYPE_LOSS_PROFIT type = g_loss_profit_manager.GetLastLossSuperatedType();
|
|
if(type == LP_ML)
|
|
{
|
|
if(InpRmRiskMode == risk_mode_propfirm_dynamic_daiy_loss)
|
|
{
|
|
Print("The expert advisor lost the funding test");
|
|
}
|
|
else
|
|
{
|
|
Print("Maximum loss exceeded now");
|
|
}
|
|
|
|
//---
|
|
Remover();
|
|
}
|
|
else
|
|
if(type == LP_MDL)
|
|
{
|
|
Print("Maximum daily loss exceeded now");
|
|
}
|
|
|
|
//---
|
|
g_strategy.OnInterupcion();
|
|
g_risk.CloseAllPositions();
|
|
g_can_trade = false;
|
|
}
|
|
else
|
|
if(g_loss_profit_manager.MaxProfitIsSuperated())
|
|
{
|
|
if(g_loss_profit_manager.GetLastProfitSuperatedType() != LP_MDP)
|
|
return;
|
|
|
|
//---
|
|
g_strategy.OnInterupcion();
|
|
g_risk.CloseAllPositions();
|
|
Print("Excellent Maximum daily profit achieved");
|
|
g_can_trade = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--- Bloque 3 | Ejecucion
|
|
if(!g_can_trade) // Si se superaron los limites de MDL, o MDP enotnces no CanTrader
|
|
return;
|
|
|
|
//---
|
|
/*
|
|
Bien, llegamos a esta parte del código donde debemos ejecutar los conceptos ICT.
|
|
|
|
Este bloque, como tal, no es “fijo”; existen muchas combinaciones posibles.
|
|
Esto se debe a que intervienen varios factores:
|
|
|
|
1. ¿El timeframe de todos los conceptos y el que utiliza la estrategia es el mismo?
|
|
2. ¿Existe algún concepto en M1 (que, en lugar de usar OnNewBar, utilice
|
|
OnNewBarM1), por ejemplo sesiones o High/Low Zones?
|
|
|
|
En base a estos dos criterios podemos optimizar la ejecución.
|
|
|
|
Por ejemplo, en el caso de utilizar sesiones, y cuando los conceptos no varían
|
|
de timeframe (o en caso de hacerlo, el período actual es múltiplo del timeframe
|
|
de los conceptos), podríamos hacer lo siguiente:
|
|
|
|
if(CNewBarManager_IsNewBarM1(g_new_bar_manager))
|
|
{
|
|
//---
|
|
// Esta función siempre se ejecuta en cada nueva barra M1
|
|
ICTGen_FuncionOnBarM1(g_new_day, time_curr);
|
|
|
|
// Aquí irían las sesiones u otros objetos en M1
|
|
|
|
//---
|
|
if(CNewBarManager_IsNewBar(g_new_bar_manager, g_idx_controler_curr))
|
|
{
|
|
//---
|
|
// Aquí se ejecutan los conceptos,
|
|
// o bien se delega dentro de la clase, dependiendo de la estrategia
|
|
|
|
//---
|
|
g_strategy.OnNewBar(time_curr);
|
|
}
|
|
}
|
|
|
|
Por otro lado, si tenemos conceptos en varios timeframes, o los timeframes no son
|
|
fijos ni múltiplos entre sí, entonces deberíamos ejecutar los conceptos en cada
|
|
vela M1, y también llamar a OnNewBar de la estrategia en M1. En ese caso, el control
|
|
de la apertura de velas deberá gestionarse internamente.
|
|
|
|
if(CNewBarManager_IsNewBarM1(g_new_bar_manager))
|
|
{
|
|
//---
|
|
// Siempre se ejecuta en cada nueva barra M1
|
|
ICTGen_FuncionOnBarM1(g_new_day, time_curr);
|
|
// Aquí las sesiones u objetos M1
|
|
|
|
//---
|
|
// Aquí los conceptos, o dentro de la clase de la estrategia
|
|
|
|
//---
|
|
g_strategy.OnNewBar(time_curr);
|
|
}
|
|
|
|
Para nuestro caso es especial, ya que:
|
|
- El punto 1 es falso (todo trabaja en el timeframe actual).
|
|
- El punto 2 también es falso (no utilizamos sesiones).
|
|
|
|
Por lo tanto, podemos optimizar ejecutando todo únicamente en cada nueva barra
|
|
del timeframe actual, siempre que también exista una nueva barra M1.
|
|
|
|
if(CNewBarManager_IsNewBarM1(g_new_bar_manager) &&
|
|
CNewBarManager_IsNewBar(g_new_bar_manager, g_idx_controler_curr))
|
|
{
|
|
//---
|
|
// Siempre ejecutamos esta función en cada nueva barra M1
|
|
ICTGen_FuncionOnBarM1(g_new_day, time_curr);
|
|
|
|
//---
|
|
// Conceptos
|
|
|
|
//---
|
|
g_strategy.OnNewBar(time_curr);
|
|
}
|
|
|
|
Siendo esto lo que haremos a continuación.
|
|
*/
|
|
|
|
//---
|
|
if(CNewBarManager_IsNewBarM1(g_new_bar_manager) &&
|
|
CNewBarManager_IsNewBar(g_new_bar_manager, g_idx_controler_curr))
|
|
{
|
|
//---
|
|
// Siempre se ejecuta en cada nueva barra M1
|
|
ICTGen_FuncionOnBarM1(g_new_day, time_curr);
|
|
|
|
//---
|
|
g_fvg.OnNewBar();
|
|
|
|
//---
|
|
g_strategy.OnNewBar(time_curr);
|
|
}
|
|
|
|
//---
|
|
// También es importante mencionar que, siempre que trabajemos con g_new_bar_manager
|
|
// dentro de OnTick, debemos comprobar la nueva vela M1.
|
|
// En cambio, dentro de CEstrategia::OnNewBar, si esta función se ejecuta en cada vela M1,
|
|
// dicha comprobación ya no es necesaria, ya que sería una forma de “simplificar”
|
|
// las primeras verificaciones.
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| TradeTransaction function |
|
|
//+------------------------------------------------------------------+
|
|
void OnTradeTransaction(const MqlTradeTransaction & trans,
|
|
const MqlTradeRequest & request,
|
|
const MqlTradeResult & result)
|
|
{
|
|
//---
|
|
account_status.OnTradeTransactionEvent(trans);
|
|
}
|
|
//+------------------------------------------------------------------+
|