Estrategia Dinámica de Pivote de Soporte y Resistencia
Esta estrategia deriva niveles dinámicos de soporte y resistencia a partir de máximos y mínimos de pivote recientes. Entra largo cuando el precio cruza por encima del soporte cerca del nivel y entra corto cuando el precio cruza por debajo de la resistencia. La gestión de riesgos utiliza niveles fijos de stop-loss y toma de ganancias en porcentaje.
Detalles
- Criterios de entrada: Precio cerca del soporte/resistencia dentro del porcentaje
SupportResistanceDistancey cruce por encima del soporte o por debajo de la resistencia. - Largo/Corto: Ambos.
- Criterios de salida: Toma de ganancias y stop-loss fijos.
- Stops: Sí.
- Valores predeterminados:
PivotLength= 2SupportResistanceDistance= 0.4mStopLossPercent= 10.0mTakeProfitPercent= 26.0mCandleType= TimeSpan.FromMinutes(5)
- Filtros:
- Categoría: Ruptura
- Dirección: Ambos
- Indicadores: Pivot
- Stops: Sí
- Complejidad: Principiante
- Marco temporal: Intradía
- Estacionalidad: No
- Redes neuronales: No
- Divergencia: No
- Nivel de riesgo: Medio
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Dynamic Support and Resistance Pivot strategy.
/// Support is the last pivot low and resistance the last pivot high, a pivot being a candle whose low (high) is beyond those of the
/// PivotLength candles on each side. A close crossing above support goes long and a close crossing below resistance goes short,
/// reversing an opposite position, when the close is within SupportResistanceDistance percent of that level. Percent stop loss and
/// take profit manage the position.
/// </summary>
public class DynamicSupportAndResistancePivotStrategy : Strategy
{
private readonly StrategyParam<int> _pivotLength;
private readonly StrategyParam<decimal> _supportResistanceDistance;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<decimal> _takeProfitPercent;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _highs = [];
private readonly List<decimal> _lows = [];
private decimal? _support;
private decimal? _resistance;
private decimal? _prevClose;
/// <summary>
/// Candles on each side of a pivot.
/// </summary>
public int PivotLength
{
get => _pivotLength.Value;
set => _pivotLength.Value = value;
}
/// <summary>
/// Maximum distance of the close from the level, in percent.
/// </summary>
public decimal SupportResistanceDistance
{
get => _supportResistanceDistance.Value;
set => _supportResistanceDistance.Value = value;
}
/// <summary>
/// Stop loss percentage from entry price.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Take profit percentage from entry price.
/// </summary>
public decimal TakeProfitPercent
{
get => _takeProfitPercent.Value;
set => _takeProfitPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public DynamicSupportAndResistancePivotStrategy()
{
_pivotLength = Param(nameof(PivotLength), 2)
.SetGreaterThanZero()
.SetDisplay("Pivot Length", "Candles on each side of a pivot", "Pivots");
_supportResistanceDistance = Param(nameof(SupportResistanceDistance), 0.4m)
.SetNotNegative()
.SetDisplay("S/R Distance %", "Maximum distance of the close from the level, in percent", "Pivots");
_stopLossPercent = Param(nameof(StopLossPercent), 10.0m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk");
_takeProfitPercent = Param(nameof(TakeProfitPercent), 26.0m)
.SetNotNegative()
.SetDisplay("Take Profit %", "Take profit 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();
ResetState();
}
private void ResetState()
{
_highs.Clear();
_lows.Clear();
_support = null;
_resistance = null;
_prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
ResetState();
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var take = TakeProfitPercent > 0 ? new Unit(TakeProfitPercent, UnitTypes.Percent) : new Unit();
var stop = StopLossPercent > 0 ? new Unit(StopLossPercent, UnitTypes.Percent) : new Unit();
StartProtection(take, stop, useMarketOrders: true);
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var length = PivotLength;
var size = length * 2 + 1;
_highs.Add(candle.HighPrice);
_lows.Add(candle.LowPrice);
if (_highs.Count > size)
{
_highs.RemoveAt(0);
_lows.RemoveAt(0);
}
if (_highs.Count == size)
{
var centerHigh = _highs[length];
var centerLow = _lows[length];
var isPivotHigh = true;
var isPivotLow = true;
for (var i = 0; i < size; i++)
{
if (i == length)
continue;
if (_highs[i] >= centerHigh)
isPivotHigh = false;
if (_lows[i] <= centerLow)
isPivotLow = false;
}
if (isPivotHigh)
_resistance = centerHigh;
if (isPivotLow)
_support = centerLow;
}
var close = candle.ClosePrice;
var prevClose = _prevClose;
_prevClose = close;
if (prevClose is not decimal pc)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var maxDistance = SupportResistanceDistance / 100m;
var longSignal = _support is decimal support && support > 0
&& pc <= support && close > support
&& Math.Abs(close - support) / support <= maxDistance;
var shortSignal = _resistance is decimal resistance && resistance > 0
&& pc >= resistance && close < resistance
&& Math.Abs(close - resistance) / resistance <= maxDistance;
if (longSignal && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortSignal && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class dynamic_support_and_resistance_pivot_strategy(Strategy):
"""
Dynamic Support and Resistance Pivot strategy.
Support is the last pivot low and resistance the last pivot high, a pivot being a candle whose low (high) is beyond those of the
PivotLength candles on each side. A close crossing above support goes long and a close crossing below resistance goes short,
reversing an opposite position, when the close is within SupportResistanceDistance percent of that level. Percent stop loss and
take profit manage the position.
"""
def __init__(self):
super(dynamic_support_and_resistance_pivot_strategy, self).__init__()
self._pivot_length = self.Param("PivotLength", 2).SetGreaterThanZero().SetDisplay("Pivot Length", "Candles on each side of a pivot", "Pivots")
self._support_resistance_distance = self.Param("SupportResistanceDistance", 0.4).SetNotNegative().SetDisplay("S/R Distance %", "Maximum distance of the close from the level, in percent", "Pivots")
self._stop_loss_percent = self.Param("StopLossPercent", 10.0).SetNotNegative().SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk")
self._take_profit_percent = self.Param("TakeProfitPercent", 26.0).SetNotNegative().SetDisplay("Take Profit %", "Take profit 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._reset_state()
@property
def candle_type(self):
return self._candle_type.Value
def _reset_state(self):
self._highs = []
self._lows = []
self._support = None
self._resistance = None
self._prev_close = None
def OnReseted(self):
super(dynamic_support_and_resistance_pivot_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(dynamic_support_and_resistance_pivot_strategy, self).OnStarted2(time)
self._reset_state()
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._process_candle).Start()
take_percent = Decimal(self._take_profit_percent.Value)
stop_percent = Decimal(self._stop_loss_percent.Value)
take = Unit(take_percent, UnitTypes.Percent) if take_percent > 0 else Unit()
stop = Unit(stop_percent, UnitTypes.Percent) if stop_percent > 0 else Unit()
self.StartProtection(take, stop, useMarketOrders=True)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
length = self._pivot_length.Value
size = length * 2 + 1
self._highs.append(candle.HighPrice)
self._lows.append(candle.LowPrice)
if len(self._highs) > size:
self._highs.pop(0)
self._lows.pop(0)
if len(self._highs) == size:
center_high = self._highs[length]
center_low = self._lows[length]
is_pivot_high = True
is_pivot_low = True
for i in range(size):
if i == length:
continue
if self._highs[i] >= center_high:
is_pivot_high = False
if self._lows[i] <= center_low:
is_pivot_low = False
if is_pivot_high:
self._resistance = center_high
if is_pivot_low:
self._support = center_low
close = candle.ClosePrice
pc = self._prev_close
self._prev_close = close
if pc is None:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
max_distance = Decimal(self._support_resistance_distance.Value) / Decimal(100)
support = self._support
resistance = self._resistance
long_signal = support is not None and support > 0 and pc <= support and close > support and \
abs(close - support) / support <= max_distance
short_signal = resistance is not None and resistance > 0 and pc >= resistance and close < resistance and \
abs(close - resistance) / resistance <= max_distance
if long_signal and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif short_signal and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
def CreateClone(self):
return dynamic_support_and_resistance_pivot_strategy()