盈透证券
通过TWS API(socket协议)直连托管者所在机器上运行的「IB Gateway」或「TWS(Trader Workstation)」,交易盈透证券账户中的股票、期货、期权等。以TWS为例:登录后点击右上角的配置按钮,选择「配置」→「API」→「设置」,不要勾选「只读API」,勾选「启用ActiveX和套接字客户端」,并记下「套接字端口」(TWS默认实盘7496、模拟盘7497;IB Gateway默认实盘4001、模拟盘4002),填入交易所配置的服务器地址。鉴权在TWS或IB Gateway的登录状态中完成,交易所配置不需要密钥。
名称与配置
exchange.GetName():Futures_IB(证券与期货);别名:IB、盈透。
| 配置项 | 必填 | 默认值 | 说明 |
|---|---|---|---|
| 服务器地址 | 是 | localhost:7496 | TWS或IB Gateway的API地址和端口,例如localhost:7496。 |
| 行情类型 | 是 | 1 | 实时数据、冻结数据、延迟数据、延迟冻结数据之一。没有订阅实时行情的账户可以选择延迟数据。运行中可用exchange.IO("marketDataType", n)切换。可选:实时数据、冻结数据、延迟数据、延迟冻结数据 |
交易对与合约代码
交易对示例:AAPL.US、TSLA.US
用exchange.SetContractType()(或exchange.SetCurrency())设置,交易所对象配置的交易对就是初始品种。格式为代码.货币[.类型[.交易所]],类型缺省为股票STK,交易所缺省为SMART,整串作为一个品种:
- 美股:
AAPL.US、TSLA.US(US表示美元计价,HK表示港币计价,其它货币直接写货币代码)。 - 期货(
FUT):代码-到期月份[-乘数].货币.FUT.交易所,到期月份写成YYYYMM,交易所为IB的交易所代码。 - 期权(
OPT)与期货期权(FOP):代码-到期-C或P-行权价×100[-乘数].货币.OPT或FOP.交易所,行权价乘以100后写成整数。 - 纯数字:直接作为IB的合约ID(conId)。
持仓、订单的Symbol是简写形式(如Z74.SGD),exchange.GetPositions()、exchange.GetOrders()传入简写或下单时用的完整代码(如Z74.SGD.STK.SGX)都可以。
exchange.SetContractType()向网关查询合约详情并返回,包括InstrumentID、PriceTick、VolumeMultiple(乘数,股票为1)、TradingHours、LiquidHours、IsTrading等;IsTrading按交易时段判断当前是否在交易,第二个参数传liquid时改按流动性时段判断。
专属IO指令
| 指令 | 参数 | 说明 |
|---|---|---|
status | — | 与TWS/IB Gateway的会话是否已建立(不主动建立连接)。 |
time | — | 获取IB服务器时间(毫秒时间戳)。 |
accounts | — | 获取托管账户(账户号)列表。 |
reqId | — | 分配一个新的请求ID(每次递增)。 |
orderId | — | 取出下一个可用订单ID并占用它,之后托管者下单不再使用这个号,可用于api指令直接下单。 |
ignore | codes | 设置同步请求时忽略的TWS错误码(整表替换,传空数组清空),参数为错误码数组或数组的JSON字符串。2100到2200段的通知以及10167、399本来就不中止请求。返回:设置后的错误码列表(升序、去重)。 |
scan | object | 执行市场扫描器,参数为扫描订阅字段(对象或JSON字符串,键名同旧版ScannerSubscription,如Instrument、LocationCode、ScanCode、NumberOfRows、AbovePrice),必须包含Instrument,例如STK配合LocationCode为STK.US.MAJOR;ScanCode缺省为HOT_BY_VOLUME。(详见表下) |
wait | [number] | 等待并返回TWS/IB Gateway发来的下一条完整消息;参数为超时毫秒数(最多600秒),负数表示不等待,0或不传最多等30秒,超时返回空值。返回:{id, fields},id为TWS消息ID,fields为其余字段的字符串数组。 |
debug | [bool] | 查询或设置调试模式:开启后把与TWS/IB Gateway收发的每一帧按TWS API日志的格式(每帧最多512字节)写入托管者的标准输出日志,不显示在机器人日志中。返回:当前的调试模式(true/false)。 |
marketDataType | number | 切换行情数据类型(1实时、2冻结、3延迟、4延迟冻结)。返回:true |
api | msgId, ...fields | name[, params[, filterMsgId[, timeout]]] | 发送原始TWS消息:exchange.IO("api", 消息ID, 字段...)发送后返回true。(详见表下) |
表中长说明的其余部分:
scan:返回:扫描结果数组,每项{rank, symbol, conId, secType, exchange, currency, localSymbol, tradingClass, marketName, ...},symbol是可以直接传给exchange.SetContractType()的品种代码(如AAPL.US)。api:也可以按旧版写法exchange.IO("api", 请求名或消息ID, 参数数组, 等待的消息ID, 超时秒数)调用(请求名如PlaceOrder、CancelOrder,参数数组可以是JSON字符串):不给等待的消息ID时发送后返回true;给了就返回从发送到收到该消息ID为止的所有消息,每条为去掉消息ID后的字段字符串数组。
通用指令base、currency见exchange.IO。
常用用法
检查与网关的会话,读取服务器时间和托管账户
javascript
function main() {
// status 不主动建立连接:第一次请求之前为 false
Log("会话已建立:", exchange.IO("status"))
var t = exchange.IO("time") // 毫秒时间戳,这次请求会建立会话
Log("IB服务器时间:", _D(t), "与本机相差(毫秒):", t - Date.now())
Log("托管账户:", exchange.IO("accounts")) // 下单默认用第一个
Log("会话已建立:", exchange.IO("status"))
}
用市场扫描器选出涨幅榜股票,再取行情
javascript
function main() {
var rows = exchange.IO("scan", {
Instrument: "STK",
LocationCode: "STK.US.MAJOR",
ScanCode: "TOP_PERC_GAIN",
NumberOfRows: 10,
AbovePrice: 5
})
if (!rows) {
Log("扫描失败:", GetLastError())
return
}
rows.forEach(function (r) {
Log(r.rank, r.symbol, "conId:", r.conId, r.exchange, r.currency)
})
// symbol 可以直接用作品种代码
exchange.SetContractType(rows[0].symbol)
Log(rows[0].symbol, exchange.GetTicker())
}
没有实时行情订阅时改用延迟行情,忽略部分行情未订阅的错误
javascript
function main() {
exchange.IO("marketDataType", 3) // 1实时、2冻结、3延迟、4延迟冻结
// 10090(部分行情未订阅)不再中止请求;整表替换,返回设置后的列表
Log("忽略的错误码:", exchange.IO("ignore", [10090]))
exchange.SetContractType("AAPL.US")
Log(exchange.GetTicker())
exchange.IO("ignore", []) // 清空
}
发送原始TWS请求,收集应答或用wait逐条读取消息
javascript
function main() {
exchange.IO("debug", true) // 收发的每一帧写入托管者标准输出日志
// 旧版命名调用:ReqMktData 快照请求,收集消息直到 tickSnapshotEnd(消息ID 57),最多10秒
var id = exchange.IO("reqId")
var msgs = exchange.IO("api", "ReqMktData", [id, "AAPL.US", "", true, false], 57, 10)
if (msgs) {
Log("收到", msgs.length, "条消息(不含消息ID):", msgs)
}
// 原始帧:消息ID 49(reqCurrentTime,版本 1),发送后返回 true
exchange.IO("api", 49, 1)
while (true) {
var m = exchange.IO("wait", 5000)
if (!m) {
Log("5秒内没有消息")
break
}
if (m.id == 49) {
Log("服务器时间(秒):", m.fields[1]) // fields[0] 是消息版本
break
}
Log("其它消息:", m.id, m.fields)
}
exchange.IO("debug", false)
}
函数支持差异
不支持(调用时报错并返回空值):exchange.GetTrades、exchange.GetHistoryOrders、exchange.GetFundings、exchange.SetMarginLevel、exchange.ModifyOrder、exchange.CreateConditionOrder、exchange.ModifyConditionOrder、exchange.CancelConditionOrder、exchange.GetConditionOrder、exchange.GetConditionOrders、exchange.GetHistoryConditionOrders。
以回退方式支持:
exchange.GetRecords:原生周期为1分钟、3分钟、5分钟、15分钟、30分钟、1小时、2小时、4小时、6小时、1天、1周;其它60秒整数倍的周期由托管者用原生K线合成,其余周期(如秒级)不可用(本交易所对象不支持exchange.GetTrades())。
保证金、账户与模拟盘
账户:使用TWS/IB Gateway登录的第一个托管账户。exchange.GetAssets()按币种返回各币种的净清算值(NetLiquidationByCurrency,没有时取该币种的现金余额),冻结数量为0;exchange.GetAccount()的Balance与Equity为账户基础币种计的净清算总值,Info中有TWS下发的全部账户值。exchange.GetPositions()的Price为每单位均价(期货、期权的平均成本已除以合约乘数,原值见Info中的AvgCost),Profit为0(IB持仓查询不提供浮动盈亏)。
注意事项
- 托管者以实盘ID作为连接TWS的客户端号(clientId),实盘重启后客户端号不变,仍可撤销此前挂出的订单。TWS只允许订单的原始客户端号(或主客户端)撤销订单。
exchange.GetOrders()返回网关上全部未完成的订单(不传品种时为所有合约);exchange.GetOrder()只能查到当前未完成的订单和本次运行中见过的订单,此前已完结的订单查不到。订单的Time为0(TWS的订单回报不带下单时间)。 - 行情为快照:
exchange.GetDepth()只有买一、卖一一档,没有有效买卖价时报错;exchange.GetTickers()返回本次运行中已经使用过的合约的行情,既没有最新价也没有昨收价的合约不列出。美股exchange.GetTicker()的Volume已由TWS的手数(100股)换算成股数。 exchange.GetMarkets()通过市场扫描器(STK、STK.US.MAJOR、按成交量排序的HOT_BY_VOLUME)取得合约列表,再逐个查询合约详情取精度,只包含扫描结果中的合约。- 下单数量是股数(期货、期权为张数),不是金额;价格传
-1或0时按市价单(MKT)提交。默认GTC,下单函数最后的选项对象可传{tif: "ioc"}或{tif: "fok"},不支持postOnly;选项对象中outsideRth: true允许在常规交易时段以外成交(默认不允许),account指定下单账户。 closebuy、closesell只是按反方向(卖出、买入)下单,没有只减仓保证:没有对应持仓时会开出反向仓位。- 订单被网关拒绝时,订单
Info中的Reject字段记录拒单原因。