Ver en GitHub

Scheduled Time Trader Strategy

This strategy submits market orders at a predefined time and protects them with fixed stop loss and take profit levels.

Trading Rules

  • When the current time reaches Trade Hour:Trade Minute:Trade Second, the strategy fires once per session.
  • If Allow Buy is enabled, a long position is opened with the specified Volume.
  • If Allow Sell is enabled, a short position is opened with the same Volume.
  • Protective orders are managed via StartProtection using point values for stop loss and take profit.

Parameters

Name Description
Volume Order size.
Take Profit (ticks) Take profit distance from entry in ticks.
Stop Loss (ticks) Stop loss distance from entry in ticks.
Allow Buy Enable long trades.
Allow Sell Enable short trades.
Trade Hour Hour of the day to trade (0-23).
Trade Minute Minute of the hour to trade (0-59).
Trade Second Second of the minute to trade (0-59).
Candle Type Candle series used to track time, default is 1-second candles.

Notes

The strategy opens trades only once per run. To trade again, restart the strategy or adjust the trade time.

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 trend-following strategy with RSI filter.
/// </summary>
public class ScheduledTimeTraderStrategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevEma;
	private decimal _prevClose;
	private bool _hasPrev;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public ScheduledTimeTraderStrategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI 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;
		_prevClose = 0;
		_hasPrev = false;
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

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

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

		var close = candle.ClosePrice;

		if (!_hasPrev) { _prevEma = emaValue; _prevClose = close; _hasPrev = true; return; }

		// Buy: close crosses above EMA and RSI confirms
		if (_prevClose <= _prevEma && close > emaValue && rsiValue < 65 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		// Sell: close crosses below EMA and RSI confirms
		else if (_prevClose >= _prevEma && close < emaValue && rsiValue > 35 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevEma = emaValue;
		_prevClose = close;
	}
}