AOCCI — это прямой перенос советника MetaTrader 4 «AOCCI». Стратегия комбинирует индикаторы импульса (Awesome Oscillator) и отклонения от среднего (Commodity Channel Index) с дневным пивотом предыдущей сессии. Перенос выполнен на высокоуровневом API StockSharp и сохраняет защитные механизмы оригинала.
Логика работы
Подготовка данных
Для формирования сигналов используются внутридневные свечи (по умолчанию часовые).
Дневные свечи применяются для расчёта пивота предыдущего дня по формуле (High + Low + Close) / 3.
Хранятся последние шесть цен открытия внутридневных свечей для контроля крупных гэпов.
Фильтр гэпов
Если разница между соседними открытиями превышает порог Big Jump Filter, сигнал пропускается.
Если разница между открытиями через одну свечу превышает Double Jump Filter, сигнал также игнорируется.
Проверка индикаторов
На текущей свече AO должен быть больше нуля, а CCI — не ниже нуля.
На предыдущей свече хотя бы одно условие должно выполняться: AO < 0, CCI ≤ 0 или цена закрытия ниже пивота.
Фильтр направления
Закрытие текущей свечи должно находиться выше пивота.
Правила входа
В оригинальном советнике условие на продажу совпадает с условием на покупку, поэтому реально открываются только длинные позиции. Конвертация сохраняет такую же логику.
Объём рыночного ордера задаётся параметром Order Volume.
Защитные механизмы
Начальные стоп-лосс и тейк-профит задаются в шагах цены.
Опциональный трейлинг-стоп подтягивает стоп, когда цена проходит заданное расстояние в прибыльную сторону.
Параметры
Название
Описание
CciPeriod
Период расчёта индикатора CCI (по умолчанию 55).
SignalCandleOffset
Дополнительное смещение при обращении к историческим дневным свечам (по умолчанию 0).
StopLossPoints
Размер стоп-лосса в шагах цены.
TakeProfitPoints
Размер тейк-профита в шагах цены.
TrailingStopPoints
Дистанция трейлинг-стопа в шагах цены (0 — отключен).
BigJumpPoints
Максимально допустимый гэп между соседними открытиями в шагах цены.
DoubleJumpPoints
Максимально допустимый совокупный гэп между открытиями через одну свечу.
OrderVolume
Объём заявок при входе в позицию.
CandleType
Тип внутридневных свечей (по умолчанию часовые).
DailyCandleType
Тип дневных свечей для расчёта пивота.
Рекомендации по использованию
Необходимо подписывать стратегию одновременно на внутридневные и дневные данные.
Минимальный шаг цены инструмента используется для пересчёта параметров, заданных в пунктах.
Управление трейлинг-стопом выполняется по факту закрытия свечи, что соответствует поведению MQL4 версии.
Поскольку исходный советник не открывает короткие позиции, портированная стратегия также работает только в длинную сторону.
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>
/// AOCCI Pivot strategy - CCI crossover with momentum filter.
/// Buys when CCI crosses above 0 with positive momentum.
/// Sells when CCI crosses below 0 with negative momentum.
/// </summary>
public class AocciPivotFilterStrategy : Strategy
{
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<int> _momentumPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevCci;
private bool _hasPrev;
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AocciPivotFilterStrategy()
{
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetDisplay("CCI Period", "CCI period", "Indicators");
_momentumPeriod = Param(nameof(MomentumPeriod), 10)
.SetDisplay("Momentum Period", "Momentum period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = 0m;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var mom = new Momentum { Length = MomentumPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(cci, mom, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue, decimal momValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevCci = cciValue;
_hasPrev = true;
return;
}
// CCI crosses above 0 with positive momentum
if (_prevCci <= 0 && cciValue > 0 && momValue > 0 && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// CCI crosses below 0 with negative momentum
else if (_prevCci >= 0 && cciValue < 0 && momValue < 0 && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevCci = cciValue;
}
}