使用blpapi或xbbg获取彭博SPX指数期权历史数据问题求解
如何通过Python从彭博终端获取SPX指数期权历史数据
我试图通过Python从彭博获取SPX INDEX期权数据,目标是获取指定日期下所有期权的现货价格、买价、卖价和隐含波动率。
Excel端已验证实现逻辑:先通过BQL语句筛选指定到期日的所有期权,代码为
BQL("filter(options('SPX Index'),expire_dt=='"+"08/15/21"+"')","ID_SECURITY_DES,px_bid().value","showids=false","cols=2;rows=495"),可生成包含期权名称、价格、行权价、期权类型(看涨/看跌)的列,再通过BDH函数逐行查询每个期权的全量字段信息,示例代码为BDH('SPX US 08/15/21 4440P Index','Ivol_MID','08/18/21','08/18/21')。
原生blpapi实现报错问题
代码如下:
import blpapi import pandas import csv options = blpapi.SessionOptions() options.setServerHost('localhost') options.setServerPort(8194) SECURITY_DATA = blpapi.Name("securityData") SECURITY = blpapi.Name("security") FIELD_DATA = blpapi.Name("fieldData") FIELD_ID = blpapi.Name("fieldId") OPT_CHAIN = blpapi.Name("OPT_CHAIN") SECURITY_DES = blpapi.Name("Security Description") def getOptionChain (sec_list): import pdb;pdb.set_trace() session = blpapi.Session(options) session.start() session.openService('//blp/refdata') refDataService = session.getService("//blp/refdata") request = refDataService.createRequest("ReferenceDataRequest") for s in sec_list: request.append("securities",s) request.append("fields", "OPT_CHAIN") cid = session.sendRequest(request) try: while(True): ev = session.nextEvent(500) response = [] for msg in ev: if cid in msg.correlationIds(): securityDataArray = msg.getElement(SECURITY_DATA) for securityData in securityDataArray.values(): fieldData = securityData.getElement(FIELD_DATA) for field in fieldData.elements(): for n in range(field.numValues()): fld = field.getValueAsElement(n) response.append (fld.getElement(SECURITY_DES).getValueAsString()) if ev.eventType() == blpapi.Event.RESPONSE: break finally: session.stop() return response def getPX (sec_list, fld_list): opt_chain_list = getOptionChain(sec_list) session = blpapi.Session(options) session.start() session.openService('//blp/refdata') refDataService = session.getService("//blp/refdata") request = refDataService.createRequest("ReferenceDataRequest") for s in opt_chain_list: request.append("securities",s) for f in fld_list: request.append("fields",f) cid = session.sendRequest(request) try: response = {} while(True): ev = session.nextEvent(500) for msg in ev: if cid in msg.correlationIds(): securityDataArray = msg.getElement(SECURITY_DATA) for securityData in securityDataArray.values(): secName = securityData.getElementAsString(SECURITY) fieldData = securityData.getElement(FIELD_DATA) response[secName] = {} for field in fieldData.elements(): response[secName][field.name()] = field.getValueAsFloat() if ev.eventType() == blpapi.Event.RESPONSE: break finally: session.stop() tempdict = {} for r in response: tempdict[r] = pandas.Series(response[r]) data = pandas.DataFrame(tempdict) return data sec = ["SPX INDEX Equity"] fld = ["PX_ASK","PX_BID"] print(getPX(sec,fld))
原始报错信息:
blpapi.exception.InvalidArgumentException: Choice sub-element not found for name 'securityData'. (0x00020002)
报错翻译:blpapi异常.无效参数异常:未找到名称为'securityData'的选择子元素 (0x00020002)
xbbg库实现问题
尝试使用xbbg查询的代码如下:
blp.bdh(tickers='SPX INDEX',flds=['PX_LAST','Bid','Ask'],start_date='09-26-20',end_date='09-30-20')
返回空DataFrame。
问题补充(2021年8月19日)
已修正标的证券名称,但问题仍未解决,使用sec = ["SPX US 08/15/21 4440P Index"]、fld = ["IVOL"]查询时仍返回上述相同报错。
当前已知直接指定具体期权标的可查询到目标数据,但需要先获取完整的期权列表和到期日列表,才能按指定到期日查询数据。
解决方案
问题根因
- 标的代码格式错误:彭博API要求的SPX标的正确格式为
SPX Index,不需要额外加Equity后缀,错误的标的代码会导致API返回无有效securityData节点的响应,触发对应报错。 - OPT_CHAIN字段默认返回全量到期日期权,未按指定到期日过滤,查询量过大也可能导致响应异常。
- xbbg的bdh是历史时序数据查询接口,直接传入指数标的查期权相关字段自然返回空,需要先拿到期权链后再批量查询。
原生blpapi修正后实现
import blpapi import pandas as pd # 配置会话 session_opts = blpapi.SessionOptions() session_opts.setServerHost('localhost') session_opts.setServerPort(8194) session = blpapi.Session(session_opts) session.start() session.openService('//blp/refdata') ref_svc = session.getService('//blp/refdata') def get_filtered_option_chain(underlying: str, expire_date: str) -> list: """ 获取指定标的、指定到期日的期权代码列表 :param underlying: 标的代码,如'SPX Index' :param expire_date: 到期日,格式为'MM/DD/YY' """ req = ref_svc.createRequest("ReferenceDataRequest") req.append("securities", underlying) req.append("fields", "OPT_CHAIN") # 新增到期日过滤参数,避免返回全量期权 req.set("overrides", f"OPTS_CHAIN_EXP_DT={expire_date}") cid = session.sendRequest(req) opt_list = [] while True: ev = session.nextEvent(1000) for msg in ev: if cid not in msg.correlationIds(): continue if msg.hasElement("securityData"): sec_data = msg.getElement("securityData") for sec in sec_data.values(): field_data = sec.getElement("fieldData") if field_data.hasElement("OPT_CHAIN"): opt_chain = field_data.getElement("OPT_CHAIN") for i in range(opt_chain.numValues()): opt_item = opt_chain.getValueAsElement(i) opt_code = opt_item.getElementAsString("Security Description") opt_list.append(opt_code) if ev.eventType() == blpapi.Event.RESPONSE: break return opt_list def get_option_fields(opt_list: list, fields: list, trade_date: str) -> pd.DataFrame: # 单日历史数据用BDH接口更稳定,和Excel端逻辑一致 req = ref_svc.createRequest("HistoricalDataRequest") for opt in opt_list: req.append("securities", opt) for f in fields: req.append("fields", f) req.set("startDate", trade_date) req.set("endDate", trade_date) req.set("nonTradingDayFillOption", "ALL_CALENDAR_DAYS") cid = session.sendRequest(req) res = [] while True: ev = session.nextEvent(1000) for msg in ev: if cid not in msg.correlationIds(): continue if msg.hasElement("securityData"): sec_data = msg.getElement("securityData") sec_name = sec_data.getElementAsString("security") field_data = sec_data.getElement("fieldData") for i in range(field_data.numValues()): item = field_data.getValueAsElement(i) date = item.getElementAsString("date") row = {"ticker": sec_name, "date": date} for f in fields: row[f] = item.getElementAsFloat(f) if item.hasElement(f) else None res.append(row) if ev.eventType() == blpapi.Event.RESPONSE: break session.stop() return pd.DataFrame(res) # 调用示例 if __name__ == "__main__": # 1. 获取2021年8月15日到期的SPX期权列表 opt_codes = get_filtered_option_chain("SPX Index", "08/15/21") # 2. 查询2021年8月18日的买价、卖价、中期隐含波动率 df = get_option_fields(opt_codes, ["PX_BID", "PX_ASK", "IVOL_MID"], "08/18/21") print(df.head())
xbbg简化实现
如果用xbbg可以省去自行解析响应的逻辑,代码如下:
from xbbg import blp # 先获取指定到期日的期权链 opt_chain = blp.bdtick('SPX Index', flds=['opt_chain'], overrides={'OPTS_CHAIN_EXP_DT': '08/15/21'}) opt_codes = opt_chain['security_description'].tolist() # 批量查历史数据 df = blp.bdh( tickers=opt_codes, flds=['px_bid', 'px_ask', 'ivol_mid'], start_date='2021-08-18', end_date='2021-08-18' )
内容的提问来源于stack exchange,提问作者curious123456789
相关产品推荐
相关产品推荐

