首页
/
策略示例
在 GitHub 上查看
AO Lightning 策略
概述
AO Lightning 使用 StockSharp 的高级 API 复刻 MT5 专家顾问 “AO_Lightning”。策略跟踪基于中值价格的 Awesome Oscillator (AO) 斜率:当 AO 下降时逐步加仓多头,而当 AO 上升时逐步建立空头。头寸以分层方式累积,并受最大层数限制;方向切换前会先平掉反向仓位。
交易逻辑
订阅所选的蜡烛序列,并以默认的短周期 5、长周期 34 计算 Awesome Oscillator(与原始 MQL 代码一致)。
仅处理收盘完成的蜡烛,以避免重复触发。
第一根完成的蜡烛仅用于存储参考 AO 值。
当当前 AO 值 低于 前一根蜡烛时:
如果存在空头仓位,发送市价买单,既平掉全部空头又同时新增一层多头。
如果当前没有空头且多头仓位尚未达到上限,则再买入一层。
当当前 AO 值 高于 前一根蜡烛时:
如果存在多头仓位,发送市价卖单,既平掉全部多头又同时新增一层空头。
如果当前没有多头且空头仓位尚未达到上限,则再卖出一层。
AO 值与上一根相等时不做操作。
启动时调用 StartProtection(),方便在 Designer 中附加止损等保护模块。
该流程与原始专家顾问一致:AO 斜率决定方向,翻转前会先平仓,随后按照设定的层数线性加仓。
仓位管理
TradeVolume 决定每次加仓的数量,对应 MT5 中的 LotFixed 参数。
MaxPositions 对应 MT5 的 Orders 输入,用于限制每个方向的最大层数。
分层加仓 为线性方式,只要未达上限,每个有效信号增加一层相同的手数。
方向翻转 通过单一的市价单完成,同时平掉旧仓并建立新方向的首层仓位。
参数
名称
说明
默认值
TradeVolume
每层加仓的下单数量。
1
MaxPositions
任一方向允许的最大层数。
10
AoShortPeriod
Awesome Oscillator 中的快速 SMA 周期(基于中值价格)。
5
AoLongPeriod
Awesome Oscillator 的慢速 SMA 周期。
34
CandleType
策略使用的蜡烛类型。
5 分钟周期
备注
原 MT5 专家顾问使用 Period_sma_slow 与 Period_sma_fast 作为输入,但数值 5 和 34 实际上互换。该移植版本以 AoShortPeriod/AoLongPeriod 直观地暴露参数,同时保持相同行为。
根据任务要求,此次未提供 Python 版本。
仓库未附带测试,请在投入真实环境前通过 Designer 或自有回测平台进行验证。
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// AO Lightning strategy.
/// Trades based on the Awesome Oscillator momentum slope direction.
/// Buys when AO is rising, sells when AO is falling.
/// </summary>
public class AoLightningStrategy : Strategy
{
private readonly StrategyParam<int> _aoShortPeriod;
private readonly StrategyParam<int> _aoLongPeriod;
private readonly StrategyParam<DataType> _candleType;
private decimal _prevAo;
private bool _initialized;
public int AoShortPeriod
{
get => _aoShortPeriod.Value;
set => _aoShortPeriod.Value = value;
}
public int AoLongPeriod
{
get => _aoLongPeriod.Value;
set => _aoLongPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public AoLightningStrategy()
{
_aoShortPeriod = Param(nameof(AoShortPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("AO Fast", "Short SMA period for Awesome Oscillator", "Indicators");
_aoLongPeriod = Param(nameof(AoLongPeriod), 34)
.SetGreaterThanZero()
.SetDisplay("AO Slow", "Long SMA period for Awesome Oscillator", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Source candles", "General");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevAo = 0m;
_initialized = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevAo = 0;
_initialized = false;
var ao = new AwesomeOscillator
{
ShortMa = { Length = AoShortPeriod },
LongMa = { Length = AoLongPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ao, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ao);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, decimal aoValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (!_initialized)
{
_prevAo = aoValue;
_initialized = true;
return;
}
// Buy when AO is rising (bullish momentum)
if (aoValue > _prevAo && Position <= 0)
{
BuyMarket();
}
// Sell when AO is falling (bearish momentum)
else if (aoValue < _prevAo && Position >= 0)
{
SellMarket();
}
_prevAo = aoValue;
}
}
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 AwesomeOscillator
from StockSharp.Algo.Strategies import Strategy
class ao_lightning_strategy(Strategy):
def __init__(self):
super(ao_lightning_strategy, self).__init__()
self._ao_short_period = self.Param("AoShortPeriod", 5) \
.SetDisplay("AO Fast", "Short SMA period for Awesome Oscillator", "Indicators")
self._ao_long_period = self.Param("AoLongPeriod", 34) \
.SetDisplay("AO Slow", "Long SMA period for Awesome Oscillator", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Source candles", "General")
self._prev_ao = 0.0
self._initialized = False
@property
def AoShortPeriod(self):
return self._ao_short_period.Value
@property
def AoLongPeriod(self):
return self._ao_long_period.Value
@property
def CandleType(self):
return self._candle_type.Value
def OnReseted(self):
super(ao_lightning_strategy, self).OnReseted()
self._prev_ao = 0.0
self._initialized = False
def OnStarted2(self, time):
super(ao_lightning_strategy, self).OnStarted2(time)
self._prev_ao = 0.0
self._initialized = False
ao = AwesomeOscillator()
ao.ShortMa.Length = self.AoShortPeriod
ao.LongMa.Length = self.AoLongPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(ao, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ao)
self.DrawOwnTrades(area)
def _on_process(self, candle, ao_value):
if candle.State != CandleStates.Finished:
return
av = float(ao_value)
if not self._initialized:
self._prev_ao = av
self._initialized = True
return
if av > self._prev_ao and self.Position <= 0:
self.BuyMarket()
elif av < self._prev_ao and self.Position >= 0:
self.SellMarket()
self._prev_ao = av
def CreateClone(self):
return ao_lightning_strategy()