Bounce-Strength-Index-Strategie
Diese Strategie implementiert eine vereinfachte Version des Bounce Strength Index (BSI). Der Indikator misst, wie der Kurs innerhalb einer jüngsten Spanne schließt, und wendet eine doppelte Glättung an, um Momentum-Wechsel hervorzuheben.
Logik
- Berechnung der jüngsten Höchst- und Tiefstkurse mit den Indikatoren Highest und Lowest.
- Bestimmung der Schlusskursposition innerhalb dieser Spanne und zweimalige Glättung des Ergebnisses mit SimpleMovingAverage.
- Wenn der Indikator nach oben dreht, werden Short-Positionen geschlossen und eine Long-Position eröffnet.
- Wenn der Indikator nach unten dreht, werden Long-Positionen geschlossen und eine Short-Position eröffnet.
Parameter
CandleType– Kerzenserie für die Analyse.RangePeriod– Lookback-Periode für die Berechnung der Spanne.Slowing– Länge der schnellen Glättung.AvgPeriod– Länge der langsamen Glättung.
Indikatoren
- BounceStrengthIndex (benutzerdefiniert)
- Highest
- Lowest
- SimpleMovingAverage
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>
/// Bounce Strength Index strategy.
/// Uses close price position within recent range to generate momentum signals.
/// </summary>
public class BounceStrengthIndexStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rangePeriod;
private readonly StrategyParam<int> _smaPeriod;
private readonly List<decimal> _highs = new();
private readonly List<decimal> _lows = new();
private decimal? _prevBsi;
private bool? _prevRising;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RangePeriod { get => _rangePeriod.Value; set => _rangePeriod.Value = value; }
public int SmaPeriod { get => _smaPeriod.Value; set => _smaPeriod.Value = value; }
public BounceStrengthIndexStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_rangePeriod = Param(nameof(RangePeriod), 10)
.SetDisplay("Range Period", "Period for highest and lowest search", "Indicator");
_smaPeriod = Param(nameof(SmaPeriod), 10)
.SetDisplay("SMA Period", "SMA period for trend filter", "Indicator");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_highs.Clear();
_lows.Clear();
_prevBsi = null;
_prevRising = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new ExponentialMovingAverage { Length = SmaPeriod };
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);
if (_highs.Count > RangePeriod) _highs.RemoveAt(0);
if (_lows.Count > RangePeriod) _lows.RemoveAt(0);
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_highs.Count < 3)
return;
var high = _highs.Max();
var low = _lows.Min();
var range = high - low;
if (range <= 0)
return;
var bsi = (candle.ClosePrice - low) / range * 100m;
if (_prevBsi is decimal prev)
{
var rising = bsi > prev;
if (rising && _prevRising != true && Position <= 0)
BuyMarket();
else if (!rising && _prevRising != false && Position >= 0)
SellMarket();
_prevRising = rising;
}
_prevBsi = bsi;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class bounce_strength_index_strategy(Strategy):
def __init__(self):
super(bounce_strength_index_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._range_period = self.Param("RangePeriod", 10) \
.SetDisplay("Range Period", "Period for highest and lowest search", "Indicator")
self._sma_period = self.Param("SmaPeriod", 10) \
.SetDisplay("SMA Period", "SMA period for trend filter", "Indicator")
self._highs = []
self._lows = []
self._prev_bsi = None
self._prev_rising = None
@property
def candle_type(self):
return self._candle_type.Value
@property
def range_period(self):
return self._range_period.Value
@property
def sma_period(self):
return self._sma_period.Value
def OnReseted(self):
super(bounce_strength_index_strategy, self).OnReseted()
self._highs = []
self._lows = []
self._prev_bsi = None
self._prev_rising = None
def OnStarted2(self, time):
super(bounce_strength_index_strategy, self).OnStarted2(time)
sma = ExponentialMovingAverage()
sma.Length = self.sma_period
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_value):
if candle.State != CandleStates.Finished:
return
rp = int(self.range_period)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
self._highs.append(high)
self._lows.append(low)
if len(self._highs) > rp:
self._highs.pop(0)
if len(self._lows) > rp:
self._lows.pop(0)
if len(self._highs) < 3:
return
h = max(self._highs)
l = min(self._lows)
rng = h - l
if rng <= 0:
return
bsi = (close - l) / rng * 100.0
if self._prev_bsi is not None:
rising = bsi > self._prev_bsi
if rising and self._prev_rising != True and self.Position <= 0:
self.BuyMarket()
elif not rising and self._prev_rising != False and self.Position >= 0:
self.SellMarket()
self._prev_rising = rising
self._prev_bsi = bsi
def CreateClone(self):
return bounce_strength_index_strategy()