Стратегия Basic CCI RSI повторяет оригинального советника MetaTrader, который ожидает подтверждения импульса от индикаторов Commodity Channel Index (CCI) и Relative Strength Index (RSI) на двух подряд закрытых свечах перед открытием сделки. В версии для StockSharp сохранены все правила управления рисками в пунктах, расстояния автоматически переводятся в шаги цены, а логика трейлинг-стопа полностью повторяет функцию Trailing() из MQL5.
Алгоритм работы
После закрытия каждой свечи (по умолчанию — часовой) стратегия получает новые значения CCI и RSI.
Для открытия длинной позиции оба индикатора должны находиться выше своих верхних порогов на текущей и предыдущей закрытых свечах. Для открытия короткой позиции оба индикатора должны быть ниже нижних уровней на двух последних свечах.
При появлении сигнала стратегия открывает позицию заданного объёма (закрывая встречное плечо, если оно было) и сразу вычисляет уровни стоп-лосса и тейк-профита исходя из заданных расстояний в пунктах.
Пока позиция открыта, стратегия проверяет диапазон текущей свечи: если минимум/максимум касается стопа или тейка, происходит немедленный выход по рынку.
Трейлинг-стоп повторяет реализацию из MetaTrader: как только прибыль превышает сумму TrailingStopPips + TrailingStepPips, защитный стоп переносится на TrailingStopPips пунктов от текущего закрытия (для лонга) или выше него (для шорта). Каждое последующее подтягивание требует ещё TrailingStepPips пунктов прибыли.
Такое построение сохраняет логику MQL5-советника, но использует высокоуровневые подписки на свечи и индикаторы из StockSharp.
Управление рисками
Стоп-лосс: фиксированное расстояние в пунктах, преобразованное в шаг цены инструмента. При значении 0 не используется.
Тейк-профит: фиксированное расстояние в пунктах, преобразованное в шаг цены. При значении 0 отключается.
Трейлинг-стоп: опциональный трейлинг с буфером TrailingStepPips, полностью соответствующий функции Trailing() из исходника. При TrailingStopPips = 0 не активируется.
Размер позиции: задаётся свойством Volume стратегии; по умолчанию торгуется один контракт.
Параметры
Параметр
Описание
StopLossPips
Расстояние в пунктах между ценой входа и стоп-лоссом.
TakeProfitPips
Расстояние в пунктах до тейк-профита.
TrailingStopPips
Прибыль в пунктах, после которой запускается трейлинг.
TrailingStepPips
Дополнительная прибыль (в пунктах) для очередного подтягивания стопа.
CciPeriod
Период усреднения индикатора CCI.
RsiPeriod
Период усреднения индикатора RSI.
RsiLevelUp
Верхний уровень RSI, подтверждающий покупки.
RsiLevelDown
Нижний уровень RSI, подтверждающий продажи.
CciLevelUp
Верхний порог CCI для бычьих сигналов.
CciLevelDown
Нижний порог CCI для медвежьих сигналов.
CandleType
Таймфрейм свечей, по которым ведутся расчёты.
Значения по умолчанию
StopLossPips = 125
TakeProfitPips = 60
TrailingStopPips = 5
TrailingStepPips = 5
CciPeriod = 12
RsiPeriod = 15
RsiLevelUp = 75
RsiLevelDown = 30
CciLevelUp = 80
CciLevelDown = -95
CandleType = свечи 1 часа
Дополнительные замечания
При трёх- и пятизначной котировке стратегия автоматически умножает шаг цены на 10, что соответствует расчёту adjusted point в MetaTrader.
Сигналы анализируются только на закрытых свечах, поэтому поведение полностью соответствует условию «работать на новом баре» из оригинального кода.
Выходы выполняются рыночными ордерами, что обеспечивает детерминированный результат в тестере StockSharp.
Классификация
Категория: подтверждение осцилляторов
Направление: двунаправленная торговля
Индикаторы: CCI, RSI
Стопы: фиксированные и трейлинг (в пунктах)
Сложность: базовая
Таймфрейм: внутридневной/среднесрочный (по умолчанию 1 час)
Сезонность: нет
Нейросети: нет
Дивергенции: нет
Уровень риска: умеренный
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>
/// Basic CCI RSI strategy. Uses CCI zero-line crossover with RSI confirmation.
/// </summary>
public class BasicCciRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cciPeriod;
private decimal? _prevCci;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int CciPeriod { get => _cciPeriod.Value; set => _cciPeriod.Value = value; }
public BasicCciRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_cciPeriod = Param(nameof(CciPeriod), 20).SetGreaterThanZero().SetDisplay("CCI Period", "CCI lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevCci = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevCci = null;
var cci = new CommodityChannelIndex { Length = CciPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(cci, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal cciVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevCci = cciVal; return; }
if (_prevCci == null) { _prevCci = cciVal; return; }
if (_prevCci.Value < 0m && cciVal >= 0m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevCci.Value > 0m && cciVal <= 0m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevCci = cciVal;
}
}
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.Indicators import CommodityChannelIndex
from StockSharp.Algo.Strategies import Strategy
class basic_cci_rsi_strategy(Strategy):
def __init__(self):
super(basic_cci_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._cci_period = self.Param("CciPeriod", 20) \
.SetDisplay("CCI Period", "CCI lookback", "Indicators")
self._prev_cci = None
@property
def candle_type(self):
return self._candle_type.Value
@candle_type.setter
def candle_type(self, value):
self._candle_type.Value = value
@property
def cci_period(self):
return self._cci_period.Value
@cci_period.setter
def cci_period(self, value):
self._cci_period.Value = value
def OnReseted(self):
super(basic_cci_rsi_strategy, self).OnReseted()
self._prev_cci = None
def OnStarted2(self, time):
super(basic_cci_rsi_strategy, self).OnStarted2(time)
self._prev_cci = None
cci = CommodityChannelIndex()
cci.Length = self.cci_period
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(cci, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def OnProcess(self, candle, cci_val):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_cci = float(cci_val)
return
if self._prev_cci is None:
self._prev_cci = float(cci_val)
return
if self._prev_cci < 0 and cci_val >= 0 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_cci > 0 and cci_val <= 0 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_cci = float(cci_val)
def CreateClone(self):
return basic_cci_rsi_strategy()