Full Damp — это контртрендовая стратегия, использующая три набора полос Боллинджера и фильтр на основе RSI. Система ищет выбросы цены за пределы самых широких полос, чтобы обнаружить возможное истощение движения. После фиксации экстремума проверяется, попадал ли RSI в зону перепроданности или перекупленности в пределах последних LookbackBars свечей. Вход осуществляется, когда цена возвращается внутрь средней полосы. Управление позицией включает частичную фиксацию прибыли, перенос стоп-ордера и выход по сигналу полос Боллинджера.
Торговая логика
Определение сигнала
Лонг сигнал формируется, когда минимум свечи закрывается ниже нижней полосы Боллинджера с шириной 3. Шорт сигнал возникает при закрытии максимума выше верхней полосы того же набора.
В течение последних LookbackBars завершённых свечей RSI должен достигнуть значения ниже 30 (для покупки) или выше 70 (для продажи). Каждый новый экстремум обновляет таймер.
Точка входа
Покупка выполняется после закрытия цены выше нижней полосы набора с шириной 2 и при отсутствии открытой длинной позиции.
Продажа инициируется, когда цена закрывается ниже верхней полосы среднего набора.
Начальный стоп-лосс устанавливается на минимуме (для покупок) или максимуме (для продаж), зарегистрированном после появления сигнальной свечи, и расширяется на заданное количество пунктов.
Сопровождение позиции
При достижении прибыли, равной первоначальному риску, половина позиции закрывается, а стоп переносится в точку входа.
Оставшаяся часть закрывается, если максимум (для покупок) или минимум (для продаж) пересекает среднюю полосу Боллинджера в противоположную сторону.
Если цена раньше доходит до стоп-уровня, позиция закрывается полностью.
Параметры
Параметр
Описание
Значение по умолчанию
CandleType
Тип свечей, используемых для расчётов и торговли.
Часовые свечи
BollingerPeriod1
Период узких полос Боллинджера (ширина = 1).
20
BollingerPeriod2
Период средних полос Боллинджера (ширина = 2).
20
BollingerPeriod3
Период широких полос Боллинджера (ширина = 3).
20
RsiPeriod
Период RSI для фильтрации сигналов.
14
LookbackBars
Количество свечей для поиска экстремальных значений RSI.
6
StopOffsetPoints
Дополнительный зазор в пунктах для расчёта стоп-лосса.
10
Volume
Объём заявки, задаётся базовым классом.
1
Примечания
Пороговые значения RSI фиксированы на уровнях 30 и 70, чтобы соответствовать оригинальному советнику MQL.
Стратегия использует высокоуровневый API StockSharp: индикаторы подключаются через Bind, ордера исполняются по рынку, логика стопов и частичных выходов управляется внутри стратегии.
Все решения принимаются по закрытию свечи, что исключает реакции на незавершённые данные.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class FullDampStrategy : Strategy
{
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevRsi; private bool _hasPrev;
private int _cooldown;
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public FullDampStrategy()
{
_rsiPeriod = Param(nameof(RsiPeriod), 14).SetDisplay("RSI Period", "RSI lookback", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(15).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevRsi = default;
_hasPrev = default;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsi)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) return;
if (!_hasPrev) { _prevRsi = rsi; _hasPrev = true; return; }
if (_cooldown > 0)
{
_cooldown--;
_prevRsi = rsi;
return;
}
if (_prevRsi <= 30 && rsi > 30 && Position <= 0)
{
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
_cooldown = 2;
}
else if (_prevRsi >= 70 && rsi < 70 && Position >= 0)
{
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
_cooldown = 2;
}
_prevRsi = rsi;
}
}