指数历年各月涨幅分析-验证五穷六绝七翻身是否可信

指数通常反映了一个行业或者一类股票的行情数据。本文将对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”

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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Coding的叶子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值