GitHub で見る

マックバリューのクラウド戦略

このフォルダには、MetaTrader エキスパート アドバイザー「Mc_valute」の StockSharp ポートが含まれています。ショート丈を組み合わせたオリジナルロボット 3 つの平滑化移動平均、Ichimoku クラウド フィルター、および複数の MACD インスタンスを含む指数移動平均 (EMA) トレンドにスケーリングします。 StockSharp の実装は、コアのトレンド確認スタックを維持しながら、ポジション管理を簡素化します ロジックが高レベルの API に自然に適合するように、各方向で単一の露出に対応します。

取引ロジック

  1. 価格フィルター EMAFilterMaLength EMA は、2 つの滑らかな動きの上(ロングの場合)または下(ショートの場合)に配置する必要があります 平均 (BlueMaLengthLimeMaLength)。平滑化された平均は、MT4 テンプレートの「青」と「ライム」の線をエミュレートします。
  2. Ichimoku クラウドの確認 – EMA もクラウドの外にある必要があります。ロングトレードには両方の上にフィルター EMA が必要です センコウはスパンですが、ショートトレードでは雲底を下回ることが要求されます。
  3. MACD の勢いチェック – メインの MACD ラインは、ロングエントリーの場合はシグナルラインより上にあり、ショートエントリーの場合はシグナルラインより下にある必要があります。 残りのコピーは最終的な MQL バージョンで無効になっているため、元の EA の最初の MACD セットのみが保持されます。
  4. 単一ポジション管理 – 新しいシグナルが現れるたびに、戦略は既存の反対ポジションを相殺し、ポジションをオープンします。 設定された Volume との新たな取引。保護注文は成行注文が送信された直後に更新されます。
  5. ローソクごとの評価 – すべてのインジケーターは、CandleType で定義された時間枠で動作します。取引に関する決定が下される 閉じたバーを処理した MT4 start() ハンドラーをミラーリングするために、終了したローソク足でのみ使用します。

リスク管理

  • TakeProfitStopLoss は価格ポイントで測定されます。各エントリの後に、ヘルパー SetTakeProfitSetStopLoss 関数は、予想される結果のポジションサイズを使用して呼び出されます。これは、ストップが適用されたMT4の動作を反映しています。 チケット。
  • 元のエキスパートアドバイザーは、Step の距離を使用して、最大 3 つの追加注文をピラミッド化しました。 StockSharp ポートは 上位レベルのオーダーヘルパー内に留まる単一のポジション。スケーリングが必要なユーザーは、Volume を増やすか、クローンを作成できます。 複数のポートフォリオにわたる戦略。

パラメーター

パラメータ 説明
Volume 高レベルの BuyMarket/SellMarket 呼び出しで使用される基本取引サイズ。
CandleType インジケーターとトレードロジックを動かす主要なローソク足シリーズ。
FilterMaLength EMA トレンド フィルターの長さ。
BlueMaLength, LimeMaLength 方向性バンドとして機能する 2 つの平滑化移動平均の長さ。
MacdFastLength, MacdSlowLength, MacdSignalLength MACD 確認の EMA の長さ。
TenkanLength, KijunLength, SenkouLength Ichimoku クラウドフィルターのKinko Hyo設定。
TakeProfit, StopLoss 保護距離は価格で表されます。

使用上の注意

  1. インジケーター シフト – MetaTrader では、平滑化移動平均を作成するときにゼロ以外の「シフト」パラメーターが許可されました。 StockSharpさん インジケーターは現在のバーで動作するため、ポートは元の期間を維持しながらこれらのシフトを無視します。
  2. MACD のバリアント – ソース コードでは 3 つの MACD ブロックが宣言されていますが、ライブ信号に参加するのは最初のブロックのみです。港 その行動に従います。追加の MACD フィルターは、インジケーター バインディングを複製することで再度有効にすることができます。
  3. 取引のスケーリング – MT4 ロボットは、Step ポイントで区切られた最大 3 つの平均注文を送信しました。この動作は文書化されています ただし、高レベルの戦略は単一の集約されたポジションで機能するため、意図的に省略されています。
  4. 保護ブロックStartProtection() は起動時に 1 回呼び出され、組み込みインフラストラクチャが停止を監視します。 再接続後も注文をターゲットにします。

