80-20-Strategie
Die Strategie erkennt Kerzen, bei denen der Kurs in den oberen oder unteren 20 % der Sitzung schließt. Ein bullisches Signal tritt auf, wenn der Schluss im oberen Fünftel und die Eröffnung im unteren Fünftel der Spanne liegt. Ein bärisches Signal tritt auf, wenn die Eröffnung im oberen Fünftel und der Schluss im unteren Fünftel liegt. Der Ansatz zielt darauf ab, schnelle Umkehrungen von extremen Kerzenschlüssen zu erfassen.
Details
- Einstiegskriterien:
- Schluss in den oberen 20 % und Eröffnung in den unteren 20 % → Long.
- Eröffnung in den oberen 20 % und Schluss in den unteren 20 % → Short.
- Long/Short: Beide.
- Ausstiegskriterien:
- Ein entgegengesetztes Signal kehrt die Position um.
- Stops: Keine.
- Standardwerte:
- Range percent = 0.2.
- Filter:
- Kategorie: Muster
- Richtung: Beide
- Indikatoren: Keine
- Stops: Nein
- Komplexität: Niedrig
- Zeitrahmen: Beliebig
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// 80-20 strategy - trades when price closes near extremes of the candle.
/// Buys on strong bullish candles (close near high, open near low).
/// Sells on strong bearish candles (open near high, close near low).
/// Uses EMA as trend filter.
/// </summary>
public class EightyTwentyStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _rangePercent;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _cooldownBars;
private ExponentialMovingAverage _ema;
private int _cooldownRemaining;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public decimal RangePercent { get => _rangePercent.Value; set => _rangePercent.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int CooldownBars { get => _cooldownBars.Value; set => _cooldownBars.Value = value; }
public EightyTwentyStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_rangePercent = Param(nameof(RangePercent), 0.2m)
.SetDisplay("Range Percent", "Fraction of candle range for trigger zone", "General");
_emaLength = Param(nameof(EmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ema = null;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ema, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ema);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
return;
}
var range = candle.HighPrice - candle.LowPrice;
if (range <= 0)
return;
var offset = RangePercent * range;
var triggerGreen = candle.ClosePrice >= candle.HighPrice - offset &&
candle.OpenPrice <= candle.LowPrice + offset;
var triggerRed = candle.OpenPrice >= candle.HighPrice - offset &&
candle.ClosePrice <= candle.LowPrice + offset;
if (triggerGreen && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
else if (triggerRed && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class eighty_twenty_strategy(Strategy):
"""80-20 Strategy."""
def __init__(self):
super(eighty_twenty_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._range_percent = self.Param("RangePercent", 0.2) \
.SetDisplay("Range Percent", "Fraction of candle range for trigger zone", "General")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA trend filter period", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars between trades", "Risk")
self._ema = None
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(eighty_twenty_strategy, self).OnReseted()
self._ema = None
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(eighty_twenty_strategy, self).OnStarted2(time)
self._ema = ExponentialMovingAverage()
self._ema.Length = int(self._ema_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, ema_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
open_p = float(candle.OpenPrice)
close = float(candle.ClosePrice)
rng = high - low
if rng <= 0:
return
offset = float(self._range_percent.Value) * rng
cooldown = int(self._cooldown_bars.Value)
trigger_green = close >= high - offset and open_p <= low + offset
trigger_red = open_p >= high - offset and close <= low + offset
if trigger_green and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif trigger_red and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
def CreateClone(self):
return eighty_twenty_strategy()