GitHub で見る

Parabolic SAR Cross戦略

この戦略は、MetaTraderの「PSAR Trader EA」エキスパートアドバイザーをStockSharpへ移植したものです。価格がParabolic SAR指標とどう相互作用するかを観察し、点のフィールドがローソク足実体の片側から反対側へ反転した場合にのみ反応します。変換では元の資金管理ロジックを保持しています。固定ロットで取引するか、口座残高に基づいて注文数量を動的調整でき、固定ストップロスとテイクプロフィットを適用し、取引が十分な利益を積み上げるとトレーリングストップを起動します。

戦略ロジック

  • 選択したローソク足系列(既定は30分足)上に、ユーザー定義の加速値と最大値を持つParabolic SAR指標を構築します。
  • SARドットがローソク足実体の上から下へ移動したとき、強気反転を検出します。ポジションがなければ成行買い注文を送信します。ショートポジションがある場合は先に閉じ、次のシグナルでロングへ再エントリーします。
  • SARドットがローソク足実体の下から上へ移動したとき、弱気反転を検出します。フラットならショートを開きます。ロングポジションが有効な場合は閉じ、次のシグナルまでエントリーを延期します。
  • 各確定ローソク足でオープン取引を監視し、現在ローソク足の高値/安値が保護水準(ストップロス、テイクプロフィット、トレーリングストップ)に到達した場合に決済します。

リスク管理

  • Stop loss: ポイント(価格ステップ)で表します。ロングではエントリー価格の下、ショートでは上に置きます。
  • Take profit: これもポイントで表します。目標はストップの反対方向に対応し、到達するとポジション全体を閉じます。
  • Trailing stop: 価格が設定ポイント数だけ取引に有利に動いた後で開始します。トレーリングストップは利益方向にのみ引き締まり、元EAの「tighten stops only」動作を再現します。

数量管理

  • 固定ロット: auto-lotが無効な場合、戦略は設定した固定ロットサイズで注文を送信します。
  • 残高ベースロット: auto-lotが有効な場合、数量は(Account Balance / 1000) * LotsPerThousandとして計算され、銘柄の数量ステップと最小数量に合わせられます。

パラメーターと既定値

  • SarStep: Parabolic SAR加速係数。既定値: 0.02
  • SarMaximum: Parabolic SAR最大加速。既定値: 0.2
  • CandleType: 分析時間軸。既定値: 30分足。
  • UseAutoLot: 動的ロットサイズを有効化。既定値: false
  • FixedLot: auto lot sizingが無効な場合の数量。既定値: 0.1
  • LotsPerThousand: auto-lot計算用乗数。既定値: 0.05
  • StopLossPoints: ストップまでの距離(ポイント)。既定値: 500
  • TakeProfitPoints: テイクプロフィットまでの距離(ポイント)。既定値: 1000
  • TrailingStartPoints: トレーリングを有効にする利益しきい値。既定値: 500
  • TrailingDistancePoints: 有効化後のトレーリングオフセット。既定値: 100

注記

  • 戦略はロングとショートの両方向を取引しますが、一度に保持するポジションは最大1つです。
  • 保護注文はローソク足データ上でシミュレートされます。選択時間軸より短いバー内スパイクは、ライブ取引で約定品質に影響する場合があります。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Parabolic SAR Cross strategy: PSAR crossover.
/// Buys when close crosses above PSAR. Sells when close crosses below PSAR.
/// </summary>
public class ParabolicSarCrossStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;

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

	public ParabolicSarCrossStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var sar = new ParabolicSar { Acceleration = 0.02m, AccelerationStep = 0.02m, AccelerationMax = 0.2m };

		decimal? prevSar = null;
		decimal? prevClose = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sar, (candle, sarVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;

				if (prevSar.HasValue && prevClose.HasValue)
				{
					var crossUp = prevClose.Value <= prevSar.Value && close > sarVal;
					var crossDown = prevClose.Value >= prevSar.Value && close < sarVal;

					if (crossUp && Position <= 0)
						BuyMarket();
					else if (crossDown && Position >= 0)
						SellMarket();
				}

				prevSar = sarVal;
				prevClose = close;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, sar);
			DrawOwnTrades(area);
		}
	}
}