ファイル

  • CS/McValuteCloudStrategy.cs – インジケーター バインディングと詳細を備えた高レベルの戦略 API を使用した C# 実装 コメント。
  • README.md – 英語のドキュメント (このファイル)。
  • README_zh.md – 簡体字中国語翻訳。
  • README_ru.md – ロシア語の翻訳。
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;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trend-following strategy inspired by the "Mc_valute" MetaTrader expert advisor.
/// Combines smoothed moving averages, an Ichimoku cloud filter and a MACD confirmation.
/// </summary>
public class McValuteCloudStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _filterMaLength;
	private readonly StrategyParam<int> _blueMaLength;
	private readonly StrategyParam<int> _limeMaLength;
	private readonly StrategyParam<int> _macdFastLength;
	private readonly StrategyParam<int> _macdSlowLength;
	private readonly StrategyParam<int> _macdSignalLength;
	private readonly StrategyParam<int> _tenkanLength;
	private readonly StrategyParam<int> _kijunLength;
	private readonly StrategyParam<int> _senkouLength;
	private readonly StrategyParam<int> _takeProfit;
	private readonly StrategyParam<int> _stopLoss;

	private ExponentialMovingAverage _filterMa;
	private SmoothedMovingAverage _blueMa;
	private SmoothedMovingAverage _limeMa;
	private MovingAverageConvergenceDivergenceSignal _macd;
	private Ichimoku _ichimoku;

	private decimal? _filterValue;
	private decimal? _blueValue;
	private decimal? _limeValue;
	private decimal? _senkouAValue;
	private decimal? _senkouBValue;
	private decimal? _macdMainValue;
	private decimal? _macdSignalValue;

	private DateTimeOffset _lastProcessedTime;

	/// <summary>
	/// Initializes a new instance of the <see cref="McValuteCloudStrategy"/> class.
	/// </summary>
	public McValuteCloudStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
		.SetDisplay("Candle Type", "Primary timeframe used for signals", "General");

		_filterMaLength = Param(nameof(FilterMaLength), 3)
		.SetDisplay("Filter EMA", "Length of the trend filter EMA", "Trend")
		
		.SetOptimize(2, 20, 1);

		_blueMaLength = Param(nameof(BlueMaLength), 13)
		.SetDisplay("Blue SMMA", "Length of the slower smoothed MA", "Trend")
		
		.SetOptimize(5, 60, 1);

		_limeMaLength = Param(nameof(LimeMaLength), 5)
		.SetDisplay("Lime SMMA", "Length of the faster smoothed MA", "Trend")
		
		.SetOptimize(3, 40, 1);

		_macdFastLength = Param(nameof(MacdFastLength), 12)
		.SetDisplay("MACD Fast", "Short EMA length for the MACD", "Momentum")
		
		.SetOptimize(5, 30, 1);

		_macdSlowLength = Param(nameof(MacdSlowLength), 26)
		.SetDisplay("MACD Slow", "Long EMA length for the MACD", "Momentum")
		
		.SetOptimize(10, 80, 1);

		_macdSignalLength = Param(nameof(MacdSignalLength), 9)
		.SetDisplay("MACD Signal", "Signal EMA length for the MACD", "Momentum")
		
		.SetOptimize(3, 30, 1);

		_tenkanLength = Param(nameof(TenkanLength), 12)
		.SetDisplay("Tenkan", "Tenkan-sen length for the Ichimoku cloud", "Ichimoku")
		
		.SetOptimize(5, 30, 1);

		_kijunLength = Param(nameof(KijunLength), 20)
		.SetDisplay("Kijun", "Kijun-sen length for the Ichimoku cloud", "Ichimoku")
		
		.SetOptimize(10, 60, 1);

		_senkouLength = Param(nameof(SenkouLength), 40)
		.SetDisplay("Senkou Span B", "Span B length for the Ichimoku cloud", "Ichimoku")
		
		.SetOptimize(20, 120, 1);

		_takeProfit = Param(nameof(TakeProfit), 30)
		.SetDisplay("Take Profit", "Take profit distance in points", "Risk")
		
		.SetOptimize(10, 200, 5);

		_stopLoss = Param(nameof(StopLoss), 350)
		.SetDisplay("Stop Loss", "Stop loss distance in points", "Risk")
		
		.SetOptimize(50, 600, 10);

		_lastProcessedTime = DateTimeOffset.MinValue;
	}

	/// <summary>
	/// Timeframe used for the working candles.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Length of the EMA filter.
	/// </summary>
	public int FilterMaLength
	{
		get => _filterMaLength.Value;
		set => _filterMaLength.Value = value;
	}

	/// <summary>
	/// Length of the slower smoothed moving average.
	/// </summary>
	public int BlueMaLength
	{
		get => _blueMaLength.Value;
		set => _blueMaLength.Value = value;
	}

	/// <summary>
	/// Length of the faster smoothed moving average.
	/// </summary>
	public int LimeMaLength
	{
		get => _limeMaLength.Value;
		set => _limeMaLength.Value = value;
	}

	/// <summary>
	/// Fast EMA length used by the MACD.
	/// </summary>
	public int MacdFastLength
	{
		get => _macdFastLength.Value;
		set => _macdFastLength.Value = value;
	}

	/// <summary>
	/// Slow EMA length used by the MACD.
	/// </summary>
	public int MacdSlowLength
	{
		get => _macdSlowLength.Value;
		set => _macdSlowLength.Value = value;
	}

	/// <summary>
	/// Signal EMA length used by the MACD.
	/// </summary>
	public int MacdSignalLength
	{
		get => _macdSignalLength.Value;
		set => _macdSignalLength.Value = value;
	}

	/// <summary>
	/// Tenkan-sen length for the Ichimoku indicator.
	/// </summary>
	public int TenkanLength
	{
		get => _tenkanLength.Value;
		set => _tenkanLength.Value = value;
	}

	/// <summary>
	/// Kijun-sen length for the Ichimoku indicator.
	/// </summary>
	public int KijunLength
	{
		get => _kijunLength.Value;
		set => _kijunLength.Value = value;
	}

	/// <summary>
	/// Senkou Span B length for the Ichimoku indicator.
	/// </summary>
	public int SenkouLength
	{
		get => _senkouLength.Value;
		set => _senkouLength.Value = value;
	}

	/// <summary>
	/// Take profit distance in points.
	/// </summary>
	public int TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Stop loss distance in points.
	/// </summary>
	public int StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

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

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

		_filterMa = null;
		_blueMa = null;
		_limeMa = null;
		_macd = null;
		_ichimoku = null;
		_filterValue = null;
		_blueValue = null;
		_limeValue = null;
		_senkouAValue = null;
		_senkouBValue = null;
		_macdMainValue = null;
		_macdSignalValue = null;
		_lastProcessedTime = DateTimeOffset.MinValue;
	}

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

		_filterMa = new ExponentialMovingAverage { Length = FilterMaLength };
		_blueMa = new SmoothedMovingAverage { Length = BlueMaLength };
		_limeMa = new SmoothedMovingAverage { Length = LimeMaLength };

		_macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = MacdFastLength },
				LongMa = { Length = MacdSlowLength },
			},
			SignalMa = { Length = MacdSignalLength }
		};

		_ichimoku = new Ichimoku
		{
			Tenkan = { Length = TenkanLength },
			Kijun = { Length = KijunLength },
			SenkouB = { Length = SenkouLength }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
		.Bind(_filterMa, _blueMa, _limeMa, ProcessMovingAverages)
		.BindEx(_macd, ProcessMacd)
		.BindEx(_ichimoku, ProcessIchimoku)
		.Start();

		StartProtection(null, null);

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, _filterMa);
			DrawIndicator(area, _blueMa);
			DrawIndicator(area, _limeMa);
			DrawIndicator(area, _macd);
			DrawOwnTrades(area);
		}
	}

	private void ProcessMovingAverages(ICandleMessage candle, decimal filter, decimal blue, decimal lime)
	{
		if (candle.State != CandleStates.Finished)
		return;

		_filterValue = filter;
		_blueValue = blue;
		_limeValue = lime;

		TryTrade(candle);
	}

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

		var typed = (MovingAverageConvergenceDivergenceSignalValue)macdValue;
		if (typed.Macd is not decimal macd || typed.Signal is not decimal signal)
		return;

		_macdMainValue = macd;
		_macdSignalValue = signal;

		TryTrade(candle);
	}

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

		var ichimokuValue = (IchimokuValue)value;
		if (ichimokuValue.SenkouA is not decimal spanA || ichimokuValue.SenkouB is not decimal spanB)
		return;

		_senkouAValue = spanA;
		_senkouBValue = spanB;

		TryTrade(candle);
	}

	private void TryTrade(ICandleMessage candle)
	{
		// indicators formed check removed

		if (candle.State != CandleStates.Finished)
		return;

		if (_lastProcessedTime == candle.OpenTime)
		return;

		if (_filterValue is not decimal filter ||
		_blueValue is not decimal blue ||
		_limeValue is not decimal lime ||
		_senkouAValue is not decimal spanA ||
		_senkouBValue is not decimal spanB ||
		_macdMainValue is not decimal macd ||
		_macdSignalValue is not decimal signal)
		{
			return;
		}

		_lastProcessedTime = candle.OpenTime;

		var cloudTop = Math.Max(spanA, spanB);
		var cloudBottom = Math.Min(spanA, spanB);
		var maUpper = Math.Max(blue, lime);
		var maLower = Math.Min(blue, lime);

		var allowLong = filter > maUpper && filter > cloudTop && macd > signal;
		var allowShort = filter < maLower && filter < cloudBottom && macd < signal;

		var closePrice = candle.ClosePrice;

		if (allowLong && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (allowShort && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
	}
}