Estrategia Exp de Media Móvil FN
Esta estrategia opera basándose en reversiones de la pendiente de una media móvil exponencial (EMA). Entra en largo cuando la EMA gira hacia arriba tras una caída y entra en corto cuando la EMA gira hacia abajo tras una subida. Los niveles opcionales de stop-loss y take-profit se definen en unidades de precio absoluto.
Detalles
- Criterios de entrada:
- Largo: La pendiente de la EMA cambia de bajista a alcista.
- Corto: La pendiente de la EMA cambia de alcista a bajista.
- Largo/Corto: Ambos.
- Criterios de salida:
- Reversión de pendiente opuesta.
- Activación del stop-loss o take-profit.
- Stops: Sí, usando distancias de precio absoluto.
- Valores predeterminados:
EMA Length= 12Stop Loss= 1000Take Profit= 2000Candle Type= marco temporal de 4 horas
- Filtros:
- Categoría: Seguimiento de tendencia
- Dirección: Ambos
- Indicadores: Único (EMA)
- Stops: Sí
- Complejidad: Moderado
- Marco temporal: Medio plazo
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Moderado
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>
/// EMA slope reversal with absolute stop loss and take profit protection.
/// </summary>
public class ExpMovingAverageFnStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private decimal _prevEma;
private decimal _prevPrevEma;
private int _count;
public int Length { get => _length.Value; set => _length.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public ExpMovingAverageFnStrategy()
{
_length = Param(nameof(Length), 12)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_stopLoss = Param(nameof(StopLoss), 1000m)
.SetDisplay("Stop Loss", "Absolute price distance from entry", "Risk");
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take Profit", "Absolute price distance from entry", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevEma = 0;
_prevPrevEma = 0;
_count = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ema = new ExponentialMovingAverage { Length = Length };
SubscribeCandles(CandleType)
.Bind(ema, ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(TakeProfit, UnitTypes.Absolute),
stopLoss: new Unit(StopLoss, UnitTypes.Absolute));
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
_count++;
if (_count < 3)
{
_prevPrevEma = _prevEma;
_prevEma = emaValue;
return;
}
var turnUp = _prevEma < _prevPrevEma && emaValue > _prevEma;
var turnDown = _prevEma > _prevPrevEma && emaValue < _prevEma;
if (turnUp && Position <= 0)
{
if (Position < 0)
BuyMarket(-Position);
BuyMarket(Volume);
}
else if (turnDown && Position >= 0)
{
if (Position > 0)
SellMarket(Position);
SellMarket(Volume);
}
_prevPrevEma = _prevEma;
_prevEma = emaValue;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_moving_average_fn_strategy(Strategy):
def __init__(self):
super(exp_moving_average_fn_strategy, self).__init__()
self._length = self.Param("Length", 12) \
.SetDisplay("EMA Length", "EMA period", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._stop_loss = self.Param("StopLoss", 1000.0) \
.SetDisplay("Stop Loss", "Absolute price distance from entry", "Risk")
self._take_profit = self.Param("TakeProfit", 2000.0) \
.SetDisplay("Take Profit", "Absolute price distance from entry", "Risk")
self._prev_ema = 0.0
self._prev_prev_ema = 0.0
self._count = 0
@property
def Length(self):
return self._length.Value
@Length.setter
def Length(self, value):
self._length.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
def OnStarted2(self, time):
super(exp_moving_average_fn_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self.Length
self.SubscribeCandles(self.CandleType) \
.Bind(ema, self.ProcessCandle) \
.Start()
self.StartProtection(
takeProfit=Unit(self.TakeProfit, UnitTypes.Absolute),
stopLoss=Unit(self.StopLoss, UnitTypes.Absolute))
def ProcessCandle(self, candle, ema_value):
if candle.State != CandleStates.Finished:
return
ema_val = float(ema_value)
self._count += 1
if self._count < 3:
self._prev_prev_ema = self._prev_ema
self._prev_ema = ema_val
return
turn_up = self._prev_ema < self._prev_prev_ema and ema_val > self._prev_ema
turn_down = self._prev_ema > self._prev_prev_ema and ema_val < self._prev_ema
if turn_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(-self.Position)
self.BuyMarket(self.Volume)
elif turn_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket(self.Position)
self.SellMarket(self.Volume)
self._prev_prev_ema = self._prev_ema
self._prev_ema = ema_val
def OnReseted(self):
super(exp_moving_average_fn_strategy, self).OnReseted()
self._prev_ema = 0.0
self._prev_prev_ema = 0.0
self._count = 0
def CreateClone(self):
return exp_moving_average_fn_strategy()