GitHub で見る

Exp 2XMA Ichimoku オシレーター戦略

この戦略は、MetaTraderのエキスパートアドバイザー「Exp_2XMA_Ichimoku_Oscillator」のロジックを再現します。設定可能な移動平均で平滑化された2つのIchimokuスタイルの価格エンベロープを組み合わせています。StockSharpの実装は高レベル戦略APIを使用し、ローソク足ベースのシグナル生成に焦点を当てながら、ソースアルゴリズムのポジション管理ルールを維持します。

コアアイデア

  1. 選択したタイムフレームで2つのDonchian的な中点が計算されます:
    • 速い中点UpPeriod1DownPeriod1バー間の最高値と最安値を平均します。
    • 遅い中点UpPeriod2DownPeriod2バーで同じ操作を行います。
  2. 各中点は長さXLength1XLength2の移動平均(Method1Method2)で平滑化されます。利用可能な平滑化方法は単純、指数、平滑化、線形加重です。
  3. オシレーターの値は2つの平滑化された中点の差です。4つの色の状態がその挙動を表します:
    • PositiveRising (0):オシレーターはゼロより上で上昇中。
    • PositiveFalling (1):オシレーターはゼロより上だがモメンタムを失っている。
    • NegativeRising (3):オシレーターはゼロより下だがゼロに向かって上昇中。
    • NegativeFalling (4):オシレーターはゼロより下でさらに下落中。
    • Neutral (2) はウォームアップ中に割り当てられます。
  4. シグナルはSignalBarにあるバーと直前のバー(SignalBar + 1)の色を使って評価されます。これはMQLバージョンのバッファシフトを反映しています。

トレードロジック

  • ロングエントリーEnableBuyOpenが真の場合に許可されます。古いバー(SignalBar + 1)の色が上昇中(0または3)で、より新しいバー(SignalBar)が下降色(1または4)に変わった場合、戦略はショートポジションを閉じ(EnableSellClose)、Volume + |Position|ユニットのロングポジションを開く/拡張します。
  • ショートエントリーEnableSellOpenが真の場合に許可されます。古いバーの色が下降中(1または4)で、より新しいバーが上昇色(0または3)に変わった場合、戦略は既存のロングを閉じ(EnableBuyClose)、Volume + |Position|ユニットのショートポジションを開く/拡張します。
  • すべての実行はシグナルを生成したローソク足のクローズで行われます。注文は常に成行注文で、戦略は追加のストップロスやテイクプロフィットレベルを適用しません;エグジットは色の遷移のみに依存します。
  • StartProtection()は起動時に有効化され、予期しないポジションに対するフレームワークの組み込みセーフティチェックを使用します。

パラメーター

名前 説明 デフォルト値
CandleType インジケーター計算に使用するタイムフレーム。 4時間ローソク足
UpPeriod1, DownPeriod1 速い中点のルックバックウィンドウ。 6, 6
UpPeriod2, DownPeriod2 遅い中点のルックバックウィンドウ。 9, 9
XLength1, XLength2 2つの移動平均の平滑化長。 25, 80
Method1, Method2 移動平均タイプ(単純、指数、平滑化、加重)。 単純
SignalBar オシレーター色を読み取るための履歴バーシフト。 1
EnableBuyOpen, EnableSellOpen ロング/ショートエントリーの切り替え。 true
EnableBuyClose, EnableSellClose ロング/ショートエグジットの切り替え。 true
Volume 基本取引サイズ;反転時に既存ポジションをこの値に追加します。 1

使用上の注意

  • 移動平均タイプは元のエキスパートから最も一般的な平滑化動作をカバーします。カスタムXMAフェーズ調整などの高度なオプションはStockSharpでは利用できず、標準インジケーターに置き換えられました。
  • オシレーターは閉じたローソク足で計算されるため、MQL実装が使用していたのと同じ1バー遅延でシグナルが表示されます(SignalBar = 1)。追加の確認バーが必要な場合はSignalBarを増やしてください。
  • エグジットがオシレーター色の反転のみに依存しているため、ライブ市場で運用する際は外部のリスク管理(ポートフォリオマネージャー、保護ストップ)と組み合わせることを検討してください。
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// Exp 2XMA Ichimoku Oscillator strategy (simplified).
/// Uses two SMAs of different periods as a crossover oscillator.
/// Buys when fast SMA crosses above slow SMA, sells when fast crosses below.
/// </summary>
public class Exp2XmaIchimokuOscillatorStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public Exp2XmaIchimokuOscillatorStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Source candles", "General");

		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast moving average length", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow moving average length", "Indicators");
	}

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

		var fastMa = new ExponentialMovingAverage { Length = FastPeriod };
		var slowMa = new ExponentialMovingAverage { Length = SlowPeriod };

		decimal prevFast = 0, prevSlow = 0;
		bool prevInitialized = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastMa, slowMa, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					prevInitialized = true;
					return;
				}

				if (!prevInitialized)
				{
					prevFast = fastValue;
					prevSlow = slowValue;
					prevInitialized = true;
					return;
				}

				// Buy on bullish crossover
				if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
				{
					BuyMarket();
				}
				// Sell on bearish crossover
				else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
				{
					SellMarket();
				}

				prevFast = fastValue;
				prevSlow = slowValue;
			})
			.Start();

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