Auf GitHub ansehen

Perceptron AC Strategy

This strategy implements a simple perceptron on top of the Accelerator Oscillator (AC). The AC value of the current candle and of three past offsets are multiplied by adjustable weights. The sum of these products forms the perceptron output that determines the trade direction.

How It Works

  1. Calculate the Accelerator Oscillator (AC) from the difference between the Awesome Oscillator and its 5-period SMA.
  2. Store the latest 22 AC values to access offsets of 0, 7, 14 and 21 bars.
  3. Compute the perceptron output: P = (X1-100)*AC[0] + (X2-100)*AC[7] + (X3-100)*AC[14] + (X4-100)*AC[21].
  4. If P > 0 open or maintain a long position; if P < 0 open or maintain a short position.
  5. When a position gains at least StopLoss points beyond the initial stop level:
    • If the perceptron flips direction, reverse the position.
    • Otherwise trail the stop to the new price minus/plus StopLoss.

Parameters

  • X1 – weight for the current AC value (default 288).
  • X2 – weight for AC 7 bars ago (default 216).
  • X3 – weight for AC 14 bars ago (default 144).
  • X4 – weight for AC 21 bars ago (default 72).
  • Stop Loss – trailing and reversal threshold in price units (default 300).
  • Volume – order volume (default 1).
  • Candle Type – candle series to subscribe to (default 5-minute).

Trading Rules

  • Enter long when P > 0 and no position is open.
  • Enter short when P < 0 and no position is open.
  • For open positions, move the stop loss after the price moves in profit by Stop Loss * 2.
  • Reverse the position if the perceptron output changes sign at that time.

Original Version

Converted from the MQL4 script auto_m5.mq4 located in MQL/11102.

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-based strategy using EMA crossover.
/// </summary>
public class PerceptronAcStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public PerceptronAcStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA period", "Perceptron");
		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA period", "Perceptron");
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0;
		_prevSlow = 0;
		_hasPrev = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

		SubscribeCandles(CandleType)
			.Bind(fast, slow, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
	{
		if (candle.State != CandleStates.Finished) return;

		if (!_hasPrev)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			_hasPrev = true;
			return;
		}

		var crossUp = _prevFast <= _prevSlow && fastVal > slowVal;
		var crossDown = _prevFast >= _prevSlow && fastVal < slowVal;

		if (crossUp && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
		}
		else if (crossDown && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
		}

		_prevFast = fastVal;
		_prevSlow = slowVal;
	}
}