Стратегия SilverTrend ColorJFatl Digit объединяет две популярные MQL-системы в одном высокоуровневом алгоритме StockSharp. Блок SilverTrend измеряет импульс выхода цены из короткого канального диапазона, а блок ColorJFatl Digit сглаживает выбранную цену с помощью Юрьевского скользящего среднего (Jurik Moving Average) и анализирует знак его наклона. Сделки совершаются только тогда, когда оба блока синхронно подтверждают одно направление; при расхождении сигналов позиция закрывается.
Реализация следует рекомендациям AGENTS.md: используется подписка на свечи, индикаторы подключаются через Bind, накопительные массивы заменены компактными очередями, а в коде присутствуют подробные английские комментарии.
Логика работы
1. Детектор пробоя SilverTrend
Используются индикаторы Highest и Lowest с окном SilverTrendLength + 1, формирующие актуальный ценовой канал.
Параметр SilverTrendRisk сжимает границы канала (формула оригинала 33 - risk): чем больше значение, тем ближе пороги к середине диапазона и тем раньше фиксируется разворот.
При закрытии свечи выше верхнего порога блок генерирует бычий тренд (+1), ниже нижнего порога — медвежий (-1).
Параметр SilverTrendSignalBar задаёт задержку в количестве полностью сформированных свечей перед подтверждением смены цвета индикатора.
2. Фильтр подтверждения ColorJFatl Digit
JurikMovingAverage сглаживает цену, выбранную параметром JmaPriceType. Поддерживаются все варианты applied price из MetaTrader (close, open, median, typical, weighted, simple, quarter, TrendFollow0/1, Demark).
Результат JMA округляется до JmaRoundDigits знаков — так воспроизводится «дискретизация» оригинального индикатора.
Знак наклона округлённого JMA задаёт направление: положительный наклон -> +1, отрицательный -> -1. При нулевом наклоне сохраняется предыдущий знак, что снижает дёрганость.
Параметр JmaSignalBar добавляет задержку, требуя чтобы новый наклон удержался нужное число свечей.
3. Исполнение сделок
Входы:
Открытие лонга — когда оба блока дают +1, а текущая позиция не длинная.
Открытие шорта — когда оба блока дают -1, а текущая позиция не короткая.
Выходы:
Немедленное закрытие позиции при расхождении сигналов или появлении нейтрального состояния (0).
Перед разворотом стратегия сначала закрывает встречную позицию, затем открывает новую — без усреднений и пирамидинга.
Активные заявки отменяются перед разворотом, чтобы не оставлять «хвостов» в стакане.
Параметры
Имя
Описание
SilverTrendCandleType
Таймфрейм свечей для расчёта канала SilverTrend (по умолчанию аналог H4).
SilverTrendLength
Длина окна канала (SSP в исходном советнике).
SilverTrendRisk
Риск-параметр, сжимающий границы канала (33 - risk).
SilverTrendSignalBar
Количество закрытых свечей, которое нужно дождаться перед подтверждением смены цвета SilverTrend.
ColorJfatlCandleType
Таймфрейм свечей для расчёта Jurik (может отличаться от SilverTrend).
JmaLength
Длина Jurik Moving Average.
JmaSignalBar
Задержка (в свечах) перед использованием нового наклона Jurik.
JmaPriceType
Тип цены, подаваемой на вход Jurik (все варианты applied price).
JmaRoundDigits
Количество знаков для округления результата Jurik.
Особенности реализации
Для задержки сигналов применяются короткие очереди FIFO — они экономят память и повторяют логику MQL без обращения к историческим буферам.
Индикаторы не опрашиваются вручную. Всё вычисление идёт через высокоуровневый Bind, что упрощает поддержку и тестирование.
В коде оставлены английские комментарии, поясняющие ключевые шаги: перерасчёт порогов, работу очередей, условия выхода и т.п.
Если доступен график, стратегия рисует свечи, линии канала и совершённые сделки для визуального контроля.
Практические рекомендации
Рынки и таймфрейм. Оригинальная система создавалась для форекса на H4. Хорошо работают криптовалюты и сырьевые фьючерсы с отчётливыми свингами. Для более быстрых данных уменьшайте SilverTrendLength и JmaLength аккуратно.
Оптимизация. Оптимизируйте параметры пробоя и фильтра одновременно — асимметричное изменение приводит к частым конфликтам сигналов.
Applied price. Экспериментируйте с режимами TrendFollow и Demark, особенно на свечах Хейкен-Аши и Ренко — они лучше сглаживают шум.
Риск-менеджмент. Внутренние выходы защищают от большинства ложных пробоев, но резкие движения всё же могут выйти за пределы канала. Используйте дополнительные портфельные стопы или StartProtection.
Управление объёмом. Размер позиции задаётся свойством Strategy.Volume. При необходимости подключайте внешние модули управления капиталом (например, процент от капитала или ступенчатое уменьшение).
Идеи для развития
Добавить StartProtection со стоп-лоссом/тейк-профитом на основе ATR после статистического анализа.
Использовать более высокий таймфрейм (день/неделя) для блока Jurik в качестве трендового фильтра.
Расширить стратегию фильтрами по объёму или сантименту, чтобы сократить количество сделок в боковике.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// SilverTrend ColorJFatl Digit strategy (simplified). Uses Highest/Lowest channel
/// breakout combined with EMA slope for trend confirmation.
/// </summary>
public class SilverTrendColorJFatlDigitStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _channelLength;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _riskLevel;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int ChannelLength
{
get => _channelLength.Value;
set => _channelLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int RiskLevel
{
get => _riskLevel.Value;
set => _riskLevel.Value = value;
}
public SilverTrendColorJFatlDigitStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_channelLength = Param(nameof(ChannelLength), 21)
.SetGreaterThanZero()
.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators");
_emaLength = Param(nameof(EmaLength), 10)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period for trend confirmation", "Indicators");
_riskLevel = Param(nameof(RiskLevel), 3)
.SetDisplay("Risk Level", "Channel threshold tightness", "Logic");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = ChannelLength + 1 };
var lowest = new Lowest { Length = ChannelLength + 1 };
var lastTrend = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, (ICandleMessage candle, decimal highVal, decimal lowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var range = highVal - lowVal;
if (range <= 0)
return;
var riskModifier = 33m - RiskLevel;
if (riskModifier < 0m) riskModifier = 0m;
if (riskModifier > 33m) riskModifier = 33m;
var thresholdPercent = riskModifier / 100m;
var lowerThreshold = lowVal + range * thresholdPercent;
var upperThreshold = highVal - range * thresholdPercent;
var close = candle.ClosePrice;
// SilverTrend breakout logic
if (close < lowerThreshold)
lastTrend = -1;
else if (close > upperThreshold)
lastTrend = 1;
// Simple EMA slope confirmation using close vs channel midpoint
var midpoint = (highVal + lowVal) / 2m;
var emaConfirmUp = close > midpoint;
var emaConfirmDown = close < midpoint;
if (lastTrend > 0 && emaConfirmUp && Position <= 0)
BuyMarket();
else if (lastTrend < 0 && emaConfirmDown && Position >= 0)
SellMarket();
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class silver_trend_color_j_fatl_digit_strategy(Strategy):
def __init__(self):
super(silver_trend_color_j_fatl_digit_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._channel_length = self.Param("ChannelLength", 21) \
.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators")
self._risk_level = self.Param("RiskLevel", 3) \
.SetDisplay("Risk Level", "Channel threshold tightness", "Logic")
self._last_trend = 0
@property
def CandleType(self):
return self._candle_type.Value
@property
def ChannelLength(self):
return self._channel_length.Value
@property
def RiskLevel(self):
return self._risk_level.Value
def OnReseted(self):
super(silver_trend_color_j_fatl_digit_strategy, self).OnReseted()
self._last_trend = 0
def OnStarted2(self, time):
super(silver_trend_color_j_fatl_digit_strategy, self).OnStarted2(time)
self._last_trend = 0
highest = Highest()
highest.Length = self.ChannelLength + 1
lowest = Lowest()
lowest.Length = self.ChannelLength + 1
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _on_process(self, candle, high_value, low_value):
if candle.State != CandleStates.Finished:
return
hv = float(high_value)
lv = float(low_value)
rng = hv - lv
if rng <= 0:
return
risk_modifier = 33.0 - self.RiskLevel
if risk_modifier < 0:
risk_modifier = 0.0
if risk_modifier > 33:
risk_modifier = 33.0
threshold_pct = risk_modifier / 100.0
lower_threshold = lv + rng * threshold_pct
upper_threshold = hv - rng * threshold_pct
close = float(candle.ClosePrice)
if close < lower_threshold:
self._last_trend = -1
elif close > upper_threshold:
self._last_trend = 1
midpoint = (hv + lv) / 2.0
if self._last_trend > 0 and close > midpoint and self.Position <= 0:
self.BuyMarket()
elif self._last_trend < 0 and close < midpoint and self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return silver_trend_color_j_fatl_digit_strategy()