Estrategia Tres Indicadores
Descripción general
Esta estrategia es una conversión de StockSharp del expert original "Three indicators" de MQL5. Evalúa tres osciladores clásicos—MACD, Oscilador Estocástico y RSI—en cada vela terminada del marco temporal seleccionado. Solo cuando todos los filtros se alinean la estrategia entra en una posición, asegurando que cada operación siga una confirmación multi-indicador consistente.
Lógica de trading
- Filtro de dirección de vela – compara el precio de apertura de la vela terminada actual con el precio de apertura de la anterior. Una apertura más alta favorece operaciones largas, una apertura más baja favorece cortos.
- Filtro de pendiente MACD – observa la pendiente de la línea principal MACD (diferencia entre el valor MACD principal actual y el anterior). Un MACD en caída favorece posiciones largas, un MACD en ascenso favorece cortos, exactamente como en el experto de origen.
- Filtro de sesgo estocástico – comprueba si el valor %D está por debajo o por encima del punto medio 50. Valores por debajo de 50 apoyan largos, valores por encima de 50 apoyan cortos.
- Filtro de sesgo RSI – usa el valor RSI relativo a 50. Valores por debajo de 50 autorizan largos, valores por encima de 50 autorizan cortos.
Solo si los cuatro filtros apoyan la misma dirección abrirá la estrategia una nueva operación. Si aparece una señal opuesta mientras hay una posición abierta, la estrategia revierte inmediatamente enviando una única orden de mercado que cierra la exposición existente y abre la nueva dirección, reflejando el comportamiento de la lógica MQL original.
Parámetros
| Parámetro |
Descripción |
CandleType |
Marco temporal de las velas suministradas a la estrategia. Predeterminado: 1 minuto. |
TradeVolume |
Volumen usado al abrir una posición o revertir al lado opuesto. |
MacdFastPeriod |
Longitud de la EMA rápida dentro del cálculo MACD. |
MacdSlowPeriod |
Longitud de la EMA lenta dentro del cálculo MACD. |
MacdSignalPeriod |
Longitud de la EMA para la línea de señal MACD. |
MacdPriceType |
Precio aplicado al indicador MACD (Close, Open, High, Low, Median, Typical, Weighted). |
StochasticKPeriod |
Período de retroceso para la línea %K. |
StochasticDPeriod |
Período de suavizado para la línea %D. |
StochasticSlowing |
Suavizado adicional aplicado a %K antes de calcular %D. |
RsiPeriod |
Período de promediado usado por el filtro RSI. |
RsiPriceType |
Precio aplicado al alimentar el indicador RSI. |
Indicadores
- MACD (Convergencia/Divergencia de Medias Móviles) – configurado con los períodos rápido, lento y de señal especificados por el usuario.
- Oscilador Estocástico – usa la implementación de StockSharp con longitudes %K/%D y suavizado configurables.
- Índice de Fuerza Relativa (RSI) – proporciona la confirmación de impulso final.
Notas de comportamiento
- La estrategia procesa solo velas terminadas, mejorando la estabilidad en comparación con el desencadenador basado en ticks del experto original.
- La pausa de 30 segundos presente en la versión MQL se elimina; las reversiones se emiten inmediatamente con la orden de mercado combinada.
- El suavizado estocástico usa la implementación de media móvil predeterminada de StockSharp, que corresponde al suavizado estándar basado en SMA del script original.
- La selección de fuente de precio para MACD y RSI se proporciona a través del enum
IndicatorAppliedPrice, coincidiendo con las opciones disponibles en MetaTrader (Close, Open, High, Low, Median, Typical, Weighted).
Gestión de riesgo
No se colocan órdenes de stop-loss o take-profit automáticamente. La gestión de posición está impulsada exclusivamente por la lógica de reversión multi-indicador. Agregar controles de riesgo externos si se requiere.
Consejos de uso
- Seleccionar el instrumento y marco temporal deseados a través de
CandleType.
- Ajustar los parámetros del indicador para adecuarse a la volatilidad del mercado y la frecuencia de señales.
- Monitorear los objetos de gráfico añadidos por la estrategia (velas más los tres indicadores) para validar la alineación de señales.
- Combinar con gestión de dinero externa si se requieren stops fijos o objetivos de beneficio.
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Combines MACD, Stochastic Oscillator, and RSI filters.
/// All three indicators must agree on direction to enter a trade.
/// </summary>
public class ThreeIndicatorsStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _macdFastPeriod;
private readonly StrategyParam<int> _macdSlowPeriod;
private readonly StrategyParam<int> _macdSignalPeriod;
private readonly StrategyParam<int> _stochasticKPeriod;
private readonly StrategyParam<int> _stochasticDPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _signalCooldownBars;
private decimal? _previousOpen;
private decimal? _previousMacdMain;
private int _previousCompositeSignal;
private int _cooldownRemaining;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int MacdFastPeriod { get => _macdFastPeriod.Value; set => _macdFastPeriod.Value = value; }
public int MacdSlowPeriod { get => _macdSlowPeriod.Value; set => _macdSlowPeriod.Value = value; }
public int MacdSignalPeriod { get => _macdSignalPeriod.Value; set => _macdSignalPeriod.Value = value; }
public int StochasticKPeriod { get => _stochasticKPeriod.Value; set => _stochasticKPeriod.Value = value; }
public int StochasticDPeriod { get => _stochasticDPeriod.Value; set => _stochasticDPeriod.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public int SignalCooldownBars { get => _signalCooldownBars.Value; set => _signalCooldownBars.Value = value; }
public ThreeIndicatorsStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle type", "Primary timeframe", "General");
_macdFastPeriod = Param(nameof(MacdFastPeriod), 11)
.SetDisplay("MACD fast", "Fast EMA length", "MACD");
_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 53)
.SetDisplay("MACD slow", "Slow EMA length", "MACD");
_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 26)
.SetDisplay("MACD signal", "Signal smoothing", "MACD");
_stochasticKPeriod = Param(nameof(StochasticKPeriod), 40)
.SetDisplay("Stochastic %K", "%K length", "Stochastic");
_stochasticDPeriod = Param(nameof(StochasticDPeriod), 23)
.SetDisplay("Stochastic %D", "%D smoothing", "Stochastic");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI period", "RSI length", "RSI");
_signalCooldownBars = Param(nameof(SignalCooldownBars), 2)
.SetNotNegative()
.SetDisplay("Signal Cooldown Bars", "Closed candles to wait before a new entry", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_previousOpen = null;
_previousMacdMain = null;
_previousCompositeSignal = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_previousOpen = null;
_previousMacdMain = null;
_previousCompositeSignal = 0;
_cooldownRemaining = 0;
var macd = new MovingAverageConvergenceDivergenceSignal();
macd.Macd.ShortMa.Length = MacdFastPeriod;
macd.Macd.LongMa.Length = MacdSlowPeriod;
macd.SignalMa.Length = MacdSignalPeriod;
var stochastic = new StochasticOscillator();
stochastic.K.Length = StochasticKPeriod;
stochastic.D.Length = StochasticDPeriod;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, stochastic, rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue stochValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFinal || !stochValue.IsFinal || !rsiValue.IsFinal)
return;
if (_cooldownRemaining > 0)
_cooldownRemaining--;
if (!macdValue.IsFormed || !stochValue.IsFormed || !rsiValue.IsFormed)
return;
var macdVal = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
var macdMain = macdVal.Macd ?? 0m;
var stoch = (StochasticOscillatorValue)stochValue;
var stochasticD = stoch.D ?? 50m;
var rsi = rsiValue.GetValue<decimal>();
if (_previousOpen == null || _previousMacdMain == null)
{
_previousOpen = candle.OpenPrice;
_previousMacdMain = macdMain;
return;
}
// Candle direction
var candleSignal = candle.OpenPrice > _previousOpen.Value ? 1 : candle.OpenPrice < _previousOpen.Value ? -1 : 0;
// MACD direction (difference decreasing = bullish momentum)
var macdDelta = macdMain - _previousMacdMain.Value;
var macdSignal = macdDelta < 0m ? 1 : macdDelta > 0m ? -1 : 0;
// Stochastic direction
var stochSignal = stochasticD < 50m ? 1 : stochasticD > 50m ? -1 : 0;
// RSI direction
var rsiSignal = rsi < 50m ? 1 : rsi > 50m ? -1 : 0;
var longSignal = candleSignal >= 0 && macdSignal >= 0 && stochSignal >= 0 && rsiSignal >= 0;
var shortSignal = candleSignal <= 0 && macdSignal <= 0 && stochSignal <= 0 && rsiSignal <= 0;
var compositeSignal = longSignal ? 1 : shortSignal ? -1 : 0;
if (_cooldownRemaining == 0 && compositeSignal != 0 && compositeSignal != _previousCompositeSignal)
{
if (compositeSignal > 0 && Position <= 0)
{
BuyMarket(Volume + (Position < 0 ? -Position : 0m));
_cooldownRemaining = SignalCooldownBars;
}
else if (compositeSignal < 0 && Position >= 0)
{
SellMarket(Volume + (Position > 0 ? Position : 0m));
_cooldownRemaining = SignalCooldownBars;
}
}
_previousOpen = candle.OpenPrice;
_previousMacdMain = macdMain;
_previousCompositeSignal = compositeSignal;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import (
MovingAverageConvergenceDivergenceSignal,
StochasticOscillator,
RelativeStrengthIndex,
)
from StockSharp.Algo.Strategies import Strategy
class three_indicators_strategy(Strategy):
def __init__(self):
super(three_indicators_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle type", "Primary timeframe", "General")
self._macd_fast_period = self.Param("MacdFastPeriod", 11) \
.SetDisplay("MACD fast", "Fast EMA length", "MACD")
self._macd_slow_period = self.Param("MacdSlowPeriod", 53) \
.SetDisplay("MACD slow", "Slow EMA length", "MACD")
self._macd_signal_period = self.Param("MacdSignalPeriod", 26) \
.SetDisplay("MACD signal", "Signal smoothing", "MACD")
self._stochastic_k_period = self.Param("StochasticKPeriod", 40) \
.SetDisplay("Stochastic %K", "%K length", "Stochastic")
self._stochastic_d_period = self.Param("StochasticDPeriod", 23) \
.SetDisplay("Stochastic %D", "%D smoothing", "Stochastic")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI period", "RSI length", "RSI")
self._signal_cooldown_bars = self.Param("SignalCooldownBars", 2) \
.SetDisplay("Signal Cooldown Bars", "Closed candles to wait before a new entry", "General")
self._previous_open = None
self._previous_macd_main = None
self._previous_composite_signal = 0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
@property
def macd_fast_period(self):
return self._macd_fast_period.Value
@property
def macd_slow_period(self):
return self._macd_slow_period.Value
@property
def macd_signal_period(self):
return self._macd_signal_period.Value
@property
def stochastic_k_period(self):
return self._stochastic_k_period.Value
@property
def stochastic_d_period(self):
return self._stochastic_d_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def signal_cooldown_bars(self):
return self._signal_cooldown_bars.Value
def OnReseted(self):
super(three_indicators_strategy, self).OnReseted()
self._previous_open = None
self._previous_macd_main = None
self._previous_composite_signal = 0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(three_indicators_strategy, self).OnStarted2(time)
self._previous_open = None
self._previous_macd_main = None
self._previous_composite_signal = 0
self._cooldown_remaining = 0
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.macd_fast_period
macd.Macd.LongMa.Length = self.macd_slow_period
macd.SignalMa.Length = self.macd_signal_period
stochastic = StochasticOscillator()
stochastic.K.Length = self.stochastic_k_period
stochastic.D.Length = self.stochastic_d_period
rsi = RelativeStrengthIndex()
rsi.Length = self.rsi_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(macd, stochastic, rsi, self._process_candle).Start()
def _process_candle(self, candle, macd_value, stoch_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not stoch_value.IsFinal or not rsi_value.IsFinal:
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
if not macd_value.IsFormed or not stoch_value.IsFormed or not rsi_value.IsFormed:
return
macd_main = macd_value.Macd if macd_value.Macd is not None else 0.0
stochastic_d = stoch_value.D if stoch_value.D is not None else 50.0
rsi = float(rsi_value)
if self._previous_open is None or self._previous_macd_main is None:
self._previous_open = float(candle.OpenPrice)
self._previous_macd_main = float(macd_main)
return
open_price = float(candle.OpenPrice)
# Candle direction
if open_price > self._previous_open:
candle_signal = 1
elif open_price < self._previous_open:
candle_signal = -1
else:
candle_signal = 0
# MACD direction
macd_delta = float(macd_main) - self._previous_macd_main
if macd_delta < 0:
macd_signal = 1
elif macd_delta > 0:
macd_signal = -1
else:
macd_signal = 0
# Stochastic direction
stoch_d_val = float(stochastic_d)
if stoch_d_val < 50.0:
stoch_signal = 1
elif stoch_d_val > 50.0:
stoch_signal = -1
else:
stoch_signal = 0
# RSI direction
if rsi < 50.0:
rsi_signal = 1
elif rsi > 50.0:
rsi_signal = -1
else:
rsi_signal = 0
long_signal = candle_signal >= 0 and macd_signal >= 0 and stoch_signal >= 0 and rsi_signal >= 0
short_signal = candle_signal <= 0 and macd_signal <= 0 and stoch_signal <= 0 and rsi_signal <= 0
if long_signal:
composite_signal = 1
elif short_signal:
composite_signal = -1
else:
composite_signal = 0
if self._cooldown_remaining == 0 and composite_signal != 0 and composite_signal != self._previous_composite_signal:
if composite_signal > 0 and self.Position <= 0:
vol = self.Volume + (-self.Position if self.Position < 0 else 0)
self.BuyMarket(vol)
self._cooldown_remaining = self.signal_cooldown_bars
elif composite_signal < 0 and self.Position >= 0:
vol = self.Volume + (self.Position if self.Position > 0 else 0)
self.SellMarket(vol)
self._cooldown_remaining = self.signal_cooldown_bars
self._previous_open = open_price
self._previous_macd_main = float(macd_main)
self._previous_composite_signal = composite_signal
def CreateClone(self):
return three_indicators_strategy()