A estratégia AMA Trader 2 replica o fluxo de trabalho médio do especialista MetaTrader original de Vladimir Karputov. Ele combina um filtro de tendência Kaufman Adaptive Moving Average (AMA) com um bloco de confirmação do Índice de Força Relativa (RSI). Quando o preço fecha acima da AMA e o RSI mergulha em território de sobrevenda, a estratégia adiciona exposição longa; a regra simétrica se aplica a negociações curtas quando o preço fecha abaixo da AMA enquanto RSI imprime uma leitura de sobrecompra. As negociações médias são enviadas em tamanhos de lote fixos e podem ser restringidas por meio de parâmetros de risco, como contagem máxima de posições, espaçamento mínimo de entrada e trailing stops de proteção.
Suposições de mercado
Instrumento: Projetado para símbolos FX/CFD negociados com spreads reduzidos, mas aplicável a qualquer instrumento líquido onde a média seja aceitável.
Dados: Opera em velas baseadas em tempo concluídas. O intervalo de tempo é configurável através do parâmetro CandleType (padrão: 1 minuto).
Sessões: janela intradiária opcional. A negociação pode ser limitada a um horário de início/término em UTC com a sinalização UseTimeWindow.
Indicadores
Média Móvel Adaptativa Kaufman (AMA) – detecta a tendência predominante com constantes de suavização rápida/lenta configuráveis e comprimento médio.
Índice de Força Relativa (RSI) – valida extremos de momento. O número de leituras RSI consecutivas que devem confirmar um sinal é controlado por StepLength (0 se comporta como 1, correspondendo à versão MQL).
Lógica de negociação
Processe apenas velas finalizadas e certifique-se de que a estratégia esteja online e com permissão para negociação.
Aplique o filtro de tempo opcional; pular o processamento fora da janela intradiária quando ativado.
Atualize a fila de valores RSI recentes e calcule ajustes de trailing stop para a exposição existente.
Configuração longa: preço de fechamento acima da AMA e pelo menos um dos valores inspecionados de RSI abaixo de RsiLevelDown. Se a posição longa ativa estiver perdendo dinheiro, uma ordem média será colocada na fila antes da entrada padrão, imitando o comportamento de “recuperação de perdas” do consultor especialista. Os sinais curtos seguem a regra simétrica (RsiLevelUp).
As inscrições homenageiam MaxPositions, MinStep e OnlyOnePosition. Quando CloseOpposite está habilitado, a estratégia primeiro compensa o lado oposto e só considera novas entradas após a confirmação da negociação de achatamento.
Cada nova posição pode anexar distâncias fixas de stop-loss/take-profit e, opcionalmente, permitir um trailing stop baseado em lucro com ativação, distância e limites de passo.
Gestão de risco
Tamanho de lote fixo: Todas as entradas utilizam LotSize, permitindo o dimensionamento da posição via parâmetro ou portfólio de hospedagem.
Profundidade média máxima: MaxPositions limita quantas vezes a exposição pode ser aumentada por direção.
Controle de espaçamento: MinStep impõe uma distância mínima de preço entre entradas consecutivas, reduzindo o agrupamento no mesmo nível.
Saídas de proteção: as lógicas opcionais de stop-loss, take-profit e trailing replicam o kit de ferramentas de proteção do especialista MetaTrader.
Exposição oposta: CloseOpposite força a estratégia a fechar posições vendidas antes de abrir uma posição longa (e vice-versa). OnlyOnePosition garante que a estratégia nunca mantenha os dois lados simultaneamente.
Parâmetros
Parâmetro
Descrição
CandleType
Tipo de dados/período de vela usado para cálculos.
LotSize
Volume para cada ordem de mercado.
RsiLength
RSI período médio.
StepLength
Número de leituras recentes de RSI inspecionadas (0 → 1).
RsiLevelUp
RSI limite de sobrecompra para entradas curtas.
RsiLevelDown
RSI limite de sobrevenda para entradas longas.
AmaLength
Comprimento de suavização AMA.
AmaFastPeriod
Constante de suavização rápida para AMA.
AmaSlowPeriod
Constante de suavização lenta para AMA.
StopLoss
Distância de parada fixa em unidades de preço (0 desabilita).
TakeProfit
Distância alvo fixa em unidades de preço (0 desabilita).
TrailingActivation
Lucro necessário para armar o trailing stop (0 desabilita).
TrailingDistance
Distância mantida pelo trailing stop.
TrailingStep
Melhoria mínima antes que o trailing stop seja apertado.
MaxPositions
Entradas médias máximas por direção (0 desabilita).
MinStep
Distância mínima entre entradas consecutivas (0 desabilita).
CloseOpposite
Feche a exposição oposta antes de abrir uma negociação.
OnlyOnePosition
Bloqueie novas entradas sempre que existir alguma posição.
UseTimeWindow
Ative a filtragem de horário de início/término intradiário.
StartTime
Hora de início da sessão (UTC) quando a janela está habilitada.
EndTime
Hora de término da sessão (UTC) quando a janela está habilitada.
Notas de implementação
Apenas API de alto nível: as velas são inscritas via SubscribeCandles, AMA e RSI são vinculadas a .Bind e todos os cálculos acontecem no retorno de chamada vinculado sem usar getters de indicadores proibidos.
A contabilidade de posição reflete o especialista MQL: acumuladores separados rastreiam volumes/preços médios longos e curtos para avaliar o lucro não realizado para decisões de cálculo médio.
Os trailing stops reconfiguram a distância de stop-loss no nível da estratégia em vez de manipular diretamente as filas de pedidos, mantendo a compatibilidade com o modelo de execução StockSharp.
Os sinais são restritos a uma execução por barra de cada lado, reproduzindo a verificação MetaTrader que evita entradas duplicadas na mesma vela.
Diferenças do especialista MetaTrader
Parâmetros específicos de MetaTrader, como números mágicos, desvio, verificações de nível de congelamento e emulação de retirada do testador são omitidos. O ambiente StockSharp gerencia o deslizamento de pedidos e taxas internamente.
Os preços stop/limit são calculados a partir do fechamento da vela, em vez dos ticks de compra/venda. Isso corresponde ao fluxo de trabalho baseado em velas de StockSharp.
O EA original usa configurações de margem da conta para calcular tamanhos de lote dinâmicos. A porta mantém um LotSize fixo, deixando o dimensionamento baseado em risco para o ambiente de hospedagem.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Adaptive moving average strategy with RSI confirmation.
/// Simplified from the "AMA Trader 2" MetaTrader expert using EMA + RSI.
/// </summary>
public class AmaTrader2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<decimal> _rsiLevelUp;
private readonly StrategyParam<decimal> _rsiLevelDown;
private RelativeStrengthIndex _rsi;
private ExponentialMovingAverage _ema;
private decimal? _prevPrice;
private decimal? _prevEma;
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// RSI period.
/// </summary>
public int RsiLength
{
get => _rsiLength.Value;
set => _rsiLength.Value = value;
}
/// <summary>
/// EMA period.
/// </summary>
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
/// <summary>
/// RSI overbought level.
/// </summary>
public decimal RsiLevelUp
{
get => _rsiLevelUp.Value;
set => _rsiLevelUp.Value = value;
}
/// <summary>
/// RSI oversold level.
/// </summary>
public decimal RsiLevelDown
{
get => _rsiLevelDown.Value;
set => _rsiLevelDown.Value = value;
}
public AmaTrader2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations", "General");
_rsiLength = Param(nameof(RsiLength), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Length", "RSI period", "Indicators");
_emaLength = Param(nameof(EmaLength), 50)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "Adaptive MA period", "Indicators");
_rsiLevelUp = Param(nameof(RsiLevelUp), 60m)
.SetDisplay("RSI Up", "RSI bullish confirmation threshold", "Signals");
_rsiLevelDown = Param(nameof(RsiLevelDown), 40m)
.SetDisplay("RSI Down", "RSI bearish confirmation threshold", "Signals");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevPrice = null;
_prevEma = null;
_rsi = new RelativeStrengthIndex { Length = RsiLength };
_ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, _ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_rsi.IsFormed || !_ema.IsFormed)
{
_prevPrice = candle.ClosePrice;
_prevEma = emaValue;
return;
}
if (_prevPrice is null || _prevEma is null)
{
_prevPrice = candle.ClosePrice;
_prevEma = emaValue;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
// Price crosses above EMA + RSI confirms bullish
var priceAboveEma = candle.ClosePrice > emaValue;
var prevBelowEma = _prevPrice < _prevEma;
if (priceAboveEma && prevBelowEma && rsiValue > RsiLevelUp)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
// Price crosses below EMA + RSI confirms bearish
else if (!priceAboveEma && !prevBelowEma && rsiValue < RsiLevelDown)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevPrice = candle.ClosePrice;
_prevEma = emaValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_rsi = null;
_ema = null;
_prevPrice = null;
_prevEma = null;
base.OnReseted();
}
}
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 DataType, CandleStates
from StockSharp.Algo.Indicators import RelativeStrengthIndex, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class ama_trader2_strategy(Strategy):
def __init__(self):
super(ama_trader2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._rsi_length = self.Param("RsiLength", 14)
self._ema_length = self.Param("EmaLength", 50)
self._rsi_level_up = self.Param("RsiLevelUp", 60.0)
self._rsi_level_down = self.Param("RsiLevelDown", 40.0)
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiLength(self):
return self._rsi_length.Value
@RsiLength.setter
def RsiLength(self, value):
self._rsi_length.Value = value
@property
def EmaLength(self):
return self._ema_length.Value
@EmaLength.setter
def EmaLength(self, value):
self._ema_length.Value = value
@property
def RsiLevelUp(self):
return self._rsi_level_up.Value
@RsiLevelUp.setter
def RsiLevelUp(self, value):
self._rsi_level_up.Value = value
@property
def RsiLevelDown(self):
return self._rsi_level_down.Value
@RsiLevelDown.setter
def RsiLevelDown(self, value):
self._rsi_level_down.Value = value
def OnReseted(self):
super(ama_trader2_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(ama_trader2_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_ema = 0.0
self._has_prev = False
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiLength
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, ema, self._process_candle).Start()
def _process_candle(self, candle, rsi_value, ema_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
rsi_val = float(rsi_value)
ema_val = float(ema_value)
if self._has_prev:
price_above_ema = close > ema_val
prev_below_ema = self._prev_close < self._prev_ema
if price_above_ema and prev_below_ema and rsi_val > float(self.RsiLevelUp) and self.Position <= 0:
self.BuyMarket()
elif not price_above_ema and not prev_below_ema and rsi_val < float(self.RsiLevelDown) and self.Position >= 0:
self.SellMarket()
self._prev_close = close
self._prev_ema = ema_val
self._has_prev = True
def CreateClone(self):
return ama_trader2_strategy()