RSI Martingale es un puerto del MetaTrader 5 asesor experto RSI&Martingale1.5. La estrategia busca reversiones de impulso esperando hasta que el índice de fuerza relativa (RSI) alcance un valor extremo dentro de una ventana retrospectiva configurable. Cuando aparece un extremo, abre una operación en la dirección de la reversión media esperada y sale cuando RSI cruza la línea media de 50 o cuando se alcanza un objetivo fijo de parada/toma. Opcionalmente, un módulo martingala puede reabrir la posición en la dirección opuesta con un mayor volumen después de una operación perdedora. Los límites diarios de pérdidas y ganancias, junto con los filtros horarios, permiten suspender las operaciones durante sesiones más riesgosas o después de alcanzar los objetivos de preservación de capital.
Lógica estratégica
RSI extremos
Indicador: un único RSI calculado sobre el tipo de vela seleccionado. Se debe formar el indicador (suficientes datos históricos) antes de considerar las operaciones.
Detección mínima: si el último valor de RSI es menor o igual a cada valor de RSI dentro de la ventana Bars For Extremes configurada y el valor está por debajo de 50, la estrategia abre una posición larga.
Detección máxima: si el último valor de RSI es mayor o igual a todos los valores dentro de la ventana retrospectiva y el valor es superior a 50, la estrategia abre una posición corta.
Gestión de posiciones
Activador de salida: las posiciones se cierran cuando RSI cruza la línea neutral 50 hacia el lado opuesto (los largos salen por encima de 50, los cortos salen por debajo de 50).
Objetivos fijos: distancias opcionales de stop-loss y take-profit expresadas en pips. Cuando está habilitada, la estrategia compara el máximo/mínimo de la vela más reciente con esos precios objetivo y cierra la posición si se alcanza cualquiera de los niveles.
Alineación del volumen: cada volumen de pedido está alineado con la configuración de paso, mínimo y máximo del valor antes del envío.
Martingale recuperación
Activador: después de que una posición se cierra con una ganancia negativa, la estrategia recuerda la dirección y el volumen de la operación perdedora.
Reingreso: en la siguiente vela elegible, y solo si no hay ninguna posición abierta, puede abrir inmediatamente una operación en la dirección opuesta. El volumen es el volumen perdedor multiplicado por Martingale Multiplier o la base Initial Volume dependiendo del interruptor Enable Martingale.
Restablecer: una vez enviada la orden de martingala, la información de pérdida almacenada se borra para evitar intentos repetidos.
Control diario de capital
Línea de base: la estrategia captura el capital de la cuenta al comienzo de cada día de negociación y restablece el indicador de suspensión.
Ventana de monitoreo: los límites diarios se evalúan solo entre Daily Control Start y Daily Control End horas.
Suspensión: si el capital crece más allá de Daily Profit % o cae por debajo de Daily Loss %, la estrategia cierra cualquier posición abierta y omite nuevas operaciones hasta el día siguiente.
Filtros de sesión
Ventana de negociación: se permiten nuevas posiciones solo cuando la hora actual es entre Trading Start y Trading End (inclusive).
Evitación de horas: 24 parámetros booleanos reflejan la configuración de "evitación de noticias" de la fuente EA y bloquean el comercio durante las horas seleccionadas.
Parámetros
Volumen inicial: volumen de pedido base para entradas estándar.
RSI Período: número de períodos utilizados por el indicador RSI.
Bars For Extremes: cuántas velas terminadas se escanean cuando se busca el último RSI mínimo o máximo.
Take Profit (pips) – distancia al take-profit fijo; configúrelo en 0 para deshabilitarlo.
Stop Loss (pips) – distancia hasta el stop-loss fijo; configúrelo en 0 para deshabilitarlo.
Habilitar Martingale: habilita el módulo de recuperación de martingala después de una operación perdedora.
Martingale Multiplicador: multiplicador aplicado al volumen perdedor anterior cuando la martingala está activa.
Objetivos diarios: alterna la lógica de suspensión de pérdidas/ganancias diarias.
% de beneficio diario: porcentaje de beneficio que detiene las operaciones del día actual.
% de pérdida diaria: porcentaje de pérdida que detiene la negociación del día actual.
Inicio del control diario / Fin del control diario: límites de horas para evaluar los límites diarios.
Inicio de negociación/Fin de negociación: límites horarios que permiten nuevas posiciones.
Evitar la hora 00... Evitar la hora 23: deshabilita el comercio durante la hora correspondiente.
Tipo de vela: suscripción de vela utilizada para el indicador RSI y todos los cálculos.
Notas adicionales
La estrategia opera únicamente con velas terminadas y no evalúa los ticks intrabar.
Los cálculos de ganancias diarias combinan la estrategia realizada PnL con PnL flotante basada en el último precio de cierre.
No hay ninguna implementación de Python para esta estrategia en el paquete; sólo se proporciona la versión C#.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// RSI extremes strategy with martingale recovery.
/// Buys when RSI is at a local minimum below 50, sells when RSI is at a local maximum above 50.
/// Closes on RSI crossing 50. Doubles volume after a losing trade.
/// </summary>
public class RSIMartingaleStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<int> _barsForCondition;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _recentRsi = new();
private decimal _entryPrice;
private int _direction; // 1=long, -1=short, 0=flat
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public int BarsForCondition
{
get => _barsForCondition.Value;
set => _barsForCondition.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public RSIMartingaleStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetDisplay("RSI Period", "RSI indicator period", "Indicator");
_barsForCondition = Param(nameof(BarsForCondition), 10)
.SetDisplay("Bars For Extremes", "Number of RSI values to check for extremes", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "Data");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_recentRsi.Add(rsiValue);
if (_recentRsi.Count > BarsForCondition)
_recentRsi.RemoveAt(0);
if (_recentRsi.Count < BarsForCondition)
return;
// Check exit: close on RSI crossing 50
if (_direction > 0 && rsiValue > 50)
{
SellMarket();
_direction = 0;
return;
}
else if (_direction < 0 && rsiValue < 50)
{
BuyMarket();
_direction = 0;
return;
}
if (Position != 0)
return;
// Check if current RSI is local minimum (oversold entry)
if (IsLocalMinimum() && rsiValue < 50 && Position <= 0)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_direction = 1;
}
// Check if current RSI is local maximum (overbought entry)
else if (IsLocalMaximum() && rsiValue > 50 && Position >= 0)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_direction = -1;
}
}
private bool IsLocalMinimum()
{
if (_recentRsi.Count < 2)
return false;
var current = _recentRsi[_recentRsi.Count - 1];
for (var i = 0; i < _recentRsi.Count - 1; i++)
{
if (current > _recentRsi[i])
return false;
}
return true;
}
private bool IsLocalMaximum()
{
if (_recentRsi.Count < 2)
return false;
var current = _recentRsi[_recentRsi.Count - 1];
for (var i = 0; i < _recentRsi.Count - 1; i++)
{
if (current < _recentRsi[i])
return false;
}
return true;
}
/// <inheritdoc />
protected override void OnReseted()
{
_recentRsi.Clear();
_entryPrice = 0;
_direction = 0;
base.OnReseted();
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class rsi_martingale_strategy(Strategy):
def __init__(self):
super(rsi_martingale_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._bars_for_condition = self.Param("BarsForCondition", 10)
self._recent_rsi = []
self._entry_price = 0.0
self._direction = 0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def BarsForCondition(self):
return self._bars_for_condition.Value
@BarsForCondition.setter
def BarsForCondition(self, value):
self._bars_for_condition.Value = value
def OnReseted(self):
super(rsi_martingale_strategy, self).OnReseted()
self._recent_rsi = []
self._entry_price = 0.0
self._direction = 0
def OnStarted2(self, time):
super(rsi_martingale_strategy, self).OnStarted2(time)
self._recent_rsi = []
self._entry_price = 0.0
self._direction = 0
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _is_local_minimum(self):
if len(self._recent_rsi) < 2:
return False
current = self._recent_rsi[-1]
for i in range(len(self._recent_rsi) - 1):
if current > self._recent_rsi[i]:
return False
return True
def _is_local_maximum(self):
if len(self._recent_rsi) < 2:
return False
current = self._recent_rsi[-1]
for i in range(len(self._recent_rsi) - 1):
if current < self._recent_rsi[i]:
return False
return True
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
rsi_val = float(rsi_value)
bars_for_cond = self.BarsForCondition
self._recent_rsi.append(rsi_val)
while len(self._recent_rsi) > bars_for_cond:
self._recent_rsi.pop(0)
if len(self._recent_rsi) < bars_for_cond:
return
# Check exit: close on RSI crossing 50
if self._direction > 0 and rsi_val > 50:
self.SellMarket()
self._direction = 0
return
elif self._direction < 0 and rsi_val < 50:
self.BuyMarket()
self._direction = 0
return
if self.Position != 0:
return
close = float(candle.ClosePrice)
# Local minimum + RSI below 50 -> buy
if self._is_local_minimum() and rsi_val < 50 and self.Position <= 0:
self.BuyMarket()
self._entry_price = close
self._direction = 1
# Local maximum + RSI above 50 -> sell
elif self._is_local_maximum() and rsi_val > 50 and self.Position >= 0:
self.SellMarket()
self._entry_price = close
self._direction = -1
def CreateClone(self):
return rsi_martingale_strategy()