Esta estrategia StockSharp reproduce el comportamiento del asesor experto MetaTrader "DeMarker Pending 2.5". El robot evalúa el oscilador DeMarker en un período de tiempo configurable y, cuando se cruzan niveles extremos, coloca una orden pendiente en la dirección de ruptura. La orden puede ser una orden stop o limitada compensada por un número fijo de puntos. El filtrado opcional de la ventana comercial y el vencimiento automático mantienen las órdenes pendientes alineadas con el comportamiento del experto original.
Lógica comercial
Suscríbase a la serie de velas seleccionada y calcule el indicador DeMarker con período DemarkerPeriod.
Detecte cruces de los umbrales inferior (DemarkerLowerLevel) y superior (DemarkerUpperLevel) utilizando los valores de vela finalizados actuales y anteriores.
Cuando el nivel inferior se cruza hacia arriba, se hace una cola larga; cuando el nivel superior se cruza hacia abajo, haga cola para una configuración breve.
Convierta configuraciones en órdenes pendientes al precio Close ± PendingIndentPoints * PriceStep, usando órdenes stop en modo de ruptura o órdenes limitadas para entradas de retroceso dependiendo de Mode.
Adjunte niveles de stop-loss y take-profit a la orden pendiente compensando el precio de entrada en StopLossPoints y TakeProfitPoints puntos.
Cancele o reutilice pedidos pendientes anteriores de acuerdo con ReplacePreviousPending y SinglePendingOnly antes de registrar uno nuevo.
Elimine los pedidos pendientes automáticamente una vez que transcurra su PendingExpirationMinutes vida útil.
Ignore las señales fuera de la ventana intradiaria cuando UseTimeWindow esté habilitado. Cada barra se procesa solo una vez, por lo que se crea como máximo una nueva orden pendiente por barra y dirección.
Gestión de pedidos
Todas las entradas se crean como órdenes pendientes (BuyStop, SellStop, BuyLimit, SellLimit).
Cada orden pendiente tiene sus propios precios de límite de pérdidas y obtención de ganancias para que la posición esté protegida inmediatamente después de la activación.
Las órdenes pendientes se cancelan al vencimiento, cuando se reemplazan por nuevas configuraciones o cuando el estado de la orden cambia a un estado inactivo (completado, cancelado, rechazado).
Parámetros
Parámetro
Descripción
Volume
Volumen de pedidos en lotes.
StopLossPoints
Distancia entre el precio de entrada y el stop-loss en puntos.
TakeProfitPoints
Distancia entre el precio de entrada y el take-profit en puntos.
PendingIndentPoints
Compensación entre el precio de mercado y la orden pendiente.
PendingExpirationMinutes
Duración de cada orden pendiente en minutos (0 desactiva el vencimiento).
Mode
Tipo de orden pendiente (parada para rupturas o límite para retrocesos).
SinglePendingOnly
Si está habilitado, evita realizar más de una orden pendiente activa.
ReplacePreviousPending
Cancela las órdenes pendientes activas antes de emitir una nueva.
DemarkerPeriod
Período retrospectivo del oscilador DeMarker.
DemarkerUpperLevel
Umbral de DeMarker que desencadena configuraciones de venta.
DemarkerLowerLevel
Umbral de DeMarker que desencadena configuraciones de compra.
CandleType
Plazo utilizado para la suscripción de velas y la evaluación de indicadores.
UseTimeWindow
Habilita el filtrado horario intradiario.
StartTime
Inicio de la ventana de negociación intradiaria.
EndTime
Fin de la ventana de negociación intradiaria.
Notas
El experto original incluye sofisticadas rutinas de gestión del dinero y trailing-stop. Este puerto mantiene la generación de señales y el manejo de órdenes pendientes, pero simplifica el tamaño de la posición a un único parámetro fijo Volume.
StockSharp adjunta precios de límite de pérdidas y obtención de ganancias en el momento del registro de la orden; Dependiendo del corredor, es posible que deba verificar que las órdenes de parada y límite respalden esos niveles de protección.
Asegúrese siempre de que las distancias basadas en puntos sean compatibles con el PriceStep del símbolo negociado. Establezca PendingIndentPoints, StopLossPoints y TakeProfitPoints en valores que satisfagan los requisitos de distancia mínima del corredor.
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();
}
}