Ver no GitHub

Cross MA ATR Notification Strategy

Overview

This strategy is a StockSharp port of the MetaTrader 4 "CrossMA" expert advisor. It trades the crossover between two simple moving averages and protects each trade with an Average True Range (ATR) based stop loss. In addition to the original logic, the strategy records detailed information messages instead of sending e-mails.

Trading Logic

  1. The strategy subscribes to the configured candle series and calculates a fast and a slow simple moving average together with an ATR indicator.
  2. When the fast SMA crosses above the slow SMA, any short exposure is closed and a long position is opened. The stop loss is placed one ATR below the entry price.
  3. When the fast SMA crosses below the slow SMA, any long exposure is closed and a short position is opened. The stop loss is placed one ATR above the entry price.
  4. On every finished candle the stop price is checked. If price touches the stop level the position is immediately closed at market.

Risk Management

  • Position size is computed from the account equity and the Maximum Risk parameter. If equity information is not available the strategy falls back to the Base Volume value.
  • After two or more consecutive losing trades the position size is reduced proportionally to the Decrease Factor, reproducing the original MetaTrader behaviour.
  • All volumes are normalized to the security volume step to ensure valid order sizes.

Notifications

Instead of sending e-mails the strategy writes clear log messages whenever orders are opened or closed by signals or stops. Logging can be disabled through the Enable Notifications parameter.

Parameters

  • Candle Type – candle type used for indicator calculations.
  • Fast SMA Period – period of the fast moving average (default 4).
  • Slow SMA Period – period of the slow moving average (default 12).
  • ATR Period – number of candles used by ATR for the stop calculation (default 6).
  • Base Volume – minimum traded volume when risk based sizing is unavailable (default 0.1).
  • Maximum Risk – fraction of equity allocated to each trade (default 0.02).
  • Decrease Factor – reduces position size after losing trades (default 3).
  • Enable Notifications – enables logging of trade actions.
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>
/// CrossMA strategy - fast/slow SMA crossover with ATR volatility filter.
/// Buys when fast SMA crosses above slow SMA.
/// Sells when fast SMA crosses below slow SMA.
/// </summary>
public class CrossMaAtrNotificationStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public CrossMaAtrNotificationStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 40)
			.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevSlow = 0m; _hasPrev = false; }

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

		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
	}

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

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

		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fast;
		_prevSlow = slow;
	}
}