Ver en GitHub

Estrategia de Exp Slow Stoch Duplex

Esta estrategia es un port de alto nivel de StockSharp del asesor experto MetaTrader 5 Exp_Slow-Stoch_Duplex. Combina dos osciladores estocásticos lentos que funcionan en marcos temporales independientes para generar señales largas y cortas coordinadas. Cada oscilador entrega sus propias señales de cruce, permitiendo a la estrategia abrir o cerrar posiciones direccionales mientras las órdenes protectoras emulan la gestión original de stop-loss y take-profit.

Reglas de trading

  • Módulo largo
    • Evaluar el estocástico largo en el marco temporal LongCandleType.
    • Aplicar el método de suavizado configurado a los valores %K y %D y desplazarlos LongSignalBar barras.
    • Abrir una posición larga cuando %K cruza por encima de %D (previousK <= previousD y currentK > currentD).
    • Cerrar una posición larga existente cuando %K vuelve a bajar por debajo de %D (currentK < currentD).
  • Módulo corto
    • Evaluar el estocástico corto en el marco temporal ShortCandleType.
    • Abrir una posición corta cuando %K cruza por debajo de %D (previousK >= previousD y currentK < currentD).
    • Cerrar una posición corta existente cuando %K vuelve a subir por encima de %D (currentK > currentD).
  • Las órdenes se ejecutan con órdenes de mercado. El volumen enviado es igual a TradeVolume más el valor absoluto de la posición actual para que las reversiones aplanen primero la exposición anterior.
  • Se adjuntan un take-profit y un stop-loss protectores en puntos de precio a través de StartProtection para imitar los parámetros de orden de MT5.

Parámetros

Parámetro Tipo Predeterminado Descripción
LongCandleType DataType Velas de 8 horas Marco temporal para el oscilador estocástico largo.
LongKPeriod int 5 Período de cálculo %K para el estocástico largo.
LongDPeriod int 3 Período de suavizado %D para el estocástico largo.
LongSlowing int 3 Ralentización adicional aplicada dentro del cálculo estocástico.
LongSignalBar int 1 Número de barras cerradas usadas para evaluar el cruce.
LongSmoothingMethod SmoothingMethod Smoothed Suavizado secundario aplicado a %K y %D (None, Simple, Exponential, Smoothed, Weighted).
LongSmoothingLength int 5 Longitud del filtro de suavizado secundario para el oscilador largo.
LongEnableOpen bool true Permitir a la estrategia abrir posiciones largas.
LongEnableClose bool true Permitir a la estrategia cerrar posiciones largas.
ShortCandleType DataType Velas de 8 horas Marco temporal para el oscilador estocástico corto.
ShortKPeriod int 5 Período de cálculo %K para el estocástico corto.
ShortDPeriod int 3 Período de suavizado %D para el estocástico corto.
ShortSlowing int 3 Ralentización adicional aplicada dentro del cálculo estocástico.
ShortSignalBar int 1 Número de barras cerradas usadas para evaluar el cruce corto.
ShortSmoothingMethod SmoothingMethod Smoothed Suavizado secundario aplicado a los valores cortos %K y %D.
ShortSmoothingLength int 5 Longitud del filtro de suavizado secundario para el oscilador corto.
ShortEnableOpen bool true Permitir a la estrategia abrir posiciones cortas.
ShortEnableClose bool true Permitir a la estrategia cerrar posiciones cortas.
TradeVolume decimal 0.1 Volumen base para entradas de posición.
TakeProfitPoints decimal 2000 Distancia del take-profit expresada en puntos de precio.
StopLossPoints decimal 1000 Distancia del stop-loss expresada en puntos de precio.

Notas

  • El SmoothingMethod adicional imita el suavizado opcional basado en JJMA del indicador original usando las medias móviles estándar disponibles en StockSharp. Elija None para deshabilitar esta etapa si no se requiere replicación exacta.
  • Los módulos largo y corto son independientes; puede habilitar o deshabilitar cualquier lado usando los flags booleanos correspondientes.
  • Debido a que StockSharp opera con posiciones netas, la estrategia siempre cierra la exposición opuesta cuando una nueva señal invierte la dirección.
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>
/// Slow Stochastic Duplex strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class ExpSlowStochDuplexStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

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

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ExpSlowStochDuplexStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { 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;

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

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

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}