GitHub で見る

Martingale MA ブレイクアウト戦略 (ID 2861)

概要

Martingale MA ブレイクアウト戦略は、MetaTrader 5のオリジナルエキスパートアドバイザーMartingale.mq5の移植版です。より高いタイムフレームでプロットされた移動平均から現在の価格がどれだけ離れているかを監視します。距離が設定可能なpips数を超えると、戦略は動きの方向に新しいポジションを開き、固定のストップロス、テイクプロフィット、トレーリングロジックで管理します。ポジションサイズは損失シークエンス後に取引サイズを増加させ、利益期間後に削減するマーチンゲールスタイルの調整に従います。

デフォルトでは戦略は6分ローソク足を評価しますが、周辺のプラットフォームは任意のベースタイムフレームで動作できます。すべてのインジケーター計算は選択されたローソク足タイプで実行され、注文は成行実行を使用して送信されます。

トレードロジック

  1. 選択された平滑化方法、適用価格、シフトを使用して現在のローソク足の移動平均値を計算します。
  2. 設定されたpips距離を絶対価格デルタに変換します。ピップサイズはオリジナルのMQLチューニングを複製します:3または5桁の小数点を持つシンボルは価格ステップに10を掛けます。
  3. ローソク足が閉じたとき:
    • 終値がシフトされた移動平均よりDistanceFromMaPips pips以上上にあり、アクティブなロング露出がない場合、市場買い注文を送信します。
    • 終値がシフトされた移動平均よりDistanceFromMaPips pips以上下にあり、アクティブなショート露出がない場合、市場売り注文を送信します。
  4. 完成した各ローソク足もトレーリングストップを更新し、終値がシミュレートされたストップロスまたはテイクプロフィットに違反するかどうかを確認します。ポジションを閉じるとResetTradeStateがトリガーされ、保存されたすべてのレベルがクリアされます。

資金管理

  • RiskPercentPortfolio.CurrentValue(取引が行われていない場合はBeginValue)を使用して金銭的リスク予算に変換します。ストップロスが指定されている場合、予算をストップ距離とセキュリティ乗数で割ることで最大手頃なボリュームを推定します。
  • リスクによるサイジング後、ボリュームはApplyMartingaleを通過します:最後に記録された残高(前回のエントリー後に取得)が現在の残高より高い場合、ボリュームは1単位増加します;低い場合、ボリュームは1単位減少しますが、戦略のベースボリューム以下には決してなりません。
  • トレーリングロジックはオリジナルEAを模倣します:価格がポジションの有利な方向にTrailingStopPips + TrailingStepPips動くと、ストップがTrailingStopPipsオフセットを維持するように引き寄せられます。戦略はトレーリングが有効なときにTrailingStepPipsがゼロでないことを検証し、MQLのエラー処理を反映します。

パラメーター

パラメーター 説明
StopLossPips pipsで表されるストップロス距離。ゼロの値はストップとリスクベースのサイジングを無効化します。
TakeProfitPips pipsでのテイクプロフィット距離。無効にするにはゼロ。
TrailingStopPips pipsでのトレーリングストップオフセット。TrailingStepPipsと組み合わせる必要があります。
TrailingStepPips トレーリングストップが進む前に必要な追加価格移動。トレーリングがアクティブな場合はゼロにできません。
DistanceFromMaPips エントリーをトリガーする価格とシフトされた移動平均の間の最小距離。
CandleType インジケーター計算のデータタイプ(デフォルト6分タイムフレーム)。
MaPeriod 移動平均の期間。
MaShift 移動平均が前方にシフトされるバーの数。戦略はMQLの動作をエミュレートするために履歴MA値を保存します。
MaMethod 移動平均の平滑化タイプ:単純、指数、平滑化、または加重。
MaAppliedPrice 移動平均に使用されるローソク足価格(終値、始値、高値、安値、中値、典型的または加重)。
RiskPercent ストップロスリスク予算に割り当てられた現在の資本のパーセンテージ。

実行上の注意

  • 戦略はオリジナルEAの「新しいバー」処理を複製するために完成したローソク足のみで動作します。BuyMarket/SellMarketは反対ポジションの絶対値を加算することで既存の露出を転換します。
  • この変換ではStockSharpが自動的にストップとターゲットを管理しないため、ストップとターゲットはコードでシミュレートされます。終値はティックレベルの実行のプロキシとして使用されます。
  • マーチンゲール調整は各エントリー直後に取得されたアカウント残高スナップショットで動作し、ソースEAと同様です。
  • シンボルに有効な価格ステップや乗数がない場合、除算エラーを避けるために0.00011のデフォルト値が使用されます。

オリジナルEAとの相違点

  • MQLバージョンはbid/ask価格を使用していました;このポートは高レベルAPIでは高周波ティックが利用できないため、ローソク足の終値を使用します。
  • ボリュームのサイジングはCMoneyFixedMarginヘルパーの代わりにポートフォリオの資本とセキュリティ乗数に依存します。
  • チャートビジュアライゼーションはオプションです:チャートエリアが利用可能な場合、戦略はローソク足を描画します;デフォルトでは追加のインジケーターはプロットされません。
  • トレーリングが有効なときにTrailingStepPipsが正でなければならないという検証は、Alertを呼び出す代わりに起動時に例外をスローします。
namespace StockSharp.Samples.Strategies;

using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Martingale MA Breakout strategy (simplified).
/// Enters long when price crosses above EMA, enters short when below.
/// Uses simple position flipping with market orders.
/// </summary>
public class MartingaleMaBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<int> _atrPeriod;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public int AtrPeriod
	{
		get => _atrPeriod.Value;
		set => _atrPeriod.Value = value;
	}

	public MartingaleMaBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Source candles", "General");

		_maPeriod = Param(nameof(MaPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Moving average period", "Indicators");

		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period for volatility filter", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ema = new ExponentialMovingAverage { Length = MaPeriod };
		var atr = new AverageTrueRange { Length = AtrPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, atr, (ICandleMessage candle, decimal emaValue, decimal atrValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var distance = Math.Abs(candle.ClosePrice - emaValue);

				// Buy when price breaks above MA by at least half ATR
				if (candle.ClosePrice > emaValue && distance > atrValue && Position <= 0)
				{
					BuyMarket();
				}
				// Sell when price breaks below MA by at least half ATR
				else if (candle.ClosePrice < emaValue && distance > atrValue && Position >= 0)
				{
					SellMarket();
				}
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, ema);
			DrawIndicator(area, atr);
			DrawOwnTrades(area);
		}
	}
}