從無到用寫個股票分析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="#/home"> <ion-nav-view name="tab-home"></ion-nav-view> </ion-tab> <!-- 自選 --> <ion-tab title="自選" icon="ion-person-add" href="#/user"> <ion-nav-view name="tab-user"></ion-nav-view> </ion-tab> <!-- 回測 --> <ion-tab title="回測" icon="ion-clock" href="#/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="{{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(一)