Prop Firm Helper Strategy es un sistema de desglose de canales Donchian convertido del asesor experto MetaTrader "Prop Firm Helper". La estrategia envía órdenes stop por encima del rango reciente para entradas largas y por debajo del rango para entradas cortas. Automáticamente aplica las reglas de impugnación de las empresas de apoyo al detener la negociación después de alcanzar el capital objetivo o cuando se supera el límite de pérdida diaria.
Lógica de trading
Suscríbase a velas definidas por el parámetro Candle Type.
Calcula dos Donchian canales:
Entry Period/Entry Shift para detectar brotes.
Exit Period/Exit Shift para rastrear las operaciones abiertas.
Coloque órdenes stop de compra un tick por encima del máximo superior Donchian desplazado cuando esté plano o en corto.
Coloque órdenes de stop de venta un tick por debajo del mínimo inferior desplazado Donchian cuando esté plano o en posición larga.
Utilice el suavizado de rango verdadero promedio (ATR Period) para decidir cuándo avanzar las órdenes stop.
Cierre posiciones largas si la vela se sitúa por debajo del mínimo final Donchian. Cierre las posiciones cortas cuando la vela cierre por encima del máximo final Donchian.
Gestión del riesgo
Risk Per Trade % calcula el volumen de la orden a partir del capital de la cartera actual, el tamaño del paso del instrumento y el precio del paso. El volumen se redondea al paso de volumen de intercambio y se limita al volumen mínimo/máximo.
Las órdenes stop de protección siguen la posición utilizando el canal de salida Donchian más un búfer ATR para evitar una rotación excesiva de órdenes.
Reglas de desafío de la empresa de utilería
Use Challenge Rules habilita comprobaciones de desafío.
Las operaciones se detienen una vez que se alcanza el capital Pass Criteria. Todas las órdenes se cancelan y la posición se cierra.
Las reducciones diarias superiores a Daily Loss Limit desencadenan una liquidación completa y desactivan nuevas órdenes durante el resto de la sesión. El valor de referencia se reinicia al comienzo de cada día de negociación.
Parámetros
Nombre
Descripción
Entry Period
Búsqueda retrospectiva del canal Donchian principal.
Entry Shift
Número de velas terminadas ignoradas cuando se utiliza el canal de ruptura.
Exit Period
Búsqueda retrospectiva del canal final de Donchian.
Exit Shift
Número de velas terminadas ignoradas para los trailingstops.
Risk Per Trade %
Porcentaje de capital de la cartera a riesgo en cada entrada.
ATR Period
Búsqueda retrospectiva del filtro ATR utilizado cuando se detiene el movimiento.
Use Challenge Rules
Permite propiciar condiciones de desafío firme.
Pass Criteria
Nivel de capital que impide seguir negociando.
Daily Loss Limit
Reducción diaria permitida antes de que se detenga la negociación.
Candle Type
Suscripción de vela utilizada para los cálculos.
Notas
La estrategia requiere una conexión de cartera para calcular el tamaño de las posiciones basadas en el riesgo y las métricas de desafío.
Las órdenes se cancelan y se vuelven a enviar en cada vela terminada para mantener los precios de activación alineados con los últimos niveles de Donchian.
Los parámetros predeterminados reproducen el comportamiento del asesor experto MetaTrader original.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Breakout strategy that recreates the MetaTrader "Prop Firm Helper" expert advisor.
/// Uses Donchian channel breakouts for entry signals with market orders.
/// </summary>
public class PropFirmHelperStrategy : Strategy
{
private readonly StrategyParam<int> _entryPeriod;
private readonly StrategyParam<int> _exitPeriod;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _signalCooldownBars;
private DonchianChannels _entryChannel;
private DonchianChannels _exitChannel;
private decimal _entryUpper;
private decimal _entryLower;
private decimal _exitLower;
private decimal _exitUpper;
private decimal _prevEntryUpper;
private decimal _prevEntryLower;
private bool _hasValues;
private decimal _entryPrice;
private int _cooldownRemaining;
/// <summary>
/// Initializes a new instance of <see cref="PropFirmHelperStrategy"/>.
/// </summary>
public PropFirmHelperStrategy()
{
_entryPeriod = Param(nameof(EntryPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Entry Period", "Number of candles used for breakout Donchian channel", "Entries");
_exitPeriod = Param(nameof(ExitPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Exit Period", "Number of candles used for trailing Donchian channel", "Exits");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe used for Donchian calculations", "General");
_signalCooldownBars = Param(nameof(SignalCooldownBars), 4)
.SetNotNegative()
.SetDisplay("Signal Cooldown Bars", "Closed candles to wait before a new breakout entry", "General");
}
/// <summary>
/// Donchian breakout lookback length.
/// </summary>
public int EntryPeriod
{
get => _entryPeriod.Value;
set => _entryPeriod.Value = value;
}
/// <summary>
/// Donchian trailing lookback length.
/// </summary>
public int ExitPeriod
{
get => _exitPeriod.Value;
set => _exitPeriod.Value = value;
}
/// <summary>
/// Candle type used for indicator subscriptions.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int SignalCooldownBars
{
get => _signalCooldownBars.Value;
set => _signalCooldownBars.Value = value;
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryChannel = null;
_exitChannel = null;
_entryUpper = 0m;
_entryLower = 0m;
_exitLower = 0m;
_exitUpper = 0m;
_prevEntryUpper = 0m;
_prevEntryLower = 0m;
_hasValues = false;
_entryPrice = 0m;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasValues = false;
_cooldownRemaining = 0;
_entryChannel = new DonchianChannels { Length = EntryPeriod };
_exitChannel = new DonchianChannels { Length = ExitPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _entryChannel);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (_cooldownRemaining > 0)
_cooldownRemaining--;
var entryValue = _entryChannel.Process(new CandleIndicatorValue(_entryChannel, candle));
var exitValue = _exitChannel.Process(new CandleIndicatorValue(_exitChannel, candle));
if (!_entryChannel.IsFormed || !_exitChannel.IsFormed)
return;
if (entryValue is not DonchianChannelsValue entryBands || exitValue is not DonchianChannelsValue exitBands)
return;
if (entryBands.UpperBand is not decimal entryUpper || entryBands.LowerBand is not decimal entryLower)
return;
if (exitBands.UpperBand is not decimal exitUpper || exitBands.LowerBand is not decimal exitLower)
return;
_prevEntryUpper = _entryUpper;
_prevEntryLower = _entryLower;
_entryUpper = entryUpper;
_entryLower = entryLower;
_exitUpper = exitUpper;
_exitLower = exitLower;
if (!_hasValues)
{
_hasValues = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
return;
ProcessSignal(candle);
}
private void ProcessSignal(ICandleMessage candle)
{
var close = candle.ClosePrice;
// Exit logic
if (Position > 0 && close < _exitLower)
{
SellMarket(Position);
_cooldownRemaining = SignalCooldownBars;
return;
}
else if (Position < 0 && close > _exitUpper)
{
BuyMarket(-Position);
_cooldownRemaining = SignalCooldownBars;
return;
}
// Entry logic - breakout above previous entry channel upper
if (_cooldownRemaining == 0 && _prevEntryUpper > 0 && close > _prevEntryUpper && Position <= 0)
{
BuyMarket(Volume + (Position < 0 ? -Position : 0m));
_entryPrice = close;
_cooldownRemaining = SignalCooldownBars;
}
else if (_cooldownRemaining == 0 && _prevEntryLower > 0 && close < _prevEntryLower && Position >= 0)
{
SellMarket(Volume + (Position > 0 ? Position : 0m));
_entryPrice = close;
_cooldownRemaining = SignalCooldownBars;
}
}
}