191 lines
5.7 KiB
Python
191 lines
5.7 KiB
Python
from multiprocessing import Process
|
||
from datetime import datetime
|
||
|
||
from vnpy.trader.database import BarOverview
|
||
from vnpy.trader.datafeed import get_datafeed
|
||
from vnpy.trader.object import ContractData, BarData, HistoryRequest
|
||
from vnpy.trader.constant import Exchange, Product, OptionType, Interval
|
||
from vnpy.trader.setting import SETTINGS
|
||
|
||
from elite_database import EliteDatabase
|
||
|
||
|
||
# 配置迅投研数据服务
|
||
SETTINGS["datafeed.name"] = "xt"
|
||
SETTINGS["datafeed.username"] = "token"
|
||
SETTINGS["datafeed.password"] = "4aff6f3b0dcfc990ec9476213ba784e17c34e757"
|
||
|
||
|
||
# 交易所映射关系
|
||
EXCHANGE_XT2VT = {
|
||
"SH": Exchange.SSE,
|
||
"SZ": Exchange.SZSE,
|
||
"BJ": Exchange.BSE,
|
||
"SF": Exchange.SHFE,
|
||
"IF": Exchange.CFFEX,
|
||
"INE": Exchange.INE,
|
||
"DF": Exchange.DCE,
|
||
"ZF": Exchange.CZCE,
|
||
"GF": Exchange.GFEX
|
||
}
|
||
|
||
|
||
def update_history_data() -> None:
|
||
"""更新历史合约信息"""
|
||
# 在子进程中加载xtquant
|
||
from xtquant.xtdata import download_history_data
|
||
|
||
# 初始化数据服务
|
||
datafeed = get_datafeed()
|
||
datafeed.init()
|
||
|
||
# 下载历史合约信息
|
||
download_history_data("", "historycontract")
|
||
|
||
print("xtquant历史合约信息下载完成")
|
||
|
||
|
||
def update_contract_data(sector_name: str) -> None:
|
||
"""更新合约数据"""
|
||
# 在子进程中加载xtquant
|
||
from xtquant.xtdata import (
|
||
get_stock_list_in_sector,
|
||
get_instrument_detail
|
||
)
|
||
|
||
# 初始化数据服务
|
||
datafeed = get_datafeed()
|
||
datafeed.init()
|
||
|
||
# 查询中金所历史合约代码
|
||
vt_symbols: list[str] = get_stock_list_in_sector(sector_name)
|
||
|
||
# 遍历列表查询合约信息
|
||
contracts: list[ContractData] = []
|
||
|
||
for xt_symbol in vt_symbols:
|
||
# 拆分XT代码
|
||
symbol, xt_exchange = xt_symbol.split(".")
|
||
|
||
# 筛选期权合约合约
|
||
if "-" in symbol:
|
||
data: dict = get_instrument_detail(xt_symbol, True)
|
||
|
||
type_str = data["InstrumentID"].split("-")[1]
|
||
if type_str == "C":
|
||
option_type = OptionType.CALL
|
||
elif type_str == "P":
|
||
option_type = OptionType.PUT
|
||
|
||
contract: ContractData = ContractData(
|
||
symbol=data["InstrumentID"],
|
||
exchange=EXCHANGE_XT2VT[xt_exchange.replace("O", "")],
|
||
name=data["InstrumentName"],
|
||
product=Product.OPTION,
|
||
size=data["VolumeMultiple"],
|
||
pricetick=data["PriceTick"],
|
||
min_volume=data["MinLimitOrderVolume"],
|
||
option_strike=data["ExtendInfo"]["OptExercisePrice"],
|
||
option_listed=datetime.strptime(data["OpenDate"], "%Y%m%d"),
|
||
option_expiry=datetime.strptime(data["ExpireDate"], "%Y%m%d"),
|
||
option_portfolio=data["ProductID"],
|
||
option_index=str(data["ExtendInfo"]["OptExercisePrice"]),
|
||
option_type=option_type,
|
||
gateway_name="XT"
|
||
)
|
||
contracts.append(contract)
|
||
|
||
# 保存合约信息到数据库
|
||
database: EliteDatabase = EliteDatabase()
|
||
database.save_contract_data(contracts)
|
||
|
||
print("合约信息更新成功", len(contracts))
|
||
|
||
|
||
def update_bar_data() -> None:
|
||
"""更新K线数据"""
|
||
# 初始化数据服务
|
||
datafeed = get_datafeed()
|
||
datafeed.init()
|
||
|
||
# 获取当前时间戳
|
||
now: datetime = datetime.now()
|
||
|
||
# 获取合约信息
|
||
database: EliteDatabase = EliteDatabase()
|
||
contracts: list[ContractData] = database.load_contract_data()
|
||
|
||
# 获取数据汇总
|
||
data: list[BarOverview] = database.get_bar_overview()
|
||
|
||
overviews: dict[str, BarOverview] = {}
|
||
for o in data:
|
||
# 只保留分钟线数据
|
||
if o.interval != Interval.MINUTE:
|
||
continue
|
||
|
||
vt_symbol: str = f"{o.symbol}.{o.exchange.value}"
|
||
overviews[vt_symbol] = o
|
||
|
||
# 遍历所有合约信息
|
||
for contract in contracts:
|
||
# 如果没有到期时间,则跳过
|
||
if not contract.option_expiry:
|
||
continue
|
||
|
||
# 查询数据汇总
|
||
overview: BarOverview = overviews.get(contract.vt_symbol, None)
|
||
|
||
# 如果已经到期,则跳过
|
||
if overview and contract.option_expiry < now:
|
||
continue
|
||
|
||
# 初始化查询开始的时间中金所期权最早在2019-12-13,商品期权最早为豆粕期权2017年3月31日
|
||
start: datetime = datetime(2017, 3, 1)
|
||
|
||
# 实现增量查询
|
||
if overview:
|
||
start = overview.end
|
||
|
||
# 执行数据查询和更新入库
|
||
req: HistoryRequest = HistoryRequest(
|
||
symbol=contract.symbol,
|
||
exchange=contract.exchange,
|
||
start=start,
|
||
end=datetime.now(),
|
||
interval=Interval.MINUTE
|
||
)
|
||
|
||
bars: list[BarData] = datafeed.query_bar_history(req)
|
||
|
||
if bars:
|
||
database.save_bar_data(bars)
|
||
|
||
start_dt: datetime = bars[0].datetime
|
||
end_dt: datetime = bars[-1].datetime
|
||
msg: str = f"{contract.vt_symbol}数据更新成功,{start_dt} - {end_dt}"
|
||
print(msg)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
# 使用子进程更新历史合约信息
|
||
process: Process = Process(target=update_history_data)
|
||
process.start()
|
||
process.join() # 等待子进程执行完成
|
||
|
||
# 更新合约信息
|
||
update_contract_data("中金所")
|
||
update_contract_data("过期中金所")
|
||
|
||
# 更新历史数据
|
||
update_bar_data()
|
||
|
||
|
||
# "IF":"过期中金所",
|
||
# "SF":"过期上期所",不在此更新第26课
|
||
# "DF":"过期大商所",不在此更新第26课
|
||
# "ZF":"过期郑商所",未完成,不在此更新第26课
|
||
# "INE":"过期能源中心",
|
||
# "SHO":"过期上证期权",未完成,不在此更新第26课
|
||
# "SZO":"过期深证期权",未完成,不在此更新第26课
|