GitHub で見る

テンポイント3戦略

概要

  • MetaTrader 4 エキスパート アドバイザー 10p3v004 ("10points 3") を StockSharp の高レベル戦略フレームワークに変換します。
  • MACD スロープベースのグリッドエントリーロジックを、マーチンゲールスケーリング、トレーリングプロテクション、株式ベースのイグジットとともに再作成します。
  • オリジナルの EA の動作を再現したり、安全に調整したりできるように、すべてのパラメータに関する広範なドキュメントが提供されます。

取引ロジック

  1. シグナル検出。 設定されたタイムフレームの完了したローソク足ごとに、ストラテジーはユーザー定義の高速、低速、およびシグナルの長さを使用して MACD を計算します。メインの MACD 値が前のバーと比較して上昇すると、システムは長いグリッドを準備します。落ちた場合は短いグリッドが用意されます。 ReverseSignals フラグはこの解釈を反転します。
  2. グリッド エントリ。 一度にアクティブにできる方向グリッドは 1 つだけです。最初の注文はシグナルの直後に出されます。次の場合に追加注文が追加されます。
    • アクティブなグリッドの方向が現在の信号と一致し、
    • 価格は最新の約定から少なくとも GridSpacingPoints * PriceStep だけ有利な平均方向に移動しており、
    • オープングリッド取引の数は MaxTrades に達していません。 注文サイズは、小さなグリッド (最大 12 エントリ) の場合は 2^n、大きなグリッドの場合は 1.5^n を乗算し、ソース コードからマーチンゲール ロジックを再現します。最終的なサイズは機器の音量ステップに四捨五入され、セキュリティ制限と MaxVolumeCap の安全上限の両方によって制限されます。
  3. 資金管理。 UseMoneyManagement が有効な場合、基本ロット サイズは現在のポートフォリオ値と RiskPerTenThousand から導出されます。元の EA では、標準アカウントとミニアカウントに別々のルールが使用されていました。この変換では、IsStandardAccount パラメータを介して同じ動作が維持されます。設定が無効になっている場合は、固定の BaseVolume が使用されます。
  4. 終了ルール
    • オプションの 初期停止 は、集計された位置がグリッドに対して InitialStopPoints 移動した場合にグリッド全体を閉じます。
    • オプションの 利益確定 は、価格が TakeProfitPoints に達するとネット ポジションを優先してグリッドを閉じます。
    • オプションの トレーリング ストップは、平均エントリー価格から (TrailingStopPoints + GridSpacingPoints) 移動した後、価格の追従を開始し、TrailingStopPoints のトレーリング バッファーを保持します。
    • オプションの 株式保護 は、ポイントとボリュームで測定される未実現利益を監視します。 OrdersToProtect 以上のポジションがオープンし、利益が SecureProfit に達すると、戦略は直ちに終了します。

パラメーター

パラメータ 説明 デフォルト
CandleType MACD の計算と注文処理に使用される主な時間枠。 30分キャンドル
MacdFastPeriod / MacdSlowPeriod / MacdSignalPeriod MACD 設定は MT4 インジケーターと同じです (デフォルトでは 14/26/9)。 14/26/9
BaseVolume グリッド位置が存在せず、資金管理が無効な場合に使用される初期ロット サイズ。 0.01
GridSpacingPoints 連続するグリッド エントリ間の最小距離。価格ステップで表されます。 15
TakeProfitPoints 完全なテイクプロフィットをトリガーするための平均エントリーからの距離。無効にするには、0 に設定します。 40
InitialStopPoints グリッドを平らにする前に許容される最大逆距離。無効にするには、0 に設定します。 0
TrailingStopPoints 後続バッファのサイズ。価格が GridSpacingPoints + TrailingStopPoints 進んだ後にトレイルが有効になります。 20
MaxTrades 方向ごとの平均オーダーの最大数。 9
OrdersToProtect 株式保護チェックが評価される前に必要なオープン取引の最小数。 3
SecureProfit 株式保護エグジットのトリガーとなる含み益目標 (ポイント × ボリューム)。 8
AccountProtectionEnabled 株式保護ブロックを有効または無効にします。 true
ReverseSignals MACD の傾きの解釈を反転します (ミラーリングされたテストに役立ちます)。 false
UseMoneyManagement RiskPerTenThousand を使用した動的体積計算を有効にします。 false
RiskPerTenThousand 資金管理がアクティブな場合に使用される残高 10,000 単位あたりのリスク量。 12
IsStandardAccount 元のロットの四捨五入ルールを複製します (true = 標準ロット、false = ミニ ロット)。 true
MaxVolumeCap マーチンゲール スケーリング後に適用されるハード キャップは、ポジション サイズを制御下に保ちます。 100

