上一次简单的做了大盘股指的移动平滑预测,但在实际中,变化时受到多种因素影响的
所以这次基于上次的基础,用python来进行股票价格的多元线性预测
那么先明确一下预测的目的,得到某支股票的拟合模型,用来预测它在第二天或者未来的最低价(抄底),最高价(脱手)。
不专业的简单分析下多元有那些元:
1.大概会跟昨天的振幅和涨跌幅有关,毕竟如果看到昨天在跌可能就会犹豫买入
2.跟昨天的价格有关,可能资金有限,操作的时候股票的价格会影响买入态度
3.跟昨天的成交量有关,可能昨天成交了特别多导致今天有人跟风
4.跟节假日休市时间有关,可能之前放假回来后出现上扬,或者接下来准备休市三天小长假很多人开始割肉收回款项
5.另外,肯定也跟大盘的变化,公司的市值,行业的景气情况等等有关,但是考虑到数据的来源复杂性,就不纳入本次学习的研究范围。
下面的内容代码部分可以跳过阅读,在最后附上所有的代码
一、 获取下数据:
#1.get请求
shuju = requests.get(URL) #用requests模块请求网页
#整理得到的数据
liebiao_1= re.split(r'\[',shuju.content.decode('utf-8'))[-1] #把字符串按方括号[切割取后面部分
liebiao_2 = re.split(r']',liebiao_1)[0] #把字符串按方括号]切割取前面部分
liebiao_3 = re.split(r'","|"',liebiao_2) #把字符串按引号和逗号切割
liebiao = [] #建立一个空列表
for x in liebiao_3: #遍历原先切割字符串等得到的列表
if x != '': #剔除空集
liebiao.append(x) #放回空列表
Shuangxiang = {}
#"日期,开盘,收盘,最高,最低,成交量,成交额,振幅,不知道是啥"
#有:T_1(前面有没有放假),T_2(后面有没有放假),Zkai,Zshou,Zmax,Zmin,Zdeal,ZE,Zfu,ZX,Zcha=(Zshou-Zkai)/Zkai,,F容错
for i in range(0,len(liebiao)): #遍历数据的行数
Shuangxiang['第'+str(i+1)+'行'] = {} #生成行字典
i_biao = re.split(r',',liebiao[i]) #对数据按逗号再切割
for k in range(0,len(i_biao)): #遍历切割好的数据到行列表下的列键
if k+1 ==1:
Shuangxiang['第' + str(i + 1) + '行']['第' + str(k + 1) + '列'] = day_num(i_biao[k])
else:
if '%' in i_biao[k]:
m = float(re.split(r'%', i_biao[k])[0])/100
Shuangxiang['第' + str(i + 1) + '行']['第' + str(k + 1) + '列'] = m
else:
if i_biao[k] == '-':
m = float(0)
Shuangxiang['第' + str(i + 1) + '行']['第' + str(k + 1) + '列'] = m
else:
Shuangxiang['第' + str(i + 1) + '行']['第' + str(k + 1) + '列'] = float(i_biao[k])
通过类似上一次的操作,我们能够得到N组这样的数据:
日期 | 开盘 | 收盘 | 最高 | 最低 | 成交量 | 成交额 | 振幅 | 不知道是啥 |
---|---|---|---|---|---|---|---|---|
2019-09-20 | 23.05 | 23.44 | 23.67 | 22.73 | 8795 | 20393557 | 4.1% | 0.49 |
当然,实际上在代码中已经处理了几个数据:
1. 振幅是带有百分号的字符串所以重新去掉百分号转换成浮点数据
2. 有时存在数据缺失,比如刚刚上市的时候,系统获取的数据时-号,用0替换掉
3. 日期的显示通过一个day_num()函数转化为了日序数,便于计算上一次交易和下一次交易的时间间隔,day_num()函数:
#用于识别2019-09-20类型日期,便于计算两组数据之间的时间间隔
def day_num(y_m_d):
import time
daynum = time.mktime(time.strptime(y_m_d,"%Y-%m-%d"))/int(86400)
return daynum
二、 对数据进行处理
我们需要用于多元分析的数据应为:
第1列 | 第2列 | 第3列 | 第4列 | 第5列 | 第6列 | 第7列 | 第8列 | 第9列 | 第10列 | 第11列 | 第12列 | 第13列 | 第14列 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
日期 | 开盘 | 收盘 | 最高 | 最低 | 成交量 | 成交额 | 振幅 | 不知是啥 | 已休市 | 预备休市 | 涨跌幅 | 次日最低价 | 次日最高价 |
日期 | X1 | X2 | X3 | X4 | X5 | X6 | X7 | X8 | X9 | X10 | X11 | Y1 | Y2 |
得到的两个模型应该为:
AX1+BX2+CX3+DX4+EX5+FX6+GX7+HX8+IX9+JX10+KX11+F容错=Y1次日最低价
aX1+ bX2+ cX3+dX4+ eX5+fX6+ gX7+ hX8+ iX9+jX10+ kX11+ f容错=Y2次日最高价
# 第10列为向前减天数(已放假)
for i in list(range(1,len(Shuangxiang)+1)):
if i == 1:
Shuangxiang['第' + str(i) + '行']['第' + str(10) + '列'] = 0
else:
Shuangxiang['第'+str(i)+'行']['第'+str(10)+'列'] = Shuangxiang['第'+str(i)+'行']['第'+str(1)+'列']-Shuangxiang['第'+str(i-1)+'行']['第'+str(1)+'列']-1
# 第11列为向后减天数(预备放假)
for i in list(range(1,len(Shuangxiang)+1)):
if i == len(Shuangxiang):
day_last = Shuangxiang['第'+str(i)+'行']['第'+str(1)+'列']*86400
import time
Week = int(time.strftime("%w", time.localtime(day_last)))
if Week == 5:
Shuangxiang['第' + str(i) + '行']['第' + str(11) + '列'] = float(2)
else:
Shuangxiang['第' + str(i) + '行']['第' + str(11) + '列'] = float(0)
else:
Shuangxiang['第'+str(i)+'行']['第'+str(11)+'列'] = Shuangxiang['第'+str(i+1)+'行']['第'+str(1)+'列']-Shuangxiang['第'+str(i)+'行']['第'+str(1)+'列']-1
# 第12列为涨跌幅(Zshou-Zkai)/Zkai,收在第三列,开在第二列
for i in list(range(1,len(Shuangxiang)+1)):
Shuangxiang['第'+str(i)+'行']['第'+str(12)+'列'] = (Shuangxiang['第'+str(i)+'行']['第'+str(3)+'列']-Shuangxiang['第'+str(i)+'行']['第'+str(2)+'列'])/Shuangxiang['第'+str(i)+'行']['第'+str(2)+'列']
# 第13列为后一天的最低价,第14列为后一天的最高价,及用前一天的所有数据求出与后一天这两个值的系数关系
for i in list(range(1,len(Shuangxiang)+1)):
if i == len(Shuangxiang):
Shuangxiang['第' + str(i) + '行']['第' + str(13) + '列'] = 0
Shuangxiang['第' + str(i) + '行']['第' + str(14) + '列'] = 0
else:
Shuangxiang['第'+str(i)+'行']['第'+str(13)+'列'] = Shuangxiang['第'+str(i+1)+'行']['第'+str(5)+'列']
Shuangxiang['第'+str(i)+'行']['第'+str(14)+'列'] = Shuangxiang['第'+str(i+1)+'行']['第'+str(4)+'列']
三、 对数据进行计算
这里主要用了一个第三方库
介绍一下这个第三方库,当然,也能百度到
import numpy as np
X_zu = [[X11,X12,X13]
[X21,X22,X23]
[X31,X32,X33] ]
Y_zu = [y1,y2,y3]
xishu = np.linalg.solve(X_zu,Y_zu)
#可以得到aX11+bX12+cX13=y1
aX21+bX22+cX23=y2
aX31+bX32+cX33=y3方程组的系数解
的系数,结果为[a,b,c]
得到K1,K2分别为两个模型的系数列表
把两个表复制到另外两个列表上写到Excel里面看下系数的变化
KK1 = []
KK2 = []
for m in K1:
KK1.append(m)
for n in K2:
KK2.append(n)
for m in range(0,len(KK1)):
for m_i in range(0,len(KK1[m])):
KK1[m][m_i]= str(KK1[m][m_i])
for n in range(0,len(KK2)):
for n_i in range(0,len(KK2[n])):
KK2[n][n_i]= str(KK2[n][n_i])
for m in range(0,len(KK1)):
KK1[m] = '\t'.join(KK1[m])
for n in range(0,len(KK2)):
KK2[n] = '\t'.join(KK2[n])
kk1 = '\n'.join(KK1)
kk2 = '\n'.join(KK2)
lujing = input('路径:')
save_excel(kk1,lujing,'k1','xls')
save_excel(kk2,lujing,'k2','xls')
导出后在EXCEL里用折线图看下变化
选了K1中11个数据的前两个来看,在某些时候,所有的系数都会出现同时性的异常变化,然后又恢复到稳定平缓的区间内
所以这个时候,如果剔除掉这些极值的变化,是否就意味着得到了误差较小的模型系数
那么简单剔除这些极值后求下平均
#复制一下列表,不改变原始列表数据
KK1 = []
KK2 = []
for m in K1:
KK1.append(m)
for n in K2:
KK2.append(n)
Min_xishu = [] #次日最低价模型系数
for m in KK1:
m_jizhi = sum(Maxbox(m))+sum(Minbox(m))
m_pingjun = (sum(m)-m_jizhi)/(len(m)-len(Maxbox(m))-len(Minbox(m)))
Min_xishu.append(m_pingjun)
Max_xishu = [] #次日最低价模型系数
for n in KK2:
n_jizhi = sum(Maxbox(n))+sum(Minbox(n))
n_pingjun = (sum(n)-n_jizhi)/(len(n)-len(Maxbox(n))-len(Minbox(n)))
Max_xishu.append(n_pingjun)
得到两个模型的较为平缓的系数列表
[-9.87415007673367, 14.446784122123194, 1.010947292700218, -0.6713494282167548, 0.004399760010864537, 3.3945343773612057e-09, -21.086355791490657, -7.300150600152714, -0.059418146292691564, -0.023176762967006607, -187.71050254233998]
[-11.61087869160444, 12.975152480636996, 5.314732749838108, -4.383161888273938, 0.006608535250453917, -5.837076664947736e-07, -105.80464849744256, -10.279447137600293, -0.009796891546675993, 0.030801842614598465, -194.7853503579903]
如果实际使用的时候,不删减小数点后面的数值自然更为精准,但是在这里我们删减一下得到两个模型方程;
日期 | 开盘 | 收盘 | 最高 | 最低 | 成交量 | 成交额 | 振幅 | 不知是啥 | 已休市 | 预备休市 | 涨跌幅 | 次日最低价 | 次日最高价 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
日期 | X1 | X2 | X3 | X4 | X5 | X6 | X7 | X8 | X9 | X10 | X11 | Y1 | Y2 |
次日最低价=-9.87×开盘价+14.45×收盘价+1.01×最高价-0.67×最低价+0.004×成交量+0.0000000003×成交额-21.09×振幅-7.30×未知参数-0.059×已休市天数-0.023×预备休市天数-187.7×涨跌幅+容错
可以看到,成交量和额的影响微乎其微
这里的容错是通过公式回测后,得到预测值和实际值之间的偏差数值的平均常数或误差函数
实际上,股票价格上升和下降时的变化应该是不一样的,因素的影响也是不一样的,所以实际操作中,最好将上涨和下跌做两个模型来进行分析
本次学习的代码:
URL = "http://pdfm.eastmoney.com/EM_UBG_PDTI_Fast/api/js?rtntype=5&token=4f1862fc3b5e77c150a2b985b12db0fd&cb=jQuery18302552622653333736_1569140962147&id=0023952&type=k&authorityType=&_=1569140965266"
import re
import requests
import numpy as np
#在单独表字典中单独读取某行某列的一段数据为列表
def quhang(zidian,hang,lie1,lie2):
liebiao = []
for i in list(range(lie1,lie2+1)):
x = zidian['第'+str(hang)+'行']['第'+str(i)+'列']
liebiao.append(x)
return liebiao
def qulie (zidian,lie,hang1,hang2):
liebiao = []
for i in list(range(hang1,hang2+1)):
x = zidian['第'+str(i)+'行']['第'+str(lie)+'列']
liebiao.append(x)
return liebiao
#用于识别2019-09-20类型日期,便于计算两组数据之间的时间间隔
def day_num(y_m_d):
import time
daynum = time.mktime(time.strptime(y_m_d,"%Y-%m-%d"))/int(86400)
return daynum
#把特定的字符串写入特定路径按特定名和格式保存
def save_excel(baocunduixiang,wenjianjialujing,baocunming,geshihouzhui):
baocunming = str(baocunming) #指定保存名
LUJING_NEW = wenjianjialujing + '\\' + baocunming + '.'+ geshihouzhui #拼装最终路径
f = open(LUJING_NEW, 'w') # 在目的路径声明一个文件及格式并打开
f.write(baocunduixiang) # 把处理好的信息写入这个文件
f.close() # 关闭写入操作
#极大值极小值
def Maxbox(liebiao):
Maxbox_num = []
for i in range(0,len(liebiao)):
if i == 0 :
if liebiao[i]>liebiao[i+1]:
Maxbox_num.append(i+1)
else:
if i == len(liebiao)-1:
if liebiao[i]>liebiao[i-1]:
Maxbox_num.append(i+1)
else:
if liebiao[i]>liebiao[i-1]:
if liebiao[i]>liebiao[i+1]:
Maxbox_num.append(i+1)
jieguo = []
for a in Maxbox_num:
jieguo.append(liebiao[a-1])
return jieguo
def Minbox(liebiao):
Minbox_num = []
for i in range(0,len(liebiao)):
if i == 0 :
if liebiao[i]