Tägliche Pivot Points und ihre Unterstützungs- und Widerstandsniveaus fungieren häufig als Wendepunkte für die Intraday-Kursentwicklung. Diese Strategie berechnet die klassischen Floor-Trader-Pivots aus dem Hoch, Tief und Schlusskurs des Vortages und sucht dann nach Kerzen, die von S1 oder R1 abprallen.
Tests zeigen eine durchschnittliche Jahresrendite von etwa 127%. Die Strategie eignet sich am besten für den Aktienmarkt.
Wenn der Kurs das Unterstützungsniveau S1 erreicht und eine bullische Kerze bildet, wird eine Long-Position eröffnet. Wenn der Kurs das Widerstandsniveau R1 testet und eine bearische Kerze druckt, wird ein Short eröffnet. Trades werden beim Erreichen des zentralen Pivots oder beim Auslösen des Schutzstops beendet.
Die Methode wird zu Beginn jedes Handelstages mit neuen Pivot-Berechnungen zurückgesetzt, was sie für Handelssitzungen mit klaren Intraday-Spannen gut geeignet macht.
Details
Einstiegskriterien: Bullische Kerze nahe S1 oder bearische Kerze nahe R1.
Long/Short: Beide.
Ausstiegskriterien: Kurs kreuzt den zentralen Pivot oder Stop-Loss.
Stops: Ja, prozentbasiert.
Standardwerte:
CandleType = 5 minute
StopLossPercent = 2
Filter:
Kategorie: Mean Reversion
Richtung: Beide
Indikatoren: Pivot Points
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>
/// Pivot Point Reversal strategy.
/// Calculates pivot points from a rolling window of highs, lows, closes.
/// P = (H + L + C) / 3, S1 = 2*P - H, R1 = 2*P - L
/// Buys on bounce off S1, sells on bounce off R1, exits at pivot.
/// </summary>
public class PivotPointReversalStrategy : Strategy
{
private readonly StrategyParam<int> _lookback;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private readonly List<decimal> _highs = new();
private readonly List<decimal> _lows = new();
private readonly List<decimal> _closes = new();
private int _cooldown;
/// <summary>
/// Lookback period for pivot calculation.
/// </summary>
public int Lookback
{
get => _lookback.Value;
set => _lookback.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public PivotPointReversalStrategy()
{
_lookback = Param(nameof(Lookback), 60)
.SetGreaterThanZero()
.SetDisplay("Lookback", "Lookback for pivot calc", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highs.Clear();
_lows.Clear();
_closes.Clear();
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highs.Clear();
_lows.Clear();
_closes.Clear();
_cooldown = 0;
var sma = new SimpleMovingAverage { Length = 20 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal smaValue)
{
if (candle.State != CandleStates.Finished)
return;
_highs.Add(candle.HighPrice);
_lows.Add(candle.LowPrice);
_closes.Add(candle.ClosePrice);
if (_highs.Count > Lookback)
{
_highs.RemoveAt(0);
_lows.RemoveAt(0);
_closes.RemoveAt(0);
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_highs.Count < Lookback)
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
// Calculate pivot points from lookback window
decimal high = decimal.MinValue, low = decimal.MaxValue, close = 0;
for (int i = 0; i < _highs.Count; i++)
{
if (_highs[i] > high) high = _highs[i];
if (_lows[i] < low) low = _lows[i];
}
close = _closes[_closes.Count - 1];
var pivot = (high + low + close) / 3;
var r1 = 2 * pivot - low;
var s1 = 2 * pivot - high;
var buffer = (r1 - s1) * 0.02m;
if (buffer <= 0)
return;
var isBullish = candle.ClosePrice > candle.OpenPrice;
var isBearish = candle.ClosePrice < candle.OpenPrice;
// Bounce off S1 (buy)
if (Position == 0 && candle.LowPrice <= s1 + buffer && isBullish)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Bounce off R1 (sell)
else if (Position == 0 && candle.HighPrice >= r1 - buffer && isBearish)
{
SellMarket();
_cooldown = CooldownBars;
}
// Exit at pivot
else if (Position > 0 && candle.ClosePrice > pivot)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && candle.ClosePrice < pivot)
{
BuyMarket();
_cooldown = CooldownBars;
}
}
}
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 pivot_point_reversal_strategy(Strategy):
"""
Pivot Point Reversal strategy.
Calculates pivot points from a rolling window of highs, lows, closes.
P = (H + L + C) / 3, S1 = 2*P - H, R1 = 2*P - L
Buys on bounce off S1, sells on bounce off R1, exits at pivot.
"""
def __init__(self):
super(pivot_point_reversal_strategy, self).__init__()
self._lookback = self.Param("Lookback", 60).SetDisplay("Lookback", "Lookback for pivot calc", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._highs = []
self._lows = []
self._closes = []
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(pivot_point_reversal_strategy, self).OnReseted()
self._highs = []
self._lows = []
self._closes = []
self._cooldown = 0
def OnStarted2(self, time):
super(pivot_point_reversal_strategy, self).OnStarted2(time)
self._highs = []
self._lows = []
self._closes = []
self._cooldown = 0
sma = SimpleMovingAverage()
sma.Length = 20
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, sma_val):
if candle.State != CandleStates.Finished:
return
self._highs.append(float(candle.HighPrice))
self._lows.append(float(candle.LowPrice))
self._closes.append(float(candle.ClosePrice))
lb = self._lookback.Value
if len(self._highs) > lb:
self._highs.pop(0)
self._lows.pop(0)
self._closes.pop(0)
if len(self._highs) < lb:
return
if self._cooldown > 0:
self._cooldown -= 1
return
# Calculate pivot points from lookback window
high = max(self._highs)
low = min(self._lows)
close = self._closes[-1]
pivot = (high + low + close) / 3.0
r1 = 2.0 * pivot - low
s1 = 2.0 * pivot - high
buffer = (r1 - s1) * 0.02
if buffer <= 0:
return
is_bullish = candle.ClosePrice > candle.OpenPrice
is_bearish = candle.ClosePrice < candle.OpenPrice
cd = self._cooldown_bars.Value
# Bounce off S1 (buy)
if self.Position == 0 and float(candle.LowPrice) <= s1 + buffer and is_bullish:
self.BuyMarket()
self._cooldown = cd
# Bounce off R1 (sell)
elif self.Position == 0 and float(candle.HighPrice) >= r1 - buffer and is_bearish:
self.SellMarket()
self._cooldown = cd
# Exit at pivot
elif self.Position > 0 and float(candle.ClosePrice) > pivot:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and float(candle.ClosePrice) < pivot:
self.BuyMarket()
self._cooldown = cd
def CreateClone(self):
return pivot_point_reversal_strategy()