针对股票涨跌信息的一系列处理
针对股票涨跌信息的一系列处理
- 线性模型
- 线性预测
- 线性拟合
- 协方差
- 相关系数
- 相关矩阵
- 多项式拟合
- 数据平滑
- 符号数组
- 矢量化
线性模型
什么是线性关系?
x = 1 → y = 60 x = 2 → y = 65 x = 3 → y = 70 x = 4 → y = 75 x = 5 → y = ? ? ? x=1 \quad \rarr \quad y=60 \\ x=2 \quad \rarr \quad y=65 \\ x=3 \quad \rarr \quad y=70 \\ x=4 \quad \rarr \quad y=75 \\ x=5 \quad \rarr \quad y= ??? \\ x=1→y=60x=2→y=65x=3→y=70x=4→y=75x=5→y=???
线性预测
假设一组数据符合一种线型规律,那么就可以预测未来将会出现的数据。
a b c d e f ? a b c d e f g h ?{ a w 0 + b w 1 + c w 2 = d b w 0 + c w 1 + d w 2 = e c w 0 + d w 1 + e w 2 = f \begin{cases} aw_0 + bw_1 + cw_2 = d \\ bw_0 + cw_1 + dw_2 = e \\ cw_0 + dw_1 + ew_2 = f \\ \end{cases} ⎩⎪⎨⎪⎧aw0+bw1+cw2=dbw0+cw1+dw2=ecw0+dw1+ew2=f
线型方程组转换为矩阵相乘的形式:
[ a b c b c d c d e ] × [ w 0 w 1 w 2 ] = [ d e f ] A x B \left[ \begin{array}{ccc} a & b & c\\ b & c & d\\ c & d & e\\ \end{array} \right ] \times \left[ \begin{array}{ccc} w_0\\ w_1\\ w_2\\ \end{array} \right ]= \left[ \begin{array}{ccc} d\\ e\\ f\\ \end{array} \right ] \\ \quad \quad A \quad \quad \quad \quad \quad x\quad \quad \quad B \quad ⎣⎡abcbcdcde⎦⎤×⎣⎡w0w1w2⎦⎤=⎣⎡def⎦⎤AxB
根据线性模型的特点可以通过一组历史数据求出线性关系系数x, y, z,从而预测d、e、f下的一个数据是多少。
线性预测需要使用历史数据进行检验,让预测结果可信度更高
案例:使用线性预测,预测下一天的收盘价。
import numpy as np import matplotlib.pyplot as mp import datetime as dtdef dmy2ymd(dmy):dmy = str(dmy, encoding='utf-8')time = dt.datetime.strptime(dmy, '%d-%m-%Y').date()t = time.strftime('%Y-%m-%d')return tdates, opening_prices, highest_prices, \lowest_prices, closing_prices = \np.loadtxt('C:/Users/ADMIN/Desktop/DATASCIENCE/day03/da_data/aapl.csv', delimiter=',', usecols=(1,3,4,5,6),unpack=True, dtype='M8[D],f8,f8,f8,f8',converters={1:dmy2ymd})# 绘制收盘价折线图 mp.figure('AAPL', facecolor='lightgray') mp.title('AAPL', fontsize=18) mp.xlabel('Date', fontsize=14) mp.ylabel('Price', fontsize=14) mp.grid(linestyle=':') # 设置刻度定位器 import matplotlib.dates as md ax = mp.gca() ax.xaxis.set_major_locator( # 每周一为主刻度md.WeekdayLocator(byweekday=md.MO)) # 每天一个次刻度 ax.xaxis.set_minor_locator(md.DayLocator()) # 设置主刻度文本格式 ax.xaxis.set_major_formatter(md.DateFormatter('%Y/%m/%d')) dates = dates.astype(md.datetime.datetime) mp.plot(dates, closing_prices, color='dodgerblue',label='Closing Price', linewidth=2,linestyle='--')# 线性预测 # 通过前6天的股票价格,整理A与B,得到x,预测第7天收盘价 N = 3 pred_prices = np.zeros(closing_prices.size - N*2) for i in range(pred_prices.size):A = np.zeros((N, N))for j in range(N):A[j,:] = closing_prices[j+i:i+j+N]B = closing_prices[N+i:N*2+i]x = np.linalg.lstsq(A, B)[0]# dot点积:B[0]*x[0] + B[1]*x[1] + B[2]*x[2]pred = B.dot(x)pred_prices[i] = predmp.plot(dates[N*2:], pred_prices, 'o-', color='orangered', label='Prediction Price')mp.legend() mp.gcf().autofmt_xdate() mp.show()线性拟合
线性拟合可以寻求与一组散点走向趋势规律相适应的线型表达式方程。
有一组散点描述时间序列下的股价:
[x1, y1] [x2, y2] [x3, y3] ... [xn, yn]根据线型 y=kx + b 方程可得:
kx1 + b = y1 kx2 + b = y2 kx3 + b = y3 ... kxn + b = yn [ x 1 1 x 2 1 x 3 1 x n 1 ] × [ k b ] = [ y 1 y 2 y 3 y n ] \left[ \begin{array}{ccc} x{_1} & 1\\ x{_2} & 1\\ x{_3} & 1 \\ x{_n} & 1 \\ \end{array} \right ] \times \left[ \begin{array}{ccc} k\\ b\\ \end{array} \right ]= \left[ \begin{array}{ccc} y{_1}\\ y{_2}\\ y{_3}\\ y{_n}\\ \end{array} \right ] ⎣⎢⎢⎡x1x2x3xn1111⎦⎥⎥⎤×[kb]=⎣⎢⎢⎡y1y2y3yn⎦⎥⎥⎤
样本过多,每两组方程即可求得一组k与b的值。
np.linalg.lstsq(a, b) 可以通过最小二乘法求出所有结果中拟合误差最小的k与b的值。
案例:利用线型拟合画出股价的趋势线
绘制趋势线(趋势可以表示为最高价、最低价、收盘价的均值):
协方差
通过两组统计数据计算而得的协方差可以评估这两组统计数据的相似程度。
样本:
A = [a1, a2, ..., an] B = [b1, b2, ..., bn]平均值:
ave_a = (a1 + a2 +...+ an)/n ave_b = (b1 + b2 +...+ bn)/n离差(用样本中的每一个元素减去平均数,求得数据的误差程度):
dev_a = [a1, a2, ..., an] - ave_a dev_b = [b1, b2, ..., bn] - ave_b协方差
协方差可以简单反映两组统计样本的相关性
cov_ab = ave(dev_a x dev_b) cov_ba = ave(dev_b x dev_a)案例:计算两组数据的协方差,并绘图观察。
import numpy as np import matplotlib.pyplot as mpa = np.random.randint(1, 30, 10) b = np.random.randint(1, 30, 10) #平均值 ave_a = np.mean(a) ave_b = np.mean(b) #离差 dev_a = a - ave_a dev_b = b - ave_b #协方差 cov_ab = np.mean(dev_a * dev_b) cov_ba = np.mean(dev_b * dev_a) print('a与b数组:', a, b) # a与b数组: [ 4 28 22 28 14 12 19 2 26 5] [14 8 29 5 11 12 27 21 9 18] print('a与b样本方差:', np.sum(dev_a**2)/(len(dev_a)-1), np.sum(dev_b**2)/(len(dev_b)-1)) # a与b样本方差: 101.55555555555556 66.04444444444445 print('a与b协方差:',cov_ab, cov_ba) # a与b协方差: -22.9 -22.9 #绘图,查看两条图线的相关性 mp.figure('COV LINES', facecolor='lightgray') mp.title('COV LINES', fontsize=16) mp.xlabel('x', fontsize=14) mp.ylabel('y', fontsize=14) x = np.arange(0, 10) #a,b两条线 mp.plot(x, a, color='dodgerblue', label='Line1') mp.plot(x, b, color='limegreen', label='Line2') #a,b两条线的平均线 mp.plot([0, 9], [ave_a, ave_a], color='dodgerblue', linestyle='--', alpha=0.7, linewidth=3) mp.plot([0, 9], [ave_b, ave_b], color='limegreen', linestyle='--', alpha=0.7, linewidth=3)mp.grid(linestyle='--', alpha=0.5) mp.legend() mp.tight_layout() mp.show()相关系数
协方差除去两组统计样本标准差的乘积是一个[-1, 1]之间的数。该结果称为统计样本的相关系数。
# a组样本 与 b组样本做对照后的相关系数 cov_ab / (std_a * std_b) # b组样本 与 a组样本做对照后的相关系数 cov_ba / (std_b * std_a) # a样本与a样本作对照 b样本与b样本做对照 二者必然相等 cov_ab / (std_a * std_b)=cov_ba/(std_b * std_a)通过相关系数可以分析两组数据的相关性:
若相关系数越接近于0,越表示两组样本越不相关。 若相关系数越接近于1,越表示两组样本正相关。 若相关系数越接近于-1,越表示两组样本负相关。案例:输出案例中两组数据的相关系数。
print('相关系数:', cov_ab / (np.std(a) * np.std(b)), cov_ba / (np.std(a) * np.std(b))) 相关系数: 0.2208660975292323 0.2208660975292323相关矩阵
[ v a r _ a s t d _ a × s t d _ a c o v _ a b s t d _ a × s t d _ b c o v _ b a s t d _ b × s t d _ a v a r _ b s t d _ b × s t d _ b ] \left[ \begin{array}{c} \frac{var\_a}{std\_a \times std\_a} & \frac{cov\_ab}{std\_a \times std\_b} \\ \frac{cov\_ba}{std\_b \times std\_a} & \frac{var\_b}{std\_b \times std\_b}\\ \end{array} \right ] [std_a×std_avar_astd_b×std_acov_bastd_a×std_bcov_abstd_b×std_bvar_b]
矩阵正对角线上的值都为1。(同组样本自己相比绝对正相关)
[ 1 c o v _ a b s t d _ a × s t d _ b c o v _ b a s t d _ b × s t d _ a 1 ] \left[ \begin{array}{ccc} 1 & \frac{cov\_ab}{std\_a \times std\_b} \\ \frac{cov\_ba}{std\_b \times std\_a} & 1\\ \end{array} \right ] [1std_b×std_acov_bastd_a×std_bcov_ab1]
numpy提供了求得相关矩阵的API:
# 相关矩阵 numpy.corrcoef(a, b)# 相关矩阵的分子矩阵 即协方差矩阵 # [[a方差,ab协方差], [ba协方差, b方差]] numpy.cov(a, b) # 这个函数求的协方差用的是样本方差(分母是n- 1)综合两支股票收盘价的涨跌情况求出协方差,相关系数,相关矩阵:
import numpy as np import matplotlib.pyplot as mp import datetime as dtdef dmy2ymd(dmy):dmy = str(dmy, encoding='utf-8')time = dt.datetime.strptime(dmy, '%d-%m-%Y').date()t = time.strftime('%Y-%m-%d')return tdates, vale_closing_prices = \np.loadtxt('C:/Users/ADMIN/Desktop/DATASCIENCE/vale.csv', delimiter=',', usecols=(1, 6),unpack=True, dtype='M8[D], f8',converters={1:dmy2ymd})bhp_closing_prices = np.loadtxt('C:/Users/ADMIN/Desktop/DATASCIENCE/bhp.csv', delimiter=',',usecols=(6,))# 计算协方差 vale_mean = np.mean(vale_closing_prices) bhp_mean = np.mean(bhp_closing_prices) vale_dev = vale_closing_prices - vale_mean bhp_dev = bhp_closing_prices - bhp_mean cov = np.mean(vale_dev * bhp_dev) print(cov) # 3.135577333333333# 相关系数 coef = cov / (bhp_closing_prices.std() * vale_closing_prices.std()) print(coef) # 0.8664988296368299# 相关矩阵 m = np.corrcoef(bhp_closing_prices, vale_closing_prices,) print(m, m[0,1]) # [[1. 0.86649883] # [0.86649883 1. ]] 0.86649882963683v = np.cov(bhp_closing_prices, vale_closing_prices) # 这个函数得到的 协方差矩阵里的元素 都是样本方差(所以偏大),而上面我们算的是总体方差 print(v) # [[8.53844379 3.24370069] # [3.24370069 1.64122023]]多项式拟合
多项式的一般形式:
y = p 0 x n + p 1 x n − 1 + p 2 x n − 2 + p 3 x n − 3 + . . . + p n y=p_{0}x^n + p_{1}x^{n-1} + p_{2}x^{n-2} + p_{3}x^{n-3} +...+p_{n} y=p0xn+p1xn−1+p2xn−2+p3xn−3+...+pn
多项式拟合的目的是为了找到一组 p 0 , p 1 , . . . , p n p_0, p_1, ..., p_n p0,p1,...,pn,使得拟合方程尽可能的与实际样本数据相符合。
假设拟合得到的多项式如下:
f ( x ) = p 0 x n + p 1 x n − 1 + p 2 x n − 2 + p 3 x n − 3 + . . . + p n f(x)=p_{0}x^n + p_{1}x^{n-1} + p_{2}x^{n-2} + p_{3}x^{n-3} +...+p_{n} f(x)=p0xn+p1xn−1+p2xn−2+p3xn−3+...+pn
则拟合函数与真实结果的差方如下
l o s s = ( y 1 − f ( x 1 ) ) 2 + ( y 2 − f ( x 2 ) ) 2 + . . . + ( y n − f ( x n ) ) 2 loss = (y_1-f(x_1))^2 + (y_2-f(x_2))^2 + ... + (y_n-f(x_n))^2 loss=(y1−f(x1))2+(y2−f(x2))2+...+(yn−f(xn))2
那么多项式拟合的过程即为求取一组 p 0 , p 1 , . . . , p n p_0, p_1, ..., p_n p0,p1,...,pn, 使得loss的值最小。
多项式拟合相关API:
根据一组样本,并给出最高次幂,求出拟合系数 np.polyfit(X, Y, 最高次幂) -> P多项式运算相关API:
根据拟合系数与自变量求出拟合值, 由此可得拟合曲线坐标样本数据 [X, Y'] np.polyval(P, X) -> Y'多项式函数求导,根据拟合系数求出多项式函数导函数的系数 np.polyder(P) -> Q 已知多项式系数Q 求多项式函数的根(与x轴交点的横坐标) xs = np.roots(Q)两个多项式函数的差函数的系数(可以通过差函数的根求取两个曲线的交点) Q = np.polysub(P1, P2)案例:求多项式 y = 4x3 + 3x2 - 1000x + 1曲线驻点的坐标。
''' 1. 求出多项式的导函数 2. 求出导函数的根,若导函数的根为实数,则该点则为曲线驻点。 ''' import numpy as np import matplotlib.pyplot as mpP = [4, 3, -1000, 1]# 画出函数图像 x = np.linspace(-20, 20, 1000) y = np.polyval(P, x) mp.grid(linestyle=':') mp.plot(x, y)# 画出驻点 Q = np.polyder(P) xs = np.roots(Q) print(xs) ys = np.polyval(P, xs) mp.scatter(xs, ys, s=100, marker='*',color='red', zorder=3) mp.show()
使用多项式函数拟合两只股票bhp、vale的差价函数:
数据平滑
数据的平滑处理通常包含有降噪、拟合等操作。降噪的功能意在去除额外的影响因素,拟合的目的意在数学模型化,可以通过更多的数学方法识别曲线特征。
案例:绘制两只股票收益率曲线。收益率 =(后一天收盘价-前一天收盘价) / 前一天收盘价
说明:
1、颜色最浅的两条折线是收益线
2、颜色较浅的两条折线是卷积降噪线
3、颜色最深的两条折线是针对卷积结果,作出的多项式拟合曲线
符号数组
sign函数可以把样本数组的变成对应的符号数组,正数变为1,负数变为-1,0则变为0。
ary = np.sign(源数组)净额成交量(OBV)
成交量可以反映市场对某支股票的人气,而成交量是一只股票上涨的能量。一支股票的上涨往往需要较大的成交量。而下跌时则不然。
若相比上一天的收盘价上涨,则为正成交量;若相比上一天的收盘价下跌,则为负成交量。
绘制OBV柱状图
dates, closing_prices, volumes = np.loadtxt('C:/Users/ADMIN/Desktop/DATASCIENCE/bhp.csv', delimiter=',',usecols=(1, 6, 7), unpack=True,dtype='M8[D], f8, f8', converters={1: dmy2ymd}) diff_closing_prices = np.diff(closing_prices) sign_closing_prices = np.sign(diff_closing_prices) # [ 1. -1. -1. 1. -1. -1. 1. -1. 1. 1. -1. 1. 1. -1. -1. -1. -1. -1. # 1. -1. -1. -1. 1. 1. 1. -1. 1. 1. -1.] obvs = volumes[1:] * sign_closing_prices mp.figure('On-Balance Volume', facecolor='lightgray') mp.title('On-Balance Volume', fontsize=20) mp.xlabel('Date', fontsize=14) mp.ylabel('OBV', fontsize=14) ax = mp.gca() ax.xaxis.set_major_locator(md.WeekdayLocator(byweekday=md.MO)) ax.xaxis.set_minor_locator(md.DayLocator()) ax.xaxis.set_major_formatter(md.DateFormatter('%d %b %Y')) mp.tick_params(labelsize=10) mp.grid(axis='y', linestyle=':') dates = dates[1:].astype(md.datetime.datetime) mp.bar(dates, obvs, 1.0, color='dodgerblue',edgecolor='white', label='OBV') mp.legend() mp.gcf().autofmt_xdate() mp.show()数组处理函数
ary = np.piecewise(源数组, 条件序列, 取值序列)针对源数组中的每一个元素,检测其是否符合条件序列中的每一个条件,符合哪个条件就用取值系列中与之对应的值,表示该元素,放到目标 数组中返回。
条件序列: [a < 0, a == 0, a > 0]
取值序列: [-1, 0, 1]
a = np.array([70, 80, 60, 30, 40]) d = np.piecewise(a, [a < 60, a == 60, a > 60],[-1, 0, 1]) # d = [ 1 1 0 -1 -1]矢量化
矢量化指的是用数组代替标量来操作数组里的每个元素。
numpy提供了vectorize函数,可以把处理标量的函数矢量化,返回的函数可以直接处理ndarray数组。
``
vectorized_foo = np.vectorize(foo)
vectorized_foo(X, Y)
两行代码可以写成:
np.vectorize(foo)(X, Y)
numpy还提供了frompyfunc函数,也可以完成与vectorize相同的功能:
# 把foo转换成矢量函数,该矢量函数接收2个参数,返回一个结果 fun = np.frompyfunc(foo, 2, 1) fun(X, Y)案例:定义一种买进卖出策略,通过历史数据判断这种策略是否值得实施。
import numpy as np import matplotlib.pyplot as mp import datetime as dt import matplotlib.dates as mddef dmy2ymd(dmy):dmy = str(dmy, encoding='utf-8')time = dt.datetime.strptime(dmy, '%d-%m-%Y').date()t = time.strftime('%Y-%m-%d')return t dates, opening_prices, highest_prices, \lowest_prices, closing_prices = np.loadtxt('C:/Users/ADMIN/Desktop/DATASCIENCE/bhp.csv', delimiter=',',usecols=(1, 3, 4, 5, 6), unpack=True,dtype='M8[D], f8, f8, f8, f8',converters={1: dmy2ymd})# 定义一种投资策略 def profit(opening_price, highest_price,lowest_price, closing_price):buying_price = opening_price * 0.99if lowest_price <= buying_price <= highest_price:return (closing_price - buying_price) * \100 / buying_pricereturn np.nan # 无效值# 矢量化投资函数 profits = np.vectorize(profit)(opening_prices, highest_prices, lowest_prices, closing_prices) # 判断无效值 nan = np.isnan(profits) dates, profits = dates[~nan], profits[~nan] gain_dates, gain_profits = dates[profits > 0], profits[profits > 0] loss_dates, loss_profits = dates[profits < 0], profits[profits < 0] # 绘制收盘价折线图 mp.figure('Trading Simulation', facecolor='lightgray') mp.title('Trading Simulation', fontsize=20) mp.xlabel('Date', fontsize=14) mp.ylabel('Profit', fontsize=14) # 设置刻度定位器 ax = mp.gca() ax.xaxis.set_major_locator(md.WeekdayLocator(byweekday=md.MO)) # 每周一为主刻度 ax.xaxis.set_minor_locator(md.DayLocator()) # 每天一个次刻度 ax.xaxis.set_major_formatter(md.DateFormatter('%d %b %Y')) # 设置主刻度文本格式 mp.tick_params(labelsize=10) mp.grid(linestyle=':')# 绘制收益率折线 if dates.size > 0:dates = dates.astype(md.datetime.datetime)mp.plot(dates, profits, c='gray',label='Profit')mp.axhline(y=profits.mean(), linestyle='--',color='gray')# 绘制收益率为正的点和平均线 if gain_dates.size > 0:gain_dates = gain_dates.astype(md.datetime.datetime)mp.plot(gain_dates, gain_profits, 'o',c='orangered', label='Gain Profit')mp.axhline(y=gain_profits.mean(), linestyle='--',color='orangered')# 绘制收益率为负的点和平均线 if loss_dates.size > 0:loss_dates = loss_dates.astype(md.datetime.datetime)mp.plot(loss_dates, loss_profits, 'o',c='limegreen', label='Loss Profit')mp.axhline(y=loss_profits.mean(), linestyle='--',color='limegreen') mp.legend() mp.gcf().autofmt_xdate() mp.show()总结
以上是生活随笔为你收集整理的针对股票涨跌信息的一系列处理的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: Plan for the day
- 下一篇: P5737 【深基7.例3】闰年展示