在 GitHub 上查看
Alliheik Trader 策略
本策略来自 MetaTrader 4 专家顾问 alliheik.mq4 的转换。它将双重平滑的 Heiken Ashi 蜡烛与前移的鳄鱼指标下颚线结合使用。当平滑后的 Heiken Ashi 缓冲区交叉时入场,离场依靠下颚过滤、固定止盈以及基于价格的移动止损。
交易逻辑
- Heiken Ashi 构建
- 使用
PreSmoothMethod / PreSmoothPeriod 对原始开高低收数据进行第一次平滑。
- 基于平滑后的价格构建标准 Heiken Ashi 蜡烛。
- 根据蜡烛颜色重新排列高/低缓冲区(看涨保留低/高,看跌交换为高/低)。
- 对条件缓冲区再次平滑(参数
PostSmoothMethod / PostSmoothPeriod),所得数值用于信号判断。
- 信号判定
- 做多:当前下方缓冲区小于上方缓冲区,且上一根柱子的关系相反或相等。
- 做空:当前下方缓冲区大于上方缓冲区,且上一根柱子的关系相反或相等。
- 下颚过滤与移动止损
- 鳄鱼下颚是一条长度为
JawsPeriod 的均线,向前偏移 JawsShift 根柱子,并使用 JawsPrice 指定的价格源。
- 只有当
Close[6](向前第六根收盘价)穿越下颚后,策略才允许自动平仓。
- 当
Close[6] 与下颚的距离达到 8 个点且价格反向穿越下颚时,立即平仓。
- 若
TrailingStopPoints 大于 0,当 Close[6] 位于盈利方向时,止损价格会跟随其移动。
- 止损与止盈
StopLossPoints 与 TakeProfitPoints 定义固定距离的止损、止盈(0 表示禁用)。
- 当价格继续向盈利方向发展时,移动止损会覆盖原始止损位置。
默认参数
| 参数 |
默认值 |
说明 |
CandleType |
TimeSpan.FromHours(1).TimeFrame() |
计算所用时间框架。 |
JawsPeriod |
144 |
鳄鱼下颚移动平均的长度。 |
JawsShift |
8 |
下颚向前偏移的柱数。 |
JawsMethod |
Simple |
下颚所用均线类型(Simple/Exponential/Smoothed/Weighted)。 |
JawsPrice |
Close |
输入下颚的价格类型(收盘、开盘、最高、最低、中价、典型价、加权价)。 |
PreSmoothMethod |
Exponential |
第一次平滑 OHLC 的均线类型。 |
PreSmoothPeriod |
21 |
第一次平滑的周期。 |
PostSmoothMethod |
Weighted |
第二次平滑 Heiken Ashi 缓冲区的均线类型。 |
PostSmoothPeriod |
1 |
第二次平滑的周期(1 表示不改变数值)。 |
StopLossPoints |
0 |
固定止损距离,单位为点。 |
TrailingStopPoints |
0 |
基于 Close[6] 的移动止损距离。 |
TakeProfitPoints |
225 |
固定止盈距离。 |
OrderVolume |
0.1 |
每次下单的手数。 |
使用的指标
- 对开、高、低、收四个序列分别进行的平滑移动平均。
- 基于平滑价格重建的 Heiken Ashi 蜡烛。
- 对条件缓冲区进行的第二次平滑,用于生成买卖信号。
- 可配置类型、偏移和价格源的鳄鱼下颚均线。
进出场规则
- 做多入场:下方缓冲区由上向下穿越上方缓冲区,同时上一根柱子尚未满足做多条件。
- 做多离场:满足以下任意条件即平仓:
Close[6] 曾位于下颚之上,并在距离达到 ≥8 点后重新跌破下颚;
- 达到
TakeProfitPoints 所设目标;
- 触发固定止损或移动止损。
- 做空入场:下方缓冲区由下向上穿越上方缓冲区,同时上一根柱子尚未满足做空条件。
- 做空离场:满足以下任意条件即平仓:
Close[6] 曾位于下颚之下,并在距离达到 ≥8 点后重新上破下颚;
- 达到
TakeProfitPoints 所设目标;
- 触发固定止损或移动止损。
转换说明
- 通过记录最近一次成交的 K 线,只允许每根 K 线触发一次新交易,复现原版
isOrderAllowed() 的限制。
- 保护性止损/止盈在策略内部模拟,因为 StockSharp 无法依赖 MT4 服务器端订单。
- 为了复制
iMA 在 ma_shift = JawsShift 下的行为,策略保存了带偏移的下颚历史值。
- 计算全部使用 StockSharp 的高阶 API 与内建指标,满足仓库编码规范。
风险提示与使用建议
- 策略支持同一标的的双向交易。
- 更适合趋势行情,平滑后的 Heiken Ashi 能够过滤噪音并突出摆动。
- 请根据标的波动性调整
TrailingStopPoints 与 TakeProfitPoints。
- 正式使用前务必进行历史回测与模拟账户验证。
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Alliheik Trader: uses smoothed Heiken Ashi candles (EMA of OHLC)
/// with Alligator jaw (long SMA) as trend filter.
/// Entry on HA color change above/below jaw, exit on reversal.
/// </summary>
public class AlliheikTraderStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smoothPeriod;
private readonly StrategyParam<int> _jawPeriod;
private decimal _prevHaOpen;
private decimal _prevHaClose;
private bool _prevBullish;
private bool _hasPrev;
private decimal _entryPrice;
public AlliheikTraderStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Timeframe.", "General");
_smoothPeriod = Param(nameof(SmoothPeriod), 6)
.SetDisplay("Smooth Period", "EMA period for HA smoothing.", "Indicators");
_jawPeriod = Param(nameof(JawPeriod), 144)
.SetDisplay("Jaw Period", "SMA period for Alligator jaw.", "Indicators");
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int SmoothPeriod
{
get => _smoothPeriod.Value;
set => _smoothPeriod.Value = value;
}
public int JawPeriod
{
get => _jawPeriod.Value;
set => _jawPeriod.Value = value;
}
/// <inheritdoc />
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevHaOpen = 0;
_prevHaClose = 0;
_prevBullish = false;
_hasPrev = false;
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevHaOpen = 0;
_prevHaClose = 0;
_prevBullish = false;
_hasPrev = false;
_entryPrice = 0;
var ema = new ExponentialMovingAverage { Length = SmoothPeriod };
var jaw = new SimpleMovingAverage { Length = JawPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ema, jaw, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, jaw);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaVal, decimal jawVal)
{
if (candle.State != CandleStates.Finished)
return;
var close = candle.ClosePrice;
// Compute smoothed Heiken Ashi
var haClose = (candle.OpenPrice + candle.HighPrice + candle.LowPrice + close) / 4m;
var haOpen = _prevHaOpen == 0
? (candle.OpenPrice + close) / 2m
: (_prevHaOpen + _prevHaClose) / 2m;
var bullish = haClose > haOpen;
if (!_hasPrev)
{
_prevHaOpen = haOpen;
_prevHaClose = haClose;
_prevBullish = bullish;
_hasPrev = true;
return;
}
var colorChange = bullish != _prevBullish;
// Exit on color change
if (Position > 0 && colorChange && !bullish)
{
SellMarket();
_entryPrice = 0;
}
else if (Position < 0 && colorChange && bullish)
{
BuyMarket();
_entryPrice = 0;
}
// Entry on color change confirmed by jaw filter
if (Position == 0 && colorChange)
{
if (bullish && close > jawVal)
{
_entryPrice = close;
BuyMarket();
}
else if (!bullish && close < jawVal)
{
_entryPrice = close;
SellMarket();
}
}
_prevHaOpen = haOpen;
_prevHaClose = haClose;
_prevBullish = bullish;
}
}
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 ExponentialMovingAverage, SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class alliheik_trader_strategy(Strategy):
"""
Alliheik Trader: uses smoothed Heiken Ashi candles (EMA of OHLC)
with Alligator jaw (long SMA) as trend filter.
Entry on HA color change above/below jaw, exit on reversal.
"""
def __init__(self):
super(alliheik_trader_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Timeframe.", "General")
self._smooth_period = self.Param("SmoothPeriod", 6) \
.SetDisplay("Smooth Period", "EMA period for HA smoothing.", "Indicators")
self._jaw_period = self.Param("JawPeriod", 144) \
.SetDisplay("Jaw Period", "SMA period for Alligator jaw.", "Indicators")
self._prev_ha_open = 0.0
self._prev_ha_close = 0.0
self._prev_bullish = False
self._has_prev = False
self._entry_price = 0.0
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, v): self._candle_type.Value = v
@property
def SmoothPeriod(self): return self._smooth_period.Value
@SmoothPeriod.setter
def SmoothPeriod(self, v): self._smooth_period.Value = v
@property
def JawPeriod(self): return self._jaw_period.Value
@JawPeriod.setter
def JawPeriod(self, v): self._jaw_period.Value = v
def OnReseted(self):
super(alliheik_trader_strategy, self).OnReseted()
self._prev_ha_open = 0.0
self._prev_ha_close = 0.0
self._prev_bullish = False
self._has_prev = False
self._entry_price = 0.0
def OnStarted2(self, time):
super(alliheik_trader_strategy, self).OnStarted2(time)
self._prev_ha_open = 0.0
self._prev_ha_close = 0.0
self._prev_bullish = False
self._has_prev = False
self._entry_price = 0.0
ema = ExponentialMovingAverage()
ema.Length = self.SmoothPeriod
jaw = SimpleMovingAverage()
jaw.Length = self.JawPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, jaw, self.ProcessCandle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, jaw)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, ema_val, jaw_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
o = float(candle.OpenPrice)
h = float(candle.HighPrice)
l = float(candle.LowPrice)
# Compute smoothed Heiken Ashi
ha_close = (o + h + l + close) / 4.0
if self._prev_ha_open == 0:
ha_open = (o + close) / 2.0
else:
ha_open = (self._prev_ha_open + self._prev_ha_close) / 2.0
bullish = ha_close > ha_open
if not self._has_prev:
self._prev_ha_open = ha_open
self._prev_ha_close = ha_close
self._prev_bullish = bullish
self._has_prev = True
return
color_change = bullish != self._prev_bullish
# Exit on color change
if self.Position > 0 and color_change and not bullish:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0 and color_change and bullish:
self.BuyMarket()
self._entry_price = 0.0
# Entry on color change confirmed by jaw filter
if self.Position == 0 and color_change:
if bullish and close > jaw_val:
self._entry_price = close
self.BuyMarket()
elif not bullish and close < jaw_val:
self._entry_price = close
self.SellMarket()
self._prev_ha_open = ha_open
self._prev_ha_close = ha_close
self._prev_bullish = bullish
def CreateClone(self):
"""!! REQUIRED!! Creates a new instance of the strategy."""
return alliheik_trader_strategy()