GitHub で見る

ペドロ MOD 戦略

概要

この戦略は、Pedroxxmod MetaTrader 4 エキスパート アドバイザーの StockSharp 移植です。オリジナルの EA は市場が動くのを待ちます。 基準価格から数ピップス離れたところで、逆張りポジションをオープンします。後続の注文は同じ方向で平均化されます 価格が設定可能な距離だけ反転するたびに。 StockSharp 実装は、公開中に動作をそのまま維持します。 高レベルの Strategy API を通じて厳密に型指定されたパラメータ。

取引ロジック

  1. レベル 1 の最高買値/売値を購読し、最新の値をキャッシュします。
  2. オープンな取引がない場合は、現在の売り値を参照エントリーレベルとして保存します。取引は以下の間でのみ許可されます StartHourEndHour、および StartYear 以降。
  3. ベストアスクが基準値より Gap MetaTrader ピップス上昇した場合は、成行売り注文を送信します。 Gap ピップ下がった場合、 成行買い注文を提出します。保護的なストップロスとテイクプロフィットのレベルは、呼び出しによって自動的に設定されます。 SetStopLoss / SetTakeProfit はエキスパートアドバイザーと同じピップ距離です。
  4. バスケットの方向が確立されると、戦略はヘッジをエミュレートするために合成ポジションの FIFO リストを保持します。 MetaTrader のスタイル。現在のバスケット サイズが MaxTrades を下回っている限り、最適なアスクのときに平均注文が追加されます 最新のエントリー価格から ReEntryGap ピップス以内のリターン。
  5. 資金管理では、固定の Lots パラメータを使用するか、EA ルールに従ってボリュームを動的に割り当てることができます floor(Equity / 20000)、上限は MaxLots です。すべてのボリュームは、セキュリティのボリューム ステップ/最小/最大に対して正規化されます。
  6. 営業時間外の更新では、次のセッション開始時の誤った取引を避けるために内部エントリーアンカーがリセットされます。

パラメーター

名前 説明
Lots 資金管理が無効になっている場合の注文量を修正しました。
StopLoss プロテクティブストップ距離(MetaTrader ピップス)。停止を無効にするには、0 に設定します。
TakeProfit 利益目標距離 (MetaTrader ピップ単位)。ターゲットを無効にするには、0 に設定します。
Gap 最初の取引を開始する前に、MetaTrader ピップの距離でアスクがリファレンスから離れる必要があります。
MaxTrades 同時にオープンする取引の最大数 (バスケット サイズ)。
ReEntryGap バスケット方向の注文の平均化をトリガーする距離 (MetaTrader ピップ)。
MoneyManagement true に設定すると、ダイナミック ボリューム ルール floor(Equity / 20000) が有効になります。
MaxLots 動的に計算されるボリュームの上限。
StartHour / EndHour 取引所サーバー時間 (両端を含む) での取引ウィンドウ。
StartYear 取引が許可される暦年。それ以前のデータは無視されます。

注意事項

  • この戦略はレベル 1 データのみを消費し、キャンドルを要求しません。したがって軽量であり、すぐに反応します。 MT4 start() ティック ハンドラーと同様に、相場が変更されます。
  • ストップとターゲットは、Strategy のヘルパー メソッドに依存して、MetaTrader のピップ距離をブローカー固有の距離に変換します。 価格レベル。接続された会場が正しい PriceStepStepPrice、および VolumeStep の値を公開していることを確認してください。
  • 合成バスケット カウンターを使用すると、StockSharp がポジションを集計しても、戦略でヘッジ口座を模倣することができます。 部分的なフィルとストップ ヒットは、FIFO キューを維持する OnPositionChanged コールバックを介して処理されます。
  • Python の実装は、リポジトリのガイドラインに従って意図的に省略されています。
namespace StockSharp.Samples.Strategies;

using System;
using System.Collections.Generic;

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

/// <summary>
/// Pedro Mod mean reversion strategy using Bollinger Bands.
/// Buy when price touches the lower band, sell when price touches the upper band.
/// </summary>
public class PedroModStrategy : Strategy
{
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerWidth;
	private readonly StrategyParam<DataType> _candleType;

	public int BollingerPeriod { get => _bollingerPeriod.Value; set => _bollingerPeriod.Value = value; }
	public decimal BollingerWidth { get => _bollingerWidth.Value; set => _bollingerWidth.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public PedroModStrategy()
	{
		_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
			.SetDisplay("Bollinger Period", "Bollinger Bands period", "Indicators");

		_bollingerWidth = Param(nameof(BollingerWidth), 1.5m)
			.SetDisplay("Bollinger Width", "Standard deviation multiplier", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

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

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

		var bb = new BollingerBands { Length = BollingerPeriod, Width = BollingerWidth };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(bb, ProcessCandle)
			.Start();
	}

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

		if (!bbValue.IsFinal)
			return;

		var bb = (BollingerBandsValue)bbValue;
		if (bb.UpBand is not decimal upper || bb.LowBand is not decimal lower || bb.MovingAverage is not decimal middle)
			return;

		// Buy when price touches lower band (mean reversion)
		if (Position <= 0 && candle.ClosePrice <= lower)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Sell when price touches upper band
		else if (Position >= 0 && candle.ClosePrice >= upper)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
		// Exit at middle band
		else if (Position > 0 && candle.ClosePrice >= middle)
		{
			SellMarket();
		}
		else if (Position < 0 && candle.ClosePrice <= middle)
		{
			BuyMarket();
		}
	}
}