GitHub で見る

Fractals Martingale戦略

このフォルダーには、MetaTraderのエキスパートアドバイザー「Fractals Martingale」のStockSharp移植版が含まれています。戦略はBill Williamsのフラクタル、Ichimokuベースのトレンドフィルター、月次MACD確認を組み合わせています。ポジションサイジングは、毎回の負けサイクル後に取引ボリュームを乗算するクラシックなマーティンゲールシーケンスに従い、オプションのクールダウンが暴走したエクスポージャーを防ぎます。

トレーディングロジック

  1. 作業タイムフレームでのフラクタル検出 – 完成したローソク足はFractalDepthの隣接バーで区切られたローカル高値と安値を検出するためにバッファリングされます。次のローソク足がフラクタル高値の上で始値をつけると強気のセットアップが登録され、弱気のセットアップはフラクタル安値の下で始値をつけることを必要とします。検出されたレベルはFractalLookbackの処理されたローソク足の間有効のままです。
  2. Ichimokuトレンドフィルター – フラクタルはIchimokuCandleTypeで定義された高い時間軸で計算されたIchimokuトレンドと一致する必要があります。ロングトレードはTenkan-senがKijun-senを上回ることを要求し、ショートトレードはTenkan-senがKijun-senを下回ることを要求します。
  3. 月次MACD確認 – 元のEAは買い手か売り手かを決定するために月次MACDを使用していました。移植版はMACDラインがシグナルラインの上にある場合のみロングシグナルを受け入れるMacdCandleTypeシリーズ(デフォルトは30日足)を購読します。ショートシグナルは反対の条件が必要です。
  4. セッションフィルター – 注文はStartHour(含む)とEndHour(含まない)の間にのみ配置されます。翌日夜間の取引セッション用のラップアラウンドウィンドウがサポートされています。
  5. マーティンゲールボリュームスケーリング – ベース注文サイズはTradeVolumeから来ます。負けラウンドごとに、次の注文ボリュームはMultiplierで乗算されてインストゥルメントのボリュームステップに合わせられます。勝ちトレードはシーケンスをリセットします。MaxConsecutiveLossesを超えると、アルゴリズムはベースボリュームで再開する前にPauseMinutes停止します。
  6. 方向切り替え – 新しいトレードが送信されるたびに、戦略は要求された方向にエクスポージャーを開く前に自動的に反対のポジションをオフセットします。

リスク管理

  • StopLossPipsTakeProfitPipsは検出されたpipサイズを使用して絶対価格距離に変換され、StartProtectionを通じて適用されます。これは両方のストップがpipで定義されていた元のEAを反映しています。
  • 元の実装はオプションのマネーベースのトレーリングストップを公開していました。StockSharp移植版は実際のポートフォリオ通貨処理がブローカー固有であるため、組み込みの保護ブロックに依存します。

パラメーター

パラメーター 説明
TradeVolume シーケンスの最初のエントリーに使用するベース注文サイズ。
Multiplier 損失後に次の取引ボリュームに適用される係数。
StopLossPips, TakeProfitPips pipで測定した保護ストップとターゲット距離。
FractalDepth フラクタル高値/安値を確認するために各側に必要なローソク足の数。
FractalLookback 検出されたフラクタルが有効のままとなる最大処理ローソク足数。
StartHour, EndHour 取引所の時間で表した取引ウィンドウ。両方の値が一致するとフィルターは無効になります。
MaxConsecutiveLosses 戦略が停止する前の負けトレードの数。
PauseMinutes 損失上限を超えた後に有効になるクールダウン期間の長さ。
TenkanPeriod, KijunPeriod, SenkouPeriod 高い時間軸で使用するIchimoku Kinko Hyoの長さ。
MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod 高い時間軸のMACD確認のEMA長さ。
CandleType フラクタルと実行が評価されるプライマリローソク足シリーズ。
IchimokuCandleType TenkanとKijunラインの計算に使用する高い時間軸。
MacdCandleType MACDフィルターの計算に使用するタイムフレーム(デフォルトは月次)。

使用上の注意

  1. pip計算 – pip値はSecurity.PriceStepから導出されます。5桁のフォレックス相場はソースEAで使用されるMetaTrader定義に合わせるために自動的にスケーリングされます。
  2. インジケーターサブスクリプション – 戦略は最大3つのローソク足シリーズを使用します。フィルターを同期させるために、データフィードが要求されたすべてのタイムフレームを供給できることを確認してください。
  3. マーティンゲールの注意事項 – ボリュームを倍にするとエクスポージャーが急速に増加します。口座が長期の負け連続に耐えられない場合は、クールダウンパラメーターを使用するか乗数を下げてください。
  4. MT4 EAとの違い – メール/通知アラート、残高ベースのトレーリングストップ、明示的なマージンチェックは、StockSharpがすでに接続性、ポートフォリオの安全性、注文実行を処理するため削除されました。コアのエントリー/エグジットロジックはMQL実装と一致します。

ファイル

  • CS/FractalsMartingaleStrategy.cs – 高水準Strategy APIを使用したC#実装。
  • README.md – 英語ドキュメント(このファイル)。
  • README_zh.md – 簡体字中国語翻訳。
  • README_ru.md – ロシア語翻訳。
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 FractalsMartingaleStrategy : 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 FractalsMartingaleStrategy()
	{
		_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;
	}
}