Strategie Williams %R Hook Reversal
Die Williams %R Hook Reversal-Strategie folgt dem Williams %R-Indikator, wenn er schnell von einer Extremzone zurückschnappt. Wenn der Wert über -20 oder unter -80 steigt und dann zur Mitte hakt, ist der vorherige Schub wahrscheinlich erschöpft.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 172%. Die Strategie funktioniert am besten am Devisenmarkt.
Die Strategie kauft, wenn %R aus dem überverkauften Bereich nach oben dreht, während der Preis neue Tiefs drückt, und verkauft, wenn er aus dem überkauften Bereich nach unten hakt, während neue Hochs gebildet werden.
Ein enger prozentualer Stop kontrolliert das Risiko, und Trades werden beendet, sobald %R in die entgegengesetzte Richtung hakt oder der Stop ausgelöst wird.
Details
- Einstiegskriterien: Indikatorsignal
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 MinutenStopLoss= 2%
- Filter:
- Kategorie: Umkehr
- Richtung: Beide
- Indikatoren: Williams %R
- 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>
/// Williams %R Hook Reversal strategy.
/// Enters long when Williams %R hooks up from oversold zone.
/// Enters short when Williams %R hooks down from overbought zone.
/// Exits when Williams %R reaches neutral zone.
/// Uses cooldown to control trade frequency.
/// </summary>
public class WilliamsRHookReversalStrategy : Strategy
{
private readonly StrategyParam<int> _willRPeriod;
private readonly StrategyParam<decimal> _oversoldLevel;
private readonly StrategyParam<decimal> _overboughtLevel;
private readonly StrategyParam<decimal> _exitLevel;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal? _prevWillR;
private int _cooldown;
/// <summary>
/// Williams %R period.
/// </summary>
public int WillRPeriod
{
get => _willRPeriod.Value;
set => _willRPeriod.Value = value;
}
/// <summary>
/// Oversold level (typically -80).
/// </summary>
public decimal OversoldLevel
{
get => _oversoldLevel.Value;
set => _oversoldLevel.Value = value;
}
/// <summary>
/// Overbought level (typically -20).
/// </summary>
public decimal OverboughtLevel
{
get => _overboughtLevel.Value;
set => _overboughtLevel.Value = value;
}
/// <summary>
/// Exit level (neutral zone).
/// </summary>
public decimal ExitLevel
{
get => _exitLevel.Value;
set => _exitLevel.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public WilliamsRHookReversalStrategy()
{
_willRPeriod = Param(nameof(WillRPeriod), 14)
.SetRange(7, 21)
.SetDisplay("Williams %R Period", "Period for Williams %R", "Williams %R");
_oversoldLevel = Param(nameof(OversoldLevel), -80m)
.SetRange(-90m, -70m)
.SetDisplay("Oversold", "Oversold level", "Williams %R");
_overboughtLevel = Param(nameof(OverboughtLevel), -20m)
.SetRange(-30m, -10m)
.SetDisplay("Overbought", "Overbought level", "Williams %R");
_exitLevel = Param(nameof(ExitLevel), -50m)
.SetRange(-60m, -40m)
.SetDisplay("Exit Level", "Neutral exit zone", "Williams %R");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevWillR = null;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevWillR = null;
_cooldown = 0;
var williamsR = new WilliamsR { Length = WillRPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(williamsR, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, williamsR);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal willRValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_prevWillR == null)
{
_prevWillR = willRValue;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevWillR = willRValue;
return;
}
// Hook up from oversold
var oversoldHookUp = _prevWillR < OversoldLevel && willRValue > _prevWillR;
// Hook down from overbought
var overboughtHookDown = _prevWillR > OverboughtLevel && willRValue < _prevWillR;
if (Position == 0 && oversoldHookUp)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && overboughtHookDown)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && willRValue < ExitLevel)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && willRValue > ExitLevel)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevWillR = willRValue;
}
}
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 WilliamsR
from StockSharp.Algo.Strategies import Strategy
class williams_r_hook_reversal_strategy(Strategy):
"""
Williams %R Hook Reversal strategy.
Enters long when Williams %R hooks up from oversold zone.
Enters short when Williams %R hooks down from overbought zone.
Exits when Williams %R reaches neutral zone.
"""
def __init__(self):
super(williams_r_hook_reversal_strategy, self).__init__()
self._wr_period = self.Param("WillRPeriod", 14).SetDisplay("Williams %R Period", "Period for Williams %R", "Williams %R")
self._oversold_level = self.Param("OversoldLevel", -80.0).SetDisplay("Oversold", "Oversold level", "Williams %R")
self._overbought_level = self.Param("OverboughtLevel", -20.0).SetDisplay("Overbought", "Overbought level", "Williams %R")
self._exit_level = self.Param("ExitLevel", -50.0).SetDisplay("Exit Level", "Neutral exit zone", "Williams %R")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._prev_wr = None
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(williams_r_hook_reversal_strategy, self).OnReseted()
self._prev_wr = None
self._cooldown = 0
def OnStarted2(self, time):
super(williams_r_hook_reversal_strategy, self).OnStarted2(time)
self._prev_wr = None
self._cooldown = 0
wr = WilliamsR()
wr.Length = self._wr_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(wr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, wr)
self.DrawOwnTrades(area)
def _process_candle(self, candle, wr_val):
if candle.State != CandleStates.Finished:
return
wv = float(wr_val)
if self._prev_wr is None:
self._prev_wr = wv
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_wr = wv
return
cd = self._cooldown_bars.Value
oversold = self._oversold_level.Value
overbought = self._overbought_level.Value
exit_lvl = self._exit_level.Value
# Hook up from oversold
oversold_hook_up = self._prev_wr < oversold and wv > self._prev_wr
# Hook down from overbought
overbought_hook_down = self._prev_wr > overbought and wv < self._prev_wr
if self.Position == 0 and oversold_hook_up:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and overbought_hook_down:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and wv < exit_lvl:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and wv > exit_lvl:
self.BuyMarket()
self._cooldown = cd
self._prev_wr = wv
def CreateClone(self):
return williams_r_hook_reversal_strategy()