Stochastic Failure Swing Strategie
Stochastic Failure Swing überwacht den Oszillator auf ein niedrigeres Hoch über 80 oder ein höheres Tief unter 20. Wenn der Indikator keinen neuen Extremwert erreicht und dann umkehrt, signalisiert dies oft einen Trendwechsel.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 70%. Die Strategie funktioniert am besten am Aktienmarkt.
Die Strategie kauft, wenn sich ein höheres Tief unter 20 bildet und %K wieder über %D kreuzt, oder verkauft, wenn ein niedrigeres Hoch über 80 auftritt und %K darunter kreuzt.
Trades verwenden einen kleinen prozentualen Stop und werden geschlossen, wenn der Stochastic durch das vorherige Swing-Niveau zurückkreuzt.
Details
- Einstiegskriterien: Indikatorsignal
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 minuteStopLoss= 2%
- Filter:
- Kategorie: Umkehr
- Richtung: Beide
- Indikatoren: Stochastic
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Intraday
- 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 that trades based on Stochastic Oscillator Failure Swing pattern.
/// A failure swing occurs when Stochastic reverses direction without crossing through centerline.
/// Uses cooldown to control trade frequency.
/// </summary>
public class StochasticFailureSwingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _kPeriod;
private readonly StrategyParam<int> _dPeriod;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<int> _cooldownBars;
private StochasticOscillator _stochastic;
private decimal _prevK;
private decimal _prevPrevK;
private int _cooldown;
/// <summary>
/// Candle type and timeframe.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <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>
/// Oversold level.
/// </summary>
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Overbought level.
/// </summary>
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public StochasticFailureSwingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_kPeriod = Param(nameof(KPeriod), 14)
.SetDisplay("K Period", "%K period", "Stochastic")
.SetRange(5, 30);
_dPeriod = Param(nameof(DPeriod), 3)
.SetDisplay("D Period", "%D period", "Stochastic")
.SetRange(2, 10);
_oversoldLevel = Param(nameof(OversoldLevel), 30m)
.SetDisplay("Oversold Level", "Stochastic oversold", "Stochastic")
.SetRange(10m, 40m);
_overboughtLevel = Param(nameof(OverboughtLevel), 70m)
.SetDisplay("Overbought Level", "Stochastic overbought", "Stochastic")
.SetRange(60m, 90m);
_cooldownBars = Param(nameof(CooldownBars), 250)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(10, 2000);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_stochastic = default;
_prevK = 0;
_prevPrevK = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_stochastic = new StochasticOscillator
{
K = { Length = KPeriod },
D = { Length = DPeriod },
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_stochastic, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _stochastic);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stochValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var stoch = (StochasticOscillatorValue)stochValue;
if (stoch.K is not decimal kValue)
return;
// Need at least 2 previous values
if (_prevK == 0 || _prevPrevK == 0)
{
_prevPrevK = _prevK;
_prevK = kValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevPrevK = _prevK;
_prevK = kValue;
return;
}
// Bullish Failure Swing: K was oversold, rose, pulled back but stayed above prior low
var isBullish = _prevPrevK < OversoldLevel &&
_prevK > _prevPrevK &&
kValue < _prevK &&
kValue > _prevPrevK;
// Bearish Failure Swing: K was overbought, fell, bounced but stayed below prior high
var isBearish = _prevPrevK > OverboughtLevel &&
_prevK < _prevPrevK &&
kValue > _prevK &&
kValue < _prevPrevK;
if (Position == 0)
{
if (isBullish)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (isBearish)
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position > 0)
{
// Exit long when K crosses above overbought
if (kValue > OverboughtLevel)
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position < 0)
{
// Exit short when K crosses below oversold
if (kValue < OversoldLevel)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
_prevPrevK = _prevK;
_prevK = kValue;
}
}
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_failure_swing_strategy(Strategy):
"""
Strategy that trades based on Stochastic Oscillator Failure Swing pattern.
A failure swing occurs when Stochastic reverses direction without crossing through centerline.
Uses cooldown to control trade frequency.
"""
def __init__(self):
super(stochastic_failure_swing_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._k_period = self.Param("KPeriod", 14).SetDisplay("K Period", "%K period", "Stochastic")
self._d_period = self.Param("DPeriod", 3).SetDisplay("D Period", "%D period", "Stochastic")
self._oversold_level = self.Param("OversoldLevel", 30.0).SetDisplay("Oversold Level", "Stochastic oversold", "Stochastic")
self._overbought_level = self.Param("OverboughtLevel", 70.0).SetDisplay("Overbought Level", "Stochastic overbought", "Stochastic")
self._cooldown_bars = self.Param("CooldownBars", 250).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._prev_k = 0.0
self._prev_prev_k = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(stochastic_failure_swing_strategy, self).OnReseted()
self._prev_k = 0.0
self._prev_prev_k = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(stochastic_failure_swing_strategy, self).OnStarted2(time)
self._prev_k = 0.0
self._prev_prev_k = 0.0
self._cooldown = 0
stochastic = StochasticOscillator()
stochastic.K.Length = self._k_period.Value
stochastic.D.Length = self._d_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(stochastic, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, stochastic)
self.DrawOwnTrades(area)
def _process_candle(self, candle, stoch_iv):
if candle.State != CandleStates.Finished:
return
k_val = stoch_iv.K
if k_val is None:
return
kv = float(k_val)
# Need at least 2 previous values
if self._prev_k == 0 or self._prev_prev_k == 0:
self._prev_prev_k = self._prev_k
self._prev_k = kv
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_prev_k = self._prev_k
self._prev_k = kv
return
cd = self._cooldown_bars.Value
oversold = self._oversold_level.Value
overbought = self._overbought_level.Value
# Bullish Failure Swing: K was oversold, rose, pulled back but stayed above prior low
is_bullish = (
self._prev_prev_k < oversold and
self._prev_k > self._prev_prev_k and
kv < self._prev_k and
kv > self._prev_prev_k
)
# Bearish Failure Swing: K was overbought, fell, bounced but stayed below prior high
is_bearish = (
self._prev_prev_k > overbought and
self._prev_k < self._prev_prev_k and
kv > self._prev_k and
kv < self._prev_prev_k
)
if self.Position == 0:
if is_bullish:
self.BuyMarket()
self._cooldown = cd
elif is_bearish:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0:
# Exit long when K crosses above overbought
if kv > overbought:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0:
# Exit short when K crosses below oversold
if kv < oversold:
self.BuyMarket()
self._cooldown = cd
self._prev_prev_k = self._prev_k
self._prev_k = kv
def CreateClone(self):
return stochastic_failure_swing_strategy()