GitHub で見る

SilverTrend Duplex戦略

概要

SilverTrend Duplex戦略はMetaTrader 5エキスパートアドバイザーExp_SilverTrend_DuplexのStockSharpポートです。元のロボットは2つの独立したSilverTrendフィルター(ロングとショートの決定用)を組み合わせ、インジケーターの色が強気状態と弱気状態の間で切り替わるときにトレードを実行します。このC#実装はデュアルフィルターアーキテクチャを維持し、StockSharpの高レベルAPIを活用しながらロングとショートのロジックを個別に調整できます。

戦略は完了したロウソク足のみで動作します。2つの別々のサブスクリプションを設定できるため、ロングとショートのシグナルは必要に応じて異なる時間軸や銘柄を観察できます。内部では、カスタムSilverTrendIndicatorがDonchianチャネルの極値とリスク乗数を組み合わせて元のSilverTrendバンドをエミュレートすることでMQLバージョンのカラーロジックを再構築します。

取引ロジック

  1. インジケーターの再構築

    • 各ロウソク足に対してSSPバー上のDonchianの上限と下限が計算されます。
    • 適応閾値sminsmaxはリスク係数(33 - risk)を使用して導出され、MLQアルゴリズムと同一です。
    • 価格がsmaxより上で閉じると強気状態が記録され、sminより下で閉じると弱気状態が記録されます;それ以外の場合は前の状態が保持されます。ロウソク足のボディ方向が元のSilverTrendインジケーターと全く同様に最終的なカラーコード(0..4)を決定します。
  2. シグナルの準備

    • カラー値はロングフィルターとショートフィルターの両方について、最新のSignalBar + 1個の完了したロウソク足に対して保存されます。
    • ロングシグナルは選択されたオフセットでの色が2未満(強気)に落ちながら前の色が1より大きい(非強気)場合にトリガーされ、MQLのValue[1] < 2 && Value[0] > 1を再現します。
    • ショートシグナルは色が2より上(弱気)に上昇し、前の色が0より上の場合にトリガーされ、スクリプトのValue[1] > 2 && Value[0] > 0に一致します。
  3. 注文実行

    • エントリーはVolume + |Position|に等しいボリュームでBuyMarketまたはSellMarketを使用し、反対側のエクスポージャーを決済して新しい側を1つのマーケット注文で開きます。
    • 出口はインジケーターが反対のカラーバンドに戻ることに依存します。ロングポジションは色が2より上に動くと決済され、ショートポジションは2未満に落ちると決済されます。

戦略はTradeAlgorithms.mqhの元のマネーマネジメントマトリクスやサーバーサイドのストップ配置を再現しません。したがってリスク制御はStockSharpの組み込み保護メカニズムまたはブローカールールで管理する必要があります。

パラメーター

名前 デフォルト 説明
LongCandleType 4時間ロウソク足 ロングサイドインジケーターに使用するデータタイプ。
LongSsp 9 ロングフィルターのSilverTrendルックバック長。
LongRisk 3 チャネル幅に適用するリスク乗数(33 - risk)。
LongSignalBar 1 ロングシグナル評価のオフセット(完了したロウソク足単位)。≥ 1でなければなりません。
EnableLongEntries true ロングポジションのオープンを切り替えます。
EnableLongExits true 弱気色が現れた際のロングポジションのクローズを切り替えます。
ShortCandleType 4時間ロウソク足 ショートサイドインジケーターに使用するデータタイプ。
ShortSsp 9 ショートフィルターのSilverTrendルックバック長。
ShortRisk 3 ショートフィルターのリスク乗数。
ShortSignalBar 1 ショートシグナル評価のオフセット。≥ 1でなければなりません。
EnableShortEntries true ショートポジションのオープンを切り替えます。
EnableShortExits true 強気色が現れた際のショートポジションのクローズを切り替えます。
Volume 1 エントリーに使用するベース注文ボリューム。

実装メモ

  • シグナルはインジケーターとカラー履歴の両方が十分なデータ(SignalBar + 1の値)を含んでいる場合にのみ評価されます。これはMQLエキスパートのBarsCalculatedチェックを反映しています。
  • カスタムインジケーターは生のバッファーデータをコピーする代わりに10進数のカラー値を公開します。Bind高レベルAPIのおかげでGetValueへの直接呼び出しは必要ありません。
  • ロングとショートのロウソク足タイプが同一の場合、パラメーターセットを分離するために意図的に2つのサブスクリプションが作成されます。これは元のアドバイザーのダブルハンドル動作に一致します。
  • ソーススクリプトのストップロス、テイクプロフィット、スリッページ、マージン管理オプションは再現されません。同様の動作が必要な場合はStockSharpリスクルール(例:StopLossRule)を追加できます。

使用のヒント

  • 各市場レジームにブレイクアウト閾値を適応させるためにLongSspShortSspおよび対応するリスク値を別々に最適化します。
  • 元の「前のバーのシグナル」動作をエミュレートしたい場合はSignalBar1に維持します。より大きな値は反応する前に戦略に追加バーを待つことを強制します。
  • SilverTrendの色の切り替えは横ばい市場で頻繁なレジーム変化を引き起こす可能性があるため、複数の銘柄で実行する場合は戦略をポートフォリオレベルのリスク制御や時間フィルターと組み合わせます。
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;

/// <summary>
/// SilverTrend Duplex strategy (simplified). Uses ATR channel breakout.
/// </summary>
public class SilverTrendDuplexStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<int> _emaLength;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	public int EmaLength
	{
		get => _emaLength.Value;
		set => _emaLength.Value = value;
	}

	public SilverTrendDuplexStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

		_atrLength = Param(nameof(AtrLength), 10)
			.SetGreaterThanZero()
			.SetDisplay("ATR Length", "ATR period", "Indicators");

		_emaLength = Param(nameof(EmaLength), 21)
			.SetGreaterThanZero()
			.SetDisplay("EMA Length", "EMA trend", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ema = new ExponentialMovingAverage { Length = EmaLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ema, (ICandleMessage candle, decimal emaValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				var close = candle.ClosePrice;
				var range = candle.HighPrice - candle.LowPrice;
				if (range <= 0m)
					return;

				if (close > emaValue + range * 1.5m && Position <= 0)
					BuyMarket();
				else if (close < emaValue - range * 1.5m && Position >= 0)
					SellMarket();
			})
			.Start();

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