ICTLibraryExamples/Sensei/Est2023/Main.mqh
410 lines
16 KiB
MQL5
Nique_372
2025-11-26 07:19:36 -05:00
//+------------------------------------------------------------------+
//| Main.mqh |
//| Copyright 2025, Niquel Mendoza. |
//| https://www.mql5.com/es/users/nique_372/news |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Niquel Mendoza."
#property link "https://www.mql5.com/es/users/nique_372/news"
#property strict
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
#include "Confirmacion.mqh"
// Source: https://www.youtube.com/watch?v=1gDEl5FxsGA
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Nique_372
2026-10-23 21:51:38 -05:00
class CEstrategia : public TSN::CStrategyBase
Nique_372
2025-11-26 07:19:36 -05:00
{
private:
//--- General
datetime m_next_max_espera;
Nique_372
2026-11-06 15:35:47 -05:00
ENUM_ESTRATEGIA_SENSEI_STATE m_state;
Nique_372
2025-11-26 07:19:36 -05:00
bool m_operate;
//--- Htf
ENUM_TIMEFRAMES m_timeframe_htf;
Nique_372
2026-01-06 06:46:34 -05:00
int8_t m_index_contoler_htf;
Nique_372
2025-11-26 07:19:36 -05:00
IConfirmacion* m_confirmacion_htf;
//--- MidTimeframe
ENUM_TIMEFRAMES m_timeframe_mid_tf;
// Fibbo
Nique_372
2026-11-06 15:35:47 -05:00
TSN::CFibbo m_fibbo;
Nique_372
2025-11-26 07:19:36 -05:00
double m_price_fibbo;
Nique_372
2026-11-06 15:35:47 -05:00
int m_level_fibbo;
Nique_372
2025-11-26 07:19:36 -05:00
// Espera
int m_max_espera_to_descuento_in_bars; // Velas en timeframe curr
//--- Timefgrame de entrada
IConfirmacion* m_confirmation_entrada;
//---
void Clean();
void OpenOrder(ENUM_POSITION_TYPE type);
//---
void ChangeTimeframeConcepts(ENUM_TIMEFRAMES tf);
public:
Nique_372
2026-11-06 15:35:47 -05:00
CEstrategia(ulong magic_number_, string symbol_, bool draw_fibbo, ENUM_TIMEFRAMES timeframe_ = PERIOD_CURRENT, long chart_id_ = 0,
Nique_372
2025-11-26 07:19:36 -05:00
int subwindow_ = 0, ulong max_deviation_ = NO_MAX_DEVIATION_DEFINED);
~CEstrategia(void);
//---
Nique_372
2026-11-06 15:35:47 -05:00
bool SetFibbo(color clr_fibbo, string fibbo_levels, string fibbo_colors, double fibbo_level_principal = 0.50);
Nique_372
2025-11-26 07:19:36 -05:00
void SetConfirmations(IConfirmacion* confirmation_htf, IConfirmacion* confirmaction_entrada);
void Init(ENUM_TIMEFRAMES tf_mif, ENUM_TIMEFRAMES tf_high, int max_epsera_para_descuento, ENUM_ESTRATEGIA_SENSEI_DIRECCION_IND tpye_dir);
//---
Nique_372
2026-11-06 15:35:47 -05:00
void OnNewBar(const datetime curr_time) override final;
void OnNewWeek(const datetime curr_time) override final;
void OnTick(const datetime curr_time) override final { }
//--- Error
static void FormatTrace(const TSN::TSNErrorFrame &trace[], int &trace_idx, string &out);
Nique_372
2025-11-26 07:19:36 -05:00
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Nique_372
2026-11-06 15:35:47 -05:00
CEstrategia::CEstrategia(ulong magic_number_, string symbol_, bool draw_fibbo, ENUM_TIMEFRAMES timeframe_ = PERIOD_CURRENT, long chart_id_ = 0,
Nique_372
2025-11-26 07:19:36 -05:00
int subwindow_ = 0, ulong max_deviation_ = NO_MAX_DEVIATION_DEFINED)
Nique_372
2026-11-06 15:35:47 -05:00
: CStrategyBase(magic_number_, symbol_, timeframe_, chart_id_, subwindow_, max_deviation_, "Estrategia sensei"), m_fibbo(draw_fibbo),
m_confirmacion_htf(NULL), m_confirmation_entrada(NULL), m_index_contoler_htf(NULL), m_operate(true),
m_state(ESTRATEGIA_SENSEI_STATE_BUSCAR_DIR), m_price_fibbo(0.00), m_level_fibbo(-1), m_next_max_espera(0) // no se llama Clean() aqui: los conceptos globales aun no estan creados
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-02-01 13:11:51 -05:00
CBasicEvents::RegisterEvent(&this, BASICEVENT_REG_FLAG_ON_NEW_WEEK);
Nique_372
2025-11-26 07:19:36 -05:00
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CEstrategia::~CEstrategia(void)
{
Nique_372
2026-02-01 13:11:51 -05:00
if(CBasicEvents::IsActive())
CBasicEvents::UnregisterEvent(&this, BASICEVENT_REG_FLAG_ON_NEW_WEEK);
Nique_372
2025-11-26 07:19:36 -05:00
if(::CheckPointer(m_confirmation_entrada) == POINTER_DYNAMIC)
delete m_confirmation_entrada;
if(::CheckPointer(m_confirmacion_htf) == POINTER_DYNAMIC)
delete m_confirmacion_htf;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Nique_372
2026-11-06 15:35:47 -05:00
bool CEstrategia::SetFibbo(color clr_fibbo, string fibbo_levels, string fibbo_colors, double fibbo_level_principal = 0.500000)
{
// estos ya ponen su error en el trace
if(!m_fibbo.Create(m_chart_id, "FibboSensei", m_subwindow, clr_fibbo, STYLE_SOLID, 1, "Fibbo", true))
return false;
if(!m_fibbo.InitFibbo(fibbo_levels, fibbo_colors, STYLE_SOLID, 1, ','))
return false;
// este no pone error (usa un hashmap de bajo nivel), hace falta que lo hagamos nosotros
if(!m_fibbo.GetLevelIndex(fibbo_level_principal, m_level_fibbo))
return TSN::CErrorTrace::FailInit<CEstrategia>(ESTRATEGIA_ERR_FAILED_CALC_LEVEL_IDX, TSN::CBitsReinterprete::ToBasic<ulong, double>(fibbo_level_principal));
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
static void CEstrategia::FormatTrace(const TSN::TSNErrorFrame &trace[], int &trace_idx, string &out)
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
TSNSTD_ERRMAN_PUSHINI(out, trace_idx)
switch(trace[trace_idx].code)
{
case ESTRATEGIA_ERR_NOT:
TSNSTD_ERRMAN_PUSHOUT(out, "Not error", trace_idx)
break;
case ESTRATEGIA_ERR_FAILED_CALC_LEVEL_IDX:
TSNSTD_ERRMAN_PUSHOUT(out, StringFormat("The chosen fibbo level [%.4f] is not one of the fibbo levels (InpStrategyFibboLevels)",
TSN::CBitsReinterprete::ToBasic<double, ulong>(trace[trace_idx].info)), trace_idx)
break;
default:
TSNSTD_ERRMAN_PUSHOUT(out, "Unknow error", trace_idx)
break;
}
Nique_372
2025-11-26 07:19:36 -05:00
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Nique_372
2026-02-14 17:50:28 -05:00
void CEstrategia::OnNewWeek(const datetime curr_time)
Nique_372
2025-11-26 07:19:36 -05:00
{
// Limpieza semanal
g_fvg.DeleteAll();
g_ob.DeleteAll();
g_zz.DeleteAll();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CEstrategia::SetConfirmations(IConfirmacion *confirmation_htf, IConfirmacion *confirmaction_entrada)
{
m_confirmacion_htf = confirmation_htf;
m_confirmation_entrada = confirmaction_entrada;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CEstrategia::Init(ENUM_TIMEFRAMES tf_mif, ENUM_TIMEFRAMES tf_high, int max_epsera_para_descuento, ENUM_ESTRATEGIA_SENSEI_DIRECCION_IND tpye_dir)
{
Nique_372
2026-01-06 06:46:34 -05:00
//---
Nique_372
2025-11-26 07:19:36 -05:00
m_timeframe_htf = tf_high;
m_timeframe_mid_tf = tf_mif;
m_max_espera_to_descuento_in_bars = max_epsera_para_descuento;
//---
Nique_372
2026-01-06 06:46:34 -05:00
// Aqui algo.. el HTF siempre debera de ser mayor al timeframe de la estrateiga el current
Nique_372
2025-11-26 07:19:36 -05:00
if(tpye_dir == SENSEI_DIR_MANIPULACION_SESIONES)
Nique_372
2026-01-06 06:46:34 -05:00
g_new_bar_manager.GetPosExecute(m_timeframe, m_index_contoler_htf); // Usamos directament ela funcion para registar el TF
Nique_372
2025-11-26 07:19:36 -05:00
else
Nique_372
2026-01-06 06:46:34 -05:00
g_new_bar_manager.GetPosExecute(tf_high, m_index_contoler_htf);
Nique_372
2025-11-26 07:19:36 -05:00
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CEstrategia::Clean(void)
{
Nique_372
2026-11-06 15:35:47 -05:00
m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_DIR;
Nique_372
2025-11-26 07:19:36 -05:00
m_price_fibbo = 0.00;
m_next_max_espera = 0;
g_ob.SetParo();
g_fvg.SetParo();
// g_zz.SetParo(); // zz se ejecuta en todo momento
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CEstrategia::ChangeTimeframeConcepts(ENUM_TIMEFRAMES tf)
{
g_fvg.ChangeTimeframe(tf);
g_ob.ChangeTimeframe(tf);
g_fvg.SetCalculatePrevInNextBar();
g_ob.SetCalculatePrevInNextBar();
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Nique_372
2026-02-14 17:50:28 -05:00
void CEstrategia::OnNewBar(const datetime curr_time)
Nique_372
2025-11-26 07:19:36 -05:00
{
if(risk.GetPositionsTotal() > 0)
return;
//---
if(g_session_operativa.EnSesion())
{
//---
if(g_session_operativa.IsInitSession())
{
Nique_372
2026-01-06 06:46:34 -05:00
LogInfo("Inicio de sesion", FUNCION_ACTUAL);
Nique_372
2025-11-26 07:19:36 -05:00
ChangeTimeframeConcepts(m_timeframe_htf);
m_operate = true;
}
//---
if(!m_operate)
return; // No ejeuctamos nada
//---
g_fvg.OnNewBar();
g_ob.OnNewBar();
//---
Nique_372
2026-11-06 15:35:47 -05:00
do
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
switch(m_state)
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
case ESTRATEGIA_SENSEI_STATE_BUSCAR_DIR:
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
// Importnate descomentamos debido a que;
// Dado queestamos segurmos que no habra "colgamiento" para empeozae
// OnNewBar se jecuta cada M3 current mismo perido que m_confirmation_entrada asi que por mas que este listo para entener
// Esperara una vela para limpiar data previa por lo que no quedara "data colgada" ademas otra razon es que solo llaamsmo a una vez
// SizeAlcista y SizeBajistas y par ala siutiente llamada si o si es un diferte "timestap" no el mismo..
// Ahora cuando SI LLAMAR este caos: digmaos que OnNEWbAR DE AQUI SE ejeucta m1 entonces luego de esto busco doble mtiigaicon de fvg o cosas que esten
// En la misma insurccion o conseuticaaos en este caso si el timeframel dle ob e smaytor entonce quedaria "colgado" pro lqo ei la siugietne codnicon
// Se elualria como TRUE cuando no lo es ahi si vale la pena controlar la arptuira de las velas
// if(true /*CNewBarManager_IsNewBar(g_new_bar_manager, m_index_contoler_htf)*/) // OB-LOWHIGH-FVG (NO SABEMOS NO ESTAMOS SEGUROs)
// {
// }
//---
if(m_confirmacion_htf.ConfirmacionCompra())
{
LogInfo("Direccion detectada: compra", FUNCION_ACTUAL);
m_next_max_espera = curr_time + (m_period_in_seconds * m_max_espera_to_descuento_in_bars);
//---
// Fibbo de compra
::SymbolInfoTick(m_symbol, m_tick);
const Swings swing = g_zz.GetSwingHighMasCeracanoPorPrecioYTime(m_tick.bid, SWING_MAYOR_A_TARGET_PRICE);
const double minimo = ::iLow(m_symbol, m_timeframe_mid_tf, ::iLowest(m_symbol, m_timeframe_mid_tf, MODE_LOW, ::iBarShift(m_symbol, m_timeframe_mid_tf, swing.time), 0));
//Print(minimo);
m_fibbo.Move(swing.time, m_tick.time, swing.price, minimo);
m_price_fibbo = m_fibbo.GetLevelPrice(m_level_fibbo);
//---
ChangeTimeframeConcepts(m_timeframe); // Timefrmae de entrada
m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_DESCUENTO_COMPRA;
continue; // "al toque" sale a laa siuginte (Esto para uqe sea "fiel" a como estaba antes)
}
else
if(m_confirmacion_htf.ConfirmacionVenta())
{
m_next_max_espera = curr_time + (m_period_in_seconds * m_max_espera_to_descuento_in_bars);
//---
// Fibob de venta
::SymbolInfoTick(m_symbol, m_tick);
const Swings swing = g_zz.GetSwingLowMasCeracanoPorPrecioYTime(m_tick.bid, SWING_MENOR_A_TARGET_PRICE);
const double maximo = ::iHigh(m_symbol, m_timeframe_mid_tf, ::iHighest(m_symbol, m_timeframe_mid_tf, MODE_HIGH, ::iBarShift(m_symbol, m_timeframe_mid_tf, swing.time), 0));
m_fibbo.Move(swing.time, m_tick.time, maximo, swing.price);
m_price_fibbo = m_fibbo.GetLevelPrice(m_level_fibbo);
//---
ChangeTimeframeConcepts(m_timeframe); // Timefrmae de entrada
LogInfo("Direccion detectada: venta", FUNCION_ACTUAL);
m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_DESCUENTO_VENTA;
continue; // "al toque" sale a laa siuginte (Esto para uqe sea "fiel" a como estaba antes)
}
break;
Nique_372
2025-11-26 07:19:36 -05:00
}
Nique_372
2026-11-06 15:35:47 -05:00
//--- Ya hay direccion de compra: esperamos que el precio este en descuento (concepto MID-TF)
case ESTRATEGIA_SENSEI_STATE_BUSCAR_DESCUENTO_COMPRA:
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
if(g_zz.IsNewBarConcept()) // El desucuento siempre sera el concepto MID-TF
{
// Actulizacion del fibbo y vemos si estamos en descuento
m_fibbo.UpdateTime2(curr_time);
::SymbolInfoTick(m_symbol, m_tick);
if(m_price_fibbo > m_tick.bid) // Bid en desucneto
{
m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_ENTRADA_COMPRA; // la entrada se busca en la siguiente llamada
LogInfo("Precio en descuento", FUNCION_ACTUAL);
}
}
// Maxima espera (se evalua aunque en esta misma llamada ya se haya llegado al descuento, igual que antes)
if(curr_time > m_next_max_espera)
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_DIR; // Reinicio
LogInfo("Max espera para fibbo superada", FUNCION_ACTUAL);
// Aqui podemos hacer dos cosas o cambiar de timeframe
m_operate = false;
// O calendar el trade m_operate = false
Nique_372
2025-11-26 07:19:36 -05:00
}
Nique_372
2026-11-06 15:35:47 -05:00
break;
Nique_372
2025-11-26 07:19:36 -05:00
}
Nique_372
2026-11-06 15:35:47 -05:00
//--- Ya hay direccion de venta: esperamos que el precio este en premium
case ESTRATEGIA_SENSEI_STATE_BUSCAR_DESCUENTO_VENTA:
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
if(g_zz.IsNewBarConcept())
{
m_fibbo.UpdateTime2(curr_time);
::SymbolInfoTick(m_symbol, m_tick);
if(m_tick.bid > m_price_fibbo) // Bid en premiun
{
m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_ENTRADA_VENTA;
LogInfo("Precio en premiun", FUNCION_ACTUAL);
}
}
if(curr_time > m_next_max_espera)
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_DIR; // Reinicio
LogInfo("Max espera para fibbo superada", FUNCION_ACTUAL);
m_operate = false;
Nique_372
2025-11-26 07:19:36 -05:00
}
Nique_372
2026-11-06 15:35:47 -05:00
break;
Nique_372
2025-11-26 07:19:36 -05:00
}
Nique_372
2026-11-06 15:35:47 -05:00
//--- Entrada
case ESTRATEGIA_SENSEI_STATE_BUSCAR_ENTRADA_COMPRA:
{
if(m_confirmation_entrada.ConfirmacionCompra())
OpenOrder(POSITION_TYPE_BUY);
break;
}
case ESTRATEGIA_SENSEI_STATE_BUSCAR_ENTRADA_VENTA:
Nique_372
2025-11-26 07:19:36 -05:00
{
Nique_372
2026-11-06 15:35:47 -05:00
if(m_confirmation_entrada.ConfirmacionVenta())
OpenOrder(POSITION_TYPE_SELL);
break;
Nique_372
2025-11-26 07:19:36 -05:00
}
Nique_372
2026-11-06 15:35:47 -05:00
default:
break;
}
//--- sale siempre
break;
Nique_372
2025-11-26 07:19:36 -05:00
}
Nique_372
2026-11-06 15:35:47 -05:00
while(true);
Nique_372
2025-11-26 07:19:36 -05:00
}
else
if(g_session_operativa.IsEndSession()) // Session finalizada
{
Clean();
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CEstrategia::OpenOrder(ENUM_POSITION_TYPE type)
{
::SymbolInfoTick(m_symbol, m_tick);
if(type == POSITION_TYPE_BUY)
{
double entry = m_tick.ask;
double sl = GetSL(entry, type, m_tick.time);
double tp = GetTP(entry, type, m_tick.time);
Nique_372
2026-11-01 22:12:14 -05:00
risk.SetStopLoss(m_symbol, entry - sl);
Nique_372
2025-11-26 07:19:36 -05:00
double l = m_LOT_SIZE > 0.00 ? m_LOT_SIZE : risk.GetLote(ORDER_TYPE_BUY, entry, m_max_deviation, 0);
m_trade.Buy(l, m_symbol, entry, sl, tp, "Ea buy");
}
else
if(type == POSITION_TYPE_SELL)
{
double entry = m_tick.bid;
double sl = GetSL(entry, type, m_tick.time);
double tp = GetTP(entry, type, m_tick.time);
Nique_372
2026-11-01 22:12:14 -05:00
risk.SetStopLoss(m_symbol, sl - entry);
Nique_372
2025-11-26 07:19:36 -05:00
double l = m_LOT_SIZE > 0.00 ? m_LOT_SIZE : risk.GetLote(ORDER_TYPE_SELL, entry, m_max_deviation, 0);
m_trade.Sell(l, m_symbol, entry, sl, tp, "Ea sell");
}
Nique_372
2026-01-06 06:46:34 -05:00
m_operate = false;
Nique_372
2025-11-26 07:19:36 -05:00
Clean();
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+