2024年2月28日 星期三

[網站開發] 新增班佛定律頁面檢測美股財報 (Norn-StockScreener投資網站開發)

最近在看"為什麼我們會被騙?:破解金錢騙局、假新聞、政治謊言背後的詐騙機制"這本書, 書中其中一段有提到班佛定律, 這個定律可以用來檢測各種數據是否有造假的可能, 公式也很簡單, 只要將整份數據的所有數字, 取首位數並計算1~9的總數並計算分布就好, 如果計算後的分布近似於下面公式(wiki)的機率分布, 就代表數據受到操弄的可能性低:


要用班佛定律判斷數據是否造假有兩大前提:

(1) 數據的差距必須要夠大, 且樣本數要夠多

(2) 不能有人為操控


(1) 的說明我直接貼wiki, 最簡單明瞭XD


(2) 的部分則是你取樣的數據的類別不能是特殊被人為操控限制的, 例如電話號碼, 身份證字號開頭, 身高, 體重等等, 這些數字本身的範圍通常是固定的, 有些首位數也是固定值(例如成年人身高開頭通常會是1, 體重分布大多也侷限在特定範圍, 數據的差距太小等等)

關於班佛定律更詳細的說明, 有興趣可以參考下面兩個文章:

其中第二篇還有附Python程式碼, 並且用Fibonacci數列作為demo展示:


可以看到在N=10的時候, SSE (The sum of squares due to error, 和方差、誤差平方和) 非常高, 因為數據的差距太小 & 樣本數太少, 4, 6, 7, 9這四個數字連出現的機會都沒有, 所以SSE很高; 而隨著N越大取樣數字越多, SSE也越來越低, 最後跟班佛定律的公式分布幾乎一致。 


講解完班佛定律之後, 再來就是怎麼套用在投資上了, 看介紹班佛定律很適合用來分析財務報表上的數字, 如果SSE很高就代表財報受操弄的機率可能較高, 就決定來玩玩看, 並整合到自己寫的投資網站上, 做完的成果如下:


Norn-StockScreener投資網站: 
https://norn-stockscreener.zmcx16.moe/stock-benford-law/

Github: https://github.com/zmcx16/Norn-StockScreener


另外我以前也有實作另一套偵測財報造假的公式: Beneish M-Score模型, 有興趣的人也可以看看:

Blog文章: Beneish Model - 一個簡單識別公司財務報表是否造假的公式

公式網站: https://project.zmcx16.moe/?page=investment-formula


回歸正題, 這次整合班佛定律的財報來源是從Yahoo財經取得, 分析數據是標準的財報三表: 損益表, 資產負債表, 現金流量表。 而Yahoo的金融頁面的財報可以分別看季報跟年報, 並且最多可以分別看最近4期的財報, 所以這次整合班佛定律會分別計算以下SSE:

  • LastQ SSE (近一季財報)
  • LastY SSE (近一年財報)
  • AllQ SSE (近四季財報)
  • AllY SSE (近四年財報)
  • AllQY SSE (近四季+近四年財報)
其實要看的話最主要還是看AllQY SSE就好, 原因是只看這三大表數字的話, 取樣數字還是太少太少了, 看近四季+近四年, 才勉強達到取樣數字>1000的標準...。


另外前面有提到班佛定律的前提是數據類型差距要夠大 & 不能有人為操控, 所以我把財報三表中的: ["Diluted EPS", "Basic EPS", "Tax Rate For Calcs"] 特別過濾掉, 畢竟像這種ratio的數字本來就不適合套用在班佛定律上, 就決定把這種可能成為雜訊的數據類型事先過濾掉了。


首先來看看AAPL財報跑班佛定律的結果:



可以看到近一季 & 近一年的SSE特別高, 原因其實也不意外, 因為只看近一季或近一年的財報三表所有數字也才100多個, 取樣數字太少沒有鑑別性; 而近四季的SSE跟前面比就大幅降低, 代表隨著取樣數字增加SSE有降低, 是有符合班佛定律的; 而近四年的SSE跟前面相比雖然較低, 可是卻不顯著, 這是因為取樣數字還是不高導致的鑑別性太低, 還是有其他原因, 就需要再調查研究看看; 不過看近四季 + 近四年的SSE是最低的, 取樣數字有1240個, 看1~9的分布機率跟班佛定律也算接近, 從網站目前整合的4182檔個股來看, SSE排序大約在13XX/4182左右還算安全, 代表至少單從班佛定律看, AAPL的財報應該問題不太大。


