View on GitHub

Accelerator Trailing TP & SL Strategy

Overview

The Accelerator Trailing TP & SL strategy ports the "Accelerator Trailing TP&SL" Expert Advisor from MetaTrader to the StockSharp high-level API. The system blends Bill Williams' Accelerator Oscillator with multi-timeframe momentum confirmation and a monthly MACD trend filter. Entries are layered with geometric position sizing while exits combine classic stop/target distances, adaptive trailing and break-even logic.

Trading Logic

  • Momentum filter – a 14-period Momentum indicator calculated on a higher timeframe must deviate from the neutral 100 level by at least the configured threshold on any of the last three completed bars.
  • Accelerator Oscillator – long trades require a positive accelerator reading, short trades require a negative reading on the signal timeframe.
  • Moving averages – a fast linear weighted moving average (LWMA) must be above the slow LWMA for longs and below it for shorts, approximating the original fast/slow trend filter.
  • Monthly MACD trend – by default the filter observes monthly candles. Long trades demand the MACD line to be above the signal line (even when both values are negative), while short trades require the opposite condition.
  • Layered entries – the strategy can pyramid up to the configured maximum number of positions per direction. Each additional entry is multiplied by the lot exponent, recreating the martingale-style sizing used in the MQL program.

Risk Management

  • Static stop loss / take profit – distances in pips mirror the original Stop Loss and Take Profit settings.
  • Trailing stop – when enabled the strategy trails the most favorable price by the configured number of pips.
  • Break-even move – after a trade reaches the trigger distance the stop is advanced by the specified offset, protecting accumulated profits.
  • MACD exit – when the MACD filter flips against the active position the strategy can close all positions immediately, matching the manual exit helper in the MQL code.

Parameters

Parameter Description
FastMaLength / SlowMaLength Periods of the fast and slow LWMAs on the trading timeframe.
MomentumThreshold Minimum absolute deviation of momentum from the neutral 100 value on the higher timeframe.
StopLossPips / TakeProfitPips Protective stop and target distances in pips.
TrailingStopPips Distance used by the optional trailing stop manager.
BreakEvenTriggerPips / BreakEvenOffsetPips Defines when and how the stop is moved to break-even.
MaxTrades Maximum number of layered entries per direction.
BaseVolume Volume of the first order in a sequence.
LotExponent Multiplier applied to each additional layered entry.
EnableTrailing Enables or disables trailing-stop management.
UseBreakEven Enables or disables the break-even stop movement.
CloseOnMacdFlip Closes all trades if the higher timeframe MACD reverses.
CandleType Primary candle series for signals (defaults to 15 minutes).
MomentumCandleType Higher timeframe candles used by the momentum filter (defaults to 1 hour).
MacdCandleType Candle series used for the MACD trend filter (defaults to monthly candles).

Notes

  • The strategy relies on the instrument PriceStep to convert pip-based risk settings to price distances. Please ensure the security metadata is populated when running the strategy.
  • Because StockSharp uses net positions, additional layered entries are opened by repeatedly sending market orders until the configured maximum is reached. Exits close the entire net position, matching the "close all" routines in the original expert.
  • The monthly MACD timeframe can be adjusted through the MacdCandleType parameter to suit different instruments or backtests.
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;

public class AcceleratorTrailingTPSLStrategy : 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 AcceleratorTrailingTPSLStrategy()
	{
		_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;
	}
}