阅读 39

Python数据分析之亚马逊股价

今天用Python简单分析一下亚马逊上市至今的股价,没有太多实质性的东西,但学学技术还可以。主要包括下面几个方面:

  1. 画股价走势图
  2. 计算年度收益率
  3. 用股价拟合多项式曲线并预测股价
  4. 画K线图

首先,导入模块

import pandas as pd
import matplotlib.pylab as plt
import numpy as np
# 绘图显示中文
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
复制代码

读入文件,预览数据

data = pd.read_csv('./data/Amazon.csv')
data
复制代码

数据包含亚马逊1997年5月到今年7月底的股价,共5842条。

来看看上市至今的股价走势

# 整体走势
data.plot(x='Date', y='Close', rot=30, figsize=(15, 8), title='amazon股价')
复制代码

这个涨势太厉害了,上市至今暴涨了1600倍。

再来看看每年的收益率,先增加年份列,然后按照该列分组,用当年的第一天和最后一天的收盘价计算涨跌幅。

# 计算每年收益率
data['year'] = data['Date'].apply(lambda x: x[:4])

def get_rate_of_change(group):
    price1 = group.sort_values(by='Date')[:1]['Close']
    price2 = group.sort_values(by='Date', ascending=False)[:1]['Close']
    
    return (price2.values[0] / price1.values[0] - 1) * 100

data.groupby('year').apply(get_rate_of_change).plot(kind='bar', rot=30, figsize=(15, 8), title='每年收益率')
复制代码

大部分年份都是上涨的,尤其是上市后的第二年涨了将近10倍。当然也有些年份是跌的,只要长期持有都会转正,但前提得是好股票。

既然股票收益率能达到如此高,那么有没有可能通过历史股价的走势来预测未来股价呢?下面我们就将2020年之前的股价作为样本,拟合一个多项式函数,来预测2020年的股价,看看跟实际的差异。

我们先在数据集上增加一列,作为自变量x,收盘价Close列作为因变量y

# 计算Date列与1997-05-15相差的天数,作为自变量x
from datetime import datetime

start_date = datetime(1997, 5, 15)
def get_Date_diff(date1):
    date1_arr = date1.split('-')
    cur_date = datetime(int(date1_arr[0]), int(date1_arr[1]), int(date1_arr[2]))
    
    return (cur_date - start_date).days

data['day'] = data['Date'].apply(get_Date_diff)

# 2020年之前的作为拟合的样本
data_before_2020 = data[data['Date'] < '2020-01-01']

data_2020 = data[data['Date'] >= '2020-01-01']
复制代码

有了样本后,我们用numpy模块的polyval函数进行拟合

# 对2020年之前的股价进行多项式拟合
x = data_before_2020['day'].values
y = data_before_2020['Close'].values
# 拟合
reg = np.polyfit(x, y, deg=15)
# 计算拟合后的值
y_predict = np.polyval(reg, x)
复制代码

参数deg代表多项式的次数,如果是deg=2,最终拟合的多项式函数就是y = a*x^2 + b*x + c,函数返回值reg就是系数abc。上述代码里deg=15,说明拟合了一个15次多项式函数,次数越高拟合的结果越接近样本,当然要注意过拟合。

np.polyval函数可以根据给定的多项式系数和自变量x计算因变量y,即:预测值。

下面我们将实际股价和预测股价画在同一个图里来观察拟合的效果

plt.figure(figsize=(15, 8))
plt.plot(x, y, 'b')
plt.plot(x, y_predict, 'r.')
plt.xlabel('日期')
plt.ylabel('股价')
plt.show()
复制代码

效果看起来还凑合,我们就可以用这个多项式来预测2020年股价

# 使用之前拟合的多项式预测2020年股价
x_2020 = data_2020['day'].values
y_2020 = data_2020['Close'].values
y_predict_2020 = np.polyval(reg, x_2020)

plt.figure(figsize=(15, 8))
plt.plot(x_2020, y_2020, 'b')
plt.plot(x_2020, y_predict_2020, 'r.')
plt.xlabel('日期')
plt.ylabel('股价')
plt.show()
复制代码

可以看到,图的右半部分预测股价(红色虚线)明显高于实际股价(蓝线),这种方式预测股价还是不靠谱的。因为该方式只用了价格这一个因素,而影响股价的因素特别多,因此抛开其他因素单纯看股票价格的波动是没有规律的。

当然我们可以考虑一些优秀的机器学习模型或者深度学习模型来进行预测,但我觉得精确到天级的预测难度很大,并且意义也不大。但我们可以将问题简化为预测趋势,或者将预测结果作为一个信息辅助人来做判断。

进行到这里貌似还不太过瘾,那就画个K线图吧,说不定以后能用上。

# 画K线图
from pyecharts import options as opts
from pyecharts.charts import Kline, Line

def calculate_ma(day_count: int, prices):
    result: List[Union[float, str]] = []

    for i in range(len(prices)):
        if i < day_count:
            result.append("-")
            continue
        sum_total = 0.0
        for j in range(day_count):
            sum_total += float(prices[i - j][1])
        result.append(abs(float("%.2f" % (sum_total / day_count))))
    return result

x = data_2020['Date'].values.tolist()
y = data_2020[['Open', 'Close', 'Low', 'High']].values.tolist()


kline = (
    Kline()
    .add_xaxis(x)
    .add_yaxis(
        "kline",
        y,
        itemstyle_opts=opts.ItemStyleOpts(
            color="#ec0000",
            color0="#00da3c",
            border_color="#8A0000",
            border_color0="#008F28",
        ),
    )
    .set_global_opts(
        xaxis_opts=opts.AxisOpts(is_scale=True),
        yaxis_opts=opts.AxisOpts(
            is_scale=True,
            splitarea_opts=opts.SplitAreaOpts(
                is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
            ),
        ),
        datazoom_opts=[opts.DataZoomOpts(type_="inside")],
        title_opts=opts.TitleOpts(title="2020年K线图"),
    )
)

kline_line = (
    Line()
    .add_xaxis(x)
    .add_yaxis(
        series_name="MA5",
        y_axis=calculate_ma(5, y),
        is_smooth=True,
        linestyle_opts=opts.LineStyleOpts(opacity=0.5),
        label_opts=opts.LabelOpts(is_show=False),
    )
    .set_global_opts(
        xaxis_opts=opts.AxisOpts(
            type_="category",
            grid_index=1,
            axislabel_opts=opts.LabelOpts(is_show=False),
        ),
        yaxis_opts=opts.AxisOpts(
            grid_index=1,
            split_number=3,
            axisline_opts=opts.AxisLineOpts(is_on_zero=False),
            axistick_opts=opts.AxisTickOpts(is_show=False),
            splitline_opts=opts.SplitLineOpts(is_show=False),
            axislabel_opts=opts.LabelOpts(is_show=True),
        ),
    )
)
# Overlap Kline + Line
overlap_kline_line = kline.overlap(kline_line)

overlap_kline_line.render_notebook()
复制代码

这里只用了2020年的数据进行绘制,看起来还像是那么回事。这个图包含两部分,一部分是单纯调用Kline绘制的K线图,另一部分是调用Line绘制了一个折线图,它的y坐标调用calculate_ma函数,计算5日平均收盘价。最后调用overlap_kline_line = kline.overlap(kline_line)将二者合并在一起。

我的分析就到这里了,感兴趣的朋友可以自行分析。公众号回复关键字亚马逊股价获取数据和源码。

欢迎公众号 「渡码」