可视化神器Plotly玩转股票图

2,092

可视化神器Plotly玩转股票图

本文是可视化神器Plotly绘图的第7篇,讲解的是如何通过Plotly来绘制与股市相关的图形,比如基础K线图、OHLC图等。

温馨提示⚠️:股市有风险,投资需谨慎,这并不妨碍大家学习Plotly的绘图技巧!

扩展阅读

Plotly的文章会形成连载系列,前面6篇的Plotly可视化文章分别是:

导入库

import pandas as pd
import numpy as np

# 两个接口
import plotly_express as px
import plotly.graph_objects as go

股市图

下面简单介绍下两种股市相关的图:

  • K线图
  • OHLC图

K线图

K线由开盘价、收盘价、最高价、最低价四个价位组成。开盘价低于收盘价称为阳线,反之叫阴线。

中间的矩形称为实体,实体以上细线叫上影线,实体以下细线叫下影线

1、红色上涨:

2、绿色下跌

3、持平状态

根据K线的计算周期可将其分为:日K线、周K线、月K线、年K线

OHLC线图

摘录来自维基百科的一段介绍:

美国线**(英语:Open-High-Low-Close chart,OHLC chart),以竖立的线条表现股票价格的变化,可以呈现“开盘价、最高价、最低价、收盘价”,竖线呈现最高价和最低价间的价差间距,左侧横线代表开盘价,右侧横线代表收盘价

绘制OHLC图

绘图数据

在本文中很多图形都是基于Plotly中自带的一份关于苹果公司AAPL的股票数据绘制,先看看具体的数据长什么样子:利用pandas读取网站在线的csv文件

# 读取在线的csv文件

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
df.head()  # 显示前5行数据

数据大小为:

df.shape

# 结果
(506,11)

所有的字段为:

df.columns

# 结果
Index(['Date', 'AAPL.Open', 'AAPL.High', 'AAPL.Low', 'AAPL.Close',
       'AAPL.Volume', 'AAPL.Adjusted', 'dn', 'mavg', 'up', 'direction'],
      dtype='object')

基础绘图

# The 'close' property is an array that may be specified as a tuple, list, numpy array, or pandas Series

fig = go.Figure(data=go.Ohlc(
    x=df['Date'],
    open=df['AAPL.Open'],    # 字段数据必须是元组、列表、numpy数组、或者pandas的Series数据
    high=df['AAPL.High'],
    low=df['AAPL.Low'],
    close=df['AAPL.Close']
))

fig.update(layout_xaxis_rangeslider_visible=False)

fig.show()

添加文本信息和备注

fig = go.Figure(data=go.Ohlc(
    x=df['Date'],  # 日期和四组数据
    open=df['AAPL.Open'],
    high=df['AAPL.High'],
    low=df['AAPL.Low'],
    close=df['AAPL.Close']
))

fig.update_layout(
    title="苹果公司股票走势图",  # 标题
    yaxis_title="股票价格",  # y轴名称
    shapes = [dict(  # 显示形状的位置和线宽等信息
        x0='2015-06-01', x1='2016-05-13',  # x的取值
        y0=0, y1=1,  # y的取值
        xref='x', yref='paper',
        line_width=2)],
    annotations=[dict(   #  备注信息
        x='2015-06-01', y=0.05, 
        xref='x', yref='paper',
        showarrow=False, 
        xanchor='left', 
        text='下降阶段')]
)

fig.show()

上图中添加了方框中的特选部分和备注

自定义颜色

上面的图形是Plotly自带的颜色:涨是红色,跌是绿色,下图中将涨变成了蓝色

fig = go.Figure(data=[go.Ohlc(
    x=df['Date'],  # 日期
    open=df['AAPL.Open'],   # 4组数据 
    high=df['AAPL.High'],
    low=df['AAPL.Low'], 
    close=df['AAPL.Close'],
    increasing_line_color= 'blue',   # 上升趋势颜色
    decreasing_line_color= 'green'  # 下降趋势颜色
)])

fig.show()

具体日期的OHLC图

上面的图形都是连续型日期(基于月份)的OHLC图形,下面介绍的是如何绘制具体某些日期的OHLC图形

# 如何生成一个datetime时间对象
import plotly.graph_objects as go
from datetime import datetime

datetime(year=2013, month=10, day=10)   

# 绘制的4份数据
open_data = [133.0, 133.3, 133.5, 133.0, 134.1]
high_data = [133.1, 133.3, 133.6, 133.2, 134.8]
low_data = [132.7, 132.7, 132.8, 132.6, 132.8]
close_data = [133.0, 132.9, 133.3, 133.1, 133.1]

