Auf GitHub ansehen

Strategie Williams R Ichimoku

Dieses Setup kombiniert die Momentum-Extreme von Williams %R mit der Trendstruktur, die durch die Ichimoku Cloud definiert wird. Die Idee ist, starken Bewegungen nur dann beizutreten, wenn der Preis auf der günstigen Seite der Cloud liegt und die kurzfristigen Linien die Richtung bestätigen.

Tests zeigen eine durchschnittliche Jahresrendite von etwa 73%. Sie funktioniert am besten auf dem Kryptomarkt.

Eine Long-Gelegenheit entsteht, wenn der Oszillator unter -80 fällt, während der Preis über der Cloud liegt und Tenkan-sen über Kijun-sen kreuzt. Ein Short-Signal entsteht, wenn %R über -20 steigt, der Preis unter der Cloud liegt und Tenkan-sen unter Kijun-sen. Die Position bleibt offen, bis der Preis die entgegengesetzte Seite der Cloud überkreuzt.

Da die Methode auf mehrere Bestätigungen wartet, eignet sie sich für Trader, die klare Trendfilter gegenüber schnellen Umkehrungen bevorzugen. Dynamische Stops werden um den Kijun-sen gesetzt, sodass das Risiko sich mit der zugrunde liegenden Trendstärke anpasst.

Details

  • Einstiegskriterien:
    • Long: %R < -80 && price above Ichimoku cloud and Tenkan-sen > Kijun-sen
    • Short: %R > -20 && price below Ichimoku cloud and Tenkan-sen < Kijun-sen
  • Long/Short: Beide Seiten.
  • Ausstiegskriterien:
    • Long: Ausstieg, wenn der Preis unter die Cloud fällt
    • Short: Ausstieg, wenn der Preis über die Cloud steigt
  • Stops: Ja.
  • Standardwerte:
    • WilliamsRPeriod = 14
    • TenkanPeriod = 9
    • KijunPeriod = 26
    • SenkouSpanBPeriod = 52
    • CandleType = TimeSpan.FromMinutes(15)
  • Filter:
    • Kategorie: Gemischt
    • Richtung: Beide
    • Indikatoren: Williams R Ichimoku
    • Stops: Ja
    • Komplexität: Mittel
    • Zeitrahmen: Intraday
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel
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 and Ichimoku indicators.
/// Enters long when Williams %R is below -80 (oversold) and price is above Ichimoku Cloud with Tenkan-sen > Kijun-sen.
/// Enters short when Williams %R is above -20 (overbought) and price is below Ichimoku Cloud with Tenkan-sen < Kijun-sen.
/// </summary>
public class WilliamsIchimokuStrategy : Strategy
{
	private readonly StrategyParam<int> _williamsRPeriod;
	private readonly StrategyParam<int> _tenkanPeriod;
	private readonly StrategyParam<int> _kijunPeriod;
	private readonly StrategyParam<int> _senkouSpanBPeriod;
	private readonly StrategyParam<int> _cooldownBars;
	private readonly StrategyParam<DataType> _candleType;
	
	private WilliamsR _williamsR;
	private Ichimoku _ichimoku;
	
	private decimal? _lastKijun;
	private decimal _prevWilliamsR;
	private int _cooldown;
	
	/// <summary>
	/// Williams %R indicator period.
	/// </summary>
	public int WilliamsRPeriod
	{
		get => _williamsRPeriod.Value;
		set => _williamsRPeriod.Value = value;
	}
	
	/// <summary>
	/// Tenkan-sen period (Ichimoku).
	/// </summary>
	public int TenkanPeriod
	{
		get => _tenkanPeriod.Value;
		set => _tenkanPeriod.Value = value;
	}
	
	/// <summary>
	/// Kijun-sen period (Ichimoku).
	/// </summary>
	public int KijunPeriod
	{
		get => _kijunPeriod.Value;
		set => _kijunPeriod.Value = value;
	}
	
	/// <summary>
	/// Senkou Span B period (Ichimoku).
	/// </summary>
	public int SenkouSpanBPeriod
	{
		get => _senkouSpanBPeriod.Value;
		set => _senkouSpanBPeriod.Value = value;
	}
	
	/// <summary>
	/// Bars to wait between trades.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

	/// <summary>
	/// Candle type parameter.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}
	