另外雖然網站整合了這個功能, 可是可惜的是YAHOO財經有不少個股的財報三表數據還是不完整, 數據不完整導致樣本數低就沒辦法用班佛定律檢測, 不過只要不買股本小的冷門股基本上就不會遇到這問題, 對大多數人來說應該影響不大。


比較遺憾的是, YAHOO財經有整理的只有財報三表的資料, 可是一間公司完整的季報或年報, 其實是有更多數據資料的, 像是航運公司的財報就會說自己旗下有多少船, 以及這些船的營運成本跟收益如何; 礦產公司也會說明旗下有多少礦坑, 以及目前自己的原料庫存有多少等等..., 這些數據如果都能拿來計算的話, 班佛定律要求的樣本數要夠多就比較不是問題, 不過要我自己寫程式去parser SEC的財報數據太痛苦了, 也不一定能100%做到, 整理財報資料到財經網站這工作應該也有人工負責, 寫個一體適用的程式不太實際...。


最後總結一下, 班佛定律雖然可以用來辨識數據是否造假, 不過首先必須先確保數據是否適用(數據區間&差距夠大以及樣本數夠多; 並且數據類型不能有人為操控限制), 再來就是檢查出來就算不符合分布, 也不代表數據一定有造假, 只是這個可能性較高而已; 而就算完美符合班佛定律的公式分布, 也不代表一定沒有造假, 還是要用其他方式多加檢查(e.g. 使用Beneish M-Score模型檢查或是人工分析財報三表), 進行多種獨立性檢查才能更降低踩雷的風險...。

2024年2月18日 星期日

[網站開發] 2023年最有價值品牌 (Norn-StockScreener投資網站開發)

接前篇:

[網站開發] 2022年最有價值品牌 (Norn-StockScreener投資網站開發)

最近發現Interbrand已經發表2023全球最有價值品牌TOP100了:

https://interbrand.com/best-global-brands/



Norn-StockScreener投資網站: https://norn-stockscreener.zmcx16.moe/ranking/

Github: https://github.com/zmcx16/Norn-StockScreener



這次新入榜的有以下兩間公司:


很神奇的Oracle這麼大間的公司竟然是新上榜! 看了品牌價值趨勢圖, 發現Interbrand到2019年之前都是有納入品牌價值評估的, 至於中間為什麼斷了三年就不知道了, 不知道是不是Oracle一度不允許Interbrand評論的關係?

而另一間新上榜的公司是一間雀巢的子公司咖啡品牌, 加上這品牌雀巢目前總共有三個品牌在Interbrand Top100裡, 因為雀巢本來就在Interbrand Top100裡, 就不多加分析了。



這邊想額外分析的是, 因為有過去2022年的Interbrand Top100資料, 可以回測看看2022年的資料看品牌價值顯著上升/下降的公司, 看看對應的股價市值是否之後一年有隨之上漲/下跌, 2022年品牌價值變化超過+20%的有以下品牌:

Brand Value / 52-Week Stock Price Change
  • Microsoft (MSFT): +32% / +59.92%
  • Google (GOOG): +28% / +54%
  • Tesla (TSLA): +32% / +1.31%
  • Louis Vuitton (LVMUY): +21% / +2.31%
  • Adobe (ADBE): +23% / +57.68%
  • Chanel (-): +32% / None
  • Hermès (HESAY): +27% / +29.89%
  • Gucci (KER.PA): +23% / -27.58%
  • Allianz (ALV.DE): +23% / +13.17%
  • Mastercard (MA): +23% / +31.51%
  • Siemens (SIEGY): +21% / +18.47%
  • LEGO (-): +30% / None
  • Ferrari (RACE): +31% / +48.11%
  • Dior (CDI.PA): +27% / -3.05% 
  • Prada (PRDSY): +21% / 1.89%
也看看品牌價值負成長的品牌:
  • Facebook (META): -5% / +175.06%
  • Intel (INTC): -8% / +66.96%
  • Pampers (PG): -1% / +12.58%
  • H&M (HM-B.ST): -8% / +10.56%
  • Gillette (PG): -4% / +12.58%
  • Danone (BN.PA): -3% / +17.30%
  • Canon (CAJ): -15% / 美股ADR已退市

另外也順便看看2022新上榜的品牌:
  • Airbnb (ABNB): New / +18.43%
  • Red Bull (-): New / None
  • Xiaomi (XIACY): New / +6.67% 

而S&P500近一年的價格變化則是+25.22%, 品牌價值超過+20%並超過S&P500的有(6/13)間(扣掉未上市公司), 而不漲反跌的則有(2/13)間; 以這數字來說我覺得算合理, 至少有差不多快一半贏大盤, 而下跌的也只有兩間, 平均下來也有+22.12%, 只不過略輸大盤就是了 (看到這邊就會覺得是不是直接買大盤就好XDD)。

