数据分析手把手入门:打造自己的股票分析系统

作者:琥珀里有波罗的海

来源:数据如琥珀

打造自己的股票分析系统

1、前言

数据分析很重要的一步是结果展示与汇报,无论是给客户还是上级。你可以选择PPT展示,也可以给出word文档展示,但是如果有一个交互式的网站(app)展示,无疑是更加吸引人。

说起网站,很多人想到PHP,JS,但是绝大多数“数据分析师”没有这些技术,原因主要是:这完全是两个领域,精力有限的人很少会大量投入时间来精通。

python有很多优秀的开源网页设计框架,Django和Flask便是其中两个“巨头”,在企业中应用广泛。但是Django和Flask 固然优秀,但是它毕竟只是框架,关于页面设计的细节多数还是JS,而且有的时候你学了好几天设计出来的页面依然平庸无奇(我的就是奇丑无比)。

但是数据分析数据师如果想通过网页快速展示自己的成果,一定要学JS?一定要“重量级”框架?一定要忍受奇丑无比?

NO!NO! NO!

今天我们可以用纯python入门一个股票分析系统,不用JS,不用深入框架,入门一样酷炫,简约而不简单。

2、主角登场

作为入门教程,我们要实现以下功能:

  • 设计一个网站app,查看股票的历史记录

  • 获取股票列表,支持下拉选择以及输入检索

  • 支持时间段查询

  • 画出经典的股票趋势图

  • 动态调整时间段

  • 支持鼠标悬停显示当日详细详细

下面我们一一解释每个环节的实现方式,我估计本实现的难度系数在2颗星(只要你懂python)。

2.1 网站如何设计

这是一个轻量版的网站,我们这里自然无需用Django和(原生)Flask的重量级框架,但是即便是一个简单的demo,我依然希望网站保留可扩展的能力,比如实际的应用中我们可能还需要其他功能:

  • 需要实时显示当日股票信息

  • 显示大盘信息

  • 显示多个趋势

  • 显示周趋势,月度趋势

  • 添加表格,显示股票问题

  • 显示实时新闻

  • 甚至增加一键买/卖

  • 增加量化分析模型

以上通通可以实现,依然无需JS,有兴趣的可以进一步交流。

今天的网站设计采用的Plotly Dash,我相信很多人听过Plolty这个包,也用它画过简单的图(相当于交互版的matplotlib),但是dash 的功能很多人没有使用过。

网站链接如下:https://plotly.com/dash/

你可以看到很多交互式Dashboard的设计,比如用于制造业。

关于Plotly Dash,以下优缺点纯属个人亲测(实际项目)感受,可以帮你决定是否适合你:

  • 优点:

    • html 设计以及用户操作响应采用python,无需了解JS

    • 框架采用的Flask,所以Flask的功能都可以在这里实现,意味着强大的后续功能扩展

    • 对Flask进行了一定程度的封装,所以入手极快

    • 界面美观,如上图,用过plotly的人都喜欢它的设计

    • 支持交互式操作,比如plotly的图画带有各种按钮

    • 被很多开源BI 支持,比如Grafana

    • 适合数据分析师

  • 缺点:

    • 不适合大型项目,用户响应速度没有JS快(因为是纯python)

    • 不适合网站开发者,因为使用习惯不同

2.2 股票信息如何获取

这里不建议采用爬虫的方式进行获取,因为时间成本太高,而且获取的质量不稳定,作为一个网站,我们需要选用稳定的源。

有很多股票信息的开源包可以选择,我亲测过两个接口包,一个是akshare,一个Tushare。

这个demo中我们两个都进行了测试,但是akshare的访问速度和稳定性不佳(有可能是我个人网络问题),最后我选择了Tushare。

关于Tushare,采用注册制,注册即可获取足够积分来稳定的获取股票的信息,为了稳定性,我最终选择了Tushare,它也的确不辜负所望。由于我的积分目前不足以获取股票的周线,月线,以及大盘的信息,所以没法在demo中涵盖。

如果你是新手,不如点击我的邀请链接,注册的同时帮我获取积分吧:

https://tushare.pro/register?reg=129033

2.3 开启实战

首先导入我们所需的“主角”以及“配角”,这里依然将每个所需的包功能放在注释中。

