2025-11-26 07:19:36 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| TradingLabS1.mqh |
|
| | | //| Copyright 2025, Leo. |
|
| | | //| https://www.mql5.com/es/users/nique_372/news |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2025, Leo."
|
| | | #property link "https://www.mql5.com/es/users/nique_372/news"
|
| | | #property strict
|
| | |
|
2026-11-01 22:12:14 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-02-01 12:28:19 -05:00 | | | #include "..\\..\\DefGlobal.mqh"
|
2026-01-02 10:21:37 -05:00 | | | #include <TSN\\ICTLibrary\\Liquidity.mqh>
|
| | | #include <TSN\\MQLArticles\\Strategy\\Main.mqh>
|
| | | #include <TSN\\MQLArticles\\PosMgmt\\Trailing Stop.mqh>
|
2026-11-01 22:12:14 -05:00 | | | #include <TSN\\MQLArticles\\RM\\RiskManagement.mqh>
|
2025-11-26 07:19:36 -05:00 | | |
|
2026-11-01 22:12:14 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2025-11-26 07:19:36 -05:00 | | | /*
|
| | | Fuente: https://www.youtube.com/watch?v=Up-Vs2afNGs&t=278s | @InstitucionalTradingLab
|
| | | */
|
| | |
|
| | | IBlocksGen* g_block; // Bloque fvg o tick
|
| | | CSwingBar* swing_externo; //15M
|
2025-12-27 19:14:26 -05:00 | | | CSessionManager<CTradingSession, ICTContainer<CTradingSession>> sesion;
|
2026-10-23 21:51:38 -05:00 | | | TSN::CRiskManagemet* risk;
|
2025-11-26 07:19:36 -05:00 | | | CLiquidity sweep;
|
| | |
|
| | | #define LIQ_TIPO_SWING 0
|
| | |
|
2026-11-06 15:36:06 -05:00 | | | //--- Estados de la estrategia (en vez de flags)
|
| | | enum ENUM_S1_STATE
|
| | | {
|
| | | S1_STATE_BUSCAR_SWEEP, // esperando un sweep de liquidez (swing externo)
|
| | |
|
| | | //---
|
| | | S1_STATE_BUSCAR_PDA_VENTA, // sweep al alza: se espera un bloque bajista mitigado para vender
|
| | | S1_STATE_BUSCAR_PDA_COMPRA, // sweep a la baja: se espera un bloque alcista mitigado para comprar
|
| | | };
|
| | |
|
2025-11-26 07:19:36 -05:00 | | | //---
|
| | | enum ENUM_BLOQUE_TO_USE
|
| | | {
|
| | | USE_OB, // Order block
|
| | | USE_FVG // Fvg
|
| | | };
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Estrategia que implementa el uso de la libreria ICTLIbrary |
|
| | | //+------------------------------------------------------------------+
|
2026-10-23 21:51:38 -05:00 | | | class CEstrategia : public TSN::CStrategyBase
|
2025-11-26 07:19:36 -05:00 | | | {
|
| | | private:
|
2026-11-06 15:36:06 -05:00 | | | ENUM_S1_STATE m_state; // Estado actual de la estrategia
|
| | | int m_curr_idx; // Indice actual de la sesion
|
| | | ulong m_last_ticket; // Ultimo ticket abierto
|
| | | bool m_confirm; // Confirmar
|
2025-11-26 07:19:36 -05:00 | | |
|
| | | //---
|
| | | void OpenOrder(ENUM_POSITION_TYPE type);
|
| | | void Clean();
|
| | |
|
| | |
|
| | | //---
|
2026-11-06 15:36:06 -05:00 | | | bool CheckSwingAlignment();
|
2025-11-26 07:19:36 -05:00 | | |
|
| | | public:
|
| | | CEstrategia(ulong magic_number_, string symbol_, ENUM_TIMEFRAMES timeframe_ = PERIOD_CURRENT, long chart_id_ = 0,
|
| | | int subwindow_ = 0, ulong max_deviation_ = NO_MAX_DEVIATION_DEFINED);
|
| | |
|
| | |
|
2026-11-06 15:36:06 -05:00 | | | //---
|
2025-11-26 07:19:36 -05:00 | | | void Set(bool usar_confirmacion_Extra);
|
2026-11-06 15:36:06 -05:00 | | |
|
| | | //---
|
| | | void OnNewBar(const datetime curr_time) override final;
|
| | | void OnTick(const datetime curr_time) override final { }
|
| | | void OnInterupcion() override final;
|
| | |
|
| | | //---
|
| | | inline ulong GetLastTicket() const { return m_last_ticket; }
|
2025-11-26 07:19:36 -05:00 | | | };
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | CEstrategia::CEstrategia(ulong magic_number_, string symbol_, ENUM_TIMEFRAMES timeframe_ = PERIOD_CURRENT, long chart_id_ = 0,
|
| | | int subwindow_ = 0, ulong max_deviation_ = NO_MAX_DEVIATION_DEFINED)
|
2026-11-06 15:36:06 -05:00 | | | : CStrategyBase(magic_number_, symbol_, timeframe_, chart_id_, subwindow_, max_deviation_, "TradingLabS1"),
|
| | | m_last_ticket(INVALID_TICKET), m_state(S1_STATE_BUSCAR_SWEEP), m_curr_idx(INVALID_SESION)
|
2025-11-26 07:19:36 -05:00 | | | {
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void CEstrategia::Set(bool usar_confirmacion_Extra)
|
| | | {
|
2026-11-06 15:36:06 -05:00 | | | m_confirm = usar_confirmacion_Extra;
|
2025-11-26 07:19:36 -05:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void CEstrategia::Clean(void)
|
| | | {
|
2026-11-06 15:36:06 -05:00 | | | m_state = S1_STATE_BUSCAR_SWEEP;
|
| | | m_curr_idx = INVALID_SESION;
|
2025-11-26 07:19:36 -05:00 | | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-02-14 17:50:28 -05:00 | | | void CEstrategia::OnNewBar(const datetime curr_time)
|
2025-11-26 07:19:36 -05:00 | | | {
|
| | | if(risk.GetPositionsTotal() > 0)
|
| | | return;
|
| | |
|
| | | //--- Obtenemos el indice de la seison actual
|
2026-11-06 15:36:06 -05:00 | | | m_curr_idx = sesion.GetSesionActualIdx();
|
2025-11-26 07:19:36 -05:00 | | |
|
2026-11-06 15:36:06 -05:00 | | | //--- Logica (un paso por vela, igual que EasySb)
|
| | | if(m_curr_idx != INVALID_SESION)
|
2025-11-26 07:19:36 -05:00 | | | {
|
2026-11-06 15:36:06 -05:00 | | | switch(m_state)
|
2025-11-26 07:19:36 -05:00 | | | {
|
2026-11-06 15:36:06 -05:00 | | | //--- Esperando un sweep de la liquidez, la direccion de la entrada es la contraria al sweep
|
| | | case S1_STATE_BUSCAR_SWEEP:
|
2025-11-26 07:19:36 -05:00 | | | {
|
2026-11-06 15:36:06 -05:00 | | | if(m_confirm && CheckSwingAlignment()) // Solo si hay confiramcion previa corremos el chek
|
| | | break;
|
| | |
|
| | | if(sweep.NuevaManipulacionAlAlza())
|
2025-11-26 07:19:36 -05:00 | | | {
|
2026-11-06 15:36:06 -05:00 | | | LogInfo("Nuevo sweep arriba", FUNCION_ACTUAL);
|
| | | m_state = S1_STATE_BUSCAR_PDA_VENTA;
|
2025-11-26 07:19:36 -05:00 | | | }
|
2026-11-06 15:36:06 -05:00 | | | else
|
| | | if(sweep.NuevaManipulacionAlaBaja())
|
| | | {
|
| | | LogInfo("Nuevo sweep abajo", FUNCION_ACTUAL);
|
| | | m_state = S1_STATE_BUSCAR_PDA_COMPRA;
|
| | | }
|
| | | break;
|
| | | }
|
| | |
|
| | | //--- Entrada de venta: se mitigo un bloque bajista
|
| | | case S1_STATE_BUSCAR_PDA_VENTA:
|
2025-11-26 07:19:36 -05:00 | | | {
|
2026-11-06 15:36:06 -05:00 | | | if(g_block.SizeBajistasMitigados() > 0)
|
| | | OpenOrder(POSITION_TYPE_SELL);
|
| | | break;
|
2025-11-26 07:19:36 -05:00 | | | }
|
2026-11-06 15:36:06 -05:00 | | |
|
| | | //--- Entrada de compra: se mitigo un bloque alcista
|
| | | case S1_STATE_BUSCAR_PDA_COMPRA:
|
| | | {
|
| | | if(g_block.SizeAlcistasMitigados() > 0)
|
| | | OpenOrder(POSITION_TYPE_BUY);
|
| | | break;
|
| | | }
|
| | | default:
|
| | | break;
|
| | | }
|
2025-11-26 07:19:36 -05:00 | | | }
|
| | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Open Order Default |
|
| | | //+------------------------------------------------------------------+
|
| | | 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);
|
| | |
|
2026-11-01 22:12:14 -05:00 | | | risk.SetStopLoss(m_symbol, entry - sl);
|
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);
|
| | | if(m_trade.Buy(l, m_symbol, entry, sl, tp, "Ea buy"))
|
2026-11-06 15:36:06 -05:00 | | | m_last_ticket = m_trade.ResultOrder();
|
2025-11-26 07:19:36 -05:00 | | | }
|
| | | 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);
|
| | |
|
2026-11-01 22:12:14 -05:00 | | | risk.SetStopLoss(m_symbol, sl - entry);
|
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);
|
| | | if(m_trade.Sell(l, m_symbol, entry, sl, tp, "Ea sell"))
|
2026-11-06 15:36:06 -05:00 | | | m_last_ticket = m_trade.ResultOrder();
|
2025-11-26 07:19:36 -05:00 | | | }
|
| | |
|
2026-11-06 15:36:06 -05:00 | | | //---
|
2025-11-26 07:19:36 -05:00 | | | Clean();
|
| | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-11-06 15:36:06 -05:00 | | | bool CEstrategia::CheckSwingAlignment()
|
2025-11-26 07:19:36 -05:00 | | | {
|
| | | // Get recent price data for external timeframe (M15)
|
2026-11-06 15:36:06 -05:00 | | | double externo_close_0 = iClose(m_symbol, PERIOD_M15, 0);
|
| | | double externo_close_1 = iClose(m_symbol, PERIOD_M15, 1);
|
| | | double externo_close_2 = iClose(m_symbol, PERIOD_M15, 2);
|
2025-11-26 07:19:36 -05:00 | | |
|
| | | // Get recent price data for mid timeframe (H1)
|
2026-11-06 15:36:06 -05:00 | | | double mid_close_0 = iClose(m_symbol, PERIOD_H1, 0);
|
| | | double mid_close_1 = iClose(m_symbol, PERIOD_H1, 1);
|
| | | double mid_close_2 = iClose(m_symbol, PERIOD_H1, 2);
|
2025-11-26 07:19:36 -05:00 | | |
|
| | | // Determine trend direction for external timeframe (M15)
|
| | | bool externo_trend_bullish = (externo_close_0 > externo_close_1) && (externo_close_1 > externo_close_2);
|
| | | bool externo_trend_bearish = (externo_close_0 < externo_close_1) && (externo_close_1 < externo_close_2);
|
| | |
|
| | | // Determine trend direction for mid timeframe (H1)
|
| | | bool mid_trend_bullish = (mid_close_0 > mid_close_1) && (mid_close_1 > mid_close_2);
|
| | | bool mid_trend_bearish = (mid_close_0 < mid_close_1) && (mid_close_1 < mid_close_2);
|
| | |
|
| | | // Only allow trades when both timeframes show clear directional alignment
|
| | | bool aligned_bullish = externo_trend_bullish && mid_trend_bullish;
|
| | | bool aligned_bearish = externo_trend_bearish && mid_trend_bearish;
|
| | |
|
| | | return (aligned_bullish || aligned_bearish);
|
| | | }
|
| | |
|
2026-11-06 15:36:06 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void CEstrategia::OnInterupcion()
|
| | | {
|
| | | g_block.SetParo();
|
| | | sweep.SetParo();
|
| | | }
|
| | | //+------------------------------------------------------------------+
|
| | |
|
| | |
|
2025-11-26 07:19:36 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | void Liq_AddSwing()
|
| | | {
|
| | | const int idx_a = swing_externo.HayUnNuevoSwing(SWING_ALCISTA);
|
| | | const int idx_b = swing_externo.HayUnNuevoSwing(SWING_BAJISTA);
|
| | |
|
| | | //--- Nuevo, usamos directamente la funcion sobrecargada
|
| | | if(idx_a >= 0)
|
| | | {
|
| | | sweep.AddLiquidityLevel(swing_externo.GetSwingsAlcistas(idx_a), LIQ_TIPO_SWING, LIQUIDITY_BULL);
|
| | | }
|
| | | else
|
| | | if(idx_b >= 0)
|
| | | {
|
| | | sweep.AddLiquidityLevel(swing_externo.GetSwingsBasjitas(idx_b), LIQ_TIPO_SWING, LIQUIDITY_BEAR);
|
| | | }
|
| | | }
|
| | | //+------------------------------------------------------------------+
|