而更讓人驚訝的是品牌價值下跌的公司, 其中META可是爆漲了+175%, INTC也上漲+66.96%, 明明品牌價值是下跌的, 股價卻大幅上漲成這樣, 為什麼會這樣呢?  先來看一下META的資料:





可以看到META在2021年8月達到新高價379元之後, 之後一路下跌到最低93元, 下跌幅度高達-75%, 而之後上漲也很驚人, 目前已達到473元新高價。 而META會暴跌的原因主要是2022年開始營收跟獲利都大幅衰退, 後來是2023年恢復成長才大幅上漲, 而且2023Q4的財報又爆好, 過去一年績效才贏大盤這麼多。


再來看看INTC:




INTC的情形也跟META差不多, 從2022年開始營收跟獲利都大幅衰減, 可是到2023Q1最低點之後, 公司獲利開始轉虧為盈, 所以股價也隨著公司獲利改善上漲, 不過離以前的公司股價高點還有一段長遠的路...。


從META & INTC可以看出, 雖然品牌價值下跌但股價大漲甚至贏過大盤的原因, META是因為公司的獲利能力還是很強勁的, 而且公司也還有IG這個品牌(2022 brand value +14%), 再加上之前下跌太誇張, 所以之後回漲的幅度當然也更大, 會大幅超過S&P500也就不意外了。 而INTC的情況則是標準的轉虧為盈轉機股, 雖然獲利能力跟過去相比仍算差, 但也是之前下跌太深, 所以轉虧為盈後的上漲幅度才會相對大盤來得大得多。


至於從這些資料分析後得出的結論是什麼呢? 以我個人來說, 從上面的資料看來與其看品牌價值來決定投資標的, 那還不如買大盤就好, 勝率還會高一咪咪..., 可是我覺得重要的是, 投資不是看單一因素決定的, 我們必須評估各種因素, 建立自己的投資多因子模型, 來決定自己的投資標的&進出場策略。 

從品牌價值作為選股標的的最大好處, 我覺得第一個是踩雷的可能性大幅降低, 如果投資的標的是從品牌價值TOP100選, 選到地雷的可能性就會低不少; 而如果把品牌價值下跌的公司剃掉, 踩雷的機率則是又會更小得多 (當然也可能會錯過像META or INTC這種轉機股, 這就要投資者自行去判斷了)。 然後品牌價值也只是其中一個投資因子, 在透過其他各種不同的投資因子(e.g. 分析財報, 預測產業前景, etc...), 盡可能一點一點增加投資獲利的勝率就好。



最後在附上2023年的品牌價值數據, 至於股價會怎麼反應, 就觀察這一年看看結果如何了XD


2023年品牌價值變化超過+20% (跟2022年比超少, 如果想分析更多間公司也可以拉低門檻觀察):
  • Chanel (-): +32%
  • Hermès (HESAY): +27% 
  • Airbnb (ABNB): +22%
  • Porsche (POAHY): +20%
品牌價值負成長的品牌:
  • Disney (DIS): -4%
  • Facebook (META): -8%
  • Intel (INTC): -14%
  • UPS (UPS): -4%
  • Gucci (KER.PA): -2%
  • Nescafé (NSRGY): -2%
  • Goldman Sachs (GS): -2%
  • Budweiser (BUD): -16%
  • Philips (PHG): -12%
  • Nintendo (NTDOY): -2%
  • 3M (MMM): -7%
  • Danone (BN.PA): -4%
  • FedEx (FDX): -1%
  • Xiaomi (XIACY): -1%
  • Huawei (-): -2%

ABNB個人覺得是蠻有潛力的(2022年新上榜, 2023年品牌價值成長幅度也大, 不過之前疫情關係跌太慘, 疫情結束後已大幅上漲一波, 估值是否過高不好說...), 而DIS我覺得跟上面INTC一樣算是轉機股, 尤其是DIS最近的財報真的不錯, 我自己低檔也撿了不少, 等待並心懷希望了XD

2024年1月25日 星期四

MongoDB Atlas Auto-Scaling的神奇事

最近工作負責了改善產品系統使用Mongo DB的效能部分, 最主要做了把部分大流量的操作從Synchronous改成Asynchronous, 以及針對一些DB的寫入操作做Cache壓縮, 把一些暫態的寫入操作放到Cache keep住, 等Cache滿了或Schedule Timer時間到了在自動刷新Cache & 寫入到DB, 節省不必要的DB寫入。

