Ver en GitHub

Estrategia de Scalper de Un Minuto

Esta estrategia porta el asesor experto 1 MINUTE SCALPER de MetaTrader 4 a la API de alto nivel de StockSharp. Mantiene la confirmación de tendencia multicapa, el momentum multi-temporal y el filtro MACD a largo plazo del robot original mientras adapta los controles de riesgo al modelo centrado en posiciones de StockSharp.

Lógica Central

  1. Pila de Tendencia – trece medias móviles linealmente ponderadas (LWMA 3/5/8/10/12/15/30/35/40/45/50/55/200) deben alinearse en orden estricto. Las operaciones largas requieren que cada media más corta imprima por encima de la siguiente, mientras que los cortos invierten la condición.
  2. Puerta de Tendencia Principal – una LWMA rápida adicional (por defecto 6) debe mantenerse por encima de la LWMA lenta (por defecto 85) para largos y por debajo para cortos, reflejando la comprobación rápido-vs-lento del EA.
  3. Estructura de Vela – las entradas solo se activan cuando los patrones de superposición del script están presentes: para largos el mínimo de dos barras atrás debe estar por debajo del máximo anterior; para cortos el mínimo anterior debe caer bajo el máximo de dos barras atrás.
  4. Filtro de Momentum – un indicador de momentum de 14 períodos calculado en un marco temporal superior (por defecto velas de 15 minutos) debe desviarse de 100 al menos en los umbrales configurados en cualquiera de los últimos tres valores. Esto reproduce las comparaciones MomLevelB/MomLevelS.
  5. Sesgo MACD Mensual – un MACD construido en el marco temporal MACD seleccionado (por defecto velas de 30 días como proxy de datos mensuales) debe mostrar la línea principal por encima de la señal para largos o por debajo para cortos.

Gestión de Operaciones

  • Protección Inicial – las distancias de stop-loss y take-profit se expresan en pasos del instrumento (puntos). Cuando abre una posición, la estrategia convierte estos recuentos de pasos a precios absolutos usando Security.PriceStep.
  • Movimiento de Punto de Equilibrio – después de que el precio se mueve BreakEvenTriggerSteps a favor, el stop se mueve a la entrada más BreakEvenOffsetSteps (para cortos se aplica la lógica espejada). El indicador se activa una vez por posición.
  • Trailing por Pasos – cuando TrailingStopSteps es positivo, el stop sigue el precio más alto (o más bajo) desde la entrada en el número especificado de pasos.
  • Trailing Monetario – una vez que el beneficio flotante supera MoneyTrailTarget (divisa), la estrategia rastrea el PnL flotante máximo y cierra la posición si el retroceso es igual a MoneyTrailStop.
  • Objetivos Monetarios/Porcentuales – objetivos de take-profit absolutos u opcionales cierran toda la exposición cuando el PnL flotante cruza los umbrales configurados. El objetivo porcentual usa el valor inicial de la cartera capturado cuando comienza la estrategia.
  • Stop de Capital – la estrategia monitoriza el capital máximo (valor de cartera más PnL abierto). Si el drawdown desde ese pico supera EquityRiskPercent, todas las posiciones se cierran, replicando la salvaguarda AccountEquityHigh() del EA.

Parámetros

