Adam and Eve-Strategie
Trendfolge-Strategie, die Heiken Ashi-Kerzen mit einer Kaskade einfacher gleitender Durchschnitte kombiniert. Eine Short-Position wird eröffnet, wenn eine bärische Heiken Ashi-Kerze ohne oberen Docht erscheint und alle überwachten gleitenden Durchschnitte (5, 7, 9, 10, 12, 14, 20) nach unten zeigen. Eine Long-Position wird durch eine bullische Kerze ohne unteren Docht und alle aufwärts zeigenden Durchschnitte ausgelöst. Jeder Trade zielt auf einen Gewinn in einem Abstand von einem ATR(14) vom Einstieg ohne Stop-Loss.
Details
- Einstiegskriterien: vorherige Heiken Ashi-Kerze ohne oberen (Short) oder unteren (Long) Docht und ausgerichteter SMA-Stapel
- Long/Short: Beide
- Ausstiegskriterien: Gewinnziel im ATR(14)-Abstand
- Stops: Keine
- Standardwerte:
AtrPeriod= 14
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide
- Indikatoren: SMA (5,7,9,10,12,14,20), Heiken Ashi, ATR
- Stops: Nur Ziel
- Komplexität: Mittel
- Zeitrahmen: Konfigurierbar, Standard 15 Minuten
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Moderat
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>
/// Adam and Eve strategy.
/// Uses Heiken Ashi candles and a stack of SMAs to detect strong trends.
/// A bearish Heiken Ashi candle without an upper wick and falling averages opens a short.
/// A bullish candle without a lower wick and rising averages opens a long.
/// Each trade targets one ATR from entry without a stop loss.
/// </summary>
public class AdamAndEveStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrPeriod;
private decimal? _prevHaOpen;
private decimal? _prevHaClose;
private decimal? _prevHaHigh;
private decimal? _prevHaLow;
private decimal? _sma5Prev1;
private decimal? _sma5Prev2;
private decimal? _sma7Prev1;
private decimal? _sma7Prev2;
private decimal? _sma9Prev1;
private decimal? _sma9Prev2;
private decimal? _sma10Prev1;
private decimal? _sma10Prev2;
private decimal? _sma12Prev1;
private decimal? _sma12Prev2;
private decimal? _sma14Prev1;
private decimal? _sma14Prev2;
private decimal? _sma20Prev1;
private decimal? _sma20Prev2;
private decimal? _targetPrice;
/// <summary>
/// Candle type to process.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// ATR period for profit target.
/// </summary>
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
/// <summary>
/// Initializes a new instance of the <see cref="AdamAndEveStrategy"/>.
/// </summary>
public AdamAndEveStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetDisplay("ATR Period", "Period for ATR based profit target", "Indicators");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHaOpen = null;
_prevHaClose = null;
_prevHaHigh = null;
_prevHaLow = null;
_sma5Prev1 = _sma5Prev2 = null;
_sma7Prev1 = _sma7Prev2 = null;
_sma9Prev1 = _sma9Prev2 = null;
_sma10Prev1 = _sma10Prev2 = null;
_sma12Prev1 = _sma12Prev2 = null;
_sma14Prev1 = _sma14Prev2 = null;
_sma20Prev1 = _sma20Prev2 = null;
_targetPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma5 = new ExponentialMovingAverage { Length = 5 };
var sma7 = new ExponentialMovingAverage { Length = 7 };
var sma9 = new ExponentialMovingAverage { Length = 9 };
var sma10 = new ExponentialMovingAverage { Length = 10 };
var sma12 = new ExponentialMovingAverage { Length = 12 };
var sma14 = new ExponentialMovingAverage { Length = 14 };
var sma20 = new ExponentialMovingAverage { Length = 20 };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma5, sma7, sma9, sma10, sma12, sma14, sma20, atr, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(
ICandleMessage candle,
decimal sma5,
decimal sma7,
decimal sma9,
decimal sma10,
decimal sma12,
decimal sma14,
decimal sma20,
decimal atr)
{
if (candle.State != CandleStates.Finished)
return;
if (!_prevHaOpen.HasValue)
{
ComputeHeikenAshi(candle, out var haOpen, out var haClose, out var haHigh, out var haLow);
_prevHaOpen = haOpen;
_prevHaClose = haClose;
_prevHaHigh = haHigh;
_prevHaLow = haLow;
UpdateSma(sma5, ref _sma5Prev1, ref _sma5Prev2);
UpdateSma(sma7, ref _sma7Prev1, ref _sma7Prev2);
UpdateSma(sma9, ref _sma9Prev1, ref _sma9Prev2);
UpdateSma(sma10, ref _sma10Prev1, ref _sma10Prev2);
UpdateSma(sma12, ref _sma12Prev1, ref _sma12Prev2);
UpdateSma(sma14, ref _sma14Prev1, ref _sma14Prev2);
UpdateSma(sma20, ref _sma20Prev1, ref _sma20Prev2);
return;
}
var bearishPrev = _prevHaClose < _prevHaOpen;
var bullishPrev = _prevHaClose > _prevHaOpen;
var noUpperWickPrev = _prevHaOpen == _prevHaHigh;
var noLowerWickPrev = _prevHaOpen == _prevHaLow;
var smasDown =
IsDecreasing(sma5, _sma5Prev1, _sma5Prev2) &&
IsDecreasing(sma7, _sma7Prev1, _sma7Prev2) &&
IsDecreasing(sma9, _sma9Prev1, _sma9Prev2) &&
IsDecreasing(sma10, _sma10Prev1, _sma10Prev2) &&
IsDecreasing(sma12, _sma12Prev1, _sma12Prev2) &&
IsDecreasing(sma14, _sma14Prev1, _sma14Prev2) &&
IsDecreasing(sma20, _sma20Prev1, _sma20Prev2);
var smasUp =
IsIncreasing(sma5, _sma5Prev1, _sma5Prev2) &&
IsIncreasing(sma7, _sma7Prev1, _sma7Prev2) &&
IsIncreasing(sma9, _sma9Prev1, _sma9Prev2) &&
IsIncreasing(sma10, _sma10Prev1, _sma10Prev2) &&
IsIncreasing(sma12, _sma12Prev1, _sma12Prev2) &&
IsIncreasing(sma14, _sma14Prev1, _sma14Prev2) &&
IsIncreasing(sma20, _sma20Prev1, _sma20Prev2);
if (Position == 0 && IsFormedAndOnlineAndAllowTrading())
{
if (bearishPrev && noUpperWickPrev && smasDown)
{
SellMarket();
_targetPrice = candle.ClosePrice - atr;
}
else if (bullishPrev && noLowerWickPrev && smasUp)
{
BuyMarket();
_targetPrice = candle.ClosePrice + atr;
}
}
else if (Position > 0 && _targetPrice.HasValue && candle.HighPrice >= _targetPrice.Value)
{
SellMarket();
_targetPrice = null;
}
else if (Position < 0 && _targetPrice.HasValue && candle.LowPrice <= _targetPrice.Value)
{
BuyMarket();
_targetPrice = null;
}
ComputeHeikenAshi(candle, out var nextOpen, out var nextClose, out var nextHigh, out var nextLow);
_prevHaOpen = nextOpen;
_prevHaClose = nextClose;
_prevHaHigh = nextHigh;
_prevHaLow = nextLow;
UpdateSma(sma5, ref _sma5Prev1, ref _sma5Prev2);
UpdateSma(sma7, ref _sma7Prev1, ref _sma7Prev2);
UpdateSma(sma9, ref _sma9Prev1, ref _sma9Prev2);
UpdateSma(sma10, ref _sma10Prev1, ref _sma10Prev2);
UpdateSma(sma12, ref _sma12Prev1, ref _sma12Prev2);
UpdateSma(sma14, ref _sma14Prev1, ref _sma14Prev2);
UpdateSma(sma20, ref _sma20Prev1, ref _sma20Prev2);
}
private void ComputeHeikenAshi(ICandleMessage candle, out decimal haOpen, out decimal haClose, out decimal haHigh, out decimal haLow)
{
haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + candle.ClosePrice) / 4m;
haOpen = _prevHaOpen.HasValue ? (_prevHaOpen.Value + _prevHaClose.Value) / 2m : (candle.OpenPrice + candle.ClosePrice) / 2m;
haHigh = Math.Max(candle.HighPrice, Math.Max(haOpen, haClose));
haLow = Math.Min(candle.LowPrice, Math.Min(haOpen, haClose));
}
private static void UpdateSma(decimal current, ref decimal? prev1, ref decimal? prev2)
{
prev2 = prev1;
prev1 = current;
}
private static bool IsDecreasing(decimal current, decimal? prev1, decimal? prev2)
=> prev1.HasValue && prev2.HasValue && current < prev1.Value && prev1.Value < prev2.Value;
private static bool IsIncreasing(decimal current, decimal? prev1, decimal? prev2)
=> prev1.HasValue && prev2.HasValue && current > prev1.Value && prev1.Value > prev2.Value;
}
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, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class adam_and_eve_strategy(Strategy):
def __init__(self):
super(adam_and_eve_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._atr_period = self.Param("AtrPeriod", 14) \
.SetDisplay("ATR Period", "Period for ATR based profit target", "Indicators")
self._prev_ha_open = None
self._prev_ha_close = None
self._prev_ha_high = None
self._prev_ha_low = None
self._sma5_prev1 = None
self._sma5_prev2 = None
self._sma7_prev1 = None
self._sma7_prev2 = None
self._sma9_prev1 = None
self._sma9_prev2 = None
self._sma10_prev1 = None
self._sma10_prev2 = None
self._sma12_prev1 = None
self._sma12_prev2 = None
self._sma14_prev1 = None
self._sma14_prev2 = None
self._sma20_prev1 = None
self._sma20_prev2 = None
self._target_price = None
@property
def candle_type(self):
return self._candle_type.Value
@property
def atr_period(self):
return self._atr_period.Value
def OnReseted(self):
super(adam_and_eve_strategy, self).OnReseted()
self._prev_ha_open = None
self._prev_ha_close = None
self._prev_ha_high = None
self._prev_ha_low = None
self._sma5_prev1 = None
self._sma5_prev2 = None
self._sma7_prev1 = None
self._sma7_prev2 = None
self._sma9_prev1 = None
self._sma9_prev2 = None
self._sma10_prev1 = None
self._sma10_prev2 = None
self._sma12_prev1 = None
self._sma12_prev2 = None
self._sma14_prev1 = None
self._sma14_prev2 = None
self._sma20_prev1 = None
self._sma20_prev2 = None
self._target_price = None
def _compute_heiken_ashi(self, candle):
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._prev_ha_open is not None:
ha_open = (self._prev_ha_open + self._prev_ha_close) / 2.0
else:
ha_open = (o + c) / 2.0
ha_high = max(h, max(ha_open, ha_close))
ha_low = min(l, min(ha_open, ha_close))
return ha_open, ha_close, ha_high, ha_low
@staticmethod
def _is_decreasing(current, prev1, prev2):
if prev1 is None or prev2 is None:
return False
return current < prev1 and prev1 < prev2
@staticmethod
def _is_increasing(current, prev1, prev2):
if prev1 is None or prev2 is None:
return False
return current > prev1 and prev1 > prev2
def OnStarted2(self, time):
super(adam_and_eve_strategy, self).OnStarted2(time)
sma5 = ExponentialMovingAverage()
sma5.Length = 5
sma7 = ExponentialMovingAverage()
sma7.Length = 7
sma9 = ExponentialMovingAverage()
sma9.Length = 9
sma10 = ExponentialMovingAverage()
sma10.Length = 10
sma12 = ExponentialMovingAverage()
sma12.Length = 12
sma14 = ExponentialMovingAverage()
sma14.Length = 14
sma20 = ExponentialMovingAverage()
sma20.Length = 20
atr = AverageTrueRange()
atr.Length = self.atr_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma5, sma7, sma9, sma10, sma12, sma14, sma20, atr, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle, v5, v7, v9, v10, v12, v14, v20, atr_val):
if candle.State != CandleStates.Finished:
return
v5 = float(v5)
v7 = float(v7)
v9 = float(v9)
v10 = float(v10)
v12 = float(v12)
v14 = float(v14)
v20 = float(v20)
atr_val = float(atr_val)
if self._prev_ha_open is None:
ha_open, ha_close, ha_high, ha_low = self._compute_heiken_ashi(candle)
self._prev_ha_open = ha_open
self._prev_ha_close = ha_close
self._prev_ha_high = ha_high
self._prev_ha_low = ha_low
self._sma5_prev2 = self._sma5_prev1
self._sma5_prev1 = v5
self._sma7_prev2 = self._sma7_prev1
self._sma7_prev1 = v7
self._sma9_prev2 = self._sma9_prev1
self._sma9_prev1 = v9
self._sma10_prev2 = self._sma10_prev1
self._sma10_prev1 = v10
self._sma12_prev2 = self._sma12_prev1
self._sma12_prev1 = v12
self._sma14_prev2 = self._sma14_prev1
self._sma14_prev1 = v14
self._sma20_prev2 = self._sma20_prev1
self._sma20_prev1 = v20
return
bearish_prev = self._prev_ha_close < self._prev_ha_open
bullish_prev = self._prev_ha_close > self._prev_ha_open
no_upper_wick_prev = self._prev_ha_open == self._prev_ha_high
no_lower_wick_prev = self._prev_ha_open == self._prev_ha_low
smas_down = (
self._is_decreasing(v5, self._sma5_prev1, self._sma5_prev2) and
self._is_decreasing(v7, self._sma7_prev1, self._sma7_prev2) and
self._is_decreasing(v9, self._sma9_prev1, self._sma9_prev2) and
self._is_decreasing(v10, self._sma10_prev1, self._sma10_prev2) and
self._is_decreasing(v12, self._sma12_prev1, self._sma12_prev2) and
self._is_decreasing(v14, self._sma14_prev1, self._sma14_prev2) and
self._is_decreasing(v20, self._sma20_prev1, self._sma20_prev2)
)
smas_up = (
self._is_increasing(v5, self._sma5_prev1, self._sma5_prev2) and
self._is_increasing(v7, self._sma7_prev1, self._sma7_prev2) and
self._is_increasing(v9, self._sma9_prev1, self._sma9_prev2) and
self._is_increasing(v10, self._sma10_prev1, self._sma10_prev2) and
self._is_increasing(v12, self._sma12_prev1, self._sma12_prev2) and
self._is_increasing(v14, self._sma14_prev1, self._sma14_prev2) and
self._is_increasing(v20, self._sma20_prev1, self._sma20_prev2)
)
close_price = float(candle.ClosePrice)
high_price = float(candle.HighPrice)
low_price = float(candle.LowPrice)
if self.Position == 0:
if bearish_prev and no_upper_wick_prev and smas_down:
self.SellMarket()
self._target_price = close_price - atr_val
elif bullish_prev and no_lower_wick_prev and smas_up:
self.BuyMarket()
self._target_price = close_price + atr_val
elif self.Position > 0 and self._target_price is not None and high_price >= self._target_price:
self.SellMarket()
self._target_price = None
elif self.Position < 0 and self._target_price is not None and low_price <= self._target_price:
self.BuyMarket()
self._target_price = None
ha_open, ha_close, ha_high, ha_low = self._compute_heiken_ashi(candle)
self._prev_ha_open = ha_open
self._prev_ha_close = ha_close
self._prev_ha_high = ha_high
self._prev_ha_low = ha_low
self._sma5_prev2 = self._sma5_prev1
self._sma5_prev1 = v5
self._sma7_prev2 = self._sma7_prev1
self._sma7_prev1 = v7
self._sma9_prev2 = self._sma9_prev1
self._sma9_prev1 = v9
self._sma10_prev2 = self._sma10_prev1
self._sma10_prev1 = v10
self._sma12_prev2 = self._sma12_prev1
self._sma12_prev1 = v12
self._sma14_prev2 = self._sma14_prev1
self._sma14_prev1 = v14
self._sma20_prev2 = self._sma20_prev1
self._sma20_prev1 = v20
def CreateClone(self):
return adam_and_eve_strategy()