Открыть на GitHub

Стратегия EA Stochastic

Высокоуровневый порт стратегии MetaTrader «EA Stochastic» на платформу StockSharp. Стратегия подписывается на одну серию свечей, получает значения стохастического осциллятора и удерживает не более одной позиции. Вход выполняется, когда основная линия стохастика несколько свечей подряд остается по одну сторону от заданных порогов. Защитные выходы и трейлинг-стоп повторяют логику оригинального советника с использованием расстояний в пунктах.

Обзор стратегии

  • Индикатор: классический стохастический осциллятор (%K и %D с настраиваемым сглаживанием)
  • Направление: покупки и продажи
  • Позиционирование: одновременно открывается только одна позиция (новые сигналы игнорируются, пока ожидается закрытие)
  • Тип заявок: рыночные приказы фиксированным объемом
  • Данные: одна серия свечей, задаваемая пользователем (по умолчанию 15-минутные свечи)

Логика входа

  1. На каждой завершенной свече сохраняется значение основной линии стохастика.
  2. После накопления как минимум ComparedBar значений текущая величина сравнивается со значением ComparedBar - 1 свечей назад.
  3. Покупка выполняется, если оба значения ниже порога UpperLevel. Это повторяет логику EA, который открывает лонг, когда осциллятор удерживается ниже верхней границы заданное число свечей.
  4. Продажа выполняется, если оба значения выше порога LowerLevel. Оригинальный советник заходил в шорт, пока стохастик оставался выше нижнего уровня.
  5. Новые входы пропускаются, если позиция уже открыта или для текущей позиции уже отправлен приказ на закрытие.

Выход и управление рисками

  • Стоп-лосс: необязательная дистанция в пунктах от цены входа. Для лонгов контроль ведется по минимуму свечи, для шортов — по максимуму.
  • Тейк-профит: необязательная фиксация прибыли по достижении указанного количества пунктов. Используются максимумы/минимумы свечей, чтобы имитировать поведение заявок MetaTrader.
  • Трейлинг-стоп: активируется, когда прибыль превышает (TrailingStopPips + TrailingStepPips) пунктов. После этого стоп переносится на расстояние TrailingStopPips от актуального экстремума, при этом соблюдается зазор TrailingStepPips, как в исходном советнике.
  • Закрытие позиций: позиции закрываются рыночными приказами (SellMarket / BuyMarket). Флаг блокирует повторные заявки до тех пор, пока OnPositionChanged не подтвердит закрытие.

Параметры

  • StopLossPips (по умолчанию 50): дистанция стоп-лосса в пунктах. Ноль отключает защитный стоп.
  • TakeProfitPips (по умолчанию 150): дистанция тейк-профита в пунктах. Ноль отключает фиксацию прибыли.
  • TrailingStopPips (по умолчанию 15): расстояние трейлинг-стопа. Должно быть больше нуля при включении трейлинга.
  • TrailingStepPips (по умолчанию 5): минимальное продвижение цены в пунктах для обновления трейлинг-стопа. Нулевое значение запрещено при активном трейлинге.
  • Volume (по умолчанию 1): объем рыночных заявок для покупок и продаж.
  • KPeriod (по умолчанию 5): период расчета линии %K.
  • DPeriod (по умолчанию 3): период сглаживания линии %D.
  • Slowing (по умолчанию 3): финальное сглаживание линии %K.
  • UpperLevel (по умолчанию 80): порог фильтрации лонгов.
  • LowerLevel (по умолчанию 20): порог фильтрации шортов.
  • ComparedBar (по умолчанию 3): число свечей для сравнения стохастика (минимум 1).
  • CandleType (по умолчанию 15-минутные свечи): тип свечей, на который подписывается стратегия.

Особенности реализации

  • Размер пункта оценивается по Security.PriceStep. Если шаг меньше 0.001, он умножается на 10 — аналог логики MetaTrader с поправкой на количество знаков.
  • Конфигурация трейлинг-стопа проверяется при старте, чтобы исключить ошибку оригинального EA (TrailingStop > 0 при нулевом шаге).
  • Встроенный стохастический осциллятор StockSharp использует базовые режимы (диапазон high/low и простое сглаживание), что соответствует настройкам советника.
  • В оригинальном коде присутствовал выбор между фиксированным лотом и расчетом по проценту риска. В порте оставлен фиксированный Volume; при необходимости можно расширить стратегию расчетом по капиталу.
  • На график выводятся свечи, индикатор и сделки для наглядного анализа.

Рекомендации по использованию

  • Подходит для внутридневных и среднесрочных таймфреймов; подбирайте CandleType и периоды стохастика под конкретный инструмент.
  • Настраивайте пороги UpperLevel, LowerLevel и длину ComparedBar под разные режимы рынка (флэт/тренд).
  • Для реальной торговли сочетайте стратегию с брокерскими стопами, так как закрытие происходит рыночными приказами после подтверждения свечи.
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>
/// EA Stochastic strategy (simplified). Uses RSI as oscillator proxy.
/// </summary>
public class EaStochasticStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiLength;
	private readonly StrategyParam<decimal> _upperLevel;
	private readonly StrategyParam<decimal> _lowerLevel;

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

	public int RsiLength
	{
		get => _rsiLength.Value;
		set => _rsiLength.Value = value;
	}

	public decimal UpperLevel
	{
		get => _upperLevel.Value;
		set => _upperLevel.Value = value;
	}

	public decimal LowerLevel
	{
		get => _lowerLevel.Value;
		set => _lowerLevel.Value = value;
	}

	public EaStochasticStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

		_rsiLength = Param(nameof(RsiLength), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Length", "RSI period", "Indicators");

		_upperLevel = Param(nameof(UpperLevel), 70m)
			.SetDisplay("Upper Level", "Overbought level", "Levels");

		_lowerLevel = Param(nameof(LowerLevel), 30m)
			.SetDisplay("Lower Level", "Oversold level", "Levels");
	}

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

		var rsi = new RelativeStrengthIndex { Length = RsiLength };
		decimal prevRsi = 50;
		bool hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, (ICandleMessage candle, decimal rsiValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevRsi = rsiValue;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevRsi = rsiValue;
					return;
				}

				// Cross up from oversold
				if (prevRsi < LowerLevel && rsiValue >= LowerLevel && Position <= 0)
				{
					BuyMarket();
				}
				// Cross down from overbought
				else if (prevRsi > UpperLevel && rsiValue <= UpperLevel && Position >= 0)
				{
					SellMarket();
				}

				prevRsi = rsiValue;
			})
			.Start();

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