Die Berlin-Range-Index-Strategie filtert den Standard-Choppiness-Index mit einem ATR-basierten Faktor, um Trend- und Seitwärtsphasen hervorzuheben. Wenn der gefilterte Index unter einen Mindestschwellenwert fällt, öffnet die Strategie eine Position in Richtung der aktuellen Kerze. Positionen werden geschlossen, wenn der Index eine Seitwärtsbewegung oder einen sich abschwächenden Trend anzeigt.
Details
Einstiegskriterien:
Gefilterter Bereichsindex unterhalb von ChopMin und Kerzenrichtung bestimmt Long oder Short.
Ausstiegskriterien:
Bereichsindex oberhalb von ChopMax oder sich abschwächender Trend.
Stops: Keine.
Standardwerte:
Length = 9
ChopMax = 40
ChopMin = 10
AtrLength = 14
LowLookback = 14
UseNormalized = true
StdDevLength = 14
Filter:
Kategorie: Trendfolge
Richtung: Beide
Indikatoren: Choppiness Index, ATR, Standard Deviation
Komplexität: Mittel
Zeitrahmen: Beliebig
Saisonalität: Nein
Neuronale Netze: Nein
Divergenz: Nein
Risikolevel: Mittel
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()