Mittagsumkehr-Strategie
Die Mittagsumkehr sucht nach Wendepunkten, die gegen Mittag auftreten, wenn Morgendliche Trends oft erschöpft sind. Die Liquidität trocknet typischerweise in der Mitte der Sitzung aus, was zu Umkehrungen führt, wenn Trader Positionen glattstellen.
Tests zeigen eine durchschnittliche jährliche Rendite von etwa 121%. Sie funktioniert am besten im Kryptomarkt.
Das System überwacht eine Momentumverschiebung gegen Mittag und tritt entgegen der Morgenrichtung ein.
Ein prozentualer Stop kontrolliert das Risiko, und Positionen werden geschlossen, wenn sich die Umkehr bis zum Nachmittag nicht entwickelt.
Details
- Einstiegskriterien: Indikatorsignal
- Long/Short: Beide
- Ausstiegskriterien: Stop-Loss oder entgegengesetztes Signal
- Stops: Ja, prozentbasiert
- Standardwerte:
CandleType= 15 minuteStopLoss= 2%
- Filter:
- Kategorie: Intraday
- Richtung: Beide
- Indikatoren: Price Action
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Intraday
- Saisonalität: Nein
- 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 Midday Reversal trading strategy.
/// Trades on price reversals that occur around midday, using MA for trend confirmation.
/// </summary>
public class MiddayReversalStrategy : Strategy
{
private readonly StrategyParam<int> _maPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private SimpleMovingAverage _ma;
private decimal _prevClose;
private decimal _prevPrevClose;
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="MiddayReversalStrategy"/>.
/// </summary>
public MiddayReversalStrategy()
{
_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;
_prevClose = 0;
_prevPrevClose = 0;
_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 hour = candle.OpenTime.Hour;
if (_prevClose == 0)
{
_prevClose = close;
return;
}
if (_prevPrevClose == 0)
{
_prevPrevClose = _prevClose;
_prevClose = close;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevPrevClose = _prevClose;
_prevClose = close;
return;
}
// Midday zone: hours 11-14
var isMidday = hour >= 11 && hour <= 14;
var isBullishCandle = close > candle.OpenPrice;
var isBearishCandle = close < candle.OpenPrice;
var wasPriceDecreasing = _prevClose < _prevPrevClose;
var wasPriceIncreasing = _prevClose > _prevPrevClose;
// Buy at midday reversal: previous decline then bullish candle
if (isMidday && wasPriceDecreasing && isBullishCandle && Position == 0)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Sell short at midday reversal: previous increase then bearish candle
else if (isMidday && wasPriceIncreasing && isBearishCandle && Position == 0)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit on MA cross
if (Position > 0 && close < maValue)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && close > maValue)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevPrevClose = _prevClose;
_prevClose = close;
}
}
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 midday_reversal_strategy(Strategy):
"""
Midday Reversal: trades on price reversals around midday hours, using MA for exit.
"""
def __init__(self):
super(midday_reversal_strategy, self).__init__()
self._ma_period = self.Param("MaPeriod", 20).SetDisplay("MA Period", "Moving average period", "Strategy")
self._cooldown_bars = self.Param("CooldownBars", 30).SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Timeframe", "General")
self._prev_close = 0.0
self._prev_prev_close = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(midday_reversal_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_prev_close = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(midday_reversal_strategy, self).OnStarted2(time)
ma = SimpleMovingAverage()
ma.Length = self._ma_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
hour = candle.OpenTime.Hour
if self._prev_close == 0:
self._prev_close = close
return
if self._prev_prev_close == 0:
self._prev_prev_close = self._prev_close
self._prev_close = close
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_prev_close = self._prev_close
self._prev_close = close
return
is_midday = hour >= 11 and hour <= 14
is_bullish = close > float(candle.OpenPrice)
is_bearish = close < float(candle.OpenPrice)
was_decreasing = self._prev_close < self._prev_prev_close
was_increasing = self._prev_close > self._prev_prev_close
if is_midday and was_decreasing and is_bullish and self.Position == 0:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
elif is_midday and was_increasing and is_bearish and self.Position == 0:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
ma = float(ma_val)
if self.Position > 0 and close < ma:
self.SellMarket()
self._cooldown = self._cooldown_bars.Value
elif self.Position < 0 and close > ma:
self.BuyMarket()
self._cooldown = self._cooldown_bars.Value
self._prev_prev_close = self._prev_close
self._prev_close = close
def CreateClone(self):
return midday_reversal_strategy()