Ver en GitHub

Estrategia Vector

Descripción general

La Estrategia Vector es un sistema de seguimiento de tendencia multi-divisa convertido del experto "Vector" de MetaTrader 5. Opera cuatro pares forex principales — EURUSD, GBPUSD, USDCHF y USDJPY — simultáneamente. La estrategia calcula medias móviles suavizadas sobre el precio mediano de cada par y abre posiciones sincronizadas cuando la tendencia combinada apunta en la misma dirección. Un objetivo de pips dinámico basado en la volatilidad de cuatro horas y umbrales de ganancia y pérdida a nivel de cartera controlan las salidas.

Ideas principales

  • Usar medias móviles suavizadas (SMMA) construidas sobre precios medianos para medir la dirección en cada par de divisas.
  • Resumir las medias rápidas y lentas de todos los instrumentos para determinar un sesgo alcista o bajista común.
  • Ingresar una única orden de mercado por par cuando el sesgo global y el cruce rápido/lento local coinciden.
  • Gestionar posiciones con un objetivo de pips flotante derivado del rango promedio de 50 velas de 4 horas completadas en EURUSD.
  • Cerrar todas las operaciones simultáneamente si la ganancia o pérdida flotante alcanza el porcentaje configurado del saldo inicial.

Parámetros

Parámetro Descripción
Fast MA Longitud de la media móvil suavizada utilizada para la tendencia rápida en cada par.
Slow MA Longitud de la media móvil suavizada utilizada para la tendencia lenta en cada par.
MA Shift Número adicional de velas finalizadas requeridas antes de que se evalúen las señales, reflejando la configuración de desplazamiento en el EA original.
Equity Take Profit % Porcentaje de ganancia flotante que activa el cierre de todas las posiciones abiertas.
Equity Stop Loss % Porcentaje de pérdida flotante que activa una salida de emergencia para todas las operaciones.
Signal Timeframe Marco temporal de velas usado para las medias móviles suavizadas (por defecto 15 minutos).
Range Timeframe Marco temporal de velas usado para el promedio de volatilidad (por defecto 4 horas).
Range Period Número de velas de marco temporal superior usadas para calcular el objetivo de pips promedio.
EURUSD / GBPUSD / USDCHF / USDJPY Valores que corresponden a cada instrumento operado.

Todos los parámetros soportan rangos de optimización idénticos al asesor experto original donde aplica.

Lógica de trading

  1. Actualización de indicador — Cada vela finalizada en un marco temporal de trading actualiza las medias móviles suavizadas rápida y lenta para el par correspondiente. Los valores solo se consideran después de que se completa el precalentamiento configurado (MA Shift).
  2. Cálculo de sesgo — La estrategia suma las últimas medias rápidas de todos los pares y resta la suma de medias lentas. Un resultado positivo indica presión alcista, mientras que uno negativo indica presión bajista.
  3. Condiciones de entrada — Cuando no existe posición para un par, la estrategia ingresa una orden de compra si el sesgo global es alcista y la media rápida del par está por encima de la lenta. Abre una orden de venta en el caso contrario.
  4. Salida por objetivo de pips — La suscripción de cuatro horas de EURUSD calcula el rango de vela promedio sobre el período configurado. El objetivo de pips actual es el mayor entre este promedio y 13 pips. Los largos cierran una vez que el precio gana al menos el número objetivo de pips, y los cortos cierran después de un movimiento favorable equivalente.
  5. Protección de capital — Siempre que la ganancia flotante supere el porcentaje de take-profit, o la pérdida flotante supere el porcentaje de stop-loss, la estrategia cierra inmediatamente todas las posiciones gestionadas.

Notas de uso

  • Adjunte la estrategia a una cartera que proporcione acceso a los cuatro instrumentos forex y establezca cada parámetro de seguridad explícitamente.
  • El marco temporal de señal predeterminado es 15 minutos; asegúrese de que las velas coincidentes estén disponibles para cada par de divisas.
  • Solo se mantiene una posición abierta por par en cualquier momento. El parámetro de volumen de la estrategia base se usa para cada entrada.
  • Dado que las salidas dependen de la ganancia/pérdida flotante, la estrategia está pensada para operación continua en lugar de solo backtesting barra a barra.
  • El objetivo de pips dinámico usa la volatilidad de EURUSD en línea con la implementación original. Ajuste el marco temporal de rango o el período si prefiere adaptar el objetivo a un entorno de mercado diferente.
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>
/// Trend strategy using smoothed moving averages. Simplified from multi-currency Vector.
/// </summary>
public class VectorStrategy : Strategy
{
	private readonly StrategyParam<int> _fastMaPeriod;
	private readonly StrategyParam<int> _slowMaPeriod;
	private readonly StrategyParam<int> _maShift;
	private readonly StrategyParam<decimal> _profitPercent;
	private readonly StrategyParam<decimal> _lossPercent;
	private readonly StrategyParam<DataType> _candleType;

