Открыть на GitHub

Стратегия Awesome Oscillator Trader

Стратегия Awesome Oscillator Trader — это точная конверсия советника MetaTrader «AwesomeOscTrader». В её основе лежит индикатор Bill Williams Awesome Oscillator, фильтр ширины полос Боллинджера и стохастик. Цель — находить моменты, когда после затухания волатильности возникает импульсный пробой. Базовый таймфрейм — часовые свечи по одной валютной паре (например, EURUSD), что полностью повторяет оригинальные настройки.

Система ждёт, пока расстояние между верхней и нижней полосами Боллинджера попадёт в заданный диапазон — это означает, что рынок сжался, но не уснул. Во время такого «зажима» гистограмма Awesome Oscillator должна сформировать характерный разворотный рисунок из пяти баров: четыре подряд гистограммы понижательного цвета ниже нуля, а затем новая гистограмма противоположного цвета, но всё ещё ниже нуля. Если одновременно %K стохастика поднимается выше порога перепроданности, стратегия открывает длинную позицию, ожидая выход вверх. Зеркальное условие — четыре положительные гистограммы выше нуля и новая нисходящая гистограмма, остающаяся в положительной области, плюс %K ниже верхнего порога — даёт сигнал на короткую позицию.

Защита позиции строится на динамическом стопе: каждая свеча считывается ATR с периодом 3, умножается на коэффициент и переводится в пункты с учётом шага цены инструмента. Полученное значение задаёт одновременно стоп-лосс и тейк-профит, что полностью соответствует симметричной логике советника. Дополнительный трейлинг-стоп подтягивает защитный уровень при движении цены в нужную сторону, а параметр CloseOnReversal позволяет закрывать сделки при появлении обратного сигнала или смены цвета гистограммы. Фильтр прибыли ProfitFilter задаёт, нужно ли закрывать любые сделки, только прибыльные или только убыточные — аналог опции «ProfitTypeClTrd» в MT4.

Правила торговли

  • Таймфрейм: по умолчанию свечи H1 (можно изменить).
  • Фильтры:
    • Ширина полос Боллинджера должна находиться между BollingerSpreadLower и BollingerSpreadUpper пунктами.
    • Стохастик сравнивается с уровнями StochasticLowerLevel (для покупок) и StochasticUpperLevel (для продаж).
    • Awesome Oscillator обязан сформировать описанную пятибаровую структуру, причём последняя гистограмма меняет цвет, оставаясь по ту же сторону нуля, а её нормированная величина превышает AoStrengthLimit.
  • Входы:
    • Покупка: выполнены фильтры и текущий бар попадает в торговое окно по времени.
    • Продажа: зеркальные условия.
  • Выходы:
    • Стоп-лосс и тейк-профит размещаются симметрично на основе ATR.
    • При TrailingStopPips > 0 включается трейлинг-стоп.
    • При активном CloseOnReversal сделки закрываются по обратному сигналу, с учётом фильтра ProfitFilter.

Основные параметры

Параметр Значение по умолчанию Описание
CandleType 1 час Таймфрейм для расчёта индикаторов.
BollingerPeriod 20 Период полос Боллинджера.
BollingerSigma 2.0 Множитель стандартного отклонения.
BollingerSpreadLower 24 пункта Минимальная ширина полос.
BollingerSpreadUpper 230 пунктов Максимальная ширина полос.
AoFastPeriod / AoSlowPeriod 4 / 28 Быстрая и медленная части Awesome Oscillator.
AoStrengthLimit 0.0 Минимальная нормированная величина AO для подтверждения входа.
StochasticKPeriod / StochasticDPeriod / StochasticSlowing 1 / 4 / 1 Периоды стохастика, совпадающие с настройками советника.
StochasticLowerLevel / StochasticUpperLevel 12 / 21 Пороги перепроданности и перекупленности.
EntryHour / OpenHours 16 / 13 Начальный час торговли и длительность окна (учитывает переход через полночь).
RiskPercent 0.5% Процент риска для расчёта объёма, если доступны данные портфеля.
AtrMultiplier 4.5 Множитель ATR для вычисления стопа.
TrailingStopPips 40 пунктов Дистанция трейлинг-стопа (0 — отключить).
ProfitFilter OnlyProfitable Тип сделок, которые можно закрывать при развороте сигнала.
MaxOpenOrders 1 Максимальное число одновременных позиций.

Особенности реализации

  • Используются штатные индикаторы StockSharp: BollingerBands, StochasticOscillator, AwesomeOscillator, AverageTrueRange, Highest — никаких ручных расчётов.
  • Значения AO нормируются по максимуму за последние 100 баров, что имитирует буферы кастомного индикатора и полностью сохраняет цветовую логику.
  • Расчёт объёма учитывает Security.StepVolume, Security.MinVolume, Security.MaxVolume и Security.StepPrice; при отсутствии данных берётся объём стратегии.
  • Проверки стоп-лосса и тейк-профита выполняются внутри стратегии на каждой завершённой свече, что повторяет тиковое сопровождение из 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>
/// Awesome Oscillator Trader strategy: SMA 5/20 crossover (AO concept).
/// Buys when fast SMA crosses above slow SMA, sells on cross below.
/// </summary>
public class AwesomeOscillatorTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public AwesomeOscillatorTraderStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 34)
			.SetGreaterThanZero()
			.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };

		decimal? prevFast = null;
		decimal? prevSlow = null;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, (candle, fastVal, slowVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (prevFast.HasValue && prevSlow.HasValue)
				{
					var crossUp = prevFast.Value <= prevSlow.Value && fastVal > slowVal;
					var crossDown = prevFast.Value >= prevSlow.Value && fastVal < slowVal;

					if (crossUp && Position <= 0)
						BuyMarket();
					else if (crossDown && Position >= 0)
						SellMarket();
				}

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fast);
			DrawIndicator(area, slow);
			DrawOwnTrades(area);
		}
	}
}