Стратегия Heiken Ashi Smoothed MTF — это порт советника "HASNEWJ" с платформы MetaTrader. Она заново строит сглаженные свечи Heiken Ashi на шести таймфреймах (M1, M5, M15, M30, H1, H4) и ждёт, пока старшие интервалы полностью совпадут по направлению. Сделка открывается, когда поток M5 показывает свежую коррекцию, а более длинные временные рамки продолжают демонстрировать сильный бычий или медвежий тренд. Ручные стоп-лосс и тейк-профит повторяют поведение оригинального EA, включая автоматическое увеличение стопа после убыточной сделки.
Индикаторы и данные
Сглаженные свечи Heiken Ashi на таймфреймах M1, M5, M15, M30, H1 и H4.
Первый этап сглаживания применяет настраиваемое скользящее среднее к исходным значениям OHLC.
Второй этап сглаживает промежуточные значения открытия и закрытия Heiken Ashi ещё одним скользящим средним.
Счётчики направлений, которые показывают, сколько обновлений M1 каждый таймфрейм оставался бычьим или медвежьим.
Цена закрытия M1 для проверки условий по стоп-лоссу и тейк-профиту.
Логика входа
При закрытии каждой свечи обновлять направление сглаженного Heiken Ashi на соответствующем таймфрейме.
После закрытия M1 увеличивать или сбрасывать счётчики бычьих/медвежьих состояний в зависимости от текущего направления на каждом таймфрейме.
Условия для покупки:
Сглаженный Heiken Ashi на M5 бычий и счётчик бычьих обновлений меньше MaxM5TrendLength (по умолчанию 10).
Сглаженный Heiken Ashi на M15 бычий и счётчик бычьих обновлений превышает MinM15TrendLength (по умолчанию 200).
Сглаженные свечи на M30, H1 и H4 также бычьи.
В настоящий момент нет длинной позиции (короткая позиция может быть перевёрнута).
Условия для продажи:
Сглаженный Heiken Ashi на M5 медвежий и счётчик медвежьих обновлений меньше MaxM5TrendLength.
Сглаженный Heiken Ashi на M15 медвежий и счётчик медвежьих обновлений превышает MinM15TrendLength.
Сглаженные свечи на M30, H1 и H4 медвежьи.
Нет открытой короткой позиции (длинная позиция будет закрыта или перевёрнута).
Объём рыночного ордера равен TradeVolume плюс модуль текущей позиции противоположного направления, чтобы переворот закрывал прежнюю сделку.
Управление рисками
На каждом закрытии M1 рассчитывается ручной стоп-лосс и тейк-профит с использованием Security.PriceStep.
Позиция закрывается по тейк-профиту, если цена проходит TakeProfitPoints шагов в прибыльную сторону.
Позиция закрывается по стоп-лоссу, если цена проходит StopLossPoints шагов против позиции.
После убыточной сделки следующий вход расширяет стоп-лосс на ExtraStopLossPoints шагов, имитируя флаг fail из оригинального советника.
Объём сделки фиксируется параметром TradeVolume; стратегия не наращивает позицию, кроме случаев переворота.
Параметры
Имя
Описание
Значение по умолчанию
TradeVolume
Базовый объём рыночных ордеров
0.1
TakeProfitPoints
Дистанция тейк-профита в ценовых шагах
20
StopLossPoints
Дистанция стоп-лосса в ценовых шагах
500
ExtraStopLossPoints
Дополнительные шаги стоп-лосса после убыточной сделки
5
FirstMaPeriod
Период первого сглаживающего скользящего среднего
6
FirstMaMethod
Тип первого скользящего среднего (Simple, Exponential, Smoothed, LinearWeighted)
Smoothed
SecondMaPeriod
Период второго сглаживающего скользящего среднего
2
SecondMaMethod
Тип второго скользящего среднего
LinearWeighted
MaxM5TrendLength
Максимальное число обновлений M5, разрешающее вход на откате
10
MinM15TrendLength
Минимальное число обновлений M15, подтверждающее тренд
200
M1CandleType
Тип данных для базовых минутных свечей
TimeFrame(00:01:00)
M5CandleType
Тип данных для свечей подтверждения на M5
TimeFrame(00:05:00)
M15CandleType
Тип данных для свечей подтверждения на M15
TimeFrame(00:15:00)
M30CandleType
Тип данных для свечей подтверждения на M30
TimeFrame(00:30:00)
H1CandleType
Тип данных для свечей подтверждения на H1
TimeFrame(01:00:00)
H4CandleType
Тип данных для свечей подтверждения на H4
TimeFrame(04:00:00)
Рекомендации по использованию
Счётчики направлений обновляются на закрытии каждой M1 свечи, что приблизительно воспроизводит тиковые счётчики MetaTrader, оставаясь при этом в рамках свечной модели.
Убедитесь, что для инструмента задан Security.PriceStep; если его нет, стратегия использует шаг 0.0001 при расчёте стопа и цели.
Оба этапа сглаживания строятся на скользящих средних. Подбор метода и периода для каждого этапа помогает адаптировать систему к разным уровням волатильности инструмента.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Heiken Ashi Smoothed MTF: EMA trend with RSI filter and ATR stops.
/// </summary>
public class HeikenAshiSmoothedMtfStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _rsiLength;
private readonly StrategyParam<int> _atrLength;
private decimal _prevClose;
private decimal _entryPrice;
public HeikenAshiSmoothedMtfStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_emaLength = Param(nameof(EmaLength), 20)
.SetDisplay("EMA Length", "Trend filter.", "Indicators");
_rsiLength = Param(nameof(RsiLength), 14)
.SetDisplay("RSI Length", "RSI period.", "Indicators");
_atrLength = Param(nameof(AtrLength), 14)
.SetDisplay("ATR Length", "ATR period.", "Indicators");
}
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
public int RsiLength { get => _rsiLength.Value; set => _rsiLength.Value = value; }
public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevClose = 0; _entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevClose = 0; _entryPrice = 0;
var ema = new ExponentialMovingAverage { Length = EmaLength };
var rsi = new RelativeStrengthIndex { Length = RsiLength };
var atr = new AverageTrueRange { Length = AtrLength };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, rsi, atr, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal rsiVal, decimal atrVal)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
if (_prevClose == 0 || atrVal <= 0) { _prevClose = close; return; }
if (Position > 0)
{
if (close < emaVal || close <= _entryPrice - atrVal * 1.5m || close >= _entryPrice + atrVal * 2.5m) { SellMarket(); _entryPrice = 0; }
}
else if (Position < 0)
{
if (close > emaVal || close >= _entryPrice + atrVal * 1.5m || close <= _entryPrice - atrVal * 2.5m) { BuyMarket(); _entryPrice = 0; }
}
if (Position == 0)
{
if (close > emaVal && _prevClose <= emaVal && rsiVal > 50) { _entryPrice = close; BuyMarket(); }
else if (close < emaVal && _prevClose >= emaVal && rsiVal < 50) { _entryPrice = close; SellMarket(); }
}
_prevClose = close;
}
}
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, RelativeStrengthIndex, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class heiken_ashi_smoothed_mtf_strategy(Strategy):
"""
Heiken Ashi Smoothed MTF: EMA trend with RSI filter and ATR stops.
Buys on EMA cross up with RSI > 50. Sells on EMA cross down with RSI < 50.
Uses ATR for dynamic SL/TP.
"""
def __init__(self):
super(heiken_ashi_smoothed_mtf_strategy, self).__init__()
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "Trend filter", "Indicators")
self._rsi_length = self.Param("RsiLength", 14) \
.SetDisplay("RSI Length", "RSI period", "Indicators")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._prev_close = 0.0
self._entry_price = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(heiken_ashi_smoothed_mtf_strategy, self).OnReseted()
self._prev_close = 0.0
self._entry_price = 0.0
def OnStarted2(self, time):
super(heiken_ashi_smoothed_mtf_strategy, self).OnStarted2(time)
ema = ExponentialMovingAverage()
ema.Length = self._ema_length.Value
rsi = RelativeStrengthIndex()
rsi.Length = self._rsi_length.Value
atr = AverageTrueRange()
atr.Length = self._atr_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(ema, rsi, atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _process_candle(self, candle, ema_val, rsi_val, atr_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
ema = float(ema_val)
rsi = float(rsi_val)
atr = float(atr_val)
if self._prev_close == 0.0 or atr <= 0:
self._prev_close = close
return
if self.Position > 0:
if close < ema or close <= self._entry_price - atr * 1.5 or close >= self._entry_price + atr * 2.5:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close > ema or close >= self._entry_price + atr * 1.5 or close <= self._entry_price - atr * 2.5:
self.BuyMarket()
self._entry_price = 0.0
if self.Position == 0:
if close > ema and self._prev_close <= ema and rsi > 50:
self._entry_price = close
self.BuyMarket()
elif close < ema and self._prev_close >= ema and rsi < 50:
self._entry_price = close
self.SellMarket()
self._prev_close = close
def CreateClone(self):
return heiken_ashi_smoothed_mtf_strategy()