A estratégia Rapid Doji replica a lógica do consultor especialista "Rapid Doji EA" original. Ele verifica velas concluídas de um período configurável (diariamente por padrão) e coloca ordens de entrada de parada acima e abaixo de cada vela doji. Os stops de proteção são posicionados usando um multiplicador Average True Range (ATR), enquanto um trailing stop auxiliar mantém a distância de risco fixa em pontos brutos depois que uma posição se torna lucrativa.
Lógica de negociação
Assinatura de dados – a estratégia escuta velas finalizadas do período selecionado e mantém um indicador ATR com período configurável.
Detecção de Doji – uma vela é tratada como doji quando o tamanho absoluto do corpo é no máximo 3% da faixa completa da vela. Apenas velas concluídas são avaliadas.
Colocação de pedido – quando um doji válido é encontrado:
Uma ordem de compra stop é colocada na máxima doji.
Uma ordem de stop de venda é colocada na mínima doji.
Cada entrada lembra um preço de parada de proteção igual ao extremo oposto menos/mais ATR × multiplicador.
Gerenciamento de risco – assim que uma posição é aberta, a ordem pendente restante é cancelada, o stop memorizado é registrado como um stop de proteção e a lógica móvel assume o controle.
Trailing stop – em cada nova vela o nível de stop é movido para manter uma distância fixa (em pontos convertidos através da etapa de preço do instrumento) do último preço de fechamento, mas somente quando a posição já for lucrativa.
A estratégia nunca utiliza metas de lucro; as saídas acontecem através da parada de proteção ou intervenção manual.
Parâmetros
Parâmetro
Descrição
CandleType
Tipo de dados Candle usado para detecção de padrões (período diário por padrão).
AtrPeriod
Comprimento de lookback do indicador ATR.
AtrMultiplier
Multiplicador aplicado ao valor ATR para cálculo de stop loss.
TrailingDistancePoints
Distância fixa em pontos brutos usados ao rastrear a parada.
Todos os parâmetros suportam otimização dentro do ambiente StockSharp.
Notas de implementação
O código depende da assinatura de vela de alto nível API (SubscribeCandles) combinada com a vinculação do indicador (Bind) para evitar o tratamento manual do histórico.
Os pedidos são normalizados por meio de Security.ShrinkPrice para respeitar o tamanho do tick da exchange.
As paradas de proteção são gerenciadas explicitamente para imitar o comportamento do consultor especialista MetaTrader original.
O projeto omite intencionalmente uma implementação Python de acordo com os requisitos da tarefa.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Rapid Doji strategy: detects doji candles and trades the breakout direction.
/// Buys on next candle if it closes above doji high, sells if below doji low.
/// Uses ATR for volatility confirmation.
/// </summary>
public class RapidDojiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _dojiThreshold;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _prevHigh;
private decimal _prevLow;
private bool _prevWasDoji;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal DojiThreshold { get => _dojiThreshold.Value; set => _dojiThreshold.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public RapidDojiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period for volatility filter", "Indicators");
_dojiThreshold = Param(nameof(DojiThreshold), 0.15m)
.SetDisplay("Doji Threshold", "Max body/range ratio for doji detection", "Pattern");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between breakouts", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHigh = 0m;
_prevLow = 0m;
_prevWasDoji = false;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevWasDoji = false;
_candlesSinceTrade = SignalCooldownCandles;
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal atr)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
if (_prevWasDoji && atr > 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
var close = candle.ClosePrice;
if (close > _prevHigh + atr * 0.2m && Position <= 0)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (close < _prevLow - atr * 0.2m && Position >= 0)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
var range = candle.HighPrice - candle.LowPrice;
var body = Math.Abs(candle.ClosePrice - candle.OpenPrice);
_prevWasDoji = range > 0 && body <= DojiThreshold * range;
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
}
}
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 AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class rapid_doji_strategy(Strategy):
def __init__(self):
super(rapid_doji_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "ATR period for volatility filter", "Indicators")
self._doji_threshold = self.Param("DojiThreshold", 0.15) \
.SetDisplay("Doji Threshold", "Max body/range ratio for doji detection", "Pattern")
self._signal_cooldown = self.Param("SignalCooldownCandles", 6) \
.SetDisplay("Signal Cooldown", "Bars to wait between breakouts", "Trading")
self._atr = None
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_was_doji = False
self._candles_since_trade = 0
@property
def atr_period(self):
return self._atr_period.Value
@property
def doji_threshold(self):
return self._doji_threshold.Value
@property
def signal_cooldown(self):
return self._signal_cooldown.Value
def OnReseted(self):
super(rapid_doji_strategy, self).OnReseted()
self._atr = None
self._prev_high = 0.0
self._prev_low = 0.0
self._prev_was_doji = False
self._candles_since_trade = self.signal_cooldown
def OnStarted2(self, time):
super(rapid_doji_strategy, self).OnStarted2(time)
self._atr = AverageTrueRange()
self._atr.Length = self.atr_period
self._prev_was_doji = False
self._candles_since_trade = self.signal_cooldown
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(15)))
subscription.Bind(self._atr, self._process_candle)
subscription.Start()
def _process_candle(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
if not self._atr.IsFormed:
return
atr_val = float(atr_value)
if self._candles_since_trade < self.signal_cooldown:
self._candles_since_trade += 1
if self._prev_was_doji and atr_val > 0 and self._candles_since_trade >= self.signal_cooldown:
close = float(candle.ClosePrice)
if close > self._prev_high + atr_val * 0.2 and self.Position <= 0:
self.BuyMarket()
self._candles_since_trade = 0
elif close < self._prev_low - atr_val * 0.2 and self.Position >= 0:
self.SellMarket()
self._candles_since_trade = 0
high = float(candle.HighPrice)
low = float(candle.LowPrice)
range_size = high - low
body = abs(float(candle.ClosePrice) - float(candle.OpenPrice))
self._prev_was_doji = range_size > 0 and body <= self.doji_threshold * range_size
self._prev_high = high
self._prev_low = low
def CreateClone(self):
return rapid_doji_strategy()