Estrategia de Tendencia de Mercado por Niveles Sin Repintado
Estrategia de cruce de EMA que opcionalmente filtra las operaciones usando RSI. Las posiciones largas se abren cuando la EMA rápida cruza por encima de la EMA lenta, mientras que las operaciones cortas se activan en el cruce opuesto. Cuando ApplyExitFilters está habilitado y el filtro RSI está activo, las posiciones se cierran si el RSI sale de la zona permitida.
Detalles
- Criterios de entrada:
- Largo:
Fast EMAcruza por encima deSlow EMAyRSI > RsiLongThresholdcuando está habilitado - Corto:
Fast EMAcruza por debajo deSlow EMAyRSI < RsiShortThresholdcuando está habilitado
- Largo:
- Criterios de salida: Cruce opuesto o fallo del filtro RSI cuando
ApplyExitFilterses verdadero - Tipo: Seguimiento de tendencia
- Indicadores: EMA, RSI
- Marco temporal: 5 minutos (por defecto)
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;
public class MarketTrendLevelsNonRepaintingStrategy : Strategy
{
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private ExponentialMovingAverage _emaFast;
private ExponentialMovingAverage _emaSlow;
private RelativeStrengthIndex _rsi;
private decimal? _prevDiff;
private int _barsFromSignal;
public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public MarketTrendLevelsNonRepaintingStrategy()
{
_fastLength = Param(nameof(FastLength), 12);
_slowLength = Param(nameof(SlowLength), 25);
_rsiLength = Param(nameof(RsiLength), 14);
_cooldownBars = Param(nameof(CooldownBars), 3);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(10).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_emaFast = null;
_emaSlow = null;
_rsi = null;
_prevDiff = null;
_barsFromSignal = CooldownBars;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_emaFast = new ExponentialMovingAverage { Length = FastLength };
_emaSlow = new ExponentialMovingAverage { Length = SlowLength };
_rsi = new RelativeStrengthIndex { Length = RsiLength };
_prevDiff = null;
_barsFromSignal = CooldownBars;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_emaFast, _emaSlow, _rsi, Process)
.Start();
}
private void Process(ICandleMessage candle, decimal fast, decimal slow, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_emaFast.IsFormed || !_emaSlow.IsFormed || !_rsi.IsFormed)
{
_prevDiff = fast - slow;
return;
}
var diff = fast - slow;
var crossUp = _prevDiff.HasValue && _prevDiff <= 0 && diff > 0;
var crossDown = _prevDiff.HasValue && _prevDiff >= 0 && diff < 0;
_prevDiff = diff;
var filterLong = rsiValue > 52;
var filterShort = rsiValue < 48;
if (crossUp && Position <= 0 && filterLong)
BuyMarket();
if (crossDown && Position >= 0 && filterShort)
SellMarket();
}
}
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
from StockSharp.Algo.Indicators import ExponentialMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class market_trend_levels_non_repainting_strategy(Strategy):
"""
Market Trend Levels: EMA crossover with RSI filter.
"""
def __init__(self):
super(market_trend_levels_non_repainting_strategy, self).__init__()
self._fast_length = self.Param("FastLength", 12).SetDisplay("Fast", "Fast EMA", "Indicators")
self._slow_length = self.Param("SlowLength", 25).SetDisplay("Slow", "Slow EMA", "Indicators")
self._rsi_length = self.Param("RsiLength", 14).SetDisplay("RSI", "RSI period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(10))).SetDisplay("Candle Type", "Candles", "General")
self._prev_diff = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(market_trend_levels_non_repainting_strategy, self).OnReseted()
self._prev_diff = None
def OnStarted2(self, time):
super(market_trend_levels_non_repainting_strategy, self).OnStarted2(time)
self._prev_diff = None
self._ema_fast = ExponentialMovingAverage()
self._ema_fast.Length = self._fast_length.Value
self._ema_slow = ExponentialMovingAverage()
self._ema_slow.Length = self._slow_length.Value
self._rsi = RelativeStrengthIndex()
self._rsi.Length = self._rsi_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ema_fast, self._ema_slow, self._rsi, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._ema_fast)
self.DrawIndicator(area, self._ema_slow)
self.DrawOwnTrades(area)
def _process_candle(self, candle, fast_val, slow_val, rsi_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
rsi = float(rsi_val)
diff = fast - slow
if not self._ema_fast.IsFormed or not self._ema_slow.IsFormed or not self._rsi.IsFormed:
self._prev_diff = diff
return
if self._prev_diff is None:
self._prev_diff = diff
return
cross_up = self._prev_diff <= 0 and diff > 0
cross_down = self._prev_diff >= 0 and diff < 0
self._prev_diff = diff
if cross_up and self.Position <= 0 and rsi > 52:
self.BuyMarket()
if cross_down and self.Position >= 0 and rsi < 48:
self.SellMarket()
def CreateClone(self):
return market_trend_levels_non_repainting_strategy()