GitHub で見る

FT Bill Williams トレーダー戦略

概要

FT Bill Williams トレーダー戦略 は、MetaTrader エキスパート アドバイザー「FT_BillWillams_Trader」の高レベルの StockSharp 翻訳です。 Bill Williams フラクタルと Alligator インジケーターを組み合わせて、トレンドのブレイクアウトをトレードします。この戦略は、新しいフラクタルを監視し、Alligator 構造がブレイクアウト方向を確認していることを検証し、オプションでポジションを開く前に距離、アライメント、およびリバースシグナルフィルターを適用します。

取引ロジック

  1. フラクタル検出 – この戦略は、最新の FractalPeriod の高値と安値をバッファーします。中央のバーがウィンドウ内の最高 (または最低) ポイントになると、新しいブレイクアウト レベルが記録されます。時期尚早のエントリを避けるために、フラクタルの上下に IndentPoints オフセットが追加されます。
  2. ブレイクアウトの確認EntryConfirmation に応じて:
    • PriceBreakout は、ローソク足の範囲がブレイクアウトレベルを横切るときを確認します。
    • CloseBreakout は、前のローソク足の終値がそのレベルを超えるまで待ちます。
  3. 距離チェック – ブレイクアウト レベルが Alligator リップ (以前のバー値) から MaxDistancePoints よりも遠い場合、エントリーは拒否されます。フィルターを無効にするには、距離をゼロに設定します。
  4. 歯フィルタUseTeethFilter が有効な場合、前のクローズは Alligator の歯の上(ロングの場合)または下(ショートの場合)にある必要があります。
  5. トレンドの調整UseTrendAlignment = true では、唇、歯、顎はそれぞれ少なくとも TeethLipsDistancePointsJawTeethDistancePoints ポイント離れている必要があり、Alligator がトレンドであることを確認します。
  6. リバース イグジットReverseExit = OppositeFractal の場合、新しい反対のフラクタルはオープン ポジションを即座にクローズします。 OppositePosition の場合、この戦略はまず現在の取引を終了してから、反対方向の取引を開始します。
  7. ジョー出口JawExit は、価格が Alligator ジョー(バー内またはローソク足終値)を横切ったときにポジションをクローズするかどうかを定義します。
  8. トレーリング ストップEnableTrailing が true で、取引に利益がある場合、唇と SlopeSmaPeriod SMA の相対的な傾きに応じて、ストップは唇または歯に移動します。最初の保護ストップと利益目標は、StopLossPointsTakeProfitPoints によって制御されます。

パラメーター

プロパティ 説明 デフォルト
OrderVolume 成行注文を送る際に使用される取引量。 0.1
FractalPeriod フラクタル パターンのバーの数 (奇数の値を推奨)。 5
IndentPoints ブレークアウト レベルに追加されるオフセット (ポイント単位)。 1
EntryConfirmation ブレークアウト確認モード (PriceBreakoutCloseBreakout)。 CloseBreakout
UseTeethFilter 以前の歯が Alligator の歯の正しい側にある必要があります。 true
MaxDistancePoints ブレイクアウト レベルと Alligator 個の唇 (ポイント) の間の最大距離。 1000
UseTrendAlignment Alligator 行間の最小間隔を強制します。 false
JawTeethDistancePoints アライメントフィルターで使用される顎と歯の最小距離。 10
TeethLipsDistancePoints アライメントフィルターで使用される歯と唇の最小距離。 10
JawExit ジョークロスオーバーでポジションをクローズするモード (DisabledPriceCrossCloseCross)。 CloseCross
ReverseExit 逆信号処理 (DisabledOppositeFractalOppositePosition)。 OppositePosition
EnableTrailing Alligator ベースのトレーリング ストップ管理を有効にします。 true
SlopeSmaPeriod 唇の傾きと比較されるSMAの周期。 5
StopLossPoints ポイント単位のストップロス距離 (0 無効)。 50
TakeProfitPoints テイクプロフィット距離 (ポイント単位) (0 無効)。 50
JawPeriod, TeethPeriod, LipsPeriod Alligator 行のピリオド。 13, 8, 5
JawShift, TeethShift, LipsShift 各 Alligator 行の前方シフト。 8, 5, 3
MaMethod Alligator (SimpleExponentialSmoothedWeighted) の移動平均タイプ。 Simple
AppliedPrice Alligator に提供されたローソク足の価格。 CandlePrice.Median
CandleType マーケットデータからサブスクライブされたローソク足タイプ。 15-minute timeframe

追加メモ

  • この戦略は、デフォルトのチャート領域で Alligator ラインを描画し、取引を実行します。
  • FractalPeriod は、中央のバーがフラクタルの頂点を表すように奇数のままにする必要があります。デフォルト値は元の Expert Advisor と一致します。
  • 距離ベースのパラメータ (IndentPointsMaxDistancePointsJawTeethDistancePointsTeethLipsDistancePointsStopLossPointsTakeProfitPoints) はブローカー ポイント (Security.PriceStep) で表されます。
  • トレーリングストップとジョーイグジットは完了したローソク足に依存し、Alligator の前のバー値で動作する元の MQL ロジックを反映しています。
