GitHub で見る

BandOsMa戦略

概要

BandOsMa 戦略 は、MetaTrader 5 "BandOsMA" エキスパート アドバイザーを StockSharp 戦略に変換します。ヒストグラム値に直接構築された Bollinger バンドを使用して、MACD ヒストグラム (OsMA) を評価します。バンドの上または下のブレイクアウトはエントリーシグナルを作成し、ヒストグラムの追加の移動平均がシグナルの出口を管理します。

この戦略は、ユーザーが選択した単一のシンボルと時間枠で動作します。インジケーターの値は、StockSharp の高レベルのキャンドル サブスクリプションを使用して、完成したキャンドルで計算されます。

取引ロジック

  1. 指標
    • MovingAverageConvergenceDivergenceSignal は、MACD ヒストグラム (OsMA) を提供します。
    • BollingerBands は、極端な逸脱を検出するために OsMA シーケンスに適用されます。
    • 構成可能な移動平均はヒストグラムを平滑化し、出口フィルターとして機能します。
  2. エントリー
    • ロングシグナルは、前のバーが下位バンドより上に留まりながら、現在の OsMA が下位バンドの下で終了したときに表示されます。
    • ショートシグナルは、前のバーが上部バンドよりも下に留まっていたときに、現在の OsMA が上部バンドより上で終了したときに表示されます。
  3. 終了
    • ヒストグラムが移動平均を反対方向に横切ると、シグナルがクリアされます。
    • オープンポジションがアクティブシグナルと一致しなくなった場合、そのポジションは直ちにクローズされます。
    • 各ポジションにはピップベースのストップロスが付加されます。このストップは、同じ距離と StopLossPoints / 50 に等しいトレーリング ステップを持つトレーリング ストップとしても機能します (MetaTrader ヘルパー クラスをミラーリングします)。

ポジション管理

  • ストップロスとトレーリング: ストップ距離は MetaTrader ポイントで表され、商品の PriceStep を使用して価格単位に変換されます。同じ距離がトレーリング ストップにも使用され、終値が少なくともトレーリング ステップ分改善すると、トレーリング ストップが前進します。
  • 一度に 1 つのポジション: 維持されるネット ポジションは 1 つだけです。反対のシグナルは、新しいエントリーを検討する前に現在のポジションを閉じます。

パラメーター

グループ 名前 説明 デフォルト
一般 CandleType ローソク足のサブスクリプションとインジケーターの計算の時間枠。 H1
リスク LotSize ロット単位の取引量。 0.01
リスク StopLossPoints MetaTrader ポイントで表されるストップロス距離 (トレーリングにも使用されます)。 1000
指標 MacdFastPeriod MACD の高速な EMA の長さ。 12
指標 MacdSlowPeriod MACD の EMA の長さが遅いです。 26
指標 MacdSignalPeriod MACD の信号 EMA の長さ。 9
指標 PriceType MACD 入力に適用される価格 (CloseOpenHighLowMedianTypicalWeighted)。 Typical
指標 BollingerPeriod OsMA シーケンス上の Bollinger バンドの期間。 26
指標 BollingerShift Bollinger バッファに適用されるシフト (負ではない)。 0
指標 BollingerDeviation Bollinger バンドの標準偏差乗数。 2
指標 MovingAveragePeriod OsMA に適用される移動平均の長さ。 10
指標 MovingAverageShift 移動平均バッファに適用されるシフト (負ではない)。 0
指標 MovingAverageMethod 移動平均タイプ (SimpleExponentialSmoothedLinearWeighted)。 Simple

実装メモ

  • ローソク足の処理では、WhenCandlesFinished を使用して、最後のバーのみがロジックを駆動するようにします。
  • インジケーター値は、MetaTrader スタイルのバッファー シフトをエミュレートするために履歴バッファーに保存されます。負のシフトはサポートされていません。元のエキスパートのデフォルトと同様に、ゼロまたは正の値を使用します。
  • トレーリングストップはティックごとの更新ではなく、ローソク足の終値に依存します。正確なティックレベルのトレーリングが必要な場合は、ピップ距離を調整します。

