Открыть на GitHub

Стратегия Candels High Open

Стратегия торгует, когда свеча открывается точно на своем максимуме или минимуме. Длинная позиция открывается, если цена открытия равна минимуму свечи, ожидая роста. Короткая позиция открывается, если цена открытия равна максимуму свечи, ожидая снижения. Выход осуществляется при пересечении цены с значением Parabolic SAR, который выступает в роли трейлинг-выхода.

Подробности

  • Условия входа:
    • Длинная: Open == Low
    • Короткая: Open == High
  • Long/Short: Оба
  • Условия выхода: цена пересекает Parabolic SAR или появляется противоположный сигнал
  • Стопы: используется фиксированный стоп-лосс и тейк-профит
  • Параметры по умолчанию:
    • StopLevel = 50m
    • TakeLevel = 50m
    • SarStep = 0.02m
    • SarMax = 0.2m
    • CandleType = TimeSpan.FromMinutes(5).TimeFrame()
    • ReverseSignals = false
  • Фильтры:
    • Категория: ценовое действие
    • Направление: оба
    • Индикаторы: Parabolic SAR
    • Стопы: да
    • Сложность: базовая
    • Таймфрейм: внутридневной
    • Сезонность: нет
    • Нейросети: нет
    • Дивергенция: нет
    • Уровень риска: средний
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy that enters when a candle opens at its high or low and exits on Parabolic SAR reversal.
/// </summary>
public class CandelsHighOpenStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<bool> _reverseSignals;
	private readonly StrategyParam<decimal> _stopLevel;
	private readonly StrategyParam<decimal> _takeLevel;
	private readonly StrategyParam<decimal> _sarStep;
	private readonly StrategyParam<decimal> _sarMax;

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

	/// <summary>
	/// Reverse entry signals.
	/// </summary>
	public bool ReverseSignals
	{
		get => _reverseSignals.Value;
		set => _reverseSignals.Value = value;
	}

	/// <summary>
	/// Stop loss level in absolute price.
	/// </summary>
	public decimal StopLevel
	{
		get => _stopLevel.Value;
		set => _stopLevel.Value = value;
	}

	/// <summary>
	/// Take profit level in absolute price.
	/// </summary>
	public decimal TakeLevel
	{
		get => _takeLevel.Value;
		set => _takeLevel.Value = value;
	}

	/// <summary>
	/// Parabolic SAR acceleration step.
	/// </summary>
	public decimal SarStep
	{
		get => _sarStep.Value;
		set => _sarStep.Value = value;
	}

	/// <summary>
	/// Parabolic SAR maximum acceleration.
	/// </summary>
	public decimal SarMax
	{
		get => _sarMax.Value;
		set => _sarMax.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of the strategy.
	/// </summary>
	public CandelsHighOpenStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles used for processing", "General")
			;

		_reverseSignals = Param(nameof(ReverseSignals), false)
			.SetDisplay("Reverse Signals", "Invert long and short signals", "General")
			;

		_stopLevel = Param(nameof(StopLevel), 50m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Level", "Absolute stop loss distance", "Protection")
			;

		_takeLevel = Param(nameof(TakeLevel), 50m)
			.SetGreaterThanZero()
			.SetDisplay("Take Level", "Absolute take profit distance", "Protection")
			;

		_sarStep = Param(nameof(SarStep), 0.02m)
			.SetGreaterThanZero()
			.SetDisplay("SAR Step", "Acceleration factor step for Parabolic SAR", "Indicators")
			;

		_sarMax = Param(nameof(SarMax), 0.2m)
			.SetGreaterThanZero()
			.SetDisplay("SAR Max", "Maximum acceleration factor for Parabolic SAR", "Indicators")
			;
	}

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

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

		var psar = new ParabolicSar
		{
			Acceleration = SarStep,
			AccelerationMax = SarMax,
			AccelerationStep = SarStep
		};

		var subscription = SubscribeCandles(CandleType);

		subscription
			.Bind(psar, ProcessCandle)
			.Start();

		StartProtection(
			stopLoss: new Unit(StopLevel, UnitTypes.Absolute),
			takeProfit: new Unit(TakeLevel, UnitTypes.Absolute));

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

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

		// Exit conditions based on Parabolic SAR reversal
		if (Position > 0 && candle.ClosePrice < psarValue)
		{
			SellMarket();
			return;
		}
		if (Position < 0 && candle.ClosePrice > psarValue)
		{
			BuyMarket();
			return;
		}

		var openAtHigh = candle.OpenPrice == candle.HighPrice;
		var openAtLow = candle.OpenPrice == candle.LowPrice;

		if (ReverseSignals)
		{
			var tmp = openAtHigh;
			openAtHigh = openAtLow;
			openAtLow = tmp;
		}

		if (openAtLow && Position <= 0)
		{
			BuyMarket();
		}
		else if (openAtHigh && Position >= 0)
		{
			SellMarket();
		}
	}
}