現代化風險管理第2部分:聚合,大規模回溯測試和引入替代數據
理解和降低風險是任何金融服務機構的首要任務。然而,正如這個由兩部分組成的係列的第一篇博客中所討論的那樣,如今的銀行仍在努力跟上其業務麵臨的新風險和威脅。受本地基礎設施和遺留技術限製的困擾,銀行直到最近才擁有有效構建現代風險管理實踐的工具。幸運的是,基於雲原生基礎設施支持的開源技術,目前存在更好的替代方案。這現代風險管理框架支持日內視圖,按需聚合和未來證明/規模風險管理的能力。在這個由兩部分組成的係列博客中,我們將演示如何通過使用的方法使傳統的風險價值計算現代化三角洲湖,Apache火花TM而且MLflow為了使一個更靈活和前瞻性的方法,風險管理。
第一個演示通過數據和高級分析解決了與風險管理實踐現代化相關的技術挑戰,涵蓋了使用MLflow和Apache Spark進行風險建模和蒙特卡羅模擬的概念TM.本文主要關注風險分析師角色及其需求,以便在新威脅出現時實時更好地理解投資組合風險,從而有效地分割和細分風險模擬(按需)。我們將討論以下主題:
- 使用Delta Lake和SQL按需聚合風險價值
- 使用Apache SparkTM和MLflow對模型進行回測,並向監管機構報告違規情況
- 探索使用替代數據來更好地評估您的風險暴露
三角洲湖的風險價值
在第一部分在這個由兩部分組成的係列博客中,我們揭示了現代風險管理平台的樣子,以及金融服務機構需要改變看待數據的視角:不再將數據視為成本,而是將其視為資產。Beplay体育安卓版本我們展示了數據的多用途性質,以及如何以最細粒度的形式存儲蒙特卡羅數據,從而支持多個用例,同時為分析師提供運行特別分析的靈活性,有助於對銀行麵臨的風險進行更健壯和敏捷的查看。
在這個博客和演示中,我們揭示了由多個行業的40種工具組成的拉丁美洲股票投資組合的各種投資風險。為此,我們利用了通過蒙特卡羅模擬(40個儀器x 50,000個模擬x 52周= 1億條記錄)生成的大量數據,按天劃分,並通過我們的投資組合分類法進行豐富,如下所示。
風險價值
風險價值是模擬隨機遊走的過程,它涵蓋了可能的結果和最壞的情況(n)。(t)天內95%的風險值是最糟糕的5%試驗中的最佳情況。
由於我們的試驗是按天劃分的,分析師可以很容易地訪問一天的模擬數據,並通過試驗Id(即用於生成金融市場條件的種子)對個人回報進行分組,以訪問我們投資回報的每日分布及其各自的風險價值。我們的第一種方法是使用Spark SQL來聚合給定一天(50,000條記錄)的模擬回報,並使用內存中的python通過簡單的numpy操作來計算5%的分位數。
返回=火花\.read \.表格(monte_carlo_table) \.過濾器(F.col (“run_date”)==“2020-01-01”) \.groupBy (“種子”) \.agg (F。總和(“審判”) .alias (“返回”)) \.選擇(“返回”) \.toPandas () (“返回”]value_at_risk=np.quantile (返回,5/One hundred.)
如果在我們所有的拉丁美洲股票工具上進行1萬美元的初始投資,在特定的時間點上95%的風險價值將是3000美元。這是我們的業務在所有可能發生的事件中最糟糕的5%中(至少)準備損失的金額。
這種方法的缺點是,我們首先需要收集內存中的所有日常試驗,以便計算5%的分位數。雖然在使用1天的數據時可以輕鬆地執行這個過程,但在較長時間內聚集風險價值時,它很快就會成為一個瓶頸。
一種實用的、可擴展的解決問題的方法
從大型數據集中提取百分位數對於任何分布式計算環境都是一個已知的挑戰。一種常見的(盡管效率很低)做法是:1)對所有數據進行排序,2)使用takeOrdered選擇特定的行,或者通過approxQuantile方法找到近似值。我們的挑戰略有不同,因為我們的數據不構成一個單一的數據集,而是跨越多個天、多個行業和多個國家,其中每個桶可能太大,無法在內存中有效地收集和處理。
在實踐中,我們利用風險價值的本質,隻關注最壞的n個事件(n小)。給定每台儀器50,000次模擬和99%的VaR,我們隻感興趣在最差的500個實驗中找到最好的。為此,我們創建了一個用戶定義的聚合函數(UDAF),它隻返回最差n個事件中的最佳事件。這種方法將大大減少計算大規模VaR聚合時可能出現的內存占用和網絡約束。
類ValueAtRisk(n:Int)擴展UserDefinedAggregateFunction{//這些是聚合函數的輸入字段。重寫inputSchema: org.apache.spark.sql.types.StructType = {StructType (StructField (“價值”, DoubleType):: Nil)}//這些是你為計算聚合而保留的內部字段。重載bufferSchema: StructType = StructType數組(StructField (“壞的”ArrayType(倍增式)))//聚合函數的輸出類型。重寫dataType: dataType = DoubleType//我們處理數據幀的順序不重要//最壞的永遠是最壞的覆蓋定義確定性:布爾=真正的//這是緩衝區模式的初始值。重寫def初始化(緩衝區:MutableAggregationBuffer):單位= {緩衝(0) = Seq。空[雙]}這是如何在給定輸入的情況下更新你的緩衝區模式。重寫def update(buffer: MutableAggregationBuffer, input: Row): Unit = {緩衝(0) = buffer.getAs[Seq[雙]] (0):+ input.getAs[雙](0)}這是如何合並bufferSchema類型的兩個對象。//我們隻保留最差N個事件重寫def merge(buffer: MutableAggregationBuffer, row: row): Unit = {緩衝(0) = (buffer.getAs [Seq [雙]] (0getas [Seq[雙]] (0)) .sorted.take (n)}//這是輸出最終值的地方//我們的風險值是所有風險值中最好的override def evaluate(buffer: Row): Any = {返回buffer.getAs [Seq [雙]] (0) .sorted.last}
}// 95%的風險值是最壞的N個事件中的最佳Val n = (One hundred.-95) * numSimulations /One hundred.//注冊uadfspark.udf.register (“VALUE_AT_RISK”,新ValueAtRisk (n))
通過spark.udf.register方法注冊我們的UADF,我們將該功能暴露給所有用戶,無需scala / python / spark高級知識的所有人都可以進行風險分析。人們隻需按試驗Id(即種子)進行分組,以便應用上述方法,並在所有數據中使用普通的舊SQL功能提取相關的風險值。
選擇t.run_date作為一天,VALUE_AT_RISK (t.return)作為value_at_risk從(選擇m.run_date,m.seed,總和(m.trial)作為返回從monte_carlo米集團通過m.run_date,m.seed) t集團通過t.run_date訂單通過t.run_dateASC
我們可以很容易地發現COVID-19對我們市場風險計算的影響。自2020年3月初以來,90天的經濟波動期導致風險價值大幅降低,因此整體風險敞口大幅上升。
全麵看待我們的風險暴露
在大多數情況下,僅僅了解總體的風險價值是不夠的。分析師需要了解不同賬簿、資產類別、不同行業或不同運營國家的風險敞口。除了前麵討論過的時間旅行和ACID事務等Delta Lake功能之外,Delta Lake和Apache SparkTM在Databricks運行時進行了高度優化,以提供讀取時的快速聚合。通過使用我們的本地分區邏輯(按日期)以及適用於國家和行業的z順序索引,可以實現高性能。在選擇國家或行業級別的特定數據切片時,將充分利用這個額外的索引,從而大大減少在VaR聚合之前需要讀取的數據量。
優化蒙特卡羅ZORDER BY(國家,行業)
通過使用國家和行業作為VALUE_AT_RISK方法的分組參數,我們可以輕鬆地調整上麵的SQL代碼,以便對風險暴露有一個更細粒度和描述性的視圖。由此產生的數據集可以使用Databricks筆記本進行可視化,並可以進一步細化,以了解這些國家對我們整體風險價值的確切貢獻。
在這個例子中,秘魯似乎對我們整體風險敞口的貢獻最大。在秘魯的行業級別上查看相同的SQL代碼,我們可以調查跨行業風險的貢獻。
2020年3月,秘魯的主要風險敞口似乎與采礦業有關,這一比例接近60%。為應對新冠病毒而實施的越來越嚴格的封鎖措施,影響了銅、黃金和白銀生產中心秘魯的采礦項目。源).
擴展本文的範圍,我們可能想知道是否可以更早地使用替代數據,特別是使用事件、位置和基調的全球數據庫(GDELT).我們在下麵的圖表中報告秘魯采礦業的媒體報道,通過簡單的移動平均線對積極和消極趨勢進行顏色編碼。
這清楚地顯示了2月初的積極趨勢,即在觀察到的股票波動的15天之前,這可能是風險增加的早期跡象。這一分析強調了風險價值計算現代化的重要性,用來自替代數據的外部因素來補充曆史數據。
模型,val
為了應對2008年金融危機,巴塞爾銀行監管委員會又製定了一套措施。1天VaR 99結果將與每日損益進行比較。每季度使用最近250天的數據進行回測。根據在此期間所經曆的超標次數,VaR測量被分為三個彩色區域之一。
水平 | 閾值 | 結果 |
---|---|---|
綠色 | 最多超過4項 | 沒有特別的擔憂 |
黃色的 | 最多超過9項 | 監測要求 |
紅色的 | 超過10項 | VaR措施有待改進 |
的風險價值
根據我們前麵定義的聚合函數,我們可以在整個投資組合中提取每日的風險價值。由於我們的聚合風險價值數據集很小(包含2年的曆史,即365 x 2個數據點),我們的策略是收集每日VaR並將其廣播到更大的數據集,以避免不必要的混亂。關於AS-OF功能的更多細節可以在更早的文章中找到博客民主化金融時間序列分析.
情況下類VarHistory(time:長,valueAtRisk:字符串)瓦爾historicalVars=sql(年代”“”SELECT t.run_date, VALUE_AT_RISK(t.return) AS valueAtRisk從(SELECT m.run_date, m.seed, sum(m.trial)作為返回值來自蒙特卡洛mGROUP BY m.run_date, m.seed) t集團t.run_date”“”).withColumn(“時間”convertDate (坳(“run_date”))).orderBy(asc (“時間”)).選擇(“時間”,“valueAtRisk”).作為[VarHistory].收集().sortBy(_.time).反向瓦爾historicalVarsB=火花.sparkContext.廣播(historicalVars)
我們通過一個簡單的用戶定義函數檢索與實際收益最接近的風險價值,並執行250天的滑動窗口來提取連續的每日違規。
val asOfVar=udf ((s: java.sql.Date)=>{val historicalVars=historicalVarsB.value如果(s。取得時間s.getTime).headOption.map (_.valueAtRisk)}})val windowSpec=Window.orderBy(“時間”).rangeBetween (-3600年*24*250,0)val countBreaches=udf (asOfVar:雙,返回: Seq [雙])=>{的回報。數(_我們可以觀察到一個連續的級數的17違反從二月以後就需要了來報告來法規依據來巴塞爾協議III框架。同樣的情況也可以反映在圖表上,在時間。