FT Bill Williams AO — порт MetaTrader 4-советника FT_BillWillams_AO, опубликованного на FORTRADER.RU. Алгоритм сочетает
фракталы Билла Вильямса, индикатор «Аллигатор» и Awesome Oscillator для поиска пробоев ранних импульсов. Версия под StockSharp
сохраняет исходную логику, но работает с одной суммарной позицией, автоматически закрывая противоположные сделки при реверсе.
На каждом завершённом баре стратегия выполняет следующий цикл:
Выявляет бычий и медвежий фракталы на базе нечётного количества свечей.
Проверяет, что уровень фрактала находится выше/ниже линии зубов Аллигатора.
Оценивает трёхбарное ускорение Awesome Oscillator (условия A>B, B<C и знак значений).
Готовит уровень пробоя над/под максимумом или минимумом свечи с учётом параметра IndentPoints в пунктах MetaTrader.
Управляет позицией через исходные правила закрытия по челюсти (CloseDropTeeth), обратному сигналу (CloseReverseSignal) и
трейлинг по методике Грагуса (UseTrailing).
Вход в позицию
Покупка
Сформирован бычий фрактал и его максимум выше линии зубов Аллигатора.
Значения AO на свечах SignalShift+2, SignalShift+1 и SignalShift положительные и образуют восходящую последовательность.
Уровень пробоя рассчитывается как High[SignalShift] + IndentPoints * шаг_цены.
Если закрывшийся бар пробивает уровень и AO продолжает расти (C > B), открывается длинная позиция (или выполняется разворот).
Продажа
Сформирован медвежий фрактал, минимум ниже линии зубов.
Значения AO отрицательны и удовлетворяют A < B и B > C.
Уровень пробоя: Low[SignalShift] - IndentPoints * шаг_цены.
При пробое уровня и сохранении снижения AO (C < B) стратегия открывает короткую позицию (либо переворачивается).
Управление рисками и выход
Стоп-лосс и тейк-профит задаются в пунктах MetaTrader и переводятся в цену через шаг инструмента.
Параметр CloseDropTeeth позволяет закрывать позиции при пересечении челюсти текущим или предыдущим закрытием.
CloseReverseSignal определяет, закрывать ли позицию при появлении противоположного фрактала или при активации встречного
пробойного сигнала.
UseTrailing включает трейлинг Грагуса: если губы растут быстрее вспомогательной SMA, стоп переносится на линию губ, иначе —
на зубы. В обоих случаях требуется расстояние не менее 12 пунктов.
Параметры
Параметр
Описание
TradeVolume
Объём сделки в лотах, также записывается в Strategy.Volume.
CandleType
Тип и таймфрейм свечей.
FractalPeriod
Нечётное число баров для подтверждения фрактала (по умолчанию 5).
IndentPoints
Смещение уровня пробоя в пунктах MetaTrader.
JawPeriod, TeethPeriod, LipsPeriod
Периоды сглаженных средних Аллигатора.
JawShift, TeethShift, LipsShift
Сдвиг линий Аллигатора вперёд (в барах).
CloseDropTeeth
Правило закрытия по челюсти: отключено, текущее закрытие или предыдущее закрытие.
CloseReverseSignal
Реакция на противоположный сигнал: отключено, по новому фракталу, либо при готовом обратном пробое.
UseTrailing
Включение трейлинга по Грагусу.
TrendSmaPeriod
Период вспомогательной SMA в трейлинге.
StopLossPoints
Первичный стоп в пунктах MetaTrader (0 отключает).
TakeProfitPoints
Первичный тейк-профит в пунктах MetaTrader (0 отключает).
SignalShift
Сдвиг по готовым барам при чтении AO и максимумов/минимумов.
Дополнительно
Стратегия использует PriceStep инструмента, при его отсутствии берётся MinPriceStep, далее — значение 0.0001.
В StockSharp ведётся единая позиция; разворот закрывает противоположный объём и открывает новую позицию.
Рекомендуется оставлять FractalPeriod нечётным, как в оригинале (5 баров).
Параметры IndentPoints, StopLossPoints и TakeProfitPoints соответствуют пунктам MT4. Подбирайте их с учётом точности котировок.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Bill Williams Awesome Oscillator strategy.
/// Buys when AO crosses above zero and sells when AO crosses below zero,
/// filtered by Alligator teeth alignment.
/// </summary>
public class FtBillWilliamsAoStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _jawPeriod;
private readonly StrategyParam<int> _teethPeriod;
private readonly StrategyParam<int> _lipsPeriod;
private decimal _prevAo;
private decimal _prevTeeth;
private bool _isReady;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int JawPeriod
{
get => _jawPeriod.Value;
set => _jawPeriod.Value = value;
}
public int TeethPeriod
{
get => _teethPeriod.Value;
set => _teethPeriod.Value = value;
}
public int LipsPeriod
{
get => _lipsPeriod.Value;
set => _lipsPeriod.Value = value;
}
public FtBillWilliamsAoStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle type for strategy", "General");
_jawPeriod = Param(nameof(JawPeriod), 13)
.SetDisplay("Jaw Period", "Alligator jaw SMA period", "Alligator");
_teethPeriod = Param(nameof(TeethPeriod), 8)
.SetDisplay("Teeth Period", "Alligator teeth SMA period", "Alligator");
_lipsPeriod = Param(nameof(LipsPeriod), 5)
.SetDisplay("Lips Period", "Alligator lips SMA period", "Alligator");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevAo = 0;
_prevTeeth = 0;
_isReady = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var ao = new AwesomeOscillator();
var teeth = new SMA { Length = TeethPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ao, teeth, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ao);
DrawIndicator(area, teeth);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal aoVal, decimal teethVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_isReady)
{
_prevAo = aoVal;
_prevTeeth = teethVal;
_isReady = true;
return;
}
var close = candle.ClosePrice;
// Buy signal: AO crosses above zero, price above teeth
if (_prevAo <= 0 && aoVal > 0 && close > teethVal)
{
if (Position < 0)
BuyMarket(); // close short
if (Position <= 0)
BuyMarket();
}
// Sell signal: AO crosses below zero, price below teeth
else if (_prevAo >= 0 && aoVal < 0 && close < teethVal)
{
if (Position > 0)
SellMarket(); // close long
if (Position >= 0)
SellMarket();
}
_prevAo = aoVal;
_prevTeeth = teethVal;
}
}
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
class ft_bill_williams_ao_strategy(Strategy):
"""
FT Bill Williams AO: Awesome Oscillator zero-line cross with SMA teeth filter.
Buys when AO crosses above zero and price above teeth SMA.
Sells when AO crosses below zero and price below teeth SMA.
"""
def __init__(self):
super(ft_bill_williams_ao_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candle type for strategy", "General")
self._jaw_period = self.Param("JawPeriod", 13) \
.SetDisplay("Jaw Period", "Alligator jaw SMA period", "Alligator")
self._teeth_period = self.Param("TeethPeriod", 8) \
.SetDisplay("Teeth Period", "Alligator teeth SMA period", "Alligator")
self._lips_period = self.Param("LipsPeriod", 5) \
.SetDisplay("Lips Period", "Alligator lips SMA period", "Alligator")
self._prev_ao = 0.0
self._prev_teeth = 0.0
self._is_ready = False
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(ft_bill_williams_ao_strategy, self).OnReseted()
self._prev_ao = 0.0
self._prev_teeth = 0.0
self._is_ready = False
def OnStarted2(self, time):
super(ft_bill_williams_ao_strategy, self).OnStarted2(time)
ao = AwesomeOscillator()
teeth = SimpleMovingAverage()
teeth.Length = self._teeth_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ao, teeth, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ao)
self.DrawIndicator(area, teeth)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ao_val, teeth_val):
if candle.State != CandleStates.Finished:
return
ao_val = float(ao_val)
teeth_val = float(teeth_val)
if not self._is_ready:
self._prev_ao = ao_val
self._prev_teeth = teeth_val
self._is_ready = True
return
close = float(candle.ClosePrice)
if self._prev_ao <= 0 and ao_val > 0 and close > teeth_val:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif self._prev_ao >= 0 and ao_val < 0 and close < teeth_val:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
self._prev_ao = ao_val
self._prev_teeth = teeth_val
def CreateClone(self):
return ft_bill_williams_ao_strategy()