GitHub で見る

Color Schaff JJRSX MMRec Duplex戦略

概要

この戦略はMetaTraderのエキスパートアドバイザーExp_ColorSchaffJJRSXTrendCycle_MMRec_DuplexのStockSharpへのポートです。元のロボットはJJRSXモメンタムによって駆動される2つのSchaff Trend Cycleオシレーターと、損失の連続後にエクスポージャーを削減するMMRec(資金管理再計算)モジュールを組み合わせています。C#変換はデュアルロング/ショートレイアウトを保持し、調整可能なリスクコントロールを再現しながら、利用できないJJRSXインジケーターをプラットフォーム内の堅牢な近似で置き換えます。

トレードロジック

  • ユーザーが選択した2つの時間軸で2つの独立したオシレーターが計算されます:1つはロングエントリーを管理し、もう1つはショートエントリーを管理します。各オシレーターは高速と低速のRSXスタイルのモメンタムラインを使用し、Schaff Trend Cycleパイプラインでスムーズ化および正規化されて[-100, 100]の範囲の値を出力します。
  • ロングポジションはロングオシレーターがゼロを下方クロスするとき(previous > 0かつcurrent <= 0)に開かれます。元のエキスパートはこれらのイベントを強気のモメンタムリバーサルとしてマークします。ロングエグジットは1バー前のインジケーター値が負のときにトリガーされます。
  • ショートポジションはショートオシレーターがゼロを上方クロスするとき(previous < 0かつcurrent >= 0)に開かれます。ショートエグジットは1バー前のインジケーター値が正のときにトリガーされます。
  • SignalBar設定は、履歴バーでシグナルを評価するMetaTraderの動作を再現します。例えば、SignalBar = 1は最後に完全に閉じたローソク足とその前のローソク足を検査します。戦略はMQLコードからのCopyBuffer呼び出しをエミュレートするためにローリングインジケーター履歴を維持します。

資金管理(MMRec)

  • ロングとショートのトレードに対して別々の資金管理ブロックが維持されます。基本ボリュームはStrategy.Volume * MMに等しく、MMは設定可能な通常の乗数(LongMm/ShortMm)です。
  • すべてのクローズトレードの後、戦略は結果が収益性があったかどうかを記録します(エントリー/エグジットローソク足の価格に基づき、HistorySelectを通じて履歴を追跡するEAロジックと同一です)。
  • 最後のTotalTriggerトレードに少なくともLossTriggerの敗者が含まれている場合、その側の次のオーダーは削減された乗数(SmallMm)に切り替わります。損失条件が消えると、基本乗数が自動的に復元されます。
  • ポジションリバーサルはMMRecルールを尊重します:ロングからショート(またはその逆)への切り替えは、最初に既存のトレードの結果を確定させ、損失カウンターを更新してから新しいオーダーをサイジングします。

インジケーター近似

元のロボットはJJRSXオシレーターとJurikスムージングライブラリ上に構築されたカスタムColorSchaffJJRSXTrendCycleインジケーターに依存します。StockSharpはそれらのコンポーネントを含んでいないため、変換ではColorSchaffJjrsxTrendCycleIndicatorを実装します:

  • 軽量なRSI近似(SimpleRsi)がEAのスムージング期間と同一の指数平滑でモメンタムベースラインを計算します。
  • 高速と低速のRSI曲線が減算されてMACD様の系列が取得され、それから周期的ウィンドウで正規化されて設定可能なファクター(デフォルト0.5)で二重スムージングされ、Schaff Trend Cycle動作を模倣します。
  • インジケーターは同じ価格ソース(クローズ、オープン、ハイ、ロー、メジアン、典型、加重など)を受け付け、サイクル/長さパラメータを保持して最適化ワークフローがソース戦略に忠実に保たれます。

パラメータ

グループ 名前 説明
Long LongCandleType ロングインジケーターに使用するローソク足タイプまたは時間軸。
Long LongTotalTrigger 損失カウンターを評価する際に検査される完了したロングトレードの数。
Long LongLossTrigger 削減された乗数を活性化する検査ウィンドウ内の最小損失数。
Long LongSmallMm 繰り返し損失後に適用される削減ボリューム乗数。
Long LongMm デフォルトのロングボリューム乗数。
Long LongEnableOpen ロングエントリーを有効にします。
Long LongEnableClose ロングエグジットを有効にします。
Long LongFastLength 高速JJRSX期間近似。
Long LongSlowLength 低速JJRSX期間近似。
Long LongSmooth Schaff正規化前に適用される指数平滑長。
Long LongCycleLength 最小/最大正規化に使用するサイクルウィンドウ。
Long LongSignalBar ロングシグナルを分析する際の履歴シフト。
Long LongAppliedPrice ロングインジケーターが使用する価格ソース。
Short ShortCandleType ショートインジケーターに使用するローソク足タイプまたは時間軸。
Short ShortTotalTrigger 損失カウンターを評価する際に検査される完了したショートトレードの数。
Short ShortLossTrigger 削減された乗数を活性化する検査ウィンドウ内の最小損失数。
Short ShortSmallMm 繰り返し損失後に適用される削減ボリューム乗数(ショート)。
Short ShortMm デフォルトのショートボリューム乗数。
Short ShortEnableOpen ショートエントリーを有効にします。
Short ShortEnableClose ショートエグジットを有効にします。
Short ShortFastLength ショート用高速JJRSX期間近似。
Short ShortSlowLength ショート用低速JJRSX期間近似。
Short ShortSmooth ショート用Schaff正規化前の指数平滑長。
Short ShortCycleLength ショート側の最小/最大正規化に使用するサイクルウィンドウ。
Short ShortSignalBar ショートシグナルを分析する際の履歴シフト。
Short ShortAppliedPrice ショートインジケーターが使用する価格ソース。

実装に関する注意事項

  • 戦略はStockSharpの高レベルローソク足サブスクリプションを使用し、変換ガイドラインに従ってインジケーターバッファへの直接アクセスを避けます。
  • MetaTraderはポイントベースの距離を使用するため、MQLバージョンのプロテクティブストップ(StopLoss/TakeProfit)はポートされません;ユーザーは必要に応じてStartProtectionまたはカスタムリスクモジュールをアタッチできます。
  • トレード履歴はローソク足のクローズ価格を使用して評価されます。これはStockSharp内でロジックを決定論的に保ちながら、EAの歴史的ディールレコードへの依存を反映しています。
  • カスタムインジケーターはIsFormedを公開するので、戦略はウォームアップ中の早期シグナルを防ぐために十分なデータが蓄積された後にのみ反応します。

免責事項

このポートはMetaTrader戦略の論理的構造を複製しますが、データフィード、執行ポリシー、JJRSX近似のため、パフォーマンスが異なる場合があります。ライブで展開する前に、常にデモデータで動作を検証してください。

using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

public class ColorSchaffJjrsxMmrecDuplexStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast, _prevSlow;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public ColorSchaffJjrsxMmrecDuplexStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 10).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 30).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}