Стратегия Wlx BW5 Zone
Стратегия использует осцилляторы Билла Уильямса — Awesome (AO) и Accelerator (AC). Сигнал на покупку появляется, когда оба индикатора пять баров подряд растут, на продажу — когда пять баров подряд падают. При получении противоположного сигнала позиция переворачивается.
Подробности
- Условия входа:
- Long:
AOиACрастут пять последовательных баров. - Short:
AOиACпадают пять последовательных баров.
- Long:
- Направление: Обе стороны.
- Условия выхода: Переворот при противоположном сигнале.
- Стопы: Нет.
- Значения по умолчанию:
Таймфрейм= 4 часа.Direct= true.SignalBar= 1.
- Фильтры:
- Категория: Моментум
- Направление: Обе
- Индикаторы: Несколько
- Стопы: Нет
- Сложность: Средняя
- Таймфрейм: Среднесрочный
- Сезонность: Нет
- Нейросети: Нет
- Дивергенция: Нет
- Уровень риска: Средний
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>
/// Bill Williams zone strategy based on Awesome and Accelerator oscillators.
/// Opens or reverses positions after five consecutive oscillator moves.
/// </summary>
public class WlxBw5ZoneStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<bool> _direct;
private readonly StrategyParam<int> _signalBar;
private AwesomeOscillator _ao;
private SimpleMovingAverage _aoSma;
private decimal? _ao0, _ao1, _ao2, _ao3, _ao4;
private decimal? _ac0, _ac1, _ac2, _ac3, _ac4;
private bool _flagUp;
private bool _flagDown;
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Direction flag. If false signals are reversed.
/// </summary>
public bool Direct { get => _direct.Value; set => _direct.Value = value; }
/// <summary>
/// Signal bar shift.
/// </summary>
public int SignalBar { get => _signalBar.Value; set => _signalBar.Value = value; }
/// <summary>
/// Initializes a new instance of <see cref="WlxBw5ZoneStrategy"/>.
/// </summary>
public WlxBw5ZoneStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
_direct = Param(nameof(Direct), true)
.SetDisplay("Direct", "Use direct signals", "General");
_signalBar = Param(nameof(SignalBar), 1)
.SetRange(0, 5)
.SetDisplay("Signal Bar", "Bar shift for signals", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_ao = null;
_aoSma = null;
_ao0 = _ao1 = _ao2 = _ao3 = _ao4 = null;
_ac0 = _ac1 = _ac2 = _ac3 = _ac4 = null;
_flagUp = false;
_flagDown = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ao = new AwesomeOscillator();
_aoSma = new SimpleMovingAverage { Length = 5 };
_ao0 = _ao1 = _ao2 = _ao3 = _ao4 = null;
_ac0 = _ac1 = _ac2 = _ac3 = _ac4 = null;
_flagUp = false;
_flagDown = false;
var subscription = SubscribeCandles(CandleType);
subscription.Bind(_ao, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ao);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal ao)
{
if (candle.State != CandleStates.Finished)
return;
var ac = ao - _aoSma.Process(new DecimalIndicatorValue(_aoSma, ao, candle.CloseTime) { IsFinal = true }).ToDecimal();
_ao4 = _ao3;
_ao3 = _ao2;
_ao2 = _ao1;
_ao1 = _ao0;
_ao0 = ao;
_ac4 = _ac3;
_ac3 = _ac2;
_ac2 = _ac1;
_ac1 = _ac0;
_ac0 = ac;
if (_ao4 is null || _ac4 is null)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var isUpSeq = _ao0 > _ao1 && _ao1 > _ao2 && _ao2 > _ao3 && _ao3 > _ao4 &&
_ac0 > _ac1 && _ac1 > _ac2 && _ac2 > _ac3 && _ac3 > _ac4;
var isDownSeq = _ao0 < _ao1 && _ao1 < _ao2 && _ao2 < _ao3 && _ao3 < _ao4 &&
_ac0 < _ac1 && _ac1 < _ac2 && _ac2 < _ac3 && _ac3 < _ac4;
if (!_flagUp && isUpSeq)
{
if (Direct)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Volume + Math.Abs(Position) : Volume);
}
else
{
if (Position >= 0)
SellMarket(Position > 0 ? Volume + Position : Volume);
}
_flagUp = true;
}
if (!_flagDown && isDownSeq)
{
if (Direct)
{
if (Position >= 0)
SellMarket(Position > 0 ? Volume + Position : Volume);
}
else
{
if (Position <= 0)
BuyMarket(Position < 0 ? Volume + Math.Abs(Position) : Volume);
}
_flagDown = true;
}
if (_ao0 <= _ao1 || _ac0 <= _ac1)
_flagUp = false;
if (_ao0 >= _ao1 || _ac0 >= _ac1)
_flagDown = false;
}
}
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 AwesomeOscillator, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class wlx_bw5_zone_strategy(Strategy):
def __init__(self):
super(wlx_bw5_zone_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._direct = self.Param("Direct", True) \
.SetDisplay("Direct", "Use direct signals", "General")
self._signal_bar = self.Param("SignalBar", 1) \
.SetDisplay("Signal Bar", "Bar shift for signals", "General")
self._ao = None
self._ao_sma = None
self._ao0 = None
self._ao1 = None
self._ao2 = None
self._ao3 = None
self._ao4 = None
self._ac0 = None
self._ac1 = None
self._ac2 = None
self._ac3 = None
self._ac4 = None
self._flag_up = False
self._flag_down = False
@property
def candle_type(self):
return self._candle_type.Value
@property
def direct(self):
return self._direct.Value
@property
def signal_bar(self):
return self._signal_bar.Value
def OnReseted(self):
super(wlx_bw5_zone_strategy, self).OnReseted()
self._ao = None
self._ao_sma = None
self._ao0 = self._ao1 = self._ao2 = self._ao3 = self._ao4 = None
self._ac0 = self._ac1 = self._ac2 = self._ac3 = self._ac4 = None
self._flag_up = False
self._flag_down = False
def OnStarted2(self, time):
super(wlx_bw5_zone_strategy, self).OnStarted2(time)
self._ao0 = self._ao1 = self._ao2 = self._ao3 = self._ao4 = None
self._ac0 = self._ac1 = self._ac2 = self._ac3 = self._ac4 = None
self._flag_up = False
self._flag_down = False
self._ao = AwesomeOscillator()
self._ao_sma = SimpleMovingAverage()
self._ao_sma.Length = 5
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._ao, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._ao)
self.DrawOwnTrades(area)
def process_candle(self, candle, ao):
if candle.State != CandleStates.Finished:
return
ao = float(ao)
sma_result = process_float(self._ao_sma, ao, candle.CloseTime, True)
ac = ao - float(sma_result)
self._ao4 = self._ao3
self._ao3 = self._ao2
self._ao2 = self._ao1
self._ao1 = self._ao0
self._ao0 = ao
self._ac4 = self._ac3
self._ac3 = self._ac2
self._ac2 = self._ac1
self._ac1 = self._ac0
self._ac0 = ac
if self._ao4 is None or self._ac4 is None:
return
is_up_seq = (self._ao0 > self._ao1 and self._ao1 > self._ao2 and
self._ao2 > self._ao3 and self._ao3 > self._ao4 and
self._ac0 > self._ac1 and self._ac1 > self._ac2 and
self._ac2 > self._ac3 and self._ac3 > self._ac4)
is_down_seq = (self._ao0 < self._ao1 and self._ao1 < self._ao2 and
self._ao2 < self._ao3 and self._ao3 < self._ao4 and
self._ac0 < self._ac1 and self._ac1 < self._ac2 and
self._ac2 < self._ac3 and self._ac3 < self._ac4)
if not self._flag_up and is_up_seq:
if self.direct:
if self.Position <= 0:
self.BuyMarket()
else:
if self.Position >= 0:
self.SellMarket()
self._flag_up = True
if not self._flag_down and is_down_seq:
if self.direct:
if self.Position >= 0:
self.SellMarket()
else:
if self.Position <= 0:
self.BuyMarket()
self._flag_down = True
if self._ao0 <= self._ao1 or self._ac0 <= self._ac1:
self._flag_up = False
if self._ao0 >= self._ao1 or self._ac0 >= self._ac1:
self._flag_down = False
def CreateClone(self):
return wlx_bw5_zone_strategy()