2020年11月23日 星期一

[網站開發] 美股搜尋網站 (1) 後端程式開發 - 使用Azure Cosmos DB & Azure Function

去年自己寫了個美股掃雷網: https://norn-minehunter.zmcx16.moe/

至於選股則是都透過Finviz的screener功能: https://finviz.com/screener.ashx?v=111&ft=4

雖然說Finviz真的很好用, 功能也非常強大, 可是能看的東西都是已知的基本面或技術分析指標, 沒辦法做自己的客製化指標, 變成我每次都得先用Finviz的screener先搜尋過濾, 在用自己的指標挑選一次, 這樣很麻煩又會有缺漏, 就想說還是自己來做個美股搜尋器好了。

再來就是做搜尋器最大的問題點了, 我要怎麼取得所有美股的數據資料? 美股大概有一萬檔以上的上市股票, 扣掉市值太低以及成交量太低的個股, 也還是有近3000~6000檔個股。 而我目前使用的數據源都是免費的, 只要使用量太大就會被ban IP, 如果乖乖的在不被ban IP的情況去取得所有美股資料的話, 目前估算抓完一輪至少要一個多禮拜, 這樣每次過濾搜尋的資料會離得目前市價太遠, 會有工具失真的問題...。

以自己來說要達到搜尋器可用等級的話, 數據資料最多不能差超過一天, 所以我至少要有7個IP以上每天不斷的抓數據才有辦法, 幸好之後有想到辦法, 詳情可以參考以下這篇:

[雲端服務] 被ban ip又沒有穩定的proxy server怎麼辦? 用Azure Function自己架個代理伺服器吧

Ban IP的問題解決了, 再來就是伺服器工作量的問題, 基本上就是要寫個一直取得美股數據並生成報表的程式, 由於自己的Azure VM是最低階規格, 而且已經掛了幾個我的網站服務, 所以就不太想把這個一直忙跟佔網路流量的程式放在自己的Azure VM server上了。思考了下最後決定把這個程式寫在Azure Function上, 像這種 I/O bound的工作放在Azure Function可以幾乎花不到什麼錢, 至於取得的數據部分, 原本是想直接上傳到我自己的Azure VM上或是存到Azure storage account, 不過剛好最近玩Azure時有注意到他們的Azure Cosmos DB的免費層還蠻佛心的, 剛好又想玩玩NoSQL, 就決定趁這次機會玩玩看。

下面是Azure Cosmos DB免費層規格:


RU是request unit的縮寫, 認真講還真看不懂要怎麼換算, 不過以容量來說有5G已經很佛心了, 而container則是有限制最多只能開到25個, 以我來說算綽綽有餘了。 另外由於Azure Cosmos DB分片是以10G為單位, 以免費層來說等於不會有用到分片的機會, 沒辦法享受到NoSQL水平擴展的魅力。

建好的DB概觀圖如下, 目前正在用Azure Function慢慢抓資料放到DB中, 這資料跟索引大小的比例真是讓人愉悅XD



下圖是Azure Cosmos DB的資料總管, 可以直接從網頁看到你的資料庫內容, 目前我主要拿來放每檔美股的基本以及生成掃雷報表的分數結果, 用平均分數當作Partition Key, 不過因為容量只有5G, 基本上也沒有這個key的表現機會就是了。 另外從圖中可以看到, 資料是以JSON表示, 另外Azure也很貼心的提供SQL command支援, 不過畢竟是NoSQL, 已經不是關聯式資料庫了, 應該還是有些語法不支援吧, 這個就有空在研究了。 另外很可惜的是Azure Cosmos DB免費層不支援VNet, 這代表我沒辦法設定防火牆只讓我的Azure入口網站還有Azure Function存取, 只能用Authorization Key當作最終保護DB的手段。



基本上都是用async的function讀寫, 寫入的時候都會指定你資料的Partition Key, 另外奇怪的是範例上的讀寫資料都是用自己寫的class定義document的結構, 在讓SDK把資料轉入 / 出 定義好的class物件, 基本上這樣超麻煩..., 畢竟這等於每種類型的document都得寫個class去定義schema, 這樣跟關聯式資料庫時定義schema不是沒兩樣嗎..., 如果是多層的json資料不是會寫到死, 更何況json還有可能是動態的, 如果圖方便用字串存那之後query又得去parser字串效能不就悲劇了嗎?

因為範例那種作法超麻煩, 所以我自己是把有可能是動態的資料都直接宣告成dynamic了, 而且這樣寫進去的資料從Azure資料總管看也是多階層的JSON, 而讀取的話我是直接用dynamic去接, 在用JSON parser去parse我要的資料, 這樣效能應該是會比自己定義class去存取慢, 不過基本上不用在意效能的地方很方便就是了, 不如說有可能動態階層的document也只能這樣讀吧?



這次分享就到這邊, 基本上後端這樣就搞定了, 再來就是苦力的前端, 基本上大多數網站的Stock Screener的頁面都大同小異, 應該是不用花太多心力刻啦, 不過我自己每次寫前端都覺得超累, 不像後端寫好功能邏輯就好, 前端layout跟微調每次都得花大把時間, 可以的話能不寫還真想不寫XD

沒有留言:

張貼留言