Estrategia de Reversión de Tendencia EMA RSI
Estrategia que entra en largo cuando el EMA cruza con confirmación del RSI y sale cuando se produce el cruce opuesto con RSI por debajo del nivel. Usa take profit y stop loss basados en porcentaje.
Detalles
- Criterios de entrada:
- Largo:
FastEMA crosses above SlowEMA && RSI > RsiLevel
- Largo:
- Largo/Corto: Solo largos
- Stops: Take profit y stop loss porcentuales
- Valores predeterminados:
FastLength= 9SlowLength= 21RsiLength= 14RsiLevel= 50mTakeProfitPercent= 2mStopLossPercent= 1mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filtros:
- Categoría: Tendencia
- Dirección: Solo largos
- Indicadores: EMA, RSI
- Stops: Sí
- Complejidad: Principiante
- Marco temporal: Medio plazo
- 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>
/// EMA RSI trend reversal strategy.
/// Long only: buys when the fast EMA crosses above the slow EMA with RSI above RsiLevel and closes the long when the fast EMA
/// crosses below the slow EMA with RSI below RsiLevel. Percent take profit and stop loss protect the position.
/// </summary>
public class EmaRsiTrendReversalStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<decimal> _rsiLevel;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevFast;
private decimal? _prevSlow;
/// <summary>
/// Fast EMA length.
/// </summary>
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
/// <summary>
/// Slow EMA length.
/// </summary>
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
/// <summary>
/// RSI length.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// RSI level that confirms entries and exits.
/// </summary>
public decimal RsiLevel
{
get => _rsiLevel.Value;
set => _rsiLevel.Value = value;
}
/// <summary>
/// Take profit percentage from entry price.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public EmaRsiTrendReversalStrategy()
{
_fastLength = Param(nameof(FastLength), 9)
.SetGreaterThanZero()
.SetDisplay("Fast EMA", "Fast EMA length", "Indicators");
_slowLength = Param(nameof(SlowLength), 21)
.SetGreaterThanZero()
.SetDisplay("Slow EMA", "Slow EMA length", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI length", "Indicators");
_rsiLevel = Param(nameof(RsiLevel), 50m)
.SetDisplay("RSI Level", "RSI level that confirms entries and exits", "Indicators");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 2m)
.SetNotNegative()
.SetDisplay("Take Profit %", "Take profit percentage from entry price", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 1m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_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();
_prevFast = null;
_prevSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevSlow = null;
var fast = new ExponentialMovingAverage { Length = FastLength };
var slow = new ExponentialMovingAverage { Length = SlowLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, slow, rsi, ProcessCandle)
.Start();
StartProtection(
TakeProfitPercent > 0m ? new Unit(TakeProfitPercent, UnitTypes.Percent) : new Unit(),
StopLossPercent > 0m ? new Unit(StopLossPercent, UnitTypes.Percent) : new Unit(),
useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, slow);
DrawOwnTrades(area);
var oscillators = CreateChartArea();
if (oscillators != null)
DrawIndicator(oscillators, rsi);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
var prevFast = _prevFast;
var prevSlow = _prevSlow;
_prevFast = fast;
_prevSlow = slow;
if (prevFast is not decimal pf || prevSlow is not decimal ps)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (Position == 0 && pf <= ps && fast > slow && rsi > RsiLevel)
BuyMarket(Volume);
else if (Position > 0 && pf >= ps && fast < slow && rsi < RsiLevel)
SellMarket(Position);
}
}
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 ExponentialMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class ema_rsi_trend_reversal_strategy(Strategy):
"""
EMA RSI trend reversal strategy.
Long only: buys when the fast EMA crosses above the slow EMA with RSI above RsiLevel and closes the long when the fast EMA
crosses below the slow EMA with RSI below RsiLevel. Percent take profit and stop loss protect the position.
"""
def __init__(self):
super(ema_rsi_trend_reversal_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 9).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA length", "Indicators")
self._slow_length = self.Param("SlowLength", 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA length", "Indicators")
self._rsi_length = self.Param("RsiLength", 14).SetGreaterThanZero().SetDisplay("RSI Length", "RSI length", "Indicators")
self._rsi_level = self.Param("RsiLevel", 50.0).SetDisplay("RSI Level", "RSI level that confirms entries and exits", "Indicators")
self._take_profit_percent = self.Param("TakeProfitPercent", 2.0).SetNotNegative().SetDisplay("Take Profit %", "Take profit percentage from entry price", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 1.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
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._prev_fast = None
self._prev_slow = None
def OnReseted(self):
super(ema_rsi_trend_reversal_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(ema_rsi_trend_reversal_strategy, self).OnStarted2(time)
self._reset_state()
fast = ExponentialMovingAverage()
fast.Length = self._fast_length.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, rsi, self._process_candle).Start()
take = float(self._take_profit_percent.Value)
stop = float(self._stop_loss_percent.Value)
self.StartProtection(
Unit(Decimal(take), UnitTypes.Percent) if take > 0 else Unit(),
Unit(Decimal(stop), UnitTypes.Percent) if stop > 0 else Unit(),
useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
oscillators = self.CreateChartArea()
if oscillators is not None:
self.DrawIndicator(oscillators, rsi)
def _process_candle(self, candle, fast_value, slow_value, rsi_value):
if candle.State != CandleStates.Finished:
return
fast = float(fast_value)
slow = float(slow_value)
rsi = float(rsi_value)
prev_fast = self._prev_fast
prev_slow = self._prev_slow
self._prev_fast = fast
self._prev_slow = slow
if prev_fast is None or prev_slow is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
level = float(self._rsi_level.Value)
if self.Position == 0 and prev_fast <= prev_slow and fast > slow and rsi > level:
self.BuyMarket(self.Volume)
elif self.Position > 0 and prev_fast >= prev_slow and fast < slow and rsi < level:
self.SellMarket(self.Position)
def CreateClone(self):
return ema_rsi_trend_reversal_strategy()