1 数据获取
量化数据接口有很多,有tushare、alltick、xtquant等等。本文使用的是akshare库,它是开源的财经数据库,不仅包含股票、期货、期权、外汇、基金等常见的金融数据,还包括能源、事件、舆情和艺人指数这类不常见但可能影响市场行为的其他数据,可以说是目前市面上免费接口里最全的一个。
以获取深市a股历史日线数据为例,首先获取深市a股的股票信息:
import akshare as ak
stock_info = ak.stock_info_sz_name_code()
stock_info.to_excel('stock_code.xlsx')
2 应用架构
本应用基于dash框架、开源组件库feffery_antd_components与akshare金融数据接口开发的轻量级应用。app.py中进行应用对象的实例化,并构建应用的初始化页面内容;setting.css进行前端界面样式的调整;data储存的是深交所a股信息。
- demo
- data
- stock_code.xlsx
- assets
- setting.css
- app.py
3 应用启动
安装好当前项目依赖库,然后直接在终端执行python app.py即可启动应用,按照控制台提示的信息,浏览器访问本地http://127.0.0.1:8050地址即可访问应用。

4 代码
# app.py
import pandas as pd
import dash
from pyecharts import options as opts
import akshare as ak
from dash import dash, html, dcc, callback, output, input, state
import dash_bootstrap_components as dbc
from pyecharts.charts import kline
import feffery_antd_components as fac
# 应用实例化
app = dash(
__name__,
title='量化小应用',
update_title='加载中...',
assets_url_path='assets/setting.css'
)
app.layout = fac.antdspace([
dcc.store(storage_type='local', id='stock-code-store', data=pd.read_excel('data\stock_code.xlsx', dtype={'a股代码': 'str'}).to_dict('records')),
fac.antdflex([
fac.antdicon(icon='antd-right', style={'color': '#0069d9'}),
fac.antdtext('股票历史日线数据查询', classname='header')
]),
fac.antdflex([
fac.antdflex([
'股票代码:',
dcc.dropdown(
id='stock-dropdown',
multi=false,
searchable=true,
value='000001',
placeholder='股票代码',
style={'width': '100px'}
),
], align='center', gap='small'),
fac.antdflex([
'日期:',
fac.antddaterangepicker(
placeholder=['选择开始日期', '选择结束日期'],
id='stock-dropdown datepicker',
size='middle',
prefix=fac.antdicon(icon='antd-calendar')
),
], gap='small'),
fac.antdbutton(
'搜索',
type='primary',
id='stock-dropdown btn',
loadingchildren="查询中",
),
], align='center', gap='large'),
fac.antdcard(
title='收益概述',
headstyle={'background': 'rgba(0, 0, 0, 0.3)', 'text-align': 'left'},
id='card-content',
classname='card'
),
], classname='container')
@app.callback(
output('stock-dropdown', 'options'),
input('stock-code-store', 'data')
)
def code_info(data):
data = pd.dataframe(data)
data['a股代码'] = data['a股代码'].astype('str')
options = [
{'label': x, 'value': 'sz' + y}
for x, y in zip(data['a股代码'], data['a股代码'])
]
return options
@app.callback(
output('card-content', 'children'),
input('stock-dropdown btn', 'nclicks'),
[state('stock-code-store', 'data'),
state('stock-dropdown', 'value'),
state('stock-dropdown datepicker', 'value')],
running=[(output('stock-dropdown btn', "loading"), true, false)],
)
def update(nclicks, data, value, date):
stock_info = pd.dataframe(data)
stock_info = stock_info[stock_info['a股代码'] == value[2:]].to_dict('records')
title = stock_info[0]['a股简称'] + '(sz:' + stock_info[0]['a股代码'] + ')'
result = ak.stock_zh_a_daily(symbol=value, start_date=date[0], end_date=date[1])
result.rename(columns={'open': '开盘价', 'close': '收盘价', 'low': '最低', 'high': '最高'}, inplace=true)
fig = (
kline(init_opts=opts.initopts(width='1200px', height='300px'))
.add_xaxis(list(result['date']))
.add_yaxis(series_name='k线', y_axis=result[['开盘价', '收盘价', '最低', '最高']].values.tolist(),
itemstyle_opts=opts.itemstyleopts(color='rgb(192, 51, 47)', color0='green'))
.set_global_opts(
title_opts=opts.titleopts(title=f'{date[0]}-{date[1]}日k线'),
yaxis_opts=opts.axisopts(name='单位净值(元)', min_=result[['开盘价', '收盘价', '最低', '最高']].min().min(), max_=result[['开盘价', '收盘价', '最低', '最高']].max().max()),
tooltip_opts=opts.tooltipopts(trigger='axis', axis_pointer_type='cross', formatter='{b}: {c}', border_color='#ccc', background_color='rgba(245, 245, 245, 0.8)'),
datazoom_opts=opts.datazoomopts(is_show=true, range_start=result['date'].min(), range_end=result['date'].max()),
)
.set_series_opts(
markpoint_opts=opts.markpointopts(data=[opts.markpointitem(type_='max', name='最高价', value=result['最高'].max()), opts.markpointitem(type_='min', name='最低价', value=result['最低'].min())], symbol='pin'),
splitline_opts=opts.splitareaopts(is_show=true),
linestyle_opts=opts.linestyleopts(type_='dashed', color='lightgrey'),
)
)
fig.render('kline.html')
card_layout = [
fac.antdrow(title, classname='card-content title', wrap=true),
fac.antdrow([
fac.antdcol([
fac.antdtext('最高:', classname='card-content index'),
fac.antdtext(result['最高'].max(), classname='card-content value', style={'color': 'red'})
]),
fac.antdcol([
fac.antdtext('最低:', classname='card-content index'),
fac.antdtext(result['最低'].max(), classname='card-content value', style={'color': 'green'})
]),
fac.antdcol([
fac.antdtext(f'成交量:{str(result['volume'].sum())}手', classname='card-content index'),]),
fac.antdcol([
fac.antdtext(f'成交额:{str(result['amount'].sum())}元', classname='card-content index'),]),
], gutter=20),
html.iframe(
srcdoc=open('kline.html', 'r').read(),
style={
'height': 300,
'width': '100%',
'align': 'center'
}
)
]
return card_layout
if __name__ == '__main__':
app.run(debug=false)
/* setting.css*/
html,body {
background-color: #ffffff;
color: #000000;
text-align: center !important;
margin: 1%;
padding: 1%;
font-family: 'sans ser-if';
}
.container {
display: grid;
width: 1200px;
}
/* 标题样式 */
.header {
font-size: 18px;
font-weight: bold;
}
/* 卡片样式 */
.card {
width: 1400px;
}
.ant-card-body {
display: flex;
flex-direction: column;
}
.card-content {
}
.title {
font-size: 24px;
font-weight: bold;
}
.index {
font-size: 12px;
font-weight: bold;
}
.value {
font-weight: bold;
}
5 优化方向
由于本文涉及的数据交互与计算较少,历史数据获取的方式是直接调用akshare库,而该库有的数据不能频繁获取。若数据量增多,为提高系统效率与性能,需要采取适当的方式,将数据持久化保存到本地。
构建成多页面应用,一个页面存放一个指标
到此这篇关于使用python实现构建量化小程序的文章就介绍到这了,更多相关python构建量化程序内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论