Turnaround Tuesday Strategie
Turnaround Tuesday beschreibt die Tendenz von Märkten, die am Montag gefallen sind, am nächsten Tag zu erholen. Der Effekt wird oft darauf zurückgeführt, dass Trader nach dem Wochenende überreagieren und dann den Kurs umkehren.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 91%. Es funktioniert am besten auf dem Aktienmarkt.
Diese Strategie kauft zur Eröffnung des Dienstags, wenn der Montag rückläufig war, und hält die Position nur für die Session oder bis ein moderates Gewinnziel erreicht wird.
Stops sind eng gesetzt, um bei anhaltender Schwäche zu schützen, falls der Aufschwung ausbleibt.
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 Turnaround Tuesday trading strategy.
/// Buys on Tuesday if previous session declined, sells on Friday or if price crosses MA.
/// Also goes short on Wednesday if previous session rallied.
/// Uses half-day detection to simulate daily sessions on intraday data.
/// </summary>
public class TurnaroundTuesdayStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _ma;
private decimal _prevMa;
private decimal _sessionOpen;
private decimal _sessionClose;
private int _prevSessionDay;
private bool _prevSessionDecline;
private bool _prevSessionRally;
private int _currentSessionDay;
private bool _enteredThisSession;
private int _cooldown;
/// <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="TurnaroundTuesdayStrategy"/>.
/// </summary>
public TurnaroundTuesdayStrategy()
{
_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), 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;
_prevMa = 0;
_sessionOpen = 0;
_sessionClose = 0;
_prevSessionDay = -1;
_prevSessionDecline = false;
_prevSessionRally = false;
_currentSessionDay = -1;
_enteredThisSession = false;
_cooldown = 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 dayOfYear = candle.OpenTime.DayOfYear;
var dayOfWeek = (int)candle.OpenTime.DayOfWeek;
// Detect new session (new calendar day)
if (dayOfYear != _currentSessionDay)
{
// Save previous session result
if (_currentSessionDay >= 0 && _sessionOpen > 0)
{
_prevSessionDecline = _sessionClose < _sessionOpen;
_prevSessionRally = _sessionClose > _sessionOpen;
_prevSessionDay = _currentSessionDay;
}
_currentSessionDay = dayOfYear;
_sessionOpen = candle.OpenPrice;
_enteredThisSession = false;
}
_sessionClose = close;
if (_cooldown > 0)
{
_cooldown--;
_prevMa = maValue;
return;
}
// Entry: buy on any day if previous session declined and no position
if (Position == 0 && !_enteredThisSession && _prevSessionDecline && close > maValue)
{
BuyMarket();
_cooldown = CooldownBars;
_enteredThisSession = true;
_prevSessionDecline = false;
}
// Entry: sell on any day if previous session rallied and no position
else if (Position == 0 && !_enteredThisSession && _prevSessionRally && close < maValue)
{
SellMarket();
_cooldown = CooldownBars;
_enteredThisSession = true;
_prevSessionRally = false;
}
// Exit long if price crosses below MA
if (Position > 0 && _prevMa > 0 && close < maValue)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit short if price crosses above MA
if (Position < 0 && _prevMa > 0 && close > maValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevMa = maValue;
}
}
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 turnaround_tuesday_strategy(Strategy):
"""
Turnaround Tuesday trading strategy.
Buys if previous session declined and price above MA.
Sells if previous session rallied and price below MA.
Uses session detection via day-of-year transitions.
"""
def __init__(self):
super(turnaround_tuesday_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", 30).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._prev_ma = 0.0
self._session_open = 0.0
self._session_close = 0.0
self._prev_session_day = -1
self._prev_session_decline = False
self._prev_session_rally = False
self._current_session_day = -1
self._entered_this_session = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(turnaround_tuesday_strategy, self).OnReseted()
self._prev_ma = 0.0
self._session_open = 0.0
self._session_close = 0.0
self._prev_session_day = -1
self._prev_session_decline = False
self._prev_session_rally = False
self._current_session_day = -1
self._entered_this_session = False
self._cooldown = 0
def OnStarted2(self, time):
super(turnaround_tuesday_strategy, self).OnStarted2(time)
self._prev_ma = 0.0
self._session_open = 0.0
self._session_close = 0.0
self._prev_session_day = -1
self._prev_session_decline = False
self._prev_session_rally = False
self._current_session_day = -1
self._entered_this_session = False
self._cooldown = 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_year = candle.OpenTime.DayOfYear
cd = self._cooldown_bars.Value
# Detect new session (new calendar day)
if day_of_year != self._current_session_day:
# Save previous session result
if self._current_session_day >= 0 and self._session_open > 0:
self._prev_session_decline = self._session_close < self._session_open
self._prev_session_rally = self._session_close > self._session_open
self._prev_session_day = self._current_session_day
self._current_session_day = day_of_year
self._session_open = float(candle.OpenPrice)
self._entered_this_session = False
self._session_close = close
if self._cooldown > 0:
self._cooldown -= 1
self._prev_ma = ma
return
# Entry: buy if previous session declined and no position
if self.Position == 0 and not self._entered_this_session and self._prev_session_decline and close > ma:
self.BuyMarket()
self._cooldown = cd
self._entered_this_session = True
self._prev_session_decline = False
# Entry: sell if previous session rallied and no position
elif self.Position == 0 and not self._entered_this_session and self._prev_session_rally and close < ma:
self.SellMarket()
self._cooldown = cd
self._entered_this_session = True
self._prev_session_rally = False
# Exit long if price crosses below MA
if self.Position > 0 and self._prev_ma > 0 and close < ma:
self.SellMarket()
self._cooldown = cd
# Exit short if price crosses above MA
if self.Position < 0 and self._prev_ma > 0 and close > ma:
self.BuyMarket()
self._cooldown = cd
self._prev_ma = ma
def CreateClone(self):
return turnaround_tuesday_strategy()