A estratégia CDC PL RSI replica o MQL Expert Advisor Expert_ADC_PL_RSI dentro do ecossistema StockSharp. O sistema verifica as velas finalizadas em busca de padrões de reversão de velas japonesas e confirma as entradas com o Índice de Força Relativa (RSI). As negociações longas dependem do padrão Piercing Line durante condições de sobrevenda RSI, enquanto as negociações curtas exigem o padrão Dark Cloud Cover combinado com leituras de sobrecompra RSI. A abordagem mantém o conceito original de gerenciamento de dinheiro simples, usando o volume da estratégia e deixando StockSharp lidar com o dimensionamento da posição.
Lógica de padrões e indicadores
Padrões de velas: A estratégia reconstrói a lógica MetaTrader analisando as duas últimas velas concluídas. As regras Piercing Line e Dark Cloud Cover refletem o código original, incluindo verificações de lacunas, corpos longos em relação a uma média corporal adaptativa e a direção da tendência subjacente.
RSI filtro: um RSI de 20 períodos (otimizável) confirma o impulso. Leituras de sobrevenda (RSI < 40) desbloqueiam entradas longas e leituras de sobrecompra (RSI > 60) desbloqueiam entradas curtas. O histórico RSI também é usado para detectar saídas quando o oscilador cruza os 30 ou 70 níveis na direção oposta.
Média corporal e filtro de tendência: uma média móvel simples dos tamanhos dos corpos das velas e outro SMA de preços de fechamento replicam as funções auxiliares MetaTrader (AvgBody e CloseAvg). Essas médias evitam sinais durante o ruído e garantem que os padrões apareçam após um movimento claro.
Regras de negociação
Configuração longa
Detecte um padrão de linha perfurante nas duas últimas velas concluídas.
Exige que RSI da vela finalizada anterior esteja abaixo de 40.
Se as condições se mantiverem, compre no mercado. Quando existe uma posição oposta, a estratégia inverte comprando o tamanho absoluto da posição mais o volume configurado.
Configuração curta
Detecte um padrão de Dark Cloud Cover nas duas velas mais recentes.
Exige que RSI da vela finalizada anterior esteja acima de 60.
Se as condições se mantiverem, venda no mercado. Uma posição oposta é fechada e revertida usando a mesma lógica de volume.
Condições de saída
Feche as posições longas quando RSI cruzar para baixo até 70 ou cruzar para cima até 30, sinalizando que o impulso diminuiu ou foi revertido.
Feche as posições curtas quando RSI ultrapassar 30 ou descer até 70, espelhando a implementação de MetaTrader.
Parâmetros
Nome
Padrão
Descrição
RsiPeriod
20
RSI comprimento de retrospectiva. Otimizável entre 10 e 40 em passos de 5.
BodyAveragePeriod
14
Período para o tamanho médio do corpo da vela e para o filtro de tendência de preço de fechamento. Otimizável entre 10 e 30 em passos de 5.
CandleType
Período de 1 hora
Série de velas usadas para cálculos. Qualquer tipo de vela compatível com StockSharp pode ser selecionado.
Volume (classe base)
-
Volume de negociação definido na instância da estratégia antes do lançamento.
Uso
Anexe a estratégia a um portfólio e segurança em StockSharp Designer, Shell ou Runner.
Configure o tipo e o volume da vela de acordo com o mercado que está sendo negociado.
Opcionalmente, ajuste os períodos RSI e a média corporal para corresponder à volatilidade do instrumento ou execute otimizações usando o StockSharp Optimizer.
Inicie a estratégia e monitore as sobreposições do gráfico (velas, RSI e linha de média próxima) para revisar as confirmações de padrão e as negociações executadas.
Notas
A estratégia chama StartProtection() para que as rotinas de proteção integradas possam ser configuradas, se necessário (stop-loss, take-profit, trailing, etc.).
Apenas velas concluídas são processadas, mantendo a lógica consistente com o Expert Advisor MQL.
Nenhuma coleção adicional é armazenada; instâncias de indicadores carregam os cálculos de janela deslizante necessários para as verificações de padrão.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// CDC PL RSI strategy: Dark Cloud Cover and Piercing Line candlestick patterns
/// confirmed by RSI levels.
/// </summary>
public class CdcPlRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<int> _signalCooldownCandles;
private readonly List<ICandleMessage> _candles = new();
private decimal _prevRsi;
private bool _hasPrevRsi;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal OversoldLevel { get => _oversoldLevel.Value; set => _oversoldLevel.Value = value; }
public decimal OverboughtLevel { get => _overboughtLevel.Value; set => _overboughtLevel.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public CdcPlRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_oversoldLevel = Param(nameof(OversoldLevel), 40m)
.SetDisplay("Oversold Level", "RSI below this for long entry", "Signals");
_overboughtLevel = Param(nameof(OverboughtLevel), 60m)
.SetDisplay("Overbought Level", "RSI above this for short entry", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candles.Clear();
_prevRsi = 0m;
_hasPrevRsi = false;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_hasPrevRsi = false;
_candlesSinceTrade = SignalCooldownCandles;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(1, UnitTypes.Percent)
);
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
_candles.Add(candle);
if (_candles.Count > 5)
_candles.RemoveAt(0);
if (_candles.Count >= 2 && _hasPrevRsi)
{
var curr = _candles[^1];
var prev = _candles[^2];
// Piercing Line
var isPiercing = prev.OpenPrice > prev.ClosePrice
&& curr.ClosePrice > curr.OpenPrice
&& curr.OpenPrice < prev.LowPrice
&& curr.ClosePrice > (prev.OpenPrice + prev.ClosePrice) / 2m;
// Dark Cloud Cover
var isDarkCloud = prev.ClosePrice > prev.OpenPrice
&& curr.OpenPrice > curr.ClosePrice
&& curr.OpenPrice > prev.HighPrice
&& curr.ClosePrice < (prev.OpenPrice + prev.ClosePrice) / 2m;
if (isPiercing && rsiValue < OversoldLevel && Position == 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (isDarkCloud && rsiValue > OverboughtLevel && Position == 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
_prevRsi = rsiValue;
_hasPrevRsi = true;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class cdc_pl_rsi_strategy(Strategy):
def __init__(self):
super(cdc_pl_rsi_strategy, self).__init__()
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "RSI period", "Indicators")
self._oversold_level = self.Param("OversoldLevel", 40.0) \
.SetDisplay("Oversold Level", "RSI below this for long entry", "Signals")
self._overbought_level = self.Param("OverboughtLevel", 60.0) \
.SetDisplay("Overbought Level", "RSI above this for short entry", "Signals")
self._signal_cooldown = self.Param("SignalCooldownCandles", 6) \
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading")
self._rsi = None
self._candles = []
self._has_prev_rsi = False
self._candles_since_trade = 0
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def oversold_level(self):
return self._oversold_level.Value
@property
def overbought_level(self):
return self._overbought_level.Value
@property
def signal_cooldown(self):
return self._signal_cooldown.Value
def OnReseted(self):
super(cdc_pl_rsi_strategy, self).OnReseted()
self._rsi = None
self._candles = []
self._has_prev_rsi = False
self._candles_since_trade = self.signal_cooldown
def OnStarted2(self, time):
super(cdc_pl_rsi_strategy, self).OnStarted2(time)
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self.rsi_period
self._candles = []
self._has_prev_rsi = False
self._candles_since_trade = self.signal_cooldown
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._rsi, self._process_candle)
subscription.Start()
self.StartProtection(takeProfit=Unit(2, UnitTypes.Percent), stopLoss=Unit(1, UnitTypes.Percent), useMarketOrders=True)
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if not self._rsi.IsFormed:
return
rsi_val = float(rsi_value)
if self._candles_since_trade < self.signal_cooldown:
self._candles_since_trade += 1
self._candles.append(candle)
if len(self._candles) > 5:
self._candles.pop(0)
if len(self._candles) >= 2 and self._has_prev_rsi:
curr = self._candles[-1]
prev = self._candles[-2]
is_piercing = (float(prev.OpenPrice) > float(prev.ClosePrice)
and float(curr.ClosePrice) > float(curr.OpenPrice)
and float(curr.OpenPrice) < float(prev.LowPrice)
and float(curr.ClosePrice) > (float(prev.OpenPrice) + float(prev.ClosePrice)) / 2.0)
is_dark_cloud = (float(prev.ClosePrice) > float(prev.OpenPrice)
and float(curr.OpenPrice) > float(curr.ClosePrice)
and float(curr.OpenPrice) > float(prev.HighPrice)
and float(curr.ClosePrice) < (float(prev.OpenPrice) + float(prev.ClosePrice)) / 2.0)
if is_piercing and rsi_val < self.oversold_level and self.Position == 0 and self._candles_since_trade >= self.signal_cooldown:
self.BuyMarket()
self._candles_since_trade = 0
elif is_dark_cloud and rsi_val > self.overbought_level and self.Position == 0 and self._candles_since_trade >= self.signal_cooldown:
self.SellMarket()
self._candles_since_trade = 0
self._has_prev_rsi = True
def CreateClone(self):
return cdc_pl_rsi_strategy()