Start
/
Strategie-Beispiele
Auf GitHub ansehen
Strategie Pivot Point Supertrend
Strategie, die Pivot Points mit einem ATR-basierten Supertrend kombiniert, um Trendwenden zu erfassen.
Pivot Points definieren eine dynamische Mittellinie. Ein ATR-Multiplikator bildet obere und untere Bänder, die dem Kurs folgen. Wenn der Trend die Richtung wechselt, eröffnet die Strategie entsprechend eine Position.
Details
Einstiegskriterien : Signale basierend auf Pivot Points und ATR Supertrend.
Long/Short : Beide Richtungen.
Ausstiegskriterien : Gegensätzliches Signal.
Stops : Nein.
Standardwerte :
PivotPeriod = 2
AtrFactor = 3m
AtrPeriod = 10
CandleType = TimeSpan.FromMinutes(5)
Filter :
Kategorie: Trend
Richtung: Beide
Indikatoren: Pivot Points, ATR
Stops: Nein
Komplexität: Grundlegend
Zeitrahmen: Intraday (5m)
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
Berechnung und Ausführung
Nur abgeschlossene Kerzen werden verwendet. Ein Pivot-Hoch/-Tief muss strikt über/unter allen PivotPeriod Kerzen auf jeder Seite liegen und wird erst nach Abschluss der rechten Kerzen bestätigt. Erfüllt eine Kerze beide Bedingungen, hat das Hoch Vorrang. Der erste Pivot initialisiert center; danach gilt (2 * center + pivot) / 3.
Die Pivot-Bänder verwenden Wilder ATR: Mittelwert der ersten AtrPeriod True Ranges, danach Glättung mit Gewicht 1 / AtrPeriod. Grundwerte für Unterstützung/Widerstand sind center ± AtrFactor * ATR. Unterstützung übernimmt das Maximum aus Grundwert und Vorwert, wenn der vorige Schlusskurs über der vorigen Unterstützung liegt; sonst wird sie zurückgesetzt. Widerstand übernimmt das Minimum, wenn der vorige Schlusskurs unter dem vorigen Widerstand liegt; sonst wird er zurückgesetzt. Schlusskurs strikt über dem vorigen Widerstand schaltet aufwärts, strikt unter der vorigen Unterstützung abwärts; sonst bleibt die Richtung. Initialrichtung ist aufwärts; Initialisierung ist kein Signal.
Wilder ATR und eine bestätigte Pivot-Mitte müssen bereit sein. Nur ein Richtungswechsel der Pivot-Bänder eröffnet eine Position: aufwärts Long, abwärts Short. Initialrichtung ist aufwärts; die Initialisierung erzeugt keine Order. Jedes Gegensignal kehrt die ganze Position mit einer Market-Order von Volume + abs(Position) um; ein Einstieg ohne Position nutzt Volume. Kein SMA, separater Preis-SuperTrend, Datumsfilter, keine Wartefrist und keine Schutzstopps.
Pivot-Konzept: Pivot Point Supertrend von LonesomeTheBlue . Die obigen Regeln definieren das bidirektionale Modell dieses Beispiels.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Trades direction changes of ATR bands around a center of confirmed swing pivots.
/// </summary>
public class PivotPointSupertrendStrategy : Strategy
{
private readonly StrategyParam<int> _pivotPeriod;
private readonly StrategyParam<decimal> _atrFactor;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly List<(decimal High, decimal Low)> _pivots = [];
private decimal? _center;
private decimal? _support;
private decimal? _resistance;
private decimal? _previousClose;
private bool? _pivotUp;
/// <summary>
/// Initializes the published pivot period, ATR settings and five-minute candles.
/// </summary>
public PivotPointSupertrendStrategy()
{
_pivotPeriod = Param(nameof(PivotPeriod), 2).SetGreaterThanZero()
.SetDisplay("Pivot Period", "Finished candles on each side of a confirmed pivot", "Indicators");
_atrFactor = Param(nameof(AtrFactor), 3m).SetGreaterThanZero()
.SetDisplay("ATR Factor", "ATR width of the pivot bands", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 10).SetGreaterThanZero()
.SetDisplay("ATR Period", "Wilder ATR period of the pivot bands", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of finished candles", "General");
}
/// <summary>
/// Number of finished candles required on each side of a pivot.
/// </summary>
public int PivotPeriod { get => _pivotPeriod.Value; set => _pivotPeriod.Value = value; }
/// <summary>
/// Wilder ATR multiplier for the pivot bands.
/// </summary>
public decimal AtrFactor { get => _atrFactor.Value; set => _atrFactor.Value = value; }
/// <summary>
/// Wilder ATR period.
/// </summary>
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
/// <summary>
/// Candle type; five minutes by default.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetSignals();
}
private void ResetSignals()
{
_pivots.Clear();
_center = _support = _resistance = _previousClose = null;
_pivotUp = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetSignals();
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(atr, ProcessCandle, allowEmpty: true).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue atrValue)
{
if (candle.State != CandleStates.Finished)
return;
var previousClose = _previousClose ?? candle.ClosePrice;
_previousClose = candle.ClosePrice;
_pivots.Add((candle.HighPrice, candle.LowPrice));
if (_pivots.Count > 2 * PivotPeriod + 1)
_pivots.RemoveAt(0);
if (_pivots.Count == 2 * PivotPeriod + 1)
{
var candidate = _pivots[PivotPeriod];
var isHigh = true;
var isLow = true;
for (var i = 0; i < _pivots.Count; i++)
{
if (i == PivotPeriod)
continue;
isHigh &= candidate.High > _pivots[i].High;
isLow &= candidate.Low < _pivots[i].Low;
}
if (isHigh || isLow)
{
var pivot = isHigh ? candidate.High : candidate.Low;
_center = _center is decimal center ? (2m * center + pivot) / 3m : pivot;
}
}
var previousPivotUp = _pivotUp;
if (_center is decimal pivotCenter && atrValue.IsFormed && !atrValue.IsEmpty)
{
var width = AtrFactor * atrValue.ToDecimal();
var oldSupport = _support;
var oldResistance = _resistance;
_support = oldSupport is decimal support && previousClose > support ? Math.Max(pivotCenter - width, support) : pivotCenter - width;
_resistance = oldResistance is decimal resistance && previousClose < resistance ? Math.Min(pivotCenter + width, resistance) : pivotCenter + width;
_pivotUp = oldResistance is decimal upper && candle.ClosePrice > upper ? true
: oldSupport is decimal lower && candle.ClosePrice < lower ? false : _pivotUp ?? true;
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (previousPivotUp == false && _pivotUp == true && Position <= 0m)
BuyMarket(Volume + Math.Abs(Position));
else if (previousPivotUp == true && _pivotUp == false && Position >= 0m)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import Decimal, TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class pivot_point_supertrend_strategy(Strategy):
def __init__(self):
super(pivot_point_supertrend_strategy, self).__init__()
self._pivot_period = self.Param("PivotPeriod", 2).SetGreaterThanZero() \
.SetDisplay("Pivot Period", "Finished candles on each side of a confirmed pivot", "Indicators")
self._atr_factor = self.Param("AtrFactor", Decimal.Parse("3")).SetGreaterThanZero() \
.SetDisplay("ATR Factor", "ATR width of the pivot bands", "Indicators")
self._atr_period = self.Param("AtrPeriod", 10).SetGreaterThanZero() \
.SetDisplay("ATR Period", "Wilder ATR period of the pivot bands", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of finished candles", "General")
self._reset_signals()
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def _reset_signals(self):
self._pivots = []
self._center = None
self._support = None
self._resistance = None
self._previous_close = None
self._pivot_up = None
def OnReseted(self):
super(pivot_point_supertrend_strategy, self).OnReseted()
self._reset_signals()
def OnStarted2(self, time):
super(pivot_point_supertrend_strategy, self).OnStarted2(time)
self._reset_signals()
atr = AverageTrueRange()
atr.Length = self._atr_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(atr, self.OnProcess, True).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def OnProcess(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
previous_close = candle.ClosePrice if self._previous_close is None else self._previous_close
self._previous_close = candle.ClosePrice
self._pivots.append((candle.HighPrice, candle.LowPrice))
period = self._pivot_period.Value
if len(self._pivots) > 2 * period + 1:
self._pivots.pop(0)
if len(self._pivots) == 2 * period + 1:
candidate = self._pivots[period]
neighbors = self._pivots[:period] + self._pivots[period + 1:]
is_high = all(candidate[0] > bar[0] for bar in neighbors)
is_low = all(candidate[1] < bar[1] for bar in neighbors)
if is_high or is_low:
pivot = candidate[0] if is_high else candidate[1]
self._center = pivot if self._center is None else (Decimal(2) * self._center + pivot) / Decimal(3)
previous_pivot_up = self._pivot_up
if self._center is not None and atr_value.IsFormed and not atr_value.IsEmpty:
width = self._atr_factor.Value * atr_value.GetValue[Decimal](None)
old_support = self._support
old_resistance = self._resistance
basic_support = self._center - width
basic_resistance = self._center + width
self._support = max(basic_support, old_support) if old_support is not None and previous_close > old_support else basic_support
self._resistance = min(basic_resistance, old_resistance) if old_resistance is not None and previous_close < old_resistance else basic_resistance
if old_resistance is not None and candle.ClosePrice > old_resistance:
self._pivot_up = True
elif old_support is not None and candle.ClosePrice < old_support:
self._pivot_up = False
elif self._pivot_up is None:
self._pivot_up = True
if not self.IsFormedAndOnlineAndAllowTrading():
return
if previous_pivot_up is False and self._pivot_up and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif previous_pivot_up is True and not self._pivot_up and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return pivot_point_supertrend_strategy()