Ver no GitHub

Estratégia WPR de Cruzamento de Nível

Esta estratégia opera com base no oscilador Williams %R ao cruzar níveis predefinidos de sobrecompra e sobrevenda.

Quando o indicador cruza abaixo do Low Level, sinaliza uma possível reversão de uma condição de sobrevenda. Quando cruza acima do High Level, indica uma possível reversão de uma condição de sobrecompra. Dependendo do Trend Mode selecionado, a estratégia pode operar na direção do indicador ou inverter os sinais para negociação contra-tendência.

Parâmetros

  • WprPeriod – período de lookback para Williams %R.
  • HighLevel – limite de sobrecompra.
  • LowLevel – limite de sobrevenda.
  • TrendDirect opera com os sinais do indicador, Against os inverte.
  • EnableBuyEntry / EnableSellEntry – permitir entrar em posições compradas/vendidas.
  • EnableBuyExit / EnableSellExit – permitir fechar posições vendidas/compradas.
  • StopLoss – valor do stop-loss em unidades de preço.
  • TakeProfit – valor do take-profit em unidades de preço.
  • CandleType – período dos candles usados para cálculos.

Como Funciona

  1. A estratégia subscreve candles e calcula o indicador Williams %R.
  2. Em cada candle concluído, verifica se o indicador cruzou os níveis especificados.
  3. Dependendo de Trend e das ações habilitadas, abre ou fecha posições usando ordens de mercado.
  4. A proteção opcional de stop-loss e take-profit é ativada através de StartProtection.

Notas

  • Os comentários no código estão em inglês.
  • Apenas a versão C# está implementada; a versão Python é omitida intencionalmente.
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
	}
}