Fork me on GitHub

可视化神器Plotly玩转股票图

可视化神器Plotly玩转股票图

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

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

扩展阅读

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

导入库

1
2
3
4
5
6
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文件

1
2
3
4
# 读取在线的csv文件

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

数据大小为:

1
2
3
4
df.shape

# 结果
(506,11)

所有的字段为:

1
2
3
4
5
6
df.columns

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

基础绘图

1
2
3
4
5
6
7
8
9
10
11
12
13
# 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()

添加文本信息和备注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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自带的颜色:涨是红色,跌是绿色,下图中将涨变成了蓝色

1
2
3
4
5
6
7
8
9
10
11
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图形

1
2
3
4
5
# 如何生成一个datetime时间对象
import plotly.graph_objects as go
from datetime import datetime

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 绘制的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

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

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

1
2
3
4
5
6
7
8
9
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中自带的股票数据:

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

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

基于px实现

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 绘制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方法实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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()

共享时间轴

1
2
3
4
import plotly.express as px

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

1
2
3
4
5
6
7
fig = px.bar(
stock, # 数据
x=stock.index, # x轴
y="GOOG" # y轴
)

fig.show()

多面图共享时间轴

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

fig.show()

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

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

fig.show()

Label标签个性设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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()

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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()

指定交易日

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 添加画布
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()

指定交易范围

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

1
2
3
4
5
6
7
8
9
10
11
12
13
# 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()

带有区间滑块绘图

1
2
3
4
5
6
7
8
9
10
11
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()

滑块和时间按钮结合

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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、首先看看在某个具体的时间段内,如果我们不对非交易日进行处理,图形会是什么样子?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 默认形式

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、指定需要隐藏的时间:可以是星期,也可以是具体的某天

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 隐藏周末和节假日

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小时都在交易的,我们需要对非交易时间段进行隐藏:

1
2
3
4
5
6
7
8
9
10
11
12
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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库:

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

获取数据

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

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

往数据中添加两个字段:

1
2
3
4
5
6
7
8
9
10
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绘图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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函数:

1
2
3
4
# tushare_data

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

3个股票的OHLC绘图:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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()

往期精选

本文标题:可视化神器Plotly玩转股票图

发布时间:2021年04月27日 - 17:04

原始链接:http://www.renpeter.cn/2021/04/27/%E5%8F%AF%E8%A7%86%E5%8C%96%E7%A5%9E%E5%99%A8Plotly%E7%8E%A9%E8%BD%AC%E8%82%A1%E7%A5%A8%E5%9B%BE.html

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

Coffee or Tea