Открыть на GitHub

Стратегия AbsolutelyNoLagLWMA Digit MMRec

Идея

Это перенос на StockSharp советника MetaTrader Exp_AbsolutelyNoLagLwma_Digit_NN3_MMRec. Сохранена исходная многотаймфреймовая архитектура на основе индикатора «AbsolutelyNoLagLWMA» и правила восстановления объёма (MMRec). Три независимых модуля (A/B/C) анализируют свечи 12h, 4h и 2h. Каждый модуль управляет своей долей позиции, а стратегия суммирует общий результат.

Внутри каждого модуля строится двойная взвешенная скользящая средняя (WMA от WMA) выбранного ценового ряда. Полученное значение округляется до указанного количества знаков, как в исходном индикаторе. Изменение наклона сглаженной линии (значение стало расти после падения и наоборот) трактуется как смена тренда и запускает торговые действия модуля.

Правила торговли

  1. Дождаться закрытия свечи соответствующего таймфрейма.
  2. Выбрать цену согласно параметру (close, open, median, typical и т.д.).
  3. Передать цену через основную WMA и затем через вторую WMA, получая аналог "AbsolutelyNoLagLWMA".
  4. Округлить результат до нужного количества знаков и сравнить с предыдущим значением.
  5. Рост линии (value > previous):
    • Закрыть короткую долю модуля, если разрешено закрытие шортов.
    • Если включён вход в лонг и сейчас нет длинной позиции, открыть покупку текущим объёмом модуля.
    • Пересчитать уровни стоп-лосса и тейк-профита в шагах цены для длинной доли.
  6. Падение линии (value < previous):
    • Закрыть длинную долю модуля, если разрешено закрытие лонгов.
    • Если разрешены продажи и короткая позиция отсутствует, открыть шорт.
    • Обновить защитные уровни для короткой доли.
  7. На каждой свече модуль проверяет, пробили ли максимум/минимум текущие уровни стопа или тейка. При срабатывании позиция закрывается по соответствующей цене, а результат попадает в систему управления капиталом.
  8. Денежное управление хранит результаты последних сделок для каждого направления. Если последние N сделок (где N равно триггеру) были убыточными, следующий ордер используется с уменьшенным объёмом, иначе — с нормальным. Для оценки результата берутся цена входа (запоминается при открытии) и цена выхода (стоп/тейк/закрытие по сигналу).

Входы и выходы выполняются рыночными ордерами. Для сигналов предполагается исполнение по цене закрытия свечи, а для стопов/тейков — по защитной цене.

Параметры

Набор параметров у всех модулей одинаков; значения по умолчанию повторяют оригинал.

Параметр Описание
ACandleType / BCandleType / CCandleType Таймфрейм свечей модуля (по умолчанию 12ч / 4ч / 2ч).
ALength / BLength / CLength Период сглаживания AbsolutelyNoLagLWMA (для обеих WMA).
AAppliedPrice / BAppliedPrice / CAppliedPrice Источник цены (close, open, high, low, median, typical, weighted, simple, quarter, TrendFollow1, TrendFollow2, Demark).
ADigits / BDigits / CDigits Количество знаков для округления сглаженного значения.
Флаги ABuyOpen, ASellOpen, ABuyClose, ASellClose и аналоги для B/C Разрешения на открытия/закрытия лонгов и шортов в модуле.
ASmallVolume, ANormalVolume Уменьшенный и обычный объём заявок (используются и для покупок, и для продаж).
ABuyLossTrigger, ASellLossTrigger Число подряд убыточных сделок, после которого модуль переходит на уменьшенный объём (для лонгов/шортов).
AStopLossPoints, ATakeProfitPoints Стоп-лосс и тейк-профит в шагах цены для доли модуля. Аналогичные параметры есть у B и C.

Очереди результатов очищаются, если соответствующий триггер равен нулю. Расчёт шагов цены опирается на Security.Step; при его отсутствии используется значение 1.

Особенности

  • Каждый модуль ведёт собственный объём, поэтому одновременно могут существовать разнонаправленные позиции разных модулей. Итоговая позиция стратегии — сумма всех долей.
  • Контроль стопов и тейков выполняется на закрытой свече по экстремумам свечи.
  • Перечень значений AppliedPrices полностью повторяет оригинальный индикатор, включая варианты TrendFollow и формулу DeMark.
  • Индикаторы не добавляются в коллекцию стратегии — всё связывается через Bind, что соответствует требованиям руководства.
  • Сделки совершаются только при смене наклона, что предотвращает повторные ордера на последовательных барах с тем же направлением.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Double WMA crossover strategy with money management recovery.
/// Uses fast and slow weighted moving averages and trades on crossovers.
/// </summary>
public class AbsolutelyNoLagLwmaDigitMmRecStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;

	private int _prevSignal;

	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 AbsolutelyNoLagLwmaDigitMmRecStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastLength = Param(nameof(FastLength), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast Length", "Fast WMA period", "Indicators");

		_slowLength = Param(nameof(SlowLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow WMA period", "Indicators");
	}

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

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

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

		_prevSignal = 0;

		var fastWma = new WeightedMovingAverage { Length = FastLength };
		var slowWma = new WeightedMovingAverage { Length = SlowLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastWma, slowWma, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var signal = fastVal > slowVal ? 1 : fastVal < slowVal ? -1 : _prevSignal;

		if (signal == _prevSignal)
			return;

		var oldSignal = _prevSignal;
		_prevSignal = signal;

		if (signal == 1 && oldSignal <= 0)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (signal == -1 && oldSignal >= 0)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}
	}
}