GitHub で見る

Smart AC Trader Strategy

Overview

Smart AC Trader adapts the original MetaTrader "Smart AC Trader" idea to StockSharp's high level API. The MQL expert evaluated the relative strength of the currencies inside a pair and reacted when the base currency outperformed the quote currency. In StockSharp we focus on the same momentum-driven behaviour but operate on a single instrument that the strategy is attached to. Strength is approximated through a combination of exponential moving averages (EMAs) and the rate of change (ROC) indicator:

  • A fast EMA measures short-term trend direction.
  • A slow EMA represents the primary trend.
  • ROC confirms that price momentum aligns with the trend before entries are allowed.

Once a position is opened, the strategy actively manages the trade using stop-loss, take-profit, trailing stop and break-even rules that mirror the extensive money management configuration of the original expert.

Trading Logic

  1. Subscribe to the configured candle type (time-frame) and calculate the fast EMA, slow EMA and ROC on the candle close.
  2. Enter a long position when the fast EMA is above the slow EMA and ROC is greater than or equal to the buy momentum threshold. Existing short exposure is closed before the new long is opened.
  3. Enter a short position when the fast EMA is below the slow EMA and ROC is less than or equal to the negative sell momentum threshold. Existing long exposure is closed before the new short is opened.
  4. Manage an open position on every finished candle:
    • Close the trade at the configured take-profit or stop-loss distances (expressed in price steps).
    • Optionally arm a break-even exit once price moves in favour of the trade by the trigger distance and liquidate if price returns to the preserved offset.
    • Optionally trail the stop by the configured distance from the highest high (long) or lowest low (short) observed after entry.

Parameters

Parameter Description
Fast EMA Length of the fast EMA trend filter.
Slow EMA Length of the slow EMA trend filter.
ROC Period Lookback window for the rate of change momentum filter.
Buy Momentum Minimum positive ROC required to open long trades.
Sell Momentum Minimum absolute negative ROC required to open short trades.
Stop Loss Stop-loss distance expressed in price steps.
Take Profit Take-profit distance expressed in price steps.
Use Trailing Enables trailing stop management.
Trailing Trailing stop distance in price steps.
Use Break Even Enables the break-even protection logic.
Break Even Trigger Profit in price steps required to arm the break-even logic.
Break Even Offset Distance in price steps kept after the break-even trigger is hit.
Candle Type Candle type used to feed the indicators.

Notes

  • The strategy uses Strategy.StartProtection() once at start-up to ensure the built-in position protection system is active as recommended by the project guidelines.
  • Position sizing relies on the base Strategy.Volume property. Reversal orders automatically include the current exposure so that an opposite signal both closes the existing position and establishes a new one.
  • All risk parameters are expressed in price steps because the original expert advisor used pip-based distances. Make sure the instrument has a valid PriceStep configured.
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Smart AC Trader: EMA trend + ROC momentum filter.
/// Buys when fast EMA above slow EMA and ROC positive.
/// Sells when fast EMA below slow EMA and ROC negative.
/// </summary>
public class SmartAcTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _rocPeriod;

	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 int RocPeriod
	{
		get => _rocPeriod.Value;
		set => _rocPeriod.Value = value;
	}

	public SmartAcTraderStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

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

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

		_rocPeriod = Param(nameof(RocPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("ROC Period", "Rate of Change period", "Indicators");
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var roc = new RateOfChange { Length = RocPeriod };

		decimal? prevFast = null;
		decimal? prevSlow = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, roc, (candle, fastVal, slowVal, rocVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevFast.HasValue && prevSlow.HasValue)
				{
					var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
					var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;

					if (crossUp && rocVal > 0 && Position <= 0)
						BuyMarket();
					else if (crossDown && rocVal < 0 && Position >= 0)
						SellMarket();
				}

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

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