GitHub で見る

Bollinger バンドのセッションの反転

この戦略は、MetaTrader エキスパート アドバイザー BollingerBandsEA (ver. 3.0) の C# ポートです。アクティブな取引セッション中に価格が Bollinger バンドを超えた後に発生する平均回帰セットアップを取引します。

取引ロジック

  1. 主要な日中ローソク足シリーズ (デフォルトでは 15 分足ローソク足) と、トレンド フィルターの構築に使用される日次ローソク足シリーズを購読します。
  2. 日中シリーズの Bollinger バンド (長さ 20、幅 2.0) と日次終値の 100 期間 SMA を計算します。
  3. 現在および前日の高値/安値を追跡し、信号評価のために以前の Bollinger バンド値を保持します。
  4. 取引セッションウィンドウ内でのみエントリーを許可します。取引日開始後の SessionStartOffsetMinutes から取引日終了前の SessionEndOffsetMinutes までです。
  5. その日の累積損益がプラスになったら取引をスキップし、EA の毎日のストップを模倣します。
  6. 前のローソク足が弱気で、上部バンドより上で終了し、現在の終値がそのバンドより上に留まり、バンド幅が十分に広く、価格が日次 SMA を下回り、価格が現在または以前の日次高値を上回って取引されている場合、ショートにエントリーします。
  7. 前のローソク足が強気で、下限バンドを下回って終了し、現在の終値がそのバンドを下回ったままで、バンド幅が十分に広く、価格が日次 SMA を上回り、価格が現在または以前の日次安値を下回って取引されている場合に、ロングに入ります。
  8. ポジションサイズは、構成された固定ボリュームまたはポイント単位のストップロスまでの距離を使用するリスクベースのサイジングのいずれかによって決定されます。
  9. 終了は、ストップロス、テイクプロフィット、オプションのミドルバンドでのクローズ、オプションのトレーリングストップ、オプションの損益分岐点ロジックをチェックすることによって実行されます。負けた取引は、設定可能な保持時間の経過後に清算することもできます。

パラメーター

パラメータ 説明
CandleType 取引に使用される日中ローソク足シリーズ。
BollingerLength Bollinger バンドの移動平均の期間。
BollingerWidth Bollinger バンドの幅の乗数。
DailyMaLength 日次の SMA フィルターの長さ。
StopLossPoints インスツルメントポイントで表されるストップロス距離。
UseRiskVolume リスクベースのポジションサイジングを可能にします。
RiskPercent リスクベースのサイジングに使用されるアカウントの割合。
FixedVolume リスクサイジングが無効または不可能な場合、固定ボリュームをフォールバックします。
SessionStartOffsetMinutes セッション開始後、エントリーが許可されるまでの数分。
SessionEndOffsetMinutes エントリがブロックされるセッション終了の数分前。
CloseOnMiddleBand 価格がBollingerのミドルバンドを横切ったときにポジションを終了します。
EnableTrailing トレーリングストップ調整を有効にします。
TrailingFactor ストップを追跡するまでに必要な距離の乗数。
EnableBreakEven ストップをエントリー価格に移動できるようにします。
BreakEvenFactor ストップを損益分岐点に移動するには利益倍数が必要です。
CloseLosingAfterMinutes 指定された分間保持した後、負けた取引を閉じます。

注意事項

  • 保護的なストップロス注文と利食い注文は、更新ごとにローソク足の極値をチェックすることによってシミュレートされます。取引所側の保護命令が必要な場合は、このセクションを調整します。
  • リスクベースのサイジングは、Security.StepSecurity.StepPrice に依存します。これらの値が欠落している場合、戦略は固定ボリュームに戻ります。
  • 毎日のプロフィットストップは損益戦略を使用するため、実現損益と変動損益はポートフォリオと同じ通貨である必要があります。
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trades reversals from Bollinger Bands.
/// Buys when price closes below lower band and sells when price closes above upper band.
/// </summary>
public class BollingerBandsSessionReversalStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _bollingerLength;
	private readonly StrategyParam<decimal> _bollingerWidth;

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Length of the Bollinger Bands moving average.
	/// </summary>
	public int BollingerLength
	{
		get => _bollingerLength.Value;
		set => _bollingerLength.Value = value;
	}

	/// <summary>
	/// Width multiplier for Bollinger Bands.
	/// </summary>
	public decimal BollingerWidth
	{
		get => _bollingerWidth.Value;
		set => _bollingerWidth.Value = value;
	}

	/// <summary>
	/// Initializes strategy parameters.
	/// </summary>
	public BollingerBandsSessionReversalStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Primary candle series", "General");

		_bollingerLength = Param(nameof(BollingerLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("Bollinger Length", "MA period for Bollinger Bands", "Indicators");

		_bollingerWidth = Param(nameof(BollingerWidth), 2.0m)
			.SetGreaterThanZero()
			.SetDisplay("Bollinger Width", "Band width multiplier", "Indicators");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var bollinger = new BollingerBands
		{
			Length = BollingerLength,
			Width = BollingerWidth
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(bollinger, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue bbValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (bbValue is not IBollingerBandsValue bb)
			return;

		var middle = bb.MovingAverage ?? 0m;
		var upper = bb.UpBand ?? 0m;
		var lower = bb.LowBand ?? 0m;

		if (middle == 0m || upper == 0m || lower == 0m)
			return;

		var price = candle.ClosePrice;

		// Reversal: buy when price falls below lower band
		if (price < lower && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Reversal: sell when price rises above upper band
		else if (price > upper && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
		// Exit at middle band
		else if (Position > 0 && price >= middle)
		{
			SellMarket();
		}
		else if (Position < 0 && price <= middle)
		{
			BuyMarket();
		}
	}
}