[翻译] 使用Apache Spark估算金融风险

[翻译] 使用Apache Spark估算金融风险

阅读:161 2015-03-16 11:58
这篇博文将会介绍如何使用Spark来实现计算密集型统计量的计算,例如使用蒙特卡罗方法计算VaR
在理性条件下,你预计将损失多少金钱?金融统计量风险价值(Value at Risk, VaR)可以用来回答这个问题。自从1987年股票市场崩盘后由华尔街开发出来,VaR在整个金融服务领域得到了广泛的使用。一些机构使用VaR以满足监管单位的要求,一些机构使用VaR更好地理解资产组合(Porfolio)的风险特性,还有一些机构利用VaR指导交易决策。
处于种种原因 (后续我们会看到),要正确估计VaR是需要很高计算代价的。最先进的方法使用蒙特卡罗模拟 (Monte Carlo simulations),一类通过重复随机取样进行量化的算法。当我们无法直接求解某一概率分布函数时,我们可以通过对组成这一个分布的简单变量进行重复取样、聚合分析模拟出概率分布的形状。
很多Cloudera金融领域的客户与我们进行联系,咨询如何使用我们的平台对金融风险进行分析,比如计算VaR。通过与这些机构的合作与研究,我们对如何使用Apache Hadoop生态系统进行风险分析积累了一些最佳实践 (使用Apache Spark,一个通用的分布式计算框架,支持基于内存的分析,受到不同行业的青睐)。其实一些客户自己已经摸索到了Apache Spark平台,同时我们也向其他客户进行了推荐,总的来说,Spark还是相当适合的。
在这篇博文中,你将首先了解到VaR的背景知识及其计算的方式。这篇博文主要关注模型的架构,同时也会对如何使用复杂技术或者领域知识对模型进行扩展给出建议。
示例代码以及小型样本数据集参照 https://github.com/sryza/montecarlorisk
VaR背景知识
VaR是一种可交易资产(instrument)风险的度量方法,用于描述在一段时间时期内最大可能的损失。VaR的计算往往涉及置信区间:95%置信区间+VaR值1,000,000美元 意味着我们的可交易资产在给定时间时期内只有5%的概率损失超过1百万美元。
计算VaR的几种算法:
方差-协方差 (Variance-covariance):最简单、计算量最小的方法,简化模型中概率分布的假设,可以通过分析法直接求解;
历史模拟 (Historical simulation):利用历史数据推断风险值。该方法的缺点在于历史数据的局限性。在资产组合中,可交易资产的历史数据很可能没有包含市场暴跌的情况,但是我们希望通过模型观测到在市场暴跌情况下资产组合的回报/损失情况。当前一些技术可以提高这种方法的健壮性,不过在这篇文章中不会进行讨论。
蒙特卡罗模拟 (Monte Carlo simulation):该方法尽可能避免前两种方法中涉及的前提假设。在其最一般的形式下,该方法:
定义市场因素与每个可交易资产回报之间的关系 对市场因素进行大量随机“试验” 计算每次试验中资产组合的损失,聚合试验数据,描述资产组合的风险特性
值得注意的是,蒙特卡罗方法也不是完美的。试验的随机生成、可交易资产指标性能推导都必须使用简化的假设。因此通过蒙特卡罗方法获得的概率分布也不会比其他模型精确太多。
模型
蒙特卡罗风险模型使用一组市场因素 (例如标普500、美国GDP、汇率) 来描述资产回报。在模拟中,我们采用简单的线性模型:对市场因素计算加权和来计算资产回报。每种资产拥有自己的一组回归权重。我们可以利用历史数据通过线性回归来训练模型。除此之外,还可以在模型中加入非线性的因素 (方差-协方差模型很难处理)。
需要提到的是,这里我们也可以使用更加复杂的模型,比如整合领域知识 (domain specific knowledge)。而这种每种资产一个模型的建模方式也蛮符合Spark计算模型的。
现在我们已经有了一个模型可以通过市场因素计算出资产损失,我们还需要一种方式来模拟市场因素的行为。一种简单的假设是认为每种市场因素都是正态分布的。为了反映不同市场因素之间常常是相关的,例如纳斯达克(NASDAQ)指数下跌时,道琼斯(Dow)指数一般也是下跌的,我们使用多元正态分布进行建模。跟线性回归模型一样,这里我们也可以使用一个更加复杂的方法来模拟市场因素或者假设另一种更加契合金融领域的概率分布,比如fatter tail分布。
总结一下,试验是根据多元正态分布随机产生的:
[翻译] 使用Apache Spark估算金融风险 X

