GitHub で見る

Random Hedg戦略

概要

Random Hedg戦略は、MetaTraderエキスパートアドバイザー「Random Hedg」のStockSharp高レベルポートです。元のEAは同時に市場買い注文と市場売り注文を出し、固定ストップロス、テイクプロフィット、ブレークイーブン、トレーリングロジックの組み合わせで両ポジションを管理します。変換はそのコア動作を維持しながら、すべての設定を戦略パラメーターとして公開し、ボットをStockSharp Designerで直接調整または最適化できるようにします。

トレーディングロジック

  1. 初期ヘッジ – 戦略がフラットな時、同じ設定可能ボリュームを使って2つの市場注文(買いと売り)をすぐに送ります。両ポジションはpipsで表されるストップロスとテイクプロフィットを受け取ります。
  2. ブレークイーブン保護 – 設定されたpips数だけ価格がポジションに有利に動いた後、ストップレベルはブレークイーブンにオプションのオフセットを加えたもの(ロングポジション)またはブレークイーブンからオフセットを引いたもの(ショートポジション)に移動します。これはEAの「ノーロスへ移動」トグルを反映します。
  3. Trailingストップ – 利益がTrailing距離を超えると、ストップが価格を追います。ロングではストップは最高値からTrailing距離を引いた値を追い、ショートでは最安値にTrailing距離を加えた値を追います。
  4. 保護的出口 – 各ポジションはテイクプロフィットまたはストップロスに触れると決済されます。オプションで、ローソク足がボリンジャーバンドの下限を下回って閉じた場合、戦略は両ポジションを清算し、元のコードの出口フィルターを再現します。
  5. サイクル再開 – 両ポジションが決済されると、戦略は内部トラッカーをリセットし、次のローソク足で新しいヘッジペアを開くのを待ちます。

パラメーター

  • HedgeVolume – 両ヘッジポジションを開くために使用されるボリューム(デフォルト0.1契約)。
  • StopLossPips – 保護的ストップロスの距離(デフォルト200 pips)。
  • TakeProfitPips – テイクプロフィットの距離(デフォルト200 pips)。
  • TrailingStopPips – ポジションが利益に転じた後に適用されるTrailingステップ(デフォルト40 pips)。
  • BreakEvenTriggerPips – ストップをブレークイーブンに移動する前に必要な利益(デフォルト10 pips)。
  • BreakEvenOffsetPips – ブレークイーブン移動時に確保される追加利益(デフォルト5 pips)。
  • EnableTrailing – Trailingストップ管理を有効または無効にします。
  • EnableBreakEven – ブレークイーブン機能を有効または無効にします。
  • EnableExitStrategy – ボリンジャーバンドベースの清算フィルターを有効にします。
  • BollingerPeriod – オプションの出口に使用されるボリンジャーバンドの期間(デフォルト20ローソク足)。
  • BollingerWidth – ボリンジャーバンドの幅の乗数(デフォルト2)。
  • CandleType – ロジックを実行するローソク足データシリーズ(デフォルト30分時間軸)。

実装ノート

  • 変換は、ローソク足サブスクリプションとBindExメカニズムを使った高レベルStrategy APIを使用してボリンジャーバンドをその場で計算します。
  • 内部状態は各ポジションのエントリー価格、ボリューム、動的保護レベルを追跡します。これにより、C#バージョンはプラットフォーム固有の注文ハンドルに依存せずに元のEAのマネー管理ヘルパーを模倣できます。
  • 保留中の注文ボリュームは個別に追跡されるため、買いと売りの取引が連続して発生した場合でも、約定はエントリーまたは出口として分類できます。
  • 戦略はソースエキスパートアドバイザーと同様に、ロングとショートのエクスポージャーを同時に維持するためヘッジ対応口座を期待します。
  • MQLコードのマネーベースTrailingと割合テイクプロフィット機能は意図的に省略されています。これらはブローカー固有の残高データに依存し、実際にはほとんど使用されなかったため、StockSharpバージョンはコアの価格アクション管理に集中します。

ファイル

  • CS/RandomHedgStrategy.cs – 詳細な英語インラインコメント付きのメインC#実装。
  • 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 RandomHedgStrategy : 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 RandomHedgStrategy()
	{
		_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;
	}
}