首页 > 代码库 > 从无到用写个股票分析APP(一)

从无到用写个股票分析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。

<ion-tabs class="tabs-icon-top">
<!-- 首页 -->
<ion-tab title="首页" icon="ion-home" href="http://www.mamicode.com/#/home">
<ion-nav-view name="tab-home"></ion-nav-view>
</ion-tab>
<!-- 自选 -->
<ion-tab title="自选" icon="ion-person-add" href="http://www.mamicode.com/#/user">
<ion-nav-view name="tab-user"></ion-nav-view>
</ion-tab>
<!-- 回测 -->
<ion-tab title="回测" icon="ion-clock" href="http://www.mamicode.com/#/backtest">
<ion-nav-view name="tab-backtest"></ion-nav-view>
</ion-tab>
</ion-tabs>


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组件已经有现成的了,所以可以直接拿过来用

代码如下:

<ion-refresher
pulling-text="Pull to refresh..."
on-refresh="loadNewer()">
</ion-refresher>
<a class="item item-thumbnail-left"
ng-repeat="n in news track by n.item_id"
ng-click="openLink(n.article_url)">
<img ng-src="http://www.mamicode.com/{{n.media_avatar_url}}">
<h2 class="news-title">{{n.title}}</h2>
<p><span am-time-ago="n.behot_time | amFromUnix"></span> - {{n.media_name}}</p>
</a>
</div>
<ion-infinite-scroll
on-infinite="loadOlder()"
distance="1%">
</ion-infinite-scroll>

然后在相应的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: utf8
from flask import Flask
from flask import Response, request, abort
import urlparse
import requests
import json
import tushare as ts
from random import randint
from bs4 import BeautifulSoup
import 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("/<app>/", 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.index
df.index = range(len(df.index))
ret = df.to_json()
elif app == "detail":
# 获取股票基本数据
# 公司名称
# 所属地域
# 公司简介
# 经营范围
ret = {}
url = detailUrl % code
page = requests.get(url, headers=headers)
soup = BeautifulSoup(page.content, "html.parser")
name = soup.select("td span")[0].text
bussines = soup.select("td span")[3].text
region = soup.select("td span")[1].text
intro = soup.select("p.tip.lh24")[-2].text[:-3]
ret["name"] = name
ret["bussines"] = bussines
ret["region"] = region
ret["intro"] = intro
elif 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"] = ret
data["error"] = error
# print data
resp = Response(json.dumps(data))
if error:
abort(500)
resp.headers["Content-Type"] = "application/json; charset=UTF-8"
resp.headers["access-control-allow-origin"] = "*"
return resp
if __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源码解读。

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

技术分享技术分享


本文出自 “又耳笔记” 博客,请务必保留此出处http://youerning.blog.51cto.com/10513771/1943259

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