Estrategia X2MA JJRSX
Estrategia que combina un filtro de tendencia de doble media móvil con un disparador de entrada basado en RSI. La tendencia se define en un marco temporal superior comparando una media rápida y una lenta. Las entradas se ejecutan en un marco temporal inferior cuando el RSI sale de las zonas de sobreventa o sobrecompra en la dirección de la tendencia.
Detalles
- Criterios de entrada:
- Largo: tendencia alcista y RSI cruza por encima de
Oversold - Corto: tendencia bajista y RSI cruza por debajo de
Overbought
- Largo: tendencia alcista y RSI cruza por encima de
- Largo/Corto: Ambos
- Criterios de salida: Umbral RSI opuesto o reversión de tendencia
- Stops: Ninguno
- Valores predeterminados:
TrendCandleType= velas de 4hSignalCandleType= velas de 30mFastMaPeriod= 12SlowMaPeriod= 5RsiPeriod= 8Overbought= 70Oversold= 30
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that combines dual moving average trend filter with RSI entries.
/// </summary>
public class X2MaJjrsxStrategy : Strategy
{
private readonly StrategyParam<DataType> _trendCandleType;
private readonly StrategyParam<DataType> _signalCandleType;
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<bool> _useLong;
private readonly StrategyParam<bool> _useShort;
private SimpleMovingAverage _fastMa;
private SimpleMovingAverage _slowMa;
private RelativeStrengthIndex _rsi;
private int _trend;
private decimal _prevRsi;
/// <summary>
/// Constructor.
/// </summary>
public X2MaJjrsxStrategy()
{
_trendCandleType = Param(nameof(TrendCandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Trend Candle Type", "Timeframe for trend moving averages", "General");
_signalCandleType = Param(nameof(SignalCandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Signal Candle Type", "Timeframe for entry signals", "General");
_fastMaPeriod = Param(nameof(FastMaPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast MA Period", "Length of fast moving average", "Indicators");
_slowMaPeriod = Param(nameof(SlowMaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Slow MA Period", "Length of slow moving average", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "Length of RSI filter", "Indicators");
_overbought = Param(nameof(Overbought), 75m)
.SetDisplay("Overbought", "RSI overbought threshold", "Risk");
_oversold = Param(nameof(Oversold), 25m)
.SetDisplay("Oversold", "RSI oversold threshold", "Risk");
_useLong = Param(nameof(UseLong), true)
.SetDisplay("Enable Long", "Allow long trades", "General");
_useShort = Param(nameof(UseShort), true)
.SetDisplay("Enable Short", "Allow short trades", "General");
}
/// <summary>
/// Candle type for trend calculation.
/// </summary>
public DataType TrendCandleType
{
get => _trendCandleType.Value;
set => _trendCandleType.Value = value;
}
/// <summary>
/// Candle type for entry signals.
/// </summary>
public DataType SignalCandleType
{
get => _signalCandleType.Value;
set => _signalCandleType.Value = value;
}
/// <summary>
/// Fast moving average period.
/// </summary>
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
/// <summary>
/// Slow moving average period.
/// </summary>
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal Overbought
{
get => _overbought.Value;
set => _overbought.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal Oversold
{
get => _oversold.Value;
set => _oversold.Value = value;
}
/// <summary>
/// Enable long trades.
/// </summary>
public bool UseLong
{
get => _useLong.Value;
set => _useLong.Value = value;
}
/// <summary>
/// Enable short trades.
/// </summary>
public bool UseShort
{
get => _useShort.Value;
set => _useShort.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, TrendCandleType), (Security, SignalCandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_trend = 0;
_prevRsi = 50m;
_fastMa = null;
_slowMa = null;
_rsi = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fastMa = new SimpleMovingAverage { Length = FastMaPeriod };
_slowMa = new SimpleMovingAverage { Length = SlowMaPeriod };
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_prevRsi = 50m;
var trendSub = SubscribeCandles(TrendCandleType);
trendSub.Bind(_fastMa, _slowMa, ProcessTrend).Start();
var signalSub = SubscribeCandles(SignalCandleType);
signalSub.Bind(_rsi, ProcessSignal).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, signalSub);
DrawIndicator(area, _fastMa);
DrawIndicator(area, _slowMa);
DrawIndicator(area, _rsi);
DrawOwnTrades(area);
}
}
private void ProcessTrend(ICandleMessage candle, decimal fastMa, decimal slowMa)
{
if (candle.State != CandleStates.Finished)
return;
_trend = fastMa > slowMa ? 1 : fastMa < slowMa ? -1 : _trend;
}
private void ProcessSignal(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevRsi = rsi;
return;
}
if (UseLong && _trend > 0 && Position <= 0 && _prevRsi < Oversold && rsi >= Oversold)
BuyMarket();
if (UseShort && _trend < 0 && Position >= 0 && _prevRsi > Overbought && rsi <= Overbought)
SellMarket();
if (Position > 0 && (rsi >= Overbought || _trend < 0))
SellMarket();
if (Position < 0 && (rsi <= Oversold || _trend > 0))
BuyMarket();
_prevRsi = rsi;
}
}
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 SimpleMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class x2_ma_jjrsx_strategy(Strategy):
def __init__(self):
super(x2_ma_jjrsx_strategy, self).__init__()
self._trend_candle_type = self.Param("TrendCandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Trend Candle Type", "Timeframe for trend moving averages", "General")
self._signal_candle_type = self.Param("SignalCandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Signal Candle Type", "Timeframe for entry signals", "General")
self._fast_ma_period = self.Param("FastMaPeriod", 5) \
.SetDisplay("Fast MA Period", "Length of fast moving average", "Indicators")
self._slow_ma_period = self.Param("SlowMaPeriod", 20) \
.SetDisplay("Slow MA Period", "Length of slow moving average", "Indicators")
self._rsi_period = self.Param("RsiPeriod", 14) \
.SetDisplay("RSI Period", "Length of RSI filter", "Indicators")
self._overbought = self.Param("Overbought", 75.0) \
.SetDisplay("Overbought", "RSI overbought threshold", "Risk")
self._oversold = self.Param("Oversold", 25.0) \
.SetDisplay("Oversold", "RSI oversold threshold", "Risk")
self._use_long = self.Param("UseLong", True) \
.SetDisplay("Enable Long", "Allow long trades", "General")
self._use_short = self.Param("UseShort", True) \
.SetDisplay("Enable Short", "Allow short trades", "General")
self._trend = 0
self._prev_rsi = 50.0
@property
def trend_candle_type(self):
return self._trend_candle_type.Value
@property
def signal_candle_type(self):
return self._signal_candle_type.Value
@property
def fast_ma_period(self):
return self._fast_ma_period.Value
@property
def slow_ma_period(self):
return self._slow_ma_period.Value
@property
def rsi_period(self):
return self._rsi_period.Value
@property
def overbought(self):
return self._overbought.Value
@property
def oversold(self):
return self._oversold.Value
@property
def use_long(self):
return self._use_long.Value
@property
def use_short(self):
return self._use_short.Value
def OnReseted(self):
super(x2_ma_jjrsx_strategy, self).OnReseted()
self._trend = 0
self._prev_rsi = 50.0
def OnStarted2(self, time):
super(x2_ma_jjrsx_strategy, self).OnStarted2(time)
self._trend = 0
self._prev_rsi = 50.0
fast_ma = SimpleMovingAverage()
fast_ma.Length = int(self.fast_ma_period)
slow_ma = SimpleMovingAverage()
slow_ma.Length = int(self.slow_ma_period)
rsi = RelativeStrengthIndex()
rsi.Length = int(self.rsi_period)
trend_sub = self.SubscribeCandles(self.trend_candle_type)
trend_sub.Bind(fast_ma, slow_ma, self._process_trend).Start()
signal_sub = self.SubscribeCandles(self.signal_candle_type)
signal_sub.Bind(rsi, self._process_signal).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, signal_sub)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
self.DrawIndicator(area, rsi)
self.DrawOwnTrades(area)
def _process_trend(self, candle, fast_ma, slow_ma):
if candle.State != CandleStates.Finished:
return
fast_ma = float(fast_ma)
slow_ma = float(slow_ma)
if fast_ma > slow_ma:
self._trend = 1
elif fast_ma < slow_ma:
self._trend = -1
def _process_signal(self, candle, rsi):
if candle.State != CandleStates.Finished:
return
rsi = float(rsi)
ob = float(self.overbought)
os_val = float(self.oversold)
if self.use_long and self._trend > 0 and self.Position <= 0 and self._prev_rsi < os_val and rsi >= os_val:
self.BuyMarket()
if self.use_short and self._trend < 0 and self.Position >= 0 and self._prev_rsi > ob and rsi <= ob:
self.SellMarket()
if self.Position > 0 and (rsi >= ob or self._trend < 0):
self.SellMarket()
if self.Position < 0 and (rsi <= os_val or self._trend > 0):
self.BuyMarket()
self._prev_rsi = rsi
def CreateClone(self):
return x2_ma_jjrsx_strategy()