Ver en GitHub

Estrategia SpectrAnalysis WPR

Esta estrategia se convirtió a partir del experto MQL5 Exp_i-SpectrAnalysis_WPR. Analiza la dirección del indicador Williams %R y abre o cierra posiciones según los giros del indicador.

Lógica

  1. Suscribirse a las velas del marco temporal seleccionado.
  2. Calcular Williams %R con el período configurado.
  3. Conservar los últimos dos valores del indicador para detectar dirección ascendente o descendente.
  4. Cuando el indicador gira hacia arriba y las entradas largas están permitidas:
    • Cerrar posiciones cortas si está habilitado.
    • Abrir una nueva posición larga.
  5. Cuando el indicador gira hacia abajo y las entradas cortas están permitidas:
    • Cerrar posiciones largas si está habilitado.
    • Abrir una nueva posición corta.

Solo se procesan velas completadas. La estrategia no utiliza consultas históricas complejas y se basa en enlaces de API de alto nivel.

Parámetros

Nombre Descripción Predeterminado
Candle Type Marco temporal de las velas utilizadas para los cálculos 4h
WPR Period Período del indicador Williams %R 13
Allow Long Entry Permitir abrir posiciones largas true
Allow Short Entry Permitir abrir posiciones cortas true
Allow Long Exit Permitir cerrar posiciones largas true
Allow Short Exit Permitir cerrar posiciones cortas true

Notas

La versión MQL original aplicaba análisis espectral a la salida de Williams %R. Esta conversión en C# usa el indicador Williams %R estándar y replica la lógica de señales rastreando los valores recientes del indicador.

using System;
using System.Collections.Generic;

using Ecng.Common;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy based on Williams %R trend direction.
/// </summary>
public class SpectrAnalysisWprStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _wprPeriod;
	private readonly StrategyParam<bool> _buyPosOpen;
	private readonly StrategyParam<bool> _sellPosOpen;
	private readonly StrategyParam<bool> _buyPosClose;
	private readonly StrategyParam<bool> _sellPosClose;

	private decimal? _prev;
	private decimal? _prev2;

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

	/// <summary>
	/// Williams %R period.
	/// </summary>
	public int WprPeriod
	{
		get => _wprPeriod.Value;
		set => _wprPeriod.Value = value;
	}

	/// <summary>
	/// Allow opening long positions.
	/// </summary>
	public bool BuyPosOpen
	{
		get => _buyPosOpen.Value;
		set => _buyPosOpen.Value = value;
	}

	/// <summary>
	/// Allow opening short positions.
	/// </summary>
	public bool SellPosOpen
	{
		get => _sellPosOpen.Value;
		set => _sellPosOpen.Value = value;
	}

	/// <summary>
	/// Allow closing long positions.
	/// </summary>
	public bool BuyPosClose
	{
		get => _buyPosClose.Value;
		set => _buyPosClose.Value = value;
	}

	/// <summary>
	/// Allow closing short positions.
	/// </summary>
	public bool SellPosClose
	{
		get => _sellPosClose.Value;
		set => _sellPosClose.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public SpectrAnalysisWprStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for indicator", "General");
		_wprPeriod = Param(nameof(WprPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("WPR Period", "Williams %R period", "Indicator");
		_buyPosOpen = Param(nameof(BuyPosOpen), true)
			.SetDisplay("Allow Long Entry", "Enable long position opening", "Trading");
		_sellPosOpen = Param(nameof(SellPosOpen), true)
			.SetDisplay("Allow Short Entry", "Enable short position opening", "Trading");
		_buyPosClose = Param(nameof(BuyPosClose), true)
			.SetDisplay("Allow Long Exit", "Enable closing of long positions", "Trading");
		_sellPosClose = Param(nameof(SellPosClose), true)
			.SetDisplay("Allow Short Exit", "Enable closing of short positions", "Trading");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prev = null;
		_prev2 = null;
	}

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

		_prev = null;
		_prev2 = null;

		var wpr = new WilliamsR { Length = WprPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(wpr, ProcessCandle).Start();

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

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

		if (_prev is null || _prev2 is null)
		{
			_prev2 = _prev;
			_prev = wprValue;
			return;
		}

		// Upward direction detected (WPR was falling, now turning up)
		if (_prev < _prev2 && wprValue >= _prev)
		{
			if (BuyPosOpen && Position <= 0)
				BuyMarket(Position < 0 ? Volume + Math.Abs(Position) : Volume);
			else if (SellPosClose && Position < 0)
				BuyMarket(Math.Abs(Position));
		}
		// Downward direction detected (WPR was rising, now turning down)
		else if (_prev > _prev2 && wprValue <= _prev)
		{
			if (SellPosOpen && Position >= 0)
				SellMarket(Position > 0 ? Volume + Position : Volume);
			else if (BuyPosClose && Position > 0)
				SellMarket(Position);
		}

		_prev2 = _prev;
		_prev = wprValue;
	}
}