Estrategia 5 EMA
La estrategia 5 EMA marca una vela que cierra completamente por debajo o por encima de la EMA de 5 períodos. Si el precio rompe el extremo de la vela de señal dentro de tres barras y fuera de la ventana de bloqueo, la estrategia entra en la dirección del rompimiento. Los objetivos se basan en una relación riesgo-recompensa definida por el usuario y las operaciones pueden cerrarse forzosamente a una hora específica.
Detalles
- Criterios de entrada:
- Cierre de vela y máximo por debajo de la EMA → marcar para largo; comprar cuando el precio cruce por encima del máximo de la señal en 3 barras.
- Cierre de vela y mínimo por encima de la EMA → marcar para corto; vender cuando el precio cruce por debajo del mínimo de la señal en 3 barras.
- Largo/Corto: Ambos.
- Criterios de salida:
- Stop en el extremo opuesto de la vela de señal.
- Objetivo en
TargetRR× riesgo. - Salida opcional a hora personalizada (
ExitHour,ExitMinute).
- Stops: Sí.
- Valores predeterminados:
EmaLength= 5TargetRR= 3.0ExitHour= 15,ExitMinute= 30BlockStartHour= 15,BlockStartMinute= 0BlockEndHour= 15,BlockEndMinute= 30
- Filtros:
- Categoría: Ruptura
- Dirección: Largo/Corto
- Indicadores: EMA
- Stops: Sí
- Complejidad: Bajo
- Marco temporal: 5 minutos
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
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>
/// 5 EMA strategy.
/// A candle whose close and high are below the EMA marks a long setup, one whose close and low are above it marks a short setup.
/// If price breaks the signal candle's high (long) or low (short) within the next three candles and outside the block window, the
/// strategy enters in that direction with the stop at the signal candle's opposite extreme and the target at TargetRR times the risk.
/// Open positions are closed at ExitHour:ExitMinute.
/// </summary>
public class FiveEmaStrategy : Strategy
{
private const int _signalBars = 3;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<decimal> _targetRR;
private readonly StrategyParam<int> _exitHour;
private readonly StrategyParam<int> _exitMinute;
private readonly StrategyParam<int> _blockStartHour;
private readonly StrategyParam<int> _blockStartMinute;
private readonly StrategyParam<int> _blockEndHour;
private readonly StrategyParam<int> _blockEndMinute;
private readonly StrategyParam<DataType> _candleType;
private decimal? _signalHigh;
private decimal? _signalLow;
private bool _signalIsLong;
private int _barsSinceSignal;
private decimal? _stopPrice;
private decimal? _targetPrice;
/// <summary>
/// EMA period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// Reward to risk ratio of the target.
/// </summary>
public decimal TargetRR
{
get => _targetRR.Value;
set => _targetRR.Value = value;
}
/// <summary>
/// Hour of the forced exit.
/// </summary>
public int ExitHour
{
get => _exitHour.Value;
set => _exitHour.Value = value;
}
/// <summary>
/// Minute of the forced exit.
/// </summary>
public int ExitMinute
{
get => _exitMinute.Value;
set => _exitMinute.Value = value;
}
/// <summary>
/// Hour the entry block starts.
/// </summary>
public int BlockStartHour
{
get => _blockStartHour.Value;
set => _blockStartHour.Value = value;
}
/// <summary>
/// Minute the entry block starts.
/// </summary>
public int BlockStartMinute
{
get => _blockStartMinute.Value;
set => _blockStartMinute.Value = value;
}
/// <summary>
/// Hour the entry block ends.
/// </summary>
public int BlockEndHour
{
get => _blockEndHour.Value;
set => _blockEndHour.Value = value;
}
/// <summary>
/// Minute the entry block ends.
/// </summary>
public int BlockEndMinute
{
get => _blockEndMinute.Value;
set => _blockEndMinute.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public FiveEmaStrategy()
{
_emaLength = Param(nameof(EmaLength), 5)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "EMA");
_targetRR = Param(nameof(TargetRR), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Target R:R", "Reward to risk ratio of the target", "Risk");
_exitHour = Param(nameof(ExitHour), 15)
.SetRange(0, 23)
.SetDisplay("Exit Hour", "Hour of the forced exit", "Time");
_exitMinute = Param(nameof(ExitMinute), 30)
.SetRange(0, 59)
.SetDisplay("Exit Minute", "Minute of the forced exit", "Time");
_blockStartHour = Param(nameof(BlockStartHour), 15)
.SetRange(0, 23)
.SetDisplay("Block Start Hour", "Hour the entry block starts", "Time");
_blockStartMinute = Param(nameof(BlockStartMinute), 0)
.SetRange(0, 59)
.SetDisplay("Block Start Minute", "Minute the entry block starts", "Time");
_blockEndHour = Param(nameof(BlockEndHour), 15)
.SetRange(0, 23)
.SetDisplay("Block End Hour", "Hour the entry block ends", "Time");
_blockEndMinute = Param(nameof(BlockEndMinute), 30)
.SetRange(0, 59)
.SetDisplay("Block End Minute", "Minute the entry block ends", "Time");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).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();
ResetState();
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
DrawOwnTrades(area);
}
}
private void ResetState()
{
_signalHigh = null;
_signalLow = null;
_signalIsLong = false;
_barsSinceSignal = 0;
_stopPrice = null;
_targetPrice = null;
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!emaValue.IsFormed)
return;
var ema = emaValue.ToDecimal();
var high = candle.HighPrice;
var low = candle.LowPrice;
var close = candle.ClosePrice;
if (_signalHigh != null)
{
_barsSinceSignal++;
if (_barsSinceSignal > _signalBars)
_signalHigh = _signalLow = null;
}
var signalHigh = _signalHigh;
var signalLow = _signalLow;
var signalIsLong = _signalIsLong;
// A new signal candle replaces the pending one and can only be broken by later candles.
var newSignal = true;
if (close < ema && high < ema)
SetSignal(high, low, true);
else if (close > ema && low > ema)
SetSignal(high, low, false);
else
newSignal = false;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var tod = candle.OpenTime.TimeOfDay;
var exitTime = new TimeSpan(ExitHour, ExitMinute, 0);
var frame = CandleType.Arg is TimeSpan tf ? tf : TimeSpan.Zero;
if (Position != 0 && tod <= exitTime && exitTime < tod + frame)
{
ClosePosition();
return;
}
if (Position > 0 && _stopPrice is decimal longStop && _targetPrice is decimal longTarget)
{
if (low <= longStop || high >= longTarget)
{
ClosePosition();
return;
}
}
else if (Position < 0 && _stopPrice is decimal shortStop && _targetPrice is decimal shortTarget)
{
if (high >= shortStop || low <= shortTarget)
{
ClosePosition();
return;
}
}
if (signalHigh is not decimal sHigh || signalLow is not decimal sLow)
return;
var blockStart = new TimeSpan(BlockStartHour, BlockStartMinute, 0);
var blockEnd = new TimeSpan(BlockEndHour, BlockEndMinute, 0);
if (tod >= blockStart && tod < blockEnd)
return;
var risk = sHigh - sLow;
if (risk <= 0)
return;
if (signalIsLong && high > sHigh && Position <= 0)
{
BuyMarket(Volume + Math.Abs(Position));
_stopPrice = sLow;
_targetPrice = sHigh + risk * TargetRR;
if (!newSignal)
_signalHigh = _signalLow = null;
}
else if (!signalIsLong && low < sLow && Position >= 0)
{
SellMarket(Volume + Math.Abs(Position));
_stopPrice = sHigh;
_targetPrice = sLow - risk * TargetRR;
if (!newSignal)
_signalHigh = _signalLow = null;
}
}
private void SetSignal(decimal high, decimal low, bool isLong)
{
_signalHigh = high;
_signalLow = low;
_signalIsLong = isLong;
_barsSinceSignal = 0;
}
private void ClosePosition()
{
if (Position > 0)
SellMarket(Position);
else if (Position < 0)
BuyMarket(-Position);
_stopPrice = null;
_targetPrice = null;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
SIGNAL_BARS = 3
class five_ema_strategy(Strategy):
"""
5 EMA strategy.
A candle whose close and high are below the EMA marks a long setup, one whose close and low are above it marks a short setup.
If price breaks the signal candle's high (long) or low (short) within the next three candles and outside the block window, the
strategy enters in that direction with the stop at the signal candle's opposite extreme and the target at TargetRR times the risk.
Open positions are closed at ExitHour:ExitMinute.
"""
def __init__(self):
super(five_ema_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 5).SetGreaterThanZero().SetDisplay("EMA Length", "EMA period", "EMA")
self._target_rr = self.Param("TargetRR", 3.0).SetGreaterThanZero().SetDisplay("Target R:R", "Reward to risk ratio of the target", "Risk")
self._exit_hour = self.Param("ExitHour", 15).SetRange(0, 23).SetDisplay("Exit Hour", "Hour of the forced exit", "Time")
self._exit_minute = self.Param("ExitMinute", 30).SetRange(0, 59).SetDisplay("Exit Minute", "Minute of the forced exit", "Time")
self._block_start_hour = self.Param("BlockStartHour", 15).SetRange(0, 23).SetDisplay("Block Start Hour", "Hour the entry block starts", "Time")
self._block_start_minute = self.Param("BlockStartMinute", 0).SetRange(0, 59).SetDisplay("Block Start Minute", "Minute the entry block starts", "Time")
self._block_end_hour = self.Param("BlockEndHour", 15).SetRange(0, 23).SetDisplay("Block End Hour", "Hour the entry block ends", "Time")
self._block_end_minute = self.Param("BlockEndMinute", 30).SetRange(0, 59).SetDisplay("Block End Minute", "Minute the entry block ends", "Time")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._signal_high = None
self._signal_low = None
self._signal_is_long = False
self._bars_since_signal = 0
self._stop_price = None
self._target_price = None
def OnReseted(self):
super(five_ema_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(five_ema_strategy, self).OnStarted2(time)
self._reset_state()
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(ema, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
if not ema_value.IsFormed:
return
ema = ema_value.GetValue[Decimal](None)
high = candle.HighPrice
low = candle.LowPrice
close = candle.ClosePrice
if self._signal_high is not None:
self._bars_since_signal += 1
if self._bars_since_signal > SIGNAL_BARS:
self._signal_high = None
self._signal_low = None
signal_high = self._signal_high
signal_low = self._signal_low
signal_is_long = self._signal_is_long
# A new signal candle replaces the pending one and can only be broken by later candles.
new_signal = True
if close < ema and high < ema:
self._set_signal(high, low, True)
elif close > ema and low > ema:
self._set_signal(high, low, False)
else:
new_signal = False
if not self.IsFormedAndOnlineAndAllowTrading():
return
tod = candle.OpenTime.TimeOfDay
exit_time = TimeSpan(self._exit_hour.Value, self._exit_minute.Value, 0)
frame = self.candle_type.Arg if isinstance(self.candle_type.Arg, TimeSpan) else TimeSpan.Zero
if self.Position != 0 and tod <= exit_time and exit_time < tod + frame:
self._close_position()
return
if self.Position > 0 and self._stop_price is not None and self._target_price is not None:
if low <= self._stop_price or high >= self._target_price:
self._close_position()
return
elif self.Position < 0 and self._stop_price is not None and self._target_price is not None:
if high >= self._stop_price or low <= self._target_price:
self._close_position()
return
if signal_high is None or signal_low is None:
return
block_start = TimeSpan(self._block_start_hour.Value, self._block_start_minute.Value, 0)
block_end = TimeSpan(self._block_end_hour.Value, self._block_end_minute.Value, 0)
if tod >= block_start and tod < block_end:
return
risk = signal_high - signal_low
if risk <= 0:
return
target_rr = Decimal(self._target_rr.Value)
if signal_is_long and high > signal_high and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._stop_price = signal_low
self._target_price = signal_high + risk * target_rr
if not new_signal:
self._signal_high = None
self._signal_low = None
elif not signal_is_long and low < signal_low and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._stop_price = signal_high
self._target_price = signal_low - risk * target_rr
if not new_signal:
self._signal_high = None
self._signal_low = None
def _set_signal(self, high, low, is_long):
self._signal_high = high
self._signal_low = low
self._signal_is_long = is_long
self._bars_since_signal = 0
def _close_position(self):
if self.Position > 0:
self.SellMarket(self.Position)
elif self.Position < 0:
self.BuyMarket(-self.Position)
self._stop_price = None
self._target_price = None
def CreateClone(self):
return five_ema_strategy()