GitHub で見る

Exp Adaptive Renko MMRec Duplex戦略

この戦略は、MetaTrader 5のエキスパートアドバイザー Exp_AdaptiveRenko_MMRec_Duplex.mq5 をStockSharpの高レベルAPIにポートしたものです。2つの独立したAdaptive Renkoストリーム — ロングの機会用に設定されたものとショート用のもの — が、カスタムレンガチャンネルがサポートとレジスタンス間でどのようにフリップするかを観察します。ロングチャンネルが新しいサポートを報告し、ショートチャンネルがレジスタンスを失う(またはその逆)と、戦略は対応する市場ポジションを開きます。C#バージョンは、設定可能な一連の損失後にトレードサイズを削減し、連続が終わると復元するオリジナルの「MM Recounter」マネーマネジメントブロックを保持します。

コアワークフロー

  1. データサブスクリプション – 各サイドは自身のローソク足タイプ(時間軸)をサブスクライブし、SubscribeCandles().BindEx(...) を通じてボラティリティインジケーター(ATRまたは標準偏差)をバインドします。インジケーターが適応的なレンガの高さを駆動します。
  2. Adaptive Renko処理 – ヘルパー AdaptiveRenkoProcessor がMQLインジケーターのロジックを再構築し、最新のトレンド、サポートおよびレジスタンスレベルを含むスナップショットを返します。シグナルは完成したローソク足のみで評価されます。
  3. エントリーロジック – ロングRenkoスナップショットが上昇トレンドを示す(シグナルバーにサポートが出現)と、戦略はロングポジションを開きます。ショートエントリーはショートストリームからの下落トレンドを要求します。
  4. エグジットロジック – 反対のRenkoイベントがアクティブなポジションを閉じます。追加のチェックがストップロスとテイクプロフィットの距離を価格ステップで適用します。
  5. MMRecマネーマネジメント – 各方向は最近実現したPnL値のキューを維持します。設定されたウィンドウ内の損失数が損失トリガーに達すると、次の注文は削減されたマネーマネジメント値(LongSmallMoneyManagement / ShortSmallMoneyManagement)を使用します。そうでない場合は通常値(LongMoneyManagement / ShortMoneyManagement)が使用されます。MarginModeOption enumがMQLのサイジングモード(ロット、残高比率、損失ベース比率等)を再現します。
  6. 取引登録 – 各エグジットが RegisterTradeResult を呼び出してMMRecキューに供給します。キューのトリミングはターミナル履歴をスキャンせずにオリジナルの BuyTradeMMRecounterSSellTradeMMRecounterS 関数を反映します。

パラメーターグループ

グループ 主要パラメーター 説明
ロングサイド LongCandleType, LongVolatilityMode, LongVolatilityPeriod, LongSensitivity, LongPriceMode, LongMinimumBrickPoints, LongSignalBarOffset ロングエントリーを生成するAdaptive Renkoストリームを制御します。
ショートサイド ShortCandleType, ShortVolatilityMode, ShortVolatilityPeriod, ShortSensitivity, ShortPriceMode, ShortMinimumBrickPoints, ShortSignalBarOffset ショートモジュールの設定を反映します。
MMRec LongTotalTrigger, LongLossTrigger, LongSmallMoneyManagement, LongMoneyManagement, LongMarginMode, ShortTotalTrigger, ShortLossTrigger, ShortSmallMoneyManagement, ShortMoneyManagement, ShortMarginMode マネーマネジメント回復ブロックを複製します。TotalTriggerパラメーターはローリングウィンドウサイズを定義し、LossTriggerは削減ボリュームをアクティブにする損失数を定義します。
リスク LongStopLossPoints, LongTakeProfitPoints, ShortStopLossPoints, ShortTakeProfitPoints, LongDeviationSteps, ShortDeviationSteps 保護レベルと情報的なスリッページを価格ステップで表します。

動作ノート

  • 戦略はネッティング口座モデルで動作します:ロングトレードを開く前に未決のショートを閉じ、その逆も同様です。
  • ポジションサイズは CalculateVolume を通じて計算されます。ヘルパーは設定されたストップロス距離に依存する損失ベースのサイジングを含む全ての元のマージンモードをサポートします。
  • すべてのインジケーター処理はソースEAを尊重して完成したローソク足のみで行われます。
  • ログにはトレーサビリティのためにマネーマネジメント乗数と期待されるスリッページ(ステップ単位)が含まれます。

ファイル

  • CS/ExpAdaptiveRenkoMmrecDuplexStrategy.cs – Adaptive Renkoプロセッサとで MMRecモジュールを含む戦略実装。
  • README.md – 英語ドキュメント(このファイル)。
  • README_ru.md – ロシア語ドキュメント。
  • README_zh.md – 中国語ドキュメント。
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 ExpAdaptiveRenkoMmrecDuplexStrategy : 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 ExpAdaptiveRenkoMmrecDuplexStrategy()
	{
		_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;
	}
}