GitHub で見る
FXカオスピラミッド戦略
概要
FX カオス ピラミッドは、MQL/8055 にある MetaTrader 4「FX-CHAOS」エキスパート アドバイザーから変換されたマルチステージ ブレイクアウト戦略です。ポートは元のマルチタイムフレーム ロジックを保持します。プライマリ実行は 4 時間タイムフレームで発生し、日次タイムフレームはより高レベルのブレイクアウト フィルターを提供します。エントリーは、最初のステージが開かれる前に、Awesome Oscillator のモーメンタム フィルターで確認されます。トレンドが主な時間枠で継続するたびに、追加のステージが既存のポジションにピラミッド状に組み込まれます。
StockSharp 実装では、ローソク足サブスクリプション、インジケーター バインディング、ネイティブ注文ヘルパーを備えた高レベルの API を使用するため、この戦略は追加のインフラストラクチャ コードなしでバックテストとライブ取引の両方に使用できます。
取引ロジック
より高い時間枠フィルター
- 毎日のローソク足を購読し、5 ローソク足フラクタル検出器を使用して最後に確認されたジグザグ スイングを計算します。
- 前日の高値と安値を保存します。価格ステップの構成可能なバッファーは、ブレークアウト チェックが実行される前に両方のレベルに追加されます。
プライマリタイムフレーム実行
- 4 時間足のローソク足を購読し、Awesome Oscillator (デフォルトの 5/34 構成) をバインドします。
- オリジナルの
zzf カスタム インジケーターの類似物として、4 時間の時間枠で最新のフラクタル スイングを追跡します。
- 新しい取引日ごとに、最初の 4 時間足のローソク足の始値を記録します。この値は、MQL の
iOpen(NULL, 1440, 0) と同じ役割を果たします。
エントリールール
- 最初のロングステージ: 現在の日は緩衝された前日の日次高値を下回って始まり、4 時間足の終値はその緩衝されたレベルを上回り、価格は依然として最後の日次上昇フラクタルを下回ったままで、オーサムオシレーターはマイナスです。既存のショート ポジションはロングをオープンする前にクローズされます。
- 最初のショートステージ: 日々の安値とゼロを超えるオーサムオシレーターを備えたミラーロジック。
ピラミッドステージ
初期ステージが満たされた後、戦略は完了したすべての 4 時間足のローソク足を評価します。
- ロング追加は、ローソク足がバッファリングされた過去 4 時間の高値を下回って開始し、上で終了する一方で、終値が主要な時間枠の最後の上昇フラクタルの下に留まるときに配置されます。
- 短い追加では、バッファされた 4 時間の安値と最後の下向きフラクタルが使用されます。
- オプションの資本フィルター: さらなるステージは、ポートフォリオの資本が残高より大きい場合にのみ許可され、MQL エキスパートの
AccountEquity() > AccountBalance() 要件を再現します。
追加ステージの数は構成可能です (元のロット マトリックスに一致するために最大 5 つまで)。ポジションがクローズされるか、反転シグナルが反対側をクローズするとステージはリセットされます。
資金管理
オリジナルの専門家が口座残高に応じてロットマトリックスを調整します。このポートは同じ区分定義を保持し、基本バランス、バランス ステップ、およびグローバル ボリューム乗数をパラメータとして公開します。現在のポートフォリオの資産は MAX_Lots バケット (3.0 から 15.0 ロットの範囲) にマッピングされ、適切なロット ベクトルが選択されます。
MAX_Lots 範囲 |
ステージ1 |
ステージ2 |
ステージ3 |
ステージ4 |
ステージ5 |
| < 2 |
0.10 |
0.50 |
0.40 |
0.30 |
0.20 |
| [2、4) |
0.20 |
1.00 |
0.80 |
0.60 |
0.40 |
| [4、5) |
0.30 |
1.50 |
1.20 |
0.90 |
0.60 |
| [5、7) |
0.40 |
2.00 |
1.60 |
1.20 |
0.80 |
| [7、8) |
0.50 |
2.50 |
2.00 |
1.50 |
1.00 |
| [8、10) |
0.60 |
3.00 |
2.40 |
1.80 |
1.20 |
| [10、11) |
0.70 |
3.50 |
2.80 |
2.10 |
1.40 |
| [11、13) |
0.80 |
4.00 |
3.20 |
2.40 |
1.60 |
| [13、14) |
0.90 |
4.50 |
3.60 |
2.70 |
1.80 |
| ≥ 14 |
1.00 |
5.00 |
4.00 |
3.00 |
2.00 |
VolumeScale パラメータを乗算すると、同じ相対分布を異なるブローカーまたは資産クラスに適用できます。
パラメーター
| 名前 |
説明 |
| プライマリーキャンドル |
エントリーに使用される取引時間枠 (デフォルトは 4 時間)。 |
| デイリーキャンドル |
以前の高値/安値レベルを提供するより高い時間枠のローソク足 (デフォルトは 1 日)。 |
| AO 高速 / AO 低速 |
オーサムオシレーターの短期および長期。 |
| ブレイクアウトバッファ |
価格ステップのバッファーが以前の高値/安値に追加されます。 |
| 最大ステージ数 |
ピラミッド エントリの最大数 (1 ~ 5)。 |
| 利益が必要 |
資本が残高を超えた場合にのみ、追加のステージを許可します。 |
| ボリュームスケール |
選択したロット ベクトルに適用されるグローバル乗数。 |
| ベースバランス |
最小ロットベクトルに割り当てられる残高。 |
| バランスステップ |
次のベクトルに移動するバランス増分。 |
MQL4 エキスパートとの違い
- StockSharp バージョンは、直接の
iClose/iHigh 呼び出しの代わりに組み込みのキャンドル サブスクリプションを使用し、必要な価格レベルを内部に保存します。
- オリジナルの
zzf カスタム インジケーターは、5 つのローソク足のスイングを確認する軽量のフラクタル検出器を通じてエミュレートされます。
- ストップロスとテイクプロフィットの管理は含まれていません。オリジナルのエキスパートは動的に停止するように修正されましたが、アルゴリズムはブローカー固有の機能に大きく依存していました。トレーダーは、必要に応じて独自のリスク モジュールを追加できます。
- サウンド通知と端末グローバル変数は意図的に省略されています。
使用のヒント
- ロット マトリックスが MetaTrader とまったく同じように動作するように、残高と資本の両方をレポートするポートフォリオに戦略をアタッチします。
- バックテストを行う場合は、現実的な 4 時間および毎日の履歴データを使用します。解像度が混在すると、ピラミッド ロジックが低下します。
- 異なるティック サイズまたはスプレッドを使用する市場に切り替える場合は、
BreakoutBuffer パラメータを試してください。
- デバッグ時にチャートを有効にします。戦略は、ローソク足、オーサム オシレーター ヒストグラム、および実行された取引を自動的にプロットします。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class FxChaosPyramidStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
private int _cooldownRemaining;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FxChaosPyramidStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 20).SetDisplay("Fast WMA", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 80).SetDisplay("Slow WMA", "Slow WMA period", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 150).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = default;
_prevSlow = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var fast = new WeightedMovingAverage { Length = FastPeriod };
var slow = new WeightedMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(fast, slow, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev) { _prevFast = fast; _prevSlow = slow; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevFast = fast;
_prevSlow = slow;
}
}
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class fx_chaos_pyramid_strategy(Strategy):
def __init__(self):
super(fx_chaos_pyramid_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 20).SetDisplay("Fast WMA", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 80).SetDisplay("Slow WMA", "Slow WMA period", "Indicators")
self._cooldown_candles = self.Param("CooldownCandles", 150).SetDisplay("Cooldown", "Candles between signals", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._cooldown_remaining = 0
@property
def fast_period(self): return self._fast_period.Value
@property
def slow_period(self): return self._slow_period.Value
@property
def cooldown_candles(self): return self._cooldown_candles.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(fx_chaos_pyramid_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(fx_chaos_pyramid_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
self._cooldown_remaining = 0
fast = WeightedMovingAverage()
fast.Length = self.fast_period
slow = WeightedMovingAverage()
slow.Length = self.slow_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(fast, slow, self.process_candle).Start()
def process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast)
slow_val = float(slow)
if not self._has_prev:
self._prev_fast = fast_val
self._prev_slow = slow_val
self._has_prev = True
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._cooldown_remaining = self.cooldown_candles
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._cooldown_remaining = self.cooldown_candles
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return fx_chaos_pyramid_strategy()