GitHub で見る

Parabolic SAR バグ 3 戦略

概要

Parabolic SAR バグ 3 戦略 は、MQL/9786 にある MetaTrader 4 Expert Advisor pSAR_bug_3.mq4 の StockSharp の高レベル移植です。ロボットは、価格の反対側に表示される最初の Parabolic SAR ドットに反応します。 SAR がローソク足の終値を下回った場合、この戦略は短期エクスポージャーをクローズした後にロングポジションをオープンします。 SAR が終値を超えてジャンプすると、反転してショートポジションになります。各取引は、Parabolic SAR ポイントで測定される固定のストップロスとテイクプロフィットのレベルによって保護され、元の MQL プログラムと同じ乗数によってスケールされます。

取引ロジック

  1. 市場データとインジケーター – この戦略は、設定可能なローソク足タイプ (デフォルトでは 15 分の時間枠) をサブスクライブし、ユーザー指定の加速ステップと最大加速度を備えた Parabolic SAR インジケーターをバインドします。
  2. 状態追跡 – 最初に完了したローソク足の後、コードは Parabolic SAR の値が終値より上か下かを格納します。次のローソク足は、新しい状態と前の状態を比較して、インジケーターの反転を検出します。
  3. ロングエントリー – Parabolic SAR が終値を上から下に切り替わった場合、ストラテジーはアクティブなショートポジションをクローズし、設定されたロングボリュームをオープンするサイズの成行注文を送信します。プロテクティブのストップロス価格とテイクプロフィット価格はエントリー直後に計算されます。
  4. ショートエントリー – Parabolic SAR が終値の下から上にクロスすると、コードはショートトレードの動作を反映します。つまり、ロングポジションをフラットにしてショートオーダーをオープンします。
  5. 終了 – 完成したすべてのキャンドルの高値と安値が、保存されている保護レベルと比較されます。ストップロスまたはテイクプロフィットを突破すると、ブローカー側の保護注文の MetaTrader アプローチと一致して、オープンポジションを閉じる成行注文がトリガーされます。

リスク管理

  • ストップロスとテイクプロフィットの距離は、StopLossPoints または TakeProfitPoints に、StopMultiplier および銘柄 PriceStep (シンボルがステップを提供しない場合は 0.0001) を乗算することによって変換されます。
  • 成行注文は、サブスクリプションが有効で取引が許可されていることが IsFormedAndOnlineAndAllowTrading() によって確認された場合にのみ送信されます。
  • 位置の方向が変わるたびに、古い側の未使用の保護レベルがクリアされ、期限切れの終了が防止されます。

パラメーター

名前 デフォルト 説明
TradeVolume 0.1 ロット単位での注文量。値を更新すると、ベースの Strategy.Volume プロパティも変更されます。
StopLossPoints 90 ストップロス距離は Parabolic SAR ポイントで表され、後で StopMultiplier と商品価格ステップによってスケールされます。
TakeProfitPoints 20 利食い距離は Parabolic SAR ポイントで表され、後で StopMultiplier と価格ステップによってスケールされます。
StopMultiplier 10 MetaTrader StopMult 入力を再現する乗算器で、小数ピップ ブローカーの互換性を有効にします。
SarStep 0.02 Parabolic SAR インジケーターの初期加速係数。
SarMaximum 0.2 Parabolic SAR インジケーターの最大加速係数。
CandleType 15m time-frame インジケーターの計算とシグナル検出に使用されるローソク足タイプ。

変換メモ

  • MetaTrader は、別の注文を使用して反対の取引を開始する前にポジションをクローズしました。 StockSharp バージョンは、逆エクスポージャーを相殺して新しいポジション量を確立するサイズの単一の成行注文を送信することで、同じ結果を達成します。
  • ブローカー側のストップロス注文とテイクプロフィット注文は、ローソク足の極値を監視し、しきい値に違反した場合に市場から撤退することによってエミュレートされます。
  • 追加の StopMultiplier パラメータは任意の正の値を受け入れますが、デフォルトは 10 になります。これは、元のコード コメントに記載されている唯一の乗数です。
  • タスクの説明で要求されているとおり、この変換には Python バージョンは提供されていません。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Parabolic SAR Bug 3: EMA crossover with RSI filter and ATR stops.
/// </summary>
public class ParabolicSarBug3Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastEmaLength;
	private readonly StrategyParam<int> _slowEmaLength;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public ParabolicSarBug3Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_fastEmaLength = Param(nameof(FastEmaLength), 9)
			.SetDisplay("Fast EMA Length", "Fast EMA period.", "Indicators");
		_slowEmaLength = Param(nameof(SlowEmaLength), 26)
			.SetDisplay("Slow EMA Length", "Slow EMA period.", "Indicators");
		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastEmaLength { get => _fastEmaLength.Value; set => _fastEmaLength.Value = value; }
	public int SlowEmaLength { get => _slowEmaLength.Value; set => _slowEmaLength.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

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

		_prevFast = 0; _prevSlow = 0; _entryPrice = 0;
	}

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

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

		if (Position > 0)
		{
			if ((fastVal < slowVal && _prevFast >= _prevSlow) || close <= _entryPrice - atrVal * 2m) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if ((fastVal > slowVal && _prevFast <= _prevSlow) || close >= _entryPrice + atrVal * 2m) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (fastVal > slowVal && _prevFast <= _prevSlow && rsiVal > 50) { _entryPrice = close; BuyMarket(); }
			else if (fastVal < slowVal && _prevFast >= _prevSlow && rsiVal < 50) { _entryPrice = close; SellMarket(); }
		}
		_prevFast = fastVal; _prevSlow = slowVal;
	}
}