Vela Doji Aprimorada
Esta estratégia opera velas Doji com regras de confirmação simples e gestão de risco-recompensa fixa. Ela entra quando um Doji aparece e a vela ou seu predecessor confirma a direção fechando além da abertura com sombras pequenas. As ordens de proteção usam um stop-loss em pips e um take-profit definido por uma relação risco-recompensa.
Detalhes
- Critérios de entrada: Vela Doji (corpo <= 30% do intervalo). Se de alta com sombra inferior <=1% ou a vela anterior for de alta, ir comprado. Se de baixa com sombra superior <=1% ou a vela anterior for de baixa, ir vendido.
- Comprado/Vendido: Ambos.
- Critérios de saída: Take-profit ou stop-loss, ou qualquer novo Doji que encerre a posição.
- Stops: Sim.
- Valores padrão:
RiskRewardRatio= 2.0mStopLossPips= 5SmaPeriod= 20CandleType= TimeSpan.FromMinutes(1)
- Filtros:
- Categoria: Candlestick
- Direção: Ambos
- Indicadores: SMA
- Stops: Sim
- Complexidade: Iniciante
- Período: Intradiário
- Sazonalidade: Não
- Redes neurais: Não
- Divergência: Não
- Nível de risco: Baixo
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>
/// Enhanced doji candle strategy.
/// A doji has a body of at most 30% of its range. When flat, a doji goes long if it is bullish with a lower wick of at most 1% of
/// its range or the previous candle was bullish, and short if it is bearish with an upper wick of at most 1% or the previous
/// candle was bearish. While a position is open any new doji closes it. The stop lies StopLossPips price steps from the entry and
/// the take profit RiskRewardRatio times that distance. The SMA is drawn for reference.
/// </summary>
public class EnhancedDojiCandleStrategy : Strategy
{
private const decimal _dojiBodyPercent = 30m;
private const decimal _wickPercent = 1m;
private readonly StrategyParam<decimal> _riskRewardRatio;
private readonly StrategyParam<int> _stopLossPips;
private readonly StrategyParam<int> _smaPeriod;
private readonly StrategyParam<DataType> _candleType;
private ICandleMessage _prevCandle;
/// <summary>
/// Take profit distance in multiples of the stop distance.
/// </summary>
public decimal RiskRewardRatio
{
get => _riskRewardRatio.Value;
set => _riskRewardRatio.Value = value;
}
/// <summary>
/// Stop loss in price steps.
/// </summary>
public int StopLossPips
{
get => _stopLossPips.Value;
set => _stopLossPips.Value = value;
}
/// <summary>
/// SMA period.
/// </summary>
public int SmaPeriod
{
get => _smaPeriod.Value;
set => _smaPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public EnhancedDojiCandleStrategy()
{
_riskRewardRatio = Param(nameof(RiskRewardRatio), 2.0m)
.SetGreaterThanZero()
.SetDisplay("Risk Reward", "Take profit in multiples of the stop distance", "Risk");
_stopLossPips = Param(nameof(StopLossPips), 5)
.SetNotNegative()
.SetDisplay("Stop Loss Pips", "Stop loss in price steps", "Risk");
_smaPeriod = Param(nameof(SmaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("SMA Period", "SMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
var sma = new SimpleMovingAverage { Length = SmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var stopDistance = StopLossPips * (Security?.PriceStep ?? 1m);
StartProtection(
stopDistance > 0m ? new Unit(stopDistance * RiskRewardRatio, UnitTypes.Absolute) : new Unit(),
stopDistance > 0m ? new Unit(stopDistance, UnitTypes.Absolute) : new Unit(),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal sma)
{
if (candle.State != CandleStates.Finished)
return;
var prev = _prevCandle;
_prevCandle = candle;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var range = candle.HighPrice - candle.LowPrice;
if (range <= 0m)
return;
var open = candle.OpenPrice;
var close = candle.ClosePrice;
var isDoji = Math.Abs(close - open) / range * 100m <= _dojiBodyPercent;
if (!isDoji)
return;
if (Position > 0)
{
SellMarket(Position);
return;
}
if (Position < 0)
{
BuyMarket(-Position);
return;
}
var lowerWick = (Math.Min(open, close) - candle.LowPrice) / range * 100m;
var upperWick = (candle.HighPrice - Math.Max(open, close)) / range * 100m;
var prevBullish = prev != null && prev.ClosePrice > prev.OpenPrice;
var prevBearish = prev != null && prev.ClosePrice < prev.OpenPrice;
if ((close > open && lowerWick <= _wickPercent) || prevBullish)
BuyMarket(Volume);
else if ((close < open && upperWick <= _wickPercent) || prevBearish)
SellMarket(Volume);
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
DOJI_BODY_PERCENT = 30.0
WICK_PERCENT = 1.0
class enhanced_doji_candle_strategy(Strategy):
"""
Enhanced doji candle strategy.
A doji has a body of at most 30% of its range. When flat, a doji goes long if it is bullish with a lower wick of at most 1% of
its range or the previous candle was bullish, and short if it is bearish with an upper wick of at most 1% or the previous
candle was bearish. While a position is open any new doji closes it. The stop lies StopLossPips price steps from the entry and
the take profit RiskRewardRatio times that distance. The SMA is drawn for reference.
"""
def __init__(self):
super(enhanced_doji_candle_strategy, self).__init__()
self._risk_reward_ratio = self.Param("RiskRewardRatio", 2.0).SetGreaterThanZero().SetDisplay("Risk Reward", "Take profit in multiples of the stop distance", "Risk")
self._stop_loss_pips = self.Param("StopLossPips", 5).SetNotNegative().SetDisplay("Stop Loss Pips", "Stop loss in price steps", "Risk")
self._sma_period = self.Param("SmaPeriod", 20).SetGreaterThanZero().SetDisplay("SMA Period", "SMA period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(enhanced_doji_candle_strategy, self).OnReseted()
self._prev = None
def OnStarted2(self, time):
super(enhanced_doji_candle_strategy, self).OnStarted2(time)
self._prev = None
sma = SimpleMovingAverage()
sma.Length = self._sma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
stop_distance = self._stop_loss_pips.Value * step
rr = float(self._risk_reward_ratio.Value)
self.StartProtection(
Unit(Decimal(stop_distance * rr), UnitTypes.Absolute) if stop_distance > 0 else Unit(),
Unit(Decimal(stop_distance), UnitTypes.Absolute) if stop_distance > 0 else Unit(),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_value):
if candle.State != CandleStates.Finished:
return
o = float(candle.OpenPrice)
h = float(candle.HighPrice)
l = float(candle.LowPrice)
c = float(candle.ClosePrice)
prev = self._prev
self._prev = (o, c)
if not self.IsFormedAndOnlineAndAllowTrading():
return
rng = h - l
if rng <= 0:
return
is_doji = abs(c - o) / rng * 100.0 <= DOJI_BODY_PERCENT
if not is_doji:
return
if self.Position > 0:
self.SellMarket(self.Position)
return
if self.Position < 0:
self.BuyMarket(-self.Position)
return
lower_wick = (min(o, c) - l) / rng * 100.0
upper_wick = (h - max(o, c)) / rng * 100.0
prev_bullish = prev is not None and prev[1] > prev[0]
prev_bearish = prev is not None and prev[1] < prev[0]
if (c > o and lower_wick <= WICK_PERCENT) or prev_bullish:
self.BuyMarket(self.Volume)
elif (c < o and upper_wick <= WICK_PERCENT) or prev_bearish:
self.SellMarket(self.Volume)
def CreateClone(self):
return enhanced_doji_candle_strategy()