import tushare as ts  # 获取股票信息import dash # 设计网站from datetime import datetime, timedeltaimport dash_core_components as dcc #设计网站采用的核心插件库import dash_bootstrap_components as dbc #设计网站采用的美化页面import dash_html_components as html  #设计网站采用的核心插件库from dash.dependencies import Input, Output, State # 完成用户点击响应import plotly.graph_objects as go # 画出趋势图from dash.exceptions import PreventUpdateimport pandas as pd


我们需要给我们网站中每个元素定义ID,方便后面进行回调,响应用户的操作。

# ID definitionsid_button_update_a_share_list = 'id-button-update-a-share-list'id_dpl_share_code = 'id-dpl-share-code'id_date_picker_range = 'id-date-picker-range'id_button_query_trend = 'id-button-query-trend'id_graph_hist_trend_graphic = 'id-graph-hist-trend-graphic'


这里主要的控件就是:

  1. 下拉列表,用于选择股票

  2. 右侧有更新股票清单按钮,用于更新股票清单,因为股票清单很久才更新一次,我们没有必要每次开网页都实时获取,可以从本地数据库或者本地文件中获取。

  3. 选择时间控件

  4. 查看股票信息按钮

  5. 绘图区

2.4 定义多个功能函数

为了方便调用,我们将一些常用的功能变成函数:

  1. update_a_share_list 用于从csv中读取股票代码以及名称

  2. get_A_stock_list 用于从网上下载最新的股票清单信息

  3. write_A_stock_list_to_csv 网上下载的信息同步到本地

  4. share_dict_to_option 将本地文件中的信息,合并成控件的选项,因为有些人知道股票代码,有些人知道股票名称,因此有必要支持两种检索

  5. get_trend_df:用于通过股票代码,以及时间段来获取日线

  6. plot_candlestick:用于画股票的K线,

def update_a_share_list():
    # display a stock share list from csv
    a_share_list_df = pd.read_csv(A_STOCK_FILE, index_col='ts_code')
    share_dict = a_share_list_df.to_dict()['name']
    return share_dict_to_option(share_dict)


def get_A_stock_list():
    # fetch list from internet
    share_df = ts_pro.stock_basic(
        exchange='',
        list_status='L',
        fields='ts_code,name')
    share_df.set_index('ts_code', inplace=True)
    return share_df


def write_A_stock_list_to_csv(file):
    # sync to csv
    share_df = get_A_stock_list()
    share_df.to_csv(file)


def share_dict_to_option(share_dict):
    # convert name and code to options
    name_list = [str(key) + '-' + str(value)
                 for key, value in share_dict.items()]
    return list_to_option_list(name_list)


def split_share_to_code(share):
    # split options to get code
    code = share.split('-')[0]
    return code


def list_to_option_list(list):
    # quick create dropdown options from list
    return [{"label": i, "value": i} for i in list]


def get_trend_df(code, start_date, end_date):
    # get history tend by ts_code,start_date,end_datess
    df = ts_pro.daily(ts_code=code, start_date=start_date, end_date=end_date)
    df['trade_date'] = pd.to_datetime(df['trade_date'], format='%Y%m%d')
    df.set_index('trade_date', inplace=True)
    df.sort_index(inplace=True)  # sort result by date (datetime)
    return df


def plot_candlestick(df):
    # plot candlestick
    # customize the color to China Stock
    fig = go.Figure(
        data=[
            go.Candlestick(
                x=df.index,
                open=df['open'],
                high=df['high'],
                low=df['low'],
                close=df['close'],
                increasing=dict(
                    line=dict(
                        color="#FF0000")),
                decreasing=dict(
                    line=dict(
                        color="#00FF00")),
            )])

    fig.update_layout(
        margin=dict(l=2, r=10, t=20, b=20),
        paper_bgcolor="LightSteelBlue",
    )  # change the layout of figure
    return fig

2.5 设计网页

网站框架的建立仅仅需要一行代码:dash.Dash(__name__)。这样就自动创建好一切框架,剩下的就是需要添加按钮,控件等。

这里我们通过按钮的设计来看一下该方案的简单快捷:

update_a_share_button = dbc.Button(
    id=id_button_update_a_share_list,
    color='light',
    children='更新列表', outline=True)

这是一个python函数,意味着你需要的主要配置都在函数的参数中。id 是前文提到的元素id,主要用于回调函数。color 不用说,就是颜色定义。因为这个更新股票列表按钮不常用,所以配色采用‘light’,outline 设为True,让他看起来像隐藏了一样,只有鼠标滑过才会显示。

  • Dropdown 是下拉列表控件,option参数很关键,也就是下拉的选项。调用我们前面定义的函数update_a_share_list来添加选项。

  • 为了让界面美观一点,这里我们调用bootstrap进行对齐设计。

  • Graph 控件用于绘图,核心的K线采用plot_candlestick函数绘制。

  • 最后,设计好的所有控件,放在app.layout中即可。

