指数通常反映了一个行业或者一类股票的行情数据。本文将对697支指数的历史各月涨幅进行分析,为量化投资作一个参考。从分析中,我们可以验证五穷六绝七翻身是否可信,并找出上涨概率最大的一些指数和月份。
1、数据准备
本文程序中用到两个数据:
(1)index20210703.csv:存储了697支指数代码。
(2)2010-2021全部指数K线数据:存储了697支指数的历史K线数据。
指数历史数据获取方式在文末给出。
2、获取某一指数指定时间段内的历史数据
#获取某一指数指定时间段内的历史数据
def y_get_price(stockfile, start_date, end_date):
start_date_time = datetime.strptime(start_date, '%Y-%m-%d')
end_date_time = datetime.strptime(end_date, '%Y-%m-%d')
df_data = pd.read_csv(stockfile)
if date_str_compare(start_date, df_data.iloc[0, 0]) == 0:
start_date = df_data.iloc[0, 0]
if date_str_compare(start_date, end_date) != 0:
end_date = df_data.iloc[-1, 0]
if date_str_compare(start_date, end_date) != 0:
sys.exit('[INFO] 日期范围有误,请更正。')
while start_date not in df_data.iloc[:, 0].values:
start_date_time += timedelta(days=1)
start_date = start_date_time.strftime('%Y-%m-%d')
start_index = df_data[df_data.iloc[:, 0] == start_date].index[0]
while end_date not in df_data.iloc[:, 0].values:
end_date_time -= timedelta(days=1)
end_date = end_date_time.strftime('%Y-%m-%d')
end_index = df_data[df_data.iloc[:, 0] == end_date].index[0] + 1
df_res = df_data.iloc[start_index:end_index, :]
return df_res
3、获取指数历史月涨幅
#获取指数历史月涨幅
def month_increase_ratio(stockfile):
days = ['31', '28', '31', '30', '31', '30', '31', '31', '30', '31', '30', '31']
df_data = pd.read_csv(stockfile)
target_month = '07'
start_date = df_data.iloc[0, 0]
start_date_list = start_date.split('-')
end_date = df_data.iloc[-1, 0]
end_date_list = end_date.split('-')
if int(start_date_list[2]) > 10:
delta_year, month_str = month_add(start_date_list[1], 1)
start_date_list[0] = str(int(start_date_list[0]) + delta_year)
start_date_list[1] = month_str
start_date_list[2] = '01'
start_date = '-'.join(start_date_list)
if int(end_date_list[2])< 20:
delta_year, month_str = month_minus(end_date_list[1], 1)
end_date_list[0] = str(int(end_date_list[0]) - delta_year)
end_date_list[1] = month_str
end_date_list[2] = days[int(month_str) - 1]
end_date = '-'.join(end_date_list)
start_year = int(start_date.split('-')[0])
end_year = int(end_date.split('-')[0]) + 1
res_dict = {i:[] for i in range(1, 13)}
for year in range(start_year, end_year):
for m in range(1, 13):
target_month = str(m).zfill(2)
target_start_date = str(year) + '-' + target_month + '-10'
if date_str_compare(target_start_date, start_date) == 0:
continue
if date_str_compare(end_date, target_start_date) == 0:
continue
target_start_date = str(year) + '-' + target_month + '-01'
target_end_date = str(year) + '-' + target_month + '-' + days[int(target_month) - 1]
# print(target_start_date, target_end_date)
df_tmp = y_get_price(stockfile, target_start_date, target_end_date)
ratio = round((df_tmp.iloc[-1, 2] - df_tmp.iloc[0, 1]) / df_tmp.iloc[0, 1] * 100, 2)
res_dict[m].append(ratio)
return res_dict
4、全部代码
# -*- coding: utf-8 -*-
"""
Created on Sun Jul 4 15:17:02 2021
@author: Administrator
"""
import os
import sys
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
from datetime import timedelta
#比较两个时间字符串的先后顺序
def date_str_compare(date1, date2):
date1 = list(map(int, date1.split('-')))
date2 = list(map(int, date2.split('-')))
if date1[0] < date2[0]:
return 0
elif date1[0] > date2[0]:
return 1
elif date1[1] < date2[1]:
return 0
elif date1[1] > date2[1]:
return 1
elif date1[2] < date2[2]:
return 0
elif date1[2] > date2[2]:
return 1
else:
return 2
#月份加法
def month_add(m0, n):
m = (int(m0) + n)
y = m // 12
m = m % 12
if m == 0:
m = 12
m = str(m).zfill(2)
return y, m
#月份减法
def month_minus(m0, n):
m = (int(m0) - n)
if m > 0:
y = 0
else:
y = abs(m) // 12 + 1
m = m + 12 * y
if m == 0:
m = 12
m = str(m).zfill(2)
return y, m
#获取某一指数指定时间段内的历史数据
def y_get_price(stockfile, start_date, end_date):
start_date_time = datetime.strptime(start_date, '%Y-%m-%d')
end_date_time = datetime.strptime(end_date, '%Y-%m-%d')
df_data = pd.read_csv(stockfile)
if date_str_compare(start_date, df_data.iloc[0, 0]) == 0:
start_date = df_data.iloc[0, 0]
if date_str_compare(start_date, end_date) != 0:
end_date = df_data.iloc[-1, 0]
if date_str_compare(start_date, end_date) != 0:
sys.exit('[INFO] 日期范围有误,请更正。')
while start_date not in df_data.iloc[:, 0].values:
start_date_time += timedelta(days=1)
start_date = start_date_time.strftime('%Y-%m-%d')
start_index = df_data[df_data.iloc[:, 0] == start_date].index[0]
while end_date not in df_data.iloc[:, 0].values:
end_date_time -= timedelta(days=1)
end_date = end_date_time.strftime('%Y-%m-%d')
end_index = df_data[df_data.iloc[:, 0] == end_date].index[0] + 1
df_res = df_data.iloc[start_index:end_index, :]
return df_res
#获取指数历史月涨幅
def month_increase_ratio(stockfile):
days = ['31', '28', '31', '30', '31', '30', '31', '31', '30', '31', '30', '31']
df_data = pd.read_csv(stockfile)
target_month = '07'
start_date = df_data.iloc[0, 0]
start_date_list = start_date.split('-')
end_date = df_data.iloc[-1, 0]
end_date_list = end_date.split('-')
if int(start_date_list[2]) > 10:
delta_year, month_str = month_add(start_date_list[1], 1)
start_date_list[0] = str(int(start_date_list[0]) + delta_year)
start_date_list[1] = month_str
start_date_list[2] = '01'
start_date = '-'.join(start_date_list)
if int(end_date_list[2])< 20:
delta_year, month_str = month_minus(end_date_list[1], 1)
end_date_list[0] = str(int(end_date_list[0]) - delta_year)
end_date_list[1] = month_str
end_date_list[2] = days[int(month_str) - 1]
end_date = '-'.join(end_date_list)
start_year = int(start_date.split('-')[0])
end_year = int(end_date.split('-')[0]) + 1
res_dict = {i:[] for i in range(1, 13)}
for year in range(start_year, end_year):
for m in range(1, 13):
target_month = str(m).zfill(2)
target_start_date = str(year) + '-' + target_month + '-10'
if date_str_compare(target_start_date, start_date) == 0:
continue
if date_str_compare(end_date, target_start_date) == 0:
continue
target_start_date = str(year) + '-' + target_month + '-01'
target_end_date = str(year) + '-' + target_month + '-' + days[int(target_month) - 1]
# print(target_start_date, target_end_date)
df_tmp = y_get_price(stockfile, target_start_date, target_end_date)
ratio = round((df_tmp.iloc[-1, 2] - df_tmp.iloc[0, 1]) / df_tmp.iloc[0, 1] * 100, 2)
res_dict[m].append(ratio)
return res_dict
#获取涨幅比例大于零的比例
def increase_times_ratio(mir):
itr = mir.copy()
for key in mir.keys():
x = mir[key]
if len(x) == 0:
itr[key] = 0
else:
r = round(np.count_nonzero(np.array(x) > 0)/len(x), 2)
itr[key] = r
return itr
if __name__ == '__main__':
mir_list = []
itr_list = []
df_data = pd.read_csv('index20210703.csv')
df_index = df_data.iloc[:, 0].tolist()
df_display_name = df_data.iloc[:, 1].tolist()
if not (os.path.exists('mir.npy') and os.path.exists('m_itr.npy')):
for i in range(0, len(df_index)):
stockfile = '../../Data/2010-2021全部指数K线数据/' + df_index[i] + '.csv'
#每个月历年涨幅
mir = month_increase_ratio(stockfile)
#每个月历年上涨次数统计
mir_list.append(mir)
itr = increase_times_ratio(mir)
itr_list.append(itr)
if (i+1) % 50 == 0:
print('[INFO] {}/{} processed.'.format(i+1, len(df_index)))
np.save('mir.npy', mir_list)
np.save('m_itr.npy', itr_list)
print('[INFO] completed.')
#加载计算得到的数据
mir_list = np.load('mir.npy', allow_pickle=True)
itr_list = np.load('m_itr.npy', allow_pickle=True)
#用A股指数验证无穷六绝七翻身是否正确
#结果看到五月六月上涨比例为0.5,也就是上涨概率为50%,而7月份为65%。
#看来似乎有一定道理,但是这种效应确并不是很显著,65%概率也只是比蒙高出一点点。
mir = mir_list[1]
itr = itr_list[1]
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.plot(range(3, 13), list(itr.values())[2:], marker='.', color='blue', linewidth=1.0, label='A股上涨次数比例')
plt.legend()
plt.show()
print(itr)
#筛选历史月份数量至少有8个月,且上涨次数比例大于0.95
select_index = []
for i in range(len(mir_list)):
mir = mir_list[i]
itr = itr_list[i]
for j in range(1, 13):
#历史月份数量至少有8个月,且上涨次数比例大于0.95
if len(mir[j]) < 8 or itr[j] < 0.95:
del mir[j]
del itr[j]
if len(mir) != 0:
select_index.append(i)
if (i+1) % 50 == 0:
print('[INFO] {}/{} processed.'.format(i+1, len(mir_list)))
print('[INFO] 历史上涨次数比例为100%的指数和月份依次如下:')
for i in select_index:
temp_str = ''
for m in itr_list[i].keys():
temp_str += str(m) + '月、'
print('[INFO] {}、{}: {}'.format(i+1, df_display_name[i], temp_str))
print('[INFO] completed.')
5、验证五穷六月七翻身
#用A股指数验证无穷六绝七翻身是否正确。
#结果看到五月六月上涨比例为0.5,也就是上涨概率为50%,而7月份为65%。
#看来似乎有一定道理,但是这种效应确并不是很显著,65%概率也只是比蒙高出一点点。
相比之下一二月份规律更加明显,具体规律请参考数据获取部分,运行代码即可。

6、数据获取方式
(1)index20210703.csv:关注"量化之窗"公众号,并输入zsdm”。
(2)2010-2021全部指数K线数据:关注"量化之窗"公众号,并输入“zskxsj”。
(3)获取历史月涨幅概率为100%的指数名称和月份:关注"量化之窗"公众号,并输入“mp100”

如有疑问,请在文章下方留言。

被折叠的 条评论
为什么被折叠?



