Heiken Ashi Simplified EA Strategie
Ein musterbasiertetes System, das auf Heikin Ashi-Kerzen aufbaut. Die Strategie beobachtet eine Sequenz vorheriger Heikin Ashi-Eröffnungen und -Schlusskurse. Wenn drei aufeinanderfolgende Schlusskurse über ihre jeweiligen Eröffnungen steigen (oder fallen), während die Eröffnungen eine decelerating Pullback bilden, kann die nächste Kerze einen Ausbruchstrade auslösen, sobald sich der Kurs um eine Mindestdistanz von der letzten Heikin Ashi-Eröffnung entfernt. Der Algorithmus skaliert Positionen bis zu einem definierten Limit.
Details
- Einstiegskriterien:
- Long: Drei vorherige HA-Schlusskurse liegen über früheren Eröffnungen und die Eröffnungen bilden eine absteigende Reihe mit schrumpfenden Differenzen.
- Short: Drei vorherige HA-Schlusskurse liegen unter früheren Eröffnungen und die Eröffnungen bilden eine aufsteigende Reihe mit expandierenden Differenzen.
- Long/Short: Beide Seiten
- Ausstiegskriterien:
- Entgegengesetztes Signal
- Stops: Keine
- Standardwerte:
CandleType= 1 StundeMaxPositions= 3DistancePoints= 300Volume= 1
- Filter:
- Kategorie: Muster-Ausbruch
- Richtung: Beide
- Indikatoren: Heikin Ashi
- Stops: Nein
- Komplexität: Moderat
- Zeitrahmen: Stündlich
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on simplified Heikin Ashi pattern analysis.
/// </summary>
public class HeikenAshiSimplifiedEaStrategy : Strategy
{
private readonly StrategyParam<int> _maxPositions;
private readonly StrategyParam<int> _distancePoints;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private decimal _haOpen1;
private decimal _haOpen2;
private decimal _haOpen3;
private decimal _haOpen4;
private decimal _haClose1;
private decimal _haClose2;
private decimal _haClose3;
private decimal _priceDistance;
private int _positionCount;
private int _cooldownRemaining;
/// <summary>
/// Initializes a new instance of the <see cref="HeikenAshiSimplifiedEaStrategy"/> class.
/// </summary>
public HeikenAshiSimplifiedEaStrategy()
{
_maxPositions = Param(nameof(MaxPositions), 1)
.SetDisplay("Max Positions", "Maximum number of positions in direction", "General")
.SetOptimize(1, 5, 1);
_distancePoints = Param(nameof(DistancePoints), 400)
.SetDisplay("Distance Points", "Minimum distance in price steps from last HA open", "General")
.SetOptimize(50, 500, 50);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for Heikin Ashi calculation", "General");
_cooldownBars = Param(nameof(CooldownBars), 6)
.SetDisplay("Cooldown Bars", "Completed candles to wait after a position change", "Trading");
}
/// <summary>
/// Maximum number of positions allowed in one direction.
/// </summary>
public int MaxPositions
{
get => _maxPositions.Value;
set => _maxPositions.Value = value;
}
/// <summary>
/// Minimum distance in price steps from last Heikin Ashi open.
/// </summary>
public int DistancePoints
{
get => _distancePoints.Value;
set => _distancePoints.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Number of completed candles to wait after a position change.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_haOpen1 = 0m;
_haOpen2 = 0m;
_haOpen3 = 0m;
_haOpen4 = 0m;
_haClose1 = 0m;
_haClose2 = 0m;
_haClose3 = 0m;
_priceDistance = 0m;
_positionCount = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_priceDistance = DistancePoints * (Security.PriceStep ?? 1m);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_cooldownRemaining > 0)
_cooldownRemaining--;
if (Position == 0)
_positionCount = 0;
if (_haOpen4 != 0m)
{
var direction = 0;
if (_haClose1 > _haOpen1 && _haClose2 > _haOpen2 && _haClose3 > _haOpen3)
direction = 1;
else if (_haClose1 < _haOpen1 && _haClose2 < _haOpen2 && _haClose3 < _haOpen3)
direction = -1;
if (direction != 0)
{
if (Position * direction < 0)
{
if (Position > 0)
SellMarket();
else if (Position < 0)
BuyMarket();
_positionCount = 0;
_cooldownRemaining = CooldownBars;
}
var distanceFromAnchor = candle.ClosePrice - _haOpen1;
if (_cooldownRemaining == 0 && distanceFromAnchor * direction > 0m && Math.Abs(distanceFromAnchor) >= _priceDistance)
{
if (direction > 0 && _positionCount < MaxPositions && Position <= 0)
{
BuyMarket();
_positionCount = 1;
_cooldownRemaining = CooldownBars;
}
else if (direction < 0 && _positionCount > -MaxPositions && Position >= 0)
{
SellMarket();
_positionCount = -1;
_cooldownRemaining = CooldownBars;
}
}
}
}
var haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
var haOpen = _haOpen1 == 0m && _haClose1 == 0m
? (candle.OpenPrice + candle.ClosePrice) / 2m
: (_haOpen1 + _haClose1) / 2m;
_haOpen4 = _haOpen3;
_haOpen3 = _haOpen2;
_haOpen2 = _haOpen1;
_haOpen1 = haOpen;
_haClose3 = _haClose2;
_haClose2 = _haClose1;
_haClose1 = haClose;
}
}
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.Strategies import Strategy
class heiken_ashi_simplified_ea_strategy(Strategy):
def __init__(self):
super(heiken_ashi_simplified_ea_strategy, self).__init__()
self._max_positions = self.Param("MaxPositions", 1) \
.SetDisplay("Max Positions", "Maximum number of positions in direction", "General")
self._distance_points = self.Param("DistancePoints", 400) \
.SetDisplay("Distance Points", "Minimum distance in price steps from last HA open", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe for Heikin Ashi calculation", "General")
self._cooldown_bars = self.Param("CooldownBars", 6) \
.SetDisplay("Cooldown Bars", "Completed candles to wait after a position change", "Trading")
self._ha_open1 = 0.0
self._ha_open2 = 0.0
self._ha_open3 = 0.0
self._ha_open4 = 0.0
self._ha_close1 = 0.0
self._ha_close2 = 0.0
self._ha_close3 = 0.0
self._price_distance = 0.0
self._position_count = 0
self._cooldown_remaining = 0
@property
def max_positions(self):
return self._max_positions.Value
@property
def distance_points(self):
return self._distance_points.Value
@property
def candle_type(self):
return self._candle_type.Value
@property
def cooldown_bars(self):
return self._cooldown_bars.Value
def OnReseted(self):
super(heiken_ashi_simplified_ea_strategy, self).OnReseted()
self._ha_open1 = 0.0
self._ha_open2 = 0.0
self._ha_open3 = 0.0
self._ha_open4 = 0.0
self._ha_close1 = 0.0
self._ha_close2 = 0.0
self._ha_close3 = 0.0
self._price_distance = 0.0
self._position_count = 0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(heiken_ashi_simplified_ea_strategy, self).OnStarted2(time)
step = self.Security.PriceStep if self.Security.PriceStep is not None else 1.0
self._price_distance = self.distance_points * float(step)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
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
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
if self.Position == 0:
self._position_count = 0
if self._ha_open4 != 0:
direction = 0
if self._ha_close1 > self._ha_open1 and self._ha_close2 > self._ha_open2 and self._ha_close3 > self._ha_open3:
direction = 1
elif self._ha_close1 < self._ha_open1 and self._ha_close2 < self._ha_open2 and self._ha_close3 < self._ha_open3:
direction = -1
if direction != 0:
if self.Position * direction < 0:
if self.Position > 0:
self.SellMarket()
elif self.Position < 0:
self.BuyMarket()
self._position_count = 0
self._cooldown_remaining = self.cooldown_bars
distance_from_anchor = float(candle.ClosePrice) - self._ha_open1
if self._cooldown_remaining == 0 and distance_from_anchor * direction > 0 and abs(distance_from_anchor) >= self._price_distance:
if direction > 0 and self._position_count < self.max_positions and self.Position <= 0:
self.BuyMarket()
self._position_count = 1
self._cooldown_remaining = self.cooldown_bars
elif direction < 0 and self._position_count > -self.max_positions and self.Position >= 0:
self.SellMarket()
self._position_count = -1
self._cooldown_remaining = self.cooldown_bars
o = float(candle.OpenPrice)
h = float(candle.HighPrice)
l = float(candle.LowPrice)
c = float(candle.ClosePrice)
ha_close = (o + h + l + c) / 4.0
if self._ha_open1 == 0 and self._ha_close1 == 0:
ha_open = (o + c) / 2.0
else:
ha_open = (self._ha_open1 + self._ha_close1) / 2.0
self._ha_open4 = self._ha_open3
self._ha_open3 = self._ha_open2
self._ha_open2 = self._ha_open1
self._ha_open1 = ha_open
self._ha_close3 = self._ha_close2
self._ha_close2 = self._ha_close1
self._ha_close1 = ha_close
def CreateClone(self):
return heiken_ashi_simplified_ea_strategy()