The AMA Trader v2.1 strategy is a conversion of the MetaTrader 4 expert advisor AMA_TRADER_v2_1.mq4 that combines Kaufman's Adaptive Moving Average (AMA) bursts with a double-smoothed Heiken Ashi filter and RSI momentum checks.
Core Logic
Adaptive Trend Filter – A custom AMA engine reproduces the original indicator, including the fast/slow constants, efficiency ratio, and the power parameter. The algorithm watches for momentum bursts where the AMA value jumps by more than AmaThreshold price steps compared with the previous bar.
Heiken Ashi Confirmation – Price candles are smoothed twice: first by a configurable moving average on the raw OHLC prices, then by a second moving average on the Heiken Ashi buffers. A bullish (close above open) smoothed bar allows long trades, while a bearish bar allows shorts.
RSI Momentum Check – A classic RSI with configurable period confirms momentum: longs require the RSI to pull back from a previous value while staying below 70, shorts require a bounce while the oscillator remains above 30.
Position Management – The strategy opens a single position at a time, applies optional stop-loss and take-profit distances (in price steps), and can trail the stop once price moves in the trade direction. When RSI crosses the 70/30 extremes, an optional partial close is performed before a full exit occurs on the next crossing.
Parameters
Name
Default
Description
CandleType
15-minute candles
Timeframe for all calculations.
TradeVolume
0.1
Base market order volume.
AmaLength
9
Lookback used by the adaptive moving average.
AmaFastPeriod
2
Fast constant in bars for the AMA smoothing.
AmaSlowPeriod
30
Slow constant in bars for the AMA smoothing.
AmaPower
2
Exponent applied to the smoothing constant (matches G in the MQ4 code).
AmaThreshold
2 steps
Minimum AMA change (in price steps) to trigger a signal.
FirstMaMethod
Smoothed
First smoothing method for Heiken Ashi construction.
FirstMaPeriod
6
Length of the first smoothing moving average.
SecondMaMethod
LinearWeighted
Second smoothing method applied to the Heiken Ashi buffers.
SecondMaPeriod
2
Length of the second smoothing moving average.
RsiPeriod
14
RSI period used by the momentum filter.
PartialClosePercent
70%
Portion of the active position to close when RSI crosses an extreme. Set to 0 to disable.
StopLossSteps
50
Stop-loss distance expressed in instrument price steps. Set to 0 to disable.
TakeProfitSteps
100
Take-profit distance expressed in price steps. Set to 0 to disable.
TrailingSteps
30
Trailing stop distance in price steps. Set to 0 to disable trailing.
Trading Rules
Long Entry – When the AMA jump is positive and exceeds AmaThreshold, the latest smoothed Heiken Ashi candle is bullish, and RSI is pulling back (previous value greater than the current value) while staying at or below 70.
Short Entry – When the AMA jump is negative beyond AmaThreshold, the smoothed Heiken Ashi candle is bearish, and RSI is rising (previous value less than current) while staying at or above 30.
Partial Close – If enabled, close PartialClosePercent of the position when RSI crosses above 70 (longs) or below 30 (shorts).
Full Exit – Close the entire position on the opposing RSI extreme, on stop-loss, take-profit, or when the trailing stop is hit.
The implementation uses the high-level StockSharp API: a candle subscription feeds the custom AMA calculator, the Heiken Ashi smoothing pipeline, and the RSI indicator. All comments in the source code are in English, mirroring the requirements from the conversion guidelines.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class AmaTraderV21Strategy : 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;
private int _cooldown;
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 AmaTraderV21Strategy()
{
_fastPeriod = Param(nameof(FastPeriod), 10).SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30).SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var slow = new ExponentialMovingAverage { 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 (_cooldown > 0) { _cooldown--; _prevFast = fast; _prevSlow = slow; return; }
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _cooldown = 140; }
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _cooldown = 140; }
_prevFast = fast; _prevSlow = slow;
}
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
_cooldown = 0;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class ama_trader_v21_strategy(Strategy):
"""
AMA Trader V2.1: dual EMA crossover strategy.
"""
def __init__(self):
super(ama_trader_v21_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def FastPeriod(self): return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, v): self._fast_period.Value = v
@property
def SlowPeriod(self): return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, v): self._slow_period.Value = v
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
def OnReseted(self):
super(ama_trader_v21_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(ama_trader_v21_strategy, self).OnStarted2(time)
self._has_prev = False
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self.ProcessCandle).Start()
def ProcessCandle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
if not self._has_prev:
self._prev_fast = fast
self._prev_slow = slow
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fast > slow and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fast < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return ama_trader_v21_strategy()