Открыть на GitHub

Стратегия Arttrader v1.5

Общее описание

Arttrader v1.5 — это конверсия одноимённого советника MetaTrader 5 на платформу StockSharp. Стратегия относится к трендовым и сочетает фильтрацию направления по экспоненциальной среднеарифметической (EMA) старшего таймфрейма с точками входа на младших свечах. В переносе сохранены ключевые особенности оригинала: жёсткий контроль за резкими гэпами, использование временных окон для сделок и аварийные выходы при достижении критических ценовых уровней.

Для работы применяются две подписки на свечи:

  • Торговый таймфрейм (по умолчанию 5 минут) — все сигналы, фильтры и выходы.
  • Трендовый таймфрейм (по умолчанию 1 час) — расчёт EMA и её наклона.

Торговля ведётся с неттингом: при появлении противоположного сигнала текущая позиция закрывается и открывается новая в направлении сигнала одной рыночной заявкой.

Логика входов

  1. Фильтр наклона EMA
    • Рассчитывается EMA от цены открытия свечей трендового таймфрейма.
    • Для покупок наклон должен лежать между SlopeSmall и SlopeLarge и быть положительным; для продаж — между теми же пределами, но со знаком «минус».
  2. Временное окно
    • Проверка ведётся только после того, как от начала текущего часа прошло не менее MinutesBegin минут (аналог MT5 функции TimeCurrent).
  3. Подтверждение ценой
    • Для длинных входов свеча должна закрыться недалеко от минимума и не выше открытия (SlipBegin задаёт допуск).
    • Для коротких входов свеча должна закрыться недалеко от максимума и не ниже открытия.
  4. Фильтр гэпов
    • Любой разрыв между соседними открытиями больше BigJump в последних шести свечах блокирует сигнал.
    • Разрывы между открытиями через одну свечу больше DoubleJump также блокируют сделки.

Логика выходов

  1. Отложенный «умный» стоп
    • При входе сохраняется опорная цена с корректировкой Adjust, имитирующей работу со спредом.
    • Если цена закрытия ушла против позиции минимум на StopLoss, стратегия ждёт, пока с начала часа пройдёт MinutesEnd минут и свеча покажет восстановление (SlipEnd). После выполнения условий позиция закрывается по рынку.
  2. Аварийный стоп
    • При достижении ценой уровня, удалённого от входа на EmergencyLoss, позиция закрывается немедленно (аналог брокерского стоп-лосса в советнике).
  3. Тейк-профит
    • При касании уровня TakeProfit позиция закрывается.
  4. Контроль объёма
    • Если объём предыдущей свечи не превышает MinVolume, текущая позиция закрывается во избежание торговли в тонком рынке.

Параметры

Параметр Значение по умолчанию Назначение
Volume 1 Объём рыночных заявок, дополнительно учитывает величину обратной позиции при переворотах.
EmaPeriod 11 Период EMA на трендовом таймфрейме (используется цена открытия).
BigJump 30 Максимальный допустимый гэп между соседними открытиями (в пунктах инструмента).
DoubleJump 55 Максимальный гэп между открытиями через одну свечу.
StopLoss 20 Порог убытка, при котором активируется отложенный выход.
EmergencyLoss 50 Дистанция аварийного стоп-лосса.
TakeProfit 25 Дистанция тейк-профита.
SlopeSmall 5 Минимальная величина наклона EMA для открытия.
SlopeLarge 8 Максимальная величина наклона EMA для открытия.
MinutesBegin 25 Количество минут от начала часа до появления новых сигналов.
MinutesEnd 25 Количество минут от начала часа до разрешения выхода по отложенному стопу.
SlipBegin 0 Допустимое отклонение закрытия от экстремума при подтверждении входа.
SlipEnd 0 Допустимое отклонение закрытия при подтверждении выхода.
MinVolume 0 Минимальный объём предыдущей свечи; меньшие значения приводят к закрытию позиции.
Adjust 1 Сдвиг опорной цены, имитирующий учёт спреда.
CandleType 5 минут Торговые свечи для сигналов.
TrendCandleType 1 час Свечи для расчёта EMA.

Все ценовые параметры автоматически умножаются на шаг цены инструмента. Если у инструмента 3 или 5 знаков после запятой, дополнительно применяется множитель 10, аналогично оригинальному советнику.

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

  • При смене направления используется одна рыночная заявка с объёмом, достаточным для закрытия старой позиции и открытия новой.
  • Подписка на свечи дублируется только при различии торгового и трендового таймфреймов; иначе используется один поток данных.
  • Аварийный стоп и тейк-профит реализованы в коде стратегии, поскольку StockSharp не создаёт связанные ордера автоматически.
  • Применены высокоуровневые методы (Bind, StartProtection, построение графика), соответствующие правилам репозитория.

Рекомендации по использованию

  • Корректируйте MinutesBegin и MinutesEnd под расписание выбранного рынка; базовые значения подходят для валютных пар с ярко выраженной часовой структурой.
  • На инструментах с периодическими провалами ликвидности имеет смысл увеличить MinVolume.
  • Фильтр гэпов анализирует лишь шесть свечей, поэтому на слишком крупном таймфрейме его действие ослабевает — используйте более короткие свечи или увеличивайте порог.
  • Перед оптимизацией убедитесь, что величины BigJump, StopLoss и других параметров согласованы с шагом цены вашего инструмента.
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>
/// Arttrader v1.5 strategy (simplified).
/// Uses EMA slope on a higher timeframe to filter entries,
/// with candle pattern confirmation on the trading timeframe.
/// </summary>
public class ArttraderV15Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<DataType> _trendCandleType;
	private readonly StrategyParam<int> _emaPeriod;

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

	public DataType TrendCandleType
	{
		get => _trendCandleType.Value;
		set => _trendCandleType.Value = value;
	}

	public int EmaPeriod
	{
		get => _emaPeriod.Value;
		set => _emaPeriod.Value = value;
	}

	public ArttraderV15Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Trading candles", "General");

		_trendCandleType = Param(nameof(TrendCandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Trend Candle Type", "Trend candles for EMA", "General");

		_emaPeriod = Param(nameof(EmaPeriod), 11)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period on trend timeframe", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		decimal currentEma = 0;
		decimal previousEma = 0;
		bool hasCurrentEma = false;
		bool hasPreviousEma = false;

		// Subscribe to trend timeframe for EMA slope
		var trendSub = SubscribeCandles(TrendCandleType);
		trendSub
			.Bind(ema, (ICandleMessage candle, decimal emaVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (hasCurrentEma)
				{
					previousEma = currentEma;
					hasPreviousEma = true;
				}

				currentEma = emaVal;
				hasCurrentEma = true;
			})
			.Start();

		// Subscribe to trading timeframe for signals
		var tradeSub = SubscribeCandles(CandleType);
		tradeSub
			.Bind((ICandleMessage candle) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!IsFormedAndOnlineAndAllowTrading())
					return;

				if (!hasPreviousEma)
					return;

				var emaSlope = currentEma - previousEma;
				var close = candle.ClosePrice;
				var open = candle.OpenPrice;

				// Long: EMA slope positive, bearish candle (close < open), close near low
				if (emaSlope > 0 && close <= open && Position <= 0)
					BuyMarket();
				// Short: EMA slope negative, bullish candle (close > open), close near high
				else if (emaSlope < 0 && close >= open && Position >= 0)
					SellMarket();
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, tradeSub);
			DrawIndicator(area, ema);
			DrawOwnTrades(area);
		}
	}
}