Ver en GitHub

Estrategia de Portafolio Forex Fraus

Esta estrategia opera un único instrumento basándose en el indicador Williams %R con un período largo. Cuando el indicador sale de zonas extremas, la estrategia abre posiciones en la dirección del rompimiento.

Cómo funciona

  1. Se calcula Williams %R durante WprPeriod velas.
  2. Cuando el indicador cae por debajo de BuyThreshold, se prepara una oportunidad larga. Una vez que sube por encima del umbral, se coloca una orden de compra de mercado.
  3. Cuando el indicador sube por encima de SellThreshold, se prepara una oportunidad corta. Una vez que cae por debajo del umbral, se coloca una orden de venta de mercado.
  4. Las posiciones solo se permiten durante la ventana de tiempo entre StartHour y StopHour.
  5. Se pueden habilitar stop loss, take profit y trailing stop opcionales a través de parámetros.

Parámetros

  • WprPeriod – período de Williams %R.
  • BuyThreshold – valor para habilitar una señal larga.
  • SellThreshold – valor para habilitar una señal corta.
  • StartHour / StopHour – límites de la sesión de trading.
  • SlPoints – stop loss en puntos. Desactivado si es 0.
  • TpPoints – take profit en puntos. Desactivado si es 0.
  • UseTrailing – habilitar la lógica de trailing stop.
  • TrailingStop – distancia de trailing en puntos.
  • TrailingStep – paso para actualizaciones del trailing.
  • CandleType – tipo de vela a suscribir.

Notas

La versión MQL4 original operaba múltiples pares de divisas y gestionaba órdenes para cada uno. Este puerto en C# se enfoca en un único instrumento y demuestra la idea central usando la API de alto nivel de StockSharp.

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>
/// Williams %R based strategy with trailing stop logic.
/// </summary>
public class ForexFrausPortfolioStrategy : Strategy
{
	private readonly StrategyParam<int> _wprPeriod;
	private readonly StrategyParam<decimal> _buyThreshold;
	private readonly StrategyParam<decimal> _sellThreshold;
	private readonly StrategyParam<int> _startHour;
	private readonly StrategyParam<int> _stopHour;
	private readonly StrategyParam<DataType> _candleType;

	private bool _okBuy;
	private bool _okSell;

	public int WprPeriod { get => _wprPeriod.Value; set => _wprPeriod.Value = value; }
	public decimal BuyThreshold { get => _buyThreshold.Value; set => _buyThreshold.Value = value; }
	public decimal SellThreshold { get => _sellThreshold.Value; set => _sellThreshold.Value = value; }
	public int StartHour { get => _startHour.Value; set => _startHour.Value = value; }
	public int StopHour { get => _stopHour.Value; set => _stopHour.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ForexFrausPortfolioStrategy()
	{
		_wprPeriod = Param(nameof(WprPeriod), 60)
			.SetDisplay("WPR Period", "Williams %R calculation period", "Parameters")
			.SetOptimize(20, 200, 20);

		_buyThreshold = Param(nameof(BuyThreshold), -90m)
			.SetDisplay("Buy Threshold", "Trigger level for long entry", "Parameters");

		_sellThreshold = Param(nameof(SellThreshold), -10m)
			.SetDisplay("Sell Threshold", "Trigger level for short entry", "Parameters");

		_startHour = Param(nameof(StartHour), 0)
			.SetDisplay("Start Hour", "Trading start hour", "Time");

		_stopHour = Param(nameof(StopHour), 24)
			.SetDisplay("Stop Hour", "Trading stop hour", "Time");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_okBuy = false;
		_okSell = false;
	}

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

		_okBuy = false;
		_okSell = false;

		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)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var hour = candle.OpenTime.Hour;
		var inTime = StartHour <= StopHour
			? hour >= StartHour && hour < StopHour
			: hour >= StartHour || hour < StopHour;

		if (!inTime)
		{
			if (Position > 0)
				SellMarket();
			else if (Position < 0)
				BuyMarket();
			return;
		}

		// WPR dips below buy threshold => arm buy signal
		if (wprValue < BuyThreshold)
			_okBuy = true;

		// WPR crosses back above buy threshold while armed => buy
		if (wprValue > BuyThreshold && _okBuy)
		{
			_okBuy = false;
			if (Position <= 0)
				BuyMarket();
			return;
		}

		// WPR rises above sell threshold => arm sell signal
		if (wprValue > SellThreshold)
			_okSell = true;

		// WPR crosses back below sell threshold while armed => sell
		if (wprValue < SellThreshold && _okSell)
		{
			_okSell = false;
			if (Position >= 0)
				SellMarket();
		}
	}
}