GitHub で見る

AOライトニング戦略

概要

AOライトニングはStockSharpの高レベルAPIを使用してMT5エキスパートアドバイザー「AO_Lightning」を再現します。このシステムは中央値価格から構築されたAwesome Oscillator(AO)の傾きを監視します。オシレーターが下降すると、戦略はロングエクスポージャーを積み上げ、オシレーターが上昇するとショートポジションを構築します。ポジションは設定可能な上限まで積み上げられ、方向を変える前に反対のポジションは閉じられます。

トレーディングロジック

  1. 選択されたローソク足シリーズを購読し、短期5と長期34でAwesome Oscillatorを計算します(オリジナルのMQLコードから取られたデフォルト値)。
  2. 完了したローソク足のみを待ちます。戦略は二重カウントを避けるために中間の更新を無視します。
  3. 最初の完了したローソク足でAO値が参照として保存されます。
  4. 現在のAO値が前の値より低い場合:
    • オープンなショートポジションが存在する場合、ショート全体を閉じてすぐにロング層を1つ追加するようにサイズを調整した成行買い注文を送信します。
    • ショートがなく、ロングエクスポージャーが上限を下回っている場合、追加の層を1つ買います。
  5. 現在のAO値が前の値より高い場合:
    • オープンなロングポジションが存在する場合、ロングエクスポージャーを閉じて同時にショート層を1つ開く成行売り注文を送信します。
    • ロングがなく、ショートエクスポージャーが上限を下回っている場合、追加の層を1つ売ります。
  6. 前の値と等しいAO値はポジションを変更しません。
  7. 組み込みのStartProtection()は起動時に一度有効になり、Designerユーザーが希望する場合にストップやその他のリスクモジュールを付加できます。

ロジックはオリジナルのエキスパートアドバイザーを反映しています:AOの傾きがトレード方向を定義し、反対のトレードは新しいエントリーの前に解消され、増分注文は上限に達するまで積み上がり続けます。

ポジション管理

  • トレードボリュームは各追加層のサイズを定義し、MT5パラメーターLotFixedに対応します。
  • 最大ポジション数はMT5のOrders入力に対応します。どちらの側で積み上げられる層の数を制限します。
  • ピラミッディングは線形です:各有効なシグナルは上限に達していない限り、正確に1ロットサイズの層を追加します。
  • 解消はショートからロングまたはその逆に変わる際に中間フラット状態を避けるために、結合された注文(決済+新方向)を送信します。

パラメーター

名前 説明 デフォルト
TradeVolume 各新しい層の注文サイズ。 1
MaxPositions 同時にアクティブにできるロングまたはショート層の最大数。 10
AoShortPeriod Awesome Oscillatorで使用される高速SMAの長さ(中央値価格SMA)。 5
AoLongPeriod Awesome Oscillatorの低速SMAの長さ。 34
CandleType 戦略によって処理されるローソク足データソース。 5分時間軸

ノート

  • オリジナルのMT5エキスパートは入力にPeriod_sma_slowPeriod_sma_fastという名前を付けていますが、値(5と34)を入れ替えています。StockSharpポートは直感的なAoShortPeriod/AoLongPeriodパラメーターを公開することで機能的マッピングを維持しています。
  • タスクリクエストに合わせて、まだPythonバージョンは提供されていません。
  • テストは含まれていません。本番環境に展開する前に、Designerまたは独自のバックテストハーネスを通じて必要な検証を実行してください。
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// AO Lightning strategy.
/// Trades based on the Awesome Oscillator momentum slope direction.
/// Buys when AO is rising, sells when AO is falling.
/// </summary>
public class AoLightningStrategy : Strategy
{
	private readonly StrategyParam<int> _aoShortPeriod;
	private readonly StrategyParam<int> _aoLongPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevAo;
	private bool _initialized;

	public int AoShortPeriod
	{
		get => _aoShortPeriod.Value;
		set => _aoShortPeriod.Value = value;
	}

	public int AoLongPeriod
	{
		get => _aoLongPeriod.Value;
		set => _aoLongPeriod.Value = value;
	}

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

	public AoLightningStrategy()
	{
		_aoShortPeriod = Param(nameof(AoShortPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("AO Fast", "Short SMA period for Awesome Oscillator", "Indicators");

		_aoLongPeriod = Param(nameof(AoLongPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("AO Slow", "Long SMA period for Awesome Oscillator", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Source candles", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevAo = 0m;
		_initialized = false;
	}

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

		_prevAo = 0;
		_initialized = false;

		var ao = new AwesomeOscillator
		{
			ShortMa = { Length = AoShortPeriod },
			LongMa = { Length = AoLongPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ao, OnProcess)
			.Start();

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

	private void OnProcess(ICandleMessage candle, decimal aoValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (!_initialized)
		{
			_prevAo = aoValue;
			_initialized = true;
			return;
		}

		// Buy when AO is rising (bullish momentum)
		if (aoValue > _prevAo && Position <= 0)
		{
			BuyMarket();
		}
		// Sell when AO is falling (bearish momentum)
		else if (aoValue < _prevAo && Position >= 0)
		{
			SellMarket();
		}

		_prevAo = aoValue;
	}
}