Artificial Intelligence Perceptron 策略
该策略将 Accelerator Oscillator (AC) 指标的值作为线性感知器的输入。以七根K线为间隔获取四个AC值,并乘以用户设定的权重。感知器输出为正时开多,为负时开空。
策略始终使用止损。如果出现反向信号且盈利超过止损的两倍,则在增加手数的同时反手;否则将止损移动到盈亏平衡点。
细节
- 入场条件:
- 多头:感知器输出 > 0。
- 空头:感知器输出 < 0。
- 方向:双向。
- 出场条件:
- 盈利 > 2 * StopLoss 时的反向信号 → 反手。
- 盈利较小的反向信号 → 止损移到入场价。
- 触发止损。
- 止损:按点数固定止损。
- 过滤器:无。
参数
StopLoss– 止损点数(默认 850)。Shift– 指标取值的K线偏移(默认 1)。X1,X2,X3,X4– 感知器权重。CandleType– K线周期。
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()