Ver en GitHub

Estrategia Starter Triple Stochastic

Esta estrategia porta el experto de MetaTrader Starter.mq5 a la API de alto nivel de StockSharp. Sincroniza tres osciladores stochastic (rápido, normal, lento) con medias móviles coincidentes calculadas en diferentes marcos temporales. Un trade se permite solo cuando todos los filtros confirman la misma dirección y el precio opera en el lado correcto de cada media móvil desplazada.

Lógica de trading

  1. La estrategia se suscribe a tres flujos de velas:
    • Marco temporal rápido (por defecto M5).
    • Marco temporal normal (por defecto M30).
    • Marco temporal lento (por defecto H2).
  2. Para cada flujo construye una media móvil (método configurable, longitud y precio aplicado) y un oscilador stochastic con los mismos parámetros %K, %D y slowdown.
  3. El marco temporal lento impulsa la ejecución. Cuando una vela lenta cierra, se comparan los últimos valores de todos los marcos temporales:
    • Configuración larga: cada línea stochastic tiene %K > %D, todos los valores %K están por debajo de 50, y el precio está por debajo de cada media móvil desplazada.
    • Configuración corta: cada línea stochastic tiene %K < %D, todos los valores %K están por encima de 50, y el precio está por encima de cada media móvil desplazada.
  4. Las señales pueden invertirse opcionalmente a través de ReverseSignals. Cuando se toma una entrada, la estrategia invierte la exposición existente (si CloseOppositePositions = true) o ignora la señal hasta que el posición opuesta esté cerrada.
  5. Después de un llenado, los niveles de stop-loss y take-profit se simulan en el espacio de precio. Un trailing stop replica la lógica MQL original requiriendo TrailingStopPips + TrailingStepPips de ganancia antes de mover el stop por TrailingStopPips.
  6. El dimensionamiento de posición basado en riesgo refleja el interruptor lot/risk de MetaTrader. Cuando el modo es RiskPercent, el volumen del trade se deriva del valor de la cuenta, el porcentaje de riesgo y la distancia de stop-loss en pips.

Parámetros

Nombre Predeterminado Descripción
StopLossPips 45 Distancia protectora de stop en pips. Establecer en 0 para deshabilitar el stop fijo.
TakeProfitPips 105 Distancia de take-profit en pips. Establecer en 0 para deshabilitar el objetivo.
TrailingStopPips 5 Offset de trailing stop aplicado después del avance mínimo.
TrailingStepPips 5 Avance mínimo de ganancia (en pips) requerido antes de que el trailing stop se mueva.
MoneyMode RiskPercent Selecciona entre dimensionamiento de lote fijo y riesgo porcentual por trade.
MoneyValue 3 Tamaño de lote cuando se usa FixedLot, o porcentaje de riesgo cuando se usa RiskPercent.
FastCandleType M5 Tipo de vela para el conjunto de indicadores rápido.
NormalCandleType M30 Tipo de vela para el conjunto de indicadores intermedio.
SlowCandleType H2 Tipo de vela que desencadena la evaluación de señales y órdenes.
MaPeriod 20 Longitud de todas las medias móviles.
MaShift 1 Desplazamiento horizontal aplicado a cada media móvil (barras atrás).
MaMethod Simple Suavizado de media móvil: Simple, Exponential, Smoothed, o Weighted.
MaPriceType Close Precio aplicado para alimentar las medias móviles.
StochasticKPeriod 5 Longitud %K para todos los osciladores stochastic.
StochasticDPeriod 3 Longitud de suavizado %D.
StochasticSlowing 3 Factor de slowdown final para %K.
ReverseSignals false Intercambia las condiciones larga y corta.
CloseOppositePositions false Si es true, revierte la posición en una única orden cuando aparece una señal en la dirección opuesta.

Gestión monetaria

  • MoneyMode = FixedLot envía cada orden con el volumen exacto de MoneyValue.
  • MoneyMode = RiskPercent reproduce el comportamiento original: el efectivo arriesgado equivale a AccountValue * MoneyValue / 100. El tamaño del trade se calcula como efectivo arriesgado / (StopLossPips * tamaño del pip). Si StopLossPips es cero o el valor de la cartera no está disponible, la estrategia se niega a operar.

Protección y trailing

  • Los niveles de stop-loss y take-profit se rastrean internamente y se comparan con los máximos/mínimos de las velas, emulando las órdenes protectoras de MetaTrader.
  • El trailing stop se activa solo después de que la ganancia no realizada supere TrailingStopPips + TrailingStepPips pips, cumpliendo el requisito original de que tanto un offset inicial como un paso mínimo deben satisfacerse antes de mover el stop.

Alineación multitemporal

Todos los indicadores se recalculan en cada vela cerrada de su respectivo marco temporal. El marco temporal lento espera a que las tres medias móviles y los stochastics formen y utiliza los valores más recientes de la media móvil desplazada, imitando el parámetro de desplazamiento iMA de MetaTrader. Esto asegura que el port de StockSharp dispara trades en la misma barra que el experto MQL original.

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;

public class StarterTripleStochasticStrategy : 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 StarterTripleStochasticStrategy()
	{
		_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;
	}
}