GitHub で見る

Cs2011戦略

概要

Cs2011 戦略は、オリジナルの cs2011.mq5 エキスパート アドバイザーから翻訳されたリバーサル システムです。これは、完成したすべてのローソク足の MACD ヒストグラムとシグナル ラインを監視し、ゼロ ライン付近の枯渇パターンを検索します。 C# ポートは、コア タイミング ルールを維持しながら、高レベルの StockSharp API を通じて公開します。

取引ロジック

  • ゼロライン反転 – 前のバーの MACD 値がゼロを超え、その前のバーがゼロ未満の場合、ストラテジーは ショート シグナルを発行します。逆の遷移 (正から負へ) は 長い 信号を発行します。これは、MQL5 スクリプトに実装された逆張りエントリを模倣しています。
  • 信号線の極値 – この戦略は、最後の 3 つの信号線の読み取り値を保存します。 MACD が負の状態にある間に極大値が発生すると、追加のショート エントリがトリガーされます。 MACD が正の状態にある間の極小値はロングエントリーをトリガーします。これにより、ソース EA 内の Sig[0]Sig[1]、および Sig[2] に基づいてパターン チェックが再現されます。
  • シグナルは、SubscribeCandles によって提供される完成したローソク足でのみ評価されるため、部分的なデータは無視されます。

ポジションの扱い

  • この戦略は 固定絶対ポジション サイズ (TargetVolume) をターゲットとしています。強気シグナルが到着すると、+TargetVolume に到達するのに十分な契約を購入します。弱気シグナルは -TargetVolume に対しても同様です。同じ方向の既存のエクスポージャが尊重されます。目標がすでに達成されている場合、追加の注文は出されません。
  • StartProtection は、元のテイクプロフィットとストップロスの設定を反映します。ポイント距離は UnitTypes.Point 値に変換され、組み込みのリスク モジュールに渡されます。どちらかの値を 0 のままにすると、対応するバリアが無効になります。
  • MQL バージョンの低レベルのリクエスト構造の代わりに、高レベルのヘルパー (BuyMarketSellMarket) が使用されます。

パラメーター

名前 デフォルト 説明
TargetVolume 1ロット 信号後に達成される絶対位置サイズ。 EA の Risk × バランス サイジング ルーチンを置き換えます。
TakeProfitPoints 2200 利益確定管理の価格ポイントの距離。 0 はテイクプロフィットを無効にします。
StopLossPoints 0 ストップロスの価格ポイントの距離。 0 はストップロスを無効にし、EA のデフォルトと一致します。
FastEmaPeriod 30 MACD コアの高速な EMA の長さ。
SlowEmaPeriod 500 MACD の EMA の長さが遅いです。
SignalPeriod 36 信号線平滑化期間。
CandleType 1 hour 時間枠 SubscribeCandlesが使用するキャンドルソース。 MetaTrader で使用されているチャート期間と一致するようにこれを調整します。

すべてのパラメータは Param() を通じて登録されるため、StockSharp オプティマイザー UI 内で最適化できます。

MQL5 バージョンとの違い

  • 資金管理ルーチン (Money_M) は、過去の取引と MetaTrader の口座残高に依存していました。 StockSharp 戦略はブローカーに依存しないポートフォリオで動作するため、ポートは単純な TargetVolume パラメータを公開します。ユーザーは、パラメータ値または ExecuteSignals メソッドをオーバーライドすることで、独自の資金管理を接続できます。
  • 注文リクエストは単一市場注文に簡略化されます。再試行ロジック、スプレッドベースの逸脱、取引コンテキストのチェックは、StockSharp インフラストラクチャによって処理されます。
  • この戦略は、カスタム IsNewBar ヘルパーではなく、キャンドル サブスクリプションで実行されます。これにより、完全に形成されたキャンドルのみが処理されることが保証されます。

使用上の注意

  1. 戦略を開始する前に、証券、ポートフォリオ、ローソクの種類を設定します。
  2. 希望の公称ロットサイズに合わせて TargetVolume を調整します。
  3. 必要に応じて、TakeProfitPointsStopLossPoints を調整して、元の EA の保護レベルを再現します。
  4. 戦略を開始します – ログメッセージは、ターゲットを絞ったエクスポージャーとともにすべての取引トリガーを記録します。

コードには、移植プロセスの各ステップを説明する英語のインライン コメントが含まれています。


namespace StockSharp.Samples.Strategies;

using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

/// <summary>
/// MACD based reversal strategy converted from the original cs2011 MetaTrader 5 expert advisor.
/// It reacts to zero line crosses and local extremes of the MACD signal line.
/// </summary>
public class Cs2011Strategy : Strategy
{
	private readonly StrategyParam<decimal> _targetVolume;
	private readonly StrategyParam<int> _takeProfitPoints;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _macdPrev1;
	private decimal? _macdPrev2;
	private decimal? _signalPrev1;
	private decimal? _signalPrev2;
	private decimal? _signalPrev3;

	/// <summary>
	/// Target absolute position in lots when a bullish signal appears.
	/// </summary>
	public decimal TargetVolume
	{
		get => _targetVolume.Value;
		set => _targetVolume.Value = value;
	}

	/// <summary>
	/// Take-profit distance expressed in instrument points.
	/// </summary>
	public int TakeProfitPoints
	{
		get => _takeProfitPoints.Value;
		set => _takeProfitPoints.Value = value;
	}

