GitHub で見る

SuperForexV2 戦略

概要

SuperForexV2 は、MetaTrader 4 エキスパート アドバイザー SuperForexV2.mq4 の StockSharp ポートです。オリジナルの脚本は短期的なものを組み合わせたものです。 固定テイクプロフィット、ストップロス、トレーリングストップ距離を備えた相対強度指数 (RSI) オシレーター。 C# の実装 高レベルの StockSharp API を使用して同じ意思決定プロセスを再構築します。戦略は終了したローソク足を観察し、RSI に反応します しきい値の超過を検出し、pip ベースのリスク制限を使用して単一のネット ポジションを管理します。

取引ロジック

  1. インジケーターパイプライン
    • 設定可能なローソク足シリーズ (デフォルトでは 15 分足) をサブスクライブし、終了したすべてのバーを RSI インジケーターにフィードします。
    • RSI の長さは構成可能で、デフォルトは元の MT4 値の 4 です。
  2. 動的な位置サイジング
    • すべてのエントリーの前に、戦略は現在のポートフォリオ値を BalanceToVolumeDivider で割った値から作業ロット サイズを導き出します。
    • 結果のボリュームは、InitialVolume (残高が不明な場合のフォールバック) と MaxVolume によってクランプされ、次に丸められます。 楽器のボリュームステップ。
  3. エントリールール
    • 未決済ポジションがなく、RSI が RsiLowerLevel を下回った場合、成行買い注文が発注されます。
    • RSI が RsiUpperLevel を超えると、成行売り注文が発行されます。
  4. 撤退とリスク管理
    • 各ポジションには、ピップベースの距離から計算された絶対的なストップロスとテイクプロフィットのレベルが保存されます。
    • 終了したローソクごとに、戦略はバーがそれらのレベルに触れたかどうかをチェックします。そうであれば、市場でのポジションをクローズします。
    • トレーリング ストップは MT4 ロジックを模倣しています。価格が少なくとも TrailingStopPips 進むと、ストップが近づくため、 現在の利益は固定されています。
    • また、RSI が反対の極値にクロスするたびに、ポジションは閉じられます (例: RSI が上限レベルを超えたときにロングが終了する)。
  5. ポジション範囲
    • このボットは、新しいエントリーを評価する前にフラットブックを強制することで、EA の「シンボルごとに 1 つの取引」の動作を反映しています。

パラメーター

名前 説明 デフォルト 注意事項
CandleType インジケーターの計算を推進するローソク足シリーズ。 15m 時間枠 コネクタでサポートされている任意の DataType を受け入れます。
RsiPeriod RSI ルックバックの長さ。 4 ゼロより大きくなければなりません。
RsiUpperLevel ショートとロングのエグジットに使用される買われすぎのしきい値。 62 MT4 入力 Pos と一致します。
RsiLowerLevel ロングとショートのエグジットに使用される売られ過ぎのしきい値。 42 MT4 入力 Neg と一致します。
TakeProfitPips ピップスで表されるテイクプロフィット距離。 109 テイクプロフィットを無効にするには、0 に設定します。
StopLossPips ピップスで表されるストップロス距離。 9 ストップロスを無効にするには、0 に設定します。
TrailingStopPips ピップ単位で表されるトレーリング ストップの距離。 6 トレーリング動作をオフにするには、0 に設定します。
InitialVolume ポートフォリオ残高が利用できない場合のフォールバックロットサイズ。 0.1 動的サイジングによって正以外の値が生成される場合にも使用されます。
MaxVolume エントリごとに許可される最大ボリューム。 100 バランスベースのサイジングが過度にスケールされるのを防ぎます。
BalanceToVolumeDivider 取引高を計算するために口座残高に適用される除算器。 10000 MT4 式 Lots = AccountBalance()/10000 を複製します。

