GitHub で見る

6つの指標 モメンタム戦略

この戦略は、StockSharp の高レベル API を使用して、MetaTrader 4 エキスパート アドバイザー 6xIndics_M を再現します。 Bill Williams のアクセラレーター オシレーター (AC) とオーサム オシレーター (AO) から派生した 6 つの運動量入力を混合し、選択可能な決定マトリックスに供給します。低速確率オシレーターは最終フィルターとして機能します。一度にオープンできるポジションは 1 つだけです。マーチンゲール資金管理、ストップロス/テイクプロフィット、およびオプションのトレーリングストップは、元の動作をエミュレートします。

戦略の仕組み

  1. データ サブスクリプション – この戦略は、設定されたローソク足シリーズ (CandleType、デフォルトの 1 時間足) をサブスクライブします。
  2. 指標
    • Awesome Oscillator は、中央価格の 5 期間と 34 期間の単純移動平均の差を計算します。
    • AO の 5 期間の単純移動平均により、アクセラレータ オシレータ値 (AC) が生成されます。
    • パラメーター 5/5/5 の Stochastic オシレーターは、1 つの閉じたローソク足 (MT4 シフト = 1) だけ遅延される %K ラインを供給します。
  3. 6 つのインジケーター スロット – 完成したすべてのキャンドルは次のバッファーを満たします。
    • スロット 0: AC 値が 1 キャンドル分シフトされました (AC[1])。
    • スロット 1: AC 値が 10 キャンドル分シフトされました (AC[10])。
    • スロット 2: AC 値が 20 キャンドル分シフトされました (AC[20])。
    • スロット 3: AO モメンタム、つまり AO[0] - AO[shift]、シフトは構成可能 (AoMomentumShift)。
    • スロット 4: AC モメンタム AC[0] - AC[shift #1] (AcPrimaryShift)。
    • スロット 5: AC モメンタム AC[0] - AC[shift #2] (AcSecondaryShift)。
  4. 選択可能な信号行列 – パラメータ FirstSourceIndexSixthSourceIndex は、元々 kutero という名前だった 6 つのブール チェックにフィードするスロットを選択します。 CloseOnReverseSignal が有効な場合、エントリの生成と取引の終了の両方に同じインデックスが再利用されます。
  5. エントリーロジック
    • 購入は、選択したスロットが A > 0B > 0.0001 × SensitivityC > 0.0002 × SensitivityD < 0E < 0.0001 × SensitivityF < 0.0002 × Sensitivity を満たし、前の確率 %K が 15 未満である場合に購入します。
    • 売りは、A < 0B < 0.0001 × SensitivityC < 0.0002 × SensitivityD > 0E > 0.0001 × SensitivityF > 0.0002 × Sensitivity、および前の確率 %K が 85 を超えている場合に行います。
  6. ポジション管理
    • 許可されるポジションは 1 つだけです。取引が開始されている場合、戦略は新しいエントリーをスキップし、MT4 エキスパートを反映します。
    • ストップロスとテイクプロフィットのレベルは、商品ティックサイズを使用してピップから絶対価格に変換されます(MT4 での Point の動作とまったく同じです)。
    • オプションのトレーリングストップは元の動作を再現します。価格がエントリーを超えて TrailingStopPips だけ移動するとアクティブになります (RequireProfitForTrailing が true の場合は追加の LockProfitPips だけ)。ストップは有利な方向にのみ価格に従います。
    • CloseOnReverseSignal は、反対のシグナルが表示された場合に収益性の高い取引を終了します (ロングの場合はエントリーの上に入札、ショートの場合は下にアスク)。
  7. Martingale のサイジング – 有効にすると、取引が損失または損益分岐点で終了するたびに、次の注文量は前の取引量に (TakeProfitPips + StopLossPips) / TakeProfitPips を乗じたものと等しくなります。取引に勝つと、サイズがベース Volume にリセットされます。

パラメーター

パラメータ 説明 デフォルト
AllowBuy, AllowSell 長い/短いエントリを有効または無効にします。 true
CloseOnReverseSignal 取引が利益を上げているときに反対のシグナルが表示された場合は、現在のポジションを閉じます。 false
FirstSourceIndexSixthSourceIndex 6 つのインジケーター スロットのどれが各論理チェックにフィードするかを選択します。 0 ~ 5 以外の値はクランプされます。 1,2,3,4,3,4
AoMomentumShift 現在の AO 値とスロット 3 で使用される比較の間のバーの数。 10
AcPrimaryShift, AcSecondaryShift 現在の AC 値とスロット 4 および 5 の比較の間のバーの数。 10 / 10
SensitivityMultiplier スロット チェックで使用される 0.0001 および 0.0002 のしきい値に適用される乗数。 1.0
TakeProfitPips, StopLossPips MetaTrader スタイルのピップで表される終了距離 (ティック サイズによって再スケールされます)。 300 / 300
UseTrailingStop トレーリングストップロジックを有効にします。 false
TrailingStopPips 価格とトレーリングストップの間の距離 (ピップ単位)。 300
RequireProfitForTrailing 有効にすると、トレーリングストップは取引で追加の LockProfitPips を獲得した後にのみ有効になります。 false
LockProfitPips トレーリングストップが動き始める前にロックする必要がある追加利益(ピップ単位)。 300
Volume 基本注文サイズ。 0.1
UseMartingale マーチンゲール位置のサイジングを有効にします。 false
CandleType すべての計算に使用されるローソク足シリーズ。 TimeSpan.FromHours(1)

注意事項とベストプラクティス

  • すべてのローソク足は終了後にのみ処理されるため、シグナルはバーごとに 1 回実行される MT4 エキスパートを模倣します (元のコードでは prevtime ガード)。
  • この戦略は、インジケーターで GetValue() を呼び出すことなく MT4 シフト計算を再現するために必要な履歴 (最大 256 バー) のみを保存し、プロジェクト ガイドラインを満たしています。
  • トレーリングおよびストップ/リミットの出口は、ローソク足の高値/安値でシミュレートされます。ライブ環境では、実行を保証するために実際のストップ注文を使用する必要があります。
  • Martingale のサイジングでは、商品の VolumeStepMinVolume、および MaxVolume の制限を使用して、ボリュームをブローカー ルール内に保ちます。
  • AllowBuy または AllowSell が無効になっている場合、対応する信号は無視されますが、反対の信号は引き続き CloseOnReverseSignal に使用できます。

MT4エキスパートとの違い

  • インジケーターの計算には、StockSharp の組み込み Awesome Oscillator クラスと SMA クラスが使用されます。手動のバッファ管理は必要ありません。
  • すべての取引は成行注文 (BuyMarket / SellMarket) 経由で実行され、ClosePosition() 経由で終了しますが、MT4 バージョンでは明示的な OrderSend / OrderClose リクエストが送信されました。
  • ロットサイジングでは、VolumeStep に四捨五入し、[MinVolume, MaxVolume] にクランプすることで、取引量の粒度が考慮されます。
  • チャートが使用可能な場合、視覚的に検査できるようにチャート ヘルパー (DrawCandlesDrawIndicatorDrawOwnTrades) が追加されます。
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Six Indicators Momentum: RSI + EMA trend with ATR stops.
/// </summary>
public class SixIndicatorsMomentumStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevRsi;
	private decimal _entryPrice;

	public SixIndicatorsMomentumStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");
		_emaLength = Param(nameof(EmaLength), 30)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevRsi = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = 0; _entryPrice = 0;
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ema, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevRsi == 0 || atrVal <= 0) { _prevRsi = rsiVal; return; }
		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 70) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 30) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (rsiVal > 55 && _prevRsi <= 55 && close > emaVal) { _entryPrice = close; BuyMarket(); }
			else if (rsiVal < 45 && _prevRsi >= 45 && close < emaVal) { _entryPrice = close; SellMarket(); }
		}
		_prevRsi = rsiVal;
	}
}