Ver en GitHub

Estrategia Yesterday Today

La Estrategia Yesterday Today reproduce el clásico breakout de MetaTrader donde el precio actual se compara con el máximo y mínimo de ayer. La estrategia rastrea la última vela diaria completada y observa las velas intradía para reaccionar rápidamente cuando el precio escapa del rango de ayer. Antes de revertir, siempre cierra cualquier exposición opuesta, lo que resulta en un flujo de trabajo limpio de una sola posición.

Resumen

  • Rastrea el rango diario anterior y espera el cierre de una vela intradía para romperlo.
  • Abre posiciones largas cuando el cierre supera el máximo de ayer; abre posiciones cortas cuando el cierre cae por debajo del mínimo de ayer.
  • Aplica niveles de stop-loss y take-profit a distancia fija expresados en pips. El tamaño del pip se adapta a cotizaciones forex de 3 o 5 dígitos, tal como en la implementación MQL original.
  • Los niveles de riesgo se evalúan en cada vela intradía terminada usando su máximo/mínimo para detectar alcances de stop-loss o take-profit.
  • Utiliza el framework de protección integrado para protegerse contra problemas inesperados de margen.

Flujo de trabajo

  1. Suscribirse a velas diarias y almacenar el máximo/mínimo de la última sesión completada.
  2. Suscribirse a velas intradía (15 minutos por defecto) para evaluación de señales.
  3. En cada vela intradía terminada:
    • Salir inmediatamente si la vela viola el stop-loss o take-profit activo.
    • Entrar en largo si el cierre está por encima del máximo de ayer y no hay posición larga abierta.
    • Entrar en corto si el cierre está por debajo del mínimo de ayer y no hay posición corta abierta.
    • Cualquier posición opuesta se cierra primero aumentando el volumen de la orden de mercado.
  4. Cada vez que se complete una nueva vela diaria, actualizar el rango almacenado para el siguiente día de operaciones.

Parámetros

  • TradeVolume — tamaño de lote para nuevas posiciones. Al revertir, la estrategia añade automáticamente la exposición opuesta para aplanar primero.
  • StopLossPips — distancia desde el precio de entrada al stop protector, expresada en pips. Un valor de 0 desactiva el stop.
  • TakeProfitPips — distancia desde el precio de entrada al objetivo de beneficio, expresada en pips. Un valor de 0 desactiva el objetivo.
  • SignalCandleType — tipo de vela intradía utilizado para la detección de ruptura (por defecto velas de 15 minutos).

Detalles

  • Criterios de entrada: La vela intradía cierra por encima del máximo de ayer (largo) o por debajo del mínimo de ayer (corto).
  • Largo/Corto: Ambas direcciones soportadas.
  • Criterios de salida: Niveles de stop-loss o take-profit tocados por los extremos de la vela intradía.
  • Stops: Sí, distancias fijas en pips.
  • Valores predeterminados:
    • TradeVolume = 1
    • StopLossPips = 50
    • TakeProfitPips = 50
    • SignalCandleType = TimeSpan.FromMinutes(15).TimeFrame()
  • Filtros:
    • Categoría: Ruptura
    • Dirección: Ambos
    • Indicadores: Price Action
    • Stops: Sí
    • Complejidad: Básico
    • Marco temporal: Entradas intradía con contexto diario
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • Nivel de riesgo: Medio

Notas

  • La estrategia está diseñada para un único instrumento. Configure Security y Portfolio antes de iniciar.
  • El tamaño del pip se calcula a partir de Security.PriceStep y se escala automáticamente para símbolos forex de 3 o 5 decimales, replicando la lógica original del EA.
  • La protección se activa en OnStarted, de modo que las salvaguardas globales de la cuenta permanecen activas cuando la estrategia opera.
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>
/// Yesterday Today strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class YesterdayTodayStrategy : 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 YesterdayTodayStrategy()
	{
		_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;
	}
}