Открыть на GitHub

Стратегия по модели "Вечерняя звезда"

Паттерн "Вечерняя звезда" является зеркальным отражением "Утренней звезды" и указывает на возможное формирование вершины. Он начинается с сильной бычьей свечи, за которой следует небольшая свеча неопределенности, и заканчивается медвежьей свечой, закрывающейся ниже середины первой.

Тестирование показывает среднегодичную доходность около 100%. Стратегию лучше запускать на рынке Форекс.

Алгоритм следит за последовательностями из трех свечей. Когда формируется шаблон, открывается короткая позиция со стопом выше максимума маленькой средней свечи. Позиции закрываются, когда цена падает ниже минимума подтверждающей свечи или если сработает стоп.

Так как сетап подразумевает быстрое разворотное движение от перекупленных условий, сделки обычно нацелены на короткие импульсные движения вниз.

Детали

  • Условия входа: Паттерн "Вечерняя звезда" из трех свечей.
  • Лонг/Шорт: Только шорт.
  • Условия выхода: Цена ниже минимума подтверждающей свечи или стоп‑лосс.
  • Стопы: Да, выше максимума средней свечи.
  • Значения по умолчанию:
    • CandleType = 5 минут
    • StopLossPercent = 1
  • Фильтры:
    • Категория: Паттерн
    • Направление: Шорт
    • Индикаторы: Свечные модели
    • Стопы: Да
    • Сложность: Средняя
    • Таймфрейм: Внутридневной
    • Сезонность: Нет
    • Нейронные сети: Нет
    • Дивергенция: Нет
    • Уровень риска: Средний
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>
/// Evening Star candle pattern strategy.
/// Evening Star: 1st bullish, 2nd small body (doji), 3rd bearish closing below midpoint of 1st.
/// Morning Star (reverse): 1st bearish, 2nd small body, 3rd bullish closing above midpoint of 1st.
/// Uses SMA for exit signals.
/// </summary>
public class EveningStarStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _cooldownBars;

	private ICandleMessage _bar1;
	private ICandleMessage _bar2;
	private int _cooldown;

	/// <summary>
	/// MA Period.
	/// </summary>
	public int MAPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	/// <summary>
	/// Candle type.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Cooldown bars.
	/// </summary>
	public int CooldownBars
	{
		get => _cooldownBars.Value;
		set => _cooldownBars.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public EveningStarStrategy()
	{
		_maPeriod = Param(nameof(MAPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Period for SMA", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to use", "General");

		_cooldownBars = Param(nameof(CooldownBars), 500)
			.SetRange(1, 1000)
			.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_bar1 = null;
		_bar2 = null;
		_cooldown = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_bar1 = null;
		_bar2 = null;
		_cooldown = 0;

		var sma = new SimpleMovingAverage { Length = MAPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		if (_cooldown > 0)
		{
			_cooldown--;
			_bar1 = _bar2;
			_bar2 = candle;
			return;
		}

		if (_bar1 != null && _bar2 != null)
		{
			var firstBody = Math.Abs(_bar1.OpenPrice - _bar1.ClosePrice);
			var secondBody = Math.Abs(_bar2.OpenPrice - _bar2.ClosePrice);
			var secondSmall = firstBody > 0 && secondBody < firstBody * 0.5m;
			var firstMid = (_bar1.HighPrice + _bar1.LowPrice) / 2;

			// Evening Star (bearish reversal) - primary
			var firstBullish = _bar1.ClosePrice > _bar1.OpenPrice;
			var thirdBearish = candle.ClosePrice < candle.OpenPrice;
			var eveningStar = firstBullish && secondSmall && thirdBearish && candle.ClosePrice < firstMid;

			// Morning Star (bullish reversal) - secondary
			var firstBearish = _bar1.ClosePrice < _bar1.OpenPrice;
			var thirdBullish = candle.ClosePrice > candle.OpenPrice;
			var morningStar = firstBearish && secondSmall && thirdBullish && candle.ClosePrice > firstMid;

			if (Position == 0 && eveningStar)
			{
				SellMarket();
				_cooldown = CooldownBars;
			}
			else if (Position == 0 && morningStar)
			{
				BuyMarket();
				_cooldown = CooldownBars;
			}
			else if (Position > 0 && candle.ClosePrice < smaValue)
			{
				SellMarket();
				_cooldown = CooldownBars;
			}
			else if (Position < 0 && candle.ClosePrice > smaValue)
			{
				BuyMarket();
				_cooldown = CooldownBars;
			}
		}

		_bar1 = _bar2;
		_bar2 = candle;
	}
}