起初,我并不在意echarts,这不过是一个偶然、一次选择、一条简单的代码、一个图表的诞生,直到我完成了K线图的绘制。
股票,一个神奇的发明,他看不见摸不着,无法预测,却时刻让你的神经紧绷。他的出现,是对打工人的福音?还是一场灾难?是命运的转折点,还是一夜回到解放前。他都可以帮你实现。
K线图,他让你的投资有了参考,花哨的图表下面隐藏着财富的密码。接下来就让我们一起揭开这神秘的面纱。
输入你喜欢的股票代码,就可以生成近一年的K线图。如此方便简洁,难免不让人心动。
更加令人兴奋的是,根据算法,可以预测出明天股票的涨跌情况。当然准不准我也不知道,仅供参考。
该工具使用的股票数据来自于Tushare,只需要注册获取一个token就可以免费得到股票数据。
Tushare官网地址:https://tushare.pro/document/2?doc_id=14
第一步: 从文末的源码地址,下载项目并解压到本地电脑
第二步: 配置运行环境,使用pycharm导入项目,在【terminal】下运行下面命令:
pip install -r requirements.txt
如果下载第三方库比较慢,可以考虑换一下pip的下载源:
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
阿里云 http://mirrors.aliyun.com/pypi/simple/
中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
豆瓣(douban) http://pypi.douban.com/simple/
清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/
中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/
第三步: 更改app.py中的ts_token,使用自己在tushare网站注册获取的token。右击运行app.py在浏览器中就可以看到图表。
前端的技术主要用到echarts、element、vue等技术,官方文档上多有详细的案例,只需要参照官方文档案例代码,根据自己需求修改调试好代码即可。
绘制K线图
echarts图表案例:Examples - Apache ECharts
elements组件案例:组件 | Element
源码展示:
<html>
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<title>股票小工具title>
head>
<body>
<div id="app">
<el-row :gutter="10" style="margin-top: 20px;">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>K线图span>
div>
<el-row>
<el-col>
<el-form label-width="80px" :inline="true" :model="stockForm">
<el-form-item label="股票代码:">
<el-input v-model="stockForm.code" placeholder="例如:000001.SZ" clearable />
el-form-item>
<el-form-item>
<el-button type="primary" v-if="stockForm.code"
@click="stockFormSubmit('stockForm')">确定el-button>
<el-tooltip class="item" v-else effect="dark" content="请填写股票代码!">
<el-button type="danger">确定el-button>
el-tooltip>
el-form-item>
<el-form-item>
[{stockName+forcastMsg}]
el-tag>
<el-tag v-else type="success" effect="dark">
[{stockName+forcastMsg}]
el-tag>
el-form-item>
el-form>
el-col>
el-row>
<el-row>
<div id="main" style="width:1000px;height:500px;">div>
el-row>
el-card>
el-row>
div>
body>
<script src="../static/js/echarts.min.js">script>
<script src="https://unpkg.com/[email protected]/dist/vue.min.js">script>
<script src="https://unpkg.com/element-ui/lib/index.js">script>
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js">script>
<script>
const upColor = "#ec0000"
const upBorderColor = "#8A0000"
const downColor = "#00da3c"
const downBorderColor = "#008F28"
var nv = new Vue({
el: '#app',
delimiters: ['[{', '}]'],
data: function() {
return {
// 表单数据
stockForm: {
code: '000001.SZ',
},
// 图表数据
kChartdata: null,
// 预测信息
forcastMsg: "预测信息",
// 股票名
stockName: "",
}
},
created:function(){
this.stockFormSubmit()
},
methods: {
// 获取输入的股票代码数据
async stockFormSubmit(stockForm) {
const {
data: res
} = await this.$http.post("http://127.0.0.1:12345/stock", this.stockForm)
if (res.status != 200) {
this.$message({
showClose: true,
message: res.msg,
center: true,
type: 'error'
})
} else {
this.$message({
showClose: true,
message: res.msg,
center: true,
type: 'success'
})
// 重新赋值新的股票数据
var myChart = echarts.init(document.getElementById('main'))
this.kChartdata = res.stock_data
this.forcastMsg = this.kChartdata.forcast
this.stockName = this.kChartdata.name
var option = {
// 图表标题配置
title: {
text: this.stockName + '近一年K线图'
},
// 提示框配置
tooltip: {
// 是否显示提示框
show: true,
// 触发类型,axis 移动到坐标轴就触发
trigger: "axis",
// 坐标轴上提示点设置
axisPointer: {
type: "cross"
}
},
// 图例配置
legend: {
data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30']
},
// X 轴配置项
xAxis: {
type: "category",
data: this.kChartdata.stock_trade_days,
boundaryGap: false,
axisLine: {
onZero: false
},
splitLine: {
show: true
},
min: "dataMin",
max: "dataMax"
},
// y 轴配置项
yAxis: {
scale: true,
splitArea: {
show: true
}
},
dataZoom: [{
type: "inside",
start: 50,
end: 100
},
{
show: true,
type: "slider",
top: "90%",
start: 50,
end: 100
}
],
// 系列配置,根据不同图表有不同的配置
series: [{
name: "日K",
// 图表类型
type: 'candlestick',
// 数据内容
data: this.kChartdata.stock_trade_data,
// K 线图的图形样式
itemStyle: {
// 阳线 图形的颜色
color: upColor,
// 阴线 图形的颜色。
color0: downColor,
// 阳线 图形的描边颜色
borderColor: upBorderColor,
// 阴线 图形的描边颜色
borderVolor0: downBorderColor
},
// 标记点配置
markPoint: {
// 标注的文本
label: {
// 标签内容格式器,支持字符串模板和回调函数两种形式,字符串模板与回调函数返回的字符串均支持用 \n 换行。
// 参数 params 是 formatter 需要的单个数据集, value是传入的数据值。
formatter: function(param) {
return param != null ? Math.round(param.value) + "" :
"";
}
},
// 标注的数据数组。每个数组项是一个对象
data: [
// 特殊的标注类型,用于标注最大值最小值等
{
name: "highest value",
type: "max",
// 在使用 type 时有效,用于指定在哪个维度上指定最大值最小值。
valueDim: "highest",
},
{
name: 'lowest value',
type: 'min',
valueDim: 'lowest'
},
{
name: 'average value on close',
type: 'average',
valueDim: 'close'
}
],
// 提示框浮层内容格式器,支持字符串模板和回调函数两种形式。
tooltip: {
// params 是 formatter 需要的数据集
formatter: function(param) {
// name数据名,类目名,data传入的原始数据项
return param.name + "
" + (param.data.coord || "")
}
}
},
markLine: {
// 标线两端的标记类型,可以是一个数组分别指定两端,也可以是单个统一指定
symbol: ['none', 'none'],
// 标线的数据数组。每个数组项可以是一个两个值的数组,分别表示线的起点和终点,每一项是一个对象
data: [
[
// 定义从最小值到最大值的线
{
name: "from lowest to highest",
type: "min",
valueDim: "lowest",
symbol: "circle",
symbolSize: 10,
label: {
show: false
},
emphasis: {
label: {
show: false
}
}
},
{
type: "max",
valueDim: "highest",
symbol: "circle",
symbolSize: 10,
label: {
show: false
},
emphasis: {
label: {
show: false
}
}
},
],
// 最小值水平线
{
name: "min line on close",
type: "min",
valueDim: "close"
},
// 最大值水平线
{
name: "max line on close",
type: "max",
valueDim: "close"
},
],
}
},
{
name: "MA5",
type: "line",
data: this.kChartdata.MA5,
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: "MA10",
type: "line",
data: this.kChartdata.MA10,
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: "MA20",
type: "line",
data: this.kChartdata.MA20,
smooth: true,
lineStyle: {
opacity: 0.5
}
},
{
name: "MA30",
type: "line",
data: this.kChartdata.MA30,
smooth: true,
lineStyle: {
opacity: 0.5
}
},
]
}
//使用刚指定的配置项和数据显示图像
myChart.setOption(option)
}
},
}
});
script>
html>
使用flask搭建的微应用,接口介绍:
import pandas as pd
from flask import Flask, render_template, request
from flask import jsonify
from flask_cors import CORS
import webbrowser
from datetime import datetime, timedelta
import tushare as ts
ts_token = "填写在tushare获取的token"
ts.set_token(ts_token)
pro = ts.pro_api()
app = Flask(__name__)
CORS(app, supports_credentials=True)
def get_stock(code):
# 获取股票数据
end_date = datetime.now().strftime("%Y%m%d")
start_date = datetime.strftime(datetime.now() - timedelta(365), "%Y%m%d")
df = pro.daily(ts_code=code, start_date=start_date, end_date=end_date).sort_values(by="trade_date")
try:
data = pro.query('stock_basic', exchange='', list_status='L', fields='ts_code,name')
data.to_excel("./static/excel/stock_basic_info.xlsx", index=False)
name = data[data["ts_code"] == code]["name"].values[0]
except Exception as e:
data = pd.read_excel("./static/excel/stock_basic_info.xlsx")
name = data[data["ts_code"] == code]["name"].values[0]
if df.empty:
return None
df["MA5"] = df["close"].rolling(4).mean().map(lambda x: round(x, 3))
df["f1"] = df["MA5"] - df["close"]
forcast_msg = f"预测 {end_date} 会跌!"
if sum(df.tail(7)["f1"] > 0) > 4:
forcast_msg = f"预测 {end_date} 会涨!"
result = {
"stock_trade_days": df["trade_date"].values.tolist(),
"stock_trade_data": df[["open", "close", "low", "high"]].values.tolist(),
"MA5": df["close"].rolling(4).mean().map(lambda x: round(x, 3)).fillna("-").tolist(),
"MA10": df["close"].rolling(9).mean().map(lambda x: round(x, 3)).fillna("-").tolist(),
"MA20": df["close"].rolling(19).mean().map(lambda x: round(x, 3)).fillna("-").tolist(),
"MA30": df["close"].rolling(29).mean().map(lambda x: round(x, 3)).fillna("-").tolist(),
"forcast": forcast_msg,
"name": name
}
return result
@app.route("/")
def index():
return render_template('index.html')
@app.route("/stock", methods=["GET", "POST"])
def stock():
# 获取提交的股票代码
rq_json = request.json
stock_code = rq_json["code"]
# 获取股票数据,数据解释:时间,开盘价,收盘价,最低价,最高价
get_stock_result = get_stock(stock_code)
if get_stock_result:
result = {
"status": 200,
"stock_data": get_stock_result,
"msg": f"获取{stock_code}股票数据成功!"
}
return jsonify(result)
else:
result = {
"status": 400,
"stock_data": None,
"msg": f"获取{stock_code}股票数据失败!"
}
return jsonify(result)
if __name__ == '__main__':
webbrowser.open("http://127.0.0.1:12345/")
app.run(debug=False, port=12345)
运行后就可以在浏览器中看到,感兴趣的朋友可以试试!
链接:https://pan.baidu.com/s/1pkAZDi3jLQoh8vifHaj0nA?pwd=vd3s