Esta estrategia porta el experto Peceptron_Mult.mq5 a la API de alto nivel de StockSharp. Monitorea simultáneamente hasta tres mercados independientes y aplica el oscilador Acceleration/Deceleration (AC) dentro de un modelo de perceptrón. Cada mercado recibe su propia configuración de pesos, dimensionamiento de posición y salidas de protección, de modo que se preserve el comportamiento del asesor original multi-símbolo.
Lógica de Trading
Para cada instrumento configurado, la estrategia se suscribe al mismo tipo de vela (predeterminado: 1 minuto).
En cada vela terminada calcula el oscilador Acceleration/Deceleration de Bill Williams:
Calcular el Awesome Oscillator (AO) a partir de los máximos y mínimos de la vela (medias móviles de precio mediano 5/34).
Restar una media móvil simple de 5 períodos de AO del valor actual de AO.
Se mantiene un buffer circular con los últimos 22 valores de AC por instrumento.
La señal del perceptrón se forma a partir de cuatro valores retardados de AC usando pesos (w - 100) exactamente como en el código MQL:
AC[0], AC[7], AC[14], AC[21] corresponden a la lectura más reciente y tres históricas.
Reglas de entrada:
Suma positiva ⇒ abrir posición larga si no existe posición en ese instrumento.
Suma negativa ⇒ abrir posición corta si el instrumento está plano.
Reglas de salida:
Las distancias de stop-loss y take-profit se expresan en puntos. Se convierten a desplazamientos de precio absolutos usando el paso de precio del instrumento.
Las salidas de protección se evalúan en cada vela terminada. Una operación larga se cierra cuando el mínimo de la vela toca el stop o el máximo alcanza el objetivo de ganancia; los cortos usan la lógica espejada.
Las posiciones son mutuamente exclusivas por instrumento. La estrategia ignora nuevas señales mientras la exposición permanece abierta, replicando el comportamiento del asesor original.
Parámetros
Parámetro
Descripción
FirstSecurity, SecondSecurity, ThirdSecurity
Instrumentos procesados por el perceptrón. Dejar en null para deshabilitar un slot.
Distancia de take-profit en puntos de precio para cada instrumento. Establecer en 0 para deshabilitar.
CandleType
Serie de velas compartida por todos los instrumentos.
Notas de Implementación
La estrategia utiliza los indicadores AwesomeOscillator y SimpleMovingAverage de StockSharp para reconstruir el oscilador AC, evitando recálculos manuales.
Los buffers circulares se usan solo para emular las entradas del perceptrón de la implementación MQL (índices 0, 7, 14, 21).
Los niveles de protección se aplican sin registrar órdenes stop separadas: la estrategia monitorea los extremos de las velas y cierra posiciones con órdenes a mercado cuando se violan los niveles, reflejando el comportamiento del EA original en nuevos ticks.
Cada instrumento mantiene un estado de indicador independiente, volumen de orden y configuraciones de riesgo, coincidiendo con la estructura de tres símbolos del asesor fuente.
Consejos de Uso
Asignar hasta tres instrumentos en el panel de parámetros. Cualquier slot no utilizado puede quedar como null.
Ajustar los stops y objetivos basados en puntos para que coincidan con el tamaño de tick de los instrumentos seleccionados.
Ajustar los pesos del perceptrón para enfatizar rezagos específicos del oscilador AC si se requiere optimización.
Dado que todos los instrumentos comparten el mismo tipo de vela, asegurarse de que los datos históricos estén disponibles para cada instrumento configurado.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Perceptron strategy that uses weighted moving average crossover signals
/// to determine trade direction. Simplified from multi-symbol to single security.
/// </summary>
public class PerceptronMultStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public PerceptronMultStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 200)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 100)
.SetNotNegative()
.SetDisplay("Stop Loss", "Stop-loss distance in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 200)
.SetNotNegative()
.SetDisplay("Take Profit", "Take-profit distance in price steps", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fast = null;
_slow = null;
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_fast.IsFormed || !_slow.IsFormed)
{
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
// Entry: fast crosses slow
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
}
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
}
_prevFast = fastValue;
_prevSlow = slowValue;
}
}
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
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class perceptron_mult_strategy(Strategy):
def __init__(self):
super(perceptron_mult_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 50).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 200).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._sl_points = self.Param("StopLossPoints", 100).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._tp_points = self.Param("TakeProfitPoints", 200).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle timeframe", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(perceptron_mult_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
def OnStarted2(self, time):
super(perceptron_mult_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
def _get_step(self):
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
return float(self.Security.PriceStep)
return 1.0
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = candle.ClosePrice
step = self._get_step()
if self.Position > 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close <= self._entry_price - self._sl_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close >= self._entry_price + self._tp_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close >= self._entry_price + self._sl_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close <= self._entry_price - self._tp_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return perceptron_mult_strategy()