Открыть на GitHub

Стратегия True Scalper Profit Lock BreakEven

Обзор

Стратегия True Scalper Profit Lock BreakEven представляет собой портирование эксперта MetaTrader 4 TrueScalperProfitLock.mq4 на API StockSharp. Комбинация пересечения экспоненциальных скользящих средних (3 и 7 периодов) и двух режимов RSI используется для поиска краткосрочных разворотов. После открытия позиции система автоматически выставляет фиксированные уровни стоп-лосса и тейк-профита, а также может переносить стоп в безубыток при достижении заданной прибыли.

Торговая логика

  • Фильтр тренда. Быстрая EMA, рассчитанная на предыдущей свече, должна находиться выше (для покупок) или ниже (для продаж) медленной EMA. Разница между средними должна превышать один шаг цены, чтобы исключить флэтовые участки.
  • Подтверждение RSI. Реализованы оба метода из оригинального советника. Метод A отслеживает пересечение 2-периодного RSI с порогом между двумя последними закрытыми свечами. Метод B проверяет, находится ли RSI двух свечей назад выше или ниже порога. Методы можно использовать по отдельности или совместно.
  • Направление сделок. Для входа в лонг требуется, чтобы быстрая EMA была выше медленной, а RSI указывал на перепроданность (значение ниже порога). Для шорта условия зеркальные.

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

  • Начальная защита. После открытия рассчитываются уровни стоп-лосса и тейк-профита на фиксированном расстоянии в шагах цены (по умолчанию 90 и 44).
  • Profit Lock. При активации функция переносит стоп-лосс в область безубытка плюс смещение BreakEvenOffsetPoints, если цена прошла BreakEvenTriggerPoints шагов в нужном направлении.
  • Таймер отказа. Параметр AbandonBars определяет, через сколько закрытых свечей позиция закрывается принудительно. Метод A дополнительно инициирует противоположный вход, метод B просто фиксирует результат и ждёт нового сигнала.
  • Управление капиталом. Формула расчёта объёма полностью повторяет версию MT4: используется баланс портфеля, процент риска, тип счёта (мини/стандарт) и ограничения «боевого» режима. При отключении UseMoneyManagement применяется фиксированный объём.

Параметры

Параметр Описание
CandleType Таймфрейм анализируемых свечей.
FixedVolume Базовый объём заявки при отключённом ММ.
TakeProfitPoints / StopLossPoints Дистанция до тейк-профита и стоп-лосса в шагах цены.
UseRsiMethodA / UseRsiMethodB Переключатели двух режимов подтверждения RSI.
RsiThreshold Пороговое значение RSI.
AbandonMethodA / AbandonMethodB Варианты логики принудительного выхода.
AbandonBars Количество закрытых свечей до срабатывания отказа.
UseMoneyManagement, RiskPercent, AccountIsMini, LiveTradingMode Настройки управления капиталом.
UseProfitLock, BreakEvenTriggerPoints, BreakEvenOffsetPoints Параметры переноса стоп-лосса в безубыток.
MaxOpenTrades Максимальное число одновременных позиций (по умолчанию одна).

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

  1. Анализ ведётся только на закрытых свечах, что соответствует обращению к барам со смещением в исходном эксперте.
  2. Комбинируйте режимы RSI в зависимости от желаемой чувствительности фильтра.
  3. Перенос стопа и логика отказа опираются на экстремумы свечей. На длинных таймфреймах учитывайте возможные внутридневные проскальзывания.
  4. Для работы управления капиталом необходим портфель с заполненным BeginValue. При его отсутствии стратегия использует фиксированный объём.

Файлы

  • CS/TrueScalperProfitLockBreakEvenStrategy.cs – реализация стратегии на C#.
  • README.md – документация на английском языке.
  • README_zh.md – документация на китайском языке.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// True Scalper strategy - RSI overbought/oversold reversal.
/// Buys when RSI drops below oversold level.
/// Sells when RSI rises above overbought level.
/// </summary>
public class TrueScalperProfitLockBreakEvenStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _overbought;
	private readonly StrategyParam<decimal> _oversold;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRsi;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
	public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public TrueScalperProfitLockBreakEvenStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI lookback", "Indicators");
		_overbought = Param(nameof(Overbought), 75m)
			.SetDisplay("Overbought", "RSI overbought", "Levels");
		_oversold = Param(nameof(Oversold), 25m)
			.SetDisplay("Oversold", "RSI oversold", "Levels");
		_cooldownCandles = Param(nameof(CooldownCandles), 10)
			.SetDisplay("Cooldown", "Candles to wait between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevRsi = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

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

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

		if (!_hasPrev) { _prevRsi = rsi; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevRsi = rsi;
			return;
		}

		var oversold = Oversold;
		var overbought = Overbought;

		if (_prevRsi >= oversold && rsi < oversold && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (_prevRsi <= overbought && rsi > overbought && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevRsi = rsi;
	}
}