GitHub で見る

シンプルAlligator戦略

概要

シンプルAlligator戦略は、StockSharpの高レベルAPIを使用してMetaTraderの「Alligator Simple v1.0」エキスパートアドバイザーを再現します。完了ローソク足でBill WilliamsのAlligatorインジケーターを読み取り、前の完了バーでLips、Teeth、Jawラインが同じ方向に拡張したときにポジションを開きます。各トレードには、元のMQL実装を反映したpipベースのストップロス、テイクプロフィット、トレーリングストップ管理をオプションで含めることができます。

インジケーターとデータ

  • Alligatorライン: Jaw、Teeth、Lipsの設定可能な長さと前方シフトを持つローソク足の中央価格(high + low) / 2で計算された3つのSmoothed Moving Average(SMMA)。
  • ローソク足: 戦略は1つの設定可能なCandleType(デフォルトで1時間ローソク足)を購読し、先読みバイアスを避けるために完了したローソク足のみを処理します。

トレードロジック

  1. シグナル評価
    • 前の完了ローソク足のシフトされたAlligator値を取得します。
    • ロングシグナル:Lips[t-1] > Teeth[t-1] > Jaw[t-1]
    • ショートシグナル:Lips[t-1] < Teeth[t-1] < Jaw[t-1]
  2. 実行
    • ポジションが開いていない場合、OrderVolumeで市場に入ります。
    • 一度に1つのポジションのみを保持します;現在のポジションが決済されるまで反対のシグナルは無視されます。

エグジットとリスク管理

  • 初期ストップロス: StopLossPips > 0の場合、戦略は銘柄の価格ステップで変換したpip距離分(MetaTraderシンボルが使用する3/5桁pip乗数を含む)だけ執行価格をオフセットします。
  • テイクプロフィット: TakeProfitPips > 0の場合、利益目標がエントリー価格の周囲に対称的に配置されます。ゼロ値は目標を無効にします。
  • トレーリングストップ: TrailingStopPipsTrailingStepPipsの両方が正の場合、価格がトレードに有利な方向に少なくともTrailingStop + TrailingStep動くと、ストップがclose − TrailingStop(ロング)またはclose + TrailingStop(ショート)に進みます。トレーリング更新はバー内タッチをシミュレートするためにローソク足の高値/安値に依存します。
  • エグジット処理: ストップロス、テイクプロフィット、トレーリングの条件はポジションをフラットにする成行注文を発し、完了したすべてのローソク足で評価されます。

パラメーター

  • OrderVolume(デフォルト1):ロットまたはコントラクトのトレードサイズ。
  • StopLossPips(デフォルト100):pipsでの初期ストップロス距離。無効にするにはゼロに設定します。
  • TakeProfitPips(デフォルト100):pipsでのテイクプロフィット距離。無効にするにはゼロに設定します。
  • TrailingStopPips(デフォルト5):pipsでのトレーリングストップ距離。ゼロはトレーリングを無効にします。
  • TrailingStepPips(デフォルト5):トレーリングストップが進む前に価格が移動する必要がある追加pip距離。トレーリングが有効な場合は正である必要があります。
  • JawPeriodTeethPeriodLipsPeriod:jaw、teeth、lipsのSMMA長さ(デフォルト13/8/5)。
  • JawShiftTeethShiftLipsShift:Alligator値を読み取る際に適用される前方シフト(デフォルト8/5/3)。
  • CandleType:計算のためのローソク足データタイプ/時間軸(デフォルト1時間ローソク足)。

実装上の注意

  • pip距離は証券のティックサイズに自動的に適応します。3桁または5桁の小数を持つ銘柄は、MetaTraderのpip定義を複製するために価格ステップを10倍します。
  • インジケーター履歴バッファは設定された前方シフトを尊重するのに十分な値を保存し、手動配列操作を排除します。
  • 戦略は注文を送信するためにBuyMarketSellMarketヘルパーを使用し、コードをシグナル生成とリスク処理に集中させます。
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Simplified Bill Williams Alligator breakout strategy.
/// Buys when Lips > Teeth > Jaw (upward expansion).
/// Sells when Lips less than Teeth less than Jaw (downward expansion).
/// Uses stop-loss and take-profit for risk management.
/// </summary>
public class AlligatorSimpleStrategy : Strategy
{
	private readonly StrategyParam<int> _jawPeriod;
	private readonly StrategyParam<int> _teethPeriod;
	private readonly StrategyParam<int> _lipsPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private SmoothedMovingAverage _jaw;
	private SmoothedMovingAverage _teeth;
	private SmoothedMovingAverage _lips;

	private decimal _entryPrice;
	private int _cooldown;

	/// <summary>
	/// Period for the Alligator jaw (blue) smoothed moving average.
	/// </summary>
	public int JawPeriod
	{
		get => _jawPeriod.Value;
		set => _jawPeriod.Value = value;
	}

	/// <summary>
	/// Period for the Alligator teeth (red) smoothed moving average.
	/// </summary>
	public int TeethPeriod
	{
		get => _teethPeriod.Value;
		set => _teethPeriod.Value = value;
	}

	/// <summary>
	/// Period for the Alligator lips (green) smoothed moving average.
	/// </summary>
	public int LipsPeriod
	{
		get => _lipsPeriod.Value;
		set => _lipsPeriod.Value = value;
	}

	/// <summary>
	/// Stop-loss distance in price steps.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Take-profit distance in price steps.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Initialize <see cref="AlligatorSimpleStrategy"/>.
	/// </summary>
	public AlligatorSimpleStrategy()
	{
		_jawPeriod = Param(nameof(JawPeriod), 13)
			.SetGreaterThanZero()
			.SetDisplay("Jaw Period", "Alligator jaw period", "Alligator");

		_teethPeriod = Param(nameof(TeethPeriod), 8)
			.SetGreaterThanZero()
			.SetDisplay("Teeth Period", "Alligator teeth period", "Alligator");

		_lipsPeriod = Param(nameof(LipsPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Lips Period", "Alligator lips period", "Alligator");

		_stopLossPoints = Param(nameof(StopLossPoints), 200)
			.SetNotNegative()
			.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400)
			.SetNotNegative()
			.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_jaw = null;
		_teeth = null;
		_lips = null;
		_entryPrice = 0;
		_cooldown = 0;
	}

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

		_jaw = new SmoothedMovingAverage { Length = JawPeriod };
		_teeth = new SmoothedMovingAverage { Length = TeethPeriod };
		_lips = new SmoothedMovingAverage { Length = LipsPeriod };

		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_jaw, _teeth, _lips, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal jawValue, decimal teethValue, decimal lipsValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_jaw.IsFormed || !_teeth.IsFormed || !_lips.IsFormed)
			return;

		if (_cooldown > 0)
		{
			_cooldown--;
			return;
		}

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		// Check SL/TP for existing positions
		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 110;
				return;
			}

			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
			{
				SellMarket();
				_entryPrice = 0;
				_cooldown = 110;
				return;
			}
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 110;
				return;
			}

			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
			{
				BuyMarket();
				_entryPrice = 0;
				_cooldown = 110;
				return;
			}
		}

		// Buy when lips > teeth > jaw (Alligator opening upward)
		if (lipsValue > teethValue && teethValue > jawValue && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();

			BuyMarket();
			_entryPrice = close;
			_cooldown = 110;
		}
		// Sell when lips < teeth < jaw (Alligator opening downward)
		else if (lipsValue < teethValue && teethValue < jawValue && Position >= 0)
		{
			if (Position > 0)
				SellMarket();

			SellMarket();
			_entryPrice = close;
			_cooldown = 110;
		}
	}
}