GitHub で見る

MACD 1 MIN SCALPER戦略

この戦略はMetaTraderエキスパートアドバイザー "MACD 1 MIN SCALPER" のC#ポートです。トレードを開く前に加重移動平均、マルチタイムフレームMACDの確認、モメンタムフィルターを組み合わせます。目標は、低位・高位の時間軸のインジケーターが揃い、価格のモメンタムが十分に強い場合にトレンド方向で取引することです。

取引ロジック

  1. 基本時間軸 – 設定可能(デフォルトM1)。典型価格 (高値 + 安値 + 終値) / 3 を使って期間50と200の加重移動平均(WMA)2本が短期トレンドを定義します。
  2. 高位時間軸トレンドフィルター – H1時間軸で同じ期間のWMAを計算します。ロングセットアップは両方の高速WMAが低速WMAの上にあることを要求し、ショートはその逆を要求します。作業時間軸がすでにH1の場合、ベースWMAが再利用されます。
  3. MACD確認 – MACD(12、26、9)は基本時間軸、H1時間軸、月足時間軸(約43200分)でメインラインがシグナルラインを上回っている必要があります。ショートエントリーは3つすべてのMACDがシグナルを下回ることを要求します。
  4. モメンタムフィルター – MetaTraderの基本期間から派生した高位時間軸(M1→M15、M5→M30、…)で期間14のモメンタムインジケーターが動作します。100からの絶対偏差が最後の3つの完了バーの少なくとも1つで設定可能なしきい値を超える必要があります。
  5. エントリールール – すべての強気条件が満たされ、戦略が現在ロング露出を持たない場合にロングポジションが開かれます。ショートポジションは反転した弱気条件を必要とします。反対のポジションが開いている場合、注文サイズには自動的にそれを決済するために必要な数量が含まれます。
  6. リスク管理 – オプションのストップロスとテイクプロフィットの距離はピップで指定され、起動時に銘柄のポイントに変換されます。トレーリング、ブレイクイーブン、マネーマネジメント機能はこの高レベルポートでは意図的に省略されています。

パラメーター

パラメーター 説明
CandleType ベースインジケーターの作業時間軸。
OrderVolume 各市場エントリーで送信されるボリューム。ポジションの決済・反転にも使用。
FastMaPeriod / SlowMaPeriod 高速・低速加重移動平均の期間。
MacdFastPeriod / MacdSlowPeriod / MacdSignalPeriod MACDインジケーターに使用するEMA期間。
MomentumPeriod 確認時間軸でのモメンタムインジケーター期間。
MomentumThreshold モメンタムを受け入れるために必要な100からの最小絶対偏差。
TakeProfitPips / StopLossPips ピップで指定されるオプションの保護レベル。

実装上の注記

  • 戦略はStockSharpの高レベルローソク購読(SubscribeCandles)とインジケーターバインディング(Bind / BindEx)に依存します。手動のインジケーター計算や履歴バッファは使用されません。
  • モメンタムの時間軸はMetaTraderのマッピングから派生します:[1,5,15,30,60,240,1440,10080,43200]。値がこのリストに含まれない場合、ベース時間軸の4倍のフォールバックが使用されます。
  • StartProtection はリスクパラメーターの少なくとも1つがゼロより大きい場合にのみ起動されます。このポートにはトレーリングストップの実装はありません。
  • デバッグ中やライブ取引中の視覚的な検査を容易にするために、ベースローソク、両WMA、MACDのチャートレンダリングが有効になっています。

使用上のヒント

  • 銘柄の最小ロットサイズに応じて OrderVolume パラメーターを設定します。ヘルパーは自動的に送信されるボリュームをシンボルのステップとmin/max制約に合わせて調整します。
  • データフィードで高位時間軸のデータ(H1と月足)が利用可能であることを確認してください。これらのローソクがないと、確認シグナルが不完全なままになるため戦略はポジションを開きません。
  • モメンタムフィルタリングは選択したしきい値に敏感です。高い値は強いモメンタムの急上昇を要求し、低い値はより頻繁な取引につながります。
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 Macd1MinScalperStrategy : 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 Macd1MinScalperStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12).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;
	}
}