欢迎使用RiskQuantLib¶
RiskQuantLib是金融工程中著名的衍生品定价库Quantlib的一个衍生库,但不同于QuantLib,RiskQuantLib是一个金融数据分析脚手架。RiskQuantLib提供默认的python类文件,作为金融工具的模板类,并且在给定继承规则和其他信息的条件下,允许使用者通过RiskQuantLib自动创建更多自定义的python类。RiskQuantLib也提供自动化工具,来为创建的python类自动添加属性。
为什么我应该使用RiskQuantLib?¶
RiskQuantLib提供了方便的工具来供金融分析师进行对象化编程。
RiskQuantLib是基于QuantLib实现的,你可以使用QuantLib的内置函数,并且可以很好地与RiskQuantLib相结合。
RiskQuantLib是一个脚手架,这意味着他可以为每一个数据分析项目单独新建一个工程,在新建工程之后,RiskQuantLib将会成为新工程的一部分,你可以更改工程中RiskQuantLib的源代码,使得RiskQuantLib符合当前工程的需要。
RiskQuantLib适用于不同的市场,所有的金融工具模板类是由使用者自定义的,这使得RiskQuantLib使用者有极大的自由度。
RiskQuantLib使得数据的处理流程彼此分开。使用RiskQuantLib,可以将数据存储,数据输入,数据分析,以及数据输出彼此隔离。你甚至可以在数据输入之前提前开始编写数据处理逻辑,而不是等待数据输入之后,再进行分析。
RiskQuantLib提供工程模板管理功能,使用者可以编写符合自己数据处理习惯的工程模板,比如股票收益分析,然后将这个模板保存为模板工程,与其他人分享。或者在遇见下一个相似的数据分析项目时,使用已有的模板工程来初始化新的工程。
谁适合使用RiskQuantLib?¶
RiskQuantLib是为了使金融分析师更快速,更方便地进行数据分析而设计的。任何金融分析师,金融相关专业的学生,量化交易员都可以使用RiskQuantLib。当需要处理多种金融工具时,RiskQuantLib尤为有用。
注意: RiskQuantLib并不是为大数据分析而设计的,RiskQuantLib牺牲了运行速度和内存空间来换取更快的代码开发速度。
一个例子¶
假设你是一家著名的国际投行的员工。一天,你的老板叫你去办公室,他告诉你他想要投资一个家族基金,名为Archegos。如果你选择接受这份任务,老板将需要你通过数据研究,来计算这项投资的风险。
三思后的冒险,和鲁莽截然不同。
你调查了一番,从彭博获取了一些数据,但是这些数据只告诉你了Archegos的一些股票持仓,其中有一些中概股,比如腾讯或者阿里巴巴。你获取的第一个数据表格看起来像这样:
Index |
Holding Mkt Value |
Stock |
|---|---|---|
0 |
239018292 |
TCEHY US Equity |
1 |
710281723 |
ABC US Equity |
2 |
7497233 |
HIYJ US Equity |
3 |
179321234 |
SPACEX US Equity |
4 |
83249 |
HE US Equity |
在这之后,你决定下载一些股票在过去三年的每日收盘价,你的第二个数据表看起来像这样:
Date |
HIYJ US Equity |
U7HJ US Equity |
HE US Equity |
|---|---|---|---|
2020-01-01 |
23.9 |
nan |
9.8 |
2020-01-02 |
nan |
12.8 |
9.5 |
2020-01-03 |
21.9 |
13.1 |
9.3 |
2020-01-04 |
22.1 |
13.2 |
9.7 |
2020-01-05 |
22.4 |
12.9 |
9.8 |
… |
… |
… |
… |
你决定计算Archegos股票持仓的历史波动率,你开始一段python编程计算,看起来像这样::
df_stock_holding = pd.read_excel(path_one)
df_stock_close = pd.read_excel(path_two)
如果你不使用RiskQuantLib,你可能这样做::
df_std = df_stock_close.std()
std_of_archegos_stock_holdings = df_std[df_stock_holding.columns.to_list()]
现在你对于自己的结果非常满意,似乎股票的部分风险已经可以被解释,至少在某种程度上,可以被解释。在下午,你的老板又告诉你,他知道Archegos还持有两支著名基金,名为H和JK,他告诉你这是重大非公开信息,所以你可能无法仅凭自己找到这两支基金的单位净值,幸运的是,你的老板通过某种手段找到了这些信息,这就是你拿到的第三个数据表格,他看起来像这样:
Index |
Net Asset Value |
Fund |
|---|---|---|
0 |
2.39 |
H |
1 |
7.22 |
JK |
2 |
0.98 |
UIH |
… |
… |
… |
Archegos对于这两支基金的持仓份额是你的第四个数据表,它看起来像这样:
Index |
Holding Shares |
Fund |
|---|---|---|
0 |
20000000 |
H |
1 |
45000000 |
JK |
… |
… |
… |
你的同事曾经进行过一个关于单位净值的极端回撤的研究,他告诉你,你可以使用1.5%作为单日99%置信度的VaR(在险价值),所以你听从了他的建议,你这样计算风险指标::
df_fund_holding = pd.read_excel(path_four)
df_fund_nav = pd.read_excel(path_three)
df_fund = pd.merge(df_fund_holding, df_fund_nav, on = 'Fund', how = 'left')
df_fund['Total Holding'] = df_fund['Holding Shares'] * df_fund['Net Asset Value']
df_fund['VaR'] = df_fund['Total Holding'] * 0.015
因为Archegos很少公布他们的持仓,可以说现在你已经使用了所有可以使用的信息。所以你对于结果也是有一些自信的,你去找你的老板,等待被表扬,但你的老板勃然大怒,他用了很久平复自己的心情,然后告诉你你忘了很多重要的事情:
股票的收盘价包含很多空值,空值应该被处理,而且不应该用上一个非空值填充,因为如果你用上一个非空值填充,会导致计算出的波动性相比真实波动性偏小。
老板想要的是关于Archegos风险的结论,而不是一堆风险指标。
你使用的股价是错误的,因为没有考虑到分红的影响。
Archegos买入并持仓这两支基金的唯一原因是Archegos可以利用它们来加杠杆,购买更多的股票,比如TCEHY US Equity。这两支基金起到了通道作用,你应该对这两支基金的持仓进行深入研究,而不是停留在表面。
事情现在变得越发复杂,你决定使用RiskQuantLib。首先,你需要新建一个文件夹,来作为数据分析项目的工程文件夹。新建的文件夹名为’Archegos_Risk’,然后你打开了命令终端,通过以下命令来创建一个RiskQuantLib工程::
newRQL Archegos_Risk
在此步操作之后,你的文件夹看起来像这样::
--Archegos_Risk
--Cache
--Data
--Result
--RiskQuantLib
--Src
--build.bat
--build.py
--config.py
--debug.bat
--main.py
打开 config.py,你对文件进行编辑,使得它看起来像这样:
#!/usr/bin/python
# coding = utf-8
#-|instrument: security, company, index, interest
#-|instrument: bond@security, stock@security, derivative@security, fund@security
#-|instrument: future@derivative, option@derivative
#-|instrument-DefaultInstrumentType: security@Security, company@Company, index@Index, interest@Interest
#-|instrument-DefaultInstrumentType: bond@Bond, stock@Stock, derivative@Derivative, fund@Fund
#-|instrument-DefaultInstrumentType: future@Future, option@Option
#-|attribute: fund.netAssetValue@number, fund.amount@number, fund.varPercentage@number
#-|attribute: stock.mktValue@number, stock.closeSeries@series
注意到你只是在默认的参数信息后面增加了两行。你关闭这个源文件,然后通过以下终端命令来编译你的RiskQuantLib工程::
python build.py
在此之后,你打开 RiskQuantLib.Instrument.Security.Fund.fund 以便于新增一个你自定义的类函数::
def calVaR(self):
self.VaR = self.netAssetValue * self.amount * self.varPercentage
接着,你打开 RiskQuantLib.Instrument.Security.Stock.stock 来新增一个自定义类函数::
def calVaRPercentage(self):
from RiskQuantLib.Tool.mathTool import percentageOfSeries
self.varPercentage = percentageOfSeries(self.closeSeries.dropna().values(),99)
def calVaR(self):
self.VaR = self.mktValue * self.varPercentage
注意:所有这些操作是在数据输入之前发生的,此时你并不知道数据的形状,列名等信息。
接着进入你的项目工程文件夹根目录,打开 main.py,我们开始分析过程::
from RiskQuantLib.Module import *
# Read files
df_stock_holding = pd.read_excel(path_one)
df_stock_close = pd.read_excel(path_two)
df_fund_holding = pd.read_excel(path_four)
df_fund_nav = pd.read_excel(path_three)
# Initialize RQL list object
fund_holdings = fundList()
stock_holdings = stockList()
# Add securities to list
fund_holdings.addFundSeries(df_fund_holding['Fund'],df_fund_holding['Fund'])
stock_holdings.addStockSeries(df_stock_holding['Stock'],df_stock_holding['Stock'])
# Set input
fund_holdings.setNetAssetValue(df_fund_nav['Fund'],df_fund_nav['Net Asset Value'])
fund_holdings.setAmount(df_fund_holding['Fund'],df_fund_holding['Holding Shares'])
stock_holdings.setMktValue(df_stock_holding['Stock'],df_stock_holding['Holding Mkt Value'])
stock_holdings.setCloseSeries(df_stock_close)
[fund.setVarPercentage(0.15) for fund in fund_holdings]
# Calculation
fund_holdings.execFunc('calVaR')
stock_holdings.execFunc('calVaRPercentage')
stock_holdings.execFunc('calVaR')
现在,你的python源码变得更加易于阅读和修改了,不是么?你决定继续分析过程,接下来的一步是将你的结果保存为excel文件,所以你这样做::
# Data output
result = stock_holdings + fund_holdings
df_result = pd.DataFrame(result[['code','VaR']])
df_result.to_excel(path)
到现在为止,相比于用pandas进行数据分析,使用RiskQuantLib似乎更加麻烦。但是如果你注意到,在使用RiskQuantLib时,数据的输入,数据的处理,数据的输出是彼此独立的。改变其中的任何一个是不会影响到其他部分的运行的。(比如更改了输入文件的列名,你只需要对应更改RiskQuantLib输入部分的代码,分析和输出部分的代码完全不需要改动。)让我们来仔细看看源码,以便于了解这一点:
数据输入:¶
main.py:
from RiskQuantLib.Module import *
# Read files
df_stock_holding = pd.read_excel(path_one)
df_stock_close = pd.read_excel(path_two)
df_fund_holding = pd.read_excel(path_four)
df_fund_nav = pd.read_excel(path_three)
# Initialize RQL list object
fund_holdings = fundList()
stock_holdings = stockList()
# Add securities to list
fund_holdings.addFundSeries(df_fund_holding['Fund'],df_fund_holding['Fund'])
stock_holdings.addStockSeries(df_stock_holding['Stock'],df_stock_holding['Stock'])
# Set input
fund_holdings.setNetAssetValue(df_fund_nav['Fund'],df_fund_nav['Net Asset Value'])
fund_holdings.setAmount(df_fund_holding['Fund'],df_fund_holding['Holding Shares'])
stock_holdings.setMktValue(df_stock_holding['Stock'],df_stock_holding['Holding Mkt Value'])
stock_holdings.setCloseSeries(df_stock_close)
[fund.setVarPercentage(0.15) for fund in fund_holdings]
数据分析¶
RiskQuantLib.Instrument.Security.Fund.fund:
def calVaR(self):
self.VaR = self.netAssetValue * self.amount * self.varPercentage
RiskQuantLib.Instrument.Security.Stock.stock
def calVaRPercentage(self):
from RiskQuantLib.Tool.mathTool import percentageOfSeries
self.varPercentage = percentageOfSeries(self.closeSeries.dropna().values(),99)
def calVaR(self):
self.VaR = self.mktValue * self.varPercentage
main.py
# Calculation
fund_holdings.execFunc('calVaR')
stock_holdings.execFunc('calVaRPercentage')
stock_holdings.execFunc('calVaR')
数据输出¶
main.py
# Data output
result = stock_holdings + fund_holdings
df_result = pd.DataFrame(result[['code','VaR']])
df_result.to_excel(path)
当所有这些做完后,你可以将这个工程项目保存为模板。保存为模板的终端命令是这样的::
saveRQL Archegos_Risk
如果之后几天,你的老板又希望你分析另一只基金,你可以用这个已经存在的模板工程来初始化新的工程,你可以这样使用::
tplRQL Archegos_Risk target_path
这是RiskQuantLib的一个简单介绍,其中包含的内容包括 创建一个项目,编译你的项目,分离数据处理流程,将项目保存为模板,以及 用保存的模板初始化新项目。 你可能注意到了,我们并没有完全解决之前老板给我们的所有问题。为了解决这些问题,RiskQuantLib提供了很多高级函数。你可以参考RiskQuantLib的类文件说明来获取更多信息。