Los Pivot Points diarios y sus niveles de soporte y resistencia a menudo actúan como puntos de giro para la acción del precio intradía. Esta estrategia calcula los pivotes clásicos del floor-trader a partir del máximo, mínimo y cierre del día anterior, y luego busca velas que reboten desde S1 o R1.
Las pruebas indican un rendimiento anual promedio de aproximadamente el 127%. Funciona mejor en el mercado de acciones.
Cuando el precio se acerca al nivel de soporte S1 y forma una vela alcista, se toma una entrada larga. Si el precio prueba el nivel de resistencia R1 e imprime una vela bajista, se abre un corto. Las operaciones salen al alcanzar el pivot central o si se activa el stop de protección.
El método se restablece al inicio de cada sesión de negociación con nuevos cálculos de pivote, lo que lo hace muy adecuado para sesiones con rangos intradía claros.
Detalles
Criterios de entrada: Vela alcista cerca de S1 o vela bajista cerca de R1.
Largo/Corto: Ambos.
Criterios de salida: Precio cruzando el pivot central o stop-loss.
Stops: Sí, basados en porcentaje.
Valores predeterminados:
CandleType = 5 minute
StopLossPercent = 2
Filtros:
Categoría: Reversión a la media
Dirección: Ambos
Indicadores: Pivot Points
Stops: Sí
Complejidad: Intermedio
Marco temporal: Intradía
Estacionalidad: Sí
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
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()