GitHub で見る
Graal フラクタル チャネル戦略
概要
Graal フラクタル チャネル戦略 は、MetaTrader 4 エキスパート アドバイザー「Graal-003」の StockSharp 移植です。このアルゴリズムは、5 つのローソク足のフラクタル パターンを監視し、適応価格チャネルを使用してブレイクアウトを確認します。有効な強気または弱気のフラクタルが表示されると、戦略はブレイクアウト方向に入る前にいくつかのフィルター (フラクタル トンネル、終値エンベロープ、およびオプションのフラット市場抑制) を評価します。オプションの Williams %R オーバーレイは、元のロボットの手動終了ロジックを複製します。一方、ヘッジストップ注文は、EA の逆トレンド保護をエミュレートするように段階的に設定できます。
データの流れと指標
- 設定された
CandleType をサブスクライブします (デフォルトでは時間ごとのキャンドル)。
- 最後の
ChannelPeriod ローソク足のローリング キューを構築し、フラット フィルターと方向性チェックに使用される Donchian のような終値チャネルを計算します。
- ローソク足の流れから 5 バー フラクタルの高値と安値を直接検出します。
- 組み込みの
WilliamsPercentRange インジケーターをフィードして、オプションの終了信号を監視します。
取引ワークフロー
- フラクタル検出 – この戦略は、5 つの連続した完成したキャンドルを追跡します。中央のバーの高値/安値が、その 2 つの先行バーと 2 つの後続バーと比較して極端である場合、上部または下部のフラクタルを記録し、保留中のショートまたはロングシグナルをマークします。
- 信号の経年変化 – 新しいキャンドルが出現するたびに、フラクタルの年齢が増加します。
SignalAgeLimit バーが実行されずに経過すると、保留中のシグナルは期限切れになります。
- チャネル評価 – ローリングクローズチャネルは 3 つのフィルターを提供します。
- フラクタル トンネル:
UseFractalChannel が有効な場合、終値は最新のフラクタル高値と安値の間の距離 (DepthPercent) のパーセンテージ以内に収まる必要があります。
- 高/低方向:
UseHighLowChannel では、終値はエンベロープの限られた部分 (OrientationPercent) のみを貫通する必要があります。
- フラット ブロッキング:
AllowFlatTrading が無効になっている場合、チャネル幅が FlatThresholdPips を下回っている間、取引は一時停止されます。
- 注文執行 – フィルターが通過すると、ストラテジーは商品の制約に対して目的の
OrderVolume を正規化し、フラクタル方向に成行注文を送信します。
- ヘッジストップ –
UseCounterOrders がアクティブな場合、アルゴリズムはフラクタル価格プラス/マイナス OffsetPips で反対のストップ注文を配置し、EA の逆トレンドのステージングを反映します。
- Williams が終了 –
UseWilliamsExit が有効な場合、最新の Williams %R 値は、-WilliamsThreshold を超えるとロングポジションを決済し、-100 + WilliamsThreshold を下回るとショートポジションを決済します。
ストップロスとテイクプロフィットの距離はオプションです。 StopLossPips または TakeProfitPips が正の場合、ストラテジーは商品ティック サイズを使用してピップ距離を絶対価格オフセットに変換し(EA から 3/5 桁の調整を加えて)、保護注文の管理を StartProtection に委任します。
パラメーター
| パラメータ |
デフォルト |
説明 |
OrderVolume |
0.1 |
金融商品の制限に対して正規化する前のベース成行注文サイズ。 |
StopLossPips |
500 |
ピップ単位の保護停止距離。価格に変換され、StartProtection 経由で適用されます。 |
TakeProfitPips |
500 |
利食い距離をピップス単位で指定します。価格に変換され、StartProtection 経由で適用されます。 |
OffsetPips |
5 |
カウンタートレンドのストップ注文をステージングするときに使用される追加の距離。 |
ChannelPeriod |
14 |
終値チャネル用に保存された最近のローソク足の数。 |
UseFractalChannel |
false |
エントリー前に価格が内部フラクタルコリドー内に留まる必要があります。 |
DepthPercent |
25 |
内側の回廊を定義するフラクタル範囲のパーセンテージ。 |
UseHighLowChannel |
false |
Donchian スタイルのクローズ チャネル指向フィルターを有効にします。 |
OrientationPercent |
20 |
UseHighLowChannel が true の場合、閉じたチャネルへの侵入が許可されます。 |
AllowFlatTrading |
true |
クローズチャネル幅に応じて、市場が横ばいの場合でも取引が可能になります。 |
FlatThresholdPips |
20 |
フラット取引が無効な場合に必要な最小チャネル幅 (ピップ単位)。 |
UseWilliamsExit |
false |
Williams %R ベースの終了ルールをアクティブ化します。 |
WilliamsPeriod |
14 |
Williams %R インジケーターのルックバック期間。 |
WilliamsThreshold |
30 |
Williams %R の感度しきい値 (パーセント ポイント) が終了しました。 |
UseCounterOrders |
false |
市場エントリー後に反対の逆指値注文を出します。 |
SinglePosition |
false |
ポジションがオープンしている間、同じ方向への追加エントリーをブロックします。 |
SignalAgeLimit |
3 |
フラクタル信号が有効である間の新しいバーの最大数。 |
CandleType |
H1 |
分析に使用されるローソク足データシリーズ (デフォルトは 1 時間の時間枠)。 |
使用上の注意
- この戦略では、ボリュームの正規化とピップ変換が正しく機能するように、有効な
PriceStep、MinVolume、および VolumeStep を持つインストゥルメントが期待されます。
- カウンタートレンド注文は、ポジションが決済されたとき、戦略が停止したとき、または機能が無効になったときに自動的にキャンセルされます。
- Williams %R イグジットはセーフティ ネットとして機能し、元のフラクタル シグナルがまだアクティブであってもポジションを閉じることができます。
- このアルゴリズムは、
OnReseted がトリガーされるたびに、キャッシュされたすべての状態 (フラクタル バッファー、Williams 履歴、ステージングされた注文) をリセットします。
- StockSharp 実装では、手動インジケーター ループの代わりに高レベルの
SubscribeCandles().Bind(...) サブスクリプションを使用します。
- プロテクティブストップは
StartProtection に依存しているため、直接のストップ注文/指値注文の記録は必要ありません。
- 数量は、注文が送信される前に、StockSharp の規則に従って、為替制限に対して正規化されます。
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Graal Fractal Channel strategy - Highest/Lowest channel breakout.
/// Buys when close crosses above the upper channel.
/// Sells when close crosses below the lower channel.
/// Uses midpoint crossing for exits.
/// </summary>
public class GraalFractalChannelStrategy : Strategy
{
private readonly StrategyParam<int> _channelPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevClose;
private decimal _prevMid;
private bool _hasPrev;
public int ChannelPeriod { get => _channelPeriod.Value; set => _channelPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public GraalFractalChannelStrategy()
{
_channelPeriod = Param(nameof(ChannelPeriod), 20)
.SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevClose = 0m; _prevMid = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var highest = new Highest { Length = ChannelPeriod };
var lowest = new Lowest { Length = ChannelPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal highest, decimal lowest)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
var mid = (highest + lowest) / 2;
if (!_hasPrev)
{
_prevClose = close;
_prevMid = mid;
_hasPrev = true;
return;
}
// Close crosses above midpoint = buy
if (_prevClose <= _prevMid && close > mid && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Close crosses below midpoint = sell
else if (_prevClose >= _prevMid && close < mid && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevClose = close;
_prevMid = mid;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class graal_fractal_channel_strategy(Strategy):
def __init__(self):
super(graal_fractal_channel_strategy, self).__init__()
self._channel_period = self.Param("ChannelPeriod", 20).SetDisplay("Channel Period", "Highest/Lowest lookback", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
@property
def channel_period(self): return self._channel_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(graal_fractal_channel_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_mid = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(graal_fractal_channel_strategy, self).OnStarted2(time)
self._has_prev = False
highest = Highest()
highest.Length = self.channel_period
lowest = Lowest()
lowest.Length = self.channel_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self.process_candle).Start()
def process_candle(self, candle, highest, lowest):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
mid = (float(highest) + float(lowest)) / 2.0
if not self._has_prev:
self._prev_close = close
self._prev_mid = mid
self._has_prev = True
return
if self._prev_close <= self._prev_mid and close > mid and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_close >= self._prev_mid and close < mid and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_close = close
self._prev_mid = mid
def CreateClone(self):
return graal_fractal_channel_strategy()