Открыть на GitHub

Стратегия Breadandbutter2

Обзор

Breadandbutter2 — конвертация советника MT4 из файла MQL/7710/Breadandbutter2.mq4. Стратегия анализирует часовые свечи и отслеживает три линейно-взвешенные скользящие средние (LWMA), построенные по ценам открытия. Согласованный разворот всех трёх средних трактуется как смена тренда: позиция немедленно переворачивается в новую сторону, а при продолжении тренда возможна пирамидальная доборка.

Логика работы

  1. Подписка на часовые свечи (тип можно изменить через параметр Candle Type).
  2. Расчёт LWMA(5), LWMA(10) и LWMA(15) от цен открытия каждой свечи.
  3. Бычий сигнал: на предыдущей свече выполнялось LWMA5 < LWMA10 < LWMA15, а на текущей LWMA5 > LWMA10 > LWMA15. Медвежий сигнал формируется при обратном неравенстве.
  4. При бычьем пересечении целевая позиция выставляется в лонг объёмом Volume. При медвежьем — в шорт тем же объёмом. Текущая позиция корректируется покупкой или продажей только необходимой разницы до целевого объёма.
  5. После каждой сделки счётчик Interval обнуляется. Если проходит указанное число завершённых свечей без нового сигнала, стратегия добавляет ещё один ордер в текущем направлении (пирамидинг) и пересчитывает защитные уровни.
  6. Защитные ордера выставляются через SetTakeProfit и SetStopLoss на расстоянии Take Profit и Stop Loss (в шагах цены). Нулевое значение отключает соответствующий уровень.

Параметры

Параметр По умолчанию Описание
Volume 0.1 Объём базового входа и каждой пирамидальной добавки (в лотах).
Take Profit 20 Дистанция тейк-профита в шагах цены. 0 — отключить.
Stop Loss 20 Дистанция стоп-лосса в шагах цены. 0 — отключить.
Interval 4 Количество завершённых свечей до следующей пирамидальной сделки. 0 — без пирамидинга.
Cross Filter 1.1 Зарезервированный параметр для возможной фильтрации по ADX (сейчас не используется).
Candle Type Часовой таймфрейм Источник свечей для расчёта LWMA.

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

  • Вспомогательный метод AdjustPosition доводит итоговый объём до требуемого значения после каждого разворота.
  • Пирамидальные сделки открываются только в сторону существующей позиции, используя знак свойства Position.
  • SetTakeProfit и SetStopLoss вызываются после каждой сделки, чтобы защитные уровни соответствовали актуальному объёму.

Примечания

  • В исходном коде MT4 рассчитывался ADX, но результат нигде не использовался. Параметр Cross Filter сохранён для совместимости и возможного расширения функциональности.
  • В оригинале счётчик интервала был закомментирован. В версии для StockSharp пирамидинг работает согласно изначальной задумке — по количеству завершённых свечей.
  • Метод StartProtection() вызывается при запуске, чтобы активировать встроенные механизмы защиты позиций.
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>
/// Bread and Butter strategy - triple WMA crossover.
/// Buys when WMA(5) crosses above WMA(10) and WMA(10) is above WMA(15).
/// Sells when WMA(5) crosses below WMA(10) and WMA(10) is below WMA(15).
/// </summary>
public class Breadandbutter2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevWma5;
	private decimal _prevWma10;
	private bool _hasPrev;

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

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevWma5 = 0m; _prevWma10 = 0m; _hasPrev = false; }

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

		_hasPrev = false;

		var wma5 = new WeightedMovingAverage { Length = 5 };
		var wma10 = new WeightedMovingAverage { Length = 10 };
		var wma15 = new WeightedMovingAverage { Length = 15 };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(wma5, wma10, wma15, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal wma5, decimal wma10, decimal wma15)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!_hasPrev)
		{
			_prevWma5 = wma5;
			_prevWma10 = wma10;
			_hasPrev = true;
			return;
		}

		if (_prevWma5 <= _prevWma10 && wma5 > wma10 && wma10 > wma15 && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (_prevWma5 >= _prevWma10 && wma5 < wma10 && wma10 < wma15 && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevWma5 = wma5;
		_prevWma10 = wma10;
	}
}