GitHub で見る

Close Orders Strategy

This utility strategy immediately closes existing positions and cancels pending orders according to user-defined filters. It can operate on the attached security only or on all portfolio securities. Optional time window and price range restrictions allow precise control over which orders are affected.

Details

  • Purpose: risk management and manual liquidation.
  • Operation:
    • On start the strategy checks the optional time window.
    • If allowed it closes positions and cancels orders matching the filters.
    • After processing the strategy stops automatically.
  • Filters:
    • CloseAllSecurities – include all portfolio instruments instead of only the attached security.
    • CloseOpenLongOrders / CloseOpenShortOrders – close existing long or short positions.
    • ClosePendingLongOrders / ClosePendingShortOrders – cancel pending buy or sell orders.
    • SpecificOrderId – only touch orders with the given transaction id when non-zero.
    • CloseOrdersWithinRange, CloseRangeHigh, CloseRangeLow – limit by entry price range.
    • EnableTimeControl, StartCloseTime, StopCloseTime – apply only during a specific time window.
  • Default Values:
    • All closing options enabled.
    • SpecificOrderId = 0.
    • CloseOrdersWithinRange = false.
    • CloseRangeHigh = 0.
    • CloseRangeLow = 0.
    • EnableTimeControl = false.
    • StartCloseTime = 02:00.
    • StopCloseTime = 02:30.
  • Notes:
    • The strategy does not open new positions.
    • Price range filters are ignored when bounds are zero or negative.
    • When CloseAllSecurities is enabled, positions across the entire portfolio are processed.
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>
/// Strategy that closes positions based on time-of-day and EMA conditions.
/// Opens positions during trend and closes them at specific time.
/// </summary>
public class CloseOrdersStrategy : Strategy
{
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private bool _hasPrev;

	public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public CloseOrdersStrategy()
	{
		_emaLength = Param(nameof(EmaLength), 40)
			.SetGreaterThanZero()
			.SetDisplay("EMA Length", "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();
		_prevEma = 0;
		_hasPrev = false;
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaLength };

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

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

		if (!_hasPrev)
		{
			_prevEma = emaVal;
			_hasPrev = true;
			return;
		}

		var close = candle.ClosePrice;

		// EMA rising -> buy
		if (emaVal > _prevEma && close > emaVal && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// EMA falling -> sell
		else if (emaVal < _prevEma && close < emaVal && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevEma = emaVal;
	}
}