GitHub で見る

メス戦略

概要

Scalpel Strategy は、MetaTrader 4 エキスパート アドバイザー Scalpel.mq4 の StockSharp 移植です。システムは、ベースタイムフレームでモメンタムのブレイクアウトを検索し、より高いタイムフレームの安値/高値で動きを確認し、1分ローソク足に基づいて構築された方向性ボリュームスタディを使用してエントリーをフィルタリングします。ポジション管理はオリジナルの EA を反映しています。利益は時間の経過とともに縮小する固定テイクプロフィットで獲得され、価格が取引に有利に動くとストップロスを追跡することができ、すべてのポジションは設定可能な有効期限が経過した後、または金曜日の夜に強制的に閉じることができます。

取引ロジック

  • マルチタイムフレームトレンドフィルター: ロングシグナルでは、H4、H1、および M30 ローソク足の現在の安値が以前の安値よりも高いことが必要です。短いシグナルは、同じ時間枠でのより低い高値を要求します。
  • ブレイクアウトの確認: 戦略は、基準時間枠で最良の売り値が前の高値 (ロング) を超えるか、最良の買い値が前の安値 (ショート) を下回るのを待ちます。さらに、前の 3 つの高値 (または安値) はブレイクアウト方向の階段を形成する必要があります。
  • CCI ウィンドウ: 前回閉じたローソク足の商品チャネル指数は、ゼロ付近の設定可能な範囲内に留まっている必要があります。正の制限では対称ウィンドウを使用します。負の制限は、元の EA とまったく同様に、一方の側の要件を緩和します。
  • 方向性ボリュームフィルター: ボラティリティ時間枠からのボリュームは 2 つのローリングブロックに分割されます。取引は、最新のブロックが古いブロックよりも方向性のあるボリュームを示し、古いブロックがゼロでない場合にのみ許可されます。負の VolatilityWindow 値は、フィルターを範囲ベース (無方向) 累積に切り替えます。
  • リスク管理:
    • 最小価格ステップで表される固定テイクプロフィット距離とストップロス距離。
    • テイクプロフィットレベルは、ポジションがオープンのままである場合、TakeProfitReduceMinutes 分ごとに 1 価格ステップずつ減ります。
    • トレーリングストップは、価格が TrailingStopPoints だけ移動した後にアクティブになり、ローソク足ごとに移動します。
    • ポジションは、LiveMinutes の後、または設定された FridayCloseHour で強制的に閉じることができます。
    • 新しいエントリーは、絶対ネットポジションが MaxDirectionalPositions * TradeVolume に等しい間、およびオプションで再エントリーのクールダウンがアクティブである間はブロックされます。

パラメーター

名前 デフォルト 説明
TradeVolume -5 注文サイズ。正の値は固定ロットを使用します。負の値は、現在の売値を使用して出来高に換算されたポートフォリオ資本の割合を表します。
TakeProfitPoints 40 価格ステップでのエントリーからテイクプロフィットターゲットまでの距離。
StopLossPoints 340 価格ステップでのエントリーからストップロスまでの距離。
TrailingStopPoints 25 価格ステップでのトレーリングストップ距離。移動がこの距離を超えると、トレイルが開始されます。
CciPeriod 14 基本時間枠に基づいて計算された商品チャネル指数のルックバック期間。
CciLimit 75 長いエントリの上限と短いエントリのミラー負の境界。負の値は、元の EA の非対称制限を再現します。
MaxDirectionalPositions 1 一方向に許可される最大ネットポジション単位(計算された取引量の倍数)。
ReentryIntervalMinutes 0 2 つの連続するエントリ間で待機する最小時間 (分)。
TakeProfitReduceMinutes 600 テイクプロフィットしきい値が 1 価格ステップ引き下げられる数分前。削減を無効にするには、0 に設定します。
LiveMinutes 0 ポジションの最大存続期間 (分単位)。値 0 はタイマーを無効にします。
VolatilityWindow 100 各ローリング ブロックに保存されているボラティリティ キャンドルの数。負の値は範囲ベースの累積に切り替わり、0 は最新のローソク足のみを使用します。
VolatilityThresholdPoints 1 ボリュームを蓄積するために必要な最小ローソク本体 (正のウィンドウ) または範囲 (非方向性ウィンドウ)。記号はボリュームの上下の解釈を反転します。
FridayCloseHour 22 金曜日の夜にポジションを清算するために使用される時間帯 (0 ~ 23)。 0 は金曜日の出口を無効にします。
SpreadLimitPoints 5.5 新しいポジションをオープンする際の価格ステップにおける最大許容スプレッド。
CandleType 1 minute エントリーを生成し、エグジットを管理する基準時間枠。
Hour1CandleType 1 hour H1 トレンドの確認に使用されるより高い時間枠。
Hour4CandleType 4 hours H4 トレンドの確認に使用されるより高い時間枠。
Minute30CandleType 30 minutes M30 トレンドの確認に使用されるより高いタイムフレーム。
VolatilityCandleType 1 minute 方向性ボリュームフィルターにフィードを与えるタイムフレーム。

実装メモ

  • この戦略は、オーダーブックをサブスクライブして、ブレイクアウト検出とスプレッドフィルタリングのために最新の最良買値/売値を再利用します。
  • すべてのインジケーター バインディングは、StockSharp の高レベルの API に依存します。CCI の値は BindEx を通じて取得されますが、より高いタイムフレームでは専用のサブスクリプションが使用されます。
  • トレーリング ストップとテイクプロフィット リダクションは、元の EA の動作を模倣するための保護命令ではなく、コード内で実行されます。
  • 負の TradeVolume 値は、現在の売値と証券ボリュームの制約に依存します。計算されたサイズが最小ロットを下回る場合、自動的に切り上げられます。

使用法

  1. 戦略をポートフォリオに添付し、目的の証券を選択します。
  2. タイムフレームパラメータ、リスクしきい値、ボリュームサイジングルールを設定します。
  3. 戦略を開始します。シグナルは完成したキャンドルのみで評価されます。ポジションは成行注文でオープンされ、組み込みのリスク管理ルールを通じてクローズされます。
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Scalpel: CCI-based scalping with EMA filter and ATR stops.
/// </summary>
public class ScalpelStrategy : 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 ScalpelStrategy()
	{
		_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), 20)
			.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 * 2m || close <= _entryPrice - atrVal * 1.5m || rsiVal > 70)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2m || close >= _entryPrice + atrVal * 1.5m || rsiVal < 30)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

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

		_prevRsi = rsiVal;
	}
}