# 绘图的5个日期:指定年、月、日
dates = [datetime(year=2019, month=10, day=10),
         datetime(year=2019, month=11, day=10),
         datetime(year=2019, month=12, day=10),
         datetime(year=2020, month=1, day=10),
         datetime(year=2020, month=2, day=10)]

# 绘图:传入时间和数据
fig = go.Figure(data=[go.Ohlc(
    x=dates,
    open=open_data, 
    high=high_data,
    low=low_data, 
    close=close_data)])

fig.show()

增加悬停信息hovertext

悬停信息指的是:在图形中数据本身是不能看到的,当我们将光标移动到图中便可以看到对应的数据。

还是通过苹果公司股票的数据为例:

hovertext=[]  # 添加悬停信息

for i in range(len(df['AAPL.Open'])):  # <br>表示
    hovertext.append('Open: '+str(df['AAPL.Open'][i])+'<br>Close: '+str(df['AAPL.Close'][i]))

# 结果表现形式
['Open: 127.489998<br>Close: 127.830002',
 'Open: 127.629997<br>Close: 128.720001',
 'Open: 128.479996<br>Close: 128.449997']

上面图中的红色部分就是悬停信息

基于时间序列

绘图数据

下面开始介绍的是如何绘制基于时间序列time series的股票图形,使用的是Plotly中自带的股票数据:

stocks = px.data.stocks()
stocks.head()  # 显示前5行数据

第一个字段是日期时间,其余字段是不同的公司名称:谷歌、苹果、亚马逊等

基于px实现

我们利用plotly_express来实现基础图形的绘制,选取的公司是FB:Facebook

# 绘制FB股票走势

fig = px.line(
    stocks,
    x='date',
    y='FB'
)

fig.update_layout(title={
    'text':'Facebook股票走势',
    'x':0.52,
    'y':0.96,
    'xanchor':'center',
    'yanchor':'top'
})

fig.show()

基于go实现

下面采用的是基于go方法实现:

import pandas as pd
import numpy as np

# 两个接口
import plotly_express as px
import plotly.graph_objects as go

# 基于go
fig = go.Figure([go.Scatter(
    x=stocks['date'], 
    y=stocks['FB'])])

fig.update_layout(title={
    'text':'Facebook股票走势',
    'x':0.52,
    'y':0.96,
    'xanchor':'center',
    'yanchor':'top'
})

fig.show()

共享时间轴

import plotly.express as px

stock = px.data.stocks(indexed=True) - 1  # 将原始数据减掉1
stock.head()

fig = px.bar(
  stock,  # 数据
  x=stock.index,  # x轴 
  y="GOOG"  # y轴
)

fig.show()

多面图共享时间轴

fig = px.area(
    stock,
    facet_col="company",  # 根据公式显示不同的元素
    facet_col_wrap=3   # 每行显示的图形数量
)

fig.show()

改变参数每行显示2个图形:

fig = px.area(
    stock,
    facet_col="company",
    facet_col_wrap=2   # 每行显示的图形数量
)

fig.show()

Label标签个性设置

fig = px.line(
    df4,   # 绘图数据
    x="date",  # x轴标签
    y=df4.columns,
    hover_data={"date": "|%B %d, %Y"},  # 悬停信息设置
    title='标签个性化设置-居中'   # 图标题
)

fig.update_xaxes(
    dtick="M1",   # 表示one month:每个月显示一次
    tickformat="%b\n%Y",   # 日期显示模式
    ticklabelmode='instant'  # ticklabelmode模式:居中 'instant', 'period'
)

fig.show()

基于直方图的时间序列实现

import plotly.express as px
import plotly.graph_objects as go
import pandas as pd

# 读取在线csv文件
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')

fig = px.histogram(  # 直方图
    df, 
    x="Date", 
    y="AAPL.Open", 
    histfunc="avg",  # 直方图函数
    title="时间轴的直方图实现")

fig.update_traces(xbins_size="M1")  # 按月显示

fig.update_xaxes(
    showgrid=False, 
    dtick="M1",  # 按月显示
    ticklabelmode="period",   # instant  period
    tickformat="%b\n%Y"   # 标签显示模式
)

fig.update_layout(bargap=0.1)

fig.show()

上面绘制的是单纯的直方图,再此基础上可以结合散点图来进行展示:

import plotly.express as px
import plotly.graph_objects as go
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')

# 1、生成直方图
fig = px.histogram(
    df, 
    x="Date", 
    y="AAPL.Open", 
    histfunc="avg", 
    title="直方图+散点图")

# 2、更新轨迹:按月显示
fig.update_traces(xbins_size="M1")   # 每个柱子显示几个月的数据:M1显示一个月  M2表示2个月


