The FT Bill Williams AO Strategy is a high-level StockSharp port of the MetaTrader 4 expert FT_BillWillams_AO. The original
robot was published on FORTRADER.RU and combines Bill Williams fractals, the Alligator indicator, and the Awesome Oscillator to
identify early breakout opportunities. The StockSharp version keeps the original logic but works with a single net position instead of
multiple simultaneous orders.
The algorithm operates on completed candles from a configurable timeframe. Every bar it:
Detects bullish and bearish fractals built from an odd number of candles.
Filters fractals by checking whether the fractal price is outside the Alligator teeth line.
Waits for the Awesome Oscillator (AO) to form the classic three-bar acceleration pattern.
Places a breakout trigger above/below the recent high or low shifted by a user-defined number of MetaTrader points.
Applies Bill Williams' Gragus trailing routine and optional jaw-based exit rules.
Entry logic
Long entries
A bullish fractal appears and its high price sits above the Alligator teeth.
AO values taken SignalShift + 2, SignalShift + 1, and SignalShift candles ago satisfy A > B, B < C, and all three are
positive.
A pending breakout level is calculated as High[SignalShift] + IndentPoints * price step.
When a completed candle crosses that level and AO still increases (C > B), the strategy opens or reverses into a long position.
Short entries
A bearish fractal appears and its low is below the Alligator teeth.
AO values satisfy A < B, B > C, and all three are negative.
A breakout trigger is placed at Low[SignalShift] - IndentPoints * price step.
A short position (or reversal from long) is opened when the candle dips below that trigger while AO keeps falling (C < B).
Exit and risk management
Initial stop-loss and take-profit are expressed in MetaTrader points and translate into actual price distance via the instrument
price step.
The CloseDropTeeth mode can close positions when either the current close or the previous close crosses the Alligator jaw.
CloseReverseSignal determines whether an opposite fractal or the activation of the opposite breakout signal should force an
exit.
The UseTrailing switch enables the original Gragus trailing stop routine: when the Alligator lips advance faster than a short
SMA, the stop is moved to the lips; otherwise it trails the teeth. Both moves require the price to stand at least 12 points away
from the target line.
Parameters
Name
Description
TradeVolume
Order size in lots. It is also written to Strategy.Volume.
CandleType
Data type and timeframe of the input candles.
FractalPeriod
Odd number of candles used to confirm fractals (default 5).
IndentPoints
MetaTrader points added above/below the breakout candle high/low.
JawPeriod, TeethPeriod, LipsPeriod
Length of the smoothed moving averages used by the Alligator lines.
JawShift, TeethShift, LipsShift
Forward displacement (in candles) applied to the Alligator lines.
CloseDropTeeth
Behaviour of the jaw-based close rule: disabled, current close crossing, or previous close crossing.
CloseReverseSignal
Exit condition on opposite signals: disabled, on new fractal, or once the opposite breakout is armed.
UseTrailing
Enables or disables the Gragus trailing stop routine.
TrendSmaPeriod
Period of the auxiliary SMA used by the trailing comparison.
StopLossPoints
Initial stop-loss distance in MetaTrader points. Set to zero to disable.
TakeProfitPoints
Initial take-profit distance in MetaTrader points. Set to zero to disable.
SignalShift
Number of fully closed candles skipped when reading AO values and recent highs/lows.
Notes
The strategy assumes the security exposes a valid PriceStep (falls back to MinPriceStep); if both are missing, a default of
0.0001 is used.
Only one net position is managed. Reversal signals automatically close the opposite position before opening a new one.
For best results keep FractalPeriod odd; the original expert used 5 candles.
IndentPoints, StopLossPoints, and TakeProfitPoints mimic MetaTrader points. Adjust them according to the instrument's price
scale.
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()