千家信息网

从无到用写个股票分析APP(一)

发表于:2024-09-22 作者:千家信息网编辑
千家信息网最后更新 2024年09月22日,前言:再给自己挖个坑吧。我想写个什么东西呢?一:可以浏览当下相关资讯,以及大盘指数实时更新。二:添加自选股票,可以查看该股票的走势图,相关资讯以及基本数据。三:通过 server 端定义相关指标及常用
千家信息网最后更新 2024年09月22日从无到用写个股票分析APP(一)

前言:再给自己挖个坑吧。


我想写个什么东西呢?

一:可以浏览当下相关资讯,以及大盘指数实时更新。

二:添加自选股票,可以查看该股票的走势图,相关资讯以及基本数据。

三:通过 server 端定义相关指标及常用策略,手机上可以直接添加已定义的技术指标及策略用以组合,然后在在 server 端得到结果,手机端查看。


项目地址:https://github.com/youerning/pstock


所用技术:

● nodejs:socket.io

● golang

● javascript:angularjs,chartjs

● css.

● Python:tushare,PyAlgoTrade,tornado,flask

● 打包:ionic


然后预览一下两天做的 demo



文章目录:

一:布局

二:部分细节说明

三:获取数据

四:绘图

五:编写策略 //等待填坑

六:优化细节 //等待填坑

七:美化,收尾 //等待填坑

注:为了使文章不会过于冗长,代码细节可能有所删减,详情参考项目源码:


(一)

1. 环境搭建参考:从无到有写一个运维APP(一)


2. 创建项目

ionic start pstock blank


3. 编写index.html。


4. 创建相应模板文件,结构大致如下



5. 创建路由

