Tests zeigen eine durchschnittliche jährliche Rendite von etwa 112%. Sie funktioniert am besten auf dem Forexmarkt.
Stochastic RSI Cross beobachtet die %K- und %D-Linien des StochRSI. Bullische Kreuzungen in der Nähe von überverkauften Niveaus lösen Käufe aus, bärische Kreuzungen in der Nähe von überkauften lösen Verkäufe aus, und entgegengesetzte Kreuzungen steigen aus.
Da der StochRSI schnell oszilliert, können Signale häufig sein. Viele Trader verlangen, dass die Kreuzung in der Nähe eines Extrems erfolgt, um Rauschen herauszufiltern.
Details
Einstiegskriterien: Signale basierend auf RSI, Stochastic.
Long/Short: Beide Richtungen.
Ausstiegskriterien: Gegensätzliches Signal oder Stop.
Stops: Ja.
Standardwerte:
RsiPeriod = 14
StochPeriod = 14
KPeriod = 3
DPeriod = 3
StopLossPercent = 2m
CandleType = TimeSpan.FromMinutes(5)
Filter:
Kategorie: Trend
Richtung: Beide
Indikatoren: RSI, Stochastic
Stops: Ja
Komplexität: Grundlegend
Zeitrahmen: Intraday (5m)
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
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()