一次试验中,某种资产的损失可以通过市场因素点乘资产模型权重,再加上最大值xi、最小值ni约束获得:
[翻译] 使用Apache Spark估算金融风险
资产组合的值通过所有资产值求和获得:
[翻译] 使用Apache Spark估算金融风险
Spark上的执行
蒙特卡罗方法的一个主要缺点是计算非常密集。为了得到比较准确的结果需要大量试验,而每次试验又涉及大量计算。于是,这部分我们开始使用Spark。
Spark允许开发人员使用简单的算子将计算并行到不同的机器。一个Spark作业包含了一组在并行集合上的转化操作。我们只需要传递Scala (或者Java或者Python)函数,Spark会将计算自动分布到不同的机器。Spark支持容错,因此如果在计算过程出现机器宕机、进程出错的问题,我们不需要从头重新计算。
计算的大致框架如下所示:
将可交易资产数据广播到集群的每个节点上。即使包含百万数量级资产的资产组合,内存使用量最多也就是几十GB,在当前主流的机器上可以轻松存入内存; 创建一组并行化的种子(seeds RDD)用于随机数生成器; 利用种子生成随机试验 (随机的市场因素),根据每种资产的转换模型计算在该试验条件下的价值,最后对同一次试验中的所有资产进行汇总 (计算过程通过Spark充分利用集群资源); 找到最差的5%试验结果与其他试验结果的边界; 提取边界值作为Value At Risk的最终结果。
下面的Scala代码用于计算试验的结果:
def trialValues(seed: Long, numTrials: Int, instruments: Seq[Instrument], factorMeans: Array[Double], factorCovariances: Array[Array[Double]]): Seq[Double] {
val rand = new MersenneTwister(seed)
val multivariateNormal = new MultivariateNormalDistribution(rand, factorMeans, factorCovariances)
val trialValues = new Array[Double](numTrials)
for (i <- 0 until numTrials) {
val trial = multivariateNormal.sample()
trialValues(i) = trialValue(trial, instruments)
}
trialValues
}
def trialValue(trial: Array[Double], instruments: Seq[Instrument]): Double = {
var totalValue = 0.0
for (instrument <- instruments) {
totalValue += instrumentTrialValue(instrument, trial)
}
totalValue
}
def instrumentTrialValue(instrument: Instrument, trial:Array[Double]): Double = {
var instrumentTrailValue = 0.0
var i = 0
while (i < trial.length) {
instrumentTrialValue = trial(i) * instrument.factorWeights(i)
i++
}
Math.min(Math.max(instrumentTrialValue, instrument.minValue), insturment.maxValue)
}
我们也可以将这部分代码使用Java或者Python实现,在Spark上运行以上代码需要实现相应的driver程序:
val broadcastInstruments = sc.broadcast(instruments)
val seeds = (seed until seed + parallelism)
val seedRdd = sc.parallelize(seeds, parallelism)
val trialsRdd = seedRdd.flatMap(trialValues(_, numnumTrials / parallelism, broadcastcastInstruments.value, factorMeans, factorCovariances))
现在我们已经计算获得了一组随机试验的结果。为了计算VaR,我们需要观察最差的5%试验的表现:
val varFivePercent = trialsRdd.takeOrdered(numTrials / 20).last
当然,我们还可以进一步深入分析:模拟中其实包含了大量资产组合的风险信息。例如,我们可以基于试验观测是什么资产、市场因素导致了最差的结果;Spark也可以用来计算更多聚合的结果;我们可以使用核密度估计 (kernel density estimation) 可视化资产组合的概率分布图……
使用测试数据 (包含了4种资产、3种市场因素),我们进行了1,000,000次试验,我们可以得到如下图的风险概率分布:
[翻译] 使用Apache Spark估算金融风险
其他考虑
交互式分析
目前我们所呈现的计算是批量的;然而,Spark同时也支持交互式计算。例如,分析人员与交易人员希望可以实时看到调整模型参数的效果,通过某些特定的标准对资产进行过滤,或者对资产组合进行调整。通过广播 (broadcasting),Spark会将所有资产信息存储到集群中每一台机器的内存里,使得这些数据可以方便地用于交互式查询。如果对资产进行过滤是一项比较常用的功能,还可以将过滤的特征作为主键以资产作为值保存到字典/哈希表中。
海量资产数据
如果 (虽然很少出现) 单个资产组合包含了太多种资产以致于无法存入每台机器的内存中,例如包含大量小型企业贷款的资产组合,就需要将资产组合的数据分布到集群的不同机器上。
Spark也可以处理这个问题,代码框架如下所示:
val sc = new SparkContext(...)
val instrumentsRdd = sc.parallelize(instruments, numPartitions)
val fragmentedTrialsRDD = instrumentsRdd.mapPartitions(trialReturns(seed, _, numTrials, modelParameters))
val trialsRdd = fragmentedTrialsRDD.sumByKey()
def trialReturns(seed: Long, instruments: Iterator[Instrument], numTrials: Int, modelParameters: YourModelParameters): Iterator[(Int, Double)] = {
// Compute the value of the given subset of instruments for all trials,
// and emit tuples of (trialId, value)
}
从核心上讲,原先分布式计算时
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值