GitHub で見る

ProffessorV3 戦略

概要

この戦略は、MetaTrader エキスパート ProffessorV3 を StockSharp の高水準 API に完全変換したものです。 ADX レジームフィルタリングと保護・平均化注文のグリッドを組み合わせるというオリジナルの概念を保持しています。

  • インジケーター: +DI/-DI 値を持つ 14 期間の Average Directional Index(ADX)。
  • モード: 横ばいレジーム(ADX が閾値以下)とトレンドレジーム(ADX が閾値以上)。
  • 注文: 市場ポジションを 1 つ開き、ヘッジ、ピラミッド、または平均回帰のために 価格を囲む保留注文を置きます。
  • エグジット: 設定した利益または損失レベルに達したときにすべてのポジションと 保留注文を閉じます。
  • スケジュール: 選択した時間範囲内でのみ取引します。

取引ロジック

レジーム検出

  1. 設定されたローソク足タイプをサブスクライブして ADX 値を計算します。
  2. 元の CopyBuffer(handle, shift) の使用を再現するために、設定した閉じたローソク足の数(BarOffset)だけ ADX シグナルを遅延させます。
  3. ポジションが開いていない場合、最後の遅延した ADX 値を評価します:
    • 横ばい強気ADX < AdxFlatLevel かつ +DI > -DI
    • 横ばい弱気ADX < AdxFlatLevel かつ +DI < -DI
    • トレンド強気ADX ≥ AdxFlatLevel かつ +DI > -DI
    • トレンド弱気ADX ≥ AdxFlatLevel かつ +DI < -DI

注文配置

各モードに対して、ストラテジーはベースボリュームで市場ポジションを開き、 次に現在の価格の周りに対称的なグリッドを配置します。グリッド距離は MQL コードとまったく同様に「ポイント」で表現され、銘柄の価格ステップで 自動的にスケーリングされます。

  • 横ばい強気: ロング成行エントリー、ビッド下の保護的 sell-stop、 ask 下の buy limit と bid 上の sell limit で振動をキャプチャ。
  • 横ばい弱気: ショート成行エントリー、ask 上の保護的 buy-stop、 プルバックでの buy limit とショートをリロードするための高い sell limit。
  • トレンド強気: ロング成行エントリー、ヘッジ用の sell-stop と ブレイクアウトピラミッドの buy-stop。
  • トレンド弱気: ショート成行エントリー、トレンドをトレールする sell-stop と 反転を抑制する buy-stop。

グリッド間隔はオリジナルと同じ式で計算されます:各レベルが GridStep + GridDeltaIncrement * level / 2 を追加します。各保留注文のボリュームは LotMultiplierLotAddition で調整され、取引所のボリュームステップと制限に正規化されます。

エグジット管理

  • 未実現利益は、ストラテジーポジションの平均価格と最新のローソク足の終値から計算されます。
  • 利益が ProfitTarget を超えるか、LossLimit を下回った場合(後者がゼロでない場合)、 ストラテジーはネットポジションを閉じ、すべての保留注文をキャンセルします。
  • [StartHour, EndHour) の区間外では取引がスキップされ、オリジナルの Time() ヘルパーに対応します。

実装メモ

  • 保留注文の bid/ask 価格は、最後のローソク足の終値から価格ステップの半分を加減して近似されます。 これはローソク足駆動の環境でのティックベースのロジックを反映します。
  • ポイント値は銘柄の価格ステップでスケーリングされ、MQL 変数 m_adjusted_point とまったく同様に 3 桁および 5 桁の相場に対して調整されます。
  • ボリュームと価格の正規化は、注文を送信する前に銘柄のステップ、最小値、最大値制約を尊重します。
  • ストラテジーは早期シグナルを避けるために完了したローソク足のみを処理します。

パラメーター

パラメーター 説明
Volume 成行注文のベースボリューム。
LotMultiplier 各保留注文のボリュームに適用される乗数。
LotAddition 乗数後に保留注文に追加される余分なボリューム。
MaxLevels 各側のグリッドレベルの最大数。
GridDeltaIncrement レベルが深まるにつれてグリッド間隔に追加されるインクリメント(ポイント)。
GridInitialOffset 最初の保護注文までの距離(ポイント)。
GridStep 連続するレベル間のベース距離(ポイント)。
ProfitTarget すべてを閉じるトリガーとなる未実現利益レベル。
LossLimit すべてを閉じるトリガーとなる未実現損失レベル(0 で無効)。
AdxFlatLevel 横ばいとトレンドのレジームを分ける ADX 閾値。
BarOffset ADX 値を遅延させるために使用する閉じたローソク足の数。
StartHour 取引ウィンドウが開く時間(UTC)。
EndHour 取引ウィンドウが閉じる時間(UTC)。
CandleType 計算に使用するローソク足シリーズ。
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Proffessor V3 strategy. Uses RSI 50-line crossover (period 10).
/// </summary>
public class ProffessorV3Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private decimal? _prevRsi;

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

	public ProffessorV3Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 10).SetGreaterThanZero().SetDisplay("RSI Period", "RSI lookback", "Indicators");
	}

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

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

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = null;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevRsi = rsiVal; return; }
		if (_prevRsi == null) { _prevRsi = rsiVal; return; }
		if (_prevRsi.Value < 45m && rsiVal >= 55m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (_prevRsi.Value > 55m && rsiVal <= 45m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
		_prevRsi = rsiVal;
	}
}