Открыть на GitHub

Стратегия Up3x1 Investor

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

Это порт советника MetaTrader 4 up3x1_Investor. Стратегия торгует одним инструментом по закрытым свечам выбранного таймфрейма (по умолчанию H1). В реализации для StockSharp сохранены все ключевые правила оригинала и добавлены наглядные параметры управления рисками.

Логика входов

  • Анализируется последняя завершённая свеча, и проверяется:
    • Размах свечи (High − Low) больше 0.0060 ценовых единиц.
    • Тело свечи (|Open − Close|) больше 0.0050 ценовых единиц.
  • Если свеча закрылась ростом и выполняются оба условия, открывается рыночная покупка.
  • Если свеча закрылась падением и выполняются оба условия, открывается рыночная продажа.
  • Торговля полностью отключается по понедельникам (аналог условия DayOfWeek()==1 в MQL).

Сопровождение позиции

  • При входе рассчитываются внутренние уровни:
    • TakeProfitPoints — расстояние до целевой прибыли.
    • StopLossPoints — защитный стоп.
    • TrailingStopPoints — шаг для последующего подтягивания стопа.
  • На каждой завершённой свече проверяется:
    • Достигнута ли цель — позиция закрывается по тейк-профиту.
    • Сработал ли стоп — позиция закрывается для ограничения убытка.
    • Продвинулся ли рынок дальше trailing-расстояния — стоп подтягивается ближе к цене.
  • Дополнительно позиция закрывается, если простые средние за 24 и 60 периодов совпали (с точностью до одного шага цены). Это повторяет поведение iMA из исходника.

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

  • BaseVolume — базовый объём сделки, если не удаётся рассчитать его от капитала.
  • MaximumRisk повторяет формулу AccountFreeMargin()*MaximumRisk/1000. При наличии стоимости портфеля объём = value * MaximumRisk / 1000, округление до одной десятой.
  • DecreaseFactor уменьшает объём после серии убытков: при более чем одном подряд убытке объём сокращается пропорционально losses / DecreaseFactor.
  • MinimumVolume ограничивает объём снизу (минимум 0.1 лота, как в MQL).

Параметры

Имя Значение по умолчанию Назначение
BaseVolume 0.1 Базовый размер позиции.
MaximumRisk 0.2 Коэффициент риска для расчёта объёма от капитала.
DecreaseFactor 3 Множитель уменьшения объёма после убыточных сделок.
MinimumVolume 0.1 Минимально допустимый объём.
TakeProfitPoints 20 Расстояние до тейк-профита в шагах цены.
StopLossPoints 50 Расстояние до стоп-лосса в шагах цены.
TrailingStopPoints 10 Расстояние для трейлинг-стопа.
SkipMondays true Запрет на торговлю по понедельникам.
CandleType 1 час Таймфрейм свечей.

Дополнительно

  • Одновременно может быть открыта только одна позиция, что соответствует функции CalculateCurrentOrders в MQL.
  • Счётчик серий убытков ведётся внутри стратегии, так как StockSharp не предоставляет историю сделок MetaTrader.
  • Используются только рыночные заявки (BuyMarket и SellMarket).
using System;







using StockSharp.Algo.Indicators;



using StockSharp.Algo.Strategies;



using StockSharp.BusinessEntities;



using StockSharp.Messages;







namespace StockSharp.Samples.Strategies;







public class Up3x1InvestorRangeFilterStrategy : Strategy



{



	private readonly StrategyParam<int> _emaPeriod;



	private readonly StrategyParam<int> _atrPeriod;



	private readonly StrategyParam<DataType> _candleType;







	private decimal _prevClose; private decimal _prevEma; private bool _hasPrev;



	private int _cooldown;







	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }



	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }



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







	public Up3x1InvestorRangeFilterStrategy()



	{



		_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA lookback", "Indicators");



		_atrPeriod = Param(nameof(AtrPeriod), 14).SetDisplay("ATR Period", "ATR lookback", "Indicators");



		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");



	}







	/// <inheritdoc />



	protected override void OnReseted()



	{



		base.OnReseted();



		_prevClose = default;



		_prevEma = default;



		_hasPrev = default;



		_cooldown = default;



	}







	/// <inheritdoc />



	/// <inheritdoc />

	protected override void OnStarted2(DateTime time)



	{



		base.OnStarted2(time);



		_hasPrev = false;



		var ema = new ExponentialMovingAverage { Length = EmaPeriod };



		var subscription = SubscribeCandles(CandleType);



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



	}







	private void ProcessCandle(ICandleMessage candle, decimal ema)



	{



		if (candle.State != CandleStates.Finished) return;



		if (!IsFormedAndOnlineAndAllowTrading()) return;



		var close = candle.ClosePrice;



		if (!_hasPrev) { _prevClose = close; _prevEma = ema; _hasPrev = true; return; }



		if (_cooldown > 0)



		{



			_cooldown--;



			_prevClose = close; _prevEma = ema;



			return;



		}







		if (_prevClose <= _prevEma && close > ema && Position <= 0)



		{



			var volume = Volume + Math.Abs(Position);



			BuyMarket(volume);



			_cooldown = 6;



		}



		else if (_prevClose >= _prevEma && close < ema && Position >= 0)



		{



			var volume = Volume + Math.Abs(Position);



			SellMarket(volume);



			_cooldown = 6;



		}



		_prevClose = close; _prevEma = ema;



	}



}