Перед вами конверсия эксперта MetaTrader N7S_AO_772012 на платформу StockSharp. Исходный робот сочетает несколько «персептронов» индикатора Awesome Oscillator (AO) на разных таймфреймах, фильтр по ценовому паттерну и особый режим neuro, который может переопределять базовую логику. В порте сохранена структура решений, а все параметры вынесены в свойства стратегии.
Стратегия работает по выбранному инструменту и использует следующие данные:
Свечи M1 – для синхронизации входов и расчёта ценового персептрона.
Свечи H1 – источник значений AO для пяти персептронов.
Свечи H4 – позволяют вычислять дельту AO, которую использует базовый блок Buy/Sell (BTS).
Логика торговли
На закрытии каждой M1-свечи обновляется история ценового паттерна, выполняется сопровождение позиции и проверяется торговый интервал (торговля запрещена в понедельник до 02:00 и в пятницу с 18:00 по локальному времени платформы).
Значения AO с часового таймфрейма подаются на пять персептронов:
Perceptron X/Y – базовые фильтры BTS, которые работают вместе с ценовым персептроном и H4-дельтой AO.
Neuro X/Y – продвинутые фильтры для лонга/шорта, имеющие приоритет в выбранных режимах neuro.
Neuro Z – управляющий персептрон, разрешающий или запрещающий сигналы Neuro X в режиме 4.
Ценовой персептрон вычисляет взвешенные разности между текущим закрытием и несколькими прошлыми открытиями M1.
Параметр NeuroMode определяет порядок работы продвинутых персептронов:
4: если Neuro Z > 0, то допускаются только лонги от Neuro X; иначе возможен шорт от Neuro Y. При отсутствии сигналов выполняется откат к BTS.
3: при Neuro Y > 0 открывается шорт, иначе используется BTS.
2: при Neuro X > 0 открывается лонг, иначе используется BTS.
Любое другое значение – продвинутый слой пропускается, сразу выполняется BTS.
Блок 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.
При выполнении условий открывается рыночный ордер в разрешённом направлении. Защитные уровни хранятся внутри стратегии: каждая завершённая свеча 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-персептронов.
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();
}
}
}
}
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.Strategies import Strategy
from StockSharp.Algo.Indicators import AwesomeOscillator
class n7_s_ao772012_strategy(Strategy):
def __init__(self):
super(n7_s_ao772012_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(2))) \
.SetDisplay("Candle Type", "Timeframe for analysis", "General")
self._ao_period = self.Param("AoPeriod", 5) \
.SetDisplay("AO Period", "Period for the Awesome Oscillator", "Indicators")
self._lookback = self.Param("Lookback", 3) \
.SetDisplay("Lookback", "Number of AO values to look back for signal", "Indicators")
self._ao_history = []
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def AoPeriod(self):
return self._ao_period.Value
@property
def Lookback(self):
return self._lookback.Value
def OnStarted2(self, time):
super(n7_s_ao772012_strategy, self).OnStarted2(time)
self._ao_history = []
self._entry_price = 0.0
self._ao = AwesomeOscillator()
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._ao, self.ProcessCandle).Start()
def ProcessCandle(self, candle, ao_value):
if candle.State != CandleStates.Finished:
return
ao_val = float(ao_value)
self._ao_history.append(ao_val)
if len(self._ao_history) > 50:
self._ao_history.pop(0)
lookback = self.Lookback
if len(self._ao_history) < lookback + 1:
return
close = float(candle.ClosePrice)
current = self._ao_history[-1]
prev = self._ao_history[-1 - lookback]
rising = current > prev and current > 0
falling = current < prev and current < 0
# Manage positions
if self.Position > 0:
if current < 0 or (self._entry_price > 0 and close < self._entry_price * 0.98):
self.SellMarket()
elif self.Position < 0:
if current > 0 or (self._entry_price > 0 and close > self._entry_price * 1.02):
self.BuyMarket()
# Entry
if self.Position == 0:
if rising:
self._entry_price = close
self.BuyMarket()
elif falling:
self._entry_price = close
self.SellMarket()
def OnReseted(self):
super(n7_s_ao772012_strategy, self).OnReseted()
self._ao_history = []
self._entry_price = 0.0
def CreateClone(self):
return n7_s_ao772012_strategy()