Данная стратегия переносит советника MetaTrader "_HPCS_IntFourth_MT4_EA_V01_WE" на высокоуровневый API StockSharp. Оригинальный скрипт мгновенно открывает длинную позицию, выставляет защитные уровни в метатрейдеровских пунктах (pip) и закрывает сделку после короткого промежутка времени. В версии на C# те же действия выполняются с помощью встроенного менеджера защитных ордеров и таймера с периодом в одну секунду, который отслеживает время с момента входа.
Логика торговли
Инициализация
При запуске определяется размер MetaTrader-пункта на основе PriceStep инструмента и количества десятичных знаков (для 5- и 3-значных котировок применяется множитель 10).
Метод StartProtection настраивается с учётом выбранных дистанций для тейк-профита и стоп-лосса. В стоп включена дополнительная «просадка», которую оригинальный советник применял через OrderModify.
Объём сделки фиксированный и задаётся параметром OrderVolume.
Вход
Сразу после старта отправляется одна рыночная заявка на покупку. Повторных входов не происходит.
После получения первой сделки запоминается время исполнения для дальнейшего контроля.
Выход
Таймер проверяет состояние позиции каждую секунду.
Когда длительность удержания достигает CloseDelaySeconds, стратегия закрывает длинную позицию рыночной продажей при наличии открытого объёма.
Защитные стоп-лосс и тейк-профит автоматически поддерживаются менеджером защиты и исполняются по рынку, как и в исходном советнике через OrderClose.
Стратегия работает только в длинную сторону, полностью повторяя оригинал.
Параметры
Имя
Описание
Значение по умолчанию
Оптимизация
OrderVolume
Фиксированный объём для стартовой рыночной покупки.
1
Нет
StopLossPips
Базовая дистанция стоп-лосса в MetaTrader-пунктах.
10
Нет
ExtraStopPips
Дополнительный отступ стопа, применяемый после входа.
10
Нет
TakeProfitPips
Дистанция тейк-профита в MetaTrader-пунктах.
10
Нет
CloseDelaySeconds
Количество секунд до принудительного закрытия позиции (0 отключает таймер).
30
Нет
Особенности реализации
Расчёт размера пункта умножает PriceStep на 10 для инструментов с 3 или 5 десятичными знаками, чтобы параметры сохраняли масштаб MetaTrader.
StartProtection использует расстояния типа UnitTypes.Price, поэтому защитные выходы выполняются рыночными заявками и повторяют поведение OrderClose.
В OnNewMyTrade сохраняется время первой покупки и сбрасывается состояние после полного выхода из позиции, что позволяет корректно отсчитывать задержку.
Таймер с шагом в одну секунду заменяет проверку OnTick, поэтому логика продолжает работать даже при отсутствии новых котировок.
Все комментарии в исходном коде написаны на английском языке в соответствии с требованиями репозитория.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Port of the "_HPCS_IntFourth_MT4_EA_V01_WE" MetaTrader expert advisor.
/// Uses SMA crossover to enter positions with time-based exit.
/// </summary>
public class HpcsInter4Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal _prevFast;
private decimal _prevSlow;
private bool _isFirstValue = true;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public HpcsInter4Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Time frame for calculation", "General");
_fastPeriod = Param(nameof(FastPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Fast SMA", "Fast SMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow SMA", "Slow SMA period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = 0;
_prevSlow = 0;
_isFirstValue = true;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = 0;
_prevSlow = 0;
_isFirstValue = true;
var fastSma = new ExponentialMovingAverage { Length = FastPeriod };
var slowSma = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastSma, slowSma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastSma);
DrawIndicator(area, slowSma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (_isFirstValue)
{
_prevFast = fastValue;
_prevSlow = slowValue;
_isFirstValue = false;
return;
}
// Fast crosses above slow - buy
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
BuyMarket();
}
// Fast crosses below slow - sell
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
SellMarket();
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
}