在 GitHub 上查看
Exp CandlesticksBW Tm 策略
该策略在 StockSharp 高级 API 上复刻了 MetaTrader 专家顾问 Exp_CandlesticksBW_Tm。它使用 Bill Williams 的 Candlesticks BW 指标,通过组合 Awesome Oscillator (AO) 与 Accelerator Oscillator (AC) 的方向来为蜡烛染色,并据此捕捉动能加速或减速。可选的交易时段过滤器可以让策略只在特定时间范围内进出场。
工作流程
- 订阅所选时间框(默认 H4),将每根已完成蜡烛传递到 5/34 周期的 Awesome Oscillator。随后利用 5 周期简单移动平均线对 AO 进行平滑,得到 Accelerator 值。
- 每根蜡烛被划分为六种颜色中的一种:两种多头动能颜色(AO、AC 同时上升)、两种空头动能颜色(AO、AC 同时下降)以及两种中性颜色(AO、AC 方向不一致)。蜡烛实体的方向决定具体使用哪一种色调。
- 使用环形缓冲区保存最近的颜色索引及其开盘时间。参数 SignalBar 指定需要评估的历史蜡烛(默认 1,表示上一根蜡烛),再往前一根蜡烛用于上下文判断。
- 当较早的蜡烛处于多头动能区,而信号蜡烛离开该区域时触发多头开仓。空头逻辑与之相反。离场信号使用相同的颜色条件来关闭已有仓位。
- 当启用时间过滤 (UseTimeFilter) 时,交易仅允许在 StartHour:StartMinute 与 EndHour:EndMinute 之间进行。一旦超出窗口,策略会立即平掉全部仓位,避免持仓过夜。
- 通过
StartProtection 注册止损与止盈,参数以价格点为单位,会根据合约的最小价格步长自动换算。
交易规则
- 开多:
SignalBar + 1 的颜色索引 < 2(动能向上),同时 SignalBar 的颜色索引 > 1。只有在允许做多且当前无多单时才会进场。
- 开空:
SignalBar + 1 的颜色索引 > 3(动能向下),同时 SignalBar 的颜色索引 < 4。
- 平多:
SignalBar + 1 的颜色索引 > 3,并且启用了多头平仓。
- 平空:
SignalBar + 1 的颜色索引 < 2,并且启用了空头平仓。
- 启用时间过滤后,无论是否出现颜色信号,只要超出交易区间都会立即平仓。
参数
| 名称 |
说明 |
默认值 |
CandleType |
AO/AC 使用的时间框。 |
TimeSpan.FromHours(4).TimeFrame() |
Volume |
开仓手数。 |
1m |
SignalBar |
要回溯的已完成蜡烛数量(1 代表上一根)。 |
1 |
StopLossPoints |
止损距离(点数,0 表示关闭)。 |
1000m |
TakeProfitPoints |
止盈距离(点数,0 表示关闭)。 |
2000m |
EnableLongEntries, EnableShortEntries |
是否允许开多/开空。 |
true |
EnableLongExits, EnableShortExits |
是否允许根据信号平多/平空。 |
true |
UseTimeFilter |
是否启用交易时间过滤。 |
true |
StartHour, StartMinute, EndHour, EndMinute |
交易窗口(开始时间包含,结束时间在小时相等时不包含)。 |
0/0/23/59 |
其他说明
- 止损与止盈会按照标的价格步长自动换算实际价格。
- 信号时间戳基于所分析蜡烛的收盘时间,可避免在同一根 K 线内重复下单。
- 未提供 Python 版本,以保持与原始 MQL 包相同的结构。
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>
/// Bill Williams Candlesticks BW strategy (simplified).
/// Uses candle body direction with SMA trend filter.
/// </summary>
public class ExpCandlesticksBwTimeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _smaLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int SmaLength
{
get => _smaLength.Value;
set => _smaLength.Value = value;
}
public ExpCandlesticksBwTimeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_smaLength = Param(nameof(SmaLength), 34)
.SetGreaterThanZero()
.SetDisplay("SMA Length", "Bill Williams median line proxy", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var sma = new SimpleMovingAverage { Length = SmaLength };
int bullCount = 0, bearCount = 0;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(sma, (ICandleMessage candle, decimal smaValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var isBullish = candle.ClosePrice > candle.OpenPrice;
var isBearish = candle.ClosePrice < candle.OpenPrice;
if (isBullish)
{
bullCount++;
bearCount = 0;
}
else if (isBearish)
{
bearCount++;
bullCount = 0;
}
// 3 consecutive bullish candles above SMA
if (bullCount >= 3 && candle.ClosePrice > smaValue && Position <= 0)
{
BuyMarket();
bullCount = 0;
}
// 3 consecutive bearish candles below SMA
else if (bearCount >= 3 && candle.ClosePrice < smaValue && Position >= 0)
{
SellMarket();
bearCount = 0;
}
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, sma);
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 exp_candlesticks_bw_time_strategy(Strategy):
"""
Bill Williams Candlesticks BW strategy (simplified).
Uses candle body direction with SMA trend filter.
Buys after 3 consecutive bullish candles above SMA, sells after 3 bearish below SMA.
"""
def __init__(self):
super(exp_candlesticks_bw_time_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Candles", "General")
self._sma_length = self.Param("SmaLength", 34) \
.SetDisplay("SMA Length", "Bill Williams median line proxy", "Indicators")
self._bull_count = 0
self._bear_count = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(exp_candlesticks_bw_time_strategy, self).OnReseted()
self._bull_count = 0
self._bear_count = 0
def OnStarted2(self, time):
super(exp_candlesticks_bw_time_strategy, self).OnStarted2(time)
self._bull_count = 0
self._bear_count = 0
sma = SimpleMovingAverage()
sma.Length = self._sma_length.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(sma, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, sma)
self.DrawOwnTrades(area)
def _process_candle(self, candle, sma_val):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_p = float(candle.OpenPrice)
sma_val = float(sma_val)
is_bullish = close > open_p
is_bearish = close < open_p
if is_bullish:
self._bull_count += 1
self._bear_count = 0
elif is_bearish:
self._bear_count += 1
self._bull_count = 0
if self._bull_count >= 3 and close > sma_val and self.Position <= 0:
self.BuyMarket()
self._bull_count = 0
elif self._bear_count >= 3 and close < sma_val and self.Position >= 0:
self.SellMarket()
self._bear_count = 0
def CreateClone(self):
return exp_candlesticks_bw_time_strategy()