Открыть на GitHub

Стратегия Wajdyss MA Expert

Обзор

Wajdyss MA Expert — это порт на C# советника MetaTrader 4 «wajdyss MA expert v3». Стратегия сравнивает две скользящие средние с независимыми периодами, методами расчёта, сдвигами и типами цен. Пересечение быстрой средней над медленной открывает длинную позицию, обратное пересечение — короткую. Реализация повторяет исходное управление капиталом, опциональное автоматическое закрытие встречных сделок и фильтры принудительного закрытия в конце дня и недели.

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

  1. Подписаться на выбранный CandleType (по умолчанию 15-минутные свечи) и рассчитать быстрый и медленный мувинги с указанными параметрами MovingAverageMethod и PriceSource для каждой линии.
  2. Хранить значения индикаторов только для завершённых свечей. Формировать бычий сигнал, когда быстрая средняя (с учётом её Shift) находится выше медленной на последней закрытой свече и ниже две свечи назад; для медвежьего сигнала условия обратные.
  3. Между сделками одного направления выдерживать паузу не менее одной свечи выбранного таймфрейма — аналог MT4-версии, где использовались глобальные переменные времени.
  4. При включённом AutoCloseOpposite сначала отменять активные заявки и разворачивать позицию одной рыночной сделкой. Новый объём включает текущую противоположную позицию, что обеспечивает мгновенный разворот.
  5. Применять дневной и пятничный фильтры. После наступления DailyCloseHour/DailyCloseMinute или FridayCloseHour/FridayCloseMinute все позиции закрываются, новые сделки не открываются до следующей сессии.

Риск-менеджмент и объём

  • Параметры TakeProfitPips, StopLossPips и TrailingStopPips задаются в целых пунктах. Они автоматически переводятся в ценовые шаги инструмента и передаются в StartProtection, чтобы повторить поведение стопов и трейлинга оригинального советника.
  • Включённый UseMoneyManagement воспроизводит формулу MT4: объём = (баланс / BalanceReference) * InitialVolume. Далее объём приводится к шагу и попадает в диапазон между минимально и максимально допустимыми значениями инструмента.
  • При отключённом управлении капиталом используется фиксированный объём InitialVolume.

Параметры

Параметр Тип Значение по умолчанию Описание
FastPeriod int 10 Период быстрой скользящей средней.
FastShift int 0 Сдвиг быстрой средней при сравнении значений.
FastMethod MovingAverageMethod Ema Метод сглаживания быстрой средней (Sma, Ema, Smma, Lwma).
FastPriceType PriceSource Close Тип цены для быстрой средней (Close, Open, High, Low, Median, Typical, Weighted).
SlowPeriod int 20 Период медленной скользящей средней.
SlowShift int 0 Сдвиг медленной средней.
SlowMethod MovingAverageMethod Ema Метод сглаживания медленной средней.
SlowPriceType PriceSource Close Тип цены для медленной средней.
TakeProfitPips decimal 100 Дистанция до тейк-профита в пунктах (0 — отключено).
StopLossPips decimal 50 Дистанция до стоп-лосса в пунктах (0 — отключено).
TrailingStopPips decimal 0 Ширина трейлинг-стопа в пунктах (0 — отключено).
AutoCloseOpposite bool true Закрывать противоположные позиции перед открытием новой.
InitialVolume decimal 0.1 Базовый объём сделки до применения мани-менеджмента.
UseMoneyManagement bool true Включить динамический расчёт объёма от баланса.
BalanceReference decimal 1000 Делитель баланса при расчёте динамического объёма.
DailyCloseHour int 23 Час (0-23), после которого позиции закрываются каждый день.
DailyCloseMinute int 45 Минута ежедневного закрытия.
FridayCloseHour int 22 Час окончания торговли в пятницу (0-23).
FridayCloseMinute int 45 Минута окончания торговли в пятницу.
CandleType DataType Таймфрейм 15 минут Свечи, используемые для расчётов и контроля паузы между сделками.

Примечания

  • Используется только высокоуровневый API StockSharp: свечи приходят через SubscribeCandles, индикаторы связаны напрямую, а StartProtection управляет стопами, тейками и трейлингом.
  • Позиции закрываются рыночными заявками, что повторяет немедленное закрытие ордеров в версии MT4.
  • Python-реализация отсутствует; в каталоге представлена только C# стратегия.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Wajdyss MA Expert: Fast/slow EMA crossover with ATR stops.
/// </summary>
public class WajdyssMaExpertStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;

	public WajdyssMaExpertStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastLength = Param(nameof(FastLength), 10)
			.SetDisplay("Fast EMA", "Fast EMA period.", "Indicators");

		_slowLength = Param(nameof(SlowLength), 20)
			.SetDisplay("Slow EMA", "Slow EMA period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period for stops.", "Indicators");
	}

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

	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	/// <inheritdoc />
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;
	}

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

		_prevFast = 0;
		_prevSlow = 0;
		_entryPrice = 0;

		var fast = new ExponentialMovingAverage { Length = FastLength };
		var slow = new ExponentialMovingAverage { Length = SlowLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, slow, atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fast);
			DrawIndicator(area, slow);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevFast == 0 || _prevSlow == 0 || atrVal <= 0)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var close = candle.ClosePrice;

		// Exit
		if (Position > 0)
		{
			if (close <= _entryPrice - atrVal * 2m || close >= _entryPrice + atrVal * 3m || fastVal < slowVal)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close >= _entryPrice + atrVal * 2m || close <= _entryPrice - atrVal * 3m || fastVal > slowVal)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		// Entry: EMA crossover
		if (Position == 0)
		{
			if (_prevFast <= _prevSlow && fastVal > slowVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (_prevFast >= _prevSlow && fastVal < slowVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}