A estratégia replica a lógica central do especialista MetaTrader "DeMarker Pending 2" usando o StockSharp API de alto nível. Ele avalia um oscilador DeMarker no período de trabalho e prepara entradas pendentes de compra ou venda quando o indicador ultrapassa limites configuráveis. As ordens podem ser criadas como solicitações de stop ou limite com um recuo adicional do preço de mercado atual. Um filtro de sessão, proteção de propagação e verificações de distância mantêm as novas entradas sob controle.
Lógica de negociação
Assine a série de velas configurada e calcule o indicador DeMarker com o período selecionado.
Quando o valor anterior estiver acima do nível inferior e o valor atual estiver abaixo dele, coloque uma ordem pendente longa na fila. Quando o valor anterior estiver abaixo do nível superior e o valor atual ultrapassar ele, coloque uma ordem pendente curta na fila. Apenas um sinal por vela é processado.
As ordens pendentes são colocadas como ordens stop ou limit usando a distância de recuo expressa em pontos. Os pedidos existentes podem ser cancelados antes da nova solicitação se a opção de substituição estiver habilitada. A estratégia limita o número total de posições abertas mais ordens pendentes e impõe uma distância mínima do preço médio atual da posição.
As posições longas e curtas usam lógica opcional de stop-loss, take-profit e trailing. Os níveis de proteção são calculados em faixas de preço e monitorados em cada vela fechada. Os trailing stops são ajustados quando a posição obtém o lucro de ativação e a distância adicional do trailing step.
Um filtro de spread evita novos pedidos se o melhor spread de compra/venda exceder o limite configurado. Limites de sessão opcionais podem desabilitar novas entradas fora da janela de negociação permitida.
Parâmetros
Nome
Descrição
Velas de trabalho
Prazo usado para sinais e verificações de proteção.
Volume do pedido
Volume padrão para ordens pendentes.
Stop Loss (pontos)
Distância inicial do stop-loss em pontos de preço.
Obter lucro (pontos)
Distância inicial de lucro em faixas de preço.
Ativação final (pts)
Lucro necessário antes que o trailing stop seja ativado.
Parada final (pontos)
Distância entre o preço e o trailing stop.
Etapa final (pts)
Ganho adicional necessário para mover o trailing stop.
Trilha próxima
Atualize o trailing stop somente em velas finalizadas quando habilitado.
Posições máximas
Número máximo de posições abertas mais ordens pendentes. Zero desativa o limite.
Distância mínima (pontos)
Distância mínima do preço da posição atual até novas entradas pendentes.
Use ordens de parada
Coloque ordens de parada quando verdadeiro, caso contrário, serão usadas ordens de limite.
Único pendente
Permitir apenas uma ordem pendente ativa por vez.
Substituir Pendentes
Cancele pedidos pendentes pendentes antes de fazer um novo.
Deslocamento pendente (pts)
Recuo para novos preços pendentes em relação ao mercado.
Spread máximo (pontos)
Spread máximo permitido antes de pular a colocação do pedido.
Usar filtro de sessão
Ative ou desative o filtro da janela de negociação.
Hora/minuto inicial, hora/minuto final
Limites de sessão quando o filtro de sessão está ativo.
Período DeMarker
Período médio para o oscilador DeMarker.
Nível Superior
Limite que aciona configurações curtas.
Nível inferior
Limite que aciona configurações longas.
Notas
A expiração do pedido e o dimensionamento do risco de gerenciamento de dinheiro do especialista original não são transferidos. Em vez disso, é usado um parâmetro de volume fixo.
Os níveis de stop-loss e take-profit são avaliados em velas fechadas usando preços altos/baixos, que podem diferir da execução intrabarra em MetaTrader.
A lógica final é avaliada apenas em velas fechadas. O rastreamento baseado em ticks em tempo real não é reproduzido.
Os pedidos pendentes dependem das melhores cotações de compra/venda fornecidas pela fonte de dados. Certifique-se de que as assinaturas de nível 1 estejam disponíveis.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Pending order strategy driven by the DeMarker oscillator.
/// Simplified from "DeMarker Pending 2" to use market orders on threshold crossovers.
/// </summary>
public class DeMarkerPending2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _demarkerPeriod;
private readonly StrategyParam<decimal> _demarkerUpperLevel;
private readonly StrategyParam<decimal> _demarkerLowerLevel;
private RelativeStrengthIndex _rsi;
private decimal? _prevOscillator;
/// <summary>
/// Candle type for calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// DeMarker oscillator period.
/// </summary>
public int DemarkerPeriod
{
get => _demarkerPeriod.Value;
set => _demarkerPeriod.Value = value;
}
/// <summary>
/// Upper DeMarker threshold for sell signal.
/// </summary>
public decimal DemarkerUpperLevel
{
get => _demarkerUpperLevel.Value;
set => _demarkerUpperLevel.Value = value;
}
/// <summary>
/// Lower DeMarker threshold for buy signal.
/// </summary>
public decimal DemarkerLowerLevel
{
get => _demarkerLowerLevel.Value;
set => _demarkerLowerLevel.Value = value;
}
public DeMarkerPending2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for calculations", "General");
_demarkerPeriod = Param(nameof(DemarkerPeriod), 14)
.SetDisplay("DeMarker Period", "DeMarker oscillator period", "Indicator")
.SetGreaterThanZero();
_demarkerUpperLevel = Param(nameof(DemarkerUpperLevel), 0.7m)
.SetDisplay("Upper Level", "Overbought threshold", "Indicator");
_demarkerLowerLevel = Param(nameof(DemarkerLowerLevel), 0.3m)
.SetDisplay("Lower Level", "Oversold threshold", "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 not decimal prev)
{
_prevOscillator = rsiValue / 100m;
return;
}
var oscillatorValue = rsiValue / 100m;
var volume = Volume;
if (volume <= 0)
volume = 1;
// Cross above lower level from below => buy
if (prev < DemarkerLowerLevel && oscillatorValue >= DemarkerLowerLevel)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
// Cross below upper level from above => sell
else if (prev > DemarkerUpperLevel && oscillatorValue <= DemarkerUpperLevel)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
_prevOscillator = oscillatorValue;
}
/// <inheritdoc />
protected override void OnReseted()
{
_rsi = null;
_prevOscillator = null;
base.OnReseted();
}
}