using System;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Bill Williams Fractal Breakout strategy filtered by Alligator alignment.
/// Buys on up-fractal breakout when price is above alligator teeth,
/// sells on down-fractal breakout when price is below alligator teeth.
/// Exits on opposite signal (reverse position).
/// </summary>
public class FTBillWillamsTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _jawPeriod;
	private readonly StrategyParam<int> _teethPeriod;
	private readonly StrategyParam<int> _lipsPeriod;
	private readonly StrategyParam<int> _fractalLen;

	private SMA _jaw = null!;
	private SMA _teeth = null!;
	private SMA _lips = null!;

	private decimal[] _highBuf = Array.Empty<decimal>();
	private decimal[] _lowBuf = Array.Empty<decimal>();
	private int _bufCount;

	private decimal? _pendingBuyLevel;
	private decimal? _pendingSellLevel;
	private decimal _prevJaw;
	private decimal _prevTeeth;
	private decimal _prevLips;
	private decimal _entryPrice;

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

	public int JawPeriod
	{
		get => _jawPeriod.Value;
		set => _jawPeriod.Value = value;
	}

	public int TeethPeriod
	{
		get => _teethPeriod.Value;
		set => _teethPeriod.Value = value;
	}

	public int LipsPeriod
	{
		get => _lipsPeriod.Value;
		set => _lipsPeriod.Value = value;
	}

	public int FractalLen
	{
		get => _fractalLen.Value;
		set => _fractalLen.Value = value;
	}

	public FTBillWillamsTraderStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Candle type for strategy", "General");

		_jawPeriod = Param(nameof(JawPeriod), 13)
			.SetDisplay("Jaw Period", "Alligator jaw SMA period", "Alligator");

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

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

		_fractalLen = Param(nameof(FractalLen), 5)
			.SetDisplay("Fractal Length", "Number of bars for fractal detection", "Signals");
	}

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

		_jaw = new SMA { Length = JawPeriod };
		_teeth = new SMA { Length = TeethPeriod };
		_lips = new SMA { Length = LipsPeriod };
		_highBuf = new decimal[FractalLen];
		_lowBuf = new decimal[FractalLen];
		_bufCount = 0;
		_pendingBuyLevel = null;
		_pendingSellLevel = null;
		_prevJaw = 0;
		_prevTeeth = 0;
		_prevLips = 0;
		_entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

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

		_highBuf = new decimal[FractalLen];
		_lowBuf = new decimal[FractalLen];
		_bufCount = 0;
		_pendingBuyLevel = null;
		_pendingSellLevel = null;
		_prevJaw = 0;
		_prevTeeth = 0;
		_prevLips = 0;
		_entryPrice = 0;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_jaw, _teeth, _lips, OnProcess)
			.Start();

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

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

		// Update fractal buffers
		UpdateFractals(candle);

		var close = candle.ClosePrice;
		var high = candle.HighPrice;
		var low = candle.LowPrice;

		// Manage existing positions - exit on opposite signal
		if (Position > 0)
		{
			// Close long if price breaks below pending sell level or close drops below teeth
			if (_pendingSellLevel is decimal sellLvl && low < sellLvl)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			// Close short if price breaks above pending buy level or close rises above teeth
			if (_pendingBuyLevel is decimal buyLvl && high > buyLvl)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		// Enter long: price breaks above up-fractal level, close above teeth (bullish)
		if (Position <= 0 && _pendingBuyLevel is decimal pendBuy)
		{
			if (high > pendBuy && close > teethVal)
			{
				if (Position < 0)
					BuyMarket(); // close short first

				BuyMarket();
				_entryPrice = close;
			}
		}

		// Enter short: price breaks below down-fractal level, close below teeth (bearish)
		if (Position >= 0 && _pendingSellLevel is decimal pendSell)
		{
			if (low < pendSell && close < teethVal)
			{
				if (Position > 0)
					SellMarket(); // close long first

				SellMarket();
				_entryPrice = close;
			}
		}

		_prevJaw = jawVal;
		_prevTeeth = teethVal;
		_prevLips = lipsVal;
	}

	private void UpdateFractals(ICandleMessage candle)
	{
		var len = _highBuf.Length;
		if (len < 3)
			return;

		// Shift buffers
		Array.Copy(_highBuf, 1, _highBuf, 0, len - 1);
		_highBuf[len - 1] = candle.HighPrice;
		Array.Copy(_lowBuf, 1, _lowBuf, 0, len - 1);
		_lowBuf[len - 1] = candle.LowPrice;

		_bufCount++;
		if (_bufCount < len)
			return;

		var wing = (len - 1) / 2;
		var center = len - 1 - wing;

		// Check up fractal
		var centerHigh = _highBuf[center];
		var isUp = true;
		for (var i = 0; i < len; i++)
		{
			if (i != center && _highBuf[i] >= centerHigh)
			{
				isUp = false;
				break;
			}
		}

		if (isUp)
			_pendingBuyLevel = centerHigh;

		// Check down fractal
		var centerLow = _lowBuf[center];
		var isDown = true;
		for (var i = 0; i < len; i++)
		{
			if (i != center && _lowBuf[i] <= centerLow)
			{
				isDown = false;
				break;
			}
		}

		if (isDown)
			_pendingSellLevel = centerLow;
	}
}