Pre-Holiday Strength Strategy
Pre-Holiday Strength refers to the bullish tendency just before major market holidays when volume is lighter and sentiment optimistic. Traders often position ahead of the break, pushing prices higher in the final session or two.
Testing indicates an average annual return of about 109%. It performs best in the crypto market.
The strategy goes long on the day before a holiday and exits the following session or at the close, capturing that short-term bias.
A tight stop is used in case the expected lift doesn't occur.
Details
- Entry Criteria: calendar effect triggers
- Long/Short: Both
- Exit Criteria: stop-loss or opposite signal
- Stops: Yes, percent based
- Default Values:
CandleType= 15 minuteStopLoss= 2%
- Filters:
- Category: Seasonality
- Direction: Both
- Indicators: Seasonality
- Stops: Yes
- Complexity: Intermediate
- Timeframe: Intraday
- Seasonality: Yes
- Neural networks: No
- Divergence: No
- Risk level: Medium
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>
/// Implementation of Pre-Holiday Strength trading strategy.
/// Buys on Thursday (pre-weekend strength effect) if above MA, exits Monday.
/// Also buys before month-end holidays (last 2 days of month).
/// </summary>
public class PreHolidayStrengthStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _ma;
private int _cooldown;
private DayOfWeek _prevDayOfWeek;
private bool _enteredThisDay;
/// <summary>
/// Moving average period.
/// </summary>
public int MaPeriod
{
get => _maPeriod.Value;
set => _maPeriod.Value = value;
}
/// <summary>
/// Candle type for strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="PreHolidayStrengthStrategy"/>.
/// </summary>
public PreHolidayStrengthStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period", "Strategy");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for strategy", "Strategy");
_cooldownBars = Param(nameof(CooldownBars), 30)
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
.SetRange(5, 500);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ma = default;
_cooldown = 0;
_prevDayOfWeek = DayOfWeek.Sunday;
_enteredThisDay = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ma = new SimpleMovingAverage { Length = MaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal maValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
var dayOfWeek = candle.OpenTime.DayOfWeek;
// Reset entry flag on new day
if (dayOfWeek != _prevDayOfWeek)
_enteredThisDay = false;
if (_cooldown > 0)
{
_cooldown--;
_prevDayOfWeek = dayOfWeek;
return;
}
// Pre-weekend buy: Thursday if above MA
if (dayOfWeek == DayOfWeek.Thursday && !_enteredThisDay && Position == 0 && close > maValue)
{
BuyMarket();
_cooldown = CooldownBars;
_enteredThisDay = true;
}
// Exit on Monday
else if (dayOfWeek == DayOfWeek.Monday && Position > 0 && !_enteredThisDay)
{
SellMarket();
_cooldown = CooldownBars;
_enteredThisDay = true;
}
// Short on Tuesday if below MA
else if (dayOfWeek == DayOfWeek.Tuesday && !_enteredThisDay && Position == 0 && close < maValue)
{
SellMarket();
_cooldown = CooldownBars;
_enteredThisDay = true;
}
// Cover short on Wednesday
else if (dayOfWeek == DayOfWeek.Wednesday && Position < 0 && !_enteredThisDay)
{
BuyMarket();
_cooldown = CooldownBars;
_enteredThisDay = true;
}
_prevDayOfWeek = dayOfWeek;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, DayOfWeek
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class pre_holiday_strength_strategy(Strategy):
"""
Pre-Holiday Strength trading strategy.
Buys on Thursday (pre-weekend strength effect) if above MA, exits Monday.
Shorts on Tuesday if below MA, covers Wednesday.
"""
def __init__(self):
super(pre_holiday_strength_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 20).SetDisplay("MA Period", "Moving average period", "Strategy")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles for strategy", "Strategy")
self._cooldown_bars = self.Param("CooldownBars", 30).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._cooldown = 0
self._prev_day_of_week = DayOfWeek.Sunday
self._entered_this_day = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(pre_holiday_strength_strategy, self).OnReseted()
self._cooldown = 0
self._prev_day_of_week = DayOfWeek.Sunday
self._entered_this_day = False
def OnStarted2(self, time):
super(pre_holiday_strength_strategy, self).OnStarted2(time)
self._cooldown = 0
self._prev_day_of_week = DayOfWeek.Sunday
self._entered_this_day = False
sma = SimpleMovingAverage()
sma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ma = float(ma_val)
day_of_week = candle.OpenTime.DayOfWeek
cd = self._cooldown_bars.Value
# Reset entry flag on new day
if day_of_week != self._prev_day_of_week:
self._entered_this_day = False
if self._cooldown > 0:
self._cooldown -= 1
self._prev_day_of_week = day_of_week
return
# Pre-weekend buy: Thursday if above MA
if day_of_week == DayOfWeek.Thursday and not self._entered_this_day and self.Position == 0 and close > ma:
self.BuyMarket()
self._cooldown = cd
self._entered_this_day = True
# Exit on Monday
elif day_of_week == DayOfWeek.Monday and self.Position > 0 and not self._entered_this_day:
self.SellMarket()
self._cooldown = cd
self._entered_this_day = True
# Short on Tuesday if below MA
elif day_of_week == DayOfWeek.Tuesday and not self._entered_this_day and self.Position == 0 and close < ma:
self.SellMarket()
self._cooldown = cd
self._entered_this_day = True
# Cover short on Wednesday
elif day_of_week == DayOfWeek.Wednesday and self.Position < 0 and not self._entered_this_day:
self.BuyMarket()
self._cooldown = cd
self._entered_this_day = True
self._prev_day_of_week = day_of_week
def CreateClone(self):
return pre_holiday_strength_strategy()