//+------------------------------------------------------------------+ //| 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 //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CEstrategia : public TSN::CStrategyBase { private: //--- General datetime m_next_max_espera; ENUM_ESTRATEGIA_SENSEI_STATE m_state; bool m_operate; //--- Htf ENUM_TIMEFRAMES m_timeframe_htf; int8_t m_index_contoler_htf; IConfirmacion* m_confirmacion_htf; //--- MidTimeframe ENUM_TIMEFRAMES m_timeframe_mid_tf; // Fibbo TSN::CFibbo m_fibbo; double m_price_fibbo; int m_level_fibbo; // 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: CEstrategia(ulong magic_number_, string symbol_, bool draw_fibbo, ENUM_TIMEFRAMES timeframe_ = PERIOD_CURRENT, long chart_id_ = 0, int subwindow_ = 0, ulong max_deviation_ = NO_MAX_DEVIATION_DEFINED); ~CEstrategia(void); //--- bool SetFibbo(color clr_fibbo, string fibbo_levels, string fibbo_colors, double fibbo_level_principal = 0.50); 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); //--- 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); }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CEstrategia::CEstrategia(ulong magic_number_, string symbol_, bool draw_fibbo, ENUM_TIMEFRAMES timeframe_ = PERIOD_CURRENT, long chart_id_ = 0, int subwindow_ = 0, ulong max_deviation_ = NO_MAX_DEVIATION_DEFINED) : 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 { CBasicEvents::RegisterEvent(&this, BASICEVENT_REG_FLAG_ON_NEW_WEEK); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CEstrategia::~CEstrategia(void) { if(CBasicEvents::IsActive()) CBasicEvents::UnregisterEvent(&this, BASICEVENT_REG_FLAG_ON_NEW_WEEK); if(::CheckPointer(m_confirmation_entrada) == POINTER_DYNAMIC) delete m_confirmation_entrada; if(::CheckPointer(m_confirmacion_htf) == POINTER_DYNAMIC) delete m_confirmacion_htf; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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(ESTRATEGIA_ERR_FAILED_CALC_LEVEL_IDX, TSN::CBitsReinterprete::ToBasic(fibbo_level_principal)); return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ static void CEstrategia::FormatTrace(const TSN::TSNErrorFrame &trace[], int &trace_idx, string &out) { 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(trace[trace_idx].info)), trace_idx) break; default: TSNSTD_ERRMAN_PUSHOUT(out, "Unknow error", trace_idx) break; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CEstrategia::OnNewWeek(const datetime curr_time) { // 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) { //--- m_timeframe_htf = tf_high; m_timeframe_mid_tf = tf_mif; m_max_espera_to_descuento_in_bars = max_epsera_para_descuento; //--- // Aqui algo.. el HTF siempre debera de ser mayor al timeframe de la estrateiga el current if(tpye_dir == SENSEI_DIR_MANIPULACION_SESIONES) g_new_bar_manager.GetPosExecute(m_timeframe, m_index_contoler_htf); // Usamos directament ela funcion para registar el TF else g_new_bar_manager.GetPosExecute(tf_high, m_index_contoler_htf); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CEstrategia::Clean(void) { m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_DIR; 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(); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CEstrategia::OnNewBar(const datetime curr_time) { if(risk.GetPositionsTotal() > 0) return; //--- if(g_session_operativa.EnSesion()) { //--- if(g_session_operativa.IsInitSession()) { LogInfo("Inicio de sesion", FUNCION_ACTUAL); ChangeTimeframeConcepts(m_timeframe_htf); m_operate = true; } //--- if(!m_operate) return; // No ejeuctamos nada //--- g_fvg.OnNewBar(); g_ob.OnNewBar(); //--- do { switch(m_state) { case ESTRATEGIA_SENSEI_STATE_BUSCAR_DIR: { // 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; } //--- Ya hay direccion de compra: esperamos que el precio este en descuento (concepto MID-TF) case ESTRATEGIA_SENSEI_STATE_BUSCAR_DESCUENTO_COMPRA: { 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) { 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 } break; } //--- Ya hay direccion de venta: esperamos que el precio este en premium case ESTRATEGIA_SENSEI_STATE_BUSCAR_DESCUENTO_VENTA: { 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) { m_state = ESTRATEGIA_SENSEI_STATE_BUSCAR_DIR; // Reinicio LogInfo("Max espera para fibbo superada", FUNCION_ACTUAL); m_operate = false; } break; } //--- 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: { if(m_confirmation_entrada.ConfirmacionVenta()) OpenOrder(POSITION_TYPE_SELL); break; } default: break; } //--- sale siempre break; } while(true); } 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); risk.SetStopLoss(m_symbol, entry - sl); 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); risk.SetStopLoss(m_symbol, sl - entry); 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"); } m_operate = false; Clean(); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+