GitHub で見る

AMA Trader 戦略

概要

AMA Trader戦略はMetaTrader 5エキスパート「AMA Trader」の元の動作を複製します。カウフマンの適応型移動平均(AMA)と相対力指数(RSI)を組み合わせて、価格が適応型トレンドフィルターの優勢側に留まる間、短期的なプルバックに対してトレードに平均化します。StockSharp実装は高レベルAPIとキャンドルサブスクリプションおよびインジケーターバインディングを使用して、StockSharp実行モデルと完全に互換性を保ちながら元のロジックに近い状態を維持します。

市場の前提

  • インストゥルメントタイプ: スポットFXまたはCFD向けに設計されていますが、平均化をサポートするトレンドのある任意のインストゥルメントに適用可能です。
  • 時間軸: デフォルトは1分キャンドル、CandleTypeパラメーターで設定可能。
  • セッション: 明示的なセッション処理なし。すべての完成したキャンドルでシグナルが評価されます。

インジケーター

  1. カウフマン適応型移動平均(AMA)
    • 高速・低速の平滑化定数(AmaFastPeriodAmaSlowPeriod)と平均化長さ(AmaLength)のパラメーターで価格動向を平滑化します。
    • 主要なトレンド方向を定義します。クローズ価格がAMAより上の場合のみロングトレードを検討;以下の場合のみショートトレードを検討。
  2. 相対力指数(RSI)
    • キャンドルクローズにRsiLength期間で評価されます。
    • StepLengthは何個の最近のRSI値が買われ過ぎ/売られ過ぎ状態を確認する必要があるかを制御します。値が0の場合、StepLength == 0が1として扱われるMQL実装を反映して最後のバーのみを確認するようにフォールバックします。
    • RsiLevelDown(デフォルト30)とRsiLevelUp(デフォルト70)はそれぞれ売られ過ぎと買われ過ぎのしきい値を定義します。

取引ロジック

  1. バー検証
    • トレードは完成したキャンドルでのみ、かつ戦略がオンラインで取引を許可されている場合に評価されます。
  2. 新規エントリー前の利益管理
    • すべてのオープンポジションの未実現利益がProfitTargetを超えた場合、戦略はすべてのオープンポジションをクローズし、次のシグナルを待ちます。
    • 最後のリセット以来の実現利益がWithdrawalAmountを超えて成長すると、すべてのポジションがクローズされ、実現利益のチェックポイントが更新されます。これは元のエキスパートの引き出しメカニクスを模倣します(実際の現金は削除されません;チェックポイントのみがリセットされます)。
  3. ロングエントリー
    • 条件:クローズ価格 > AMA かつ検査されたRSI値の少なくとも1つがRsiLevelDown未満。
    • アクション:成行買い注文を送る。現在のロングエクスポージャーが損失中の場合(追跡された平均エントリー価格に基づいた負の未実現PnL)、追加の平均化買い注文が送られます。
  4. ショートエントリー
    • 条件:クローズ価格 < AMA かつ検査されたRSI値の少なくとも1つがRsiLevelUp超過。
    • アクション:成行売り注文を送る。現在のショートエクスポージャーが損失中の場合、追加の平均化売り注文が送られます。
  5. ポジション追跡
    • 実行はOnOwnTradeReceivedで処理されます。ロングとショートのエクスポージャーに対して別々の平均価格とボリュームが追跡され、市場が買いと売りを交互に繰り返す場合でも正確な未実現PnL推定が可能です。

リスク管理

  • 平均化ボリューム: 各エントリーは固定LotSizeを使用します。損失が発生すると、アルゴリズムは同じ方向に追加注文を加えることで倍増します。
  • 未実現利益目標: ProfitTarget(デフォルト50通貨単位)は浮動利益が指定されたレベルに達したとき完全なエグジットを強制します。
  • 実現利益チェックポイント: WithdrawalAmount(デフォルト1000)は累積実現PnLがしきい値を超えるとすべてのポジションをクローズし、その後チェックポイントは現在の実現PnLにリセットされます。
  • 手動保護: 未実現利益目標を超えた自動ストップロスまたはテイクプロフィットは設定されていません。必要に応じてユーザーは外部リスク制御を有効にできます。