这样一个静态的网页就设计好了。

# create dash app
app = dash.Dash(__name__)

# layout design
header = html.H2("股票查询", className='text-center')
# update list button
update_a_share_button = dbc.Button(
    id=id_button_update_a_share_list,
    color='light',
    children='更新列表', outline=True)
# share select dropdown list
select_share = dcc.Dropdown(
    id=id_dpl_share_code,
    options=update_a_share_list()
)
# datetime picker
date_pick = dcc.DatePickerRange(
    id='id-date-picker-range',
    max_date_allowed=datetime.today(),
    start_date=datetime.today().date() - timedelta(days=60),
    end_date=datetime.today().date()
)
# query button
query_button = dbc.Button(
    "查询",
    color="warning",
    className="mr-1",
    id=id_button_query_trend,
    outline=False)

# make a better row/col layout
select_share_row = dbc.Container(
    [
        dbc.Row(
            [
                dbc.Col(
                    [select_share],
                    className='col-5'),
                dbc.Col(
                    [update_a_share_button],
                    className='col-2')]),
        html.Br(),
        dbc.Row(
            [
                dbc.Col(
                    [date_pick],
                    className='col-5'),
                dbc.Col(
                    [query_button],
                    className='col-1')])])

# get default figure
default_fig = plot_candlestick(
    get_trend_df(
        '000001.SZ',
        start_date='20200101',
        end_date='20200707'))
# graphic div
graphic_div = dbc.Container(
    [dcc.Graph(figure=default_fig, id=id_graph_hist_trend_graphic)])

# fully layout
app.layout = html.Div([
    header,
    select_share_row,
    html.Br(),
    graphic_div,
])

2.6 响应用户操作

Dash 采用callback 函数用于响应用户的操作,主要的状态有三个:

  • Input:表示”一触即发“,也就是用户只要进行了该操作,就会调用callback 函数,常见的如按钮的点击动作

  • State:表示“整装待发”,也就是只有Input 被执行时,callback会检查该元素的状态。该状态改变时,不会立马执行callback操作。比如下拉列表的选择。注意:如果你想让下拉列表选择变化后,立马会调出相应的趋势,那么可以把下拉列表的相应操作放在Input中

  • Output:就是callback的结果返回给哪个控件。

所以结合上面的基本信息,我们可以写出绘图callback。

Output, Input,State 函数都会有两个参数,第一个是元素的id,也就是指定元素。第二个是元素的属性,比如按钮的n_clicks属性,下拉列表的当然值value,日期选择控件的start_date和end_date。

  • Output(id_graph_hist_trend_graphic, 'figure'),    

  • Input(id_button_query_trend, 'n_clicks'),    

  • State(id_dpl_share_code, 'value'),      

  • State(id_date_picker_range, 'start_date'),    

  • State(id_date_picker_range, 'end_date')]



@app.callback(
    Output(id_graph_hist_trend_graphic, 'figure'),
    [Input(id_button_query_trend, 'n_clicks')],
    [State(id_dpl_share_code, 'value'),
     State(id_date_picker_range, 'start_date'),
     State(id_date_picker_range, 'end_date')]
)
def update_output_div(query, share, start, end):
    if query is not None:
        share_code = split_share_to_code(share)
        start_str = start.replace("-", "")
        end_str = end.replace("-", "")
        return plot_candlestick(
            get_trend_df(
                share_code,
                start_date=start_str,
                end_date=end_str))
    else:
        raise PreventUpdate

2.7 运行程序

运行程序只有一行代码,但是这里可以指定IP,端口等,让网站被其他人访问。默认的网址 http://127.0.0.1:8050/

if __name__ == '__main__':
    app.run_server(debug=True)

3、总结

作为一个入门级,适合数据分析师的网站设计示例,本示例演示如何设计一个股票历史查询网站。Plotly 以及Dash 对于数据分析来说,无疑是利器,可以不需其他前端语言完成一个酷炫的界面设计。Tushare 可以稳定的获取各种股票/金融相关的信息。

最重要的是,虽然该方案入门及其简单,但是扩展能力也很强,适合快速交付成果给客户。

扫描回复「股票02」获取本文代码

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值