Vela Doji Mejorada
Esta estrategia opera velas Doji con reglas de confirmación simples y gestión de riesgo-recompensa fija. Entra cuando aparece un Doji y la vela o su predecesora confirma la dirección cerrando más allá de la apertura con pequeñas mechas. Las órdenes de protección utilizan un stop-loss en pips y un take-profit definido por una relación riesgo-recompensa.
Detalles
- Criterios de entrada: Vela Doji (cuerpo <= 30% del rango). Si es alcista con mecha inferior <=1% o la vela anterior es alcista, ir largo. Si es bajista con mecha superior <=1% o la vela anterior es bajista, ir corto.
- Largo/Corto: Ambos.
- Criterios de salida: Take-profit o stop-loss, o cualquier nuevo Doji que cierre la posición.
- Stops: Sí.
- Valores predeterminados:
RiskRewardRatio= 2.0mStopLossPips= 5SmaPeriod= 20CandleType= TimeSpan.FromMinutes(1)
- Filtros:
- Categoría: Candlestick
- Dirección: Ambos
- Indicadores: SMA
- Stops: Sí
- Complejidad: Principiante
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Bajo
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()