Открыть на GitHub

Стратегия Expotest

Общее описание

Expotest — это перенос оригинального советника Expotest.mq5 на платформу StockSharp. Стратегия торгует одним инструментом, использует индикатор Parabolic SAR и простое правило управления объёмом по принципу мартингейла. В рынке находится только одна позиция, выход осуществляется по заданным уровням стоп-лосса и тейк-профита.

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

  • Индикатор: Parabolic SAR на выбранном типе свечей. Параметры ускорения (SarStep) и максимального ускорения (SarMaximum) настраиваются.
  • Вход в рынок: анализируется только последняя закрытая свеча и только при отсутствии позиции.
    • Если значение SAR ниже либо равно цене закрытия, открывается длинная позиция.
    • Если значение SAR выше либо равно цене закрытия, открывается короткая позиция.
  • Выход из позиции: стоп-лосс и тейк-профит рассчитываются от цены входа на фиксированное количество шагов цены. На каждой новой свече проверяется, достиг ли диапазон свечи заданных уровней. Тип выхода (прибыль/убыток) запоминается для расчёта объёма следующей сделки.

Управление объёмом

  • Базовый объём: определяется параметром FixedVolume, если он больше нуля. В противном случае объём вычисляется исходя из текущей стоимости портфеля, параметров RiskPercent и StopLossPoints. Если расчёт невозможен, используется стандартное значение Strategy.Volume.
  • Двойной шаг: после убыточной сделки объём следующей позиции удваивается по сравнению с объёмом убыточной. После прибыльного выхода стратегия возвращается к базовому объёму.

Настраиваемые параметры

  • CandleType – тип данных для построения свечей (например, таймфрейм).
  • SarStep – начальный коэффициент ускорения Parabolic SAR.
  • SarMaximum – максимальный коэффициент ускорения Parabolic SAR.
  • StopLossPoints – расстояние до стоп-лосса в шагах цены.
  • TakeProfitPoints – расстояние до тейк-профита в шагах цены.
  • RiskPercent – доля капитала, которой стратегия рискует в одной сделке при динамическом расчёте объёма.
  • FixedVolume – фиксированный торговый объём; значение 0 включает риск-менеджмент на основе процента.

Дополнительные замечания

  • Стратегия обрабатывает только закрытые свечи, что позволяет максимально приблизиться к исходной логике MQL и корректно работать с подписками StockSharp.
  • Стоп-уровни хранятся внутри стратегии, без регистрации отдельных стоп/лимит заявок, что упрощает тестирование.
  • По запросу заказчика Python-версия и соответствующая папка не создавались.
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// Parabolic SAR based strategy converted from the Expotest MQL expert advisor.
/// Enters long when SAR is below price, short when SAR is above price.
/// </summary>
public class ExpotestStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _sarStep;
	private readonly StrategyParam<decimal> _sarMaximum;

	private bool _prevSarBelow;
	private bool _initialized;

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

	public decimal SarStep
	{
		get => _sarStep.Value;
		set => _sarStep.Value = value;
	}

	public decimal SarMaximum
	{
		get => _sarMaximum.Value;
		set => _sarMaximum.Value = value;
	}

	public ExpotestStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle type for signal generation", "General");

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

		_sarMaximum = Param(nameof(SarMaximum), 0.2m)
			.SetDisplay("SAR Maximum", "Maximum acceleration factor for Parabolic SAR", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevSarBelow = false;
		_initialized = false;
	}

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

		_prevSarBelow = false;
		_initialized = false;

		var sar = new ParabolicSar
		{
			Acceleration = SarStep,
			AccelerationMax = SarMaximum
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(sar, OnProcess)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var sarBelow = sarValue < candle.ClosePrice;

		if (!_initialized)
		{
			_prevSarBelow = sarBelow;
			_initialized = true;
			return;
		}

		// SAR flipped from above to below price => Buy signal
		if (sarBelow && !_prevSarBelow && Position <= 0)
		{
			BuyMarket();
		}
		// SAR flipped from below to above price => Sell signal
		else if (!sarBelow && _prevSarBelow && Position >= 0)
		{
			SellMarket();
		}

		_prevSarBelow = sarBelow;
	}
}