	/// <summary>
	/// Constructor.
	/// </summary>
	public WilliamsIchimokuStrategy()
	{
		_williamsRPeriod = Param(nameof(WilliamsRPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("Williams %R Period", "Period for Williams %R calculation", "Indicators")
			
			.SetOptimize(10, 20, 2);
			
		_tenkanPeriod = Param(nameof(TenkanPeriod), 9)
			.SetGreaterThanZero()
			.SetDisplay("Tenkan-sen Period", "Period for Tenkan-sen line (Ichimoku)", "Indicators")
			
			.SetOptimize(7, 13, 1);
			
		_kijunPeriod = Param(nameof(KijunPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Kijun-sen Period", "Period for Kijun-sen line (Ichimoku)", "Indicators")
			
			.SetOptimize(20, 30, 2);
			
		_senkouSpanBPeriod = Param(nameof(SenkouSpanBPeriod), 52)
			.SetGreaterThanZero()
			.SetDisplay("Senkou Span B Period", "Period for Senkou Span B line (Ichimoku)", "Indicators")
			
			.SetOptimize(40, 60, 4);

		_cooldownBars = Param(nameof(CooldownBars), 60)
			.SetRange(1, 200)
			.SetDisplay("Cooldown Bars", "Bars between trades", "General");
			
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).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();

		_williamsR = null;
		_ichimoku = null;
		_lastKijun = null;
		_prevWilliamsR = -50m;
		_cooldown = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		// Initialize indicators
		_williamsR = new WilliamsR
		{
			Length = WilliamsRPeriod
		};
		
		_ichimoku = new Ichimoku
		{
			Tenkan = { Length = TenkanPeriod },
			Kijun = { Length = KijunPeriod },
			SenkouB = { Length = SenkouSpanBPeriod }
		};
		
		// Create candles subscription
		var subscription = SubscribeCandles(CandleType);
		
		// Bind indicators to subscription
		subscription
			.BindEx(_williamsR, _ichimoku, ProcessCandle)
			.Start();
		
		// Setup chart if available
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _williamsR);
			DrawIndicator(area, _ichimoku);
			DrawOwnTrades(area);
		}
	}
	
	private void ProcessCandle(ICandleMessage candle, IIndicatorValue williamsRValue, IIndicatorValue ichimokuValue)
	{
		// Skip unfinished candles
		if (candle.State != CandleStates.Finished)
			return;
			
		// Skip if strategy is not ready to trade
		if (!IsFormedAndOnlineAndAllowTrading())
			return;
			
		// Extract Ichimoku values
		var ichimokuTyped = (IchimokuValue)ichimokuValue;

		if (ichimokuTyped.Tenkan is not decimal tenkan)
			return;

		if (ichimokuTyped.Kijun is not decimal kijun)
			return;

		if (ichimokuTyped.SenkouA is not decimal senkouA)
			return;

		if (ichimokuTyped.SenkouB is not decimal senkouB)
			return;

		// Determine if price is above or below the Kumo (cloud)
		var kumoTop = Math.Max(senkouA, senkouB);
		var kumoBottom = Math.Min(senkouA, senkouB);
		var isPriceAboveKumo = candle.ClosePrice > kumoTop;
		var isPriceBelowKumo = candle.ClosePrice < kumoBottom;

		var williamsRDec = williamsRValue.ToDecimal();
		var crossedBelow80 = _prevWilliamsR >= -90m && williamsRDec < -90m;
		var crossedAbove20 = _prevWilliamsR <= -10m && williamsRDec > -10m;
		_prevWilliamsR = williamsRDec;
		if (_cooldown > 0)
			_cooldown--;

		// Save current Kijun for stop-loss
		_lastKijun = kijun;
		
		// Trading logic
		if (_cooldown == 0 && crossedBelow80 && candle.ClosePrice > kumoTop * 1.002m && isPriceAboveKumo && tenkan > kijun)
		{
			// Long signal: %R < -80 (oversold), price above Kumo, Tenkan > Kijun
			if (Position <= 0)
			{
				// Close any existing short position and open long
				BuyMarket(Volume + Math.Abs(Position));
				_cooldown = CooldownBars;
			}
		}
		else if (_cooldown == 0 && crossedAbove20 && candle.ClosePrice < kumoBottom * 0.998m && isPriceBelowKumo && tenkan < kijun)
		{
			// Short signal: %R > -20 (overbought), price below Kumo, Tenkan < Kijun
			if (Position >= 0)
			{
				// Close any existing long position and open short
				SellMarket(Volume + Math.Abs(Position));
				_cooldown = CooldownBars;
			}
		}
		else if ((Position > 0 && candle.ClosePrice < kumoBottom) || 
				(Position < 0 && candle.ClosePrice > kumoTop))
		{
			// Exit positions when price crosses the Kumo
			if (Position > 0)
			{
				SellMarket(Math.Abs(Position));
				_cooldown = CooldownBars;
			}
			else if (Position < 0)
			{
				BuyMarket(Math.Abs(Position));
				_cooldown = CooldownBars;
			}
		}
	}
}