	private SmoothedMovingAverage _fastMa;
	private SmoothedMovingAverage _slowMa;
	private decimal _entryPrice;
	private decimal _initialBalance;
	private int _processedBars;

	/// <summary>
	/// Fast smoothed moving average period.
	/// </summary>
	public int FastMaPeriod
	{
		get => _fastMaPeriod.Value;
		set => _fastMaPeriod.Value = value;
	}

	/// <summary>
	/// Slow smoothed moving average period.
	/// </summary>
	public int SlowMaPeriod
	{
		get => _slowMaPeriod.Value;
		set => _slowMaPeriod.Value = value;
	}

	/// <summary>
	/// Additional warm-up shift in bars.
	/// </summary>
	public int MaShift
	{
		get => _maShift.Value;
		set => _maShift.Value = value;
	}

	/// <summary>
	/// Floating profit target percent of balance.
	/// </summary>
	public decimal ProfitPercent
	{
		get => _profitPercent.Value;
		set => _profitPercent.Value = value;
	}

	/// <summary>
	/// Floating loss limit percent of balance.
	/// </summary>
	public decimal LossPercent
	{
		get => _lossPercent.Value;
		set => _lossPercent.Value = value;
	}

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

	/// <summary>
	/// Initializes strategy parameters.
	/// </summary>
	public VectorStrategy()
	{
		_fastMaPeriod = Param(nameof(FastMaPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA", "Fast smoothed moving average period", "Indicators")
			.SetOptimize(3, 15, 1);

		_slowMaPeriod = Param(nameof(SlowMaPeriod), 7)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA", "Slow smoothed moving average period", "Indicators")
			.SetOptimize(5, 25, 1);

		_maShift = Param(nameof(MaShift), 8)
			.SetNotNegative()
			.SetDisplay("MA Shift", "Additional warm-up bars before signals", "Indicators");

		_profitPercent = Param(nameof(ProfitPercent), 0.5m)
			.SetNotNegative()
			.SetDisplay("Equity TP %", "Close all when floating profit reaches this percent", "Risk");

		_lossPercent = Param(nameof(LossPercent), 30m)
			.SetNotNegative()
			.SetDisplay("Equity SL %", "Close all when floating loss reaches this percent", "Risk");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Signal Timeframe", "Timeframe for moving averages", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_fastMa = null;
		_slowMa = null;
		_entryPrice = 0m;
		_initialBalance = 0m;
		_processedBars = 0;
	}

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

		_fastMa = new SmoothedMovingAverage { Length = FastMaPeriod };
		_slowMa = new SmoothedMovingAverage { Length = SlowMaPeriod };
		_initialBalance = Portfolio?.CurrentValue ?? 0m;

		SubscribeCandles(CandleType)
			.Bind(_fastMa, _slowMa, ProcessCandle)
			.Start();
	}

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

		_processedBars++;

		if (!IsFormed)
			return;

		if (_processedBars <= MaShift)
			return;

		// Check equity thresholds
		if (Position != 0 && _initialBalance > 0m)
		{
			var equity = Portfolio?.CurrentValue ?? 0m;
			var floating = equity - _initialBalance;
			var profitThreshold = _initialBalance * ProfitPercent / 100m;
			var lossThreshold = _initialBalance * LossPercent / 100m;

			if ((profitThreshold > 0m && floating >= profitThreshold) ||
				(lossThreshold > 0m && floating <= -lossThreshold))
			{
				if (Position > 0) SellMarket();
				else if (Position < 0) BuyMarket();
				_entryPrice = 0m;
				return;
			}
		}

		// Entry/exit logic
		if (fastValue > slowValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
			_entryPrice = candle.ClosePrice;
		}
		else if (fastValue < slowValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
			_entryPrice = candle.ClosePrice;
		}
	}
}