# 3、设置x轴
fig.update_xaxes(
    showgrid=True, 
    dtick="M1",  # 按月显示
    ticklabelmode="period",   # instant  period
    tickformat="%b\n%Y"   
)

# 4、每个柱状图间隔
fig.update_layout(bargap=0.1) 

# 5、红色轨迹的设置
fig.add_trace(go.Scatter(
    mode="lines",   # ['lines', 'markers', 'text'] 
    x=df["Date"],   # 两个轴的数据
    y=df["AAPL.Open"], 
    name="daily"))   # 轨迹名称

fig.show()

指定交易日

import plotly.graph_objects as go
import pandas as pd

df = pd.DataFrame(dict(
    # 横轴
    date=["2019-01-10", 
          "2019-02-10", 
          "2019-03-10",
          "2019-04-10", 
          "2019-05-10",
          "2019-06-10"
         ],
    # 纵轴
    value=[10,12,13,11,12,13]
))

df

# 添加画布
fig = go.Figure()

# 添加不同的轨迹
fig.add_trace(go.Scatter(  # 散点图
    name="轨迹1",  # 轨迹名称
    mode="markers+lines",  # 轨迹模式 :标记+折线
    x=df["date"],  #  两个轴的数据
    y=df["value"],
    marker_symbol="star"   # 标记符号:星星star
))

fig.add_trace(go.Scatter(
    name="轨迹2",
    mode="markers+lines", 
    x=df["date"], 
    y=df["value"],
    xperiod="M1",  # x轴时间阶段显示模式:以1个月为基准
    xperiodalignment="start"   # start左边  middle中间   end右边
))

fig.add_trace(go.Scatter(
    name="轨迹3",
    mode="markers+lines", 
    x=df["date"], 
    y=df["value"],
    xperiod="M1",
    xperiodalignment="middle"
))

fig.add_trace(go.Scatter(
    name="轨迹4",
    mode="markers+lines", 
    x=df["date"],
    y=df["value"],
    xperiod="M1",
    xperiodalignment="end"
))

fig.add_trace(go.Bar(  # 柱状图
    name="轨迹5",
    x=df["date"], 
    y=df["value"],
    xperiod="M1",
    xperiodalignment="middle"
))

fig.update_xaxes(showgrid=True, ticklabelmode="period")

fig.show()

指定交易范围

在某个时间范围内进行绘图,还是以苹果公司股票为例:

# px 实现

import plotly.express as px
import pandas as pd

# 苹果公司数据
df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')

fig = px.line(df, 
              x='Date',  # x轴
              y='AAPL.High',  # y轴
              range_x=['2015-07-01','2016-8-31'])   # 指定交易时间范围
fig.show()

带有区间滑块绘图

import plotly.express as px
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')

fig = px.line(df, 
              x='Date',
              y='AAPL.Open',
              title='带有区间滑块绘图')
fig.update_xaxes(rangeslider_visible=True)  # 开启区间滑块
fig.show()

滑块和时间按钮结合

除了滑块,我们还可以在图形中还可以设置按钮进行选择:

import plotly.express as px
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')

fig = px.line(
    df,
    x='Date',
    y='AAPL.High',
    title='带有滑块和按钮的时间序列绘图')

fig.update_xaxes(
    rangeslider_visible=True,   # 开始显示
    rangeselector=dict(
        buttons=list([
            dict(count=1, label="1m", step="month", stepmode="backward"),  # 往前推一个月
            dict(count=6, label="6m", step="month", stepmode="backward"),  # 往前推6个月
            dict(count=1, label="YTD", step="year", stepmode="todate"),  # 只显示今年数据
            dict(count=1, label="1y", step="year", stepmode="backward"),  # 显示过去一年的数据
            dict(step="all")   # 显示全部数据
        ])
    )
)


fig.show()

隐藏周末和交易日

1、首先看看在某个具体的时间段内,如果我们不对非交易日进行处理,图形会是什么样子?

# 默认形式

import plotly.express as px
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')

fig = px.scatter(
    df, 
    x='Date', 
    y='AAPL.High', 
    range_x=['2015-12-01', '2016-01-31'],  # 指定绘图时间范围
    title="非交易日(隐藏)")

fig.show()

2、指定需要隐藏的时间:可以是星期,也可以是具体的某天

# 隐藏周末和节假日

fig = px.scatter(
    df, 
    x='Date', y='AAPL.High', 
    range_x=['2015-12-01', '2016-01-15'],
    title="隐藏周末和节假日(指定日期)")

fig.update_xaxes(
    rangebreaks=[
        dict(bounds=["sat", "mon"]), # 隐藏周六、周一
        dict(values=["2015-12-25", "2016-01-01"])  # 隐藏具体日期
    ]
)
fig.show()