変換メモ

  • MQL の専門家は、別々のチケットレベルの停留所を維持しました。 StockSharp では、グリッドは単一の集約された位置として管理されます。したがって、トレーリングレベルとプロテクティブレベルは、出来高加重平均エントリー価格から再計算されます。
  • EA は、利益を通貨に換算するためにブローカーのティック値に依存していました。ここで、株式保護のしきい値は、ソースの pip ベースの比較を反映して、ポイントとボリュームを乗じた単位で測定されます。
  • AccountFreeMarginCheck およびその他のアカウント固有の MT4 検証には、StockSharp に直接相当するものはありません。代わりに、この戦略では、商品のボリューム境界とオプションの MaxVolumeCap が考慮されます。
  • MT4 の注文コメント、マジック ナンバー、グラフィカル アノテーションは、StockSharp に対応するものがないため再現されません。

使用法

  1. 戦略をプロジェクトに追加し、通常どおり、StockSharp 戦略に対して Security と Portfolio を設定します。
  2. 分析する必要がある時間枠に一致するように CandleType を調整します (MT4 バージョンは現在のチャートの時間枠で機能しました)。
  3. リスク パラメータを調整します。固定の BaseVolume を維持するか、適切な RiskPerTenThousand および IsStandardAccount オプションを使用して UseMoneyManagement を有効にします。
  4. どの保護層 (イニシャルストップ、テイクプロフィット、トレーリングストップ、株式保護) を有効にするかを決定し、商品のボラティリティに合わせてしきい値を設定します。
  5. 戦略を開始します。組み込みのチャート ヘルパーは、ローソク足、MACD の値、および実行された取引を表示します。

さらなる開発のアイデア

  • 固定の GridSpacingPoints の代わりに、適応間隔ロジックを統合します (たとえば、ATR を使用)。
  • 長いグリッドと短いグリッドに対して個別の後続パラメーターを公開するか、非対称グリッドを許可します。
  • MACD の傾きとトレンド フィルター (移動平均、より高い時間枠の確認) を組み合わせて、逆トレンド グリッドの数を減らします。

C# と Python の両方の実装が提供されています。

using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// TenPoints3: RSI reversal with EMA filter and ATR stops.
/// </summary>
public class TenPoints3Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevRsi;
	private decimal _entryPrice;

	public TenPoints3Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_rsiLength = Param(nameof(RsiLength), 14)
			.SetDisplay("RSI Length", "RSI period.", "Indicators");
		_emaLength = Param(nameof(EmaLength), 25)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
	public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

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

		_prevRsi = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = 0; _entryPrice = 0;
		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ema, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (_prevRsi == 0 || atrVal <= 0) { _prevRsi = rsiVal; return; }
		var close = candle.ClosePrice;

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 70) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 30) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (rsiVal > 55 && _prevRsi <= 55 && close > emaVal) { _entryPrice = close; BuyMarket(); }
			else if (rsiVal < 45 && _prevRsi >= 45 && close < emaVal) { _entryPrice = close; SellMarket(); }
		}
		_prevRsi = rsiVal;
	}
}