app.config(function($stateProvider, $urlRouterProvider, $ionicConfigProvider) {$ionicConfigProvider.tabs.position('bottom');$stateProvider.state("home", {url:"/home",views:{"tab-home":{controller:"homeCtrl",templateUrl: "tpls/home.html"}}});略...


至此,基本结构确定。


(二)

1. 上拉,下拉。

按住屏幕上下拖动,用以刷新数据以及加载数据在 ionic 的 JavaScript 组件已经有现成的了,所以可以直接拿过来用


代码如下:

`n`.`title`

- `n`.`media_name`


然后在相应的 controller 里面定义指定的执行函数 loadNewer(),loadOlder()


2. 自选股票的数据保存。

因为没有打算将自选的股票放在 server 端,所以数据应该保存在本地,即 localStorage 里面


$scope.userCode = angular.fromJson(window.localStorage["userCode"] || "{}");function persist() {window.localStorage["userCode"] = angular.toJson($scope.userCode)};


(三)

1. 获取新闻数据

在国内获取数据时间很难过的事情,为什么难过就不说了,当然可以自己爬,但是那样太不优雅了。


这里我们今日头条的新闻数据(今日头条不是没有公开过自己的API么?)


首先我们打开以下今日头条的网站


然后数据就出现了,就是这么有尿性,其实还有很多网站也这样,大家可以自己试试。


参考:

https://github.com/iMeiji/Toutiao/wiki/%E4%BB%8A%E6%97%A5%E5%A4%B4%E6%9D%A1Api%E5%88%86%E6%9E%90


2. 获取股票数据

这里用 tushare,当然了也可以用其他的 API。

参考:http://tushare.org/trading.html#id2


3. 策略数据(待填坑。。。)

PyAlgoTrade 策略。

其实直接用 tushare 的数据会报错,不过,也就是少了个 Adj Close,加个字段也不会那么难得。。。


4. server端代码

#coding: utf8from flask import Flaskfrom flask import Response, request, abortimport urlparseimport requestsimport jsonimport tushare as tsfrom random import randintfrom bs4 import BeautifulSoupimport pandas as pd# import sys# reload(sys)# sys.setdefaultencoding('utf-8')app = Flask(__name__)# sinaApi = "http://hq.sinajs.cn/list="detailUrl = "http://stockpage.10jqka.com.cn/%s/company/"toutiao = "http://www.toutiao.com/api/article/recent/?source=2&category=%s&as=A105177907376A5&cp=5797C7865AD54E1&count=5&offset=0&_=%s"def getUserAgent():userAgent = ["Mozilla/5.0 (compatible, MSIE 10.0, Windows NT, DigExt)","Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, 360SE)","Mozilla/4.0 (compatible, MSIE 8.0, Windows NT 6.0, Trident/4.0)","Mozilla/5.0 (compatible, MSIE 9.0, Windows NT 6.1, Trident/5.0,","Opera/9.80 (Windows NT 6.1, U, en) Presto/2.8.131 Version/11.11","Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, TencentTraveler 4.0)","Mozilla/5.0 (Windows, U, Windows NT 6.1, en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50","Mozilla/5.0 (Macintosh, Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11","Mozilla/5.0 (Macintosh, U, Intel Mac OS X 10_6_8, en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50","Mozilla/5.0 (Linux, U, Android 3.0, en-us, Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13","Mozilla/5.0 (iPad, U, CPU OS 4_3_3 like Mac OS X, en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5","Mozilla/4.0 (compatible, MSIE 7.0, Windows NT 5.1, Trident/4.0, SE 2.X MetaSr 1.0, SE 2.X MetaSr 1.0, .NET CLR 2.0.50727, SE 2.X MetaSr 1.0)","Mozilla/5.0 (iPhone, U, CPU iPhone OS 4_3_3 like Mac OS X, en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5","MQQBrowser/26 Mozilla/5.0 (Linux, U, Android 2.3.7, zh-cn, MB200 Build/GRJ22, CyanogenMod-7) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"]return userAgent[randint(0,len(userAgent)-1)]@app.route("//", methods=["GET","POST"])def index(app):headers = {"User-Agent": getUserAgent()}code = request.args["code"]data = {}error = ""if app == "now":# 获取当前价格code = code.split(",")df = ts.get_realtime_quotes(code)ret = df.to_json()elif app == "stock":# 获取股票历史数据df = ts.get_hist_data(code)df = df.sort_index()df["date"] = df.indexdf.index = range(len(df.index))ret = df.to_json()elif app == "detail":# 获取股票基本数据# 公司名称# 所属地域# 公司简介# 经营范围ret = {}url = detailUrl % codepage = requests.get(url, headers=headers)soup = BeautifulSoup(page.content, "html.parser")name = soup.select("td span")[0].textbussines = soup.select("td span")[3].textregion = soup.select("td span")[1].textintro = soup.select("p.tip.lh34")[-2].text[:-3]ret["name"] = nameret["bussines"] = bussinesret["region"] = regionret["intro"] = introelif app == "bt":ret = [{"status":"ok"}]elif app == "news":# 反向代理今日头条catelog = request.args["catelog"]time = request.args["now"]url = toutiao % (catelog, time)page = requests.get(url, headers=headers)ret = [{"status":"ok"}]else:ret = ""error = "incorrect url"try:data["data"] = json.loads(ret)except Exception as e:data["data"] = retdata["error"] = error# print dataresp = Response(json.dumps(data))if error:abort(500)resp.headers["Content-Type"] = "application/json; charset=UTF-8"resp.headers["access-control-allow-origin"] = "*"return respif __name__ == "__main__":app.run(port=80,debug=True, host="0.0.0.0")


5. client 端代码

$http.get(surl).success(function(resp) {$scope.labelsline = Object.values(resp.data.date);$scope.seriesline = ["ma5", "ma10", "ma20", "close"];$scope.dataline = [Object.values(resp.data.ma5),Object.values(resp.data.ma10),Object.values(resp.data.ma20),Object.values(resp.data.close)];$scope.optionsline = {title: {display:true,text: "趋势图"},elements: {point:{radius: 0}},xAxis: {display:true,axisLabel: 'X Axis',rotateLabels: 90}};


(四)

用 echarts 或者 chartjs,其实这没有技术含量的来着。。。主要查 API。

不过似乎手机端显示有问题,可能数据量过大或者不兼容之类的,待排查。。。


5,6,7 待填坑


自问自答:

Q:明明没用 golang,socket.io,tornado,为毛在所用技术中写出来。

A:我构思了,可是还没写完。


Q:写一个 web 的不也挺好的么。

A:写完了 app 自然会写 web 的。。。


后记:值得一说的事,好像也没想象中的那么简单,预想是三天就写完的来着,在下一篇之前,我应该先写 pyalgotrade 源码解读。


如果觉得不错,并有所收获,请我喝杯茶呗



0