RSI Martingale é uma versão do MetaTrader 5 consultor especialista RSI&Martingale1.5. A estratégia procura reversões de impulso aguardando até que o Índice de Força Relativa (RSI) atinja um valor extremo dentro de uma janela de lookback configurável. Quando um extremo aparece, ele abre uma negociação na direção da reversão média esperada e sai quando RSI cruza a linha média 50 ou quando uma meta fixa de stop/take é atingida. Um módulo martingale pode opcionalmente reabrir a posição na direção oposta com um volume aumentado após uma negociação perdida. Os limites diários de lucros e perdas, juntamente com filtros horários, tornam possível suspender a negociação durante sessões mais arriscadas ou após cumprir as metas de preservação de capital.
Lógica estratégica
RSI extremos
Indicador – um único RSI calculado no tipo de vela selecionado. O indicador deve ser formado (dados históricos suficientes) antes que as negociações sejam consideradas.
Detecção mínima – se o valor RSI mais recente for menor ou igual a cada valor RSI dentro da janela Bars For Extremes configurada e o valor estiver abaixo de 50, a estratégia abre uma posição longa.
Detecção máxima – se o valor RSI mais recente for maior ou igual a todos os valores dentro da janela de lookback e o valor estiver acima de 50, a estratégia abre uma posição curta.
Gestão de posição
Gatilho de saída – as posições são fechadas quando RSI cruza a linha neutra 50 para o lado oposto (comprados saem acima de 50, shorts saem abaixo de 50).
Metas fixas – distâncias opcionais de stop-loss e take-profit expressas em pips. Quando ativada, a estratégia compara a máxima/mínima da vela mais recente com os preços-alvo e fecha a posição se qualquer um dos níveis for atingido.
Alinhamento de volume – cada volume de pedido é alinhado à etapa de segurança, configurações mínimas e máximas antes do envio.
Martingale recuperação
Gatilho – após o fechamento de uma posição com lucro negativo, a estratégia lembra a direção e o volume da negociação perdedora.
Reentrada – na próxima vela elegível, e somente se nenhuma posição estiver aberta, ela poderá abrir imediatamente uma negociação na direção oposta. O volume é o volume perdido multiplicado por Martingale Multiplier ou pela base Initial Volume dependendo da opção Enable Martingale.
Redefinir – assim que o pedido de martingale for enviado, as informações de perda armazenadas serão apagadas para evitar tentativas repetidas.
Controle diário de capital
Linha de base – a estratégia captura o patrimônio da conta no início de cada dia de negociação e redefine o sinalizador de suspensão.
Janela de monitoramento – os limites diários são avaliados somente entre Daily Control Start e Daily Control End horas.
Suspensão – se o patrimônio crescer além de Daily Profit % ou cair abaixo de Daily Loss %, a estratégia fecha qualquer posição aberta e pula novas negociações até o dia seguinte.
Filtros de sessão
Janela de negociação – novas posições são permitidas somente quando a hora atual estiver entre Trading Start e Trading End (inclusive).
Evitação de horas – 24 parâmetros booleanos refletem as configurações de “evitar notícias” da fonte EA e bloqueiam a negociação durante as horas selecionadas.
Parâmetros
Volume Inicial – volume base do pedido para lançamentos padrão.
RSI Período – número de períodos usados pelo indicador RSI.
Barras para extremos – quantas velas finalizadas são verificadas ao procurar o mínimo ou máximo RSI mais recente.
Take Profit (pips) – distância até o take-profit fixo; defina como 0 para desativar.
Stop Loss (pips) – distância até o stop-loss fixo; defina como 0 para desativar.
Ativar Martingale – ativa o módulo de recuperação martingale após uma negociação perdida.
Martingale Multiplicador – multiplicador aplicado ao volume perdido anterior quando o martingale está ativo.
Metas Diárias – alterna a lógica diária de suspensão de lucros/perdas.
% de lucro diário – porcentagem de lucro que interrompe a negociação no dia atual.
% de perda diária – porcentagem de perda que interrompe a negociação no dia atual.
Início do Controle Diário/Fim do Controle Diário – limites de horas para avaliar os limites diários.
Início / Fim da Negociação – limites de horas que permitem novas posições.
Evitar a hora 00… Evitar a hora 23 – desativa a negociação durante a hora correspondente.
Tipo de vela – assinatura de vela usada para o indicador RSI e todos os cálculos.
Notas adicionais
A estratégia opera apenas em velas finalizadas e não avalia ticks intrabarras.
Os cálculos de lucro diário combinam o PnL da estratégia realizada com o PnL flutuante com base no último preço de fechamento.
Não há implementação Python para esta estratégia no pacote; apenas a versão C# é fornecida.
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()