WPR Niveau-Kreuzungs-Strategie
Diese Strategie handelt auf Basis des Williams %R-Oszillators, wenn er vordefinierte Überkauf- und Überverkauf-Niveaus kreuzt.
Wenn der Indikator unter das Low Level fällt, signalisiert er eine mögliche Umkehr aus einer überkauften Bedingung. Wenn er über das High Level steigt, deutet er auf eine mögliche Umkehr aus einer überkauften Bedingung hin. Je nach ausgewähltem Trend Mode kann die Strategie in Richtung des Indikators handeln oder die Signale für gegenläufiges Trading umkehren.
Parameter
WprPeriod– Lookback-Periode für Williams %R.HighLevel– Überkauf-Schwellenwert.LowLevel– Überverkauf-Schwellenwert.Trend–Directhandelt mit Indikatorsignalen,Againstkehrt sie um.EnableBuyEntry/EnableSellEntry– Einstieg in Long-/Short-Positionen erlauben.EnableBuyExit/EnableSellExit– Schließen von Short-/Long-Positionen erlauben.StopLoss– Stop-Loss-Wert in Preiseinheiten.TakeProfit– Take-Profit-Wert in Preiseinheiten.CandleType– Zeitrahmen der für Berechnungen verwendeten Kerzen.
Funktionsweise
- Die Strategie abonniert Kerzen und berechnet den Williams %R-Indikator.
- Bei jeder abgeschlossenen Kerze prüft sie, ob der Indikator die angegebenen Niveaus gekreuzt hat.
- Abhängig von
Trendund aktivierten Aktionen öffnet oder schließt sie Positionen mit Marktaufträgen. - Optionaler Stop-Loss- und Take-Profit-Schutz wird über
StartProtectionaktiviert.
Hinweise
- Kommentare im Code sind auf Englisch.
- Nur die C#-Version ist implementiert; die Python-Version ist absichtlich weggelassen.
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 based on Williams %R indicator crossing specified levels.
/// </summary>
public class WprLevelCrossStrategy : Strategy
{
private readonly StrategyParam<int> _wprPeriod;
private readonly StrategyParam<decimal> _highLevel;
private readonly StrategyParam<decimal> _lowLevel;
private readonly StrategyParam<TrendModes> _trend;
private readonly StrategyParam<bool> _enableBuyEntry;
private readonly StrategyParam<bool> _enableSellEntry;
private readonly StrategyParam<bool> _enableBuyExit;
private readonly StrategyParam<bool> _enableSellExit;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevWr;
/// <summary>
/// Lookback period for Williams %R.
/// </summary>
public int WprPeriod
{
get => _wprPeriod.Value;
set => _wprPeriod.Value = value;
}
/// <summary>
/// Upper threshold to detect overbought levels.
/// </summary>
public decimal HighLevel
{
get => _highLevel.Value;
set => _highLevel.Value = value;
}
/// <summary>
/// Lower threshold to detect oversold levels.
/// </summary>
public decimal LowLevel
{
get => _lowLevel.Value;
set => _lowLevel.Value = value;
}
/// <summary>
/// Trend mode: Direct trades with indicator, Against inverts signals.
/// </summary>
public TrendModes Trend
{
get => _trend.Value;
set => _trend.Value = value;
}
/// <summary>
/// Enable opening of long positions.
/// </summary>
public bool EnableBuyEntry
{
get => _enableBuyEntry.Value;
set => _enableBuyEntry.Value = value;
}
/// <summary>
/// Enable opening of short positions.
/// </summary>
public bool EnableSellEntry
{
get => _enableSellEntry.Value;
set => _enableSellEntry.Value = value;
}
/// <summary>
/// Enable closing of short positions.
/// </summary>
public bool EnableBuyExit
{
get => _enableBuyExit.Value;
set => _enableBuyExit.Value = value;
}
/// <summary>
/// Enable closing of long positions.
/// </summary>
public bool EnableSellExit
{
get => _enableSellExit.Value;
set => _enableSellExit.Value = value;
}
/// <summary>
/// Stop loss value in price units.
/// </summary>
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
/// <summary>
/// Take profit value in price units.
/// </summary>
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
/// <summary>
/// Candle type to process.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="WprLevelCrossStrategy"/>.
/// </summary>
public WprLevelCrossStrategy()
{
_wprPeriod = Param(nameof(WprPeriod), 14)
.SetDisplay("WPR Period", "Lookback period for Williams %R", "Indicators")
.SetOptimize(10, 20, 2);
_highLevel = Param(nameof(HighLevel), -20m)
.SetDisplay("High Level", "Overbought threshold", "Indicators");
_lowLevel = Param(nameof(LowLevel), -80m)
.SetDisplay("Low Level", "Oversold threshold", "Indicators");
_trend = Param(nameof(Trend), TrendModes.Direct)
.SetDisplay("Trend Mode", "Direct - trade with indicator; Against - inverse signals", "General");
_enableBuyEntry = Param(nameof(EnableBuyEntry), true)
.SetDisplay("Enable Buy Entry", "Allow opening long positions", "Trading");
_enableSellEntry = Param(nameof(EnableSellEntry), true)
.SetDisplay("Enable Sell Entry", "Allow opening short positions", "Trading");
_enableBuyExit = Param(nameof(EnableBuyExit), true)
.SetDisplay("Enable Buy Exit", "Allow closing short positions", "Trading");
_enableSellExit = Param(nameof(EnableSellExit), true)
.SetDisplay("Enable Sell Exit", "Allow closing long positions", "Trading");
_stopLoss = Param(nameof(StopLoss), 1000m)
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk");
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take Profit", "Take profit in price units", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Time frame for candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevWr = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var wpr = new WilliamsR { Length = WprPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(wpr, ProcessCandle).Start();
StartProtection(
new Unit(TakeProfit, UnitTypes.Absolute),
new Unit(StopLoss, UnitTypes.Absolute));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, wpr);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal wr)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevWr == 0m)
{
_prevWr = wr;
return;
}
var crossedBelowLow = _prevWr > LowLevel && wr <= LowLevel;
var crossedAboveHigh = _prevWr < HighLevel && wr >= HighLevel;
if (Trend == TrendModes.Direct)
{
if (crossedBelowLow && EnableBuyEntry && Position <= 0)
BuyMarket();
if (crossedAboveHigh && EnableSellEntry && Position >= 0)
SellMarket();
}
else
{
if (crossedBelowLow && EnableSellEntry && Position >= 0)
SellMarket();
if (crossedAboveHigh && EnableBuyEntry && Position <= 0)
BuyMarket();
}
_prevWr = wr;
}
/// <summary>
/// Trend modes for interpreting Williams %R signals.
/// </summary>
public enum TrendModes
{
/// <summary>
/// Trade in the direction of indicator signals.
/// </summary>
Direct,
/// <summary>
/// Invert indicator signals for counter-trend trading.
/// </summary>
Against
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import WilliamsR
from StockSharp.Algo.Strategies import Strategy
class wpr_level_cross_strategy(Strategy):
DIRECT = 0
AGAINST = 1
def __init__(self):
super(wpr_level_cross_strategy, self).__init__()
self._wpr_period = self.Param("WprPeriod", 14)
self._high_level = self.Param("HighLevel", -20.0)
self._low_level = self.Param("LowLevel", -80.0)
self._trend = self.Param("Trend", 0)
self._enable_buy_entry = self.Param("EnableBuyEntry", True)
self._enable_sell_entry = self.Param("EnableSellEntry", True)
self._enable_buy_exit = self.Param("EnableBuyExit", True)
self._enable_sell_exit = self.Param("EnableSellExit", True)
self._stop_loss = self.Param("StopLoss", 1000.0)
self._take_profit = self.Param("TakeProfit", 2000.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._prev_wr = 0.0
@property
def WprPeriod(self):
return self._wpr_period.Value
@WprPeriod.setter
def WprPeriod(self, value):
self._wpr_period.Value = value
@property
def HighLevel(self):
return self._high_level.Value
@HighLevel.setter
def HighLevel(self, value):
self._high_level.Value = value
@property
def LowLevel(self):
return self._low_level.Value
@LowLevel.setter
def LowLevel(self, value):
self._low_level.Value = value
@property
def Trend(self):
return self._trend.Value
@Trend.setter
def Trend(self, value):
self._trend.Value = value
@property
def EnableBuyEntry(self):
return self._enable_buy_entry.Value
@EnableBuyEntry.setter
def EnableBuyEntry(self, value):
self._enable_buy_entry.Value = value
@property
def EnableSellEntry(self):
return self._enable_sell_entry.Value
@EnableSellEntry.setter
def EnableSellEntry(self, value):
self._enable_sell_entry.Value = value
@property
def EnableBuyExit(self):
return self._enable_buy_exit.Value
@EnableBuyExit.setter
def EnableBuyExit(self, value):
self._enable_buy_exit.Value = value
@property
def EnableSellExit(self):
return self._enable_sell_exit.Value
@EnableSellExit.setter
def EnableSellExit(self, value):
self._enable_sell_exit.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(wpr_level_cross_strategy, self).OnStarted2(time)
self._prev_wr = 0.0
wpr = WilliamsR()
wpr.Length = self.WprPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(wpr, self.ProcessCandle).Start()
self.StartProtection(
Unit(self.TakeProfit, UnitTypes.Absolute),
Unit(self.StopLoss, UnitTypes.Absolute))
def ProcessCandle(self, candle, wr_value):
if candle.State != CandleStates.Finished:
return
wr = float(wr_value)
if self._prev_wr == 0.0:
self._prev_wr = wr
return
crossed_below_low = self._prev_wr > float(self.LowLevel) and wr <= float(self.LowLevel)
crossed_above_high = self._prev_wr < float(self.HighLevel) and wr >= float(self.HighLevel)
if self.Trend == self.DIRECT:
if crossed_below_low and self.EnableBuyEntry and self.Position <= 0:
self.BuyMarket()
if crossed_above_high and self.EnableSellEntry and self.Position >= 0:
self.SellMarket()
else:
if crossed_below_low and self.EnableSellEntry and self.Position >= 0:
self.SellMarket()
if crossed_above_high and self.EnableBuyEntry and self.Position <= 0:
self.BuyMarket()
self._prev_wr = wr
def OnReseted(self):
super(wpr_level_cross_strategy, self).OnReseted()
self._prev_wr = 0.0
def CreateClone(self):
return wpr_level_cross_strategy()