GitHub で見る

FiboChannel Line戦略

概要

FiboChannel Line戦略は、MetaTraderエキスパートアドバイザー「FIBOCHANNEL」の変換版です。オリジナルのロボットは手動で描かれたFibonacciチャネルの方向、上位時間軸でのMomentumスイング、線形加重移動平均とMACDシグナルの組み合わせに依存していました。StockSharpポートは高レベルのインジケーターバインディングと組み込みのリスク管理を活用しながら同じ精神を維持します。

主要なアイデア:

  • 線形加重移動平均(LWMA)のペアを使用して支配的なトレンドに従います。
  • Momentumオシレーターの中立レベル周辺のMomentumスパイクを確認します。
  • MACD線とシグナル線の関係でトレードをフィルタリングします。
  • チャートオブジェクトを読む代わりに線形回帰チャネルの傾きを確認します。
  • 自動パーセントベースの保護を通じてポジションを管理します。

戦略はキャンドル集計をサポートする任意のインストゥルメントで機能します。デフォルトの時間軸は30分キャンドルで、応答性とインジケーター安定性のバランスを提供します。

トレードロジック

  1. トレンドフィルター – 高速LWMAが低速LWMAの上でクローズすると、市場は強気と見なされ、ロングトレードのみが評価されます。低速LWMAを下回ると、ショートのみが考慮されます。
  2. Momentum要件 – 直近3つのMomentum読み取りのローリングウィンドウで、少なくとも1つの値が設定された閾値によって中立レベル100から偏差していることを示す必要があります。これはMQLバージョンのマルチバーMomentum強度チェックを再現します。
  3. MACDフィルター – ロングはMACD線がシグナル線を上回ることを必要とし、ショートはその逆を必要とします。
  4. チャネル方向 – 線形回帰の傾きはSlope Thresholdを超えてポジティブ(ロング向け)またはネガティブ(ショート向け)でなければなりません。これはFibonacialチャネルオブジェクトのアンカーポイントを比較したオリジナルエキスパートの上昇/下降チャネル検証を模倣します。
  5. エントリーと反転 – すべての条件が揃い、その方向に既存のポジションがない場合、戦略はアクティブな注文をキャンセルし、サイズVolume + |Position|の成行注文を送信します。これにより滑らかな反転が可能になります。
  6. エグジット – チャネル方向またはMACDフィルターがオープントレードを支持しなくなった場合、未決注文をキャンセルした後にポジションが閉じられます。さらに、保護的なストップロス、テイクプロフィット、最大ドローダウンルールがStartProtectionを通じて設定されます。

パラメーター

パラメーター 説明 デフォルト
Candle Type すべてのインジケーターに使用されるキャンドル集計。 30分時間軸
Fast LWMA 高速線形加重移動平均の長さ。 6
Slow LWMA 低速線形加重移動平均の長さ。 85
Momentum Period Momentumインジケーターのバー数。 14
Momentum Threshold Momentumバッファー内で必要な100からの最小絶対偏差。 0.3
Channel Length 線形回帰傾き計算に使用されるバー。 50
Slope Threshold トレンド方向を確認するための最小絶対傾き値。 0.0
MACD Fast MACD計算内の高速EMA期間。 12
MACD Slow MACD計算内の低速EMA期間。 26
MACD Signal MACDのシグナル線期間。 9
Take Profit % パーセントでの保護テイクプロフィット距離。 2
Stop Loss % パーセントでの保護ストップロス距離。 1
Equity Risk % すべてのポジションをフラット化する前に許可される最大口座エクイティドローダウン。 3

すべての数値パラメーターはMQL入力の典型的な範囲を反映する最適化ヒントを公開します。

リスク管理

StartProtectionは以下を適用するように設定されています:

  • エントリー価格に対するパーセントベースのストップロスとテイクプロフィット。
  • 損失が設定されたパーセンテージを超えると戦略をフラット化するエクイティドローダウン保護。

これらの保護は、オリジナルエキスパートの多数のバランス、トレーリング、ブレークイーブンルーティンを置き換え、StockSharp内でより明確で安全な動作を提供します。

MetaTraderバージョンとの違い

  • チャートオブジェクトの読み取りはStockSharp戦略が手動Fibonacci チャネルと相互作用しないため、回帰傾きフィルターに置き換えられました。
  • 金銭ベースのトレーリングロジックの混合の代わりに、戦略はStartProtectionに依存します。
  • インジケータースタックは同じまま(LWMA、Momentum、MACD)ですが、高レベルバインディングを使用して直接インジケーター値のポーリングなしで実装されています。
  • アラート、メール、プッシュ通知はStockSharp環境がすでに統合ログを提供しているため削除されました。

使用ノート

  1. 戦略をポートフォリオとセキュリティにアタッチし、Volumeプロパティを通じてロットサイズを設定し、必要に応じてパラメーターを調整します。
  2. Momentumバッファーと傾きインジケーターが適切に形成できるように、選択されたキャンドルタイプの履歴データが利用可能であることを確認します。
  3. まずペーパートレードで実行して、取引されるインストゥルメントのボラティリティに応じてMomentum閾値とリスクパラメーターを微調整します。
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;

public class FiboChannelLineStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public FiboChannelLineStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

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

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

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

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}