Открыть на GitHub

Стратегия Market Master

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

MarketMasterStrategy — высокоуровневая реализация советника MetaTrader 4 "Market Master" (MQL/31326/MarketMaster EN.mq4) на платформе StockSharp. Исходный робот сочетал большую связку индикаторов, гибкое управление капиталом, фильтр по новостям и сложную систему дозагрузок. При портировании сохранена детерминированная техническая часть, чтобы стратегия работала в событийной модели StockSharp без внешних HTTP-запросов. Все расчёты выполняются на одном таймфрейме свечей, а индикаторы подключаются через Bind согласно требованиям репозитория.

Набор индикаторов

  • AverageTrueRange (ATR) — две копии: основная для первого входа и "hedge"-ATR, который использовался в МТ4 при восстановительных ордерах.
  • MoneyFlowIndex (MFI) — объёмно-ценовой индикатор для оценки притока/оттока капитала.
  • BullsPower / BearsPower — аналоги функций iBullsPower/iBearsPower, подтверждающие доминирование покупателей или продавцов.
  • StochasticOscillator — выдаёт линии %K и %D; параметры периода и замедления совпадают с оригиналом и могут отключаться пользователем.
  • ParabolicSar — две независимые SAR-кривые (основная и подтверждающая), повторяющие настройки MT4.

StockSharp автоматически прогревает индикаторы. История значений не запрашивается через GetValue(), вместо этого прошлые значения сохраняются в полях _prevAtr, _prevMfi, _prevStochasticMain и т.д., как предписано правилами портирования.

Логика сигналов

В советнике присутствовали две ветви условий — «ZERO» и «MA». Обе используют одинаковые фильтры ATR/MFI/Bulls/Bears, а различаются только работой осцилляторов. В StockSharp реализована более строгая ветка «MA», поскольку она ближе к реальным условиям торговли. Лонг подтверждается, если на закрытой свече выполняется набор условий:

  1. ATR растёт относительно предыдущей свечи (используется основной или hedge-ATR в зависимости от наличия позиции).
  2. MFI растёт, а Bears Power положителен — есть бычье давление.
  3. Включён стохастический фильтр: %K выше %D, движется вверх и остаётся ниже порога StochasticBuyLevel.
  4. Включены фильтры Parabolic SAR, и цена закрытия выше обоих SAR-значений.
  5. Объём свечи превышает порог MinVolume (для первого входа) или MinHedgeVolume (для дозагрузки).

Шорт-сигнал зеркален: ATR растёт, MFI падает, Bulls Power отрицателен, %K ниже %D, цена закрытия ниже SAR, а объём соответствует требованиям.

Управление позицией

  • Автообъём. Метод CalculateBaseVolume повторяет подход MT4: умножает баланс портфеля на RiskMultiplier, затем нормализует объём с учётом VolumeStep, MinVolume и MaxVolume инструмента.
  • Пирамидинг. При AllowSameSignalEntries = true добавочные сделки используют базовый объём, умноженный на VolumeMultiplier. В StockSharp работает неттинговая модель, поэтому итоговое значение Position просто увеличивается по модулю.
  • Обратные сигналы. Флаг AllowOppositeEntries определяет, разрешено ли немедленно закрывать позицию и открываться в противоположную сторону. Если флаг выключен, стратегия только выходит из сделки и ждёт нового сигнала, полностью повторяя поведение опции "Open_opposite_signal" в MT4.
  • Стоп-лосс. Параметр StopLossPoints — аналог входного StopLoss в MT4. При наличии PriceStep вызывается StartProtection, который выставляет защитный ордер в нужном отступе.
  • Торговые часы. Параметры UseTradingWindow, TradingStart, TradingEnd, UseTradingBreak, BreakStart, BreakEnd реализуют временные фильтры советника: основное окно и короткий перерыв. Сравнение времени ведётся в часовом поясе, приходящем со свечами.

Отличия от MetaTrader-версии

  • Новостной фильтр. Оригинал обращался к Investing.com и DailyFX. В порте сетевые вызовы отсутствуют, поэтому новостные паузы задаются вручную через временные параметры либо внешними управляющими модулями.
  • История ордеров. Функции OrdersHistoryTotal() и вспомогательные процедуры открытия новых сделок привязывались к модели тикетов MT4. В StockSharp реализован чистый неттинг, и повторный вход разрешается, как только индикаторы снова согласованы.
  • Восстановительные ступени. MT4 использовал Magic Number и комментарии для различения ступеней. В C# сохранён множитель объёма (VolumeMultiplier), но все сделки отражаются одной совокупной позицией.
  • Трейлинг. Блок TrailingStop/TrailingStep работал через модификацию заявок. Базовая реализация не включает трейлинг; при необходимости его можно добавить через параметры StartProtection или подписку на PositionChanged.