隐藏非交易时间

在一天中并不是24小时都在交易的,我们需要对非交易时间段进行隐藏:

import plotly.express as px
import pandas as pd
import numpy as np
np.random.seed(1)

work_week_40h = pd.date_range(
    start='2020-03-01', 
    end='2020-03-07', 
    freq="BH"   # 数据产生的频率:按照小时
)

work_week_40h

df5 = pd.DataFrame(dict(
    date = work_week_40h,
    value = np.cumsum(np.random.rand(40)-0.5)
))

fig = px.scatter(df5, 
                 x="date", 
                 y="value",
                 title="排除非交易时间段")

fig.update_xaxes(
    rangebreaks=[  # 排除时间段
        dict(bounds=[17, 9], pattern="hour"), # 排除下午5点(17点)到上午9点的时间h
    ]
)

fig.show()

实战案例

下面我们通过A股中的3个股票来实际绘图:

  • 中国平安
  • 平安银行
  • 福建金森

tushare

tushare是一个提供财经类数据的网站,包含:股票、债券、期货、基金等,主要特点是:

  • 数据丰富:拥有丰富的数据内容,如股票、基金、期货、数字货币等行情数据,公司财务、基金经理等基本面数据
  • 获取简单:SDK开发包支持语言,同时提供HTTP Restful接口,最大程度方便不同人群的使用
  • 落地方便:提供多种数据储存方式,如Oracle、MySQL,MongoDB、HDF5、CSV等,为数据获取提供了性能保证

为了使用这些数据,我们需要安装tushare库:

pip install tushare   # 下图显示安装成功

获取数据

我们以获取中国平安的数据为例:14个字段有开盘价open、最高价high等;每个网站机构采集数据的标准不同,本文中的数据仅供参考学习。

import pandas as pd
import tushare as ts
pingan = ts.get_hist_data("603018")  # 股票代码要事先准备
pingan   # 数据显示总共607行,14个字段

往数据中添加两个字段:

pingan = pingan.reset_index()

pingan["code_name"] = "中国平安"
pingan["code"] = "603018"

# 全部字段
Index(['date', 'open', 'high', 'close', 'low', 'volume', 'price_change',
       'p_change', 'ma5', 'ma10', 'ma20', 'v_ma5', 'v_ma10', 'v_ma20',
       'turnover', 'code_name', 'code'],
      dtype='object')

同样方法可以获取平安银行福建金森的股票数据

OHLC绘图

fig = go.Figure(data=go.Ohlc(
    x=pingan['date'],  # 传入日期
    open=pingan['open'],  # 传入4份数据
    high=pingan['high'],
    low=pingan['low'],
    close=pingan['close']
))

fig.update(layout_xaxis_rangeslider_visible=False)  # 隐藏滑块

fig.update_xaxes(
    rangebreaks=[   # 设置隐藏数据
        dict(bounds=["sat", "sun"]), # 隐藏周六、周日
    ]
)

fig.show()

开启显示滑块:fig.update(layout_xaxis_rangeslider_visible=True)

合并数据绘图

我们将3个股票的数据进行合并再绘图,使用的是concat函数:

# tushare_data

td = pd.concat([pingan,pinganbank,jinsen],axis=0).reset_index(drop=True)  # 指定横纵axis=0上的合并数据
td

3个股票的OHLC绘图:

fig = go.Figure()

fig.add_trace(go.Scatter(
    x=pingan['date'],
    y=pingan['open'],
    mode='lines',
    name='中国平安'
))

fig.add_trace(go.Scatter(
    x=pinganbank['date'],
    y=pinganbank['open'],
    mode='lines',
    name='平安银行'
))


fig.add_trace(go.Scatter(
    x=jinsen['date'],
    y=jinsen['open'],
    mode='lines',
    name='福建金森'
))

fig.update_xaxes(
    rangeslider_visible=True,   # 开启显示滑块
    rangeselector=dict(
        buttons=list([
            dict(count=1, label="1m", step="month", stepmode="backward"),  # 往后推一个月
            dict(count=6, label="6m", step="month", stepmode="backward"),  # 往后推6个月
            dict(count=1, label="YTD", step="year", stepmode="todate"),  # 只显示今年数据
            dict(count=1, label="1y", step="year", stepmode="backward"),  # 显示过去一年的数据
            dict(step="all")   # 显示全部数据
        ])
    )
)

fig.show()

进入股市7年,唯一的经验总结:不要炒股,不要炒股,不要炒股😭

扩展阅读

尤而小屋,一个温馨的小屋。小屋主人,一手代码谋求生存,一手掌勺享受生活,欢迎你的光临😃