GitHub で見る

Accelerator Trailing TP & SL戦略

概要

Accelerator Trailing TP & SL戦略は、MetaTraderの「Accelerator Trailing TP&SL」エキスパートアドバイザーをStockSharpの高レベルAPIにポートします。このシステムはビル・ウィリアムズのAcceleratorオシレーターをマルチタイムフレームのモメンタム確認と月次MACDトレンドフィルターと組み合わせます。エントリーは幾何学的なポジションサイジングで積み上げられ、出口は古典的なストップ/ターゲット距離、適応型トレーリング、ブレイクイーブンロジックを組み合わせます。

トレードロジック

  • モメンタムフィルター – 上位時間軸で計算された14期間のモメンタムインジケーターが、直近3つの確定バーのいずれかで中性の100レベルから少なくとも設定された閾値だけ偏差している必要があります。
  • Acceleratorオシレーター – ロング取引はシグナル時間軸でポジティブなAccelerator読み取りを、ショート取引はネガティブな読み取りを必要とします。
  • 移動平均 – 速い線形加重移動平均(LWMA)はロングでは遅いLWMAの上、ショートでは下にある必要があり、元の速い/遅いトレンドフィルターを近似します。
  • 月次MACDトレンド – デフォルトではフィルターは月次ロウソク足を観察します。ロング取引はMACD線がシグナル線の上にあることを要求します(両方の値が負の場合でも)、ショート取引は逆の条件を必要とします。
  • 段階的エントリー – 戦略はディレクションごとに設定された最大ポジション数までピラミッドできます。各追加エントリーはロットエクスポーネントで乗算され、MQLプログラムで使用されるマーチンゲールスタイルのサイジングを再現します。

リスク管理

  • 静的ストップロス/テイクプロフィット – pip距離は元のStop LossとTake Profit設定を反映します。
  • トレーリングストップ – 有効化されると、戦略は設定されたpip数で最も有利な価格を追跡します。
  • ブレイクイーブン移動 – 取引がトリガー距離に達した後、ストップが指定されたオフセット分だけ前進し、累積した利益を保護します。
  • MACD出口 – MACDフィルターがアクティブなポジションに反転した場合、戦略は直ちにすべてのポジションを閉じることができ、MQLコードの手動出口ヘルパーに対応します。

パラメーター

パラメーター 説明
FastMaLength / SlowMaLength 取引時間軸における速いLWMAと遅いLWMAの期間。
MomentumThreshold 上位時間軸でのモメンタムの中性100値からの最小絶対偏差。
StopLossPips / TakeProfitPips pip単位の保護ストップとターゲット距離。
TrailingStopPips オプションのトレーリングストップマネージャーが使用する距離。
BreakEvenTriggerPips / BreakEvenOffsetPips ストップをブレイクイーブンに移動する時期と方法を定義します。
MaxTrades ディレクションごとの段階的エントリーの最大数。
BaseVolume シーケンスの最初の注文のボリューム。
LotExponent 各追加段階的エントリーに適用される乗数。
EnableTrailing トレーリングストップ管理を有効/無効にします。
UseBreakEven ブレイクイーブンストップ移動を有効/無効にします。
CloseOnMacdFlip 上位時間軸のMACDが反転した場合、すべての取引を閉じます。
CandleType シグナル用の主要ロウソク足シリーズ(デフォルト:15分)。
MomentumCandleType モメンタムフィルターに使用する上位時間軸ロウソク足(デフォルト:1時間)。
MacdCandleType MACDトレンドフィルターに使用するロウソク足シリーズ(デフォルト:月次ロウソク足)。

注意事項

  • 戦略はpipベースのリスク設定を価格距離に変換するために楽器の PriceStep に依存します。戦略を実行する際に証券メタデータが入力されていることを確認してください。
  • StockSharpはネットポジションを使用するため、追加の段階的エントリーは設定された最大値に達するまで成行注文を繰り返し送信することで開かれます。出口はすべてのネットポジションを閉じ、元のエキスパートの「すべて閉じる」ルーティンに対応します。
  • 月次MACDの時間軸は MacdCandleType パラメーターを通じて、異なる楽器やバックテストに合わせて調整できます。
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 AcceleratorTrailingTPSLStrategy : 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 AcceleratorTrailingTPSLStrategy()
	{
		_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;
	}
}