Live Alligator 策略
该策略利用动态配置的 Alligator 指标和多条 EMA 过滤器来捕捉趋势反转。
当 Alligator 线条改变方向且五条 EMA 确认趋势时开仓。
可选的交易时段过滤器限制在指定时间内入场。
当价格跌破或突破基于 TrailPeriod 的平滑移动平均线时平仓。
- 入场条件
- Lips 在 Jaw 之上、Teeth 在 Jaw 之下且前一根柱子的 Lips 位于 Jaw 下方时,在空头趋势后开多。
- Lips 在 Jaw 之下、Teeth 在 Jaw 之上且前一根柱子的 Lips 位于 Jaw 上方时,在多头趋势后开空。
- 基于收盘价、加权价、典型价、中位价和开盘价的五条 EMA 必须按趋势方向严格排列。
- 出场条件
- 价格穿越
TrailPeriod平滑移动平均线。 - 开仓时可选择设置止损。
- 价格穿越
- 使用的指标
- Alligator 三条线及其基于 SMMA 的跟踪止损。
- 不同价格类型上的 EMA。
参数可配置 Alligator 基准周期、EMA 确认周期、跟踪周期、止损和交易时间窗口。
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>
/// Alligator strategy using three smoothed moving averages (jaw, teeth, lips).
/// Buys when lips cross above jaw; sells when lips cross below jaw.
/// Uses a trailing SMA for exit.
/// </summary>
public class LiveAlligatorStrategy : Strategy
{
private readonly StrategyParam<int> _jawLength;
private readonly StrategyParam<int> _teethLength;
private readonly StrategyParam<int> _lipsLength;
private readonly StrategyParam<int> _trailLength;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevLips;
private decimal _prevJaw;
private decimal _prevTrail;
private bool _hasPrev;
public int JawLength { get => _jawLength.Value; set => _jawLength.Value = value; }
public int TeethLength { get => _teethLength.Value; set => _teethLength.Value = value; }
public int LipsLength { get => _lipsLength.Value; set => _lipsLength.Value = value; }
public int TrailLength { get => _trailLength.Value; set => _trailLength.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public LiveAlligatorStrategy()
{
_jawLength = Param(nameof(JawLength), 21)
.SetGreaterThanZero()
.SetDisplay("Jaw", "Alligator Jaw length", "Indicators");
_teethLength = Param(nameof(TeethLength), 13)
.SetGreaterThanZero()
.SetDisplay("Teeth", "Alligator Teeth length", "Indicators");
_lipsLength = Param(nameof(LipsLength), 8)
.SetGreaterThanZero()
.SetDisplay("Lips", "Alligator Lips length", "Indicators");
_trailLength = Param(nameof(TrailLength), 50)
.SetGreaterThanZero()
.SetDisplay("Trail", "Trailing SMA length", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_prevLips = 0;
_prevJaw = 0;
_prevTrail = 0;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var jaw = new SmoothedMovingAverage { Length = JawLength };
var teeth = new SmoothedMovingAverage { Length = TeethLength };
var lips = new SmoothedMovingAverage { Length = LipsLength };
var trail = new SimpleMovingAverage { Length = TrailLength };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(jaw, teeth, lips, trail, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal jawVal, decimal teethVal, decimal lipsVal, decimal trailVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!_hasPrev)
{
_prevLips = lipsVal;
_prevJaw = jawVal;
_prevTrail = trailVal;
_hasPrev = true;
return;
}
var close = candle.ClosePrice;
// Lips cross above jaw -> uptrend start
if (_prevLips <= _prevJaw && lipsVal > jawVal && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Lips cross below jaw -> downtrend start
else if (_prevLips >= _prevJaw && lipsVal < jawVal && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
// Trail exit: close below trail for longs
if (Position > 0 && close < _prevTrail)
{
SellMarket();
}
// Trail exit: close above trail for shorts
else if (Position < 0 && close > _prevTrail)
{
BuyMarket();
}
_prevLips = lipsVal;
_prevJaw = jawVal;
_prevTrail = trailVal;
}
}
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, SmoothedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class live_alligator_strategy(Strategy):
def __init__(self):
super(live_alligator_strategy, self).__init__()
self._jaw_length = self.Param("JawLength", 21) \
.SetDisplay("Jaw", "Alligator Jaw length", "Indicators")
self._teeth_length = self.Param("TeethLength", 13) \
.SetDisplay("Teeth", "Alligator Teeth length", "Indicators")
self._lips_length = self.Param("LipsLength", 8) \
.SetDisplay("Lips", "Alligator Lips length", "Indicators")
self._trail_length = self.Param("TrailLength", 50) \
.SetDisplay("Trail", "Trailing SMA length", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._prev_lips = 0.0
self._prev_jaw = 0.0
self._prev_trail = 0.0
self._has_prev = False
@property
def jaw_length(self):
return self._jaw_length.Value
@property
def teeth_length(self):
return self._teeth_length.Value
@property
def lips_length(self):
return self._lips_length.Value
@property
def trail_length(self):
return self._trail_length.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(live_alligator_strategy, self).OnReseted()
self._prev_lips = 0.0
self._prev_jaw = 0.0
self._prev_trail = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(live_alligator_strategy, self).OnStarted2(time)
jaw = SmoothedMovingAverage()
jaw.Length = self.jaw_length
teeth = SmoothedMovingAverage()
teeth.Length = self.teeth_length
lips = SmoothedMovingAverage()
lips.Length = self.lips_length
trail = SimpleMovingAverage()
trail.Length = self.trail_length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(jaw, teeth, lips, trail, self.on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def on_process(self, candle, jaw_val, teeth_val, lips_val, trail_val):
if candle.State != CandleStates.Finished:
return
if not self._has_prev:
self._prev_lips = lips_val
self._prev_jaw = jaw_val
self._prev_trail = trail_val
self._has_prev = True
return
close = candle.ClosePrice
# Lips cross above jaw -> uptrend start
if self._prev_lips <= self._prev_jaw and lips_val > jaw_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Lips cross below jaw -> downtrend start
elif self._prev_lips >= self._prev_jaw and lips_val < jaw_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
# Trail exit: close below trail for longs
if self.Position > 0 and close < self._prev_trail:
self.SellMarket()
# Trail exit: close above trail for shorts
elif self.Position < 0 and close > self._prev_trail:
self.BuyMarket()
self._prev_lips = lips_val
self._prev_jaw = jaw_val
self._prev_trail = trail_val
def CreateClone(self):
return live_alligator_strategy()