Parámetro Descripción
Volume Volumen de orden para nuevas entradas. Se añade a la posición actual absoluta para que las reversiones cambien la exposición inmediatamente.
FastMaPeriod / SlowMaPeriod Longitudes de LWMA para el filtro de tendencia principal.
MomentumPeriod Longitud del indicador de momentum en marco temporal superior.
MomentumBuyThreshold / MomentumSellThreshold Desviación absoluta mínima de 100 requerida para la confirmación de momentum largo/corto.
MacdFastLength / MacdSlowLength / MacdSignalLength Configuración de MACD aplicada a MacdCandleType.
StopLossSteps / TakeProfitSteps Distancias de stop protector y objetivo medidas en pasos de precio. Poner en cero para deshabilitar.
TrailingStopSteps Distancia del trailing stop basado en pasos (0 deshabilita).
BreakEvenTriggerSteps / BreakEvenOffsetSteps Distancia para activar el movimiento de punto de equilibrio y el offset aplicado al mover el stop.
UseMoneyTakeProfit, MoneyTakeProfit Habilitar y dimensionar el objetivo de beneficio flotante basado en divisa.
UsePercentTakeProfit, PercentTakeProfit Habilitar y dimensionar el objetivo de beneficio flotante como porcentaje del capital inicial.
EnableMoneyTrailing, MoneyTrailTarget, MoneyTrailStop Configurar la lógica de trailing del beneficio flotante.
UseEquityStop, EquityRiskPercent Habilitar el stop de drawdown y definir el porcentaje máximo de drawdown.
CandleType Velas de trabajo principales (por defecto 1 minuto).
MomentumCandleType Velas de marco temporal superior para el indicador de momentum (por defecto 15 minutos).
MacdCandleType Velas usadas para el filtro de tendencia MACD (por defecto 30 días ≈ mensual).

Diferencias vs. el Experto de MT4

  • StockSharp utiliza posiciones netas, por lo que la estrategia siempre mantiene una única posición agregada en lugar de múltiples tickets hasta Max_Trades. Las reversiones cierran la exposición existente antes de abrir en la dirección opuesta.
  • PercentTakeProfit hace referencia al valor de cartera capturado al inicio en lugar del AccountBalance() en constante cambio usado por MetaTrader, lo que evita objetivos ruidosos cuando las operaciones externas modifican el saldo.
  • La lógica de salida basada en dinero (Take_Profit_In_Money y TRAIL_PROFIT_IN_MONEY2) opera sobre el PnL flotante en vivo calculado desde el precio de entrada promedio de la estrategia. Esto coincide con el comportamiento del EA pero dentro del marco de protección de StockSharp.
  • La plataforma debe suministrar feeds de velas para los marcos temporales seleccionados (CandleType, MomentumCandleType, MacdCandleType). Asegúrese de que los adaptadores que utiliza admitan las resoluciones solicitadas.

Ajuste los umbrales para adaptarse a su instrumento y sesión. Los pares con spreads estrechos o muy volátiles pueden requerir distancias de pasos más amplias o umbrales de momentum más grandes para reducir el ruido.

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>
/// One-minute scalper strategy using fast/slow WMA crossover.
/// Buys on bullish crossover, sells on bearish crossover.
/// </summary>
public class OneMinuteScalperStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private WeightedMovingAverage _fast;
	private WeightedMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	/// <summary>
	/// Fast WMA period.
	/// </summary>
	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	/// <summary>
	/// Slow WMA period.
	/// </summary>
	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in price steps.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in price steps.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the <see cref="OneMinuteScalperStrategy"/> class.
	/// </summary>
	public OneMinuteScalperStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast WMA period", "Indicator");

		_slowPeriod = Param(nameof(SlowPeriod), 85)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow WMA period", "Indicator");

		_stopLossPoints = Param(nameof(StopLossPoints), 200)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 500)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_fast = null;
		_slow = null;
		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
		_cooldown = 0;
	}

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

		_fast = new WeightedMovingAverage { Length = FastPeriod };
		_slow = new WeightedMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

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

		if (!_fast.IsFormed || !_slow.IsFormed)
		{
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		if (_cooldown > 0)
		{
			_cooldown--;
			_prevFast = fastValue;
			_prevSlow = slowValue;
			return;
		}

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		// Check SL/TP
		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}

			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 60;
				_prevFast = fastValue;
				_prevSlow = slowValue;
				return;
			}
		}

		// WMA crossover
		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
			_entryPrice = close;
			_cooldown = 60;
		}
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
			_entryPrice = close;
			_cooldown = 60;
		}

		_prevFast = fastValue;
		_prevSlow = slowValue;
	}
}