pandas计算主力合约收益率

数据:

链接:https://pan.baidu.com/s/1XGfITsSWdP_c1_wFepUs0A 
提取码:b880

特殊处理:

考虑到换月不同合约的数据会有较大差异,避免在计算收益率时在换月时间点使用两个合约的数据,对数据作如下处理:
处理逻辑:
1). 换月日(即切换为新合约的第一日)需要有前一个主力合约的数据和下一个主力合约的数据
2). 换月日的收益率=(前一个主力合约换月日收盘价-前一个主力合约换月日前一日收盘价)/前一个主力合约换月日前一日收盘价
3). 换月日第二日收益率=(新主力合约换月日第二日收盘价-新主力合约换月日收盘价)/新主力合约换月日收盘价
计算方法:
1). 在新表中(res_pd)中增加一列pre_ticker,这一列是ticker列整列向下移动一格,这样在换月日那一行pre_ticker就是前一个主力合约
2). 对ticker列进行分组,获取每组第一行,获取一个新表 three_df
3). 去除 three_df 的第一行,因为第一行不是换月日,是历史上第一个合约
4). 从第一个大表 all_df 中查询 three_df 每行 pre_ticker 对应 date 的 close 值,并覆盖到 three_df 表的 close
5). 对 three_df 进行日期升序排序
6). 对 three_df 增加一个 counter 列填充整数递增
7). 对 res_pd 增加一个 counter 列填充整数递增
8). 将 res_pd 和 three_df 合并成一个表 four_df
9). 对 four_df 进行 date 和 counter 升序排序,排序优先级为先date后counter
10). 计算收益率列
11). 对 date 列进行去重,保留重复数值的第一个
至此,主力合约收益率计算完毕

计算过程(jupyter notebook):

import os
import numpy as np
import pandas as pd
# if_list文件夹中是每个合约的日数据
dir = r'./if_list/'
file_list = os.listdir(dir)
# 将所有合约读出,合并到一个大表中
all_df = None
for file_name in file_list:
    ticker = file_name[0:-4]
    file_path = dir + file_name
    df = pd.read_csv(file_path,encoding='utf-8',header=0,names=['date','open','close','low','high','volume','money','factor','high_limit','low_limit','avg','pre_close','paused','open_interest'])
    df['ticker'] = ticker
    if all_df is None:
        all_df = df
    else:
        all_df = pd.concat([all_df,df])

# 这个方法是对 成交量 和 持仓量 进行降序排序(即由大到小),排序优先级为先成交量后持仓量;排序后把第一行返回
def get_biggest_openinterest(x):
    df = x.sort_values(['volume','open_interest'],ascending=[False,False])
    return df.iloc[0,:]
# 对所有合约合成的大表 all_df 按日期进行分组,每个日期的组里提取出成交量和持仓量最大的行 组成一个新的表 res_pd
all_df['date'] = pd.to_datetime(all_df['date'])
all_df.sort_values(by='date')
res_pd = all_df.groupby('date').apply(get_biggest_openinterest)
# 检查合约是否连续,一般是连续的,万一有不连续的,再手动处理
# 检查方法:提取每组的日期存入列表,然后对日期进行校验,确保每一组最早的那个日期都不会早于前一组的所有的日期,满足这个条件说明是连续合约
res_pd.sort_index(inplace=True)
res_group = res_pd.groupby('ticker')
results_list = []
for name,group in res_group:
    results_list.append(group['date'].tolist())
for i in range(len(results_list)-1):
    pre_list = results_list[i]
    now_first = results_list[i+1][0]
    for item in pre_list:
        if item >= now_first:
            print(item,now_first)
            break
# 将合约数据整列往下推一格,这样换月日那行数据里pre_ticker字段就是前一个主力合约
res_pd['pre_ticker'] = res_pd['ticker'].shift(1)
# 对表 res_pd 按合约进行分组,取每组第一行数据,组成一个新表 three_df, 该表除第一行外每一行都是换月日
three_df = res_pd.groupby('ticker').head(1)
three_df = three_df.iloc[1:,:]
three_df.head()

# 新增一个字段 origi_close 用于存储原始的 close 字段数据,后续的计算会将 close 原来的值覆盖
three_df['origi_close'] = three_df['close']
# 遍历three_df的每行,将换月日对应的前一个主力合约的收盘价填入close 字段
all_df['date'] = pd.to_datetime(all_df['date'])
for index,row in three_df.iterrows():
    row_res = all_df.loc[(all_df['date']==row['date']) & (all_df['ticker'].str.startswith(row['pre_ticker']))]
    res_list = row_res['close'].values.tolist()
    if len(res_list)<=0:
        continue
    three_df.at[index,'close'] = res_list[0]

three_df.sort_index(inplace=True)
three_df = three_df.loc[:,['date','close','volume','open_interest','ticker','pre_ticker','origi_close']]
res_df = res_pd.loc[:,['date','close','volume','open_interest','ticker','pre_ticker']]
res_df.sort_index(inplace=True)
# 下面将three_df和res_df整合到一起时,每个换月日会有两行,要保留有用的一行,three_df提供的行是要保留的,所以通过counter实现
three_df['counter'] = range(len(three_df))
res_df['counter'] = range(len(res_df))
# 将两个表整合到一起,形成一个新表 four_df
four_df = pd.concat([three_df,res_df])
# 后续要对date和counter进行排序,date作为索引不能与值之间同时排序,所以重置索引
four_df.reset_index(drop=True,inplace=True)
# 对表four_df进行排序,升序排序(即从小到大),排序优先级先date后counter, 由于从小到达,three_df的行都是换月日的行,所以换月日对应的counter的值总是比res_df中换月日对应的counter小,所以在升序排序中,总是排在前面
four_df.sort_values(['date','counter'],ascending=[True,True],inplace=True)
# 计算收益率
four_df['pe'] = (four_df['close'] - four_df['close'].shift(1))/four_df['close'].shift(1)
# 将换月日重复的行去掉,只保留有效的行
four_df.drop_duplicates(subset='date',keep='first',inplace=True)




至此,four_df 即为最终需要的收益率数据

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值