Monatsend-Stärke-Strategie
Die Monatsend-Stärke beobachtet, dass Aktien häufig in den letzten Handelstagen steigen, da Portfoliomanager ihre Positionen anpassen. Kaufdruck durch Window Dressing kann einen zuverlässigen Aufwärtstrend vor dem Monatsschluss erzeugen.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 94%. Es funktioniert am besten auf dem Aktienmarkt.
Die Strategie kauft kurz vor den letzten Tagen des Monats und steigt am ersten Handelstag des neuen Monats aus, um diese Tendenz zu nutzen.
Stops werden unterhalb des jüngsten Supports platziert, um sich gegen unerwartete Schwäche zu schützen.
Details
- Einstiegskriterien: Kalendereffekt-Auslöser
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 minuteStopLoss= 2%
- Filter:
- Kategorie: Saisonalität
- Richtung: Beide
- Indikatoren: Saisonalität
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Intraday
- Saisonalität: Ja
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
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 End of Month Strength trading strategy.
/// Buys on the last week of the month, exits on the first week of the next month.
/// Also sells short in mid-month if price below MA.
/// </summary>
public class EndOfMonthStrengthStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _ma;
private int _cooldown;
private int _prevDayOfMonth;
private int _prevMonth;
/// <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="EndOfMonthStrengthStrategy"/>.
/// </summary>
public EndOfMonthStrengthStrategy()
{
_maPeriod = Param(nameof(MaPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("MA Period", "Moving average period for trend confirmation", "Strategy");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles for strategy", "Strategy");
_cooldownBars = Param(nameof(CooldownBars), 50)
.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;
_prevDayOfMonth = 0;
_prevMonth = 0;
}
/// <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 dayOfMonth = candle.OpenTime.Day;
var month = candle.OpenTime.Month;
// Detect new day transition
var isNewDay = dayOfMonth != _prevDayOfMonth;
if (_cooldown > 0)
{
_cooldown--;
_prevDayOfMonth = dayOfMonth;
_prevMonth = month;
return;
}
// End-of-month zone: day >= 24
var isEndOfMonth = dayOfMonth >= 24;
// Beginning-of-month zone: day <= 5
var isBeginOfMonth = dayOfMonth <= 5;
// Mid-month zone: day between 10 and 20
var isMidMonth = dayOfMonth >= 10 && dayOfMonth <= 20;
// Entry: buy at end of month if flat
if (isEndOfMonth && isNewDay && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Exit: sell at beginning of next month
else if (isBeginOfMonth && isNewDay && Position > 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Short in mid-month if below MA
else if (isMidMonth && isNewDay && Position == 0 && close < maValue)
{
SellMarket();
_cooldown = CooldownBars;
}
// Cover short at end of month
else if (isEndOfMonth && isNewDay && Position < 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevDayOfMonth = dayOfMonth;
_prevMonth = month;
}
}
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
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class end_of_month_strength_strategy(Strategy):
"""
End of Month Strength trading strategy.
Buys on the last week of the month, exits on the first week of the next month.
Also sells short in mid-month if price below MA.
"""
def __init__(self):
super(end_of_month_strength_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 20).SetDisplay("MA Period", "Moving average period for trend confirmation", "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", 50).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._cooldown = 0
self._prev_day_of_month = 0
self._prev_month = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(end_of_month_strength_strategy, self).OnReseted()
self._cooldown = 0
self._prev_day_of_month = 0
self._prev_month = 0
def OnStarted2(self, time):
super(end_of_month_strength_strategy, self).OnStarted2(time)
self._cooldown = 0
self._prev_day_of_month = 0
self._prev_month = 0
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_month = candle.OpenTime.Day
month = candle.OpenTime.Month
cd = self._cooldown_bars.Value
is_new_day = day_of_month != self._prev_day_of_month
if self._cooldown > 0:
self._cooldown -= 1
self._prev_day_of_month = day_of_month
self._prev_month = month
return
is_end_of_month = day_of_month >= 24
is_begin_of_month = day_of_month <= 5
is_mid_month = day_of_month >= 10 and day_of_month <= 20
# Entry: buy at end of month if flat
if is_end_of_month and is_new_day and self.Position == 0:
self.BuyMarket()
self._cooldown = cd
# Exit: sell at beginning of next month
elif is_begin_of_month and is_new_day and self.Position > 0:
self.SellMarket()
self._cooldown = cd
# Short in mid-month if below MA
elif is_mid_month and is_new_day and self.Position == 0 and close < ma:
self.SellMarket()
self._cooldown = cd
# Cover short at end of month
elif is_end_of_month and is_new_day and self.Position < 0:
self.BuyMarket()
self._cooldown = cd
self._prev_day_of_month = day_of_month
self._prev_month = month
def CreateClone(self):
return end_of_month_strength_strategy()