Estrategia Stochastic RSI Cross
Estrategia basada en el cruce del Stochastic RSI
Las pruebas indican un rendimiento anual promedio de aproximadamente 112%. Funciona mejor en el mercado forex.
Stochastic RSI Cross observa las líneas %K y %D del StochRSI. Los cruces alcistas cerca de niveles de sobreventa desencadenan compras, los cruces bajistas cerca de la sobrecompra desencadenan ventas, y los cruces opuestos salen.
Dado que el StochRSI oscila rápidamente, las señales pueden ser frecuentes. Muchos traders requieren que el cruce ocurra cerca de un extremo para filtrar el ruido.
Detalles
- Criterios de entrada: Señales basadas en RSI, Stochastic.
- Largo/Corto: Ambos direcciones.
- Criterios de salida: Señal opuesta o stop.
- Stops: Sí.
- Valores predeterminados:
RsiPeriod= 14StochPeriod= 14KPeriod= 3DPeriod= 3StopLossPercent= 2mCandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Tendencia
- Dirección: Ambos
- Indicadores: RSI, Stochastic
- Stops: Sí
- Complejidad: Básico
- Marco temporal: Intradía (5m)
- 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>
/// Strategy based on Stochastic Oscillator K/D crossover.
/// Buys when %K crosses above %D in oversold zone.
/// Sells when %K crosses below %D in overbought zone.
/// </summary>
public class StochasticRsiCrossStrategy : Strategy
{
private readonly StrategyParam<int> _kPeriod;
private readonly StrategyParam<int> _dPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevK;
private decimal _prevD;
private bool _hasPrevValues;
private int _cooldown;
/// <summary>
/// K period.
/// </summary>
public int KPeriod
{
get => _kPeriod.Value;
set => _kPeriod.Value = value;
}
/// <summary>
/// D period.
/// </summary>
public int DPeriod
{
get => _dPeriod.Value;
set => _dPeriod.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="StochasticRsiCrossStrategy"/>.
/// </summary>
public StochasticRsiCrossStrategy()
{
_kPeriod = Param(nameof(KPeriod), 14)
.SetDisplay("K Period", "Period for %K line", "Indicators")
.SetOptimize(10, 20, 2);
_dPeriod = Param(nameof(DPeriod), 3)
.SetDisplay("D Period", "Period for %D line", "Indicators")
.SetOptimize(3, 5, 1);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).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();
_prevK = default;
_prevD = default;
_hasPrevValues = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var stoch = new StochasticOscillator
{
K = { Length = KPeriod },
D = { Length = DPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(stoch, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, stoch);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var stoch = (IStochasticOscillatorValue)stochValue;
if (stoch.K is not decimal k || stoch.D is not decimal d)
return;
if (!_hasPrevValues)
{
_hasPrevValues = true;
_prevK = k;
_prevD = d;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevK = k;
_prevD = d;
return;
}
// %K crosses above %D in oversold zone (< 20) - buy
if (_prevK <= _prevD && k > d && k < 20 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 5;
}
// %K crosses below %D in overbought zone (> 80) - sell
else if (_prevK >= _prevD && k < d && k > 80 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 5;
}
_prevK = k;
_prevD = d;
}
}
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 StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
class stochastic_rsi_cross_strategy(Strategy):
"""
Stochastic K/D crossover strategy.
Buys when %K crosses above %D in oversold zone.
Sells when %K crosses below %D in overbought zone.
"""
def __init__(self):
super(stochastic_rsi_cross_strategy, self).__init__()
self._k_period = self.Param("KPeriod", 14).SetDisplay("K Period", "Period for %K line", "Indicators")
self._d_period = self.Param("DPeriod", 3).SetDisplay("D Period", "Period for %D line", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(15))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_k = 0.0
self._prev_d = 0.0
self._has_prev = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(stochastic_rsi_cross_strategy, self).OnReseted()
self._prev_k = 0.0
self._prev_d = 0.0
self._has_prev = False
self._cooldown = 0
def OnStarted2(self, time):
super(stochastic_rsi_cross_strategy, self).OnStarted2(time)
stoch = StochasticOscillator()
stoch.K.Length = self._k_period.Value
stoch.D.Length = self._d_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(stoch, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, stoch)
self.DrawOwnTrades(area)
def _process_candle(self, candle, stoch_val):
if candle.State != CandleStates.Finished:
return
if stoch_val.K is None or stoch_val.D is None:
return
k = float(stoch_val.K)
d = float(stoch_val.D)
if not self._has_prev:
self._has_prev = True
self._prev_k = k
self._prev_d = d
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_k = k
self._prev_d = d
return
# %K crosses above %D in oversold zone (< 20)
if self._prev_k <= self._prev_d and k > d and k < 20 and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
self._cooldown = 5
# %K crosses below %D in overbought zone (> 80)
elif self._prev_k >= self._prev_d and k < d and k > 80 and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._cooldown = 5
self._prev_k = k
self._prev_d = d
def CreateClone(self):
return stochastic_rsi_cross_strategy()