Параметры

Параметр Значение по умолчанию Описание
OrderVolume 1 Базовый объём при отключённом авторасчёте.
UseAutoVolume true Включить расчёт объёма от капитала.
RiskMultiplier 10 Аналог Risk_Multiplier из MT4.
VolumeMultiplier 2 Множитель для повторных входов (KLot).
MinVolume 3000 Минимальный объём для первой сделки (MinVol).
MinHedgeVolume 3000 Объём для дозагрузок (MinVolH).
AtrPeriod / AtrHedgePeriod 14 Периоды основного и hedge-ATR.
MfiPeriod 14 Период Money Flow Index.
BullBearPeriod 14 Период Bulls/Bears Power.
StochasticKPeriod / StochasticDPeriod / StochasticSlowing 5 / 3 / 3 Настройки стохастика.
StochasticBuyLevel / StochasticSellLevel 60 / 40 Пороговые значения StoBuy и StoSell.
UseStochasticFilter / UsePsarFilter / UsePsarConfirmation true Переключатели фильтров.
PsarStep / PsarMaxStep / PsarConfirmStep / PsarConfirmMaxStep 0.02 / 0.2 / 0.02 / 0.2 Параметры двух SAR.
AllowSameSignalEntries false Разрешить пирамидинг.
AllowOppositeEntries true Разрешить мгновенный реверс.
UseTradingWindow false Ограничение по времени.
TradingStart / TradingEnd 06:00 / 18:00 Рабочее окно.
UseTradingBreak false Включить паузу.
BreakStart / BreakEnd 06:00:01 / 06:00:02 Параметры перерыва.
StopLossPoints 0 Стоп-лосс в пунктах инструмента.
CandleType 15m TimeFrame Таймфрейм свечей.

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

  1. Назначьте стратегии инструмент и портфель в Designer или коде и дайте ей время на прогрев индикаторов до наступления основного окна торговли.
  2. Для многофреймового анализа измените CandleType и параметры SAR. Все индикаторы уже подключены через Bind, поэтому дополнительная регистрация не требуется.
  3. При расширении логики используйте LogInfo/LogWarning для диагностики. Код специально оставлен компактным, чтобы легко добавлять модули (например, трейлинг или дополнительные фильтры).
  4. Помните, что стратегия оперирует чистой позицией. Если нужна тикетная схема как в MT4, оберните её в пользовательский менеджер ордеров.

Возможные расширения

  • Переопределить OnNewMyTrade или подписаться на PositionChanged, чтобы реализовать выходы по собственной логике.
  • Добавить внешний сервис новостей, который будет менять параметры окна торговли или останавливать стратегию перед важными событиями.
  • При необходимости визуализации вызвать CreateChartArea() и DrawIndicator() в OnStarted — в портированной версии эти вызовы опущены для ясности.

Код соблюдает правила репозитория: отступы табуляцией, использование высокоуровневого Bind, отсутствие прямых обращений к истории индикаторов и публикация всех настроек через StrategyParam.

namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Market Master strategy: EMA trend with RSI momentum filter.
/// Buys when above EMA and RSI rising, sells when below EMA and RSI falling.
/// </summary>
public class MarketMasterStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _rsiPeriod;

	private decimal _prevRsi;
	private bool _hasPrevRsi;
	private bool _wasBullish;

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

	public MarketMasterStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("EMA Period", "EMA period", "Indicators");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = 0m;
		_hasPrevRsi = false;
		_wasBullish = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrevRsi = false;
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, rsi, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal rsiValue)
	{
		if (candle.State != CandleStates.Finished) return;

		var close = candle.ClosePrice;
		var isBullish = close > emaValue && rsiValue > _prevRsi;

		if (_hasPrevRsi)
		{
			if (isBullish && !_wasBullish && Position <= 0)
				BuyMarket();
			else if (!isBullish && close < emaValue && rsiValue < _prevRsi && _wasBullish && Position >= 0)
				SellMarket();
		}

		_prevRsi = rsiValue;
		_hasPrevRsi = true;
		_wasBullish = isBullish;
	}
}