Bollinger Heikin Ashi Einstiegs-Strategie
Strategie, die Bollinger Bands auf Heikin Ashi Kerzen anwendet. Kauft nach zwei aufeinanderfolgenden bearischen Heikin Ashi Kerzen, die die untere Band berühren, gefolgt von einer bullischen Kerze darüber. Verkauft in umgekehrter Richtung.
Nach dem Einstieg wird ein erstes Ziel in Höhe des Risikos genommen und der Stop wird mit den Extremen der vorherigen Kerze nachgezogen.
Details
- Einstiegskriterien:
- Long: zwei bearische HA-Kerzen, die die untere Band berühren, dann bullisch darüber
- Short: zwei bullische HA-Kerzen, die die obere Band berühren, dann bearisch darunter
- Long/Short: Beide
- Ausstiegskriterien:
- Long: erstes Ziel bei 1R, dann Trailing-Stop an vorherigen Tiefs
- Short: erstes Ziel bei 1R, dann Trailing-Stop an vorherigen Hochs
- Stops: Tief/Hoch der vorherigen Kerze
- Standardwerte:
BollingerPeriod= 20BollingerDeviation= 2mCandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filter:
- Kategorie: Umkehr
- Richtung: Beide
- Indikatoren: Bollinger Bands, Heikin Ashi
- Stops: Ja
- Komplexität: Mittel
- Zeitrahmen: Mittelfristig
- 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;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy using Bollinger Bands with Heikin Ashi entries.
/// </summary>
public class BollingerHeikinAshiEntryStrategy : Strategy
{
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
private decimal _initialStop;
private decimal _firstTarget;
private bool _firstTargetReached;
private decimal _trailStop;
private bool _isHaInitialized;
private decimal _haOpen1;
private decimal _haClose1;
private decimal _haHigh1;
private decimal _haLow1;
private decimal _haOpen2;
private decimal _haClose2;
private decimal _haHigh2;
private decimal _haLow2;
private decimal _upperBb1;
private decimal _lowerBb1;
private decimal _upperBb2;
private decimal _lowerBb2;
private decimal _prevHigh;
private decimal _prevLow;
private int _cooldown;
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public BollingerHeikinAshiEntryStrategy()
{
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetDisplay("Bollinger Period", "Bollinger Bands length", "Indicators")
.SetOptimize(10, 50, 5);
_bollingerDeviation = Param(nameof(BollingerDeviation), 1.5m)
.SetDisplay("Bollinger Deviation", "Bollinger Bands standard deviation", "Indicators")
.SetOptimize(1m, 3m, 0.5m);
_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();
_entryPrice = default;
_initialStop = default;
_firstTarget = default;
_firstTargetReached = default;
_trailStop = default;
_isHaInitialized = default;
_haOpen1 = default;
_haClose1 = default;
_haHigh1 = default;
_haLow1 = default;
_haOpen2 = default;
_haClose2 = default;
_haHigh2 = default;
_haLow2 = default;
_upperBb1 = default;
_lowerBb1 = default;
_upperBb2 = default;
_lowerBb2 = default;
_prevHigh = default;
_prevLow = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var bb = new BollingerBands
{
Length = BollingerPeriod,
Width = BollingerDeviation
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(bb, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue bbValue)
{
if (candle.State != CandleStates.Finished)
return;
if (bbValue is not BollingerBandsValue bb ||
bb.UpBand is not decimal upper ||
bb.LowBand is not decimal lower)
return;
var haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
decimal haOpen;
if (!_isHaInitialized)
{
haOpen = (candle.OpenPrice + candle.ClosePrice) / 2m;
_isHaInitialized = true;
}
else
haOpen = (_haOpen1 + _haClose1) / 2m;
var haHigh = Math.Max(Math.Max(candle.HighPrice, haOpen), haClose);
var haLow = Math.Min(Math.Min(candle.LowPrice, haOpen), haClose);
var red1 = _haClose1 < _haOpen1 && (_haLow1 <= _lowerBb1 || _haClose1 <= _lowerBb1);
var red2 = _haClose2 < _haOpen2 && (_haLow2 <= _lowerBb2 || _haClose2 <= _lowerBb2);
var green1 = _haClose1 > _haOpen1 && (_haHigh1 >= _upperBb1 || _haClose1 >= _upperBb1);
var green2 = _haClose2 > _haOpen2 && (_haHigh2 >= _upperBb2 || _haClose2 >= _upperBb2);
var buySignal = red1 && haClose > haOpen && haClose > lower;
var sellSignal = green1 && haClose < haOpen && haClose < upper;
if (_cooldown > 0)
_cooldown--;
if (buySignal && Position <= 0 && _cooldown == 0)
{
_entryPrice = candle.ClosePrice;
_initialStop = _prevLow > 0 ? _prevLow : candle.LowPrice;
_firstTarget = _entryPrice + (_entryPrice - _initialStop);
_firstTargetReached = false;
_trailStop = default;
_cooldown = 20;
BuyMarket();
}
else if (sellSignal && Position >= 0 && _cooldown == 0)
{
_entryPrice = candle.ClosePrice;
_initialStop = _prevHigh > 0 ? _prevHigh : candle.HighPrice;
_firstTarget = _entryPrice - (_initialStop - _entryPrice);
_firstTargetReached = false;
_trailStop = default;
_cooldown = 20;
SellMarket();
}
if (Position > 0)
{
if (candle.HighPrice >= _firstTarget)
{
_firstTargetReached = true;
_trailStop = Math.Max(_entryPrice, _prevLow);
}
if (_firstTargetReached)
_trailStop = Math.Max(_trailStop, _prevLow);
var currentStop = _firstTargetReached ? _trailStop : _initialStop;
if (currentStop > 0 && candle.LowPrice <= currentStop)
SellMarket();
}
else if (Position < 0)
{
if (candle.LowPrice <= _firstTarget)
{
_firstTargetReached = true;
_trailStop = Math.Min(_entryPrice, _prevHigh);
}
if (_firstTargetReached && _trailStop > 0)
_trailStop = Math.Min(_trailStop, _prevHigh);
var currentStop = _firstTargetReached ? _trailStop : _initialStop;
if (currentStop > 0 && candle.HighPrice >= currentStop)
BuyMarket();
}
_haOpen2 = _haOpen1;
_haClose2 = _haClose1;
_haHigh2 = _haHigh1;
_haLow2 = _haLow1;
_upperBb2 = _upperBb1;
_lowerBb2 = _lowerBb1;
_haOpen1 = haOpen;
_haClose1 = haClose;
_haHigh1 = haHigh;
_haLow1 = haLow;
_upperBb1 = upper;
_lowerBb1 = lower;
_prevHigh = candle.HighPrice;
_prevLow = candle.LowPrice;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import BollingerBands
from StockSharp.Algo.Strategies import Strategy
class bollinger_heikin_ashi_entry_strategy(Strategy):
def __init__(self):
super(bollinger_heikin_ashi_entry_strategy, self).__init__()
self._bollinger_period = self.Param("BollingerPeriod", 20) \
.SetDisplay("Bollinger Period", "Bollinger Bands length", "Indicators")
self._bollinger_deviation = self.Param("BollingerDeviation", 1.5) \
.SetDisplay("Bollinger Deviation", "Bollinger Bands standard deviation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._entry_price = 0.0
self._initial_stop = 0.0
self._first_target = 0.0
self._first_target_reached = False
self._trail_stop = 0.0
self._is_ha_initialized = False
self._ha_open1 = 0.0
self._ha_close1 = 0.0
self._ha_high1 = 0.0
self._ha_low1 = 0.0
self._ha_open2 = 0.0
self._ha_close2 = 0.0
self._ha_high2 = 0.0
self._ha_low2 = 0.0
self._upper_bb1 = 0.0
self._lower_bb1 = 0.0
self._upper_bb2 = 0.0
self._lower_bb2 = 0.0
self._prev_high = 0.0
self._prev_low = 0.0
self._cooldown = 0
@property
def bollinger_period(self):
return self._bollinger_period.Value
@property
def bollinger_deviation(self):
return self._bollinger_deviation.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(bollinger_heikin_ashi_entry_strategy, self).OnReseted()
self._entry_price = 0.0
self._initial_stop = 0.0
self._first_target = 0.0
self._first_target_reached = False
self._trail_stop = 0.0
self._is_ha_initialized = False
self._ha_open1 = 0.0
self._ha_close1 = 0.0
self._ha_high1 = 0.0
self._ha_low1 = 0.0
self._ha_open2 = 0.0
self._ha_close2 = 0.0
self._ha_high2 = 0.0
self._ha_low2 = 0.0
self._upper_bb1 = 0.0
self._lower_bb1 = 0.0
self._upper_bb2 = 0.0
self._lower_bb2 = 0.0
self._prev_high = 0.0
self._prev_low = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(bollinger_heikin_ashi_entry_strategy, self).OnStarted2(time)
bb = BollingerBands()
bb.Length = self.bollinger_period
bb.Width = self.bollinger_deviation
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(bb, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def OnProcess(self, candle, bb_value):
if candle.State != CandleStates.Finished:
return
if bb_value.UpBand is None or bb_value.LowBand is None:
return
upper = float(bb_value.UpBand)
lower = float(bb_value.LowBand)
ha_close = (float(candle.OpenPrice) + float(candle.HighPrice) + float(candle.LowPrice) + float(candle.ClosePrice)) / 4.0
if not self._is_ha_initialized:
ha_open = (float(candle.OpenPrice) + float(candle.ClosePrice)) / 2.0
self._is_ha_initialized = True
else:
ha_open = (self._ha_open1 + self._ha_close1) / 2.0
ha_high = max(float(candle.HighPrice), ha_open, ha_close)
ha_low = min(float(candle.LowPrice), ha_open, ha_close)
red1 = self._ha_close1 < self._ha_open1 and (self._ha_low1 <= self._lower_bb1 or self._ha_close1 <= self._lower_bb1)
green1 = self._ha_close1 > self._ha_open1 and (self._ha_high1 >= self._upper_bb1 or self._ha_close1 >= self._upper_bb1)
buy_signal = red1 and ha_close > ha_open and ha_close > lower
sell_signal = green1 and ha_close < ha_open and ha_close < upper
if self._cooldown > 0:
self._cooldown -= 1
if buy_signal and self.Position <= 0 and self._cooldown == 0:
self._entry_price = float(candle.ClosePrice)
self._initial_stop = self._prev_low if self._prev_low > 0 else float(candle.LowPrice)
self._first_target = self._entry_price + (self._entry_price - self._initial_stop)
self._first_target_reached = False
self._trail_stop = 0.0
self._cooldown = 20
self.BuyMarket()
elif sell_signal and self.Position >= 0 and self._cooldown == 0:
self._entry_price = float(candle.ClosePrice)
self._initial_stop = self._prev_high if self._prev_high > 0 else float(candle.HighPrice)
self._first_target = self._entry_price - (self._initial_stop - self._entry_price)
self._first_target_reached = False
self._trail_stop = 0.0
self._cooldown = 20
self.SellMarket()
if self.Position > 0:
if float(candle.HighPrice) >= self._first_target:
self._first_target_reached = True
self._trail_stop = max(self._entry_price, self._prev_low)
if self._first_target_reached:
self._trail_stop = max(self._trail_stop, self._prev_low)
current_stop = self._trail_stop if self._first_target_reached else self._initial_stop
if current_stop > 0 and float(candle.LowPrice) <= current_stop:
self.SellMarket()
elif self.Position < 0:
if float(candle.LowPrice) <= self._first_target:
self._first_target_reached = True
self._trail_stop = min(self._entry_price, self._prev_high)
if self._first_target_reached and self._trail_stop > 0:
self._trail_stop = min(self._trail_stop, self._prev_high)
current_stop = self._trail_stop if self._first_target_reached else self._initial_stop
if current_stop > 0 and float(candle.HighPrice) >= current_stop:
self.BuyMarket()
self._ha_open2 = self._ha_open1
self._ha_close2 = self._ha_close1
self._ha_high2 = self._ha_high1
self._ha_low2 = self._ha_low1
self._upper_bb2 = self._upper_bb1
self._lower_bb2 = self._lower_bb1
self._ha_open1 = ha_open
self._ha_close1 = ha_close
self._ha_high1 = ha_high
self._ha_low1 = ha_low
self._upper_bb1 = upper
self._lower_bb1 = lower
self._prev_high = float(candle.HighPrice)
self._prev_low = float(candle.LowPrice)
def CreateClone(self):
return bollinger_heikin_ashi_entry_strategy()