การวัด VaR. และ CVaR. ด้วย Python
การทำ portfolio optimization ด้วย google colab VI
วันนี้เราจะพูดถึงวิธีการทางสถิติที่สามารถนำมาใช้ในการวัดความเสี่ยงที่เรียกว่า value at risk.
Value at risk (VaR) เป็นสถิติที่ใช้วัดและกำหนดระดับความเสี่ยงของพอร์ตโฟลิโอ ตัวชี้วัดนี้ใช้เพื่อกำหนดขอบเขตและอัตราส่วนการเกิดขึ้นของการสูญเสียที่อาจเกิดขึ้นในพอร์ตการลงทุน
Conditional Value at Risk (CVaR) เป็นการประเมินความเสี่ยงที่วัดปริมาณความเสี่ยงที่พอร์ตการลงทุนมี CVaR นั้นได้มาจากการใช้ค่าเฉลี่ยถ่วงน้ำหนักของการสูญเสียที่“ รุนแรง” ในการกระจายตัวของผลตอบแทนที่เป็นไปได้นอกเหนือจากจุดตัดที่มีความเสี่ยง (VaR) ค่าความเสี่ยงแบบมีเงื่อนไขจะใช้ในการปรับพอร์ตให้เหมาะสมเพื่อการบริหารความเสี่ยง
เริ่มที่ Colab กันเลย
เหมือนกับทุกครังคือการ Import liberly
# load packages
import pandas as pd
import numpy as np
import pandas_datareader as pdr
import seaborn as sns
from matplotlib import pyplot as plt
import pandas_datareader as web
import datetime# not needed, only to prettify the plots.import matplotlib
from IPython.display import set_matplotlib_formats
%matplotlib inline
load data
ดึงข้อมูลจาก yahoo
start = datetime.datetime(2000, 1, 1)
end = datetime.datetime(2020, 1, 1)
df = web.DataReader("VOO", 'yahoo', start, end)df_daily_returns = df[['Adj Close']].pct_change().dropna()df_monthly_returns =
df[['AdjClose']].resample('M').ffill().pct_change().dropna()df_Yearly_returns = df[['Adj
Close']].resample('Y').ffill().pct_change().dropna()df_daily_returns.rename(columns={'Adj
Close':'daily_returns'},inplace=True)df_monthly_returns.rename(columns={'Adj
Close':'monthly_returns'},inplace=True)df_Yearly_returns.rename(columns={'Adj
Close':'Yearly_returns'},inplace=True)
VaR
การวัด VaR มีด้วยกันสามวิธีคือ
- Historic VaR
- Parametric Gaussian VaR
- Modified (Cornish-Fisher) VaR
Historic VaR
ในการคำนวณ VaR จากข้อมูลในอดีตคือการหาค่า ณ เปอร์เซ็นไทล์ที่ 5 หมายความว่ามีข้อมูลน้อยกว่านั้น 5 % numpy สามารภเรียหใช้np.percentile
if isinstance(r, pd.DataFrame):return r.aggregate(var_historic, level=level)elif isinstance(r, pd.Series):return -np.percentile(r, level)else:raise TypeError("Expected r to be a Series or DataFrame")
เรียกใช้ฟังชั่นได้ดังนี้
var_historic(df_monthly_returns, level=1)
ในการรายงานเป็นเรื่องปกติที่จะกลับเครื่องหมายดังนั้นเราจึงรายงานตัวเลขที่เป็นบวกเพื่อแสดงถึงการสูญเสียเช่นจำนวนเงินที่มีความเสี่ยง
Conditional VaR aka Beyond VaR
CVaR นั้นง่ายมาก ทั้งหมดที่เราต้องการคือการหาค่าเฉลี่ยของตัวเลขที่ต่ำกว่า VaR!
def cvar_historic(r, level=5):"""Computes the Conditional VaR of Series or DataFrame"""if isinstance(r, pd.Series):is_beyond = r <= -var_historic(r, level=level)return -r[is_beyond].mean()elif isinstance(r, pd.DataFrame):return r.aggregate(cvar_historic, level=level)else:raise TypeError("Expected r to be a Series or DataFrame")cvar_historic(df_monthly_returns, level=1)
Parametric Gaussian VaR
หากชุดของผลตอบแทนกระจายตามปกติเรารู้เช่นว่า 50% ของผลตอบแทนต่ำกว่าค่าเฉลี่ยและ 50% อยู่เหนือค่าเฉลี่ย
เรารู้ด้วยว่าประมาณสองในสามของผลตอบแทนอยู่ภายใน 1 ส่วนเบี่ยงเบนมาตรฐาน นั่นหมายถึงหนึ่งในสามอยู่เหนือค่าเบี่ยงเบนมาตรฐานหนึ่งค่าจากค่าเฉลี่ย เนื่องจากการกระจายตัวแบบปกตินั้นสมมาตรจะมีค่าประมาณหนึ่งในหก (ประมาณ 16%) ต่ำกว่าค่าเบี่ยงเบนมาตรฐานหนึ่งค่าจากค่าเฉลี่ย ดังนั้นถ้าเรารู้ค่าเฉลี่ยและส่วนเบี่ยงเบนมาตรฐานและถ้าเราคิดว่าผลตอบแทนปกติกระจาย 16% VaR จะเป็นค่าเฉลี่ยลบหนึ่งส่วนเบี่ยงเบนมาตรฐาน
โดยทั่วไปเราสามารถแปลงค่าเปอร์เซ็นไทล์เป็นคะแนน z ได้เสมอ (ซึ่งคือจำนวนส่วนเบี่ยงเบนมาตรฐานจากค่าเฉลี่ยที่เป็นตัวเลข) ดังนั้นหากเราสามารถแปลงระดับ VaR (เช่น 1% หรือ 5%) เป็นคะแนน z เราสามารถคำนวณระดับผลตอบแทนโดยที่เปอร์เซ็นต์ของผลตอบแทนอยู่ด้านล่าง
scipy.stat.norm มีฟังก์ชัน ppf () ซึ่งทำสิ่งนั้น มันใช้เปอร์เซ็นต์ไทล์เช่น 0.05 หรือ 0.01 และให้คะแนน z ที่สอดคล้องกับการแจกแจงแบบปกติ
from scipy.stats import normdef var_gaussian(r, level=5):# compute the Z score assuming it was Gaussianz = norm.ppf(level/100)return -(r.mean() + z*r.std(ddof=0))var_gaussian(df_monthly_returns)
Cornish-Fisher Modification
Cornish-Fisher Modificationเป็นการปรับแต่งที่เรียบง่าย คะแนน z บอกเราว่าความเบี่ยงเบนมาตรฐานอยู่ห่างจากค่าเฉลี่ยที่เราต้องไปหาค่า VaR หากผลตอบแทนไม่ปกติเรารู้ว่าคะแนน z จะให้ตัวเลขที่ไม่ถูกต้องกับเรา แนวคิดพื้นฐานคือเนื่องจากเราสามารถสังเกตความเบ้และความโด่งของข้อมูลเราสามารถปรับคะแนน z ขึ้นหรือลงเพื่อให้ได้คะแนน z ที่ปรับเปลี่ยน เช่น. สิ่งอื่น ๆ ที่เท่าเทียมกันถ้าความเบ้เป็นลบเราจะลดคะแนน z ลงอีกและถ้าความเบ้เป็นบวกเราจะผลักมันขึ้น
อย่างแรกเราต้องหาค่า skewness และ kurtosis
def skewness(r):"""Alternative to scipy.stats.skew()Computes the skewness of the supplied Series or DataFrameReturns a float or a Series"""demeaned_r = r - r.mean()# use the population standard deviation, so set dof=0sigma_r = r.std(ddof=0)exp = (demeaned_r**3).mean()return exp/sigma_r**3def kurtosis(r):"""Alternative to scipy.stats.kurtosis()Computes the kurtosis of the supplied Series or DataFrameReturns a float or a Series"""demeaned_r = r - r.mean()# use the population standard deviation, so set dof=0sigma_r = r.std(ddof=0)exp = (demeaned_r**4).mean()return exp/sigma_r**4
เราสามารถเขียนฟังชั่นได้ดังนี้
from scipy.stats import normdef var_gaussian(r, level=5, modified=False):"""Returns the Parametric Gauusian VaR of a Series or DataFrameIf "modified" is True, then the modified VaR is returned,using the Cornish-Fisher modification"""# compute the Z score assuming it was Gaussianz = norm.ppf(level/100)if modified:# modify the Z score based on observed skewness and kurtosiss = skewness(r)k = kurtosis(r)z = (z +(z**2 - 1)*s/6 +(z**3 -3*z)*(k-3)/24 -(2*z**3 - 5*z)*(s**2)/36)return -(r.mean() + z*r.std(ddof=0))
และเรียกใช้งานฟังชั่น
var_gaussian(df_monthly_returns, modified=True)
เปรียบเทียบวิธีต่างๆ
เราสามารถเปรียบเทียบการหาค่า Var จากวิธีต่างๆดังนี้
var_table_1 = [var_gaussian(df_monthly_returns),var_gaussian(df_monthly_returns, modified=True),var_historic(df_monthly_returns)]comparison_1 = pd.concat(var_table_1, axis=1)comparison_1.columns=['Gaussian', 'Cornish-Fisher', 'Historic']comparison_1
หาเราอยากหาค่า VaR ของรายวันหรือรายเดือน ทำได้ดังนี้
var_table_2 = [var_gaussian(df_daily_returns),var_gaussian(df_daily_returns, modified=True),var_historic(df_daily_returns)]comparison_2 = pd.concat(var_table_2 , axis=1)comparison_2.columns=['Gaussian', 'Cornish-Fisher', 'Historic']comparison_2var_table_3 = [var_gaussian(df_Yearly_returns),var_gaussian(df_Yearly_returns, modified=True),var_historic(df_Yearly_returns)]comparison_3 = pd.concat(var_table_3, axis=1)comparison_3.columns=['Gaussian', 'Cornish-Fisher', 'Historic']comparison_3all_comparisson =
pd.concat([comparison_2,comparison_1,comparison_3])all_comparisson.plot()
จะเห็นได้ว่าVarแบบข้อมูลย้อนหลังค่อนข้างผิดปกติเป็นผลมาจากจำนวนข้อมูลที่ไม่มากพอ และวิธี Cornish-fisher ติดลบสูงกว่า Gaussian เนื่องจากข้อมูลเบ้ขวา
Note book;
อ่านตอนอื่นๆได้ที่
- การคำนวณผลตอบแทนการลงทุนด้วย Python
- การหาความผันผวนของพอร์ตการลงทุนด้วย Python
- การหา Max Drawdown ด้วย Python
- การวัด การเบี่ยงเบนของผลตอบแทนด้วย Python
- การวัด SemiDeviation ด้วย Python
- การวัด VaR. และ CVaR. ด้วย Python
- รีวิวการใช้ ffn. ใน Python
- การหา Top Drawdown ด้วย Python
- การหาค่า Sharpe ratio ด้วย Python
- การหากลุ่มหลักรัพย์ที่เส้นประสิทธิภาพ Efficient Frontier ด้วย Python
- การหา shape ratio สูงสุดและเส้น CML ด้วย Python
- การสร้างมูลค่าตลาดแบบถ่วงน้ำหนักด้วย PYTHON
- ข้อจำกัดของการกระจายความเสี่ยงและการทำประกันพอร์ตการลงทุน
- การจำลอง ผลตอบแทนด้วย RANDOM WALK Generation และ Montecarlo simulation
- Sharpe Style Analysis
- Factor Investing ด้วย Python
- วิเคราะห์ ประเภทกองทุนรวมด้วย Python
- การทำ Portfolio optimization
- สร้างแนวรับแนวต้านวิเคราะห์หุ้นด้วย Python