GitHub で見る

Fibonacci の潜在的なエントリー戦略

概要

この戦略は、元の EA_PUB_FibonacciPotentialEntries エキスパート アドバイザーの動作を再現します。 50% と 61% の Fibonacci リトレースメント レベルで 2 つの指値注文を出し、高レベルの StockSharp API を使用してライフサイクルを管理します。

取引ロジック

  1. 初期配置

    • 買値/売値が利用可能になるとすぐに、戦略は現在のスプレッドを計算し、2 つの指値注文を送信します。
      • オーダー #1: 61% レベルより下 (ショートの場合は上) の保護ストップを備えた 50% レベルに配置されます。
      • オーダー #2: 61% レベルで配置され、100% レベルの途中に保護ストップが配置されます。
    • 最初の取引ではポートフォリオの 0.7% のリスクが発生し、2 番目の取引では RiskPercent パラメータの残りの部分のリスクが発生するようにボリュームのサイズが設定されます。
  2. ターゲットの処理

    • 価格が TargetPrice レベルに達すると、戦略は成行注文を使用して各約定ポジションの半分をクローズします。
    • 部分的にエグジットした後、残りのボリュームは損益分岐点(エントリー価格)で保護されます。市場がそのレベルに戻ると、残りのポジションは自動的にクローズされます。
  3. 方向

    • IsBullish = true は購入制限を作成します (元の強気テンプレート)。
    • IsBullish = false は、売り指値と逆ストップ/ターゲット チェックを使用した動作を反映しています。

パラメーター

名前 説明
PriceOn50Level 最初の指値注文の価格レベル。
PriceOn61Level 2 番目の指値注文の価格レベル。
PriceOn100Level 2 番目の取引ストップを計算するために使用される基準レベル。
TargetPrice 両方のポジションの共通利益目標。
RiskPercent 両方のエントリーにわたるポートフォリオ資本のリスクの合計パーセンテージ。
IsBullish 長いセットアップと短いセットアップから選択します。

変換メモ

  • リポジトリ ガイドラインの要求どおりに、高レベルのヘルパー (SubscribeLevel1BuyLimitSellLimitBuyMarketSellMarket) のみが使用されます。
  • 部分的なエグジットと損益分岐点調整は成行注文で再現され、低レベルの注文変更呼び出しに依存することなく、MQL ロボットの動作に一致します。
  • ポジションボリュームは、StockSharp の規則との一貫性を保つために、楽器のボリュームステップに正規化されます。
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Fibonacci Potential Entries strategy: Two-candle reversal with RSI filter.
/// Uses price swing highs/lows as fibonacci reference points.
/// </summary>
public class FibonacciPotentialEntriesStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal _highestHigh;
	private decimal _lowestLow;
	private decimal _prevClose;
	private int _barCount;
	private int _candlesSinceTrade;
	private bool _hasPrevClose;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public FibonacciPotentialEntriesStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_highestHigh = 0;
		_lowestLow = decimal.MaxValue;
		_prevClose = 0;
		_barCount = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrevClose = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_highestHigh = 0;
		_lowestLow = decimal.MaxValue;
		_prevClose = 0;
		_barCount = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrevClose = false;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (candle.HighPrice > _highestHigh) _highestHigh = candle.HighPrice;
		if (candle.LowPrice < _lowestLow) _lowestLow = candle.LowPrice;
		_barCount++;

		if (_barCount < 20) return;

		var range = _highestHigh - _lowestLow;
		if (range <= 0) return;

		var fib382 = _highestHigh - range * 0.382m;
		var fib618 = _highestHigh - range * 0.618m;
		var close = candle.ClosePrice;
		var crossedIntoBuyZone = _hasPrevClose && _prevClose > fib618 && close <= fib618;
		var crossedIntoSellZone = _hasPrevClose && _prevClose < fib382 && close >= fib382;

		if (crossedIntoBuyZone && rsiValue < 40 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			BuyMarket();
			_candlesSinceTrade = 0;
		}
		else if (crossedIntoSellZone && rsiValue > 60 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
		{
			SellMarket();
			_candlesSinceTrade = 0;
		}

		_prevClose = close;
		_hasPrevClose = true;
	}
}