パラメーター

パラメーター 説明
CandleType インジケーター計算のためのキャンドルデータタイプまたは時間軸。
LotSize 各成行注文の固定ボリューム。
RsiLength RSI平均化期間。
StepLength 検査される最近のRSI値の数(0は1にフォールバック)。
RsiLevelUp ショートシグナルのためのRSI買われ過ぎしきい値。
RsiLevelDown ロングシグナルのためのRSI売られ過ぎしきい値。
AmaLength AMA平滑化期間。
AmaFastPeriod AMA高速平滑化定数。
AmaSlowPeriod AMA低速平滑化定数。
ProfitTarget すべてのポジションをフラット化するために必要な未実現利益(0はルールを無効にする)。
WithdrawalAmount 完全なエグジットをトリガーする実現利益の増分(0はルールを無効にする)。

実装上の注意

  • 高レベルAPIの使用:キャンドルはSubscribeCandlesを通じて購読され、AMA/RSIは.Bindを介してサブスクリプションにバインドされます。処理デリゲートは生の10進数値を受け取り、手動のインジケーター値アクセスを避けます。
  • ポジション監視はOnOwnTradeReceived内で更新されるプライベートアキュムレーターに依存します。これは禁止された集約ゲッターに頼ることなくMQLエキスパートのポジション検査を反映します。
  • 注文は現在のLotSizeを使用してBuyMarketSellMarketで送られます。フラット化はロングとショートの両方のエクスポージャーをクリアできるように明示的なボリューム引数を使用します。
  • StockSharpバージョンはAMA関係を評価する際にMetaTraderのask/bid確認の代わりにキャンドルクローズ価格を使用し、これはキャンドルベースのワークフロー内で利用可能な最も近い情報です。

MetaTraderエキスパートとの違い

  • WithdrawalAmountはStockSharpのバックテスターが合成引き出しをサポートしないため、TesterWithdrawalを呼び出す代わりに内部チェックポイントを更新します。
  • 元のEAからのAMAシフトと適用価格オプションは公開されていません。StockSharpインジケーターはキャンドルクローズ価格で動作します。
  • 手数料とスワップは未実現PnL計算に明示的に追加されません;StockSharpの実行環境がトレード決済時に内部で手数料を処理します。

使用上のヒント

  • 取引されるインストゥルメントに対して平均化が積極的すぎる場合は、ポートフォリオレベルのリスク制限または組み込みの保護モジュールと戦略を組み合わせることを検討してください。
  • インストゥルメントごとにAMAとRSIの設定を最適化してください。低い時間軸は多くの場合、より短いAMA期間とより広いRSIしきい値から恩恵を受けます。
  • StepLength > 1のときにドローダウンを監視してください。強い逆トレンド動向中に平均化が複数回発動する可能性があります。
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>
/// AMA Trader strategy. Uses Kaufman Adaptive MA with price crossover.
/// </summary>
public class AmaTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _amaPeriod;
	private decimal? _prevClose;
	private decimal? _prevAma;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int AmaPeriod { get => _amaPeriod.Value; set => _amaPeriod.Value = value; }

	public AmaTraderStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_amaPeriod = Param(nameof(AmaPeriod), 10).SetGreaterThanZero().SetDisplay("AMA Period", "Kaufman AMA period", "Indicators");
	}

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

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevClose = null; _prevAma = null;
		var ama = new KaufmanAdaptiveMovingAverage { Length = AmaPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ama, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ama); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal amaVal)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevClose = close; _prevAma = amaVal; return; }
		if (_prevClose == null || _prevAma == null) { _prevClose = close; _prevAma = amaVal; return; }
		if (_prevClose.Value <= _prevAma.Value && close > amaVal && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (_prevClose.Value >= _prevAma.Value && close < amaVal && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
		_prevClose = close; _prevAma = amaVal;
	}
}