GitHub で見る

Bread and Butter 2 (ADX + AMA)

Overview

This strategy is a port of the MetaTrader 5 expert advisor Breadandbutter2 created by Ron Thompson. The original logic waits for a fresh bar, compares the latest Average Directional Index (ADX) value with the previous one, and checks whether the Kaufman Adaptive Moving Average (KAMA, also known as AMA) is rising or falling. A long position is opened when the trend strength weakens while price momentum improves, whereas a short position is opened when trend strength increases while momentum deteriorates. The StockSharp version keeps the behaviour of closing any opposite exposure before opening a new order, and applies the same fixed stop-loss and take-profit distances that were specified in pips in the original script.

Indicators

  • Average Directional Index (ADX) – measures the strength of the current trend. The strategy looks at the main ADX line and compares the last two values to determine whether trend strength is increasing or decreasing.
  • Kaufman Adaptive Moving Average (KAMA/AMA) – adapts to market volatility using separate fast and slow smoothing constants. The strategy compares the last two values to evaluate momentum direction.

Strategy Logic

  1. Work with the configured candle type (default: 1-hour bars) and wait until a candle is fully closed before processing.
  2. Calculate KAMA with the selected length, fast period, and slow period.
  3. Calculate ADX with the configured averaging period and extract the main line value.
  4. Compare the current and previous indicator readings:
    • Long setup – the ADX value decreases (trend strength weakens) while KAMA rises (price momentum improves).
    • Short setup – the ADX value increases while KAMA falls.
  5. When a signal appears, close any opposite-side exposure and open a new market order so that the final position matches the base strategy volume.
  6. Continuously monitor the active position. If price touches the configured stop-loss or take-profit levels (expressed in pips and converted to price units according to the security tick size), exit the trade immediately.

Trade Management

  • Stop-loss – expressed in pips; converted into price units using the security PriceStep. For symbols quoted with 3 or 5 decimal places the pip size is 10 times the price step, matching the MetaTrader implementation.
  • Take-profit – also expressed in pips and handled in the same way as the stop-loss distance.
  • The strategy uses market orders for entries and exits and flips the position when an opposite signal occurs.

Parameters

Name Default Description
CandleType TimeSpan.FromHours(1).TimeFrame() Candle type used for all calculations.
AdxPeriod 14 Averaging length of the ADX main line.
AmaPeriod 9 Base period of the Kaufman Adaptive Moving Average.
AmaFastPeriod 2 Fast EMA period used inside the AMA.
AmaSlowPeriod 30 Slow EMA period used inside the AMA.
StopLossPips 50 Distance to the protective stop-loss in pips. Set to 0 to disable.
TakeProfitPips 50 Distance to the profit target in pips. Set to 0 to disable.

Usage Notes

  • Ensure the strategy is attached to a security that exposes a valid PriceStep. For forex symbols with fractional pips the pip size is calculated automatically.
  • Volume controls the base order size. When a reversal signal appears the algorithm adds enough volume to close any opposite exposure and establish a position equal to Volume in the new direction.
  • Because stop-loss and take-profit exits are evaluated on candle highs and lows, the behaviour approximates the original MetaTrader pending-order execution.

References

  • Original MetaTrader 5 strategy: MQL/22003/Breadandbutter2.mq5
  • StockSharp indicators: KaufmanAdaptiveMovingAverage, AverageDirectionalIndex
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>
/// Bread and Butter 2 ADX AMA strategy. Uses KAMA direction with ADX filter.
/// </summary>
public class Breadandbutter2AdxAmaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _kamaPeriod;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevKama;

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

	public Breadandbutter2AdxAmaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_kamaPeriod = Param(nameof(KamaPeriod), 10).SetGreaterThanZero().SetDisplay("KAMA Period", "KAMA lookback", "Indicators");
		_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

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

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevKama = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevKama = fast; return; }
		if (_prevKama == null) { _prevKama = fast; return; }
		var prevAbove = _prevKama.Value > slow;
		var currAbove = fast > slow;
		_prevKama = fast;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}