Hpcs Inter7 — это система пробоя полос Боллинджера, конвертированная из эксперт-советника MetaTrader 4 _HPCS_Inter7_MT4_EA_V01_We.mq4. Алгоритм рассчитывает стандартные полосы Боллинджера по выбранной серии свечей. Когда цена закрытия выходит за границы диапазона, стратегия воспринимает это как импульсный пробой и открывает позицию по направлению движения. Для каждой новой сделки сразу выставляются стоп-лосс и тейк-профит на фиксированном расстоянии от цены входа, полностью повторяя оригинальную логику EA.
Логика торговли
Открытие продажи: если предыдущая свеча закрылась выше нижней полосы, а последняя закрытая свеча завершилась ниже нижней полосы, подаётся рыночная заявка на продажу. Условие соответствует MQL4-выражению Close[0] < LowerBand[0] && Close[1] > LowerBand[1].
Открытие покупки: если предыдущая свеча закрылась ниже верхней полосы, а последняя закрытая свеча закрылась выше неё, размещается рыночная заявка на покупку. Это реализует условие Close[0] > UpperBand[0] && Close[1] < UpperBand[1].
Одна сделка на свечу: стратегия запоминает время открытия свечи, на которой была совершена последняя сделка. Повторный сигнал на той же свече игнорируется — аналог переменной gdt_Candle из MQL4.
Защитные приказы: после открытия позиции вызываются методы SetStopLoss и SetTakeProfit, которые симметрично размещают стоп-лосс и тейк-профит относительно цены входа и обеспечивают постоянный контроль риска.
Параметры
Название
Описание
Значение по умолчанию
Оптимизация
BollingerLength
Количество свечей для расчёта полос Боллинджера.
20
Да
BollingerDeviation
Множитель стандартного отклонения для ширины полос.
2
Да
CandleType
Тип свечей для расчётов (по умолчанию минутные).
Свечи 1 минута
Нет
ProtectionDistancePoints
Расстояние до стоп-лосса и тейк-профита в шагах цены.
10
Да
Дополнительная информация
Используется высокоуровневый API StockSharp (SubscribeCandles().Bind(...)), поэтому не требуется хранить собственные массивы данных.
Метод StartProtection() активируется при запуске, чтобы платформа автоматически сопровождала защитные ордера, установленные SetStopLoss и SetTakeProfit.
Размер позиции задаётся свойством Strategy.Volume, что соответствует оригинальному советнику с фиксированным объёмом в один лот.
Хотя стратегия была создана для валютного рынка, её можно применять к любому инструменту с корректным PriceStep и информативными сигналами полос Боллинджера.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy converted from _HPCS_Inter7_MT4_EA_V01_We.mq4.
/// Sells when price crosses below the lower Bollinger band and buys when price crosses above the upper band.
/// </summary>
public class HpcsInter7Strategy : Strategy
{
private readonly StrategyParam<int> _bollingerLength;
private readonly StrategyParam<decimal> _bollingerDeviation;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _bandPercent;
private decimal? _prevClose;
private decimal? _prevLower;
private decimal? _prevUpper;
/// <summary>
/// Initializes a new instance of the <see cref="HpcsInter7Strategy"/> class.
/// </summary>
public HpcsInter7Strategy()
{
_bollingerLength = Param(nameof(BollingerLength), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Length", "Number of candles included in the Bollinger Bands calculation", "Indicators");
_bollingerDeviation = Param(nameof(BollingerDeviation), 2m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Deviation", "Standard deviation multiplier for the Bollinger Bands", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Time frame used for Bollinger Bands", "General");
_bandPercent = Param(nameof(BandPercent), 0.01m)
.SetGreaterThanZero()
.SetDisplay("Band Percent", "MA percentage band width", "Indicators");
}
/// <summary>
/// Bollinger Bands length.
/// </summary>
public int BollingerLength
{
get => _bollingerLength.Value;
set => _bollingerLength.Value = value;
}
/// <summary>
/// Bollinger Bands deviation multiplier.
/// </summary>
public decimal BollingerDeviation
{
get => _bollingerDeviation.Value;
set => _bollingerDeviation.Value = value;
}
/// <summary>
/// Candle type used for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public decimal BandPercent
{
get => _bandPercent.Value;
set => _bandPercent.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = null;
_prevLower = null;
_prevUpper = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = null;
_prevLower = null;
_prevUpper = null;
var bollinger = new ExponentialMovingAverage { Length = BollingerLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(bollinger, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, bollinger);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal middle)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var upper = middle * (1 + BandPercent);
var lower = middle * (1 - BandPercent);
if (_prevClose.HasValue && _prevLower.HasValue && _prevUpper.HasValue)
{
// Downward cross through the lower band - open short
if (_prevClose.Value > _prevLower.Value && candle.ClosePrice < lower && Position >= 0)
{
SellMarket();
}
// Upward cross through the upper band - open long
else if (_prevClose.Value < _prevUpper.Value && candle.ClosePrice > upper && Position <= 0)
{
BuyMarket();
}
}
_prevClose = candle.ClosePrice;
_prevLower = lower;
_prevUpper = upper;
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class hpcs_inter7_strategy(Strategy):
def __init__(self):
super(hpcs_inter7_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(60)))
self._bollinger_length = self.Param("BollingerLength", 20)
self._band_percent = self.Param("BandPercent", 0.01)
self._prev_close = 0.0
self._prev_lower = 0.0
self._prev_upper = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def BollingerLength(self):
return self._bollinger_length.Value
@BollingerLength.setter
def BollingerLength(self, value):
self._bollinger_length.Value = value
@property
def BandPercent(self):
return self._band_percent.Value
@BandPercent.setter
def BandPercent(self, value):
self._band_percent.Value = value
def OnReseted(self):
super(hpcs_inter7_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_lower = 0.0
self._prev_upper = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(hpcs_inter7_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_lower = 0.0
self._prev_upper = 0.0
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.BollingerLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, self._process_candle).Start()
def _process_candle(self, candle, middle_value):
if candle.State != CandleStates.Finished:
return
middle = float(middle_value)
band_pct = float(self.BandPercent)
upper = middle * (1.0 + band_pct)
lower = middle * (1.0 - band_pct)
close = float(candle.ClosePrice)
if self._has_prev:
# Downward cross through lower band - short
if self._prev_close > self._prev_lower and close < lower and self.Position >= 0:
self.SellMarket()
# Upward cross through upper band - long
elif self._prev_close < self._prev_upper and close > upper and self.Position <= 0:
self.BuyMarket()
self._prev_close = close
self._prev_lower = lower
self._prev_upper = upper
self._has_prev = True
def CreateClone(self):
return hpcs_inter7_strategy()