GitHub で見る

Open Oscillator Cloud MMRec Strategy

This strategy ports the MetaTrader expert advisor Exp_Open_Oscillator_Cloud_MMRec to the StockSharp high level API. The system trades the crossover of the Open Oscillator Cloud indicator, which compares the current open price with the opens of the highest and lowest bars inside a rolling window and smooths the result with a configurable moving average.

Strategy logic

Indicator construction

  • Build a lookback window (Oscillator Period, default 20 bars) of finished candles from the selected timeframe.
  • Find the bar with the highest high and store its open price, and find the bar with the lowest low and store its open price.
  • Compute two raw values for the current candle:
    • Upper band = current open − open price at the highest high.
    • Lower band = open price at the lowest low − current open.
  • Smooth both series with the chosen moving average (Smoothing Method, Smoothing Length). Supported types are Simple, Exponential, Smoothed, and Weighted moving averages.
  • Store the smoothed history and delay the signal by Signal Bar fully closed candles (default 1) to mimic the original EA logic that acts on the prior bar.

Entry conditions

  • Long entry: previous bar upper band was above the lower band and the latest delayed value crosses below (upper ≤ lower). Optionally disabled through Enable Long Entries.
  • Short entry: previous bar upper band was below the lower band and the latest delayed value crosses above (upper ≥ lower). Optionally disabled through Enable Short Entries.

Exit conditions

  • Long exit: previous bar upper band was below the lower band, signalling a bearish regime. Controlled by Enable Long Exits.
  • Short exit: previous bar upper band was above the lower band, signalling a bullish regime. Controlled by Enable Short Exits.
  • Risk management: if Stop Loss Points or Take Profit Points are greater than zero the strategy automatically closes the position once price reaches those distances (measured in instrument price steps) from the entry.

Order handling

  • Only market orders are used. Before opening a new position the opposite side is flattened to stay aligned with the single-position behaviour of the MetaTrader robot.
  • The Trade Volume parameter sets the base position size for every entry.

Parameters

  • Candle Type – timeframe of the candles used for the oscillator (default 1 hour).
  • Oscillator Period – number of candles in the rolling window (default 20).
  • Smoothing Method – moving average applied to the open gaps (Simple, Exponential, Smoothed, Weighted).
  • Smoothing Length – length of the smoothing moving average (default 10).
  • Signal Bar – number of fully closed bars to delay the signal evaluation (default 1).
  • Enable Long Entries / Enable Short Entries – allow or block opening trades in each direction.
  • Enable Long Exits / Enable Short Exits – allow or block automatic exits for the respective direction.
  • Trade Volume – size of every market order (default 1 contract/lot).
  • Stop Loss Points – protective stop distance in price steps (0 disables the stop, default 1000).
  • Take Profit Points – profit target distance in price steps (0 disables the target, default 2000).

Implementation notes

  • The smoothing methods match the most common options of the original EA. Exotic modes such as JJMA, T3, VIDYA, or AMA are not ported because StockSharp already provides rich alternatives for optimisation and robustness.
  • Signals are evaluated only on CandleStates.Finished events to avoid acting on incomplete data.
  • The strategy keeps an internal history of smoothed values instead of querying indicator buffers, which aligns with the recommended high level StockSharp workflow.
  • Protective levels are cleared automatically when the position becomes flat to prevent stale stops from reopening trades.

Default behaviour

  • Trend following across both directions with delayed confirmation to reduce noise.
  • Uses fixed money management (constant Trade Volume) while honouring stop loss and take profit distances similar to the MetaTrader version.
  • Suitable as a template for experimenting with different smoothing types or combining the oscillator with additional filters.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Open oscillator cloud strategy using EMA crossover as trend proxy.
/// </summary>
public class OpenOscillatorCloudMmrecStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public OpenOscillatorCloudMmrecStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

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

		_prevFast = null;
		_prevSlow = null;

		var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fast;
			_prevSlow = slow;
			return;
		}

		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;

		_prevFast = fast;
		_prevSlow = slow;

		if (!prevAbove && currAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (prevAbove && !currAbove)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}