Port of the "AK47_A1" MetaTrader expert. The strategy combines Bill Williams' Alligator, DeMarker oscillator, Williams %R filter and fractal triggers to trade breakouts only when the market leaves ranging conditions.
Details
Data: Price candles defined by CandleType.
Indicators:
Alligator jaw/teeth/lips are 13/8/5 period SMMAs shifted by 8/5/3 bars and fed with median price.
DeMarker with period 13 must be on the long side of 0.5 for buys and below 0.5 for sells.
Williams %R with period 14 is normalized to [0;1]; the previous bar must stay between 0.25 and 0.75 to avoid overbought/oversold states.
Fractals are detected from the last 5 highs and lows and remain valid for three bars.
Entry Criteria:
All three Alligator lines must be separated by at least SpanGatorPoints points (in both bullish and bearish alignment).
Long: The most recent lower fractal is fresh, DeMarker ≥ 0.5 and the Williams %R filter approves the trade.
Short: The most recent upper fractal is fresh, DeMarker ≤ 0.5 and the Williams %R filter approves the trade.
Opposite positions are flattened before opening a new one.
Exit Criteria:
Hard stop-loss and take-profit defined by StopLossPoints and TakeProfitPoints (converted to absolute prices via the instrument step).
Optional trailing stop that trails the close by TrailingStopPoints points once the position moves in favor.
When a reverse signal appears the current position is closed before opening the new one.
Defaults:
SpanGatorPoints = 0.5
TakeProfitPoints = 100
StopLossPoints = 0 (disabled)
TrailingStopPoints = 50
CandleType = 1 hour candles
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// AK47 A1 strategy - Alligator-like triple SMA crossover.
/// Buys when fast SMA crosses above medium and medium is above slow.
/// Sells when fast SMA crosses below medium and medium is below slow.
/// </summary>
public class AK47A1Strategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _medPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevFast;
private decimal _prevMed;
private bool _hasPrev;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int MedPeriod { get => _medPeriod.Value; set => _medPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public AK47A1Strategy()
{
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetDisplay("Fast SMA", "Lips period", "Indicators");
_medPeriod = Param(nameof(MedPeriod), 8)
.SetDisplay("Medium SMA", "Teeth period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 13)
.SetDisplay("Slow SMA", "Jaw period", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
protected override void OnReseted() { base.OnReseted(); _prevFast = 0m; _prevMed = 0m; _hasPrev = false; }
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var fast = new SimpleMovingAverage { Length = FastPeriod };
var med = new SimpleMovingAverage { Length = MedPeriod };
var slow = new SimpleMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, med, slow, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal med, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevFast = fast;
_prevMed = med;
_hasPrev = true;
return;
}
if (_prevFast <= _prevMed && fast > med && med > slow && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (_prevFast >= _prevMed && fast < med && med < slow && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevFast = fast;
_prevMed = med;
}
}
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
class ak47_a1_strategy(Strategy):
def __init__(self):
super(ak47_a1_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 5).SetDisplay("Fast SMA", "Lips period", "Indicators")
self._med_period = self.Param("MedPeriod", 8).SetDisplay("Medium SMA", "Teeth period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 13).SetDisplay("Slow SMA", "Jaw period", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))).SetDisplay("Candle Type", "Candle timeframe", "General")
self._prev_fast = 0.0; self._prev_med = 0.0; self._has_prev = False
@property
def fast_period(self): return self._fast_period.Value
@property
def med_period(self): return self._med_period.Value
@property
def slow_period(self): return self._slow_period.Value
@property
def candle_type(self): return self._candle_type.Value
def OnReseted(self):
super(ak47_a1_strategy, self).OnReseted()
self._prev_fast = 0.0; self._prev_med = 0.0; self._has_prev = False
def OnStarted2(self, time):
super(ak47_a1_strategy, self).OnStarted2(time)
self._has_prev = False
fast = SimpleMovingAverage(); fast.Length = self.fast_period
med = SimpleMovingAverage(); med.Length = self.med_period
slow = SimpleMovingAverage(); slow.Length = self.slow_period
sub = self.SubscribeCandles(self.candle_type)
sub.Bind(fast, med, slow, self.process_candle).Start()
def process_candle(self, candle, fast, med, slow):
if candle.State != CandleStates.Finished: return
f = float(fast); m = float(med); s = float(slow)
if not self._has_prev: self._prev_fast = f; self._prev_med = m; self._has_prev = True; return
if self._prev_fast <= self._prev_med and f > m and m > s and self.Position <= 0:
if self.Position < 0: self.BuyMarket()
self.BuyMarket()
elif self._prev_fast >= self._prev_med and f < m and m < s and self.Position >= 0:
if self.Position > 0: self.SellMarket()
self.SellMarket()
self._prev_fast = f; self._prev_med = m
def CreateClone(self): return ak47_a1_strategy()