Эта стратегия переносит советник MetaTrader 5 "Expert_AML_CCI" в высокоуровневый фреймворк StockSharp. Исходный робот объединяет
японскую свечную модель «Meeting Lines» с фильтром Commodity Channel Index (CCI) и использует механизм Expert Advisor для
взвешивания бычьих и медвежьих сигналов. Порт на StockSharp сохраняет ту же логику подтверждения, переписывает распознавание
свечных моделей через арифметику свечей и делает все пороговые уровни доступными для оптимизации.
Как это работает
Источник данных – Стратегия подписывается на свечи выбранного таймфрейма (по умолчанию 30 минут) с помощью SubscribeCandles.
Каждый завершённый бар поступает вместе с синхронизированным значением CCI через высокоуровневый конвейер Bind, поэтому
ручное сопровождение индикатора не требуется.
Основной индикатор – Один CommodityChannelIndex с периодом CciPeriod полностью повторяет осциллятор из MetaTrader. Значения
сохраняются во внутреннем буфере, чтобы сравнивать два последних завершённых чтения, тем самым имитируя вызовы CCI(1) и
CCI(2) в MQL.
Логика свечей – Вспомогательные методы воспроизводят проверки "Bullish Meeting Lines" и "Bearish Meeting Lines". Они вычисляют
скользящее среднее длины тел за AverageBodyPeriod свечей (по умолчанию 3) и соблюдают требования к длинным телам и почти равным
закрытиям, заложенные в фильтре CML_CCI. StockSharp работает с закрытыми свечами, поэтому модель оценивается в тот же момент,
когда закрывается вторая свеча паттерна – именно тогда MQL-советник отдаёт свои 80 голосов.
Правила входа –
Для открытия лонга необходим бычий паттерн Meeting Lines и последнее завершённое значение CCI, не превышающее LongEntryCciLevel
(по умолчанию −50). Если в рынке уже есть шорт, объём заявки автоматически включает абсолютную величину текущей позиции, чтобы
перевернуться, как в оригинальном роботе.
Для шорта условия зеркальные: медвежий Meeting Lines и значение CCI не ниже ShortEntryCciLevel (по умолчанию +50).
Правила выхода – Вместо голосов Expert Advisor используются явные команды на закрытие позиции. Выход выполняется, когда CCI
пересекает экстремальную границу ExtremeCciLevel (по умолчанию 80):
Шорты закрываются, когда CCI пробивает снизу вверх уровень −Extreme или возвращается ниже +Extreme.
Лонги закрываются, когда CCI опускается ниже +Extreme или прорывает вниз уровень −Extreme.
Эти условия повторяют ветку с весом 40 в методах LongCondition и ShortCondition класса сигнала MQL.
Управление рисками – Защитные стопы и тейк-профиты оставлены на усмотрение пользователя. При необходимости можно подключить
стандартный StartProtection из StockSharp.
Параметры
Параметр
Описание
Значение по умолчанию
CandleType
Таймфрейм исходных свечей.
30 минут
CciPeriod
Период осциллятора CCI.
18
AverageBodyPeriod
Количество свечей для расчёта средней длины тела.
3
LongEntryCciLevel
Уровень перепроданности для подтверждения бычьего паттерна.
−50
ShortEntryCciLevel
Уровень перекупленности для подтверждения медвежьего паттерна.
+50
ExtremeCciLevel
Абсолютное значение полосы CCI для выходов.
80
Все числовые параметры имеют диапазоны оптимизации, соответствующие настройкам оригинального советника, поэтому стратегию можно
тонко настраивать через инструменты оптимизации StockSharp.
Рекомендации по использованию
Перед запуском привяжите стратегию к инструменту и задайте желаемый Volume.
При необходимости скорректируйте пороговые значения под свою модель управления капиталом или под требуемую чувствительность.
Графический модуль отображает свечи, кривую CCI и совершённые сделки, что упрощает визуальную проверку работы фильтра свечей.
Сохраняя ту же комбинацию свечных моделей и CCI, порт на StockSharp обеспечивает точное соответствие советнику Expert_AML_CCI и
следует рекомендациям по использованию высокоуровневого API.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Meeting Lines + CCI strategy.
/// Buys on bullish meeting lines with low CCI, sells on bearish meeting lines with high CCI.
/// </summary>
public class AmlCciMeetingLinesStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private readonly StrategyParam<decimal> _cciLow;
private readonly StrategyParam<decimal> _cciHigh;
private ICandleMessage _prevCandle;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public decimal CciLow { get => _cciLow.Value; set => _cciLow.Value = value; }
public decimal CciHigh { get => _cciHigh.Value; set => _cciHigh.Value = value; }
public AmlCciMeetingLinesStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("CCI Period", "CCI period", "Indicators");
_cciLow = Param(nameof(CciLow), -50m)
.SetDisplay("CCI Low", "CCI level for bullish entry", "Signals");
_cciHigh = Param(nameof(CciHigh), 50m)
.SetDisplay("CCI High", "CCI level for bearish entry", "Signals");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCandle = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCandle = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal cciValue)
{
if (candle.State != CandleStates.Finished) return;
if (_prevCandle != null)
{
var avgBody = (Math.Abs(candle.ClosePrice - candle.OpenPrice) +
Math.Abs(_prevCandle.ClosePrice - _prevCandle.OpenPrice)) / 2m;
if (avgBody > 0)
{
var prevBearish = _prevCandle.OpenPrice > _prevCandle.ClosePrice;
var currBullish = candle.ClosePrice > candle.OpenPrice;
var closesNear = Math.Abs(candle.ClosePrice - _prevCandle.ClosePrice) < avgBody * 0.3m;
// Bullish meeting lines
if (prevBearish && currBullish && closesNear && cciValue < CciLow && Position <= 0)
BuyMarket();
var prevBullish = _prevCandle.ClosePrice > _prevCandle.OpenPrice;
var currBearish = candle.OpenPrice > candle.ClosePrice;
var closesNear2 = Math.Abs(candle.ClosePrice - _prevCandle.ClosePrice) < avgBody * 0.3m;
// Bearish meeting lines
if (prevBullish && currBearish && closesNear2 && cciValue > CciHigh && Position >= 0)
SellMarket();
}
}
_prevCandle = candle;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import CandleStates
from StockSharp.Algo.Indicators import CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
class aml_cci_meeting_lines_strategy(Strategy):
"""
Meeting Lines + CCI strategy.
Buys on bullish meeting lines with low CCI, sells on bearish meeting lines with high CCI.
"""
def __init__(self):
super(aml_cci_meeting_lines_strategy, self).__init__()
self._candle_type = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Candle timeframe", "General")
self._cci_period = self.Param("CciPeriod", 14) \
.SetGreaterThanZero() \
.SetDisplay("CCI Period", "CCI period", "Indicators")
self._cci_low = self.Param("CciLow", -50.0) \
.SetDisplay("CCI Low", "CCI level for bullish entry", "Signals")
self._cci_high = self.Param("CciHigh", 50.0) \
.SetDisplay("CCI High", "CCI level for bearish entry", "Signals")
self._prev_open = None
self._prev_close = None
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
@property
def CciPeriod(self): return self._cci_period.Value
@CciPeriod.setter
def CciPeriod(self, v): self._cci_period.Value = v
@property
def CciLow(self): return self._cci_low.Value
@CciLow.setter
def CciLow(self, v): self._cci_low.Value = v
@property
def CciHigh(self): return self._cci_high.Value
@CciHigh.setter
def CciHigh(self, v): self._cci_high.Value = v
def OnReseted(self):
super(aml_cci_meeting_lines_strategy, self).OnReseted()
self._prev_open = None
self._prev_close = None
def OnStarted2(self, time):
super(aml_cci_meeting_lines_strategy, self).OnStarted2(time)
self._prev_open = None
self._prev_close = None
cci = CommodityChannelIndex()
cci.Length = self.CciPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(cci, self.ProcessCandle).Start()
def ProcessCandle(self, candle, cci_value):
if candle.State != CandleStates.Finished:
return
c_open = float(candle.OpenPrice)
c_close = float(candle.ClosePrice)
if self._prev_open is not None and self._prev_close is not None:
avg_body = (abs(c_close - c_open) + abs(self._prev_close - self._prev_open)) / 2.0
if avg_body > 0:
prev_bearish = self._prev_open > self._prev_close
curr_bullish = c_close > c_open
closes_near = abs(c_close - self._prev_close) < avg_body * 0.3
if prev_bearish and curr_bullish and closes_near and cci_value < self.CciLow and self.Position <= 0:
self.BuyMarket()
prev_bullish = self._prev_close > self._prev_open
curr_bearish = c_open > c_close
closes_near2 = abs(c_close - self._prev_close) < avg_body * 0.3
if prev_bullish and curr_bearish and closes_near2 and cci_value > self.CciHigh and self.Position >= 0:
self.SellMarket()
self._prev_open = c_open
self._prev_close = c_close
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return aml_cci_meeting_lines_strategy()