Открыть на GitHub

Hard Profit

Обзор

Hard Profit — это порт стратегии MetaTrader 4 hardprofit.mq4 на платформу StockSharp. Стратегия ищет импульсный пробой в моменты, когда свеча закрывается на экстремуме, а сглаженный тренд подтверждает направление. При портировании воспроизведены режимы управления капиталом, ступенчатый выход и защита позиции с использованием высокоуровневого API StockSharp.

Логика стратегии

Формирование пробоя

  • Стратегия обрабатывает закрытые свечи выбранного таймфрейма и отслеживает максимум и минимум предыдущих Breakout Period баров (без текущей свечи), что полностью повторяет вызовы iHighest/iLowest с параметром сдвига 1 в исходном советнике.
  • Средняя цена (High+Low)/2 передается в сглаженную скользящую среднюю длиной Trend Period. Разница между текущим и прошлым значением служит фильтром направления.

Правила входа

  • Длинная позиция открывается, если выполняются условия:
    • Свеча закрылась на максимуме и пробила предыдущий диапазон максимумов.
    • Наклон сглаженной средней положительный.
    • Позиция отсутствует, лимит Max Trades Per Bar не исчерпан.
    • При наличии котировок bid/ask текущий спред не превышает Max Spread (pips).
    • Не включен режим Only Short.
  • Короткая позиция открывается при зеркальных условиях: закрытие на минимуме, пробой предыдущего минимума, отрицательный наклон, соблюдение фильтра по спреду и выключенный Only Long.

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

  • Фиксированный стоп (Stop Loss (pips)) и опциональный тейк-профит (Take Profit (pips)) образуют внешний защитный диапазон.
  • При достижении прибыли Break-even (pips) стоп переносится на цену входа. После Trailing Activation (pips) стоп смещается дальше на величину стоп-лосса, что полностью соответствует логике MetaTrader.
  • Реализованы два частичных выхода:
    • При достижении Partial TP1 (pips) закрывается Partial Ratio 1 (%) текущей позиции.
    • При достижении Partial TP2 (pips) закрывается Partial Ratio 2 (%) от оставшегося объема. Расчёт основан на фактическом объеме позиции, поэтому второй выход автоматически учитывает первый.
  • Стопы и тейки реагируют на экстремумы внутри свечи: длинная позиция закрывается, если минимум пробивает стоп или максимум касается цели; короткая позиция — при зеркальных условиях.

Управление капиталом

Реализованы пять режимов, адаптированных к данным портфеля StockSharp:

  1. Fixed — каждый вход выполняется фиксированным объемом Fixed Volume.
  2. Geometrical — размер сделки пропорционален квадратному корню из стоимости портфеля (0.1 * sqrt(balance / 1000) * Geometrical Factor).
  3. Proportional — распределяет долю капитала относительно последней цены (equity * Risk Percent / (price * 1000)).
  4. Smart — берет пропорциональный объем и уменьшает его при более чем одной убыточной сделке подряд, используя делитель Decrease Factor.
  5. TSSF — повторяет Triggered Smart Safe-Factor. Средние прибыль/убыток и винрейт вычисляются по последним Last Trades закрытым сделкам, после чего метрика переключает делители TSSF Ratio. При ухудшении условий объем возвращается к минимуму 0.1 лота. Итоговый объем нормализуется по VolumeStep, MinVolume и MaxVolume инструмента.

Параметры

  • Breakout Period — количество свечей для расчета пробойных максимумов/минимумов.
  • Trend Period — период сглаженной скользящей средней.
  • Only Short / Only Long — флаги, ограничивающие торговлю одним направлением.
  • Max Trades Per Bar — ограничение на число входов в пределах одной свечи (0 — без лимита).
  • Stop Loss (pips) — расстояние защитного стопа, 0 отключает уровень.
  • Break-even (pips) — профит, при котором стоп переносится в безубыток.
  • Trailing Activation (pips) — профит, при котором стоп переносится дальше на размер исходного стопа.
  • Partial TP1 / Ratio 1 — дистанция и процент первого частичного выхода.
  • Partial TP2 / Ratio 2 — дистанция и процент второго частичного выхода.
  • Take Profit (pips) — финальная цель, 0 отключает жесткий тейк.
  • Max Spread (pips) — допустимый спред при открытии позиции.
  • Money Management — выбор режима управления капиталом (Fixed, Geometrical, Proportional, Smart, TSSF).
  • Fixed Volume — объем для режима Fixed.
  • Geometrical Factor — множитель в геометрической формуле.
  • Risk Percent — доля капитала для режимов Proportional, Smart и TSSF.
  • Last Trades — количество закрытых сделок, участвующих в адаптивной статистике.
  • Decrease Factor — делитель, уменьшающий объем при серии убыточных сделок в режиме Smart.
  • TSSF Trigger 1/2/3 и TSSF Ratio 1/2/3 — пороги и коэффициенты для режима TSSF.
  • Candle Type — таймфрейм, на котором рассчитываются индикаторы и сигналы.

Дополнительная информация

  • Размер пункта автоматически вычисляется из шага цены инструмента: для пятизначных валютных пар один пункт соответствует десяти шагах цены.
  • Частичные выходы не сбрасывают счетчик входов на свечу, что совпадает с поведением оригинального советника.
  • Статистика для режимов Smart и TSSF формируется по изменениям реализованной прибыли, поэтому она становится информативной после первых закрытых сделок в среде StockSharp.
  • При отсутствии котировок bid/ask фильтр по спреду отключается, как и в исходном советнике при нулевом спреде брокера.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Hard Profit: Previous candle breakout with EMA filter and ATR stops.
/// </summary>
public class HardProfitStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevHigh;
	private decimal _prevLow;
	private decimal _entryPrice;

	public HardProfitStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");
		_emaLength = Param(nameof(EmaLength), 20)
			.SetDisplay("EMA Length", "Trend filter.", "Indicators");
		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period.", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int EmaLength { get => _emaLength.Value; set => _emaLength.Value = value; }
	public int AtrLength { get => _atrLength.Value; set => _atrLength.Value = value; }

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevHigh = 0; _prevLow = 0; _entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevHigh = 0; _prevLow = 0; _entryPrice = 0;
		var ema = new ExponentialMovingAverage { Length = EmaLength };
		var atr = new AverageTrueRange { Length = AtrLength };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, atr, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, ema); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (_prevHigh == 0 || atrVal <= 0) { _prevHigh = candle.HighPrice; _prevLow = candle.LowPrice; return; }

		if (Position > 0)
		{
			if (close >= _entryPrice + atrVal * 2.5m || close <= _entryPrice - atrVal * 1.5m) { SellMarket(); _entryPrice = 0; }
		}
		else if (Position < 0)
		{
			if (close <= _entryPrice - atrVal * 2.5m || close >= _entryPrice + atrVal * 1.5m) { BuyMarket(); _entryPrice = 0; }
		}

		if (Position == 0)
		{
			if (close > _prevHigh && close > emaVal) { _entryPrice = close; BuyMarket(); }
			else if (close < _prevLow && close < emaVal) { _entryPrice = close; SellMarket(); }
		}
		_prevHigh = candle.HighPrice; _prevLow = candle.LowPrice;
	}
}