La Estrategia de comercio automático de NNFX replica el flujo de trabajo de gestión y dimensionamiento de riesgos del panel original NNFX MetaTrader 4 dentro de StockSharp. En lugar de una interfaz gráfica, la estrategia expone comandos manuales a través de parámetros. Los operadores pueden solicitar entradas largas o cortas, reducir instantáneamente la exposición o aplicar una lógica de equilibrio y seguimiento que refleje al asesor experto.
Características clave:
Tamaño de volatilidad impulsado por ATR con una anulación opcional para distancias de parada y toma de ganancias manuales.
Las entradas de posiciones se dividen en dos partes: una con un objetivo proyectado y un corredor que se deja abierto para gestión discrecional.
Los comandos de equilibrio y seguimiento funcionan según demanda, actualizando los niveles de parada almacenados sin activarse automáticamente en cada barra.
Se puede incluir capital adicional al calcular el riesgo monetario, coincidiendo con el comportamiento del script MQL.
Lógica de trading
Colección ATR: la estrategia se suscribe al tipo de vela configurado y procesa un indicador de rango verdadero promedio. Cuando UsePreviousDailyAtr está habilitado, copia el valor ATR del día anterior durante las primeras 12 horas del nuevo día de negociación, imitando el script original.
Dimensionamiento basado en el riesgo: con un comando manual Buy o Sell, el motor calcula el riesgo monetario por unidad utilizando la distancia de parada protectora y convierte el porcentaje de riesgo deseado en un volumen ejecutable.
División de posición: el volumen de entrada se divide en dos mitades. La primera mitad se liquida automáticamente cuando se toca el objetivo proyectado, mientras que la segunda mitad permanece hasta que el comerciante da más órdenes.
Manejo de paradas: las paradas iniciales se almacenan internamente y se evalúan en cada vela terminada. Los comandos manuales pueden empujar el tope hasta el punto de equilibrio o avanzarlo de acuerdo con la fórmula final de NNFX.
Controles de salida: CloseAll aplana inmediatamente el libro, mientras que las violaciones de los límites o los objetivos parciales desencadenan salidas del mercado que respetan los volúmenes calculados.
Parámetros
Parámetro
Predeterminado
Descripción
RiskPercent
2.0
Porcentaje del capital de la cuenta (más AdditionalCapital) arriesgado por operación.
AdditionalCapital
0
Capital adicional añadido a la base patrimonial al dimensionar las posiciones.
UseAdvancedTargets
false
Cambia las distancias de riesgo de múltiplos de ATR a valores de pips manuales.
AdvancedStopPips
0
Distancia de parada en pips cuando el modo avanzado está activo.
AdvancedTakeProfitPips
0
Distancia objetivo en pips para la salida parcial cuando el modo avanzado está activo.
UsePreviousDailyAtr
true
Copia el ATR diario anterior durante las primeras 12 horas de un nuevo día.
AtrPeriod
14
ATR longitud retrospectiva.
AtrStopMultiplier
1.5
Multiplicador aplicado a ATR al calcular la distancia de parada.
AtrTakeProfitMultiplier
1.0
Multiplicador aplicado a ATR al calcular la distancia de obtención de beneficios.
CandleType
1 Minute
Tipo de vela utilizado para ATR y seguimiento de precios.
BuyCommand
false
Bandera manual: configurada en true para solicitar una entrada larga. Se reinicia automáticamente.
SellCommand
false
Bandera manual: configurada en true para solicitar una entrada breve. Se reinicia automáticamente.
BreakevenCommand
false
Bandera manual: mueve el stop de protección al precio de entrada. Se reinicia automáticamente.
TrailingCommand
false
Bandera manual: aplique la fórmula final NNFX una vez. Se reinicia automáticamente.
CloseAllCommand
false
Bandera manual: cierre todas las posiciones abiertas al instante. Se reinicia automáticamente.
Notas de uso
La estrategia requiere una cartera conectada y seguridad con metadatos Step, StepPrice y VolumeStep válidos para realizar cálculos de riesgo precisos.
Los comandos se evalúan en velas terminadas, por lo que se debe recibir una nueva barra (o actualización de vela) después de alternar un parámetro manual.
Cuando utilice distancias avanzadas, asegúrese de que tanto AdvancedStopPips como AdvancedTakeProfitPips estén completos; de lo contrario, los valores predeterminados basados en ATR seguirán vigentes.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// NNFX Auto Trade strategy: ATR-based trend following with EMA filter.
/// Enters on EMA direction with ATR-based trailing stop management.
/// </summary>
public class NnfxAutoTradeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private readonly StrategyParam<int> _signalCooldownCandles;
private decimal _entryPrice;
private decimal _bestPrice;
private bool _wasBullish;
private bool _hasPrevSignal;
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public NnfxAutoTradeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(120).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_emaPeriod = Param(nameof(EmaPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period", "Indicators");
_atrMultiplier = Param(nameof(AtrMultiplier), 2.5m)
.SetDisplay("ATR Multiplier", "ATR multiplier for stop", "Risk");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 12)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0m;
_bestPrice = 0m;
_wasBullish = false;
_hasPrevSignal = false;
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_entryPrice = 0;
_bestPrice = 0;
_hasPrevSignal = false;
_candlesSinceTrade = SignalCooldownCandles;
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var atr = new AverageTrueRange { Length = AtrPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ema, atr, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal atrValue)
{
if (candle.State != CandleStates.Finished) return;
var close = candle.ClosePrice;
var stopDist = atrValue * AtrMultiplier;
var isBullish = close > emaValue;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
// Trailing stop check
if (Position > 0)
{
if (close > _bestPrice) _bestPrice = close;
if (_bestPrice - close > stopDist)
{
SellMarket();
_entryPrice = 0;
_bestPrice = 0;
_candlesSinceTrade = 0;
return;
}
}
else if (Position < 0)
{
if (close < _bestPrice) _bestPrice = close;
if (close - _bestPrice > stopDist)
{
BuyMarket();
_entryPrice = 0;
_bestPrice = 0;
_candlesSinceTrade = 0;
return;
}
}
// Entry signals
if (_hasPrevSignal && isBullish != _wasBullish && _candlesSinceTrade >= SignalCooldownCandles)
{
if (isBullish && Position <= 0)
{
BuyMarket();
_entryPrice = close;
_bestPrice = close;
_candlesSinceTrade = 0;
}
else if (!isBullish && Position >= 0)
{
SellMarket();
_entryPrice = close;
_bestPrice = close;
_candlesSinceTrade = 0;
}
}
_wasBullish = isBullish;
_hasPrevSignal = true;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage, AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class nnfx_auto_trade_strategy(Strategy):
def __init__(self):
super(nnfx_auto_trade_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(120)))
self._ema_period = self.Param("EmaPeriod", 100)
self._atr_period = self.Param("AtrPeriod", 14)
self._atr_multiplier = self.Param("AtrMultiplier", 2.5)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 12)
self._entry_price = 0.0
self._best_price = 0.0
self._was_bullish = False
self._has_prev_signal = False
self._candles_since_trade = 12
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def EmaPeriod(self):
return self._ema_period.Value
@EmaPeriod.setter
def EmaPeriod(self, value):
self._ema_period.Value = value
@property
def AtrPeriod(self):
return self._atr_period.Value
@AtrPeriod.setter
def AtrPeriod(self, value):
self._atr_period.Value = value
@property
def AtrMultiplier(self):
return self._atr_multiplier.Value
@AtrMultiplier.setter
def AtrMultiplier(self, value):
self._atr_multiplier.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(nnfx_auto_trade_strategy, self).OnReseted()
self._entry_price = 0.0
self._best_price = 0.0
self._was_bullish = False
self._has_prev_signal = False
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(nnfx_auto_trade_strategy, self).OnStarted2(time)
self._entry_price = 0.0
self._best_price = 0.0
self._has_prev_signal = False
self._candles_since_trade = self.SignalCooldownCandles
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
atr = AverageTrueRange()
atr.Length = self.AtrPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, atr, self._process_candle).Start()
def _process_candle(self, candle, ema_value, atr_value):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
stop_dist = float(atr_value) * float(self.AtrMultiplier)
is_bullish = close > float(ema_value)
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
# Trailing stop check
if self.Position > 0:
if close > self._best_price:
self._best_price = close
if self._best_price - close > stop_dist:
self.SellMarket()
self._entry_price = 0.0
self._best_price = 0.0
self._candles_since_trade = 0
return
elif self.Position < 0:
if close < self._best_price:
self._best_price = close
if close - self._best_price > stop_dist:
self.BuyMarket()
self._entry_price = 0.0
self._best_price = 0.0
self._candles_since_trade = 0
return
# Entry signals
if self._has_prev_signal and is_bullish != self._was_bullish and self._candles_since_trade >= self.SignalCooldownCandles:
if is_bullish and self.Position <= 0:
self.BuyMarket()
self._entry_price = close
self._best_price = close
self._candles_since_trade = 0
elif not is_bullish and self.Position >= 0:
self.SellMarket()
self._entry_price = close
self._best_price = close
self._candles_since_trade = 0
self._was_bullish = is_bullish
self._has_prev_signal = True
def CreateClone(self):
return nnfx_auto_trade_strategy()