Estrategia de Inteligencia Artificial Perceptron
Esta estrategia utiliza los valores del Accelerator Oscillator (AC) como entradas de un perceptrón lineal simple. Cuatro lecturas de AC separadas siete barras se ponderan mediante coeficientes definidos por el usuario. Una salida positiva del perceptrón abre una posición larga, y una salida negativa abre una posición corta.
La estrategia siempre aplica un stop-loss. Si aparece una señal opuesta después de que el beneficio supere el doble del stop-loss, la posición se invierte con volumen aumentado. De lo contrario, el stop-loss se mueve al punto de equilibrio.
Detalles
- Criterios de entrada:
- Largo: Salida del perceptrón > 0.
- Corto: Salida del perceptrón < 0.
- Largo/Corto: Ambos.
- Criterios de salida:
- Señal opuesta con beneficio > 2 * StopLoss → reversión.
- Señal opuesta con menor beneficio → stop movido a la entrada.
- Stop-loss alcanzado.
- Stops: Stop-loss fijo en puntos.
- Filtros: Ninguno.
Parámetros
StopLoss– distancia del stop-loss en puntos (por defecto 850).Shift– desplazamiento de barra para los valores del indicador (por defecto 1).X1,X2,X3,X4– pesos del perceptrón.CandleType– marco temporal de velas.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Perceptron strategy driven by four Accelerator Oscillator samples spaced seven bars apart.
/// </summary>
public class ArtificialIntelligencePerceptronStrategy : Strategy
{
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<int> _shift;
private readonly StrategyParam<decimal> _x1;
private readonly StrategyParam<decimal> _x2;
private readonly StrategyParam<decimal> _x3;
private readonly StrategyParam<decimal> _x4;
private readonly StrategyParam<DataType> _candleType;
private readonly List<decimal> _median = [];
private readonly List<decimal> _ao = [];
private readonly List<decimal> _ac = [];
private decimal _entryPrice;
private decimal? _stopPrice;
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public int Shift { get => _shift.Value; set => _shift.Value = value; }
public decimal X1 { get => _x1.Value; set => _x1.Value = value; }
public decimal X2 { get => _x2.Value; set => _x2.Value = value; }
public decimal X3 { get => _x3.Value; set => _x3.Value = value; }
public decimal X4 { get => _x4.Value; set => _x4.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public ArtificialIntelligencePerceptronStrategy()
{
_stopLoss = Param(nameof(StopLoss), 850m).SetGreaterThanZero()
.SetDisplay("Stop Loss", "Stop distance in price steps.", "Risk");
_shift = Param(nameof(Shift), 1).SetNotNegative()
.SetDisplay("Shift", "Latest AC sample shift.", "Perceptron");
_x1 = Param(nameof(X1), 1m).SetDisplay("X1", "Weight for the newest AC sample.", "Perceptron");
_x2 = Param(nameof(X2), 1m).SetDisplay("X2", "Weight for AC sample 7 bars older.", "Perceptron");
_x3 = Param(nameof(X3), 1m).SetDisplay("X3", "Weight for AC sample 14 bars older.", "Perceptron");
_x4 = Param(nameof(X4), 1m).SetDisplay("X4", "Weight for AC sample 21 bars older.", "Perceptron");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe.", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_median.Clear();
_ao.Clear();
_ac.Clear();
_entryPrice = 0m;
_stopPrice = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var median = (candle.HighPrice + candle.LowPrice) / 2m;
_median.Add(median);
if (_median.Count < 34)
return;
var ao = AverageTail(_median, 5) - AverageTail(_median, 34);
_ao.Add(ao);
if (_ao.Count < 5)
return;
var ac = ao - AverageTail(_ao, 5);
_ac.Add(ac);
if (ApplyStop(candle))
return;
var newest = _ac.Count - 1 - Shift;
if (newest - 21 < 0)
return;
var output =
X1 * _ac[newest] +
X2 * _ac[newest - 7] +
X3 * _ac[newest - 14] +
X4 * _ac[newest - 21];
var signal = output > 0m ? 1 : output < 0m ? -1 : 0;
if (signal == 0)
return;
var step = Security?.PriceStep ?? 1m;
if (step <= 0m)
step = 1m;
var stopDistance = StopLoss * step;
if (Position == 0)
{
Enter(signal, Volume, candle.ClosePrice, stopDistance);
return;
}
var currentDirection = Position > 0 ? 1 : -1;
if (signal == currentDirection)
return;
var profitDistance = currentDirection > 0
? candle.ClosePrice - _entryPrice
: _entryPrice - candle.ClosePrice;
if (profitDistance > stopDistance * 2m)
{
// Reverse and increase the new exposure to twice the base volume.
var orderVolume = Math.Abs(Position) + Volume * 2m;
if (signal > 0)
BuyMarket(orderVolume);
else
SellMarket(orderVolume);
_entryPrice = candle.ClosePrice;
_stopPrice = signal > 0 ? _entryPrice - stopDistance : _entryPrice + stopDistance;
}
else
{
// Opposite signal without enough profit: protect the current trade at break-even.
_stopPrice = _entryPrice;
}
}
private bool ApplyStop(ICandleMessage candle)
{
if (Position > 0 && _stopPrice is decimal longStop && candle.LowPrice <= longStop)
{
SellMarket(Math.Abs(Position));
_entryPrice = 0m;
_stopPrice = null;
return true;
}
else if (Position < 0 && _stopPrice is decimal shortStop && candle.HighPrice >= shortStop)
{
BuyMarket(Math.Abs(Position));
_entryPrice = 0m;
_stopPrice = null;
return true;
}
return false;
}
private void Enter(int signal, decimal volume, decimal price, decimal stopDistance)
{
if (signal > 0)
BuyMarket(volume);
else
SellMarket(volume);
_entryPrice = price;
_stopPrice = signal > 0 ? price - stopDistance : price + stopDistance;
}
private static decimal AverageTail(List<decimal> values, int count)
{
var start = values.Count - count;
var sum = 0m;
for (var i = start; i < values.Count; i++)
sum += values[i];
return sum / count;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class artificial_intelligence_perceptron_strategy(Strategy):
def __init__(self):
super(artificial_intelligence_perceptron_strategy, self).__init__()
self._stop_loss = self.Param("StopLoss", 850.0).SetGreaterThanZero()
self._shift = self.Param("Shift", 1).SetNotNegative()
self._x1 = self.Param("X1", 1.0)
self._x2 = self.Param("X2", 1.0)
self._x3 = self.Param("X3", 1.0)
self._x4 = self.Param("X4", 1.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._median = []
self._ao = []
self._ac = []
self._entry_price = 0.0
self._stop_price = None
@property
def CandleType(self):
return self._candle_type.Value
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnReseted(self):
super(artificial_intelligence_perceptron_strategy, self).OnReseted()
self._median = []
self._ao = []
self._ac = []
self._entry_price = 0.0
self._stop_price = None
def OnStarted2(self, time):
super(artificial_intelligence_perceptron_strategy, self).OnStarted2(time)
self.SubscribeCandles(self.CandleType).Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
median = (float(candle.HighPrice) + float(candle.LowPrice)) / 2.0
self._median.append(median)
if len(self._median) < 34:
return
ao = self._avg_tail(self._median, 5) - self._avg_tail(self._median, 34)
self._ao.append(ao)
if len(self._ao) < 5:
return
ac = ao - self._avg_tail(self._ao, 5)
self._ac.append(ac)
if self._apply_stop(candle):
return
newest = len(self._ac) - 1 - int(self._shift.Value)
if newest - 21 < 0:
return
output = (
float(self._x1.Value) * self._ac[newest] +
float(self._x2.Value) * self._ac[newest - 7] +
float(self._x3.Value) * self._ac[newest - 14] +
float(self._x4.Value) * self._ac[newest - 21]
)
signal = 1 if output > 0 else (-1 if output < 0 else 0)
if signal == 0:
return
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if step <= 0:
step = 1.0
stop_distance = float(self._stop_loss.Value) * step
close = float(candle.ClosePrice)
if self.Position == 0:
self._enter(signal, float(self.Volume), close, stop_distance)
return
current_direction = 1 if self.Position > 0 else -1
if signal == current_direction:
return
profit_distance = close - self._entry_price if current_direction > 0 else self._entry_price - close
if profit_distance > stop_distance * 2.0:
order_volume = abs(float(self.Position)) + float(self.Volume) * 2.0
if signal > 0:
self.BuyMarket(order_volume)
else:
self.SellMarket(order_volume)
self._entry_price = close
self._stop_price = close - stop_distance if signal > 0 else close + stop_distance
else:
self._stop_price = self._entry_price
def _apply_stop(self, candle):
if self.Position > 0 and self._stop_price is not None and float(candle.LowPrice) <= self._stop_price:
self.SellMarket(Math.Abs(self.Position))
self._entry_price = 0.0
self._stop_price = None
return True
elif self.Position < 0 and self._stop_price is not None and float(candle.HighPrice) >= self._stop_price:
self.BuyMarket(Math.Abs(self.Position))
self._entry_price = 0.0
self._stop_price = None
return True
return False
def _enter(self, signal, volume, price, stop_distance):
if signal > 0:
self.BuyMarket(volume)
else:
self.SellMarket(volume)
self._entry_price = price
self._stop_price = price - stop_distance if signal > 0 else price + stop_distance
@staticmethod
def _avg_tail(values, count):
return sum(values[-count:]) / float(count)
def CreateClone(self):
return artificial_intelligence_perceptron_strategy()