改善完以後觀察Mongo Atlas Metrics, IOPS, CPU, Network, DB Update都降了不少, 可是唯獨Memory的使用量卻幾乎沒變, 用量一直維持在50%~60%左右, 而且不管是尖峰或離峰的情況都一直維持一個很平穩的狀態。

常理想應該是Mongo Atlas的DB Server在啟動時有預留一些記憶體當Cache使用, 所以照理說也不是什麼大問題。會覺得奇怪的地方是, 因為我們使用了Mongo Atlas Auto-Scaling服務, 在改善效能之前我們的DB Cluster Tier是M40, 這次改善的部分還不小, 對比過去的資料應該M30就夠用了, 為什麼沒有觸發Auto Scaling Down到M30呢?


後來就去查了一下Mongo Atlas的文件, 關於Auto-Scaling的文件可以參考這裡:

https://www.mongodb.com/docs/atlas/cluster-autoscaling/

其中關於Auto-Scaling的條件如下:



Scaling Up的條件是過去一小時內CPU or Memory > 75%; 而Scaling Down的條件則是過去24小時CPU and Memory < 50%, 看條件其實蠻合理的, 畢竟會需要Scaling Up的時候通常是系統忽然遇到高流量的情況, 不趕緊Scaling Up可能就要被打爆了; 而Scaling Down就比較寬鬆, 畢竟反反覆覆Scaling對系統也不太好, 系統穩定性相對Cost重要得多。


看上面的條件可以發現是因為M40的System Memory使用率一直都高於50%, 所以才無法觸發Auto Scaling Down, 可是我觀察過去系統在M30的Metrics, 發現記憶體用量卻是一直低於50%, 反而是Scaling Up到M40的瞬間就一直大於50%了, 相同流量下規格較差的DB Clusters反而記憶體整體用量比較小也太奇怪。


後來去查了下Mongo關於Atlas Cluster Sizing and Tier Selection的文件:

https://www.mongodb.com/docs/atlas/sizing-tier-selection/


M40或更高規格的Clusters, 會預設把50%的實體記憶體給WiredTiger Cache使用, M30或更低規格的Clusters則是預設把25%實體記憶體給WiredTiger用。 這也是為什麼會觀察到低規格的Clusters記憶體整體用量會比高規格小的關係。


然後問題就來了, 我要Auto Scaling Down就必須過去24小時CPU and Memory < 50%, 可是M40以上的Clusters又預設給WiredTiger 50%的實體記憶體, 這樣我這Auto Scaling Down的機制還能work嗎XD  後來就乾脆把上述的finding以及過去兩年Scaling Event整理一下, 敲Support Ticket Case請Mongo的人幫忙解答, Mongo Support的回覆如下:

for M40 or larger clusters, WiredTiger dedicates more than 50% of RAM - 1 GB for the WiredTiger cache in Atlas. Out which Atlas always tries to maintain 80% of the total allocated WiredTiger cache for performance optimisation. The main goal of WiredTiger cache is to avoid I/O operations to load the page from the disk while not reaching a fill ratio of over 80%. If the working set is bigger than the cache, the goal is to perform as few evictions as possible. Our internal article on How does MongoDB use memory? will provide you more insights.

...

Our product team is aware of the issues with auto downscaling based on memory utilisation for M40+ tier and they are working internally to improve this.


WiredTiger Storage Engine的文件中Memory Use的段落也有提到WiredTiger使用的預設記憶體大小:
https://www.mongodb.com/docs/manual/core/wiredtiger/


因為WiredTiger預設會吃50% - 1GB的實體記憶體, 所以只要M40 Clusters使用的記憶體扣掉WiredTiger超過1GB, 那就很難有機會Trigger到Auto Scaling Down, 尤其是對越高規格的Clusters來說更是如此。 而關於這問題Mongo Support也有回覆他們有注意到Auto Scaling Down在M40+會有這問題, 內部正在研究怎麼改善它, 而在Mongo改善這問題之前, 如果你遇到偶發的高流量事件或是寫出某個Bug導致Auto Scaling Up, 又或者你最近有Enhance Performance而且改善後目前的Cluster Tier太高的話, 可能就得自己手動降低Spec, 避免多花無謂的$$。


這次的分享大概就到這邊, 好久沒寫開發雜談了, 雖然工作上總會遇到各種神奇事, 不過會想要分享寫到部落格的卻很少, 畢竟寫部落格文章還蠻花時間的, 只想寫些印象深刻的事件並記錄下來XD