蒙特卡洛模拟分析市场风险
摘要
1:本文討論將蒙特卡洛模擬的理念運用在市場風險分析上;
2:筆者希望搭建出一套交易體系,原則是只做干貨的分享。后續將更新更多模塊及內容,但工作學習之余的閑暇時間有限,更新速度慢還請諒解;
3:文中假設與觀點是基于筆者對模型及數據的一孔之見,若有不同見解歡迎隨時留言交流;
4:本文所涉及數據均通過公開渠道獲取,本文所涉內容與項目相關方不存在利益沖突;
5:模型實現基于python3.8;
目錄
1. 蒙特卡洛模擬
2. 項目背景和目標
3. 數據分析
4. 模型推導
4.1 足球參與人數模擬
4.2?腦震蕩數據模擬
4.2.1 原方案:線性擬合假設
4.2.2 新方案:正態分布假設
5. 代碼實現
6. 結果展示及討論
7. 本文所用到的腦震蕩數據集
1. 蒙特卡洛模擬
????????筆者去年寫過一篇蒙特卡洛模擬預測股價的文章,也有不少讀者發出質疑,畢竟用蒙特卡洛模擬無規律的布朗運動,得到的不還是一堆無規律的結果,云云。其實筆者只是舉個例子,更重要的是介紹蒙特卡洛模擬的理念。畢竟模型需要假設分布,而無規律的布朗運動正好是用來描述股價的方式之一。哪天您要是讀到筆者的文章獲得了什么靈感可以洞悉市場規律,筆者給您的忠告是:請千萬不要告訴任何人,拿著模型去賺錢吧。
????????蒙特卡洛模擬的理念和方式本文就不再贅述了,網上有很多文章,之前筆者也寫過,附傳送門:
(16條消息) 淺談股價預測模型(一):捉摸不定,最為致命_Simon Cao的博客-CSDN博客_股價預測模型https://blog.csdn.net/simon1223z/article/details/120495434?spm=1001.2014.3001.5501
2. 項目背景和目標
????????為了彌補下之前股價模型假設的遺憾,筆者出一期關于市場預測的內容,正好最近筆者的項目與之相關,在得到項目方允許的情況下,筆者利用公開數據及部分模型僅作展示,更重要的還是理念的講解。
????????該項目是關于澳大利亞大健康領域,數據方面筆者挑選了損傷數據中的運動腦震(Concussion)數據。任務目標是模擬出這該損傷未來五年的市場數據,并且判斷出第五年的市場下行風險。
????????由于當地州政府和衛生局比較懶(官網稱目前正在推進國家級運動損傷數據庫的建設,等它建好我們就該喝西北風去了),相關數據十分匱乏,給項目推進造成不小的阻礙。并且,進行大范圍的市場調查也非常吃力。在這種數據匱乏的時候筆者選擇使用蒙特卡洛模擬,其精妙之處在于可以進行一堆高大上的假設和推導(前提是合理公允),其過程看上去無比復雜,充分展現筆者的專業性。但其結果卻是通俗易懂的分布展示,即使客戶沒學過統計,您也可以用幾分鐘的時間向他展示通俗易懂的分布,充分體現客戶關懷。像這種又能體現專(裝)業(13),又客戶友好型的解決方案那不得用爆哇?
? ? ? ? 廢話不多說,馬上開整。
3. 數據分析
????????在項目一開始時所有人直接定位腦震蕩和軟組織損傷,因為澳洲醫療條件完備,近幾年來所有運動損傷中就腦震蕩是所有運動損傷中增長最大的,除此之外其它運動損傷數據近幾年都有遞減的趨勢。而且,這兩種損傷醫院和政府也更關切,可以說是投其所好了。但筆者提出幾個不一樣的觀查點:
????????首先是在所有運動損傷中,腦震蕩數字增長的確很大,如圖一數據:
圖一:運動腦震蕩統計
????????數據來源:
AFL 2021: Concussion is most common injury in Australian rules community footy and it’s getting worse (theage.com.au)https://www.theage.com.au/interactive/2021/sports-injuries/
????????雖然其絕對的數額很低,只有幾百人,但在澳洲引發的關注度很高,甚至連醫院的數據集都要給腦震蕩單開好幾張統計表。
那么:
????????為什么其它的運動損傷都在遞減, 就腦震蕩眾人皆跌它獨漲呢?因為澳洲人喜歡踢足球。
????????為什么喜歡踢足球腦震蕩數字會漲呢?因為為人腦在顱腔內像塊豆腐一樣很脆弱,研究表明頭球,沖撞等因素都是腦震蕩的元兇,感興趣的可以了解一下腦震蕩,有很多相關的文章和研究。
????????為什么關注度這么高呢?因為球迷們喜歡的球星得了腦震蕩,害得退賽了球迷那不得瘋狂diss它。
????????好家伙,一波為什么三連直接把筆者調查好長時間的結果全說完了,令人唏噓不已。。畢竟這不是重點,來看看數據吧:
?圖二:澳大利亞足球運動參與人數與年化增速
????????數據來源:
National Participation Reports | Football Australiahttps://www.footballaustralia.com.au/national-participation-reports
????????可以看到,澳洲踢足球的疫情前大概2百萬人,也就是說大概十個澳洲人里有一個是踢球的。(不知道我們國家是多少,反正筆者是純粹不踢球的人)。
? ? ? ? 從增速上看,即使排除疫情這兩年的異常數據,增速也是一直在下滑的。原因無非是澳洲人口總量的限制,總有一個天花板在。因此,以足球數據反推腦震蕩數據,將來想預期腦震蕩市場一直這樣高增長下去非常不現實。況且隨著社會的發展,醫療條件只會越來越進步, 更好的醫療條件只會讓腦震蕩案例進一步下降。
4. 模型推導
????????在上面分析和數據基礎上,筆者對未來五年的腦震蕩案例數據進行模型推演。
4.1 足球參與人數模擬
????????由于腦震蕩數據與足球參與人數相關性很強, 首先是未來的足球參與人數滿足方程[1]:
?? ?[1]
其中:
i: 年份?
g: 復合增長率(年化)
p:參與人數
????????就是很簡單的復合增速算數值的公式,C站插公式有點迷,上面的是i次根號才對,看上去像乘。
????????關鍵就在于這個g,筆者通過時間序列回歸擬合過去增速并且加入隨機游走項得到, 刨去2021, 2020及2016幾年的異常數據,經過擬合可得腦震蕩年化復合增速滿足方程[2]:
? [2]
其中:g為年化復合增速,x為年份
????????經假設檢驗,該式在99%置信水平下有效,?。
? ? ? ? 結合方程[2],在[1]式基礎上加入隨機游走項有公式[3]:
? [3]
????????其中:服從該隨機游走過程, N服從均值為0, 方差為的正態分布
4.2?腦震蕩數據模擬
????????筆者一開始的方案是照前面足球運動參與人數的方式估計腦震蕩數據,但是后面模擬發現效果并不理想。
4.2.1 原方案:線性擬合假設
取2014-2018年腦震蕩數據與足球參與人數可得腦震蕩比率:
| year no. | concussion rate? |
| 1 | 0.051778 |
| 2 | 0.047775 |
| 3 | 0.041499 |
| 4 | 0.035621 |
| 5 | 0.035373 |
回歸擬合可得方程[4]:
? [4]
其中:
c:腦震蕩比例
x: 年份
????????經假設檢驗,該式在99%置信水平下有效,?。
????????由于腦震蕩比例降低,市場趨于穩定,其數據的波動率其實也有隨著降低的趨勢, 因此這里筆者假設腦震蕩的標準差比例隨著腦震蕩比率的下降而降低。其實這樣假設是有點問題的,因為線性擬合的其中一個假設是獨立同分布,如果假設方差隨時間變化而遞減則產生異方差,而且是那種條件異方差,但蒙特卡洛模擬好就好在假設靈活,而且是對未來的估計。筆者認為這么用符合實際情況,依舊是公允的。結合之前的方程[3]加入比例隨機游走過程得總方程[5]:
? [5]
變量有點多,重新列一下,?服從該隨機游走過程, 其中:
i: 年份?
g: 復合增長率(年化)
p:參與人數
N服從均值為0, 方差為的正態分布
C服從均值為0, 方差為?的正態分布
? ? ? ? 除了假設外,從公式看這個方案效果依舊不是很理想,因為它是線性時間序列數據擬合,樣本點也非常少,這導致在模擬很多期帶入公式后產生負值,而這個比率是不可能為負的,于是這個方案在項目上就被放棄了,不過筆者在下面代碼實現中還是把它運行出來,畢竟也是花了幾行代碼實現出來的,在文章里發光發熱一下。
4.2.2 新方案:正態分布假設
????????假設腦震蕩比率服從正態分布, 直接在分布里面取數然后乘到之前足球人數里, 于是有總方程[6]:
? [6]
?????????這個方案簡潔明了,筆者就不在下面代碼中實現了。
5. 代碼實現
????????將上述過程以代碼實現:
import pandas as pd import numpy as np import random import matplotlib.pyplot as plt import seaborn as snsdef player_simulation(years, beg, sigma, player_sim): # just for football playeryears_data = []for i in range(0, years):if player_sim is True: # football player number simulationg = 0.217433 - 0.01738 * (1 + i) + random.normalvariate(0, sigma/(i+1))compunded_g = (1 + g) ** (1 + i)years_data.append(beg * compunded_g)else: # 原腦震蕩比例線性擬合模擬方案 concussion number simulationproportion = 0.055899 - 0.0045 * (1 + i) + random.normalvariate(0, sigma/(i+1))years_data.append(proportion/100)return years_datadf = pd.read_excel("file.xlsx", sheet_name="name") # 導入本地數據集 player_data = df[df.columns[1]] # 運動員數據 growth = [] for i in range(len(player_data)-1): growth.append((1 + (player_data[i+1]-player_data[0])/player_data[0])**(1/(i+1)) - 1) # compunded g: (1+g)^(1/year no.) - 1 std_player_g, mean_player_g = np.std(growth[:5]), np.mean(growth[:5]) # 后面兩年COVID異常數據不要 concussion_rate_data = pd.read_excel("file.xlsx", sheet_name="name") # 導入本地數據集 concussion_ratio = concussion_rate_data["concussion_rate_in_football_players"].values[5:8] # 筆者只用16-18年數據, 其它drop掉 std_c_r, mean_c_r = np.std(concussion_ratio), np.mean(concussion_ratio)players_simu = [] # 腦震蕩運動員數量模擬結果 for times in range(200000):player_simu = player_simulation(5, player_data[len(player_data)-1], std_player_g, player_sim = True)c_simu = player_simulation(5, concussion_ratio[len(concussion_ratio)-1], std_c_r, player_sim = False)players_simu.append(np.multiply(player_simu, c_simu))print("No.{} simulation\r".format(times), end="") print("simulation success")????????將模擬數據展示出來,可以選擇動態展示(plot動態畫線,將plt.show()去掉,在for循環中加入下面兩句就可以動態展示)。
plt.draw() plt.pause(0.001)????????但模擬上萬次的線要畫很長時間,屬于給別人展示時候的耍酷功能, 如果模擬幾十上百萬次估計睡一覺明天起來看還在畫線呢。
????????也可以一次性展示出來, 快,但是幾十萬次模擬也要幾十秒才能刷出來。
selector = input("Draw simulation lines? (y/n):") # 要不要展示作圖過程 fig1 = plt.figure(1) if (selector == "Y") or (selector == "y"):for i in range(len(players_simu)):plt.plot([2022,2023,2024,2025,2026], players_simu[i])plt.xticks([2022,2023,2024,2025,2026])plt.xlabel("years")plt.ylabel("Number")plt.draw()plt.pause(0.001)plt.close(fig1) elif (selector == "N") or (selector == "n"):for i in range(len(players_simu)):plt.plot([2022, 2023, 2024, 2025, 2026], players_simu[i])plt.xticks([2022, 2023, 2024, 2025, 2026])plt.xlabel("years")plt.ylabel("E(No.)")plt.show() else:print("Error instruction, input y or n, please run again")????????最后一年的分布也可以導出:
last_y = [] for i in range(len(players_simu)):last_y.append(players_simu[i][-1]) sns.distplot(last_y) plt.xlabel("E(No.)") plt.show()6. 結果展示及討論
圖三:蒙特卡洛模擬(20萬次)
圖四:蒙特卡洛模擬第五年分布情況(20萬次)
????????可以看到,腦震蕩在未來5年中呈現先揚后抑的走勢。由于疫情好轉,可以說未來幾年內市場還是比較安全的。但在市場到達頂點之前就要提前考慮第二增長曲線,提早進行部署。從最后一年的分布來看,市場雖然會經歷下滑,但總量上依舊維持在一個歷史較高的水平。值得注意的是有10%的情況下,市場將下滑至低于848例腦震蕩患者。
? ? ? ? 可以看到,這一通分析還是很有價值的,只是損傷數據豈止腦震蕩那么簡單,很多數據也很不完善,實務中仍然有一堆問題要解決不過模擬方法大同小異。
? ? ? ? 市場分析對基本面分析依舊意義重大,市場是水,公司是船,水漲自然船高,無水自然擱淺,而蒙特卡洛模擬用簡單的分布告訴我們未來的水位究竟會如何變化,其實在筆者看來數據缺少是可以克服的困難,因此不算是困難,此外,代碼不是困難,建模不是困難,分析也不是困難,真正困難的是合理公允的假設,這是技術活中的技術活。
7. 本文所用到的腦震蕩數據集
????????由于數據及其少,筆者簡單po這里了, 鏈接在前文放了,這里就不放了:
????????澳洲足球運動參與人數:
| year | No. of football players in AU |
| 2014 | 990759 |
| 2015 | 1188911 |
| 2016 | 1301244 |
| 2017 | 1631041 |
| 2018 | 1851683 |
| 2019 | 1957552 |
| 2020 | 1181931 |
| 2021 | 1421804 |
?足球運動腦震蕩人數:
| Year | Concussion No. |
| 2011 | 346 |
| 2012 | 334 |
| 2013 | 417 |
| 2014 | 513 |
| 2015 | 568 |
| 2016 | 540 |
| 2017 | 581 |
| 2018 | 655 |
您若不棄,我們風雨共濟!
總結
以上是生活随笔為你收集整理的蒙特卡洛模拟分析市场风险的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mac 下的代码比对工具
- 下一篇: opendrive中的几何形状