Ride Alligator Williams 策略
该策略实现了比尔·威廉姆斯的 Alligator 指标。使用中值价格计算嘴唇、牙齿和下颚的平滑移动平均线,其长度由基准周期通过黄金比例推导而来。当嘴唇线上穿下颚且牙齿线仍在下颚下方时开多;当嘴唇线下穿下颚且牙齿线仍在下颚上方时开空。持仓期间,止损沿下颚线移动。
参数
- Base Period – 用于推导 Alligator 各线长度的基准周期。
- Candle Type – 策略使用的K线周期。
指标
- 平滑移动平均线(嘴唇、牙齿、下颚)
入场规则
- 嘴唇上穿下颚且牙齿位于下颚下方时开多。
- 嘴唇下穿下颚且牙齿位于下颚上方时开空。
出场规则
- 出现反向交叉时平仓。
- 当价格突破下颚线时,移动止损触发平仓。
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Bill Williams Alligator.
/// Buys when the lips cross above the jaws while the teeth remain below.
/// Sells when the lips cross below the jaws while the teeth remain above.
/// A trailing stop is placed at the jaws line.
/// </summary>
public class RideAlligatorWilliamsStrategy : Strategy
{
private readonly StrategyParam<int> _basePeriod;
private readonly StrategyParam<DataType> _candleType;
private SmoothedMovingAverage _jaw;
private SmoothedMovingAverage _teeth;
private SmoothedMovingAverage _lips;
private bool _prevLipsAboveJaw;
private decimal? _stopPrice;
/// <summary>
/// Base period used to calculate Alligator lengths.
/// </summary>
public int BasePeriod
{
get => _basePeriod.Value;
set => _basePeriod.Value = value;
}
/// <summary>
/// Candle type for strategy calculations.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of <see cref="RideAlligatorWilliamsStrategy"/>.
/// </summary>
public RideAlligatorWilliamsStrategy()
{
_basePeriod = Param(nameof(BasePeriod), 8)
.SetGreaterThanZero()
.SetDisplay("Base Period", "Root period for Alligator lines", "Alligator");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for strategy", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevLipsAboveJaw = false;
_stopPrice = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var a1 = (int)Math.Round(BasePeriod * 1.61803398874989m);
var a2 = (int)Math.Round(a1 * 1.61803398874989m);
var a3 = (int)Math.Round(a2 * 1.61803398874989m);
_jaw = new SmoothedMovingAverage { Length = a3 };
_teeth = new SmoothedMovingAverage { Length = a2 };
_lips = new SmoothedMovingAverage { Length = a1 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle);
subscription.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _jaw);
DrawIndicator(area, _teeth);
DrawIndicator(area, _lips);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
var median = (candle.HighPrice + candle.LowPrice) / 2m;
var isFinal = candle.State == CandleStates.Finished;
var jawVal = _jaw.Process(new DecimalIndicatorValue(_jaw, median, candle.ServerTime) { IsFinal = isFinal });
var teethVal = _teeth.Process(new DecimalIndicatorValue(_teeth, median, candle.ServerTime) { IsFinal = isFinal });
var lipsVal = _lips.Process(new DecimalIndicatorValue(_lips, median, candle.ServerTime) { IsFinal = isFinal });
if (!isFinal)
return;
if (!_jaw.IsFormed || !_teeth.IsFormed || !_lips.IsFormed)
return;
var jaw = jawVal.GetValue<decimal>();
var teeth = teethVal.GetValue<decimal>();
var lips = lipsVal.GetValue<decimal>();
var lipsAboveJaw = lips > jaw;
var lipsBelowJaw = lips < jaw;
var teethAboveJaw = teeth > jaw;
var teethBelowJaw = teeth < jaw;
if (Position <= 0 && !_prevLipsAboveJaw && lipsAboveJaw && teethBelowJaw)
{
BuyMarket();
_stopPrice = null;
}
else if (Position >= 0 && _prevLipsAboveJaw && lipsBelowJaw && teethAboveJaw)
{
SellMarket();
_stopPrice = null;
}
if (Position > 0)
{
if (jaw < candle.ClosePrice)
{
var step = Security.PriceStep ?? 0m;
if (_stopPrice is null || jaw > _stopPrice + step)
_stopPrice = jaw;
}
if (_stopPrice != null && candle.ClosePrice <= _stopPrice)
{
SellMarket(Position);
_stopPrice = null;
}
}
else if (Position < 0)
{
if (jaw > candle.ClosePrice)
{
var step = Security.PriceStep ?? 0m;
if (_stopPrice is null || jaw < _stopPrice - step)
_stopPrice = jaw;
}
if (_stopPrice != null && candle.ClosePrice >= _stopPrice)
{
BuyMarket(Math.Abs(Position));
_stopPrice = null;
}
}
_prevLipsAboveJaw = lipsAboveJaw;
}
}
import clr
import math
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math, Decimal
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SmoothedMovingAverage
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class ride_alligator_williams_strategy(Strategy):
def __init__(self):
super(ride_alligator_williams_strategy, self).__init__()
self._base_period = self.Param("BasePeriod", 8)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._jaw = None
self._teeth = None
self._lips = None
self._prev_lips_above_jaw = False
self._stop_price = None
@property
def BasePeriod(self):
return self._base_period.Value
@BasePeriod.setter
def BasePeriod(self, value):
self._base_period.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(ride_alligator_williams_strategy, self).OnStarted2(time)
self._prev_lips_above_jaw = False
self._stop_price = None
bp = int(self.BasePeriod)
phi = 1.61803398874989
a1 = int(round(bp * phi))
a2 = int(round(a1 * phi))
a3 = int(round(a2 * phi))
self._jaw = SmoothedMovingAverage()
self._jaw.Length = a3
self._teeth = SmoothedMovingAverage()
self._teeth.Length = a2
self._lips = SmoothedMovingAverage()
self._lips.Length = a1
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
h = float(candle.HighPrice)
l = float(candle.LowPrice)
median = (h + l) / 2.0
is_final = candle.State == CandleStates.Finished
jaw_result = process_float(self._jaw, median, candle.ServerTime, is_final)
teeth_result = process_float(self._teeth, median, candle.ServerTime, is_final)
lips_result = process_float(self._lips, median, candle.ServerTime, is_final)
if not is_final:
return
if not self._jaw.IsFormed or not self._teeth.IsFormed or not self._lips.IsFormed:
return
jaw_val = float(jaw_result)
teeth_val = float(teeth_result)
lips_val = float(lips_result)
close = float(candle.ClosePrice)
lips_above_jaw = lips_val > jaw_val
lips_below_jaw = lips_val < jaw_val
teeth_above_jaw = teeth_val > jaw_val
teeth_below_jaw = teeth_val < jaw_val
pos = float(self.Position)
if pos <= 0 and not self._prev_lips_above_jaw and lips_above_jaw and teeth_below_jaw:
self.BuyMarket()
self._stop_price = None
elif pos >= 0 and self._prev_lips_above_jaw and lips_below_jaw and teeth_above_jaw:
self.SellMarket()
self._stop_price = None
pos = float(self.Position)
if pos > 0:
if jaw_val < close:
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 0.0
if self._stop_price is None or jaw_val > self._stop_price + step:
self._stop_price = jaw_val
if self._stop_price is not None and close <= self._stop_price:
self.SellMarket(pos)
self._stop_price = None
elif pos < 0:
if jaw_val > close:
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 0.0
if self._stop_price is None or jaw_val < self._stop_price - step:
self._stop_price = jaw_val
if self._stop_price is not None and close >= self._stop_price:
self.BuyMarket(abs(pos))
self._stop_price = None
self._prev_lips_above_jaw = lips_above_jaw
def OnReseted(self):
super(ride_alligator_williams_strategy, self).OnReseted()
self._jaw = None
self._teeth = None
self._lips = None
self._prev_lips_above_jaw = False
self._stop_price = None
def CreateClone(self):
return ride_alligator_williams_strategy()