Pivot Point Umkehrstrategie
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
Die Pivots jedes UTC-Tages stammen aus Hoch, Tief und Schluss des Vortags. Ein Long braucht eine bullische Kerze, die S1 berührt und darüber schließt, ein Short eine bärische Kerze, die R1 erreicht und darunter schließt; der Stop ist ein Prozentsatz des Einstiegskurses.
- 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.
/// Each day the classic floor pivots come from the previous day's high, low and close: P = (H + L + C) / 3, R1 = 2P - L, S1 = 2P - H.
/// While flat, a bullish candle that dips to S1 and closes above it buys, and a bearish candle that reaches R1 and closes below it sells.
/// The position closes when the close reaches the central pivot or at the percent stop.
/// </summary>
public class PivotPointReversalStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private DateTime? _day;
private decimal _dayHigh;
private decimal _dayLow;
private decimal _dayClose;
private (decimal Pivot, decimal R1, decimal S1)? _levels;
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public PivotPointReversalStrategy()
{
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_day = null;
_dayHigh = default;
_dayLow = default;
_dayClose = default;
_levels = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_day = null;
_levels = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(new Unit(), new Unit(StopLossPercent, UnitTypes.Percent), useMarketOrders: true, isLocalStop: true);
// The stop has to see prices between candles, not only at their close.
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quotes = new Subscription(DataType.Level1, Security);
quotes.MarketData.BuildField = field;
SubscribeLevel1(quotes).Bind(ObserveProtectionQuote).Start();
}
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ObserveProtectionQuote(Level1ChangeMessage quote)
{
// The high-level handler activates native protection before this callback, also between signal bars.
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var day = candle.OpenTime.Date;
if (_day != day)
{
// A new day takes its pivots from the day that has just ended.
if (_day != null)
{
var pivot = (_dayHigh + _dayLow + _dayClose) / 3m;
_levels = (pivot, 2 * pivot - _dayLow, 2 * pivot - _dayHigh);
}
_day = day;
_dayHigh = candle.HighPrice;
_dayLow = candle.LowPrice;
}
else
{
_dayHigh = Math.Max(_dayHigh, candle.HighPrice);
_dayLow = Math.Min(_dayLow, candle.LowPrice);
}
_dayClose = candle.ClosePrice;
if (_levels is not { } levels || !IsFormedAndOnlineAndAllowTrading())
return;
var close = candle.ClosePrice;
if (Position > 0)
{
if (close >= levels.Pivot)
SellMarket(Position);
}
else if (Position < 0)
{
if (close <= levels.Pivot)
BuyMarket(-Position);
}
else if (close > candle.OpenPrice && candle.LowPrice <= levels.S1 && close > levels.S1)
{
BuyMarket(Volume);
}
else if (close < candle.OpenPrice && candle.HighPrice >= levels.R1 && close < levels.R1)
{
SellMarket(Volume);
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
clr.AddReference("StockSharp.BusinessEntities")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes, Level1Fields
from StockSharp.BusinessEntities import Subscription
from StockSharp.Algo.Strategies import Strategy
class pivot_point_reversal_strategy(Strategy):
"""
Pivot Point Reversal strategy.
Each day the classic floor pivots come from the previous day's high, low and close: P = (H + L + C) / 3, R1 = 2P - L, S1 = 2P - H.
While flat, a bullish candle that dips to S1 and closes above it buys, and a bearish candle that reaches R1 and closes below it sells.
The position closes when the close reaches the central pivot or at the percent stop.
"""
def __init__(self):
super(pivot_point_reversal_strategy, self).__init__()
self._stop_loss_percent = self.Param("StopLossPercent", 2.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._day = None
self._day_high = Decimal(0)
self._day_low = Decimal(0)
self._day_close = Decimal(0)
self._levels = None
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(pivot_point_reversal_strategy, self).OnReseted()
self._day = None
self._day_high = Decimal(0)
self._day_low = Decimal(0)
self._day_close = Decimal(0)
self._levels = None
def OnStarted2(self, time):
super(pivot_point_reversal_strategy, self).OnStarted2(time)
self._day = None
self._levels = None
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
self.StartProtection(Unit(), Unit(Decimal(self._stop_loss_percent.Value), UnitTypes.Percent), useMarketOrders=True, isLocalStop=True)
# The stop has to see prices between candles, not only at their close.
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quotes = Subscription(DataType.Level1, self.Security)
quotes.MarketData.BuildField = field
self.SubscribeLevel1(quotes).Bind(self._observe_protection_quote).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _observe_protection_quote(self, quote):
# The high-level handler activates native protection before the callback, including between bars.
pass
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
day = candle.OpenTime.Date
if self._day is None or self._day != day:
# A new day takes its pivots from the day that has just ended.
if self._day is not None:
pivot = (self._day_high + self._day_low + self._day_close) / Decimal(3)
self._levels = (pivot, Decimal(2) * pivot - self._day_low, Decimal(2) * pivot - self._day_high)
self._day = day
self._day_high = candle.HighPrice
self._day_low = candle.LowPrice
else:
self._day_high = Math.Max(self._day_high, candle.HighPrice)
self._day_low = Math.Min(self._day_low, candle.LowPrice)
self._day_close = candle.ClosePrice
if self._levels is None or not self.IsFormedAndOnlineAndAllowTrading():
return
pivot, r1, s1 = self._levels
close = candle.ClosePrice
if self.Position > 0:
if close >= pivot:
self.SellMarket(self.Position)
elif self.Position < 0:
if close <= pivot:
self.BuyMarket(-self.Position)
elif close > candle.OpenPrice and candle.LowPrice <= s1 and close > s1:
self.BuyMarket(self.Volume)
elif close < candle.OpenPrice and candle.HighPrice >= r1 and close < r1:
self.SellMarket(self.Volume)
def CreateClone(self):
return pivot_point_reversal_strategy()