Artificial Intelligence Accelerator Strategy
This strategy implements a simple perceptron model on top of Bill Williams' Acceleration/Deceleration Oscillator (AC). Four oscillator readings are sampled at lags of 0, 7, 14 and 21 bars and multiplied by adjustable weights. The weighted sum acts as a decision signal: positive values imply bullish momentum and negative values imply bearish momentum. The strategy reverses its position whenever the signal changes sign and places a fixed stop-loss from the entry price.
The AC itself is derived from the Awesome Oscillator (AO) by subtracting a 5-period moving average from the AO. This makes the strategy sensitive to shifts in market acceleration.
Details
- Entry Criteria:
- Long: Perceptron signal > 0.
- Short: Perceptron signal < 0.
- Long/Short: Both sides; the strategy reverses if the signal flips.
- Exit Criteria:
- Stop-loss triggered from the entry price.
- Reverse when signal crosses zero.
- Stops: Yes, fixed stop-loss in price units.
- Default Values:
X1= 76X2= 47X3= 153X4= 135StopLoss= 8355CandleType= 1-minute candles
- Filters:
- Category: Trend following
- Direction: Both
- Indicators: AC (derived from AO)
- Stops: Yes
- Complexity: Moderate
- Timeframe: Short-term
- Neural networks: Perceptron
- Risk level: High
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Perceptron-based strategy using Acceleration/Deceleration values.
/// </summary>
public class ArtificialIntelligenceAcceleratorStrategy : Strategy
{
private readonly StrategyParam<int> _x1;
private readonly StrategyParam<int> _x2;
private readonly StrategyParam<int> _x3;
private readonly StrategyParam<int> _x4;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<DataType> _candleType;
private SimpleMovingAverage _aoFast;
private SimpleMovingAverage _aoSlow;
private SimpleMovingAverage _acMa;
private readonly decimal[] _acBuffer = new decimal[22];
private int _bufferCount;
private decimal _entryPrice;
private decimal? _prevSignal;
private int _barsSinceTrade;
/// <summary>
/// First weight of perceptron.
/// </summary>
public int X1 { get => _x1.Value; set => _x1.Value = value; }
/// <summary>
/// Second weight of perceptron.
/// </summary>
public int X2 { get => _x2.Value; set => _x2.Value = value; }
/// <summary>
/// Third weight of perceptron.
/// </summary>
public int X3 { get => _x3.Value; set => _x3.Value = value; }
/// <summary>
/// Fourth weight of perceptron.
/// </summary>
public int X4 { get => _x4.Value; set => _x4.Value = value; }
/// <summary>
/// Stop loss in price units.
/// </summary>
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
/// <summary>
/// Candle series type.
/// </summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>
/// Initializes a new instance of <see cref="ArtificialIntelligenceAcceleratorStrategy"/>.
/// </summary>
public ArtificialIntelligenceAcceleratorStrategy()
{
_x1 = Param(nameof(X1), 76)
.SetDisplay("X1", "Perceptron weight 1", "Parameters");
_x2 = Param(nameof(X2), 47)
.SetDisplay("X2", "Perceptron weight 2", "Parameters");
_x3 = Param(nameof(X3), 153)
.SetDisplay("X3", "Perceptron weight 3", "Parameters");
_x4 = Param(nameof(X4), 135)
.SetDisplay("X4", "Perceptron weight 4", "Parameters");
_stopLoss = Param(nameof(StopLoss), 8355m)
.SetDisplay("Stop Loss", "Stop loss in price units", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
Array.Clear(_acBuffer);
_bufferCount = 0;
_entryPrice = 0m;
_prevSignal = null;
_barsSinceTrade = 10;
_aoFast = null;
_aoSlow = null;
_acMa = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
Array.Clear(_acBuffer);
_bufferCount = 0;
_entryPrice = 0m;
_prevSignal = null;
_barsSinceTrade = 10;
_aoFast = new SimpleMovingAverage { Length = 5 };
_aoSlow = new SimpleMovingAverage { Length = 34 };
_acMa = new SimpleMovingAverage { Length = 5 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
_barsSinceTrade++;
// Calculate Accelerator Oscillator value.
var hl2 = (candle.HighPrice + candle.LowPrice) / 2m;
var t = candle.ServerTime;
var aoFastResult = _aoFast.Process(hl2, t, true);
var aoSlowResult = _aoSlow.Process(hl2, t, true);
if (!_aoFast.IsFormed || !_aoSlow.IsFormed)
return;
var ao = aoFastResult.ToDecimal() - aoSlowResult.ToDecimal();
var acMaResult = _acMa.Process(ao, t, true);
if (!_acMa.IsFormed)
return;
var ac = ao - acMaResult.ToDecimal();
for (var i = 21; i > 0; i--)
_acBuffer[i] = _acBuffer[i - 1];
_acBuffer[0] = ac;
if (_bufferCount < 22)
{
_bufferCount++;
return;
}
var signal = Perceptron();
var previousSignal = _prevSignal;
_prevSignal = signal;
if (previousSignal is null)
return;
if (_barsSinceTrade >= 5 && previousSignal <= 0m && signal > 0m && Position <= 0)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_barsSinceTrade = 0;
}
else if (_barsSinceTrade >= 5 && previousSignal >= 0m && signal < 0m && Position >= 0)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_barsSinceTrade = 0;
}
else if (Position > 0 && candle.ClosePrice <= _entryPrice - StopLoss)
{
SellMarket();
_barsSinceTrade = 0;
}
else if (Position < 0 && candle.ClosePrice >= _entryPrice + StopLoss)
{
BuyMarket();
_barsSinceTrade = 0;
}
}
private decimal Perceptron()
{
var w1 = X1 - 100m;
var w2 = X2 - 100m;
var w3 = X3 - 100m;
var w4 = X4 - 100m;
return w1 * _acBuffer[0] + w2 * _acBuffer[7] + w3 * _acBuffer[14] + w4 * _acBuffer[21];
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class artificial_intelligence_accelerator_strategy(Strategy):
def __init__(self):
super(artificial_intelligence_accelerator_strategy, self).__init__()
self._x1 = self.Param("X1", 76)
self._x2 = self.Param("X2", 47)
self._x3 = self.Param("X3", 153)
self._x4 = self.Param("X4", 135)
self._stop_loss = self.Param("StopLoss", 8355.0)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1)))
self._ac_buffer = [0.0] * 22
self._buffer_count = 0
self._entry_price = 0.0
self._prev_signal = None
self._bars_since_trade = 10
@property
def X1(self):
return self._x1.Value
@X1.setter
def X1(self, value):
self._x1.Value = value
@property
def X2(self):
return self._x2.Value
@X2.setter
def X2(self, value):
self._x2.Value = value
@property
def X3(self):
return self._x3.Value
@X3.setter
def X3(self, value):
self._x3.Value = value
@property
def X4(self):
return self._x4.Value
@X4.setter
def X4(self, value):
self._x4.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(artificial_intelligence_accelerator_strategy, self).OnStarted2(time)
self._ac_buffer = [0.0] * 22
self._buffer_count = 0
self._entry_price = 0.0
self._prev_signal = None
self._bars_since_trade = 10
self._ao_fast = SimpleMovingAverage()
self._ao_fast.Length = 5
self._ao_slow = SimpleMovingAverage()
self._ao_slow.Length = 34
self._ac_ma = SimpleMovingAverage()
self._ac_ma.Length = 5
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
self._bars_since_trade += 1
hl2 = (float(candle.HighPrice) + float(candle.LowPrice)) / 2.0
t = candle.OpenTime
ao_fast_result = process_float(self._ao_fast, hl2, t, True)
ao_slow_result = process_float(self._ao_slow, hl2, t, True)
if not self._ao_fast.IsFormed or not self._ao_slow.IsFormed:
return
ao = float(ao_fast_result) - float(ao_slow_result)
ac_ma_result = process_float(self._ac_ma, ao, t, True)
if not self._ac_ma.IsFormed:
return
ac = ao - float(ac_ma_result)
for i in range(21, 0, -1):
self._ac_buffer[i] = self._ac_buffer[i - 1]
self._ac_buffer[0] = ac
if self._buffer_count < 22:
self._buffer_count += 1
return
signal = self._perceptron()
previous_signal = self._prev_signal
self._prev_signal = signal
if previous_signal is None:
return
close = float(candle.ClosePrice)
if self._bars_since_trade >= 5 and previous_signal <= 0.0 and signal > 0.0 and self.Position <= 0:
self.BuyMarket()
self._entry_price = close
self._bars_since_trade = 0
elif self._bars_since_trade >= 5 and previous_signal >= 0.0 and signal < 0.0 and self.Position >= 0:
self.SellMarket()
self._entry_price = close
self._bars_since_trade = 0
elif self.Position > 0 and close <= self._entry_price - float(self.StopLoss):
self.SellMarket()
self._bars_since_trade = 0
elif self.Position < 0 and close >= self._entry_price + float(self.StopLoss):
self.BuyMarket()
self._bars_since_trade = 0
def _perceptron(self):
w1 = float(self.X1) - 100.0
w2 = float(self.X2) - 100.0
w3 = float(self.X3) - 100.0
w4 = float(self.X4) - 100.0
return w1 * self._ac_buffer[0] + w2 * self._ac_buffer[7] + w3 * self._ac_buffer[14] + w4 * self._ac_buffer[21]
def OnReseted(self):
super(artificial_intelligence_accelerator_strategy, self).OnReseted()
self._ac_buffer = [0.0] * 22
self._buffer_count = 0
self._entry_price = 0.0
self._prev_signal = None
self._bars_since_trade = 10
def CreateClone(self):
return artificial_intelligence_accelerator_strategy()