Стратегия переносит эксперта MetaTrader "DeMarker Pending 2.5" на платформу StockSharp. Робот рассчитывает индикатор DeMarker на выбранном таймфрейме и при пересечении заданных уровней формирует отложенный ордер в сторону пробоя. Ордер выставляется на фиксированном отступе в пунктах и может быть как стоповым, так и лимитным. Для контроля торгов доступны фильтр торгового окна и автоматическое истечение ожидания ордеров.
Логика торговли
Подписаться на свечи выбранного типа и рассчитывать DeMarker с периодом DemarkerPeriod.
Сравнивать значения текущей и предыдущей завершённой свечи с уровнями DemarkerLowerLevel и DemarkerUpperLevel.
При пробое нижнего уровня вверх подготовить длинный сетап; при пробое верхнего уровня вниз — короткий сетап.
Сформировать цену отложенного ордера как Close ± PendingIndentPoints * PriceStep, используя стоп-ордера для пробоя либо лимит-ордера для отката (в зависимости от Mode).
Добавить к отложенному ордеру уровни стоп-лосса и тейк-профита, смещённые на StopLossPoints и TakeProfitPoints пунктов от цены активации.
Перед размещением нового сигнала отменить или сохранить существующие отложенные ордера согласно параметрам ReplacePreviousPending и SinglePendingOnly.
Автоматически снимать ордера, у которых истёк срок жизни PendingExpirationMinutes.
При включённом UseTimeWindow пропускать сигналы вне торгового окна; один бар даёт не более одного нового ордера на направление.
Управление ордерами
Все входы выполняются отложенными ордерами (BuyStop, SellStop, BuyLimit, SellLimit).
К каждому ордеру сразу добавляются уровни защиты, чтобы позиция была защищена моментально после активации.
Ордера снимаются при истечении срока, при замене новым сигналом или при изменении состояния на неактивное (исполнено, отменено, отклонено).
Параметры
Параметр
Описание
Volume
Объём сделки в лотах.
StopLossPoints
Расстояние от цены входа до стоп-лосса в пунктах.
TakeProfitPoints
Расстояние от цены входа до тейк-профита в пунктах.
PendingIndentPoints
Отступ между рыночной ценой и отложенным ордером.
PendingExpirationMinutes
Время жизни отложенного ордера в минутах (0 — без ограничения).
Mode
Тип отложенного ордера (стоп или лимит).
SinglePendingOnly
Запрет на одновременное наличие более одного активного отложенного ордера.
ReplacePreviousPending
Автоматическая отмена существующих ордеров перед постановкой нового.
DemarkerPeriod
Период расчёта индикатора DeMarker.
DemarkerUpperLevel
Уровень DeMarker для сигналов на продажу.
DemarkerLowerLevel
Уровень DeMarker для сигналов на покупку.
CandleType
Таймфрейм свечей для анализа.
UseTimeWindow
Включает фильтрацию по торговому окну.
StartTime
Начало внутридневного торгового окна.
EndTime
Конец внутридневного торгового окна.
Примечания
В оригинальном эксперте реализованы сложные модули управления капиталом и трейлинг-стоп. В порте сохранены сигнал и отложенные ордера, а размер позиции задаётся фиксированным параметром Volume.
StockSharp прикрепляет уровни стоп-лосса и тейк-профита к ордеру при регистрации. Убедитесь, что брокер поддерживает такие параметры для стоповых и лимитных заявок.
Перед запуском проверьте, что значения в пунктах совместимы с минимальным шагом цены инструмента (PriceStep), и соответствуют требованиям площадки по минимальным дистанциям для защитных приказов.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from the "DeMarker Pending 2.5" MetaTrader expert.
/// Uses DeMarker indicator level crossovers to generate buy/sell market signals.
/// Original used pending orders; this version uses market orders.
/// </summary>
public class DeMarkerPendingStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _demarkerPeriod;
private readonly StrategyParam<decimal> _demarkerUpper;
private readonly StrategyParam<decimal> _demarkerLower;
private RelativeStrengthIndex _rsi;
private decimal? _prevOscillator;
/// <summary>
/// Candle type used for signal evaluation.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// DeMarker indicator period.
/// </summary>
public int DemarkerPeriod
{
get => _demarkerPeriod.Value;
set => _demarkerPeriod.Value = value;
}
/// <summary>
/// Upper DeMarker threshold that triggers sell signals.
/// </summary>
public decimal DemarkerUpperLevel
{
get => _demarkerUpper.Value;
set => _demarkerUpper.Value = value;
}
/// <summary>
/// Lower DeMarker threshold that triggers buy signals.
/// </summary>
public decimal DemarkerLowerLevel
{
get => _demarkerLower.Value;
set => _demarkerLower.Value = value;
}
public DeMarkerPendingStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for signal evaluation", "General");
_demarkerPeriod = Param(nameof(DemarkerPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("DeMarker Period", "Averaging period for DeMarker indicator", "Indicator");
_demarkerUpper = Param(nameof(DemarkerUpperLevel), 0.7m)
.SetDisplay("Upper Level", "DeMarker value that triggers sell setup", "Indicator");
_demarkerLower = Param(nameof(DemarkerLowerLevel), 0.3m)
.SetDisplay("Lower Level", "DeMarker value that triggers buy setup", "Indicator");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevOscillator = null;
_rsi = new RelativeStrengthIndex { Length = DemarkerPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_rsi.IsFormed)
{
_prevOscillator = rsiValue / 100m;
return;
}
if (_prevOscillator is null)
{
_prevOscillator = rsiValue / 100m;
return;
}
var oscillatorValue = rsiValue / 100m;
var volume = Volume;
if (volume <= 0)
volume = 1;
// DeMarker crosses below lower level -> buy signal
var crossDown = _prevOscillator.Value > DemarkerLowerLevel && oscillatorValue <= DemarkerLowerLevel;
// DeMarker crosses above upper level -> sell signal
var crossUp = _prevOscillator.Value < DemarkerUpperLevel && oscillatorValue >= DemarkerUpperLevel;
if (crossDown)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossUp)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevOscillator = oscillatorValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_rsi = null;
_prevOscillator = null;
base.OnReseted();
}
}