Открыть на GitHub

Стратегия N7S AO 772012

Общее описание

Перед вами конверсия эксперта MetaTrader N7S_AO_772012 на платформу StockSharp. Исходный робот сочетает несколько «персептронов» индикатора Awesome Oscillator (AO) на разных таймфреймах, фильтр по ценовому паттерну и особый режим neuro, который может переопределять базовую логику. В порте сохранена структура решений, а все параметры вынесены в свойства стратегии.

Стратегия работает по выбранному инструменту и использует следующие данные:

  • Свечи M1 – для синхронизации входов и расчёта ценового персептрона.
  • Свечи H1 – источник значений AO для пяти персептронов.
  • Свечи H4 – позволяют вычислять дельту AO, которую использует базовый блок Buy/Sell (BTS).

Логика торговли

  1. На закрытии каждой M1-свечи обновляется история ценового паттерна, выполняется сопровождение позиции и проверяется торговый интервал (торговля запрещена в понедельник до 02:00 и в пятницу с 18:00 по локальному времени платформы).
  2. Значения AO с часового таймфрейма подаются на пять персептронов:
    • Perceptron X/Y – базовые фильтры BTS, которые работают вместе с ценовым персептроном и H4-дельтой AO.
    • Neuro X/Y – продвинутые фильтры для лонга/шорта, имеющие приоритет в выбранных режимах neuro.
    • Neuro Z – управляющий персептрон, разрешающий или запрещающий сигналы Neuro X в режиме 4.
  3. Ценовой персептрон вычисляет взвешенные разности между текущим закрытием и несколькими прошлыми открытиями M1.
  4. Параметр NeuroMode определяет порядок работы продвинутых персептронов:
    • 4: если Neuro Z > 0, то допускаются только лонги от Neuro X; иначе возможен шорт от Neuro Y. При отсутствии сигналов выполняется откат к BTS.
    • 3: при Neuro Y > 0 открывается шорт, иначе используется BTS.
    • 2: при Neuro X > 0 открывается лонг, иначе используется BTS.
    • Любое другое значение – продвинутый слой пропускается, сразу выполняется BTS.
  5. Блок BTS использует ценовой персептрон и H4-дельту AO как фильтры:
    • Лонг: ценовой персептрон > 0 (или игнорируется, если BtsMode = 0), персептрон X > 0 и H4-дельта AO > 0. Стоп равен BaseStopLossPointsLong, тейк – BaseTakeProfitFactorLong × BaseStopLossPointsLong.
    • Шорт: ценовой персептрон < 0 (или игнорируется при BtsMode = 0), персептрон Y > 0 и H4-дельта AO < 0. Стоп равен BaseStopLossPointsShort, тейк – BaseTakeProfitFactorShort × BaseStopLossPointsShort.
  6. При выполнении условий открывается рыночный ордер в разрешённом направлении. Защитные уровни хранятся внутри стратегии: каждая завершённая свеча M1 проверяет пробой стопа или цели по экстремумам свечи и закрывает позицию при достижении. Противоположный сигнал сначала закрывает текущую позицию, а на следующей свече логика оценивается заново.

Параметры

Торговля

  • OrderVolume – базовый объём рыночных заявок.
  • AllowLongTrades / AllowShortTrades – включение/отключение лонгов и шортов.
  • BtsMode – при значении 0 знак ценового персептрона в BTS не учитывается; иначе он должен совпадать с направлением сделки.
  • NeuroMode – выбор сценария участия продвинутых персептронов (см. выше).

Базовые персептроны BTS

  • BaseStopLossPointsLong / BaseTakeProfitFactorLong – стоп и множитель тейка для лонгов.
  • BaseStopLossPointsShort / BaseTakeProfitFactorShort – аналогичные параметры для шортов.
  • PerceptronPeriodX / Y – смещение AO (в барах H1) для соответствующего персептрона.
  • PerceptronWeightX1..4 / Y1..4 – веса входов (0–100), внутри стратегии из них вычитается 50 для центрирования.
  • PerceptronThresholdX / Y – минимальный по модулю результат персептрона, чтобы считать его валидным.

