GitHub で見る

AMA トレーダー 2 戦略

概要

AMA Trader 2 戦略は、ウラジミール カルプトフによるオリジナルの MetaTrader エキスパートの平均化ワークフローを再現しています。これは、Kaufman Adaptive Moving Average (AMA) トレンド フィルターと相対強度指数 (RSI) 確認ブロックを組み合わせたものです。価格がAMAを上回って終了し、RSIが売られ過ぎの領域に落ちた場合、戦略は長期エクスポージャーを追加します。対称ルールは、価格が AMA を下回って終了し、RSI が買われすぎの読み取り値を表示する場合の空売り取引に適用されます。平均取引は固定ロットサイズで送信され、最大ポジション数、最小エントリー間隔、保護トレーリングストップなどのリスクパラメーターによって制限できます。

市場の仮定

  • 商品: 狭いスプレッドで取引されるFX/CFDシンボル用に設計されていますが、平均化が許容されるあらゆる流動性商品に適用できます。
  • データ: 完成した時間ベースのローソク足で動作します。時間枠は、CandleType パラメータを通じて設定できます (デフォルト: 1 分)。
  • セッション: オプションの日中ウィンドウ。 UseTimeWindow フラグを使用すると、取引を UTC の開始時間と終了時間に制限できます。

インジケーター

  1. Kaufman Adaptive Moving Average (AMA) – 構成可能な高速/低速平滑化定数と平均長を使用して、一般的な傾向を検出します。
  2. 相対強度指数 (RSI) – 運動量の極値を検証します。信号を確認する必要がある連続した RSI 読み取りの数は、StepLength によって制御されます (0 は 1 のように動作し、MQL のバージョンと一致します)。

取引ロジック

  1. 完成したキャンドルのみを処理し、戦略がオンラインで取引可能であることを確認します。
  2. オプションの時間フィルターを適用します。有効にすると、日中枠外の処理をスキップします。
  3. 最近の RSI 値のキューを更新し、既存のエクスポージャのトレーリングストップ調整を計算します。
  4. 長い設定: 終値が AMA を上回り、検査された RSI 値の少なくとも 1 つが RsiLevelDown を下回っています。アクティブなロングポジションが損失を出している場合、平均化注文は標準エントリーの前にキューに入れられ、エキスパートアドバイザーの「損失回復」動作を模倣します。短い信号は対称規則 (RsiLevelUp) に従います。
  5. エントリは MaxPositionsMinStep、および OnlyOnePosition を尊重します。 CloseOpposite が有効な場合、戦略は最初に反対側を相殺し、フラット化トレードが確認された後にのみ新しいエントリーを考慮します。
  6. 新しいポジションごとに、固定のストップロス/テイクプロフィット距離を付けることができ、オプションで、アクティブ化、距離、およびステップしきい値を備えた利益ベースのトレーリングストップを有効にすることができます。

リスク管理

  • 固定ロットサイズ: すべてのエントリーは LotSize を使用し、パラメーターまたはホスティング ポートフォリオを介してポジションのサイジングを可能にします。
  • 最大平均深度: MaxPositions は、方向ごとに露出を増やすことができる回数を制限します。
  • 間隔制御: MinStep は、連続するエントリ間の最小価格距離を強制し、同じレベルでのクラスタリングを減らします。
  • 保護的出口: オプションのストップロス、テイクプロフィット、トレーリングロジックは、MetaTrader エキスパートの保護ツールキットを複製します。
  • 反対エクスポージャー: CloseOpposite は、ロングを開く前にショートを閉じる戦略を強制します (逆も同様です)。 OnlyOnePosition は、戦略が双方を同時に維持しないことを保証します。

パラメーター

パラメータ 説明
CandleType 計算に使用されるローソク足のデータ型/タイムフレーム。
LotSize 各成行注文の出来高。
RsiLength RSI の平均期間。
StepLength 検査された最近の RSI 読み取り値の数 (0 → 1)。
RsiLevelUp RSI のショートエントリーの買われすぎのしきい値。
RsiLevelDown RSI のロングエントリーの売られ過ぎのしきい値。
AmaLength AMA スムージングの長さ。
AmaFastPeriod AMA の高速平滑化定数。
AmaSlowPeriod AMA の低速平滑化定数。
StopLoss 価格単位での固定停止距離 (0 無効)。
TakeProfit 価格単位での固定ターゲット距離 (0 無効)。
TrailingActivation トレーリングストップを作動させるために必要な利益 (0 無効)。
TrailingDistance トレーリングストップによって維持される距離。
TrailingStep トレーリングストップが強化される前の最小限の改善。
MaxPositions 方向ごとの最大平均エントリ数 (0 無効)。
MinStep 連続するエントリ間の最小距離 (0 は無効)。
CloseOpposite 取引を開始する前に、反対のエクスポージャをクローズします。
OnlyOnePosition ポジションが存在する場合は常に新しいエントリーをブロックします。
UseTimeWindow 日中の開始/終了時間のフィルタリングを有効にします。
StartTime ウィンドウが有効な場合のセッション開始時刻 (UTC)。
EndTime ウィンドウが有効になっているときのセッション終了時刻 (UTC)。

実装メモ

  • 高レベルの API のみ: キャンドルは SubscribeCandles 経由でサブスクライブされ、AMA と RSI は .Bind にバインドされ、すべての計算は禁止されたインジケーター ゲッターを使用せずにバインドされたコールバックで行われます。
  • ポジション会計は、MQL のエキスパートを反映しています。個別のアキュムレーターがロングとショートの出来高/平均価格を追跡し、平均化の決定のために未実現損益を評価します。
  • トレーリング ストップは、注文キューを直接操作するのではなく、ストラテジー レベルのストップロス距離を再構成し、StockSharp 実行モデルとの互換性を保ちます。
  • シグナルはサイドごとにバーごとに 1 回の実行に制限されており、同じローソク足での重複エントリーを防ぐ MetaTrader チェックが再現されます。

MetaTrader エキスパートとの違い

  • マジックナンバー、偏差、フリーズレベルチェック、テスター引き出しエミュレーションなどの、MetaTrader 固有のパラメータは省略されています。 StockSharp 環境は、注文の遅延と手数料を内部で管理します。
  • ストップ/リミット価格は、ビッド/アスクティックではなくローソク足の終値から計算されます。これは、StockSharp のキャンドルベースのワークフローと一致します。
  • 元の EA は、口座証拠金設定を使用して動的なロットサイズを計算します。ポートは固定の LotSize を維持し、リスクに基づいたサイジングはホスティング環境に任せます。
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();
	}
}