GitHub で見る

CloseDeleteEA戦略

概要

CloseDeleteEA戦略は、ポジションを一括決済し、保留注文を削除する MetaTrader ユーティリティを再現します。選択されたポートフォリオを定期的にスキャンし、ユーザー定義フィルターに従って成行注文またはキャンセル要求を送信します。手動の注文管理が遅すぎる緊急清算や整理シナリオで有用です。

主な機能

  • 成行注文でロングおよび/またはショートエクスポージャーを閉じます。
  • 設定されたフィルターに一致する保留注文をキャンセルします。
  • 特定ポジションを触らないための任意の利益/損失フィルター。
  • スキャンを現在の銘柄に制限するか、ポートフォリオ全体を処理します。
  • 戦略識別子でポジションと注文をフィルターします。

パラメーター

名前 説明
CloseBuyPositions フィルターに一致するロングエクスポージャーを閉じます。
CloseSellPositions フィルターに一致するショートエクスポージャーを閉じます。
CloseMarketPositions 市場ポジション決済モジュールを有効にします。
CancelPendingOrders 保留注文のキャンセルを有効にします。
CloseOnlyProfitable 現在の PnL が非負の場合にのみポジションを閉じます。
CloseOnlyLosing 現在の PnL が非正の場合にのみポジションを閉じます。
ApplyToCurrentSecurity true の場合、戦略の銘柄だけをスキャンします。それ以外の場合、ポートフォリオ内のすべての銘柄を処理します。
TargetStrategyId 任意の戦略識別子フィルター (空値はすべてに一致)。
TimerInterval 管理ループで使用するタイマー頻度。

使用上の注意

  1. 割り当て済みポートフォリオを持つコネクターに戦略を接続します。
  2. 戦略開始前に必要なフィルターを設定します。
  3. 戦略を開始して close/delete サイクルを起動します。一致するポジションまたは注文がなくなると、戦略は自動的に停止します。
  4. キャンセル要求は、コネクターを通じて戦略から見える注文だけを対象にできることに注意してください。

MQL版との違い

  • StockSharp は集約ポジションで動作するため、個別 ticket レベルの制御は数量ベースのネットエクスポージャー管理に置き換えられます。
  • 戦略 ID フィルターは、元の magic number の概念を模倣します。
  • MetaTrader のチャート整理用ビジュアル要素は再現されていません。
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;

public class CloseDeleteEaStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public CloseDeleteEaStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}