GitHub で見る

利益確定クローズ戦略

この戦略は、戦略が実行したすべての取引の実現損益を監視します。累積利益がユーザー定義の閾値を超えると、オープンポジションを即座に決済し、オプションでアクティブな注文をキャンセルします。損失上限を設定することで、ドローダウンにも同じ動作を有効にできます。

この戦略はインジケーターや価格の動きを分析しません。代わりに、金銭的な目標またはストップレベルに達したらマーケットを退場させる保護オーバーレイとして機能します。シンプルなローソク足のサブスクリプションは、現在のPnL値を定期的に確認するためだけに使用されます。

パラメーター

  • UseProfitToClose – 利益目標によるクローズを有効または無効にします。デフォルト: true
  • ProfitToClose – 完全退場をトリガーする通貨単位での利益値。デフォルト: 20
  • UseLossToClose – 損失上限によるクローズを有効または無効にします。デフォルト: false
  • LossToClose – 超過した際に完全退場をトリガーする通貨単位での損失値。デフォルト: 100
  • ClosePendingOrders – ポジション決済時にすべてのアクティブ注文をキャンセルします。デフォルト: true
  • CandleType – 定期的なチェックのトリガーに使用するローソク足の種類。デフォルト: 1分の時間軸。

取引ロジック

  1. 選択した時間軸のローソク足を購読します。
  2. 各完了ローソク足で現在の実現PnLを計算します。
  3. 利益が ProfitToClose 以上の場合、ポジション全体を決済し、オプションで未決注文をキャンセルします。
  4. 損失監視が有効で現在のPnLが -LossToClose 以下の場合、ポジション全体を決済し、オプションで未決注文をキャンセルします。

追加事項

  • 戦略は紐づいている銘柄のポジションのみを決済します。
  • 未決注文は組み込みの CancelActiveOrders メソッドを使用してキャンセルされます。
  • このロジックは他のエントリー戦略と組み合わせて、利益確定またはポートフォリオ保護を実装できます。

フィルター

  • カテゴリ: リスク管理
  • 方向: 両方
  • インジケーター: なし
  • ストップ: はい
  • 複雑さ: 基本
  • 時間軸: 任意
  • 季節性: いいえ
  • ニューラルネットワーク: いいえ
  • ダイバージェンス: いいえ
  • リスクレベル: 中
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>
/// EMA crossover strategy with profit/loss exit targets.
/// </summary>
public class CloseAtProfitStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public CloseAtProfitStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "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();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

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

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType).Bind(fast, slow, ProcessCandle).Start();
	}

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

		if (!_hasPrev)
		{
			_prevFast = fast;
			_prevSlow = slow;
			_hasPrev = true;
			return;
		}

		// Fast crosses above slow => buy
		if (_prevFast <= _prevSlow && fast > slow && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// Fast crosses below slow => sell
		else if (_prevFast >= _prevSlow && fast < slow && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fast;
		_prevSlow = slow;
	}
}