Auf GitHub ansehen

Yesterday Today Strategy

Yesterday Today Strategy reproduces the classic MetaTrader breakout where today's price is compared with yesterday's high and low. The strategy keeps track of the last completed daily candle, then watches intraday candles to react quickly when price escapes yesterday's range. Before reversing, it always closes any opposite exposure, delivering a clean one-position workflow.

Overview

  • Tracks the previous daily range and waits for the close of an intraday candle to break it.
  • Opens long positions when the close exceeds yesterday's high; opens short positions when the close drops below yesterday's low.
  • Applies fixed-distance stop-loss and take-profit levels expressed in pips. Pip size adapts to 3- or 5-digit forex quotes just like in the original MQL implementation.
  • Risk levels are evaluated on every finished intraday candle using its high/low to detect stop-loss or take-profit hits.
  • Uses the built-in protection framework to guard against unexpected margin issues.

Workflow

  1. Subscribe to daily candles and store the high/low of the last completed session.
  2. Subscribe to intraday candles (15-minute by default) for signal evaluation.
  3. On each finished intraday candle:
    • Exit immediately if the candle violates the active stop-loss or take-profit.
    • Enter long if the close is above yesterday's high and no long position is open.
    • Enter short if the close is below yesterday's low and no short position is open.
    • Any opposing position is closed first by increasing the market order volume.
  4. Whenever a new daily candle completes, update the stored range for the next trading day.

Parameters

  • TradeVolume — lot size for new positions. When reversing, the strategy automatically adds the opposite exposure to flatten first.
  • StopLossPips — distance from the entry price to the protective stop, expressed in pips. A value of 0 disables the stop.
  • TakeProfitPips — distance from the entry price to the profit target, expressed in pips. A value of 0 disables the target.
  • SignalCandleType — intraday candle type used for breakout detection (default is 15-minute candles).

Details

  • Entry Criteria: Intraday candle closes above yesterday's high (long) or below yesterday's low (short).
  • Long/Short: Both directions supported.
  • Exit Criteria: Stop-loss or take-profit levels touched by intraday candle extremes.
  • Stops: Yes, fixed pip distances.
  • Default Values:
    • TradeVolume = 1
    • StopLossPips = 50
    • TakeProfitPips = 50
    • SignalCandleType = TimeSpan.FromMinutes(15).TimeFrame()
  • Filters:
    • Category: Breakout
    • Direction: Both
    • Indicators: Price Action
    • Stops: Yes
    • Complexity: Basic
    • Timeframe: Intraday entries with daily context
    • Seasonality: No
    • Neural Networks: No
    • Divergence: No
    • Risk Level: Medium

Notes

  • The strategy is designed for a single instrument. Configure Security and Portfolio before starting.
  • Pip size is computed from Security.PriceStep and automatically scaled for 3 or 5 decimal forex symbols, mirroring the original EA logic.
  • Protection is enabled in OnStarted, so global account safeguards remain active when the strategy trades.
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;
	}
}