在 GitHub 上查看
Expert Alligator 策略
Expert Alligator 策略 是 MetaTrader 5 内置专家顾问 Expert_Alligator.mq5 的 StockSharp 复刻版。原始 EA 使用比尔·威廉姆斯 (Bill Williams) 的 Alligator 指标:三条平滑移动平均线(颚线、齿线、唇线)按经典长度计算,并向未来平移数根 K 线。EA 通过观察这些线条的收敛和发散来捕捉新的交叉点,并在“鳄鱼之口”重新张开之前禁止再次入场。此 C# 实现完全按照该流程构建,使用 StockSharp 的高级策略 API 与指标库复现原始逻辑。
交易逻辑
指标准备
- 对每根完成的 K 线计算中位价
(最高价 + 最低价) / 2,分别输入到长度为 13、8、5 的平滑移动平均 (SMMA) 中。
- 按照 Alligator 的设定将颚线、齿线、唇线分别向前平移 8、5、3 根 K 线,并维护足够的历史缓冲以重现 EA 中
LipsTeethDiff(-2) 这类未来索引。
入场条件
- 多头:当唇线-齿线和齿线-颚线的差值在连续三个平移位置上逐步缩小且保持在零以上时触发,代表绿色唇线向下穿过红色齿线,预示上行张口。
- 空头:完全对称,只是差值在零以下逐步增大,表示唇线向上穿过齿线与颚线。
- 成交后会设置内部的
crossed 标志,在三条线的间距重新扩大到不少于 Cross Measure(以 MetaTrader 点数计)之前禁止再次开仓。
离场条件
- 多头平仓:当最近的平移值上唇线-齿线差值跌破零,而更早的两个平移值仍保持正数(对应原始 EA 的
-1、0、1 索引)。
- 空头平仓:当差值序列出现相反的符号变换时平掉空单。
参数
| 名称 |
说明 |
默认值 |
Order Volume |
市价单的交易数量(手数或合约数)。 |
0.1 |
Candle Type |
订阅的 K 线周期。 |
1 小时 |
Jaw Period |
颚线的 SMMA 长度。 |
13 |
Jaw Shift |
颚线向前平移的根数。 |
8 |
Teeth Period |
齿线的 SMMA 长度。 |
8 |
Teeth Shift |
齿线向前平移的根数。 |
5 |
Lips Period |
唇线的 SMMA 长度。 |
5 |
Lips Shift |
唇线向前平移的根数。 |
3 |
Cross Measure |
交叉后重新允许入场所需的最小张口距离(以 MetaTrader 点数衡量)。 |
5 |
实现细节
- 所有计算都基于收盘状态的 K 线;在蜡烛未完成之前不会执行任何交易决策。
- 指标历史通过固定长度数组维护,既可访问过去的数值,也可在 Alligator 向前平移后访问“未来”索引,以匹配 MQL5 的
CiAlligator 行为。
- MetaTrader 的
_Point 值使用品种的 PriceStep(报价步长)近似;若不可用,则回退到 10^-Decimals 或默认 0.0001。
- 策略会在图表面板上绘制 K 线与三条 Alligator 线,方便快速验证移植是否正确。
使用方法
- 将策略附加到具备所需行情数据的
Connector,并确保可提供设定周期的 K 线(默认 1 小时)。
- 等待数据订阅完成后调用
Start() 启动策略。
- 如需优化,可调整 Alligator 的长度、平移量或
Cross Measure 阈值。
- 通过 StockSharp 的标准界面监控持仓与绩效。
原始专家顾问仅使用固定手数和 Alligator 的几何关系管理仓位,因此本移植版未增加其他资金管理或跟踪止损模块。
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Expert Alligator strategy: Triple SMA (Alligator concept).
/// Buys when lips > teeth > jaw (bullish alignment).
/// Sells when lips < teeth < jaw (bearish alignment).
/// </summary>
public class ExpertAlligatorStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ExpertAlligatorStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Alligator: Jaw=13, Teeth=8, Lips=5
var lips = new SimpleMovingAverage { Length = 5 };
var teeth = new SimpleMovingAverage { Length = 8 };
var jaw = new SimpleMovingAverage { Length = 13 };
decimal? prevLips = null;
decimal? prevTeeth = null;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(lips, teeth, jaw, (candle, lipsVal, teethVal, jawVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (prevLips.HasValue && prevTeeth.HasValue)
{
var lipsCrossUp = prevLips.Value <= prevTeeth.Value && lipsVal > teethVal;
var lipsCrossDown = prevLips.Value >= prevTeeth.Value && lipsVal < teethVal;
if (lipsCrossUp && teethVal > jawVal && Position <= 0)
BuyMarket();
else if (lipsCrossDown && teethVal < jawVal && Position >= 0)
SellMarket();
}
prevLips = lipsVal;
prevTeeth = teethVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, lips);
DrawIndicator(area, teeth);
DrawIndicator(area, jaw);
DrawOwnTrades(area);
}
}
}
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 expert_alligator_strategy(Strategy):
def __init__(self):
super(expert_alligator_strategy, self).__init__()
self._lips = None
self._teeth = None
self._jaw = None
self._prev_lips = None
self._prev_teeth = None
def OnReseted(self):
super(expert_alligator_strategy, self).OnReseted()
self._lips = None
self._teeth = None
self._jaw = None
self._prev_lips = None
self._prev_teeth = None
def OnStarted2(self, time):
super(expert_alligator_strategy, self).OnStarted2(time)
self._lips = SimpleMovingAverage()
self._lips.Length = 5
self._teeth = SimpleMovingAverage()
self._teeth.Length = 8
self._jaw = SimpleMovingAverage()
self._jaw.Length = 13
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(30)))
subscription.Bind(self._lips, self._teeth, self._jaw, self._process_candle)
subscription.Start()
def _process_candle(self, candle, lips_value, teeth_value, jaw_value):
if candle.State != CandleStates.Finished:
return
if not self._lips.IsFormed or not self._teeth.IsFormed or not self._jaw.IsFormed:
return
lips_val = float(lips_value)
teeth_val = float(teeth_value)
jaw_val = float(jaw_value)
if self._prev_lips is not None and self._prev_teeth is not None:
lips_cross_up = self._prev_lips <= self._prev_teeth and lips_val > teeth_val
lips_cross_down = self._prev_lips >= self._prev_teeth and lips_val < teeth_val
if lips_cross_up and teeth_val > jaw_val and self.Position <= 0:
self.BuyMarket()
elif lips_cross_down and teeth_val < jaw_val and self.Position >= 0:
self.SellMarket()
self._prev_lips = lips_val
self._prev_teeth = teeth_val
def CreateClone(self):
return expert_alligator_strategy()