Auf GitHub ansehen

WPRSI-Signal-Strategie

Überblick

Diese Strategie repliziert den WPRSIsignal-Experten aus MetaTrader. Sie kombiniert den Williams Percent Range (WPR) und den Relative Strength Index (RSI), um Kauf- und Verkaufssignale zu generieren.

Logik

  • Ein Kaufsignal wird erzeugt, wenn der WPR von unten über -20 kreuzt und der RSI über 50 liegt. Das Signal wird nur bestätigt, wenn der WPR für die nächsten FilterUp Balken über -20 bleibt.
  • Ein Verkaufssignal wird erzeugt, wenn der WPR von oben unter -80 kreuzt und der RSI unter 50 liegt. Das Signal wird nur bestätigt, wenn der WPR für die nächsten FilterDown Balken unter -80 bleibt.
  • Bei Bestätigung eines Kaufsignals eröffnet die Strategie eine Long-Position, sofern keine aktive Long-Position vorhanden ist. Bei Bestätigung eines Verkaufssignals wird eine Short-Position eröffnet, sofern keine aktive Short-Position vorhanden ist.

Parameter

  • Period – Berechnungslänge für WPR und RSI.
  • FilterUp – Anzahl der Balken, die WPR über -20 halten müssen, um ein Kaufsignal zu bestätigen.
  • FilterDown – Anzahl der Balken, die WPR unter -80 halten müssen, um ein Verkaufssignal zu bestätigen.
  • CandleType – Zeitrahmen der für Berechnungen verwendeten Kerzen.

Verwendung

Hängen Sie die Strategie an ein beliebiges Wertpapier. Die Strategie verwendet SubscribeCandles und Bind, um Kerzendaten und Indikatorwerte zu empfangen. Positionen werden mit Marktaufträgen verwaltet: BuyMarket für Long-Einstiege und SellMarket für Short-Einstiege. Die Strategie implementiert weder Stop-Loss noch Take-Profit; Positionen werden durch entgegengesetzte Signale geschlossen.

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 RSI combination.
/// </summary>
public class WprsiSignalStrategy : Strategy
{
	private readonly StrategyParam<int> _period;
	private readonly StrategyParam<int> _filterUp;
	private readonly StrategyParam<int> _filterDown;
	private readonly StrategyParam<DataType> _candleType;

	private WilliamsR _wpr;
	private RelativeStrengthIndex _rsi;

	private decimal _prevWpr;
	private bool _isPrevInit;
	private bool _pendingBuy;
	private bool _pendingSell;
	private int _upCounter;
	private int _downCounter;

	/// <summary>
	/// Calculation length for WPR and RSI.
	/// </summary>
	public int Period
	{
		get => _period.Value;
		set => _period.Value = value;
	}

	/// <summary>
	/// Bars count to confirm buy signal.
	/// </summary>
	public int FilterUp
	{
		get => _filterUp.Value;
		set => _filterUp.Value = value;
	}

	/// <summary>
	/// Bars count to confirm sell signal.
	/// </summary>
	public int FilterDown
	{
		get => _filterDown.Value;
		set => _filterDown.Value = value;
	}

	/// <summary>
	/// Candle type for indicators calculation.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="WprsiSignalStrategy"/>.
	/// </summary>
	public WprsiSignalStrategy()
	{
		_period = Param(nameof(Period), 27)
			.SetGreaterThanZero()
			.SetDisplay("Period", "Period for WPR and RSI", "Parameters");

		_filterUp = Param(nameof(FilterUp), 10)
			.SetNotNegative()
			.SetDisplay("Filter Up", "Bars to confirm buy", "Parameters");

		_filterDown = Param(nameof(FilterDown), 10)
			.SetNotNegative()
			.SetDisplay("Filter Down", "Bars to confirm sell", "Parameters");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Time frame for candles", "Parameters");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevWpr = 0m;
		_isPrevInit = false;
		_pendingBuy = false;
		_pendingSell = false;
		_upCounter = 0;
		_downCounter = 0;
	}

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

		_wpr = new WilliamsR { Length = Period };
		_rsi = new RelativeStrengthIndex { Length = Period };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(_wpr, _rsi, ProcessCandle).Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _wpr);
			DrawIndicator(area, _rsi);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal wprValue, decimal rsiValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_isPrevInit)
		{
			_prevWpr = wprValue;
			_isPrevInit = true;
			return;
		}

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevWpr = wprValue;
			return;
		}

		if (_pendingBuy)
		{
			if (wprValue <= -20)
				_pendingBuy = false;
			else if (--_upCounter <= 0)
			{
				if (rsiValue > 50 && Position <= 0)
					BuyMarket();
				_pendingBuy = false;
			}
		}
		else if (_prevWpr < -20 && wprValue > -20 && rsiValue > 50)
		{
			_pendingBuy = true;
			_upCounter = FilterUp;
		}

		if (_pendingSell)
		{
			if (wprValue >= -80)
				_pendingSell = false;
			else if (--_downCounter <= 0)
			{
				if (rsiValue < 50 && Position >= 0)
					SellMarket();
				_pendingSell = false;
			}
		}
		else if (_prevWpr > -80 && wprValue < -80 && rsiValue < 50)
		{
			_pendingSell = true;
			_downCounter = FilterDown;
		}

		_prevWpr = wprValue;
	}
}