Die Zonal-Trading-Strategie repliziert Bill Williams' klassisches "Zonen"-Konzept. Sie überwacht die Farbe des Awesome Oscillator (AO) und des Accelerator Oscillator (AC). Ein grüner Balken bedeutet, dass der Oszillatorwert im Vergleich zum vorherigen Balken gestiegen ist, ein roter Balken bedeutet, dass er gefallen ist. Wenn beide Oszillatoren grün werden, öffnet die Strategie eine Long-Position. Wenn beide rot werden, öffnet sie eine Short-Position. Jede entgegengesetzte Farbe schließt bestehende Positionen.
Details
Einstiegskriterien:
Long: AO steigt und AC steigt.
Short: AO fällt und AC fällt.
Ausstiegskriterien:
Long: AO oder AC fällt.
Short: AO oder AC steigt.
Stops: standardmäßig keine.
Parameter:
AoCandleType – Zeitrahmen für den Awesome Oscillator (standardmäßig H4).
AcCandleType – Zeitrahmen für den Accelerator Oscillator (standardmäßig H4).
BuyOpen, SellOpen – aktivieren oder deaktivieren Long- und Short-Einstiege.
BuyClose, SellClose – aktivieren oder deaktivieren Ausstiege für Long- und Short-Positionen.
Indikatoren: Awesome Oscillator (5/34), Accelerator Oscillator (AO minus SMA(5)).
Typ: Momentum-Folge, funktioniert auf jedem Markt und Zeitrahmen, auf dem die Oszillatoren verfügbar sind.
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>
/// Zone trading strategy based on Bill Williams' Awesome and Accelerator Oscillators.
/// Buys when both oscillators turn green and sells when both turn red.
/// </summary>
public class ZonalTradingOscillatorStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _medians = new();
private readonly List<decimal> _aoValues = new();
private decimal? _prevAo;
private decimal? _prevAc;
private int _aoTrend;
private int _acTrend;
private int _lastSignal;
/// <summary>
/// Candle type for analysis.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ZonalTradingOscillatorStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle type for oscillators", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_medians.Clear();
_aoValues.Clear();
_prevAo = null;
_prevAc = null;
_aoTrend = 0;
_acTrend = 0;
_lastSignal = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType)
.Bind(ProcessCandle)
.Start();
StartProtection(
new Unit(2000m, UnitTypes.Absolute),
new Unit(1000m, UnitTypes.Absolute));
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_medians.Add((candle.HighPrice + candle.LowPrice) / 2m);
if (_medians.Count > 34)
_medians.RemoveAt(0);
if (_medians.Count < 34)
return;
var ao = GetAverage(_medians, 5) - GetAverage(_medians, 34);
_aoValues.Add(ao);
if (_aoValues.Count > 5)
_aoValues.RemoveAt(0);
if (_aoValues.Count < 5)
{
_prevAo = ao;
return;
}
var ac = ao - GetAverage(_aoValues, 5);
if (_prevAo is not null && _prevAc is not null)
{
_aoTrend = ao > _prevAo ? 1 : ao < _prevAo ? -1 : _aoTrend;
_acTrend = ac > _prevAc ? 1 : ac < _prevAc ? -1 : _acTrend;
if (_aoTrend > 0 && _acTrend > 0 && _lastSignal != 1 && Position <= 0)
{
BuyMarket();
_lastSignal = 1;
}
else if (_aoTrend < 0 && _acTrend < 0 && _lastSignal != -1 && Position >= 0)
{
SellMarket();
_lastSignal = -1;
}
}
_prevAo = ao;
_prevAc = ac;
}
private static decimal GetAverage(List<decimal> values, int length)
{
var start = values.Count - length;
var sum = 0m;
for (var i = start; i < values.Count; i++)
sum += values[i];
return sum / length;
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Strategies import Strategy
class zonal_trading_oscillator_strategy(Strategy):
def __init__(self):
super(zonal_trading_oscillator_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._medians = []
self._ao_values = []
self._prev_ao = None
self._prev_ac = None
self._ao_trend = 0
self._ac_trend = 0
self._last_signal = 0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def _get_average(self, values, length):
start = len(values) - length
s = 0.0
for i in range(start, len(values)):
s += values[i]
return s / length
def OnStarted2(self, time):
super(zonal_trading_oscillator_strategy, self).OnStarted2(time)
self._medians = []
self._ao_values = []
self._prev_ao = None
self._prev_ac = None
self._ao_trend = 0
self._ac_trend = 0
self._last_signal = 0
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
self.StartProtection(
Unit(2000.0, UnitTypes.Absolute),
Unit(1000.0, UnitTypes.Absolute))
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
median = (float(candle.HighPrice) + float(candle.LowPrice)) / 2.0
self._medians.append(median)
if len(self._medians) > 34:
self._medians.pop(0)
if len(self._medians) < 34:
return
ao = self._get_average(self._medians, 5) - self._get_average(self._medians, 34)
self._ao_values.append(ao)
if len(self._ao_values) > 5:
self._ao_values.pop(0)
if len(self._ao_values) < 5:
self._prev_ao = ao
return
ac = ao - self._get_average(self._ao_values, 5)
if self._prev_ao is not None and self._prev_ac is not None:
if ao > self._prev_ao:
self._ao_trend = 1
elif ao < self._prev_ao:
self._ao_trend = -1
if ac > self._prev_ac:
self._ac_trend = 1
elif ac < self._prev_ac:
self._ac_trend = -1
if self._ao_trend > 0 and self._ac_trend > 0 and self._last_signal != 1 and self.Position <= 0:
self.BuyMarket()
self._last_signal = 1
elif self._ao_trend < 0 and self._ac_trend < 0 and self._last_signal != -1 and self.Position >= 0:
self.SellMarket()
self._last_signal = -1
self._prev_ao = ao
self._prev_ac = ac
def OnReseted(self):
super(zonal_trading_oscillator_strategy, self).OnReseted()
self._medians = []
self._ao_values = []
self._prev_ao = None
self._prev_ac = None
self._ao_trend = 0
self._ac_trend = 0
self._last_signal = 0
def CreateClone(self):
return zonal_trading_oscillator_strategy()