	/// <summary>
	/// Stop-loss distance expressed in instrument points.
	/// </summary>
	public int StopLossPoints
	{
		get => _stopLossPoints.Value;
		set => _stopLossPoints.Value = value;
	}

	/// <summary>
	/// Fast EMA length used in MACD calculation.
	/// </summary>
	public int FastEmaPeriod
	{
		get => _fastEmaPeriod.Value;
		set => _fastEmaPeriod.Value = value;
	}

	/// <summary>
	/// Slow EMA length used in MACD calculation.
	/// </summary>
	public int SlowEmaPeriod
	{
		get => _slowEmaPeriod.Value;
		set => _slowEmaPeriod.Value = value;
	}

	/// <summary>
	/// Period of the MACD signal line.
	/// </summary>
	public int SignalPeriod
	{
		get => _signalPeriod.Value;
		set => _signalPeriod.Value = value;
	}

	/// <summary>
	/// Candle type used for indicator calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initialize strategy parameters with defaults close to the original expert.
	/// </summary>
	public Cs2011Strategy()
	{
		_targetVolume = Param(nameof(TargetVolume), 1m)
			.SetDisplay("Target Volume", "Absolute position size targeted on entries", "Risk")
			
			.SetOptimize(0.5m, 3m, 0.5m);

		_takeProfitPoints = Param(nameof(TakeProfitPoints), 2200)
			.SetDisplay("Take Profit (points)", "Take-profit distance in price points", "Risk")
			
			.SetOptimize(200, 4000, 200);

		_stopLossPoints = Param(nameof(StopLossPoints), 0)
			.SetDisplay("Stop Loss (points)", "Stop-loss distance in price points", "Risk")
			
			.SetOptimize(0, 2000, 200);

		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 30)
			.SetDisplay("Fast EMA", "Fast EMA period for MACD", "Indicators")
			
			.SetOptimize(10, 60, 5);

		_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 50)
			.SetDisplay("Slow EMA", "Slow EMA period for MACD", "Indicators")
			
			.SetOptimize(200, 700, 20);

		_signalPeriod = Param(nameof(SignalPeriod), 36)
			.SetDisplay("Signal Period", "Signal line period for MACD", "Indicators")
			
			.SetOptimize(10, 60, 5);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Source timeframe for MACD", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_macdPrev1 = null;
		_macdPrev2 = null;
		_signalPrev1 = null;
		_signalPrev2 = null;
		_signalPrev3 = null;
	}

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

		Volume = TargetVolume;

		var macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = FastEmaPeriod },
				LongMa = { Length = SlowEmaPeriod }
			},
			SignalMa = { Length = SignalPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(macd, ProcessCandle)
			.Start();

		var chartArea = CreateChartArea();
		if (chartArea != null)
		{
			DrawCandles(chartArea, subscription);
			DrawIndicator(chartArea, macd);
			DrawOwnTrades(chartArea);
		}

		// removed StartProtection
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue indicatorValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (indicatorValue is not IMovingAverageConvergenceDivergenceSignalValue macdValue)
			return;

		if (macdValue.Macd is not decimal macd || macdValue.Signal is not decimal signal)
			return;

		var prevMacd1 = _macdPrev1;
		var prevMacd2 = _macdPrev2;
		var prevSignal1 = _signalPrev1;
		var prevSignal2 = _signalPrev2;
		var prevSignal3 = _signalPrev3;

		var upSignal = false;
		var downSignal = false;

		if (prevMacd1.HasValue && prevMacd2.HasValue)
		{
			if (prevMacd1 > 0m && prevMacd2 < 0m)
				downSignal = true;

			if (prevMacd1 < 0m && prevMacd2 > 0m)
				upSignal = true;
		}

		if (prevMacd2.HasValue && prevSignal1.HasValue && prevSignal2.HasValue && prevSignal3.HasValue)
		{
			if (prevMacd2 < 0m && prevSignal1 < prevSignal2 && prevSignal2 > prevSignal3)
				downSignal = true;

			if (prevMacd2 > 0m && prevSignal1 > prevSignal2 && prevSignal2 < prevSignal3)
				upSignal = true;
		}

		if (upSignal || downSignal)
			ExecuteSignals(upSignal, downSignal);

		_macdPrev2 = _macdPrev1;
		_macdPrev1 = macd;
		_signalPrev3 = _signalPrev2;
		_signalPrev2 = _signalPrev1;
		_signalPrev1 = signal;
	}

	private void ExecuteSignals(bool upSignal, bool downSignal)
	{
		// removed IsFormedAndOnlineAndAllowTrading guard

		if (upSignal)
		{
			var targetPosition = TargetVolume;
			var difference = targetPosition - Position;
			if (difference > 0m)
			{
				BuyMarket(difference);
				LogInfo($"Buy signal executed. Target={targetPosition:F2}, current position after order={Position + difference:F2}");
			}
		}

		if (downSignal)
		{
			var targetPosition = -TargetVolume;
			var difference = targetPosition - Position;
			if (difference < 0m)
			{
				SellMarket(-difference);
				LogInfo($"Sell signal executed. Target={targetPosition:F2}, current position after order={Position - difference:F2}");
			}
		}
	}
}