La estrategia Berlin Range Index filtra el Índice de Choppiness estándar con un factor basado en ATR para resaltar las fases de tendencia y de rango. Cuando el índice filtrado cae por debajo de un umbral mínimo, la estrategia abre una posición en la dirección de la vela actual. Las posiciones se cierran cuando el índice indica una fase de rango o una tendencia debilitada.
Detalles
Criterios de entrada:
Índice de rango filtrado por debajo de ChopMin y la dirección de la vela define largo o corto.
Criterios de salida:
Índice de rango por encima de ChopMax o tendencia debilitada.
Stops: Ninguno.
Valores predeterminados:
Length = 9
ChopMax = 40
ChopMin = 10
AtrLength = 14
LowLookback = 14
UseNormalized = true
StdDevLength = 14
Filtros:
Categoría: Seguimiento de tendencia
Dirección: Ambos
Indicadores: Choppiness Index, ATR, Standard Deviation
Complejidad: Medio
Marco temporal: Cualquiera
Estacionalidad: No
Redes neuronales: No
Divergencia: No
Nivel de riesgo: Medio
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Berlin Range Index strategy.
/// Uses choppiness index to detect trending vs ranging markets.
/// Enters in trend direction when choppiness is low (strong trend).
/// Exits when choppiness is high (choppy/ranging market).
/// </summary>
public class BerlinRangeIndexStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _chopThreshold;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevChop;
public int Length { get => _length.Value; set => _length.Value = value; }
public decimal ChopThreshold { get => _chopThreshold.Value; set => _chopThreshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BerlinRangeIndexStrategy()
{
_length = Param(nameof(Length), 7)
.SetGreaterThanZero()
.SetDisplay("Length", "Choppiness index period", "General")
.SetOptimize(5, 30, 5);
_chopThreshold = Param(nameof(ChopThreshold), 55m)
.SetDisplay("Chop Threshold", "Threshold for trend vs range", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
protected override void OnReseted()
{
base.OnReseted();
_prevChop = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var choppiness = new ChoppinessIndex { Length = Length };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(choppiness, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, choppiness);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal chopValue)
{
if (candle.State != CandleStates.Finished)
return;
if (_prevChop == 0)
{
_prevChop = chopValue;
return;
}
// Low choppiness = strong trend; enter in candle direction
if (chopValue < ChopThreshold && _prevChop >= ChopThreshold)
{
if (candle.ClosePrice > candle.OpenPrice && Position <= 0)
BuyMarket();
else if (candle.ClosePrice < candle.OpenPrice && Position >= 0)
SellMarket();
}
// High choppiness = choppy market; exit positions
else if (chopValue > ChopThreshold && _prevChop <= ChopThreshold)
{
if (Position > 0)
SellMarket();
else if (Position < 0)
BuyMarket();
}
_prevChop = chopValue;
}
}
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 ChoppinessIndex
from StockSharp.Algo.Strategies import Strategy
class berlin_range_index_strategy(Strategy):
def __init__(self):
super(berlin_range_index_strategy, self).__init__()
self._length = self.Param("Length", 7) \
.SetGreaterThanZero() \
.SetDisplay("Length", "Choppiness index period", "General")
self._chop_threshold = self.Param("ChopThreshold", 55.0) \
.SetDisplay("Chop Threshold", "Threshold for trend vs range", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_chop = 0.0
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
def OnReseted(self):
super(berlin_range_index_strategy, self).OnReseted()
self._prev_chop = 0.0
def OnStarted2(self, time):
super(berlin_range_index_strategy, self).OnStarted2(time)
chop = ChoppinessIndex()
chop.Length = self._length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(chop, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, chop)
self.DrawOwnTrades(area)
def OnProcess(self, candle, chop_val):
if candle.State != CandleStates.Finished:
return
chop_v = float(chop_val)
if self._prev_chop == 0:
self._prev_chop = chop_v
return
threshold = float(self._chop_threshold.Value)
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
if chop_v < threshold and self._prev_chop >= threshold:
if close > open_p and self.Position <= 0:
self.BuyMarket()
elif close < open_p and self.Position >= 0:
self.SellMarket()
elif chop_v > threshold and self._prev_chop <= threshold:
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
self._prev_chop = chop_v
def CreateClone(self):
return berlin_range_index_strategy()