GitHub で見る

コンパスライン戦略

この戦略は、2 つの補完的なフィルターを結合することで CompassLine エキスパートを複製します。

  • フォローライン — Bollinger バンドのブレイクアウトトレイル (オプションで ATR 分シフト)。価格がバンドの外側で終了すると、トレイルはブレイクアウト方向に延長され、トレンドが続く限り後退することはありません。
  • コンパス — 移動平均ウィンドウ上の最高高値と最低安値に対する中央値のロジスティック変換。生の信号は二重平滑化 (三角平均化) され、安定した強気/弱気の状態が生成されます。

ポジションは、両方のフィルターがトレンドに一致する場合にのみオープンされます。オプションの時間フィルタリングと保護停止は、MQL ロジックを反映します。

詳細

  • エントリー基準:
    • フォローラインはロングの場合は上向き(直近終値が上部バンドより上)、ショートの場合は下向き(直近終値が下部バンドより下)を指す必要があります。 ATR の変位は UseAtrFilter で切り替えることができます。
    • コンパスの状態 (CompassPeriod に基づく) は、二重平滑化フェーズの後、ロングの場合は正、ショートの場合は負でなければなりません。
    • 取引は、オプションのセッション フィルタ (HHmm-HHmm の Session を含む UseTimeFilter) が許可する場合にのみ実行されます。
  • ロング/ショート: 両方向がサポートされています。
  • 終了基準:
    • CloseMode = None は、反対側のエントリーまたは保護停止が発生するまでその位置を維持します。
    • CloseMode = BothIndicators は、フォローラインとコンパスの両方が同時に方向を逆にすると閉じます。
    • CloseMode = FollowLineOnly は、フォローラインがポジションに対して反転すると終了します。
    • CloseMode = CompassOnly は、コンパスの極性が変わると終了します。
  • ストップ: TakeProfit および StopLoss の距離 (セキュリティ ステップ内) は、ゼロより大きい場合、すべての入場後に適用されます。
  • デフォルト値:
    • FollowBbPeriod = 21
    • FollowBbDeviation = 1
    • FollowAtrPeriod = 5
    • UseAtrFilter = 偽
    • CompassPeriod = 30 (平滑化長 =round(CompassPeriod / 3))
    • CloseMode = なし
    • UseTimeFilter = 偽
    • Session = "0000-2400"
    • TakeProfit = 0
    • StopLoss = 0
    • CandleType = TimeSpan.FromMinutes(15)
  • フィルター:
    • カテゴリー: トレンド
    • 方向: 両方
    • インジケーター: Bollinger バンド、ATR、三角移動平均
    • 停留所: オプション
    • 複雑さ: 中級
    • 時間枠: 日中
    • 季節性: いいえ
    • ニューラルネットワーク: いいえ
    • 発散: いいえ
    • リスクレベル: 中

追加メモ

  • コンパスのスムージングでは、round(CompassPeriod / 3) に等しい三角ウィンドウが使用され、元のインジケーターの実装と厳密に一致します。
  • 0930-1600 などのセッション文字列は、セッション外でインジケーターの状態を更新しながら、指定されたウィンドウへの取引を制限します。
  • 保護命令は StockSharp の高レベル ヘルパーを再利用するため、ロジックはポートフォリオ リスク管理モジュールと互換性があります。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Compass Line strategy: BB + RSI trend filter.
/// Buys when close < lower BB and RSI < 45.
/// Sells when close > upper BB and RSI > 55.
/// </summary>
public class CompassLineStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _bbPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

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

	public int BbPeriod
	{
		get => _bbPeriod.Value;
		set => _bbPeriod.Value = value;
	}

	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

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

		_bbPeriod = Param(nameof(BbPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("BB Period", "Bollinger Bands period", "Indicators");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

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

		var bb = new BollingerBands { Length = BbPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		decimal? prevClose = null;
		decimal? prevLower = null;
		decimal? prevUpper = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(bb, rsi, (candle, bbVal, rsiVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var bbv = (BollingerBandsValue)bbVal;
				if (bbv.UpBand is not decimal upper || bbv.LowBand is not decimal lower)
					return;

				if (rsiVal.IsEmpty)
					return;

				var rsiDec = rsiVal.GetValue<decimal>();
				var close = candle.ClosePrice;

				if (prevClose.HasValue && prevLower.HasValue && prevUpper.HasValue)
				{
					var crossBelowLower = prevClose.Value > prevLower.Value && close <= lower;
					var crossAboveUpper = prevClose.Value < prevUpper.Value && close >= upper;

					if (crossBelowLower && rsiDec < 45m && Position <= 0)
						BuyMarket();
					else if (crossAboveUpper && rsiDec > 55m && Position >= 0)
						SellMarket();
				}

				prevClose = close;
				prevLower = lower;
				prevUpper = upper;
			})
			.Start();

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