GitHub で見る

JS MA SAR 取引戦略

JS MA SAR Trades は、MetaTrader 5 のエキスパート「JS MA SAR Trades」を StockSharp の高水準 API に変換したものです。この戦略は ZigZag スタイルのフィルターで検出された高いスイングローまたは低いスイングハイを探し、2本の移動平均でモメンタムを確認してから、Parabolic SAR のブレイクアウト方向にエントリーします。ポジションはクラシックなストップ、オプションのトレーリングストップ、および明示的な取引セッションフィルターで保護されます。

ロジックの概要

  1. スイング構造 – 設定された深度の Highest/Lowest インジケーターがオリジナルの ZigZag を近似します。直近の 2 つのスイングローとスイングハイが追跡されます。ロングセットアップは最新のローが前のローより高いこと(上昇構造)を要求し、ショートセットアップは最新のハイが前のハイより低いこと(下降構造)を要求します。偏差フィルター(pips 単位)と最小バックステップ(ピボット間のバー数)により、ノイズピボットが受け入れられるのを防ぎます。
  2. 移動平均による確認 – 両方の移動平均は、オプションの正のシフト(右へのバー数)を含む MT5 バージョンと同じスムージングタイプと適用価格を使用します。ロングシグナルは、シフトされた速い MA がシフトされた遅い MA より上に留まることを必要とし、ショートシグナルは逆の関係を必要とします。
  3. Parabolic SAR トリガー – スイングと移動平均の条件が満たされると、ローソク足が Parabolic SAR レベルを超えて終値を形成した場合にのみ取引が実行されます:ロングは SAR の上での終値、ショートは下での終値。SAR が反対側に反転すると、エントリーウィンドウ外でも既存のポジションをすべて決済します。
  4. リスク管理 – ストップロスとテイクプロフィットレベルは pips 単位で計算されます(銘柄の価格ステップで変換)。オプションのトレーリングストップは MT5 ロジックを模倣します:エントリー価格から設定されたトレーリングストップとトレーリングステップ距離だけ価格が動いた後にのみ、ストップがシフトされます。
  5. セッションフィルター – 有効にすると、新規注文は指定した開始時間と終了時間の間(両端含む)のみ許可されます。保護的な決済(ストップ/テイク/トレーリングおよび SAR 反転)は引き続きすべての完成したローソク足で評価されます。

エントリーとエグジットのルール

  • ロングエントリー: より高いスイングロー、終値の下に Parabolic SAR、遅い MA より上の(シフトされた)速い MA、そして取引ウィンドウ内での終値。ストラテジーはショートを決済してロングポジションを開くために OrderVolume + |Position| を買います。
  • ショートエントリー: より低いスイングハイ、終値の上に Parabolic SAR、遅い MA より下の(シフトされた)速い MA、時間フィルター充足。
  • ロング決済:
    • 終値が Parabolic SAR を下回るクロス;
    • ストップロス、トレーリングストップ、またはテイクプロフィットレベルに到達。
  • ショート決済:
    • 終値が Parabolic SAR を上回るクロス;
    • ストップロス、トレーリングストップ、またはテイクプロフィットレベルに到達。

パラメーター

パラメーター デフォルト 説明
OrderVolume 1 新規エントリーに使用するベース注文サイズ。ストラテジーは即座に反転するために絶対現在ポジションを加算します。
StopLossPips 50 エントリー価格とストップロス間の pips 距離。無効にするには 0 に設定。
TakeProfitPips 50 エントリー価格とテイクプロフィット間の pips 距離。無効にするには 0 に設定。
TrailingStopPips 5 pips 単位のトレーリングストップ距離。TrailingStepPips と連携して機能します。
TrailingStepPips 5 トレーリングストップが引き締められる前に価格が移動しなければならない追加距離(pips)。トレーリングが有効な場合は正でなければなりません。
UseTimeFilter true 新規エントリーの開始/終了時間フィルターを有効にする。
StartHour 19 取引ウィンドウの開始(両端含む、取引所時間)。
EndHour 22 取引ウィンドウの終了(両端含む)。
FastMaPeriod 55 速い移動平均の期間。
FastMaShift 3 速い移動平均値に適用される前方シフト(バー単位)。
SlowMaPeriod 120 遅い移動平均の期間。
SlowMaShift 0 遅い移動平均の前方シフト(バー単位)。
MaType Smoothed 移動平均スムージング方法(Simple、Exponential、Smoothed、Weighted)。
AppliedPrice Median 両方の移動平均の価格ソース(Close、Open、High、Low、Median、Typical、Weighted)。
SarStep 0.02 Parabolic SAR の初期加速係数。
SarMax 0.2 Parabolic SAR の最大加速係数。
ZigZagDepth 12 スイング検出のルックバックウィンドウ(バー)。
ZigZagDeviation 5 新しいピボットを受け入れるための pips 単位の最小スイングサイズ。
ZigZagBackstep 3 同じタイプの連続ピボット間の最小バー数。
CandleType H1 ローソク足サブスクリプションの取引時間軸。

備考

  • ストラテジーはエントリーウィンドウ外でも保護ロジックをアクティブに保ち、ストップと SAR 反転が遵守されることを保証します。
  • トレーリングストップは MT5 実装を再現します:価格が TrailingStop + TrailingStep だけ前進すると、ロングのストップは Close - TrailingStop に移動されます(ショートの場合は逆)。
  • 移動平均は選択された適用価格で評価されます。シフトは MT5 インジケーターオフセットを模倣します。
  • 銘柄に有効な PriceStep があることを確認してください。そうでなければ pip ベースの距離はスキップされます。
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>
/// JS MA SAR Trades strategy. Uses EMA crossover (8/21).
/// </summary>
public class JsMaSarTradesStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast;
	private decimal? _prevSlow;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public JsMaSarTradesStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 8).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 21).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

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

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}