# 50ETF-期权-备兑看涨策略 # 参考资料: # - 原始策略来源: https://www.joinquant.com/view/community/detail/2b40f724dcea54aaa06419a46517f3db # - 研究网址: https://www.joinquant.com/research?target=research&url=/user/75474983526/notebooks/Options/50ETF-%E6%9C%9F%E6%9D%83-%E5%A4%87%E5%85%91%E7%9C%8B%E6%B6%A8%E7%AD%96%E7%95%A5.ipynb # TODO: 添加50ETF期权备兑看涨策略相关代码 import jqdata from jqdata import * import pandas as pd import numpy as np import datetime import matplotlib.pyplot as plt plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus'] = False #获取交易时间和时间间隔(频率:月) trade_days = pd.Series(index=jqdata.get_trade_days('2025-03-01','2025-06-10')) trade_days.index = pd.to_datetime(trade_days.index) month_split = list(trade_days.resample('M',label='left').mean().index) + [pd.to_datetime('20250610')] month_split ##传统备兑开仓策略 holding_contract2 = pd.Series(index=trade_days.index) #获取首个持仓合约 q_contract_info = query(opt.OPT_CONTRACT_INFO.code, opt.OPT_CONTRACT_INFO.trading_code, opt.OPT_CONTRACT_INFO.name, #合约代码,合约交易代码,合约简称 opt.OPT_CONTRACT_INFO.exercise_price, opt.OPT_CONTRACT_INFO.last_trade_date, opt.OPT_CONTRACT_INFO.list_date ).filter(opt.OPT_CONTRACT_INFO.contract_type == 'CO', #看涨期权 opt.OPT_CONTRACT_INFO.exchange_code == 'XSHG', #上交所 opt.OPT_CONTRACT_INFO.last_trade_date > month_split[0], #时间-到期月开始 opt.OPT_CONTRACT_INFO.last_trade_date < month_split[1], #时间-到期月结束 opt.OPT_CONTRACT_INFO.list_date < trade_days.index[0]) #在交易前上市 # 对应的期权列表 contract_info = opt.run_query(q_contract_info) # 要先使用trading_code前6位为'510050'过滤 contract_info = contract_info[contract_info['trading_code'].str[:6] == '510050'] # 获取etf第一个交易日的收盘价etf_cls,price_spread是行权价exercise_price和etf价格的差 etf_cls = get_price('510050.XSHG',trade_days.index[0],trade_days.index[0],fields=['close']).values[0][0] contract_info['price_spread'] = contract_info['exercise_price'] - etf_cls if contract_info['price_spread'].max() > 0: #选出认购虚值期权 contract_info = contract_info[contract_info['price_spread'] > 0] contract_info = contract_info.sort_values('exercise_price') else: #全是认购实值期权 contract_info = contract_info.sort_values('exercise_price',ascending=False) holding_contract2[trade_days.index[0]] = contract_info['code'].iloc[0] newest_exercise_price = contract_info['exercise_price'].iloc[0] newest_expire_date = contract_info['last_trade_date'].iloc[0] print(f"newest_exercise_price:{newest_exercise_price}") print(f"newest_expire_date: {newest_expire_date}") print(f"first trading day: {trade_days.index[0]}") print(f"etf_cls: {etf_cls}") # 循环访问每一个交易日,判断交易情况 # 规则:持有略虚值看涨期权,待行权价低于现价的 95% 时,平仓原期权合约 # 重新开仓略虚值看涨期权;到期前1天移仓换月至次月合约 for t in trade_days.index[1:]: the_date = pd.to_datetime(get_trade_days(end_date=pd.to_datetime(newest_expire_date),count=2)[0]) print(f"processing day: {t} data, newest_expire_date: {newest_expire_date}, the_date: {the_date}") #到期前一天 if t >= the_date: print(f"{t} 晚于 the_date: {the_date} 日期") #寻找month_idx for month_idx in range(len(month_split)): if month_split[month_idx] >= t: break q_contract_info = query(opt.OPT_CONTRACT_INFO.code, opt.OPT_CONTRACT_INFO.trading_code, opt.OPT_CONTRACT_INFO.name, opt.OPT_CONTRACT_INFO.exercise_price, opt.OPT_CONTRACT_INFO.last_trade_date, opt.OPT_CONTRACT_INFO.list_date ).filter(opt.OPT_CONTRACT_INFO.contract_type == 'CO', #看涨期权 opt.OPT_CONTRACT_INFO.exchange_code == 'XSHG', #上交所 opt.OPT_CONTRACT_INFO.last_trade_date > month_split[month_idx], #时间-到期月开始 opt.OPT_CONTRACT_INFO.last_trade_date <= month_split[month_idx+1], #时间-到期月结束 opt.OPT_CONTRACT_INFO.list_date < t) #在交易前上市 contract_info = opt.run_query(q_contract_info) print(f"contract_info in the 1st step: {contract_info.head()}") etf_cls = get_price('510050.XSHG',t,t,fields=['close']).values[0][0] #现货收盘价 contract_info['price_spread'] = contract_info['exercise_price'] - etf_cls print(f"contract_info in the 2nd step: {contract_info.head()}") if contract_info['price_spread'].max() > 0: contract_info = contract_info[contract_info['price_spread'] > 0] #选出虚值期权 contract_info = contract_info.sort_values('exercise_price') else: #全是实值期权 contract_info = contract_info.sort_values('exercise_price',ascending=False) print(f"contract_info in the 3rd step: {contract_info.head()}") if contract_info['last_trade_date'].iloc[0] >= newest_expire_date: holding_contract2[t] = contract_info['code'].iloc[0] newest_exercise_price = contract_info['exercise_price'].iloc[0] newest_expire_date = contract_info['last_trade_date'].iloc[0] else: print(f"{t} 早于 newest_expire_date: {newest_expire_date} 日期") #获取昨日50etf收盘价 pre_cls = get_price('510050.XSHG',t,t,fields=['pre_close']).values[0][0] if pre_cls*0.95 >= newest_exercise_price: #原虚值变为实值,重新开仓略虚值期权 #寻找 month_idx for month_idx in range(len(month_split)): if month_split[month_idx] >= t: break q_contract_info = query(opt.OPT_CONTRACT_INFO.code, opt.OPT_CONTRACT_INFO.trading_code, opt.OPT_CONTRACT_INFO.name, opt.OPT_CONTRACT_INFO.exercise_price, opt.OPT_CONTRACT_INFO.last_trade_date, #行权价格,最后交易日 opt.OPT_CONTRACT_INFO.list_date ).filter(opt.OPT_CONTRACT_INFO.contract_type == 'CO', #看涨期权 opt.OPT_CONTRACT_INFO.exchange_code == 'XSHG', #上交所 opt.OPT_CONTRACT_INFO.last_trade_date > month_split[month_idx-1], #时间-到期月开始 opt.OPT_CONTRACT_INFO.last_trade_date <= month_split[month_idx], #时间-到期月结束 opt.OPT_CONTRACT_INFO.list_date < t) #在交易前上市 contract_info = opt.run_query(q_contract_info) etf_cls = get_price('510050.XSHG',t,t,fields=['close']).values[0][0] contract_info['price_spread'] = contract_info['exercise_price'] - etf_cls if contract_info['price_spread'].max() > 0: contract_info = contract_info[contract_info['price_spread'] > 0] #选出虚值期权 contract_info = contract_info.sort_values('exercise_price') else: #全是实值期权 contract_info = contract_info.sort_values('exercise_price',ascending=False) if contract_info['last_trade_date'].iloc[0] >= newest_expire_date: holding_contract2[t] = contract_info['code'].iloc[0] newest_exercise_price = contract_info['exercise_price'].iloc[0] newest_expire_date = contract_info['last_trade_date'].iloc[0] holding_contract2 = holding_contract2.fillna(method='ffill') holding_contract2 data2 = pd.DataFrame(holding_contract2) data2.columns = ['holding_contract'] data2 = data2.reindex(columns=['holding_contract','close','last_close']) last_contract = holding_contract2.iloc[0] #记录上个持仓 for t in data2.index: if last_contract == data2.loc[t,'holding_contract']: #期权未换仓 #收盘价 q_price = query(opt.OPT_DAILY_PRICE.code, opt.OPT_DAILY_PRICE.date, opt.OPT_DAILY_PRICE.close, ).filter(opt.OPT_DAILY_PRICE.code==last_contract, opt.OPT_DAILY_PRICE.date==t) price = opt.run_query(q_price)['close'][0] data2.loc[t,'close'] = price else: #收盘价,新 q_price = query(opt.OPT_DAILY_PRICE.code, opt.OPT_DAILY_PRICE.date, opt.OPT_DAILY_PRICE.close, ).filter(opt.OPT_DAILY_PRICE.code==data2.loc[t,'holding_contract'], opt.OPT_DAILY_PRICE.date==t) price = opt.run_query(q_price)['close'][0] data2.loc[t,'close'] = price #收盘价,旧 q_price = query(opt.OPT_DAILY_PRICE.code, opt.OPT_DAILY_PRICE.date, opt.OPT_DAILY_PRICE.close, ).filter(opt.OPT_DAILY_PRICE.code==last_contract, opt.OPT_DAILY_PRICE.date==t) price = opt.run_query(q_price)['close'][0] data2.loc[t,'last_close'] = price last_contract = data2.loc[t,'holding_contract'] data2 #计算卖出期权的收益 opt_ret2 = pd.Series(0,index=data2.index) pre_close2 = data2['close'].iloc[0] for t in data2.index[1:]: if data2.isna().loc[t,'last_close']: #未换仓,last为空 opt_ret2[t] = -10000*(data2.loc[t,'close'] - pre_close2) else: opt_ret2[t] = -10000*(data2.loc[t,'last_close'] - pre_close2) - 5 #手续费5元 pre_close2 = data2.loc[t,'close'] opt_ret2 #计算持仓收益 etf_price = get_price('510050.XSHG',trade_days.index[0],trade_days.index[-1],fields=['close'])['close'] etf_ret = 10000*etf_price.diff(1).fillna(0) etf_ret #计算净值 init_asset2 = etf_price.iloc[0]*10000 ass2 = init_asset2 + (etf_ret + opt_ret2).cumsum() pfl_ret2 = (ass2/ass2.shift(1) - 1).fillna(0) pfl_nv2 = (1 + pfl_ret2).cumprod() pfl_nv2 #绘制净值图 plt.figure(figsize=(8, 5)) plt.plot(etf_price/etf_price.iloc[0], label='50ETF现货净值') plt.plot(pfl_nv2, label='备兑看涨策略净值') plt.legend(loc='upper left', fontsize='large') plt.xlabel('时间',size=12) plt.ylabel('净值',size=12) plt.show()