A estratégia Mean Reversion é uma porta direta do consultor especialista MetaTrader Mean reversion.mq4. A versão StockSharp mantém a ideia comercial original: comprar após uma longa série de fechamentos decrescentes e vender após uma corrida de alta semelhante. As entradas são confirmadas pelo alinhamento de tendências usando duas médias móveis lineares ponderadas, força de impulso em um período de tempo mais alto e um filtro mensal MACD.
Uma vez posicionada, a estratégia recria as regras de gerenciamento de dinheiro da versão MQL: stop-loss e take-profit configuráveis em pips, realocação opcional do ponto de equilíbrio e um trailing stop que bloqueia os lucros à medida que o mercado se move a favor da negociação.
Lógica de negociação
Período de sinal – a estratégia opera na série de velas selecionada (padrão 15 minutos).
Detecção de exaustão – coleta os últimos BarsToCount fechamentos. Uma configuração longa exige que o fechamento mais recente seja inferior a cada um dos fechamentos anteriores, sinalizando uma liquidação. Uma configuração curta precisa da condição oposta.
Filtro de tendência – LWMA rápido (comprimento FastMaLength) deve estar acima do LWMA lento (SlowMaLength) para posições compradas e abaixo para posições vendidas.
Filtro de impulso – o indicador de impulso (período MomentumLength) é calculado no período de tempo superior do estilo MetaTrader (M15 → H1, H1 → D1, etc.). Pelo menos uma das últimas três leituras de momento deve divergir de 100 em mais de MomentumThreshold.
MACD confirmação – um MACD mensal (26/12/9) deve ter a linha principal acima da linha de sinal para posições compradas e abaixo para posições vendidas.
Se todas as condições forem satisfeitas, a estratégia abre uma posição usando OrderVolume. As negociações opostas achatam a posição atual antes de reverter.
Gerenciamento de posição
Stop-loss e take-profit – configurados em pips via StopLossPips e TakeProfitPips.
Ponto de equilíbrio – quando ativado, o stop é movido para o preço de entrada mais BreakEvenOffsetPips após o preço avançar em BreakEvenTriggerPips.
Trailing Stop – se EnableTrailing for verdadeiro e o lucro não realizado exceder TrailingStopPips, o stop segue o preço com a etapa TrailingStepPips.
Todas as conversões de preço usam o tamanho do pip do instrumento para corresponder ao comportamento MetaTrader.
Parâmetros
Nome
Descrição
Padrão
OrderVolume
Tamanho do pedido usado para entradas no mercado.
1
CandleType
Série de velas primárias usadas para sinais.
M15
BarsToCount
Número de fechamentos anteriores verificados quanto à exaustão.
10
FastMaLength
Período LWMA rápido.
6
SlowMaLength
Período LWMA lento.
85
MomentumLength
Período de impulso no período de tempo superior.
14
MomentumThreshold
Desvio absoluto mínimo de 100 para confirmação do impulso.
0.3
StopLossPips
Distância de stop-loss em pips.
20
TakeProfitPips
Distância de lucro em pips.
50
UseBreakEven
Habilite a relocação de parada para atingir o ponto de equilíbrio.
false
BreakEvenTriggerPips
Lucro em pips necessário antes de mover o stop.
30
BreakEvenOffsetPips
Pips extras adicionados ao passar para o ponto de equilíbrio.
30
EnableTrailing
Ative o gerenciamento de trailing stop.
true
TrailingStopPips
Lucro em pips necessário para iniciar o trailing.
40
TrailingStepPips
Distância mantida pelo trailing stop.
40
Notas
O prazo mais alto para o impulso segue MetaTrader etapas: M1→M15, M5→M30, M15→H1, M30→H4, H1→D1, H4→W1, D1→MN1, W1→MN1.
A confirmação de MACD sempre usa o período mensal (MN1).
A estratégia espera tipos de velas baseadas em prazos; velas de tick ou intervalo não são suportadas.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Mean Reversion" MetaTrader expert.
/// Buys after multi-bar sell-off when RSI is oversold, sells after multi-bar rally when RSI is overbought.
/// Uses consecutive bar count for exhaustion detection with RSI confirmation.
/// </summary>
public class MeanReversionMomentumStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _barsToCount;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<decimal> _rsiOversold;
private RelativeStrengthIndex _rsi;
private readonly List<decimal> _closeHistory = new();
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BarsToCount
{
get => _barsToCount.Value;
set => _barsToCount.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
public MeanReversionMomentumStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Primary timeframe", "General");
_barsToCount = Param(nameof(BarsToCount), 5)
.SetGreaterThanZero()
.SetDisplay("Bars To Count", "Number of consecutive bars for exhaustion detection", "Signal");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period for confirmation", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "RSI level for sell signal", "Signals");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "RSI level for buy signal", "Signals");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_closeHistory.Clear();
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
_closeHistory.Add(candle.ClosePrice);
if (_closeHistory.Count > BarsToCount + 1)
_closeHistory.RemoveAt(0);
if (!_rsi.IsFormed || _closeHistory.Count < BarsToCount + 1)
return;
var volume = Volume;
if (volume <= 0)
volume = 1;
// Count consecutive down bars
var downCount = 0;
for (int i = _closeHistory.Count - 1; i >= 1; i--)
{
if (_closeHistory[i] < _closeHistory[i - 1])
downCount++;
else
break;
}
// Count consecutive up bars
var upCount = 0;
for (int i = _closeHistory.Count - 1; i >= 1; i--)
{
if (_closeHistory[i] > _closeHistory[i - 1])
upCount++;
else
break;
}
// Multi-bar sell-off + RSI oversold -> mean reversion buy
if (downCount >= BarsToCount && rsiValue < RsiOversold)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
if (Position <= 0)
BuyMarket(volume);
}
// Multi-bar rally + RSI overbought -> mean reversion sell
else if (upCount >= BarsToCount && rsiValue > RsiOverbought)
{
if (Position > 0)
SellMarket(Position);
if (Position >= 0)
SellMarket(volume);
}
}
/// <inheritdoc />
protected override void OnReseted()
{
_closeHistory.Clear();
_rsi = null;
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 mean_reversion_momentum_strategy(Strategy):
def __init__(self):
super(mean_reversion_momentum_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._bars_to_count = self.Param("BarsToCount", 5)
self._rsi_period = self.Param("RsiPeriod", 14)
self._rsi_overbought = self.Param("RsiOverbought", 70.0)
self._rsi_oversold = self.Param("RsiOversold", 30.0)
self._close_history = []
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def BarsToCount(self):
return self._bars_to_count.Value
@BarsToCount.setter
def BarsToCount(self, value):
self._bars_to_count.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def RsiOverbought(self):
return self._rsi_overbought.Value
@RsiOverbought.setter
def RsiOverbought(self, value):
self._rsi_overbought.Value = value
@property
def RsiOversold(self):
return self._rsi_oversold.Value
@RsiOversold.setter
def RsiOversold(self, value):
self._rsi_oversold.Value = value
def OnReseted(self):
super(mean_reversion_momentum_strategy, self).OnReseted()
self._close_history = []
def OnStarted2(self, time):
super(mean_reversion_momentum_strategy, self).OnStarted2(time)
self._close_history = []
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
rsi_val = float(rsi_value)
bars_to_count = self.BarsToCount
self._close_history.append(close)
while len(self._close_history) > bars_to_count + 1:
self._close_history.pop(0)
if len(self._close_history) < bars_to_count + 1:
return
# Count consecutive down bars
down_count = 0
for i in range(len(self._close_history) - 1, 0, -1):
if self._close_history[i] < self._close_history[i - 1]:
down_count += 1
else:
break
# Count consecutive up bars
up_count = 0
for i in range(len(self._close_history) - 1, 0, -1):
if self._close_history[i] > self._close_history[i - 1]:
up_count += 1
else:
break
# Multi-bar sell-off + RSI oversold -> mean reversion buy
if down_count >= bars_to_count and rsi_val < float(self.RsiOversold):
if self.Position <= 0:
self.BuyMarket()
# Multi-bar rally + RSI overbought -> mean reversion sell
elif up_count >= bars_to_count and rsi_val > float(self.RsiOverbought):
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return mean_reversion_momentum_strategy()