Открыть на GitHub

Стратегия Technical Trader

Technical Trader — это перенос советника MetaTrader из MQL/22304/Technical_trader.mq5 на высокоуровневый API StockSharp. Стратегия объединяет два простых скользящих среднего с поиском ценовых кластеров ликвидности рядом с текущими котировками. Сделки открываются только тогда, когда найденный кластер подтверждает направление пересечения быстрых и медленных SMA, а управление рисками выполняется через стоп-лосс и тейк-профит, рассчитываемые в шагах цены, как и в оригинальном коде.

Общая информация

  • Платформа: высокоуровневый API StockSharp.
  • Данные: свечи выбранного таймфрейма и подписка на стакан для получения лучших цен bid/ask.
  • Тип стратегии: направленная торговля от кластеров ликвидности.
  • Связь с исходником: параметры SMA, выборка исторических закрытий, порог кластеризации и расчёт оффсетов полностью воспроизводят MQL-реализацию.

Логика торговли

  1. Подписка на свечи заданного типа и расчёт двух SMA с периодами FastMaPeriod и SlowMaPeriod.
  2. Поддержание скользящего окна (HistoryDepth) из последних закрытий с округлением до трёх знаков — аналог функции NormalizeDouble.
  3. Построение гистограммы повторяемости цен и выделение уровней, у которых количество появлений превышает ResistanceThreshold.
  4. Отслеживание актуальных bid/ask через подписку на стакан и использование цены закрытия свечи как резервного источника.
  5. Условия входа в лонг:
    • Быстрая SMA выше медленной.
    • Найденный кластер расположен непосредственно под текущим ask и попадает в допуск LevelTolerance.
    • При отсутствии позиции либо при открытом шорте стратегия покупает объём, достаточный для переворота и открытия базового лонга.
  6. Вход в шорт зеркален: кластер должен находиться над текущим bid, а быстрая SMA — ниже медленной.
  7. После открытия позиции рассчитываются уровни стоп-лосса и тейк-профита как произведение шага цены (PriceStep) на StopLossPoints и TakeProfitPoints, что эквивалентно умножению на _Point в MQL.
  8. На каждой закрывшейся свече стратегия проверяет, достигли ли bid/ask защитных уровней, и закрывает позицию при срабатывании стопа или цели.

Параметры

Параметр Описание Значение по умолчанию
FastMaPeriod Период быстрой SMA для генерации сигнала. 25
SlowMaPeriod Период медленной SMA для фильтра тренда. 30
StopLossPoints Дистанция стопа в шагах цены (PriceStep * StopLossPoints). 30
TakeProfitPoints Цель по прибыли в шагах цены (PriceStep * TakeProfitPoints). 100
ResistanceThreshold Минимальное число повторений цены, чтобы считать её кластером ликвидности. 15
HistoryDepth Количество свечей в окне анализа (для XAUUSD рекомендуется 100, как в исходнике). 500
LevelTolerance Максимальное допустимое расстояние от текущего bid/ask до кластера. 0.0005
CandleType Тип обрабатываемых свечей (таймфрейм или пользовательский тип). Таймфрейм 1 минута

Особенности реализации

  • Подписка на стакан обеспечивает актуальные цены bid/ask и имитирует тиковое выполнение MQL-советника.
  • Подсчёт кластеров выполнен без LINQ и с повторным использованием буферов в соответствии с требованиями конверсии StockSharp.
  • Стоп-лосс и тейк-профит управляются внутри стратегии, поскольку в StockSharp ордера исполняются синтетически, а не брокером.
  • Визуализация добавляет на график свечи, обе SMA и сделки для удобства тестирования.

Рекомендации по настройке

  • Увеличивайте HistoryDepth на старших таймфреймах, чтобы сохранять релевантный объём данных для кластеризации.
  • Уменьшайте LevelTolerance на инструментах с мелким шагом цены для отсечения посторонних уровней.
  • Снижайте ResistanceThreshold на неликвидных рынках, где повторений меньше.
  • Размер позиции задаётся свойством Volume базового класса Strategy; скорректируйте его перед запуском стратегии.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class TechnicalTraderStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private decimal? _prevRsi;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }

	public TechnicalTraderStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 10).SetGreaterThanZero().SetDisplay("RSI Period", "RSI lookback", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = null;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiVal)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevRsi = rsiVal; return; }
		if (_prevRsi == null) { _prevRsi = rsiVal; return; }
		if (_prevRsi.Value < 45m && rsiVal >= 55m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (_prevRsi.Value > 55m && rsiVal <= 45m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
		_prevRsi = rsiVal;
	}
}