実装メモ

  • ローソク足の処理は、MT4 の start() ティックエンド動作を反映するために、CandleStates.Finished の後にのみ発生します。 不完全なデータ。
  • ピップ距離は、商品の PriceStep を使用して絶対価格に変換されます。 3 桁および 5 桁の外国為替記号の場合、コード StockSharp の「pip」が MetaTrader ポイントの定義と一致するように、ステップを 10 倍します。
  • ストップロス、テイクプロフィット、トレーリングレベルは内部的に保存され、ローソク足の高値と安値と比較してチェックされます。なぜなら、StockSharp は、MT4 スタイルの注文レベルのストップを自動的に管理しません。
  • この戦略は、MinVolumeMaxVolume、および VolumeStep を尊重しながら、計算されたボリュームを最も近い有効なロットに丸めます。 セキュリティによって公開される制限。
  • 一度に許可されるネット ポジションは 1 つだけです。戦略がすでにロングまたはショートの場合、エントリーロジックは早期に終了します。

MT4版との違い

  • StockSharp ポートは個々のティックではなく完成したローソク足で動作するため、バー内ストップまたはターゲットのヒットが検出されます。 次のバーが閉まります。
  • MetaTrader の AccountFreeMargin() ガードは、より安全なバランス派生ボリュームに置き換えられます。コネクタが提供できない場合は、 ポートフォリオ値は、中止される代わりにフォールバック InitialVolume が使用されます。
  • 注文のストップロスとテイクプロフィットの値はブローカーに送信されません。代わりに、この戦略はレベルごとに市場でのポジションをクローズします。 高レベルの StockSharp 注文は戦略が管理する Exit に依存しているため、違反されます。
  • MT4 注文のフィルタリングに使用される NumeroMagico 入力は、StockSharp では不要なので省略されています。
  • 元の EA からのログ メッセージは再現されません。さらに必要な場合は、StockSharp 独自のロギング機能を使用する必要があります 計装が必要です。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// SuperForexV2: RSI threshold reversal with ATR trailing stop.
/// Buys when RSI below lower level, sells when above upper level.
/// </summary>
public class SuperForexV2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _atrLength;
	private readonly StrategyParam<decimal> _upperLevel;
	private readonly StrategyParam<decimal> _lowerLevel;

	private decimal _entryPrice;
	private decimal _trailStop;

	public SuperForexV2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_rsiLength = Param(nameof(RsiLength), 4)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period for trailing.", "Indicators");

		_upperLevel = Param(nameof(UpperLevel), 62m)
			.SetDisplay("RSI Upper", "Overbought for shorts.", "Signals");

		_lowerLevel = Param(nameof(LowerLevel), 42m)
			.SetDisplay("RSI Lower", "Oversold for longs.", "Signals");
	}

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

	public int RsiLength
	{
		get => _rsiLength.Value;
		set => _rsiLength.Value = value;
	}

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

	public decimal UpperLevel
	{
		get => _upperLevel.Value;
		set => _upperLevel.Value = value;
	}

	public decimal LowerLevel
	{
		get => _lowerLevel.Value;
		set => _lowerLevel.Value = value;
	}

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

		_entryPrice = 0;
		_trailStop = 0;
	}

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

		_entryPrice = 0;
		_trailStop = 0;

		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, atr, ProcessCandle)
			.Start();

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

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (atrVal <= 0)
			return;

		var close = candle.ClosePrice;

		// Trailing stop + opposite RSI exit
		if (Position > 0)
		{
			var newTrail = close - atrVal * 1.5m;
			if (newTrail > _trailStop)
				_trailStop = newTrail;

			if (close <= _trailStop || rsiVal > UpperLevel)
			{
				SellMarket();
				_entryPrice = 0;
				_trailStop = 0;
			}
		}
		else if (Position < 0)
		{
			var newTrail = close + atrVal * 1.5m;
			if (_trailStop == 0 || newTrail < _trailStop)
				_trailStop = newTrail;

			if (close >= _trailStop || rsiVal < LowerLevel)
			{
				BuyMarket();
				_entryPrice = 0;
				_trailStop = 0;
			}
		}

		// Entry on RSI levels
		if (Position == 0)
		{
			if (rsiVal < LowerLevel)
			{
				_entryPrice = close;
				_trailStop = close - atrVal * 2m;
				BuyMarket();
			}
			else if (rsiVal > UpperLevel)
			{
				_entryPrice = close;
				_trailStop = close + atrVal * 2m;
				SellMarket();
			}
		}
	}
}