高级订阅
概览
Strategy 类提供了一组高级市场数据订阅方法:SubscribeCandles、SubscribeTicks、SubscribeLevel1 和 SubscribeOrderBook。这些方法返回一个 ISubscriptionHandler<T> 对象,该对象允许以方便的链式风格绑定数据处理器和指标。
与手动创建 Subscription 对象并调用 Subscribe() 不同,高级方法:
- 自动使用正确的参数创建订阅
- 提供一个用于绑定处理程序的已键入
ISubscriptionHandler<T> - 通过
Bind方法与指示器系统集成 - 支持自动图表渲染
- 妥善管理订阅生命周期
订阅方式
订阅K线
订阅K线。接受时间框架或 DataType:
// 按时间周期订阅
ISubscriptionHandler<ICandleMessage> SubscribeCandles(
TimeSpan tf,
bool isFinishedOnly = true,
Security security = default);
// 按 DataType 订阅(支持所有 K线类型)
ISubscriptionHandler<ICandleMessage> SubscribeCandles(
DataType dt,
bool isFinishedOnly = true,
Security security = default);
// 使用现成的 Subscription 对象订阅
ISubscriptionHandler<ICandleMessage> SubscribeCandles(Subscription subscription);
isFinishedOnly 参数默认值为 true -- 处理程序只接收完成的K线。
订阅Ticks
订阅逐笔交易:
ISubscriptionHandler<ITickTradeMessage> SubscribeTicks(Security security = null);
ISubscriptionHandler<ITickTradeMessage> SubscribeTicks(Subscription subscription);
订阅等级1
订阅一级市场数据(最佳买/卖价、最近成交以及其他字段):
ISubscriptionHandler<Level1ChangeMessage> SubscribeLevel1(Security security = null);
ISubscriptionHandler<Level1ChangeMessage> SubscribeLevel1(Subscription subscription);
订阅订单簿
订阅订单簿:
ISubscriptionHandler<IOrderBookMessage> SubscribeOrderBook(Security security = null);
ISubscriptionHandler<IOrderBookMessage> SubscribeOrderBook(Subscription subscription);
如果未指定 security 参数,则使用策略的 Security。
ISubscriptionHandler 接口
ISubscriptionHandler<T> 对象提供以下方法:
开始 / 停止
开始和停止订阅:
handler.Start(); // calls Subscribe
handler.Stop(); // calls UnSubscribe
绑定(无指示器)
绑定一个简单的数据处理器:
handler.Bind(Action<T> callback);
绑定(带指示器)
将处理程序绑定到一个或多个指标。指标会自动处理传入的数据,而处理程序接收已经计算好的值:
// 一个指标 -- decimal 数值
handler.Bind(IIndicator indicator, Action<T, decimal> callback);
// 两个指标
handler.Bind(IIndicator ind1, IIndicator ind2, Action<T, decimal, decimal> callback);
// 最多八个指标
handler.Bind(ind1, ind2, ind3, ..., callback);
// 指标数组
handler.Bind(IIndicator[] indicators, Action<T, decimal[]> callback);
仅当所有指标都返回非空值时,才会调用 Bind 的处理程序。
绑定为空
类似于 Bind,但即使指标返回空值,也会调用处理程序。值表示为 decimal?:
handler.BindWithEmpty(IIndicator indicator, Action<T, decimal?> callback);
绑定扩展
提供对完整 IIndicatorValue 对象的访问,而不是提取的 decimal:
handler.BindEx(IIndicator indicator, Action<T, IIndicatorValue> callback, bool allowEmpty = false);
示例:带指标的策略
public class SmaStrategy : Strategy
{
private readonly StrategyParam<int> _shortPeriod;
private readonly StrategyParam<int> _longPeriod;
private readonly StrategyParam<DataType> _candleType;
public int ShortPeriod
{
get => _shortPeriod.Value;
set => _shortPeriod.Value = value;
}
public int LongPeriod
{
get => _longPeriod.Value;
set => _longPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public SmaStrategy()
{
_shortPeriod = Param(nameof(ShortPeriod), 10);
_longPeriod = Param(nameof(LongPeriod), 20);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var shortSma = new SimpleMovingAverage { Length = ShortPeriod };
var longSma = new SimpleMovingAverage { Length = LongPeriod };
var subscription = SubscribeCandles(CandleType);
// 绑定两个指标 -- 处理程序会被调用
// 当两个指标都已形成时
subscription
.Bind(shortSma, longSma, (candle, shortValue, longValue) =>
{
if (!IsFormedAndOnlineAndAllowTrading())
return;
if (shortValue > longValue && Position <= 0)
BuyMarket(Volume + Math.Abs(Position));
else if (shortValue < longValue && Position >= 0)
SellMarket(Volume + Math.Abs(Position));
})
.Start();
// 图表设置
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, shortSma);
DrawIndicator(area, longSma);
DrawOwnTrades(area);
}
}
}
示例:勾选订阅
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeTicks()
.Bind(tick =>
{
if (!IsFormedAndOnlineAndAllowTrading())
return;
this.AddInfoLog("逐笔成交: 价格={0}, 数量={1}", tick.Price, tick.Volume);
})
.Start();
}
示例:订单簿订阅
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeOrderBook()
.Bind(book =>
{
var bestBid = book.GetBestBid();
var bestAsk = book.GetBestAsk();
if (bestBid != null && bestAsk != null)
{
var spread = bestAsk.Price - bestBid.Price;
this.AddInfoLog("Spread: {0}", spread);
}
})
.Start();
}
与手动订阅创建的区别
| 方面 | 手动订阅 | 高级方法 |
|---|---|---|
| 创建 | new Subscription(DataType, Security) |
SubscribeCandles(tf) |
| 数据处理 | 订阅连接器事件 | Bind(callback) |
| 指标 | 手动 indicator.Process() 呼叫 |
通过 Bind(indicator, callback) 自动 |
| 指标注册 | 手动添加到 Indicators |
自动添加到 Bind |
| 图表渲染 | 与 IChart 的手动集成 |
DrawCandles, DrawIndicator |
在大多数策略中建议使用高级方法,因为它们显著减少了代码量并降低了出错的可能性。