Ver en GitHub

Above Below MA Strategy

The Above Below MA strategy mirrors the MetaTrader expert advisor Above Below MA (barabashkakvn's edition). It monitors how far current prices trade relative to a configurable moving average and allows trades only when price is on the "wrong" side of the average by at least a defined distance while the average itself trends in the anticipated direction. The logic has been ported to the StockSharp high level API and executes exclusively on completed candles.

Overview

  • Market Regime: Works best on instruments that frequently retest a moving average before resuming the trend.
  • Instruments: Any instrument supported by your StockSharp connection. Forex pairs benefit the most because the original script measured distance in pips.
  • Timeframe: Adjustable through the Candle Type parameter (default 1-minute time frame).
  • Position Direction: Both long and short trades are supported, but only one net position can exist at any given time.

Strategy Logic

  1. Calculate a moving average on the selected candle series. The averaging method (SMA, EMA, SMMA, WMA), applied price (close, open, high, low, median, typical, weighted) and forward shift replicate the MetaTrader inputs.
  2. Convert the minimum distance expressed in pips into an actual price offset using the instrument's PriceStep. If the broker does not publish a price step, the distance filter is skipped automatically.
  3. On each finished candle:
    • Long setup:
      • Candle open and close must lie at least the configured distance below the shifted moving average.
      • The moving average must be rising compared with the previous candle.
    • Short setup:
      • Candle open and close must lie at least the configured distance above the shifted moving average.
      • The moving average must be falling compared with the previous candle.
  4. The strategy closes any opposite position before sending a new market order in the signal direction. No simultaneous long/short exposure is allowed.

All trading decisions are made on completed candles to avoid repeated entries inside a forming bar. Orders are executed via BuyMarket or SellMarket with the configured volume.

Parameters

Parameter Description
MaPeriod Moving average length. Default 6.
MaShift Number of candles to shift the moving average forward. A value of 0 uses the current bar, n uses the value from n bars ago. Default 0.
MaMethod Moving average type: Simple, Exponential, Smoothed, or Weighted. Default Exponential.
AppliedPrice Price source: close, open, high, low, median, typical, or weighted. Default Typical.
MinimumDistancePips Required distance in pips between candle prices and the moving average. Converted using PriceStep. Default 5.
CandleType Candle type driving indicator updates. Default 1-minute time frame.
TradeVolume Order volume for new entries. Default 1.

Additional Notes

  • No stop-loss or take-profit logic is included. Risk management must be implemented via portfolio settings or external modules.
  • The moving average shift buffer is kept minimal and respects the "no collections" guideline by storing only the values required for the specified shift.
  • When PriceStep is unavailable the minimum distance filter cannot be evaluated, so entries rely solely on the moving average conditions.
  • The strategy draws the candle series, the moving average indicator, and your trades on the default chart area when a chart container is available.
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>
/// Above/Below MA strategy. Trades when price crosses above or below a moving average.
/// </summary>
public class AboveBelowMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;

	private decimal? _prevClose;
	private decimal? _prevMa;

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

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public AboveBelowMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_maPeriod = Param(nameof(MaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Moving average period", "Indicators");
	}

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

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

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

		_prevClose = null;
		_prevMa = null;

		var sma = new SimpleMovingAverage { Length = MaPeriod };

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

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

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

		var close = candle.ClosePrice;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevClose = close;
			_prevMa = maVal;
			return;
		}

		if (_prevClose == null || _prevMa == null)
		{
			_prevClose = close;
			_prevMa = maVal;
			return;
		}

		// Price crosses above MA → buy
		if (_prevClose.Value <= _prevMa.Value && close > maVal && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Price crosses below MA → sell
		else if (_prevClose.Value >= _prevMa.Value && close < maVal && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevClose = close;
		_prevMa = maVal;
	}
}