Открыть на GitHub

Стратегия FT Bill Williams AO

Описание

FT Bill Williams AO — порт MetaTrader 4-советника FT_BillWillams_AO, опубликованного на FORTRADER.RU. Алгоритм сочетает фракталы Билла Вильямса, индикатор «Аллигатор» и Awesome Oscillator для поиска пробоев ранних импульсов. Версия под StockSharp сохраняет исходную логику, но работает с одной суммарной позицией, автоматически закрывая противоположные сделки при реверсе.

На каждом завершённом баре стратегия выполняет следующий цикл:

  1. Выявляет бычий и медвежий фракталы на базе нечётного количества свечей.
  2. Проверяет, что уровень фрактала находится выше/ниже линии зубов Аллигатора.
  3. Оценивает трёхбарное ускорение Awesome Oscillator (условия A>B, B<C и знак значений).
  4. Готовит уровень пробоя над/под максимумом или минимумом свечи с учётом параметра IndentPoints в пунктах MetaTrader.
  5. Управляет позицией через исходные правила закрытия по челюсти (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;
	}
}