GitHub で見る

WPR レベルクロス戦略

この戦略は Williams %R オシレーターが事前定義された買われすぎ・売られすぎレベルをクロスする際に取引します。

インジケーターが Low Level を下回るとき、売られすぎ状態からの潜在的な反転を示します。High Level を上回るとき、買われすぎ状態からの反転の可能性を示します。選択した Trend Mode に応じて、戦略はインジケーターの方向に取引するか、逆張り取引のためにシグナルを反転させることができます。

パラメーター

  • WprPeriod – Williams %R のルックバック期間。
  • HighLevel – 買われすぎのしきい値。
  • LowLevel – 売られすぎのしきい値。
  • TrendDirect はインジケーターシグナルに従って取引し、Against はそれらを反転させます。
  • EnableBuyEntry / EnableSellEntry – ロング/ショートポジションへのエントリーを許可。
  • EnableBuyExit / EnableSellExit – ショート/ロングポジションのクローズを許可。
  • StopLoss – 価格単位でのストップロス値。
  • TakeProfit – 価格単位でのテイクプロフィット値。
  • CandleType – 計算に使用するローソク足の時間軸。

仕組み

  1. 戦略はローソク足を購読し、Williams %R インジケーターを計算します。
  2. 各完成したローソク足でインジケーターが指定したレベルをクロスしたかどうかを確認します。
  3. Trend と有効なアクションに応じて、成行注文を使ってポジションを開くか閉じます。
  4. オプションのストップロスとテイクプロフィット保護は StartProtection を通じて有効になります。

注記

  • コード内のコメントは英語で提供されています。
  • C# バージョンのみが実装されており、Python バージョンは意図的に省略されています。
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
	}
}