Ver en GitHub

Estrategia CashMachine de 5 Minutos

Descripción general

Esta estrategia es una conversión directa del Expert Advisor CashMachine 5min de MQL a la API de alto nivel de StockSharp. Está diseñada para velas de cinco minutos y combina el indicador DeMarker con un filtro de cruce del oscilador Estocástico. La gestión de operaciones utiliza niveles ocultos de stop-loss / take-profit junto con reglas de trailing por etapas que intentan asegurar ganancias una vez que aparece el momentum del precio.

Lógica de trading

Condiciones de entrada

  • Largo: Valor anterior de DeMarker por debajo de 0.30 y valor actual en o por encima de 0.30 y el Estocástico %K cruza por encima de 20 en la misma vela. No debe haber ninguna posición abierta.
  • Corto: Valor anterior de DeMarker por encima de 0.70 y valor actual en o por debajo de 0.70 y el Estocástico %K cruza por debajo de 80. No debe haber ninguna posición abierta.

Gestión de posición

  • Solo se mantiene una posición a la vez; las señales opuestas se ignoran hasta que la operación actual se cierra.
  • Las salidas ocultas cierran la posición cuando el precio toca Entry ± HiddenStopLoss o Entry ± HiddenTakeProfit (valores interpretados en pips).
  • Tres objetivos de ganancia intermedios (TargetTp1/2/3) mueven un trailing stop oculto a precio actual - (objetivo - 13) pips para largos y precio actual + (objetivo + 13) pips para cortos. Los 13 pips adicionales imitan el comportamiento del EA original, asegurando ganancias después de cada hito sin salir inmediatamente.
  • Si el trailing stop es tocado después de la activación, la posición se cierra a mercado.

Indicadores

  • DeMarker – Detecta reversiones de momentum; el parámetro de longitud coincide con el período de promediado original.
  • Oscilador Estocástico – Usa el período original de %K (StochasticLength), suavizado de %K (StochasticK) y suavizado de %D (StochasticD).

Parámetros

Nombre Descripción Predeterminado
HiddenTakeProfit Distancia oculta del take-profit en pips. 60
HiddenStopLoss Distancia oculta del stop-loss en pips. 30
TargetTp1 Primer nivel de activación del trailing (pips). 20
TargetTp2 Segundo nivel de activación del trailing (pips). 35
TargetTp3 Tercer nivel de activación del trailing (pips). 50
DeMarkerLength Período de promediado del DeMarker. 14
StochasticLength Período de lookback del Estocástico %K. 5
StochasticK Longitud de suavizado de %K. 3
StochasticD Longitud de suavizado de %D. 3
CandleType Serie de velas usada para cálculos (por defecto 5 minutos). Marco temporal de 5 minutos

Notas

  • El tamaño del pip se deriva de Security.PriceStep. Cuando el paso es desconocido se usa un valor de respaldo de 0.0001, reproduciendo la lógica del EA que ajusta para cotizaciones de 3 y 5 dígitos.
  • Todas las decisiones de trading se basan en velas terminadas; el comportamiento intra-barra del EA original puede diferir ligeramente porque la versión MQL se ejecutaba en cada tick.
  • La estrategia depende del manejo estándar del volumen de órdenes de StockSharp—establecer Strategy.Volume para controlar el tamaño de la operación.
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>
/// Cash Machine strategy: combines DeMarker and Stochastic oscillator crossovers
/// with staged profit protection using ATR-based distances.
/// </summary>
public class CashMachine5minStrategy : Strategy
{
	private readonly StrategyParam<decimal> _tpAtrMult;
	private readonly StrategyParam<decimal> _slAtrMult;
	private readonly StrategyParam<decimal> _trailAtrMult;
	private readonly StrategyParam<int> _deMarkerLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _prevDeMarker;
	private decimal? _prevRsi;
	private decimal _entryPrice;
	private decimal? _stopPrice;

	public decimal TpAtrMult { get => _tpAtrMult.Value; set => _tpAtrMult.Value = value; }
	public decimal SlAtrMult { get => _slAtrMult.Value; set => _slAtrMult.Value = value; }
	public decimal TrailAtrMult { get => _trailAtrMult.Value; set => _trailAtrMult.Value = value; }
	public int DeMarkerLength { get => _deMarkerLength.Value; set => _deMarkerLength.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public CashMachine5minStrategy()
	{
		_tpAtrMult = Param(nameof(TpAtrMult), 2.5m)
			.SetGreaterThanZero()
			.SetDisplay("TP ATR Mult", "Take profit ATR multiplier", "Risk");

		_slAtrMult = Param(nameof(SlAtrMult), 1.5m)
			.SetGreaterThanZero()
			.SetDisplay("SL ATR Mult", "Stop loss ATR multiplier", "Risk");

		_trailAtrMult = Param(nameof(TrailAtrMult), 1.0m)
			.SetGreaterThanZero()
			.SetDisplay("Trail ATR Mult", "Trailing stop ATR multiplier", "Risk");

		_deMarkerLength = Param(nameof(DeMarkerLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("DeMarker Length", "DeMarker period", "Indicators");

		_rsiLength = Param(nameof(RsiLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Length", "RSI period", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Length", "ATR calculation period", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevDeMarker = null;
		_prevRsi = null;
		_entryPrice = 0;
		_stopPrice = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var deMarker = new DeMarker { Length = DeMarkerLength };
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(deMarker, rsi, atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, deMarker);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal deMarker, decimal rsi, decimal atr)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var close = candle.ClosePrice;

		// Manage position
		if (Position > 0)
		{
			// Trailing stop
			var trail = close - TrailAtrMult * atr;
			if (_stopPrice == null || trail > _stopPrice)
				_stopPrice = trail;

			// Take profit
			var tp = _entryPrice + TpAtrMult * atr;

			if (close <= _stopPrice || close >= tp)
			{
				SellMarket(Math.Abs(Position));
				_stopPrice = null;
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			var trail = close + TrailAtrMult * atr;
			if (_stopPrice == null || trail < _stopPrice)
				_stopPrice = trail;

			var tp = _entryPrice - TpAtrMult * atr;

			if (close >= _stopPrice || close <= tp)
			{
				BuyMarket(Math.Abs(Position));
				_stopPrice = null;
				_entryPrice = 0;
			}
		}

		// Entry signals
		if (Position == 0 && _prevDeMarker is decimal prevDe && _prevRsi is decimal prevRsi)
		{
			var longSignal = (prevDe < 0.25m && deMarker >= 0.25m) || (prevRsi < 25m && rsi >= 25m);
			var shortSignal = (prevDe > 0.75m && deMarker <= 0.75m) || (prevRsi > 75m && rsi <= 75m);

			if (longSignal)
			{
				BuyMarket();
				_entryPrice = close;
				_stopPrice = close - SlAtrMult * atr;
			}
			else if (shortSignal)
			{
				SellMarket();
				_entryPrice = close;
				_stopPrice = close + SlAtrMult * atr;
			}
		}

		_prevDeMarker = deMarker;
		_prevRsi = rsi;
	}
}