View on GitHub

Opening and Closing on Time Strategy

A simple time-based strategy that opens a market position at a specified time of day and closes it at another predefined time. The direction (buy or sell) and order volume are configurable. This example demonstrates scheduled trade execution without using indicators or additional filters.

Details

  • Entry Criteria:
    • Long: At Open Time when Is Buy is enabled.
    • Short: At Open Time when Is Buy is disabled.
  • Long/Short: Both, depending on Is Buy.
  • Exit Criteria:
    • Position is closed at Close Time regardless of profit or loss.
  • Stops: None.
  • Default Values:
    • Open Time = 13:00.
    • Close Time = 13:01.
    • Volume = 1.
    • Is Buy = true.
    • Candle Type = 1 minute.
  • Filters:
    • Category: Time
    • Direction: Both
    • Indicators: None
    • Stops: No
    • Complexity: Basic
    • Timeframe: Intraday
    • Seasonality: No
    • Neural networks: No
    • Divergence: No
    • Risk level: Low
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that opens a position at a specified time and closes it at another time.
/// </summary>
public class OpeningClosingOnTimeStrategy : Strategy
{
	private readonly StrategyParam<TimeSpan> _openTime;
	private readonly StrategyParam<TimeSpan> _closeTime;
	private readonly StrategyParam<bool> _isBuy;
	private readonly StrategyParam<DataType> _candleType;
	
	private bool _positionOpened;
	
	/// <summary>
	/// Time of day to open the position.
	/// </summary>
	public TimeSpan OpenTime
	{
		get => _openTime.Value;
		set => _openTime.Value = value;
	}
	
	/// <summary>
	/// Time of day to close the position.
	/// </summary>
	public TimeSpan CloseTime
	{
		get => _closeTime.Value;
		set => _closeTime.Value = value;
	}
	
	
	/// <summary>
	/// Direction of the initial trade.
	/// </summary>
	public bool IsBuy
	{
		get => _isBuy.Value;
		set => _isBuy.Value = value;
	}
	
	/// <summary>
	/// Candle type used for time tracking.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}
	
	/// <summary>
	/// Initializes a new instance of <see cref="OpeningClosingOnTimeStrategy"/>.
	/// </summary>
	public OpeningClosingOnTimeStrategy()
	{
		_openTime = Param(nameof(OpenTime), new TimeSpan(0, 0, 0))
		.SetDisplay("Open Time", "Time of day to open position", "General");
		_closeTime = Param(nameof(CloseTime), new TimeSpan(12, 0, 0))
		.SetDisplay("Close Time", "Time of day to close position", "General");
		_isBuy = Param(nameof(IsBuy), true)
		.SetDisplay("Is Buy", "True for buy, false for sell", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
		.SetDisplay("Candle Type", "Type of candles", "General");
	}
	
	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}
	
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_positionOpened = false;
	}
	
	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		
		_positionOpened = Position != 0;
		
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ProcessCandle).Start();
	}
	
	private void ProcessCandle(ICandleMessage candle)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var t = candle.OpenTime.TimeOfDay;

		if (!_positionOpened && t >= OpenTime && t < CloseTime)
		{
			if (IsBuy)
				BuyMarket();
			else
				SellMarket();

			_positionOpened = true;
			return;
		}

		if (_positionOpened && t >= CloseTime)
		{
			if (Position > 0)
				SellMarket();
			else if (Position < 0)
				BuyMarket();

			_positionOpened = false;
		}
	}
}