Opening and Closing on Time v2 Strategy
A time-based strategy that opens trades at a specific time and closes them later in the day. Trade direction is confirmed by comparing a fast and a slow exponential moving average. Stop-loss and take-profit levels are expressed in ticks.
Details
- Entry Criteria: At
OpenTime, go long if the fast EMA is above the slow EMA, go short if it is below. Direction depends onTradeMode. - Long/Short: Configurable (buy, sell, or both).
- Exit Criteria: Positions are closed at
CloseTimeor by protective stops. - Stops: Yes, both stop-loss and take-profit in ticks.
- Default Values:
OpenTime= 05:00CloseTime= 21:01SlowPeriod= 200FastPeriod= 50StopLossTicks= 30TakeProfitTicks= 50CandleType= TimeSpan.FromMinutes(1)
- Filters:
- Category: Time Based
- Direction: Configurable
- Indicators: EMA
- Stops: Fixed
- Complexity: Basic
- Timeframe: Intraday (1m)
- 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;
public class OpeningAndClosingOnTimeV2Strategy : Strategy
{
public enum TradeModeses
{
Buy,
Sell,
BuyAndSell
}
private readonly StrategyParam<int> _openHour;
private readonly StrategyParam<int> _closeHour;
private readonly StrategyParam<TradeModeses> _tradeMode;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevSlow;
private decimal _prevFast;
private bool _opened;
public int OpenHour
{
get => _openHour.Value;
set => _openHour.Value = value;
}
public int CloseHour
{
get => _closeHour.Value;
set => _closeHour.Value = value;
}
public TradeModeses TradeMode
{
get => _tradeMode.Value;
set => _tradeMode.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public decimal StopLoss
{
get => _stopLoss.Value;
set => _stopLoss.Value = value;
}
public decimal TakeProfit
{
get => _takeProfit.Value;
set => _takeProfit.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public OpeningAndClosingOnTimeV2Strategy()
{
_openHour = Param(nameof(OpenHour), 2)
.SetDisplay("Open Hour", "Hour of day to open trades (UTC)", "General");
_closeHour = Param(nameof(CloseHour), 14)
.SetDisplay("Close Hour", "Hour of day to close trades (UTC)", "General");
_tradeMode = Param(nameof(TradeMode), TradeModeses.BuyAndSell)
.SetDisplay("Trade Mode", "Allowed trade directions", "General");
_slowPeriod = Param(nameof(SlowPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Slow MA", "Slow EMA period", "Indicators");
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast MA", "Fast EMA period", "Indicators");
_stopLoss = Param(nameof(StopLoss), 1000m)
.SetDisplay("Stop Loss", "Stop loss in price units", "Protection");
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take Profit", "Take profit in price units", "Protection");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for strategy", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_prevSlow = 0m;
_prevFast = 0m;
_opened = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var slowMa = new ExponentialMovingAverage { Length = SlowPeriod };
var fastMa = new ExponentialMovingAverage { Length = FastPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(slowMa, fastMa, ProcessCandle)
.Start();
StartProtection(
new Unit(TakeProfit, UnitTypes.Absolute),
new Unit(StopLoss, UnitTypes.Absolute));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, slowMa);
DrawIndicator(area, fastMa);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal slow, decimal fast)
{
if (candle.State != CandleStates.Finished)
return;
var hour = candle.OpenTime.Hour;
if (!_opened && hour >= OpenHour && hour < CloseHour)
{
if (_prevSlow != 0m && _prevFast != 0m)
{
var buySignal = _prevFast <= _prevSlow && fast > slow;
var sellSignal = _prevFast >= _prevSlow && fast < slow;
if (buySignal && (TradeMode == TradeModeses.Buy || TradeMode == TradeModeses.BuyAndSell) && Position <= 0)
{
BuyMarket();
_opened = true;
}
else if (sellSignal && (TradeMode == TradeModeses.Sell || TradeMode == TradeModeses.BuyAndSell) && Position >= 0)
{
SellMarket();
_opened = true;
}
}
}
else if (_opened && hour >= CloseHour)
{
if (Position > 0)
SellMarket();
else if (Position < 0)
BuyMarket();
_opened = false;
}
_prevSlow = slow;
_prevFast = fast;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class opening_and_closing_on_time_v2_strategy(Strategy):
BUY = 0
SELL = 1
BUY_AND_SELL = 2
def __init__(self):
super(opening_and_closing_on_time_v2_strategy, self).__init__()
self._open_hour = self.Param("OpenHour", 2)
self._close_hour = self.Param("CloseHour", 14)
self._trade_mode = self.Param("TradeMode", 2)
self._slow_period = self.Param("SlowPeriod", 20)
self._fast_period = self.Param("FastPeriod", 5)
self._stop_loss = self.Param("StopLoss", 1000.0)
self._take_profit = self.Param("TakeProfit", 2000.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._prev_slow = 0.0
self._prev_fast = 0.0
self._opened = False
@property
def OpenHour(self):
return self._open_hour.Value
@OpenHour.setter
def OpenHour(self, value):
self._open_hour.Value = value
@property
def CloseHour(self):
return self._close_hour.Value
@CloseHour.setter
def CloseHour(self, value):
self._close_hour.Value = value
@property
def TradeMode(self):
return self._trade_mode.Value
@TradeMode.setter
def TradeMode(self, value):
self._trade_mode.Value = value
@property
def SlowPeriod(self):
return self._slow_period.Value
@SlowPeriod.setter
def SlowPeriod(self, value):
self._slow_period.Value = value
@property
def FastPeriod(self):
return self._fast_period.Value
@FastPeriod.setter
def FastPeriod(self, value):
self._fast_period.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(opening_and_closing_on_time_v2_strategy, self).OnStarted2(time)
self._prev_slow = 0.0
self._prev_fast = 0.0
self._opened = False
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.SlowPeriod
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.FastPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(slow_ma, fast_ma, self.ProcessCandle).Start()
self.StartProtection(
Unit(self.TakeProfit, UnitTypes.Absolute),
Unit(self.StopLoss, UnitTypes.Absolute))
def ProcessCandle(self, candle, slow, fast):
if candle.State != CandleStates.Finished:
return
hour = candle.OpenTime.Hour
slow_val = float(slow)
fast_val = float(fast)
if not self._opened and hour >= int(self.OpenHour) and hour < int(self.CloseHour):
if self._prev_slow != 0.0 and self._prev_fast != 0.0:
buy_signal = self._prev_fast <= self._prev_slow and fast_val > slow_val
sell_signal = self._prev_fast >= self._prev_slow and fast_val < slow_val
if buy_signal and (self.TradeMode == self.BUY or self.TradeMode == self.BUY_AND_SELL) and self.Position <= 0:
self.BuyMarket()
self._opened = True
elif sell_signal and (self.TradeMode == self.SELL or self.TradeMode == self.BUY_AND_SELL) and self.Position >= 0:
self.SellMarket()
self._opened = True
elif self._opened and hour >= int(self.CloseHour):
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
self._opened = False
self._prev_slow = slow_val
self._prev_fast = fast_val
def OnReseted(self):
super(opening_and_closing_on_time_v2_strategy, self).OnReseted()
self._prev_slow = 0.0
self._prev_fast = 0.0
self._opened = False
def CreateClone(self):
return opening_and_closing_on_time_v2_strategy()