GitHub で見る

Alexav SpeedUp M1 戦略

概要

Alexav SpeedUp M1 戦略 は、MetaTrader 4 エキスパート アドバイザー「Alexav_SpeedUp_M1」の直接移植です。完了した日中ローソク足の本体を評価し、ローソク足本体が設定可能なしきい値を超えるとすぐに成行注文に反応します。エントリー後、この戦略はオープンポジションにストップロス、テイクプロフィット、トレーリングストップ注文を付加することで、MetaTrader スタイルのリスク管理をエミュレートします。

変換は、StockSharp の高レベル API に依存します。ローソクは SubscribeCandles を通じて消費され、トレーリングの価格情報はレベル 1 データから受信され、保護注文は標準の BuyStopSellStopBuyLimit、および SellLimit ヘルパーで発注されます。手動でインジケーターを計算する必要はありません。

信号の生成

  1. 設定された時間枠で完成した各キャンドルが検査されます。
  2. ローソク足が本体しきい値を超えて始値を上回って終了すると、戦略は市場でロングポジションをオープン(または反転)します。
  3. ローソク足が始値を同じ閾値以上下回って終了すると、戦略は市場でショートポジションをオープン(または反転)します。
  4. 逆方向の既存のエクスポージャは、成行注文量を増やすことによって自動的にクローズされ、元のエキスパートアドバイザーの動作を忠実に再現します。

注文管理

  • 初期ストップロス: ポジション量が増加するとすぐに、エントリー価格から設定されたポイント数をマイナス (ロングの場合) またはプラス (ショートの場合) した価格で保護ストップ注文が登録されます。
  • 利益確定: 一致する指値注文は、利益確定 (ポイント) で指定された距離で取引方向に発注されます。
  • トレーリングストップ: レベル 1 のビッド/アスクの更新により、現在の利益が監視されます。未実現利益がトレーリングディスタンスを超えると、保護ストップが価格に向かって移動し、設定されたギャップを維持しながら後退することはありません。
  • ポジションがフラットに戻ると、すべての保護注文がキャンセルされます。

変換により、ロジックは意図的にシンプルに保たれます。MQL 実装に存在していたもの以外に、追加のフィルター、インジケーター、リスク制御は追加されません。

パラメーター

名前 説明
ロットサイズ 各成行注文に使用される基本取引量 (ロット単位)。既存のポジションをリバースすると、必要なボリュームが自動的に追加されます。
利益確定(ポイント) MetaTrader ポイントで測定されたエントリー価格からテイクプロフィットレベルまでの距離 (証券価格ステップを使用して変換)。
初期停止 (ポイント) エントリー価格から最初の保護ストップまでの距離をポイントで表します。
トレーリングストップ (ポイント) 価格がポジションに有利に動いた後に維持されるトレーリング距離。値をゼロにすると、後続ロジックが無効になります。
本体閾値 新しい取引をトリガーするために必要なローソク足の終値と始値の間の最小絶対差。
キャンドルタイプ 信号評価に使用されるローソク足シリーズ (タイムフレーム)。デフォルトは元の 1 分足チャートと一致します。

使用上の注意

  • セキュリティが有効な PriceStep を提供していることを確認してください。利用できない場合、戦略はポイント距離を生の価格オフセットとして解釈することに戻ります。
  • トレーリング ストップ ロジックにはレベル 1 データ (最良の買い/売り) が必要です。ローソク足データのみが利用可能な場合、トレーリング機能は休止状態のままです。
  • この戦略は日中運用向けに設計されており、元の MQL エキスパートが内部カウンターを通じて強制した 1 キャンドルあたり 1 取引の動作を反映しています。
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>
/// Alexav SpeedUp M1 Body strategy.
/// Trades based on large candle body breakouts.
/// Buys after a large bullish candle, sells after a large bearish candle.
/// Uses ATR to define "large" body threshold.
/// </summary>
public class AlexavSpeedUpM1BodyBreakStrategy : Strategy
{
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _bodyMultiplier;
	private readonly StrategyParam<DataType> _candleType;

	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public decimal BodyMultiplier { get => _bodyMultiplier.Value; set => _bodyMultiplier.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public AlexavSpeedUpM1BodyBreakStrategy()
	{
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetDisplay("ATR Period", "ATR period for body threshold", "Indicators");

		_bodyMultiplier = Param(nameof(BodyMultiplier), 1.0m)
			.SetDisplay("Body Multiplier", "Body must exceed ATR * 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();
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var atr = new AverageTrueRange { Length = AtrPeriod };

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

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

		var body = candle.ClosePrice - candle.OpenPrice;
		var absBody = Math.Abs(body);
		var threshold = atrValue * BodyMultiplier;

		if (absBody < threshold)
			return;

		// Large bullish candle - buy
		if (body > 0 && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Large bearish candle - sell
		else if (body < 0 && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
	}
}