Стратегия представляет собой порт советника MetaTrader 20/200 expert v4.2 (AntS). Каждый день в заданный час она сравнивает два значения цены открытия прошлых часовых свечей (по умолчанию 6 и 2 бара назад). Если более дальняя свеча открылась выше ближней на величину, превышающую Short Delta пунктов, открывается короткая позиция. Обратное соотношение, превышающее Long Delta, приводит к покупке.
Логика торговли
Подписка ведётся на часовые свечи (тип задаётся параметром Candle Type).
В сутки допускается только одна сделка. Заявки отправляются, когда активируется свеча с часом, равным Trade Hour.
Сигналы используют цену открытия свечей LookbackFar и LookbackNear баров назад.
Продажа:Open[t1] - Open[t2] > Short Delta × пункт.
Покупка:Open[t2] - Open[t1] > Long Delta × пункт.
После появления сигнала выставляется рыночный ордер вычисленного объёма. Стоп-лосс и тейк-профит копируют значения советника и задаются в пунктах; стратегия переводит их в цену через Security.PriceStep.
Пока позиция открыта, новых входов не происходит. На следующей календарной дате торговля возобновляется.
Управление позицией
Стоп-лосс и тейк-профит контролируются на каждом обновлении свечи по её максимуму и минимуму.
Параметр Max Open Hours принудительно закрывает позицию по рынку, если её жизнь превышает заданное количество часов (по умолчанию 504). Нулевое значение отключает ограничение.
Управление капиталом
Fixed Volume — базовый объём сделки, используемый при выключенном авто-лоте или отсутствии данных о балансе.
При включённом Use Auto Lot размер позиции повторяет огромную таблицу из MT4. В StockSharp она аппроксимирована формулой volume = round(balance × Auto Lot Factor, 2) с коэффициентом 0.000038, что даёт ту же лесенку лотов в диапазоне от 300 до 270 000+ USD.
Если текущая стоимость портфеля опускается ниже последнего зафиксированного значения, следующий вход умножается на Big Lot Multiplier, что соответствует режиму «Big Lot» оригинального советника.
Объёмы приводятся к Security.VolumeStep и ограничиваются диапазоном MinVolume/MaxVolume, если он задан.
Отличия от оригинала
В MT4 вручную перечислено более тысячи порогов для авто-лота. В порте используется линейный коэффициент (Auto Lot Factor), воспроизводящий ту же ступенчатую зависимость. При необходимости точного совпадения для другого брокера скорректируйте коэффициент.
Стоп и тейк реализованы как рыночные закрытия при достижении уровней свечой, что обеспечивает одинаковое поведение в тестах и на реале без биржевых стоп-заявок.
Глобальные переменные globalBalans и globalPosic заменены на состояние в памяти, дополнительная инфраструктура не требуется.
Параметры
Параметр
Описание
Long/Short Take Profit
Дистанция тейк-профита в пунктах.
Long/Short Stop Loss
Дистанция стоп-лосса в пунктах.
Trade Hour
Час (0–23), когда разрешены входы.
Far/Near Lookback
Количество баров для выборки двух цен открытия.
Long/Short Delta
Требуемый разрыв в пунктах для входа.
Max Open Hours
Максимальная продолжительность позиции в часах (0 отключает).
Fixed Volume
Базовый объём при выключенном авто-лоте.
Use Auto Lot
Включение авто-расчёта объёма по балансу.
Auto Lot Factor
Множитель для аппроксимации MT4-таблицы лотов.
Big Lot Multiplier
Множитель объёма после просадки счёта.
Candle Type
Таймфрейм свечей для сигналов.
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class Twenty200TimeBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _shortPeriod;
private readonly StrategyParam<int> _longPeriod;
private readonly StrategyParam<int> _cooldownCandles;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevShort;
private decimal _prevLong;
private bool _hasPrev;
private int _cooldownRemaining;
public int ShortPeriod { get => _shortPeriod.Value; set => _shortPeriod.Value = value; }
public int LongPeriod { get => _longPeriod.Value; set => _longPeriod.Value = value; }
public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public Twenty200TimeBreakoutStrategy()
{
_shortPeriod = Param(nameof(ShortPeriod), 20).SetDisplay("Short SMA", "Short SMA period", "Indicators");
_longPeriod = Param(nameof(LongPeriod), 200).SetDisplay("Long SMA", "Long SMA period", "Indicators");
_cooldownCandles = Param(nameof(CooldownCandles), 100).SetDisplay("Cooldown", "Candles between signals", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevShort = default;
_prevLong = default;
_hasPrev = default;
_cooldownRemaining = default;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevShort = 0;
_prevLong = 0;
_hasPrev = false;
_cooldownRemaining = 0;
var shortSma = new SimpleMovingAverage { Length = ShortPeriod };
var longSma = new SimpleMovingAverage { Length = LongPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(shortSma, longSma, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal shortSma, decimal longSma)
{
if (candle.State != CandleStates.Finished) return;
if (!_hasPrev) { _prevShort = shortSma; _prevLong = longSma; _hasPrev = true; return; }
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevShort = shortSma;
_prevLong = longSma;
return;
}
if (_prevShort <= _prevLong && shortSma > longSma && Position <= 0)
{
if (Position < 0) BuyMarket();
BuyMarket();
_cooldownRemaining = CooldownCandles;
}
else if (_prevShort >= _prevLong && shortSma < longSma && Position >= 0)
{
if (Position > 0) SellMarket();
SellMarket();
_cooldownRemaining = CooldownCandles;
}
_prevShort = shortSma;
_prevLong = longSma;
}
}