GitHub で見る

預言者の戦略

概要

この戦略は、MetaTrader 4 エキスパート アドバイザー「PROphet」の StockSharp 移植です。元の EA は最近の取引実行を評価します 4 つの過去のローソク足を分析し、それらの加重範囲を使用して新しい取引をトリガーします。ポジションをオープン状態に保ちます。 ヨーロッパと米国では、価格が取引に有利に一定距離動くたびにセッションが行われ、ストップロスを追跡します。 StockSharp 実装では、これらの仕組みをすべて維持しながら、StockSharp ポートフォリオで使用されるネッティング モデルに適応させます。

取引ロジック

  • 設定されたタイムフレーム (CandleType、デフォルトは M5) をサブスクライブし、終了したローソク足のみを処理します。
  • 最近完了した 3 つのローソク足を維持して、MQL バージョンで使用される High[i] および Low[i] のインデックス付けを再現します。
  • すべてのバーでロング トリガー Qu(X1, X2, X3, X4) とショート トリガー Qu(Y1, Y2, Y3, Y4) を計算します。各項は次の値を乗算します。 元のコードとまったく同じように、対応する重みから 100 を引いた重み付き範囲 (例: |High[1] - Low[2]|)。
  • 現在の時間が TradeStartHourTradeEndHour (両端の値を含む) の間にある場合にのみ、新しいエントリを許可します。これは男の真似をしている MQL のエキスパートによる通常の取引ウィンドウ (デフォルトでは 10:00 ~ 18:00)。
  • 新しいポジションを開く前に、ボリュームが反対のエクスポージャーを中和する単一の成行注文を使用します。これはマグを反映しています MetaTrader 実装からの ic 番号フィルター。

リスク管理とトレーリング

  • この戦略は、MetaTrader ポイントベースの停止距離を、商品 PriceStep を介して価格単位に変換します。デフォルト (B uyStopLossPoints = 68, SellStopLossPoints = 72) は、MQL 外部変数と一致します。
  • 買値(ロング取引の場合)または売値(ショート取引の場合)が spread + 2 * stopDistance までに既存のストップを超えると、 トレーリングストップは、利用可能な場合はライブレベル 1 データを使用して、currentPrice ± stopDistance まで進められます。
  • 開いている取引は、ExitHour の後に強制的に閉じられます。デフォルト値 (18) は、ポジションを閉じるという元の動作を再現します。 サーバー時間の 18:00 以降。
  • StockSharp の高レベルの API は逆指値注文を自動的に生成しないため、保護的出口では成行注文が使用されます。これにより、 ブローカー全体での動作は決定的です。

パラメーター

パラメータ 説明
AllowBuy ロングトレードが可能になります。
AllowSell ショートトレードを可能にします。
X1, X2, X3, X4 Qu 式内の長辺範囲コンポーネントに適用される重み。
BuyStopLossPoints ロングトレードのストップロス距離は、MetaTrader ポイントで表されます。
Y1, Y2, Y3, Y4 Qu 式内の短辺範囲コンポーネントに適用される重み。
SellStopLossPoints 短期取引のストップロス距離は MetaTrader ポイントで表されます。
TradeVolume 新しいエントリに使用される基本ボリューム (ロット)。反対側の露出を閉じるために、余分なボリュームが自動的に追加されます。
TradeStartHour 取引ウィンドウの最初の 1 時間 (これを含む)。
TradeEndHour 取引ウィンドウの最後の 1 時間 (両端を含む)。
ExitHour すべての開いている取引が終了するまでの 1 時間。
CandleType 分析に使用されるローソク足のタイムフレーム。

注意事項

  • StockSharp ポートフォリオはデフォルトでネッティングしています。新しいシグナルが現れると、戦略は元シグナルをフラットにするために必要なボリュームを追加します。 新しい取引を開始する前の現在のポジション。これにより、MetaTrader のエクスペからの方向ごとに 1 つのポジションの設計が再現されます。 RT。
  • MQL スクリプトは、MarketInfo によって報告されたシンボル スプレッドを使用しました。ポートは、利用可能な場合、レベル 1 データからスプレッドを取得します。 それ以外の場合は単一の価格ステップに戻ります。
  • トレーリングストップは終了した各ローソク足の終値で評価されるため、ティックレベルのストップと比較してスリッページが発生する可能性があります。 元の EA によって実行される更新。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Translation of the MetaTrader "PROphet" expert advisor.
/// Uses a range-weighted signal from previous candles to enter trades.
/// </summary>
public class ProphetStrategy : Strategy
{
	private readonly StrategyParam<int> _x1;
	private readonly StrategyParam<int> _x2;
	private readonly StrategyParam<int> _x3;
	private readonly StrategyParam<int> _x4;
	private readonly StrategyParam<DataType> _candleType;

	private ICandleMessage _candle1;
	private ICandleMessage _candle2;
	private ICandleMessage _candle3;
	private decimal _entryPrice;

	public ProphetStrategy()
	{
		_x1 = Param(nameof(X1), 9)
			.SetDisplay("X1", "Weight applied to |High[1] - Low[2]|.", "Signal");

		_x2 = Param(nameof(X2), 29)
			.SetDisplay("X2", "Weight applied to |High[3] - Low[2]|.", "Signal");

		_x3 = Param(nameof(X3), 94)
			.SetDisplay("X3", "Weight applied to |High[2] - Low[1]|.", "Signal");

		_x4 = Param(nameof(X4), 125)
			.SetDisplay("X4", "Weight applied to |High[2] - Low[3]|.", "Signal");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for calculations.", "General");
	}

	public int X1 { get => _x1.Value; set => _x1.Value = value; }
	public int X2 { get => _x2.Value; set => _x2.Value = value; }
	public int X3 { get => _x3.Value; set => _x3.Value = value; }
	public int X4 { get => _x4.Value; set => _x4.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

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

		_candle1 = null;
		_candle2 = null;
		_candle3 = null;
		_entryPrice = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

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

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

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

		// Shift history
		_candle3 = _candle2;
		_candle2 = _candle1;
		_candle1 = candle;

		if (_candle1 == null || _candle2 == null || _candle3 == null)
			return;

		// Manage position - simple exit on reversal signal
		if (Position > 0)
		{
			var sellSignal = CalculateSignal(true);
			if (sellSignal > 0)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			var buySignal = CalculateSignal(false);
			if (buySignal > 0)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		// Entry
		if (Position == 0)
		{
			var buySignal = CalculateSignal(false);
			var sellSignal = CalculateSignal(true);

			if (buySignal > 0 && buySignal > sellSignal)
			{
				BuyMarket();
				_entryPrice = candle.ClosePrice;
			}
			else if (sellSignal > 0 && sellSignal > buySignal)
			{
				SellMarket();
				_entryPrice = candle.ClosePrice;
			}
		}
	}

	private decimal CalculateSignal(bool isSell)
	{
		var term1 = Math.Abs(_candle1.HighPrice - _candle2.LowPrice);
		var term2 = Math.Abs(_candle3.HighPrice - _candle2.LowPrice);
		var term3 = Math.Abs(_candle2.HighPrice - _candle1.LowPrice);
		var term4 = Math.Abs(_candle2.HighPrice - _candle3.LowPrice);

		if (isSell)
		{
			// For sell, use inverted weights
			return (100 - X1) * term1 + (100 - X2) * term2 + (X3 - 100) * term3 + (X4 - 100) * term4;
		}

		// For buy, use standard weights
		return (X1 - 100) * term1 + (X2 - 100) * term2 + (100 - X3) * term3 + (100 - X4) * term4;
	}
}