Ценовой фильтр

  • PricePatternPeriod – число M1-свечей в каждом лаге ценового персептрона.
  • PriceWeight1..4 – веса (также центрируются на 50) для расчёта ценовых разностей.

Персептроны Neuro

  • NeuroStopLossPointsLong / NeuroTakeProfitFactorLong – стоп и множитель тейка для сигналов Neuro X.
  • NeuroStopLossPointsShort / NeuroTakeProfitFactorShort – стоп и множитель тейка для сигналов Neuro Y.
  • NeuroPeriodX / Y / Z – смещения AO (бары H1) для трёх neuro-персептронов.
  • NeuroWeightX1..4 / NeuroWeightY1..4 / NeuroWeightZ1..4 – веса входов.
  • NeuroThresholdX / NeuroThresholdY / NeuroThresholdZ – пороги по модулю для каждого персептрона.

Данные

  • CandleType – основной таймфрейм торговли (по умолчанию 1 минута).

Управление позицией

  • Стоп и тейк переводятся из пунктов в абсолютные цены через минимальный шаг цены инструмента; нулевое значение отключает соответствующую защиту.
  • Контроль защитных уровней ведётся на закрытии каждой свечи M1 через сравнение с High/Low.
  • Используется неттинг: стратегия не держит разнонаправленные позиции одновременно. При смене направления текущая позиция закрывается перед поиском нового входа.

Особенности конверсии

  • Для получения значений AO применены высокоуровневые привязки StockSharp (SubscribeCandles().Bind(...)), что избавляет от прямых запросов к индикатору.
  • Исторические массивы реализованы в виде ограниченных списков, что имитирует доступ по смещениям как в MQL4 и не требует вызовов GetValue.
  • Python-версия по требованию не создавалась.
  • Тестовые проекты не изменялись.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Perceptron-based strategy using Awesome Oscillator values at different lookback periods.
/// Combines weighted AO signals with price pattern confirmation for entry/exit decisions.
/// </summary>
public class N7SAo772012Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _aoPeriod;
	private readonly StrategyParam<int> _lookback;

	private readonly List<decimal> _aoHistory = new();
	private decimal _entryPrice;

	public N7SAo772012Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(2).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for analysis.", "General");

		_aoPeriod = Param(nameof(AoPeriod), 5)
			.SetDisplay("AO Period", "Period for the Awesome Oscillator.", "Indicators");

		_lookback = Param(nameof(Lookback), 3)
			.SetDisplay("Lookback", "Number of AO values to look back for signal.", "Indicators");
	}

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

	public int AoPeriod
	{
		get => _aoPeriod.Value;
		set => _aoPeriod.Value = value;
	}

	public int Lookback
	{
		get => _lookback.Value;
		set => _lookback.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_aoHistory.Clear();
		_entryPrice = 0;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ao = new AwesomeOscillator();

		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 aoValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		_aoHistory.Add(aoValue);
		if (_aoHistory.Count > 50)
			_aoHistory.RemoveAt(0);

		if (_aoHistory.Count < Lookback + 1)
			return;

		var close = candle.ClosePrice;
		var current = _aoHistory[_aoHistory.Count - 1];
		var prev = _aoHistory[_aoHistory.Count - 1 - Lookback];

		// AO momentum: current vs lookback periods ago
		var rising = current > prev && current > 0;
		var falling = current < prev && current < 0;

		// Manage positions
		if (Position > 0)
		{
			// Exit long if AO turns negative or stop-loss
			if (current < 0 || (_entryPrice > 0 && close < _entryPrice * 0.98m))
			{
				SellMarket();
			}
		}
		else if (Position < 0)
		{
			// Exit short if AO turns positive or stop-loss
			if (current > 0 || (_entryPrice > 0 && close > _entryPrice * 1.02m))
			{
				BuyMarket();
			}
		}

		// Entry
		if (Position == 0)
		{
			if (rising)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (falling)
			{
				_entryPrice = close;
				SellMarket();
			}
		}
	}
}