Esta estrategia reproduce el MetaTrader 5 asesor experto "DeMarker ganando posición volumen 2" utilizando el nivel alto de StockSharp API. Analiza una serie de velas configurables con el oscilador DeMarker y reacciona cuando el valor entra en zonas extremas. La implementación mantiene el estilo original de administración de dinero con tamaño de lote fijo, inversión opcional de señales, manejo integrado de stop-loss/take-profit y un filtro de sesión comercial opcional.
Comportamiento experto original
Plataforma: MetaTrader 5.
Indicador: oscilador DeMarker clásico (DEM), período predeterminado 14.
Entradas: abrir posiciones largas cuando DeMarker cae por debajo de un umbral inferior, abrir posiciones cortas cuando sube por encima de un umbral superior.
Controles de riesgo: stop-loss/take-profit fijo expresado en puntos, trailing stop opcional con escalón, ventana de tiempo opcional.
Gestión de posición: asegúrese de realizar solo una operación por barra y cierre el lado opuesto antes de cambiar de dirección.
La conversión StockSharp sigue los mismos principios. Las órdenes de protección se implementan con StartProtection, por lo que el límite de pérdidas, la toma de ganancias y el seguimiento se administran automáticamente una vez que se abre una posición.
Lógica comercial
Suscríbase al tipo de vela configurado (CandleType, velas de 5 minutos por defecto) y calcule el valor de DeMarker con el período elegido (DeMarkerPeriod).
Cuando se cierra una vela, evalúe el oscilador:
Si ReverseSignals es falso (predeterminado):
Configuración larga – DeMarker <= LowerLevel.
Configuración breve – DeMarker >= UpperLevel.
Si ReverseSignals es verdadero, las reglas largas/cortas se intercambian.
Opere únicamente dentro de la ventana de sesión opcional definida por SessionStart/SessionEnd cuando UseTimeFilter esté habilitado. Se admiten sesiones nocturnas.
Ejecute como máximo una nueva entrada por vela. Antes de abrir una nueva posición, la estrategia cierra cualquier posición opuesta para reflejar la lógica MT5.
Los volúmenes están fijados por el parámetro TradeVolume. Si la estrategia ya está parcialmente en la dirección deseada, se completa hasta el volumen solicitado.
Gestión de riesgos
StopLossPoints y TakeProfitPoints (en pasos de precio) se asignan a las distancias de parada y toma de ganancias basadas en puntos del experto.
Al habilitar EnableTrailing se cambia la distancia de parada a TrailingStopPoints y se activa el motor de seguimiento integrado usando TrailingStepPoints como paso de ajuste.
StartProtection está configurado con useMarketOrders = true para que las órdenes de protección se ejecuten inmediatamente, asemejándose al comportamiento de cierre comercial de MT5.
Parámetros
Parámetro
Descripción
DeMarkerPeriod
Período promedio del indicador DeMarker.
UpperLevel / LowerLevel
Umbrales de sobrecompra/sobreventa que activan posiciones cortas/largas.
ReverseSignals
Intercambie condiciones largas y cortas.
StopLossPoints
Distancia de parada de protección inicial medida en pasos de precio.
TakeProfitPoints
Distancia de obtención de beneficios medida en incrementos de precios.
EnableTrailing
Habilita el bloque trailing stop.
TrailingStopPoints
Distancia del trailing stop una vez que el trailing está activo.
TrailingStepPoints
Movimiento mínimo favorable antes de que se avance el trailing stop.
UseTimeFilter
Restringe el comercio a la ventana SessionStart–SessionEnd.
SessionStart / SessionEnd
Límites de sesión inclusivos/exclusivos (admite la integración).
TradeVolume
Cantidad a enviar con cada orden de mercado.
CandleType
Serie de velas a analizar (por defecto 5 minutos).
Notas de implementación
El experto en MT5 incluyó un umbral de "activación final". La protección de seguimiento estándar de StockSharp no expone el mismo parámetro, por lo tanto, el seguimiento se activa inmediatamente cuando EnableTrailing es verdadero.
La infraestructura de StockSharp maneja el manejo de errores para tamaños de lote no válidos, niveles de congelación y lógica de actualización de oferta/demanda, por lo que se omiten de la conversión.
El registro se realiza a través de la clase base Strategy (llame a LogInfo/LogError si se requiere seguimiento adicional).
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Strategy converted from "DeMarker gaining position volume 2" expert advisor.
/// Uses DeMarker oscillator thresholds for entry signals.
/// </summary>
public class DeMarkerGainingPositionVolume2Strategy : Strategy
{
private readonly StrategyParam<int> _deMarkerPeriod;
private readonly StrategyParam<decimal> _upperLevel;
private readonly StrategyParam<decimal> _lowerLevel;
private readonly StrategyParam<DataType> _candleType;
private RelativeStrengthIndex _rsi;
private decimal? _prevOscillator;
/// <summary>
/// DeMarker averaging period.
/// </summary>
public int DeMarkerPeriod
{
get => _deMarkerPeriod.Value;
set => _deMarkerPeriod.Value = value;
}
/// <summary>
/// Upper DeMarker threshold.
/// </summary>
public decimal UpperLevel
{
get => _upperLevel.Value;
set => _upperLevel.Value = value;
}
/// <summary>
/// Lower DeMarker threshold.
/// </summary>
public decimal LowerLevel
{
get => _lowerLevel.Value;
set => _lowerLevel.Value = value;
}
/// <summary>
/// Candle type for DeMarker calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public DeMarkerGainingPositionVolume2Strategy()
{
_deMarkerPeriod = Param(nameof(DeMarkerPeriod), 14)
.SetDisplay("DeMarker Period", "Number of bars used by the oscillator.", "Indicator");
_upperLevel = Param(nameof(UpperLevel), 0.7m)
.SetDisplay("Upper Level", "Overbought threshold.", "Indicator");
_lowerLevel = Param(nameof(LowerLevel), 0.3m)
.SetDisplay("Lower Level", "Oversold threshold.", "Indicator");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations.", "Data");
}
/// <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;
}
var oscillatorValue = rsiValue / 100m;
var volume = Volume;
if (volume <= 0)
volume = 1;
// Cross below lower level => oversold => buy
if (_prevOscillator is decimal prev)
{
var crossBelow = prev >= LowerLevel && oscillatorValue < LowerLevel;
var crossAbove = prev <= UpperLevel && oscillatorValue > UpperLevel;
if (crossBelow)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (crossAbove)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
}
_prevOscillator = oscillatorValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_rsi = null;
_prevOscillator = null;
base.OnReseted();
}
}