Williams Alligator ATR
Правила торговли
Все три линии Alligator используют сглаженную медианную цену (high+low)/2. Параметры Length и Shift задают сглаживание и задержку в завершённых свечах. Teeth вычисляется и должен сформироваться, но дополнительного фильтра входа не задаёт. После формирования всех линий и ATR Уайлдера переход Lips−Jaw из <=0 в >0 открывает лонг Volume из нуля; переход из >=0 в <0 закрывает весь фактический лонг. Шорт не открывается. На входе фиксируется расстояние ATR×AtrMultiplier для локального рыночного native-стопа от фактического исполнения. Bid/ask позволяют исполнить его между свечами. Задержки, тейка и перемещения стопа новым ATR нет.
Параметры
| Параметр | По умолчанию |
|---|---|
CandleType |
TimeSpan.FromMinutes(30).TimeFrame() |
JawLength |
13 |
TeethLength |
8 |
LipsLength |
5 |
JawShift |
8 |
TeethShift |
5 |
LipsShift |
3 |
AtrPeriod |
14 |
AtrMultiplier |
2 |
Проверка
Оба языка проверяются на имеющемся архиве BTC/TON: независимые формулы, стороны и объёмы заявок, реальные исполнения, позиции и выходы. Датированные ценовые/факторные и календарные данные проверяют механику; перенос дат OHLC/объёмов не является многолетней рыночной историей. Две корзины рангов, TopN=1 и SMA=2 — явные профили для малого универсума. Исходные длинные периоды и defaults проверяются отдельно. Доходность не заявляется.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>Long-only shifted median-price Alligator crosses with an entry-frozen native ATR stop.</summary>
public class WilliamsAlligatorAtrStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _jawLength;
private readonly StrategyParam<int> _teethLength;
private readonly StrategyParam<int> _lipsLength;
private readonly StrategyParam<int> _jawShift;
private readonly StrategyParam<int> _teethShift;
private readonly StrategyParam<int> _lipsShift;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrMultiplier;
private Order _pending;
private AlligatorLine _jaw;
private AlligatorLine _teeth;
private AlligatorLine _lips;
private AverageTrueRange _atr;
private decimal? _previousSpread;
/// <summary>Finished signal candle type.</summary>
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
/// <summary>Jaw smoothed median-price window.</summary>
public int JawLength { get => _jawLength.Value; set => _jawLength.Value = value; }
/// <summary>Teeth smoothed median-price window.</summary>
public int TeethLength { get => _teethLength.Value; set => _teethLength.Value = value; }
/// <summary>Lips smoothed median-price window.</summary>
public int LipsLength { get => _lipsLength.Value; set => _lipsLength.Value = value; }
/// <summary>Completed bars delaying the Jaw line.</summary>
public int JawShift { get => _jawShift.Value; set => _jawShift.Value = value; }
/// <summary>Completed bars delaying the Teeth line.</summary>
public int TeethShift { get => _teethShift.Value; set => _teethShift.Value = value; }
/// <summary>Completed bars delaying the Lips line.</summary>
public int LipsShift { get => _lipsShift.Value; set => _lipsShift.Value = value; }
/// <summary>Wilder true-range window.</summary>
public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
/// <summary>Entry-frozen ATR stop multiplier.</summary>
public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
/// <summary>Initialize the strategy parameters.</summary>
public WilliamsAlligatorAtrStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("CandleType", "Finished signal candle type.", "Parameters");
_jawLength = Param(nameof(JawLength), 13).SetRange(1, int.MaxValue)
.SetDisplay("JawLength", "Jaw smoothed median-price window.", "Parameters");
_teethLength = Param(nameof(TeethLength), 8).SetRange(1, int.MaxValue)
.SetDisplay("TeethLength", "Teeth smoothed median-price window.", "Parameters");
_lipsLength = Param(nameof(LipsLength), 5).SetRange(1, int.MaxValue)
.SetDisplay("LipsLength", "Lips smoothed median-price window.", "Parameters");
_jawShift = Param(nameof(JawShift), 8).SetRange(1, int.MaxValue)
.SetDisplay("JawShift", "Completed bars delaying the Jaw line.", "Parameters");
_teethShift = Param(nameof(TeethShift), 5).SetRange(1, int.MaxValue)
.SetDisplay("TeethShift", "Completed bars delaying the Teeth line.", "Parameters");
_lipsShift = Param(nameof(LipsShift), 3).SetRange(1, int.MaxValue)
.SetDisplay("LipsShift", "Completed bars delaying the Lips line.", "Parameters");
_atrPeriod = Param(nameof(AtrPeriod), 14).SetRange(1, int.MaxValue)
.SetDisplay("AtrPeriod", "Wilder true-range window.", "Parameters");
_atrMultiplier = Param(nameof(AtrMultiplier), 2m).SetRange(0.000001m, decimal.MaxValue)
.SetDisplay("AtrMultiplier", "Entry-frozen ATR stop multiplier.", "Parameters");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_pending = null;
_jaw = null;
_teeth = null;
_lips = null;
_atr = null;
_previousSpread = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
foreach (var field in new[] { Level1Fields.BestBidPrice, Level1Fields.BestAskPrice })
{
var quote = new Subscription(DataType.Level1, Security);
quote.MarketData.BuildField = field;
SubscribeLevel1(quote).Start();
}
_jaw = new AlligatorLine { Length = JawLength, Shift = JawShift };
_teeth = new AlligatorLine { Length = TeethLength, Shift = TeethShift };
_lips = new AlligatorLine { Length = LipsLength, Shift = LipsShift };
_atr = new AverageTrueRange { Length = AtrPeriod };
SubscribeCandles(CandleType).Bind(ProcessCandle).Start();
}
private bool IsPending => _pending is not null && _pending.State is not (OrderStates.Done or OrderStates.Failed);
private void Submit(Sides side, decimal quantity, string comment)
{
_pending = CreateOrder(side, 0m, quantity);
_pending.Type = OrderTypes.Market;
_pending.Comment = comment;
RegisterOrder(_pending);
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished) return;
var jaw = _jaw.Process(candle);
var teeth = _teeth.Process(candle);
var lips = _lips.Process(candle);
var atr = _atr.Process(candle);
if (!_jaw.IsFormed || !_teeth.IsFormed || !_lips.IsFormed || !_atr.IsFormed
|| jaw.IsEmpty || teeth.IsEmpty || lips.IsEmpty || atr.IsEmpty) return;
var spread = lips.ToDecimal() - jaw.ToDecimal();
var previous = _previousSpread;
_previousSpread = spread;
if (previous is null || IsPending || !IsFormedAndOnlineAndAllowTrading()) return;
if (previous >= 0m && spread < 0m && Position > 0m)
Submit(Sides.Sell, Position, "0512CrossExit");
else if (previous <= 0m && spread > 0m && Position == 0m && atr.ToDecimal() > 0m)
{
StartProtection(new Unit(), new Unit(atr.ToDecimal() * AtrMultiplier, UnitTypes.Absolute), useMarketOrders: true, isLocalStop: true);
Submit(Sides.Buy, Volume, "0512Entry");
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.BusinessEntities")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import DateTime, Decimal, Math, TimeSpan, InvalidOperationException
from System.Globalization import CultureInfo, DateTimeStyles
from System.IO import File
from StockSharp.Algo.Indicators import ExponentialMovingAverage, SimpleMovingAverage, AverageTrueRange, AlligatorLine, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
from StockSharp.BusinessEntities import Subscription
from StockSharp.Messages import Level1Fields, ITickTradeMessage, CandleStates, DataType, OrderStates, OrderTypes, Sides, Unit, UnitTypes
class williams_alligator_atr_strategy(Strategy):
"""Long-only shifted median-price Alligator crosses with an entry-frozen native ATR stop."""
def __init__(self):
super(williams_alligator_atr_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("CandleType", "Finished signal candle type.", "Parameters")
self._jaw_length = self.Param("JawLength", 13).SetRange(1, 2147483647) \
.SetDisplay("JawLength", "Jaw smoothed median-price window.", "Parameters")
self._teeth_length = self.Param("TeethLength", 8).SetRange(1, 2147483647) \
.SetDisplay("TeethLength", "Teeth smoothed median-price window.", "Parameters")
self._lips_length = self.Param("LipsLength", 5).SetRange(1, 2147483647) \
.SetDisplay("LipsLength", "Lips smoothed median-price window.", "Parameters")
self._jaw_shift = self.Param("JawShift", 8).SetRange(1, 2147483647) \
.SetDisplay("JawShift", "Completed bars delaying the Jaw line.", "Parameters")
self._teeth_shift = self.Param("TeethShift", 5).SetRange(1, 2147483647) \
.SetDisplay("TeethShift", "Completed bars delaying the Teeth line.", "Parameters")
self._lips_shift = self.Param("LipsShift", 3).SetRange(1, 2147483647) \
.SetDisplay("LipsShift", "Completed bars delaying the Lips line.", "Parameters")
self._atr_period = self.Param("AtrPeriod", 14).SetRange(1, 2147483647) \
.SetDisplay("AtrPeriod", "Wilder true-range window.", "Parameters")
self._atr_multiplier = self.Param("AtrMultiplier", Decimal(2)).SetRange(Decimal(0.000001), Decimal.MaxValue) \
.SetDisplay("AtrMultiplier", "Entry-frozen ATR stop multiplier.", "Parameters")
self._clear_state()
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def JawLength(self):
return self._jaw_length.Value
@JawLength.setter
def JawLength(self, value):
self._jaw_length.Value = value
@property
def TeethLength(self):
return self._teeth_length.Value
@TeethLength.setter
def TeethLength(self, value):
self._teeth_length.Value = value
@property
def LipsLength(self):
return self._lips_length.Value
@LipsLength.setter
def LipsLength(self, value):
self._lips_length.Value = value
@property
def JawShift(self):
return self._jaw_shift.Value
@JawShift.setter
def JawShift(self, value):
self._jaw_shift.Value = value
@property
def TeethShift(self):
return self._teeth_shift.Value
@TeethShift.setter
def TeethShift(self, value):
self._teeth_shift.Value = value
@property
def LipsShift(self):
return self._lips_shift.Value
@LipsShift.setter
def LipsShift(self, value):
self._lips_shift.Value = value
@property
def AtrPeriod(self):
return self._atr_period.Value
@AtrPeriod.setter
def AtrPeriod(self, value):
self._atr_period.Value = value
@property
def AtrMultiplier(self):
return self._atr_multiplier.Value
@AtrMultiplier.setter
def AtrMultiplier(self, value):
self._atr_multiplier.Value = value
def _clear_state(self):
self._pending = None
self._jaw = None
self._teeth = None
self._lips = None
self._atr = None
self._previous_spread = None
def OnReseted(self):
super(williams_alligator_atr_strategy, self).OnReseted()
self._clear_state()
def GetWorkingSecurities(self):
return [(self.Security, self.CandleType)]
def OnStarted2(self, time):
super(williams_alligator_atr_strategy, self).OnStarted2(time)
for field in (Level1Fields.BestBidPrice, Level1Fields.BestAskPrice):
quote = Subscription(DataType.Level1, self.Security)
quote.MarketData.BuildField = field
self.SubscribeLevel1(quote).Start()
self._jaw = AlligatorLine()
self._jaw.Length = self.JawLength
self._jaw.Shift = self.JawShift
self._teeth = AlligatorLine()
self._teeth.Length = self.TeethLength
self._teeth.Shift = self.TeethShift
self._lips = AlligatorLine()
self._lips.Length = self.LipsLength
self._lips.Shift = self.LipsShift
self._atr = AverageTrueRange()
self._atr.Length = self.AtrPeriod
self.SubscribeCandles(self.CandleType).Bind(self._process_candle).Start()
def _is_pending(self):
return self._pending is not None and self._pending.State not in (OrderStates.Done, OrderStates.Failed)
def _submit(self, side, quantity, comment):
self._pending = self.CreateOrder(side, Decimal(0), quantity)
self._pending.Type = OrderTypes.Market
self._pending.Comment = comment
self.RegisterOrder(self._pending)
@staticmethod
def _process(indicator, candle):
value = CandleIndicatorValue(indicator, candle)
value.IsFinal = True
result = indicator.Process(value)
return None if result.IsEmpty else result.GetValue[Decimal](None)
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
jaw = self._process(self._jaw, candle)
teeth = self._process(self._teeth, candle)
lips = self._process(self._lips, candle)
atr = self._process(self._atr, candle)
if not self._jaw.IsFormed or not self._teeth.IsFormed or not self._lips.IsFormed or not self._atr.IsFormed or jaw is None or teeth is None or lips is None or atr is None:
return
spread = lips - jaw
previous = self._previous_spread
self._previous_spread = spread
if previous is None or self._is_pending() or not self.IsFormedAndOnlineAndAllowTrading():
return
if previous >= 0 and spread < 0 and self.Position > 0:
self._submit(Sides.Sell, self.Position, "0512CrossExit")
elif previous <= 0 and spread > 0 and self.Position == 0 and atr > 0:
self.StartProtection(Unit(), Unit(atr * self.AtrMultiplier, UnitTypes.Absolute), useMarketOrders=True, isLocalStop=True)
self._submit(Sides.Buy, self.Volume, "0512Entry")
def CreateClone(self):
return williams_alligator_atr_strategy()