使用法

  1. StockSharp で目的のシンボルとタイムフレームを選択します。
  2. パラメータ、特に CandleTypeLotSize、インジケーター期間を設定します。
  3. 戦略を開始します。ローソク足を購読し、インジケーターを計算し、記述されたロジックに従って取引を実行します。
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>
/// Strategy combining the MACD histogram (OsMA) with Bollinger Bands to trade reversals.
/// When OsMA crosses below lower Bollinger band, buy signal is generated.
/// When OsMA crosses above upper Bollinger band, sell signal is generated.
/// </summary>
public class BandOsMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _macdFastPeriod;
	private readonly StrategyParam<int> _macdSlowPeriod;
	private readonly StrategyParam<int> _macdSignalPeriod;
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerDeviation;

	private decimal _prevOsma;
	private decimal _prevUpper;
	private decimal _prevLower;
	private bool _hasPrev;

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

	public int MacdFastPeriod
	{
		get => _macdFastPeriod.Value;
		set => _macdFastPeriod.Value = value;
	}

	public int MacdSlowPeriod
	{
		get => _macdSlowPeriod.Value;
		set => _macdSlowPeriod.Value = value;
	}

	public int MacdSignalPeriod
	{
		get => _macdSignalPeriod.Value;
		set => _macdSignalPeriod.Value = value;
	}

	public int BollingerPeriod
	{
		get => _bollingerPeriod.Value;
		set => _bollingerPeriod.Value = value;
	}

	public decimal BollingerDeviation
	{
		get => _bollingerDeviation.Value;
		set => _bollingerDeviation.Value = value;
	}

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

		_macdFastPeriod = Param(nameof(MacdFastPeriod), 20)
			.SetDisplay("MACD Fast", "Fast EMA length", "Indicators");

		_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 50)
			.SetDisplay("MACD Slow", "Slow EMA length", "Indicators");

		_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 12)
			.SetDisplay("MACD Signal", "Signal EMA length", "Indicators");

		_bollingerPeriod = Param(nameof(BollingerPeriod), 14)
			.SetDisplay("Bollinger Period", "OsMA Bollinger Bands period", "Indicators");

		_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
			.SetDisplay("Bollinger Deviation", "Bollinger Bands deviation", "Indicators");
	}

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

		var macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = MacdFastPeriod },
				LongMa = { Length = MacdSlowPeriod }
			},
			SignalMa = { Length = MacdSignalPeriod }
		};

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

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

	private BollingerBands _bollinger;

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

		var val = (IMovingAverageConvergenceDivergenceSignalValue)macdValue;
		if (val.Macd is not decimal macdLine || val.Signal is not decimal signalLine)
			return;

		var osma = macdLine - signalLine;

		_bollinger ??= new BollingerBands
		{
			Length = BollingerPeriod,
			Width = BollingerDeviation
		};

		var bbResult = (BollingerBandsValue)_bollinger.Process(new DecimalIndicatorValue(_bollinger, osma, candle.CloseTime));
		if (bbResult.UpBand is not decimal upper || bbResult.LowBand is not decimal lower)
		{
			return;
		}

		if (_hasPrev)
		{
			// Buy: OsMA crosses below lower band (reversal up expected)
			if (_prevOsma > _prevLower && osma <= lower && Position <= 0)
			{
				BuyMarket(Position < 0 ? Math.Abs(Position) + 1 : 1);
			}
			// Sell: OsMA crosses above upper band (reversal down expected)
			else if (_prevOsma < _prevUpper && osma >= upper && Position >= 0)
			{
				SellMarket(Position > 0 ? Math.Abs(Position) + 1 : 1);
			}
		}

		_prevOsma = osma;
		_prevUpper = upper;
		_prevLower = lower;
		_hasPrev = true;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_prevOsma = 0;
		_prevUpper = 0;
		_prevLower = 0;
		_hasPrev = false;
		_bollinger = null;

		base.OnReseted();
	}
}