GitHub で見る

ニュース待機注文戦略

この戦略は現在価格の周辺に一対の指値ストップ注文を置き、市場が変化するにつれてそれらを管理します。急激な動きが予想されるニュース発表時の取引を目的としています。

仕組み

  • フラット時、戦略は以下を発注します:
    • Ask + Stepバイストップ注文。
    • Bid - Stepセルストップ注文。
  • 市場が少なくともStepTrail分動いた場合、TimeModify秒ごとに待機注文の価格が更新されます。
  • 一方の注文が約定すると、反対側の待機注文がキャンセルされます。
  • エントリー価格に基づいて保護ストップロスとオプションのテイクプロフィットが設定されます。
  • ストップロスは設定された利益に達した後ブレイクイーブンに移動し、その後価格の動きに従ってトレーリングします。

この戦略はLevel1データで動作し、インジケーターには依存しません。

パラメーター

パラメーター デフォルト 説明
Step 10 待機ストップ注文を置くティック単位の距離。
StopLoss 10 初期ストップロス(ティック単位)。
TakeProfit 50 テイクプロフィット(ティック単位、0で無効)。
TrailingStop 10 トレーリングストップ距離(ティック単位)。
TrailingStart 0 トレーリング発動前の利益(ティック単位)。
StepTrail 2 新しいストップ注文を送信するためのストップ価格の最小変化(ティック単位)。
BreakEven false MinProfitBreakEvenに達したらストップをエントリーに移動。
MinProfitBreakEven 0 ブレイクイーブンにストップを移動するために必要な利益(ティック単位)。
TimeModify 30 待機注文の再価格設定試行の間隔(秒)。

注意事項

  • 注文はStockSharpの高レベルAPIを使用して管理されます。
  • ポジションが決済されると保護注文がキャンセルされます。
  • C#バージョンのみ提供されており、Python実装は含まれていません。
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// News-style volatility breakout strategy.
/// Enters on ATR expansion with momentum confirmation via EMA.
/// </summary>
public class NewsPendingOrdersStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrMult;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevAtr;
	private decimal _entryPrice;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public decimal AtrMult { get => _atrMult.Value; set => _atrMult.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public NewsPendingOrdersStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA trend period", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period", "Indicators");
		_atrMult = Param(nameof(AtrMult), 1.5m)
			.SetDisplay("ATR Mult", "ATR expansion multiplier", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevAtr = 0;
		_entryPrice = 0;
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var atr = new StandardDeviation { Length = AtrPeriod };

		SubscribeCandles(CandleType).Bind(ema, atr, ProcessCandle).Start();
	}

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

		if (_prevAtr <= 0) { _prevAtr = atr; return; }

		var close = candle.ClosePrice;
		var bodySize = Math.Abs(candle.ClosePrice - candle.OpenPrice);

		// Volatility expansion: big body candle relative to stddev
		var expansion = bodySize > atr * 0.5m;

		if (expansion && close > ema && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_entryPrice = close;
		}
		else if (expansion && close < ema && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_entryPrice = close;
		}
		// Exit long
		else if (Position > 0)
		{
			if (close < ema || (_entryPrice > 0 && close <= _entryPrice - atr * 2))
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		// Exit short
		else if (Position < 0)
		{
			if (close > ema || (_entryPrice > 0 && close >= _entryPrice + atr * 2))
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		_prevAtr = atr;
	}
}