上次那个代码有很多问题,大改了一下
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 加载ETF数据
df = pd.read_csv("C:/Users/z'z'z/Desktop/50ETF_daily.csv")
# 数据清理,移除非日期格式的行
df = df[pd.to_datetime(df['日期'], errors='coerce').notna()]
# 将'日期'列转换为datetime类型
df['日期'] = pd.to_datetime(df['日期'], format='%Y/%m/%d')
# 按日期排序
df = df.sort_values('日期')
# 生成完整日期范围
date_range = pd.date_range(df['日期'].min(),df['日期'].max() , freq='D')
full_dates = pd.DataFrame(date_range, columns=['日期'])
# 合并原始数据和完整日期表
df = pd.merge(full_dates, df, on='日期', how='left')
# 填充缺失的数据(这里假设用前一天的数据填充)
df.fillna(method='ffill', inplace=True)
# 设定均线长度
short_window = 20 # 短期均线
long_window = 50 # 长期均线
# 计算均线
df['短期均线'] = df['收盘'].rolling(window=short_window, min_periods=1).mean()
df['长期均线'] = df['收盘'].rolling(window=long_window, min_periods=1).mean()
# 生成买卖信号
df['信号'] = 0.0
df.loc[short_window:, '信号'] = (df['短期均线'] > df['长期均线']).astype(float)
df.loc[short_window:, '信号'] = df.loc[short_window:, '信号'].replace({True: 1.0, False: -1.0})
df['仓位'] = df['信号'].diff()
signal_df = df[['日期', '信号']]
# 生成完整日期范围
date_range = pd.date_range(df['日期'].min(),df['日期'].max() , freq='D')
full_dates = pd.DataFrame(date_range, columns=['日期'])
# 合并信号表和完整日期表
merged_df = pd.merge(full_dates, signal_df, on='日期', how='left')
# 填充缺失的信号值(这里假设缺失的信号为0.0)
merged_df['信号'] = merged_df['信号'].fillna(0.0)
output_file = r"C:\Users\z'z'z\Desktop\ETF_signal_output.xlsx"
merged_df.to_excel(output_file, index=False)
# 在这之后继续进行后续的信号处理和投资组合交易记录的逻辑
print(f"买卖信号已导出到文件:{output_file}")
# 加载期权数据
option_df = pd.read_csv("C:/Users/z'z'z/Desktop/50ETF期权日收盘行情2016.csv")
option_df['交易日期'] = pd.to_datetime(option_df['交易日期'], format='%Y-%m-%d')
option_df['收盘价'] = pd.to_numeric(option_df['收盘价'], errors='coerce')
option_df['成交量(手)'] = pd.to_numeric(option_df['成交量(手)'], errors='coerce')
option_df['到期日'] = pd.to_datetime(option_df['到期日'], format='%Y-%m-%d')
option_df['行权价'] = pd.to_numeric(option_df['行权价'], errors='coerce')
# 初始化资金
initial_funds = 1000000
current_funds = initial_funds
investment_amount = 1 # 每次投资数量(固定金额或固定比例)
# 构造投资组合并记录交易和每日收益率
portfolio = []
daily_returns = [] # 记录每日收益率
cumulativ_return=[]
# 根据信号选择期权合约并记录交易
for index, row in merged_df.iterrows():
#print(1)
signal = row['信号']
date = row['日期']
current_funds_prev = current_funds
profit = 0
cash_value = 0 #当日产生的全部损益
cash=0
portfolio_value=0
new_portfolio=[]
# 对冲之前构造的期权策略
# 清除牛市价差策略
# 处理投资组合
for holding in portfolio:
if (signal == -1.0 and holding['信号'] == 1.0) or (signal == 1.0 and holding['信号'] == -1.0):
portfolio.remove(holding)
option_type = '购' if signal == -1.0 else '沽'
options = option_df[(option_df['交易日期'] == date) & (option_df['合约名称'].str.contains(option_type))]
if not options.empty:
# 找到对应的买入和卖出期权合约
option1 = options[options['合约名称'] == holding['买入合约名称']].iloc[0]
option2 = options[options['合约名称'] == holding['卖出合约名称']].iloc[0]
# 对于找不到期权的情况,输出警告并跳过对冲操作
if option1.empty or option2.empty:
print(f"未找到对应的期权合约进行对冲,日期:{date}")
new_portfolio.append(holding)
continue
else:
sell_price = option1['收盘价']
buy_price = option2['收盘价']
cash = (sell_price - buy_price) * investment_amount * 10000
cash_value += cash # 更新现金损益
if signal!=0:
option_type = '购' if signal == 1.0 else '沽'
options = option_df[(option_df['交易日期'] == date) & (option_df['合约名称'].str.contains(option_type))]
if not options.empty:
# 选择较低执行价的看涨期权
if option_type =='购':
option1 = options.sort_values(by=['行权价']).iloc[0]
# 选择与较低执行价期权到期日相同且执行价较高的看涨期权
options = options[(options['行权价'] > option1['行权价']) & (options['到期日'] == option1['到期日'])]
else:
# 选择较高执行价的看跌期权
option1 = options.sort_values(by=['行权价'], ascending=False).iloc[0]
# 选择与较高执行价期权到期日相同且执行价较低的看跌期权
options = options[(options['行权价'] < option1['行权价']) & (options['到期日'] == option1['到期日'])]
if not options.empty:
option2 = options.sort_values(by=['行权价']).iloc[0]
buy_price = option1['收盘价']
sell_price = option2['收盘价']
cash= (sell_price - buy_price) * investment_amount * 10000 #负的
if current_funds >= -cash:
cash_value+=cash
portfolio.append({
'交易日期': date,
'买入合约名称':option1['合约名称'],
'买入价格': buy_price,
'行权价1': option1['行权价'],
'卖出合约名称': option2['合约名称'],
'卖出价格': sell_price,
'行权价2': option2['行权价'],
'信号': signal,
'到期日': option1['到期日']
})
else:
portfolio.append({
'交易日期': date,
'买入合约名称':'',
'买入价格': '',
'行权价1': '',
'卖出合约名称': '',
'卖出价格': '',
'行权价2': '',
'信号': signal,
'到期日': ''
})
cash=0 #、今日到期,单个期权组合行权后现金损益
value=0 #未到期,未被清除单个期权组合价值
for holding in portfolio:
price = df[df['日期'] == date]['收盘'].values[0]
if holding['信号'] == 1.0:
if price <= holding['行权价1']:
value=cash = 0
elif price >= holding['行权价2']:
value=cash = (holding['行权价2'] - holding['行权价1'])*10000
else:
value=cash = (price - holding['行权价1'])*10000
elif holding['信号'] == -1.0:
if price >= holding['行权价2']:
value=cash =0
elif price <= holding['行权价1']:
value=cash = (holding['行权价1'] - holding['行权价2'])*10000
else:
value=cash = (holding['行权价2'] - price)*10000
if holding['到期日'] ==date:
portfolio.remove(holding)
cash_value+=cash # 今日到期,单个期权组合行权后现金损益的加总
else:
portfolio_value+= value #未到期,未被清除期权组合价值的加总
current_funds=current_funds_prev +cash_value
value=current_funds+portfolio_value
b=(value-initial_funds)/initial_funds
a=(current_funds-initial_funds)/initial_funds
cumulativ_return.append({'日期':date,'累计收益率':b})
# 转换为DataFrame
returns_df = pd.DataFrame(cumulativ_return)
# 导出投资组合和收益率
portfolio_df = pd.DataFrame(portfolio)
portfolio_df.to_excel(r"C:\Users\z'z'z\Desktop\Portfolio.xlsx", index=False)
returns_df.to_excel(r"C:\Users\z'z'z\Desktop\Returns.xlsx", index=False)
print(f"投资组合和收益率已导出到文件:Portfolio.xlsx 和 Returns.xlsx")
# 绘制收益率图表
plt.figure(figsize=(14, 7))
.plot(returns_df['日期'], returns_df['累计收益率'], label='策略累计收益率')
plt.title('策略累计收益率')
plt.xlabel('日期')
plt.ylabel('累计收益率')
plt.legend()
plt.show()