You are on page 1of 345

中国工信出版集团 鲁仑巴巴七,巴兰

Python 金融实战
Python for Finance
[美] Yuxing Yan著
张少军严玉星译

人民邮电出版社
北京
图书在版编目 (C I P) 数据

Python金融实战/(美)严玉星著,张少军, 严玉
星译 -- 北京:人民邮电出版社, 2017. 7
ISBN 978-7-115-45707-3


I. (DP … II. CD严
@张… III. …
软件工具 — 程序 CD
设计 应用-金恐-分析IV. (DF830. 41-39

中国版本图书馆CIP数据核字(2017)第100748号

版权声明

Copyright©2014 Packt Publishing. First published in the English language under the title Python for Finance.

All rights reserved.


本书由英国Packt Publishing公司授权人民邮电出版社出版。 未经出版者书面许可, 对本书的任何部分不
得以任何方式或任何手段复制和传播。
版权所有, 侵权必究。

• 著 [美) YuxingYan
译 张少军 严玉星
责任编辑 胡俊英
责任印制 焦志炸
• 人民邮电出版社出版发行 北京市丰台区成寿寺路 II 号
邮编 100164 电子邮件 3 I 5@ptpress.com.cn
网址 http://www.ptpress.com.cn
北京市艺辉印刷有限公司印刷
• 开本: 800xl000 1/16
印张: 21.75
字数: 420于字 2017年7月第1版
印数: 1-2 000册 2017年7月北京第1次印刷
著作权合同登记号 图字: 01-2016-3953 号

定价: 79.00元
读者服务热线: (010) 81055410 印装质昼热线: (010) 81055316
反盗版热线: (010) 81055315
\
内容提要

Python 凭借其简单、 易读、 可 扩展性以及拥有巨大而活跃的科学计算社区, 在需要数


据分析和处理大量数据的金融领域得到了广泛而迅速的应用, 并且成为越来越多专业人士
首选的编程语言之 一 。

本书通过 12 章内容介绍了 Python 在金融领域的应用, 从 Python 的安装、 基础语法,


再到 一 系列简单的编程示例, 本书循序渐进地引导读者学习 Python 。 同时, 本书还结合
Python 的各个模块以及金融领域中的期权价格、金融图形绘制、时间序列 、 期权定价模型、
期权定价等内容 , 深度揭示了 Python 在金融行业中的应用技巧。

本书适合金融、 会计等相关专业的高校师生阅读, 也适合金融领域的研究人员和从业


人员参考学习。 对于有 一定计算机编程基础, 但想要从事金融行业的读者, 本书也是不错
的参考用书。
谨以本书献给我的父辈:

严仲仪(父) 王秀珍(母)

金清(岳父) 阴家菊(岳母)
写给中国读者的几句话:

首先感谢人民邮电出版社选择了 我的书 (Python for Finance) 并出版中译本。 我衷心


地感谢胡俊英编辑(人民邮电出版社, 信息技术分社) 为本书的出版做出的努力, 感谢张
少军教授(在香港教学的金融学教授) 为翻译本书做出的巨大 投入。

如果用一 句话来总结本书:“这是 一 本金融学教授写的基千 Python 编程的图书 。 本书


将金融理论、 金融计算、 计算机编程和金融数据有机地结合在 一 起。 由于 Python 是开源软


件, 所以本书使用了美国大 量公开的经济、 金融以及会计数据(开源数据)。

本书的读者是金融系、 会计系的硕士 研究生或高年级的本科生 , 以及金融领域的研究


人员和想进入金融领域的 IT 人士 。 本书亦可用作一学期的课程教科书 。 在美国, 已有两所
学校将本书列 为教科书。

对书中涉及的 Python 程序而言, 中译本和英文原版有众多的不 同。 主要原因是使用的


Python 版本不 一 样。 此外 Python 语言本身, 尤其是其包含的模块也在发展和演变中。 一

函数不存了, 而另 一
些函数也有

些变化 。 对此, 我已经在中文版中做了相应的修改 。

本书主要的不足之处是没有引用有关中国的经济、 金融及会计数据。 如果可能的话,


我会在本书第 3 版的写作中加入有关中国的数据 。 如有研究者、 经济学教授、 金融学教授
或会计学教授能够提供有关中国的经济、 金融和会计数据, 并希望能用 Python 以及其他计
算机语言 CR、 SAS、 Matlab或C)来加以处理, 请与我联系。

作者严玉星 (Yuxing Yan)

201 7年 3月于美国水牛城
作者简介

严玉星毕业于麦吉尔大 学, 获金融学博士 学位 。 他有丰富的


教学经验, 教授过各类本科学位和研究 生学位的金融课程, 如金
融建模 、 期权和期货、 投资组合理论、 定量财务分析、 企业融资
和金融数据库 。 他曾在8所全球知名的大学任教: 两所在加拿大 ,

所在新加坡, 5所在美国。

严博士 一 直活跃于学术研究的前沿 。 他的研究成果在多 个国


际 学术期刊发表, 包括Journal ofAccounting andFinance、Journal
。if Banking andFinance、Journal of EmpiricalFinance、 Real Estate
Review、 Pacific BasinFinance Journal、 AppliedFinancial Economics 和 A nnals of Operation
Research 。他的最新 篇学术文章是与张 少军合著的,发表在Journal of Banking andFinance

上 。 他的研究 领域包括投资 学、 市场微观结构和开放金融 。


他精通儿种计算机语言, 如 SAS、 R、MATLAB、C 和 Pyth on。 从 2003年到 201 0 年,
他在沃顿商学院研究数据服务中心 (Whart on Re se arch D at a Se rvice s, W阳)S)担任技术总
监, 为W阳)S 用户测试了与研究相关的几百个计算机程序 。 之 后, 他于 2010 年开始先后
将R引 入3所大学的若干门金融定量分析课程 。 他将讲座笔记编写成 一 本名为《基于R的
金融建模》(Financial Modeling using R)的书 。

此外, 他还是财务数据方面的专家 。 在新加坡南洋理工大学任教时, 他为博士生讲 授


门名为 金融数据库 入 门 的课程 。 在W阳)S工作期间, 他回答了许多有关金融数据库
一 “ ”

的问题并帮助更新 CRSP 、C ompu st at、IBES 和TAQ (NYSE 高频 数据) 等数据库 。 2007


年, 严博士 和朱世武合著由清华大学出版社出版的 《金融数据库》 一 书。 目前, 他花费相
当多的时间和精力在公开财务数据上 。 如果 有任何疑问, 读者可以随时通过电子邮件
y any@canisiu s.edu与他联系。

译者简介

张少军博士,1996 年 7 月毕业千北京清华大学,获应
用数学和计算机技术双学士学位。 自 1996 年 8 月至 2001
年 5 月在美国佛罗里达州立大学继续深造, 先后获得统计
学硕士学位和金融统计学博士学位。现任香港理工大学会
计与金融学院副教授。

张博士自 2001 年 6 月受聘于新加坡南洋理工大学南


洋商学院银行与金融系并担任助理教授。 为银行与金融本
科专业、 精算本科专业、 金融工程硕士专业、 金融硕士专
业以及工商管理硕士(MBA)等学位项目讲授与金融模型、
资产定价方法、 金融时间序列分析和证券投资学相关的课程, 并为来自多家银行的进修班
讲授与金融模型、 金融衍生产品、 风险管理以及基金投资等相关的课程。 独立或参与培养
了多名博士和硕士研究生,并指导了 30 多名本科生的毕业论文。任职期间,他获得了新加
坡政府及南洋理工大学的多项研究经费,荣获 2006 年度银行和金融系最佳研究教授奖,并
于 2008 年 9 月成为美国精算协会 (Associate of theSociety ofActuaries, A
SA) 准精算师。
自 2009 年 1 月起至今,在香港理工大学会计与金融学院任教,为本科学生讲授证券投资学
课程, 为研究生讲授与证券投资学和风险管理相关的课程。

张博士的学术研究涉及多个金融领域, 包括中国股市交易、 中国股权分置改革、 股权


资产定价的实证分析、 外汇期权的定价、 投资银行在债券发行市场的竞争、 公司与投资银
行的合作关系等。先后获邀在40多个国际学术会议上报告研究成果,在国际知名的学术期
刊上发表论文 10 多篇, 多次获得国际会议与国际期刊授予的研究论文奖, 2015 年荣获中
国教育部人文社科学研究优秀论文三等奖。自 2010 年 7 月至今,担任亚洲金融协会理事及
司库。如果读者有任何疑问,可以随时通过电子邮件 shaojun.zhang@polyu.edu.hk 与他联系。
致谢

我要感谢Ben Amoako- Adu和BrianSmith (他们教授我最早学习的两门金融课程,并


在我毕业后的许多年里给予我坚定的支持), George Athanassakos (他布置的作业逼着我
学习C语言)、Jin-ChunDuan、Wen-HungMao、JeromeDetemple、BillSealey、Chris Jacobs、
Mo Chaudhury (我在McGill 大学的金融学教授) 和Laurence Kryzanowski (他精彩的教
学启发我专注于实证金融。 虽然不是我的博士论文指导老师, 但他逐字逐句地批阅了我
的博士论文)。
在沃顿商学院的经历毫无疑问地塑造了我的思维方式并且增强了我的技能。感谢Chris
Schull和Michael Boldin给我这份工作, 感谢 MarkKeintz、 Dong Xu、 StevenCrispi和Dave
Robinson, 他们在最初的两年给我巨大的帮助, 还要感谢Eric Zhu、 PaulRatnaraj、 Premal
Vora、 Shuguang Zhang、 MichelleDuan、 NicholleMcniece、Russ Ney、Robin Nussbaum- Gold
和Mireia Gine给我的帮助。
此外,我要感谢Shaobo Ji、 Tong Yu、 Shaoming Huang、 Xing Zhang、 ChangwenMiao、
KarylLeggio、 Lisa Fairchild、 K.G. V iswanathan、 Na Wang、 MarkLennon和Qiyu Oason)
Zhang 在许多方面对我的帮助。 我也要感谢张少军和孙谦,我在新加坡南洋理工大学的同
事和论文合作者, 谢谢他们的宝贵意见和讨论。
出版一 本好书需要许多出众的出版专业人士和外部审稿人共同做出贡献。 我要感谢
Packt出版社的工作人员做出的优秀努力和付出 ,特别是Llewellyn F.Rozario、SwatiKumari、
ArwaManasawala、 RuchitaBbansali、 ApekshaChitnis和Pramila Balan。 也感谢外部审稿人
Martin Olveyra、 MouradMOURAFIQ和Loucas Parayia叩is的宝贵意见 、批评和建议。 还要
感谢人民邮电出版社把这本书的中文版呈现给读者, 感谢出版社胡俊英女士的大力支持和
细致工作 , 才使得中文版得以顺利及时地与大家见面。
最后 , 最重要的是 , 我感谢我的妻子金晓宁、 女儿严晶和儿子严加加的大力支持。 感
谢他们多年来给予我的理解和关爱。

审稿人简介

Jiri Pik是一 名与 投资银行、 对冲基金和其他金融机构合作的财务和商 业信息顾问。 他


为多 个行业的客户构思并搭建了有突破性的交易、 投资组合和风险管理系统, 以及决策支
待系统。
他的咨询公司WIXESYS, 为客户提供经过认证的专业知识、 快速的判断和执行能力。
W扭SYS 通过网站h ttp / / eparian .com提供功能强大的工具, 包括具有革命性的Exc el和
: s
Outloo 插
k 件等。

Loucas Papayiannis在塞浦路斯出生和长大, 毕业于尼科西亚的英语学校。 在塞浦路


斯国民警卫队服完义务兵役后, Lo ucas 前往加州大学伯克利分校, 在那里获得了电气工程
和计算机科学学士学位。 在伯克利学习期间, 他得到了在帕洛阿尔托的博世研究中心工作
的机会, 并对开发人机界面产生了强烈的兴趣。

段意想不到的经历让他在完成学业之 后获得了 一 个在伦敦为彭博公司工作的机会。
尽管开发金融软件是他职业发展方向的一 个转折点,Lo c
u as 还是抓住这次机会并搬到伦敦。
他很快成长并喜欢上这 一 新的领域。 他在伦敦全职工作的同时, 入读国王学院的金融数学
硕士课程, 并在 2011年获得了学位。

他于 2010年开始在高盛工作, 然后于 2012年8 月加入了巴克莱资 本。 直到现在, 他


的工作主要是使用C++开发与 外汇期权相关的应用程序。 这些年他已经在工作中使用了各
种编程语言和技术。 他是 一 个Linux和 Pyth on 的爱好者, 喜欢在空闲时间用它们实验和开
发应用程序。

Mourad MOURAFIQ是一 名软件工程师和数据科学家。 他在成功完成 应用数学专业


的学习后, 在 一 家投资银行担任结构性产品领域的定量分析师, 专 门研究ABS、 CDO和
2 审稿人简介

CDS, 并在法国最大 的银行担任量化分析师。

在金融领域几年之 后, 他发现了对机器学习和计算数学的热情, 并决定加入一 个创业


公司, 该公司专注于软件挖掘和人工智能领域。

“我要感谢导师们在我初到交易大厅的那段日子里对我的关照和培养 。


..a.&. .....
削百

我们正处在一个信息爆炸的大数据时代。 在计算机和网络科技的推动下, 瞬息万变的


金融市场不停地产生出大量的电子化数据, 其 中大部分是对公众免费的。 计算机是有效地
利用这些数据的必不可少的工具。 我们坚信读者应该能掌握至少 一 门计算机语言。 而 Python
则是可供学习的计算机语言中 一个比较好的选择。

为什么选择 Python?
选择 Python 有多种原因。 首先, Python 是开源的, 公众可以免费使用。 Python 可用于
几乎所有的主流操作系统上 , 如 Windows、 Linux/Unix、 OS/2、 Mac 和 Amiga, 等等。 学
习和使用免费软件有众多的好处。 毕业以后, 学生 可以把他们所学到的 Python 编程技能用
在任何工作岗位, 包括在金融领域。 与 此相反, 收费软件如 SAS 和 MATLAB 取决于公司
或单位是否订购。 其 次, Python 功能强大、 灵活、简单易学。 它能够解决几乎所有的金融
和经济方面的计量问题。 第三, Python 有处理大数据的能力。 Dasgupta (2013) 认为 R 和
Python 是当前最流行的两个用于数据分析的开源软件。 第四, Python 有许多有用的模块。
模块是为完成 一个特殊的任务 而开发的。 在本书中, 我们将学习 NumPy、 SciPy、 Matplotlib 、
Statsmodels 和 Pandas 等模块。

这是一本由金融学教授撰写的编程图书
毫无疑问, 大多数的编程图书是由计算机专业的教授和专家撰写的。 由一 位金融学教
授撰写 本书来介绍 一 门编程语言似乎十分奇怪。 其 实不然, 本书的重点和众多由计算机专
家所写的书完全不 同。 计算机专家们会把重点放在 Python 语言本身, 而正如本书的书 名所
示, 本书的重点是介绍 Python 在金融领域的应用。 作者希望为读者提供一 本将 Python 与
金融紧密结合的书。
2 前言

侧重短小而实用的 Python 程序
作者曾经在多所世 界 著名 大学任教, 包括加拿大的麦吉尔大 学和劳里埃大学、 新加坡
的南洋理工大 学 、 美国的Loyo al 大学、UMUC、Hofstra 大学、水牛城大学和 Ca nisi us学院。
他还在美国的沃顿商学院从事过 8年的技术咨 询工作。 丰富的教学和咨询经验告诉他, 大
多数金融专业的学生需要掌握编写 短 小 的程序以完成某些特 定 的任务。 大 多数编程类图书
只提供 了 几 个完整但复 杂的程序, 但对于循序渐进的学习过程而言, 程序的数 目 远远不足,
这将导致两 种后果。 首先, 读者往往淹没千 复 杂程序的细 节之中, 从 而产生 畏惧心理, 最
终 失 去学习计算机语言的任何兴趣。 其 次, 他们不知道 如何灵活运用 编程语言来解 决金融
领域的一 系列 问题, 例如, 如何用 1 99 0年�2013年的数据和资 本资 产定价模型 ( CAP M )
来估计 I BM 的 市场风险系数。 本书提供了大 约 300 个与许多金融领域相 关的 P ytho n 程序 。

使用 真实数据
编程类 的 图 书 往往有 一 个 共 同点, 就是它们常 常 使用虚构 的数据。 本书 将 大 乱 使用与
各种金融 课题相 关的真实数据 。 例如, 不仅仅只是介绍资 本资 产定价模型 CAP M 和市场风
险系数( 贝 塔值或 p), 读者学习如何利 用 实 际 数据来估计 I BM、 苹果和沃 尔 玛等公司的贝
塔值, 而不仅仅只是讲 解用来估 算投资组合的收益和风险的数学公式 。 本书会给出 P ytho n
程 序来从 互 联网 上 直接下载实时的交易数据, 构造不 同的股票组合, 然 后计算其 收益和风
险, 包括在险价值 ( VaR)。

本书的主要 内 容
第 1 章简短地介绍 P ytho n 并讨论如何安装、启 动和退出 P ytho n, 以及 一 些相关的问题。

第 2 章讲 解一 些基本概念和几 个常 用 的 P ytho n 内置函数, 如赋值、 数值精度、 加法、


减法、 除法、 幕函数和平 方根函数。

简单的 P ytho n函数来完成常 见的金融计算, 例如一 个未来现


第3章介绍如何编马 一 些
金流量的现值、 当前现金的未来价值、年金的现值及未来值、 永续年金的现值、 债券的价
格和内部收 益率 ( IRR)等 。

第 4 章介绍读者在对 P ytho n 和期权不了解的情 况下, 如何用 几行 P ytho n 代码计算看


涨期 权价格 。

第 5 章介绍模块的基础知识, 例如查 找所有可用或 已安装的模块, 以及如何安装一 个


新的模 块 。
前言 3

第 6 章介绍用于 科 研和金融计算的两 个重要模块: Nu mPy 和 SciPy 模 块 。

第 7 章通过 mat p lot ilb 模 块绘制 金融相关的图形, 展 示 如 何 利 用 mat p lot ilb 模 块绘制不
同颜色和大小 的 图表和图形来生动地解释有 关的金融概念。

第 8 章结合实际数据探讨与统计相关的许多概念和 问 题 。 具体内容 包括如 何由雅虎财


经网站下载历史数据 ; 计算收益率 、 全部风险、 市场风险、 个股之 间 的 相 关性、 不 同 市场
之间的相关性: 构 造 各种投资组合以及构建最优投 资组合。

第 9 章详细讲 解与 B al ck-Sch oel s-M e rt on 期权定价模型相关的 内 容 包


, 括看涨期权和看
跌期权的 收益和利润/损 失函数、 不 同的 期权交易策略、 绘制收益和利润/损 失函数的图形、
正态分布、与期权相关 的希 腊值以及期权 的 平价关系。

第 1 0 章介绍不 同 类型的循环, 并且 演 示如何估 算欧式和美式期权 的 隐含波动 率 。

第 1 1 章讨论如何利用蒙特 卡 罗 模 拟方法为欧 式 、 美式 、 均 价、 回 望 式和障碍 式 期权


定价。

第 12 章介绍波 动 率 的 测度以及 ARCH 和 GARCH 模型。

读 完 本 书 后 有 什 么收获 ?
我们通过 一 些具体 的例子来说 明 本书可能带给读者 的 收获。 首先, 本书的前两 章能够
帮助读者使用 Python 来计算现值、 未来值、年金现值、内部收益率, 以及 许多其他常 用 的
金融公式 。 也就是说, 我们 可以使用 Pyth on 作为一 个普通计算器来解决不少与金融相 关的
问题。 其次, 第 3 章能够 帮助读者把几十 个短小 的 Pyth on 程序结合成 一 个大的 Pyth on 模
块, 从 而用 Pyth on 完成 金融专业计算器的功能 。 这 自 制 的 模块与其他 Pyth on 模 块 一 样使
用。 第 三, 读者学习 如何编写 Pyth on 程序来下载和处理 各类开源数据, 包括雅虎财经网站、
谷歌财经网 站 、 美联储 的数据库 和 F re nch教授的在线数据库 等。 第 四 , 读者 将理解与模块
相关的基本概念。 模块是指由专家、 其他用户或 自 己编写 的 用 于 特定用途的 程序包。 第 五 ,
在了解了 mat p lot ilb 模块的特性 后, 读者可以制作各种图表。 例如, 通过绘制图形展示不同
股票和期权的交易策 略 的 收益I利润函数。 第 六, 读者将能够下 载 I BM 的 每 日 交易价格、
市场指数 ( S&P 5 00)、 雅虎财经网站的数据和运用CAP M 估计市场风险系数 ( 贝 塔值)。 亦
可以用 不 同的证券 ( 如国 债 券 、 企业债券和 股 票 、 构建投 资组合), 并且 应用马 科维茨 的 均
值-方 差模 型来优化 自 己 的投资组合。 此外, 读者会知道如何估计 其投 资 组 合 的 在险价值
( V aR)
。 第 七, 读者应该能够应用 B al ck-Sch ole s-Me rt on 期 权定价模型和蒙特 卡 罗 模 拟为欧
式或美式期权定价。 最后, 读者 能够学习 量度波动率 的 几种方法, 特 别 是 自 回 归 条件异方
差 ( ARCH )和广 义 自 回 归 条件异方差 ( GARCH )模型。
4 前言

本书 的 目 标读者
本书面向金融相关专业的从 业人士 , 尤其 是计算金融 、 金融建模 、 金融工程和商业分
析等专业方向的读者 , 会发现本 书大有裨益 。 对金融领域感兴趣的读者 也可以通过本书学
习 Python , 并把它用千许多金融项 目之中。 个人投 资者也能从 本书 受益。

约定
本书用不同的文本样式 区分不 同种 类的内容 。 下面给出 一 些 例子 , 帮助认 识这些 样式
并 了 解它们的意义。

文本里的代码 、 数据库 名、 文件夹 名、 文件 名、 文件 扩展 名 、 路径名、 网 址 、 用户 输


入和 Twitte r 昵 称 以这样的方式显示: 根据计算机操作 系 统 , 选择合适的套餐 , 例如 ,

Python Wi ndow s x 8 6 MS I I n s 七 a l l e r ( W i n dows b i n a r y - - d o e s not i n c lude


s o u r ce ) " 。

我们用到的 Python 代码会如下显示:

from matplotlib . finance impor 七 quo 七es_historical_yahoo


import numpy as np
impor 七 pandas as pd
impor 七 s tatsmodels . api as sm
七icker= ' IBM '
begda 七e= ( 2 0 0 8 , 1 0 , 1 )
endda迳= ( 2 0 1 3 , 1 1 , 30 )
p = quotes his 七orical_yahoo ( 七 icker , begdate , endda 七e , asobjec 七=True ,
adjus ted=True )

任何命令行输入或输出如下所示:

>>>from ma 七plotlib . pyplot import *


>>>plot ( [ 1 , 2 , 3 , 1 0 ] )
>>>xlabel ( "x- axi s " )
>>>ylabel ( " my numbers " )
>>>七 i 七 le ( " my figure " )
>>>show ( )

新 术语和重要的话以粗体显示。 在菜单或对话框出现的文字 , 以粗 体显示: 单击开始


按 钮, 然后启动所有程序 。

前言 5

使 用 本书 的 两 种方式

通常有 两 种方式来使用本书: 自 己阅读或参加课程。 初学者可以放慢进度, 计划每两


周学习一 章。 第 8 章是 个例外 , 它可能需要至少 3 周 。 掌握另 一 门 编程语言的专业人士可
以相对快速地掌握前儿章, 尽快接触到 后面章节的内容 。 他们可以把更多精力放在期权理
论、 隐含波动率、 波 动率的度蜇和 GARCH 模型。 本书的另 一 特点是, 第 3 章之 后的大 多
数章节之间没有很强的前后关系。 读者在学习了前 3 章和第 5 章之 后可以跳到其他 自 己 感
兴趣的章节。

此外, 本书非常 适合用作教科书。 它能让量化投 资 、 计算金融或金融工程等专业的硕


士生学习如何 在金融领域应用 Python。 本书的内容 适合一 个学期的硕士生 课程, 如果用在

年级本 科生的课程, 可以适当降低难度。

读者反馈
读者反馈 是 我们 一 直期盼的。 请 让 我们知道你对本书的意见, 包括喜欢或不喜欢的地
方。 我们渴 望读者从 本 书得到最大 的收获。 因此, 你的反馈意见至关重要。 请 把反馈意见
以电子 邮件发送至 feedback@packtpub.com , 并在邮件的主题里
包括本书的书名。

客 户 支持
作为 Packt 出版物的拥有者, 你应当感到 自 豪, 同时也会获得 我们在多方面提供的服务。

下 载示例代码

你可以通过 http://www.packtpub.com 网站的帐户下载所有 已购买的 Packt 图书里包含的


示例代码。 如果是在其他地方购买 了 本书, 你 可以在 http ://www.packtpub.com/support 网站
注册 并通过电子 邮件直接获得相关的文件。

下载书 中 的 彩 色 插 图

我们还为你准备了 一 个 PDF 文件, 里面包含本 书中用到的截屏/图形的彩色图像。 这些


彩 色 图 像 可 以 帮 助 你 更 好 地了 解 输 出 结 果。 读 者 可 以 在 以下 网 址 下 载这 些 文 件 :
https://w吓.packtpub.com/sites/default/ files/down loads/43750S_Images.pdf。

勘误表

虽然我们 已尽力确 保内容 的 准确性, 错 误难免会发生。 如果你发现书里的文本或者代


码有错误, 请 务必来信告知, 我们将不胜 感激。 这样一 来, 可以让其他读者少受 困 惑, 也
6 前言

帮助 我们提高本书 再版的质量 。 如果发现任何错误, 请 访问 http://www.packtpub.com/submit­


errata 网 页, 选择你的书, 点击勘误表提交表单链接, 并输入勘 误的详细 信息。 一
旦你的勘
误表验证通过, 提交的内容 会被接受, 勘误就会在网站上 出现, 或添加到 该书的现有勘误
列 表里 。 你可以从 http:// www.packtpub.com/support 网站选择书名 查看 任何现有的勘误表。

关千盗 版行为

互联网 上 的侵权盗版行为是所有出版商 一 直面临的问题。 Packt 出版社非常重视保护版


权和许可证 。 如果你发现任何对 我们出版物 的非法拷 贝, 不论其 在互 联网 上 是以任何形式
出现的, 请 立刻 向 我们提供 网 址或网站名称, 以便 我们可以及时补救 。

请 把涉嫌盗 版材料 的链接发送到 copyright@packtpub.com。 非常 感谢你帮助保护 我们


的作者, 协助 我们继续有能力为你带来有价值的内容 。

读者疑 问

如果你对本书有任何方 面的疑问, 你 可以通过 questions@packtpub.com 与 我们联系,


我们 一
定尽力来解决 。 \

目录

第1章 Python 简介 及安 装 … … … … … … … · l 2.2 错误提 示 · · ·· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 1 5

1.1 Python 简 介 .......... ............................ 1


2. 3 不能调 用 没有赋 值 的变量 … … … … 1 6

1 .2 如何安装 Python · … ....... . . . . . . … .......... 3


2.4 选择 有意 义 的变 量名 … … … … … … ·· 1 6
使 用 ctirO来查找变量和 函 数 … … · · 1 7
Python 的 不 同 版 本 … … … … .. … … … … 3
1 .3 2.5

1 .4 运 行 Python 的 3 种方式 … … … … … .. 4
2.6 删 除 或取 消 变量 · · · · · · · · · · · · · · · · · · · · · · · · · … 1 7

1 .4.1 用 GUI 启 动 Python … … … … … … .. 4


2.7 基本 数 学运算: 加 、 减 、
乘 、 除 · · ·· · · · · · · · · · · · · · · · · · · · · · · · · · · ······· · · ·· · · · 1 8
1 .4.2 从 Python 命令行启 动 Python … .. 5
2. 8 幕 函 数 、 取整 和 余 数 函 数 … … … … 1 9
1 .4.3 从 DOS 窗 口 启 动 Python · … … … . . 6
1 .5 如 何 退 出 Python ........ ... ...... . . . . . ........ 7
2. 9 一个真 正 的 幕 函 数 … … … · … … … … · · 20
2. 1 0 选择合适 的 数值精度 … … … … … …2 1
1 .6 错误提示 ......... ................................. 7
1 .7 Python 语 言 是 区 分 大 小 写 的 …… … · 8
2. 1 1 找 出 某个 内 置 函 数 的 详细
信 息 · · · · · · · · · · · · · · · · · · · · · ······· · · · · · · ·· · · · · · · · · · · 22
1.8 变量的 初始化 .................................. g
1 .9 寻 找 在 线 帮 助 .... ............................. . 9 2. 1 2 列 出 所 有 内 置 函 数 … … … … … … … · 22
2. 1 3 导 入数 学 模块 … . . . … ········ ···· ········ · 2 3
1 . 10 查找学 习 手册和 教程 … … … … … … 1 0
1.11 如何找 出 Python 的 版本 … … … … · 1 2 2. 1 4 7t , e、 对数和指 数 函 数 … … … … ·· 24

1.12 小 结 .. . . . . . ....................................... 1 2 2. 1 5 import math 与 from math import


* 的 区 别 ········································ 24
练 习 题 ..................................................... 12
2. 1 6 一些 常 用 的 函 数 · · ········ · · ········ ··· ··· 25
第2章 用 Python 完成普通计算器 的 2. 1 6. 1 print()函 数 ···· · · · · · · ········ ·· ········ ·· · 25
功能 .. .......... 令 . . . . . . ............ .............. 14
2. 1 6.2 type() 函 数 ······ ·· · ·· · ······ · · · · · · · · · · ·· · 26
2. 1 变量 的赋值及 显 示 … … …… … … … . . . 1 5 2. 1 6. 3 下划线 .. ........................... ...... 26
2 Python 金融 实 战

2.16.4 结合 两个字符串 … … … … ……… 26 3.18 投资 回 收 期和投资 回 收 期


2.16.5 将小写字符变成 大 写 字符 法则 ............ .................................. 4 7
的 函数: u p perO · · ········ · ····· ·· · · · · 2 7 3.1 9 内部收益率和内部收益率
2.1 7 元组数据 类型 ········· ······· · · · ········· · · 28 法则 ............................. .... ............. 4 7
2.18 1J、 结 ·········· ········· · · · · · · · · · · · · · ·············· 2 9 3.20 显示在某 个 目录下 的指定
练 习 题 · · ···················· · · · · · · · ························ 30 文件 ............ ..................................49
3.21 用 Pyth on 编写 一 个专业金融
第3章 用 Python 编 写 一 个金融
计算 器 ································· ········ 32 计算器 ........ .................................. 49
3.22 将 我们 的 目录加到 Pyth on 的
3.1 编写 不需要保存的 Python
路径 上 ........ .................................. 5 0
函数 ...... .......................................... 33
3.23 小 结 ............ .................................. 52
3.2 函数的输入 参数及它 们 的 练 习 题 ..................................................... 5 2
预设值 . . .......................................... 33
第4章 编 写 Python 程序 计算 看涨期 权
3.3 缩进格式在 Pyth on 编程中 至 关
价格 ........... .................................. 56
重要 ................................................ 34
3.4 检查 自 己编写的 函数是 否存在 … · 35 4 .1 用空壳法编写 一 个程序 . … ... ……… 5 7
3.5 在 Pyth on 编辑器里定义函数 … · … 35 4 .2 用注释法 编写 一 个程序 …………… · 59
3.6 利用 im port()在 Python 编辑器 4.3 使用和调试他人编写 的
里激活 自 己编 写 的 函数 …… · … …… 36 程序 .............. .................................. 61
3. 7 使用 Pyth on 编辑器调试程序 …… · 37 4 .4 小 结 ................................................ 61
3.8 调用 vp _f()函数的两种方法 ……… 37 练 习 题 ........................ ............................. 61
3.9 生成 自 制 的模块 ..... .... … ······ ········ · · 38
第5章 模块 简介 . . . … ....... … ····················· 64
3.10 两 种注释方法 …… ........ .. … … … · · · · · 39
3. 1 0.1 第 1 种 注释 方 法 ....... ..... ...... … 39 5 .1 什 么 是 模块 ............ ........................ 64
3. 1 0.2 第 2 种 注释 方 法 ……… …… … ··· 39 5.2 导入模块 . . . . . ................................... 65
3.11 查 找 有关 vp _f()函数的 5.2. 1 为导入 的 模块取个简称 ………… 66
信 息 · · · · · · · · · ······ · · · · ·················· ········· 4 0 5. 2 .2 显示模块里 的所有函数 ………… 66
3.12 条 件函数 : if() ······ · ········ ···· ········ · · 41 5. 2.3 比较 im port m ath和 fr om
3.13 计算年金 · · · · · ·················· · · · ············ 41 m at him port * ............................ 6 7
3.1 4 利率换 算 ······················ ················ 4 2 5.2.4 删除 已经 导入的模块· …………… 6 7
3.15 连续 复 利利 率 ........ ...................... 44 5.2. 5 导 入 几 个指 定 的函数.. ………… ·· 68
3.16 数据 类型: 列 表 ........ ·········· ······· 45 5.2.6 找出所有 的内置 模块… · ………… 69
3.1 7 净现值和净 现值法则 ……………… 45 5. 2. 7 找出所 有可 用 的模块………… .... 69

目录 3

. 找到 一 个 已安装的模块 的
5. 28 6.18 利 用 种子 ( seed)生成 可重复
目 录 位置 ....... . .......... . . . . . . . . . . . . . . . . 71 的随机数 ....................... . . . . ........... 93
5.2 .9 有关模块 的更多信 息 … … … … … · 72 6.19 在导入的模 块里查找函数 … … .... 94
5.2. 1 0 查找某个未安装的模块 \… … … 72 6.20 简介 .... … ......... ... ......... .. 95
优化算 法
5.3 模块之间 的相互 依 赖性 … … … … .... 73 6.21 线性 回 归和资 本资 产定价模型
小 结 .............. .................................. 74
5. 4 CCAP M ) .................................... 9 5
练习题 ..................................... . ............... 75 6.22 从 文本文件(. txt)输入数 据:
loadtxt()和 getfr omtxt()函 数 . … · 96
第6章 NumPy 和 SciPy 模块 简介 … … .. 76
6.23 独立安装 N urnPy 模块 … … … … · … 9 7
6.1 安装 N umPy 和 SciPy 模块 … … … .. 77 6.24 数据 类型简介 ........ .. . . … … . . . . . . . . … · 9 7
6.2 从 A n ac ond a启动 Pyth on … … … … ·· 77 6.25 1J、 结 ··········· · ··· ········ · ··· · · · · · · · · · · · · · · · · · · · 98
6.2. 1 使用 NwnPy 的示例 … … … … … .. 73 练习题 · · · · · · · · ·· · · · · · · · · ········ · · · · · ·· · · · · · · · · · · · · · · · · · · · · 98
6. 2 .2 使用 Sc iPy 的示 例 … … .. … … … … 79
6.3 显示 N umPy 和 SciPy包含的所有 第7章 用 matplotlib 模块 绘 制 与 金 融
相 关 的 图 形 ....... ... ..................... 101
函数 . . . . . . . .................... . . . . . . ............... 3 2
6.4 关于某 个函数的详 细 信 息 … …… .. 33 7.1 通过 Ac tivePyth on 安装 m at p lot ib l
6.5 理解列 表数据 类型 … … … … … … … …83 模 块 . . . . . ........................ .................1 02
6.6 使用 全 一 矩 阵 、 全零矩阵和 7.2 通过 A n ac ond a安装 m at p lot ibl
单位 矩 阵 ····· · · · · · · · · · ·· · · · · · · · · · · · · · · · · · · · · · · · 84
· 模块 . . . . ........ ......... . . . . . . ............. ......103
6. 7 执行数组操作 · · ··· ··· · · · · · · · · · · ··········· ···84 7.3 m at pl ot ibl 模 块简介 … … … … … … … 103
6.8 数组的加、 减 、 乘、 除 … … … … · · · 8 · 5 7.4 了 解 简单利 率和复利利率 … … . . . .106
6.8.1 进 行 加减 运算 .. . . . .......... ...... . . ... . g 5 7.5 为 团 形添 加文字 ..... ..... ........... .....1 0 7
6.8.2 执行矩 阵乘法运算 … … · …… … …85 7.6 杜邦 等式 的图示 . . .. … ....... … .........1 09
6.8.3 执行 逐项相乘 的乘 法运算 … ..... 3 6 7. 7 净现值图示 曲 线 .. … … … … … … … … 110
6.9 x. sum(函数
) . . ............ ............ .......... 3 7 7. 7.l 有效地使用 颜色 … · …… … … … . . 113
6.10 遍历数组的循环 语句 … … … … … …87 7. 7.2 使用 不同 形状 . . ........ . . . . . . . ..... … 114
6.11 使用 与 模块相关的帮助 … … … ..... 3 7 78
. 图形演 示分散投资 的效果 … … … · 115
6.12 SciPy 的一 系列 子函数包 …… … …88 7.9 股票的数 目和投资组合风险 …… 11 7
6.13 累 积标准正 态分布 … … … … … … … 89· 7.1 0 从 雅虎财经网站下载历史
6.1 4 与 数组相关 的逻辑关 系 .. … … … … 9 0 价格数据 .............. ...................... 119
6.15 SciPy 的统计子模块 C st at s) … .. 9 0 7. 1 0. l 用 直 方 图显 示收益率分布 … · 1 20
6.16 SciPy 模块的插值方法 … … … … … · 91 7.10.2 比较单只 股票的 收益和
6.1 7 使用 SciPy 求 解线性方程 … … … · · 92 市场 收 益 .................. . ............122
4 Python 金 融 实 战

7. 1 1 了 解现 金 的 时 间 价 值 … … … … … · 1 24 8 .4. 3 从 txt 文件输入数 据 … ……… · · · 1 48


7. 1 2 用 烛 台 图 展 示 IBM 的 每 日 8.4.4 从 Excel 文件输入数 据 ……… ·· 149
收 盘 价 ········· · · · · · · ·· · · · · · · · · · · · · · · ········· 1 25 8.4. 5 从 csv 文件输入数 据 ………… ·· 1 5 0
7. 1 3 用 图 形展 示 价 格 变化 … … . . . . … … 1 2 6 8 .4. 6 从 网 页 下 载 数 据 ....... .…… ......, 1 5 0
7 . 14 同 时 展示收 盘 价 和 交 易 量 …… ·· 1 2 9 8.4. 7 从 MATLAB 数 据 文件输入
7 . 1 4. 1 在 图 形上添加 数学 公式 … … · 1 3 0 数 据 · · · ·· · · · · · · · · · · · · ······ · · · · · · · · · · · · · · · · · 1 5 2
7 . 1 4. 2 在 图 形上添加 简 单的 图像 … · 1 3 1 8 .5 几个 重要 的 函 数 … … … … …… .. …… 1 52
7 . 1 4. 3 保存 图 形文 件 . . . . . . . . . ....... .. ..... 1 32 8. 5 . 1 使 用 pd.Series()生成 一 维 时 间
7. 1 5 比较 个 股 的 表现 …… … . . … . . . … … · 1 32 序 列 · · · · · · · · · · · · · · · · · · ·· · · · · · · · · · · · · · · · · · · · · 1 52
7. 1 6 比较 多 只 股票 的 收益 率 与 8 . 5 .2 使用 日 期变 量 · · · · · · · · · · · · · · · · ·· · · · · · · · 1 53
波 动 率 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 33 8. 5 . 3 使用 DataFrame 数 据 类型 …… 1 5 4
7. 1 7 查找学 习 手册、 示例和有关 8 . 6 计 算 回 报 率 ··· · ·········· · · · · · · · · · · · · ········ 1 5 6
视频 · · · · · · · · · · · · · ·· · · · · · · · ····················· 1 35 8 . 6. 1从 日 回 报率 计算 月 回 报 率 … … 1 57
7. 1 8 独立安装 matplotlib 模 块 … … … · 1 3 6 8. 6 .2 从 日 回 报率计算年 回报率 … · · 1 5 9
7 . 1 9 1J、 结 .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 3 6 8.7 按 日 期 合 并 数 据 集 … … … … … … … · 1 60
练 习 题 . . .. . . . . . . . . . . . ........ . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 3 6 8 .8 构建 n 只 股票 的 投 资 组 合 … … … · 1 6 1
8 .9 T-检验 和 F-检验 … .... … . . . . . . . ......... 1 6 2
第8章 时 间 序 列 的统计分析 … … … … … 1 3 9
8 .9. 1 检验方 差 是否 相 等 … … … … … · · 1 6 3
8.1 安 装 pandas 和 statsmodels 8 .9. 2 测试 ” 一 月 效 应 " ········ ········· 1 64
模 块 · · · · · · · · · · · · ·································· 1 40 8. 1 0 金融研究和 实 战 的 应 用 举例 … · 1 6 5
8. 1 . 1 在 Anaconda 命令提示符下启 动 8. 1 0. 1 基于 5 2 周 最高 价 和 最低 价
Python · · · · · · · · · · · · · · ·· · · · · ················· 1 40 的 交 易 策略 ········· · · ·· · · · · · · · · · · · · · · 1 6 5
8. 1 .2 使用 DOS 窗 口 启 动 Python … · 1 4 1 8 . 1 0. 2 用 Roll ( 1 984 ) 模型来估算
8. 1 . 3 使用 Spyder 启 动 Python … … · · 1 4 2 买卖 价 差 · · · · · · · · · · · · · · · · · · · · · · · ········ 1 66
8.2 Pandas 和 statsmodels 模 块 8 . 1 0. 3 用 Amihud ( 2002 ) 模型 来
简 介 · ········· · · · · · · · · · · · · · · · · · · · · · · · · ·· · · · · · · · · · · 1 43 估算反 流 动性 指标 … … … … · · · · 1 6 7
8.2. 1如何使用 Pandas 模块 … · … … · · 1 4 3 8 . 1 0.4 Pastor 禾D Stambaugh ( 200 3 )
8 .2.2 statsmodels 模块示例 … … … … · · 1 44 流动性指 标 · · · · · · · · · · · · · · · · · · · · · · · · · · · 1 68
8 . 3 开源 数 据 ························· · · · · ········· 1 4 5 8. \ 0. 5 Fama-French 三因 子模型 … … 1 7 1
8 .4 用 Python 代码输入 数 据 … ……… · 1 4 7 8 . 1 0. 6 Fama-MacBeth 回 归 模 型 · … · · 1 73
8 .4. 1 从剪贴板 输入数据 … … … … … · · 1 4 7 8. 1 0. 7 滚 动 式估算市场风 险 系 数 … · 1 74
8 .4.2 从雅虎财经网站 下 载 历 史 8 . 1 0. 8 在 险 价 值 简 介 · · ······· · · · · · · · · · · · · · · 1 77
价 格 数 据 · · · ·············· · · · · · · · · ·· · · · · · 1 4 7 8. 1 1 构 建 有效 组 合 边 界 … … · … … … … · 1 78
目录 5

8. 1 1 . 1 估计方差-协方差矩阵 ……… · · 1 7 8 9.8 多 种 交 易 策 略 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·2 1 3


8. 1 1 .2 优化 最 小化 . . . . . . . . . . . . . . . . . . . . . . . . . . 1 8 1 9.8. 1 股票 多 头 和看涨期权空头
8. 1 1 . 3 构建 一
个最 优投资 组合 · … … · 1 8 1 的 组合 · · · · · · · · · · · · · · · · · · · · ·· · · · · · · · · · · · · · · 2 1 4
8. 1 1 .4 构 建 n 只 股票 的 有效 组合 9.8.2 跨式期权 组 合 一一 具 有 同 样执 行
边 界 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . 1 8 3 价格的看涨期权和看跌期权的
8. 1 2 插值 法简 介 . . . . . . . . .. . . … . . . . . . . . . . . . . . . . . 1 8 6 组 合 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·2 1 5
8. 1 3 输 出 数据 到 外 部 文 件 … … … … … · 1 87 9.8.3 日 历 套利 组合 · · · · · · · · · · · · · · · · · · · · · · · · · 2 1 6
8. 1 3 . 1 输 出 数据 到 一 个 文 本文件 … · 1 8 7 9.8.4 蝶式看涨期 权 组 合 … … … … … · · 2 1 8
8. 1 3.2 输 出 数据到 个二进制 一
9.9 期权价 格 和 输 入 参数之 间 的
文 件 · · · · · · · · · · · · · ·· · · · · · · · · · · · · · · · · · · · · · · · 1 88 关 系 · · · · · · · · · · · · · · ·· · · · · · · · · · · · · · · · · · ·· · · · · · · · · · · · 2 1 9
8 . 1 3 .3 从 二 进 制 文 件 读取数据 …… .. 1 8 8 9.10 与 期 权 相 关 的 希腊字母 · … … … · · 2 1 9
8. 1 4 用 Python 分析 高 频 数据 并 计 算 9. 1 1 期权平价关 系及 其 图 形
买卖 价 差 . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . 1 88 表示 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 22 1
8. 1 5 更 多 关 千 使 用 Spyder 的 9. 1 2 二叉 树 法 及 其 图 形 表示 … … … · · · 223
信 息 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 1 94 9. 1 2. 1 为欧式期权定价的
8.16 一
个有用 的 数据 集 … … … … … … · · 1 9 5 二 叉 树法 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 229
8. 1 7 小 结 . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . 1 96 9. 1 2.2 为美 式期权定价的
练 习 题 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . 1 97 二 叉 树 法 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 22 9
9. 1 3 套 期 保 值 策 略 · · · · · · · · · · · · · · · · · · · · · · · · · · · · 23 0
第9章 Black-Scholes-Merton 期权定价
模型 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 2 0 1 9. 1 4 ;J 、 结 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·· · · · · · · · · · · · · · 23 1
练 习 题 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·· · · · · · · · · · · · · · · · · · · · · 23 2
9. 1 看涨期权和 看 跌 期 权 的 收益 和
第 10 章 Python 的循环语句 和 隐含
利 润I损 失 函 数 . . . . . . . . . . . . . . . . . . . . . . . . .. . . . 2 02
波动 率 的计 算 . . . . . . . . . . . . … · · · · · · · · · · 2 3 5
9. 2 欧 式期 权 与 美 式 期 权 … … … … … … 2 05
9. 3 现金流 、 不 同 类 型 的 期 权 、 权利 1 0. 1 隐 含 波 动 率 的 定 义 … … · … … … … · 23 6
和 责 任 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 06 1 0. 2 for 循环 简 介 · · · · · · · ·· · · · · · · · · · · · · · · · · · · · · · · 23 7
9.4 正态分布、 标准正态分布 和 累 积 1 0.2. 1 使用 for 循环计算 隐 含
标准 正 态 分 布 . . . . … … · · · · · · · · · · · · · · · · · · · · 206 波 动 率 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 23 7
9. 5 不 分 红股票 的 期 权 定 价 1 0.2.2 欧式期权 的 隐含波动率 … … ·· 23 8
模 型 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . 2 09 1 0.2.3 看 跌 期 权 的 隐 含 波 动 率 … … · · 23 9
9.6 用 于 期 权 定 价 的 p4f 模块 … … … ·· 2 1 0 1 0.2.4 enumerate () 函 数 简 介 . ……… · · 2 40
9.7 已知 分红股票 的 欧 式 期 权 1 0. 3 用 for 循 环 计算 内 部收益 率 及
价 格 · · · · · · · · · · ·· · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ····· 2 1 2 多 个 内 部 收益 率 · … … … … … … … … · 24 1
6 Python 金 融 实 战

1 0.4 whil e 循 环 简 介 . . . .. . . . . . . . . . . . . . . . . . . . . .2 43 1 1 . 1 .3 产 生 n 个服从正态分布 的


1 0.4. l 使用 键盘命令停止无 限 随机 数 · · · · · · · · ·············· ·············26 3
循环 ···· · · · ·················· ·········· · · · 244 1 1 . 1 .4 正态分布 样本 的 直 方 图 … … ··264
1 0.4. 2 使用 while 循环 计算隐含 1 1 . 1 . 5 对 数 正态分布的 图形表示 … ·26 5
波 动率 ··············· ···················244 1 1 . 1 . 6 产生服从泊松分布 的
1 0.4.3 多 重嵌套的 for 循环 … … … … ·24 6 随机数· · · · · · ············· · · · · · · · · · · · · · · · ·266
1 0. 5 美式看涨期权 的 隐含 波 动 率 . . . .2 46 1 1 . 1 . 7 产生服从均匀分布 的
1 0. 6 测 试 一 个 程 序 的运行时 间 …… · · 24 7 随机数···· · · · · · · ·························266
1 0.7 二 分 搜索 的 原理 … .. … … … …… .... 24 8 1 1 .2 利 用 蒙特 卡 罗 模拟 计 算 的
1 0 .8 顺序访 问 与 随 机 访 问 … . . . . . …… .. 249 近似 值 · · · · · · · · · ··············· ················267
1 0.9 通过循环 访 问 数 组 的 元 素 … … ..2 5 0 1 1 .3 从 只 股 票 中 随 机 选择 m 只 …… 26 8
10.9. 1 利 用 for 循环赋值 … …… … … . . 2 5 1 1 1 .4 可重复和不可重 复 的 随 机
1 0.9. 2 通过循环 访 问 词 典 的 元素 … · 2 5 1 取 样 ······························ ··············2 7 0
10.1 0 从 CBOE 网 站 下 载 期 权 1 1 .5 年收 益率 的 分 布 …… · ……… …… · · 2 7 1
数 据 .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 5 2 1 1 .6 模拟 股 价变 化 … … · · · · · · · · · ······· ······2 73
1 0. 1 1 从雅虎财经 网 页 下 载 期 权 1 1 .7 图 形 展 示 期权 到 期 日 的股票
数 据 · ·· ····················· ··················2 5 4 价 格 的 分 布 · · · · · · · · · · · · ··············· · · · · ·2 75
1 0. 1 1 . l 从雅虎财经 网 页 检索不同 1 1 .8 寻 找 有 效 的投 资 组 合 和 有 效
的 到 期 日 期 … . . . . … . . . . . . . . . . . . . . . . 254 边界 ············· ······· · · · · · · · · · · · · · · · · · · ··· ···2 7 6
1 0. 1 1 . 2 从雅虎财经 网 页 下 载当前 1 1 .8. 1 寻找基 于 两 只 股票 的 有效组合
价 格 .. . . . . . . . . . . . . . . . . . . .. . . . . . . . .. . . . . . . 2 55 及 相 关 系 数 的 影 响 . . . . . … … … · ·2 7 6
1 0. 1 2 看跌期 权和看涨期权 的 比 率 及 1 1 .8. 2 构建 n 只 股票 的 有 效
其短期 趋势 . . . …… . . . . . . … . . . . . … . . . . 2 55 边 界 ········· · · · · · · · · · ····················2 8 1
1 0 . 1 3 小 结 . . . . .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 5 8 1 1 .9 算 术平均 值 与 几何平均 值 ……… 2 83
练 习 题 ···················································2 5 8 1 1 . 1 0 预测 长 期 回 报 率 … … …… … ·······2 84
1 1 . 1 1 用 模拟法为看涨期权定 价 …… ·2 8 5
第 11 章 蒙特卡 罗模拟和期权定价 …… 26 1
1 1 . 1 2 奇异 期权 简 介 . . . . . . . . .. … ······· ·· ····2 8 6
1 1.l 产生服从标准 正 态 分 布 的 1 1 . 1 2 . 1 利 用 蒙特卡罗 模拟给
随 机 数 ················ ········· · · ············· 262 均 价 期 权 定价 ····· ·············· ···2 8 6
11.l.l 产生服从 ( 高斯 ) 正态分 布 1 1 . 1 2.2 利用 蒙特 卡 罗 模拟给
的 随 机样本 … . . . . . . . . … … . . . . . … ···26 3 障碍 式期 权 定 价 … ……… … … 2 88
1 1 . l .2 利 用 种子 ( seed ) 生成相 同 1 1 .1 3 障碍式 期 权 的 平 价 关 系 及其
的 随 机 数 ···························· ···26 3 图 形演 示 . . . .. . . . . . . . . . . .. . . . . . . . . . . . . . . . . .28 9
目录 7

1 1.14 具有浮动执行价格的回望式 1 2 .7 波动率的微笑 曲 线和斜度 …… ·· 3 07


期权的定价 . . . . . ... …… ............. … 2 9 3 1 2.8 波动率集 聚效应 的图形表示 … · 3 09
1 1 . 15 使用 Sobol 序列 来提高 1 2 .9 ARCH 模 型 及 ARCH C l ) 随 机
效率 . . . . . . . . . .................................294 过程的模 拟 . . . ...... ..... ... ......... . . . . ..3 1 0
1 1 . 1 6 小 结 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ····· 2 94 1 2. 1 0 GARCH C 广义 ARCH )
练 习 题 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·· · · · · · 2 95 模 型 ...... . . . . ..... . . .. . . .. .. ... .. .. . . . . . . .. ..3 1 2
模拟 GARCH 随机过程 . . . …3 1 2
第 12 章 波动率和 GARCH 模 型 …… ·· 2 96
1 2 . 1 0. 1
1 2 . 1 0. 2
传统的风险测度-标准方差 …… · 2 97
采用 改 良 的 garchS血()函数
1 2. 1 模拟 GARCH(p,q) 模型 … .... 3 1 3
1 2. 2 检验正 态 分 布 · ……………………… 2 97
下 偏标准方差 · …… ... … · · · · · · · · · · · · · · · 3 00
1 2 . 1 0. 3 由 Glosten 、 Jagannanthan 和
1 2. 3 Runkle C 1 99 3 ) 提 出 的 GJR_
1 2 .4 检验两个时间段的波动率是否 GARCH 模型简介 …………… 3 1 5
相等 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 3 02 1 2. 1 1 小 结 . . . . . . . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . 3 1 9
1 2.5 利用 Breusch 和 Pagan ( 1 979 ) 练 习 题 . . . . . . . . . . . . . . . . . . . . ..... . . . . . . . . . . . . . . . . . . . .. . . . . . 3 1 9
方法检 验异 方差 … … … …… ……… 3 03
1 2.6 从 雅虎财经 网 页 检 索 期权
数 据 · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · 3 06
第1 章

Pyt hon 简介 及安装

本章首先介绍为什么 采用 Python 作为计算工具和 使用 Python 有哪些优 点 , 然后讨论


如何安装、 启 动 和退出 Python, 是否区分大小写等问题, 以及一 些
简单的例子 。

本章主要 内 容 如下 。
• Python简介

• 如何安 装 Python

• 应该使用哪 个版本的 Python

• 启 动和退出 Python 的方式

• 错误提示
• Python 是区分大 小写的

• 变量的初始化

• 查找在线 帮助、 学习手 册 和 自 学教程

• 查看 自 己的 Python 版本

1 .1 Pytho n 简介

人 类在 多年前已经进入信息化时代。 事实上 , 我们 如今是淹 没在信息的海洋之中, 时


时刻 刻都有大量 的电子邮件需要阅读或太多的网 页亟待浏 览 。 互 联网 提供 了 大量 关于 任何
事物的信息, 从 重要的事件到 如何学习 Python 。 我们 可以借助互联网 搜 索 任何一 家上 市公
司的信息 。 如果想收集与国际商业机器 (IBM)相关的财务信息, 可以使用雅虎财经网站、
2 第1 章 Python 简介 及 安 装

谷 歌财经网 站 、 美国证券交易 委员会 ( SEC) 网站公布的公司报表和该公司的网 页 , 等等。


在这样的背景下, 投资 者、 专业人士和 研究人员需要一 个强有力的工具来处理如此大量的
公开信息。 同时, 我们 的社会趋向于更加开放和透 明 。 在金融领域, 开源金融的概念应运
而生。 Dane 和 Masters ( 2009) 提 出 了开源金融的 3 个组成部分: 开源软 件 、 公开 的数据
和开放的代码。 作为开源金融的第一 个组成部分, Python 是开源软件的最好选择之 一。 另

同样流行的开源软 件是 R。 下面总结学习和运用 Python 于 金融领域的一 些优点。

首先, Python 是免费的开源软件。 免费带来许多 好处。 我们 可以设想一 个


简单的实验。
假设 一 个读者没有学习过期权理论, 对 Python 也一无所知。 你觉得他/她需要多长时间能够
用 Python 来计算看涨期权的价格 ( Black-Scholes-Merton 模型)。 我们 的答案是 : 2 小时之
内 ! 首先, 下 载和安装 Python ,这不会超过 1 0分钟。 再花 10 分钟学习如何启动并退 出 Python,
并试运行几 个
简单例子 , 然后在 4. 1 节, 找到著名的 Black-Scholes- Merton 看 涨期权模型的
代码, 总共 只 有 1 3 行代码。 读者可以在接下来的 40 分钟输入代码, 调试纠 错。 2 小时之
内, 他/她应该能够 自 如 地运行 Python 程序给看涨期权定价了。 当然, 当公司采用 一种新的
计算机语言时, 应考虑 多方面的成本: 如 软件的年费 、 维护成本、 可调用的软件包和技术
支持等。 换言之 , 软件是否开源只 是 一 个因素。

再看另 外一 个涉及美国证券交易 委员会的例子。 2010 年, 美国证券交易委员会提议, 所


有的金融机构在提交 申 请 发售新的资 产支持证券时, 需要提供 一 个能够计算和演 示该证券的
合同现金流量的软件程序 ( www . sec . gov/ rul e s /propo sed/ 2 0 1 0 / 3 3 - 9 1 1 7 . pdf) , 并
建议使用 Python 作为编写 该程序的计算机语言。 考虑 Python 的重要原因之 一是其开源性。
因为任何投资 者都可以免费地学习和使用它。

Roger Ehrenberg C 2007) 建议对债券或信用风险的分析引进开源金融的概念。 是否要


求机构投资 者一定按照债券评级来决定买卖并 不重要, 重要的是知晓金融机构是如何裁定
可投资 债 券风险的级别。 试想一 下, 如 果很 多 金融机构 把 自 身的债务评级模型公之于 众,
并 由众人加以改进, 这对债券或信用风险的分析有多 么 大 的推进作用啊 ! 为了促进这方面
的发展, Python (或 R) 是用作计 算 工具的理想选择之 一 。

其次, Python 功能强大 、 灵活, 并 且简单易学。 它能够帮助解决几乎所有与金融和经


济相关的计量问题。 Python 适用于所有主要的操作系统,包括 Windows 、 Linux/Unix 、 OS/2 、
Mac 和 Amiga, 等等。

第三, Python 适合大数据的应用。 Dasgupta ( 20 1 3 ) 认为 R 和 Python 是两 个最受欢迎


的用于数据分析的开源编程语言。 与 R 相比较, Python 是 一 个更好的广泛式语言, 尤其是
考虑它与面向对象编程功能的融合。 与 S c i Py / NurnPy 、 Matp l o t l i b 和 Stat srnode l
1 .3 Python 的 不 同 版本 3

相组合, 它 提供了 一 个强有力的数据分析工具 。 本书还会讨论一 个称为 Pan das 的处理财务


数据的模块。

第四 , 类似于 MATLAB 的工具箱和 R 的软件包 , Pyth on 拥有许多非 常 有用 的模块。


每 个模块都完成 一 些 特定的功能。 在本书中, 我们 将学习十 几 个模块。 其 中, 将特别 关注
5 个对金融最有用的模块: NumPy、 S c i P y、 Ma tp l o t l ib、 S t a t smode l s 和 Pandas 。
前两 个模块与统计分析、公式 计算、矩阵 及其 操作、数据结构和数据操作有关 。 Matplot 巨b
是图形模块。 第8 章将 使用这 个模块深入讲 解如何用 图形呈现各种交易策略的收益函数和
利润/损 失函数 。 S t atsmode l s 是与计量 经济学相关的模块, 该模块包括 T-检验、 F-检验
和 G A RCH 模型等 。 Pandas 是用 于 金融数据分析的模块。

当然我们应该指出 Pyth on 的一 些 缺点。 由千它是免费的, 最主要的缺点是缺乏客户支


持。 一
些 专家 认 为, Pyth on 社区需要进一 步成长, 应该包括更多的统计学家和数学家 。

1 .2 如何安装 Python
采取以下两 个步骤来安装 Pyth on 。
I . 访问 Pyth on 的官方 网站下载 。

2 . 根据计算机的系统, 选择适当的软件, 比如 Py七hon 3 . 3 . 2 Windows x 8 6 MS I


Installer。

在当前阶段, 初学者只需选择 Pyth on 最新版本即 可 。 他们 可以跳过下一 节有关版本的


讨论而直接学习如何启 动 Pyth on 的章节 。

通常 用以下 3种方法来运行 Pyth on 。

• 从 Pyth on 的 I DLE ( GUI )。

• 从 Pyth on 命 令行 。

• 从 DOS 命令行窗 口 。

这 3种方式 将 在第 1.4. l 、 1 .4 .2 和 1. 4.3 节介绍。

1 .3 Python 的 不 同 版本
有关 Pyth on 安装最常见的问题之 一是: 我们应该下载哪 个版本? 在这 个阶段, 任何最
新的版本都可以。 换言之, 对于 初学者而言版本并不重要, 原因有三 。
4 第 1 章 Python 简介 及 安 装

• 本书前 4 章的内容 适用于 任何版本。

• 卸 载 旧 的版本和安装新的版本易如反掌。

• 不 同版本可以在同一 台电脑上 共存。

在以后的有关章节中, 将解释模块与 Python 版本的兼容 关系。 模块是许多 Python 程


序的集合, 由 一个或一组专家为完成 一 些 特殊的功能而编写的。 例如 我们将讨论一个叫作
Stat srnode l s 模块, 这是与统计和计量经济模 型 、 线性 回 归等有关的模块。 我们常常会
用到内置 模块、 标准模块、 第三方提供的模块和 自 行建造的模块。 我们将在多个章节讨论
模块这个重要的课题。

在本书中, 我们会学习大 约 20 多个模块, 其 中详 细 讨论 NurnPy、S c i P y、Matplot 让b、


Pandas 和 S t a t srnode l s 模块。 NurnPy、Matp l o t 巨b 和 S t a t srnode l s 模块需要 Python
2.7以上 版本。 有 些 模块也与 Python 2.x 版本 ( 2.5 -2.6 以上, 依情况 而定) 兼容 。

1 .4 运行 Python 的 3 种方式
以下介绍启 动 Python 的 3 种方式。

1.4.1 用 GUI 启动 Python


用 GUT 启 动 Python 的步骤如下。
] . 单击开始菜单, 然后展开 “
所有程序

菜单项。
2. 找到 Python 3.3。

3. 如图 1-1 所示, 单击 IDLE ( Python GUI )。

P汴hon 33
f7' lDLE (Python GUI)
rt' Module Docs
r' Python (com 叩 nd line)
酴 P灿on Manuals
侍 Unin申II Python

图 1 -1

4. 启动 Python 后, 出现如图 1-2 所示的窗 口 。


1 .4 运行 Python 的 3 种 方 式 5

74 Python 33.2 Shell 丘�I... 电fl百]


File Edrt Shell D的ug Opt10M Y,rindows Help
Python 3 . 3 . 2 (v3 . 3 . 2 : d047928ae3f6, May 1 6 2013 , 00 : 0 3 : 4 3 ) [MSC v . 1 6 0 0 32 bit ( In 二
tel ) ] on win32
Type " copyright " , "credits " or "license ( ) " for more 血OD吐七工on . I
>>>

图 1 -2

计算未来现金流的现值的公式如下 。
FV
P V= ( 1-1 )
( l + RY

在此等式中, P V 是现值, FV 是未来值, R 是折现率, n 是周 期数 。 根据前面的公式,


可以输入这些 数值来计算未来现金流的现值 。 假设 将在 一年后获得 100 美元, 如果年折现
率是 10%, 这 100 美元的现值是 多 少 呢 ? 下面的几行代码用来解答这 个问题。

»> 1 0 0 / ( 1 + 0 . l )


90 . 9090909090909
>>>

[� 勹 ; 于 号 ( >>> ) 是 Python 提示符 。

在电脑桌面创建一 个 Python 图标是 一 个好主意。 除了前述的方法外, 接下来的两 节会


介绍其他的方法来运行 Python 。

1.4.2 从 Python 命令行启动 Python


初学者可以跳过这一部分并转到退出 Python 部分, 学会如何用 GUI 启动 Python 已经
够用了 。 首先, 我们知道 如何使用 Python IDLE 或点击桌面上 的 Python 图标来启动 Python 。
其 次, 可以方便地使用 Python IDLE 来保存并运行 Python 程序 。

从 Python 命令行启动 Python 的步骤如下。

I . 单击开始菜单, 展开 所有程序 选项 。
“ ”

2 . 生戈至IJ Python 3 .3 。

3 . 如图 1 -3 所示, 单击 Python ( command line ) 。


6 第 1 章 Python 简介 及 安 装

Python 33
(?• [OLE (Python GUI)
fr> Module Docs
占 Python (command line)
酴 环hon M-,nu沁
弱 Unin寸:all Python

图 1 -3

4 . 单击 Python ( command line ) 之 后, 会看到如图 1 -4 所示的窗 口 。

,:,;i C:\Pytho函\p如hon 赵e
----,.日
丘匠卫

图 1 -4

1.4.3 从 DOS 窗 口 启动 Python


可以打开 一 个 DOS 窗 口 , 找到包含 Python 程序的子 目录, 然后从 那里运行 Python 。
为此, 执行以下步骤 。

1 . 单击开始菜单, 然后在如图 1 -5 所示的运行窗 口 中 输 入 cmd。

cmdl X

妒雪遭仁勤瑾 图 1 -5

2 . 输入 cd c : \ pytho n 3 3 移动 到相应的 目录 。

3 . 输入 PY七hon 命令来运行软件, 如图 1 -6 所示 。

如果要从 其他 目录 启 动 Python , 必须 在搜索路径上包括 Python 所在的 目录 。 假设 Python


安装在 C : \python 3 3 , 以上 第 2 步应当用下面的 DOS 命令。

set pa 七 h= 号 path 亳 ; C : \python 3 3


1 .6 错 误 提 示 7

图 1 -6

1 .5 如何退 出 Python
以下 是退 出 Python 的几种常用方法。

• 按 Ctrl+D 组合键。

• 按 Ctrl+Q 组合键。

• 单击 File 菜 单中的 Exit 选项。


“ ”
• 单击窗 口 右 上 角 的 关闭 按钮 ( 即 直接关闭 窗 口 )。

在 本 书 后 面部分 , 将解释如何利用代码在程序运行结束之后自动 退 出 Python。

1 .6 错误提示
对 千 前面的例 子 , 如果 1 00 美元在 两 年 后 获 得 , 输 入 1 0 0 / ( 1 + 0 . 1 ) " 2 而 不 是
1 0 0 / ( 1 + 0 . 1 ) * * 2 , 会看到下面的出 错信息。 它告诉我们 , 不 支 待 ^ 运算符号。

» > 1 0 0 / ( 1 +0 . 1 ) " 2
T raceback (mo s t recent call_l a s t ) :
File " <psyhe l l # l > , line 1 , in <modul e >
1 0 0 / ( 1+0 . 1 ) " 2
T ype E rror : unsupported operand t ype ( s ) for " : ' f loat ' and ' in七 '
>>>

初学者 需要注意 以上错误信息的最后 一 句。 最后 一 行告诉我们 , 符号 ^ 不被支持。 应该


使用双乘法符号**而不是 ^作为幕 函数。 第 2 章将介绍 一 个真正的幕函数 pow ( ) 。
8 第 1 章 Python 简 介及 安 装

下载示例代码
可 以 从 网 站 http : / /www . pac ktpub . com 上的账户

沁)
下 栽所有 已 购 买 的 书 籍 , 包括的 示 例 代码 。 如 果 你 在
其 他 地 方 购 买 了 这 本 书 , 可 以 访 问
http : / / www . pac ktpub . com/ s uppo rt 并 注 册 ,
这样含有的代码文件通过电子邮件直接发送给你 。

1 .7 Python 语言是 区分大小 写 的

区分大 小写 意味着 小写的 x 不 同于大 写 的 X ,变量 John 不 同于


变量 j ohn 。 如果为变
量 X ( 小 写字母 x )赋值, 然后调用变量 X ( 大 写字母 X )
, 会得到以下出错信息 。

>>>x = 2
>>>X
Traceback (most recent cal l l a s t ) :
File "<pyshe l l # l > " , l ine 1 , in <module>
X
NameError : name ' X ' is not de fined
>>>

在 上面的例子中, 变量 X 没有被赋值 。 因此, 当 输入 X 试图显 示 其 值时, 会收到 一 条


出错信息 。 请 注意, 最后 一行提及 NameE rror 而不是 Type E r ro r 。 在 Python 中, 我们
称变撒为 name 。

1 .8 变量 的 初始化

在 以上例子中, 给变量 x 赋值 之 后, 就 可以使用它 。 这正如在其他计算机语言, 如


变量 。 类似地, 如 果一 个变量在 Pyth on 中没有被赋值, 就
FORTRAN 和CIC++中定义一 个
无法使用它 。 与 CIC++或 FORTRAN 语言不 同的是, 我们不需要把
变量 x 定义为整数类型,
就可以把10 赋值给它。

Pyth on 语言的另 一 个优点是, 可以改变 一 个变量 的数据 类 型 。 对于 F ORT RAN 语言,


x 被定义为整数类型后, 将无法把字 符 串 赋值予它。 由于 Pyth on 语言只 有对变量 的赋值,
没有对变量 的定义, 可以给 一 个
变量 赋 任何值 。 例如, 可以将 x 赋 值为 1 0。 再把一 个字
1 .9 寻找在线帮 助 9

符 串 , 如 " Hel lo World ", 赋值予它 。 这 样 做 与 数 据 类 型 转 换 是 不 同 的 。 将 在 后 面 的 章 节


讨论不 同数据类型之 间 的转换 , 如整数转换 为 字 符 串 。

1 .9 寻找在 线 帮 助


启 动 Python 之后 , 输入 help ( ) 打 开 在 线 帮 助 ( 如 以 下代码所示 ) 。 在 线 帮 助 的 提 示
符 是 h e l p > 。 只 需 按 一 次 回 车 键或输入 qu i t 就 可 以 退 出 在线帮 助 。 退 出 之 后 , Python 提
示符>>>将 再 次 出 现 。

>>> hel p ( )
Welcome to Python 3 . 3 ! This i s the interactive help u t i l i 七 y .
I f this i s your f i r s t t ime us ing Python , you shou ld defini 七 e l y check out
the tuto rial on the In 七 ernet at http : / / docs . python . o rg / 3 . 3 / tutorial / .
Ente r the name o f any modu l e , keyword, or top i c to get help on writing
Python programs and usi ng Python modu l e s . To qu it this help u t i l i ty and
re 七 urn to the interprete r , j us t type " qu i t " .
To get a l i s t o f ava i l able modul e s , keywords , or 七 opi c s , t ype "modu l e s " ,
" keywords " , or " topics " . Each modul e also comes with a one - l ine summa ry
o f what i t does ; to list the modu les who se summa r i e s con 七 a i n a given word
such as " spam " , type "modu l e s spam" .
help>

输入 keywo rds 后 , 将 得 到 如 下 信 息 。

>>>help> keywords
Here i s a l i s t of the Python ke ywords . Enter any keyword to get mo re help .
Fal s e de f if raise
None de l import return
True elif in try
and else is wh ile
as except Lambda Wi 七 h
assert final l y Nonlocal Yield
break for Not
class f rom Or
continue g l obal Pass

help >

另 外 , 输入 topics 后 , 将 会 看 到 许多 关键词 , 如 图 1 -7 所 示 。
1 0 第 1 章 Python 简 介 及 安 装
help> cop工cs

Here i,s a li,st of available topic,i . Enter any topic n釭正 to get more help .

ASSERTION DELETION LITER压S SEQUENCES


ASSIGNl·IENT DICTIONARIES LOOPING SHIFTING
江TRIBUTEMETHODS DICTION邸江ITERALS MAPE'INGMETHODS SLICINGS
l
AITRlBUTES DYN础ICFE及TORES 也PPINGS SE'EC:也TTRIBUTES
AUG亚NTEDASSIGNMENT ELLI PSIS 立TRODS SE'ECIALIDENTIHERS
西IC泣THODS EXCEPTIONS MODU立S SE'ECIALMETHODS
BINARY EX工C可ION N碑SPACES STRINGMETBODS
BITWISE EXPRESSIONS NONE STRINGS
BOOLE妞 rILES NUMBERMETHODS SUBSCRil?TS
C辽L迼LE亚Ti:10D5 FLOAT NU亟R5 TRACEBAC:-t<S
CALLS FOR如rnG OBJECTS TRUTHV江UE
CLASSES FR碑OBJECTS OPERATORS TUPLE LITERALS
CODEOBJECTS FRAMES PACl<运S TUE'LES
COMPARISON FUNCTIONS POWER TYE'EOBJECTS
COMPLEX IDENTIFIERS P旺CEDENCE TYE'ES
CONDITIONAL IMPORTING PRIV江ENAMES UNARY
CONTEXTM五N运RS INTEGER RETURNING UNICODE
CONVERSIONS LISILIIER人LS SCOPING
DEBO伍笃G LISTS SEQU邸C细THODS

伈 lp >
图 1 -7

在此阶段, 初学者并不需要深入了解这些 主题。 只 需记住 , 我们通过 一 个命 令就可以


找到所有可能用 到的主题。

1 .10 查找 学 习 手册和教程

有很多方法都可以找到 Python 的手 册和其 他相关材 料 。 常用的资 料已经随软件安装在


电脑里或者可以在 Python 网 页上 找到 。 以下进一 步 说 明 如何获取这些 资 料 。

执行以下步骤来得到已经安装在电脑里的资 料 。
l . 单击开始菜单, 然后展开 “ 所有程序 ” 选项 。

2 . 才戈到 Python 3.3。

3. 单击 Python Manuals, 如图 1-8 所示。

I 丛 Python33
� IDLE (Python GUI)
� Module Docs '
, 研on (command fine)
啦 Python Manuals
创 Uninstall Python

图 1 -8
1 . 1 0 查找 学 习 手 册 和 教 程 1 1

4 . 单击 Python Manuals 之 后, 会看到图 1-9 所示的窗 口 。


ci
屯 臣l .,

辱5
^g
心 !«a•

伍 loa l s--叫 F- j Pytnon • 3 3 2 的c umen切lion 身 modules 1 1n<1e入


) l 2 0oc:山喊m廪
,1 卢

l')d,on 仙心血 h竺
如 ., �
� -· ·
O 加 凸中"' T......i
i:) P!I幻" S..., and u.叩' Python v3.3.2 documentation
li! O
Welcome! This IS the 心呾沁飞ahon for Python 3 3 2, last updated May 15, 2013
已 归 “幻· � 氏

己”一 沁 “如 扣心11d l.lny

仁 饮b心
nu 心心血屯 妇 八

Parts of the document詹廿on:


�I闷,_ 山 ....
E) CilOt>t.trog l')d,on 仙心妇
::J �
呱志,. I')加m 心女妇
Q I'\中... IOWTOs
CJ Pi中“ 一 心 Q立酝 What's new in Python 3.3?
oo -.
”“ 如at'$ ne啊. 一S 心 2.0
·�
J 沁-­

寸一

Tutorial
SI
Extending and Embedding
tutortal tor C'Ctt programmers
S1annere
D 心勺and lJcen的
Pythonic API
Library Reference reterer心 归 CJC++ programmer.I
keep 伽SU心 ryour,-
Installing Python Modules
Language Reference intormar/Ofl tor ,心劝爬rs & 3)'$-识勿uns
戊劝杞ssyn啦 andlanguage elements
Distributino Pvthon Modules
图 1 -9

另外 一 个主要的资 料来源是 Python 的主页 。

• Python 3.2 documen ts (3.2.5, last updated on May 1 5, 2013)

http://docs.python.org/3.2/download.html

• Python 3.3 documents (3.3.2, last updated on August 04, 2013)


http://docs.python.org/3.3/download.html

• Python 2.7 document(2.7.5, last updated on September 20, 2013)


http://docs.python .org/2. 7/down load.html

此外, Python 初学者可以在下面网站找到 Python 的很多 其 他学习 资 料 。


• Onlin e_tutorials:

。 http://docs.python.org/3/tutorial/

。 http://docs.python.org/2/tutorial/
• PDF version (424pages):

。 http://www.tutorialspoint.com/python/python_pdf_version .htm
12 第 1 章 Python 简 介 及 安 装

。 http://anh.cs.luc.edu/python/hands-on/3. I /Hands-onPythonTutorial.pdf

1 .1 1 如 何 找 出 Python 的版本

当 Python 启动时, 第 1 行会显示当前的版本。 另 一种查看 Python 版本的方法是, 在


运行 Python 后, 使用以下 Python 代码:

>>>import sys
>>>sys . vers ion
' 3 . 3 . 2 ( v3 . 3 . 2 : d0 4 7 9 2 8 ae3 f 6 , May 1 6 2 0 1 3 , 0 0 : 03 : 4 3 ) [ MSC v . 1 6 0 0 32 bit
( Int e l ) ] '
>>>

第 1 行命令导入一 个 名为 sys 的模块。 该模块包含了许多有用的 Python 程序。 了解模


块是学习 Python 的关键, 将在以下几章更 深入地讨论模块: 第 5 章模块简介 ; 第 6 章介绍
NumPy 和 SciPy 模块; 第 7 章介绍通过 matplotlib 模块绘制与金融相关的图形; 第 8 章介
绍时间序列 的统计分析。

1 . 1 2 小结

本章重点讨论了 如何安装、 启动和退出 Python, 大 小写是否 一 样, 以及其他问题, 并


给出了 一 些简单 的例子。 因为操作 简单 明了, 任何初学者都能轻松下 载 并在几分钟内安装
好 Python, 然后开始运行 Python 代码 。 此外, 我们还了解为何采用 Python 作为计算工具
和使用 Python 的优缺点。

下一 章 将介 绍 一 些 基本概念和常用的 Python 内 置函数, 并且 演 示如何使用 Python 完


成 普通计算器的功能, 并解答许多与财务相关的问题。 比如, 计算 一 个未来现金流量的现
值 、 一 笔现金的未来价值 、 永 续年金的现值或成长型永续年金的现值, 等等 。 还将 讨论
dir ( ) 、 type ( ) 、 f l o o r ( ) 、 r ound ( ) 和 help ( ) 等函数 。

练习题

l . 用几句话来介绍 Python 软件。

2 . 使用 Python 作为计算 工具有什么 优势和劣 势 ?


练习题 13

3. 从何处 可以下载 Python ? 如何安 装 ?

4 . Python 是 否 区 分大小写 ?

5 . 是否可以不定义就使用 一 个变量 ?

6 . 是否可以不给 个变量赋值就使用它 呢 ?

7 . 对于 初学者, Python 的版本重要 吗 ? 在学习 了这本书 之 后 呢 ?

8 . 有哪几种方式可以运行 Python ?

9 . 在哪里可以找到有关 如何安装 Python 的视频 ?

10. Python 主页的网址是什 么 ?

1 1 . 使用 Python 计算直径为 10 的 圆 的面积 。

12 . 如何赋值给 一 个新的变扯 ?
13. 如何能找到与 Python 有关的 一 些示例 ?

14. 如何取得 Python 的在线帮助?

) 5. 你的电脑上 安装的 Python 位于 哪个目录 ? 如何找到其路径?

16. 定义 一 个变量和赋值给 一 个变量有什么 区 别 ?


第2章
用 Python 完成普通计算器 的 功 能

本章 将介绍 一 些 基本概念和几 个常用的 Python 内 置函数, 如赋值、 数值 精度、 加、 减、


乘、 除、 幕函数和平 方 根函数 。 将学习 如何使用 Python 作为一 个普通的计算器来解决许多
与金融相关的问题。 本章主要内容 如下:

• 变量的赋值

• 显 示 一 个变量的值

• 错误提示

• 不能调用 一 个没有被 赋值的变量

• 选择有意义的变量 名

• 使用 dir ( ) 来查找变量和函数

• 删 除或取消变量

• 基本的数学运算: 加 、 减、 乘、 除

. 幕函数 、 取整和余数函数

• 选择合适的精度

• 找出指定的 内 置函数的详细 信息

• 如何导入数学模块

• pi、 e、 对数和指数函数

• 区分 import ma th 和 f rom math imp o r 七 *

• 函数: print ( ) 、 type ( ) 、 uppe r ( ) 、 下划线_, 以及如何结合两 个字符串


几 个常用
2.2 错 误 提 示 15

• 元组数据类型简介

2. 1 变量的赋值 及显示


赋值给 一个 Python 变量非常简单。 我们不 需要定义 一个变量就 可以给它赋值 。 这 一 点
与其他语言 , 如 C开或 FORTRAN 不 同。

>>>pv= 22
>>>pv +2
24


可以同时给儿个变量赋予同样的值。 在 下 面的例子中 , 次给 3 个变量 x、 y 和 z 赋
值 1 0 0。

>>>x = y=z = l O O

为显示 一 个变最的值 , 只 需输入其名称。 例 如 :

>»pv= l O O
>>>pv
100
>>>R=O . l
>>>R
0.1

2.2 错误提 示

如果 使用 sqrt ( ) 函数来估计 � 将得到以下 出 错信 息 。

>>>s qrt ( 3 )
Traceback (most recent call l a s t ) :
File " <pyshe l l # l 7 > " , line 1 , in <module>
sqrt ( 3 )
Name E rror : name ' sqrt ' is not def ined

以上提示的最后 一 行告诉我们 , Python 软件没找到 sqrt ( ) 函数。 在学习 完本章之 后 ,


大家就会知道 sqrt ( ) 函数是包含在 math 模块里的。 必须 先导入该模块 , 才 可以调用其
包含的函数。 模块是 围 绕某个特定主题将 一些相关的函数捆绑在 一起的软件包。
16 第 2 章 用 Python 完 成 普 通 计 算 器 的 功 能

2.3 不能调 用 没 有赋值 的 变量


如果从 未 赋值给变量 abcd e, 输入 abcde 后, 将得到以下 出错信息。

>>>abc de
Traceback (mo s t recent call l a s 七 ) :
File " <pyshe l l # O> " , line 1 , i n <module >
abcde
NameError : name ' abcde ' i s not defined
>>>

最后 一行告诉 我们, 这 个变量 没有定义。 在某种意义上 , 赋值给 一 个


变量 相当于做了
变量, 并在同一 时间赋值给它。
两 件事: 定义一 个

2.4 选择有意 义 的变量名

永 久年金是指未来每隔 一 段时间有等额的现金支 付, 直到永远。 比如, 在未来每年的


年底收到 5美元, 或者像英国政府发行的一种称为 con s o l的债券 支付定额的利息 。 假定第
l 笔支付发生 在第 1 个周 期的结束, 可用下面的公式 估计永久年金的现值。

C
PV(永久年金 ) = — ( 2-1 )
R

这里, PV是现值, C是每 个周 期的定额支付, R是每周 期折现率 。 C 和 R 应该有 一 致


的周 期, 也就是说, 如 果 C是年度 ( 月度 ) 的现金流, 那么 R 必须是年度 ( 月度 ) 的折现
率。 假设定额的
年度支付为 10 美元, 在第 1年 结束时收到第 1 笔支付,年度折现率为 10%。
比较以下两 种命 名
变量 的方式 。

>>>x = l O # bad way for variable names


>>>y= O . l
>>>z = x/y
>>>Z
100

>>>C= l O # good way for assignments


>>>R=O . l
>>>pv= C/R
>>>pv
2.6 删 除 或取消 变 岱 17

100

使用 C 作为定额支 付变量 名比用 x 好, 使用 R 表示折现率比用 y 更好, 因为 C 和 R 与


公式 ( 2- 1 ) 中使用的
变量 名相同, 而 x 和y 没有任何特定的含意。

增长型永 久年金是指未 来的现金流 以恒定的速度 g 增长 。 以下公式给出其 现值。


C
PV( 永 久年金 ) = ___ ( 2-2 )
R-g

在这个公式中, C 是第1 个 周 期末发生 的现金流, R 是每 周 期的折现率, g 是每 周 期的


增长率。 显 然, 增长率 g 应小于 折现率 R。 考虑购买每年支 付为 C 和每年折现率为 R 的永
久年金。 计算它今天的价值时, 需要考虑 未来的通货膨胀 率 ; 如果未来年度通胀率是 CP I
(消费者物价指数), 那么 增 长速度将等于 负 的CPI。

2.5 使 用 dir()来查找变量和 函 数

为儿 个变量 赋 值 后, 可以使用 d江 ( )函数来检 查 它们是否存在。 下 面的例子 显示 n 、


pv 和 r 等变量 。 现在不用理会最前面的 4 个变量 , 它们的 名字 开头和结尾各有两 个下
划线。

>> >pv= l O O
>>>r = O . l
> > > n= S
>>>dir ( )
[ ' bui l tins ', ' do c ', ' name ', ' package ', 'n' , ' pv ' , 'r' )
>>>

2.6 删 除或取消 变量

编写程序时, 有时需要删 除那些 不 再需 要的


变量 。 在这种情况下, 可以使用 del 命令
删除 一
个指定的
变量 。 在下面的例子中, 给变量 rate 赋值, 显示其 值, 将其 删除, 然后
输入
变量 名试图再次显示其 值 。

> > > r a七e= 0 . 0 7 5


>>> rate
0 . 075
18 第2章 用 Python 完 成 普 通 计 算 器 的 功 能

以 上 代 码 显 示 rate 的 值 为 0 . 0 7 5 。 以 下 代码先删 除 该变量 , 然 后 试 图 再 次显示其值。

> >>del rate


>>> rate
Tr aceback (mo s t recent c a l l l a s t ) :
Fi le " <pyshel l # 7 2 > " , l ine 1 , i n <modu le>
Ra 七 e
NameEr ror : name ' r ate ' i s not def ined [ End o f code s ]

一 一
以 上 出 错信 息 最 后 句 告 诉我们 , 变 量 rate 没有 被 定 义 。 如 果 需要 次 删 除 儿 个变
量 , 可 以 用 逗 号 把它们 分 隔 , 例 如 :

>>>pv= l O O
>>>r = 0 . 8 5
>>>dir ( )
[ ' builtins ' doc ', ' name ' pa c ka ge ', ' pv ' , ' r' l
>>>del pv , r
»>dir ( )
[ ' built ins ' doc ', ' name ' pac kage ']

2.7 基本数学运算 : 加 、 减 、 乘 、 除
Python 中 基 本 的 数 学 运算 采 用 传 统 的 数 学运 算 符 : + ( 加 ) 、 - ( 减 ) 、 * ( 乘 ) 、 I ( 除 )

运算 。 下 面 行代码包括所有这些运算符 。

>>>3 . 0 9+2 . 1 * 5 . 2 - 3 / 0 . 5 6
8 . 652857142857144


如 果 意外地输 入除 号 两 次 ( // ) , 会 得 到 个奇怪的 结 果 。 双斜杠II代表整 数 除 法 , 运算

结 果 是给 出 个 比商 数 小 的 最 大 整 数 。 7 除 以 3 的 结 果 为 2 . 3 3 , 2 是 比 2 . 3 3 小 的 最大整
数。 例如 :

>>>7 . / 3
2 . 3333333333333335

在 Python 2 .x 版 本 下 , 7 / 3 可 能 是 2 , 而 不 是 2 . 3 3 3 。 因 此 , 我 们 必 须 小心 。 在金融
计 算 中 较 少使用 整 数 除法 。 为 了 避 免 整 数 除 法 , 可 以 使用 7 . / 2 或 7 / 2 . , 即 这两 个数 中 至

少有 个 是真 正 的 浮 点 数 。

>»7 / / 3
2 2.8 幕 函 数 、 取整和余数 函 数 19

以下代码显示, n/lm 等价于取整 函数 i n t ( n / m ) 。

>>>x = 7 . / 3
>>>x
2 . 3333333333333335
>>>i n t ( x )
2

2.8 幕 函 数 、 取整和余数 函 数

使用幕函数来计算 FV=P V( l +Rf 。 取整 函数给 出 比输入参数值小的最大整数 。 余数是


整数除法后剩下的值 。 给定一 个正的折现率, 未来现金流量的现值总 是 比其相应的未来值
要 小 。 下面公式给出 当前值和未来值之间的关系 。

FV
PV = ( 2- 3 )
(l + RY

在这个公式中 , P V 为现值 , FV 是 未来值 , R 为每期的折现率 , n 是 周 期数 。 假设在两


年后将获得 1 00美元 , 年贴现率为 1 0%, 今天的价值是 多 少 ?

»> 1 0 0 / ( 1 +0 . 1 ) * * 2
8 2 . 6 4 4 62 8 0 9 9 1 7 3 5 4

这里, **用来计算幕 函数。 %运算符用于计算余数。 下 面的例子显示这些运算符的结 果 。

»>17/4 # norma l divi s io n


4 . 25
>»17//4 # s ave as f l o o r ( 17 / 4 )
4
>» 1 7 % 4 # find out the r emainder
1

假设第 1 笔现金流发生在第 9 年年底 , 之后每年年底获得 1 0美元, 直 到 永 远 , 如 果 折


现率为每年 8 %, 这个永久年金的现值是 多 少 ? 可以结合公式 ( 2 - 1 ) 和 ( 2-3 ) 来回 答这个
问题 。

1 C
P V ( 永久年金 , 第1 笔现金流发生m周期末 ) = (2-4 )
(l + Rf- I R
20 第2章 用 Python 完 成 普 通 计 算 器 的 功 能

在这个公式中 , C 是每个周 期定额的现金支 付 , R 是每周期的折现率 , 第 1 笔现金的


支付发生在 第 m 个周期的期末 。 当 m 取值为 1 时 , 公式 ( 2-4 ) 等 同 于 公式 ( 2 - 1 ) 。 以下代
码运用公式 ( 2-4 ) 来得到现值 67.5 3 美元。

» > 1 0 / 0 . 0 8 / ( 1 + 0 . 0 8 ) * * ( 9- 1 )
67 . 5 3 3 6 1 0 5 62 7 4 696

2.9 一个真正 的 幕 函 数

如果 今天存入 1 00 美元 , 年利 率为 1 0% , 该存款 一 年后值多少 ? 如果 FV 代表未来值 ,


PV 代表现值 , R 为年度利 率 , n 是年数 , 可以得到以下的公式 。

FV=PV( l +Rt ( 2 -5 )

需要注意的是变揽 R 和 n 对应相 同的周 期, 也 就 是 说 , 如果 R 是 月有效利 率 , n 必 须


是 月的数 目 。 如果 R 是年有效利 率 , n 必 须 是 年的数 目 。 以下代码计算未来值 。

>>>pv= l O O
>>>r = O . l
>>>n= l
>>>pv* ( l + r ) * * n
ll0 . 00000000000001

这 里 , 两个乘法 符 号 * * 代 表 幕 函数 。 事实上 , Python 有计算 f 的 内 置函 数 p ow ( ) ,


例 如:

>>>pow ( 2 , 3 )
8
>> > l O O * pow ( ( l + O . 1 ) , 1 )
110 . 00000000000001

在上面的例子中 , 这个幕 函数 pow ( x , y ) 有两个输入 参数 , 这个情况下 , 它等效千 x* *y 。


实际 上 , 该 函 数 可 以有 第 3 个 输 入 参数 。 在 上 面 的 例 子 中 , pow ( ( 1 + 0 . 1 ) , 1 ) 与

pow ( l + 0 . 1 , 1 ) 样 , 包含 1 + 0 . 1 的括号 是 没有必要的 , 但 能帮助 函数表达式更清楚 。

要了解有关 函数的更多信息 , 可以使用 help ( ) 找到此 函数的详细 信 息 , 请参考下面


的输 出 。

>>>he l p (pow)
Help on bu i l t - i n func t i on pow i n modul e bu i l 七 ins :
2. 10 选择 合 适 的 数 值 精度 21

pow ( . . . )
pow ( x , y [ , z ] ) -> number
With two a rguments , equivalent to x * * y . With three ar guments ,
equival en t to ( x * * y ) % z , but may be mor e e f f i c i en t ( e . g . for l ong s ) .

根据上述的 内 容 , 可 以 这 样 使用 该 函 数 。

>>>pow ( 3 , 1 0 , 4 )
1
>>>3 * * 1 0 % 4
1
>> > 3 * * 1 0
59049
>»5 9 0 4 9 % 4
1

Python 所谓 的 LEGB 规 则 与 局 部 变量 和 全 局 变 量 有关 。 该 规 则 如 表 2- 1 所示 。

勹::
表 2-1

变 益 的 变益
二 二二二二

:二二
G 全局 的 , 是指那 些在模块 的 顶 部 定 义 的 变 量 , 或在 函 数 中 ( def) 定 义成全局变量 的 变盘

B I 内 置 的 , 是指在 内 置模块中 固 定 的 名 词 , 如 open 、 range 和 SyntaxError

2. 1 0 选择合 适 的 数值精度

Python 的 默 认 精 度 为 1 6 位 小 数 , 例 如 :

>>>7 /3 .
2 . 3333333333333335

对 大 多 数 与 金 融 有 关 的 问 题或研究这样 的 精 度 足够 高 了 , 可 以 使用 round ( ) 函 数 来 改
变精度 。

>> >payme n t l = 3 / 7 .
>>>payment l
0 . 42857142857142855
>>>payment2=r ound ( payment l , 5 )
22 第2章 用 Python 完 成 普 通 计 算 器 的 功 能

>>>payment2
0 . 42857

假 设 payme n t l 和 payme n t 2 的 单位 是百 万 。 如 果应用 round ( ) 函 数只 保 留两位 小 数 ,



可能会导致 巨 大 的 差异 。 如 果 以 个美元为 单位, 确 切 的 支付等于 42857 1 美元 。 然 而 , 如
果 以 百万美元为单位 , 并且保 留 小 数 点 后 两 位 的 精 度 , 将得到 43 万 , 相差 1 429 美元。

>>>payment l * l 0 * * 6
42857 1 . 4285714285
>>>payment2 =round (paymen 七 1 , 2 )
>>>payme nt2
0 . 43
>>>paymen t2 * 1 0 * * 6
430000 . 0

2. 1 1 找 出 某个 内 置 函 数 的 详细信息

要 了 解某 个 数 学 函 数 的 详 细 信 息 , 可 以 使 用 h e l p ( ) 函 数 , 比 如 help ( r oun d ) ,
如 以 下代码所 示 。

>>>help ( round)
Help on buil 七 - i n function round i n modu le buil tins :
round ( . . . )
round ( numbe r [ , ndi g i t s ] ) -> number
Round a number to a given precis ion in decimal
digits ( de fault O digit s ) . This returns an int when
cal le d with one argument , othe rwi se the s ame t ype as
the numbe r . ndigits may be negative .

2. 1 2 列 出 所有 内 置 函 数

为 了 找 出 所 有 内 置 函 数 , 采 取 以 下 两个 步 骤 。 首 先 , 我们用 d i r ( ) 列 出 代表所有 内 置
函 数 的 默 认名 称 , 即 bu 辽 t i n s 。 注 意该名 称 有 两 个 下 划 线 为 前缀和 另 外两 个 下 划 线
为后缀。

>» di r ( )
[ ' bui l t i ns ' doc ', ' name I pack age I ' I X I l

然 后 , 输入 di r ( bu 旦 巨 n s ) , 第 1 行 和 最 后 几行 的输 出 结 果 如 下 。
2. 1 3 导 入 数 学模 块 23

>>>di r ( bu i l t in s )
[ ' Ar ithme t i c E r ror ' , ' As s e r t i onError ' , ' At tr ibuteEr r o r ' ,
' Bas eExcep t i o n ' , ' B lockingIOError ' , ' BrokenPipeE r ror ' ,
' Bu f fe rE r r o r ' , ' BytesWarning ' , ' Chi ldProc e s s E r ro r ' ,

' range ' , ' repr ' , ' reve r s ed ' , ' round ' , ' s e t ' , ' s etattr ' ,
' s lice ' , ' s or 七 ed ' r I S 七 aticme 七 hod ' , ' str ' , ' s um ' ,
' s upe r ' , ' tupl e ' , ' t yp e ' , ' var s ' , ' z ip ' ]

2. 1 3 导入数学模块

使 用 金 融 市 场 的 实 际数据解答 许 多 问 题 , 比 如 从雅虎财经 网 站 下 载 数据 , 构 建 最 佳 的

投 资 组 合 , 估计个股或股票组合 的波动 率 , 找 出 最 佳 组合 。 针对每 个 问 题 , 有关专家开
发 了 相 应 的模 块 。 必 须 将 其 导 入 Python , 然 后 才 能 使用 它 。 例 如 , 可 以 用 import math 导 入

常 用 的 数 学 函 数 。 下 面 的代码用来计算 个数值的平方根。

>>>import math
>>>math . s qrt ( 3 )
l . 732050807568772

为 了 找 出 数 学模块 中 包含 的 所有 函 数 , 再 次 调 用 d江 ( ) 函 数如 下 。

>>>import math
>>>di r (math )
[ ' doc ' , ' name ' pac kage ' acos ' , ' a cosh ' , ' a s in ' , ' as i nh ' ,
' a tan ' , ' a 七 an2 ' , ' a tanh ' , ' c e i l ' , ' copys i gn ' , ' cos ' , ' cos h ' , ' degree s ' , ' e ' ,
' e rf ' , ' e rfc ' , ' exp ' , ' expm l ' , ' fabs ' , ' fac 七 oria l ' , ' f l oo r ' , ' fmod ' ,
' frexp ' , ' fsum ' , ' gamma ' , ' h ypot ' , ' i s inf ' , ' i snan ' , ' l dexp ' , ' l gamma ' ,
' '
' l og ' , ' log l O ' , ' l o g lp ' , ' modf ' , ' pi ' , ' pow ' , ' radians ' , ' s in ' , ' s .1.nh ' ,
' sqrt ' , ' tan ' , ' t anh ' , ' trunc ' )

为 使编程语句 更 加 简 洁 , 可 以给 math 模块取 一 个单个字母 的 名 字 。

>>>import ma th a s m
>>>m . sqrt ( S )
2 . 2 3 6067 9 7 7 4 9 9 7 9
24 第2章 用 Python 完 成 普 通 计 算 器 的 功 能

2. 1 4 冗 、 e 、 对数和指数 函 数
兀 C 3 . 1 4 1 59265 , 在 Python 程序中用 " pi " 表示) 和 e ( 2.7 1 828 ) 是数学的常量, 用以
下 代码显示它们的值。 第 1 个命令导入 math 模块。 现阶段, 初学者只 需要记住这些 命令,
暂时不需要了解它们的含义。 以后有 4 章内容 详 细 解释 模块的用 途。

> > > import math


> >>math . pi
3 . 141592653589793
> > >math . e
2 . 718281828459045
>>>math . exp ( 2 . 2 )
9 . 025013499434122
>>>math . l o g ( math . e ) # log ( ) i s a natural l o g func t i on
1.0
»>math . l o g l O ( l O ) # loglO ( )
1.0

只需输入 pi 或 e 就可以得到它们的值。 因为它们是保 留 的关键 字 , 请 不要用 它们作为


变量 名。

2. 1 5 import math 与 from math impo们的 区别


使用 f r om math imp o r t * 可以使程序更简单 。 以 s q r t ( )函数为例。 如果使 用
i mp o r t ma t h , 就必须用 math . s qrt ( 2 ) 。 如果使用 fr om math import * , 就只需
要用 s q r t ( 2 ) 。

>>> from math imper 七 *

>>>dir ( )

[' builtins ' doc ' , ' name ' , ' packag e ' , ' acos ' , ' acosh ' ,
' a s in ' , ' a s i nh ' , ' a tan ' , ' atan2 ' , ' atanh ' , ' ce i l ' , ' c opys i gn ' , ' co s ' ,
' cos h ' , ' degree s ' , ' e ' , ' e rf ' , ' er f c ' , ' exp � , ' e xprn l ' , ' fabs ' , ' factor i al ' ,
' f loor ' , ' fmod ' , ' frexp ' , ' f sum ' , ' gamma ' , ' h ypot ' , ' i s in f ' , ' i snan ' ,
' l dexp ' , ' l gamma ' , ' l og ' , ' logl O ' , ' l oglp ' , ' rnodf ' , ' pi ' , ' pow ' , ' radians ' ,
' s in ' , ' s i nh ' , ' s qr 七 ' , ' t an ' , ' t anh ' , ' 七 rune ' ]

也就是说, 可以直接调 用这些函数或保 留 值, 如 pi 和 e 。 使用 math . p i 反而是错误


2. 1 6 一些常用 的 函 数 25

的。 例如:

>>>pi
3 . 1 4 1 5 92 65 3 5 8 97 9 3
>>>math . pi
Tr aceback (most recent call l a s 七 ) :
F i l e " <pyshel l # 2 5 > " , l i ne 1 , i n <modu l e >
math . pi
NameE r r o r : name ' math ' i s not de f i ned

这样处理的一 个优点是使编程稍微容 易 一 些 , 因为这些 数学函数都可以直接调用。 如


果给 e或 ip 赋值, 它的值将改变。 这里需要小心对待。

>> pi
3 . 1 4 15 9 2 6 5 3 5 8 97 93
>>>p i = l O
>>>pi
10

可以从 某 个模块, 如 math 模块, 导入若干指定的


函数。 在导入前:

>>>dir ( )
[ ' bu i l t ins ' do c ', ' name ' pa ckage 'l
>>>

在导入后:

>>> f rom ma 七 h import sqrt , l og


>>>dir ( )
[ ' builtins ', ' doc ' name ', ' package ', , log ' , ' sqr 七 l
I

2. 1 6 一些常 用 的 函 数

函数: p r i n t ( ) 、 t ype ( ) 、 uppe r ( ) 、 s t r i p ( )


这 一 节 将简要讨论几 个经常 使用的
和下 划线_。 此外, 还将学习如何合并两 个字符 串 以及幕函数 pow ( ) 。

2.16. 1 print()函数
有时, 需要在屏幕上显示一 些 内 容 。 一
种方法是应用 p r i nt ( 函
) 数, 例如:
26 第2章 用 Python 完 成 普 通 计 算 器 的 功 能

>>> import math


>>>print ( ' pi = ' , math . p i )
pi= 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3

2.16.2 type()函数
在 Python 中, 七 ype ( ) 函数告 诉 我们一 个变量的类型, 例如:

>>>pv= l 0 0 . 2 3
>>> typ e ( pv)
< c l a s s ' f l oat ' >
>>>n = l O
>>> type ( n )
< c l a s s ' i nt ' >
>>>

从这些 结果, 我们知道变量 pv 的类型是浮点数, n 为整数类型 。 整数和浮点数是金融


计算中最常用的两 种类型。 本书还会讨论其他数据类 型 。

2.16.3 下划线_
在交互 模 式中, 下划线符号 " _ " 代表前面最后一 个表达式的结果。

>>>x = l . 5 6
>>> y = S . 7 7
>>>x+y
7 . 33000000000000000001
>>>9+
1 6 . 32999999999999998
>>>r ound ( _ , 1 )
16. 3

2.16.4 结合两个字符串
可以通过 多种方式使用字符 串 。 有以下两 种方式为字符变量赋值。

>>>x = ' Th上 5 is I


>>>y = " a great j ob ! "

第 l 行使用单引 号, 第 2 行采用双 引 号 。 把它们结合的结果如下 。

>>>x+y
2. 1 6 一些常用 的 函 数 27

' This is a great j ob ! '

2. 16.5 将小写字符变成大写字符的函数 : upper()

uppe r ( ) 函数将 整个字符 串 全部转换为大写字母。

>>>x = ' This i s a sentence '


>>>x . upper ( )
' T HI S I S A SEN T ENCE '

请注意我们是 如何调 用 函数的。 这是我们第 一 次看到这样调 用 函数 : 变量名. 函数名。


可以使用 s t r ip ( ) 函数删 除 字 符 串 开头和结尾的空格 , 例 如 :

>>>x = " Hel l o "


>>>y=x . st rip ( )
>>>y
, He l l o '
>>>

可以把赋值操作和 s t r i p ( ) 函数连起来用。

> > > z = " He l l o " . s t rip ( )

可以用 d i r ( ' ' ) 命令列 出 所有的字 符 串 函数。

>>>dir ( ' ' ) #- l i s t a l l s t r ing functions

此命令的输 出 结 果 如下。

>>>dir ( I I )
[ ' add ' , ' c l a s s ' , ' contains ' , ' de l a 七 t r ' , ' doc ' ,
' eq ' , ' f ormat ' , ' ge ' , ' getattribute ' , ' get i tem ' ,
. .
' getnewargs ' , ' ge t s l ice ' , ' gt ' , ' ,hash . ' , ' in 工 t I I
le ' , ' l en ' , ' 1 t ' , ' mod ' , ' mul " ' , ' ne ' , ' ' new '
reduce ' , ' reduce e x ' , ' repr rmod ' , ' rmul
setattr ' ,.. s 1. ze o f. . ' , ' s t r ' , . ,subclas shook ,
' _formatter_fiel d_name_spl i t ' , ' _formatter_parser ' , ' capi t a l i z e ' ,
' c ente r ' , ' coun 七 ' , ' dec ode ' , ' encode ' , ' endswith ' , ' expand tab s ' , ' f ind ' ,
' format ' , ' i nde x ' , ' i s a l num ' , ' i s a lpha ' , ' i sdig it ' , ' i s l owe r ' , ' is space ' ,
, i s t i t l e ' , ' i s upper ' , ' j o in ' , ' l j us t ' , ' l owe r ' , ' l s 七 r ip ' , ' parti t i on ' ,
' r eplac e ' , ' r f i nd ' , ' r i ndex ' , ' r j ust ' , ' rparti tion ' , ' r spli t ' , ' rs 七 ri p ' ,
I spl i t I ' I sp l i 七 l i nes ' , ' s tarts wi th ' , ' strip ' , ' swapcase ' , ' t i t l e ' ,
28 第2章 用 Python 完 成 普 通 计 算 器 的 功 能

, 七 rans l a te ' , ' uppe r ' , ' zfill ' )


>>>

可以使用下面的代码了解某 个字符 串函数的具体信息。

>>>help ( ' ' . uppe r )

有 关内置函数 uppe r ( ) 的在线帮助内容 显示如下 。

upper ( . . . )
S . uppe r ( ) - > s t r i n g
Re七urn a copy o f t h e st r i n g S conve r七ed to upp e r ca s e .

下面是使用另 一 个内置函数 cap i t a 巨 z e ( ) 的例子 。

>>>help ( ' ' . capital i z e )

有 关内置函数 cap i t a 让 z e ( ) 的在线 帮助内容 显示如下 。

capi ta l i z e ( . . . )
S . cap i t a l i z e ( ) - > s 七 ri n g
Re七urn a copy o f 七he s 七 r ing S with o n l y i t s f i r s t character
cap i ta l i zed .
>>>

2. 1 7 元组数据类型

元组是 Pyth on 的一种数据 类型。 一 个元组类型的


变量 可以包含多种数据 类型, 如整数、
浮 点 数、 字 符 串 , 甚至是另 外 一 个元组。 所有 数据项 都包含在 一 对圆括号中。

>>>x = ( ' John ' , 2 1 )


>>>x
( ' John ' , 2 1 )

可以使用 len ( )函 数找出 一 个变量中包含多 少数据项 。 与 C++语言 类似, 元组的下 标


从 0 开始 。 如果 一 个元组变量包含 1 0 个数据项 , 它们的 下 标 将从 0� 9 。

>>>x= ( ' John ' , 2 1 )


>>>len ( x )
2
>>>x [ O )
2. 1 8 小结 29

' J ohn '


»>type ( x [ l ] )
< c l a s s ' i n七 ' >

下面的命令定义 一个没有数据的 元组变量 和只有 一个数据项的元组变量 。

> > > z= ( )


>>>type ( z )
< c l a s s ' t upl e ' >
>>>y= ( 1 , ) # genera七e one i tem tup l e
> » t ype ( y )
< c l a s s ' tuple ' >
>»x= ( 1 ) # i s x a tup l e ?

以下 代码显 示元组最重要的特 征之 一 : 无法修改 一个元组的值, 即 元组是不可改变的。


下 一 章将讨论另 一种数据 类型: 列表。 可以修改 一个列 表的值 。

> > > i nves 七ment= ( ' NPV ' , 1 0 0 , ' R= ' , 0 . 0 8 , ' ye ar ' , 1 0 )
>>> 1nve s tment ( l ]
100
> > > i nvestment ( l ] =3 4 5

Traceback ( mo s t recent c a l l l as t ) :
F i l e " <pyshe l l # 3 > " , l ine 1 , i n <modu le>
inve s trnent [ l ] = 3 4 5
TypeError : ' tuple ' obj ect does no七 suppor七 i t em a s s i gnmen t

可以使用元组类型将 John 和 2 1 分别 作为姓 名和年龄分配给 一个元组 类型变量 X, 然后


打 印 " My n ame i s John and 2 1 y e a r - o l d " 。 注意 % d 表示打 印 整数 类型的格式 。 后
面的章节会介绍用来打 印 的其他数据 类型。

>>>x= ( ' John ' , 2 1 )


>>>print ( ' My n ame i s % s and % d year -o l d ' % x )
My name i s John and 2 1 year-old

2. 1 8 小结

本章介绍了 一些 基本概念和 常用的 Python 内置函数, 如赋值、 数值精度、 加、 减、 乘、


除、幕函数以及平方根函数。 演 示了如何使用 Python 作为一个普通的计算器来解决与金融相
关的计算问题, 比如计算一个未来现金流的现值、 一个现金流的未来价值 、 永久年金的现值
30 第 2章 用 Python 完 成 普 通 计 算 器 的 功 能

以及增长型永久年金的现值等。 讨论了 d 江 ( ) 、 t ype ( ) 、 floor ( ) 、 round ( ) 和 h elp ( )



函数, 展示了如何列 出 Pyth on 的所有内置函数, 以及如何获得一 个特定函数的在线帮助。
基千本章及前一 章的学习, 将在下 一 章介绍如何使用 Pyth on 编写 一 个金融计算器。

练习题

l . 展示
变量是否存在和显示它们的值之间有什 么 差异 ?

2 . 如何得到某 个指 定函数, 如 pr i nt ( ) 的详细 信息 ?

3. 内置函数的定义是什么 ?
4 . 元组是什么 ?

5. 如何生成只含有 一 项的元组? 下 列 生成只含有 一 项的元组的方式有什么不对?

>>>abc = ( 11 John 11 )

6 . 如何改变 一 个元组的值 ?

7. pow ( ) 是不是 一 个内置函数? 如何使用它?


8. 如何找到所有内置函数? 有多少 个内置函数 ?

9 . 应该使用哪 个 Pyth on函数来计算 � ?


10. 假设 一 个永续年金的现值是 1 24 美元和每年的现金流是 50 美元, 相应的
年度折现
率是多少 ?

1 1 . 基于前一 个问题的答案, 相应的季度折现率是多少 ?

1 2 . 增长型永续年金的定义是: 现金流量 按 固 定 的增长率逐年增长直到永远 。 有以下


公式:
C
PV (增长型永续年金) = ——­
R-g

这里, PV为现值, C 是第一 个周 期末的现金流, , g 是增长率, R 为折现率 。 如果第 1


个现金流为 12.50 美元, 年增长率为 2.5% , 而年折现率是8. 5% 。 这 一 增长型永续年金的现
值等于多少 ?

13. 对于 n 天股票 回报率的方差, 有以下 公式:


练习题 31

2 2
<Yn-day <Yn-day = na-daily

这里, a1叫Y a如 ly 为 日 收益的方差, adaily 为 日 收 益的标准方 差(波 动 率 )。 如果一 只 股


票的 日 回报率的标准方差等于 0.2 , 它的 1 0 天 回报率的标准方 差是多 少 ?
1 4 . 我们期望 5年 后有 25 000 美元。 如果每年的存款 利 率 是 4.5% , 今 天 需 要存款
多少?

1 5 . 如何把 This is great ! 转换成所有都是大 写字母 ?

1 6 . 如何限制函数的输出值以美分为单位, 比如将 2.567 四舍五入至 2.5 7 ?

1 7 . 符号/和II有何区别 ?

1 8 . 班里有 4 1 名学生 。 如果 3 个学生组成 一 个作业小组, 会有多 少组? 有几位学生 不


属 于任何一 个三人小组? 如果每组有 7 个学生, 答案又是什 么 ?

1 9 . lowe r ( ) 是不是 一 个内置函数 ? 如何获得它的在线帮助 ?

20 . 用 round ( )函数解释如下 结果。

>>> x = S . 5 6 6
>>> round ( x , 2 )

>>>
5 . 57

21 . 当增长速度高于 折现率 ( g>r)时, 增长型永续年金的现值是多 少 ?

C
PV(增长型永 续年金) =
R-g
第3章
用 Python 编 写 一 个金融计算器

本章介绍如何编写 一 些简单的 Python函数来完成常见 的金融计算, 如计算未来付款的


现值、年金的现值以及按揭的月供 。 还介绍如何将 20 多个
函数集合在 一起, 用 Python 实
现一 个专业金融计算器的功能。 本章主要内容 如下。

• 编写不需要保存的 Python函数

• 缩进格式在 Python 编程中的重要性

• 输 入函数参数值的 3 种方式及它们的预设值

• 利用 d江 ( ) 检查刚完成的
函数是否存在

• 保存 自 写 的 pv_f ( )函数

• 利用 import ( ) 在 Python 编辑器里激活函数


• 在调试过程中使用 Python 编辑器激活函数

• 生成 自 制的模块

• 两 种 注释方法

• if (函
) 数

• 计算年金

• 利率换算和连续复利利率

• 数据 类型: list

• 净现值法则 (net present value , NPV)、 投资 回 收期法则 ( payback) 和内部收益率


法则 ( internal rate of return, IRR)
3 .2 函 数 的输入参数及它 们 的预设值 33

• 显示在某 个 目 录下的指定文件

• 用 Pyth on 编写 一 个金融计算器

. 将 我们的 目 录加到 Python 的路径上

3. 1 编 写 不 需要保存的 Python 函 数

从 编写 一 个最
简单的 Pyth on函数开始 。 以下 是计算未来现金的现值的数学公式 。

FV
PV = C 3- l )
( 1 + R) "

PV 代表现值, FV 代表未来获取的现金量 , R 代表每期折现率 , n 代表周 期的数 目 。 打


开 Pyth on 软件, 输入如下 两行命令, 然后连续敲击回车键两次回到 Pyth on 的提示符 。

>>> de f pv_f ( fv , r , n ) :
r e t u rn fv/ ( l + r ) * * n
>>>

def 是定义函数的关键 词 。 函数名是 p v_f, 由用户 自 己选取。 括号里是函数的输入 参


数。 注意在输 入 冒 号 和 回 车 后 , 下 一 行会 自 动缩进。 » > pv一嘈
1
现在, 就开始 使用这个函数 。 输入
函数名和 左括号 后, [Argument s

软件 自 动 提示函数需要的参数 , 如图 3 - 1 所示。 这 个 pv一于 ( 于v , r- , n )


非常有用的提示在 Python 2. 7版本之前是没有的。 图 3- 1
以下是输入 参数值 后得到的输出结果。

>» pv_f ( l 0 0 , 0 . 1 , 1 )
90 . 9090909090909
>>> pv_f ( B 0 , 0 . 0 5 , 6 )
5 9 . 697231730930 1 9

3.2 函 数 的输入 参 数及它们 的预设值

有时候给函数的输入参数预设初值, 更加便于调用函数 。 上 一章 编写了 一 个显示 目录


内容 的函数 d i r 2 ( ) , 可以把经常访问的 目 录作为预设值写 入程序, 使得每 次调用这个程
序时能够 自 动读取该 目 录的内容 。 以下代码预设输入目 录为 c : \python 3 2 :
34 第3章 用 Python 编 写 一 个 金 融 计 算 器

de f dir2 ( path= " c : \p ython32 " ) :


from o s import l i stdir
print ( l i s 七 dir ( path) )

如 果 函 数 的 输 入 参 数 没 有 预 设 值 , 调 用 函 数 时 就 需 要 提 供 参 数值 , 否 则 会得到 出 错 的
信息 。

3.3 缩进格式在 Python 编 程 中 至关重要

一 一
缩进格式在 Python 语 言 中 非 常 重 要 。 以 下 是 个用 R 语言编 写 的 计算现值 的 函 数 ,

对 花括 弧定 义 了 该 函 数 的 主体语 句 , 每 行 语 句 是 否 有 缩进 并 不 重 要 。

pv_f <- func 七 ion ( fv , r , n ) { # this i s an R program


pv< - fv* ( l+ r ) " ( -n )
pv


Python 函 数 用 缩 进来定 义 函 数 的 主 体 , 由 具 有 同 样大 小 缩进 的 语 句 构 成 同 个函数。

def pv_f ( fv , r , n ) :
pv = fv/ ( l + r ) * * n
return pv

可 以用 3 种 方 式输入 函 数 的 参 数 值 。

C l ) 如 上 例 所 示 , 调 用 函 数 p v_f ( l 0 0 , 0 . 1 , 1 ) 直 接输入 3 个 参 数 值 1 0 0 、 0 . 1 和
1 。 依 据 3 个 参 数 出 现 的 顺序可 以 判 定 1 0 0 是 未 来 现 金 董 , 0 . 1 是 每期 折现率 , l 是 未 来
多少期。

( 2 ) 采用 参 数 的 关 键词 , 不 需 要 依 据 固 定 的顺序输入参数 , 如 下 面 的 例 子所 示 。 这种
方 式 的 好 处 是避 免 因 为 忘 记参数顺 序 而 带 来 的 错 误 , 这 在 使 用 由 不 同 的 开发人 员 编 写 的 函
数 时 尤其有用 。

> >>pv f ( r = O . 1 , fv= l O O , n=l )


90 . 9090909090909
>>>pv f ( n=l , fv=l O O , r=0 . 1 )
90 . 9090909090909

( 3 ) 混合使用 前 两 种 方 式 。
3.5 在 Python 编辑器里 定义 函 数 35

>>>pv=pv_f ( 1 0 0 , r=O . 1 , n=l )


>>>pv2 =pv_f ( 1 0 0 , n = l , r = 0 . 1 )

注意在第 3 种 方 式中, 首 先 按参数 出现的顺序, 然后 由 关键词 决定相应参数的数值。

3.4 检查 自 己编 写 的 函 数是否存在

可以用 d i r ( ) 函数检查编写的 pv_ f ( ) 函数是否存在 。

»>di r ( )
[ ' bui ltins ' ''
', ' doc ', ' name ', ' package ' , ' pv . f ' ]
,

分两步保存函数。

I . 单击 " FilelNew Window " 或按 Ctrl+N 组合键, 然后输入以下 两 行代码。 注意在 第


1 行后按 回 车键, 第 2 行会自动缩进 。 在编写 复杂 函数时, 缩进的作用非常关键, 在下文
会进一 步讲解。

def pv_f ( fv , r , n ) :
return fv/ ( l + r ) * * n

2 . 单击 " FilelSave " 或者按 Ctrl+S 组合键, 可以保存以上两行代码于 一个文件中 。 给


文件命名为 te s t O l . py 。 如果 安装的是 Python 3.3 版本, 默认目录为 c:\python33 。 如果 安
装的是 Python 3 .2 版本, 默认目录为 c:\python32。

保存函数的文件名 由 用户 选择 。 一个文件中 可以包含若 干函数。 可以用两种方式调用


已经保存的函数,分别在第 3.5 和 3 .6 节介绍。 可以用多种文本编 辑器来编 写 Python 程序,
如 Python 自带的编 辑器、 NotePad 或 Word。 使用 Word 时, 需要把生成的程序以文本文件
格式.txt 保存。 相比而言,Python 自带的编辑器应 当 是首选, 因为它提供按语法自动缩进和
彩色字体等辅助 功 能 。

3.5 在 Python 编辑器里定义 函 数


保存以上两行代码之后, 单击 " RunlRun Module F5 ", 程序显示以下 内 容 。

>>>=========== RESTART - -----------------


36 第3章 用 Python 编 写 一 个金 融 计 算 器

如 果 在保存代码之 前 单 击 Run 按钮 , 软件会提醒我们 保存代码 。 用 d i r ( ) 命令检查


pv_f ( ) 函 数 是否 保 留 在 内 存 里 。

>>>dir ( )

[ ' bu i l t ins ', ' doc ', ' file ', ' l o ade r ', ' n ame ',
, package ' , 1 PV fI ]

>>>

确 认 pv_f() 函 数 已经在 内 存 里 以 后 , 可 以 调 用 该 函 数进行计 算 。

>>> pv_f ( l 0 0 , 0 . 1 , 1 )
90 . 9 0 9 0 9 0 9 0 9 0 9 0 9

如 前 所述 , 可 以 用 关 键 词 的方 式来输入参数值 。 退 出 Python 软 件 然 后 重 新打 开 , pv_ f ( )


函 数 就不在 内 存里 了 。

3.6 利 用 import() 在 Python 编辑器里激活 自 己编 写 的 函 数



在上 章 中 , 我们 学 习 了 如何使用 imp o r t math 命令来激活 math 模 块 , 从 而 可 以
调 用 该模块包含 的 函 数 。 亦 可 以用 imp o r t 命 令 来 调 用 自 己编 写 的 函 数 。 之前 把 函 数 pv—f ( )
保存在默认 目 录( c : \ P ytho n 3 3 \ ) 下 名 为 t e s t O l . p y 的 文 件里 。 需 要 用 import t e s t O l
命令来使用 它 。

>>> import t e s t O l
» > dir ( )
[ ' buil t i n s ' , ' doc ' , ' file ', ' l oader ', ' name ',
' package ' , ' t e s 七 0 1 ' J
>>> t e s t O l . pv_f ( l 0 0 , 0 . 1 , 1 )
90 . 9090909090909

第 2 章提到 匡 s t O l 被视作 一 个模块 , 必 须 用 t e s t O l . pv_f ( ) 来调用 函 数 , 而 不 是


pv_ f ( ) 。 以 下 的代码 比较 math 模块和 t e s t O l 模 块 。 其 中 用 到 的 c e i l ( ) 函 数给 出 大 于
参 数 值 的 最 小整 数 。

>>> import math


>>> math . c e i l ( 3 . 5 )
4.0
>>> imp o r t t e s t O l
3.8 调 用 pv_fO 函 数 的 两 种 方 法 37

>>> 七est O l . pv_f ( l 0 0 , 0 . 1 , 1 )


90 . 9 0 9 0 9 0 9 0 9 0 9 0 9

3.7 使用 Python 编辑器调试程序


上 面 两 节 讨 论 了 两 种 不 同 的 调 用 函 数 的 方法 : 通 过 Python 编辑器和 使 用 imp o r t 命 令 。
通 常 , 用 户 可 以任选其 一 。 不 过 , 如 果 需 要 调 试 程序 , 应 当 使 用 Python 编 辑 器 。 若 使 用 第
2 种方式, 函 数不能 自 动 更 新 。

以 下 的 函 数语 句 有 一 个 明 显 的 错 误 : 第 1 行 以 小 写 字 母 r 代表输入 参 数 , 但第 2 行却
用 大 写字母 R 来 使 用 该 参 数 。

def pv_f ( fv , r , n ) :
return fv/ ( l+ R ) * * n # a t ypo o f r

假设 把它保存在 目 录 C:\Python33 下 的 文 件 t e s t 0 2 . p y 里 。 使用 from test02 import *


调 用 该 函 数 , 会得到 出 错 信 息 :

> > > from t e s t 0 2 import *


>>> pv_f ( l 0 0 , 0 . 1 , 1 )
T raceback (mos七 recent ca l l l a s 七 ) :
F i l e " <pyshe l l # l > " , l ine 1 , in <modu l e >
pv_ f ( l 0 0 , 0 . 1 , 1 )
F i l e " . \ 七 e s t 0 2 . py " , l i ne 3 , i n pv_f
return fv/ ( l +R) * * n
NameE rror : g l obal name ' R ' is not defined

修 改 这 个 错 误 后 重 新 保 存 文 件 , 再 次 使 用 这两行命令 f rom t e s t O l imp o r t * 和


pv_ f ( 1 0 0 , 0 . 1 , 1 ) , 错误信息仍然 出 现 。 一 定 要 退 出 Python 软件然 后重新打 开 , 才 可 以
调用修改后 的 函 数 , 这增加 了 调 试 函 数 的 困难 。

3.8 调 用 pv_f() 函 数 的 两 种 方 法
在使用包含在 t e s t O l . p y 中 的 pv_f ( ) 函 数 时 , 可 以 用 i mport t e s t O l 或 f rom
t e s t O l imp o r t * 。 显然 , 使 用 pv_ f ( ) 比 t e s t O l . pv_f ( ) 要 简 单得 多 。 例 如 :

> > > from math i mport *


> > > sqr 七 ( 3 . 5 )
38 第3 章 用 Python 编 写 一 个 金 融 计 算 器

l . 870828 69338 69707


> > > from tes t O l import *
> > > pv_f ( l 0 0 , 0 . 1 , 2 )
8 2 . 6 4 4 62 8 0 9 9 1 7 3 5 4

如果 知道 t e s t O l . py 文件里包含了哪些函数 , 就 可以直接调 用它们。

> > > f rom ma th import ce i l , sqrt , pi


>>> from t e s t O l import pv_f

Python 自有的命令 de l ( ) 可以删 除指定的 函数或变量。 例 如 :

> > > del pv_f


> > > dir ( )
( ' bui l tins ' , ' ' doc ', ' loader ', ' name ,
'
, pac kage ' ]

3.9 生成 自 制 的模块

Python 自带的 math 模块包括 20 多个 函数 , 如 pow ( ) 、 s in ( ) 和 c e i l ( ) 等。 我们希


望创建 一个金融计算模块 , 其中包括 20 多个常用的金融计算函数。 首 先试着把两个函数放
在 同 一 个模块里。 第 1 个 函数就是前面 讨论的 pv_f ( ) 函数。 第 2 个函数用来计算永久年

金的现值 。 永 久 年金在每 期的期末 支付等额的 一 笔现金, 其现值 如 下 :

C
PV(永 久 年金) = —
R
0-2 )

这里, c 代表每 一 期期末 支 付的等额现金, R 代表每 一期的折现率。 例 如, 在 未来每


年的年末收到 1 0 美元, 年化折现率是 1 0% , 那 么 这 一 永久年金的现值等于 1 00 美元, 由
I 0/0 . 1 得 出 。

为 了 编 写计算永久年金的 Python 函数, 单击 " File!New Window " 或者按 Ctrl+N 组合


键, 输入以下两个函数。

def pv_f ( fv, r , n ) :


return fv* ( l +r ) * * n

def pv_pe rpe 七 uit y ( c , r ) :


return c / r
3. 1 0 两种注释方法 39

然后, 单击 FilelSave , 文件命名为 fin 1 0l .py 。 使用命令 from fi n l O l import * ,


这两个函数就可以被调 用 了 , 代码 如下 。

>>>from finlOl import *


>>> pv_perpetuity ( l 0 0 , 0 . 1 ) \
1000 . 0

3. 1 0 两种 注释方法

注释使得复杂的程序明 了 易懂, 有利于理解程序的 内 在逻辑 。 一个复 杂的程序 如果 没


有 良 好的注释, 几个月后, 程序员 往往都不易看懂 自 己 编写的程序。 注 释 可以出 现在程序
的任意位置, 可以很 长 也 可以只有 一 句话, 但不会影响程序的运行 。 例 如在程序的开始,
可以通过注释记录程序作者、 主 要 功 能、 输入变 量、 输 出 结果 、 版本沿革和联系方式等。
Python 在运行中将自动忽略这些注释语句 。 可以利 用 Python 语言提供的多种方式添加注释 。

3.10.1 第 1 种注释方法
Python 语言 用符 号#来标识注释 。 每 一 行语句中#之后的字符就是注释, 不会对语 句 的
执行产生影 响 。

>>> fv= l O O # this 1. s comment


>>> fv
100

在 函数的定义中加入注释来说 明 函数的参数及用法 。

# present value of perpe 七 uity


de f pv_perpetuity ( c , r ) :
# c i s cash flow
# r i s dis count rate
return c / r

3.10.2 第 2 种注释方法
使用#号便于添加单行注释,但不利 于添加多行的注释 。 Python 语言的第 2 种注释方法
1 1 1 1 11
是用一对重复 3 次的双 引 号 ( 即 ) 来界定注释 。 下面用此方法为 pv_f ( ) 函数加入多行
的注释 。

de f pv_f ( fv , r , n ) :
40 第3章 用 Python 编 写 一 个 金 融 计 算 器

11 11 1 1

Obj ec t ive : est imate present value


fv : future value
r : d i s count p e r i odic rate
n : number o f p e r i ods
f o rmu l a : fv/ ( l + r ) * * n
e.g. ,
>> >pv f ( l 0 0 , 0 . 1 , 1 )
90 . 9090909090909
>>>pv f ( r = O . l , fv= l O O , n = l )
90 . 9090909090909
> >>pv_f ( n = l , fv= l O O , r = O . l )
90 . 9090909090909

return fv / ( l + r ) * * n

注释符号 内 的语 句 是 否对齐并不重要, 适 当的缩进 可以增 强注释的 可读性 。

3. 1 1 查找有关 pv_f() 函 数 的 信 息

以上例子在 pv_f() 函 数中加入 多 行注释 。 用户 可以利 用 help 命令来获取 该段注释 。 具


体操作 如 下 。

>» help ( pv_f )


Help on function pv_f i n modu l e f i n l O l :

pv_f ( fv , r , n )
Obj ect i ve : e s t imate p r e s e n t value
fv : future value
r : d i s count periodic rate
n : number of p e r i ods
f o rmu l a : f v / ( l + r ) * * n
e.g. /
>>>pv f ( l 0 0 , 0 . 1 , 1 )
90 . 9090909090909
> >>pv_f ( r=O . l , fv=l O O , n= l ) ,
90 . 9090909090909
>> >pv f ( n = l , fv= l O O , r=O . l )
90 . 9090909090909

请注意, 输入 h e l p ( pv_ f ) 时, 只有 de f 的第 1 行下的注释显 示 出 来, 之后的注释


3. 1 3 计算年金 41

不会显示。 这也意味着, 如果在注释 之前增加任何代码, 如 a= l , h e l p ( pv_ f ) 命令,


就不会显示任何内容 。

3. 1 2 条件 函 数 : if()

以下公式用于 计算增长型永久年金的现值 。

P V( 永久年金) = C 3-3)
R-g
C

这里, C 是在第 1 个周 期的结束出现的第 1 笔现金流, R 是每 期折现率, g 是恒定的每


期增长率。 第 2 个和第 3 个未来现金流分别为 c*( I + g)和 c*( l + g) 。 公式 C 3-3)成立的一 个
2

必要条件是, 折现率大于增长率, 即 R 应大 于 g。 如果 C 等于 10 美元, R 是 1 0%, g 是 12%,


这个永久年金的现值是什 么 呢 ? 答案-500 明 显是错误的。 可 以用 i f ( )函数判断出这些情
况, 然后 打 印 错误 提示, 而不是给出错误的答案 。

de f pv_growing_pe rpetu i t y ( c , r , g ) :
if ( r<g) :
p r i n 七 ( " r<g ! ! ! ! " )
el s e :
re 七 urn ( c / ( r - g ) )

可 以尝试用不 同的输入值来检验这个函数, 代码如下 。

>>>pv_g rowi ng_perpetui 七 y ( l 0 , 0 . 1 , 0 . 0 8 )


499. 9999999999999
>>>pv_g rowing_perpetuity ( l 0 , 0 . 1 , 0 . 1 2 )
r<g ! ! ! !

3. 1 3 计算年金

年金是指在未来 n 个时间段每 期等额的现金支 付 。 有 两 种 类型的


年金: 普通年金的现
金流发生在各个时期的结尾和前置 型年金的现金流发生在各个时期的开始 。 在下面的例子
中, 将在未来 7
年每年年底获得 100 美元。 假设第 1 次现金支付发生 在第 1 期的结尾, 估
计年金的现值和未来值的公式如下。
42 第3 章 用 Python 编 写 一 个 金 融 计 算器

PMT l
P V( annuity) = C 3-4 )
· [1 - ( l + R Y
R ]

PMT I
P V (annu 句1 due) = [1 - l + 1 + R) C 3-5)
· R ( R )" }

PMT
FV ( annU lty
. )= [ ( 1 + R) " - I ] ( 3-6 )
R

PMT
F V( annuity due) = [ O + R )" - l ] ( I + R ) C 3- 7)
R

这里 , P V 是现值, PMT 是每期的付款额, R 是每 期的折现率 , n 是周 期数 。 在上 述年


金的公式中, PMT、 R 和 n 的周 期应该是 一 致的, 也就是说, PMT、 R 和 n 应具有相同的
周 期频率 。 例如, 对于房 贷, PMT 为月支付, R 是 有效月利 率, n 是月数 。 如果年金有恒
定的增长率, 它的现值如下 :

P V(grow;ng annu;ty) 1-
=: :[ 严 (::;J ]
( 3-8 )

计 算 增长型年金的未来值的公式如下。
PMT
F V( growing
. annui.ty ) = [ (1 + R )" - (1 + g f C 3-9 )
R -g ]

3. 1 4 利 率换算
假设 A 银行提供按半年复利年利率为 5%的贷款, B银行提供按季复利年利 率为 5.1%
的贷款 。 为了获得较低的利率, 我们应该从 哪 家银行借钱 ? 这个例子涉及不 同利 率之间的
转换 。 首先看 看用给定年利 率 ( annual perc entage rate , APR ) 计算 有效
年利率 ( effective annual
rate , EAR ) 的公式 。

EA R = ( I + A= r 习 C 3-10)
R

在这里, m 是每年的复利频率。 例如, 如果


年利率为 5% , 每 半年复利, 其 等价有效年
利 率 将为 5.0625 个百分点。 从 两 家银行的报价, 我们 会选择 A 银行的报价, 因为借贷成本
(有效年利率) 比较低, 如下面的代码所示 。
3. 14 利 率换算 43

>>> ( 1 + 0 . 0 5 / 2 ) * * 2 - 1
0 . 05062499999999992
»> ( 1+0 . 0 5 1 / 4 ) * * 4 - 1
0 . 0 5 1 9 8 3 6 92 1 1 4 0 6 66 1 5

对于 抵 押 贷 款 的计算, 如果年利率为 5% , 按 月 复 利 计算, 月利 率 将 是 0 . 41667

( 0 . 0 5 / 12 )。 然而, 如果给定的利率是 5%每 半


年复利, 什 么 是相应的有效月利 率 ? 要将
一 个有效利率转换为另 一 个有效利率, 一 个年利率转换为另 一 个年利率, 必须执行以下步
骤 。 首先, 根据下列 公 式 计算给定年利 率 APR和复利频 率的单位 时间有效利 率 。

芯ti龙 = 竺
0-1 1 )

这里, Rm 是单位 时间有效利率, APR 是每年复利 m 次的单位时间利率, m 是每年的复


利 频 率 。 例如, 如果一 个给定的
年利率是 5 % , 每 半年复利, 每半年利 率为 2 . 5% 。 结合公
式 0-1 1 ) 和公式 0- 1 2 ) , 有以下等式 。

(1 + R'!,ecrive )"'' = (1 + R'!,ecti于 0- 1 2 )

或者可以写 出下面的公 式 。

APR, P
(I + r = ( I + A R, J
m1 m2
0- 1 3 )

在这里, APR, 和 APR2 是年利率, mi 和 m2 是它们的复利频 率 。 给定 APR , 和 m, , 我们


用以下的公 式找出复利 频 率为 m2 的单位 时间有效利 率。

APR,
R'f;'"" = ( I + t -l
mi
0- 1 4 )

假设打算借 30 万 美元为期 3 0年的贷款买房子 。 如果银行贷款为 5% 的年利率每半年复


利 , 每月支付是多少? 从 公 式 0-4 ) 和公 式 0-5 ) , 我们知道, 因为 PV 为 300 000, n

为 3 0 * 1 2 , 如果 R 已知, 那么 可以计算出每月付款 ( PMT ) 。 通过 公 式 ( 3- 1 4 ) , 得出每月


按揭利率为 0.4 1 239 1 5% , 代码如下。

»>r= ( 1 + 0 . 0 5 / 2 ) * * ( 2 / 1 2 ) - 1
>>>r
44 第3章 用 Python 编 写 一 个 金 融 计 算 器

0 . 0 0 4 1 2 3 9 1 5 4 65 1 4 42 3 4 5
> >>pv = 3 0 0 0 0 0
>>>n= 3 0 * 1 2
>>>pm 七 =pv * r / ( 1 - 1 / ( l+r ) * * n )
> >>pm t
1 6 0 1 . 072 0 3 6 4 2 62 6 65
>>>

根据上 面的计算, 月 利 率为 0.4 1 239 1 5 % , 每月支付为 1 60 1 .07 美 元 。 本章有几 个相关


的练习题, 参考习题 3 . 1 8 、 3 . 1 9 和 3 .20 。

3. 1 5 连续 复 利 利 率

在 3 . 1 4 节, 复利频 率 可能是年度 C m = l ) , 每 半年 C m = 2 ) , 每季度 ( m =4 ) , 每 月 ( m= l 2 )


或每 日 ( m=365 ) 。 如果复利 频 率 一 步 一 步加快, 可以由小 时进而分钟进而秒, 达到极 限的
利率被称为连 续 复利 。 以下是连续复利的公式 。

Re = m * In ( 1 + A=勹 0-1 5 )

这里, 凡为连续复利率, ln()是 一 个 自 然对数函数, PR 是年利率, m 是每年的复利频


A
率 。 下面的代码帮助 了 解如何 使用 自 然对数函数。

> > > import math


>> >ma 七 h . e
2 . 718281828459045
>>>math . l o g ( math . e )
1.0

例如, 如果给定的年利 率是 5% 每 半年复利, 其 相应的连续复利率是 4.9385225 % , 如


下面的代码所示 。

> > > import math


> > > 2 *ma 七 h . l o g ( l+ 0 . 0 5 / 2 )
0 . 04938522518074283

第 4 章中看涨期权的计算公式 使用的无风险利率必须是连续复利 。
3.17 净 现值 和 净 现 值 法 则 45

3. 1 6 数据类型 : 列 表

列 表是另 一种常用 的 Pyth on 数据 类型。 列 表类型的


变量可以包括不 同 类型的数据,
如字符 串 、 整数、 浮点数, 甚 至 一个列 表。 元 组 用 圆括号来定义, 而 列 表用 方括号 [和]
来定义。

>>>record= [ ' John ' , 2 1 , ' Engineer ' , 3 ]


>>>record
[ ' John ' , 2 1 , ' Engineer ' , 3 ]

与元组 类似, 第 1 个数据项 的下标为 0。 使用 record [ l : ] 列 出从下标 l 开始的所有


数据项, 使用 record [ 2 : ] 列 出从下标 2 开始的所有数据项, 如以下代码所示。

>>>len ( record)

>>>record [ O ]
4

, John '
>>>record [ 2 : ]
[ ' Engineer ' , 3 ]

元组的内 容 是不可改变的。 与元组 不 同, 列 表的 内 容 可以改


变。

>>>record [ O ] = ' Mary '


>>> record [ O ]
, Mary '

3. 1 7 净现值和 净现值法则

净现值 ( net rp ese nt v a ue,


l NPV ) 被定义为所有的收 益和成本的现值之间的差额, 如
以下公式所示。
NPV=PV(be nefis
t )-PV(co
sst) 0-16 )

假 设 我们考虑投资 一 个起始资 金 1 亿美元为期 5年的项 目 。 在未来 5年每年 年底的现


金流分别是 2 000 万美元、4 000 万美元、 5 000 万美元、 2 000 万美元和 1 000 万美元。 如
果这种类型的投资 的折现率是每年 5%, 我们是否应该投资这 一 项 目 ? 首先, 需要计算项 目
的净现值。 其 次, 必须应用 下面的决策规则(即 净现值法则 )。
{ifif
46 第3章 用 Python 编 写 一个金 融 计 算 器

NP V ( project ) > 0 , accept


( 3- 1 7 )
NP V( project) > 0 , rej ect

如 果 直接计算净现值 , 可 以 用 如 下 的 代 码 。

»>-100 + 2 0 / ( 1+0 . 05 ) +4 0 / ( 1+0 . 0 5 ) * *2 +50/ ( 1 +0 . 0 5) * * 3 +20/ ( 1 +0 . 05 ) * * 4 + 1 0 /


( l+0 . 05 ) * * 5
2 2 . 8 0 9 9 8 9 2 7 30 3 7 0 7

由 于 项 目 的 净现值为 正 , 所 以 我们 应 该接受它 。 但 是 , 输入每个值相 当 繁琐 。 比如 ,



输入 0 . 0 5 C R 值 ) 5 次 。 为 了 减轻我们 打字 的 负 担 , 可 以 利 用 个变量 r , 例 如 :

>>>r=0 . 0 5
>>>- 1 0 0 + 2 0 / ( l + r ) + 4 0 / ( l + r ) * * 2 + 5 0 / ( l + r ) * * 3 + 2 0 / ( l + r ) * * 4 + 1 0 / ( l + r ) * * 5
2 2 . 8 0 9 9 8 92 7 3 0 37 0 7

一 一
个更好的方法是编写 个 NPV 函 数 , 通过输入折现率 和 所 有 的 现金流 , 包括今天的
支 出 以 及 未 来 的 收 入 来计算 NPV。 启 动 Python 后 , 单 击 FilelNew Window 命令( 或按 Ctrl+N

组合键 ), 然 后 输 入 以 下 代码。 单 击 RunlRun Module 5 命 令 。 注 意 , 如 果 要 求输入 个文件
名 , 可 以 输入 npv_f . py 。

d e f npv_f ( rate , cashf l ows ) :


total = 0 . 0
for i , cashf l ow in enume ra 七 e ( cashf lows ) :
七 otal += cash f l ow / ( 1 + rat e ) * * i
return total

在 前面 的 函 数 里 , 第 1 行 用 def 关 键 字 定 义 了 该 函 数 , 取 名 为 npv_f 而非 npv 。 如 果



用 npv 作 为 函 数 名 , 当 用 户 以 npv 作 为 变量 名 时 , 将 不 能 使 用 该 函 数 。 第 2 行 定 义 了 个
名 为 total 的 变量 并 初始化它 的值 为 0 。 基于首字母 的缩进 位 置 , 第 3 行 和 第 4 行可 以 被 认

为是同 个 区 块 。 for 循环有两 个 中 间 变量 i ( 0,.._,5 ) 和 cashflow ( 取值 为 - 1 00 、 20 、 40 、
50 、 20 和 1 0 ) 。 请注 意 , c a s h f l ow 和 c a s h f lows 是 两个 不 同 的 变 量 。 Python 的 命令 x+=v
等 同 于 x=x+v。 将在 第 1 0 章讨 论 for 循环和 其他循环 的 更 多 细 节 。 如 果 没有 任 何 出 错提示 ,
可 以 使用 npv_ f ( ) 来计算 。 用 help ( en urne ra t e ) 来 查 看 有 关 的 e n ume rate ( ) 函 数 的 帮
助信息 。

>>>r=0 . 0 5
>>>cashf lows= [ - 1 0 0 , 2 0 , 4 0 , 5 0 , 2 0 , 1 0 )
>>>npv_f ( r , c a s h f l ows )
3. 1 9 内部收益率和 内部收益率法则 47

22 . 8 0 9 9 8 9 2 7 3 0 3 7 0 7

为 了 更便于 使用这 个函数, 可以添加注释 来 说 明这两 个输入参数并且给出一 个或两 个


使用范例。

3. 1 8 投资 回 收期和投资 回 收期 法则

投资 回 收期 ( payback period ) 指 我们需要多少年才能收回初始的投资资 金。 在上面的


例子 中, 需要超过两年但不到 3年的时间来收回 1 00 亿美元的初始投资 , 因为两年收回 60
亿美元, 3年收 回 11 0 亿美元。 如果收入在一年内均 匀分布, 该项 目的投资 回收期为 28
. 年,
如以下 代码所示。

» > 4 0 / 5 0 +2
2.8

投资 回 收期法则是指, 如果项 目的预计投资 回收期小 于 临界值 ( tc riti c al ) , 我们接受这


个项 目, 否则, 就拒绝它, 如下所示。

if Payback(project) < i:nticaJ , accept


{ 0- 1 8 )
if Payback(pro._丿ect) < i: tical , rej ect
ri

与净现值法则相比, 投资 回 收期法则有很多缺点, 比如它忽略 了 现金的时间价值、 临


界值的选取比较 随意等。 它的优点是非常简单。

3. 1 9 内 部收益率和 内 部收益率 法则
内部收益率 ( internal rate of return , IRR ) 是使得净现值为零的折现率 。 IRR 法则是指,
如果项 目的内部收益 率比资 本成本大, 就接受这 个项 目, 否则拒绝它, 如下所示。

if IRR(project) < R.,,w , acc ept


{ 0- 1 9 )
if IRR(project) < R capiral , rej ect

下面的 Python 代码用来计算 IRR 。

de f IRR_f ( cashflows , interations = l O O ) :


rate = l . O
investment=cashflows [ O ]
48 第3章 用 Python 编 写 一 个 金 融 计 算 器

f o r i i n range ( l , interations+ l ) :
rat e * = ( l- npv_f ( r ate , cash f l ows ) / i nvestme n t )
return rate

对 于 初 学 者 , 这个程序 显 得 有 些 过 于 复 杂 。 如 果 不 能 完全理解 , 并 不 会 影 响 对 本 章 其
余 部 分 的 学 习 。 range C l , 1 0 0 + 1 ) 语 句 给 出 1 � 1 0 1 的 区 间 。 变 量 l 取值为 1 � 1 0 1 。 换
句 话 说 , 第 5 行代码将重复执行 1 0 1 次 。 第 5 行 基 于 的 假 设 是 , R 和 NP V 是 负 相 关 的 。 换
句 话 说 , 增加折现率 R 导 致较 小 的 NP V。

为 了 帮 助 理解 最 关键 的 第 5 行 , r a t e * = ( l -npv_f ( r a t e , c a s h f l ows ) /
i nv e s tmen 七 ) 。 可 以把 它 简 单 地看作 以 下 等 式 。

R;+1 =R;* ( 1 -k) 0-20 )



如 果 R; 导致正的 NP V 值 , k 是 个 小 的 负 数 , 折现率会增 加 , 也 就 是 , R;+1 将 比 R; 大 。
一 一
另 方 面 , 如 果 R; 导 致 负 的 NP V 值 , k 是 个 小 的 正 数 , 折现率会减少 。 下 面 是 当 R 的 初
始值等千 1 00% 时 , 第 1 轮 循环 的 结 果 。

>>>cas h f l ows= [ - 1 0 0 , 2 0 , 4 0 , 5 0 , 2 0 , 1 0 ] # cash f l ows


>>>npv_f ( l , cashf lows ) # R ( l) is 100毛
-72 . 1 8 7 5 # negati ve N PV
>>>cashflows [ O ] # we wou ld reduce R
-100
>>>k=npv_f ( l , cashf l ows ) /cash flows [ O ]
>>>k # k i s pos i t ive
0 . 721875
>>> 1 * ( 1 - k )
0 . 2 7 8 1 2 4 9 9 99 9 9 9 9 9 9 6 Jt R ( 2 ) w i l l be 0 . 2 7 8

以 上 I RR_f ( ) 函 数 用 到 我们之前编 写 的 npv_f ( ) 函 数 , 运 行 结 果 如 下 。

>>>cashfl ows= ( - 1 0 0 , 2 0 , 4 0 , 5 0 , 2 0 , 1 0 ]
>>>x=IRR_f ( c ashfl ows )
>>>x
0 . 1360125939440155

由 此 可 见 , 如 果 资 本 成 本 是 5%, 我们会接受这个项 目 。 可 以 把 它 作为 折现 率 并 使 用
npv_f ( ) 函 数验证上述结 果 , 代码如 下 。

>>>npv_f ( x , cashfl ows )


- l . 42108547 15202004e-14
3.2 1 用 Python 编 写 一 个 专 业 金 融 计 算 器 49

3.20 显示在某个 目 录 下 的指定文件

有时候, 我们想知道 一 个特定 目录或子 目录下有哪些 文件。 假设 npv_f . py 和 pv_f . py


这两 个文件保存在 C : \ Python 3 3 \ 目录下, 可以用下面的代码检查它们是否存在。

>>>from os impor t l i s tdi r


>>>l istdir ( " c : \ Python 3 3 " )

也可以编写 一 个 名为 d江2 ( ) 的
函数来模 仿 d江 ( 函
) 数。 所不同的是, di r ( 函
) 数列
出了 内 存里的
变量和函数, 而 d i r 2 ( 函
) 数显示在 一 个给定 目录中的+文件。 因此, d江 ( )
函数不需要输入参数, 而 d i r 2 ( 函
) 数需要一 个输入值, 就是需要检 查的 目 录, 如以下代
码所示。

de f dir2 (path) :
f rom os import l i s tdir
print ( l i stdi r (path) )

把文件 d江2 . py 保存在 C : \ Python 3 3 \下以后, 用下面的命 令来检验其 目录 结构 。

>>>f rom dir2 import *


>>>path= ' c : \py 七 hon33 '
>>>dir2 ( path )

3.21 用 Python 编 写 一 个专业金融计算器

根据 本章所学习的 内 容 , 最后把 20 多 个与金融计算相关的函数放在 一 个大 的文件里,


称其 为 丘 n l O l . py。 在调试解除所有的错 误 后, 可以通过 f rom 丘 n l O l import * 命
令调用此模块包括的所有程序。 以下是创建这样 一 个 Pyth on 金融计算器的详细 步骤。

1 . 创建一 个名为 fi n l O l . py 的没有 内 容 的 Pyth on 文件并将 其 保存默认 目录下, 也


就是 C : \ Python 3 3 \ , 或其他任何一 个 目录下。

2 . 添加 pv_f ( )函数到 丘 n l O l . py 文件, 并调试程序直到它没有错误。


3. 重复上 一 步每次添加一 个函数到 丘 n l O l . py 文件, 直到它包括所有函数。

4 . 生成 一 个名为 巨n l O l函数, 用来列 出 我们编写的全部函数。 假设 丘n l O l . py 文


件仅有两 个
函数, 可以编写 一 个很
简单的 f in l O l ( )函数, 如以下代码所示。
50 第3章 用 Python 编 写 一 个 金 融 计 算 器

de f f in l O l ( ) :

l ) Ba s i c func tions :
PV : pv_f , pv_annuity, pv_pe rpe tur it y
FV : fv_f , fv_annuity, fv_annuity_due
2 ) How to use pv_f ?
> > >hel p ( pv_f )

5 . 用以下的代码来调用这 个
函数。 假 设 f i n l O l . py 文件包括 3 个函数: pv_f ( ) 、
fv f ( ) 禾0 f i n l O l ( ) 。

> > > f rom f in l O l import *


>»help ( f in l O l )

3.22 将我们 的 目 录加 到 Python 的路径上

在前面的讨论中, 我们假设所有的程序都保存于 默认 目录, 即 C : \ P ython 3 3 \ 中。 有


时候 , 这样很不方便, 比如当 我们打算把与 某 个项 目有关的所有 Python 程序保存在一 个指
定的 目录下时。 假 设所有与 投 资 课程有关的文件都在 C : \ ya n \ Te a c h i n g \ Pyt hon_for_
Finance \ codes_ chapt e r s \ 目录里, 用 下面的 Python 代码将 其 纳入我们的搜索路径 。

import sys
myFolder = "C : \ \Yan\ \Teaching \ \ Python_for_Fi nance\\codes_chapters "
i f myFolder not in sys . path :
sys . path . append (myFolde r )

使用 p r i n t ( s y s . path ) 命令来检查 结果, 代码如下 。

> > > impo r t s y s


> > >print ( sys . path)
[ ' ' , ' C : \ \ Python3 3 \ \Lib\ \ i dle l ib ' , ' C : \ \wi ndows \ \ s ys 七 em32 \ \python 3 3 .
z ip ' , ' C : \ \ P ython3 3 \ \ DLLs ' , ' C : \ \Py 七 hon3 3 \ \ l ib ' , ' C : \ \ Python3 3 ' , ' C : \ \
Python 3 3 \ \ l ib\ \ s i te-pac kages ' , ' C : \ \ Yan \ \Teaching\ \ Python_for_Fi nance \ \
codes_chapte r s ' ]

另 一种方法是使用 path函数, 代码如下(仅显示儿行, 以节 省空间 ) 。

> > >impor 七 O S


>>>help ( os . path)
3.22 将我 们 的 目 录 加 到 Python 的 路 径 上 51

Help o n modu l e ntpath :


NAME
ntpath - Common pathname manipulations , W indowsNT / 9 5 ve r s i on .

表 3 - 1 列 出 了 Pytho n 金融计 算 器 的 主 要 功 能 , 该表用 到 以 下 符 号 。

• P V 为 现值

• FV 是 未 来 值

• R 是 每 期 有 效 利 率 ( 折现率 )

• n 是周期的数 目

• C 是 一 个永久年金 或 定 期 年 金 的 每 期支付

• PMI 是 一 个永久年金 或 定 期 年 金 的 每 期支付 ( 同 C )

• g 是一 个 增 长 型 永 久 年 金 ( 定 期 年 金 ) 的 增 长 率

• APR 是 年 利 率

• R e 是连续 复 利 利 率

• m 是每年复利 次数

需要注 意 的 是 C、 R 和 n 应 该 是 致 的 , 也 就 是 具 有 相 同 的 频率 ( 或单 位 时 间 ) 。 Python
金融计算器用 到 的 公 式 如 下 。

表 3-1
FV
FV=PV(l + R)" PV =
(I + R)"

C
PV( 永久年金)=— 假设第 l 次现金流批发生在第 1 期 的 结尾
R

假设第 1 次现金 流批发生在第 1 期 的 结 尾 , 并且


PV( 增长型 永久年金 ) = __!__
R-g R>g

P
PV( 定期年金)= MI' [ I - I
] 假设第 1 次现金流狱发生在第 1 期的结尾
R (I + R)"

PMT Cl
FV( 定期年 金 )= [ + R)" - 1 ] 假设第 1 次现金流篮发生在 第 1 期 的 结 尾
R

PV( 前置型永久年金) = PV( 永久 年榴金)*( J +R) 前 置 型 : 现金流盐发生在每一期 的 开始

PV( 前置型定期年金) = PV( 定 期 年金) *( l +R) FV( 前 置 型 定 期年金) = F V( 定 期年金) *( l +R)


52 第3章 用 Python 编 写 一 个 金 融 计 算 器

续表

P V(债 券)=P V(每 期支付) + P V(面值) PV(bond) = — 1 - I ] + FV


c[
R ( l + R)" ( 1 + R)"

• EAR : 有 效 年 利 率
EAR = ( I 十 宁 ) - 1 • APR : 年 利 率
• m : 每年复 利 次数

把 一 个 年 利 率转换 为 另 一 个年利率

例如 , 已知 A PR 1 、 mi 和 mi, 求 出 A PR2 (, +
A PR
m1
J'' = ( , +
AP

m 勹
,
把 一 个有效年利 率转换 为 另 一 个 有 效 年 利 率 ( l + R111effe,ctil'e r, , 111'
= ( 1 + Rm'fl,ecm· )

把 一 个年利率转换为连续复利利率 Re R" = m * ln ( I + 气
把连续 复利利率 凡 转换为年利率 生 - 1)
APR = m * ( 矿

3.23 小结

本章 学 习 了 如 何编 写 简 单 的 函 数 , 用 来 计 算 未 来现金流量 的 现值 , 现 金 的 未 来价值 、
年 金 的 现值和 年 金 终值 、 永 久 年 金 的 现值 、 债 券 的 价 格 、 内 部 收 益 率 ( IRR ) 等 。 显然 ,
单独调 用 几 十 个 小 函 数 是 困 难和 费 时 的 。 如 何把 许 多 小 函 数集成到

个 Python 文件是本章
的 重 点 。 我们 的 目 标 是 创 建 个 称 为 fin l O l .py 的 Python 模 块 , 并 用 它 作 为 个金融计算
一 一

器 。 Python 启 动 后 , 用 f rom f i n l O l imp o r t * 命 令来导入所有 函 数 。 阅 读本章后 , 读


者应该能够编写 Python 模块来使用 企业融资和投资等课程 中 的 所 有 公 式 。 第 4 章将介绍如
何 编 写 1 3 行 Python 代码来计算看涨期权 的 价 格 。 为 了 便 于读者掌握 Python 相 关 的 技巧 ,
我们 省 略 了 期权理论 中 的 数 学 公 式 。

练 习题

l . 如 何 编 写 一 个 不 需要保存 的 Python 程序 ? 如 何 编 写 二 个 函 数 来 计 算 输 入 值 的 3
倍数 。
练习题 53

2 . 如何 有效地在 Python 程序中加入注释 ?

3. 设置输入参数的默认 值有什么 好处?

4. 在本章 中 , 我们给计算现值的函数取名为 pv f ( ) 。 为什么 不 使用 pv ( ) ?

FV
PV =
(l + RY

5 . 如何调试一 个复杂的 Python 程序 ?

6 . 如何有效地测试 一 个 Python 程序 ?

7 . 为什 么缩进格式在 Python 至 关重要?

8 . 如何在同一 个 Python 函数中 使用两 个数学公式 计算并输出 结 果, 比 如 个公式计


算未来现金流量的现值而另 一 个公式计算
年金的现值 ?

9. 有多 少种 类型的注释 ? 如何有效地使用它们?

10 . 如 何 把 尽 量 多 的 函 数 放在 同 一 个 f i n l O l . py 文 件 里 , 包 括 pv_f ( ) 、
pv_pe rpetuity ( ) 、 pv_p e rpetui ty_due ( ) 、 dpv_annu i t y ( ) 、 dpv_annu i t y_
du e ( ) 、 fv_annu i t y ( ) 等 ?

1 1 . 假设 f i n l O l . p y 文件
包括若 千 小 函数。 调用函数的两 个命令 : imp o r t f i n l O l
和 f rom f i n l O l impo r t * , 有什么 区 别 ?

1 2 . 如何防止输入错误的参数值, 比如一 个负的利 率 值 ?

1 3 . 假设 目录 C : \ P ython 3 3 存在, 我们知道以下代码是正确的。

> > > from os impo r 七 l i s tdir


> > > l i s tdir ( " c : \python3 3 " )

但是, 下列 函数却有错误, 为什 么 ?

de f di r 3 ( path) :
from o s imp o r t l i s td i r
l istdi r (pa 七 h )

1 4 . 假设 npv_f . py 和 i r r_ f . p y 这两 个文件都存在于 C : \ Python 3 2 \ 。 下面的代


码是否正确 ?

>>>f rom i r r_f import *


>>>import npv_f
54 第3章 用 Python 编 写 一个金 融 计 算 器

»>dir ( )
[ ' IRR f ' , ' bu i l t i n s ' , ' doc ' , ' name ' , ' package ' , ' g l ob ' , ' npv f ' ]
>>>I RR_f ( 0 . 0 4 , [ - 1 0 0 , 5 0 , 5 0 , 5 0 ) )
Tr acebac k (most recent call l a s t ) :
File " <pyshe l l # 2 2 > " , l i ne 1 , in <module> IRR_f ( 0 . 0 4 , ( - 1 0 0 , 5 0 , 5 0 , 5 0 ) )
F i l e " C : \ Python 3 2 \ i rr—f . py " , l ine 3 , i n IRR_f inves tment = cashf l ows [ O J
T ypeError : ' fl oa t ' obj e c 七 i s not sub

1 5 . 编 写 一 个 Python 程序用 来 计 算 投 资 回 收 期 。 例如 , 初 始 投 资 为 256 美 元 , 并且在


未来 7 年每年年末 的 收入 分 别 为 3 4 美 元 、 44 美 元 、 55 美 元 、 67 美 元 、 92 美元、 70 美 元
和 5 0 美 元 。 该项 目 的 投资 回 收 期 是 多 少 年 ?

1 6 . 如 果折现率 为 每 年 7.7% , 贴现 回 收 期 是 多 少 年 ? 注 : 贴 现 回 收 期 着 眼 于 如 何 用 未
来现金流量 的 现值之和 收 回 初 始投 资 。

1 7 . 假 设 有 一 个 目 录 C : \ py吐on 3 3 。 可 以 使用 以 下 代码列 出 该 目 录 下 的 带 有.py 扩 展


名 的 Python 文 件 。

>>>import glob
>>>glob . g l ob ( " c : \python 3 3 \ * . py" )


编写 个 以 字符 串 变量 为 输入 参 数 的 Python 函 数 , 称 为 d i r 2 ( ) , 用 来实现这个 功 能 。
以命令 d i r 2 ( " c : \python 3 3 \ * . p y " ) 来调 用 它 。

1 8 . 编 写 一 个 Python 程序把给 定 复 利 频 率 的 年利 率转 换 为 个有效 利 率 。

( 1 + m 『 = (l 十 m 『
三 五

1 2

一 一
1 9 . 编 写 Python 程序结合下面 的 公 式把 个 利 率 转换 为 另 个 有 效利 率 。


A
[ 1 + A=尸1 r = [ l + =� )

e R, = ( } + 气咒

20 . 基 于 以 下 代 码 , 编 写 一 个 Python 程 序 , 把 指 定 目 录 添 加 到 搜 索 路 径 上 , 如
addPath ( ' c : \my_p r o j e c t ' ) :
练习题 55

> >>impo r t sys


> >>myFo lder = " C : \ \ Python_for_Financ e \ \ code s_chapters "
>>>if myFo lde r not in sys . path :
sys . path . append (myFolde r )

21 . 假 设 有 1 0 个项 目 文件分别存放在 10 个 目 录下 , 如 c : \ te a ch i n g \python \ 、
c : \proj ects \python\ 、 c : \proj ect s \portfol io\禾IJ c : \proj ects\ inve s tment s \ 。
创建 一 个 Pyth on 模 块 , 包括 10 个 函 数 , 分 别 以 这 10 个 目 录 为 默 认 参 数值 。 运行第 1 个 函
数后 , 第 1 个 项 目 的 目 录将被添加到 搜索路径上 , 以此类推 。
第4章
编 写 Python 程序计算看涨期 权价格

期权理论对于许多读者来说就像是高深的火箭科学。 为了 不让深奥的期权理论成为读
者学习的障碍, 本 章 没有详细介绍期权理论及相关的数学公式, 而是把重点放在用 1 3 行
Python 代码计算看涨期权的价格。 看 涨 期权的买方支付 期权费, 以获得在未来某个指定 日
期买入股票的权利, 而期权的卖方收到期权费并承担把股票卖给期权买方的义务。 欧式期
权只 能在期权到 期时行使, 而美式期权可以在到期 日或之前的任意 一 天行使。

本章将 重 点 讨论以下 内 容 。

• 计算看涨 期权价格的 1 3 行 Python 代码

• 利用空 壳法编写 一个复杂的 Python 程序

• 使用注释法编写 一个 复 杂的 Python 程序

• 如何调试他人写的程序

可以用下面 5 行 Python 代码计算欧式看涨期权的价格。

f rom math impo rt *


de f bs_c a l l ( S , X , T , r , s i gma ) :
dl = ( l og ( S / X ) + ( r +s igma * s igma / 2 . ) * T ) / ( s i gma * sqrt ( T ) )
d2 = d l - s i gma * s qrt ( T )
return S * CND ( d l ) -X* exp ( - r * T ) * CND ( d2 )

程序的第 1 行导入 math 模块, 使 我们可以调用所需的 log ( ) 、s q r t ( ) 和 exp ( 函


) 数。
看涨期权的价格依赖 5 个参数: S 是 目前的股票价格, X 是执行价格(指定价格), T 是到
期期限(以年计), r 是连续复利的无风险利率, sigma 是标的证券(如股票) 的波动率。
以上 代码 中 的CN D函数用来计算累积标准正态分布函数。 由于导入的数学模块不包括累积
4. 1 用 空 壳 法编 写 一 个 程 序 57

标准正态分布函数, 所以必须 自 己编写 一 个相应的 Python 程序 。 如果可以导入一 个


包含累
积标准正态分布函数 的模块, 就只用以上的 5 行代码给看涨期权定价 ! 第 6 章将展示如何
使用 一 个叫 作 SciPy 的模块来做到这一点。 以下是 我们 编写的 CND函数 。


de f CND ( X ) :
( a l , a2 , a3 , a 4 ,
aS ) = ( 0 . 3 1 93 8 1 5 3 , - 0 . 3 5 6 5 6 3 7 8 2 , l . 7 8 1 4 7 7 9 37 , - l . 8 2 1 2 5 5 9 7 8 , l . 3 3 0 2 7 4 4 2 9 )
L = abs ( X )
K= l . 0 / ( l . 0 + 0 . 2 3 1 6 4 1 9 * L )
w= l . 0 - l . 0 /s gr t ( 2 * pi ) * e xp ( - L * L / 2 . ) * ( a l * K+a2 * K * K+a3 *pow ( K , 3 ) +
a4 *pow ( K , 4 ) + aS * pow ( K , 5 ) )
i f X<O :
w = 1 . 0-w
return w

这 个累积标准正态分布 ( CND) 函数以 X为输入参数 。 第 2 行为 5 个 变量 a l 、 a2 、 a3 、


a4 和 as 赋值。 元组用来节省 空 间 。 Python 启 动 之 后, 单击 FilejNew Window ( 或按 Ctrl+N
组合键), 然后输入之前的 13行代码 。 输入后, 保存文件, 单击Ru n 按钮, 然后单击Ru n
Module FS 。 如果没有错误, 就会看到以下 运行 结果:

>>>==== =======RE S TART - - - - ----- - --- -----

现在可以使用刚刚完成的 Python 程序给看涨期权定 价 。 给定 一组 s、 X, T、 r 和 s i gma


的参数值, 可以很容 易 地用 Black-Scholes 公式 计算看涨期权的价格。 以下 是根据 一组数据
值得到的看涨期权价格。

>> >bs ca l l ( 4 0 , 4 2 , 0 . 5 , 0 . l , 0 . 2 )
2 . 2777859030683096

到 目 前为止, 我们学习 了 与 看涨期权定价相关的两 个


函数, 一
共有 13行代码 。 这为 我
们提供了 一
个理想的案例来解释 如何编写 一
个相对 复杂的 Python 程序 。 本 章的其 余部分将
介绍编写 Python 程序的两种方法: 空 壳法和注释法。

4. 1 用 空 壳 法 编 写 一 个程序

空 壳法的流程为: 首先生成 一 个空壳并对其 进行测试, 然后添加 一行再进行测试。 如


果没有错误, 继续添加新的代码并测试 。 重复此过程直到完成整 个程序 。 以下的例子用 CND
函数来演 示空壳法。
58 第4章 编 写 Python 程 序 计 算 看 涨 期 权价 格

1 . 启 动 Python 后, 单击 Fi lelNew Window (或按 Ctrl+N 组合键 ) 生成以下空壳。

de f CND ( x ) :
re 七 urn x

2 . 单击 FilelSave , 将 其 保存在名为 cnd . py 的文件中。

3. 单击 Run 按钮, 然后单击 Run from module F5 。 下面这一 行会出现:

> >>======= = ===RE START ===== ========= === -

4 . 可以输入不同的值来测试这个空壳程序。 如果输入 1 , 则输出为 1 。 如果输入 5 ,


则输出为 5 , 如下所示。

>> >CND ( l )
1

5. 在空壳程序中添加如下 行代码。

de f CND ( x ) :
( a l , a2 , a 3 , a 4 , a5 ) = ( 0 . 3 1 9 3 8 1 5 3 , - 0 . 3 5 6 5 6 3 7 8 2 , 1 . 7 8 1 4 7 7 9 3 7 , - 1 .
8 2 1 2 5 5 97 8 , 1 . 3 3 0 2 7 4 4 2 9 )
return a l

6 . 注意返 回值是 a l , 不是 x 。 单击 Run 按 钮, 然后单击 Run from module F S , 会看


到下面 一 行。

> > > ==== = ======R E START ==== = ==== === =====

7. 可以输入任意值测试这个程序 。 例如:

»>CND ( l )
0 . 31938153

8 . 重 复上 述步骤, 直到完成 整 个 CND ( )函数, 代码如下:

from math import *


de f CND ( X ) :
( a l , a2 , a3 , a 4 , a5 ) = ( 0 . 3 1 9 3 8 1 5 3 , - 0 . 3 5 6 5 6 3 7 8 2 , l . 7 8 1 4 7 7 9 3 7 ,

=
- l . 8 2 1 2 5 5 97 8 , 1 . 3 3 02 7 4 4 2 9 )
L abs ( X )
K= l . 0 / ( 1 . 0 + 0 . 2 3 1 6 4 1 9 * 1 )
4.2 用 注释法编写 一个程序 59

w= l . 0 - l . 0 /s q r t ( 2 * pi ) *e xp ( - L * L / 2 . ) * ( a l *K+a2 * K * K+a3 *pow ( K , 3 )


+a4 *pow ( K , 4 ) + a 5 *pow ( K , 5 ) )
if X<O :
w = 1 . 0-w
return w


9 . 因为 我们的 CND()函数 使用了包含在数学模块中的 s q rt ( )函数, 所以需要
f r omma 七 hirnp o r t * 这

行代码 。 可以按如下 步骤用不 同的输入值来测试此函数 。

»>CND ( 0 )
0 . 5000000005248 0 8 6
»>CND ( -2 . 3 2 2 9 )
0 . 010092238515047591
»>CND ( l . 6 4 7 )
0 . 9 5 0 2 2 0 9 9 3 3 62 7 8 1 7

10 . 由于一 个标准正态分布是对称 的, 其 累 积分布在零点的取值为 0.5 。 其 在-2.33 的


取值为 1%, 而在 1 .64 7的取值为 9 5%。 所以可以使用 E xce l的 N O RMDIST()函数来验证
CND()函数。 这 个 Exce 函数有
l 4 个参数: n ormdi st( x, 均值, 标准方差, 是否为密度函数
或累积发布 函数)。 最后 一 个参数的取值为 0 代表标准正态分布 的概率密度函数, 取值为 1
代表标准正态分布的累 积分布函数, 如图 4 - 1 所示。

儿 =NORMOIST(0,0,1,l) " "丘"" " '"=NORMOIST(·2.3立9,0,1,1)


D
"' 一:...,—' ......... .._,,,,,,,___- ..-=:
E f O
f,. I =NORMOIST{ l.647,0,1,1)
.........,. '一·一 ,一”“一..
E f
fo.010092J
E
0.950221

图 4- 1

4.2 用 注释法编 写 一 个 程序

注释法的流程是: 输入所有的代码行, 把它们全部标记为注释, 然后每次释放一 条 代


码并进行调试。 以 B ac
l k-Sch ole s 看涨期权公式为例来说 明 这种方法。
I . 启 动 Pyth on 后, 单击 Fi elNewWind
l ow (或按Ctrl+N组合键)。 输入下面第 3 步中
提到的 5 行代码, 在其 中有意输入几 个错误 。

2 . 单击 Fi eil Save 完成保存。

3 . 利用 一 对三重引号 使得整 个程序主体成为注释 。 由于需要输出值, 所以添加一 个返


回行 , 如下所示。
60 第4章 编 写 Python 程 序 计 算 看 涨 期 权价 格

de f bs_c a l l ( S , X , T , r , s i gma ) :

dl = ( l o ( S / X ) + ( r +s igma * s i gma /2 . ) * T ) / ( s i gma * sqrt ( T ) )


d2 = d l - s i gmasqr七 ( T )
return S * CND ( d l ) -X* exp ( - r * T ) * CND ( d2 )

return ( X )

4. 单击 Run 按 钮, 然后单击 Run from module F S , 将看到以下 输出。

>>>===========RESTART ========== �- -- -

5. 使用任意输入值测试这 个
函数。

>>>bs_ca l l ( 4 0 , 4 0 , 0 . 5 , 0 . l , 0 . 2 )
40
>>>bs_c a l l ( 4 0 , 4 2 , 0 . 5 , 0 . l , 0 . 2 )
42

注意输出值等于 第 2 个输入
变量 的值, 正如 我们设计的那样。

6 . 每 一 次释放一 行。 如果有错误, 做必要的修改。

de f bs_ca l l ( S , X , T , r , s i gma ) :
dl = ( l o ( S /X ) + ( r+ s i gma * s i gma / 2 . ) * T ) / ( s i gma * s qrt ( T ) )

d2 = d l - si gmasqrt ( T )
retu r n S * CN D ( d l ) -X* exp ( - r * T ) * CND (d2 )

return ( x )

7. 每次调用函数时, 都会得到 一 个错误信息, 提示 l o ( )函数不存在。 这让 我们意识


到, l og ( S / X )函数被错误地输入为 l o ( S / X ) 。

>>>bs_c a l l ( 4 0 , 4 0 , 0 . 5 , 0 . l , 0 . 2 )
Traceback ( mo s t recent c a l l l a s t ) :
F i l e " <pyshe l l # 5 2 > " , l ine 1 , i n <modu l皊
b s_call ( 4 0 , 4 0 , 0 . 5 , 0 . l , 0 . 2 )
F i l e " <pyshel l # 4 9 > " , l i n e 2 , in bs_c a l l
d l = ( l o ( S /X ) + ( r + s igma * s igma /2 . ) * T ) / ( s i gma * s q工七 ( T ) )
Name E r ror : g l ob a l name ' lo ' i s not def i ned
练习题 61

8. 重复步骤 4, 直到完成整 个程序的编写 。

4.3 使用 和调试他人编 写 的 程序


在开始为 自 己的项 目编写程序时, 我们往往会以已有的程序作为起点。 这些 程序可能
是 我们的研究 伙伴, 其他研究 员编写的, 也可能来 自 互 联网的开源软件, 或者是 我们用过
的程序 。 我们首先需要知道这些 程序是否
包含错 误 。 上述两 种方法可以用来检验这些 程序 。
第 2 种方法, 即注释法, 应 当是首选, 因为可以帮 我们节省 一 些 打字的时间 。 调试程序的
关键在于 找出程序错在哪里。 这里有一 个非常有用的从 雅 虎财经网站获取数据的 Pyth on 代
码文件: http : / / ca n i s i u s . edu / - yany/python / y s t o c kquote . tx七 。 初学者可以
下载该文件并试一试其 中包含的一 些 小程序 。

4.4 小结

本章没有详 细介绍期权理论及其 相关的数学公式 , 而是 把重点放在解释 如何编写


Pyth on 代码以计 算看涨期权的价格。 因此, 在很短的时间内, 一
个完全不 了解期权理论的
读者可以用著名的 Bl ac -k Sch oel s-Mert on 模型给 看 涨 期权定价。

将在第 5 章正式介绍模块, 这是与模块相关的连续 3 章中的第 1 章。 模块是由一 个或


一组专家为特定 目的编写的程序集合 。 比如, 第 6 章将演 示如何使用
包含在 SciPy 模块中
的累 积标准正 态分布函数, 从 而只 需要 5 行代码就可以计算看涨 期权的价格, 而不是现在
所用的 13行代码 。

练习题

.l 编写 一 个 Pyth on 程序给看涨 期权定价。

2 . 如何用空壳法编写 一 个复杂的 Pyth on 程序 ?

3. 如何用注释 法编写 一 个复杂的 Pyth on 程序 ?

4. 如何在调试程序时 使用返 回值?

5. 在写CND函数时, 可以分别定义 a 、l a2 、 a3、 a4 和 a5。 以下两 种方法之 间 有什


么区 别 ?
62 第 4 章 编 写 Python 程 序 计 算 看 涨 期 权 价 格

目前的做法:

( al , a2 , a3 , a4 ,
a S ) = ( 0 . 3 1 9 3 8 1 5 3 , - 0 . 3 5 6 5 6 3 7 8 2 , l . 7 8 1 4 7 7 9 37 , - l . 8 2 12 5 5 9 7 8 , l . 3 3 0 2 7 4 4 2 9 )

另 一种方法:

al=0 . 31 9 3 8 153
a2=- 0 . 3 5 6 5 6 3 7 8 2
a3=1 . 7 8 1 4 7 7 937
a 4 =- l . 8 2 1 2 5 5 9 7 8
aS=l . 33 0 2 7 4 4 2 9

6 . 看涨期权定价模 型 中, 什么 是有效的年利率 、有效的每半年复利的利 率和无风险利


率 ? 假设 目前每年无风险利率是 5%, 每 半年复利, B al ck- Sc h oel s 看 涨 期权模 型中的无风险
利率应采用什 么 值 ?

7. 给定股价 39 美元, 行权价为 40 美元, 离到期 日 有 3 个月 , 无风险利率为 3.5% C 连


续复利), 年回报率的波动率为 1 5%, 其 看涨期权的价格是多少 ?
8. 如 果第 7 题中的无风险利率仍是每年 3.5% , 但每 半年复利 , 这个看涨期权的价格
是多少 ?

9 . 使用他人编写的程序有什么 优点和缺点?

10 . 如何调试他人编写的程序 ?
11 . 写 一 个 Pyth on 程序将任意给定的每年复利 m 次的年利率 ( AP R)转换为连续复利
利率。

1 2 . 如何提高累积正态分布函数的精确度 ?

13. 年利 率 (APR)和连续复利利率 ( Re )之 间有什 么 关系 ?

14 . 一
只 股 票当前股价为 52.34 美元 。 如 果行权价和 目前的股价相同, 离到期 日 有
半年, 年 回 报 率 的波动率是 16% , 无风险利 率为 3.1% C 连 续 复利), 它的看 涨 期权价格
是多少 ?

1 5. 给定 一组 S、 X、 T、 r 和 sigma, 可以使用这 13行 Pyt h on 代码计算 一 个欧式看涨


期权的价格。 当 目前的股价 S 增加, 而其他参数值相同, 看 涨期权的价格将增加还是减少 ?
为什么 ?

1 6 . 以图形方式演 示第 15 题的结论。
练习题 63

1 7 . 当行权价 X 变 大 , 看涨期权的价格将减 少, 这是对的吗 ? 为什么 ?

18. 如果其他参数值保持不变, 看 涨期权的价格会随着 波动率 ( sig ma)增 大 而变大 。


这是否准确 ? 为什 么 ?

I 9 * . 给定一组 S、 X, T、 r 和 ;igma 的值, 可以使用本章提供的代码计算欧式看涨期


权的价格, 也就是 C。 从 另 一 个角度来看, 如果我们 观 察 到 一 个看涨期权的实际 成交价格
与它相应的 S、 X、 T 和 r 的值, 可以计算它的隐含波动率 ( sig ma)。 试着 找出一 个试错法
来粗略估算隐含波动率(如果初学者不知道如何解决这个问题, 亦是完全正常的, 因为 我
们 将用整整 一章的篇福来讨论如何做到这 一点)。

20* . 根据所谓的期权平价关系, 持有 一 个看涨期权和 适量的现金的组合相当于持有 一


个看跌期权和 标的股票的组合。 这里的看涨期权和 看跌期权都是欧式期权, 具有相同的行
使价 C X)和 到 期 日 ( T)。 如果股票价格为 1 0 美元, 行使价为 1 1 美元, 在 6 个月之 后到期,
无风险利 率为 2. 9% C 每半年复利), 欧式看跌期权的价格是多少 ?

注: *
表示 难度较高的问题。
第5章
模块简介

模块是 由专家或编程人员为了 完成 某 个具体任务而编写的软件


包。 了解模块对于 理 解
Python 并把它应用于 金融领域至 关重要。 我们将在这本书中使用大 约十几 个模块。

本章将重点讨论以下内容 。

• 什 么 是模块? 如何导入模块

• 显示 导入的模块包含的所有函数

• 为导入的模块取 个
简称

• 删 除已经导入的模块

• 从模块加 载指定的函数

• 找出所 有 的内置模块和当前所有可用的模块

• 找到特定的但未安装的模块

• 找到已安装的模块的 目 录位置

• 模块之 间 的 相 互 依 赖性

• 包括许多模块的超级包

• 在 网 上 搜索 模块和如何安装模块的视频

5. 1 什么是 模块

模 块是 由 专家或编程人员 为特定 目 的编写的一 个软件包。 例如, 名 为 quant 的 Python


模块可用来完成定械的财务分析,包含与 汇率 、 交易 代码 、 市场、 历 史价格等相关的应用 ,
5.2 导 入模 块 65

结合 了 S c i Py 模块和 Dorna inMode l 模块。 该模块对 Python 而言非常重要 。 这本 书直接


或 间 接地用 到十几个模块。 我们将详细 讨论 5 个模块: 第 6 章的 NumPy 模块和 SciPy 模块、
第 7 章 的 Ma tplo t l i b 模块、 第 8 章 的 Pandas 模块和 Statsmodels 模块。 截至 2013 年 1 1
月 6 日 , https : / /p ypi . python 'f org/ pyp 立 % 3Aa c 巨 on = b rowse 网 页 列 出 24 955
个 Python 模块 。 与 金融保险 相 关 的 有 687 个模块 。

5.2 导入模块

假设要计算 五 。 如 果运 行 以 下 代 码 , 会得到 一 个 出 错信息 。

>>>sqrt ( 3 )
S yntaxError : inva l id s yntax
>>>

原 因 在于 sqr七 ( ) 函 数不 是 Python 内 置 函 数 。 要使用 sqrt ( ) 函 数 , 需 要 先 导 入 math


模块如 下 。

>>>import math
>>>x=math . s qrt ( 3 )
>>> round ( x , 4 )
1 . 7321

如 果 使用 import ma th 命 令 导 入 math 模块 , 可 以 输入 math . s q r t ( ) 命令来使用


sqrt ( ) 函 数 。 此 外 , 使 用 命 令 di r ( ) 后 , 可 以 在 以 下 的 输 出 中 看 到 math 模块。

>> >di r ( )
[ ' builtins ', ' doc ', ' name ', ' package ' , ' ma 七 h ' l

另 外 , 只 有 安 装 一 个模块后 , 才 可 以 使用 import x_modu l e 导 入 它 。 math 模块是


一 个 内 置 模块 , 已 经 预 先 安 装 了 。 本 章 后 面 部 分 将 说 明 如 何 找 到 所 有 内 置模 块 。 在 上 面
d江 ( ) 命 令 得 到 的输 出 中 , 我们看到_bu i l t i n s_模块 。 这个模块不 同 于 其他 内 置模块 ,
如 math 模块 , 它 包含 所 有 的 内 置 函 数 。 可 以使用 dir (_bu i l dins ) 列 出 所有 的 内 置
函 数 , 如 图 5-1 所 示 。
66 第5章 模块简介

图 5- 1

5.2.1 为导人的 模块取个简称

有的模块有很长的名称, 不方便输入。 为了在编程过程中便于输入, 可以用 import


x modu l e a s y_name 命 令为模块取个
简称, 代码如下。

>>> import sys as s


>>>import time as 七七
>>>import numpy as np
> > > impo r t matp l o t l ib as mp

使用模块的
简称来调用包含在该模块中的指定函数, 比如:

>>> impor 七 t ime a s t 七


> > > t t . l o c a l time ( )
time . st ruct_time ( tm_year = 2 0 1 3 , tm_mon=7 , tm_mday =2 1 , tm_hou r=2 2 ,
tm_mi n= 3 9 , tm_sec = 4 1 , tm_wday= 6 , tm_yday=2 0 2 , 七m_i sdst = l )

模块的简 称 可 以 自 由地选择, 不 过需要遵 守 一 些 常 见 的 约 定 , 比 如 使用 np 作为


NumPy 模块的简称和 sp 作为 S c i P y 模块的
简称 。 使用这些 约定的简称 可以增强程序的
可读性。

5.2.2 显示模块 里的所有 函数

如果想知道 math 模块包含 的所有函数, 首先导入它, 然后使用 d江 ( ma 七 h ) , 代码


如下。
5 .2 导 入模 块 67

> > > import math


> > > dir ( math)
[ ' doc ' , ' n ame ' , ' package ' , ' a cos ' , ' acosh ' , ' a s in ' , ' as i nh ' ,
' atan ' , ' a 七 an2 ' , ' atanh ' , ' c e i l ' , ' copysign ' , ' cos ' , ' c as h ' , ' degree s ' , ' e ' ,
' e r f ' , ' e r f c ' , ' e xp ' , ' expm � ' , ' fabs ' , ' factorial ' , ' f loor ' , ' fmod ' ,
' f rexp ' , ' f sum ' , ' gamma ' , ' hypo 七 ' , ' i s i nf ' , ' i snan ' , ' l dexp ' , ' lgamma ' ,
' l og ' , ' logl O ' , ' l oglp ' , ' modf ' , ' pi ' , ' pow ' , ' r adians ' , ' s i n ' , ' s i nh ' ,
' s qrt ' , ' tan ' , ' tanh ' , ' t runc ' ]
>>>

5.2.3 比较 import math 和 from math import *


在前面的章节中 已经讨论过这 两 个 命 令 。 为了本章的完整性, 这里再学习 一 次。 使 用
from ma th import * 便于简 化程序, 尤其对于刚 开始学 习 Python 编程的初学者 。 我们
来看看 下 面的代码行 。

>>>f rom ma 七 h import "'

> > > sqrt ( 3 )


l . 7320508075688772

这样, math 模块中包含的所有函数都 可以直接 调 用 。 如 果 使用 imp o r t mat h , 则 必


须使用 math . sqrt ( ) 而 不 是 s q r t ( ) 。 当我们熟悉 Python 之后, 使用 imp o r t modu l e
命令将会更方便 。 主要有两个原 因 。 首 先, 我 们 明 确地知道从哪个模块中调用函数。 其次,
我们编写的函数 可能与另 一 个模块里的 函数有相 同的名字, 在 函数名之 前加上模块的名称
能将重名的函数区分开来。

> > > import math


> > >math . s qrt ( 3 )
l . 7 3 2 0 5 0 8 07 5 6 8 8 7 7 2

5.2.4 删除 已经导人的模块
de l 命 令 可以用来删 除 已经导入的模块, 代码 如 下 。

>>>import ma th
» >di r ( )
[ ' bui ltins ' doc , name ' package ' math ' )
> > >de l math
>>>dir ( )
[ ' buil tins ' do c ', ' name ' pac kage 'l
>>>
68 第 5 章 模块简介

但是, 如果使用 f rom m a t h import * , 就不能用 de l ma th 删 除所有函数。

> > > f rom math import *


> > >del math
Traceback (most recent c a l l l a s t ) :
F i l e " <pyshe l l # 2 3 > " , l i ne 1 , i n <modu l e >
de l math
Name E r r o r : name ' math ' i s not de f i ned

必须单独 删 除各个函数, 以下的代码从 内存中删 除 s q r t ( )函数。 我们通常没有理由


这样做, 仅 仅用来说 明这是可以的。 下面的两行命 令首先删 除 s q r t ( 函
) 数, 然后尝试调
用它。

> > >de l s qrt


> > > s qr 七 ( 2 )
Traceback ( mo s t recent c a l l l a s t ) :
F i l e " <pyshel l # 2 6> " , l i ne 1 , in <modu l e >
sqrt ( 2 )
NameE r ro r : name ' s qrt ' is not de f i ned

5.2.5 导人几个指定的函 数
第 4 章用到 3 个函数: l o g ( ) 、 e xp ( ) 和 s q r t ( ) 来计算看涨期权的价格。 若 要 使用
这 3 个函数, 就需要用 f rom ma七h i mport * 命 令导入包含这些函数的 math 模块。 这
个命令发出后, math 模 块包含的所有函数都可以调用了, 代码如下。

f rom math import *


def bs_ca l l ( S , X , T , r , s i gma ) :
dl = ( l og ( S / X ) + ( r + s i gma * si gma /2 . ) * T ) / ( s i gma * sqrt ( T ) )
d2 = d l - s i gma * s qrt ( T )
return S * CND (dl ) - X * exp ( - r * T ) * CND ( d2 )

如果只需要某几个函数, 可以在导入命 令中指定它们的名 字 。

> > > from math import l o g , exp, sqrt


>>> round ( log ( 2 . 3 , 4 ) )

0 . 8329
>>> round ( s qrt ( 3 . 7 ) , 4 )
1 . 92 3 5
5.2 导 入 模块 69

5.2.6 找出所有的内 置模块


一 个元组类型的字 符 串 变量包含了被编译到 Python 解释器里的所有模块的名字 。 这些
内 置 模块的名字如图 5-2 所示。

图 5-2

需要注意的是, 一 个 内 置 模块并不意味着 当前可用 。 比如, 图 5-2 显示 math 模块是


预先 内 置的。 如果要调用 math 模块中 的一 个函数, 如 s i n ( ) , 就必须首先导入 ma 七 h 模
块。 另外, 使用 s y s 模块中 的 modu l e s . k e y s ( )函 数会列 出导入的模块, 如图 5-3 所示。

图 5-3

5.2.7 找出所有可用 的模块


要找出所有可用的模块, 首先需要激活帮助窗 口 。 发出 h e l p ( ) 命 令 后的结果如图 5-4
所示。

然后, 在 help>提示符下使用 modu l e s 命 令, 得到图 5-5 所示的结果。

输出的最后几行 如图 5-6 所示。


70 第 5 章 模 块简介

图 5-4

1,, ,.,, 1 ,, ,,,,· \' \, 『 'I [ t, ,, "' I I ,, I. I,-.,,、:,



11<-. . 1" l : : • , ·. , , , ,, ,, I
\1,, I ' "'' I,'' ' ,.1 I' I , I,
11:.i I j "'' I I I I' ,._,,,,1 ,. , , I : . 1·1 ' ,.,11,.1,、
1:::::: •; I.
l li1,p l , ,.,,,, 1· J.,,, 11,
,I ' '
I,., " . , .
/,,令 ' I
' ' ' ""•' I ' "
I 11, i '
," 1.,- r
,, 1 , ' " .
l"' ·'· I' I ii.
, i:.. I ,.· ! "I, i "·''I' !' 1 ,,,, 11,
已墨雪
I , ,..,.1.- , ,, , ,,., ' "
,.,, 1 11 1 1 1'!, , I'" • , 1 i-- !, 1. . " '!
,:·'"'-'·' ,' I , , ' ;
1_; ,, ,,1 i ,J !·.. ,、 , /' [ . , .... , , ,』 , ,-,
1;,"' ' , i,,,· 1· \ 1, I l'J,I JI>• I I i, · , " ' , .. ' " "" ' I ,
,:., .. ;, ; , , I "' I I "" · , , i , I、 ,. ' " '' ' ·' " '

_...........
,:,- ,,.1,t " .. 1,,,,、,,, ' i I , ,,., ,,,』,' I、 ,- I"' '、 ,
1i:,, 1、 1 ,,..., ,- 1• 1,,., ' " ,'" ' ,, l, J , I 1 .. , I
I,,.:,,, 1,,,i,
ii. · i , , , , , , I I , , , , "' 1 ,· I '
,
I '
I
11, i ., \, .., , !.,·, ..., ,., '
!J,, , ;-: M1.1-: ,·, :., , '" , , I"' r . ,
I I I' ! i, ' , ,.;· 1 ..., 1 1,
II , i i I , , ,. ',,•• i : " ' ' ,,., I ,,
ii i i • 1, I ,, ,,,,, ' ' ,1.,、, I ' r . ' I ' ,. ,,,.,
图 5-5

图 5-6

要 查 找 某 个 特 定 的模块, 只 需 要输 入 modu l e s 和 该 模 块 的 名字 。 如 果 想 了 解
rnatp l o t l i b 模 块, 可 以 在 帮 助 窗 口 使用 modul e s rnatplot 巨b 。 前 提 条 件 是 ,
rnatplotl ib 模 块 已 经 预 装 了 。 如 果 没 有 , 就 会得到 一
个出错 信息 。 发出
rnodu l e srnatp lo七巨b 命 令 后的结果如图 5- 7所示。
5.2 导 入模块 71

图 5-7

5.2.8 找到一个巳安装的模块的 目 录位置


第 6 章将详细介 绍 如何下 载并安装 Nu mPy 模块。 这里, 假定 已经安 装 了 一 个 名为
Nu mPy 的模块。 以下是找到该模块所在 目录的 3种方式。
C I ) 使用 p r i n t ( np . f i l e ) 命令。

>> >import numpy as np


>>>print ( np . f i l e )
c : \Anaconda \ l i b \ s i te-pac kages \numpy\ init . py

(2 ) 使用 np . f 辽 e 命令, 但不调用 p r i n t ( )函数。

>>>np . f i l e
' C : \Anaconda \ l i b \ s i te-packages \numpy\_i nit_ . p y '

(3 ) 在导入模块后, 只 需输入 np 。

>>>np
<modu l e ' numpy ' from ' c : \Anaconda \ l ib \ s i te-packages \numpy\�init� . py ' >

有些 读者可能会问, 为什么 要关心模块安装的位置。 找出Nu mPy 模块所在的 目录 后,


可以直接在该 目录找到有 关这 个模块的更多信息。 比如, 在这 个 目录下, 你会发现一 些 有
趣的子 目录 , 如 doc 、 random 和 tests 。 从这些 特定的子 目录, 用户尤其是初学者可以找到
许多有用的 Python 程序。 如果不小心创建了与现有的模块名字相同的一 个 模 块, 知道在哪
里可以找到现有的模块便 于 搜索和调试。 当 然, 最好避免 使用相同的名字 。
72 第5章 模块简介

5.2.9 有关模块的更多信息

执行以下步骤来获取有 关模块的更多信息。

l . 选择 All ProgramsjPython 3.31Module Docs , 如图 5-8 所示。

2 . 也可以通过浏 览 路 径 找 到 预先安装的模块。 启 动 Python 之 后, 单击 Filei Path


Browser, 如图 5-9 所示。

7• Python 3.3.2 Shell


巴 Edit Shell Debug Options
Python 33 I- - - - - - - - --
,:a IDLE (Python GUI) New Window Ctrl+ N

,,. Module Docs Open... Ctrl+ O


Recent Files
., Python (command line)
Open Module. .. Alt+M

秽 Unin式a l l Python
啪 Python M a n u a ls
Class Browser Alt+ C
Path Browser

图 5-8 图 5-9

3 . 单击 Path Browser 之 后, 会看到 个软件包的列 表, 也就是 模块的列 表, 如图 5- 1 0


所示。

言巨亏
7矗 P或hBrows«

3 �
PY'ho" 3 p
;�

collections: package
concurren七 package
ctypes: pac lca扣
curs心 package
dbm: pac.lca尹
cf哎utils: pac.lca扣
email: package
encodin宇 package
html: package
http: package

图 5- 1 0

5.2. 10 查找某个未安装的模块

如果想使用 quant 模块来进行定釐分析, 需要用以下 代码导入它。

>>>import quant
T raceba c k (most recent call l a s t ) :
5.3 模 块之 间 的 相 互 依 赖 性 73

File "<pyshe l l # O > " , l ine 1 , in <modul e >


import quant
ImportError : No module named ' quant '
>>>

以上 出错信息告诉 我们 quant 模块没有预先安装。 可以执行以下 步 骤找到该模块。

l . 进入 https : / / pypi . python . o rg /pypi 网站的 Pyth on 软件包索 引 。

2 . 在该网站上 , 浏 览所有的软件
包。
3 . 选 择 编 程 语 言 Pyth on ( h七tp s : / / pypi . python . org/pyp 立 % 3Aac巨on =
b rowse ) 。
4 . 选择金融保险业( ht七ps : / /pyp i . python . org/pyp 立 % 3Aac巨on= br owse ) 。

5 . 单击 显 示所 有 ( https : / / pypi . python . o r g /pyp i ? : a c t i on = brows e & c =


3 3 & c=2 1 4 ) 。

6 . 用关键字 q u ant 搜索列 表。

7. 最后找到该模块, 如图 5 - 11 所示。

霆回 Enterprise architecture for quantitative anafysis in finance. 1


图 5- 1 1

单击 q u ant 后 , 我 们 找 到 它 的 相 关 网 页 https : / / pypi . python . o rg/pyp i /


qu ant / 0 . 8 。 把这 个软件下载到硬盘, 并确保 Pyth on包含该 目录路径 。

5.3 模块之 间 的 相 互依赖性


本书的引 言部分指出使用 Pyth on 的优势之 一是其包括数百个称为模块的专用软 件
包。
为了避免重复工作并节 省开发新模块的时间, 后来生成的模块选择使用 一 些 早 期模块里的
函 数, 也就是说, 它们依赖于早 期模块。

模块的优点是显 而 易见的, 开发人员在构建和测试一 个新模块时, 可以节 省 大量的时


间和精力 。 然 而, 一
个缺点
是安装模块变得困 难 。 为了便千安装, 有两 种方法。 第 1 种方
是把所有模块捆绑在一 起成为一 个超级包, 并确 保所有模块配合很 好, 这样就避免了独

立安装若 干模块的麻烦 。 这是理想的情 况 。 模块捆 绑的潜在问题
是, 各个模块的更新可能
无法及时体现在超级包中 。 第 2 种方法
是尽量减少相互之间的依赖 关系。 它 使得维护模块
74 第 5 章 模块简介

较为容 易, 但如果需要安装好几 个模块, 可能相当麻烦 。 Linux 操作系统下 有 一 个好的办法:


包的安装程序包的发布者可以声
使用软件 。 明 依赖 关系并在 Linux 存储库 里跟踪它们。 SciPy
模块、 NumPy 模块和 quant 模块都是这样设立的, 非 常 方 便 。 下 一 章 将 讨 论两 个最重要的
模块一NumPy 和 SciPy 。 单独安装它们并不简单。 我们会选择 一 个称为 Anaconda 的超级
包 。 安装 Anaconda 之 后, NumPy 模块和 SciPy 模块都将是可用的 。 表 5- 1 列 出 了 与金融有
关 的 Python 模块。

表 5-1

模块名 描述

Y stockquote 从雅虎财经网 站下载股票价格数据

Quant 金融蜇化分析的企业级架构

trytond_currency Trytond 外汇分析模块

Economics 经济数据处理 和分 析模块

trytond_project Trytond 项 目 管理模块

trytond_analytic_account Trytond 会 计 和 金 融 图 表及包括分析模块

trytond_account_statement Trytond 会计和金融报表分析模块

trytond_stock_split Trytond 股票拆分分析模块

trytond_stock_ forecast Trytond 股票预测分析模块

Finance 经过优化的金融风险计算模块

FinDates 金融行业 日 期处 理模块

网 页 h七tps : / / wi k i . python . org/mo i n / U s e fu l Modu l e s 列 出 一 些 最常用的


Python 模块的链接 。

包的索 引可在 https : / / pypi . python . o rg/pyp i 查到。 注意必须先注


Python 软件
册才能查看完整的列 表。

5.4 小结

本章 讨论了与模块有 关的内容 , 如查 找所有可用的或 已安装的 模块, 以及如何安装一


个新的模块。 本书将 使用儿十 个模块, 因此, 理解模块是至 关重要的。 比如, 在第 6 章讨
练习题 75

论著名的 Black-Scholes-Merton 期权模型时, 会重点讨论一 个名为 matp l o t l ib 的模块,


这对于绘制不 同的图表是非常有用 的。 第 6 章还将介绍最重要的两 个模块 Num.Py 和
SciPy。 这两 个模块都广泛用 于科学和金融领域的计算。 这本书中的许 多 章节 都 用 到这两 个
模块, 许多其他的模块也依赖千这两 个模块。

练习题

1 . 什么 是模块?

2. 如何知道 math 模块包含多 少 个函数?

3. importmath 和 f rommathimpo rt*有什么区别 ?


4 . 如何导入某些 特定的
函数 ?

5 . 在哪里可以找到某 个模块的使用 手 册 ?

6 . 如何删 除模块?
函数, 怎 么 只导入这几 个
7. 如果只需要 math 模块里的几 个 函数 ?

8. 什么 是模块依赖性 ? 为什么 安装一 个模块时, 模块依赖性会是一 个问题?

9. 有 一 个名为 N u mPy 的模块, 它依赖千 多 少 个模块?

简单的模块?
10. 初学者如何编写 一 个
1 1 . Python 目前包含有 多 少模块? 如何找到 一 个完整列 表?

1 2 . 找 出与 z ip import 模块相关的主要内容 。
第6章
NumPy 和 SciPy 模块简 介

本 章 将介绍两 个广泛用于 科学和金融计算的重要模块 N u mPy 和 SciP y。 本书用到


的许多其他模块都依赖这两 个模块。 本章主要内容 如下。

• NumPy 和 S c i P y 模块的安装

• 利用 Ana conda 启 动 Python

• 使用 NumPy 和 s 立 P y 的示例

• 显 示 NumPy 和 S c i P y包含的所有 函数

• 获取某 个函数的更多信息

• 理解列 表数据 类型

• NumPy 里的矩 阵以及矩阵的逻辑关 系

• 特殊矩 阵: 全 一 矩阵、 全 零 矩 阵和单位矩阵

• 执行矩 阵运算: +、 -、 *和I

• x . sum ( )函数

• 通过循环遍历一 个数组

• S c i P y 模块的子
包列 表

• 累积标准正 态分布

• 随机数的生成

• S c i Py包含的统计子 模块 C s ta区 )

• 插值、 线性方程组和优化
6.2 从 Anaconda 启 动 Python 77

• 线性 回 归 和资 本资 产定价模型 C CAPM )

• 从 外部文本文件读取数据

• 如何独立安装 NumPy 模块

\
• 数据类型简介

6. 1 安装 NumPy 和 Sci Py 模块
第 5 章讨论了模块之间 的 依 赖性并提到依赖性可能增加安装一 个模块的难度。 幸运的
是 , 有些 超级软件包, 比如 An a conda 和 E nthought Canoy, 可以同时安装多 个模块。
这本书用到了 Ana conda , 因为它同时包含 NumPy 和 S c i Py 这两 个模块 。 执行以下两 个
步骤来安装它。
1 . 访问 http : / / c o n t i nuum . i o /down l oads 。
2 . 根据你 的计算机, 选择适当的软件下载, 如图 6- 1 所示 。

Download for w,ndowS Download for OSX Download for Linus

Anaconda 4.2.0
For Windows
钮°"""' K 8SD IK<咄妞炉,心“平m出心、to 叩 归O心

..-..,,.u,.,.,,.. ,..
沁戊江心
32 BIT INSTALLER (33�沁

图 6- 1

安装完成 后将看到相关的 目 录, 如 c :\Users\yany\AppData\Local\Continuum\Anaconda3\ 。


除了 NumPy 和 SciPy 外, Anaconda 还安装了 我们 计划在这本书中讨论的其他 3 个模块。
可以在 https://docs.continuum.io/anaconda/pkg-docs 看到 Anaconda 包含的模块的完整列 表
(对应于 Anaconda 4.2.0 和 Python3 .5 版本, 共计 445 个)。

6.2 从 Anaconda 启 动 Python


在 Windows 操作系统下, 找到 " Python.exe " 然后单击它。 图 6-2 所示 的 Python 窗 口
将出现:
78 第6章 NumPy 和 SciPy 模 块 简 介

匾匾圈圈圈一i�I 图 6-2

图 6-2 显示安 装路径为 : c:\Users\yany\AppData\Local\Continuum\Anaconda3\ 。 为 了 测


试是否 已经正确 安装 NumPy 和 S c i P y , 需 要 输 入下 面 的 两 个 命 令 来 导 入它 们 。 如 果 没 有
出 现错误信 息 , 就意味着 已经正确 安装它们 。

> > > import numpy as np


>>>import scipy as sp

前面几章介 绍 过 , 可 以 用 f r om nump y imp o r t * 命 令 , 而 不 是 imp o r t numpy a s


np 命 令 来把 NumPy 模块包含 的 所 有 函 数 添 加 到 工 作 空 间 中 。 然而 , 使用 sp . p v ( ) 取 代
pv ( ) 能够更清 楚地表 明 pv ( ) 函 数 是包含在 一 个 名 为 sp 的 模 块 里 。 因 此 大 多 数 开 发 人 员 更

愿意使用 imp o r t n ump y a s np 命 令 。 从现在 开 始 , 我们将遵从这 一 传 统 。 可 以 生 成
个快捷 方 式 , 即 将它 从上述 目 录 移 动 到 桌 面上 , 生 成 一 个 Python 图 标 。

6.2. 1 使用 NumPy 的示例


在 下 面 的 例 子 中 , NumPy 包 含 的 np . s i z e ( ) 函 数 显 示 一 个 数 组 中 的 数 据 个 数 ,
np . s 七d ( ) 函 数 用 于 计 算 标准 方 差 。

> >> import numpy as np


>>>x= np . a r r ay ( [ [ l , 2 , 3 ) , ( 3 , 4 , 6 ) ) ) # 2 by 3 mat r i x
>>>np . s i z e ( x ) # number o f data i tems
6
>>>np . s i z e ( x , 1 ) # show number o f column s
3
>>> np . s td ( x )
1 . 5 7 2 3 3 0 1 8 8 67 6 1 0 0 5
>>>np . s td ( x , 1 )
Array ( [ 0 . 8 1 6 4 9 65 8 , 1 . 2 4 7 2 1 9 1 3 )
> > >total=x . sum ( ) # pay attention to 七 he fo rmat
>>>z=np . random . rand ( S O ) # 50 ra ndom obs f r 叩 [ O . 0 , 1 )
>> > y=np . r andom . norma l ( s i z e = l O O ) # f rom s t andard norma l
> > > r=np . a r ray ( r ange ( 0 , 1 0 0 ) , float) / 1 0 0 # f rom 0 , . 0 1 , to . 9 9

NumPy 的 数 组 是 一 个连 续 的 内 存块 , 直接传递给 LAPACK 进 行 计 算 。 LAPACK 是数


值线性代数 的 软 件库 , 使 Python 可 以 非常 快地完成矩 阵运算 。 NumPy 的数组就像 MATLAB
6.2 从 Anaconda 启 动 Python 79

的 矩 阵 。 与 Python 的 列 表数据类型 不 同 , 数组应 当 包 含相 同 类 型 的 数据 , 例 如 :

>> >np . a rray ( [ 1 0 0 , 0 . 1 , 2 ] , f l oa七 )

实 数 的 类 型 是 f l oa t 6 4 , 任意数值变 量 的 默 认 类型 也 是 f l oa t 6 4 。 在 以 上 的 例 子 中 ,

可 以 看到 , np . a r r a y ( ) 函 数 把 个 包 含 整 数 型 数 值 的 列 表转换 为 数 组 。 如 果 想 改 变数据
的类型 , 可 以 用 第 2 个 参 数 指 定 数 据 的类 型 。

>>>x = [ l , 2 , 3 , 2 0 )
> > > y=np . a rray ( x , dtyp e = f l o a t )
>>>y
array ( [ 1 . , 2 . , 3 . , 20 . ) )


在 以 上 的 例 子 中 , dtype 是 指 定 数 据类 型 的 关 键 字 。 个列表可 以包含不同类型的数

据 , 而 不 会 引 起 任 何 问 题 。 但 是 , 将含有不 同 数据类 型 的 列 表转 换 成 个 数 组 时 , 会得到
如 下 的错误信息 。

>>>x 2 = [ 1 , 2 , 3 , " good " )


>>>x2
[ 1 , 2, 3 , ' good ' J
>>>y3=np . a rray ( x2 , f l oat )
Traceback (mo s t recent c a l l l a s t ) :
File " <pyshe l l # 2 5 > " , line 1 , in <modu l e >
y3 = np . array ( x2 , float)
ValueError : cou l d not conve rt stri ng to f l oat : ' good '
. ll)

6.2.2 使用 SciPy 的示例


以下 几个例子用 到 SciPy 模块包含 的 函 数 。 第 1 个例子是有关净现值 ( NPV ) 的 函 数 。

>>> import scipy a s s p


>>>cashf lows= [ S 0 , 4 0 , 2 0 , 1 0 , 5 0 ]
>>>x = sp . npv ( O . l , cashflows ) # e s t imate NPV
>>> round ( x , 2 )
144 . 56

sp . npv ( ) 函 数计 算给 定 的 一 组现金流 的现值 。 第 1 个 输 入 参 数 是折现率 , 第 2 个输


入参数是现金流 的 数 组 。 sp . npv ( ) 函 数 不 同 于 Excel 的 NPV 函 数 。 Excel 的 NPV 函 数 不
是 一 个 真 正 的 NPV 函 数 , 它 实 际 上 是 一 个计算 PV 的 函 数 。 它 假 设 第 1 笔未来现金流发生
80 第6章 NumPy 和 SciPy 模 块 简 介

在第 1 个 周 期 的 结 束 。 图 6-3 展 示 如 何使用 Excel 中 的 NPV ( ) 函 数 。

E F G H
50 40 20 10 50

图 6-3

假 设 只 有单笔现金 流 , 下 面 的 代码可 以 说 明 sp . npv ( ) 函 数 的 计算 结 果 。

>»c = [ l O O ]
>>sp . npv ( O . l , c )
100 . 0


基于这个理解 , 如 果 有 笔 初 始 的现金支 出 , 金 额 为 1 00 , 结 果 如 下 。

>>>cas h f l ows= [ - 1 0 0 , 5 0 , 4 0 , 2 0 , 1 0 , 5 0 ]
>>>x=sp . npv ( O . l , cashflows )
>> >r ound ( x , 2 )
31. 41

sp.pmt( )函 数 用 来 解 答 以 下 问 题 : 假 定 年 利 率 ( A PR ) 是 4.5% , 每 月 复利 。 每 个 月 需

要 支 付 多 少来偿还 笔 为 期 30 年 , 金 额 为 250 000 美 元 的 按 揭 贷 款 ?

»>payment=sp . pmt ( 0 . 0 4 5 / 1 2 , 3 0 * 1 2 , 2 5 0 0 0 0 )
>>> round ( payment , 2 )
-1266 . 7 1

与 sp . npv ( ) 函 数 类似 , sp.pmt()函 数模仿 Excel


丘 =PMT(0.045/12,30*12,250000) 中 的 PMT 函 数 , 如 图 6-4 所 示 。 它 的 输入值包括有
E

效利 率 、 周 期 的 数 目 和现值。
�1 sp . pv ( ) 函 数 模 仿 Excel 中 的 PY 函 数 。 调用
图 6-4
sp . pv ( ) 的 格 式 是 sp . pv C rate , nper , pmt ,
fv=O . 0 , when= ' en d ' ) 。 rate 是 贴现 率 , nper 为 周 期 数 , fv 是 未 来现金量 , 其默认值为

0。 最后 个 输 入 参 数 指 定 现金流是在每个 时 间 段 的 开 始或结 束 完 成 ; 如 果 缺省 , 则意 味着
在每 个 时 间 段 的 结 束 时 支 付 。 调 用 该 函 数 的 命 令 如 下 。

>> >pv l=sp . pv ( 0 . 1 , 5 , 0 , 1 0 0 ) # pv o f one future ca_sh f l ow


>>> round ( pvl , 2 )
-92 . 0 9
6.2 从 Anaconda 启 动 Python 81

>>>pv2 =sp . pv ( O . l , 5 , 1 0 0 ) # pv o f ann u i ty


>>> round ( pv2 , 2 )
-379 . 08

sp . fv ( ) 函 数类 似 于 sp . pv ( ) 函 数 。 给 定 n 个 数值 X1 , X2 , X3, … , 用 下 面 的 公 式估计
算术平均值和 几何平均 值 :

I x;

算 术平 均 值 = ( 6- 1 )
n

n l / ll

几何平均值 = ( Q x; ) ( 6-2)

假 设 有 3 个 数字 a , b 和 c 。 它 们 的 算术平均值为 ( a+b+c ) /3 , 而它们 的 几 何平均值是


(a*b*cY( l /3 ) 。 对 千 2 、 3 和 4 这 3 个值 , 计算这两个平均 值 的 代 码如 下 。

»> ( 2 +3+ 4 ) / 3 .
3.0
>>>ge o_rnean= ( 2 * 3 * 4 ) * * ( 1 . / 3 )
>>> round ( geo_rne a n , 4 ) 2 . 8 8 4 5

当有 n 个 回 报率 时 , 计 算 其 算 术 平 均 回 报 率 使用 相 同 的 公 式 , 但 是 其 几 何 平 均 回 报 率
的计算公式 不 同 , 如下所示。

沪,
算 术平均值 = ( 6-3 )
/;l

11
1/n

几何平均值 = [ CT ( 1 + R; )] -1 ( 6-4 )

sp . prod ( ) 函 数计 算所有数据 项 的 乘 积 。 可 以 用 它 来 计 算 回 报 率 的 几 何平 均 值 。

>>>import s c ipy as s p
>>>ret=sp . array ( [ 0 . 1 , 0 . 0 5 , - 0 . 0 2 ] )
>>>sp . mean ( re t ) # ari· thmetic mean 0 . 0 4 3 3 3
> >>pow ( sp . prod ( re t + l ) , 1 . /l e n ( re 七 ) ) - 1 # geometric mean 0 . 0 4 2 1 6
82 第6章 NumPy 和 SciPy 模块简介

另 外两 个 有 用 的 函 数 是 sp.unique()和 sp.median() , 代码如 下 。

>>>sp . un i qu e ( [ 2 , 3 , 4 , 6 , 6 , 4 , 4 ] )
Arr a y ( [ 2 , 3 , 4 , 6 ] )
>>>sp . median ( [ 1 , 2 , 3 , 4 , 5 ] )
3.0

Python 的 sp . pv ( ) 、 sp . fv ( ) 和 sp . pmt ( ) 函 数 分别对应 Excel 的 PV ( ) 、 FV ( ) 和


PMT ( ) 函 数 。 它 们 具有相 同 的 符 号 约 定 : 现值 的 符 号 与 未 来 值 的 符 号 是 相 反 的 。 在 下 面 计

算现值的例 子 中 , 如 果输 入 个 正 的 未 来 值 , 得到 的现值将 是 个 负 数 。

>>>import s c ipy a s sp
>>>round ( sp . pv ( 0 . 1 , 5 , 0 , 1 0 0 ) , 2 )
-62 . 0 9
>>>round ( sp . pv ( 0 . 1 , 5 , 0 , - 1 0 0 ) , 2 )
62 . 0 9

6.3 显示 NumPy 和 SciPy 包含的所有 函 数



可 以 用 儿 种 方 法 找 出 包含在某 模块 中 的 所有 函 数 。 首 先 , 可 以 查 阅 相 关 的 手册 。 其
次 , 可 以 用 下 面 的 代码 。

>>>import numpy as np
>>>di r ( n p )

为 了 节 省 空 间 , 只 在 图 6-5 显 示 输 出 的最初儿行 。

图 6-5
一 一
个更好 的 方 法 是 把所 有 函 数 的 名 字输 出 并储存在 个 数组 中 。

>> >x=np . a rray ( dir ( n p ) )


>>>len ( x ) # showing 七 he l e ng 七 h o f the array 5 9 8
>>> x [ 2 0 0 : 2 1 0 ] # showing 1 0 lines s t a r t in g f rom 2 0 0

输 出 显示如 图 6-6 所 示 。
, · , · · · · · · · · ", . I
6.5 理 解 列 表 数据类 型 83

I 图 6-6

同样, 要找到 SciPy 模块里的所有函数, 加 载该模块之 后, 使用 di r()函数得到图 6-7 所


示的结 果。

>>>import scipy as sp

Iii}(\I·:.::· ;:):·i\t'.\\/!i)!,!; i:::: llii'. !i)ri{Ii !i!i;


>>>di r ( sp)

1
图 6-7

6.4 关千某个 函 数 的 详 细信息

_ 一
使用 d江 ( np ) 命 令 可列 出所有函数, 其 中 包括 s t d ( )函数。 要查找有 关 s 七d ( )函数


的信息时, 使用 help ( np . st d ) 。 部分输出如图 6-8所示。

1•1•1111•11111111111111111111!mtttnmt111111
N .. ... ,,.1 .. ' I' . I , ,. ,..11,,, 1· , I ,. .
, I .,, , I ,,, I" , •i <• ,I ,. j

、 ,,,..
; , , , ,.,, , i.- , .,. i ,, ,I ,,, , , · I '"" · , ,. , ,.,., .,f I /p· I"、,- .,,! " ' ., ,!1 1 1'11" ' ' 1"『, .
, , 1 ..- , , 1 , " , I ,. , , . ., , I ,,. , ,.,,1 .,,.,1 ,1,., , .,1 ; ,.,, i ""'I" ' ' ,·,I I ,,,
I I ., • ' , ,., i .. ,. 1·., · !,, ,1, I "' I • " , lw "" 1 , ,,..,. 1· I j,, I"'' ,! 1 ,.,f , . 1 .

;· , ,、 ''" ! ' I、

. ,.,、 , ,, i r J ,
, I. " I ' I ' I I" • .'"I ' '.'I 'I . ., ' . ' ' " " " ; t ,.. ' " ., I'"
" I . " l'I I " •
f! . I . I ,, ,, , i,., J. • I,, ! ,,,.1 ,;·,I ,1, " I , r j,,,, I , "『,I'" , ,. ,I . 1 1 ..- ,I,·I ., " I 1 ,
1,, , " ''I" ' ' ,. I J., I ,,,,J ,,.,1 ,I,.._, f,d I ,11 .. 1 I t,,. J 1,,1 I o•[l,•1I ,>i'I、 ,,, .

图 6-8

6.5 理解 列 表数据类型

第 3 章介绍了 元组作为数据 类型之 一 。 回 顾 一 下, 元组 由 一 对 圆 括号 来定义, 如


84 第6章 NumPy 和 SciPy 模 块 简 介

x= ( l ,2,3, "Hell o")。 此外, 定义 个元组变量之后, 不能改变它的值 。 与元组一 样, 列表


数据 类 型 可以包含不 同 类 型 的数据, 而且 第 1 下标 从 0 开始。 以下 P yth on 命 令 定义变量


x 为一 个列表。

>>>x= [ l , 2 , " John " , "M" , " S tuden t " ]


>>>t ype ( x )
<class ' l ist ' >


个列 表变量通过一 对方括号 []来定 义, 并且 可以包含不 同 类型的数据。 可以用不同
的方式来使用某 个数据项。 调用不 同数据项的命令如下。

>>>x
( 1 , 2 , ' John ' , ' M ' , ' S tudent ' J
>>>x [ l )
2
> > >x [ 2 : ]
[ ' John ' , ' M ' ' ' S tudent ' ]

与 元组数据 类型不同的 是, 可以修改 一 个列 表


变量 的值 。

6.6 使 用 全 一 矩 阵 、 全零矩 阵 和 单位矩阵


构建不 同矩 阵的代码 如下 。

>>> import numpy a s np


> > > a=np . z e r o s ( l O ) ar ray with 1 0 z e r os
###########

>>>b=np . z e r o s ( ( 3 , 2 ) , dtype=f loat ) 3 by 2 with z e r o s


> > > c= np . ones ( ( 4 , 3 ) , f l oat ) 4 by 3 w i t h a l l ones
>>>d=np . a r ray ( range ( l O ) , f l oat ) 0 , 1 , 2 , 3 . . up to 9
> > > e l =np . i den t i t y ( 4 ) ide n t i t y 4 by 4 ma t r i x
> > > e 2 =np . eye ( 4 ) s ame a s above
> > > e 3 =np . eye ( 4 , k= l ) 1 s 七 art f r om k
> > > f = np . a r ange ( l , 2 0 , 3 , f l oat ) f r om 1 to 1 9 i n te rval 3
>> >g=np . a r r ay ( [ [ 2 , 2 , 2 ) , [ 3 , 3 , 3 ) ) ) 2 by 3
> >>h=np . ze r os_l i k e ( g ) a l l zeros
>>> i =np . ones_l i ke ( g ) a l l on e s

6.7 执行数组操作
我们 有时候需要改变一 个矩 阵或数组的大小。 比 如把 组 1 00 个随机数

变成 一 个 20X
6.8 数组的加 、 减、 乘 、 除 85

5 的 矩 阵 , 或执行相 反 的 操 作 。 NumPy 包含 的 两 个 函 数 f l a t ten ( ) 和 r e s h ape ( ) , 可 以


用 来完成 这 两 个操作 , 具 体如 下 。

»>pv= np . array ( [ [ l 0 0 , 1 0 , 1 0 . 2 ) , ( 3 4 , 22 , 3 4 ) ) ) # 2 b y 3
>>>x=pv . fl a 七 ten ( ) \ # ma t r i x become s a vector
>>>vp2 = np . r e s hape ( x , [ 3 , 2 ) ) # 3 by 2 now

6.8 数组的加 、 减 、 乘 、 除
数组 的 加 和 减 运算 容 易 理 解 。 然 而 , 乘法和 除 法 有 不 同 的 定 义 。 以 乘 法 为 例 , A X B 可
以有两个 含 义 : A 和 B 相 同 位置 的 数 据 项 相 乘 ( A 和 B 应 该具有相 同 的 维 数 , 都 为 n 行 m
列 ) 或矩阵乘法 ( A 的 列 数 等于 B 的 行 数 , 也 就 是 说 , A 是 n X k 矩 阵而 B 为 k X m 矩 阵 ) 。

6.8. 1 进行加减运算
增 加 或减去两个数组时 , 它 们 必 须 具 有相 同 的 大小 , 也就是 , 两 者 的 维 数都是 n X m 。

如果 它们有不 同 的 大 小 , 将得到 个 出 错信息 。 例 如 , 两 个现金流数 组 的 和 :

>>>cashFl ows_l = np . a rray ( [ 一 1 0 0 , 5 0 , 2 0 ] l


>>>cashFlows_2 = np . array ( ( - 8 0 , 1 0 0 , 1 2 0 ] l
>>>ca shFlows_l + cash Fl ows_2
arr ay ( ( - 1 8 0 , 1 5 0 , 1 4 0 ] )

6.8.2 执行矩阵乘法运算
对 千 矩 阵 乘 法 A X E, 矩 阵 A 和 B 的 维 数 应 该 分 别 是 n X k 和 k X m 。 假 设矩 阵 A 和 B
分别有以下公式。


(

bl

b1 ·: b II
:
a

al

. .


. .

_. .

k
1

. .

A

B
=

•••
·:


. .
. an

( 6-5 )
bn

an





..

\

k
k

1

x






B
A

n
.


.
:
.

、」

CIm…

A•B�C� ( 6-6 )
cnm
丿

其 中 的 各 个 数 据 项 Cp
; 将 由 以 下 公 式得到 。
86 第6章 Nu1nPy 和 SciPy 模块简介

ciJ = LLLa;A,1
n m k

i=I )=I i=I

假设有两 个矩 阵 X( nX k)和 Y( kX m) , 它们的点积 将获得一 个 nX m 矩阵, 代码如下。

> > >x = np . array ( [ [ l , 2 , 3 ) , [ 4 , 5 , 6 ) ) , f lo a t ) # 2 by 3


> > > y=np . array ( [ [ l , 2 ) , [ 3 , 3 ) , [ 4 , 5 ] ] , f l oat ) # 3 by 2
> >>np . do七 ( x , y ) # 2 by 2
Arr a y ( [ [ 1 9 . , 23 . J ,
[ 43 . , 53 . ) ) )

另外, 可 以先把数组转换 成矩阵, 然后用*来计算矩 阵乘积, 代码如下。

>> >x=np . ma t r i x ( " l , 2 , 3 ; 4 , 5 , 6 " )


>>>y=np . ma t r i x ( " l , 2 ; 3 , 3 ; 4 , 5 " )
> > >x * y
Arr a y ( [ [ 1 9 . , 2 3 . ] , [ 4 3 . , 5 3 . ] ] )

其 实, 数组与 矩 阵 的转换相当容易, 代码如下。

>>>xl=np . arr ay ( [ ( 1 , 2 , 3 ] , ( 4 , 5, 6 ] ] , f l o at )
>>>x 2 =np . ma t r i x ( x l ) # from array to ma七rix
>>>x 3=np . arra y ( x 2 ) # from mat r i x t o array

6从3 执行逐项相乘的乘法运算
当两 个 阵 列 具有相同的维数时, x*y 将执行逐项相乘的乘法运算。 当 A 和 B 都具有相
同的维数, 如 nX m 时, 逐项相乘的乘积将有 以下形式。

cij = LLaiij
II m
( 6-7 )
i=l }=1

例如:

>>>x= np . arr ay ( [ [ 1 , 2 , 3 ] , [ 4 , 5 , 6 ] ] , f l o a t )
> > > y=np . a rray ( [ [ 2 , 1 , 2 ] , [ 4 , O , S J ] , fl oa七 )
>>>x * y
Array ( [ [ 2 . , 2 . , 6., l , [16. , 0., 30 . ] ] \)
6. 1 1 使用 与 模块相关 的 帮 助 87

6.9 x.sum() 函 数
变量 x 被 定 义 为 一 个 NumPy 的数组后 , 可 以 使用 x . f u n c t i o n ( ) 进行相 关操作 。
x . s um ( ) 的 用 法 如 下 。

> > > import numpy a s np


> > >x=np . a rray ( [ l , 2 , 3 ) )
>>>x . sum ( )
6
>>>np . s um ( x )
6

如 果变 量 x 是 一 个 NumPy 的 数 组 , 可 以 用 同 样 方式调 用 其他 点 函 数 , 如 x . mean ( ) 、


x . min ( ) 、 x . max ( ) 、 x . var ( ) 、 x . a r gmin ( ) 、 X . c l ip { ) 、 x . copy ( ) 、 x . diagonal ( ) 、
x . r e s hape ( ) 、 x . 七 o l i s 七 ( ) 、 x . f i l l ( ) 、 x . t r an s p o s e ( ) 、 x . f l a tten ( ) 以 及
x . argmax ( ) 。 这些点 函 数 方 便 易 用 。 例 如 :

> > >cashFlows=np . array ( [ - 1 0 0 , 3 0 , 5 0 , 1 0 0 , 3 0 , 4 0 ] )


>>>cashFlows . mi n ( )
-100


>>>cashFlows . ar gmin ( )

以上 x . mi n ( ) 函 数 表示数组 的最小值 , x . ar grni n ( ) 函 数给 出 最 小值在数组 中 的位置 。

6. 1 0 遍历数组的 循环语句

用 下 面 的 for 循环语句遍历数组 , 依 次 打 印 数组 包 含 的 每 个数值。

>>> import numpy a s np


> > >cash_flows = np . array ( [ - 1 0 0 , 5 0 , 4 0 , 30 , 2 5 , - 1 0 , 5 0 , 1 0 0 ) )
> >> for cash in cash f l ows :
print ( x )

6. 1 1 使用 与模块相 关 的 帮 助

可 以 使用 help ( ) 函 数 来 了 解 NumPy 和 SciPy 的 更 多 信 息 , 代码如 下 。


88 第 6章 NumPy 和 SciPy 模 块 简 介

» >he l p ( )
help>n umpy

输 出 的 前 几行如 图 6-9 所 示 。

图 6-9

同样可 以 在 帮 助 窗 口 了 解 Sc iPy 的 更 多 信 息 。

>>>help ( )
help> s c i py # to s ave space , the output i s not shown

6. 1 2 Sci Py 的 一 系 列 子 函 数包
SciPy 大约 有十几个 子 函 数包 , 表 6-1 列 出 了 SciPy 的 子 函 数包 。

表 6-1

子 函 数包 描述

Cluster 聚类算法

Constants 物理和数学常揽

Fftpack 快速傅里叶变换

Integrate 积分和 常微分方程

Interpolate 插值和 光滑样条 函 数

Io 输入与输出
6. 1 3 累 积标 准 正 态 分布 89

续表

子函数包 描述

Linalg 线性代数

Ndimage N-维 图 像处理

Odr 基于正交距离 测 度 的 回 归模型

Optimize 优化和 求解方程

Signal 信号处理

Sparse 稀疏矩阵和相关的算法

Spatial 空 间 数据结构和算法

Special 特殊 函 数

Stats 概 率 分 布 函 数和统计分析

Weave CIC 丑编程接 口

6. 1 3 累积标准 正态分布
在第 4 章中,我们 自 己 编 写 累 积标准正态分布 函数来给看涨期权定价 。 SciPy 的 一个子
模块提供了 累积标准 正态分布 函数 。 例 如, 累积标准正态分布 函数在零点的取值 如 下 。

>>>from s c ipy . stats import norm


>>>norm . cdf ( O ) 0 . 5

因 此, 可以只用 5 行代码给看涨期权定价 。 以下 代码是使用现有模块带来好 处的 一个


典型例子。

from scipy import l og , exp , sqr t , st ats


de f bs_call ( S , X , T , r , s i gma ) :
dl= ( log ( S /X ) + ( r+s igma * s i gma/2 . ) * T ) / ( s i gma * s qrt ( T ) )
d2 = d l - s i gma * s qrt ( T )
return S * s t a t s . norm . cdf (dl ) -X* exp ( - r * T ) * s tats . norm . cdf ( d2 )

现在, 输入 一 组值调用函数 b s - c a l l 。

>>>pri ce=bs_cal l ( 4 0 , 4 0 , l , 0 . 0 3 , 0 . 2 )
>>> round ( p r i ce , 2 )
3 . 77
90 第6章 NumPy 和 SciPy 模 块 简 介

6. 1 4 与 数组相 关 的逻辑关 系
有 的 数 据 取 值为 真 ( True ) 或假 ( False ) 这两者之 一 , 这种 数 据 类 型称 为 布 尔 数 。

>>> import numpy a s np


>>>x = np . a r r ay ( [ True , Fa l s e , True , False ) , b ool )
>> >a=any ( x ) # i f one i 七 em i s TRUE then return TRUE
>>>b = all ( x ) # i f a l l a r e TRUE then return TRUE
>>>cashFlows = np . array ( [ - 1 0 0 , 5 0 , 4 0 , 3 0 , 1 0 0 , - 5 ) )
>>>a = cashFlows>O # [ Fa l s e , True , True , True , T rue , Fa l s e )
> >>np . logi cal—and ( cashFl ows >O , cashFlow s < 6 0 )
Array ( [ Fa l s e , True , True , False , Fa l s e ) , dtype=boo l )

有些逻辑 函 数 , 如 l o g i c a l an d ( ) 、 l o g i c a l o r ( ) 和 l o g i ca l not ( ) 函 数 , 可
以对每个数据项进行 比 较 。 另 外 , 可 以 保存逻辑 比 较 的 结 果 , 为 后 面 的代码所用 。

>>>cashFlows=np . a rray ( [ 一 1 0 0 , 5 0 , 4 0 , 3 0 , 1 0 0 , - 5 ) )
>>>index = ( cashFlows > O ) # index i s a Boolean va riable
>>>ca shFlows [ i nde x ) # re 七 r i eve po s i tive cash f l ows
Arr a y ( [ 5 0 . , 4 0 . , 3 0 . , 1 0 0 . ) )

6. 1 5 Sci Py 的 统计子模块 ( stats )



SciPy 包 含 个统计子模块 , 即 stats 模块 , 值得特别 关 注 。 该模块帮助我们解答许 多
金融 问 题 。 用 以 下 代码找到该模块包 含 的 所 有 函 数 。

>>>f rom s c ipy import s 七 ats


> >>dir ( s ta 七 s )

为 了 节 省 空 间 , 图 6- 1 0 只 显 示 了 最初 的 几 行 。

从 d江 ( s ta t s ) 的 输 出 中 , 可 以 找到 个 t t e s t_l s amp ( ) 函 数 ( 不 过 该 函 数 没有
显 示在 图 6- 1 0 中 ) 。 随 机 生 成 服 从 标 准 正 态 分 布 的 1 00 个 随 机 数 , 然 后 使 用 ttest_ I samp()
函 数进 行 单 样 本 t-检 验 , 以 测 试均 值 是否 为 0 。 基 千 t 值 C 1 . 1 8 ) 和 p 值 ( 0.24 ) , 不 能 拒
绝零假 设 , 这 说 明 我们 的 样 本 来 自 均 值 为 0 的 分 布 。 代 码如 下 。

>>> impo r t nurnpy as np


> > > from scipy import s 七 ats
6. 1 6 SciPy 模 块 的 插 值 方 法 91

>> >np . random . s e ed ( l 2 4 ) * get the s ame random values


>> >x=np . r andom . norma l ( 0 , 1 , 1 0 0 ) jf mean = O , std = l
>>>s kew= s t a t s . s kew ( x ) *s kewne s s i s - 0 . 2 2 9 7
>>>stat s . tt e s t_ l s amp ( x , O ) *i f mean i s zero
( a rray ( 1 . 1 7 6 ) , 0 . 2 4 2 2 8 ) *,
T -value / P -value


I门

.ttr
,.
II
l 11

l ll I

·1 1�I
:几' an rut·

”jd
,
I -

-
2l“
1.l

,'

图 6- 1 0

利用 NumPy 的函数, 可以获得符合若干分布的随机数 。

>>>impor 七 nurnpy as np
>>>s = np . randorn . s tanda rd_t ( l O , s i z e = l O O O ) # from s tandard- T , df = l O
>>>x=np . r andom . uni form ( l ow= O . O , hi gh=l . O , s i z e=l O O ) # uni form
>>>stocks=np . r andom . random_i ntege r s ( l , 5 0 0 , 2 0 )
>>>stocks
array ( [ 3 7 1 , 1 5 , 1 5 8 , 4 6 8 , 2 9 9 , 4 7 0 , 2 5 7 , 4 8 1 , 7 6 , 1 9 6 , 3 5 5 , 3 8 6 , 4 3 8 ,
4 8 4 , 4 1 , 3 9 , 2 2 2 , 37 7 , 4 5 5 , 4 6 ] )

以上代码在 1 � 500 中随机挑选 了 20 个数。

6. 1 6 SciPy 模块 的插值方法

在下面的代码里 , x 是横坐 标 , 其 值为 0 ,...., 1 0 , 而 y= exp ( - x/ 3 ) 作为纵坐标 。 我们打


算采用 两种方法在 y 值之间进行线性插 值和立方插值。 SciPy 的参考手册提供下面的代码来
计算插值 。

>>>import nurnpy a s np
>>>import rnatp l o 七 l ib . pyp l o t as p l t
>>>from s c ipy . inte rpolate import interp ld
>>>x = np . l i n space ( O , 1 0 , 1 0 )
>>>y = np . exp ( - x / 3 . 0 )
92 第6章 NumPy 和 SciPy 模 块 简 介

> > > f = i n 七 e rp l d ( x , y )


> > > f 2 = interpld ( x , y, ki nd= ' cubi c ' )
> > >xnew = np . l i nspace ( O , 1 0 , 4 0 )
>>>pl 七 . p l o t ( x , y , ' o ' , xnew, f ( xnew) , ' - ' , xnew, f 2 ( xnew) , ' - - ' )
>>>pl t . l e gend ( [ ' data ' , ' l inear ' , ' cubic ' ) , loc= ' be s t ' )
> >>pl t . show ( )

以上 代码使用 np . l i n space ( 函
) 数来生成 0�10 均 匀 间 隔 的 40 个值 。 相关的输出如
图 6- 1 1 所示。

0.6

0.4 •·

02

o.o�
2

图 6- 1 1

6. 1 7 使用 SciPy 求解线性方 程

假设有以下 3 个方程:

{;勹言 昙°
( 6-8)
2x + 3y + 8z = 5

定义 A 和 B 如下。

A{ ; !] B� ff] ( 6-9)
6. 1 8 利 用 种 子 ( seed ) 生 成 可 重 复 的 随 机数 93

以下 公式给 出 该方程组的答案 。

A
� [� ; �
( 6- 1 0 )
] s{ ]

[:]�A一' 'b ( 6- 1 I )

计算答 案的 Python 代码 如 下 。

>>> import s c ipy a s s p


>>> impo rt numpy a s np
> >>A=sp . mat ( ' [ l 2 5 ; 2 5 l ; 2 3 8 ] ' )
> > > b = s p . mat ( ' [ 1 0 ; 8 ; 5 ] ' )
>>>A . I *b
Matrix ( ( - 2 2 . 4 5 , 1 0 . 0 9 , 2 . 4 5 ]
>>>np . l i nalg . s o l ve (A, b ) jf, o f f e r the s ame s o l ution

6. 1 8 利 用 种 子 ( seed ) 生成可重复的 随机数


期权理论的 一个主要 假 设 是,股票价格服从对数正 态分布, 因 而 回报率服 从正态分布 。
例 如:

>>>importscipy as sp
>>>x=sp . random . rand ( l O ) # 1 0 r andom numb e r s f rom [ 0 , 1 ]
> >>y=sp . random . rand ( S , 2 ) # random numb e r s 5 by 2 array
>>> z=sp . random . rand . norm ( l O O ) # from a s tandard norma l
>>>


以上代码随机生成 一 组数字 。 不过, 有时需 要 组 固定的随机数, 用来重复测试我们
的模型和代码 , 教学时尤其 如 此 。 以下代码利用 一 个给定的种子来产生 可以重 复获得的随
机数 。

>>>importscipy a s sp
>>>sp . random . s e ed ( 1 2 4 5 6 )
>>>sp . random . rand ( S )
[ 0 . 8 9 2 8 6 5 8 6 0 . 6 1 8 5 6 52 0 . 5 8 8 7 3 52 3 0 . 7 61 3 7 60 1 0. 74499103)
94 第6章 NumPy 和 SciPy 模 块 简 介

SciPy 模块提供大 约 二 十 几 个模 拟随机数的函数,包括二项分布 、卡方分布、指数分布、


F 分布 、 伽 玛分布 、 几何分布 、 对数正态分布 、 泊 松分布 、 均匀 分布 、 韦 伯分布 。 使用
help(np.random)可以得到图 6-12 所示的输出(仅是所有输出的 一部分)。

11 11 j V ,,i• j , t ,, ,l i· I t、 j l<1 ,t I l>f>



- -I
hr, t. ,1 111: 1 " " i ·. I 1·i ''"' i r, 11 .,,_,.. ,. �1 . I I . . .
h i11nn i .1 I ll i11 .. ,, ; ,_, I ,1 i · t 1、 ;1... , j .. 11 .
L }i 1·; <tll•I I''、 : ,-,.,, I, : 、. , I, j :> , iJ j I ,- I l,11 I ' " "
exportt•11 f. i,1 I I可'"' " '' " 『 I_, I ,t i , I I'i!,111 I " "
f F ' I i -; 1. .- ,. :: ,.,, ,1 ,, , ,, ,、 • ,I i . t ,. i "" ' ," " .
(/,Wlrld ,;,,1111,1 ,I i ; 1.1· i 1.... I'"'
\JP O II>: I I、 i , ,;,, , , ,,,. ! 1· i , ,I i 1 •· i l111 t ' '"'
•1 11nlw I ,;,.,-,1,,. I ,I i · ,_ ,、 1!,111 ;,,,, .
lt •/)10-, l、,,,.,.,.,.. , 1· , , ,
ll •n"· I'•If' " I" I I' I, ,I I I !' ",,, I I ",,
I.q,Lu.1· l.-•1• 1 -" ,. ,1 , : t , 、 r l,11 1 ' " '' ·
I " 'J ic; t i' I.,.., i I I' ,I i ' I I、 i l,11 1 ; .. .,
l11•1 1111 1•11., I 1,,.,1 " " ,.,,., I ,1 , , I ,. i'" ' I ' " " .
lro or; e r i1· ;, 1,,. ,..,,. ,1 1,n i, ·. ,· 1· i ,· , ,I i . t 1·tl,,.1 ' " "
11,,q八I "' '' h i11 or1 i f 、
ltOII(: C, ,, f l',1 I ,· I, j :, •f II_, I、,·
N.. .. .,i j '-' .. I, I"",·, I.• I ,I I. ! ,.) l,11 I I"" .
N111, , ,-11 I 1·., I r I, i · 'I" ·' 1·,· ,I i I I' i 111 』I 1"11 .
11<1111:,, 11 1 ,• ., I f No,, , ,- 11 1 t' , I 1· ,I i . I ,. i i,,. , ' " " .
""' 、n•.J N,,1·11., I · ,;,.,, . ,.,,, d i ·. t 1- il-, , 1 '"" ·
\l•• I、,, t" I',1 1、, I ,, ,I i' t I、 ;1,.. , ,,.,, .
pn , ...... 『1 f'1> j · · " II ,I I t I'I l.11 I I I, II .
P"'""、 ('111"• I' ,I I ' I I'i l,111 l " ll
".J '" i "" H-"/ '" i,11, ,I i I ,. i 1,,,, , .. 11
t t•i八11•1 11 l.ir· I 1、 』 ,I I I'I " I ,\ 1· ,I i I I' i 1,, I f i " I I 雹
,. 畸

11n i I n t·n Ii i, ; 1 .. ,、/1 ,I I ·. I !、 i l.111 ; .. ,, .


'"I II II j'. ,. . '·' " " M i . ,- ·; I i ,., '' I,, I、 I i ·. I I、
, ''"' ' '"" .
"" ],1 ,,/.1 i,1 ' j ,,,.,, I' •• r;,, 11•. i ,11, ' •1 i •.t I、 i fnI I j "/1 .
"" i 1111 I I /,· i 1.. , I I ,! i , t I' ii'" 1 1 "1,
,• i pf ·.� i I, I ' • .I i T I、 II"I I I" I1 •l " •' I I、 ,,, 1-., ,I ,I ' I ,, .
,,

图 6- 1 2

6. 1 9 在导入 的模块里查找 函 数

可以把N u mPy 模块包含的所有


函数赋值给 一 个变量 如 X , 然后用循环语句查 找和输出
某些函数。

> > > import numpy as np


> > >x=np . a rray ( d i r ( n p ) )
>>> for k i n x :
i f ( k . find ( " uni " ) ! =- 1 ) :
print ( k )
U n i code

uni codeO
uni code
unionld
unique
6.2 1 线 性 回 归 和 资 本 资 产 定 价 模 型 ( CAPM ) 95

6.20 优化算法简介

在 金 融领域 , 许 多 问 题需 要 用 优化 算 法 来 解 决 , 比 如 给 定 目 标 函 数和 组 约 束 条件选
择最佳投资 组合 。 可 以 使用 s 立 Py 模块包含 的 名 为 s cipy . opt imi z e 的优化子模块来解
2
决这些 问 题 。 假 设 要 计 算 满足方程 y=3 +x 并且使 y 取最 小 值的 x 值 。 很 显 然 , 正 确 答 案 是
当 x 等 于 0 时 y 达到 最 小 值 。

>> >import scipy . op 七 imi ze as opt imi ze


>>>def my_f ( x ) :
return 3 + x * * 2
>>> optimize . fmin (my_f , 5 ) * 5 i s initial value
Optimi z a t i on terminated succe s s f u l l y
Current function value s : 3 : 0 0 0 0 0 0
I 七 eration s : 2 0
Func 七 i on evaluati ons : 4 0
Array ( [ 0 . ] )

使用 help ( op巨mi z e . fmi n ) 命 令 查 找 fmin ( ) 函 数 的 所有 输 入 参数 及 其 含 义 。 使用


d江 ( optimi z e ) 命令列 出 包含 在 s c ipy . op巨mi z e 模块 的所有 函 数 。

6.21 线性 回 归 和 资本资产定价模型 ( CAPM )

根据著名 的 CAPM 模 型 , 单只 股 票 的 回报率和 市场 的 回报 率线性 相 关 。 通 常情况 下 ,


我们 考虑 股 票 的 超额 回 报率与 市 场 的 超 额 回 报 率之 间 的 关 系 。

R; -R1 = a+/J;(Rmkt -RJ ) ( 6- 1 2 )

这里 , R; 是 该 股 票 的 回 报 率 , /J; 是斜率 ( 用 于 量 度 市 场 风 险 ) , R mkt 是 市 场 的 回报率 ,


R1 为 无 风 险 利 率 。 前 面 的 公 式 可 改 写 为 :

y = a +f] *x ( 6- 1 3 )

下面 是估计这个线性 回 归 模 型 的 个示例 。

>>>from sc ipy import s tats


>>>stock_ret = ( 0 . 0 6 5 , 0 . 0 2 6 5 , - 0 . 0 5 9 3 , - 0 . 0 0 1 , 0 . 0 3 4 6 ]
>>>mkt_ret = ( 0 . 0 5 5 , -0 . 0 9 , - 0 . 0 4 1 , 0 . 0 4 5 , 0 . 02 2 ]
>>>beta , a lpha , r_va lue , p_value , s td e r r =
96 第6章 NumPy 和 SciPy 模 块 简 介

stats . l i n r egre s s ( s tock_re t , mkt_ret )


>>>pr in七 be七a , al pha
0 . 507743187877 -0 . 00848190035246
>>>p r i n t "R- s quared = " , r_value * * 2
R-squared = 0 . 1 4 7 8 8 5 6 6 2 9 6 6
>>>p r i n t " p-value = " , p_value
0 . 5227 15523909

6.22 从 文 本 文 件 (.txt) 输入 数 据 : loadtxt() 和 getfromtxt()


函数

从外部数据文件输入数据时 , 得到的变量将是 一 个列表。

> > > f=open ( " c : \ \data \ \ibm . csv" , " r " )
>> >da 七 a = f . readl i n e s ( )
>>>type ( da t a )
<class ' l i s t ' >

以下 显示输入文件的前儿行。 第 7 章将讨论 如何从雅虎财经 网 站获取这个数据文件。

> > > Date , Open , High , Low , C l o s e , Vo lume , Adj C l o s e


2 0 1 3 - 0 7 -2 6 , 1 9 6 . 5 9 , 1 9 7 . 3 7 , 1 9 5 . 0 0 , 1 9 7 . 3 5 , 2 4 8 5 1 0 0 , 1 9 7 . 3 5
2 0 1 3- 0 7 - 2 5 , 1 9 6 . 3 0 , 1 9 7 . 8 3 , 1 9 5 . 6 6 , 1 97 . 2 2 , 3 0 1 4 3 0 0 , 1 97 . 2 2
2 0 1 3 - 0 7 - 2 4 , 1 95 . 9 5 , 1 9 7 . 3 0 , 1 95 . 8 6 , 1 9 6 . 6 1 , 2 9 5 7 9 0 0 , 1 9 6 . 6 1
2 0 13 -07-23 , 1 9 4 . 2 1 , 19 6 . 4 3 , 1 94 . 1 0 , 1 9 4 . 98 , 2 8 6380 0 , 1 9 4 . 9 8
2 0 1 3-07-22 , 1 93 . 4 0 , 1 95 . 7 9 , 1 93 . 2 8 , 1 9 4 . 0 9 , 3 3 9 8 0 00 , 1 9 4 . 0 9
2 0 1 3 - 0 7 - 1 9 , 1 97 . 9 1 , 1 9 7 . 9 9 , 1 9 3 . 2 4 , 1 93 . 5 4 , 6 9 9 7 6 0 0 , 1 9 3 . 5 4

列 表 变 员 data 的前两个值显 示 如下。

> > >data [ l ]


' 2 0 1 3 - 0 7 - 2 6 , 1 9 6 . 5 9 , 1 97 . 3 7 , 1 9 5 . 0 0 , 1 97 . 3 5 , 2 4 8 5 1 0 0 , 1 9 7 . 3 5 \n '
>>>data [ 2 ]
' 2 0 1 3 -07-2 5, 1 9 6 . 3 0 , 1 97 . 83 , 195 . 6 6 , 1 97 . 22 , 3 0 1 4 3 0 0 , 1 97 . 22 \n '

NumPy 校块包含的 loadtxt() 函数 可以用来读取文本或 csv 文件, 代码 如下。


>>>import numpy as n y
>>>ny . loadtxt ( " c : / temp /t e s 七 . cs v " , del imi t e r = ' , ' )

gen f r orn七 xt ( ) 函 数 功能 更强大 , 但是速度较慢。 与 l o a d t x t ( ) 相 比 , 该函数的优


6.24 数据类型简介 97

点 是 自 动 把 不 能 识 别 的 值 , 如 3 .5 % 设 置 为 NA ( Pyth on 的 缺 失 代码 ) 。

6.23 独立安装 NumPy 模块


执 行 以 下 两 个 步 骤 来 独 立 安 装 NumPy 模 块 。

1 . 访 问 网 页 h t t p : / / www . l fd . uc i . e du / -gohl ke / pythonl i b s / # nump y 。

2. 选 择 合 适 的 软 件 包 下 载 和 安 装 , 如 numpy-MKL - l . 7 . l . wi n 3 2 - p y 3 . 3 . e xe 。

6.24 数据类 型简介

大 部 分 的 数 据 类 型 如 表 6-2 所示 。

表 6-2

数据类型 描述

Bool 布 尔 数(True 或 Fa l s e ) , 一字节存储

int 机器整 数 ( 通 常 32 位或 64 位存储 )

int8 8 位整数 ( 取值 范 围 为 - 1 28- 1 2 7 )

intl6 1 6 位 整 数 ( 取值 范 围 为 -32 768-32 767 )

int32 32 位 整 数 ( 取 值 范 围 为 -2 1 47 483 648�2 1 47 4 8 3 647 )

int64 64 位 整 数 ( 取值 范 围 为 9 223 3 7 2 036 854 7 7 5 808-9 223 372 036 854 7 7 5 807 )

unit8 无 符 号 8 位整 数 ( 取 值 范 围 为 0-255 )

un i 七 1 6 无符号 1 6 位 整 数 ( 取值 范 围 为 0-65 5 3 5 )

unit32 无符号 32 位 整 数 ( 取值 范 围 为 0-4 294 967 295 )

un i t 6 4 无 符 号 64 位 整 数 ( 取值 范 围 为 0 - 1 8 446 744 073 709 55 1 6 1 5 )

float 64 位 浮 点 数

floa七32 单精度 32 位 浮 点 数

float64 64 位 浮 点 数
98 第 6 章 NumPy 和 SciPy 模 块 简 介

续表
数据类型 描述
complex 1 28 位复数
compl e x 6 4 64 位 复 数 ; 两个 32 位浮点数分别代表实部和虚部
complexl 2 8 1 28 位复数; 两个 64 位浮点 数分别代表实部和虚部

6.25 小结

本章介绍了 N u mPy 和 SciPy 模块, 这是两 个广泛用于 科学和金融领域最重要的模块。


N u mPy 模块注重数值方法, SciPy 模块可以被视为 N u mPy 模块的扩展 。 本书的许 多 章节 需
要用到这两 个 模块。 此外, 许 多 其 他模块依 赖千这两 个模块, 包括第 7 章将介绍的用于绘
图的 matp lot 辽b 模块和第 8 章将介绍的用千统计/金融建模 的 s tat smode l s 模块。
matp l o t 巨 b 模块是实现可视化的 一 个 非常有用的工具, 在解释 期权定价理论时将频 繁使
用这个 模块。

练习题

1 . 什 么 是模块依赖性?
2. 为什么 独立安装 N u mPy 比较困 难 ?

3. 编写 一个 依赖于其 他模块的模块有何好处和不利之处?

4 . 使用超级软件包 同时安装多 个模块有何好处?

5. 如何才能找到包含在 N u mPy 和 SciPy 模块的所有函数?

6 . 以下命令哪里错了 ?

>>>x = [ l , 2 , 3 ]
>>>x . sum ( )

7. 如何 打 印 给定数组中的所有数据项 ?

8. 以下命 令 哪里错了 ?

>>> import np
练习题 99

>>>x=np .array ( [ True , false , t rue , false ] , bool )

9 . 如何遍历一 个数组?

1 o. 编写 一 个 Pyth on 程序使用 �ciPy 模块的累积标准正态分布函数给欧式看涨期权定


价。 比较你 的代码和第 4 章中的代码。

11 . 找出 SciPy 模块的 s kewtest ( 函


) 数的用法, 并且 给 出一 个 使用该函数的例子。

12 . 如何找到 SciPy 和N u mPy 模块里的所有


函数 ?

13 . 有以下的联立方程, X, y 和 z 分别 等于多少?

厂亿 3
一x + 2.9 y + l 8
2

. z = 3.1
:::/

1 4 . 调试以下 代码来计算 组给定的回报率的几何平均值。


>>>import scipy as sp
>>>ret = np . array ( [ O . O S , 0 . 1 1 , - 0 . 0 3 ) )
>>>pow ( np .prod ( re 七 + l ) , l / len ( re t ) ) - 1

15. 写 一 个 Pyth on 程序来计算 一组给定回报率的算术平均值和儿何平均 值。

16 . 使用回报率的标准差来衡量证券或投资组合的风险水平。 根据雅虎财经网站上最
近 5年的每 日 股票 价格, 计算 I BM 的 风险水平。 需要注意的是, 用下面的公式 把 日 回报率
的方差转化为年回报率的方差。

吐ual = 252CY� ly

17 . 找出 SciPy 模块的 z score()函数的用法, 并给出 个使用该函数的例子。


18. I BM 在 2010年的市场风险( 贝 塔值) 是多大 ? (提示: 可以用雅虎财经网站的


数据)

19 . 以下 命令哪里错了 ?

>>>c = 2 0
>>>npv=np .npv ( O . l , c )

20.N u mPy 模块的相关系数函数是 np . cor rcoe f ( ) 。 了解这个函数, 并用它计算IBM、


1 00 第 6 章 NtunPy 和 SciPy 模 块 简 介

DELL 和 WMT ( Walmart) 之 间 的相关系数 。

21 . 为什么 SciPy 模块的 s n. n vp (函数和


) Exce 的
l NPV ( 函
) 数不 同 ?

22 . 编写 一 个与 E xce l的 NPV()函数相同的函数。

23. 夏普比率用来衡量风险和收益之 间 的关系 。

R - RI
sh arpe =

R 是单只 股 票的预期回报的均值, 凡 是无风险利 率的均值 。 6 是该股票 回报率的标准
方差, 也称为波动率。 利用最近 5年的月度回报率, 计算 I B M 、DELL 、C iti 和 WMT( Walmart)
的夏普 比率 。


第7章

用 mat plot l ib 模块 绘制 与
金融相 关 的 图 形

图表等视觉表现方式越来越多 地被用来解释许多 复杂的金融概念、 公式和交易策略。


本章将讨论如何用 m at pl otlib 模块来创建不 同类型的图形。 此外, 将在第 9 章使用此模块讨
论著名的 Bl ac k - Sc h oles-Mert on 期权模 型和期权交易策略。 m at pl otl ib 模块用来制作高质量
的图形和 图像 , 与第 6 章介绍的NumPy 和 SciPy 模块密切相关, 并且有多种输出格式, 如
P DF、 P ostscri t、
p SVG 和 PNG 等。 本 章将介绍以下 内 容 。

• 安装 m at pl otl ib 模块的几种方式

• 使用 m at lp otlib 模块的简单例子
• 净现值 (NP V)的图示、 杜邦等式、 股票收益率和直方图

• 整体风险、 市场风险和非系统风险

• 股票之 间 的联动度和相关系数

• 分散投资 风险

• 绘制交易量和价格
变动的图形

• 儿只股票的回报率和风险坐标图

• 使用 m at lp otlib 模块的复杂例子
1 02 第7章 用 matplotlib 模块绘制 与 金 融 相 关 的 图 形

7. 1 通过 ActivePython 安装 matplotlib 模块
安装 matplotlib 模块的第 1 个办法是使用 ActivePython 软件。 首先安装 ActivePython
软件, 然后安装 matplotlib 模块。 在安装 matplotlib 模块的过程中 , NumPy 模块会 自 动 安装,
因为 matplotlib 模块依赖于 NumPy 和 SciPy 这两 个模块。 整 个过程有如下 4 个步骤。
1 . 转到 http://www.activestate.com/activepython/downloads 。

2 . 选择适合的可执行文件进行下载。

3 . 在 Windows 操作系统下, 单击所有程序 附件, 然后单击命令提示符, 会看到图 7- 1


所示的窗 口 。
蚀蚀


Micro:; o f t \J ind1n1,; (Ue r:; ion (, . l . 'i1,l'll l
;cop w
• i•1 ht ( 1 ,'.l1W.' M i c ,、(,: 11( 1. Ci,1·1,1< 1·.<1 iu11 . 11 1 1 1· 1 ·1 l1i , 1'•令 , ,.,, ,, ,! .
C : ,II:; Ci-:; '-'J'"' '·' )c ,I·, l'vt ho11'.c '/
,1C : ,Pvt. hon?.?)
,

图 7- 1

4 . 来到 Python 的安装 目录 C : \ Python 2 7 下, 按照图 7 - 2 所示输入 pyprn i n s t a l l


rnatp l o t l ib 命令。

\ 图 7-2

ma七pl o 七 止b 模块需要 NumPy 和 S 立 P y 这两 个模块。 安装 matp l o t l ib 模块时,


NumPy 模块将 自 动安装。 不过, 需要另行安装 Sc迁y 模块, 如图 7-3 所示。

lti:i'.![i !\[!;?;:,::: :、':'·?>> ':, ::,:: ::,:, ,:'::·,:",· :·:'.''':


图 7-3
7.3 matplotlib 模块 简介 1 03

要启 动 Python , 单 击所有程序 IActivateStateActivePython , 然后单击 IDLE ( PythonG U1),


如图 7-4 所示。 为方便起见, 可以生成 一 个置于 桌面上 的快捷方式 。
ActiveState ActivePython 2.7 (32-bit)

@ A.,ctivePython Documentation
rl IDLE (Python GUij
rl Python Interactive Shell
面 Python Package M anager (PyP M)
侍 Unin式all ActivePython

图 7-4

7.2 通过 Anaconda 安装 matplotlib 模块


在第 6 章讨论了模块的相互 依赖性 。 独立安装一 个模块可能比较困难, 因为它可能会
依赖其他许多模块。 可使用超级软件包来克服这 个 困 难 。 一
个超级软件包会同时安装我们
需要的大部分模块。 这里选择 Anaconda 超级软件包, 并按照以下两 个步骤安装它 。

1 . 转到 http : / / c ontinuum . io / down loads 。

2 . 选择合适的包 下 载 并安装。

7 .3 matplotlib 模块简 介
通过学习一 些 例子可以很快掌握如何使用 matplotlib 模块。 首先举 一 个可能是最
简单的
例子, 因为它仅有3行 Python 代码 。 这 个例子的任务是在二 维坐标图上 绘制 给定的几 个点
之间 的连线 。 默认情况下, matplotlib 模块假定 x 轴的起点为 o, 单位为 1 。 下面的命 令行
利用了 matplotlib 模块的默认情况。

>>> from matpl o t l ib . pyplot import *


>>>plot ( [ 1 , 2 , 3 , 1 0 ] )
>>>show ( )

输入 show()命 令 后按 回 车键, 会打开 一 个图形窗 口 并显示绘制的图形, 如图 7 - 5 所示。

图形窗 口 的上部有一 排图标, 可以用它们 调 整图形和完成其他功能, 比如把图形保存


在文件里。 关闭 图形窗 口 , 就 返 回 到 Python 提示符 。 另外, 如果再次发 出 show ( ) 命令,
什么都不会发生 。 为重新得到之前的图形, 必须发 出 plot([ 1 ,2,3, l O])和 show ( ) 两 个命 令 。
1 04 笫7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形
f,g,,c l

仑00 十 名 01 11 石
10

9
6
4
2

2� 30

图 7-5

用下面的命 令为 x 轴和y 轴添加标签。

>>>from matplotl i b . p yp l ot import *


>>>plot ( ( 1 , 2 , 3 , 1 0 ) )
>>>xlabe l ( " x- ax is " )
>>>ylabel ( "my numbe rs " )
> > > 七 i t l e ( "my figure " )
>>> sho w ( )

结果 如 图 7-6 所示。

10 --y figu re
-m
I
9
I


8

i 6

5
>
E

�� 2.5 3.0

图 7-6

下面这个 示 例用到了正 弦和余弦函数。


7.3 matplotlib 模 块 简 介 1 05

>>>from p y l ab import *
>>>x = np . l i nspace ( - np . p i , np . p i , 2 5 6 , endpo int=True )
>>>C , S = np . cos ( x ) , np . s in ( x )
>>>plot ( x , C ) , pl o t ( x , S )


>>> show ( )

以上用到的 linspace(函数有
) 4 个输入参数: start、 stop、 nurn 和 endpoint。 在这 个例子
里, 选取-3 . 1 4 1 5 9 1 6,..__, 3 . 1 4 1 592 6 的 2 5 6 个数, 包括两 个端点在内 。 通常情况下, num 的默
认 值是 5 0 。 两 个三角函数的图形如图 7-7 所示。

LO

0.5

0.0

-0.5

-1.0L
-4 3 4

图 7-7

下面的例子绘制 一 个散点图。 首先, np . randorn . n o rrnal ( )函数产生两组随机数 。


由千 n 是 I 02 4 , 所以有 1 024 对 x 和 y 的坐标值, 并用 s ca t t e r ( ) 命令完成图 7-8 所示的
散点图。

..
2
1

-1

-2

-3

3
2

� -3 -2 ' -1

图 7-8
1 06 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

>>>f rom pylab import *


>>>n = 1 0 2 4
>> >X = np . random . no rmal ( 0 , 1 , n )
>>>Y = np . random . normal ( 0 , 1 , n )
>>>s catte r ( X , Y )
>>> show ( )

可以通过散点图来观察 两 只 股 票之 间的相关性 。 假 设 x 坐标和 y 坐标分别 代表两 只 股


票 A 和 B 在同 时期的回报 率 。 如果这两 只 股票的回报率是强烈正相关的, 也就是说, 当

股票 A 的回报低时, 股票 B 的回报 同样低 ; 而 当股票 A 的回报高时, 股票 B 的回报也非


常高。 那么 在图 7-8 上代表 A 和 B 的回报率的散点就会沿 着倾角向上的直线分布 。

7.4 了 解简单利 率 和 复利 利 率

简单利 率 不考虑利息的利息, 而 复利利率考虑 。 简单的图示可以帮助加深理解简单


利率和复利利率之间的区 别 。 假如 我们今天借 1 000 美元为期 1 0年, 每年支付 8% 的利息。
当 8%是简单利率或复利利率时, 未来值分别 是 多 少 ? 对应简单利率 的未来值的计算公式
如下 。
FV(简单利率)=P V( l +R X n ) C 7- l )

对应的复利利率的未来值的计算公式如下:
FV( 复利利率)=P V( l +R r C 7-2 )

这里, PV 是今天的负债额, 即当前值, R 是单位周 期利率, n 是周 期数。 因此, 这 个


例子里的未来值将分别是 1 8 00 美元和 2 1 5 8 . 93 美元。 下面的代码用来绘制分别 代表本金、
简单利率下 的未 来值和复利利率下的未来值的 曲 线 。

import numpy a s np
from matp lotlib . pyplot import *
from pylab import *
pv= l O O O
r=0 . 0 8

n=lO
t=l inspace ( O , n , n )
y l =np . ones ( l en ( t ) ) *pv # this is a ho ri zontal l i ne
y2=pv* ( l + r * t )
y3 =pv* ( l + r ) * * t
7.5 为 图 形添加文字 1 07

t i t l e ( ' S impl e vs . compounded i n t e r e s t rates ' )


xlabel ( ' Number o f years ' )
ylabel ( ' Va l u e s ' )
x l im ( O , 1 1 )
y l im ( 8 0 0 , 2 2 0 0 )

\
plot ( 七 , y l , ' b- ' )
plot ( t , y2 , ' g- - ' )
plo七 ( t , y3 , ' r - ' )
sho w ( )

在上述代码中, xl皿O函数给 出 x 轴上的取值范 围 , ylim()函数给出 y 轴 上 的取值范 围 。


plot()函数的第 3 个输入参数给出颜色和线条形状 。 字 母 b 代表黑 色, g 代表绿色, r 代表红
色。 以上 代码绘制的曲 线图如图 7-9 所示 。

2200
Sl�le vs. c,ompou� tntei;est rate

2000

1800

1600

1400

1000

10
800

4 6 8
即m归 rA yurs

图 7-9

7.5 为 图 形添 加 文 字

下面的例子展示如何
简单地在图形上添加文字。 注意 figtextO函数中 x 和 y 的取值范 围
为 0�1。

>>>f rom pylab import *


>>>x = [ 0 , 1 , 2 ]
>>>y = [ 2 , 4 , 6 ]
>>> pl ot ( x , y )
>>>f igtex七 ( 0 . 2 , 0 . 7 , ' No r 七h & West ' )
>>>figtex七 ( 0 . 7 , 0 . 2 , ' E a s t & South ' )
1 08 第7章 用 matplotlib 模块 绘制 与 金 融 相 关 的 图 形

> >>s how ( )

以 上 代码生 成 的 图 形 如 图 7- 1 0 所 示 。
6.0

l
S.5 ·

5_0 North & West

4.5

4.0

3.S

3.0

2.S East & South

2-'l>'.o 0.5 1.0 1.S 2.0

图 7- 1 0

从美 国 国 家 经济研究署 的 网 页 http://www.nber.org/cycles.html 上 , 可 以 找到过去 20 年


的经济周 期 的 数 据 , 如 表 7- 1 所示。

表 7-1

Turning PointDate Peak orTrough AnnouncementDate

June I , 2009 Trough September 20,20 I 0

December 1 ,2007 Peak December 1 ,2008

November l ,200 I Trough July 1 7,2003

March 1 ,200 I Peak November 26,200 1

March I , 1 99 1 Trough December 22, 1 992

July 1 , 1 990 Peak April 25, 1 99 1

November I , 1 982 Trough July 8, 1 983

July 1 , 1 98 1 Peak June 1 , 1 982

July 1 , 1 980 Trough July 8, 1 98 1

January 1 , 1 980 Peak June 3, 1 980


7.6 杜邦等式的图示 1 09

7.6 杜邦等 式 的 图 示
在 金 融领域 , 人们 从 公 司 的 财 务寸队 表 , 如 年 度 损 益 表 、 资 产 负债表和现 金流量表 , 发
掘 有 用 的 信 息 。 比 率 分 析 是 常 用 的 工 具 之 一 , 常 常用 来 比较 不 同 企业之 间 以 及 同 一 公 司 历
年 来 的 表 现 。 杜邦等式 ( DuPont Identity ) 是 比 率 分 析 的 一 种 。 杜邦等式把股本回报率 ( ROE )
分 为 3 个 比 率 : 毛 利 率 、 资 产 周 转 率 和 权益 乘 数 。

Net Income Sales Total Assets


ROE = X X ( 7-3 )
Sales Total Assets Book value of Equity

下 面 的 代码将使用 不 同 的 颜色显示这 3 个 比 率 。 表 7- 2 给 出 3 家 公 司 的 财 务 信 息 。

表 7-2

股票代码 会计年末 股本回报率 毛盈利率 资产转手率 股本乘数

December3 1 ,
IBM 0.8804 0. 1 589 0.8766 6.3209
20 1 2

February I ,
DELL 0.222 1 0.04 1 7 1 . 1 977 4.45 1 3
20 1 3

January3 1 ,
WMT 0.2227 0.0362 2.3099 2.6604
20 1 3

使 用 如 下 的 Python 代码来绘制 与 比率分析相 关 的 图 形 。

import numpy a s np
import panda s as pd
import matp lot l ib . pyplot as p l t

ticke r= ' T icker '
name l = ' profitMa r gin '
name2= ' ass etTur nover '
name 3= ' equ itMul tipl i e r '
scale=7 # scale the 1 s t ratio

raw_data = { 七 i c ke r : [ ' I BM ' , ' DE LL ' , ' WMT ' ] ,
narne l : [ 0 . 1 5 8 9 * s c a l e , 0 . 0 4 1 7 * sc a l e , 0 . 0 3 6 * s ca l e ] ,
name 2 : ( 0 . 8 7 6 6 , 1 . 1 9 7 7 , 2 . 3 1 ] ,
110 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

n ame 3 : [ 6 . 3 2 , 4 . 4 5 , 2 . 6 60 4 ) )
df = pd . DataFrame ( raw_da ta , c o l umn s = [ t i c ke r , narne l , narne2 , name 3 ] )
f , axl = p l t . subp l ots ( l , f i g s i ze= { l 0 , 5 ) )
w= 0 . 7 5
x= [ i + l f o r i i n range ( len ( d f [ name l ) ) ) )

七 i c k_pos = [ i + (w/2 . ) for i in x )
axl . bar ( x , df [ name l ) , width=w , labe l =name l , a lpha=0 . 5 , c o l or= ' b l ue ' )
a x l . ba r ( x , df [ name 2 ] , width=w , bo七tom=df [ name l ) , l abe l =name 2 , alpha=0 . 5 ,
c o l o r= ' red ' )
a x l . bar ( x , df [ name 3 ] , width=w , bottom= [ i + j for i , j i n z i p ( d f [ n ame l ) ,
df [ name2 ) ) ) , label=name 3 , a lpha=0 . 5 , color= ' green ' )
p l t . x t i c k s ( t i c k_pos , df [ ti c k e r ) )
pl t . y l abe l ( " Dupoint Identity " )
pl t . x l abe l ( " Di f fe r ent t i c k e r s " )
p l t . l egend ( l oc= ' upper r i ght ' )
plt . t i t l e ( " DuPont Identity for 3 fi rms " )
p l t . x l im ( [ mi n ( t i c k_pos ) -w , max ( ti c k_p os ) +w ) )
p l 七 . show ( )

) 数在 x-y 位 置 添 加了 文字, x 和 y 两
在上 面的代码中, p l t . f i gt e xt(x,y, " 文本 " 函
者的取值 范 围 均为 0� 1 。 p l t . bar ( 函
) 数用来生成 3 个柱状 图, 如图 7- 1 1 所示 。

口企“真 一 应 ] firms
0g
5i
.
l
S
.
`
,

图 7- 1 1

7.7 净现值 图 示 曲 线

人们越来越多地用图表等视觉方式来解释 复 杂的金融概念、 公式和交易策略 。 净现值


7.7 净现 值 图 示 曲 线 111

(NP V ) 曲线描述 一 个项 目的净现值和折现率(或资 本成本) 之 间 的关系。 对于一 个常见的


项 目(这里是指 一 个项 目的现金支出发生 在其 现金收入之前), 其 净现值将是折现率的递减
函数。 原因是, 当 折现 率增加时, 未来现金收入的现值将减少, 而且越远 期的现金收入的
现值 降低得越多。 净现值 由以下公式 定义。
NPV = PV C所有现金收入) -PV ( 所有现金支出)

下面的代码用来展示净现值和折现率之 间 的负相关关系。

import scipy as sp
from matp l o t l ib . pyp l ot impor七 *
cashflows= ( - 2 0 0 , 8 0 , 9 0 , 1 0 0 ]
rat e = [ l
npv= [ ]
x= ( 0 , 0 . 7 )
y= ( 0 , 0 )
for i in range ( l , 7 0 ) :
rate . append ( O . O l * i )
npv . append ( s p . npv ( 0 . 0 1 * i , cash f l ows ) )

plo七 ( r ate , npv )
plo t ( x , y )
sho w ( )

这段代码绘制图 7- 1 2 中的两 条线: 位于纵轴 零点处的直线和净现值 曲 线 。 净现值 曲 线


展示净现值和折现率是负相关的。
100


- 100

。a.-.
-150I -· 豆 石 o.� 0.5 0,6 07

图 7- 1 2

内部收益率 ORR ) 定义为使净现值等于 0 的折现率 。 图 7 - 1 3 显示, 这 个例子 只 有一


个 IRR。 但是, 对于 现金收入发生 在现金支付之前的项 目, 或现金流量 的方 向多次变化的
112 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形


项 目 , 我们 不 知 道 是 否 只 有 一 个 内 部 收 益 率 。 以 下 代码说 明 有 时 可 能 出 现 多 于 个 内 部 收
益率。

>>> import scipy as sp


>>> cashf lows = [ - 1 0 0 , 5 0 , 6 0 , 7 0 )
>>> rate = O . l
>>> npv= sp . npv ( ra 七 e , cashflows )
>>> round ( npv , 2 )
47. 63

正 如 我 们 在 第 6 章 中 讨 论 的 那样 , SciPy 模 块 的 N PV ( ) 函 数模 仿 Excel 的 NPV 函 数 ,


它 实 际 上类似于 用 以 下 代码完成现值 的 计 算 。

>>> import scipy as sp


>>>import matp l o t l i b . pyp l o t as plt
>>>cashf l ows = [ 5 0 4 , - 4 3 2 , - 4 3 2 , - 4 3 2 , 8 3 2 ]
>>>rate = [ ]
>>>npv= [ ]
>>>x= [ 0 , 0 . 3 ]
>>>y= [ 0 , 0 ]
>>>for i i n range ( l , 3 0 ) :
rate . append ( O . O l * i )
npv . append ( sp . npv ( O . O l * i , cash f l ows ) )
>>>pl t . pl o t ( x , y )
>>>pl t . plot ( rate , npv)
>>>pl t . show ( )

该代码的输 出 如 图 7- 1 3 所 示 。
0
1。
5

-5

18.00 0,05 0.10 0.15 0.20 豆5 0.30

图 7- 1 3

图 7- 1 3 显示这个例 子 有两个 内 部 收 益 率 , 而 NumPy 模 块 的 i r r ( ) 函 数 只 能 找 到 其 中


的 一个 。

>>>import numpy as np
7.7 净 现值 图 示 曲 线 113

>>>c ashflows = [ 5 0 4 , - 4 3 2 , - 4 3 2 , - 4 3 2 , 8 3 2 )
>>>np . i r r ( cashf l ows )
0 . 08 949087

7.7.1 有效地使用颜色


使用不 同的颜色可以使图形或线 条更加抢 眼 。 假 设从雅虎财经获得沃尔玛和戴尔这两
家公司在 4年里的每股收益 C EP S, 扣 除 非经常性项 目的每 股收益)。 可以使用下面的代码
通过不 同的颜色来比较它们的每股收益 。

import matp l o 七 l i b . pyp l o t a s p l t


import numpy as np
A_EPS = ( 5 . 0 2 , 4 . 54 , 4 . 1 8 , 3 . 7 3 )
B EPS = ( 1 . 3 5 , 1 . 8 8 , 1 . 3 5 , 0 . 7 3 )
ind = np . ar ange ( l en (A_E P S ) ) # the x locations for the group s
w i dth = 0 . 4 0 # the width o f the bars
fig, ax = plt . subp l o t s ( )
A Std= B Std= ( 2 , 2 , 2 , 2 )
r e c t s l = ax . bar ( i nd, A_EPS , width , c o l o r = ' r ' , yerr =A_S td)
rects2 = ax . bar ( i nd+widt h , B_EPS , width , c o l o r= ' y ' , yerr = B_S td)
ax . set _ylabel ( ' E PS ' )
ax . se七_x lab e l ( ' Yea r ' )
ax . se七_t i t l e ( ' Di luted EPS Excluding Extraordinary I t ems ' )
ax . s e t—xt i cks ( i nd+width )
ax . s e t x t i c klabe l s ( ( ' 2 0 12 ' , ' 2 0 1 1 ' , ' 2 0 1 0 ' , ' 2 0 0 9 ' ) )
ax . legend ( ( re c t s l [ O ) , r e c t s 2 [ 0 ] ) , ( ' W -Mart ' , ' DELL ' ) )
de f autolabel ( re c t s ) :
for r e c t in rects :
heigh七 = rect . get_heigh t ( )
ax . text ( re c t . ge t_x ( ) + r e c t . get_width ( ) /2 . , 1 . O S * he i gh t ,
, % d ' % i nt ( he i ght ) , ha= ' center ' , va= ' bottom ' )
autolabe l ( rects l )
autolabe l ( r e c t s 2 )
p l t . show ( )

np . a range ( 3 ) 命 令得到 0 � 3 这 4 个值, 而 ax . s e t_xt i c ke r s ( ) 生成刻 度 值 。 相


应的输出如图 7- 1 4 所示。
114 第 7 章 用 matpl otl ib 模 块 绘 制 与 金 融 相 关 的 图 形

8
蠡》

-2

图 7-1 4

在图 7 - 1 4 中 , 红色代表沃 尔 玛的每股收益, 黄色代表戴尔 的每股收益。 分别 代表不同


颜色的 8 个字母如表 7-3 所示。

表 7-3
字母 颜色 字母 颜色
'b ' Blue ( 蓝色 ) I m, Magenta ( 品 红 色 )
I
gI Green C 绿 色 ) ' y' Yel l ow ( 黄 色 )
I I r Red ( 红色 ) 'k' Black ( 黑 色 )

I
C
I
Cyan ( 青色 ) ,w , White ( 白 色 )

7.7.2 使用不 同形状

可以使用不同的形状使图形更加抢眼 。 代表不同线 条 形状的字符如图 7 -4 所示。

表 7-4
字符 说明 字符 说明
Hf_Ill
实线
1113 Ill
三角 菱 形 向 左
Ill--Ill
虚线 "' "'
4 三角菱形向右
Ill Ill
点划线 Ill
s Ill
正方形
'" · "' 虚点线 Ht
p
!It
五角 形
ti! tit
点标记 "'* "' 星形
7.8 图形演示分散投资的效果 115

续表

字符 说明 字符 说明
Ill 111
六边形 1 号
"'h Ill
像素标记
Ill 。 Ill

III H "'
六边形 2 号

三角 向 下 加号
IllV I ll '"+"'

111/\111 "'X111
三角 向 上 交叉
"'<"' 三角向左 "'D "' 钻石形

三角 向 右 小钻石形
"'>lft "'d'"

三菱 向 下 垂直线
!If
l Ht '"I"'
1112 "' 三菱向上 tit Ill
水平线

7.8 图 形演 示分散投资 的效果


可以把不 同的股 票包含在投 资组合里来降低公司特有风险。 首 先, 看 一个例子, 两 只
股票在 5年里的
年收益 如表 7-5 所示 。

表 7-5

年份 股票 A 股票 B

2009 0. 1 02 0. 1 062

20 1 0 -0.02 0.23

20 1 1 0.2 1 3 0.045

20 1 2 0. 1 2 0.234

20 1 3 0. 1 3 0. 1 1 3

考虑这两 只 股票以等权重构成的投资 组合 。 使用 NumPy 模块的 mean ( ) 和 s t d ( 函


) 数,
计算这个组合的均 值 、 标 准差和相关系数。

>>> import numpy as np


>>>ret_A=np . array ( [ 0 . 1 02 , - 0 . 0 2 , 0 . 2 1 3 , 0 . 1 2 , 0 . 1 3 ) )
>>>ret_B=np . array ( [ 0 . 1 0 62 , 0 . 2 3 , 0 . 0 4 5 , 0 . 2 3 4 , 0 . 1 1 3 ) )
> > >por t_EW= ( r et_A+ r e t_B ) /2
116 第7章 用 rnatplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

>>>round ( np . mean ( ret_A ) , 3 ) , round ( np . mean ( ret_B ) , 3 ) , round (np . mean (port_EW) , 3 )
( 0 . 109, 0 . 1 46, 0 . 127 )
>>>round ( np . s td ( re七_A) , 3 ) , round ( np . s 七d ( ret_B ) , 3 ) , r ound ( np . s td ( por t_EW) , 3 )
( 0 . 07 4 5 , 0 . 07 4 , 0 . 027 )

这 个组合的波动率 ( 标准方差 ) 为 2 .7% , 比这两 只 个股 ( 股票 A 7.5% , 股票 B 7.4% )


的波动率小得多 。 用图 7 - 1 5 来表示这样的效果。

import numpy as np
import matp l o t l ib . pyp l o t a s p l t
year= [ 2 0 0 9 , 2 0 1 0 , 2 0 1 1 , 2 0 1 2 , 2 0 1 3 )
ret _A=np . a r r a y ( [ 0 . 1 0 2 , - 0 . 0 2 , 0 . 2 1 3 , 0 . 1 2 , 0 . 1 3 ) )
r et_B=np . ar r a y ( [ 0 . 1 0 6 2 , 0 . 2 3 , 0 . 0 4 5 , 0 . 2 3 4 , 0 . 1 1 3 ) )

port EW= ( r e七 A+ r e t B ) /2
p l t . f i gtex七 ( 0 . 2 , 0 . 6 5 , " S tock A" )
p l t . f i gtext ( 0 . 1 5 , 0 . 4 , " S tock B " )
p l t . x l abe l ( " Year " )
p l t . y l abe l ( " Return s " )
p l t . p l ot ( year , r e t_A, lw=2 )
p l t . p l ot ( ye a r , r e t_B , l w=2 )
p l t . plot ( ye a r , port_EW , lw = 2 )
plt . t i 七 l e ( " Indiviudal s t ocks vs . an e qual - weighted 2 - s t ock portf l i o " )
p l t . anno七a七e ( ' Equa l -weighted Po r t f o l i o ' , xy= ( 2 0 1 0 , 0 . 1 ) ,
xytext = ( 2 0 1 1 . , 0 ) , a r rowprops = dict ( facec o l o r= ' b lack ' , shrink = 0 . 0 5 ) , )
plt . y l im ( - 0 . 1 , 0 . 3 )
p l t . show ( )

这段代码绘制的图形如图 7- 1 5 所示。

Individual stocks vs. an


25 20 15 10 05 00 8
0 0 0 Q Q 0 0
i


Equal-weighted 氏rtfollo

- - -
-o.1y,1。 - 0.5 LO -1.5 2.0 2.5 3.0 3.5 4.0
妇 +2.009e3

图 7- 1 5
7.9 股 票 的 数 目 和 投 资 组 合风险 117

调用 annotate()函数添加 一 个箭 头 指 出哪 一 条 线 对应两 只 股 票的投资 组 合。 参数 XY


= ( 2 0 1 0 , 0 . 1 ) 给 出箭 头 终点的坐标值, 参数 xytext = ( 2 0 1 1 , 0 ) 给出箭 头 起点的坐标值。
箭 头 的 颜 色为 黑 色 。 可 以 输 入 irnp o r 七 rna tp l o t 巨 b . pyp l o t as pl t 和
help ( p l t . anno t a t e ) 来获得有关该函数的详细 信息 。 从 图 7-15 中, 看 到投资 组合的波
动率, 即 不确定性或风险, 比 个股要小得多。 还可以估算它们 的均 值 、 标准方差和相关系
数。 下面的代码得出这两 只 股票之间的相关系数为-0. 75, 这意味着它们各 自 的特有风险在
资 产组合里可以互相抵 消 。

>>> import s cipy as s p


>>>sp . corrcoe f ( r e t_A, r e t_B )
arra y ( [ [ 1 . , - 0 . 7 4 5 8 3 4 2 9 ) ,
( - 0 .7 4 5 8 3 4 2 9 , 1. ]])

7.9 股 票 的 数 目 和 投 资 组合风险

众所周 知, 通过增 加投资 组合中的股票数 目可以利用多元化减低 公 司的特有风险对组


合的影 响。 但需要多少只股票才 能把大部分的公司特有风险消 除 呢 ? Statman ( 1987)认为,
需要至少 30 只 股票。 他发表的论文题 目就是 多元化的投资 组合需要多少只 个股 ? 下面
“ ”

的图 7-16 以股票数 目为 x 轴 , 以组合标准差与单 股票的标准差的比为 y 轴 。 表 7-6 中的 一

值 摘 自 Statman (1 987), 其 中 n 是投资 组合中的股票数 目, cip 是投资 组合的


年收益的标准
差, a1 是单只 股票的标准方差 。

表 7-6

" 。匾p
。霓p
。曾p 生
(TI (jI

I 49.236 l .00 14 22.670 0.46


2 37.358 0.76 16 22.26 1 0.45
4 29.687 0.60 18 2 1 .939 0.45
6 26.643 0.54 20 2 1 .677 0.44
8 24.983 0.5 1 25 2 1 . 1 96 0.43
10 23.932 0.49 30 20.870 0.42
12 23.204 0.47 35 20.634 0.42
118 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

续表
up
n ap
� n (1'p
(j I uI

40 20.456 0.42 500 1 9.265 0.39

45 20.3 1 6 0.4 1 600 1 9.347 0.39

50 20.203 0.4 1 700 1 9.233 0.39

75 1 9.860 0.40 800 1 9.224 0.39


1 00 1 9.686 0.40 900 1 9.2 1 7 0.39

200 1 9.432 0.39 1 000 1 9.2 1 1 0.39

300 1 9 .336 0.39 co 1 9 . 1 58 0.39

400 1 9.292 0.39

以下是 我们 的代码 。

fr om rnatp l o 七 lib . pyp l o 七 import *


n= [ l , 2 , 4 , 6 , 8 , 1 0 , 1 2 , 1 4 , 1 6 , 1 8 , 2 0 , 2 5 , 3 0 , 3 5 , 4 0 , 4 5 , 5 0 , 7 5 , 1 0 0 , 2 0 0 , 3 0 0 , 4 0 0 , 5 0 0 ,
600, 7 00 , 8 0 0 , 900, 1000)
port_s i grna = [ 0 . 4 9 2 3 6 , 0 . 3 7 3 5 8 , 0 . 2 9 6 8 7 , 0 . 2 6 6 4 3 , 0 . 2 4 9 8 3 , 0 . 2 3 9 32 , 0 . 2 3 2 0 4 ,
0 . 2 2 6 7 0 , 0 . 2 2 2 6 1 , 0 . 2 1 9 3 9 , 0 . 2 1 677 , 0 . 2 1 1 9 6 , 0 . 2 0 8 7 0 , 0 . 2 063 4 , 0 . 2 0 4 5 6 , 0 . 2 0 3 1 6 ,
0 . 2 0 2 0 3 , 0 . 1 9 8 6 0 , 0 . 1 9 6 8 6 , 0 . 1 9 4 3 2 , 0 . 1 9 3 3 6 , 0 . 1 9 2 9 2 , 0 . 1 92 6 5 , 0 . 1 9 3 4 7 , 0 . 1 92 3 3 ,
0 . 1 9 2 2 4 , 0 . 1 92 1 7 , 0 . 1 9 2 1 1 , 0 . 1 9 1 5 8 )
x l irn ( 0 , 5 0 )
ylirn ( 0 . 1 , 0 . 4 )
h l ines ( 0 . 1 9 2 1 7 , 0 , 5 0 , c o l o r s = ' r ' , l i n e s t y l e s = ' dashed ' )
anno 七 ate ( " , xy= ( S , 0 . 1 9 ) , xycoords = ' da 七 a ' , xytext = ( 5 , 0 . 2 8 ) ,
textc oords = ' dat a ' , ar rowpr ops = { ' arrowstyle ' : ' < -> ' } )
anno 七 at e ( " , xy= ( 3 0 , 0 . 1 9 ) , xycoo rds = ' da 七 a ' , x y七 ex 七 = ( 3 0 , 0 . 1 ) ,
textcoords = ' data ' , ar r owprops = { ' a r r ows 七 y l e I : I < -> I } )
annotate ( ' Total portfolio r i s k ' , xy= ( S , 0 . 3 ) , x ytext = ( 2 5 , 0 . 3 5 ) ,
ar rowprops = d i c t ( facecolor= ' black ' , shrink = 0 . 0 2 ) )
fi gtex 七 ( 0 . 1 5 , 0 . 4 , " Divers iable r i s k " )
figtext ( 0 . 6 5 , 0 . 2 5 , "Nondive r s i f iab l e r i s k " l
plo t ( n [ 0 : 1 7 ] , po r t_s i grna [ 0 : 1 7 ] )

t i t l e ( "Re l a 七 ionship between n and p o r t f o l i o r i s k " )


x l abe l ( "Number o f s tocks i n a portf o l io " )
y l abe l ( " Ratio o f P o r t f o l i o s td t o s td o f one stoc k " )
7.10 从雅虎 财 经 网 站 下 载历 史 价 格 数 据 119

show ( )

xlim()和 ylirn()分别 设定 x 轴和 y 轴的取值 范 围 , 结果如图 7- 1 6 所示。


R血' between n and portfolio risk
0.心

I :l
To�I p«tlolio ri,k
t \ �

o•f
, •�•�'
'-
" -
-------


I Noedi,e<Sffiabl,

-- ----.....- ---
汕 功 -­
岫 IIDCb ln._a
叫 - 勿

图 7- 1 6

7. 1 0 从雅虎财经 网 站下载历史价格数据

以上 的例子使用虚构 的股 票 回 报 率 。 那 么 现实中的 IBM 和沃尔玛是 怎 么 样的呢 ? 首


先 , 必 须 知道 如 何 从 雅 虎财 经 中 获 取 股 票 的 历 史 价 格 数 据 。 matplotlib 模块 中 的
quo t e s_臣 s t o r i c a l_yahoo_ochl ( 函
) 数可用来从 雅虎财经下 载 历 史 价格数据 。 用以
下 4 行 Python 代码来下载 IBM 在 20 1 2年 1 月 1 日 至 20 1 2年 1 2 月 3 1 日 期间每 日 的价格
数据 。

>>>from matp l o t l ib . f inance impor 七 quotes h i s t o r i cal yahoo ochl


>> >da 七 e l = ( 2 0 1 2 , 1 , 1 )
>>> date 2= ( 2 0 1 2 , 12 , 3 1 )
>>>p r i ce = quotes h i s t o r i ca l yahoo ( ' I BM ' , da 七 e l , date2 )

要下载到今天为止 的 IBM 的历 史价格数据, 可以使用 日 期时间 date.today(函数。


)

>>>import date 七 ime


>>>import matp l o t l ib . finance as finance
>>> import matp l o t l ib . mlab as ml ab
>>>ticker = ' IBM '
>>>dl = datetime . date ( 2 0 1 3 , 1 , 1 )
1 20 第 7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

>>>d2 = datet ime . date . today ( )

>>>p r i c e = f i nance . fe tch_h i s tor i cal_yahoo ochl ( t i c ker , dl , d2 )


>>>r = mlab . c sv2 r e c ( p r i c e )
>>>price . cl o s e ( )
>>>r . sort ( )

因为雅 虎财经的原始数据是按 降序排列 的, 所以用 r . s o r t ( 函


) 数按升序重新排列 。
要知道有多少观测值, 可以使用 l e n ( 函
) 数。 用 r[O] 和 r[- 1 ] 来查看第 一 个和最后一 个观测
值, 结果如下 。

>>>len ( r ) 9 8 9
>>> r [ 0 : 4 )
rec . ar ray ( [ ( datetime . date ( 2 0 1 3 , 1 , 2 ) , 1 9 4 . 0 9 , 1 9 6 . 3 5 , 1 9 3 . 8 , 1 9 6 . 3 5 ,
4234100 , 1 92 . 61 ) ,
( datetirne . date ( 2 0 1 3 , 1 , 3 ) , 1 9 5 . 6 7 , 1 9 6 . 2 9 , 1 9 4 . 4 4 , 1 9 5 . 2 7 ,
36447 0 0 , 191 . 55 ) ,
( date七ime . date ( 2 0 1 3 , 1 , 4 ) , 1 9 4 . 1 9 , 1 9 4 . 4 6 , 1 92 . 7 8 , 1 9 3 . 9 9 ,
3 3 8 02 0 0 , 1 9 0 . 3 ) ,
( datetime . date ( 2 0 1 3 , 1 , 7 ) , 1 9 3 . 4 , 1 9 3 . 7 8 , 1 9 2 . 3 4 , 1 9 3 . 1 4 ,
2 8 62 3 0 0 , 1 8 9 . 4 6 ) l ,
dtype = [ ( ' date ' , ' O ' ) , ( ' open ' , ' < £ 8 ' ) , ( ' h i gh ' , ' < f B ' ) , ( ' l ow ' ,
' <fB ' ) , ( ' close ' , ' <fB ' ) , ( ' vo l ume ' , ' <i4 ' ) , ( ' adj _c l o s e ' , ' <fB ' ) ] )
>>>

7.1 0. 1 用直方图 显示收益 率分布

用历史 回报率的均值来估 计期望收益, 用历史 回报率的标准差来估计收益的风险。 直


方图可以用来显 示这两 个量 。 分布 的峰值位于右侧的股票具有较高的预期收益 , 分布的分
散度表示风险水平, 分布越广意味着 风险越高。 下 面的代码绘制 一 个直方图。

fr om rnatp l o t l ib . pyplo七 impo r t *


f r om matp l o t l ib . f i nance import quotes_h i s t o r i c a l_yahoo_ochl
import numpy as np
import ma七p l o t l ib . mlab as mlab

t i c k e r = ' IBM '


begdate= ( 2 0 1 3 , 1 , 1 )

enddate = ( 2 0 1 3 , 1 1 , 9 )
p = quotes_hi storica l_yahoo_ochl ( ti c k e r , begdate , enddate , a sob j e c t=T rue ,
adj u s ted=T rue )
ret = ( p . a c l o s e [ l : ] - p . aclose [ : - 1 ] ) /p . a c l o s e [ l : ]
[ n , b in s , patches ] = h i s t ( re t , 1 0 0 )
7. 1 0 从雅虎 财 经 网 站 下 载 历 史 价格 数据 121

mu = np . mean ( re t )
s i gma = np . s td ( re 七 )

x = mlab . no rmpdf ( b in s , mu , s i gma )


p l o t ( b i n s , x , c o l o r = ' r ed ' , 1 "{ = 2 )
t i t l e ( " I BM return dis 七 r ibution " )
xlabel ( " Re turns " )
ylabel ( " Frequen c y " )
sho w ( )

以上 代码的输出结果如图 7-1 7所示。

IBM return distribution


35 30

2 5 •-
.uuanbay
20 15

10 1·
5

图 7- 1 7

下 一 段代码使得交易 日 较均 匀 地分布。

f rom future import p r i n t func t i on


import numpy as np
import matp lot l ib . p yp l o t a s p l t
import matpl o 七 l ib . mlab a s mlab
import matp l o t l i b . cbook as cboo k
impor 七 matp l ot l ib . t i c ke r a s t i c k e r
import da 七 et ime
import matpl o t l i b . f i nance as f i nance

myti c ker = ' IBM '
begdate = date t i me . date ( 2 0 1 7 , l , 1 )
# enddate = datet ime . date . today ( )
enddate = datetime . date ( 2 0 1 7 , 2 , 27 )
begdate = datet ime . date ( 2 0 1 3 , l , l )
price = finance . f etch_h i s t o r i ca l_yahoo (myt i c k e r , begdate , enddate )
1 22 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

r = m l ab . csv2rec ( p r i ce ) ; p r i c e . close ( )
r . sort ( )
r = r [ - 3 0 : ] # ge 七 the l a s t 3 0 days f i g ,
a x = pl t . subp l o t s ( )
pl t . p l o t ( r . date , r . adj _cl o s e , ' o - ' )
p l t . t i t l e ( ' Fi g . 1 : I BM last 3 0 days with gaps on wee kends ' )
# fi g . auto fmt_xdate ( )
N = len ( r )
ind = np . a r ange ( N ) # the eve n l y spaced p l o t i ndi ces
de f f ormat_date ( x , pos =None ) :
thi s i nd = np . c l ip ( i nt ( x+ 0 . 5 ) , 0 , N- 1 )
re 七 u r n r . date [ t his i nd ] . s t r f 七 ime ( ' 毛Y- 毛m-沧d ' )

f i g , ax = p l t . subplots ( )
plt . p l o t ( i nd, r . adj_c l o s e , ' o- ' )
p l t . x l abe l ( "Every Monda y shown " )
ax . set_t i t l e ( ' Fi g 2 : I BM l a s t 3 0 days evenl y spaced p l o t indices ' )
ax . xa x i s . set_maj or_ f o rmatte r ( ti c ke r . FuncForma 七 t e r ( f orma t—dat e ) )
f i g . auto fmt_xdate ( )
p l t . show ( )

绘制的第二张图如图 7- 1 8 所示 。

182
空2: IBM 正 30 血” “如ly

180

178

17•

174 •-

172

170

1611

归 ,_

. 一心
-"� -,r> �1
164
企 ,»v 1少 1 记t � 1少 1企
. 心 少
、“
lo 令 妒 -,r>\. 令 -,r>\. 令

图 7- 1 8

7.1 0.2 比较单只股票的收益和市场收益

以下的代码从 雅虎财经下载 一 只 股票的每 日 价格数据和代表市场的标准普尔 500 指数


的数值, 计算它们各 自 的回 报率, 然后 绘制它们的图形 。
7. 1 0 从雅虎财经 网 站 下 载历 史价格数据 1 23

fr om matplo 七 lib . pyplot impor 七 *


from ma七plot巨b . finance import quo七es_h i s t o r i c a l_yahoo_ochl
import numpy as np
de f ret_f ( ti c ke r , begdate , enddat e ) :
p = quotes_h i 江 o r i ca1_¥ ahoo_ochl ( t i c ke r , begda 佳 , enddate ,
asobj ect =True , adj us 七 ed=True )
re 七 urn ( ( p . a c l o s e [ 1 : ] - p . aclose [ : - 1 ] ) /p . aclose [ : - 1 ] )

begdate = ( 2 0 1 3 , l , l )
enddate = ( 2 0 1 3 , 2 , 9 )
retl=ret_f { ' IBM ' , be gdate , e nddat e )
ret2= ret_f ( ' " GS PC ' , begdate , enddate )
n=min ( l en ( re t l ) , l en ( re t2 ) )

s = np . ones ( n ) * 2
t=range ( n )
l i ne = np . zeros ( n )
plot ( t , retl [ O : n ) , ' r o ' , s )
plot ( t , r e t2 [ 0 : n ] , ' bd ' , s )
plot ( t , l ine , ' b ' , s )
f i gtext ( 0 . 4 , 0 . 8 , " Red f o r IBM , Blue for S & P S O O " )
x l im ( 1 , n )
ylirn ( - 0 . 0 4 , 0 . 0 7 )
t i t l e ( " Cornparions between stock and mar ket re七un s " )
x l abel ( " Day " )
ylabel ( " Returns " )
sho w ( )

代码的输出如图 7-1 9 所示。


Compartons � stDck 咖 Id mat血 叩ns
0.0I Red for IBM. Blue for S&P500

0.04

O.o2

. .....

• •

o.ool • • •• •• • •
-0.02

J心 五

图 7- 1 9
1 24 第7章 用 matplotlib 模 块绘 制 与 金 融 相 关 的 图 形

7. 1 1 了解现金 的 时 间 价值

我们 知 道, 今天收到 1 00 美元 比 一年后收到 100 美元更有价值。 以下 代码绘制 大 小不



的圆 圈 来形象地表达现金的时间 价值。

fr om ma七p l o t l ib . pyp l o t imp o r t *


f i g l = f i gure ( f a c e c o l o r = ' wh i t e ' )
a x l = axe s ( frameon = Fal s e )
a x l . s e t f r ame on ( Fa l s e )
axl . get xaxis ( ) . t i c k bot tom ( )
a x l . axes . get_yaxis ( ) . s e t_v i s ible ( Fa l s e )
x = range ( 0 , 1 1 , 2 )
x l =range ( l en ( x ) , 0 , - 1 )
y = [ O ] * l en ( x ) ;

vO = " Today ' s value o f $ 1 0 0 rece ived 七oda y "
v2 = " T o day ' s va lue o f $ 1 0 0 rece ived i n 2 ye ars "
v6 = " r ece ived i n 6 ye a r s "
v l O = " rece i ved in 1 0 ye ars "
c= " b l a c k "

anno七ate ( v 0 , x y= ( O , O ) , xytext = ( 2 , 0 . l ) , ar rowprops = dict ( facecolor =c , shrink =
0 . 02 ) )
anno七ate ( v 2 , xy= ( 2 , 0 . 0 0 5 ) , xy七ex七 = ( 3 . 5 , 0 . 0 8 ) , a rrowprops=di ct ( facecolor=c ,
s h r i n k= 0 . 0 2 ) )
annota七e ( v 6 , xy = ( 4 , 0 . 0 0 0 0 5 ) , xytext = ( 5 . 3 , 0 . 0 6 ) , a r rowprops = dict ( facecolor =
c , s h r i n k= 0 . 0 2 ) )
annota七e ( v l 0 , xy= ( l 0 , - 0 . 0 0 0 0 5 ) , xytext= ( 4 , - 0 . 0 6 ) , ar rowprops =dict ( facecolor =
c , shrink=0 . 0 2 ) )
s = [ 5 0 * 2 . S * * n for n in xl ] ;
t i 七 l e ( " T ime value o f mone y " )
x l abel ( "Time ( number o f years ) " )
sea七ter ( x , y , s =s ) ;
show ( )

输出如图 7-20 所示 。

7. 1 2 用 烛 台 图 展 示 IBM 的 每 日 收 盘 价 1 25

Time value of money

.ed
Today's value of $100 received today
Today's value of $100 received in 2 years
received in 6 years


. ars
。ye
.
r
e
c
e
'
v


,0

10

-2 立
Time (number of years)
2 4 6 8

图 7-20

7. 1 2 用 烛 台 图 展 示 I BM 的每 日 收盘价

可以用一 根蜡烛来 代表每 日 的开盘价、 日 内最高价、 日 内 最低价和 收 盘 价 。 垂直线代


表 日 内最低价和 最高价的区 间, 中间的矩形条代表开盘价和 收 盘 价的区 间 。 当 收盘价高于
开盘价时, 矩形条是黑 色的, 反之是红色的。 下面的代码用来绘制烛 台 图。

import matp lo t l ib . pypl o t as p l 七


import numpy as n p
from matp l o t l ib . dates import DateFormatte r , Wee kdayLocat o r , HourLo cato r ,
DayLoca tor , MONDAY
f rom matplotlib . f i nance import quote s_h i s t o r i c a l_yahoo_och l , _candl e s t i c k ,
p l o t day summary o c l h

date l = ( 2 0 1 3 , 1 0 , 2 0 )
date2 = ( 2 0 1 3 , 1 1 , 1 0 )
t i cker= ' IBM '
mondays = Wee kdayLocator ( MONDAY) # maj o r t i cks on the mondays
a l l days = DayLocator ( ) # minor ti cks on the days
wee kForma七ter = Da teFormatter ( ' %b %d ' ) # e . g . , Jan 1 2
dayFormatter = DateForma tter ( ' %d ' ) # e . g . , 12
quo七es = quotes_h i s torica l_yahoo_ochl ( t i c ke r , date l , date2 )
i f len ( quot e s ) == 0 :
raise Sys temE x i t

1 26 笫7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

f i g , ax = plt . subplots ( )
f i g . subplot s_adj u s t (bot七om=0 . 2 )
ax . xax i s . s e 七_ma j o r_locator (monda y s )
ax . xax i s . s et_mi nor_locat or ( a l ldays )
ax . xaxi s . set_maj or_formatter ( wee kFo rmatte r )
ax . xaxis . s e 七_mi nor_formatte r ( dayFormatte r )
plot_day_summary_oclh ( a x , quo七 e s , t i c k s i z e=3 )
_candl e s t i c k ( ax , quote s , width=0 . 6 )
ax . xaxi s_date ( )
ax . autosca le_view ( )
p l t . se tp ( pl t . gca ( ) . ge 七_xt i c klabe l s ( ) , rota七ion = 8 0 ,
hori zontal al i gnment= ' r i gh七 I )
plt . f igtex t ( 0 . 3 5 , 0 . 4 5 , ' 1 0 /2 9 : Ope n , H i gh , Low , Close ' )
p l t . f i gtext ( 0 . 3 5 , 0 . 4 2 , ' 1 7 7 . 62 , 1 8 2 . 3 2 , 1 7 7 . 5 0 , 1 8 2 . 1 2 ' )
p l t . f i gtext ( 0 . 3 5 , 0 . 3 2 , ' B lack == > Close > Open ' )
plt . figtext ( 0 . 3 5 , 0 . 2 8 , ' Red ==> C l o s e < Open ' )
plt . t i t l e ( ' Candl e s t i c k s for I BM from 1 0 / 2 0 / 2 0 1 3 七Q 1 1 / 1 0 / 2 0 1 3 I )
pl七 . ylabel ( ' Pr i ce ' )
pl t . xlabel ( ' Date ' )
plt . show ( )

输出的图形如图 7-2 1 所示。

1•!血 +,
。立 竺, 邮 fn,n, 10/功'2013 llo 11/J吵13
1821,

,l
1801

',

,.,., , ,
17 8十

扣 t 10/2 9: Open, H.i3g h, Low. Close


17 7 .6 2 , 182 2 , 177 50 182 1 2

Black ==> Close > O pen


112陬l
Red ::> Close < Open

l70U-­
2

图 7-2 1

7. 1 3 用 图 形展示价 格变化

可以显示从 第 1 个 日 期到第 2 个 日 期之间股票价格的


变化。 下 面的代码用到 3 个参数
7. 1 3 用 图 形展 示 价 格 变 化 1 27

值: ticker ( 股票代号)、 begdate C 起始 日 期) 和 enddate ( 终止 日 期)。

import da 七 e time
import matp l o t l ib . pyp l o t as p l t
from matpl o t l i b . dates impor \ Mon 七 hLocator , DateFormat 七 e r
from ma 七p l o t l i b . finance import quotes_h i s t o r i c al_yahoo_ochl as get Data

t i c k e r = ' AAPL '
begda 七 e= date t ime . date ( 2 0 1 2 , 1 , 2 )
enddate = datetime . date ( 2 0 1 3 , 1 2 , 4 )
months = MonthLocator ( range ( l , 1 3 ) , bymonthday= l , inte rval = 3 )
# every 3 r d month
monthsFmt = DateFormatter ( " %b ' %Y " )
x = getData ( t i c ke r , begdate , enddate )

i f l e n ( x ) == 0 :
print ( ' Found no quotes ' )
raise SystemExit
dat es = [ q [ O ] for q i n x]
closes = [ q [ 4 ] f o r q i n x ]
f i g , ax = p l t . subplots ( )
ax . pl ot_date (dat e s , c l o ses , ' - ' )
ax . xaxis . se t_maj or_locator ( mon 七 hs )
ax . xaxi s . set_ma j o r_forma 七 ter ( monthsFm 七 )
ax . autosca l e_view ( )
ax . g r i d ( True )
f i g . auto fmt_xdat e ( )
plt . show ( )

输 出 的图形如图 7-22 所示。

700
650
600
550
500
450
· .
叩F

x=Jan '2012 y:660.042

图 7-22
1 28 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

可 以 观察在任意给定 的 时 间 区 间 内 的股票价格变 动 , 比 如 从 2009 年 1 月 至 今 。 首 先 ,


看看 日 内 价格 变化趋 势 。 下 面 的 代码将在第 8 章解 释 。

import numpy as np
import pandas as pd
import datet ime as dat e t ime
import matp l ot l ib . pyplot as p l t
t i c ker = ' AAPL '
path = ' ht 七p : //www . googl e . com/ fi nance /getpr i c e s ? q= t t t & i = 6 0 &p = ld&f=d, o , h ,
l , c,v'
p=np . array ( pd . read_csv (path . replace ( ' ttt ' , ticker) , s kiprows=7 , header =None ) )

dat e = [ l
for i in np . aran ge ( O , len ( p ) ) :
i f p [ i ] [ 0 ] [ 0 ] == I a I :
t= datetime . datetime . fromtimes tamp ( i nt ( p [ i ] [ O J . replac e ( ' a ' , ' ' ) ) )
date . append ( t )
else :
date . append ( t +da 七 etime . t imede lta (minutes = int ( p [ i ] [ O J ) ) )

final=pd . DataFrame ( p , index=dat e )
f i n a l . col umns = [ ' a ' , ' Open ' , ' High ' , ' Low ' , ' Clos e ' , ' Vol ' ]
de l final [ ' a ' ]

x = final . index
y=final . C l ose

p l 七 . 七 itle ( ' I n t raday p r i ce pattern for t tt ' . replace ( ' t t t ' , t i c ke r ) )
pl 七 . x labe l ( ' P r i ce o f s tock ' )
p l t . ylabel ( ' I nt ro-day price pa 七 t e rn ' )
pl t . pl o 七 ( x , y )
p l t . show ( )

显 示 结 果 如 图 7-23 所 示 。

可 以 在 http://matplotlib.org/examples/pylab_examples/finance_work2.html 找到 一 个绘制
日 价格 图 形 的 更 复 杂 的 代 码 。 与 之 相 比 , 我 们 的 代码较为 简 单 。 为 了 节 省 空 间 , 这 里 省 略

了 生 成 图 7-24 所 示 图 形 的 Python 代 码 。
7.14 同 时 展 示 收 盘 价和 交 易 量 1 29

lntraday price 凹ttem for 心L

566

r
I:!.

·� 562 ,.

f-
口.

560

558

10:00:00 11.00:00 12:00:00 13:00·00 14:00:00 15:00:00 16:00,00


Pnce of st吐

图 7-23

IBM daily
RSI (14)

200

160

120

80

-5
-1 0

令Flq 心`,_o0q佟 ,_ti、°沁q令°佟 妒、沁�心心��妒:i沁�,_ti、:i ,_ti令沁`,_ti、3


�'O � ` ` �'O

图 7-24

7. 1 4 同 时展示收盘价和 交 易 量

有时候, 想同时查看价格走势和交易量 。 下面的代码可以做到这一 点。

import matpl o t l i b . p yp l o t as plt


impo rt pandas_datareade r . data as getData
1 30 第 7 章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

df = get Data . DataReader ( " I BM" , ' yahoo ' )


plots = d f [ [ ' Adj C l o s e ' , ' Vo l ume ' J l . plot ( s ubp l ots=True , f i g s i z e = ( 1 0 , 1 0 ) )
p l t . show ( )

显示结 果 如 图 7-25 所 示 。

200

180

2心

1心

uo

100

|—
2.S
Volume I
20

15

1.0

心、..
05

心, 、.,
-IP"'

-,,.9
0.0
心心 夕
、令
飞0
Data

图 7-25

7.14. 1 在图形上添加数学公式
金融计算经 常 用 到 许 多 数 学 公 式 。 有 时 候 , 需要把 个 数 学 公 式 添加 到 图 形上 。 下面

的 代 码 利 用 matplotlib 模块来实现计算看涨期权价格 的 数 学 公 式 。

import numpy as np
import matplot l i b . ma thtext as mathtext
impor 七 ma tpl o t l ib . pyplot a s p l t
import matp l o t l i b

ml=r ' $ c=S. ON ( d. 1 ) -Ke" { - rT } N ( d 2 ) $ '


m3= r ' $d_l = \ f r ac { ln ( S_O /K ) + ( r+ \ s i gma " 2 / 2 ) T } { \ s i gma \ sqrt { T } } $ '
m2=r ' $ d_2 = \ f rac { l n ( S_0 / K ) + ( r- \ s i gma " 2 / 2 ) T } { \ s i gma\ s qrt { T } } =d_l一 \ s i gma \ s q
r七 { T } $ I

matp l o t l i b . r e ( ' image ' , o r i gin= ' upper ' )
p a r s e r = mathtext . MathTex七Par s e r ( " Bi tmap " )
r l , dept h l =pars e r . to_rgba (ml , c o l o r= ' red ' , f o n 七s i z e = l 2 , dp i=2 0 0 )
r2 , depth2=pa rs e r . 七 o_rgba ( m2 , c o l o r = ' bl ue ' , fon 七 s i ze= l 2 , dpi = 2 0 0 )
r 3 , depth3=par ser . to_rgba (m3 , c o l o r= ' bl ue ' , font s i ze=l 4 , dpi =2 0 0 )
7.14 同 时展 示 收盘价和 交 易 量 131


fig = p l t . f i gure ( )
fig . figimage ( r l . as type ( f l oat ) / 2 5 5 . , 1 0 0 , 1 0 0 )
f i g . figimage ( r 2 . astype ( f loat ) / 2 5 5 . , 1 0 0 , 2 0 0 )
f ig . f igimage ( r 3 . as type ( fl oa七) / 2 5 5 . , 1 0 0 , 3 0 0 )
plt . s how ( )

这段代码的关键在于 使用了 一个高品质的排版格式 LaTeX 。 它 是特别针对技术和科学文


献的 出 版而设计的。 根据 http://latex-project.org/ 网站, LaTex 是科学文献 出 版的标准软件。 上

段代码的输 出 如 图 7-26 所示。

c = Bo N估
J ) ---Ke-rT N(d.i )
) +(r+tr /2)T
"1 - = 叫 /K
· 歹
"'2 = 叫�fl(J
贮 '+ {1'-tr 几汀
r .. = d1 - 0' 汀

图 7-26

7.14.2 在图形上添加简单的图像
假设把 Python 的标志保存在 c:\temp 目录下 。 下 面的代码 可以在 http://canisius.edu/
-yany/python_logo.png 网 站下载该标志 :

>>> import matpl o t l ib . pyp lot as p l t


> > > import matp l o t l ib . cbook a s cbook
>>>image_f i l e = cbo o k . get_sampl e_data ( ' c : /temp/python_logo . png ' )
>>>image = p l t . imread ( image_f i l e )
>>>pl t . imshow ( image )
> > >plt . axis ( ' o f f ' )
>>>pl t . show ( )
= t己I
cbook 模块是 一 些实用 痉圃 石
函数和类的集 合,许多来自
Python cookbook 这 本 书 。
因 此, 它 被命名为 cbook。
图 7-27 为绘制的结果 。
图 7-27
1 32 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

7.14.3 保存图 形文件


如果打算把生成的图 形保存为 . pdf 文件, 可以使用下面的代码。

>>>f rom matpl o t l i b . pylab impor t *


>>>plot ( [ l , 1 , 4 , 5 , 1 0 , 1 1 ] )
> > > s ave fi g ( " c : / temp / te s t . pdf " )

绘制的图形如图 7-28所示。

12

10
8
6
4
2
。 LO

3
2

5
4

图 7-28

如 果 代码 不 指 定 一 个 特 定 的路 径 , 这 一 图 形 文 件 将 在 当前工作 目录下, 通 常 是
c:\ yt
p h on2 7。

>>> save f i g ( " test . pdf " )

7. 1 5 比较个 股 的 表现

下面的代码比较几只 股票在 2013年的回报率 。

import numpy a s np
import ma 七plotl ib . p yplot as p l t
import matp l ot l ib . pyplot as p l t ; p l t . rcdefa u l t s ( )
from matp lot l ib . f inance impo rt quotes_h i storical_yahoo_ochl as getData

7. 1 6 比较 多 只 股 票 的 收益 率 与 波 动 率 1 33

s tocks =( ' I BM ' , ' DELL ' , ' WMT ' , 'C' , ' AAPL ' )
begdate= ( 2 0 1 3 , 1 , 1 )
enddate = ( 2 0 1 3 , 1 1 , 3 0 )

de f re 七 _annual ( t i c k e r } :
X = ge 七 Data ( t i c ke r , begda t e , e nddat e , a s ob j e c 七 =True , adj u s t ed=Tru e )

l ogret = np . l og ( x . acl ose [ l : J / x . a c l o s e ( : - 1 ] )


return ( np . exp ( s um ( l ogre t ) ) - 1 )

per fo rmance = [ )
for 七i cker in s to c k s :
p e r fo rmance . append ( ret_annual ( 七 i c k e r ) )

y_pos = np . arange ( l en ( st o c k s ) )
plt . barh ( y_po s , p e r f o rmance , l e f t= O , alpha = 0 . 3 )
pl 七 . yt i c k s ( y_po s , s t o c k s )
pl t . xlabel ( ' Annual returns ' )
p l t . 七 i t l e ( ' Per formance compa r i sons ( annual re七u rn ) ' )
p l t . show ( )

绘制的柱状图如图 7-29 所示 。
Perfonnance compafisons (annual return)

AA.PL ,-

C卜

WMT •·

OEU

吨10
Annual n如ms
-0.05 0.00 0.05 0.10 0.15 0 20 0 2S 0.30 0.3S

图 7-29

7. 1 6 比 较 多 只 股票 的收益率 与 波 动 率

以下代码显示 5 只 股票在收益率与波动率 图 上 的位置。

import numpy as np
1 34 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

import matplotl ib . p yplot as plt


f rom matp lotlib . f i nance import quotes—h i s t o r i c a l_yahoo_o chl as getData

p l t . rcde faul ts ( )
stocks = ( ' I BM ' , ' GE ' , ' WMT ' , ' C ' , ' AAPL ' )
begdate= ( 2 0 1 3 , l , l )
enddate= ( 2 0 1 3 , 1 1 , 3 0 )

de f re 七_vol ( t i c ker ) :
X = ge 七 Data ( t i c k e r , begdate , enddate , a s ob j ect=True , ad j usted=True )

logret =np . l og ( x . a c l o s e [ l : ] / x . aclos e [ : - 1 ] )


return ( np . exp ( sum ( l ogre t ) ) - 1 , np . s td ( logret) )

ret= [ ]
vol = [ ]
for 豆 c k e r in stocks :
r , v=re 七_vol ( 七 i c ke r )
re 七 . append ( r )
vol . append ( v * np . sqrt ( 2 5 2 ) )

labe l s = [ ' { 0 } ' . fo rmat ( i ) for i i n stoc ks ]
color=np . arra y ( [ 0 . 1 8 , 0 . 9 6 , 0 . 7 5 , 0 . 3 , 0 . 9 ] )

f i g , ax = p l t . subplots ( )
ax . sea 七 t e r ( vol , ret , ma rker = ' o ' , c=color , s = 1 0 0 0 )
for i , txt i n enume rate ( s t o c ks ) :
ax . annotate ( txt , ( vol [ i ] + 0 . 0 2 , r et [ i ] + 0 . 0 1 ) )

p l t . x l abe l ( ' Volati l i t y ( annua l i zed) ' )
pl t . ylabe l ( ' Annual return ' )
plt . 七 itle ( ' Return vs . volati l i t y ' )
p l t . subp l o t s—adj ust ( bottom = 0 . 1 )
p l t . show ( )

图 7-30 中的每 个点代表一 只股票的年度收益率和年度波动率。 每只 股 票用不 同的颜色


表示, 使画面更加醒 目。

7. 1 7 查 找 学 习 手 册 、 示 例 和 有 关 视 频 1 35

o Return vs. volatility


0.3 I GE c
• .

.从
02
0 WMT

.,1
1

i 01

J PL

IB M

-01 I -

勺 �05 0.10 0.15 0. 2 0 0. 2 5 OJO 0.35


`叮 CIIMUlllizecl)

图 7-30

7. 1 7 查找学 习 手册 、 示 例 和 有 关视频

我们建议在开始 编写 自 己的应用程序之前, 应 该好好学习 和参考网 页上给出的例子。


网页 http://matplotlib.org/examples/index.html 提供了许多 Python 编程的例子。 以下网 页与
matplotlib 模块有关 。
• http://matplotlib.org/users/
• http://scipy-lectures.github.io/intro/matplotlib/matplotlib.html

下面两 个网 页给出了超过 5 000 个例子 。


• http://matplotlib.org/examples/index.html

• http://www.youtube.com/watch?v=0fumUp3hZmQ

下面的网 页介绍如何安装 ActivePython 和 matplotlib 模块。

• http://www.activestate.com/activepython/python-financial-scientific-modules (5 m, 37s)

下面的视频介绍如何通过视觉方式 分 析财务报表。
• http://www.youtube.com/watch?v= OfumUp3hZmQ
1 36 第 7 章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

7. 1 8 独立安装 matplotlib 模块

通过两 个步 骤来安装该模块。
I . 转到 http://matplotlib.org/downloads.html 。

2 . 选择合适的软件包并下载, 如 matplotlib- l .2. l .win-amd64-py3.2.exe。

7. 1 9 小结

本章介绍 了 如何使用 matplotlib 模块通过图形、 图片、 颜色和大 小 来生动地解释许多金


融概念, 比如在 一 个二维图里展示股票的收益 率和波动率的关系、 净现值 曲线、 多个内部
收益率, 以及分散投资 对投资组合风险的作用。 下 一 章首先介绍如何从 儿 个公开 的数据 网
站, 包括雅虎财经、 谷 歌财经、 美联储的数据库 和 KennethFrench 教授的数据库 中 获取历
史数据 。 然后, 讨论各种统计检验, 比如 T 检验、 F 检验和正态性检验。 此外, 编写 Python
代码来应用资 本资 产定价模 型 (CAPM)、 应用 Fama-French 三因子模 型、 计算 Roll C 1984 )
的价差模 型、 估计单只股票的在险价值 ( VaR)、 估 计 Amihud (2002 ) 的反流动性指标,
以及 Pastor 和 Stambaugh (2003) 的投资组合的流动性指标 。 检测股票 超额回报率是否存
在 一 月效应 。 对于高频 数据 , 介绍如何从 TORQ 数据库 和 TAQ 数据库 检索数据 并研究 日
内价格走势。

练 习题

I . matplotlib 模块的潜在用途是什 么 ?
2 . 如何安装 matplotlib 模块?

3. matplotlib 模块是否依赖于 NumPy 模块? 是否依赖 于 SciPy 模块?

4. 编写 一 个 Python函数用来绘制一组给定现金流的净现值 曲 线 。

5 . 编写 一 个 Python函数从 雅虎财经网站下载股票的每 日成交价。

6 . 有两 只股票在 6 年里的回报率, 打算构建 一 个


简单的等权重的投资组合。 解释下面
的 Python 代码, 并说 明投资组合。
练 习 题 1 37

>>>A= [ O . 0 9 , 0 . 0 2 , - 0 . 1 3 , 0 . 2 0 , - 0 . 0 9 , - 0 . 0 3 ]
>>> B= [ 0 . 1 0 , - 0 . 3 , -0 . 02 , 0 . 1 4 , - 0 . 1 3 , 0 . 2 3 ]
> > >C= [ 0 . 0 8 , - 0 . 1 6 , 0 . 0 3 3 , - 0 . 2 4 , 0 . 0 5 3 , - 0 . 3 9 ]
>>>port_EW= ( A+ B ) / 3 .

7. I BM、 DELL、WMT、C 和 G E 在 2011年的股票 日 回报率的标准差 各是多少 ?

8. 如何计算给定的一组股票的滑动时间窗 口 里的贝 塔值 ?

9 . 如何用 I BM 的 日 回报率绘制直方图? 可以用雅虎财经网 站上 最近 5年的 日 回报 率


来计算。

10. I BM、 DELL 和 WMT 中哪 一 对个股是最紧密的互相关联? 如何证明 你的答案 ?


可以用从 雅虎财经获得的最近 5年的数据来支持你的结论。

11 . 什 么 是资 本市场线 ? 如何以视觉方式展示这个概 念 ?

1 2 . 什么是证券市场线 ? 如何以视觉方式展示这个概 念 ?

1 3. 你是否能找到历史数据来支持或反驳 Statman ( 1987)的结论: 将 大部分公司特定


风险消 除掉的投资组合至少应该持有 30 只 股 票 ?

1 4 . 从 雅虎财经下 载十只 股票的数据来构建 个投资组合的有效边界。 可以使用每 月


或每 日 数据 。

1 5 . 如何展示风险和回报率 之间的关系?

16 . 美国股市和加 拿大 股 市 之间的相关系数是多少 ? 美国股市 和 日 本股市之间的关系


呢 ? 可 以选择 S & PSOO ( 雅 虎财经的代号为AG S PC ) 代表美国股市 。 要搜索市场指数, 先
找 finance.yahoo.com , 在搜索栏中输入^, 然后 按 回 车, 出现如 图 7-31 所示的页面。

YAF IH N CE.
NAOO ! 二一
叶�SEI OlX NIFTY
Recent 'I(, s AD.JI Dow Jones lndustnal Average
AAPL �o 5 1 % AGSPC S&P 500
DELL 0.邓 •IX!C NASDAQ Compostte
IBM �o 19% AVJX VOLATILITY S&P 500
IBM L 0.00% AJKSE Composite Index
WMT -0 97% •NOX NASOA0-100
•N225 M1kke1 225
心SPC -0 43%
ATf'll( CBOE Interest Rate 10-Year T-No
'OJI -0 43%
•HSI HAJ�G SENG INDEX
-0 51%

图 7-3 1
1 38 第7章 用 matplotlib 模 块 绘 制 与 金 融 相 关 的 图 形

1 7 . 如何从 100 个股票代码 中随机地选择 1 0 只 股 票 ?

18. 从 雅虎财经下载 5年的每 日 价格数据并绘制 1 0 只 股票的投资 组合的有效边界 。

19. 如何把三维 图 形用在金融教 学上 ?

20. 查找 关于以视觉方式表现金融概率的更多信息, 并谈谈你的看法。

21 . 找出下面代码中的错误并改正。

> > > imp o r t sc ipy a s sp


>>>impo r t rnatpl o 七 l ib . pyp l o t a s p l t
> > > ca s h f l ows= [ l 0 0 , - 5 0 , - 5 0 , - 5 0 , 60 ]
> > > rate =npv = [ ]
> > > x= [ 0 , 0 . 8 ]
> > >y = [ O , O ]
> > > f o r i i n range ( l , 3 0 ) : rate . append ( O . O l * i )
npv . append ( sp . npv ( O . O l * i , cashf l ows [ l : ] ) + c a s h f l ows [ O ] )
> > > p l t . pl ot ( x , y ) , pl t . plot ( r ate , npv)
> > >p l t . show ( )

22 . 本章讨论了有 关杜邦等式的

些 问题。 戴尔和沃尔玛这两 家公司的净资 产收益 率
ROE 同为 0.22。 然而, 图 7-32 中对应的柱状图 却有不 同的高度 。 原因是净资 产收益率 ROE
是 3 个量的乘积, 而不是求和。 找到 一 个方法来解决这个问题, 使得代表这两 家公司的柱
状 图有相同的高度。
DuPont Iden汛y ror 3 ftnns
9

一的
- profitMargin
皂I - assetTurnover
ultMultlpl1er
6
.
i
S
3
C5d8
`
`_
2

图 7-32
第8章

时 间 序列 的统计分析

时间序列 分析在金融领域有广泛而且 非常重要的应用 。 本章将讨论许多与之相关的课


题 , 如下 载历史数据、 计算回报率、 整体风险、 市场风险、 股票之 间 的相关性、 不 同 类型
的投资组合、 不同的国家或市场之间的相关性、投资组合的方差-协方 差矩 阵 、 构建有 效的
投资组合和寻 找投资组合的有效边界, 以及估算 R o l(l 1 984)的买卖价差模型、 A mihud( 2002)
的反流动性指 标、 P ast or 和 St amb augh ( 2003)的流动性指 标 。 本章主要用到 P and as 和
st at s mode sl 这两 个 Pyth on 模块。 本章主要内 容 如下 。

• 安装 Panda s 和 s tat smode l s 模块

• 使用 Panda s 和 s tatsmode l s 模块

• 开源数据, 从 E xcel 、 txt、 csv 和 MATLAB 文件输入数据, 以及从 网 站 查询数据

• d ate 类型、 D at aF r ame 类型和按 日 期合并不同的数据集

• 利率的期限 结构

• 基于 52 周 最高和最低的交易策略

• 计算回报率以及从 日 回报率得到 月 回报 率或年回报率

• 各种统计检验, 如 Durbin-W ats on 检验、T捡验和 F-检验

. 资 本资 产定价模型 CCAP M )和 F ama-M acBeth 回 归 模型

• 滚动时间窗 口 的波动 率 、 相关系数、 构建 n 只股票的投资组合、 方 差-协方差 矩 阵 、


有效投资组合和投资组合的有效边界

• R o l l (1 984 )买 卖价差模型、 A mihud ( 2002)反流动性指标、 P ast or 和 Stamb augh


( 2003) 流动性 指标
1 40 第 8 章 时 间 序列 的 统计分析

• 个股和投 资 组合 的 在 险价值 (VaR)

• 一
月 效应 、 规模效应和工作 日 效应
• 从谷歌 金融和 TORQ 数据库获取高频数据

8.1 安装 pandas 和 statsmodels 模块


上 一 章 用 到 Ac巨ve P yt hon 包含的 pypm 命 令 来 安 装 Pandas 模块, 不 过 pypm 命令不
能安装 statsmodels 模 块 。 幸运 的 是 , 我们 可 以 使用 第 4 章 介 绍 过 的 Anaconda 软 件 包 。
Anaconda 软件包有两大优点 : 第 一 , 它包 括 NumP y 、 S c i P y 、 ma tpl o t l ib 、 Pandas 和
s t a t smode l s 等常用 的模块; 第 二 , 它提供 一 个非常优秀的 编辑器 Spyder。 执行 以下两
个步骤来安装 Anaconda:
1 . 转到 http : / / c ontinuum . i o / downloads 。

2 . 根 据 你 的机器 , 选 择 一 个 合 适 的 包 , 如 Windows 版本 Anaconda- 1 .8.0-Windows­


x86.exe 。

有几种方法来运行 Python。 单击开始所有程序 , 搜索 Anaconda, 结果如图 8- 1 所示 。


Anaconda (32- bit)
面 Anaconda Command Prompt
Browse Anaconda lnst0llation Direct
(P !Python (Py 2.7) Notebook
IP !Python (Py 2.7) QTConsole
IP !Python (Py 2.7)
• launcher
心 Reset Spyder Settin尹
喝 Spy der
Wakari (in the cloud)
图 8- 1

将在接下来 的三节 内 容来说 明 如 何 以 不 同 的 方式运行 Python 。

8.1.1 在 Anaconda 命令提示符下启动 历thon


执行下列 步骤在 Anaconda 命令提示符下启 动 Python 。
1 . 单击开始所有程序 , 搜索 Anaconda, 然 后 选择 Anaconda Command Prompt, 转到
包含 了 Python 的 可执行文件 python . exe 的 目 录 下 。
8. 1 安 装 pandas 和 statsmodels 模块 141

2 . 不 同的安装可能会在不 同的路径下。 如图8-2 的第 1 行所示, 输入 yt


p h on 命令来启
动 Pyth on。 为了测试 Panda s 和 stat smode l s 模块是否 可用, 试着导入这两个模块。 如
果没有错误, 就表示它们 已经正确 安装。

图 8-2

8.1 .2 使用 DOS 窗 口 启动 Python


可以从 任何 目录运行 Pyth on。 执行下列 步骤把 Pyth on 可执行文件的安装 目录添加到搜
索路径上。

I . 通过A n acond aC ommand Pr om tp ( 参 见第 8 . 1 . 1 节的步骤) 打开命 令窗 口 , 然后 复


制 完 整 的路 径 。 第 8.1 .1 节 的例子里, 路 径 是 C : \ U se r s \ yany \AppData \ Loca l \
Continuum\Ana conda。

2 . 单击开始I控制面板I查 看高级系统设置, 单击环境变见, 找到路径, 再粘 贴以上得


到的完整路径 ( 仅适用于Wind ow s)。

3. 现在可以从 任何 目录或子 目录运行 Pyth on。 点击开始后, 在搜索程序 和 文件文本框


中输入 cmd, 然后 按 回 车键, 出现一个 DOS 窗 口 。 只需在 DOS 窗 口 输入 yth
p on 就可以启
动 Pyth on。 假设 C : \ t emp 目录下有 一个包含两 行 Pyth on 代码 的程序文件 t e s t O l . py。
该文件中的两 行代码分别是 x = l O 和 p r i n t x。

4 . 再 一 次点击开始, 在搜索程序 和 文件文本框中输入 cmd , 然后 按 回 车键。 如图8-3


所示, 在出现的 DOS 窗 口 , 进入到 C : \ t emp 目录。 使用 type t e s t O l . py 显示该程序
文件。 使用 python 七 e s t O l . py 运行该程序。

图 8-3
1 42 第8章 时 间 序 列 的 统计分析

8.1.3 使用 Spyder 启动 Python



个更好的运行 Python 的方式是使用 Anaconda 自 带 的编辑器 Spyder。 在 Windows 操
作系统下, 可以执行 以下 步骤。

1. 点击开始所有文件IAnacondalSpyder, 打开 一个包含 3 个面板的软件窗 口 , 如图 8-4


所示。 左侧 的面板显示 一个名为 temp . py 的默认 程序文件。


参 匀声 n>,tl叩 立

�� 豆 人 幻 今 Py1l,on 玩 . .,I .,.

If )(
还口 三
I 竺 ·Cc� 2\� 8 X ct下.. .呜已血

-: .. .........,. 口 Objod l;

No docume,,口tJon ..啦le
J Sp)der Edito<

s ,,,., t仑盲叩'•"Y ur,ot j ll• 1' located nor«
6 C: \U>•r汃y•••y\ , ,o,d,r>\, t•"P• PY


1 ...
8

i 空 …口擘
凶芒竺丁如吐 忐;;;- . . -
c,,,.;.. • /J X
立;;;_ , 13 I ...,1玉 '丘 儿
Python l. 7 . S I An,cc心• l . 1 . 1 (32-0it ) I (default, Jul l 2813, 12:'1 :SS) [吹 v

;:;:"心忱 屯沁$究如,. . ....... ... _ ••_,�


I I Iaport<d ._,, 1 . 1 . 1 , sciPy e.u.e, 心tplotlib 1 . 3 . 1
Type 飞cl•ntific• for 配,... d•tail,.
»>

I I c..- f Hs立, 切 l '!'.Y心竺空空一


氏叩os: _, W-of-lffl己 ru, lncodmo: 111,-1 Lone a Columnc 1 c. '1 X

图 8-4

2 . 尝试着写 一个简单的 Python 程序。 在左侧面板 内 , 输入 x = l O , 按 回 车键, 然后输


入 P r int x 。 在输入这两行代码之前, 可以删 除该窗 口 的 内 容 。 换句话说 , 这个新的程序
只 有以下两 行。

x= l O
print (x) # f o r Python2 . 7 print x

3. 单击菜单栏上 的绿色运行按钮后, 首先提示需要保 存 该 文件。 然后运行结果显示在


右 下 角 的控制台 内 , 如图8-5所示。

»> runfile ( ' c : /temp/test01 . py ' , wdir=r ' C : /temp ' )


10
»>

图 8-S
8.2 Pandas 和 statsmodels 模块简介 1 43

图 8-5 的 第 1 行 显 示运行程序的 名 称和 其 所 在 的 工 作 目 录 ( wdi r ) 。 左 侧 面 板 可 以 用



来打开程序并且修改它们 。 它 的 个 很 好 的 功 能 是 可 以 同 时打 开 多 个 Python 程 序 。

8.2 Pandas 和 statsmqdels 模块简 介



这 节给 出 多 个 使 用 Pandas 和 statsmodels 模块 的 简 单例 子 。 我们将在接 下 来 的 几章里
频繁使用这两个模块。 Pandas 模块主要用 于数据处理 , statsmodels 模块主要用 于统计分析 。

8.2.1 如何使用 Pandas 模块


以 下 的 代 码 生 成 从 20 1 3 年 1 月 1 日 起 的 两 个 时 间 序 列 , 分 别 命 名 为 A 和 B 。

>>>import numpy as np
>>>import pandas a s pd
>>>dates = pd . date_range ( ' 2 0 1 3 0 1 0 1 ' , per iods = S )
>>>np . random . s e ed ( l 2 3 4 5 )
>>>x=pd . DataFrame (np . random . rand ( S , 2 ) , i ndex = dat e s , columns= ( ' A ' , ' B ' ) )

第 1 行 和 第 2 行 分 别 加 载 NurnPy 和 Pandas 两个模块 。 pd . date_range ( ) 函 数 生成



个 用 于 索 引 的 数 组 dates。 pd . DataFrarne ( ) 函 数 生成 一 个 以 数组 dates 作 为 索 引 的 x 变

量 。 将在本章详细 讨 论 pd . Data Fr ame ( ) 函 数 。 Column s ( ) 参 数 给 出 每 列 的名 称 。 因
一 一
为 np . random . s e e d ( ) 为 随机数 设 定 了 个固 定的种子 , 每 次运行这段代码都 可 以 获
得相 同 的 结 果 。 以 下 代 码 显 示 使 用 de s c r ibe ( ) 函 数 可 以 得 到 这 两 列 数 的 基 本统计 信 息 ,
包括平均值和标准 方 差 。

>>> x
A B
2013-01-01 0 . 929616 0 . 316376
2013-01-02 0 . 1 83919 0 . 20 4 5 60
2 0 1 3 - 0 1 - 0 3 0 . 5 67 7 2 5 0 . 595545
2 0 1 3- 0 1 - 0 4 0 . 9 64 5 1 5 0 . 653177
2 0 1 3 - 0 1 -05 0 . 7 4 8 907 0 . 653570
>>>x . de scribe ( )
A B
count 5 . 000000 5 . 000000
mean 0 . 678936 0 . 484646
std 0 . 318866 0 . 209761
min 0 . 183919 0 . 2 0 4 5 60
25% 0 . 5 67 7 2 5 0 . 3 16376
1 44 第8章 时 间 序 列 的 统计分析

50% 0 . 7 48907 0 . 595545


75% 0 . 929616 0 . 653177
max O . 964515 0 . 653570
>>>

如果想用时 间 序 列 的 平 均 值 来 代 替 序 列 中 的默 认 值 ( NAN ) , 可 以用 mean ( ) 和


丘llna ( )这两 个函数来实现, 代码如下 。

> > > import pandas as pd


>>> import numpy as np
>>>x =pd . S e r i e s ( [ 0 . 1 , 0 . 0 2 , - 0 . 0 3 , np . na n , 0 . 1 3 0 , 0 . 1 2 5 ) )
>>>x


1
0 . 100
0 . 02 0
2 -0 . 030
3 NaN
4 0 . 130
5 0 . 125
d七ype : f loat 6 4
> >>m = np . mean ( x )
> > > round ( m , 4 )
0 . 069
> > > y=x . f i l lna (m)
>>> y

0 0 . 100
1 0 . 02 0
2 -0 . 030
3 0 . 0 6 9 # nan i s rep l a ced with the mean
4 0 . 130
5 0 . 12 5
dtype : f loat 6 4
>>>

8.2.2 statsmodels 模块示例


在统计学中, 普通最小二乘法 C OLS)是用于 估让线性回 归 模型参数的一 个常用方法。
它 的 目 标是选取参数使得观测值 和 模 型 的预测值之间的差值的平方之 和 最小 。 线 性 回 归 模
型 在 金融领域应用很广 。 假设有如下的等式 , 其 中 y 是 n 维列 向 量, x 是 n 行 m+1 列 的矩
阵, 其 中 m 列包含回报率, 另外 一 列 的值全部是 1 。 n 是观测值的数 目, m 是独立变揪的
个数 。
8.3 开源数据 145

y = a +f3Xx+&1 C8-1 )

以下代码在给 x 和 y变噩赋值 后, 运行 OLS ( 函


) 数估计线性回 归 模型的参数/Jo 最后
一行只是用 来 打 印 参数的估 计值 。

>>> import numpy a s np


> > >import statsmode l s . ap i as sm


>>> y= [ l , 2 , 3 , 4 , 2 , 3 , 4 ]
>>> x=range ( l , 8 )
>>>x=sm . add_con stant ( x )
>>>results =sm . OLS ( y , x ) . f it ( )
>>>pri 吐 ( r e s u l t s . pa rams )

输出显示如下 。

>» [ 1 . 2 8 5 7 1 4 2 9 0 . 357 14286)

8.3 开源数据

本章的重点是分析时间序列的统计特性 , 因此需要 一 些 可以用 来分析的数据 。 可以利


用免费的经济、 金融和会计领域的数据 。 每 个用户都可以免费获取这些 数据, 便于学习。
表8- 1 列 出了 一 些 免费数据的来源。

表 8-1
名称 网页

http : / / finance . yahoo . com


雅虎金融
股票现价 、 历 史 数 、 公 司 财 务包表等

h 七 tp : / /www . goog l e . c om/ f inance


谷歌金融
股票现价、 历 史 数 、 公 司 财务包表等

http : / /www . fede r a l r e s e rve . go v / r e l e a s e s / h 1 5 / data . htm


联邦储备银行 数 字 图 书馆
利率的历 史数据 , 评价 为 AAA 、 BBB 、 CCC 债卷的收益率

http : / /www . ru s s e l l . com


Russell 指数
Russell 指数
1 46 第8章 时 间 序列 的 统计分析

续表

名称 网页

h 七 七p : / /mba . 七 u c k . dar tmou 七 h . edu/page s / facu l t y /

French 教授 的数据库 ke n . f rench / data_l ibra r y . h tml

Fama-French 因 子 历 史 数 据 、 无风险利 率 , 及 不 同 行 业 的 历 史 收益率

http : / /www . c ensus . gov/

人 口 普 查局 http : / /www . census . gov /compendia/ sta tab/hist s tats . html

美 国 人 口 普查数据

http : / /www . t r eas . gov


美 国 财政部
美 国 国 库券数据

http : / / down l oad . b ls . gov/

美国 劳工部 h t 七 p : / /www . bl s . gov/

通货膨胀数据 、 失业率 、 商 业周 期 、 重要统计数据

我们很容 易 从这些来源下 载时 间 序列 。 比如, 执行以下 几 个步 骤可以从雅虎财经下载


IBM 的每 日 历史价格 。
1. 转到雅虎财经的网 址 h七tp : / / f i n a n c e . yahoo . c om 。
2 . 在搜索框中输入 IBM 。

3 . 单击历史价格。

4 . 选择开始 和 结束 日 期后单击 “
获取价格

按钮。

5. 转到页面底部, 单击 下 载到电子表格 。
“ ”

以下给出下载的电子表格的开始和 结尾的几行数据记录。

Date , Ope n , H i gh , Low , C l o s e , Volume , Adj C l o s e


2 0 1 3 - 0 7 - 2 6 , 1 9 6 . 5 9 , 1 9 7 . 3 7 , 1 95 . 0 0 , 1 9 7 . 3 5 , 2 4 8 5 1 0 0 , 1 97 . 3 5
2 0 1 3 - 0 7 - 2 5 , 1 9 6 . 3 0 , 1 9 7 . 8 3 , 1 9 5 . 66 , 1 97 . 2 2 , 3 0 1 4 3 0 0 , 1 9 7 . 2 2
2 0 1 3 - 0 7 - 2 4 , 1 9 5 . 9 5 , 1 9 7 . 3 0 , 1 9 5 . 8 6 , 1 9 6 . 6 1 , 29 5 7 9 0 0 , 1 9 6 . 6 1
2 0 1 3 - 0 7 - 2 3 , 1 9 4 . 2 1 , 1 9 6 . 4 3 , 1 9 4 . 1 0 , 1 9 4 . 9 8 , 2 8 6 3 8 0 0 , 1 9 4 . 98

1 9 6 2 - 0 1 - 0 9 , 5 5 2 . 0 0 , 5 6 3 . 0 0 , 5 52 . 0 0 , 5 5 6 . 0 0 , 4 9 1 2 0 0 , 2 . 4 3
1 9 62 - 0 1 -0 8 , 5 5 9 . 5 0 , 5 5 9 . 5 0 , 54 5 . 0 0 , 5 4 9 . 5 0 , 5 4 4 0 0 0 , 2 . 4 0
1 9 6 2 - 0 1 - 0 5 , 57 0 . 5 0 , 5 7 0 . 5 0 , 5 5 9 . 0 0 , 5 6 0 . 0 0 , 3 6 3 2 0 0 , 2 . 4 4
8 .4 用 Python 代 码 输 入 数 据 1 47

1 9 6 2 - 0 1 - 0 4 , 5 7 7 . 0 0 , 5 7 7 . 0 0 , 57 1 . 0 0 , 5 7 1 . 2 5 , 2 5 6 0 0 0 , 2 . 4 9
1 9 6 2 - 0 1 - 0 3 , 5 7 2 . 0 0 , 5 7 7 . 0 0 , 57 2 . 0 0 , 57 7 . 0 0 , 2 8 8 0 0 0 , 2 . 5 2
1 9 62 - 0 1 - 0 2 , 5 7 8 . 5 0 , 5 7 8 . 5 0 , 5 7 2 . 0 0 , 5 7 2 . 0 0 , 3 8 7 2 0 0 , 2 . 5 0

8.4 用 Python 代码输入数据

我们需要掌握如何输入数据, 然后才能编写 Pyth on 程序处理及分析数据 。 下面介绍从


不同渠道获取数据的方法, 比如从 剪贴板、 雅虎财经网站、 外部 txt文本或 csv 文件、 网 页
和 MATLAB 数据集 。

8.4. 1 从剪贴板输人数据

我们经常 使用记事本、Micr os oft W ord或 Exce 处


l 理数据 。 一个常用的操作是复制和粘
贴 。 P and as 模块的 pd . read_c 巨pboard ( 函
) 数可以完成 类似的操作 。 比 如, 在记事本
输入以下内容 。
x1 3 5
y2 4 6

然后, 用 鼠标选取这几行, 单击 鼠标右键, 选择 复制 。 在 Pyth on 控制台 窗 口 运行


“ ”

下面两行代码 。

>>>import pandas as pd
>> >data=pd . read_c l ipboard ( )
>>>data
X y
1 2
3 4
5 6

用同样的方法可 以 复制 W ord 和 Exce l中 的数据。

8.4.2 从雅虎财经网站下载历史价格数据
执行下面 5 行代码可以从 雅虎财经网站获取 DELL 的历史 价格数据 。

>>>from matplotlib . finance import quotes_historical_yahoo_ochl


1 48 第 8章 时 间 序 列 的 统计分析

>>>ti c ke r = ' DELL '


> >>begdate= ( 2 0 1 3 , l , l )
> > >enddate= ( 2 0 1 3 , l l , 9 )
> > >p=quotes_h i s t o r i c al_yahoo_ochl ( t i c ke r , begdate , enddate , a sob j ect=True ,
adj us ted=T rue)


可 以 使用 七 ype ( ) 和 s i z e ( ) 函 数 来进 步 了 解变 量 p 的 属 性 。 图 8-6 为 它 开 始 和 结 尾

的 几 行 。 p [ 0 ] 代 表 数组 的 第 1 个观 测 值 , P [ - 1 ] 则 是最后 个。

>>>type ( p )
< c l a s s ' numpy . core . records . r ec a r ray ' >
>>>size (p) 209
» > p(0: 3 ]
rec . arra y( [ (datetime . d ate(2013, 1, 2 ) , 2013, 1, 2 , 734870 . 0 , 1 0 . 146067415730338, 1 0 . 5 , 1 0 . 5196
62921348315, 1 0. 126404494382024, 26421700 . 0, 10 . 5 ) ,
( datetime . date(2013, 1, 3 ) , 2013, 1 , 3, 734871.0, 10.435557586837295, 1 0 . 75 , 11. 13322669
1042047, 10 . 40607861060329 1 , 38131300 . 0, 10 . 7 5 ) ,
( datetime . date ( 2013 , 1 , 4) , 2013, 1 , 4, 73487 2 . 0, 1 0 . 740692798541476, 1 0 . 78 , 1 0 . 87826800
3646307 , 10 . 622771194165907, 18706400 . 0, 10 . 78 ) ] ,
dtype�[ ( ' date ' , ' O ' ) , ( ' year ' , ' < i2 ' ) , ( ' month ' , ' il ' ) , ( ' d ay ' , ' i l ' ) , ( ' d ' , ' <f8 ' ) , ( ' op
en ' , ' <f8 ' ) , ( ' close ' , ' <f8 ' ) , ( ' h igh ' , ' <f8 ' ) , ( ' low ' , ' <f8 ' } , ( ' volume ' , ' < f8 ' ) , ( ' aclose ' , '
<f8 ' ) ] )

图 8-6

图 8-6 显示变量 p 的 数 据类型是数 组 。 通过观 察 , 我们 了 解 到 数据 集按 日 期 从远 到 近


排序 。 这 与 雅 虎 财经 网 站 上 以 最近 的 日 期 作 为 第 1 个 值 正 好 相 反 。 这 个 数组包含 7 个 变 量 :
日 期 、 开 盘 价 、 收 盘 价 、 日 内 最 高 价 、 日 内 最低价 、 成交量和 调 整 后 的 收 盘 价 。 调 整 后 的
收 盘 价 依 据 拆 股 、 配 股 和 分 红 等事件对 原 始 收 盘 价 加 以 调 整 。

8.4.3 从 txt 文件输人数据


Pandas 模 块 有 多 个 函 数 可 以 从 外 部 txt 文 件 导 入 数 据 , 如 re ad_七 ab l e ( ) 、
read_fwf ( ) 、 r e a d_hdf ( ) 和 IO()等 。 我们 不 可 能 在 本 章详细 介 绍 所有这些 函 数 , 只 能
集 中 讨 论 几 个广泛使用 的 函 数 。 假 设 需 要 输 入 Fama-French 因 子 的 每 月 回 报 率 。 到 French
教授 的 网 页 h t t p : / /rnba . t uck . dartrnou t h . e du/page s / f a c u l t y / ken . f r ench/
dat a_且b r a r y . htrnl , 单击 Fama-French 因 子 , 下载该压缩 文 件 , 解压缩 文 件 , 删 除 年
回 报 率 的 部 分 , 然 后 命 名 文 本 文 件 为 f f rn o n t h l y , t xt 。 以 下 为 该 文 件 的 前 几 行 , 数据
项 从 第 5 行 开 始 , 第 4 行给 出 每列 数据 的名 称 。

This f i l e was created by CMPT—ME_BEME—RETS u s i n g 七 he 2 0 1 2 0 9 CRSP databas e .


The 1 -mon th TBi l l return i s f rom Ibbotson and As s o c i a te s , Inc .
[ th i s i s a blank l i n e ]
8.4 用 Python 代 码 输 入 数 据 1 49

Mkt-RF SMB HML RF


192607 2 . 62 -2 . 1 6 -2 . 92 0 . 22
192608 2 . 56 -1 . 49 4 . 88 0 . 25
1 92 60 9 0 . 36 -1 . 38 -0 . 0 1 0 . 23

下面的代码使用 r e ad_table ( )函数来输入这些 数据 。

>>> import panda s a s pd


>>>x =pd . re ad_tabl e ( " c : / 七 emp / f f_monthl y . 七 x t " , s kiprows = 4 )

使用 h e l p ( re ad_tab l e ) 命 令 可以得到关千这 个
函数的更多信息, 如下所示。

> > > import pandas a s pd


>>>help (pd . read_tab l e )
Help on fun c t i o n r e a d table i n modu l e pandas . i o . pa r s e r s :

read_table ( f i l epath_or_bu f f e r , sep = ' \ t ' , dialect = None , comp r e s s ion = None ,
doub lequote = True , es capechar = None , quo techar = ' " ' , quot i n g = O ,
s ki p i n i t i a l space = Fal s e , l i n e t e rmi nator =None , heade r = ' i n f er ' , i ndex_
col = Non e , name s =Non e , pre f i x = Non e , s k iprows = None , s kipfooter = None ,
s k ip_footer = O , n a_values = None , true_val u e s = None , false_va l u e s =Non e ,
de limiter = None , c onve r t e r s = Non e , d七 ype=None , u s e c o l s = None , engine = ' c ' ,
de肛m_whitespace = Fa l s e , as_r e c a r ray= Fal s e , na_f i l te r =True , compact_
ints = Fal s e , us e_uns igned= Fal s e , l ow_memory = True , b u f f e r_l i n e s = None ,
warn bad l ines = T rue , e r r o r bad l i n e s = True , keep de f a u l t na = T rue ,
thous ands = None , commen 七 = None , dec imal = ' . ' , pars e_date s=Fa l s e , keep_
date_col = Fal s e , dayf i r s t = Fal s e , date_parser =None , memor y_map = Fa l s e ,
nrows=None , i t e r a 七 or = Fal s e , chunks i z e =None , verbose = Fal s e , e ncoding =Non e ,
squeeze = Fa l s e )
Read general de l imited f i l e i n 七 o Da 七 aFrame

Also supper 七 s opt iona lly i t e r a t ing or breaking of the f i l e


into chunks .

read_ t a b l e ( ) 函 数 最 重 要 的 参 数包 括 s k i p ro w s 、 s e p 、 i n dex c o l 和
doub l e qu o t e 。 本章的后面会对它们 做进一 步解释 。

8.4.4 从 Excel 文件输人数据


假设 一 个 Excel 文件只有两 行数据记录, 该文件名为 test.xlsx , 并且 保存在 C : \ t emp \
目录下。 这两 行数据都在该文件的工作表 S he e t l 中, 如图 8-7 所示。
1 50 第8章 时 间 序 列 的统计分析

A """'""''一"""" ,.
B ., 恤.,.一,.

C
1 1/1/2013 0.1 0.3
2 I 1/2/2013 0.2 0.4

图 8-7

以下代码从 Excel 文件直接读入这些 数据 。

> > > i n f i l e=pd . Excel F i l e ( " c : /t emp / test . x l s x " )


>>>x=i n f i l e . parse ( ' Sheetl ' , he ader =Non e )
> > >x

0 1 2
0 2013-01-01 00 : 0 0 : 00 0.1 0.3
1 2 013-01-02 00 : 00 : 00 0.2 0.4
>>>

8.4.5 从 csv 文件输人数据


可以用 re ad_c s v ( ) 或 re ad_七ab l e ( )函数来读取 csv 文件 。 假设 已经从 雅虎财经下
载数据到 立 rn . c s v 文件中, 存放在 C : \ t ernp \ 目 录下 。 读入文件后, 只 需输入命 令 f [ l : 2 ]
就可以看到第 1 和第 2 行。

> > >import pandas as p d


>>> f=pd . r ead_c sv ( " c : \ \ temp \ \ ibm . c sv" )
>>>f [ l : 2 )

Date Open H i gh Low Close Vol ume Adj Close


1 20 13-07-25 1 96 . 30 1 97 . 8 3 1 95 . 66 1 97 . 22 3014300 1 97 . 22
2 2013-07-24 1 95 . 95 197 . 30 1 95 . 8 6 1 96 . 61 2 957900 196 . 61

注意, 以上 代码使用 pd . read_c s v ( " c : \ \ t e mp \ \ ibm . c s v " ) 命令从 外部 csv 文


件读取数据 。 也可以用 pd . read_ c s v ( " c : / t emp / i bm . c s v " ) 命 令来完成这个任务 。

8.4.6 从网页下载数据
也可以用 pd . re ad_c s v ( 函
) 数从 雅 虎财经网站直接获取股票的价格数据 。

>>> import pandas as pd


>>> x =pd . read_csv ( " http : / /char t . yahoo . com/tab l e . c s v ? s = I BM " )
>>>type ( x )
< c l a s s ' pandas . core . f rame . DataFrame ' >
>>>
8.4 用 Python 代 码 输 入 数 据 1 51

以上代码的最后一个命令显示 x 的数据类型。输入 x . de s c r ibe ( ) , 即 可获得这个变


量的详细 信息。

>>> x . de scr ibe ( )

Open H i gh Low Close Vo l ume


count 13837 . 000000 13837 . 000000 13837 . 000000 13837 . 000000 l . 3 8 3 7 0 0e+04
mean 189. 818740 1 9 1 . 4 10751 188 . 325548 1 8 9 . 8 4 3 64 7 4 . 8772 58e+0 6
std 131 . 696341 132 . 478594 131 . 027731 131 . 703142 4 . 5 65 0 2 5 e + 0 6
min 41 . 000000 4 1 . 750000 4 0 . 625000 4 1 . 000000 O . O O O O OOe+OO
25% 97 . 7 5 0 0 0 0 98 . 750000 9 6 . 687500 97 . 720001 l . 1 9 5 60 0 e + 0 6
50号 1 2 8 . 62 5 0 0 0 12 9 . 750000 127 . 625000 128 . 625000 4 . 1 4 8 0 0 0 e+0 6
75% 2 62 . 7 5 0 0 0 0 264 . 750000 261 . 000000 2 62 . 8 7 5 0 0 0 6 . 943700e+06
max 649 . 000015 649 . 875031 645 . 500031 649 . 000015 6 . 9 4 4 4 7 0e + 0 7

Adj C l o s e
count 13837 . 000000
mean 42 . 316260
std 51. 321150
min 1 . 2 0 9 637
25告 5 . 8 5 4 63 6
50号 15. 980850
75% 70 . 854336
max 1 93 . 603554

>>>
>>>x [ 0 : 5 )
Da七e Open H i gh Low Close Volume
0 1 2 3 4

2 0 1 6- 1 68 . 9 7 0 0 0 1 169 . 110001 166 . 059998 166 . 729996 6 6 7 92 0 0


20 16-12-15 1 68 . 0 0 9 995 169 . 850006 1 67 . 7 7 9 9 9 9 168 . 020004 3363200
2 0 1 6- 1 2 - 1 4 1 68 . 3 6 9 9 9 5 169 . 8 8 9999 1 67 . 4 4 9997 168 . 509995 3957600
2 0 1 6- 1 65 . 6 7 9 9 9 3 169 . 949997 165 . 679993 1 68 . 2 8 9 9 9 3 5 8 38 7 0 0
2 0 1 6- 1 2 - 1 2 166. 720001 166 . 789993 1 65 . 0 7 0 0 0 7 165 . 500000 3 3 8 92 0 0

Adj C l o s e
0 1 2 3 4

166 . 729996
168 . 020004
168 . 509995
168 . 289993
165 . 500000
>>>

Pandas 模块的 r e ad_c s v ( ) 函数用来从外部文件读取数据。 如 果 只 需 要分析两个变量 ,


1 52 第8章 时 间 序 列 的 统计分析

日 期 和 调 整 后 的 收 盘 价 , 可 以 用 usecols 参数来选取它们 。 因 为 共有 7 列 , 其 中 日 期 在第 1

列 而 调 整 后 的 价格在最后 列 , 所 以它们的列编号分别为 0 和 6。

>>>impor 七 pandas a s pd
>>>url= ' h ttp : / / char 七 . yaho o . com/ 七 able . c sv ? s = IBM '
>>>x =pd . r ead_c sv ( u r l , u s e c o l s = [ 0 , 6 ] )
>>>x [ 0 : 5 ]
Date Adj C l o s e
0 1 2 3 4

2 0 1 6- 1 2 - 1 6 1 6 6 . 7 2 9 9 9 6
2 0 1 6- 1 2 - 1 5 1 6 8 . 0 2 0 0 0 4
2 0 1 6- 1 2 - 1 4 1 6 8 . 5 0 9 9 9 5
2 0 1 6- 1 2 - 1 3 1 6 8 . 2 8 9 9 9 3
2 0 1 6- 1 2 - 1 2 1 6 5 . 5 0 0 0 0 0
>>>

8.4.7 从 MATLAB 数据文件输人数据


从 阮 tp : / / c ani s i u s . e du / - yan y / i bm . ma t 下 载 MATLAB 数 据 文 件 止m . mat ,
并 保 存 在 C : \ t emp \ 。 可 以 使 用 SciPy 模 块 的 l o admat ( ) 函 数来 加 载 。

f rom future import prin 七 function


import s c i p y . io as sp
matData = sp . l oadmat ( ' c : /temp / ibm . ma 七 I )
matDat a 2 = l i s 七 (matDat a )
print (matData2 [ 0 : 2 ] )

8.5 几个重要 的 函 数

这里介绍几个在其他章 节 用 到 的 重要 函 数 。 P andas 模块包含的 s e r i e s ( ) 函 数 可 以 用



来 构 建 时 间 序列 。 因 为 日 期 是 时 间 序 列 分 析 中 最 重 要 的 变量之 , 对其 需 要 多 加 了 解 。
DataFrame 数据类型在 Python 和其他语言 ( 包括 R ) 中 广 泛应用 。

8.5. 1 使用 pd.Series() 生成一维时问序列


可 以 很方便地使用 pd.Series() 函 数来 生成 时 间 序列 , 代码 如 下 。

>>> import pandas a s pd


>>> import s c ipy as sp
>>> x = p d . date_range ( ' 1 / 1 / 2 0 1 3 ' , p e r i ods=2 52 )
>>> data = pd . S e r i e s ( sp . randn ( l e n ( x ) ) , index=x)
8.5 几个重要 的 函 数 1 53

> > > data . head ( )

20 13-01-01 0 . 77 6 670
2 0 1 3 - 0 1 - 02 0 . 12 8 904
20 13-01-03 -0 . 0 6 4 60 1
2 013-01-04 0 . 988347


2013-01-05 0 . 4 5 9587
Freq : D , dtype : f l o a t 6 4
>>>data . ta i l ( )

201 3-09-05 - 0 . 1 67 5 9 9
20 13-09-06 0 . 530 8 64
2 0 13-09-07 1 . 378951
2 0 1 3- 0 9- 0 8 - 0 . 7 2 97 0 5
2013-09-09 1 . 414596
Freq : D , dtype : f l oat 6 4
>>>

8丘2 使用 日 期变量

可以使用 Pandas 模块的 rea d_c s v ( ) 和 read_t ab l e ( )函数更好地处理时间序列 数


据 。 比如, 可以使用 p a r s e _da t e s 或 date_p a r s e 参数来指定某 一 列 作为 日 期索引。 以
下代码使用第 1 列 作为 日 期索引。

>>> import pandas as pd


>>>url = ' http : / / chart . yahoo . com/table . cs v ? s = I BM '
>>>x =pd . re ad_cs v ( ur l , index_col = O , pa r se_dates = True )
>>>x . head ( )
>>>
Open H i gh Low Close Volume
Date
2 0 1 6 - 1 2 - 1 6 1 68 . 9 7 0 0 0 1 1 69 . 1 1 0 0 0 1 1 6 6 . 0 5 9 9 9 B 1 6 6 . 7 2 9 9 9 6 6679200
2 0 1 6- 1 2 - 1 5 1 68 . 0 0 9995 1 6 9 . 8 5 0 0 0 6 1 67 . 7 7 9 9 9 9 1 6 8 . 0 2 0 0 0 4 3363200
2 0 1 6 - 1 2 - 1 4 1 6 8 . 3 6 9 9 9 5 1 6 9 . 8 8 9 9 9 9 1 67 . 4 4 9 9 9 7 1 6 8 . 5 0 9 9 9 5 3957 600
2 0 1 6- 1 2 - 1 3 1 6 5 . 6 7 9 9 9 3 1 6 9 . 9 4 9 9 9 7 1 6 5 . 67 9 9 9 3 1 6 8 . 2 8 9 9 9 3 5 838700
2 0 1 6- 1 2 - 1 2 1 6 6 . 7 2 0 0 0 1 1 6 6 . 7 8 9 9 9 3 1 65 . 0 7 0 0 0 7 1 6 5 . 5 0 0 0 0 0 3 3 8 92 0 0

Adj C l o s e
Date
2 0 1 6- 1 2 - 1 6 166. 729996
2 0 1 6- 168 . 020004
2 0 1 6- 1 2 - 1 4 168 . 509995
2 0 1 6- 1 2 - 1 3 168 . 28 9993
1 54 第8章 时 间 序列 的 统计分析

2 0 1 6- 1 2 - 1 2 1 65 . 5 0 0 0 0 0
>>>

8 丘3 使用 DataFrame 数据类型
第 1 个例子生成只有 1 列的 DataFrame 数据 。

> > >impor七 pandas as pd


> > > impo r t s c ipy as sp
>>>df =pd . Da七aFrame ( sp . random . rand ( B , 1 ) , c o l umn s = [ ' A ' ] , dtype = ' fl o a t 3 2 ' )
>>>df
A
0 -0 . 5 8 1 3 7 7
1 -1 . 7 90 7 5 8
2 -0 . 418108
3 1 . 122045
4 -0 . 4027 17
5 0 . 694823
6 0 . 035632
7 0 . 9 1 9457
>>>

因 为没有使 用 np . r a n d . s e e d ( ) 函 数 , 上 述 代码 每次运行的结果 都会不 同 。 使 用


re ad_c sv ( ) 或 r e ad_t a b l e ( ) 函 数 从 外 部 文 本 文 件 输 入 数 据 时 , 得 到 的数据 就 是
D a t a F r ame 类 型 。

>>> import pandas a s pd


>>> import s c ipy as sp
>>>index = pd . date_range ( ' l / 1 /2 0 1 3 ' , p e r i ods = 8 )
> > > c c= [ ' A ' , ' B ' , ' C ' ]
>>>df = pd . DataFrame ( s p . random . randn ( 8 , 3 ) , i ndex=inde x , columns=cc)
> > >df
A B C
2013-01-01 -1 . 185345 -0 . 422447 -0 . 610870
20 1 3 - 0 1-02 - 1 . 5 0 7 6 5 3 -0 . 2 95 8 07 -0 . 6 3 6 7 7 1
2013-01-03 1 . 6 8 6 8 5 8 -2 . 0 1 3 0 2 4 - 0 . 9 8 0 9 0 5
2013-01-04 0 . 372631 -1 . 580834 0 . 5 1 5 0 \4 5
2 0 1 3-01-05 -0 . 32272 9 -0 . 677587 - 1 . 0 5 3 5 5 5
2 0 1 3 - 0 1 - 0 6 -0 . 5 1 8 9 1 8 - 0 . 952527 0 . 000124
20 13-01-07 0 . 482760 2 . 0 4 9 4 42 1 . 8 33976
2013-01-08 0 . 313321 0 . 1 62 3 3 4 0 . 6 62 2 5 3
8.5 几个 重 要 的 函 数 1 55

如 果 希望 下载雅虎 财经上 IBM 的 历 史数据 , 而 且 只 对 日 期 和 调 整 后 的 收盘价这两个变


量感兴趣 , 其 中 日 期 作 为 索 引 变量 , 就 可 以 使 用 以 下 代 码 。

>> >import panda s as p d


>> >x=pd . read_c s v ( ' http : / / ch冶rt . yahoo . com/table . c s v ? s 气 BM ' ,
usecol s= [ 0 , 6 ] , index_col=O )
>>>type ( x )
< c l a s s ' panda s . c o r e . f r ame . Data Frame ' >
>>>x . head ( )

Date Adj C l o s e
2 013-11-21 184 . 13
2 0 1 3-1 1-20 185 . 1 9
2013-11-19 185 . 25
2 0 1 3- 1 1 - 1 8 184 . 47
2013-11-15 183 . 19

要 查 找 有 关 pd.DataFrame() 函 数 的 更 多 信 息 , 可 以 使用 help(pd.DataFrame)命 令 。

> >>help ( pd . Dat aFrame )


Help on c l a s s DataFrame in modu l e pandas . core . f rame :

c l a s s DataFrame ( pandas . co r e . gene r i c . NDFrame )


Two-dime n s i onal s i z e-mutab l e , poten t i a l l y heterogeneous tabu lar
datas 七 ructure w i th labeled axes ( rows and c olumns ) . Ar i thme t i c
operationsali gn o n both row and c ol umn label s . C a n be thought o f a s a di c t- l i ke
con 七 ainer for S e r ies obj e cts . The pr imary pandas data s t ru c ture

Parameters

da 七 a : numpy nda r r a y ( s tructu red or homogeneous ) , diet , or Da 七 aFrame


Diet can contain S e r ie s , ar rays , constants , or l i s t - l i ke ob j e c t s
index : I nde x or a r r a y- l i ke
I ndex to u s e for result ing f r ame . W i l l de fau l t to np . a range ( n } i f
no indexing i n f o rmat ion part o f input data and no i ndex provided
columns : I ndex or a r ray- l i ke W i l l de fau lt to np . a range ( n } i f not
column labe l s p rovided
dtype : dtyp e , de fault None Data type to for c e , o 七 he rwi s e i n f e r
c opy : bool ean , de faul 七 F a l s e
Copy d a t a f r om i nputs . Only a f fects DataFrame / 2d nda r r a y i nput
1 56 第8章 时 间 序 列 的 统 计 分析

8.6 计算 回 报率

可以用价格数据来计算回报率(也称为收益 率), 有时需要将 日 收益率转换为每周或每


月收益 率, 或者将月收益 率转换为季度或年度收益 率 。 因此, 了解如何计算回报率和它们
之间的转换是非常重要的。 假 设有如下 4 个价格。

> > > impo r t nurnpy as np


>> >p=np . a rray ( [ l , l . l , 0 . 9 , 1 . 0 5 ] )

了解这些 价格的排序方式很重要。 如果第 1 个价格在第 2 个价格之前发生 , 第 1 个回


报率应该是 ( 1 . 1 - 1 ) / 1 = l 0% 。 接下来, 学习如何从 一个 n 维数组检索前 n- l 和最后 n- 1
个记录。 使用 p [ : - 1 ] 列 出前 n- 1 个价格, 使用 p [ 1 : ] 列 出最后 n- l 个价格。

> > >pri n 七 ( p [ : - 1 ] )


[ 1. 1.1 0 . 9]
»>p r i n t ( p [ 1 : ] )
[ 1 . 1 0 . 9 1 . 05]

使用下面的代码计算回报率:

>>>re 七= ( p [ 1 : ] -p [ : - 1 ] ) /p [ : - 1 ]
>>>p r i n t ret
[ 0.1 -0 . 1 8 1 8 1 8 1 8 0 . 1 6666667 ]

然而, 如果价格的顺序是相反的, 也就是说, 第 1 个价格是最近发生的, 而最后 一 个


价格是最早的, 那么必须通过不 同的方式来计算回 报 率 。

» > r e t = ( p [ : - 1 ] -p [ l : ] ) /p [ l : ]
> > >p r i n t r e t
(-0 . 09090909 0 . 2 2 2 2 2 2 2 2 - 0 . 1 4 2 8 57 1 4 ]
>>>

下面的代码从 雅虎财经网站下载每 日 价格数据和计算 日 回报 率 。

f rom ma tpl o 七 li b . f inance import quotes_h i s to r i ca l_yahoo_ochl a s getData


t i c ke r= ' I BM '
begdate= ( 2 0 1 3 , 1 , 1 )
endda 七 e= ( 2 0 1 3 , 1 1 , 9 )
x = getDat a ( 七 i c ke r , begdate , e ndda t e , a s ob j ec t=True , adj u s ted=True )
8.6 计算回报率 1 57

ret= ( x . ac l o s e [ l : ] - x . ac lose [ : - 1 ] ) / x . a c l o s e [ : - 1 ]

第 1 行 从 matp l o t 且b . f i nance 模块加 载 一 个 函 数 。 使用 元组类 型 的 数据来 给 出 序



列 的 开 始 和 结 束 日 期 。 下 载 的 历 史 数据赋值给变量 x。 可 以 显 示 些价 格 和 回 报 率 , 然 后

手动计算 个或 两 个 回 报 率 , 加 以 验 证 。

>>>x . date [ 0 : 3 ]
array ( [ datet ime . date ( 2 0 1 3 , 1 , 2 ) , date t ime . date ( 2 0 1 3 , 1 , 3 ) ,
date 七 ime . da 七 e ( 2 0 1 3 , 1 , 4 ) ] , dtype=ob j e c t )
>>>x . aclose [ 0 : 3 ]
array ( [ 1 9 2 . 6 1 , 191 . 55, 1 90 . 3 ] )
>>>re 七 ( 0 : 2 ]
array ( [ - 0 . 0 0 5 5 0 3 35 , - 0 . 0 0 6 5 2 5 7 1 ] )
»> ( 1 9 1 . 5 5 - 1 9 2 . 6 1 ) / 1 9 2 . 6 1
-0 . 005503348 7 35 7 8 7 3 5 4
>>>

结 果 验 证我们 得 到 的 第 1 个 回 报 率 是 正 确 的 。

8.6.1 从 日 回报率计算月 回报率 -



可 以 用 以 下 方法来把 日 回 报 率 转 换 为 每 月 或 每 年 回 报 率 。 首先 , 计算 天 的对数回报

率。 然后, 把 个 月 内 所有天的对数回报率加起来 , 得到的 总 数 即 是相应的该月 的对数回
报率 。 最 后 把 对 数 回 报 率转换成 百 分 比 回 报 率 。 假 设 有 价 格数据 P 。, P, , P2 , . . . , Pio , 其
一 一
中 , 凡 为 上 个 月 最后 个交易 日 的 收 盘 价 , 凡 是这 个 月 第 个 交 易 日 的 收盘 价 , 依 次 为 每

个 交 易 日 的 收 盘价 , 而 P20 是 这个 月 最后 个 交 易 日 的 收 盘 价 。 计 算 这个 月 的 回 报 率 的 公
式如 下 。

Rmonthly = 片。 片 ( 8-2 )

这个月 的对数回报率的 定 义 如下 。

log_ return monthly log


(气) C 8-3 )

百 分 比 回报率和对数回报率之 间 的关系如 下 。

Rmon巾 ty = exp( log_ return) - 1 ( 8-4 )


1 58 第 8章 时 间 序 列 的 统计分析

类似地, 可以定义 日 对数回报率如下。

l og_ return尸 Y = log (!;]


1
( 8-5)

然后, 对数回报率的总和 如下 。

l og_ return _.,, � log [ 气 Po


f log_ return�,,
i=I
( 8-6 )

以下代码根据前面的步骤 把 日 回报率转换为月 回报率 。

i mport numpy as np
import pandas as pd
f rom matp l o t l ib . f i nance impor t quote s_hi s t o r i c a l_yahoo_ochl a s getData
t i c ke r = ' I BM '
begdate = ( 2 0 1 3 , l , l )
enddate= ( 2 0 1 3 , l l , 9 )
x = getData ( t i c ke r , begdate , endda t e , a s ob j ec t=Tru e , adj us ted=Tru e )
l o g r e t = np . l og ( x . a c l o s e [ l : ) / x . ac l o se [ : - 1 ) )
yyy ymrn= [ l
dO=x . date
for i i n r ange ( O , np . s i z e ( l ogre t ) ) :
yyyymrn . append ( ' ' . j o in ( [ d O [ i ) . s t r f t ime ( " 毛 Y " ) , dO [ i ] . s 七 r f t ime ( " %m" ) l ) )
y pd . DataF rame ( l ogre t , yyyymm, co lumns = [ ' ret_mon th l y ' ) )
=

ret_monthl y=y . groupby ( y . index) . sum ( )

上 面的代码从 Yahoo ! Finance 网 页下载指定股票代码在给定的开始 日 期和 结束 日 期之


间的每 日 价格数据 。 用调 整 后的收盘价来计算对数回报率 。 以公式 ( 8-6 ) 来计算 日 对数回
报率, 而不是 日 百分比回报率 。 然后, 生成 一 个 名为 yyyymrn 的 日 期
变量来代表月 份, 它
的前几 个值如图 8-8 所示。
»>
>» Y'fYY"D [ 0 : 5 ]
[ ' 201301 ' , ' 201301 ' , ' 201301 ' , ' 201301 ' , ' 201301 ' ]
>>>
>>>

图 8-8

变量把数据分组。 以 d O [ O ] 为例来说 明 如何用 j o i n ( 函


可以用这 个 日 期 ) 数生成这 个
8.6 计算 回 报 率 1 59

变量。
日期

»> dO [ O J
date 七 ime . date ( 2 0 1 3 , 1 , 2 )
> >>dO [ O ] . s tr f time ( " 毛 Y " )
' 2013 '


>>>dO [ O J . s t r f t ime ( " %m" )
' 01 '
>>> ' ' . j o i n ( [ dO [ O J . s t r f t ime ( " 毛 Y " ) , dO [ O J . s trft ime ( " %m" ) ) )
I 201301 '

>>>

显示月回报率的几 个值如下。
>>>ret_monthly
re t_monthly
201301 0 . 043980
2 0 1 302 -0 . 0 0 6 8 8 0
201303 0 . 045571
201304 -0 . 061913
201305 0 . 050327
201306 -0. 088366
201307 0 . 023441
2 0 1 30 8 -0 . 057450
2 0 1 30 9 0 . 013031
201310 -0 . 039109
201311 0 . 009602
>>>

8心2 从 日 回报率计算年回报率

用 类似的方法, 把 日 回报率转换 为年回报率的代码如下。

from matplo t l ib . f i nance import quotes_hi s t o r i c a l_yahoo_oc h l as getData


import numpy a s np
import pandas a s pd
t i c ker = ' I BM '
begdate= ( l 9 9 0 , 1 , 1 )
enddat e = ( 2 0 12 , 1 2 , 3 1 )
x=ge 七 Data ( t i c ke r , begdate , enddate , a sobj e ct=True , adj us ted= True )
logret = np . l og ( x . a c l o s e [ l : ] /x . a c l o s e [ : - 1 ] )
dat e = [ l
dO = x . date
for i i n range ( O , np . s i ze ( logret ) ) :
1 60 第 8章 时 间 序 列 的 统计分析

da七e . append (dO [ i ] . str f t ime ( " % Y " ) )


y =pd
. DataFrame ( l ogre t , dat e , c o l umns= [ ' ret—annual ' ] )
ret_annual =np . exp ( y . gr oupby ( y . inde x ) . s um ( ) ) - 1

用 Pandas 模块的 head ( ) 和 ta 口 ( 函


) 数显示以上代码的计算结果的最前和最后几个
数值 。

p r int ( r e 七_annual . head ( ) )


r e t annual
1990 0 . 197704
1991 -0 . 157614
1992 -0 . 4 1 1504
1 993 0 . 1 8 68 9 6
1994 0 . 301357

p r i nt ( ret_annual . 七 a i l ( ) )
ret annual
2008 -0 . 1508 1 3
2009 0 . 546113
2010 0 . 134778
2011 0 . 2 8 4 65 1
2012 0 . 0 4 5 4 52

8.7 按 日 期 合并数据集
通常用 日 回 报率来计算 贝 塔值, 以衡量 一家公司的市场风险。 以IBM为例, 需要 I BM
的价格、 市场回报率和无风险利率来估计资 本资 产定价模型 (CAPM)。 以下的代码用来下
载这些 数据。

f r om ma七pl o 七 lib . finance import quotes_h i s t o r i c a l_yahoo_ochl as getData


import numpy as np
import pandas as pd
t i c ke r = ' I BM '
begdate = ( 1 9 9 0 , 1 , 1 )
enddate= ( 2 0 1 2 , 12 , 3 1 )
x=getData ( t i c k e r , begdate , enddate , asobj e c t气T ru e , adj u s t ed=True )
logret = np . l og ( x . a c l o s e [ l : ) /x . ac l o s e [ : - 1 ) )
date = [ l
dO=x . date
for i in range ( O , np . si z e ( l o g r e t ) ) :
date . append (dO [ i ) . s t r f time ( " 毛 Y " ) )
8.8 构建 n 只 股 票 的投 资 组 合 161

y = pd . DataFrame ( l ogre t , dat e , columns = [ ' ret_annua l ' ] )


ret_annual = np . e xp ( y . groupby ( y . inde x ) . sum ( ) ) - 1

图8-9 显示了 其 中 一部分数据。 \


> '> > final . head ( )
I BM_adjClose M氐_Rf 邓B 卅L Rf
20131001 184 . 37 0 . 009 1 0 . 0039 -0 . 0013 0
20131002 1.82 . 97 -0 . 0010 - 0 . 0036 0 . 0004 0
20131.003 181 . 88 -0 . 0087 - 0 . 0017 0 . 0020 0
20131004 182 . 12 0. 0074 0 . 0000 0 . 0010 0
20131.007 180 . 05 -0 . 0095 -0. 0026 0 身 0006 0
»> final . tail ( )
I BM_adjClose Mlct_Rf SMB HML Rf
20131025 174 . 95 0 . 0033 - 0 . 0035 0 . 0022 0
20131028 175 . 44 0 . 0009 -0 . 0005 -0 . 0002 0
20131029 180 . 16 0 . 0054 -0 . 0016 -0 . 0015 0
20131030 178 . 21 - 0 . 0061 -0 . 0072 0 . 0040 0
20131.031 177 . 28 -0. 0034 -0 . 0008 -0 . 0036 0

图 8-9

图 8-9 显示有 5 列 数据 , 包含价格和回报率两 类数据 。 第 1 列 是价格, 其 余的列 则包


含回报 率 。 这样做其 实没有 什 么 实际意义, 只 是为了展示 如何通过 日 期
变量 把价格序列 和
回报率序列 合并起来。

8.8 构建 n 只股票 的 投 资 组合
以下的代码生成 一个包含 S & P500 指数和 3 只股票的回报率的数据集 。

from s c ipy . s tats import stats


import numpy as np
import pandas as pd
t i ckers = [ ' I BM ' , ' de l l ' , ' wmt ' ]
mkt = ' http : / /chart . yahoo . com/tabl e . csv?s = "GSPC '
final =pd . read_c s v (mkt , usecols= [ 0 , 6 ] , index_col = O )
final . co lumns = [ ' "GS PC ' ]
path= ' h 七 tp : / / chart . yahoo . com/tab l e . csv?s = tt 七 '
for ticker in t i ckers :
print 七 icker
x = pd . read_ csv (path . replace ( ' ttt ' , ti c ke r ) , usecols = [ 0 , 6 ] , index_col = O )
x . columns = [ t i c ke r ]
1 62 第8章 时 间 序 列 的 统计分析

f i n a l =pd . rnerge ( fi n al , x , l e ft_index=True , ri ght_index = True )

用 head() 和 tail()函数显 示 结果的最前和 最后几 个数值 。

> > > f i n a l . head ( )


" GS PC I BM de l l wmt
Date
2013-10-18 1744 . 50 172 . 8 5 13 . 83 75. 71
2013-10-17 1733 . 15 173 . 90 13 . 85 75 . 78
2 013-10- 1 6 17 2 1 . 5 4 185 . 73 13. 85 75 . 60
2013-10-1 5 1 698 . 06 1 8 3 . 67 13 . 83 7 4 . 37
2 0 1 3 - 1 0- 1 4 1710 . 14 1 8 5 . 97 13 . 85 7 4 . 68
>>>final . tail ( )
" GS PC I BM de l l wmt
Da七e
198 8-08-23 257 . 09 17 . 38 0 . 08 2 . 83
1988-08-22 256 . 98 17 . 3 6 0 . 08 2 . 87
1 988-08-1 9 260 . 24 1 7 . 67 0 . 09 2 . 94
1988-08-18 261 . 03 17 . 97 0 . 09 2 . 98
1988-08-17 260 . 77 17 . 97 0 . 09 2 . 98
>>>

8.9 T-检验和 F-检验


金融领域常用 t- 统计量来检验某 个零假设。 当零假 设成 立 时, t- 统计量服从 t 分布。 以
下的代码生成 1 000 个服从 标准正态分布的随机数, 然后进行两 个检验。 第 1 个检验的零
假 设是均值为 0.5, 第 2 个检验的零假 设是均值为 0。

from s cipy import s t a t s


import s cipy a s sp
sp . random . seed ( 1 2 3 5 )
X = s七ats . norm . rvs ( s i ze= l O O O O )
print ( " T-value P-value ( t wo- t ai l ) " )
prin七 ( s ta七s . 七七est_l samp ( x , 0 . 5 ) )
print ( s t a t s . t t e s t_ l s amp ( x , O ) )

T-value P-va lue ( two-ta i l ) ,


Ttest_l s amp Result ( s t a t i s t i c = - 4 9 . 7 6 3 4 7 1 2 3 1 4 2 8 9 6 6 , pvalue = 0 . 0 )
Ttest_ls amp Resul t ( s七at i s t i c = - 0 . 2 63 1 0 3 2 1 9 2 5 0 8 3 0 1 9 ,
pvalue = 0 . 7 9 2 4 7 6 4 4 3 7 5 1 6 4 8 6 1 )

第 1 个检验结果推翻了均值为 0.5 的零假 设, 因为 t 值是-49 .8 而对应的 p 值是 0。 第 2


8.9 T-检 验 和 F-检验 1 63

个检验结果接受 了 均值 为 0 的 零假 设 , 因 为 t 值接 近-0.26 而 对 应 的 p 值 是 0.79。 以 下 的 代


码测试 IBM 在 20 1 3 年 的 平均 日 回报率是否等于 0 。

fr om scipy impo rt stats


impor 七 s c ipy as sp
from matpl o t l i b . f i nance import quotes_hi storica l_yahoo_ochl as getData
ticker= ' ibm '
begdate = ( 2 0 1 3 , l , l )
enddate = ( 2 0 1 3 , l l , 9 )
p=getData ( t i c ke r , begdate , endda 七 e , asob j ect=True , adj u s ted=True )
ret=p . aclose [ l : ] /p . aclose ( : - 1 ] - 1

print ( ' Me an and T-va l ue , P-value ')


print ( round ( sp . rnean ( r e t ) , 5 ) , stats . ttest_ l s arnp ( re t , 0 ) )

Mean, T-va l ue , P -value


( - 0 . 0 0 02 4 , T 七 e s t_l sampRe s u l t ( statistic=- 0 . 2 9 6 2 6 0 6 1 2 0 9 6 9 5 0 8 1 ,
pva lue=0 . 7 67 3 1 7 0 3 4 4 9 5 6 1 9 5 ) )

以 上 结 果 显 示 IBM 的平均 日 回 报 率 为 0.024% , t 值 是-0 .30 而 p 值是 0.77 。 因 此 , 统


计检验 的 结 果 支持平均 日 回报 率 等 千 0 。

8.9.1 检验方差是否 相等
接 下 来 , 检验 IBM 和 DELL 在 20 1 3 年 的 方 差 是 否 相 等 。 sp . s ta t s . b a rt l e t t ( ) 函
数采用 Bartlett 方法来检验 多 个 样 本 集 的 方 差 是 相 等 的 这个 零假 设 , 通 常 称 为 F-检验 , 该 函
数输出 t 值和 p 值 。

impor t scipy as sp
f rom matplotl i b . finance import quotes_h i storical_yahoo_ochl a s ge 七 Da 七 a
begdate = ( 2 0 1 3 , 1 , 1 )
enddate = ( 2 0 1 3 , 1 1 , 9 )

def ret_f ( t i c ke r , begdate , enddate ) :


p =getData ( ti c ke r , begdate , enddate , a sob j ect = True , ad j u s ted=True )
return p . a c l o s e [ 1 : ) /p . aclose [ : - 1 ) - 1

y=ret_f ( ' I BM ' , begdate , endda te)


x = ret_f ( ' DELL ' , begdate , enddate )
print ( sp . stats . bartlett ( x , y ) )
Bartle ttRe s u l t ( s t a t i s t i c = S . 8 3 7 6 6 1 0 9 5 5 1 8 9 0 2 8 ,
1 64 第 8 章 时 间 序 列 的 统计 分 析

pva lue = 0 . 0 1 5 6 8 6 6 6 5 5 0 1 2 6 5 3 6 8 )

由于 t 值为 5.84 而 p 值为 1 . 6% , 依 据 5%的显著水平, 我们的结论是这两 只股票在 2013


年的 日 回报 率具有不 同的方差 。

8 从 2 测试 ” 一月 效应 ”

本节 使用 I BM 的数据来检验 月 效应 。 月 效应是指股 票在一 月 份的回报率 不同


“一 ” 一

于 其 他月份 。 首先从 雅 虎财经网站下 载 I BM 的每 日 价格, 然后把每 日 回报率转换为月回报


率 。 之 后, 把月回 报率分为两组: 一
月 份的回报率和其 他月份的回报 率来测试这两组的均
值是否相等 。

f rom matpl o t l ib . f inance imp o r t qu otes h i s 七 o r i c a l yahoo ochl as getData


import pandas as pd
import s c ipy as sp
f rom da t e t ime impo r t date t ime

t i c ke r = ' 工 BM '
begdate = ( 1 9 6 2 , 1 , 1 )
endda七e= ( 2 0 1 3 , 1 1 , 2 2 )
x =ge tData ( t i c k e r , begda七e , endda七 e , asobj ect=True , adj us ted=T rue )
logret = s p . l o g ( x . ac l o s e [ l : ] /x . ac l o s e ( : - 1 ] )
date = [ l
dO=x . date
for i i n range ( O , sp . s i z e ( l ogr e t ) ) :
t l = ' ' . j o in ( [ d O [ i ] . s t r f t ime ( " % Y " ) , dO [ i ] . s t r ftime ( " %m" ) ] )
date . appe nd ( datetime . s t rpt ime ( t l , " %Y%m " ) )

y =pd . DataFrame ( l ogret , date , c o l umns = [ ' l o g r et ' ) )


retM = y . groupby ( y . inde x ) . s um ( )
ret_Jan = retM [ re七M . i ndex . mon七h = = l ]
ret_othe r s = retM [ retM . index . month ! = l )
print ( sp . s ta t s . bartlett ( r e七_Jan . values , r e七_others . values ) )
Bartlet七Re s u l t ( st ati s t i c = l . 1 7 7 2 6 7 9 3 6 7 8 2 8 0 8 1 , pval ue = 0 . 2 7 7 9 1 2 8 9 1 9 2 0 0 8 0 1 7 )

由于 t 值是 1 .18, p 值是 0. 28, 我们认为 I BM 的 回报率不存在一 月 效应 。 因为这个结


论仅仅针对 I BM 一 只股票, 我们不应该 一 概而论。 同样的方法可以用来测试其 他 类似的效
应是否存在。
8. 1 0 金融研究和 实 战 的 应 用 举例 1 65

8. 1 0 金融研究和 实 战 的 应 用 举例

本节 将 讨论几 个有用的金融领域 的应用举 例 , 如基于 52 周 最高价和最低价的交易策


略, 估计 Roll ( 1 984 ) 买 卖 价差模型、Amihud ( 2002 ) 反流动性指标模型、Pastor 和 Stambaugh
( 2003 ) 流动性指标模型、资 本资 产定价模型、 Fama-French 三因素模型和 Fama-Mac Beth
回 归 分析, 以及计算滚动时间 窗 口 的 贝塔值和在险价值 VaR , 等等 。

8.10.1 基于 52 周最高价和最低价的交易策略
一些 投资 者/研究人员建议采用基于 52 周 最高价和最低价的交易策略, 当某 只股票今
天的价格接近过 去 52 周 达到的最高价格, 卖出该股 票 ; 当其 今天的价格接近过去 5 2 周 达
到的最低价格, 则买入该股票 。 下面的 Python 程序输出这 52 周 的价格范 围和今天价格的
相对位置。

f r om matplot l i b . f i nance import quotes_h i s 七 o r i c al_yahoo_ochl a s getData


from datet ime import datetime
from dateut i l . r e lativede l 七 a impo r t r e l a 七 ivede l t a
import numpy as np

ticker= ' I BM '


enddate = da七etime . now ( )
begdate=enddate 一 工 ela t ivede l ta ( ye a r s = l )
p = getData ( ti c ke r , begdate , enddate , asobj e ct=True , adj ust ed=True )
x=p ( - 1 ]
y=np . array ( p . tol i s t ( ) ) [ : , - 1 ]
hi gh=max ( y )
1 ow=min ( y )
print ( " Toda y , Price H i gh Low , 毛 from low " )
print ( x [ O ] , x ( - 1 ] , h i g h , low, round ( ( x [ - 1 ] -low) / ( high-low) * l 0 0 , 2 ) )

相应的输出如图 8- 1 0 所示。

Today, Price High Low, % from low


(datetime.date(20 1 7, 2, 3 ), 1 75.820007, 1 78.660004, 1 1 4.68367, 95.56)

图 8- 1 0

结果显示, 根据 5 2 周 最高价和最低价的交易策 略, 我们应该买 进 I BM 的股票。


1 66 第 8 章 时 间 序 列 的 统计分析

8. 10.2 用 Roll ( 1984 ) 模型来估算买卖价差


流动性是指如何能以很小 的代价迅速转让资 产 。 买卖价差是衡量流动性的 一 个常用指
标, 但是需要高频 交易数据来精确 估计买卖价差 。 我们将在本章后面展示如何利用高频 交
易数据直接计算买卖价差。 Roll ( 1 984 ) 给出了 一种方法, 可以利用 日 回报 率的 自 相关系
数来间接地估 计买卖价差。

S = 2 妒cov (M, 凶江 ) ( 8- 7 )

s
¾spread = — ( 8-8 )
p
这里 , S 为买卖价差, P,为股票在第 t 天的收盘价, P 是在一 段时间内每 日 收盘价的平
均值。 Roll 的方法有一 个缺陷, 某些 股票在一定时间内的 自 相关系数可能是正的, 这样等
式 (8-7) 中的平方根号下的数值是 负 的 。 在这种情况下, 需要把 S 设 置为 0 。 可以用下面
的代码来估 计 R 和 P,-1 之 间 的协方差 。 下面的 Python 代码从 雅虎财经下 载 DELL 这只股票
在最近 一年 252 个交易 日 的 日 回报率 , 并利用 Roll 的方法来估计 DELL 的买卖价差 。

f rom matp l o t l i b . finance impo r t quote s_hi s to r i c a l_yahoo_ochl a s getData


import s cipy as sp

t i cker = ' IBM '


begdate= ( 2 0 1 3 , 9 , l )
endda te= ( 2 0 1 3 , 1 1 , 1 1 )
da七a=ge七 Da七a ( 七 i c ke r , begdate , enddate , a s ob j e ct=Tru e , adj us ted=T rue )
p=data . ac l o s e
d=sp . di f f ( p )
cov_=sp . cov ( d [ : - 1 ] , d [ l : ] )
i f cov_ [ 0 , 1 ] < 0 :
print ( " Rol l spread for " , 七 i c ke r , ' i s ' , round ( 2 * sp . sqrt ( - cov_ [ O , l ] ) , 3 ) )
else :
prin七 ( " Cov is p o s i tive for " , t i c ker , ' po s i t ive ' , round ( cov_ [ O , l ] , 3 ) )

相应的输 出 如图 8- 1 1 所示。

('Roll spread for ', 'LBM', 'is', I . I 36)

图 8- 1 1

Roll 模 型得到这 个时间 段内的买卖价差是 1 .136。 Roll 模 型的主要假 设是 P, 和 P广 l 之 间


8. 1 0 金 融 研 究 和 实 战 的 应 用 举 例 1 67

的协方差为负 。 当它的值为正时, Ro l l 的模型无法给出买卖价差的估计值 。 在运用实际 数


据时, 这个假 设通常是对的 。 当假设不成立时, 也就是 当价差为负时, 可以考虑 使用其他
方法来估 算价差 。

8.10.3 用 Amihud ( 2002 )模型来估算反流动性指标


A mih ud ( 2002 ) 认为流动性反映的是 一 系列 订单对价格的影 响 。 它的反流动性指标定
义如下 。

R,
l = \ \
i liq, (8-9)
P, X �

这里, R,为第 t 日 的 日 回报率, P1为第 t 日 的收盘价, 而 V是第


1 t 日 的交易金额 。 反流
动性是流动性的对立面, 反流动性指标越低意味着 流动性越高。 首先, 用以下 代码来进行
两 个数组的逐项 除法。

>>>x = np . a rray ( [ l , 2 , 3 ] , dtype = ' f loa t ' )


>>>y=np . ar ray ( [ 2 , 2 , 4 ] , dtype = ' f loat ' )
>>>np . divide ( x , y )
array ( [ 0 . 5 , 1. 0. 75) )
>>>

以下的代码利用 2013年 10 月 的交易数据来估计 I BM 这只 股票 的 A mihud 反流动性指


标, 得到的数值为 1 .165 * 10-1 1 。 这是 一 个相当小的数值。 实 际 上, 数值的绝对大 小 没有多
大 的意义, 相对大 小更能说 明 问题。 如果估计 DEL L在同一时期的反流动性指标, 就会得
到 0.638 * 1 0-1 1 。 由于 1 .1 65 比 0.638 大 , 所以认为 I BM 比 DEL
L流动性差 。

import numpy as np
import statsmode l s . api as sm
fr om matplot巨b . f inance import quotes_h i s t o r i c a l_yahoo_ochl as getData
begdate= ( 2 0 1 3 , 1 0 , l )
enddate= ( 2 0 1 3 , 1 0 , 3 0 )
t i c ker = ' I BM '

da 七 a= getData ( t i c ke r , begdate , enddate , a s obj e ct=True , adj us t ed=True )


p = np . a rray ( data . ac l o s e )
do l l ar_vol = np . ar ray ( data . vo l ume * p )
re t=np . ar ray ( p [ 1 : ) / p [ : - 1 ) - 1 )
i l l i q=np . mean ( np . divide ( ab s ( r e t ) , do l l a r_vo l [ l : ] ) )
p r i n t ( "Ami n ud i l l iq = " , i l l i q )
1 68 第8章 时 间 序 列 的统计分析

( ' Aminud i l l i q= ' , l . 2 0 9 3 8 2 4 2 3 2 7 4 B 8 5 7 e - l l )

8.10.4 Pastor 和 Stambaugh ( 2003 ) 流动性指标


根据 Campbell , Grossman 和 Wang( 1 993 ) 的方法和 实证分析的结果, Pastor 和 Stambaugh
( 2003 ) 提出了如下的模型来衡量 个股的流动性和市场流动性。

Y, = a + /J1 x1 .,-1 十 凡 Xz,r-1 E, C 8- 1 0 )

这里, Yi 是 超 额 股 票 回 报 率 , X 1 ,1 是 市 场 回 报 率 , X2,1 是 带 符 号 的美 元 交 易 额
C x2,1 =sign(Rr -R1,1) X Pr X volumer ) , R1 为股票第 t 天的回报率, R1,1为无风险利 率 , Pr 是股票
价格, volume, 是交易额。 这 个 回 归 模 型用每 个月的 日 回报率来估计,也就是说, 每 个 月 得到
一 个 伤 的估计值 。 Pastor 和 Stambaugh ( 2003 ) 把 /J2 作为流动性指 标 。

以下的代码估计 IBM 的流动性 。 首先, 下 载 IBM 和 S & P500 每 天的价格数据, 计算


它们的 日 回报率, 并将它们合并。

f r om matpl ot l i b . finance import qu otes h i s t o r i c a l yahoo ochl


impo r t numpy as np
import pandas a s pd
import s tatsmode l s . api as sm t i c k e r = ' IBM ' begdate = ( 2 0 1 3 , l , l )
enddate = ( 2 0 1 3 , 1 , 3 1 )
data = quotes_h i s t o r i cal_yahoo_och l ( t i c ke r , begdate , endda 七 e , asobj ect =
True , adj ust ed = True )
r e t = (data . a close [ l : ] -data . ac lo s e [ : - 1 ] ) /data . ac l ose [ : - 1 ] doll ar_
vol =np . ar ray ( data . ac l o s e [ l : ) ) * np . array ( data . v o l ume [ l : ] ) date = [ ]
dO = data . da 七 e
for i i n range ( O , s i z e ( re t ) ) :
date . append ( ' ' . j oi n ( [ d O [ i ] . str ft ime ( " %Y " ) ,
dO [ i ] . s tr ftime ( " %m" ) , dO [ i ] .
str f t ime ( " %d" ) ] ) ) tt =pd . Da 七 aFrame ( re t , np . ar ray ( date , d 七 ype int 6 4 ) ,
columns = [ ' re 七 I l )

t t 2 =pd . DataFrame ( do l l a r_vol , np . array ( date , dtype = i n t 6 4 ) , c olumns =


[ ' do l l a r_vol ' ] )
f f = l oad ( ' c : / 七 emp / f fDai l y . p i c k l e ' ) t t 3 =pd . me rge ( t t , 七 七 2 , l e f t_index =True ,
r i ght_index=True ) f i nal =pd . merge ( t t 3 , f f , 1,ef t_index = T r ue , r i ght_index =
True ) y = final . ret [ 1 : ] - f inal . R f [ 1 : l
xl = f inal . Mkt_Rf [ : - 1 ]
x 2 = s i gn ( np . array ( f inal . ret [ : - 1 ] - f i n a l . Rf [ : - l ] ) ) * np . a r ray ( f inal . do l l a r
vo l ( : - 1 ) )
x3= [ x l , x2 ] n=size (x3)
8. 1 0 金 融研 究 和 实 战 的 应 用 举例 1 69

x=np . re s hape ( x 3 , [ n /2 , 2 ) ) x=sm . add_cons tan t ( x ) results =sm . OLS ( y , x ) . f i t ( )


print r e s u l t s . pa rams

在上面 的 代码 中 , y 为 IBM 在 时 间 t + 1 的 超 额 回 报 率 , X1 为 在 时 间 t 的 市场超额回报


率 , 而 X2 是 在 时 间 t 的 带 符 号 的 美 元 交 易 量 。 X2 之 前 的 系 数 是 Pastor 和 Stambaugh 的流动
性指标 。 相 应 的输 出 如 图 8- 1 2 所 示 。
const 2.702020e-03
xI -I .484492e- I 3
x2 6.390822e- 1 2
dtype: float64

图 8- 1 2

假 设 要 利 用 从雅虎财经下载的 每 日 数 据 来 估 计 IBM 的 市 场 风 险 ( 贝 塔 值 ) 。 下 面 的 线
性 回 归 定 义 了 贝 塔值 。

RI,( = Rf 十 /J1 (Rmk1 ,1 - RJ,1 ) + E, ( 8- 1 1 )

这里 , R ;,1 是 股 票 i 的 回报率 , R1是 无 风 险 利 率 , Rmk1 是 市 场 回报率 , /J; 是 股票 l 的 贝 塔


值 。 由 于 无 风 险 利 率 对 贝 塔值 的 影 响 非 常 小 , 所 以 可 以 用 下 面 的 公 式来近似 。

灼 = a + /3.凡,kt,t + 6, ( 8- 1 2 )

下 面 的 Python 代 码 下 载 I BM 和 S & PSOO 每 天 的 价 格 数 据 和 估 计 IBM 在 20 1 3 年 的 贝


塔值。

impor 七 numpy as np
impo rt s tatsmodel s . api as sm
f rom matp l o t l ib . f inance import quotes h i s t o r i c a l yahoo ochl as getData

begdate= ( 2 0 1 3 , 1 , 1 )
enddate= ( 2 0 1 3 , 1 1 , 9 )

de f re 七_f ( ti c ke r , begdate , endda te ) :


p = getDat a ( t i c ke r , begdate , e nddate , asobj e c t=True , adj us ted=True )
return p . ac l o se [ l : ] /p . a c l o s e [ : - 1 ] - 1

y=ret_f { ' I BM ' , begdate , endda t e )


x= ret_f ( ' "GSPC ' , begda t e , endda 七 e )
x=sm . add_cons 七 ant ( x )
1 70 第 8 章 时 间 序 列 的统 计 分 析

model =sm . OLS ( y , x )


r e s u l ts =mode l . f i t ( )
p r i n t ( re s u l t s . summa ry ( ) )

以上 代码使用前面讨论过的 matplotlib 模块, 特别是调用函数 qu o 七 e_臣 廷 o r i c a l


yahoo_ o ch l ( ) 来从 雅虎财经下 载 IBM 和 S& P 500 C 股票代码 AQ SPC)的每 日 价格数据。
使用调 整 后的收盘价来估计回报率 。 估计回报率的公式用到 p . a c l o s e [ : - 1 ) 。

> > > x = np . a r r ay ( [ l , 2 , 3 , 4 , 1 0 ) )


>>>x [ l : )
array ( [ 2 , 3, 4, 10 J )
> > >x [ : - 1 ]
array ( [ l , 2 , 3 , 4 ] )

输出结果如图8- 13所示。

OLS Regression Results

Dep. Variable: y R-squared: 0. 1 90


Model: OLS Adj. R-squared: 0. 1 87
Method: Least Squares F-statistic: 50.30
Date: Sun, 05 Feb 201 7 Prob (F-statistic): l .90e- 1 1
Time: 1 4:30:20 Log-Likelihood: 672.7 1
No. Observations: 216 AIC: - 1 34 1 .
Df Residuals: 214 BIC: - 1 335.
Of Model:
Covariance Type: nonrobust

coef std err P>ltl [95.0% Conf. Int.]

const -0.0009 0.001 - 1 .237 0.2 1 7 -0.002 0.001


xi 0.741 1 0. 1 05 7.092 0.000 0.535 0.947

Omnibus: 202.261 Durbin-Watson: 1 .8 1 9


Prob(Omnibus): 0.000 Jarque-Bera (JB): 7289.720
Skew: -3.379 Prob(IB): 0.00
Kurtosis: 30.646 Cond. No. 142.

Warnings:
11 Standard Errors assume that the covariance matrix ofthe errors is correctly specified.

图 8- 1 3

图8-13显 示 IBM 的贝 塔值为 0. 74 , 这意味着, 如果市场风险溢价上 升 1%, IBM 的风


8. 1 0 金融研究 和 实 战 的 应 用 举例 1 71

2
险溢价将增加 0.74% 。 20 1 3 年 共 有 2 1 6 个 观 察 值 , 调 整 后 的 R 是 1 8.7% 。 另 外 , 细 心 的 读
者会发 现更 多 的 信 息 , 比 如 Durbin-Watson 统计量和 Jarque-Bera 统计量 , 等 等 。 在讨论如

何运行 Fama-French 三 因 素 模 型 前 , 介 绍 如 何 把 Fama-French 数据保存在 个特殊 格 式 的

数据集里 。 每 个 Pandas 对象都有 内联 函 数 , 它 把 数据 以 Pickle 模 块 的 数 据 结 构 形式按照
给 定 的 名 称保存到指 定 的 目 录下 , 代码 如下 。

>>>impo rt pandas as pd
>>> import numpy as np
>>>np . random . seed ( l 2 3 4 )
>>>a = pd . DataFrame ( r andn ( 6 , 5 ) )
>>>a . to_p i c k l e ( ' c : / temp /a . pi c k l e ' )
>>>k=l oad ( " c : / temp / a . pickl e " )


在 以 上代码 中 , 如 果 只 需 要 产 生 任 意 组 6 行 5 列 的 随机数 , 就 不 需 要 np .random. seed

( 1 234 ) 。 使用 这 个 函 数 保证 每 次 运 行 上述代 码 , 都 可 以 获 得 同 样 的 组随机数 。 另 外 , 输

出 文 件 的 扩展 名 不 定 是.pickle, 任何扩展名 都 可 以 ( 即 使没有扩展 名 也 可 以 ) 。

>>>print ( k )
>>>
。 0 . 471435
。 -1 . 1 90976
1
1 . 432707
2
-0 . 3 1 2 652
3
-0 . 72058 9
4

1 0 . 8 8 7 1 63 0 . 859588 -0 . 636524 0 . 0 15 696 -2 . 2 4 2 6 8 5


2 1 . 150036 0 . 991946 0 . 953324 -2 . 0 2 1 2 5 5 -0 . 334077
3 0 . 002118 0 . 405453 0 . 2 8 9092 1 . 321158 -1 . 546906
4 -0 . 202646 -0 . 655969 0 . 1 93 4 2 1 0 . 553439 1 . 318 152
5 -0 . 4 69305 0 . 67 5 5 5 4 - 1 . 8 17027 -0 . 183109 1 . 058969
>>>

8. 10.5 Fama-French 三因 子模型



资 本 资 产 定 价 模 型 CAPM 是 个 单 因 子 模 型 。 Fama-French 三 因 子模 型把它扩展到 3
个 因 子 。 根据该模 型 , IBM 的 回 报 率满足 以 下 等 式 。

RIBM = Rf + /Jm ( Rm - Rf ) + /JsMB X SMB + /JHML X HML + &, , ( 8- 1 3 )

这里 , RrnM 是 IBM 的 回 报 率 , R1为 无风 险 收 益率 , RM 是 市 场 收 益率 , SMB 是 小 型 股


投 资 组 合 的 收 益率减去 大型股投 资 组 合 的 收益率 , HML 是 高账面 市值股投 资 组 合 的 收益 率
减去低账面市值股投 资 组 合 的 收 益 率 。 下 面 的 程序读入 Fama-French 三 因 子 的 月 回 报 率 ,
并生成 pickle 格 式 的 数 据 集 。
1 72 第8章 时 间 序 列 的统计分析

> > > impor七 pandas as pd


> > > f i l e = open ( " c : /temp / ff_mon 七h l y . t xt " , " r " )
>>>data = f i l e . readl i n e s ( )
> > > f= [ l
» > index= [ ]
> > > f o r i i n range ( 4 , s i z e ( da t a ) ) :
t = data [ i ] . sp l i t ( )
i n dex . append ( i nt ( 七 [ O J ) )
f o r j in r ange ( l , 5 ) :
k = f l oat ( 七 [ j l )
f . append ( k / 1 0 0 )
> > > n= l en ( f )
> > > f l = np . re shape ( f , [ n / 4 , 4 ] )
> > > f f=pd . Da七aFrame ( f l , index = inde x , column s = [ ' Mkt_R f ' , ' SMB ' , ' HML ' , ' Rf ' ] )
>>>f f . to_p i c k l e ( " c : /t emp / f fMonth l y . p i c k l e " )
> > > f f . head ( )

Mkt R f SMB HML Rf


1 92 6 0 7 0 . 0265 -0 . 0239 -0 . 0257 0 . 0022
1 92608 0 . 02 5 9 - 0 . 0 127 0 . 0458 0 . 0025
1 92 6 0 9 0 . 0 0 37 -0 . 0125 -0 . 0009 0 . 0023
1 92 6 1 0 -0 . 0345 -0 . 0002 0 . 0 1 02 0 . 0032
1 92 6 1 1 0 . 02 4 3 -0 . 0024 -0 . 0063 0 . 0031
»>f f . tail ( )

201306
Mkt Rf
-0 . 0121
SMB
0 . 0123
HML
-0 . 0045
Rf
。。
。。。
20 1307 0 . 0 5 65 0 . 0185 0 . 0079
201308 -0 . 0269 0 . 0028 - 0 . 02 4 6
201309 0 . 0376 0 . 0285 -0 . 0152
201310 0 . 0417 - 0 . 0 1 52 0 . 0139
>>>

接下来, 将展示如何使用从 雅虎财经下载 IBM 在 5年里的月 回 报率来估计 Fama-French


三 因 子 模 型 。 Fama-French 的 三 因 子 模 型 的 pickle 格 式 数 据 集 可 以 从 网 址
http : / / www . can i s i u s . edu / - ya n y / p yth on / f fMonthl y . p k l 下载。

f r om matplo七li b . f inance import quotes_h i s t o r i c a l_yahoo_ochl as getData


import numpy a s np
import pandas as pd
import datetime
import s 七atsmode l s . api a s sm

七 i c ke r = ' 工 BM '
8. 1 0 金融研究和实战 的应用 举例 1 73

begdate = ( 2 0 0 8 , 1 0 , l )
enddate = ( 2 0 1 3 , 1 1 , 3 0 )

p = getData ( 七 i c k e r , begdate , endda七e , a s ob j ec七=True , adj us 七ed=True )


logre七 =np . l og ( p . a c l o s e [ l : ] / R_ . a c l o s e [ : - 1 ] )
date= [ ]
dO=p . date

for i in range ( O , np . s i z e ( l ogret) ) :


y =dO [ i ] . s 七 r ftime ( " % Y " )
m=dO [ i ] . s t r f 七 ime ( " %m" )
date . append ( datet ime . da七e ( i nt ( y ) , int ( m ) , 1 ) )

t =pd . DataFrame ( logre t , index =date , c o l umns = [ ' ret ' ] )


ret = np . exp ( t . groupby ( t . inde x ) . s urn ( ) ) - 1
f f =pd . read_p i c k l e ( ' c : / temp / f fMonthl y . p kl ' )

f i n a l =pd . merge ( re t , f f , l e f 七一index = True , r i ght_index = True )


y= fina l . ret
x=final [ [ ' MKT_RF ' , ' SMB ' , ' HML ' ] ]
x= sm . add_constan t ( x )
r e s u l t s=sm . OLS ( y , x ) . f i t ( )
print ( results . pa rams )

以上的代码用 到好几个模块。 数据的起始 日 期是 2008年 1 0 月 1 日 , 结束 日 期是 20 1 3


年 1 1 月 9 日 。 获取每 日 价格数据后, 计算 日 收益率并把它们转换为月收益 率 。 Fama-French
三因子包含在 已经生成 的 pickle 格式数据集里 。 以上 的代码 使用 np.array(date , dtype=int64)
函数使这两个指数具有相同的数据 类型。 相应的输出如图 8- 1 4 所示。

const 0.001440
MKT_RF 0.803794
SMB 0. 1 04695
HML -0.336957
dtype: float64

图 8- 1 4

8.10.6 Fama-MacBeth 回归模型


首先, 演 示如何 使用 pd . o l s函数, 代码如下。

from datetime import datetime import numpy a s np


1 74 第8章 时 间 序 列 的 统计分析

import pandas a s pd
n = 252
np . randorn . seed ( 1 2 3 4 5 ) begdat e=da 七 et ime ( 2 0 1 3 , 1 , 2 )
dateRange = pd . date_range ( be gdate , per io ds=n )
xO= pd . DataFrame ( np . random . randn ( n , 1 ) , column s = [ ' ret ' ) , index = dateRange )
yO=pd . S e r i e s ( np . random . randn ( n ) , index = dat eRange )
print pd . o l s ( y=yO , x=x O )

用以下的代码来估计 Fama-MacBeth 回 归。

from da 七 etime import datet ime


import numpy as np
import pandas as pd
n = 252
np . random . seed ( l 2 3 4 5 )
begda te =datet ime ( 2 0 1 3 , 1 , 2 )
dateRange = pd . date_range ( begdate , periods=n )
de f makeDataFrame ( ) :
data = pd . DataFrame ( np . random . r andn ( n , 7 ) , c ol umns= [ ' A ' , ' B ' , ' C ' , ' D ' , ' E ' ,
, F' , ' G' ) ,
index=dateRang e )
return data

data = {
' A ' : ma keDataFrame ( ) ,
' B ' : ma keDataFrame ( ) ,
' c ' : makeDataFrame ( )

Y = makeData Frame ( )
print ( pd . fama_macbeth ( y= Y , x=data ) )

8.10.7 滚动式估算市场风险系数
以下 代码使用 pd.ols 函数和参数值 window=252 来滚动式估算市场风险系数( 贝 塔值 )。

import numpy a s np
import s t at smode l s . ap i as sm
耳nport pandas as pd
from matp l o t l ib . f inance import quotes h i s torical yahoo ochl as getData

def ret_f ( ti c ke r , begdate , endda te ) :


p = getDa 七 a ( t icke r , begdate , enddate , asobj ect=True , adj us ted= T rue )
return p . a c l o s e [ l : ] /p . aclose [ 0 : - 1 ] - l
8. 1 0 金 融 研 究 和 实 战 的 应 用 举例 1 75

begdate = ( l 9 6 2 , 1 , 1 )
enddate = ( 2 0 1 3 , 1 1 , 9 )
yO=pd . S e r i e s ( r e t_f ( ' 工 BM ' , be gd ate , enddat e ) )
x O = pd . S e r i e s ( r et_f ( ' " GSPC ' , begda t e , enddate ) )
mode l = pd . ol s ( y = yO , x = x O , wi ndow = 2 5 2 )
print (mode l . be t a . he ad ( ) )

可以用下面的代码查 看得到的贝塔值。

>>>prin七 (model . be t a . head ( ) )


X i n t e r cept
2 5 1 1 . 6 1 8 0 1 7 -0 . 0 0 0 64 8
252 1 . 620275 -0 . 0 0 0 65 1
2 5 3 1 . 6 1 8 62 2 - 0 . 0 0 0 6 9 2
2 5 4 1 . 6 2 0 3 1 0 -0 . 0 0 0 7 3 4
255 1 . 622353 -0 . 0 0 0 67 3
>>>print (mode l . beta . t a i l ( ) )
X i n 七e r cept
13049 0 . 784701 -0 . 000857
13050 0. 787247 -0 . 000911
13051 0 . 7 90106 -0 . 0 0 0 8 7 0
13052 0 . 780391 -0 . 000814
13053 0 . 776054 - 0 . 0 0 0 8 67

使用 p l o t ( )函 数绘制图形以显示贝 塔值的时间 曲 线 图。 绘制的曲 线 如图 8- 1 5 所示。


>>>mode l . be t a . plo七 ( )
2.0

L5

。心。
I.S
。 2000 - 4000
6000--- 8QllO --10000

立000 lAOOO

图 8- 1 5
1 76 第 8 章 时 间 序列 的统计分析

通常情况下 , 我们更 关心 每 一年的 贝 塔值, 而不是上面得到的时间段有所重叠的贝塔


值。 以下 代码估计每 年的 贝 塔值, 这可以视为另 一种滚动方式。

import numpy a s np
impo rt pandas as pd
impo r t stat smode l s . ap i as sm
fr om matp l ot l i b . finance impor七 qu otes h i s 七o r i c a l yahoo ochl as getData

de f ret_f ( ti c ke r , begda七e , enddate ) :


p = getDa t a ( ti c ke r , begdate , enddate , asob j ect=True , adj usted=True )
return p . a c l ose [ 1 : ) /p . a c l o s e [ : - 1 ] - 1

be gdate= ( l 9 62 , 1 , 1 )
enddate= ( 2 0 1 3 , 1 1 , 9 )

yO =pd . S e r i e s ( r et_f ( ' I BM ' , begdate , enddat e ) ) xO=pd . S e r i e s ( r et_f ( ' " GSPC ' ,
begdate , e nddate ) )
d=getData ( ' " GSPC ' , begdate , endda t e , asobj e c t=True , adj ust ed=True ) .
date [ 0 : - 1 )
l a g_year=d [ O ) . s t r f time ( " 毛 Y " )
yl= [ )
xl= [ )
beta= [ ]
indexO= [ )
for i i n range ( l , l e n ( d ) ) :
yea r=d [ i ) . s t r f time ( " 毛 Y " )
i f ( year == l a g_ye a r ) :
x l . append ( xO [ i ) )
y l . append ( yO [ i ) )
else :
model =pd . o ls ( y=pd . S e r i e s ( y l ) , x=pd . S e r i e s ( x l ) )
p r i n t ( l ag_yea r , round (mode l . beta [ 0 ) , 4 ) )
beta . append (model . be七a [ O J )
i ndex O . append ( l a g_yea r )
xl= [ )
yl= [ )
lag_year=year

下面给出最初 几年的 贝 塔值 。

( ' 1 962 ' , 1 . 617 4 )


( 1963
I
I / 1 . 0839)
( ' 1 964 ' , 1 . 5 1 8 9 )
8. 1 0 金 融 研 究 和 实 战 的 应 用 举例 1 77

( ' 1 9 65 ' , 1 . 04 9 )
( ' 1966 ' , 1 . 27 5 )
( ' 1 967 ' , 1 . 3 92 7 )
( ' 1968 ' , 1 . 5419)
( ' 1969 ' , 1 . 235)
(
I
1970 I I 1 . 3438)

8.10.8 在险价值简介
我们 常用几种方 法来 评 估 单 个公司 、证券或组合的风险, 如标准 偏 差 、 方 差、 贝 塔
值或夏 普比率。 许多企业的决 策者更喜欢用 一 个
简单 明 了 的金额来量度风险。 在险价值
C V aR)是被广泛采用的指 标之 一 , 它代表在给定的置 信水 平 于 一 段时间内的可能蒙受的
损 失 。 图8-16 基于标准 正 态分布 演 示在险价值这 个概念。

0.45
VaR based on the standard normal distribution

0.40

0.35

0.30

吕 0.25 VaR 99% confidenct/ level


g- 0.20
.r
0.15

0.10

0.05

0.00 fz= ,-2.33


_4
1

-3 -2 -1
Z-values
图 8- 1 6

下面看 几 个例子。 200 股 DELL 股票今天的价值是 2 94 2 美元, 明 天 在 99%置信水平


的最大 损 失是 239 美元。 一
个共 同基金今天价值 1 000 万 美元, 在未来 3 个月 的 99%置信
水平的最大 损 失为 5 000 美元。 银行当前的价值为 1 .5 万 亿美元, 在未来 6 个月 的 99%置信
水平的在险价值是 10 亿美元。 在险价值最常用 的是 1%和 5%的概率(对应于 99%和 95%
置信水平), 以及 1 天和两 周 ( 1 0 天 ) 的时间段。 在正态发布的假 设 下 , 有以下的数学表
达式。

V aRperiod = pos山 on x ( µperiod - z x (J'period ) (8-1 4 )


1 78 第8章 时 间 序列 的统计分析

这里 , position 是 我们投 资 组 合 的 当 前市场价 值 , J/period 是预期 的 回 报率 , z 是 取 决 于 置


信水平 的 分 界 点 , 6 是 波动率 。 正 态 分 布 对 应 99% 的 置 信 水 平 的 分 界 点 为 z = 2.33 , 而对应
95%的置信水平 的 分 界 点 为 z = 1 .64 。 当 时 间 周 期 短 , 比如 1 天 , 可 以 忽 略 µperiod 的 影 响 , 得
到 以下简单的数学式。

VaR = p X z X a C 8- 1 5 )

下 面 的代码计算在 1 0 天 时 间 里持有 5 万股沃 尔 玛股 票 的 在 险 价值 。

import numpy as np
impor七 pandas a s pd
f r om s c i p y . stats impor t norm
fr om matp l ot巨b . 丘nance impo rt quote s_hi st orical_yaho o_ochl as getDa迳
n shares = S O # input 1
conf idence l eve l 0 . 9 9
= # input 2
n_da ys = l O # i npu七 3
z=norm . pp f ( conf idence l evel )
ticker = ' WMT '
be gdate = ( 2 0 12 , l , l )
enddate = ( 2 0 1 2 , 1 2 , 3 1 )
x = ge七Data ( t i c k e r , begdate , enddate , a sobj ect = True , adj usted = True )
ret = x . a c l o s e [ l : ] / x . ac l o s e [ : - 1 ) - 1
po s i t i on=n_shares * x . close [ O ]
VaR=po s i 七 i on * z * np . s七d ( re 七 ) * np . sqrt ( n_days )
p r int ( " Ho l ding = " , po s i t ion , "VaR= " , round ( VaR, 4 ) , " i n " , n_da ys , " Days " )
( ' Ho l ding= ' , 2 6 5 0 . 3 0 7 0 4 9 9 9 9 9 9 9 9 , ' VaR= ' , 2 0 0 . 1 9 1 4 , ' i n ' , 1 0 , ' Days ' )

结 果 显 示今 天 的 股 票 价值 为 2 650.3 1 美 元 , 未 来 1 0 天 在 99% 的 置 信 水 平 的 在 险价值为


200. 1 9 美 元 。

8. 1 1 构 建有效组合边界


构 建 有 效 组 合 边 界 是 金 融领域 个 非 常 有 挑 战性 的 工 作 。 如 何 利 用 实 际 的 数据构建有
效 组 合边界难度 更 大 。 本 节 将 重 点 讨 论 如 何 从 雅 虎 财 经 下 载 历 史 数据 来估计方差-协方差矩
阵 , 找 到 最优投 资 组合 和 构 建 有 效 组 合边 界 。

8.1 1. 1 估计方差-协方差矩阵

假 定 几 只 股 票 的 回报率保存在 个 数 组 里 , 可 以 用 这个 数 组 来 计算这几 只 股 票 的方 差-
8. 1 1 构 建 有 效 组 合边界 1 79

协方差矩 阵 。 然后, 可以结合这几只股票在一个投资 组合中的权重来计算该组合的回报率


的方差 。 以下公式用来计算单只 股票的收益率的方差和标准方差 。

n
T台
RI n
( 8-16 )

-R

I(R; - 时
(J' = (8- 1 7 )
n-1
, a=品

这里 , R; 是该股 票 在时间 段 i 的回报率 , R为它们的平均值 , n 是时间段的数 目。 用以


下公式来计算一个有 n 只 股票的投资 组合的方差和标准差。

Rporl = W;R;L ( 8-1 8 )


i=I

以下的公式计算一个有两 只 股票的投资 组合的方差和标准方 差 。

2
a:,1 = w; 忒 + w回 + 2 w1 w2 a,.2 = w; 忒 + w;a, + 2 w, (1 - w2 ) pa, a2 ( 8-19 )

这里 , a, ,2 是股票 l 和股票 2 之 间 的协方差 , P 1 ,2 是股票 l 和股 票 2 之 间 的相关系数。

I ( RIJ - 瓦 )( R2,; - 困 )
= 旦 C 8-20)
<Y1 ,2 n-I

以下 的公式 计算一个有 n 只 股票的投资 组合的方差和标准方差

= 区区 W; W a;,i ' 其 中 ai,i = a,2 ( 8-2 t )


n n

吐, i=I j=I
丿

假设 回报率矩阵是 n 行 m 列 , 即 m 只 股票在 n个时间 段的回 报 率 。


R, ., R,,, · · · R,� R,., R,,, . . · R, ,.
lr
R1 ,2凡, 2 . . . 坠,n R1, 2 凡 2 . . . 凡,m
R= C 8-22 )

Rn,I Rn . 2 · · · Rn,m 丿 l Rn ,I Rn.2 · · · Rn.m


1 80 第8章 时 间 序 列 的 统 计 分析

W = (W1 , W2 , W3 , · · · , Wm ) C 8-23 )

以下公式用矩 阵形式表示投资组合的预期收益率 。

E(Rpon ) = w x E(R ) ( 8-24 )

相对应的投资组合的方差为

al.I · · · a1 ,m

a1,2 · · · 生,m

.E = ( 8- 2 5 )

CY • • · CY
n,1 n,m

CYporr = W X L X W I C 8-2 6 )
2

显然, 两 只 股 票的投资组合是 n 只 股票的投资组合的一 个特例。 给定 n 只 股票的回报


率矩 阵和它们 在投资组合里所 占 权重的向量, 以下代码用来计算这 n 只 股票的方差-协方差
矩阵和该组合的方差。

import numpy as np
ret=np . mat r i x ( np . array ( [ [ 0 . 1 , 0 . 2 ] , [ 0 . 1 0 , 0 . 1 0 7 1 ] , [ - 0 . 0 2 , 0 . 2 5 ] ,
[ 0 . 0 1 2 , 0 . 0 2 8 ] , [ 0 . 0 6 , 0 . 2 62 ] , [ 0 . 1 4 , 0 . 1 1 5 ] ] ) )
p r i n t ( " re t u rn mat ri x " , r e t )
covar_=re七 . T * ret
we i ght=np . ma t r i x ( np . array ( [ 0 . 4 , 0 . 6 ] ) )
p r i n t ( " weight ve cot " , weigh 七 )
print ( we i gh 七 * covar_*weight . T )

回报率矩 阵和给定组合的方差如图8-1 7所示。

('return matrix', matrix([[ 0.1 , 0.2 ],


[ 0. 1 , 0. 1 07 1 ] ,
(-0.02 , 0.25 ] ,
[ 0.0 1 2 , 0.028 ],
[ 0.06 , 0.262 ] ,

[ 0. 1 4 , 0.1 1 5 ]]))
('weight vecot', matrix([[ 0.4, 0.6]]))
[[ 0. 1 05559 1 5] ]

图 8- 1 7
8. 1 1 构建有效组合边界 1 81

8.1 1 .2 优化 - 最小化

下面的例子试图找到 x 的值使得 目标函数 y 的值达到最小 。

y = 2 + ax ( 8-2 7)
2


很显然, 当 x 等于 0 时, y 的值最小 。 以下代码用来找到 使 y 的值 最小的解 。

>>> from s c ipy . op七im i z e import minimi ze


>> >de f y_f ( x ) :
return ( 3 + 2 * x * * 2 )
>>>xO= l O O
>>>res = minimi ze ( y_f , x O , me thod= ' ne l der-mead ' , opt i ons = { ' xt ol ' : l e- 8 ,
' di sp ' : T rue } )
>>>print ( res . x )
Opt imi z a t i on t e rminated succe s s fu l l y .
Curren七 function value : 3 . 0 0 0 0 0 0
I te ra七ions : 3 7
Function eva l u a 七 i ons : 7 4
( 0.]
>>>

输出显示该函数的最小值为 3, 它是 当 x 取值为 0 时得到的。

8.1 1 .3 构建一个最优投资组合
金融总是在风险与 收益之间寻求平衡 。 夏普比率 是衡量风险与收益是否对等的一 个重
要指标。 其 定义如下 。

E(R ) - R1
Sharpe = ( 8-28)
erp

以下的代码通过改变股票在投资组合里的权重 寻找使得夏普比率 最高的组合。 代码的


第 部分输入组合内包括的几只 股票和股 票 回 报率的开始及结束 日 期。

import numpy a s np
import scipy a s sp
import pandas a s pd
from scipy . optimi ze import fmin
f rom matpl o t l i b . f inance import quotes_h i s t o r i ca l_yahoo_ochl a s getData
1 82 第8章 时 间 序 列 的 统计分析

# Step 1 : input area


七 icker = ( ' I BM ' , ' WMT ' , ' C ' ) 十 七 ickers
begdate = ( 1 9 9 0 , 1 , 1 ) # beginning date
endda te= ( 2 0 1 2 , 12 , 3 1 ) # ending date
rf=0 . 0 0 0 3 # annual 工 i s k- free 工 ate

代码的第二部分定义了 4 个函数来完成以下功能: 从雅虎财经下载数据、 估计 日 回报


率 并将其 转换成年回报率、 计算投资组合的方差及夏 普比率。

* Step 2 : de fine a few functions


# function 1 :
de f ret_annua l ( t i c ke r , begda 七 e , enddte ) :
x=getData ( t i c ke r , begdate , enddate , asobj e ct=Tru e , adj u s ted = True )
logre 七 =sp . log ( x . a c l o s e [ l : ] /x . aclose ( : - 1 ] )
date = [ ]
dO = x . date
for i in range ( O , sp . s i z e ( l ogret) ) :
date . append ( dO [ i ] . st r f tirne ( " 沧 Y " ) )
y =pd . DataFrarne ( l ogret , date , c o l umns = [ t icke r ] )
return sp . exp ( y . groupby ( y . index ) . sum ( ) ) 一 1
# function 2 : e s timate p o r t f o l i o var i ance
de f port f o l i o_var ( R , w ) :
cor = sp . corrcoe f ( R . T )
st d_de v= sp . std ( R , a x i s = O )
var = 0 . 0
for i in xrange ( n ) :
for j in x range ( n ) :
var + = w [ 习 *w ( j ] * s td_dev [ i ] * s 七 d_dev [ j ] * c or [ i , j ]
return var
# function 3 : e s t imate Sharpe ra 七 i o
de f s harpe ( R, w) :
var = portfol io_var ( R , w)
mean_re 七 urn = sp . mean ( R , axis= O )
ret = sp . array (rnean_return )
return ( s p . dot ( w , ret) - r f ) /sp . s qr t ( v a r )
* function 4 : for given n-1 weights , r e 七 u rn a negative sharpe ra 七 i o
de f negative sharpe n minus 1 stock ( w ) :
w2=sp . append ( w , l-sum ( w ) ) \
return -sharpe ( R , w2 ) # us ing a return matrix here ! ! ! ! ! !

第 3步调用 frnin()函数找到最优的投资组合。

# St ep 3 : generate a return mat r i x ( annul return )


8. 1 1 构 建 有 效 组 合边界 1 83

n = l e n ( 七 i c ke r ) # number o f s to c k s
x2 = ret_annual ( t i c ke r [ O ] , begdate , endda t e )
for i i n range ( l , n ) :
x_ = ret_annua l ( t i c k e r [ 辽 , begdate , endda t e )
x2 =pd . me r g e ( x2 , x_, l e f t_\ndex = True , r i gh七_index = True )

Jt us i n g s c ipy a r ray f ormat


R = sp . array ( x 2 )
print ( ' E f f icient p o r f o l i o (mean-var iance ) : t i c k e r u s ed ' )
print ( ticker)
print ( ' Sharpe r a 七 i o for an equa l -weighted por t f o l i o ' )
equal_w= sp . ones ( n , d t ype = float ) * 1 . 0 / n
print ( equal_w )
print ( sharpe ( R , e qual_w) )
Jt for n s 七ocks , we cou l d o n l y cho o s e n - 1 w e i ghts
wO= sp . ones ( n - 1 , dtype = f l o a 七 ) * 1 . 0 /n
wl = fmi n ( nega七ive sharpe n minus 1 s t o c k , wO )
f i na l_w = sp . append ( w l , 1 - s um ( w l ) )
f i nal_sharpe = sharpe ( R , f i na l_w)
print ( ' Optimal weights are ' )
print ( f inal_w)
print ( ' f i nal Sha rpe ratio i s ' )
print ( f i na l_sharp e )

输出结果 如 图 8-18所示 。 等权重投资组合的夏普比率 为 0.63, 最优投资组合的夏普比


率 为 0.6 7。
Effic ient porfolio (mean -variance ) : ticker used
( ' I印 ' , ' I吓 ' , , C ' )
Sharpe ratio for an equal -weighted portfolio
[ 0 . 33333333 0 . 33333333 0 . 33333333]
0 . 634645504708
Optimization terminated successfully .
C urrent function valu e : - 0 . 669702
Iteration s : 30
Function evaluation s : 58
Optimal ,�eights are
[ 0 . 49713116 0 . 31047116 0 . 19239769 ]
final Sharpe ratio is
0 . 669701971388
>>>

图 8- 1 8

8.1 1.4 构建 n 只股票的有效组合边界


构建有效组合边界是金融教学的一 个难点, 主要因为 较多地涉及矩 阵操作和约 束 条 件
1 84 第 8章 时 间 序 列 的 统计分析

下的优化。 绘制有效组合边界的图形有助于形象地解 释 马 科维 茨投资组合理论。 以下代码


找到 由给定的 5 支股票构成的有效组合边界, 并绘制其 图形 。

import numpy a s np
import s c ipy a s sp
import pandas as pd
import matp l o t l ib . p yp l o t as p l t
fr om numpy . l i na l g import i n v , pinv
from matp lotl i b . f i nance impor t quotes h i s t o r i c a l yahoo ochl as getData

# Step 1 : i nput area


begYear , endYea r = 2 0 0 1 , 2 0 1 3
stocks = [ ' I BM ' , ' WMT ' , ' AAPL ' , ' C ' , ' MS FT ' J

# Step 2 : de f i ne 2 func t i o n s
de f re t_mont h l y ( t i c ker ) : # functio n 1
X = ge 七 Data ( t i c ke r , (begYear , 1 , 1 ) , ( e ndYe a r , 1 2 , 3 1 ) , as obj ect = Tr ue ,

adj us ted=True )
l ogret = np . log ( x . ac l o s e [ l : ) / x . ac l o se [ : - 1 ) )
date = [ )
dO=x . date
for i i n range ( O , np . s i z e ( l ogre t ) ) :
date . append ( ' ' . j o i n ( [ dO [ i ) . s t r ft ime ( " % Y " ) , dO [ i ) . s 七 r ftime
( " %m" ) ) ) )
y=pd . DataFrame ( l ogret , da 七 e , c o l umns = [ ti c ke r ) )
return y . groupby ( y . index) . sum ( )

# function 2 : obj e ct ive func t i on


de f obj Fun c t i on ( W , R , tar get_re t ) :
stock_mean = np . mean ( R , a x i s =O )
port_mea n= np . dot ( W , stock_me an ) it p o r t fo l i o mean
cov= np . cov ( R . T ) it var - cov mat r i x
port_var = np . dot ( np . dot ( W , cov ) , W . T ) # p o r t fo l i o va r i ance
pen a l t y = 2 0 0 0 * abs (port_mean-target_re t ) # pen alty 4 deviation
return np . sqrt ( por t_var ) + pena lty # obj ective function

# Step 3 : Generate a return mat r i x R


RO = ret mon 七 h l y ( stocks ( O ] ) \ # s t a r t i n g from 1 s t stock
n stock=len ( s tocks ) # numb e r o f stocks
for i i n x r ange ( l , n s to c k ) : # merge wi 七 h other stocks
x = ret_month l y ( s t o c ks ( i ] )
RO =pd . me rge ( RO , x , l e f 七_index = True , r i ght_index = True )
R= np . array ( RO )
8.1 1 构建有效组合边界 1 85

# Step 4 : e s t imate optimal port f o l i o for a given return


out rnean , ou t s t d , out we ight = [ ] , [ ] , [ ]
s to c kMean = np . rnean ( R, axis = O )
for r in np . l inspace ( np . rnin (,ptockMe an) , np . rnax ( stockMea n) , num= l O O ) :
W = np . ones ( [ n_stoc k ] ) /n_s t o c k # star巨ng from equal weights
b_ = [ ( 0 , 1 )
for i i n range ( n_s tock ) ] # bounds , here no short
C = ( { I 七 ype ' : ' e q ' , ' fun ' : lambda W: s urn ( W) - 1 . } ) # constraint
r e s u l t=sp . optimi z e . rninimi z e ( obj Funct i on , W , ( R , r ) , method= ' S LSQP ' ,
con straints = c , bounds =b )
i f no七 resu l t . succe s s : # handle e rror r a i s e
BaseException ( re s u l t . rne s sage )
out rnean . append ( round ( r , 4 ) ) # 4 dec ima l places
s t d_= round ( np . std ( np . s um ( R * re s u l t . x , axi s = l ) ) , 6 )
out_s 七d . append ( s td_)
out_we ight . append ( re s u l t . x )

# St ep 4 : plot the e f f i c ient frontier


pl t . title ( ' E f f i cient Frontier ' )
plt . xlab e l ( ' S tandard Dev i a t i on o f the p o r f o l i o ( R i s k ) ) ' )
p l t . ylabe l ( ' Re t u rn o f the portfolio ' )
plt . figtex七 ( 0 . 5 , 0 . 7 5 , str ( n_stoc k ) + ' sto c k are used : ' )
p l 七 . f i g七ext ( 0 . 5 , 0 . 7 , ' ' + str ( stocks ) )
pl t . f i gtext ( 0 . 5 , 0 . 6 5 , ' Time period : ' + s t r (begYe a r ) + ' - -- - - - ' + s t r ( e ndYea r ) )
p l t . plot ( out_std, ou七_mea n , ' - - ' )
pl 七 . show ( )

输 出 的 图 形 如 图 8- 1 9 所 示 。

0.030 Efficient Frontier


0.025
5 stock are used:
0.020 ( 'IBM', 'WMr . 'AAPL', 'C', 'MS斤]
o
l

Time period: 2001 -一-- 2013


一七」
oooo
0150100050000
0od a41JO UJnJil'd

-0.010
0 01
- · 6.o4 0.06 0.08 0.10 0.12 0.14 0.16 0.18

图 8- 1 9
1 86 第 8 章 时 间 序 列 的 统计分析

8. 1 2 插值法简介

插值是金融分析中经常用到的技术。 下面的例子在 2 和 6 之间有两 个以 nan 为标记的


缺失值, 使用 p d.inte rp ol ate()函数以线性插值算法来计算并填充这两 个缺失值。

>>>impor 七 pandas as pd
>>>impor 七 numpy as np
>>>x=pd . Series ( [ l , 2 , np . nan , np .nan , 6 ] )
>>>x .inte rpolate ( )
0 1 . 000000
1 2 . 000000

3 4 . 6 6 6 6 67
2 3 . 333333

4 6 . 000000

如果 已知由坐标 ( x 。, yo ) 和 C x 1 , Y1 ) 给定的两 个点, 线性插值算法利用连接这两 个


点之间的直线 。 对于任 一介于横坐标 ( x 。, X1 ) 之间的 x 值, 直线 上对应的 y 值由以下公式
给出。

y-y y -y
= '
。 。
x -x 。 。 ( 8-29)
X1 - X

求解以上方程得出 y 值的计算公式为
(x - x。)Y1 - (x - x。 ) y。
y = y。 十
X1 -�。 ( 8-30)

从 雅虎财经的债券 网 页, 可以得到表 8-2 所示的信息 。

表 8-2

到期 收益率 昨天 上周 上月

3 月 0.05 0.05 0.04 0.03

6月 0.08 0.07 0.07 0.06

2年 0.29 0.29 0.3 1 0.33

3年 0.57 0.54 0.59 0.6 1

5年 1 .34 1 .32 1 .4 1 1 .39


8. 1 3 输 出 数据到外部文件 1 87

续表

到期 收益率 昨天 上周 上月

10 年 2.7 2.66 2.75 2.66

30 年 3.8 3.78 3.85 3 .72

以下 代码利 用线性插 值算法得 出 期 限分别为 4 年、 6 年、 7 年 、 8 年和 9 年的债券的 收


益率。

>>> import numpy a s np


>>>x =pd . Series ( [ 0 . 2 9 , 0 . 5 7 , np . na n , l . 3 4 , np . nan , np . nan , np . nan , np . nan , 2 . 7 ] )
>>>y= x . i n 七 erpo l a t e ( )
>>>print y

1
0 . 2 90
0 . 570
2 0 . 955
3 1 . 340
4 1 . 612
5 1 . 884
6 2 . 156
7 2 . 428
8 2 . 700
dtype : floa 七 6 4
>>>

8. 1 3 输 出 数据到外部文件
本节将讨论用来存储数据的几种方法 , 如 保存数据或结果 到 一个文本文件或二进制文
件等。

8.13. 1 输出数据到 一个文本文件


以下代码 下 载 IBM 的每 日 价格的历 史数据 , 并将其保存到 一个文本文件中。

>>>from matplot l ib . f i nance import quotes_hi s to ri c a l_yahoo_ochl


>>> import re
>>>ticker = ' de l l '
>>>out f i l e=open ( " c : /t emp /de l l . tx t " , " w " )
>>>begdate= ( 2 0 1 3 , l , l )
1 88 第 8章 时 间 序列 的统计分析

>> >endda 七 e = ( 2 0 1 3 , 1 1 , 9 )
>>>p = quotes_h i s to r i c al_yahoo_ochl ( t i c ke r , begdate , enddate ,
a s obj ect=True , adj usted=True )
> > > x 2 = re . s ub ( ' [ \ ( \ ) \ { \ } \ . < > a - zA- Z ) ' , ' ' , x )
> > >out fi l e . write ( x2 )
>>>out f i l e . c l o s e ( )

8.13.2 输出数据到 一个二进制文件


简单的仅有 3 个数值的数组, 然后将它保存在 C:\temp\ 目录下
以下代码首先生成 一 个
名为 tmp.bin 的二进制 文件里。

>>> impor 七 ar ray


>>>import numpy as np
>>>ou t f i l e = " c : /temp / tmp . b i n "
> > > f i leobj = open ( ou t f i l e , mode = ' wb ' )
>>>outva l u e s = a r r a y . array ( ' f ' )
>>>data=np . array ( [ 1 , 2 , 3 ) )
> > >outvalue s . fr oml i s t ( data . to l i s t ( ) )
> >>outva l ue s . t o f i l e ( f i l e obj )
> > > f i leobj . c l o s e ( )

8.13.3 从二进制文件读取数据
假设用以上 代码生成 了 一 个名为 C:\temp\tmp.bin 的二进制 文件, 该文件仅包含 1 、 2
和 3 这 3 个数字。 下面的代码可以从 该文件读取这几 个数字。

> > > imp ort array


> > > i n f i le =open ( " c : /t emp/tmp . bin " , " rb " )
> > > s = i n f i l e . read ( ) jf, re ad a l l bytes into a s t r i ng
> >>d=array . a r ray ( " f " , s ) * " f " f o r f l oat
> > >prin t ( d )
> > > i n f i l e . c lose ( )

8. 1 4 用 Python 分析高频数据并计算 买 卖价差


高频数据是指金融市场内以秒甚至毫秒 记录下来的每笔报价和交易数据。 纽约 证券交


易 所 交 易 和 报 价 C TAQ ) 数 据 库 是 最 常 用 的 美 国 股 市 高 频 数 据 的 数 据 库
( http://www.nyxdata.com/data-products/daily-taq ) 。 下面的代码可用千检索谷歌财经网站上 的

高频数据。
8. 1 4 用 Python 分 析 高 频 数 据 并 计 算 买 卖 价 差 1 89

>>> import re , s 七 ring


>>> imper 七 pandas as pd
> > >t i c ker = ' AAPL ' # input a 豆 c ke r
> > > f l = " c : / temp / t t t . tx t " # t t t w i l l b e replace w i th aboove s t i c ker
>>>f2= f l . replace ( " tt t " , t i c ket )
>>>ou t f i le = open ( f 2 , " w " )
>>>path = "http : / /www . googl e . com/f inance /getpr i c e s ? q= ttt & i =3 0 0 &p=l 0d & f =d, o ,
h, l , c , v "
>>>pa 七 h2 =path . replace ( " t tt " , ti c ke r )
>>>df=pd . read_c s v ( path2 , s ki p rows = 8 , heade r=None )
>>>d f . 七 o_c sv ( out f i l e , heade r = Fal s e , i ndex = Fal s e )
>>>outfi l e . c l o s e ( )

以上 代码用到两 个 输入
变量: 股 票交易代码 和 文件存储路径。 使用含有字 符 串 " ttt "
的路径名, 然后 用 string .replace()函数来把它 替换成所需 的股 票交易代码。 用 hea d ( ) 和
tail ( ) 函数显示所获得的数据文件的首 5 行和最后 5 行如下 。

>>>df . head ( )

0 1 2 3 4 5
0 1 2 3 4

1 5 19 . 55 520 . 2 0 517 . 05 517 .23 2 5 67 1 6


2 519 . 20 520 . 40 518 . 84 519 . 59 2027 1 1
3 518 . 71 519 .29 518 . 00 5 1 9 . 18 1 4 4 92 8
4 519 . 11 5 1 9 . 60 518 . 08 518 . 76 108554
5 519 . 31 519 . 80 5 1 8 . 67 519 . 09 104715

748

»>df . t a i l ( )

898
1
52 5 . 4 5 0 525 . 500
2
524 . 990
3 4
52 5 . 1 4 0 113120
5

749 899 525 . 660 5 2 5 . 67 0 5 2 5 . 17 0 525 . 440 68422

。。
750 900 525 . 460 525 . 680 525 . 37 0 525 . 660 1 0639
751 901 525 . 548 525 . 557 525 . 200 5 2 5 . 37 0
752 902 525 . 420 525 . 58 0 5 2 5 . 2 65 525 . 545
>>>

谷 歌 财 经 网 站提 供 高 频 数 据 的 相 关 网 页 位 于 h t tp : / /www . g o o gl e . com/
f i n a n c e / getp r i ce s ? q=AAPL & i = 3 0 0 & p= l 0 d & f=d , o , h , l , c , v 。 该文件的首 1 0 行
内 容 如下 。

EXCHANGE DNAS DAQ MARKET OPEN MI NUTE = 5 7 0 MARKET CLOSE MINU T E = 9 6 0


I NTERVAL=3 0 0 COLUMNS=DATE , CLOSE , H I G H , LOW , OPEN DATA=
T IME ZONE_OFFSET=- 3 0 0 a l 3 8 3 5 7 5 4 0 0 , 5 2 1 . 2 , 52 1 . 3 5 , 52 1 . 0 7 , 5 2 1 . l 1 , 5 2 2 . 4 8 ,
1 90 第8章 时 间 序 列 的 统计分析

522 . 5 8 , 5 1 9 . 75 , 521 . 37
2 , 5 1 9 . 4 4 , 5 22 . 8 9 , 5 1 8 . 8 1 , 522 . 4 9
3 , 520 . 36, 520 . 98 , 519 . 1 901, 519 . 4 9

以下代码用来添加 一个 日 期
变量 。

imp o r t panda s a s pd, numpy a s n p , da七etime


ti c ke r = ' AAPL '
path= " h ttps : / /www . goog l e . com/ f i nance /getp r i c e s ? q= ttt & i = 3 0 0 &p = l 0d& f = d, o ,
%20h, l , c , v"
x=np . array (pd . read_csv (path . replace ( ' 七七七 I I 七icker) , s kiprows = 7 , header =None) )

date = [ J
for i i n np . a range ( O , l en ( x ) ) :
i f X [ i ) [ Q ) [ Q ) == 1 a 1 ;
t= datet ime . datetime . f romtime s t amp ( int ( x [ i ) [ O J . r ep lace ( ' a ' , ' ' ) ) )
p r i n 七 t i c ke r , t , x [ i ) [ 1 : )
date . append ( 七 )
else :
da七e . append ( t +datetime . t imede l t a ( minu七es = i n t ( x [ i ) [ O J ) ) )

f i n a l = pd . DataFrarne ( x , i ndex = dat e )


f i n a l . column s= [ ' a ' , ' C LOSE ' , ' LOW ' , ' OPEN ' , ' VOL ' ]
del f i n a l [ ' a ' ]
丘nal . to_c s v ( ' c : /t emp /abc . c sv ' . replace ( ' abc ' , t i c ke r ) )

运行以上代 码 后, 可以得到图8-20 所示的输出。


AAPL 20 1 7-0 1 -24 09:30:00 [ 1 1 9.59 1 1 9.53 1 1 9.55 420367L)
AAPL 20 1 7-0 1-30 09:30:00 [ 1 20.9082 1 20.90 1 4 1 20.93 56232 1 L ]
AAPL 201 7-02-03 09:30:00 [ 1 2 8.39 128.3 1 1 28.3 1 633545L)

图 8-20

用 head ( ) 和 t a i l ( 函
) 数来查 看数据的首几行和最后几行。

> > > f i n a l . head ( )


Open High Low Close Vol
2013-11-18 09 : 30 : 00 524 . 87 525 . 2402 5 2 4 . 7 62 5 2 4 . 99 80590

2 0 13-11-18 09: 31 : 00 52 5 . 08 525 . 5 524 . 76 5 2 4 . 82 7 93 1 1
2013-11-18 0 9 : 32 : 0 0 525 . 75 525 . 8 525 . 01 525 . 03 43164
2013-11-18 0 9 : 33 : 0 0 52 6 . 4 4 5 526. 58 5 2 5 . 65 525 . 75 8 1 967
2013-11-18 09 : 34 : 00 52 6 . 4 8 526 . 5899 52 6 . 05 526 . 5899 4 0 67 1

> > > f in a l . ta i l ( )


8. 1 4 用 Python 分析 高 频 数 据 并 计 算 买 卖价 差 191

Open H i gh Low Close Vol


2 0 1 3 - 1 1-22 15 : 57 : 00 519 . 53 519 . 56 519 . 39 519 . 39 35530
2 0 13-1 1-22 15 : 58 : 00 519 . 43 519 . 56 519 . 4 519 . 53 36581
20 13-11-22 1 5 : 59 : 00 519 . 52 519 .54 519 . 41 519 . 43 50983
2013-11-22
2 0 1 3- 1 1-22
1 6 : 0 0 : 00
16 : 01 : 00
5 1 9 . 8\
519 . 8
519 . 85
519 . 8
519 . 49
519 . 8
519 . 52
519 . 8
482044

由于 TAQ 数据库 价格不 菲 , 大多数读者都无法得到该数据库 。 为了 学习 和掌握如何分
析高频数据 , 可以使用 一 个 名为 TORQ C 贸 易 、 订单、 报告和报价) 的数据库 。 Hasbrouck
教 授 创建 了这 个 数 据 库 , 并 在 h t tp : / / p e o p l e . s t e rn . nyu . edu / j hasb rou /
Re sea rch / Wo r k i n g Paper I ndex . htrn 网 页 免费提供给大家下 载, 还有 TORQ 数据
库 的使用说 明 可以在 同 一 网 页 下 载 。 我们把 Hasbrouck 教授的二进制格式数据集转换成
Pandas 模 块 使 用 的 pickle 格 式 数 据 集 。 综 合 交 易 C CT ) 数 据 集 可 以 从
h t 七p : / / c an i s i u s . e du / - yany / p ytho n / TORQct . p k l 下 载。 把这 数据集保存在 C :

\ TEMP 后, 可以用以下两 行 Python 代码加载它。

>>>import pandas as pd
>>>c t=pd . read_p i c k l e ( ' c : / t emp /TORQct . pk l ' )

用 head ( ) 和 tai l ( 函
) 数来查看首几行和最后几行。

>>>ct . head ( )

da 七 e t ime price SlZ g127 七seq cond ex


s ymbol
0 0 0 0 0

8
7 0 0 0
1
5

N M M M N

AC 19901101 10 : 39 : 06 13 100
AC 19901101 10 : 39 : 36 13 100
AC 19901101 10 : 3 9 : 38 13 100
AC 19901101 10 : 39 : 41 13 100
9
1
1
5

AC 19901101 10 : 41 : 38 13 300
>>>ct . t ail ( )
da 七 e t ime price SlZ gl27 tseq c ond ex
s ymbol
0 0 0 0 O

N N N N T

ZNT 1 9 9 1 0 1 3 1 1 1 : 03 : 3 1 12 . 375 1000 237 8 8 4


Z NT 1 9 9 1 0 1 3 1 12 : 4 7 : 2 1 12 . 500 6800 237887
ZNT 1 9 9 1 0 1 3 1 13 : 16 : 59 12 . 500 10000 237 8 8 9
ZNT 1 9 9 1 0 1 3 1 1 4 : 5 1 : 52 12 . 50 0 100 237891

z

ZNT 1 9 9 1 0 1 3 1 1 4 : 52 : 2 7 12 . 500 3600


>>>
1 92 第8章 时 间 序 列 的 统计 分 析

山 千 股票的交易代码用作索 引指标, 所以可 以列 出该数据集包括的所有 股票的 名称。

> > >import numpy as np


> > >uni que ( np . array ( ct . inde x ) )
a r ra y ( [ ' AC ' , ' ACN ' , ' AC S ' , ' ADU ' , ' AL ' , ' AL L ' ,
' ALX ' , ' AMO ' , ' AMN ' , ' AMO ' , ' AR ' , ' ARX ' , ' ATE ' , ' AYO ' , ' BA ' , ' BG ' , ' BMC ' ,
, BRT I , I B Z F I , I CAL I , I CL I , I CLE I , I CLF I , I CMH I , I CMI I , I CMY I , I COA I , I CP I ,
I CPC I , I C P Y I , I cu I , I CUC I , I CUE I , I CYM I , I CYR I , I DBD I , I DCN I , I DI I , I DLT I ,
I D P I , I OS I I , I E FG I , I E H P I , I EKO I , I EMC I , I FBO I , I FOX I , I FFB I , I FLP I ,
I FMI I , I FNM I , I FOE I , I FPC I , I FPL I , I GBE I , I GE I , I GFB I , I GLX I , I GMH I ,
I G P I I , I GRH I , I H邸 I , I HAT I , I HE I , I H F I , I H F I I , I HTR I , I I BM I , I ICM I ,
' IE I ' , ' I PT ' , ' I S ' , ' I TG ' , ' KFV ' , ' KR ' , ' KW D ' , ' LOG ' , ' LPX ' , ' LUK ' ,
, MBK ' , ' MC ' , ' MCC ' , ' MCN ' , ' MOP ' , ' MNY ' , ' MO ' , ' MON ' , ' MRT ' , ' MTR ' ,
, MX I , I NI I , I NI C I , I NNP I , I N S I I , I NSO I , I N S P I , I NT I , I OC Q I , I OEH I ,
I PCO I , I PEO I , I PH I , I P IM I , I P I R I , I P L P I , I PMI I , I POM I , I P P L I , I PRI I ,
I RDA I , I REC I , I RPS I , I SAH I , I SJI I , I SLB I , I S L T I , I SNT I , I S P F I , I SWY I , I T I , I TCI I ,
I TEK I , I TUG I , I TXI I , I UAM I , I UEP I , I UMG I , I URS I , I USH I , I UTD I , I UWR I , I vcc I ,
I VRC I , I w I , I WAE I , I WBN I , I wcs I , I WDG I , I WHX I , I W I N I , I XON I , I y I , I Z I F I , I
Z NT I l ,
dtype=obj e c t )
>>>

把 Hasbrouck 教授提供的综合报价数据集从 二进制格式转换成 pickle 格式数据集, 该


数据集可 以从 h t tp : / / c a n i s i u s . e du / - yany / p ytho n / TORQcq . pk l 下载。 把这一数
据集保存在 C : \ TEMP 后, 可 以用 以下两 行代码加载它 。

> > > impo r 七 pandas as pd


> > > c q =pd . read_p i c k l e ( " c : / t emp / TOR Qc q . p kl " )
> > > c q . head ( )
date t ime bid ofr bids i z ofrsiz mode qseq
s ymbo l
5
0 0 0 0 O
3
2 1 1 1 2

5 1 1 1 2

AC 1 9901101 9 : 30 : 44 12 . 875 1 3 . 12 5 10
AC 1 9901101 9 : 30 : 47 12 . 750 13 . 250 12
AC 1 9901101 9 : 30 : 51 12 . 7 50 13 . 250 12
AC 1 9901101 9 : 30 : 52 12 . 7 5 0 13 . 250 12
AC 1 9901101 10 : 40 : 13 12 . 750 13 . 125 12
>»cq . ta i l ( )
date t ime bid ofr b i ds i z ofrs i z mode qs eq
s ymbol \
0 0 9 0 0
1 1 1 1 1

1 1 1 1 1

1 1
2 2 3 2 3

Z NT 19910131 13 : 31 : 06 12 . 3 7 5 12 . 875
Z NT 19910131 13 : 31 : 06 12 . 37 5 12 . 875
6

Z NT 19910131 1 6 : 08 : 4 4 12 . 500 12 . 750


1

Z NT 19910131 1 6 : 08 : 49 12 . 3 7 5 12 . 875
Z NT 1 9910131 1 6 : 16 : 54 1 2 . 37 5 12 . 875
8. 1 4 用 Python 分 析 高 频 数 据 并 计 算 买 卖 价 差 1 93

同 样可以使用 u n i que ( )函数列 出该数据集包括的所有股票的名称 。 假 设 我们对股票


代号为 " MO " 的公司 感兴趣, 可以用 head ( )函数来展示它的首几行记录 。

>>>x=cq [ c q . index== ' MO ' ]


>>>x . head ( )
da 七e time bid ofr bids i z ofrsiz mode qseq
symbo l
MO 1 9 90 1 1 0 1 9 : 3 0 : 3 3 47 . 000 47 . 125 10

1
0
0 1 1 1 0

0 0 0 0 1
4 1 1 1 3

5
MO 19901 1 0 1 9 : 30 : 35 46. 750 4 7 . 37 5 12
MO 19901101 9 : 30 : 38 4 6 . 87 5 47 . 750 12
MO 1 990110 1 9 : 30 : 40 4 6 . 875 47 . 250 12
MO 19901101 9 : 30 : 47 47 . 000 47 . 125 12

5
1
O
检 查 首 几 行数 据 是 一 个 好 习惯 。 以 上 的 第 行 数 据 显 示 买 卖 价 差 应为 0. 1 25
( 47 . 1 25-47.000 ) 。

>>>x . head ( ) . o f r - x . head ( ) . bid


s ymbol
MO 0 . 12 5
MO 0 . 62 5
MO 0 . 875
MO 0 . 37 5
MO 0 . 125
dtype : f l oat 6 4
>>>

用以下代码来计算平 均价差和平均相对价差。

impor七 pandas as pd
cq= l oad ( ' c : / temp/TORQcq . p i c k l e ' )
x=cq [ c q . index== ' MO ' )
spread=mean ( x . o f r-x . b id)
rel_spread=mean ( 2 * ( x . o f r - x . bid) / ( x . o f r + x . bid) )
print round ( s p r ead , 5 )
print round ( re l_spread , 5 )
0 . 39671
0 . 00788

以上的例子没有对原始数据加以处理或清理。 我们通常 会在分析高频数据之前过滤原


始数据, 比如删 除 买卖价差为 负值的、 bids i z 为 0 或 o f r s i z 为 0 的报价数据等。
1 94 第 8 章 时 间 序 列 的 统计分析

8. 1 5 更 多 关 千使用 Spyder 的信息


S yder
p 是 一 个优秀的编辑器, 值得了解和掌握它 的更多用法。 与 S yder
p 相关的网 页是
http : / /pythonhosted . org/ spyde r / 。 S yde
p r 有 一 个非常 好的功能, 就是查 看 我们
最近使用的文件。

单击 F il ejOpen Recent, 将看到最近使用过的文件列 表。 只 需单击要打 开的文件, 就可


以在窗 口 中打开该文件, 如图 8-21 所示。
1e s吓der (P汗hon l.7)
,, J,• 吓' "1$. ll呻 “

n-
• f 、 还气,t

广, d
hh
lid 心
哼 之
.,
,妇 -C:\ttti,n廿如2.py

飞 '!ll_froo归_n_s缸尥Pv n
l .
2 •••
、,.,, ' .,
fl

3 Created en Fri Feb 14 10:43 : 20 2014


4
Definition : round(number[ , ndigits ] )
ll ...,.
Type : Function o f _builtn_ module
7
8
round(number[, ndQits]) -> floatng pont number
I__�竺In空竺 _r
吐吐 exporer I玉 叩妇 I

Python 2 . 7 . 5 ! Anaconda 1 . 8 . 0 ( 32-bit ) I (default, Jul 1 20


Type "help", "copyrigh t " , "credits" or "license" for n心re ·

Imported NumPy 1 . 7 . 1, SciPy 0.13 .0, 凡tplotlib 1 . 3 . 1


Type "scientific" for ff'Ore detoils .

图 8-2 l

运行程序的几行, 而不是整 个程序。 选择要运行的几行代码行, 然后单击图 8-22 中的


图标百邯P 可。 这 个功能使 我们的编程和调试任务容 易 一些 。

文件浏 览 窗 口 帮助 我们看到某 个 目录下的程序文件。 首先单击图 8-23 中的图标尸]打


开 文件浏 览 窗 口 。

...

.Run

� � �r;� 二已二 子 ct

图 8-22 图 8-23

包含程序 文件的 目录, 如图 8-24 所示。


然后, 选择一 个
8. 1 6 一 个 有 用 的 数据 集 1 95

C:\Yan\Te忒切,gV,ython_forJ斤口心1)rog'MIS

月 ei,plor"白

PreVIOUS 呻 Ned 个 Parent ,:: 干

Nam, Size Type Date Modified


matplotlib File Folder 11/9/2013 2:24:16 PM
_init_. py 51 byt己 py File 9/19/2006 1:35:22 PM
� 30_plot.py 293 byt己 py File 7/17几013 5:58:42 PM
4打5_06_22_int.,rpolat"·PY 78 byt己 py File 11/9/2013 1:38:37 PM
c!J 4375_06_22_scipy_interpolate.py 349 byt己 py File 11/9几013 1:32:07 PM
� 4375_06_22_scipy_interpolate_not_working,py 351 byt已 py File 11/9/2013 1:38:01 PM
� 4375_07_04_npv_ profief2.py 287 byt己 py File 11/9/2013 9:50:45 AM
� 4375_07_05_Ya hoo_price.py 295 bytes py 印e 11/9/2013 11:59:09 AM
� 4375_07.:_06 .py 100 byt•s py File 11/9/2013 3:22:54 PM
邑 4375_07_06_n一vs_port_vol.py 1 KB py File 11/11/2013 10:48:48 AM
� 4375_07_07,py 138 bytes py File 11/9/2013 3:24:36 PM
.!) 4375_07_07_s叹efig, py 76 byt已 py File 11/9/2013 3:09:47 PM

茹; �J 妇吐 e)C!llor古 1 Fie exp1or己

图 8-24

可以单击 文件浏 览 窗 口 顶部的 X 标志 关闭 窗 口 。 当 文件浏 览窗 口 没有打开时, 可以单


击 ViewlWindows and tool bars , 然后选择文件浏 览 窗 口 , 使文件浏 览 窗 口 出现。

8. 1 6 -个有用 的数据集

因为科研经费有 限, 相当多的学校通常不会购买 CRSP 数据 。 为了满足教学需要, 我


们生成了 一个金融资 产月回报率 的数据集, 其中包括超过 200 只股票、1 5 个国家的股 市指
数、 消费者物价指数 ( CPI ) 、 美国的国债利 率、 银行最优惠利率、 无风险利率、 规模 因子
( SM B ) 的回报率 、 账 面价值和 市场价值比 ( HM L ) 的回报率、 Russell 指数和黄金价格等 。
每个时间序列 以金融 资 产的名称作为索 引 指标, 包含 日 期和数值这两 列 数字 。 数值这一 列
包含的数据为价格或者 回报率 。 股市指数、消费者物价指数、债务利率、 黄金价格和 Russell
指数对应的值是价格, 而最优惠利率 、 无风险利率、 SMB 和 HML 对应的值代表回报率 。
用户 可以验证这 些 数 值 。 该数据 集 可 从 http : / / c a n i s i u s . edu / - y any/ python /
yanMo nth l y . p k l 下 载 。 假设数据集保存在 c:\TEMP 目录下, 可以用以下一行 Python 代
码来加载这些 数据 。

>>>impo rt pandas as pd
>>>df=pd . re ad_p i c k l e ( " c : / t emp / yanMonthl y . p kl " )
>>> t=uni qu e ( np . array ( d f . inde x ) )

相应的输出如图8-2 5 所示。
1 96 第 8 章 时 间 序 列 的 统计 分 析

>» t
array ( [ ' 000001 . SS ' , ' A ' , ' AA ' , ' AAP L ' , ' BC ' , ' BC F ' , ' C ' , ' CIK ' , ' COH ' ,
' CPI ' , ' DE LL " , ' GE ' , ' GOLDPRICE " , ' GV ' , ' GVT ' , ' HI ' , ' HML ' , ' HPS ' ,
, HY ' , ' IBM ' , ' ID ' , ' IL ' , ' IN ' , ' INF ' , ' ING ' , ' ItlY ' , ' IO ' , ' I S L ' ,
' IT ' , ' J ' , ' JKD ' , ' JKE ' , ' JPC ' , ' KB ' , ' KCC ' , ' KF T ' , ' KIE ' , ' KO ' ,
, KOF ' , ' LBY ' , ' LCC ' , ' LCM ' , ' LF ' , ' LG ' , ' lM ' , 飞 , ' MA ' , · �认A ' '
, MD ' , ' MF L ' , ' t-t-1 ' , ' MPV ' , '田 ' ' 'Mkt Rf ' , ' N EV ' , · �no · , ' NP ' , ' NU ' ,
' NVF ' , ' OI ' , ' OPK ' , ' PAF ' , ' PFO ' , ' PSJ ' , ' PZZA ' , ' Q ' , ' RH ' , ' RLV ' ,
' Rf ' , ' R uss3000 E D ' , ' R uss3000 E X ' , ' S , ' S BR ' , ' SC D ' , ' SE F ' , ' SI ' ,
' S KK ' , ' SMB ' , ' S干C ' , ' T ' , ' TA ' , ' TBAC ' , ' TEN ' , ' TK ' , ' TLT ' , ' TOK ' ,
' TR ' , ' TZ E ' , ' UHS ' , ' U I S ' , ' U RZ ' , ' US DEBT ' , ' US GDP 2009dollar '
, us GDP 2013dollar ' , ' V ' , 'VC ' , ' VG ' , ' VGI ' , ' VO ' , 'W ' , ' \-JG ' ,
' WI F I ' , ' \-.MT ' , ' WR ' , ' XL I ' , ' XON ' , ' Y ' , ' YANG ' , ' Z ' , ' "AORD ' ,
, "B S ESN ' , ' " CC S I ' , ' " CSE ' , ' " FCHI ' , ' " FTSE ' , ' " G S PC ' , ' 心 S PTSE ' ,
' 哗I ' , ' A IBEX ' , ' AI S EQ ' , ' "JKS E ' , ' AK LS E ' , ' AK S ll ' , ' "MXX ' ,
, A NZ50 ' , ' "OMX ' , ' ASTI ' , ' ASTOXX50 E ' , ' "飞 II ' ] , dtype=object )
» > le n ( t )
129

图 8-25

上 面的输 出 显 示 一 共有 129 个时间序列 。 每 个时间序列 可以通过索引来选择。 如果 我


们对消费者物价指数感兴趣, 可以用以下 代码来检索数据 。

> >>x=df [ df . index = = ' C P I ' )


>>>x . head ( )
DATE VALUE
NAME
CP工 19130101 9.8
CPI 19130201 9.8
CPI 19130301 9.8
CPI 19130401 9.8
CPI 19130501 9.7
>>>x . t a i l ( )
DATE VALUE
NAME
CPI 20130401 2 32 . 5 3 1
CPI 20130501 232 . 945
CPI 20130601 233 . 504
CPI 20130701 233 . 596
CPI 20130801 233 . 877
>>>

8. 1 7 小 结
本章详细 讨论了与统计分析相关的许多概念和内 容, 包括如何 由雅虎财经下 载历史数
练习题 1 97

据; 如何估算收益 率、 整体风险、 市场风险、 股票之间 的相关性以及不 同国家和市场之间 的


相关性 ; 如何估计方差-协方差矩阵, 形成不 同 类型的投资组合, 构建有效的投资组合和有效
投资组合的边界 。 还学习了估算 R ol (l 1 984)的买卖价差、Amih ud ( 2002)的反流动性指标,
h on 代码
以及 P ast or and St amb augh ( 2003)的流动性指标 。 第 4 章介绍了如何编写 13行 Pyt
来利用 Bl ack-Sch ol es-M ret on 模型给看涨期权定价, 不过并没有深入探讨期权定 价的基本理
论和逻辑。 下 一 章将进一 步解释 期权理论和相关的应用。

练习题

l . P and as 模块的主要作用是什 么 ?

2 . s t atsrnode l s 模块的主要作用是什么 ?
3. 如何安装 Pandas 和 s ta t srnode l s 模块?

4 . 哪 个模块包含 一 个 名为 r olli ng_k urt 的函数? 如何使用该函数 ?

5. 利用从 雅虎财经下 载的历史数据检验 I BM 的 日 收益率是否服从 正态分布 。

6 . 依据 2012 年的 日 收益率, I BM 和戴尔的 日 平 均 收益率是否 一 样? (提示: 可以从


雅虎财经下载历史数据。)

7. 如何使用 Pyth on 软件和CRSP 数据来重复 J ag ad eesh和Tit man C l 993)的趋势投资


策略 ? ( 假设你的学校有CRSP 数据)

8. 依据 I BM 在 201 2 年的 日 收益率, 可以判断出发生过多少次对股价有重大 影 响 的


事件 ?
9. 用 2008年至 2012 年 5年间的月 回报率 计算这几支股票:I BM、DELL、
WMT、"G SPC、
C、 A、AA 和 MOFT 之间的方 差协方差矩 阵以及它们之间 的相关系数 。 哪两 只 股票最密
切 相关?

10. 编写 Pyt
h on 程序来逐年估算 一 只 股 票 的 贝 塔 值 。 用它来计算 IBM 在 1962 年至
2013年 间 每年的 贝 塔 值 。

11 . 假设从 h ttp/
: /www.fed re arl se
e rv .eg ov/r el es
as
e/h15/d a at. h tm联邦储备委员 会的数据库
中下 载最优惠利率的历史数据 。 以下 给出所下 载文件的首 几行 。 编写 Pyth on 程序读取数据
并使用第 1 列 作为索 引 。

Series Descr iption 30 - Day AA Financia l Commercial Paper Interest Rate


1 98 第 8 章 时 间 序 列 的 统计分析

Un i t : P e r cent
Mu l t ip l i e r : 1
Currency : NA
Unique Identi f i e r : H 1 5 / H 1 5 /RIFSP PFAAD3 0 N . B
Time P e r i od R I F S P P FAAD 3 0 N . B
1/2/1997 5 . 35
1/3/1 997 5 . 34

12 . 哪 个 政 党 能 更 好 地管 理股 市 ? 根 据 h 七 tp : / / www . e n c h a n t e dl e a r n i n g .

com / h i s t o r y / u s / p r e s / l i s t . s h tml 网 页, 我们可以发现总统属 于 哪 一 个党派。 据此


可以产生表 8-3 。 PARTY 和 RANGE变量是从 网 页获得的, YEAR2 是 RANGE 的第 2 数减
去 I, 除了最后 一
行以外。

表 8-3

PARTY RANGE YEARl YEAR2

Republican 1 923- 1 929 1 923 1 928

Republican 1 929- 1 933 1 929 1 932

Democrat 1 933- 1 945 1 933 1 944

Democrat 1 945- 1 953 1 945 1 952

Republican 1 953- 1 96 1 1 953 1 960

Democrat 1 96 1 - 1 963 1 96 1 1 962

Democrat 1 963- 1 969 1 963 1 968

Republican 1 969- 1 974 1 969 1 973

Republican 1 974- 1 977 1 974 1 976

Democrat 1 977- 1 98 1 [ 977 1 980

Republican 1 98 1 - 1 989 1 98 1 1 988

Republican 1 989- 1 993 1 989 1 992

Democrat 1 993-200 1 1 993 2000

Republican 200 1 -2009 200 J \ 2008

Democrat 2009-20 1 2 2009 20 1 2

( 1 ) 从 h 七 tp : / / mba . 七u c k . dartmouth . e d u / p a g e s / f a c u 让 y / ken . f r e n c h /

dat a_让b r a r y . html 网 页上 French 教授的数据库 里, 下载超额市场收益率和无风险利率 。


练习题 1 99

( 2 ) 估 计 市 场 收 益 率 ( 超额 市 场 收 益 率 加 上无风险 利 率 ) 。

( 3 ) 把市场 收 益 率 按 年份分成 两 组 : 共和 党执政 的年 份 和 民主党执政 的 年 份 。

( 4 ) 检验这 两 组 市 场 收 益 率 的 均 值是 否 相 等 , 即

RDemocratic = RRepublican

注 : 如 何 下 载 和 估 计 市 场 收 益率 ?

( I ) 进 入 网 页 http ://mba.tuck.dartlnouth .edu/pages/faculty/ken. french/data_I ibrary. html 。

( 2 ) 单击 Fama-FrenchFactor, 并 下 载 其命名 为 F-FResearch_Data_Factors.zip。

( 3 ) 解 压 缩 zip 文 件 , 估计市场月 回报率, 如 1 926 年 7 月 , 市场收益率


=2.65/ 1 00+0.22/ 1 00 。

This f i l e was created b y CMPT_ME_BEME_RET S u s i n g the 2 0 1 2 1 2 CRS P databa s e .


The 1 -month T-B i l l return i s from Ibbotson and Associate s , Inc .

Mkt -RF SMB HM L RF


192607 2 . 65 -2 . 1 6 -2 . 92 0 .22
192608 2 . 58 -1 . 49 4 . 88 0.25
192609 0 . 37 - 1 . 38 -0 . 0 1 0 . 23
192610 -3 . 4 6 0 . 04 0 .71 0 . 32
1 92 6 1 1 2 . 43 -0 . 2 4 -0 . 3 1 0 . 31
192612 2 . 75 -0 . 01 -0 . 10 0 . 28
1 92 7 0 1 -0 . 16 -0 . 30 4 .79 0 . 25
192702 4 . 22 -0 . 24 3 . 35 0.26
1 9 2 7 03 0 . 38 - 1 . 87 -2 . 58 0 . 30
192704 0 . 41 0 . 29 0 . 95 0 . 25
1 92 7 0 5 5 . 36 1 . 53 5 . 07 0 . 30

1 3 . 从 http://rnba.tuck.dartmouth.edu/pages/faculty/ken. french/data_I ibrary.html 网 页 上


French 教授 的 资 料 库 , 下 载 Fama-French 月 回 报 率 和 日 回 报 率 因 子 , 其 中 SMB 是 小 公 司 组
合 的 收 益率减去 大 公 司 组 合 的 收 益 率 , HML 为 价值 股组 合 的 收 益 率 减 去 增 长 股 组 合 的 收 益

率 。 假设你持有 个 SMB 组 合 , 回 答 以 下 3 个 问 题 。

( 1 ) 用 日 回 报 率 计 算 自 1 989 年 1 月 1 日 � 20 1 2 年 1 2 月 3 1 日 的 累 积 收 益 ?

( 2 ) 用 月 回 报 率 计 算 自 1 989 年 1 月 1 日 � 20 1 2 年 1 2 月 3 1 日 的 累 积 收 益 ?

( 3 ) 它们 的 值 相 等吗 ? 如 果 不 相 等 , 为 什 么 ?
200 第 8章 时 间 序 列 的 统 计分析

14. 表 8-4 列 出了债券评级、 违约 风险差价和时间 之 间 的 关系 。 编写 Python 程序利 用


插值算法估算第 1 1年到第 29年这些年的违约 风险差价。

表 8-4

Rating lyr 2yr 3yr Syr 7yr l Oyr 30yr

Aaa/AAA 14 16 27 40 56 68 90

A a l /AA+ 22 30 31 48 64 77 99

Aa2/AA 24 37 39 54 67 80 1 03

Aa3/AA - 25 39 40 58 71 8[ 1 09

A l /A+ 43 48 52 65 79 93 117

A2/A 46 51 54 67 81 95 121

A3/A- 50 54 57 72 84 98 1 24

Baa l /BBB+ 62 72 80 92 121 141 1 70

Baa2/BBB 65 80 88 97 1 28 151 1 77

Baa3/BBB- 72 85 90 1 02 1 34 1 59 1 83

Ba l /BB+ 1 85 1 95 205 215 235 255 275

Ba2/BB 1 95 205 215 225 245 265 285

Ba3/BB- 205 215 225 235 255 275 295

B l /B+ 265 275 285 315 355 395 445

B2/B 275 285 295 325 365 405 455

83/8- 285 295 305 335 375 415 465

Caa/CCC+ 450 460 470 495 505 515 545

表 8-4 由 http://www.bond son line.com 网站提供 。 表中的值 以基点为单位 , 一


个基点相
当于万 分之 一
, 因此表中的值 40 其 实等于 40 X 0.000 1 。

15. 从 French 教授在以下网 页 的资 料库 下载 M叫�et 、 SMB 和 HML 这 3 个因子 的 日 回


报 率和月 回 报 率 http://mba.tuck.dartmouth.edu/pages/facu lty/ken.french/data_library.html 。 编
写 Python 程序来读取它们, 然后选择 一
个时间段, 如 2000年 1 月 1 日 � 20 1 3年 12 月 31

日 , 用 日 回报 率和月 回 报率分别计算 SMB 因子 的 累 积 收 益 。 它们相等 吗 ? 有多大 的区别 ?


如果计算每年的 收益, 它们有多大 的区别 ? 讨论你的发现。
第9章
Bl ack-Scholes- Merton 期 权
定价模型

期权理论及其应用在现代金融理论和实 践 中 发挥着重要作用 。 许 多 交易 策略 、 企业激


励计划和套期保值策略都用到各种类型的期权 。 第 4 章介 绍了如何编写 5 行 Python 代码使
用 Black-Scholes-Merton 模型给看涨期权定价 。 本章将更详细地介绍 期权的基本理论及其相
关应用, 包括以下内容 。

• 看涨期权和看 跌期权的收益和利 润/损 失函数及其 图形展示

• 欧式与美式期权

• 正态分布 、 标准正态分布和累 积分布函数


• Black-Scholes-Merton 期权 模 型

• 各种交易 策略及其图形表示,包括股 票 多 头和看涨期权空头的组合、 跨式期权组合、


蝶式 期权组合和 日 历套 利组合等

• delta、 gamma 和其他与期权有关的希腊字母

• 期权平价关系及其图形表示

• 一步和两 步 二 叉 树 模 型的图形表示

• 使用二叉树法为欧式和美式期权定价

• 套期保值策略
202 第 9 章 Black-Scholes-Merton 期 权定 价 模 型

9. 1 看涨期 权和 看跌期 权的 收益和 利 润I损失 函 数

期权是买卖双方的一 个合约, 给予合约 买方以约定的价格(行使价或执行价 ) 向合约


卖方购买或卖 出 合约 指定的标的资 产的权利。 有 一 个欧式看涨期权规定买方可以用行使价
30 美元, 在 3 个月 后购买 某只 股票, 该期权在到期 日 的收益可以用以下公式 计算。
pay off( call) = M ax(Sr - X,O) ( 9- 1 )

。 假设 3
这里, Sr是到期 日 ( T)的股票价格, X 是执行价(在这个例子里 X 等 于 30)
个月后股价是 25 美元, 我们将不会使用看涨期权以 30 美元购买股票, 因为 我们可以在公
开市场上 以 25 美元购买 同样的股 票。 另 一方面, 如果 3个月 后股价是 4 0 美元, 我们将使
用看涨期权以 30 美元 买股票, 转手在市场上以 4 0 美元售出, 从 而获得 I O 美元的收益。 以
下 代码给出看涨期权收益的函数:

>>>def payoff_ca l l ( s T , x) :
return ( s T-x+abs ( sT-x ) ) / 2

简单 易用, 代码如下 。
这个收益函数

> > >payo ff—call ( 2 5 , 3 0 )



>>>payoff_c al l ( 4 0 , 3 0 )
10

第 1 个输入参数是到期 日 T 的股票价格。 以下代码使用一 个数组作为第 1 个输入参数。

>>>import numpy as np
>>>x = 2 0
>>>s T=np . arange ( l 0 , 5 0 , 1 0 )
>>>s T
array ( [ l O , 2 0 , 3 0 , 4 0 ] )
>>>payof f_ca l l ( sT , x)
array ( [ 0 . , 0 . , 1 0 . , 2 0 . ] )
>>>

用以下代码来绘制看涨期权的收益函数 曲线。

import nurnpy as np
impor t rnatplotlib . pyplot as plt
9. 1 看 涨 期 权和看跌期 权 的 收 益 和 利 润/损 失 函 数 203

s = np . arange ( l 0 , 8 0 , 5 )
x= 3 0
payoff= ( abs ( s - x ) + s -x ) /2
plt . yl im ( - 1 0 , 5 0 )
p l t . plot ( s , payoff)
plt . show ( )


绘制的收益函数曲 线 如图 9-1 所示 。
so
40
30
20
10

- 10
10 20 30 40 SO 的 70 80
图 9- 1

看涨期权卖家的收益与买家的 收益相反。 要记住 期权合约是 一 个买卖双方的零和游戏:


一方熹钱, 另 一 方必定输钱 。 假设 一 个投资 者卖出 3 个看涨期权, 执行价格为 1 0 美元。 当
股票价格在到 期 日为 1 5美元时, 期权买家的收益为 1 5 美元, 而期权卖家的损 失也为 1 5 美
元。 如果看涨期权的期权费(即 期权价格) 为 C, 看涨期权买家的利润/损 失函数是收益与
初始投资 C c) 之 间的差额 。 支付期权费的时间与获取收益的时间是不 同的。 不过, 当期权
合约的有效期比较短时, 可以忽 略货币 的时间价值 。

看涨期权买方的利润/损 失 由以下公式计算。

看涨期权买方的利润I损 失 = M ax(Sr - X,0)-c ( 9-2)

看涨期权卖方的利润/损 失 由以下公式 计算。

看涨期权卖方的利润/损 失 = c -M ax(Sr - X,O) ( 9-3)

以下代码计算看涨 期权买卖 双方的损 益 并显示损 益函数的 曲 线 。 绘 制 的 曲 线如图 9-2


所示 。

import scipy as s p
import ma tplo 七 lib . pyplo 七 as p l t
s = sp .arange ( 3 0 , 7 0 , 5 )
x=4 5 ; ca l l =2 . 5
profit= ( abs ( s - x ) +s-x) /2 -call
y2=sp . zeros ( l en ( s ) )
204 第9章 Black-Scholes-Merton 期 权 定 价 模 型

y l im ( - 3 0 , 5 0 )
plot ( s , p r o f i t )
p l o t ( s , y2 , ' - . ' )
p l o t ( s , -pro f i t )
t i t l e ( " P r o f i t /Loss func t i o n " )
x l abel ( ' S tock p r i c e ' )
ylabel ( ' P r o f i t ( lo s s ) ' )
p l t . anno 七 ate ( ' Ca l l option buye r ' , x y= ( S S , 1 5 ) , x ytext= ( 3 5 , 2 0 ) , ar rowprops=
dict ( f a c e c o l o r = ' bl ue ' , s h r i n k = 0 . 0 1 ) , )
p l t . annotate ( ' Ca l l opt i o n s e l l e r ' , x y= ( S S , - 1 0 ) , xytext= ( 4 0 , - 2 0 ) ,
ar rowprops = dict ( f a c e c o l o r = ' red ' , s h r i n k= 0 . 0 1 ) , )
sh ow ( )

Profit/loss function for III call option


50 40 30 20 10 0
p呈
)
i

- 10 • ·

-2 0 ,.

-30
30 35 40 心 丈 印 65

图 9-2

看 跌 期权给予买方在到 期 日 以约定价格 X 向卖方出售标的资 产的权利 。 以下是其 收益


函数:
看跌 期权买方的收益函数=Max(X- Sr,O) ( 9-4 )

这里, Sr 是到 期时的股价, X 是行使 价 。 看 跌 期权买方的损 益(即利润I损 失)函数


如下 。

看跌 期权买方的损 益函数=Max(X-Sr,0)-p ( 9-5 )

看 跌 期权卖方的损 益函数正 好相反。

看跌 期权卖 方 的 损 益函数=p - Max(X-Sr, O) ( 9-6)

以下 代码绘制看跌 期权买方和卖方的损 益函数的曲 线, 如图 9-3 所示。

import s c ipy as sp
import ma 七p l o t l ib . pyplot a s p l t
9.2 欧式期权与 美式期权 205

s = sp . arange ( 3 0 , 7 0 , 5 )
x=4 5 ; p=2 ; c=2 . 5
y=c- ( abs ( x- s ) +x- s ) / 2
y2=sp . zeros ( len ( s ) )
x3= [ x , x ]


y3= [ - 3 0 , 1 0 ]
p l t . yl im ( - 3 0 , 5 0 )
p l t . plot ( s , y )
p l t • plot ( 5 f y2 f I - • I )
p l t . pl ot ( s , - y )
p l t . p l o t ( x 3 , y3 )
plt . t i t l e ( " P rofit /Loss function for a put opt i on " )
pl t . x l abel ( ' Stock price ' )
p l 七 . y label ( ' Profit ( l o s s ) ' )
plt . annotate ( ' Pu t option buyer ' , xy= ( 3 5 , 1 2 ) , xytex七= ( 3 5 , 4 5 ) , arrowprops=
die七 ( facecolor= ' r ed ' , s hrink=0 . 0 1 ) , )
plt . annotate ( ' Pu t option s e l l e r ' , xy= ( 3 5 , - 1 0 ) , xy七e x七= ( 3 5 , - 2 5 ) , ar rowprops=
dict ( facecol or= ' blue ' , shrink= 0 . 0 1 ) , )
p l 七 . annotate ( ' Exercise price ' , x y= ( 4 5 , - 3 0 ) , xytext= ( 5 0 , - 2 0 ) , arrowp rops=
dict ( facecolor = ' black ' , shrink=0 . 0 1 ) , )
p

pl t . show ( )
l

Profit/loss function for a put option



50
.
,
b
p
t
t

y
e r
u

n
u

30

! 它20
10。

- 10

-20

-3
Q30 L 35 40 45- 50 55 60 65
Stock price

阳 9-3

9.2 欧式期权与美式期 权

欧式期权只能在到 期 日 行权, 而美式期权可以在到期 日或到期 日 之前的任何时间行权。


由千美式 期权可以在到期 日 前行权, 所以它的价格 ( 期权费) 应该不低 千 欧 式 期权。
206 第 9 章 Black-Scholes-Merton 期 权定 价 模 型

t-'"= :;,, c,._


pAmerican ?: PEuropean
( 9-7 )

一 个 重 要 的区 别 是 欧 式 期 权 的定 价公式 可 以 有 一 个 解 析表达 式 , 比 如
B al c k - Sch oel s-Mert on 期权模型, 而美式期权的价格不可以用一 个解析表达式来计算。 不过,
我们有其他方法来给美式期权定价。 本章将介绍如何使用二叉树方法(也称为 CRR 方法)
为美式期权定价。

9.3 现金流 、 不 同 类型 的 期 权 、 权利 和 责任

我们知道 每 个业务合同都有买方和卖方来签订。 期权合约同样有买卖双方。 由于期权


合约 本质上 是买卖双方的一 个零和游戏, 看涨期权的买方支付现金以获得权利, 卖方则收
取现金并承担义务。 表 9-1 列 出 了 期权合约 的头 寸(买方或卖方)、 初始现金流噩(收取或
支 付) 的方向、 期权买方的权利(买或卖) 和期权卖方的义务(即 满足期权买方的要求)。

表 9-1

期权买方 ( 多头 ) 期权卖方 ( 空头 ) 欧式期权 美式期权


有权利以约定价格购 必须履 行 义 务 以 约 定 价 只 能在到 期 日 能在到期 日 之前
看涨期权
买标的资产 格 卖 出 标 的 资产 行权 行权
有权利 以约 定价格卖 必须履 行 义 务 以 约 定 价 只 能在到 期 日 能在到 期 日 之 前
看跌期权
出标的资产 格 买入标 的 资 产 行权 行权
期权费流向 支付期 权 费 收取期权 费

表 9-1 显示了 多 头/空 头 、 看涨/看跌期权、 欧式/美式 期权和初始现金流的方向。

9.4 正态分布 、 标准正态分布和 累 积标准正态分布


正态分布 在金融领域起着 重要的作用, 尤其 对于 期权理论。 我们通常 假 设 股票 价格
遵循对数正 态分布 , 因而股票 回 报 率遵循正态分布 。 正态分布 的密度函数定义如下 。
9.4 正 态 分布 、 标 准 正 态 分 布 和 累 积标准 正 态 分布 207

f (x) = e
l 一二
压2 ( 9-8 )

这里, µ是均值, 6 是标准方 差 。 \ 当µ为 o, (1 为 1 时, 正态分布密度函数称为标准正态
分布 , 其 密度
函数如下 。
_:::_
f( x) = e 2
1
( 9-9 )

以下代码生成标准 正 态分布的 曲 线 。 SciPy 模块的 stats.norm.pdf()函数用于 标准正态分
布, 其 默认 设置为零均 值和单位标准方差, 即 标准正态密度函数。

>>> f r om scipy impor七 exp , s qr 七 , s t a t s


>>> stat s . norm . pd f ( O ) 0 . 3 9 8 9 4 2 2 8 0 4 0 1 4 3 2 7
> > > 1 / sqrt ( 2 *p i ) # v e r i f y manua l l y
0 . 3 9 8 94 2 2 8 0 4 0 1 4 3 2 7
> > > s t ats . norm . pdf ( 0 , 0 . 1 , 0 . 0 5 )
1 . 0 7 9 8 1 9 3 3 0 2 63 7 6 1 1
>>> 1 / sqrt ( 2 *pi * O . 0 5 * * 2 ) * exp ( - ( 0 . 1 ) * * 2 / 0 . 0 5 * * 2 / 2 ) # ve r i f y manu a l l y
1 . 0 7 98 1 93302 637 6 1 1

函数 曲线如图 9-4 所示。


用以下代码绘制标准正态分布的曲 线 。 绘制的标准正态密度

> > > f r om scipy import exp , sqrt , st ats


>>>x = a range ( - 3 , 3 , 0 . 1 )
>>>y=stats . norm . pdf ( x )
> > >plot ( x , y )

0.40
0.35
0.30
0.25
0.20
0.15
0.10
0.05
0. 00-3
1::: -2 -1 。 1

团 9-4

累 积标准正 态分布函数是标准正态密度函数 曲 线下的面积 。 在下面的程序中, 任意选


208 第9章 Black-Scholes-Merton 期 权 定 价 模 型


择 个数 0 . 3 2 5 , 赋予变量 Z, 称 其 为 z 值 。 标 准 正 态 密 度 函 数 曲 线 下 在 z 值左侧 的 阴 影
面 积 就 是 累 积 标 准 正 态 分 布 函 数在 z 点 的 取值 。

import numpy as np
from scipy import exp , s qr t , s ta t s
from matp l o t l ib import pyp l o t as pl 七
z=O . 3 2 5 It user can change 七 his number
de f f ( 七 ) :
re 七 urn st ats . norm . pdf ( t )
plt . y l im ( 0 , 0 . 4 5 )
x = np . arange ( - 3 , 3 , 0 . 1 )
yl=f ( x )
p l t . plot ( x , y l )
x2= np . arange ( - 4 , z , 1 / 4 0 . )
sum= O
de l t a = 0 . 0 5
s = np . ar ange ( - 1 0 , z , de l t a )
f o r i in s :
sum+ = f ( i ) *delta
plt . annotate ( ' area i s ' + s t r ( r ound ( s um, 4 ) ) , x y= ( - 1 , 0 . 2 5 ) , xytext = ( - 3 . 8 , 0 . 4 ) ,
ar rowprops = dict ( facecolor= ' red ' , shrink = 0 . 0 1 ) )
plt . annotate ( ' z = ' + s tr ( z ) , x y= { z , 0 . 0 1 ) )
p l t . f i l l_be tween ( x 2 , f ( x2 ) )
p l t . show ( )

上 述 代码计 算 的 阴 影面 积 如 图 9-5 所 示 。

0.45
a
a
re

6
2

0.40
.
IS
,t', .一
0 0
3530

0.25

0.20

0 15

0. 10

0.05

0.00
-4 -3 -2
2

-1

图 9-5

下 面 的代码使用 s t a t s . n o rm . c d f ( ) 函 数计 算 累 积标准正 态 分 布 的 结 果 。
9.5 不 分红 股 票 的 期 权 定 价 模 型 209

import numpy as np
f rom scipy imp o r 七 exp , sqrt , s ta t s , a range , ones
f rom matp l o t l i b import pyplot a s p l t
z=0 . 3 2 5
def f ( x ) :
return stats . no rm . cdf ( x )
x = arange ( - 3 , 3 , 0 . 1 )
y l=f ( x )
y2=ones ( l en ( x ) ) * 0 . 5
x3= [ 0 , 0 )
y3 = [ 0 , 1 )
p l t . p l o t ( x , yl )
p l t . plot ( x , y2 , ' b - ' )
plt . p l o t ( x3 , y3 )
p l t . annotate ( ' f ( z ) = f ( ' +s tr ( z ) + ' ) i s ' + str ( np . round ( f ( z ) , 4 ) ) , x y= ( z , f ( z ) ) ,
xytext = ( z - 3 , f ( z ) ) , ar rowp rops=di ct ( facecolor= ' red ' , shrink= 0 . 0 1 ) )
p l 七 . annotate ( ' z i s ' +s tr ( z ) , xy= ( z , O ) , xytext= ( l . 5 , 0 . 3 ) , ar rowprops=di ct
( facecolor= ' blue ' , shr ink=O . 0 1 ) )
p l t . show ( )

以上代码绘制 的 图 形如 图 9-6 所示 , 由 于 正 态 分 布 是 对称 的 , 所 以 累 积 标 准 正 态 分 布
函 数 在零点 的值 为 0.5 。

1.0

0 8 ,-

f(z) =f(0.325) is 0.627 4.


0.6

0.4
z is 0.325

0 2 •·

0. �
2

图 9-6

9.5 不分红股票的期 权定价模型

不分红股票 的 期 权 定 价 ( black-scholes-merton ) 模 型 假 设 标 的 股 票 在 到 期 日 前不支付任


何 股 息 , 因 而 给 出 了 欧 式 期 权 价 格 的 解 析表达式 。 如 果 用 S。 代 表 当 前 价 格 , X 代表行使价 ,
210 第9章 Black-Scholes-Merton 期 权定价模 型

r 代表连续复利 的 无风险利 率 , T 代表 以 年 为 单位 的 期 权有 效 期 , 6 代表股票 的 波 动 率 , 那


么 欧 式看涨期权 ( c ) 的 价 格 公 式 和 欧式看跌期权 (p ) 的 价 格 公 式 分别 如 下 。

d, = m ( � ) + ( r+ ½ 叶
6行

C 9- 1 0 )
d尸
气门勹产
; = d1 - 崎


c = S N(dl ) - xe-rT N(d2 )
p = Xe-rr N(-心 - S0 N(-di )

这 里 , N()是 累积标准正态分布 函 数 。 下 面 的 Python 代码根据上述 公式计算期权 的价格 。

f r om s cipy import l o g , exp , sqrt , s tats


de f bs_call ( S , X , T , r , s i gma ) :
dl= ( l og ( S / X ) + ( r+ s i gma * s i gma / 2 . ) * T ) / ( s i gma * s qrt ( T ) )
d2 = d l - s i gma * s qrt ( T )
return S * s tats . norm . cdf ( d l ) -X* exp ( - r * T ) * s tats . n orm . cdf ( d2 )

在 以 上代码 中 , s t a t s . n o rm . c d f ( ) 函 数 给 出 累 积正态分布 函 数 的 值 。 当 前 的股票价


格 为 40 美元 , 执行价格为 42 美 元 , 到 期 时 间 为 6 个 月 , 连续 复 利 的 无风 险利 率 为 1 .5% ,
标 的 股 票 的 波 动 率 为 20% 。 使用 以 上 的 函 数 计 算 得 出 欧式看涨期权 的 价值 为 1 .56 美 元 。

>>>c=bs_cal l ( 4 0 . , 4 2 . , 0 . 5 , 0 . 0 1 5 , 0 . 2 )
>>>round ( c , 2 )
1. 56

9.6 用 千期权定价的 p4f 模块

第 3 章 建议将许 多 小 型 的 Python 代码合并在 个程序里 。 本章采用 了 同 样 的 策 略 , 把


所有程序合并到 个名 为 p 4 f . p y 的 大 文 件 中 , 包括前 节 计 算 期 权 价 格 的 bs_c a l l ( )


一 一

函 数 。 这样 的 程序集合有几个好处 。 首先 , 使用 b寻_c a l l ( ) 函 数 时 , 不 必 重新输入这 5


行代码 。 为 了 节 省 空 间 , 只 显 示 p 4 f . p y 文 件 中 包含 的 几个 函 数 。 p4f 模块可从作 者 的 网
页上下载: http ://canisius.edu/-yany/python/p4f.cpython-3 5 .pyc 。 为 简 洁起 见 , 我们删 除 了
每 个 函 数包含的 所有注释 。 这些注释 旨 在 为 用 户 提供 帮 助 信息 , 可 以 使用 help ( ) 命令来
获得 , 如 he l p ( b s _ca.1 1 ( ) ) 。
9 .6 用 于 期 权 定 价 的 p4f 模 块 211

de f bs_cal l ( S , X , T , r f , si gma ) :
from s c ip y i mport log , exp , s qr t , sta七S
dl= ( l og ( S /X ) + ( r f + s i gma * s igma /2 . ) * T ) / ( s i gma * s qrt ( T ) )
d2 = d l - s i gma * s qr t ( T )
return S * s 七 a t s . n o rm . cdf ( d l ) - X * exp ( - r f * T ) * s tats . n orm . cdf ( d2 )

以下程序使用二项式模型对看涨期权定价。

de f b i nomial_g r i d ( n ) :
import networ k x as nx
import matp l o t l ib . pyplot as p l t
G=nx . Graph ( )
for i i n range ( O , n+l ) :
for j i n range ( l , i +2 ) :
i f i<n :
G . add_edge ( ( i , j ) , ( i + 1 , j ) )
G . add_edge ( ( i , j ) , ( i + l , j + l ) )
posG= { } # di c tionary with node s p o s i t i on
for node i n G . nodes ( ) :
posG [ node ] = ( node [ O ] , n + 2 +node [ 0 ] -2 * node [ l ] )
n x . draw ( G , p o s =posG)

de f de lta_ca l l ( S , X , T , r f , s i gma ) :
from sc ipy i mport l o g , exp , sqrt , stats
dl= ( l og ( S / X ) + ( r f+s i gma * s igma / 2 . ) * T ) / ( s i gma * s qrt ( T ) )
return ( s tats . norm . cdf ( d l ) )

de f de l t a_put ( S , X , T , r f , s i gma ) :
f rom sc ipy import log , exp , sqrt , stats
dl= ( l og ( S /X ) + ( rf+s i gma * s i gma /2 . ) * T ) / ( s igma * s qrt ( T ) )
re七urn ( s ta七s . norm . cdf ( d l ) 一 1 )

使用以下代码计算 Black-Scholes-Merton 模型给出的看涨期权价格。

> > >import p 4 f


> > > c = p4 f . bs_cal l ( 4 0 , 4 2 , 0 . 5 , 0 . 0 1 5 , 0 . 2 )
>>> round ( c , 2 )
1 . 56

第二 个优点是节省 空 间 并使代码更简洁。 在本章的后面使用 b i n omi a l _gr i d ( ) 函数


时, 这 一点将变得更加清晰 。 从 现在开始, 当第一 次讨论一 个函数时, 我们 将提供完整的
212 笫9章 Black-Scholes-Merton 期 权 定价模 型

代码 。 但 是 , 当 程序相 当 复杂 并 且 再 次 用 到 它 时 , 我们会通过 p4 f 间 接调用 它 。 可 以 用 以


下 代码找到我们 的 工 作 目 录 。

>>> impor t o s
>>>print ( o s . ge tcwd ( ) )

9.7 已知 分 红股 票 的 欧式期 权价格

假 设 期 权 的 到 期 日 是 T, 已 知 标 的 股 票 在 时 间 T1 将 发 放红利 , T1 <T。 可 以修改原始的


B l ack-Scholes-Merton 模型来给该期权定 价 , 就 是 用 以 下 公 式 中 的 S 代替 S胪


S = S - e-rr, d ( 9- 1 1 )

n
d, = I ( 轩 (r + 巨 厂 ( 9- 1 2 )
6 行

d, �
In 门 (r _
X
_!_ 矿 T
2
) � d, - 顽 ( 9- 1 3 )

c = S x N( d1 ) - X x e- rT N( d2 ) ( 9- 1 4 )

p = X x e- rT N( d2 ) - S X N( -d1 ) C 9- 1 5 )


在前 节 讨 论 的 例 子 中 , 如 果 已 知 该股票在 一 个 月 后 支 付 1 .5 美 元 的 红 利 , 那 么 看涨
期 权 的 价 格 是 多 少 ? 可 以 用 以 下 的方法来计 算 。

>>>import p 4 f
>>> s 0 = 4 0
>>>d= l . 5
>>>r = 0 . 0 1 5
>>>T= 6 / 1 2
>>>s=s0- exp ( - r * T * d )
>>>x = 4 2
>>>sigma = 0 . 2
>>>round ( p 4 f . bs_ca l l ( s , x , T , r , s i gma ) , 2 )
1 . 18
9.8 多 种 交易 策略 213

代 码 的 第 1 行 导 入 p4f 模 块 , 其 中 包 含 计 算 期 权 价 格 的 函 数 。 结 果 显 示 , 看 涨 期 权
的 价 格 为 1 . 1 8 美 元 , 低 千 之 前 的 价 格 C 1 . 56 美 元 ) 。 这 主 要 是 因 为 标 的 股 票 的 价 格 将 在
一 个 月 后 大 约 降 低 1 .5 美 元 , 超 过 42 美 元 的 可 能 性 降 低 , 因 此 行 使 看 涨 期 权 的 机 率 将

会 更 小 。 以 上 的 办 法 同 样适 用 于 在 到 期 日 T 之 前 多 次 分 红 的 股 票 , 即 以 S = S z: e- rT, d; 。-
代 替 S胪

9. 8 多 种 交 易 策 略

表 9-2 总 结 几 种 常 见 的 涉 及 各 种 类 型 期 权 的 交 易 策 略 。

表 9-2

名称 描述 期权费流向 预期未来价格变化

买入执行价为 X i 的看涨期权, 卖 出 执行价


看涨期权的牛 市 多 空套 利 付 出 期权 费 价格上涨
为 X2 的看涨期权 Cx 1 < x2 )

买入执行价为 X1 的 看跌 期权 , 卖 出 执行价
看跌期权的 牛 市 多 空套利 收取期权费 价格上涨
为 X2 的 看 跌 期权 ( x,< x2 )

买 入执行价为 X2 的看跌期权, 卖 出 执行价


看跌期权的 熊 市 多 空套利 付 出 期权 费 价格下跌
为 XJ 的看跌期权 C x 1 < x2 )

跨式 期权组合 ( Straddle ) 买入执行价相 同 的看涨期权和看跌期权 付 出 期权费 价格上涨或下跌

买 入 执 行 价 相 同 的 两 个 看 跌期 权 和 一 个 价格下跌的概率大
熊市跨式期权组合 ( Strip ) 付 出 期权 费
看涨期权 千上涨的概率

牛市跨式期权组合 买入执行价相 同的 两个看涨期权和 一个 价格上涨 的 概率 大


付 出 期权 费
C Strap ) 看跌期权 于下跌的概率

异价跨式期权组合 买入执行价为 X2 的看涨期权 , 买 入执行价


付 出 期权费 价格上涨或下跌
( Strangle ) 为 X1 的看涨期权 ( x1< x2 )

买入执行价为 Xi 和 X3 的看涨期权, 卖 出 两
蝶式看涨期权组合 付 出 期权费 价格在 X2 附近
个执行价为 X2 的看涨期权 < x2=( x 广 X3)/2 )

买入执行价为 x , 和 X3 的看跌期权, 卖 出 两
蝶式看跌 期权组合 付 出 期权 费 价格在 Xz 附近
个执行价为 X2 的看跌期权 (x2=( x1+ x3 )/2 )
214 笫9章 B lack-Scho Jes-Merton 期 权定 价 模 型

续表

名称 描述 期权费流向 预期 未来价格变化

卖 出 到 期 日 为 T1 的看涨期权, 买 入 到 期 日
日 历套利组合 付 出 期权 费
为 T2 的 看涨期权, T1 <T2

9.8. 1 股票多头和看涨期权空头的组合

假 设 我们 购 买 公 司 A 的 股 票 1 00 股 , 每 股 价 格 为 1 0 美 元 , 总 成 本 是 l 000 美 元 。 如 果
一 一
同 时卖 出 个看涨期权合 同 , 每 个 合 同 对应 标 的 股 票 1 00 股 , 每 个 看涨期权 的价格为 20

美 元 。 因 此 , 我们 的 总 支 出 将 减 少 20 美元 。 进 步 假 设 行 使 价 为 1 2 美 元 , 可 以 用 以下代
码绘制损 益 函 数 的 图 形 。

import numpy a s np
import matp l o t l ib . pyplot as p l t
s T = np . arange ( 0 , 4 0 , 5 )
k= 1 5 ; s 0= 1 0 ; c=2
yO=np . zeros ( l en ( s T ) )
yl=sT-s0 # s to c k o n l y
y2= ( abs ( s T - k ) + s T - k ) / 2 - c # l ong a c a l l
y3=yl -y2 # cove r ed- c a l l
p l t . ylim ( - 1 0 , 3 0 )
p l 七 . plo七 ( s T , y l )
p l t . plot ( s T , y2 )
plt . plot ( s T , y3 , ' red ' )
p l t . plot ( s T , y O , ' b - . ' )
plt . plot ( [ k, k] , ( - 1 0 , 1 0 ] , ' black ' )
p l t . 七itle ( ' Cove red cal l ( l ong one share and short one cal l ) ' )
pl t . x l ab e l ( ' Stock p r i c e ' )
pl t . y l abel ( ' P r o f i t ( l o s s ) ' )
p l 七 . annotate ( ' Stock o n l y ( l ong one share ) ' , x y= ( 2 4 , 1 5 ) , xytext= ( l 5 , 2 0 ) ,
ar rowprops=di c t ( facecolor= ' b l ue ' , shrink=0 . 0 1 ) , )
p l t . annotate ( ' Long one share , short a c a l l ' , x y= ( l 0 , 4 ) , x ytex七= ( 9 , 2 5 ) ,
arrowprops=di c 七 ( facecol or= ' r ed ' , s hrink=0 . 0 1 ) , )
plt . annotate ( ' Exercise price= ' + s t r ( k ) , xy= ( k+ 0 . 2 , - 1 0 + 0 . 5 ) )
p l t . show ( )

图 9-7 中 的 3 条损益 函 数 曲 线 分 别 对应 3 个 交 易 策略 , 包 括 股 票 多 头 、 看涨期 权 多 头 ,


以 及 股 票多 头 和 看 涨 期 权 空 头 的 组 合 。 显 然 , 当 股 价 低 于 1 7 美元 C 1 5 + 2) 时 , 该组合的
回报要比股票 多 头 好 。
9.8 多种交易策略 215

30
Covered call (long one share and short one call)

2S Long one share. short a call

20 Stock only (long c


P
i
26

15

j_,L
10
一》


一5

- 10 ExercisEj price= .i5


0 10 15 20 25 30 35
s

亟k price

图 9-7

9从2 跨式期 权组合 具有同样执行价格的看涨期权和看跌期权


的组合

我们来看 一个非常简单的情况 。 某个企业在下个月 将发生 一个重大事件 , 但 我们不能


确定事件结果的方向 , 也就是说, 无法预测它
是 一 件好事还
是坏事。 为了利用这个重大事
件获利 , 可以同时买进执行价相同的一个看涨期权和一个看跌期权。 这意味着无论股价上
涨或下跌, 我们都可以获利。 进一 步假设行 使价为 30 美元, 这个策略的损 益函数如下 。

import numpy a s np
impor t matpl o t l ib . pyplot a s p l t
sT = np . arange ( 3 0 , 8 0 , 5 )
x=S O ; c=2 ; p= l
straddle= ( ab s ( s T- x ) +sT- x ) / 2 - c + ( ab s ( x - s T ) + x - s T ) / 2 -p
yO=np . zeros ( l en ( s T ) )
plt . ylim ( - 6 , 2 0 )
pl t . x l im ( 4 0 , 7 0 )
p l t . plot ( sT , yO )
pl t . plot ( s T , s t r addl e , ' r ' )
p l t . p l o 七 ( [ x , x ] , [ - 6 , 4 ] , ' g- . ' )
p l t . 七 i t l e ( " Pr o f i t - l o s s for a S t raddl e " )
p l t . x l abel ( ' S t o c k p r i c e ' )
plt . ylabel ( ' P r o f i t ( l o s s ) ' )
p l t . annotate ( ' P o i n t l = ' + s 七 r ( x- c - p ) , x y= ( x-p- c , O ) , xytext = ( x -p-c , 1 0 ) ,
ar rowprops =dict ( facecolor = ' r ed ' , s h r i n k=0 . 0 1 ) , )
p l t . annotate ( ' Point 2 = ' +s t r ( x+ c +p) , xy= ( x+p+ c , 0 ) , xytext = ( x +p+ c , 1 3 ) ,
arrowpr ops=di c t ( facecolor = ' bl u e ' , s h r i n k=0 . 0 1 ) , )
pl t . annotate ( ' e x e r c i s e p r i c e ' , xy= ( x + l , - 5 ) )
216 第9章 Black-Scholes-Merton 期 权 定 价 模 型

p l t . anno 七 ate ( ' Buy a c a l l and buy a put with the s ame exercise
price ' , x y= ( 4 5 , 1 6 ) )
pl t . show ( )

以上 代码绘制的图形如图 9-8所示。

20
Profit-lo巧 for a Straddle

Buy a call and buy a put with the same exericse pri
15
Point 2=53

Point 1=47
0
1
(
SSO

一拦0
5
K

• exercise price
5 40
L

心 50 55 60 65 70
StodcJ!rt�

图 9-8

图 9-8 显 示, 无论股价上涨或下跌 , 利润都 是正的。 什 么 时 候 会 出 现损 失 呢 ? 当 股票


变化不大 时, 也就是, 当 我们对未来的预期落空时。

9.8.3 日 历套利 组合

日 历套利组合包括两 个看涨期权, 它们具有相同行权价格但不 同到期 日 : T1 和 T2 ( 其


中 T1 <T2 ) 0 我们卖 出 较短期限 C T1 ) 的看涨期权, 并购买较长期限 C T2 ) 的看涨期权。 因
为看涨期权价格与有效期呈正相关, 我们需要付 出 现金来购买 日 历套利组合 。 我们希望当
第1 个看涨 期权在 T1 到期时, 标的股票的价格接近行权价格。 这 个策略的损益函数 曲 线和
图形的代码如下。

impor 七 p 4 f
import numpy a s np
耳nport matp l o t l ib . pyp lot as p l t
sT = np . ar ange ( 2 0 , 7 0 , 5 )
s = 4 0 ; x=4 0 ; T l = 0 . 5 ; T2 = l ; s igma = 0 . 3 ; r=0 . 0 5
\

payo ff= ( abs ( s T-x ) +s T-x ) /2


cal l_O l=p 4 f . bs_cal l ( s , x , Tl , r , s i gma ) Jt short
cal l_02 =p 4 f . bs_ca l l ( s , x , T2 , r , s i gma ) Jt long
9.8 多种交易策略 217

p r o f i t— O l =payo f f -cal l_O l


cal l— 0 3 =p 4 f . bs_cal l ( s T , x , ( T 2 -T l ) , r , s i gma )
cal endar—spread=cal l_0 3 - payo f f + c a l l — 0 1 - c a l l 02
yO =np . z e r o s ( l e n ( s T ) )
pl 七 . y l im ( -2 0 , 2 0 )
pl t . xlim ( 2 0 , 6 0 )
pl t . plot ( s T , cal l_0 3 , ' b- . ' )
pl 七 . plot ( s T , cal l_0 2 - cal l_O l -payof f , ' b- . ' )
p l t . p l o t ( s T , c a l e n dar_spread , ' r ' )
pl t . plo t ( [ x , x l , [ - 2 0 , - 1 5 ] )
pl t . t i t l e ( " Cal endar spread wi七h ca l l s " )
plt . xlabel ( ' S t o c k price a t matu r i t y ( s T ) ' )
pl t . y l abel ( ' P r o f i t ( l o s s ) ' )
p l t . annotate ( ' Buy a ca l l w i 七h T l a n d s e l l a ca l l w i th T2 ' , xy= ( 2 5 , 1 6 ) )
plt . annota七e ( ' where T l <T2 ' , xy= ( 2 5 , 1 4 ) )
plt . annotate ( ' Cal endar spread ' , xy= ( 2 5 , - 3 ) , xytext= ( 2 2 , - 1 5 ) ,
ar rowprops=dict ( f aceco l o r= ' r ed ' , sh r i n k= 0 . 0 1 ) , )
pl t . annotate ( ' Va l ue o f the c a l l ( T2 ) at matu r i t y ' , xy= ( 4 5 , 7 ) , xytext= ( 2 5 , 1 0 ) ,
arrowprops=dict ( faceco l or = ' bl ue ' , s h r i n k= 0 . 0 1 ) , )
plt . annotate ( ' Pro f l i t / l o s s wi七h call 1 only ' , xy= ( 5 0 , - 1 0 ) ,
xytext= ( 3 0 , - 1 0 ) , a rrowprops=dic七 ( facecolor= ' bl u e ' , s hrink=0 . 0 1 ) , )
p l t . show ( )

以上 代码绘制的图形如图 9- 9 所示。

20
Calendar spread with calls

、 . -·
Buy a call with TlOand sell a call with r2
15 where Tl <T2

10 Value of the call {TI) at maturity


5

=


0 t . . .. . ... .'. . . . �
-5 •.

-10 ,.

-15 •·
\ ' """""�'" ""' ' ""'' -
Calendar spread

-20 1
20 25 30 35 心 45 · 50 55 切
Stock 口七e at matl.lf'切 <sT>

图 9-9
21 8 第9章 Black-Scholes-Merton 期 权定 价 模 型

9.8.4 蝶式看涨期权组合
蝶式 ( butterfly ) 组合是指买入执行价格分别为 m 和 X3 的看涨期权并卖出执行价格为
X2 的两 个看涨 期权, 其 中 x2= ( x 什X3 ) /2 , 并且它们 的标的股票 和 到 期 日 都相同 。 其 损 益函
数可以 由以下 代码计算得到。

import numpy as np
import matpl o t l i b . pyp l o 七 as p l t
s T = np . ar ange ( 3 0 , 8 0 , 5 )
x l =5 0 ; cl=lO
x2=5 5 ; c2=7
x3 = 6 0 ; c3=5
y l = ( abs ( s T - x l ) + s T - x l ) / 2 - c l
y2= ( ab s ( s T-x2 ) + s T -x2 ) / 2 - c 2
y3= ( ab s ( sT-x3 ) + s T - x 3 ) / 2 - c 3
bu七ter_fl y=yl +y3 - 2 * y2
yO=np . z e r o s ( l en ( s T ) )
plt . ylim ( - 2 0 , 2 0 )
plt . x l im ( 4 0 , 7 0 )
plt . plot ( s T , yO )
plt . plot ( sT , y l )
p l t . pl o t ( s T , - y2 , ' - . ' )
p l t . p l o 七 ( s T , y3 )
p l t . plot ( s T , butter_fl y , ' r ' )
p l 七 . t i t l e ( " P r o f i t - l o s s f o r a Bu七ter f l y " )
plt . x l abe l ( ' S 七 o c k pric e ' )
pl七 . ylabe l ( ' Pro f i t ( l o s s ) ' )
pl t . anno七ate ( ' Butter f l y ' , xy= ( 5 3 , 3 ) , xytext= ( 4 2 , 4 ) , a r rowprops=dict
( f acecolor= ' r ed ' , s h r i n k=0 . 0 1 ) , )
p l t . annotate ( ' Buy 2 ca l l s with x l , x3 and s e l l 2 ca l l s w i th x2 ' , xy= ( 4 5 , 1 6 ) )
p l t . anno七a七e ( ' x2= ( x l + x 3 ) /2 ' , xy= ( 4 5 , 1 4 ) )
plt . annotate ( ' x l = 5 0 , x2=5 5 , x 3= 6 0 ' , xy= ( 4 5 , 1 2 ) )
p l t . annotate ( ' c l = l 0 , c2=7 , c3=5 ' , xy= ( 4 5 , 1 0 ) )
p l t . show ( )

以上 代码绘制的图形 如图 9-10 所示。



9. 1 0 与 期 权相 关 的 希 腊 字 母 21 9

Profit-loss for a Butterfly_


20
Buy 2 calls with xl, x3 and sell 2 calls with x2
15 x2=(xl+ x3)/2
xl =SO, x2=55, x3=60
10 c l =l0,c2=7, c3=5
- - - - - - - - - - - - - -

5上 Butterfly
(
5501}芒 0片l

-令

-5

- 10

-1 5

-2 0
40 45 50 55 60 65 70
Stock price

图 9- 1 0

9.9 期权价格和输入参数之 间 的 关 系

当标的股票的波动率增加时, 其 看涨期权和看 跌期权的价值都增加。 理 由是, 当股票


价格的波动幅度增 大 时, 股票价格有 更 大 的机会出现极端的值, 也就是 说 , 我们更加有机
会从 期权合约中获利 。 以下 Python 代码用 来展示这种关系。

impo rt numpy as np
import p 4 f a s p f
import matp l o t l ib . pyp l o t a s p l t
s 0= 3 0 ; T 0 = 0 . 5 ; s i gma 0 = 0 . 2 ; r 0 = 0 . 0 5 ; x 0 = 3 0
s i gma=np . ar ange ( 0 . 0 5 , 0 . 8 , 0 . 05 )
T=np . arange ( 0 . 5 , 2 . 0 , 0 . 5 )
cal l_O=p f . bs_ca l l ( s O , xO , T O , r O , s i gma O )
c a l l_s i gma=pf . b s_cal l ( s O , x O , T O , rO , s i gma )
c a l l_T=p f . bs_c a l l ( s O , xO , T , r O , s igma O )
plt . p l o t ( s i gma , c a l l_s i gma , ' b ' )
p l t . plot ( T , c a l l_T )
p l t . show ( )

9. 1 0 与期权相 关 的 希腊字母

在期权理论中, 几 个希腊字母 用 于 表示 期权等金融衍生品的 价格的敏 感性, 通常称为


风险敏感性 、 风险度量或套利参数。
220 第 9 章 B lack-Scholes-Merton 期 权定 价 模 型

希腊字母 del t a( � )代表期权的价格对标的股票价格的导数。 看涨期权的 delt a定义


如下 。

ac
�=— ( 9- 1 6 )
as
我们可以基于 del t a值设计 一 个套期保值策略。 假设标 的股票在有效期不分红, 它的欧
式看涨期权的 delt a 由如下公式计算。

�call
=
N (d, ) ( 9- 1 7 )

假 设 我们卖出 一 个看涨期权, 可以买入数量等于 delt a的标的股票, 使得股票价格的微


小变化可以被看涨期权的价格的
变化相抵消 。 del ta—c a l l ( 函
) 数的定义非常简单。 由于

包含在 p 4 f . py 文件中, 所以可以轻松调用它, 代码如下 。

>>>from p 4 f import *
>>> round ( del ta_call ( 4 0 , 4 0 , l , O . l , 0 . 2 ) , 4 )
0 .7 2 5 7

假设标的股 票在有效期不分红, 它的欧式看跌期权的 delt a定义如下 。

ilput = N ( di ) - l C 9- 1 8 )

可以用以下代码调用 de l t a_pu t ( )函数 。

>>>from p 4 f import *
>>> round ( delta_put ( 4 0 , 4 0 , l , O . l , 0 . 2 ) , 4 )
-0 . 2 74 3

希腊字母I' ( g amm a)是标的股票的价格


变化引起的 del t a的
变化率 。 它可以定义如下 。

r = ,a.ii. C 9- 1 9 )
as
为了实施有效的 del t a 对冲, 必须不断更新持有的标的股票的头寸, 因为 del t a与标的
股票的价格相关。 因此, 如果 g amm a值比较小, 就不必频 繁地改变持 有的标的股票的头 寸。
欧式看涨期权 (或看跌期权 ) 的 g amm a值 由如下公 式计算。

(
I' = N ' d1 ) ( 9-20)

s 6行
9. l l 期 权平价关 系 及其 图 形表 示 221

这里, N '(x) = e 2
1 工
o

9. 1 1 期 权平价关 系及其 图 形表示

让 我们看 一 个看涨 期权, 其 执行价格为 20 美元, 有效期为 3 个月 , 无风险利率为 5 %。


3 个月 以后的 20 美元的现值可以用以下 代码计算。

>>>x = 2 0 *exp ( - 0 . 0 5 * 3 / 1 2 )
>>>round ( x , 2 )

>>>
1 9 . 75

包括这个看涨期权和 1 9.75 美元 的投资组合在 3 个月 之 后的价值是多少 ? 如果股 票价


格低于 20 美元, 就不执行看涨期权和保 留 现金 。 如果股 票 价格高于 20 美元, 就 使用 20 美
元现金执行看涨期权来获得该标的股 票 。 因此, 我们的投资组合价值将是 3 个月 之 后的股
价或 20 美元这两 者中较大的一 个值, 即 max ( s , 2 0 ) 。

另 一方面, 包括股票和行使价为 20 美元的看跌期权的投资组合在 3 个 月 之 后的价值是


多少呢 ? 如果股票价格低于 20 美元, 我们行使看跌期权并获得 20 美元 。 如果股票价格在
20 美元以上, 我们只 保 留股 票 。 因此, 这 个投资组合价值 同样是 3 个 月 之 后的股价或 20
美元这两 者中较大的一 个值, 即 max ( s , 2 0 ) 。

因此, 以上两 个投资组合在 3 个月 之 后具有相同的价值 max ( s , 2 0 ) 。 根据无套利原


则 , 这两 个投资组合在当前的现值应该相等 。 我们称这个 关系为期权的平价 关系, 它 由以
下的公式表达。

C + Xe-ri = p + S 。 ( 9-2 1 )
T

如果 已知股票在到 期 日 之前将支付股 息 , 有以下等式 。

C + PV (D) + Xe- r1 = P + S 。 ( 9-22)


T

这里, PV(D)是在到期 日 ( T)之前支付的所有股 息 的现值 。 以下 Pytho n 代码给出了期


权平价 关系的图形表 示 。

import pylab as p l
222 第9章 B lack-Scholes-Merton 期 权 定 价 模 型

import numpy as np
x=lO
s T = np . arange ( 0 , 3 0 , 5 )
payo f f_c a l l = ( abs ( sT - x ) + sT- x ) /2
payof f_put = ( abs ( x - s T ) + x - s T ) / 2
cash = np . z e ros ( l en ( s T ) ) +x
de f graph ( t ext , text2= ' ' ) :
pl . x t i c k s ( ( ) )
p l . y七 i c ks ( ( ) )
p l . x l im ( O , 3 0 )
p l . ylim ( 0 , 2 0 )
pl . p l o t ( [ x , x ] , [ 0 , 3 ) )
p l . text ( x , -2 , " X " ) ;
pl . t e x t ( 0 , x , " X " )
p l . t e x t ( x , x * l . 7 , text , ha = ' center ' , va= ' center ' , s i z e = l O , a lpha = . 5 )
p l . text ( - 5 , 1 0 , text 2 , s i ze=2 5 )
pl . f i gure ( f i g s i ze = ( 6 , 4 ) )
p l . subplot ( 2 , 3 , l ) ; gr aph ( ' Payo f f of cal l ' ) ; pl . p l o t ( s T , payoff_ca l l )
p l . subp l o t ( 2 , 3 , 2 ) ; gr aph ( ' c as h ' , ' + ' ) ; pl . p l o t ( s T , c a s h )
pl . s ubpl ot ( 2 , 3 , 3 ) ; graph ( ' P o r f o l i o A ' , ' = ' ) ; pl . p l o t ( s T , cas h+payo f f
ca l l )
pl . subplot ( 2 , 3 , 4 ) ; graph ( ' Payo f f o f put ' ) ; pl . plot ( s T , payo f f_pu t )
p l . s ubplot ( 2 , 3 , 5 ) ; gr aph ( ' S t o ck ' , ' + ' ) ; p l . pl o t ( s T , s T )
pl . subp l o t ( 2 , 3 , 6 ) ; graph ( ' P o r 七 f o l i o B ' , ' ' ) ; p l . plot ( s T , s T+payo ff_pu t )
=

pl . s how ( )

产生的图形如图 9-11 所示 。

cash

图 9- 1 1
9. 1 2 二 叉 树 法 及其 图 形 表 示 223

9. 1 2 二 叉树法及 其 图 形表 示

二 叉树法 ( CRR 法 ) 是 由 Cox 、 ,Ross 和 Robinstein 在 1 979 年提 出 的 , 因 此也 被 称 为


CRR 方法。 使用 CRR 方法有 以 下 两 个 步 骤 。 首 先 , 画 一 个 树 叉 , 如 图 9- 1 2 所 示 。 假 设 当
前 的 股票价值是 s, 则 未 来 有 两 个 结 果 S*u 和 S*d, 其 中 u> l 和 d< l 0 下 面 的 代 码完成 图 9- 1 2

所示的仅 步的树叉。

import matplot l ib . pyplot a s p l t


p l t . x l im ( 0 , 1 )
plt . f i gtext ( 0 . 1 8 , 0 . 5 , ' S ' )
p l t . fi gtext ( 0 . 6 , 0 . 5 + 0 . 2 5 , ' S u ' )
p l t . f i gt e x t ( 0 . 6 , 0 . 5 - 0 . 2 5 , ' S d ' )
p l t . annotate ( ' ' , xy= ( 0 . 6 , 0 . 5+ 0 . 2 5 ) , xytext= ( 0 . 1 , 0 . 5 ) , ar rowprops =
dict ( facecolor= ' b ' , shr i n k=0 . 0 1 ) )
p l t . annotate ( ' ' , xy = ( 0 . 6 , 0 . 5 - 0 . 2 5 ) , xytext= ( 0 . 1 , 0 . 5 ) , ar rowprops =
dict ( facecolor= ' b ' , shrink=0 . 0 1 ) )
p l t . ax i s ( ' o f f ' )
p l t . show ( )

SU
s

Sd

图 9- 1 2


步 树 叉 显 然 是 最 简 单 的 二 叉 树法 。 假 设 今 天 的 价 格 是 1 0 美元 , 行 使 价 是 1 1 美 元 ,
看涨期权将在 6 个 月 后 到 期 。 此外 , 假 设 未 来 的 价格 只 有两 个 结 果 , 价格增加 ( u = 1 . 1 ) 或
减 小 ( d = 0.9 ) 。 换句 话 说 , 未 来 的 价格 是 1 1 美 元 或 9 美 元 。 基 千 这 样 的 信 息 , 有 图 9- 1 3

所示的 步二叉树。

图 9- 1 2 中 的 步 树叉 由 以 下 代 码 生 成 。

import networkx a s nx
import matplot l ib . pypl o t as p l t
224 第9章 Black-Scholes-Merton 期 权 定 价 模 型

p l t . f i gtext ( 0 . 0 8 , 0 . 6 , " S tock price = $ 2 0 " )


p l t . f i gtext ( 0 . 7 5 , 0 . 9 1 , " Stock p r i ce= $ 2 2 " )
p l t . f i gtext ( 0 . 7 5 , 0 . 8 7 , "0p t i on p r i ce=$ 1 " )
p l t . f i gtext ( 0 . 7 5 , 0 . 2 8 , "S tock price=$ 1 8 " )
p l t . f i gtext ( 0 . 7 5 , 0 . 2 4 , " 0ption p r ice= O " )
n=l
def bin omi a l_gr i d ( n ) :
G =nx . G raph ( )
for i i n r ange ( O , n + l ) :
for j i n range ( l , i + 2 ) :
i f i<n :
G . add_edge ( ( i , j ) , ( i + l , j ) )
G . add_edge ( ( i , j ) , ( i + 1 , j + 1 ) )
posG= { }
for node in G . nodes ( ) :
posG [ n ode ] = ( n ode [ O ] , n+2 +node [ O J - 2 * node [ l ] )
nx . draw ( G , pos=po sG)
'
b 1.nom1. a l g r id ( n )
plt . show ( )

图 9- 1 3


以 上 的 代码 定 义 了 个 b i n ornial_g r i d ( ) 函 数 , 本章将在后 面 多 次用 到 这 个 函 数 。

由 于事 先 知 道 未 来 只 有 两 个 结 果 , 所 以 可 以 选 择 个 股 票 和 看 涨 期 权 的 组合 使 得 该 组 合 的

未 来 结 果 是 我们所 需 的 。 假 设选择数量为 delta 的 标 的 股票 和 个 看 涨 期 权 在 未 来 具有相 同
-.
的 价值 , 也 就 是 , L1 X 1 1 .5- 1 =9L1, 即 L1= 1 /( 1 1 .5-9)=0.4 。 这 意 味 着 如 果 持 有 0.4 股和卖空
个 看涨 期 权 , 当 股价增加 时 , 这 个组 合 的 未 来价值等牛 0.4 X 1 1 .5- 1 =3.6 , 或者 当 股 价 减 小

时 , 其 未 来 价值 也 等 于 0.4 X 9=3 .6。 进 步 假 设 连续复利 的 无风 险 价 值 是 0. 1 2% , 那 么 投 资
组 合 的 价值将等于未来值 3.6 在 今 天 的 现 值 , 即 0.4 X 1 0-c=pv 0.6 ) 。 使用 Python 可 以 得
到 以下结果 。
9. 1 2 二 叉 树法及其 图 形表 示 225

>>> round ( 0 . 4 * 1 0 -exp ( - 0 . 0 1 2 * 0 . 5 ) * 3 . 6 , 2 )


0 . 42

用以下 代码构建两 步二叉树。



import p 4 f
import ma tpl o t l i b . pyplot as plt
plt . f i gtext ( 0 . 0 8 , 0 . 6 , " S tock p r i c e = $ 2 0 " )
plt . figtext ( 0 . 0 8 , 0 . 5 6 , " ca l l =7 . 4 3 " )
pl t . figtext ( 0 . 3 3 , 0 . 7 6 , " S 七ock pr ice = $ 6 7 . 4 9 " )
plt . f i g七ext ( 0 . 3 3 , 0 . 7 0 , "0ption p r i c e = 0 . 9 3 " )
pl t . f i g七ext ( 0 . 3 3 , 0 . 2 7 , " S tock p r i c e = $ 3 7 . 4 0 " )
pl t . fi gtext ( 0 . 3 3 , 0 . 2 3 , "0ption price = l 4 . 9 6 " )
plt . f i gtext ( 0 . 7 5 , 0 . 9 1 , " S tock price = $ 9 1 . l l " )
p l t . figtext ( 0 . 7 5 , 0 . 8 7 , "0ption price = O " )
plt . f i gtext ( 0 . 7 5 , 0 . 6 , " S t o c k p r i c e = $ 5 0 " )
p l t . fi gtext ( 0 . 7 5 , 0 . 5 7 , " 0pt i on p r i c e = 2 " )
pl t . fi gtext ( 0 . 7 5 , 0 . 2 8 , " S 七o c k price = $ 2 7 . 4 4 " )
plt . f i gtext ( 0 . 7 5 , 0 . 2 4 , "0ption p r i ce=2 4 . 5 6 " )
n =2
p 4 f . b inomi a l_g r i d ( n )
p l t . show ( )

基于CRR 方法, 我们有以下步 骤 。

1 . 绘制一 个 n 步树。

2. 计算在第 n 步 结束时股票 的价格。

3. 基 千 最终 股 票 价格以及是否执行看 涨 期权或 看 跌 期权来计算每 个节点上 的期权


的价值 。
4 . 根据风险中性概 率 , 将其 从 第 n 步折现到第 n -1 步。

5. 重复上 一 步 骤 , 直到在第 0 步 获得期权的 当前价值 。


用于 计算 u、 d 和 p 的公式如下 。
er£
u=e ( 9-23)
1
d=-=e
-a£
( 9-24 )
u
(r-q)6J
a=e ( 9-25 )
226 第9章 B lack-Scholes-Merton 期 权 定 价 模 型

a-d
p= C 9-26 )
u-d
V; = p凡 + (1 - p) v� l 十
( 9-27 )

在 公 式 中 , u 是价格 增 加 的 幅 度 , d 是价格减小 的 幅 度 , 6 是 标 的 股 票 的波动率 , r 是


无风险 利 率 , T 是 以年 为 单 位 的 有 效 期 , n 是 步 数 , M 是 每 一 步 的 时 间 长度 , 即 b.t =Tin 。 q
是 股 息 收 益 率 , p 是价格增 加 的 风 险 中 性 概率 。 区 n orni a l_gr i d ( ) 函 数 是基于 一 步 二 叉
树 图 形 的 函 数 。 我们之前提 到 这 个 函 数包含在 p 4 f y . py 文件 中 。 使 用 一 个两 步二 叉树来
演 示 定 价 的 整 个 过程 。 假 设 当 前 股 票 价 格 为 1 0 美 元 , 行 使 价 为 1 0 美 元 , 有 效 期 为 3 个 月 ,
步 数 为 2 , 无风 险 利 率 为 2% , 标 的 股票 的 波 动 率 为 0.2 。 以 下 Python 代码将 生 成 一 个 两 步
树 , 代 码 的 输 出 如 图 9- 1 4 所 示 。

import p 4 f
f rom math import sqr t , e xp
impor t matplot l ib . pyplot as p l t
s = l 0 ; r=0 . 0 2 ; s i gma=0 . 2 ; T= 3 . / 1 2 ; x= l 0
n=2 ; de l t aT=T /n ; q= O
u = exp ( s i gma * s qr t (del 七 aT ) ) ; d= l /u
a = exp ( ( r - q ) *deltaT)
p = ( a -d ) / ( u-d )
su=round ( s * u , 2 ) ;
suu = round ( s * u * u , 2 )
sd= round ( s * d, 2 ) ;
sdd= round ( s *d*d, 2 )
sud= s
p l t . f i gtext ( 0 . 0 8 , 0 . 6 , ' S tock ' +s tr ( s ) )
p l t . f i gtext ( 0 . 3 3 , 0 . 7 6 , " S tock price = $ " + s t r ( su ) )
p l t . f igtext ( 0 . 3 3 , 0 . 2 7 , ' Stock p ri ce= ' + s t r ( sd) )
plt . figtext ( 0 . 7 5 , 0 . 9 1 , ' S tock p r i ce = $ ' + s tr ( s uu ) )
p l t . figtext ( 0 . 7 5 , 0 . 6 , ' S tock p r i c e = $ ' + s t r ( sud) )
p l t . figtext ( 0 . 7 5 , 0 . 2 8 , " S t ock p r i ce = " + s t r ( sdd) )
p 4 f . binomial_grid ( n )
p l t . s how ( )

9. 1 2 二 叉树法及其 图 形 表 示 227

Stock price=Sll.5

Stock price=Sl0.73

Stock 10

图 9- 1 4

接 下 来, 用风险中性 概 率 把每 个值逐步向后折现 。 相应的代码如下, 生成 的图形如


图 9-1 5 所 示 。

impor七 p 4 f
f r om numpy imp o r t exp , sqrt , l o g
import matplo t l i b . pyp l o t as p l t
s = l O ; x = l O ; r=0 . 05 ; s i gma=0 . 2 ; T=3 . / 1 2 . ; n=2 ; q= O # q i s dividend y i e l d
de l t aT = T / n # s tep
u =exp ( s i gma* sqrt ( de l 七 aT ) )
d= l/ u
a = exp ( ( r-q) * de l ta T )
p = ( a-d) / ( u- d )
s_d ol l a r = ' S = $ '
c_do l l a r = ' c = $ '
p2 = round ( p , 2 )
p l t . figtext ( 0 . 1 5 , 0 . 9 1 , ' No t e : x = ' + s t r ( x ) + ' , r = ' +s t r ( r ) + ' , de l 七aT = ' + s 七 工
( de l taT ) + ' , p= ' + str ( p2 ) )
plt . f igtext ( 0 . 3 5 , 0 . 6 1 , ' p ' )
p l t . f ig七ex七 ( 0 . 6 5 , 0 . 7 6 , ' p ' )
plt . f igtext ( 0 . 6 5 , 0 . 4 3 , ' p ' )
p l t . f i gtext ( 0 . 3 5 , 0 . 3 6 , ' 1 -p ' )
pl t . f i gtext ( 0 . 6 5 , 0 . 5 3 , ' 1 -p ' )
p l t . figtex七 ( 0 . 65 , 0 . 2 1 , ' 1 -p ' )
# at level 2
su=round ( s * u , 2 ) ;
suu=round ( s * u * u , 2 )
sd= round ( s * d , 2 ) ;
sdd=round ( s * d*d, 2 )
sud=s
c suu=round (max ( suu-x , 0 ) , 2 )
c_s =round ( max ( s-x , O ) , 2 )
228 第9章 Black-Scholes-Merton 期 权 定 价模 型

c_sdd=round (max ( sdd- x , 0 ) , 2 )


plt . figtext ( 0 . 8 , 0 . 9 4 , ' s *u* u ' )
plt . figtext ( 0 . 8 , 0 . 9 1 , s_do l l a r + s t r ( s uu) )
p l 七 . f i g 七 e x t ( 0 . 8 , 0 . 8 7 , c_dol l a r + s t r ( c_suu ) )
plt . f i gtext ( O . B , 0 . 6 , s_do l l a r + s t r ( sud) )
p l t . figtext ( 0 . 8 , 0 . 6 4 , ' s * u * d= s ' )
plt . f i gtext ( 0 . 8 , 0 . 5 7 , c_do l l a r + s t r ( c_s ) )
p l t . figtext ( 0 . 8 , 0 . 3 2 , ' s *d* d ' )
p l t . f igtext ( 0 . 8 , 0 . 2 8 , s_do l l a r + s t r ( sdd) )
p l t . f i g t e x t ( 0 . 8 , 0 . 2 4 , c_dol l a r + s t r ( c_sdd) )

# at l ev e l 1
c_O l=round ( ( p * c_suu+ ( l -p) * c_s ) * e xp ( - r * de l ta T ) , 2 )
c_0 2 = round ( ( p * c_s+ ( 1 -p) * c_sdd) * e xp ( - r * de l t aT) , 2 )

p l t . f i g t e xt ( 0 . 4 3 , 0 . 7 8 , ' s * u ' )
p l t . f i g t e x t ( 0 . 4 3 , 0 . 7 4 , s_do l l a r + s t r ( s u ) )
p l t . f i g t e x t ( 0 . 4 3 , 0 . 7 1 , c_do l l ar + s 七 r ( c_O l ) )
plt . figtext ( 0 . 4 3 , 0 . 3 2 , ' s * d ' )
p l t . figtext ( 0 . 4 3 , 0 . 2 7 , s_do l l a r + s t r ( s d) )
p l t . f i g t e x t ( 0 . 4 3 , 0 . 2 3 , c_do l l a r + s t r ( c_02 ) )
# at level O ( today)

c O O = round (p* exp ( - r *de l taT ) * c 0 1 + ( 1 - p ) * e xp ( - r * d e l t aT ) * c 02 , 2 )
pH . f i g 七 e x 七 ( 0 . 0 9 , 0 . 6 , s_do l l a r + s t r ( s ) )
p l t . f i g t e x t ( 0 . 0 9 , 0 . 5 6 , c_do l l a r + s 七 r ( c_O O ) )
p4 f . b inomia l_grid ( n )
p l t . show ( )

Note. x=lO, r=0.05, deltaT=0. 125,p=0.53 拦牡1.52


c-=$1.52

图 9- 1 5

解释 一 下 图 9- 1 5 中显示的几个值 。 在右上 角 的最高节点 ( s*u*u ) , 股票 价格为 1 1 .5 2 ,


9. 1 2 二 叉树法及其 图形表示 229

行使价格为 1 0 , 因 此看 涨 期 权 的 价 值 为 1 . 52 ( 1 1 . 52- 1 0 ) 。 类似地 , 在 s *u*d=s 节 点 上 , 看


涨 期 权 的 价 值 为 0 。 以 下 代码验证在 s*u 节 点 上 看 涨 期 权 的价 值 为 0.8 。

>>>p
0 . 5 2 6 62 5 3 3 9 0 0 6 8 3 6 2 \
>>>de ltaT
0 . 12 5
>>>v= ( p* l . 52 + ( 1 - p ) * O ) * exp ( - r *de l t a T )
>>> round ( v , 2 )
0 . 80
>>>

9. 12.1 为欧式期权定价的二叉树法

以 下 代码编写 个 函 数 bi nom i a l Ca l l ( ) 来 用 二叉树法 为 欧 式期权 定 价 。

from math impo rt exp, s qrt


import s c ipy as sp
de f bi nomi alCall ( s , x , T , r , s i gma , n= l O O ) :
deltaT = T / n
u = exp ( s i gma * sqrt ( de l t aT ) )
ct = 1 . 0 I u
a = exp ( r * deltaT)
p = (a - d) / (u - d)
v = [ ( 0 . 0 f o r j in sp . arange ( i + 1 ) ) f o r i in sp . arange ( n + 1 ) )
for j in sp . a r ange ( n+ l ) :
v [ n ] [ j ) = max ( s * u * * j * d * * ( n - j ) - x , 0 . 0 )
for i in sp . arange ( n- 1 , - 1 , - 1 ) :
for j in sp . a range ( i + 1 ) :
v [ i ) [ j ) =exp ( - r * de l t aT ) * ( p * v [ i +l ) [ j + l ] + ( l . 0 -p) *v [ i + l ) [ j ) )
return v [ O ] [ O J

以 下 输 入 一 组 参 数 值 来 调 用 该 函 数 , 同 时 计 算 Black-Scholes-Merton 模 型给 出 的 期 权 价
格作为 比 较 。

>>> binomia1Ca l l ( 4 0 , 4 2 , 0 . 5 , 0 . 1 , 0 . 2 , 1 0 0 0 )
2 . 2 7 8 1 94 4 0 4 57 3 1 3 4 2
>>>bs_cal l ( 4 0 , 4 2 , 0 . S , 0 . 1 , 0 . 2 )
2 . 2777803294555348
>>>

9. 12.2 为美式期权定价的二叉树法
230 第9章 Black-Scholes-Merton 期 权 定价模 型

Black-Scholes-Merton 期权 模 型 只 能应用 于 欧 式 期 权 。 二 叉 树 C CRR ) 方法可 以 用 来 计


算 美式 期 权 的 价 格 。 与 美式 期 权 不 同 的 是 , 必 须 考 虑 提 前行 使 期 权 。 使 用 二 叉树法为美式
期 权 定 价 的 代码 如 下 。

fr om math import exp, sqrt


import numpy as np
de f binomialCallAme ri can ( s , x , T , r , s i gma , n= l O O ) :
de l ta T = T /n
u = e xp ( s i gma * sqrt ( de l 七 aT ) ) ; d = 1.0 / u
a = exp ( r * del taT ) ; p = ( a - d) / ( u - d)
v = [ [ 0 . 0 for j in np . a range ( i + 1 ) ] for i in np . a range ( n + 1 ) ]
for j i n np . a range ( n + l ) :
v [ n ] [ j ] = max ( s * u * * j * d * * ( n - j ) - x , 0 . 0 )
for i in np . ar ange ( n- 1 , - 1 , - 1 ) :
f o r j in np . ar ange ( i + 1 ) :
vl=exp ( - r * de l taT ) * ( p * v [ i + l ] [ j + 1 ] + ( 1 . 0-p) *v [ i + l ] [ j ] )
v2=max (x- s , O ) # e a r l y e x e r c i s e
v [ i ] [ j ] =max ( vl , v2 )
return v [ O ] [ O J

美式看涨期权和 欧式看涨 期 权 的 关 键 区 别 在 千 可 以 提 前 行 权 。 以 上代码 的 最 后 几 行 反



映了这 点 。 在 每个 中 间 节 点 , 需 要 计 算 两 个值 , v1 是 未 来 收 益 的 贴现值 , v2 是提前行权
所 获 得 的 收 益 。 我们选择两者之 中 较 大 的 值 , 即 max ( vl , v2 ) 。 以 下代码应 用 二 叉 树方
法来计算美式看 涨 期 权 的 价 格 。 显然 , 使用 相 同 的 参 数 值 , 美 式 看 涨 期 权 的 价 格 高 于 欧 式
看 涨期 权 的 价 格 。

>>>c a l l =binorni a1Cal1Arne r i c an ( 4 0 , 4 2 , 0 . 5 , 0 . l , 0 . 2 , 1 0 0 0 )


>>> round ( ca l l , 2 )
3 . 41

9. 1 3 套期保值策 略

卖 出 欧 式 看 涨 期 权后 , 可 以 持 有 数 量 为 4 的 标 的 股 票 来 对 冲 看 涨 期 权 空 头 的 风 险 。 这
个 策 略 称 为 delta 对冲 。 由 于 delta ( L1 ) 是 标 的 股 票 的 价 格 C S ) 的 函 数 , 为 了 保 证 有 效
的 对 冲 , 我们 必 须 不 断 调 整 股 票 的 持仓 量 , 因 而 称 为 动 态套 期 保 值 。 投 资 组 合 的 delta 是

投 资 组 合 中 各 个 证券 的 delta 的 加 权平 均 。 需 要 注 意 的 是 , 如 果 卖 空 只 证 券 , 其权重将
为负。
9. 1 4 小结 231

.1port = L卫 ( 9-28)
i=I

假 设某美国进 口 商将在 3 个月 后 支付 1 000 万 英镑 。 他担心美 元对英镑将贬值。 有 3


种方法来对冲这 个汇 率风险:现在买入英镑、签订 期货合约 以指定汇率在3个月 后买入 I 000
万 英镑, 或者购买以指定汇 率作为其 行使价的看涨期权。 第 1 选择是 昂 贵 的, 因为进 口 商
今天不需要英镑 。 第 2 选择签订 期货合约也是有风险的, 因为美元升值将 使进口 商 花费额
外的钱 。 第 3选择购买看涨期权可以在今天锁定 3 个月 后 的最高汇 率 。 同时, 如果英镑贬
值, 进 口 商 还可获利 。 这种在不同的证券采取相反的头寸被称为套期保值 。 对千货币 期权,
有以下等式 。


In S
(叶 r r
(d- l 勹叶
1
C 9-29 )
6行
di =

m ( �} ( 片
- rf + ½ 叶
d, = 丑 行 ( 9-30)
6行
- (J'

c = S X N( dl ) - X X e-rT N( d2 )
。 C 9-31 )

p = X x e-rT N(-心 - S x N(-心 。 ( 9-32 )

公式中, & 是外 币 的美元汇率, rd 是国内的无风险利 率, r1是外 币 的无风险利 率 。

9. 1 4 小结

本章详细 讨论了 B al c k - Sch oel s-Me rton 期权模型, 主 要内容包括看 涨期权和看跌期权的


收益 和损益函数及其 图形表示; 各种交易策略及其 图形表示, 比如卖 空 看 涨 期权并持有股
票、 跨式 期权组合、 蝶式 期权组合、 日 历套利组合; 正 态分布、 标 准 正 态分布 和 累 积分布
函数; de t
l a、 g a mma 和 其他希 腊 字 母 ; 期权的平价关系; 欧式与美式 期权; 用二叉树法来
给期权定价和套期保值策 略 ; 等等 。

下一 章将介绍 P yth on 的几种循环语句, 然后解释 如何计算看涨期权和 看跌期权的隐含


波动率 。 另外, 介绍如何从 几 个公开的网站下载期权的交易数据, 并用这些数据来计算隐
含波动率, 及其他一 些应用。
232 第 9 章 Black-Scholes-Merton 期 权定价模 型

练习题

1 . 欧式看涨期权与美式看涨期权之 间有什么 区 别 ?
2 . B lac k - Sc h oel s-M ert on 期权模型中无风险利率 YJ的单位是多少?

3. 如果无风险年利率为 3.4%, 每 半年复利 一 次, 那么 B al c k - Sc h oel s-Mert on 期权模 型


中使用的 YJ值应该是多少 ?
4 . 如何使用期权套期保值 ?

5 . 对欧式看涨期权进行定价时, 如何处理预先确定的现金股利 ?

6 . 为什 么美式 看涨期权比欧式看涨期权更值钱 ?

7 . 假设你是 共 同 基金经理, 你的投资组合与 市场密切相关。 你 担心市场短期内会下跌,


你 可以做些 什 么 来保护你的投资组合 ?
8. 股票 A 的当前价格为 38.5 美元, 看涨期权和 看跌期权的行使价均为 37 美元。 如果
连续复利无风险利率为 3.2%, 期权有效期为 6 个月 , 股票 A 的波动率为 0.2 5 , 欧式看涨期
权和看跌期权的价格分 别 是多少 ?
9 . 使用期权的平价关系来验证上 题的答案。

10. 如果等式 ( 9-11 )中的看涨期权和看跌期权有 不 同 的行使价, 期权的平价关系还


成立吗 ?
11 . 给定 一组 参数 值 , S =4 0, X = 4 0, t =3/1 2=0.25 , r = 0.05 和 sigma =0.20 , 使用
B al c k - Sc h ole s-M ert on 期权模型来计算这个看涨期权的价格。 保持其他参数值 不
变, 调整 S
(股票的当前价格) 来显示看涨期权的价格和 S 之 间 的关系(绘制图形更好)。

12 . 我的投资组合包括: 标的股票多头 、 欧式看涨期权多头 。 假设当前股票价格为 40 美


元 欧式看涨期权的行使价格为 45 美元, 编写 Pyth on 代码显示此投资组合的收益函数曲线。

13. 看跌期权构成的牛市多空套利 : 买入执行价格为 凡 的看跌期权, 卖出执行价格为


。 由千 K1 <K2 , 所购买的看跌期权比卖出的看跌期权价值低, 牛市多
凡 的看跌期权 ( K1 <K2 )
空套利有初始现金流入。 编写 Python 代码计算投 资组合的收益函数和损益函数, 并绘制图形。

1 4 . 看跌期权构成的熊 市多空套利 : 投资 者预计股价将下跌。 买入执行价格为 反 的看


跌期权, 卖出执行价格为 K1 的看跌期权 C K 1 <K2 )。 由于 K1 <K2 , 所购买的看跌期权比卖出
的看跌期权价值高, 熊 市多空套利有初始现金流出。 编写 Pyth on 代码计算投资组合 的收益
练习题 233

函数和损 益函数, 并绘制图形。

15. 蝶式多空套利: 买入执行价格分别为 凡 和 K3 的看涨 期权, 卖出两 个执行价格为


伦 的 看涨 期权, K2 = 0.S ( Ki +K3 ) 。

( I) 证明此策略有初始现金流出, 即证明 C1 +C3>2C2 。 你的投资组合包括 C1 和 C3 的


多头, 两 个 Q 的空头。

( 2)编写 Pytho n 代码计算这个策 略 的 损 益函数。


16 . 你有以下投资组合: 100 股标的股票的多头, 77股看涨 期权的空头, 88 股看跌 期
权的多头。 假 设 当前股价是 4 0 美元, 看 涨 期权的行使价为 4 5 美元, 看跌 期权的行使价为
38美元。
( 1 )写出你的投 资组合的收益函数。
( 2)假设看涨 期权和看跌 期权的 期权费分别为 3美元和 4 美元, 写出你 的投资组合的
损 益函数。

( 3)编写 Pytho n 代码完成以上计算。


1 7. 如果 我们以相同 的行使价买入两 个看跌 期权和一 个看涨 期权, 这 个策 略 称 为 St
ri ps
策略。 编写 Pyt
ho n 代码来显示它的损益函数 。
18. 如果 我们以相同的行使价买入一 个看跌 期权和两 个看涨 期权, 这 个策略称为 St r a p
策略。
(I) 这 个策略的 期望收益是多少?
(2) 编写代码来显示其 损 益 图。
19 . 编写 Pytho n 代码绘制图形来显示欧式不分红股票的 看 涨 期权的 delta C y 轴) 与该
标的股票 的价格 ( x 轴) 的 关系。
目前的股票价格为 30 美元, 行使价格为 30 美元, 无风险利率为每年 6%, 每 半年
20 .
复利, 波动率为每年 25%, 有效期为 4 个月 , 标 的 股票 将 在一 个月和 5 个月 末分别 支付 l
美元股息。 欧式看涨 期权和看 跌 期权的 价格分别是多少 ?

21 . 有以下 代码来展示一 步 二 叉树。

impo rt p 4 f
import matpl o t l ib . pyp l o t a s p l t
pl t . f i gtext ( 0 . 0 8 , 0 . 6 , " S tock p r i c e= $2 0 " )
pl t . f igtext ( 0 . 0 8 , 0 . 5 6 , " cal 1 = 7 . 4 3 " )
p l t . figtext ( 0 . 3 3 , 0 . 7 6 , " S t o c k price=$ 67 . 4 9 " )
234 第9章 B lack-Scholes-Merton 期 权 定 价 模 型

p l t . figtext ( 0 . 3 3 , 0 . 7 0 , "0ption p r i c e = 0 . 9 3 " )


p l t . figtext ( 0 . 3 3 , 0 . 2 7 , " S t o c k p r i c e = $ 3 7 . 4 0 " )
p l t . f i gt e x 七 ( 0 . 3 3 , 0 . 2 3 , "0ption p r i ce = l 4 . 9 6 " )
p l t . f i gtext ( 0 . 7 5 , 0 . 9 1 , " S t o c k p r i c e = $ 9 1 . l l " )
plt . f i gtext ( 0 . 7 5 , 0 . 8 7 , " 0pti o n p r i c e=O " )
p l t . f igtext ( 0 . 7 5 , 0 . 6 , " S t o c k p r i c e = $ 5 0 " )
p l t . f i g t e x t ( 0 . 7 5 , 0 . 57 , "0p t i on p r i c e = 2 " )
p l t . f i gtex 七 ( 0 . 7 5 , 0 . 2 8 , " S to c k p r i c e = $ 2 7 . 4 4 " )
p l t . figtext ( 0 . 7 5 , 0 . 2 4 , " 0p t i on p r i c e = 2 4 . 5 6 " )
n = 2 ; p4 f . binomia l_gr id ( n )

以下是其 相关图形。
Stock price=S91.ll
Option pnce=O

Stock price=S67 .49

按照以下的示例来
简化之前的代码 。

imp o r t p 4 f
p l 七 . f i g t e x t ( " S t o c k p r i c e= $ 2 0 " )
p l t . f i gtext ( " ca l l = 7 . 4 3 " )
p l t . f i g t e x七 ( " S 七o c k p r i c e=$ 6 7 . 4 9 " )
plt . f igtext ( "Opt i o n p r i c e = 0 . 93 " )
plt . f i gtext ( " Stock p r i c e = $ 37 . 4 0 " )
pl 七 . fi g t e x t ( "Op 七 ion p r i c e = l 4 . 9 6 " )
p l t . f i gtext ( " S tock p r i c e = $ 9 1 . l l " )
p l t . f i gtext ( " Opt i on p r i c e = O " )
plt . f i g t e x t ( " Stock p r i c e=$ 5 0 " )
p l t . figtext ( " Opti on p r i c e = 2 " ) ,
p l t . figtext ( " S tock p r i c e = $ 2 7 . 4 4 " )
p l t . f i gtext ( " Op 七 i on p r i c e = 2 4 . 5 6 " )
n = 2 ; p 4 f . bi nomial_gr id ( n )

22 . 编写 Python 代码来绘制 一 个三步二叉树的图形表示 。


第 10 章

Pyt hon 的循环 语句 和 隐含
波 动 率 的 计算

本章主要内容 涉及两个主题: Pyth on 的循环语句和隐含波动率的计算。 Pyth on 有两个


最常用的循环语句: f o r 循环和 while 循环。 将介绍隐含波动率的定义及其 背 后的逻辑,
然后讨论 3种计算隐含波动率的方法, 分别 基于 fo r 循环、 w hiel 循环和二分搜索 。 二分搜
索是其 中最有效的方法。 应用二分搜索方法的一个前提条 件是 目标函数单调 递增或递减,
而 期权价格恰恰是波动率的递增函数。 本章
包括以下主要内容 。

• 什么是隐含波动率

• 隐含波动率计算的逻辑

• 理解 for 循环、 whi l e 循环及其 应用

• 嵌套 (多重) 循环

• 多个 I RR 的估计
• 二分搜索方法的原理

• 计算美式看涨期权的隐含波动率

• enurne ra七e ( )函数简介

• 从 Y ah oo!Fi n ance 和芝加哥期权交易所获取期权数据

• 以图形表示看跌期权和看涨期权的比率
236 第 1 0 章 Python 的 循 环 语 句 和 隐含 波 动 率 的 计 算

1 0. 1 隐含波动率的定义

在第 9 章 中 , 我们了解到给定 一 组输入参数 s ( 当前股票 价格)、X ( 执行价格)、 T C 以


年为单位的有效期)、 r( 连续 复利的无风险利率) 和 sig ma( 股票回 报率的标准方差, 也称
为波动率) 可以利用 B al c k - Schoel s-Mert on 模型来计算看涨期权的价格。 可以用以下 5 行
Python 代码来为欧式看涨期权定价。

from scipy import l og , exp, s qr t , s tats


def b s_cal l ( S , X , T , r , s i gma ) :
dl= ( l og ( S /X) + ( r+s igma * s i gma / 2 . ) * T ) / ( s i gma* sqrt ( T ) )
d2 = d l - s i gma* s qr t ( T )
return S* sta 七 s . norm . cdf ( d l ) -X*exp ( -r * T ) * s tats . norm . cdf (d2 )

输入一 组 5 个值 后, 可以得到看涨期权的价格如下。

>>>bs call ( 4 0 , 4 0 , 0 . 5 , 0 . 0 5 , 0 . 2 5 )
3 . 30400172 84767735

另 一 方面, 如果知道 S、 X、 T、 r 和期权价格 C, 我们如何得到相对应的 sig ma? 我们


称这 个对应的 sig ma为隐含波动率 。 也就是说, 如果给出一 组 可以观察到的数值, 如 S= 4 0 、
X= 4 0 、 T= O . 5、 r= 0 . 0 5 和 c =3 . 3 0 , 就能够找出 s i gma 应该等于 0.25。 将在本章学习如
何计算隐含波动率。

实际上 , 找出隐含波动率是基千 一 个非常简单的逻辑: 试错法。 以上面的数值作为例


子。 有 5 个值 S =4 0、 X =4 0、 T =0.5、 r =0.05 和 C =3.30。 用 100 个不 同的 sig ma值, 加上
另 外 4 个参数值, 可以得到 100 个看涨期权的价格。 隐含波动率的一 个估计值是这 J OO 个
sig ma 值中使得看涨期权的价格与给定的期权价格 3.30 之 间的绝 对差 值最小的那 一 个。 当
然, 可以增 加更多的 sig ma 值, 以得到更高精度的隐含波动率的估计值 , 也就是说 精确到
小数点后更多位 。

或者可以采用另 一 个收敛标准 : 当计算得到的看涨 期权价格和给定看涨期权价格之间


的绝对差值 小 于 我们 自 定的一 个临界值, 比如 1 分钱, 即 lc-3.301<0.0 1 时, 就停止计算。
因为随机选取 1 00或 l 000 个不同的 sig ma值并不是最优的办法, 可以使用循环语句来有系
统地选择一 些 sig ma值。 接下来, 将 讨论两 类循环语句: fo r 循环和 w hile 循环 。
1 0.2 for 循 环 简介 237

1 0.2 for 循环简介

fo r 循环是许多计算机语言中最常见的循环之 一 。 图 1 0- 1 中的
流程图演示 了循环 语句如何工作。 通常从 一 个初始值开始测试循环
变量是否满足某 个条件, 如果条件不成立, 则循环停止 ; 当 条件成
立时, 执行一组命令, 改
变循环变量的值并再次测试该条件。

下面给出 一 个
简单的例子。

> > > for i i n range ( l , 5 ) :


print ( i )

运行这两 行命 令的结果是打 印 1 、 2 、3 和 4 。 需要注意 range()


函数的用法, 因为最后 一 个数字 5 不会打 印出来。 因此, 如果要打
印 J � n, 就必须 使用以下 代码。
图 I 0- 1

>>>n = l O
> > > fo r i i n range ( l , n+ l ) :
print ( i )

在以上 两 个示例中, 默认 增量值为 1 。 如果打算使用不等于 1 的增量值, 就需要 明 确


指定。 以下 代码中的增量值等千 3。

>>> for i i n range ( 1 , 1 0 , 3 ) :


print ( i )

得到的输出结果是 1 、 4 和 7。 同样, 如果要按 降序打 印 5 到 1 , 则增量值应为- 1 。

> > > f o r j in range ( S , 1 , - 1 ) :


print ( j )

10.2.1 使用 for 循环计算隐含波动率

首先, 用下面的代码编写 一 个 Python函数来根据 Black-Scholes-Merton 模 型计算看涨


期权的价格。

f r om s c ipy imp o r t l o g , exp, sqr t , s t ats


de f bs_ca l l ( S , X , T , r , s igma ) :
238 第 10 章 Python 的 循 环 语 句 和 隐 含 波 动 率 的 计 算

" " " Ob j ect ive : e s t imate c a l l for stock w i 七h one known dividend
S : current s tock p r i c e
T : maturi t y date i n y e a r s r : r i s k - f re e rate
s i gma : vo l a t i l i t y

dl= ( l og ( S /X ) + ( r+ s igma * s igma /2 . ) * T ) / ( s igma * sqrt ( T ) )


d2 = d l - s i gma * s qrt ( T )
return S * s t ats . norm . cd f ( d l ) -X* exp ( - r * T ) * s tats . norm . cd f ( d2 )
5=4 0 ; K=4 0 ; T=0 . 5 ; r=0 . 0 5 ; c=3 . 3 0
for i in range ( 2 0 0 ) :
s i gma= O . O O S * ( i + l )
d i ff=c-bs_cal l ( S , K , T , r , s igma )
i f abs ( d i f f ) <=0 . 0 1 :
pri nt ( i , s i gma , d i f f )


可 以 把 b s c a l l ( ) 函 数 放 在 个 主 程 序 文 件 ( 如 p 4 f . py ) 中 。 这 样 , 更 便 于 调 用 该
函 数 , 也使代码 更 简 单 易 懂 。 例 如 :

import p 4 f
S=4 0 ; K=4 0 ; T=0 . 5 ; r= 0 . 0 5 ; c=3 . 3 0
for i in range ( 2 0 0 ) :
s i gma=0 . 0 0 5 * ( i+ l )
d i f f=c-p4 f . bs_cal l ( S , K , T , r , s igma )
i f abs ( d i f f ) <=0 . 0 1 :
p r i n t ( i , s i gma , di f f )

一 一
以 上 的 代码使用 与 前 个示例相 同 的 组 参 数 值 , 因 此 隐 含 波 动 率 应 当 是一样 的 , 即
0.25 。 这 个 程 序 的 逻 辑 是 使 用 试 错 法 来 为 Black-Scholes-Merton 期 权 模型提供许 多 不 同 的
sigma ( 波动 率 ) 。 对 于 给 定 的 一 个 sigma 值 , 如 果 计 算 得 到 的 看涨 期 权价格和给 定 的 看涨
期权价格之 间 的 绝对 差值 小 于 0. 0 1 , 就停止计 算 。 那 个 sigma 值 就 是 隐含 波 动 率 。 以上程
序的输 出 结 果 如 下 。

( 4 9 , 0 . 2 5 , - 0 . 0 0 40 0 607 9737 2 8 8 2 8 1 7 )

第 l 个数字 4 9 是 变 量 i 在 程 序 结 束 时 的 值 , 0 . 2 5 是 隐 含波动率 , 最 后 一 个数值是计


算得到 的 看涨 期 权 价 格和 给 定 的看涨期权价格 ( 即 3 .30 美 元 ) 之 间 的绝对差值 。

10.2.2 欧式期权的隐含波动率

最后 , 可 以 编写 个 函 数 来 估 计 基 于 欧 式 看 涨 期 权 的 隐含波动 率 。 为 了 节 省 空 间 , 从
程序 中 删 除 所 有注 释 。
1 0.2 for 循 环 简 介 239

de f imp l i ed_vol_cal l ( S , X , T , r , c ) :
f r om s cipy import log , exp , sqrt , stats
for i i n range ( 2 0 0 ) :
s igma=O . O O S * ( i+ l )
dl= ( l og ( S / X ) + ( r + s i g�a * s i gma / 2 . ) * T ) / ( s i gma * sqrt ( T ) )
d2 = dl - s i gma * sqrt ( T )
di f f=c 一 ( S * stats . norm . cdf ( d l ) - X * exp ( - r * T ) * s tats . norm . cdf ( d2 ) )
i f abs ( d i f f ) <=0 . 0 1 :
return i , s igma , di f f

使用 一 组输入值, 可以方便地使用以上代码, 如 下 所 示 。

>>>imp l i ed_vol_cal l ( 4 0 , 4 0 , 0 . 5 , 0 . 0 5 , 3 . 3 )
( 4 9 , 0 . 2 5 , - 0 . 0 0 4 0 0 6 0 7 9 7 37 2 8 8 2 8 1 7 )

10.2.3 看跌期权的隐含波动率
可以基于期权模型估计欧式看跌期权的隐含波动 率 。 在以下的程序中 , 编写 一个 名 为
imp 辽 e d_vo l_put_m i n ( ) 的函数。 这个 函数和前

节的函数有几 点 区 别 。 首先,这个函
数计算看跌期权的隐含波动率, 而 不 是 看 涨期权的隐含波动 率 。 因 此, 最后 一个输入值是
看跌期权的价格, 而 不 是看涨期权的价格。 其次, 收敛标准是估 计的期权价格和给定的看
跌期权价格的绝对价差最小 。 在前 一 节的函数中 , 收敛标准是 当绝对价差 小 于 0.01 时 。 因

此 , 这个函数将保证 一 定 可以得到 个隐含波动 率的估计值, 而 前 一 节的函数不 能保证。

def impl ied_vol_put_min ( S , X , T , r , p ) :


f r om s c ipy i mp o r t log , exp , sqrt , stats
imp l i e d_vo l = l . 0 ; min_value = l 0 0 . 0
for i in x range ( l , 1 0 0 0 0 ) :
s i gma = O . O O O l * ( i + l )
dl = ( l og ( S /X ) + ( r+ s i gma * s igma /2 . ) * T ) / ( s i gma * sqrt ( T ) )
d2 = d l - s i gma * s qrt ( T )
put=X * e xp ( - r * T ) * s tats . norm . cd f ( - d2 ) - S * stats . norm . cdf ( -d l )
abs_d i f f=abs ( put-p)
i f abs d i ff <min value :
min_value = abs_d i f f ; impl i e d_vo l = s i gma
k=i; put_out = put
p r i n t ' k , imp l ied_vo l , put , abs_di f f ' re七urn k, imp l i e d_vol ,
put_out , min_value

先输入 一 组参数值来估计 隐 含 波动 率, 然 后 解释这个 函 数 内 在的逻辑 。 假 设 S =40,


X =40, T = l 2 个 月 , r =0. 1 , 看跌期权价格为 1 .50美元, 结果 如 下 。
240 第 10 章 Python 的 循 环语 句 和 隐 含波 动 率 的 计 算

>>>impl i e d_vo l_put_min ( 4 0 , 4 0 , l . , O . l , l . 5 0 1 )


k , imp l i ed_vol , put , abs_di f f
( 1 9 9 9 , 0 . 2 , l . 5 0 1 3 6 7 3 5 5 3 0 2 7 3 4 9 , 0 . 0 0 0 3 6 7 3 5 5 3 0 2 7 3 5 0 1 7 37 )

结果 显示隐含波动率 为 20%。 这个算法 的 逻辑是我们 首 先 为 一 个 名 为 mi n_value 的变


量赋 一 个 大 的 数 , 如 1 00 。 给 定 参 数 sigma 的 第 1 个 值 0.0002 , 计 算 得 出 近 乎 为 零 的 看跌期
权 价 格 , 其 与 输 入 的 看 跌 期 权 价 格 的 绝 对 价 差 为 1 . 50 。 因 为 绝 对 价 差 小 于 1 00 , 所 以
min_value 变 量 的 值将 替 换 为 1 . 5 0 。 重复这个过 程 , 直到 循 环 结 束 。 最后得到 的 min_value
对应的 sigma 值就是我们 的 隐含 波 动 率 。

可 以 生成 一 些 中 间 值 来 缩 短 计 算 所 需 的 时 间 。 例 如 , 在 以 上 的 代 码 中 , 需 要计算 ln(S/X)

共 1 0 000 次 。 可 以 定 义 一 个 新 的 变量 l o g_S_o ve r_X 等 于 ln(S/X) , 只 需 要 计 算 它 的 值
次, 然后重复使用 1 0 000 次 。 同 样 的 办 法 也 可 以 用 于 s i gma * s i gma / 2 . 0 和
s i gma * s qrt ( T ) 。

10.2.4 enumerate()函数简介
当 编 写 计 算 净现值 的 函 数 NPV() 时 , 需要 依 照 以 下 公 式 计 算 未 来 和 现 在 的 所有现金流
量 的 现值 。

NPV = I
n cashjlow;
(I 0- I )
i=O ( 1 + RY

每 笔现金流 由 两个 值来 决 定 : 发 生 的 时 间 i 和 在 时 间 l 产 生 的 现金 流量 。 下 面 的 NPV
函 数显 示 如 何 应 用 enume r a t e ( ) 函 数 来处理这种数据 。

de f npv_f ( r ate , cash f l ows ) :


total = 0 . 0
for i , cash f l ow in enumerate ( cash flows ) :
七 0 七 al += cash flow / ( 1 + rat e ) * * i

return total


enume ra七e ( ) 函 数将 生 成一 个从 0 开 始 的 索 引 以 及 对应的 值 。 可 以输入折现率和 组
现金流量 的 值 来 调 用 以上 的 函 数 , 结 果 如 下 。

»>c = [ - 1 0 0 . 0 , 6 0 . 0 , 6 0 . 0 , 6 0 . 0 ]
>>>r = O . l
> > >npv=npv_f ( r , c )
> > > round ( npv , 2 )
49.21
1 0.3 用 for 循 环 计 算 内 部 收 益 率 及 多 个 内 部 收 益 率 241

1 0.3 用 for 循环计算 内 部收益率及 多 个 内 部收益率

前两 章, 我们学习 了如何应用 内部收益率 ( IRR ) 规 则, 以一组给定的 当前和 未来的


现金流来评估项 目 。 可以利用 for 循环 语句来计算项 目 的内部收益率 。 以下是两 个相关的
函数 npv_f ( ) 和 i r r_f ( ) 。

de f npv_f ( rate , c a s h f lows ) :


total = 0 . 0
for i , c a s h f low i n enume rate ( c a s h f l ows ) :
total + = cashf low / ( 1 + r a te ) * * i
return total

这里的关键是找出中间变量 i 和 cashjlow 的值 。 上 一 节 我们知道 l 的取值为从 0 到现金


流 拯 的 个数, casriflow 依 次 等 于 每 一 个 现 金 流量 的值 。 这 个 语 句 t o t a l +=x 等 价 千
total=total+x 。 有一 个问题, 如果输入- 1 作为折现率, 该
函数将出现错误而停止工作。
可以添加一 个 if 命令来防止这种情况发生(参考 I RR ( 函
) 数的解决方案)。 另 外 个问题,

当第 2 个输入参数包含 NaN 时, npv_f ( 函


) 数将停止工作。 可以使用 NumPy 模 块中包含
的 i snan ( 函
) 数处理这 一情 况 。

de f I RR_f ( c ash f l ows , i t e r a t i on s= l O O ) :


i f len ( cashf lows ) = =O :
print ( ' number o f cash f l ows i s z e ro ' )
return - 9 9
rate = 1 . 0
i nve stment = c a s h f l ows [ O ]
for i i n range ( l , i te r ations+l ) :
rate * = ( 1 - npv f ( rate , c a s h f lows ) / inve stment )
return rate

以上 代码的基本假 设是, 第 1 笔投资 是 我们的初始投 资, 而所有未来现金流都是现金


收入。 这意味着 NPV 和折现率是 负相关的。 对于 给定的折现率, 如果其 对应的 NPV 是正
的, 就应该把折现率乘以大于 1 的数来加大折现率, 以便使得 NPV 趋近于零 。 请 注意, 投
资 是现金支出, 是 一 个负数。 因此, 表达式 ( 1 - npv_f ( rate , c a s h f l ow s ) 八nves tme nt )
的值将大于 1 。 另 一 方面, 如果 NPV 是负值, 就应该减小折现率, 也就是说, 当前的折现
率乘以小于 1 的数 。 假设有以下现金流, 相应的 IRR 是什么 ?

>>>cashfl ows = [ - 1 00 , 5 0 , 6 0 , 2 0 , 5 0 )
242 第 10 章 Python 的 循 环语句 和 隐 含 波 动 率 的 计 算

>>>x=IRR_f ( ca s h f l ows )
>>>round ( x , 3 )
0 . 304
>>>

在前面的例子中 , 现金流的正 负 符 号 ( 即 收 入或支 出 ) 只改变 一 次 , 因 此只有一 个 IRR 。


当现金流的 正 负 符 号变 化超过一 次时 , 可能会有超过一个 IRR。 假设有以下现金流 : 现金
流= [ 5 5 , - 5 0 , - s o , - s o , 1 0 0 ] 。 由 于现金流的方 向 改变了两次 , 我们预测会有两个 I RR。
如果 使用上面的 IRR 函 数 , 只 能找到 一 个 IRR 。

>>>cas hfl ows= [ 5 5 , - 5 0 , - 5 0 , - 5 0 , 1 0 0 ]


>>>round ( I RR_f ( ca s h f l ows ) , 3 )
0 . 337
>>>

可以利 用 同 样的逻辑 , 通过循环语句 尝试许多不 同的折现率来找 出 哪 两个折现率使得


NPV (净现值 ) 为 0。 下面给 出 用于估计多个 IRR 的 Python 代 码 。

import s c ipy a s s p
de f npv_f ( ra 七 e , cashflows ) :
total = 0 . 0
for i , cash f l ow i n enume rate ( ca s h f l ows ) :
total += cash f l ow / ( 1 + rat e ) * * i
r e t u rn to 七 a l
de f I RRs f ( cash f l ows ) :
n= l O O O
r=range ( l , n )
eps i l on=abs ( sp . mean ( ca s h f l ows ) * 0 . 0 1 )
irr= [ ]
npv= [ ]
for i i n r :
npv . append ( O )
l a g_s ign=sp . s i gn ( npv_f ( r [ 0 ] * l . 0 / n * l . 0 , cash_f l ows ) )
for i i n range ( l , n - 1 ) :
interest=r [ i ] * l . 0 /n * l . O
npv [ i ] =npv_f ( i n t e re s t , cash_f l ows )
s=sp . s ign ( npv [ i ] ) \
i f s * lag_s ign<O :
l ag s i gn=s
i r r . append ( inte re s t )
return i r r
1 0.4 while 循 环 简 介 243

可以调用该函数轻松地找到两 个IRR 。

>>>cas h f l ows= [ 5 5 , - 5 0 , - 5 0 , - 50 , 1 0 0 ]
>>>IRRs_f ( ca s h f l ows )
[ 0 . 072 , 0 . 3 3 7 )


>>>

1 0.4 while 循环简介

下面代码的第 l 行为循环变量 l 分配 一 个初始值。 第 2 行定义 一 个条件来决定 while


循环何时应该停止。 最后 一行 i +=l 语句等 同于 i=i + l , 即 把变量 i 的值增 加 1 。 类似地,
t * * = 2 等 同于 t= t * * 2 。

i=l
whi l e ( i <= 4 ) :
prin t ( i )
i+=l

while 循环的关键是退出条件应该至少满足

次, 否 则将进入 一 个无 限循环(死循环 ) 。
比如, 运行以下代码将 进入 一 个无限循环。 这种情况发生时, 可以按 Ctrl+c组合键停止它。

i=l
whi le (i ! =2 . 1) :
prin t ( i )
i+=l

上面这段代码比较两 个实数是否相等。 通常应该避免对两 个实数、 浮点数或双 精度数


使用等号进行判断。 下一 个例子与著名的斐波纳 契序列 有关 : 当前的数字是前面两 个数字
的和 。

斐波纳契序列 I , 1 ,2,3,5,8, 1 3, … …

用千计算斐波纳契序列 的 Python 代码如下。

de f f i b ( n ) :
" '"' Print a Fibonacci s e r i e s up to n .

a, b = 0, 1
wh i l e a < n :
prin t ( a )
a , b = b , a+b
244 第 10 章 Python 的 循 环 语 句 和 隐 含 波 动 率 的 计 算

当 n 为 I 000 时 , 得 到 以 下 结 果 。

>>>fib ( 1 0 0 0 )
0 1 1 2 3 5 8 13 2 1 34 55 8 9 144 233 377 610 987

1 0.4.1 使用键盘命令停止无限循环

有 时 , 由 于 各 种 原 因 , 代码运行可 能会进入 个 无 限循环 ( 参 见 以 下 程序 ) 。 我们 的 目
的 是 打 印 1 �4 这 4 个数字 。 然 而 , 由 于 忘记在每次打 印 之后 增 加 变 量 i, 退 出 条件永远不

会被满足 , 也 就 是 说 , 它进入 个 无 限循环 。 对 于 这 种 情 况 , 可 以 按 Ctrl+C 或 Ctrl+Enter
组合键来终止循环 。

i=l
whi le i < S :
prin七 ( i )

如 果 这些命令不起作用 , 就 需要按 Ctrl+Alt+Del 组合键启 动 任 务 管 理器 , 选择 Python ,


然 后 单击 结 束 任 务 。

10.4.2 使用 while 循环计算隐含波动率



在这 节 , 使 用 一 个 wh辽e 循环和 Black-Scholes-Merton 模 型 来估计看跌期 权 的 隐 含
波 动 率 。 首 先 , 编 写 下 面 的 计算看跌期权价格 的 函 数 。

de f bs_put ( S , X , T , r f , s i grna ) :
f rom s c ipy i mport l o g , exp , sqrt , s t ats
dl= ( l og ( S /X ) + ( r f + s i gma * s i gma /2 . ) * T ) / ( s i gma * s qrt ( T ) )
d2 = d l - s i gma * s qrt ( T )
return X * e xp ( - r f * T ) * s tats . norm . cdf ( - d2 ) - S * s tats . no rm . cdf ( - dl )

输入

组 s、 X、 T 、 rf 和 s i gma 的 参数 值来 调 用 该 函 数 , 结 果 如 下 。

>>>p u 七 =bs_put ( 4 0 , 4 0 , 0 . 5 , 0 . 0 5 , 0 . 2 )
> >>rou nd (put , 2 )
1 . 77

以 下 代码使用 wh豆e 循环来估计看跌期 权 的 隐 含波动 率 。 在这里 , 假 设 以 上 的 欧 式 看


跌 期 权 函 数包含在主程序文件 p 4 y . p y 中 。

impor t p 4 f
1 0.4 while 循 环 简 介 245

import s c ipy as sp
S=4 0 ; K= 4 0 ; T=0 . 5 ; r=0 . 0 5 ; p=l . 7 7
di f f = l ; i = l ; s i gma_o ld= 0 . 0 0 5
si gn_l=sp . s i gn ( p -p4 f . bs_put ( S , K , T , r , si gma_old) )
wh i l e ( 1 ) :


s i gma = O . O O O l * ( i + l )
si gn_2=sp . s i gn ( p-p4 f . bs_put ( S , K , T , r , s i gma ) )
i+=l
if s i gn l * s i gn 2 < 0 :
break
else :
s i gma_ol d= s i gma
print ( ' i , imp l i ed-vol , d i f f ' )
print ( i , ( s i gma_old+s igma) /2 , di f f )

以下的输出结果显示隐含波动率等于 0 . 2 , 与 我们 使用 Black-Scholes-Merton 看涨期权


模型估 计的结果一 样。 还可以使用 0 . 2 作为波动率的输入值来计算, 从 而确定得到相同的
期权价格。

i , imp l i ed-vol , di f f
(2002, 0 . 20015, 1)

以下 代码使用 b r e a k 退出一 个无限循环。 这 个 whil e 循环 的条件总是成 立的。 唯 一 可


以停止循环 的是 b r e a k 语句。 这种收敛标准的一 个优点是 我们不必考虑什么是 一 个合适的
绝对价差 水平。 因为期权价格 差异 比较大, 选择适当的水平是不容 易的。

import p 4 f
S= 4 0 ; K=4 0 ; T=0 . 5 ; r=0 . 0 5 ; p=l . 7 7
di f f= l ; i = l ; s i gma_old= 0 . 0 0 5
sign_ l=s ign ( p-bs_put ( S , K , T , r , s i gma_old) )
whi le ( l ) :
s i gma=O . O O O l * ( i + l )
s i gn_2 = s i gn ( p-p4 f . bs_put ( S , K , T , r , s i gma ) )
i+=l
i f s i gn l * s i gn 2 < 0 :
break
else :
s i gma_old= s i gma
print ( ' i , imp l i ed-vol , di f f ' )
print ( i , ( s i gma_o l d + s i gma ) /2 , d i f f )

如果输入值大于 1 , s i gn ( 函
) 数的返 回 值等千 l 。 如果输入值 小 于 o, 返 回值 则等于
246 第 10 章 Python 的 循 环 语 句 和 隐含 波 动 率 的 计 算

- 1 。 s i gn ( ) 函 数 的 示例 如 下 。

>>>import sc ipy a s sp
>>>sp . s ign ( - 2 )
-1
>>>sp . s ign ( 2 )
1


>>>sp . s ign ( O )

10.4.3 多重嵌套的 for 循环



需要两个循环变量 i 和 j 来访 问 个 二 维矩 阵 , 代码如 下 。

n l =2
n2=3
for x i n xrange ( l , n l + l ) :
for y i n xrange ( l , n2+ 1 ) :
print ' % d * %d = % d ' % ( x , y , x * y )

一 一
可 以 使 用 两 个 wh 辽 e 循环或者 个 fo r 循环和 个 wh i l e 循环 的 组合来完 成 同 样 的
任务。

1 0.5 美式看涨期 权 的 隐含波动 率

以 下 代码用 来计算美式看涨期权 的 价 格 。

f rom math import exp , sqrt


i mport numpy as np
de f binomi a l Cal lAme ri c an ( s , x , T , r , s i gma , n = l O O ) :
de l t a T = T /n
u = e xp ( s i gma * sqrt ( de l t aT ) )
ct = 1 . 0 / u
a = exp ( r * del taT )
p = ( a - d) / ( u - d )
v = [ [ 0 . 0 for j i n np . arange ( i + 1 ) ) ,fo r i in np . arange ( n + 1 ) )
for j i n np . a range ( n+ l ) :
v [ n ) [ j ) = max ( s * u * * j * d* * ( n - j ) - x , 0 . 0 )
for i in np . arange ( n- 1 , - 1 , - 1 ) :
for j i n np . ar ange ( i + 1 ) :
vl=exp ( - r " deltaT ) * ( p * v [ i + l ) [ j + l ) + ( 1 . 0 - p ) * v [ i + l ) [ j ) )
1 0.6 测 试 一 个程序 的 运 行 时 间 247

v2 =max ( v [ i ) [ j ) - x , 0 ) # early exercise


v [ i ) [ j ) =max ( vl , v2 )
return v [ O ] [ O J

第 9 章介绍了基于二叉树方法或 CRR 方法计算美式看涨期权的价格,以下 是执行 CRR


方法的 Python 代 码 。 根据输入值, 首 先计算 u 、 d 和 p , 其中 u 表示股票价格增加的幅度,
d 表示股票 价格减小的幅度, p 是风险中性概率 。 第 1 个循环计算所有末端 节点的期权价格 。

第 2 个循环从末端节 点 一 步 一 步地 向 前移动 直 到 零时刻 , 即 当前时刻 。 变量 v l 是计算得到


的期权价格 , 而 v2 是在该节点 执行美式期权得到的收 益 。

de f imp l i ed vol Ame r i can c a l l ( s , x , T , r , c ) :


imp l ied vol = l . O ; min value=l O O O
f o r i i n range ( l O O O ) :
s i gma=O . O O l * ( i + l )
c2=binomi a 1 C a l 1 Ame r i c an ( s , x , T , r , s i gma )
ab s_di f f= abs ( c 2 - c )
i f abs di f f<min va l ue :
min_v a l ue = abs_di f f ; imp巨 ed_vol=s igma ; k=i
return imp巨ed_vol

可以输入 一 组参数值 ( 包括 s i gma ) 来计算美式看涨期权的价格 , 然 后 估计它的隐含


波动率 如 下 。

>>>binomi a l C a l lAme ri can ( l S 0 , 1 5 0 , 2 . / 1 2 . , 0 . 0 0 3 , 0 . 2 ) 4 . 9 0 8 8 3 6 1 1 4 1 7 0 8 1 8


>>>imp l ied_vol_Amer i can_ca l l ( l S0 , 1 5 0 , 2 . / 1 2 . , 0 . 00 3 , 4 . 9 1 ) 0 . 2

1 0.6 测试一个程序 的运行 时 间

以下代码使用 t ime . c l o c k ( ) 函数来测试 个程序完成运行所需的时间 ( 以秒为单位 ) 。


import time
start = time . c lo c k ( )
n=l O O O O O O O
for i i n range ( l , n ) :
k=i+ i + 2 ; di f f= ( t ime . c l o c k ( ) - star 七 )
print ( round ( di f f , 2 ) )

上面这个循环 完成运行所需的时间约为 1 .5 9s 。
248 第 10 章 Python 的 循 环 语 句 和 隐含 波 动 率 的 计 算

1 0.7 二分搜 索 的原 理

以上估计隐含波动率 的方法是运行 B lack-Scholes-Merton 期权模型 1 00 次 , 从 中 选择使


得计算所得 的 期权价格和 实 际给 出 的 期 权价格之 间 的 绝对差值最小 的 sigma 值 。 这种方法

虽 然 容 易 理解 , 但 效 率 不 高 , 因 为 估算每 个 隐 含 波 动 率 都 需 要 计 算 Black-Scholes-Merton
期权模型 1 00 次 。 如 果 只 需 要 估 计 几 个 隐 含 波动 率 , 这种方法不会是 一 个 大 问 题 。 然而 ,
在两种情况下 , 这个方法有 明 显 的缺 陷 。 首 先 , 如 果 需 要 更 高精 度 的 估 计值 , 比 如 希 望
sigma=O . 2 5 3 3 3 精 确 到 小 数 点 后 4 位 数 ; 其 次 , 如 果 必 须估计几百万个 隐 含波动 率 , 就需要
更有效率的方法。
一 一
来看 个简 单 的 例 子 。 假 设 随 机选择 个 1 ,-_, 5 000 的 值 。 如 果 从 1 ,-_, 5 000 连续运 行 ,
需 要 多 少 步 才能找到这个值 ? 为 了 搜 索 一 个 1 ,-_,5 000 的 值 , 在最坏 的情况下 , 线性搜索将
需 要 5 000 步 ( 平均 需 要 2 050 步 ) , 而 在 最 坏 的情况下 , 二分搜 索 只 需 要 1 2 步 ( 平均 需 要
6 步 ) 。 以 下 Python 程序实现二分搜 索 法 。

de f binary_search ( x , targe t , my_min = l , my_max = None ) :


i f my max i s None :
my_max = len ( x ) - 1
whi l e my min <= my max :
mid = ( my min + my max ) / / 2
midval = x [ mid]
if midval < targe t :
my_min = my_mid + 1
e l i f midval > targe t :
my_max = mid - 1
else :
return mid r a i s e Va lueError

以 下 代码生成 一 份来 自 圣经 的 单 词 列 表 , 然 后 采 用 二 分搜索法找到 一 个 给定 词 的 位 置 。
首 先 , 从 网 页 https://canisius.edu/-yany/doc/AV l 6 1 l Bible.txt 下载圣经 的 文 本文 件 , 并把该
文 件保存在 C :\temp\ 目 录下 。

f rom s tring impo rt ma ke 七 rans


impo rt pandas as pd
word fre q = { )
word_l ist = open ( " c : / t ernp /AV 1 6 1 1Bible . tx t " , " r " ) . r ead ( ) . sp l i t ( )
for word i n word l i s t :
word word . t rans l ate (maketrans ( " " , " " ) , 1 ! "#$毛& ( ) *+, . / : ; <=> ? @
1 0.8 烦 序 访 问 与 随机访 问 249

( I J - 0 1 2 3 4 5 67 8 9 ' )

[\\) A
i f word . star tswi 七 h ( 1 _ I ) ;
word = wor_d . replace ( ' - ' , ' ' )
i f len ( word) :
word_f req [ wo r d ) = word_f千eq . get ( word, 0 ) + 1
keys = s o r te d ( word_f req . keys ( ) )
x = pd . Da 七 aFrame ( keys )
x . to_pickle ( ' c : / temp /uniqueWords . pi c k l e ' )


这 一 次, 我们用下 面的代码查找 个字 符 串 而不是 一 个数值 。

de f bina ryText ( x , targe t , my min = l , my max = None ) :


i f my max i s None :
my_max = len ( x ) - 1
wh ile my min <= my max :
mid = ( my min + my,.max ) / / 2
midval = x . i l o c [mid]
i f midva l . values < targe t :
my_min = mid + 1
e l i f midva l . values > targe t :
my_max = mid - l
else :
return mid raise Va lueE rror

在以上代码中, x 是 Dat a . Frame 格式, 因 此 x . 辽 o c [ mi d ] 给 出 一 个数值 。

>>>x . i loc ( 6 0 0 ]
0 Ba kba kkar
Name : 6 1 0 , dtyp e : obj e c t

如 果 在 下 载 圣经文件时遇 到 问 题 , 可 以 从 htt p : / / c an i s i u s . e du / - yany/



u n i queWords . p i c kle 下 载 个 pickle 格式的文件 。 假设这个文件 保存在 C : \ t emp \ 目
录 下 , 以下代码用来执行二分搜索。

impor t pandas as pd
x =pd . read_p i c kl e ( " c : /t emp / uniqueWords . pk l " )
pr int ( x . iloc [ 6 1 0 ] )

1 0.8 顺序 访 问 与 随机访 问

可以用不 同的模式保存每 日 的股票数据 。 种方法是将它 们 保存为股票 ID 、 日 期、 日
250 第 10 章 Python 的 循 环 语 句 和 隐含 波 动 率 的 计 算

内 最高价 、 日 内 最低价 、 开盘价、 收盘价和交易量 。 可以对股票 ID 进行排序, 然 后 一 个接



个地保存 。 有两种方法来编写 Python 代码以访 问 IBM 的数据 : 顺序访问和随机访 问 。
对千顺序访问,我们读取 一 行并检查其股票 ID 是否与所需的股票代码 匹 配 。 如果 没有,就

去下 行, 直到找到所需的数据 。

这样的顺序访问效率很低, 尤其是处理规模 巨大的数据集时, 比 如有几个 GB 大小的


数据集 。 这时最好生成 一 个索 引 文件, 包含 如 IBM、 1 000、 2000这样的信 息 。 由 此 , 我们
知道 IBM 的数据位于第 1 000行到 第 2 000行。 如 果 需要检索 IBM 的数据, 就 可以立 即 跳
转 到 第 1 000行, 而不 必经过前面的 999 行。 这个方法被称为随机访问 。

1 0.9 通过循环访 问 数组 的 元素

以下代码展示 如何打 印数组中的所有值 。

import numpy as np
x = np . arange ( l O ) . re shape ( 2 , 5 )
for y in np . ndi ter ( x ) :
pr int ( y )


从 http : / / canisius . edu / - yany/ yanMonthly . pickle 下 载 个 名 为

yanMonthl y . pi ckle 的数据集, 用来展示遍历访 问的另 个例子。 假定下载的数据集保存

在 C : \ temp \ 下, 可以使用下面的代码来检索数据集并运行 个循环来打 印 出股票的代号。

import pandas as pd
x=pd . read_pickle ( ' c : / ternp /yanMonth l y . pkl ' )
stocks =x . i ndex . unique ( )
for item in s to c ks [ : 1 0 ) :
print i tem
# add your codes here

以上代码的结果 如 下 。

0 0 0 0 0 1 . SS
A

AA
AAPL
BC
BCF
C
1 0.9 通过循 环 访 问 数 组 的 元 素 251

CNC
COH
CPI

简单地输入以下命令来看到那些 股 票 代号 。 不过, 可以在以上 代码的基础上 添加


可以
更多的功能。

>>>stocks [ 0 : 1 0 ]
array ( [ ' O O O O O l . S S ' , ' A ' , ' AA ' , ' AAPL ' , ' BC ' , ' BCF ' , 'C' , ' CN C ' , ' COH ' ,
' CP I ' ] , dtype = obj ect )
>>>

10.9.1 利用 for 循环赋值

以下代码 将多个值分配给变量 。

>>>x= [ O . O for i i n xrange ( S ) )


>>>x
(0 . 0, 0 . 0, 0 . 0, 0 . 0, 0 . 0]
>>>

简单, 可以用 x = z e r o s ( S ) 来得到 同样结果。 下面的代码更加复杂 一 些 。


这个的任务很

>>>v = ( ( 0 . 0 for j i n xrange ( i + 1 ) ] for i i n x r ange ( 4 + l ) ]


>>>v
[ [0. OJ ,
( 0 . 0, 0 . OJ ,
[ 0 . 0, 0 . 0, 0 . 0) ,
(0.0, 0 . 0, 0 . 0, 0 . 0] ,
[0 . 0, 0 . 0, 0 . 0, 0 . 0, 0 . 0] )
>>>len ( v )
5
» >v [ O ]
[0. OJ
>>>v [ l ]
(0. 0, 0. OJ
» >v [ 3 ]
[ 0 . 0, 0 . 0 , 0 . 0, 0 . 0 )

10从 2 通过循环访问词典的元素
下面是 一 个与字 典有关的示例。
252 第 10 章 Python 的 循 环 语 句 和 隐 含 波 动 率 的 计 算

>>>mar ke t_cap = { " IBM" : 2 0 0 . 9 7 , "MSFT " : 3 1 1 . 3 0 , " WMT " : 2 5 3 . 9 1 , "C" : 158 . 5 0 )

每只 股票都有它的市值 , 由一 个代号和一 个数值表示 。 以下代码显示几只股票的代号


和市值。

>> >ma r k e t_cap . keys ( )


[ I C I ' I I BM I ' I MSFT I ' I WMT I l

> >>mark e七_cap . va l u e s ( )


[ 158 . 5 , 2 00 . 97 , 3 1 1 . 3 , 253 . 91 ]

使用 江ems ( )函数来 同时显示 代号和市值 。

>>>ma rket_cap . items ( )


[ ( ' C ' , 1 5 8 . 5 ) , ( ' 工 BM ' , 2 0 0 . 9 7 ) , ( ' MS FT ' , 3 1 1 . 3 ) , ( ' WMT ' , 2 5 3 . 9 1 ) )
>>>

以下 代码 演 示 如何利用循环遍历字典。

>>>ma r k e t_cap= { " 工 BM" : 2 0 0 . 9 7 , "MSFT " : 3 1 1 . 3 0 , " WMT " : 2 5 3 . 9 1 , "C" : 158 . 5 0 )
> > > for k , v i n mar ket_cap . i tems ( ) :
print k , v

C 158 . 5
工BM 2 0 0 . 9 7
MSFT 3 1 1 . 3

1 0. 1 0 从 CBOE 网 站下载期权数据

在 芝 加 哥 期权 交 易所 (CBOE)交 易期权和期货的网 页 上 提供 很多公开数据。 可以


输入一 个代码 , 下 载与该代码相关的期权数据。 执行以下两 个 步 骤 来下载 IBM 的期权
数据。
I . 转到 http ://www.cboe.com/DelayedQuote/QuoteTableDownload.aspx 。
2 . 输入 I B M , 然后单击下载。

前 几行数据如表 I 0-1 所示。 在下载的原始数据中, 看涨期权与看跌期权并排呈现。 为


了 使数据更清楚 明 了 , 把看跌期权数据挪放到看涨期权数据之下。
1 0. 1 0 从 CBOE 网 站 下 载 期 权 数 据 253

表 1 0-1

IBM(lntemational BusinessMachines) 1 72.8 -0.57

December 1 5, 20 1 3@ I 0:30ET Bid 1 72.5 1 Ask 1 72.8 Size 2x6 Vol 4 1 84836

Calls LastSale Net Bid Ask Vol Open lnt

13 December125.00 (IBM l 3 1 3 L l 25) 0 。 46.75 50 。 。


I 3 December 1 25.00
(IBM l 3 1 3 L 1 25-4)
。 。 46.45 50.45 。 。
1 3 Dec 1 25.00 (IBM 1 3 1 3L 1 25-8) 。 。 。 。
。 。
46.2

。 。
50.3

1 3 Dec 1 25.00 (1BM l 3 1 3 L l 25-A) 46.5 50.5

1 3 Dec 1 25.00 (1BM 1 3 l 3 L l 25-B) 。 。 46. 1 5 50. 1 5 。 。


1 3 Dec 1 25.00 (IBM 1 3 1 3 L l 25-E) 。 。 46.25 50.3 。 。
Puts LastSale Net Bid Ask Vo l Open Int

1 3 Dec 1 25.00 (IBM 1 3 1 3 X l 25) 。 。 。 0.03 。 。


1 3 Dec 1 25.00 (IBM L 3 1 3 X l 25-4) 。 。 。 0.03 。 。
。 。 。 0.03 。 。
。 。 。
1 3 Dec 1 25.00 (IBM 1 3 1 3 X 1 25-8)
1 3 Dec 1 25.00 (TBM 1 3 1 3 X l 25-A) 1 .72 。 。
1 3 Dec 1 25.00 (IBM 1 3 1 3 X 1 25-B) 。 。 。 0.04 。 。
1 3 Dec 1 25.00 (IBM l 3 1 3X l 25-E) 。 。 。 0.03 。 。
假设 我们 的 数据文件保存在 C : \temp \ 目 录 下 , 以 下代 码 将 从 该 数据 文 件 中 检 索 数据 。

import numpy a s np
import pandas as pd
x=pd . read csv ( ' c : / temp /QuoteDa 七 a . da t ' , s k iprows = 2 , header = ' infer ' )
y= np . array ( x )
n=len ( y )

用 以 下 代码显示最 前 和 最 后 几 行 。

>>>print y [ 0 : 2 )
[ [ ' 1 3 Dec 1 2 5 . 0 0 ( 工 BM1 3 1 3 L l2 5 ) ' 0 . 0 0 . 0 4 6 . 7 5 5 0 . 0 OL O L
' 1 3 D e c 1 2 5 . 0 0 ( I BM1 3 1 3 X l 2 5 ) ' 0 . 0 0 . 0 0 . 0 0 . 0 3 O L O L nan ]
[ ' 1 3 Dec 1 2 5 . 0 0 ( I BM1 3 1 3 L l 2 5 - 4 ) ' 0 . 0 0 . 0 4 6 . 4 5 5 0 . 4 5 O L O L
254 第 10 章 Python 的 循 环语句 和 隐含 波 动 率 的 计算

' 1 3 Dec 1 2 5 . 0 0 ( I BM1 3 1 3 X 1 2 5 - 4 ) ' 0 . 0 0 . 0 0 . 0 0 . 0 3 O L O L nan ] ]


>>>p r i n t y ( n - 3 : n - 1 ]
[ ( ' 1 6 Jan 2 5 0 . 0 0 ( I BM1 6 1 5A2 5 0 - S ) ' 2 . 6 0 . 0 1 . 1 2 . 9 5 O L 2 1 9L
' 1 6 Jan 2 5 0 . 0 0 ( I BM1 6 1 5M2 5 0 - S ) ' 6 6 . 0 0 . 0 8 0 . 7 5 8 3 . 6 5 OL l l L nan ]
[ ' 1 6 Jan 2 5 0 . 0 0 ( 工 BM1 6 1 5A2 5 0 -X ) ' 2 . 8 7 0 . 0 1 . 0 3 2 . 9 5 O L 2 1 9L
' 1 6 Jan 2 5 0 . 0 0 ( I BM1 6 1 5M2 5 0 -X ) ' 0 . 0 0 . 0 8 0 . 7 5 8 3 . 6 5 OL l l L nan ] ]
>>>

1 0. 1 1 从雅虎财经 网 页 下载期权数据

可以利用一 些 公开的期权数据来帮助投资 、 研究或教学, 其 中一 个是 Yahoo!Finance 。


检索 IBM 的期权数据的步骤如下 。
I . 转到 http ://finance.yahoo.com 。

2 . 在搜索框(左 上方) 中输入 IBM。

3 . 单击 Options 的选项 。

Yahoo! Finance 的网址是 http://finance.yahoo.com/quote/IBM/options?p=IBM , 如图 1 0-2 所示。


(!) •""""'"立,- �
� �如… 丘书 ) 釭... . ....... ...

y�氐沪
Floam Hom,
归 O <- l><>d•

。『'•'""' ...,..
. �"'
•....,., ""'"" 正hoolo;y Mukm

臼<-Co酝" "" a ............ i:> 七- ··一 石 _.. . ....

lnau,订,.. My '"""'"

M, PoNtollo

International Business Machines Corporation (IBM)


仑 心. ., ,......,
""" ,., ...
过 了•MP••• (中”。 ""勾

1 69.11 +0 41 (+0 24%)


.. � , . , 叩 ..
- ...,_ .....

”而心, =�-- 以, p心心 ,.可,,,._ l 0o四,. . ..,.,.,, "如“心心 压心

••贮"'' '"''靶dWh心 G,a,nMon, Wll••


****1 .... 气,一,"

妇叩 6 11117 • l 1nT11e.......,. snow LI"



.. .六..., 、 ·-
S赢"'�

Cail• 幻 上心芍6 如1
.蕨八. “呵沁心硐, U\11节冷 .:,,. (.I': cr..i.心 ` 3帜蟾一心 _,., , ...
,
••
,., 心

"·'""
吧u110,0110沪“比如

Ie-.tr ro, 心劝 又如
1325

12U
1360

117�...!AO$

u 30 穴 '2
0 00,,


91 Ol

图 1 0-2

10. 1 1.J 从雅虎财经网页检索不同的到期 日 期


每只 股票有不 同执行价格和到 期 日 的期权。 上 一 节的代码检 索有效期最短的期权数据。
1 0. 1 2 看跌期权和 看 涨 期权 的 比 率及其短期趋 势 255

要检索 其他有效 期 的 期 权 , 需 要 指 定 到 期 日 的 月 份和 年份 。 首 先 , 看 看 不 同 有 效 期 的 期 权
所 在 的 网 页 http://finance.yahoo.com/quote/lBM/options?p=IBM , 如 图 1 0-3 所 示 。

介 Add
International Business Machines Corporation (IBM)
阶SE 小 HYSE R的T叩ePoee C 中虹 i 1n 1JSO

叩n
January 20 2017
January 27, 2017

气l
L
Fe即ary 3, 2017 伈出K>ns Sta沁氏 , Pron;, F,nanc,a� Opuons
Fellfuary 10. 2017
Fe!lfuary 17 20 17 �
February 24 2017
Ma兀n 11, 2011
I AprII 21 . 2017
June 16. 2017
Ju灯 21 2017
January 1 9 201e ,
January 18. 2019 j
January 5. 2017 • I In The Mon勺 Show List S叩心

图 1 0-3

10. 1 1 .2 从雅虎财经网页下载当前价格
使用 以 下 Python 代码可 以 检 索 给 定 股 票 的 当 前 价 格 。

import da tetime
impor 七 s c ipy as sp
fr om ma tplot l i b . finance import quotes_h i s to r i c a l_yahoo—o chl as getData
s tocks = [ ' ibm ' , ' ms f t ' , ' goog ' J
begdate= ( 2 0 1 7 , 1 , 1 )
endda te= datet ime . date . 七 oday ( )
n=l e n ( sto cks )
for i i n sp . arange ( n ) :
p=getData ( s 七 ocks [ i ) , begdate , enddate , as obj e ct=True , adj u s 七 ed=True )
pri ce=round ( p [ ' cl o s e ' ) [ 0 ) , 4 )
print ( " For " , s 七 ocks [ i ) . upper ( ) , " the price i s " , price )

假 如 在 20 1 7 年 3 月 3 日 运行 以 上代码 , 输 出 结 果 如 下 。

( ' For ' , ' 工 BM ' , ' 七 he price i s ' , 1 6 5 . 8 7 8 4 )


( ' For ' , ' MS FT ' , ' the price i s ' , 62 . 2 0 2 9 )
( ' For ' , ' GOOG ' , ' the price i s ' , 7 8 6 . 1 4 )
>>>

1 0. 1 2 看跌期权和看涨期 权 的 比 率及其短期趋势

看 跌 期 权 和 看 涨 期权 的 比 率 ( put-call 比 率 ) 反 映 了 投 资 者 对未来 的 看法 。 如 果 预 期 未
256 第 JO 章 Python 的 循 环 语 句 和 隐 含 波 动 率 的 计 算

来不会有 明 显 的趋势, put-call 比率应该接近 1 。 反之, 如果预期未来形势大 好, 这个比率


应该低 于 1 。 以下 代码通过绘制图形显 示过去多年的 put-call 比率。 首先, 执行以下步骤从
CBOE 下 载数据。

1. 转到 http ://www.cboe.com/data/putcallratio.aspx 。
2. 单击菜单栏 中 的 " Quotes & Data " 按钮 。
3. 单击 " CBOE Volume & Put/Call Ratio " 按钮。

4. 单击 " CBOE Total Exchange Volwne and Put/Call Ratios ( 1 1 -0 1 -2006 to present) " 按钮。

假设下载得到 名为 totalpc.csv 的文件保存在 C:\temp\ 下, 然后运行以下代码。

import pandas as pd
impor 七 s cipy as sp
from matp l o t l i b . pyp l o t import *
data =pd . re ad_csv ( ' c : /temp / totalpc . c sv ' , s k iprows = 2 , index_co l = O , parse_da te
s = True )
data . c o l umn s = ( ' Ca l l s ' , ' Put s ' , ' Total ' , ' Ra七io ' )
x = data . index; y = da 七 a . Ratio; y2 = s p . o n e s ( l en ( y ) )
七 i 七 le ( ' P u t - c a l l ratio ' ) ; xlabel ( ' Date ' ) ; y l ab e l ( ' Put-cal l ratio ' )
y l im ( 0 , l . 5)
p l o t ( x , y , ' b- ' )
plot ( x , y2 , ' r ' )
show ( )

绘制的图形如图 1 0-4 所示。

Put-call ratio
II ii ,I ' ' I
1.4

1.2

1.0

启� 0. 8

弓 0.6

0..

0.4


02

00 '
. 2007 2008 2009 2010 2011 2012 2013
Date

图 1 0-4
10. 1 2 看 跌 期 权 和 看 涨 期 权 的 比 率及其短期 趋势 257

用以下代码分析 put-call 比率在短时间内的趋势。


import pandas as pd
from matpl o t l ib . p yplot import *
import matpl o t l i b . pyplot as plt f rom date 七 ime
import datet ime
impor 七 s 七 a 七 smode l s . api as sm
import s c ipy as sp
data =pd . read_cs v ( ' c : / temp / totalpc . csv ' , s kiprows = 2 , index—co l = O , pars e_date
s T rue )
=

data . column s= ( ' C a l l s ' , ' Put s ' , ' Total ' , ' Ratio ' )
begda te=datet ime ( 2 0 1 3 , 6 , 1 )
enddate=datetime ( 2 0 1 3 , 1 2 , 3 1 )
data2=data [ ( data . i ndex>=begdate ) & ( data . index<=enddate ) ]
x = data2 . index; y =data2 . Ra tio
x2=range ( len ( x ) ) ; x3 = sm . add_constant ( x 2 )
mode l sm . OLS ( y , x 3 )
=

resul 七 s=model . f i t ( )
#print results . s ummary ( )
alpha = round ( r e s u l t s . params [ 0 ] , 3 )
s l ope=round ( re s u l t s . pa rams [ l ] , 3 )
y3=alpha+sp . do 七 ( s l ope , x2 )
y2=sp . ones ( l en ( y ) )
t i t l e ( ' Put - c a l l r a t io ' ) ; x l abel ( ' Dat e ' ) ; ylabel ( ' Put- c a l l r a t i o ' )
yl im ( 0 , 1 . 5 )
plot ( x , y , ' b- ' )
plot ( x , y2 , ' r - . ' )
plot ( x , y3 , ' y+ ' )
plt . fi gtext ( 0 . 3 , 0 . 3 5 , ' Trend : i n te rcept= ' + s t r ( al pha ) + ' , s l ope = ' + str ( s lope ) )
sho w ( )

绘制的图形如图 10-5 所示 。
Put-call ratio

1.4
0之U _
c5 0
8
_
eY3
6
Z

飞end: intercept=l.025. slope=-0.002


0.4

0.2

o.o
,..1 2013 A叩 2013父p 2013 OCt 2013 Nov 20130ec 2013
Date

图 1 0-5
258 笫 L O 章 Python 的 循 环语 句 和 隐 含 波 动 率 的 计 算

1 0. 1 3 小结

本章介绍了不 同 类型的循 环 语句, 演 示如何基于欧式期权和美式 期权的定价模 型来估


计隐含波动率。 讨论了 for 循环语句和 while 循环语句, 以及它们的应用。 展示了如何利用
Python 代码对于给定的一组输入值 , 如当前股票 价格、 行使价格、 有效期、 连续复利的无
风险利率和看涨期权价格(或看跌期权价格), 来估计隐含波动率。 还介绍了二分搜索方法
并比较其 在 估 计 隐含波 动 率 时与其 他方法在效 率 方 面的差 异 。 此外 , 还介绍了如何从
Yahoo! Finance 和 CBOE 网 页 下 载 期权相 关数据, 如看跌期权和看涨期权的比率。

下 一 章 将 重点关注 蒙特 卡 罗 模 拟在期权定价的应用。 给定 一组均值和标准方差 , 我们


可以使用服从 正态分布的随机数来模 拟股票价格的
变动, 从 而得到在期权到 期 日 股票 的价
格以及相 应的期权的收益。 使用无风险利率作为贴现率, 把期权到 期 日 的收益折现到现在
就可以得到期权的价格。

练 习题

l . Python 语言中有哪几种不 同的循环语句? 它们之间有什 么区别 ?


2 . for 循环语句和 while 循环语句各自 有什么 优点和缺点?

3 . 基于 for 循环语句, 编写 一 个 Python 代码来估计隐含波动 率。 对于给定的一组值


S = 3 5 , X =3 6 , r1 = 0.0 24 , T = l , a =0. 1 3 和 C =2 . 2 4 , 隐含波动率是多 少 ?

4 . 编写 Python 代码利用 Black-Scholes-Merton 模型来计算看跌 期权的隐含波动率。

5 . 利用 Black-Scholes-Merton 期权模 型得到的看涨期权隐含波动率和利用它得到的看


跌期权隐含波动率是不 同的吗 ?
6 . 对千具有 多 个看涨期权的股票, 可以得到各个期权对应的隐含波动率, 它们的值会
不 同吗 ?

7 . 当 估 计 很 多 只 股 票 的隐含波动率如 5 000 只 股 票时 , 如何使得 我们的代码 更有


效率 ?

8 . 可以应用二分搜索方法来估计基于 Black-Scholes-Merton 期权模型的隐含波动率。


我们是否可以应用它来估 计 多 个 IRR 以加快进度 ? 请解释你的答案 。
练习题 259

9 . 是 否 有 必 要 使 用 二叉树方法来估计 隐 含 波 动 率 ?

1 0 . 学 习 本章后 , 可 以 使用 以 下 函 数来估计看涨期权 的 隐含波 动 率 。

def impl ied—vol_cal l ( S , X , T , r , c ) :


from s cipy import log , exp , sqr t , stats
for i i n range ( 2 0 0 ) :
s igma=O . O O S * ( i + l )
dl= ( l og ( S /X ) + ( r + s i gma * s i gma / 2 . ) * T ) / ( s i gma * sqrt ( T ) )
d2 = d l - s i gma* sqrt ( T )
dif f=c- ( S * s tats . no rm . cdf ( d l ) -X* exp ( - r * T ) * s ta 七 s . no rm . cd f ( d2 ) )
i f abs ( di f f ) <=0 . 0 1 :
return i , s i gma , d i f f

对于 给 定 的 某 些输入值 , 我 们 可 能 得不 到 输 出 结 果 , 请参考 以 下 示 例 。

>>>imp l i ed_vol_cal l ( 2 5 , 4 0 , l , 0 . 0 5 , 3 . 3 )
>>>impl i ed_vol _c a l l ( 2 5 , 2 6 , l , 0 . 0 5 , 3 . 3 )
>>>imp l i e d_vo l_c a l l ( 4 0 , 4 0 , 5 , 0 . 0 5 , 3 . 3 )

找 出 原 因 并 对此程序做 出 相 应 的 修 改 。

1 1 . 本 章 学 习 了 如 何 使用 以 下 程 序 根 据 Black-Scholes-Merton 期 权 模 型 来 估 计 隐 含 波
动率。

de f impl ied_vol_put_min ( S , X , T , r , p )- :
from s cipy import l o g , exp , sqr t , s tats
imp l i ed_vo l = l . O
min_value = l O O . O
for i i n range ( l , 1 0 0 0 0 ) :
s i gma = O . O O O l * ( i + l )
d l = ( log ( S /X ) + ( r + s i grna * s i grna/2 . ) * T ) / ( si gma* s qrt ( T ) )
d2 = dl-s i gma * s qrt ( T )
put=X * e xp ( - r * T ) * s tats . no rrn . c df ( - d2 ) - S * sta 七 s . norm . cdf ( 一 d l )
abs_di ff=abs ( put-p)
if abs d i f f <min value :
min va l ue=abs d i f f
imp l i ed_vol = s i gma
k=i
put_out=put
print ' k, imp l i e d_vo l , pu t , abs_di f f ' return k , imp 巨 ed_vo l ,
put_out , min_value
260 第 J O 章 Python 的 循 环语 句 和 隐含 波 动 率 的 计算

是波动率的单调函数这一 关系, 修改此程序使其 更有效率。


根据看跌 期权的价格

12 . 以下程序有什 么 问题?

i=l
def whi l e less than n ( n , k=l ) :
i=l
whi l e True :
i f i<n :
else :
print i 丘=k
return ' done '

1 3 . 编写 一 个 Python 程序来估计美式 期权的隐含波动率 。

1 4 . 编写 一 个 Python 程序从 Yahoo!Finance 下 载期权数据, 然后使用买价和卖价的平


均值作为期权价格来估计 隐含波动率。
1 5 . 执行以下步骤从 CBOE 下 载 put-call 比率。

(1) 转到 http://www.cboe.com/ 。

(2 ) 单击菜单栏上 的 Quotes&Data 选项。

(3 ) 单击 CBOEVolume&Put-Call Ratios 选项。

(4) 单击 CBOE 总交易量和 Put-CallRatios( 1 1 -01-2006 to present)。 编写 一 个 Python 程


序来显示最前和 最后儿 个 日 期。

1 6 . 编写 一 个 Python 程序来检索 put-call 比率, 并绘制图形。 可以用语法 put_call_


graph(path, begdate,enddate) , 指定路径和 两 个 日 期来调用该函数, 如 put_call_graph('c:/temp/
totalpc.csv',20130601 ,013 123 1 ) 。
第 11 章

蒙特卡 罗 模拟和期 权定价

风险和收益之间的平衡是金融领域的核 心问题。 金融风险往往源 自 未来的不确定性。


例 如, 在评估项 目未来的盈利时, 必须预测在项 目的生 命 周 期里影 响项 目利润 的许多因素,
如年销售额、 产品价格、 原材料价格、 员工工资 增长率、通货膨胀率、 借款成本 、 新增股
权成 本和其他经济与行业因素, 等等 。 蒙特卡罗 模 拟 可以用来模 拟未来可能发生 的事件及
其 结果。 本章重点介 绍 蒙特卡 罗 模 拟在期权定价中的应用, 包括以下主要内容 。

• 产生服从 标准正态分布和正态分布的随机数

• 产生服从 均 匀分布的随机数

• 利用蒙特 卡 罗 模 拟估算亢的值

• 产生服从 泊 松分布的随机数

• 可重 复和不可重复的随机取样

• 模 拟服从 对数正 态分布的股票价格

• 模 拟股票价格
变动路径及终端价格

• 寻 找有效的投资组合和有效组合的边界

. 使用蒙特 卡 罗 模 拟计算欧式期权价格

• 路径独立与路径依赖期权

• 预测长期回报率

• 奇异期权
简介

• 具有浮动执行价格的回 望式期权的定价
262 第 11 章 蒙 特 卡 罗 模 拟 和 期 权定 价

• Sobo l 序 列

1 1 .1 产 生 服从标准 正态分布 的 随机数

正 态 分 布 在 金 融 计 算 中 有着重要作用 , 主要 因 为 许 多 金 融理论包括期权理论 的 教学模


型 都 假 设 股 票 回 报率服 从 正 态 分 布 。 以 下 两行代码产生服从标准 正 态 分 布 的 随 机 数 。

>>>impor 七 scipy as sp
>>>x=sp . r andom . s tandard_normal ( s i z e = l O )

NumPy 模 块 的 random() 函 数利 用 Mersenne Twister PRNG 算 法 生 成 了 SciPy/NumPy 模


块 中 的 基 本 随机数 。 该 随机算法运算速度 相 当快 。 使用 print() 函 数来 打 印 前 几个值 , 代码
如下 。

>>>pri nt ( x [ 0 : 5 ] )
( - 0 . 5 5 0 62594 -0 . 5 1 3 38547 -0 . 04208367 -0 . 66432268 0 . 49461661 ]
>>>

也 可 以 使 用 以下 代 码 来 产 生 标准 正 态 分 布 的 随机 数 。

>>>irnpor 七 s c ipy as s p
>>>x = sp . r andorn . norrnal ( s i ze=l O )

这 个语 句 与 下 面 语 句 的作 用 相 同 。

>>> impor 七 scipy as sp


>>>x = sp . random . normal ( 0 , 1 , 1 0 )


random.normal() 函 数 的 第 l 个输入 参 数 是 均 值 , 第 2 个输入参 数 是标 准 方 差 , 最后
个 是 随机数 的 个 数 , 也 就 是 数 据 集 的 大 小 。 均 值 和 标 准 方 差 的 默 认 值 为 0 和 1 。 可 以 使用
help() 函 数 来 了 解 输 入 参 数 的 定 义 。 为 了 节 省 空 间 , 以 下 只 显 示 help() 函 数输 出 结 果 的 前
几行 。

>>>help ( s p . random . norma l )


Help o n built-i n fun c t i on normal :


normal ( . . . )
normal ( l oc=O . O , scale=l . O , s i z e = None )
1 1 .I 产 生 服 从 标 准 正 态 分布 的 随 机 数 263

产生服从 ( 高斯 ) 正态分布的随机样本

正态分布的密度函数 由高斯和拉普拉斯在 200 多年前发现。 正态分布的密度函数具有



个钟 形 曲 线, 如图 1 1 - 1 所示。

040
0 35
030
0.25
D.20
0 15

010
o.os ,.
0.00
-3 -2 -1 0 1 2 3

图 1 1-1

标准正态分布的密度函数由以下的数学公式来表达 。

f(x) =
1 _£.
C ll-1 )

1 1 . 1 .2 利用种子 ( seed ) 生成相同的随机数

我们有时需要重复 产生 相同的随机数。 例如, 当教授解释如何计算 5 个随机数的平均


值、 标 准方差、 偏度和 峰度时, 学生在练习时最好可以得到与教师所演 示的完全相同的值。
另外, 当 调试用来模 拟 股票价格
变化的 Pyth on 代码时, 最好能够重复获得 同样的股票价格。
可以使用 seed() 函数来做到这一点。

> > > import s c i p y a s sp


>>>sp . random . s e ed ( l 2 3 4 5 )
>>>x=sp . random . norma l ( 0 , 1 , 2 0 )
»>print ( x [ 0 : 5 ] )
( - 0 . 2 0 4 7 0 7 6 6 0 . 4 7 8 94 334 - 0 . 5 1 94 3 8 7 2 -0 . 5557303 1. 96578057 )
>>>

以上 代码 使用 123 45 作为种子 。 种子的具体值并不重要, 关键是 同一 个值每次都产生


相同的随机数。

1 1. 1.3 产生 n 个服从正态分布的随机数

使用以下 代码生成 n 个服从 正态分布的随机数 。


264 第 11 章 蒙特 卡 罗 模 拟 和 期 权 定 价

>>> import s c ipy as sp


>>>sp . random . seed ( l 2 3 4 5 )
>>>x=sp . r andom . normal ( 0 . 0 5 , 0 . 1 , 5 0 )
>>>print x [ 0 : 5 ]
[ 0 . 02952923 0 . 09789433 -0 . 00194387 -0 . 00557303 0 . 24657806 ]
>>>

以上 代码与前一 个代码的区别 在于 正态分布的均值是 0.05 而不是 0, 标准偏差是 0. 1


而不是 1 。 正态分布的密度
函数 由以下公式给出, 其 中 µ 是均值, 6 是标准方差 。 显 然, 标
准正态分布只 是正 态分布的 种特殊情况 。 一

e
(x-µ)2

f (x) = 1 2u2
( 1 1 -2 )

1 1.1 .4 正态分布样本的直方图
直方图是用来分析一组数据的统计特征的常用工具。 使用以下代码绘制一组服从 给定
均值和标准方差的正态分布的随机数的直方图。

>>>import s c ipy as sp
>>> import matp lot l ib . pyp l o t as p l t
>>>sp . random . seed ( 1 2 3 4 5 )
>>>x=sp . r andom . normal ( 0 . 0 8 , 0 . 2 , 1 0 0 0 )
>>>plt . hi s t ( x , 1 5 , normed=True )
>>>pl t . show ( )

绘制的结果如图 1 1 -2 所示。

2.0

1.5

LO

0.5

一0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0

图 1 1 -2
1 1 .1 产 生 服 从 标 准 正 态 分 布 的 随机数 265

1 1.1.5 对数正态分布 的图形表示


当股票的收益 率 服 从 正态分布时, 其 价格必然服从 一个对数正态分布 。 对数正态分布
由以下数学公式定义。


1
C l l -3)
2
(ln(x)-µ)

f( x; µ, cr) = e 芷

泣尽

下面的代码绘制 3 个不 同的对数 正 态分 布 的密度函数 曲 线 , 它 们 的参数分别 是


( 0,0.25 ) 、 ( 0,0.5 ) 和 ( 0, 1 .0 ) 。 第 1 个参数代表均 值µ, 第 2 个代表标准方差 <Yo

fr om s c ipy impo r t sqrt , exp , log , p i


import sc ipy a s sp
import nurnpy as np
import matp l o t l i b . pyplot as p l 七
x = np . l inspace ( 0 . 0 0 1 , 3 , 2 0 0 )
mu = O
si gma0 = [ 0 . 2 5 , 0 . 5 , 1 ]
color = [ ' blue ' , ' red ' , ' green ' ]
target= [ ( 1 . 2 , 1 . 3 ) , ( 1 . 7 , 0 . 4 ) , ( 0 . 1 8 , 0 . 7 ) ]
start = [ ( l . 8 , 1 . 4 ) , ( 1 . 9 , 0 . 6 ) , ( 0 . 1 8 , 1 . 6 ) ]
for i in sp . arange ( len ( s i gma O ) ) :
s i gma=s i gma O [ i )
y= l/ ( x * si gma * s qrt ( 2 * pi ) ) * e xp ( - ( l og ( x ) -mu ) * * 2 / ( 2 * s igma * s i gma ) )
p l t . annotate ( ' mu = ' + s t r (mu ) + ' , s i gma = ' + s t r ( s i gma ) , xy = target [ i ] ,
xytext = start [ i ] , ar rowprops=di ct ( facecolor=color [ i ] , s h r i n k = 0 . 0 1 ) , )
p l t . plot ( x , y , color [ i ] )
p l t . t i t l e ( ' Lognormal d i s t r ibu t i on ' )
pl t . x l abel ( ' x ' )
p l 七 . ylabe l ( ' l ognormal den s i 七 y d i s t r ibu七ion ' )
plt . show ( )

将这 3条 曲线合并在一 张图(见图 1 1 -3) 中, 以方便比较它们之间的相似性和差异。


266 笫 11 章 蒙特卡 罗模 拟 和 期 权定价


1.8
Lo_g_norrnal distribution

a
n_

m
.

l

9
u

SI
l l l l 0 0 0 0
6 4 2 0 8 6 4 2

-l
uo1
1nq亡lS!
P Al/
SUap 1
eE JOU601

0.5 1.0 1.5 2.0 3.0


o- i
_ o

图 1 1 -3

1 1 .1.6 产生服从泊松分布的随机数
为了研究私有信息对股票 价格的影响 , Easley 、 Kiefer、 O' Hara 和 Paperman ( 1 996 ) 提
出 了 一个称为知情交易概率 ( PIN ) 的指标 。 这个指标 需 要 利 用 一 天 内 由 买方发起的交易个
数和 由 卖方发起的交易个数来计算 , 它的基本假设 是 一 天的交易个数服 从泊 松分布 。 生成
服 从 泊松分布的随机数的代码 如 下 。

import scipy as sp
import numpy as np
import matp l o t l ib . pyplot as plt
x=sp . random . po i s s on ( lam= l , s i z e= l O O )
a = 5
n = 1000
s = np . random . powe r ( a , n )
count, bi n s , ignored = p l t . h i s t ( s , bins=3 0 )
x = np . li nspace ( O , 1 , 1 0 0 )
y = a*x* * ( a-1 . )
normed_y = n * np . di f f (bins ) [ O ] * y
p l t . plot ( x , normed_y )
p l t . show ( )

1 1.1.7 产生服从均匀 分布的随机数


如果 需 要 从 n 只股票中随机选择 m 只 , 可以利用服从均匀分布的随机数。 用以下 代码
生成服从在 1 - 1 00 之间均 匀分布的 1 0 个随机数。 使用 s e e d ( ) 函数来保证每次获得同样的
随机数 。

> > >import scipy a s sp


1 1 .2 利 用 蒙 特 卡 罗 模 拟 计 算亢的 近 似 值 267

> > >sp . ra ndom . seed ( l 2 3 3 4 5 )


>>>x= sp . random . uniform ( low = l , high= l O O , s i z e = l O )

ran dom . uni form ( ) 函 数有 3 个输入参 数 : low 、 high 和 size 。 第 1 个输入参数指定


最 小 值 , 第 2 个指定最 大 值 , 第 3 个珨 出 需 要 生 成 的 随机 数 的 个 数 。 以 下 列 出 得 到 的 前 五
个随机数 。

>»print ( x [ 0 : 5 ] )
[ 30 . 3 2 7 4 9 0 2 1 20 . 58006409 2 . 43703988 7 6 . 1 5 66 1 2 9 3 7 5 . 069290 8 4 ]
>>>

1 1 .2 利 用 蒙特卡 罗 模拟计算 7t 的 近似值


通过蒙特 卡 罗 模 拟 计 算7t 的 近似值 是 个很好 的 练 习 。 考虑 一 个边 长 为 2R 的 正 方 形 。
这 个 正 方 形 里 可 以 放 入 的 最 大 的 圆 形 的 半 径 为 R 。 这 两 个 形 状 的 面 积可 以 由 以 下 公 式 计 算 。

scircle = pi x R 2
( 1 1 -4 )

ssqu血 = (2R) X (2R) = 4R 2 ( 1 1 -5 )

将 公 式 C l l -4 ) 和 公 式 C l l -5 ) 的 结 果 相 除 , 可 以 得到 以 下 结 果 。

Scircle pi
q11are 4

也就是说亢 的 值 等 于 4*Scircle/Ssquare。 产 生 n 对 随 机 数 : x 和 y , 它们 各 自 分别服从在


o�o.s 之 间 的 均 匀 分 布 。 然 后 计算 分 别 以 x 和 y 为 横坐标和 纵坐标 的 点 与 坐 标 原 点 的 距 离 ,
也 就 是 $了勹了 。 显然 , 当 距 离 小 于 0.5 时 , 这 个 点 会 落 入 以 0.5 为 半径 的 圆 形之 内 。 六的

值 可 以 用 以 下 公 式估计 。

number of darts in circle


pi = 4 x C l 1 -6 )
number of darts in square,ie . . . ,number of simulation

图 1 1 -4 显示这些随机产 生 的 点 落 在 正 方 形和 圆 形之 内 。
268 第 11 章 蒙 特 卡 罗 模 拟 和 期 权 定价

图 1 1-4

以下 Python 代码 使用这 个随机模 拟方法计算7t的近似值 。

import s c ipy as sp
n=l O O O O O
x = sp . random . uni form ( l ow= O , high = l , s i ze=n )
y=sp . random . u n i f o rm ( l ow=O , high = l , s i z e = n )
dis t=sp . s qrt ( x * * 2 + y * * 2 )
in_c i r c l e =dist [ d i s t < = l )
our pi = l e n ( in c i r c l e ) * 4 . / n
print ( ' p i = ' , our_p i )
print ( ' e r r o r ( % ) = ' , ( our_p i - s p . p i ) /sp . pi )

每次运行上 面的代码, 7t的近似值都会有些 不 同, 它的准确程度取决于所用到的随机数


的个数, 即 n 。

( ' pi = ' , 3 . 1 4 5 92 )
( ' err or ( % ) = ' , 0 . 0 0 1 3 7 7 4 3 7 1 4 3 3 1 0 7 3 3 5 )
>>>

1 1 .3 从 n只股票 中 随机选择 m 只
以下的代码从 500 只 股票中随机选择 20 只 。这是研究任意几 只股票如何影响投资组合
的波动率的一 个重要步 骤 。

import s c ipy a s sp
n stocks ava i l able= S O O
1 1 .3 从n只 股 票 中 随 机选择 m 只 269

n stocks = 2 0
x=sp . random . uni form ( low= l , hi gh=n_s tocks_avai l able , s i z e = n_s tocks )
y= [ ]
for i i n sp . arange ( n_stocks ) :
y . append ( i n t ( x [ i ] ) )
f i n a l = sp . u n i que ( y )
print ( f inal )
print ( l en ( f i n al ) )

以上 代码随机产生 在 1 -500 之间均匀分布的 20 个实数, 然后把它们转换成 整数 。 因为


有些 整数可能在转换 后重复出现, 我们可能会得到少于 20 个整数值 。 一 个解决方案是随机
产生超过 20 个实数, 然后选择前 20 个不同的整数 。 另 一 个方法是使用 randrange() 和 randint()
函数。 以下 代码首先从 http://canisius. edu/-yany/yanMonthly.pickle 下 载 一 个数据集, 然后从

包含的所有股票中随机选择 n 只 股 票 。

import pandas a s pd
impor t sc ipy as sp
import numpy as np
n stocks=l O
x =pd . read p i c k l e ( ' c : /temp/yanMonth l y . pkl ' ) x2 = sp . unique ( np . a 工 ray ( x . i ndex) )
x3 = x2 [ x2 < ' Z Z Z Z ' ] # r emove a l l i n d i c e s
sp . random . seed ( 1 2 3 4 5 6 7 )
nonStocks = [ ' GOLDPRICE ' , ' HML ' , ' SMB ' , ' Mkt_Rf ' , ' Rf ' , ' Ru s s 3 0 0 0E_D ' , ' US_DEBT ' ,
' Russ 3 0 0 0E_X ' , ' US_GDP2 0 0 9do l l ar ' , ' US_GDP 2 0 1 3do l l a r ' )
x4=list (x3)
for i in range ( l en ( no n S t o c ks ) ) :
x4 . remove ( nonStocks [ i ) )
k=sp . random . u n i form ( low= l , h i gh= l e n ( x4 ) , s i z e=n_s t o c k s )
y, s= [ ) , [ ]
for i i n range ( n_stocks ) :
index = i nt ( k [ i ) )
y . append ( i ndex )
s . append ( x 4 [ i nd e x ) )
f inal=sp . u n i que ( y )
p r i n t ( fi n a l )
print ( s )

以上 代码加载 一 个 名为 yanMonthly.pkl 的数据集, 其 中


包括 200 多只 股票、黄金价格、
GDP 指标、失业率、 SMB 因子、 H ML 因子、无风险利 率和 Russell 指数等的时间序列 。 我
们删 除该数据集里与 股票无关的数据项 。 扩展 名.pk.I 说 明 该数据集具有 Pandas 模块的数据
类型 。 因为 x.inde双)函数列 出所有索引指标, 而有些 指标会重 复出现, 使用 unique()函数来
270 第 11 章 蒙 特 卡 罗 模 拟 和 期 权 定价

删 除 重复出现的指标。 为了考虑只包括股票 的投资组合, 必须删 除所有 市场指数和其他非


股票证券, 如 HML 和 US_DEBT 。 由于股票市场指数的指标以符 号 ( ^) 开 头, 我们使用
指标少千 zzzz 这 个判断条件来删 除 市场指数。 对于在 A 和 Z 之间的其他指标, 如果需要,
就只能用 remove()函数逐 个删 除。 最终输出结果如图 1 1 -5 所示。
[ 1 2 4 10 17 20 21 24 31 70)
[ 'IO ' , ' A ' , ' AA ' , ' KB ' , 'DELL ' , ' IN ' , ' IHF ' , ' I昭 , ' SKK' I 'BC ' ]
•)

图 1 1 -5

1 1 .4 可重复和 不可重 复 的 随机取样

利用观察 到 的历史价格和回报率, 可以计算它们的平均值、 标准方差和其他相 关统计


盘。 那 么, 如 何 预测未来的价格和回报率呢 ? 最简单 的方法是假 设 历 史会在未来重演 , 可
以用 历史平均值和标 准方差来预测 未来。 如果希望能够更好地预测未来, 就必须找到 一种
更有效的方法来利用历 史数据。 Bootstrapping ( 自 举算法) 是 一 种常用的方法。 例如, 我
们希望利用一 只 股票最近 20年的月 回 报率, 即 24 0 个观察值来估计它在下 一年的 1 2 个月
回报率的概率分布。 首先, 可以从 历 史 回报 率的观察值中以不可重复的方式随机选取 12 个
回报率, 并计算它们的平均值和标准方差。 重 复这 个过程 5 000 次, 可以得到 5 000 个这样
的平均值和标准方差, 它们可以用来作为未来回报 率的概率分布。 可以利用这一分布函数
来了解未来回报率的其他特 征。 也可以用可重复的方式随机选取回 报 率 。

SciPy 模 块 有 一 个函数 称 为 permutation() , 可 以 产 生 不 同 的 排 列 。 以 下 代 码 用


permutatio顶)函数来对 l ,...__ 10这 1 0 个数字重新随机排列 。

import numpy as n p x=range ( l , 1 1 )


prin t ( x )
for i i n range ( S ) :
y=np . random . permutation ( x )
prin t ( y )

该代码的输出如图 1 1 -6 所示。
.[ [ [ [ [ 、,

.7 8 4 2 7 >


8 3 7 4 6
3 7 108 2
4 5 3 3 1
6 2 9 1 3
9 4 1 6 9
1 6 6 9 5
2 1 8 lolo
1
0 9 2 5 4
5 0 5 7 8

一·
_

可以基于 permutation() 函数来编写 一 个具有 3 个输



_.
1

i: :..、

函数: data、 n_obs 和 replacement。 第 1 个参数


入参数的
_.

代表数据集, 第 2 个代表从 数据集中随机选取的数据 个


、,

数, 第 3 个表示是否可重复选取数据。 图 1 1 -6
1 1 .5 年 收 益 率 的 分布 271

de f boots f ( da 七 a , n ob s , replacement=None ) :
impor 七 numpy as np
n=len ( da t a )
i f ( n< n_ob s ) :
print " n i s l e s s thah n obs "
else :
i f rep l a c ement==None :
y=np . random . permu tati on ( data )
return y [ O : n_obs )
else :
y= [ )
for i in range ( n_obs ) :
k=np . random . pe rmutat ion ( data )
y . append ( k [ O J )
return y

上 面的代码要求 已有观测值的数量 应该大于 我们计划随机选取的数据 个数。 这 个约


束 适用于 不可重复的随机选取 。 对于 可重复的随机选取, 可以放宽这 个 约 束, 请 参考相
关练习。

1 1 .5 年收益率 的分布

计算年收益率并绘制它的分布是 一 个很好的练习。 下载 Microsoft 的每 日 价格数据, 计


算它的 日 收益率, 并将其 转换为年收益 率 。 以下代码对这些年收益率应用 Bootstrapping 方
法, 以可重复的方式进行 5 000 次随机取样, 从 而获得样本的统计分布 并绘制图形。

f rom matplo 七 l i b . finance impor 七 quotes_h i s to r i ca l_yahoo_ochl as getData


impo rt matp l o 七 l ib . pyp l o t as p l t
import numpy a s np
import s c ipy as sp
impor 七 pandas as pd

# s 七 ep 1 : input area
ti cker= ' MSFT ' # i nput value 1
begdate = ( 1 9 2 6 , 1 , 1 ) # inpu t value 2
endda 七 e= ( 2 0 1 3 , 1 2 , 3 1 ) # i nput value 3
n s imu lation = S O O O # input value 4

# St ep 2 : r e t ri eve p r i c e data and e s t ima te log returns


x = getDa 七 a ( 七 i c k e r , begdate , enddate , asobj ect=T rue )
272 第 11 章 蒙 特 卡 罗 模 拟 和 期 权定 价

logret = sp . l og ( x . a c l o s e [ l : ) / x . aclos e ( : - 1 ) )

# s 七 ep 3 : e s t imate annua l returns


date = [ l
dO = x . date
for i i n r ange ( O , sp . s i z e ( logre t ) ) :
date . append (dO [ i ] . strftime ( " % Y " ) )

y=pd . Da 七 aFrame ( l ogret , date , co lumns = [ ' logret ' ] )


re t_annua l = sp . exp ( y . groupby ( y . inde x ) . s um ( ) ) - 1
re t_annua l . column s = [ ' r e t_annual ' ]
n—obs = len ( ret_annua l )

# s 七 ep 4 : e s t ima te d i s t r ibution with repla cement


sp . random . seed ( l 2 3 5 7 7 )
final = sp . z e ros ( n_obs , d 七 ype = f l o a t )
for i i n range ( O , n_obs ) :
x=sp . ra ndom . uniform ( l ow=O , hi gh=n_obs , s i ze=n_ob s )
y= [ ]
for j i n range ( n_obs ) :
y . append ( int ( x [ j ] ) )
z=np . array ( ret_annual ) [ y ]
final [ i ] =sp . mean ( z )

# step 5 : g raph
pl t . title ( ' Mean return dis 七 r ibution : number of s imu lations = ' + str
( n s imu l a t i on ) )
p l t . x l ab e l ( ' Mean return ' )
pl t . y l ab e l ( ' Frequency ' )
mean_annual =round ( np . mean ( np . array ( r et_annua l ) ) , 4 )
plt . figtex 七 ( 0 . 63 , 0 . 8 , ' mean annual= ' +str (mean_annua l ) )
p l t . hi s t ( f i na l , 5 0 , normed=True )
p l t . show ( )

绘制的样本分布图如图 1 1 - 7所示 。
1 1 .6 模拟股 价 变 化 273

10 Mean return distribution: number of simulatioins =5000

mean annual=0.3461

6
Au
uanba.y
4
00
1

图 1 1 -7

1 1 .6 模拟股 价变化

前面的章节提到 我们通常假设股票 回报率服从 正态分布, 而 价格服从 对数正态分布 。


在时刻 t +1 的股票价格与时刻 t 的股票价格以及这两 个时刻的间 隔长度有 关, 可以用以下
公式来表达上述关系:

s,+, = s, + 篮,t:,,.t + aS, E 压 C 11- 7)

其 中, s,十 ) 是 t +1 时刻 的股票价格, µ 是股票收益 率的期望值, M 是时间 间 隔 ( fl. t=Tl n),


T 是时间长度 ( 以
年为单位), n 是步数, c 是具有零期望值的随机
变量, 6 是股票的波动率 。
通过
简单的数学变换, 方程 ( 11- 7)可以导 出 以下 方程, 这 个方程将在程序中使用:

S, +I = S, exp (( 三矿 J t:..t + CY E 气 C l l -8 )

在风险中性世界中, 没有投资 者可以从 承担风险中获得补偿。 换句话说, 在这样的世


界中, 任何证券 ( 投资 ) 的预期回报是无风险利 率 。 因此, 在风险中性世界中, 等式 ( I1-8)
可以改写成:

s,+1 = s, exp (( r -扫) f:i. t + a E Ji:j) ( 11-9 )

如果想更多地了解风险中性概率, 请 参考 由 P e ar s on 出 版社出版, 约 翰 · 赫尔所著的


《期权、 期货和其他衍生品》 ( Options, Fu tures and Oth er D erivatives) 一 书 。 以下 Pyth on
代码 模 拟股票价格的
变化路 径 。
274 第 11 章 蒙特卡 罗 模 拟 和 期权定价

import s c ipy as sp
import matpl otlib . pyplo七 as p l t

s t o c k· p r i c e一 today = 9 . 1 5 # s tock p r i c e at time z e ro


T =l . # matur ity date ( i n ye a r s )
n_s teps = l O O . # number o f steps
mu = 0 . 1 5 # expected annual return
s i gma = 0 . 2 # volat i l i t y ( annual i zed)
sp . random . seed ( 1 2 3 4 5 ) # seed ( )
n s imu l a 巨 on = 5 # numb e r o f s imul a 七 i on s
dt = T / n_s 七eps
S = sp . z e r o s ( [ n st eps ] , dtype = float )
x = range ( O , int ( n_steps ) , 1 )
for j i n range ( O , n_s imu lation ) :
S [ O J = s tock pric e today
for i i n x ( : - 1 ] :
e=sp . random . no rma l ( )
S [ i + l ] =S [ i ] +S [ i ] * ( mu- 0 . 5 *pow ( s i gma , 2 ) ) * dt + s i gma * S [ i ] * sp . sqrt
(d七) * e ;
p l t . plot ( x , S )

p l 七 . fi gtext ( 0 . 2 , 0 . 8 , ' S O = ' + s t r ( S [ O ] ) + ' , mu= ' + s t r (mu ) + ' , s i gma= ' + s 七 r ( s i gma ) )
p l 七 . f i gtext ( 0 . 2 , 0 . 7 6 , ' T = ' + s 七 r ( T ) + ' , s 七 ep s = ' + s 七 r ( i nt ( n_steps ) ) )
plt . t i 七 l e ( ' Stock price ( number o f s imulations = %ct ' % n_s imulation + ' ) ' )
plt . xlabe l ( ' Total number of s teps = ' + s 七 r ( i n七 ( n_steps ) ) )
pl t . ylabe l ( ' s tock price ' )
plt . show ( )

为 了 增 加 图 形 的 可读 性 , 图 1 1 -8 只 绘制 了 5 条 模拟 出 的 价 格 曲 线 。 由 于使用 了 seed( )
函 数 , 所 以 可 以 再 次 运 行 上 面 的 代 码 来 完 全 复 制 图 1 1 -8 。

Stock price (number of simu lations = 5 )


14 13 12 1

l
8 µd�,01
l
0 9
s

6
。 20 40 的
Total num�r 9fH�杆气l的
80 100

图 1 1-8
1 1 .7 图 形展 示 期 权 到 期 日 的 股 票 价 格 的 分 布 275

1 1 .7 图 形展示期 权到期 日 的 股票价格的分布

我们在之前 提 到 欧 式 期 权 的 价 值与 到 期 前 的 股 票 价 格 无 关 , 仅 仅 取 决 于 到 期 日 的 股票
价 格 。 因 此 , 需 要 知 道 到 期 日 的股票价格 的概率分布才能给期权 定 价 。 以 下 代码可 以 依据

给定的 组参 数 来 模 拟 期 权 到 期 日 的 股 票 价格 : so ( 初始 股 票 价 格 ) 、 n_simulation ( 模 拟
的 次 数 ) 、 T C 以 年 计 的 有 效 期长度 ) 、 n—steps C 步数 ) 、 mu ( 年 回 报率 的 期望值 ) 和 sigma
( 年 回 报 率 的 标 准 方差 , 又 称波动率 )

from s c ipy impo rt z e r o s , s qr t , shape


耳npor 七 ma 七 p l o t l ib . pyp l o t as p l t
impor 七 s c ipy a s sp
so = 9 . 15 # stock pric e a t t ime zero
T =l . # years
n.. steps=l O O . # number o f s teps
mu =0 . 1 5 lt expected annual return
s i gma = 0 . 2 lt vol a t i l i ty ( annua l )
sp . random . seed ( 1 2 3 4 5 ) lt f i x those random numbers
n simula t i on = 1 0 0 0 井 number of s imu l a t ion

dt =T/n_s teps
S = sp . zeros ( [ n_simulation ] , dtype=float )
x = range ( O , i n t ( n_s 七 eps ) , 1 )
for j i n sp . arange ( n_s imu l a t i on ) :
t t=S O
for i i n sp . arange ( n_steps ) :
e=sp . random . normal ( )
t t+=tt* ( ( mu- 0 . 5 * s igma * * 2 ) *dt + s i gma *sp . s qrt ( d t ) * e ) ;
s [ j l =tt

plt . t i t l e ( ' His togram o f terminal price ' )


pl t . ylabel ( ' Number o f frequenc i e s ' )
pl t . xlabel ( ' Terminal p r i ce ' )
plt . f i gtext ( 0 . 5 , 0 . 8 , ' S O = ' + str ( S O ) + ' , mu = ' +s t r (mu ) + ' , s i gma= ' + s t r ( s igma ) )
p l t . f i gtext ( 0 . 5 , 0 . 7 6 , ' T= ' + s t r ( T ) + ' , s 七 eps = ' + s t r ( i n t ( n_steps ) ) )
plt . f i gtex 七 ( 0 . 5 , 0 . 7 2 , ' Numbe r o f terminal p r i ces= ' + s t r ( i n t ( n_simulation ) ) )
plt . h i s 七 ( S )
p l t . show ( )

期权 到期 日 的 股 票 价 格 的 直方 图 如 图 1 1 -9 所 示 。
276 第 11 章 蒙特卡 罗 模 拟 和 期 权定价

300

50=9.15,mu=0.15,sigma=0.2

2
5
0
T=l.O, ste s=lOO
Number otterminal prices 1000

sa它anba.J

2
0
0
1
0
5
J JJO 史1EnN

0
1
0
0
5
6 8 10 12 14 16 18 20

图 1 1 -9

1 1 .8 寻找有效 的 投 资 组合和 有效边界

本节 将介绍已知两 只 股 票 回报率的期望值 、 标准方差和它们之 间 的相关系数, 如何随


机产生这两只 股票的回报率。 寻 找风险最小的仅包括这两只股票的投资组合。 通过改变股
票 之 间 的相关系数来演 示相关系数对有效边界的影 响, 最后构建一 个包括多 只股票的有效
边界 。

1 1.8. 1 寻找基千两只股票的有效组合及相关 系数的影响

以下 代码用来构 造两只股票 的有效组合。 有 6 个输入参数: 两 只 股票的期望值、 标准


方差、 相关系数和模 拟的次数 。 为了生成两 个互相关联的YI 和Y2 时间序列 , 首先生成两 个
不相关的 X1 和 Xz 序列 , 然后应用以下公式。
Y, = x, ( 1 1-10)

Y2 = px, 十二 ( 1 1-1 1 )

另 一 个问题是构 造 一 个 目标函数。 我们的 目标函数是投资组合的标准方差加上 投资组


合的期望 回报率与 目标 回报率的绝对偏 差 。 也就是说, 我们希望同时优化投资组合的风险
和投资组合的期望回报率与 目标 回 报率的绝对偏 差。

import numpy as np
import s cipy as sp
import pandas as pd
f rom da 七 e time import datet ime as d 七
import matp l o t l ib . pyp lot a s p l t
1 1 .8 寻找有效 的投资组合 和有效边界 277

from scipy . op 七 imi ze import minimi z e

lt S tep 1 : input area


mean_0 = ( 0 . 1 5 , 0 . 2 5 ) # mean returns f o r 2 s 七 ocks
s td_O = ( 0 . 1 0 , 0 . 2 0 ) # s ta �dard devi ations for 2 s tocks
corr = 0 . 2 # corre l a t ion b e 七 ween 2 s tocks
n= l O O O # number o f s imulations ( r eturn s ) for each stock

# s 七 ep 2 : Genera 七 e two unc o r r e l ated t ime s e r i e s


n s t o c k= len (mean 0 )
sp . random . seed ( 1 2 3 4 5 ) # could generate the same random numbe r s
xl=sp . random . n ormal ( l oc =mean_O [ O ] , s cale = std_O [ O ] , s i z e =n )
x:2 = sp . random . no rmal ( l oc=mean_O [ l ] , scale=std_O [ l ] , s i ze=n )
i f ( any ( x l ) <=- 1 . 0 or any ( x 2 ) <=- 1 . 0 ) :
prin 七 ( ' Er r o r : return is <=- 1 0 0 号 I )

# S tep 3 : Gene r a t e two c o r r e l ated time s e r i e s


in dex_=pd . date_range ( start = dt ( 2 0 0 1 , l , l ) , pe r i ods = n , freq= ' d ' )
yl =pd . Da 七 aFrame ( x l , index = index_)
y2 =pd . DataFrame ( c orr_* x l +sp . s qr 七 ( l -c o r r_* * 2 ) *x2 , index=index_)

# s 七 ep 4 : genera 七 e a return ma 七 r i x cal led R


RO=pd . merge ( yl , y2 , le ft_index = True , r i ght_index = True )
R=np . array ( R O )

it St ep 5 : def i n e a few functions


def obj Function ( W , R, ta rget_re t ) :
stock_mean= np . mean ( R , a x i s = O )
port_mean= np . do t ( W , s 七 ock_mean) # port f o l i o mean
cov=np . cov ( R . T ) # var- covar mat r i x
po rt_var np . do 七 ( np . do 七 ( W , cov) , W . T )
= # port f o l i o var iance
pena lty = 2 0 0 0 * ab s ( po rt_mean-targe t_r e 七 ) # pena l t y 4 dev i a t i on
return np . sqrt ( port_var ) + penal t y # ob j e c 七 ive function

# Step 6 : e s t imate optimal por 七 f o l i o for a given return


out mean , out s t d , out we ight = [ ] , ( ] , [ l
s tock.Mean = np . mean ( R , axis = O )

f o r r in np . l i nspace ( np . min ( st ockMean ) , np . max ( stockMean ) , num= l O O ) :


W = sp . one s ( [ n_stock ] ) /n_s tock # s 七 art e qual w
b_ = [ ( 0 , 1 ) for i in range ( n_stoc k) ] # bounds
c_ = ( { ' type ' : ' e q ' , ' fun ' : l ambda W : s um ( W ) - 1 . } ) # constraint
resul t =minim i z e ( ob j Fun ction , W , ( R , r ) , me thod= ' S LSQP ' , con s t r a i n 七 s = c_ ,
278 第 II 章 蒙特卡 罗 模 拟 和 期 权定价

bounds=b )
i f not resu l t . succes s : # handle e r r o r
r a i s e BaseException ( re s u l t . me s sage )

out_mea n . append ( round ( r , 4 ) ) # a few decimal places


std_=r ound ( np . std ( np . sum ( R * result . x , axi s= l ) ) , 6 )
out_s t d . append ( s td_)
out_we i ght . append ( re s u l 七 . x )

# Step 7 : plot the e f f i c ient f rontier


p l 七 . ti t l e ( ' S imu l a t i on f o r an E f f i c i en t Frontier f rom g iven 2 s tocks ' )
p l t . x l abel ( ' S tandard Devi ation o f the 2 - s t o c k Port f o l i o ( R i s k ) ' )
p l t . ylabe l ( ' Retu rn o f the 2 - s t o c k portfol i o ' )
p l t . f i gtext ( 0 . 2 , 0 . 8 0 , ' mean = ' + s t r ( s t o c kMean ) )
p l t . f i gtext ( 0 . 2 , 0 . 7 5 , ' s td = ' + s t r ( s td_O ) )
p l t . f i gtext ( 0 . 2 , 0 . 7 0 , ' c o r r e l at i on = ' + str ( c orr_) )

plt . plot ( np . array ( std_O ) , np . array ( s to c kMean ) , ' o ' , marke r s i ze=B )
pl 七 . p lot (out_s 七 d , out_mean , ' - - ' , l i newidth= 3 )
p l t . show ( )

得到的图形如图 11- 1 0 所示。

0.28
o o 0 0 0 0
262422201816
o-
l
o芒 25Po}


s-z,1
41i
oEaau

0·13
.os 0.10 0.12 0.14 0.16 0.18 0.20 0.22
Standard Deviation of the 2-Slock Portfolio (Risk)

图 1 1-10

接下来, 通过改变两 只股票之间 的相关系数来演 示相关系数对投资组合的影 响 。

impor 七 numpy as np
import sc ipy as sp
impor t pandas as pd
f rom datetime import datet ime as dt
L 1 .8 寻找有效的投资组合和有效边界 279

import mat p l o 七 l i b . pyplot as p l t


f rom scipy . optimi z e import minimi z e

# Step 1 : inp 七 a r e a
mean_0 = ( 0 . 1 5 , 0 . 2 5 ) # mean returns for 2 stocks

std_O = ( 0 . 1 0 , 0 . 2 0 ) # s tandard devi a 七 ions for 2 sotcs
n= l O O O # number o f s imua t i ons ( returns ) for each s t o c k
corr_= ( 0 . 1 , 0 . 5 , 0 . 8 )

# S t ep 2 : Generate two uncor related t ime s e r i e s


n s to c k= len (mean 0 )
sp . random . seed ( l2 3 4 5 ) # could generate the s ame random numbers
x l l = sp . random . no rmal ( l o c= O , s ca l e = l , s i ze = n )
x l 2 =sp . random . normal ( l o c = O , s cale = l , s i z e =n )
n corr=le n ( corr )
S 七y l e = [ I _ • I I __ I I _ I

I I

# S tep 3 : de f i n e a few fun c t i ons


de f obj Function ( W , R , target_ret ) :
s to c k_mean=np . mean ( R , a x i s = O )
port_mean=np . do 七 ( W , s t o c k_me a n ) # portfo l i o mean
cov=np . cov ( R . T ) # var - covar ma 七 r i x
port—var = np . dot ( np . do t ( W , cov) , W . T ) # portfolio variance
penalty = 2 0 0 0 *abs (port_mean-targe 七_re 七 ) # pen a l t y 4 devi a t i on
return np . sqrt (port_va r ) + penal 七 y # obj e c t ive func t i on

for j i n range ( n_cor r ) :


# S tep 4 : Generate two c o r r e l a ted t ime s e r i e s
corr2=c orr_ [ j ]
index_=pd . da te_range ( s tart=dt ( 2 0 0 1 , l , l ) , pe r i ods = n , f req= ' d ' )
x2l =pd . DataFrame ( x l l , i ndex=i ndex_)
x22 =pd . DataFrame ( corr2 * x l l +sp . s qrt ( l - co r r2 * * 2 ) * x l 2 , index=index_)
yl=mean_O [ O ] + x 2 l * s td_O [ O J
y2=mean_O [ l ] +x2 2 * std_O [ l ]

# s tep 5 : generate a return mat r i x cal led R


RO=pd . me rge ( y l , y2 , l e f t_index= True , r i gh 七一index=True )
R=np . array ( RO )

# Step 6 : e s t imate optima l p o r t f o l o for a given return


out mean , ou t s td , out wei ght= [ ] , [ ] , [ ]
s to c kMean =np . mean ( R , axis = O )
p r i n t ( ' haha s t y l e [ j ] ' , s t o c kMe an)
280 第 11 章 蒙 特 卡 罗 模 拟 和 期 权定 价

f o r r i n np . l in space ( np . min ( s 七 o c kMean ) , np . max ( stockMean ) , num= lO O ) :


w = sp . ones ( [ n_ 江 o c k ) ) /n_s tock # s t a r t ing : equal w
b_ = [ ( 0 , 1 ) for i i n range ( n_s 七 o c k ) ) # bounds
c = ( { ' t ype ' : ' eq ' , ' fun ' : l ambda W : sum ( W ) - 1 . ) ) # constraint
r e s u lt =min imi ze ( ob j Func t i on , W , ( R , r ) , method= ' S LSQP ' , constraints=c ,
bounds=b )
i f not result . success :
r a i s e BaseExcept ion ( resu l t . me s sage )
out mean . append ( round ( r , 4 ) ) # a few decimal places
std_= round ( np . s 七 d ( np . s um (R* result . x , a x i s = l ) ) , 6 )
out_s td . append ( s td_)
ou t_we ight . append ( re s ul t . x )
# Step 7A : plot the e f f i c ient f r o n t i e r
p l t . pl o t ( out_s td, out_mean , s t y l e_ [ j ) , l abel = ' corr = ' + s t r ( c orr 2 ) ,
l i newidth= 3 )

# S tep 7 B : plot the e f f i ci en t frontier


stockMean2 = [ round ( s 七 ockMean [ 0 ) , 3 ) , round ( st ockMean [ l ] , 3 ) )
pl t . t i t l e ( ' S imu l a t i on for an E f f i cient Frontier w i th d i f f ren 七 correla tions ' )
p l t . x l abel ( ' St andard Deviation o f the P o r f o l i o ' )
pl t . ylabel ( ' Re 七 urn o f the p o r t f ol i o ' )
p l t . f i gtext ( 0 . 2 , 0 . 8 5 , ' mean = ' + str ( s tockMean2 ) )
plt . f i gtext ( 0 . 2 , 0 . 8 0 , ' s td = ' + s t r ( s td_O ) )
pl t . f igtext ( 0 . 2 , 0 . 7 5 , ' corr = ' + s t r ( corr_) )
p l t . p l ot ( np . array ( s td O ) , np . array ( s tock.Mea n ) , ' o ' , ma r ke r s i ze=l O )
p l t . legend ( l oc= ' lower r igh七 ' )
p l t . show ( )

如图 11-11 所示, 相关系数越低, 这两 只 股 票的有效边界越好。

s,mulatlon for an Efficient Frontier with dlffrent correlations


0.26
mean = (0. 15. 0.252)
std =10.1. 0.2)
0,24 J COIT =(0.1. 0.5. 0.8)
0
=oµ,
8 巴亡一
。 。。 22 20 18 16

.. . .
0Easj

o.18
. oe

图 ll-11
1 1 .8 寻找有效的投 资组合和 有效边界 281

1 1 .8.2 构建 n 只股票的有效边界
任意 n 只 股 票之 间 共有 n * (n - l )/2 个相 关 系 数 , 因 此 当 股 票 数 量 n 增 加 时 , 股 票 之 间
的相 关 系 数 的 个 数迅速增 加 。 比 如 I Q 只 股 票之 间 的 相 关 系 数 已经有 45 个 。 以 下 代 码 随 机
生成两两相 关 的 股 票 回 报 率 。

import numpy a s np
import sc ipy as s p
import pandas a s pd
from datet ime import datetime as dt
f rom s c ipy . optimi ze impor t minim i z e
import matplotl ib . pyp l o t as p l t

# Step 1 : inpu 七 a rea


n stocks = l O
sp . ra ndom . seed ( 1 2 3 4 5 6 ) # produce the same random numb e r s
n cor r=n s 七 ocks * ( n stocks- 1 ) / 2 # number o f c o r r e l a t i on
corr_O=sp . r andom . uni form ( 0 . 0 5 , 0 . 2 5 , n_corr ) # generate c o r r e l ations
mean_O sp . random . uniform ( - 0 . 1 , 0 . 2 5 , n_s toc k s ) # means
=

std_O=sp . r andom . un i forrn ( 0 . 0 5 , 0 . 3 5 , n_s tocks ) # s tandard devi taion


n obs = l O O O # number o f s imua t i ons

# S tep 2 : p roduce correla tion mat r i x : Chol e s ky decompo s i tion


corr_=sp . ze ros ( ( n_s tocks , n_s t o c ks ) )
for i i n range ( n_s tocks ) :
for j in range ( n_stocks ) :
i f i==j :
corr_ [ i , j ] =l
e l se :
corr_ [ i , j ] =corr_O [ i +j ]
U=np . l inal g . cho l e s ky ( co r r_)

lt Step 3 : Generate two uncorre lated t ime s e r i e s


RO=np . z e r o s ( ( n_obs , n_stocks ) )
for i in range ( n_obs ) :
for j in range ( n_stock s ) :
RO [ i , j ) =sp . random . norma l ( l oc =mean_O [ j ) , scale=s td_O [ j ) , s i ze=l )
i f ( RO . any ( ) < = - 1 . 0 ) :
p r int ( ' E r r o r : retur n i s <=- 1 0 0 % ' )

# S tep 4 : gene rat e correlated reurn mat r i x : Cho l e s ky


R=np . dot ( RO , U )
282 第 11 章 蒙 特 卡 罗 模 拟 和 期 权定 价

R= np . ar ra y ( R )

# Step 5 : def ine a few functions


de f ob j Fu nction ( W , R, targe 七_re 七 ) :
stoc k_mean = np . mean ( R , axis = O )
port mean=np . dot ( W , stock mean ) # portfo l i o mean
cov=np . cov ( R . T ) # var-covar ma 七 rix
port_va r=np . dot ( np . dot (W, cov) , W . T) # portfolio va r i ance
pena l t y = 2 0 0 0 * abs (por 七 _mean - target—ret ) # penalty 4 deviation
return np . sqrt (port_var ) + penal 七 y # obj ective function

# Step 6 : e s t imate optimal portfolo for a gi ven return


out me an , out std, out weight= [ ] , [ ] , [ ]
stock.Mean= np . mean ( R , axi s = O )

for r i n np . l inspace ( np . mi n ( stockMean ) , np . max ( stockMean ) , num = l O O ) :


W = sp . ones ( [ n stocks ] ) /n s 七 ocks # start ing : equal w
b_ = [ ( 0 , 1 ) f o r i i n range ( n_s tocks ) ] # bounds
c— = ( { ' type ' : ' e q ' , ' fun ' : l ambda W : sum ( W ) - 1 . } ) # constraint
resul t=minimi z e ( ob j Function , W , (R, r ) , method = ' SLSQP ' , constra ints =c_,
bounds=b )
i f not resu l t . succe s s : # handle error
raise BaseException ( re s u l t . me s s age )
out mean . append ( round ( r , 4 ) ) # a few dec ima l places
std_=round ( np . s 七 d ( np . sum ( R* resul 七 . x , axis=l ) ) , 6)
out_std . append ( s 七 d_)
out_we i ght . append ( re s u l t . x )

Jt S tep 7 : plot the e f f i c i en t f rontier


p l t . title ( ' S imu l a t ion for an E f f i c i ent Fron 七 i e r : ' + s t r ( n_stoc ks ) + ' stocks ' )
plt . xlabel ( ' S tandard Devi ation o f the Porfolio ' )
plt . y labe l ( ' Return of the2 - s tock por 七 fol io ' )
Jt xl im (min ( s td 0 ) , max ( s td 0 ) )
p l t . plot ( out_s td, out_mean , ' - - ' , l inewidth= 3 )
p l t . show ( )

产生的图 形 如 图 1 1 - 1 2 所 示 。
1 1 .9 算 术 平 均 值 与 儿何平均值 283

0.20
Simulation for an Efficient Frontier: 10 stocks


-
_
a
旦0芒

e
_
S

t

s
s
.
·

_



R三

010005000吵
8l


,,
S,


za七 j

,

詹-
'
ouI

`、
mau

、、


-0. 18.



o s
1
0.20 0.25

图 1 1-12

1 1 .9 算术平均值与几何平均值

下 一 节 将应用加权算术和儿何平 均 值来预测长期收益 率 。 这里先熟 悉或 复 习一 下 几


何平均 值 。 对于 n 个回报率( R 1 , R 2, R 五 . . , R n ) , 它们 的算术平均值和几何平 均 值定义如下 :
nT] 曰
R,

-
R

.`

C ll-12)

.
th

n
an
n
e
c
l

1 -n
nrr I
-

l

l
R

R,
。erne

、丿

( 1 1-13)
tnc
g

.
-l

在这 个公式中, R; 是股票的第 l 个回报率 。 可以使用 mean(函数来计算算术平均


) 值。
我们 大多数时候 都使用算术平均值, 因为它较为
简单 。 由于 儿何平均值考虑到投资 的复利
效应, 采用历史数据的几何平均值被认为更准确 一 些 。

个重要的区 别是, 几何平 均 值 往往小于其 对应的算术平均 值 。 由于这 个特点, 许多
人认为使用算术平均值会过高预测未来的回报率。 相反, 使用几何平均值也有可能导致低
估 。 以下是我们 自 己编写的计算回报率的几何平均值的
函数 。

de f geomean_ret ( return s ) :
product = 1
for ret in r e t u rn s :
p r oduct * = ( l + r e t )
return product * * ( 1 . 0 /l e n ( return s ) ) - 1
284 第 II 章 蒙特卡 罗 模 拟 和 期 权定价

给定 一 组 回 报 率 , 计算它们 的 算 术和 几 何平均值如 下 。

>>>import sc ipy as sp
>>>returns = [ 0 . 0 1 , 0 . 0 2 , - 0 . 0 3 , 0 . 0 1 5 , 0 . 1 0 )
>>>geornean_re t ( r eturn s )
0 . 0 2 2 1 4 0 0 4 0 7 7 4 62 3 9 4 8
>>>sp . rnean ( retu rns )
0 . 02 3

1 1 .10 预测长期 回 报率

许 多 研究 人 员 和 从 业者认 为 采 用 历 史 回 报 率 的 算 术平均值会 高 估 未 来 的 长 期 回 报 率 ,
而 采 用 历 史 回 报 率 的 几何平均值会低 估 未 来 的 长 期 回 报 率 。 Jacquier、 Kane 和 Marcus ( 2 003 )
使用 80 年 的 历 史 回 报 率 预 测 未 来 2 5 年 的 回 报 率 , 建议采用 以 下 加 权 算 法 。

25 80 - 2 5
long - term forecast g Rgeometnc. +
=—
O SO
Rari小rnetic C l 1-14)

以下代码采用 了 公 式 ( 1 1 - 1 4 )。

impor 七 numpy as np
impor 七 pandas as pd
f rom matp l o 七 l i b . finance import quo 七 es_h i s t o r i c a l_yahoo_ochl a s getData

t i cker= ' I BM ' # i nput value 1
begdate= ( 1 9 2 6 , 1 , 1 ) # input value 2
endda te= ( 2 0 1 3 , 1 2 , 3 1 ) # i nput va lue 3
n foreca s t = 1 5 # input v a l u e 4

de f geomean_re t ( return s ) :
product = 1
for ret in retu rns :
p roduct * = ( l + r e t )
return p rodu ct * * ( 1 . 0 /l e n ( r eturns ) ) - 1

x= getData ( 七 i c ke r , begdate , enddate , as ob j e c \=True , adj u st ed=Tr u e )
l o g r e t = np . log ( x . ac l o s e [ l : ] / x . a c l ose [ : - 1 ] )
da 七 e= [ ]
dO = x . date
for i in range ( O , np . s i z e ( l ogre 七 ) ) :
date . append ( d O [ i ] . s t r ftime ( " % Y " ) )
1 1 .1 1 用 模 拟 法 为 看 涨 期 权定 价 285


y=pd . DataFrame ( l ogret , date , co lumns = [ ' logret ' ] , dtype=floa七 )
ret_annual = np . e xp ( y . gr oupby ( y . inde x ) . s um ( ) ) - 1
ret_annual . column s = [ ' ret_annual ' ]
n history= len ( ret annual )
a_me an= np . mean ( np . array ( re t_annua l ) )
g_mean=geomean_ret ( np . array ( ret_annu a l ) )
w = n forecast/n h i story
future_ret=w* g_mean+ ( l -w) * a_mean
print ( ' Ar i 七 hme t r i c mean = ' , round ( a_me an , 3 ) , ' Geomean = ' , round ( g_mean , 3 ) ,
' forecast = ' , futu re_r e t )

以下 显示开始几年的年 回报率、 多少年和最终 结果。

>>>ret _annual . head ( )


ret annual
1 9 62 -0 . 326613
1 963 0 . 347305
1964 - 0 . 0 2 2 2 22
1965 0 . 222727
1966 0 . 122677
>>>le n ( re 七 _ann ua l )
52
>>>print ( ' Ari thme t r i c mean = ' , round ( a_me an , 3 ) , ' Geomean= ' , round ( g_mean , 3 ) ,
' forecast = ' , futu r e_r e t )
( ' Ar i thme tric mean = ' , 0 . 12 , ' Geome an= ' , 0 . 087 , ' forecast = ' , array
( [ 0 . 120447 3] ) )
>>>

1 1 .1 1 用模拟法为 看涨期 权定价

只 要知道期权到期 日 的股票价格, 就 可以计算一 个看涨期权在到期 日 的收益 。 看涨期


权在今天的价格等于它在到期 日 的期望收益以无风险利率为贴现率 计算出来的现值 。 以下
代码用这个方法来计算看涨期权的价格。

from s c ipy import z e ro s , s qr t , s hape


import scipy as sp

SO= 4 0 . # stock price at t ime zero


X= 4 0 . # exercise p r i ce
T =0 . 5 # years
286 第 11 章 蒙特卡 罗 模拟和期权定价

r =O . 05 # r i s k-free rate
s i gma = 0 . 2 # volati l i ty ( annua l )
=
n steps l O O . # number o f steps
sp . random . seed ( l 2 3 4 5 ) # f i x those random numbers
n s imula巨on = 5 0 0 0 # number of simula巨on

dt =T /n_steps
call = z e ros ( [ n_simulation ] , dtype=float)
x = range ( O , int ( n_steps ) , 1 )
for j in range ( O , n_s imulat ion ) :
sT=S 0
for i i n x [ : - 1 ] :
e = sp . random . normal ( )
sT* =sp . exp ( ( r - 0 . S * s igma* s igma ) *dt+ s igma * e * s qrt ( d七 ) )
call [ j ] =max ( s T-X , 0 )

cal l_price = sp .mean ( call ) * sp . exp ( - r * T )


print ' ca l l price = ' , round ( ca l l_pr i ce , 3 )

得到的看涨期权价格为 2.75 美 元 。 可以用 同样的方法来为看 跌 期权定价。

1 1 .12 奇异期 权简介

在第 9 章介绍了欧 式 期权和美式 期权, 这些 期权通常被称为“香草期权” , 也称为普通


期权 。 这些 期权的一个特性是它们的收益与股票价格的历史路径无 关 。 还有一 类更加复杂
的期权, 通 常 称为奇异 期权, 因为它们的收益与若 干股票价格的临界值有关。 奇异 期权往
往是为特定的投资 者、银行或公司量 身定做的非标准衍生产品。 奇 异 期权通常在场外交易
(OTC汃 我们没 有类似 Bl ac -k Sch oel s-Mert on 模型这样的解析公式来为奇异 期权定价 。 因此,
必 须用其他方法来确定它们的价格, 蒙特卡罗模 拟是最常用的方法之 一 。 在接下来的几节
将介绍如何给亚式 期权、 数字期权和障碍式期权定价 。

1 1 . 12. 1 利用 蒙特卡罗 模拟给均价期权定价

欧式期权和美式 期权是与路径 无 关的期权, 也就是说期权的收益只与未来某 一个时刻


的股票价格和期权的行使价有关。 有些 投资 者或套期保值者可能更 关心 一 段时间的平均价
格 而不仅仅是某 一个时刻的价格 。 例如, 某炼油 厂担心其 主要原材料石 油 在未来 3个月 内
的价格变动, 计划对原油的未来价格变化进行套期保 值 。 该公司可以买入看涨期权 。 由于
公司 每天消 耗大量的原油 , 自 然更 关心平均价格, 而不是只 关注看涨期权所依赖的 3个月
1 1.12 奇异期权简介 287

后的价格。 因 此, 均价期权将是 更 有效的套期保值工具。 均价期权是 一 种 亚式期权, 其收


益 由 标的股票在 一 个预设时间段 内 的平均 价格确定。 平均价格有两种算法 : 算术平均值和
几何平均值。

亚式均价看 涨期权的收益 函数如 下。

payoff(call) = Max(P,沁吨0 - X, O) ( 1 1-15 )

亚式均价看跌期权的收 益 函数 如 下 :

payoff (put) = Max(X - P.veras• , 0 ) ( 1 1-16)

亚式期权是奇异期权的基本形式 之 一 。 亚 式期权的另 一 个优点 是, 与欧式期权和美式


香草期权相 比 , 它们的成本更低, 因 为平 均价格的波动 率远小 于到期 日 价 格的波动率。 下
面 的 代码计算 一个基于算术平均值的亚 式均 价期权的价格。

import s cipy as sp
s 0=4 0 . # today stock p r i ce
x= 4 0 . # e x e r c i s e price
T=0 . 5 # ma 七 urity in years
r=0 . 0 5 # r i s k- f r e e rate
s i gma = 0 . 2 # vo lat i l i t y ( an nua l i z ed )
n_s imulation = l O O # number o f s imu l a t ions
n_steps = l O O # number o f s tepts

dt=T/n_steps
call=sp . zeros ( [ n_simulation ) , d七 ype=float )
for j i n range ( O , n_simu lation ) :
sT = s O ; total = O
for i in range ( O , int ( n_steps ) ) :
e = sp . random . normal ( )
s T * =sp . e xp ( ( r - 0 . S * s i gma * s i gma ) * dt+s i gma * e * sp . sqrt ( d t ) )
total+=sT
price_a verage = total / n_s teps
ca l l [ j ) =max ( p r i ce_ave rage - x , 0 )
call_p rice =sp . mean ( ca l l ) * sp . exp ( - r * T )
prin 七 ( ' ca l l p r i c e = ' , round ( ca l l_price , 3 ) )
288 第 11 章 蒙特卡 罗 模 拟和 期 权定价

1 1 .1 2.2 利用蒙特卡 罗模拟给障碍 式期权定价

障碍式 期权是 一 类与路径有 关的期权。 障碍式 期权有 一 个决定它 是否有效的触发价格;


除此之外, 在许多方面 类似于 普通 期权。 触发有效期权合约 一 开始 没有价值, 只 有 当 标的
股票价格达到预定的触发价格时, 合约 才生效。 相反, 触发无效期权合约 一 开始是有价值
的, 然而 一 旦标的股票价格达到预定的触发价格, 合 约 就 失效了。 此外 , 过了有效期, 障
碍式 期权可能 一 文 不值, 也可能有 一 个现金回扣。 以下是对 4 种障碍式 期权的描述。

• 向上触发无效: 标的股票价格从 低于 触发价格开始, 一


旦股票价格达到触发价格,
期权合约 就会朱效。

• 向下触发无效: 标的股票价格从 高于 触发价格开始, 一


旦股票价格达到触发价格,
期权合 约 就会失效。

• 向上 触发有效: 标 的 股票价格从 低于 触发价格开始, 只有当股票价格 上 升到触发价


格, 期权合约才会生效。

• 向下触发有效: 标的股票价格从 高于触发价格开始, 只有当股票价格下 降到触发价


格时, 期权合 约 才 会生效。

以下代码计算一 个向上触发无效的障碍式看涨 期权的价格。

import s cipy as sp
impor 七 p 4 f
de f up and out c a l l ( s 0 , x , T , r , s i gma , n s imu l a tion , ba r r i er ) :
n_steps = l O O .
dt=T/n_steps
total=O
for j i n range ( O , n_s imulation ) :
sT = s 0
out=Fa l s e
for i i n range ( O , int ( n_s tep s ) ) :
e = sp . random . norma l ( )
sT*= sp . exp ( ( r - 0 . S * si gma * s i gma ) *dt+s igma * e * sp . sqrt ( dt ) )
i f sT>ba r r i e r :
out = True
if out==Fa l s e :

t o t a l + = p4 f . bs_cal l ( s 0 , x , T , r , s i gma )
return tota l / n s imu l a t i on

模 拟股票价格的
变化路径 n 次, 如 100 次。 每次模 拟假定股票价格在给定时间段内有
I1.13 障 碍 式 期 权 的 平价 关 系 及其 图 形 演 示 289

1 00步 变动。每 当股票价格达到触发价格时 , 期权的收益将为 o, 否 则 收 益 将 是 一个欧式看


涨期权的收 益 。 障碍式期权的价格将是所有未 失 效的看涨期权价格的总和除以模拟次数。

s 0 =4 0 . # today s t o c k p r i c e
x= 4 0 . # exe r c i s e p r i c e
b a r r i e r = 4 2 # b a r r i e r l evel
T=0 . 5 # mat u r ity in yea r s
r = 0 . 0 5 # r i s k- free rate
s i gma= 0 . 2 # volati l i t y ( annua l i zed)
n_simulation l O O # numb e r o f simu l a tions
=

result = up_and_out_ca l l ( s O , x , T , r , s i gma , n_s imulati o n , bar r i e r )


print ' up-and-ou t - ca l l = ' , r ound ( result , 3 )
# up-and-out-cal l = 0 . 6 0 6

以下 代码计算 一个 向 下触发有效的障碍式看跌期权的价格 。

de f down_and_in_put ( s 0 , x , T , r , s i gma , n_s imu l a t i on , ba r r i e r ) :


n_s teps = l O O .
dt=T /n_step s ; 七otal=O
for j in range ( O , n_simu l ation ) :
sT = s 0 ; in_= F a l s e
f o r i in range ( O , int ( n_steps ) ) :
e = sp . random . norma l ( )
s T * = sp . exp ( ( r- 0 . S * s i gma * s igma ) *d t + s i gma * e * sp . sqr七 ( dt ) )
i f sT<ba r r i e r :
i n_= True
Jprint ' sT = ' , s T
Jprint ' j = ' , j , ' ou t = ' , out
if i n_==T rue :
七otal +=p4 f . bs_put ( s 0 , x , T , r , s i gma )
return to七a l /n s imul at i on

1 1 .13 障碍式期 权 的 平价关 系 及其 图 形演 示



个 向 上触发无效的欧式看涨期权和 一 个 向 上触发有效的欧式看涨期权满足 下 面的等
价关系。

callup姐1d-out + callup-and-in = call ( 11-17)

这个关系的逻辑很简单, 如果 股票价格达到触发价格 , 第 1 个期权失去 价值, 而第 2


290 第 11 章 蒙特卡 罗 模 拟 和 期 权定价

个期权开始生效 。 如 果股票价格从来没有触及触发价格 , 第 1 个期权将保持有效 , 而第 2


个期权 一 直没有价值 。 无论哪种情况, 其中 一 个是有效的。 以下 代码演示这种平价关系。

def up_cal l ( s O , x , T , r , s igma , n_simu l a t i on , barrie r ) :


impor七 scipy a s s p
import p 4 f
n_steps = l O O
dt=T /n_steps
inTotal=O
outTo 七 a l = O
for j in range ( O , n_s imu l at i on ) :
sT= s 0
i n S tatus = Fa lse
outStatus=True
for i in range ( O , int ( n_steps ) ) :
e=sp . random . normal ( )
sT* = sp . exp ( ( r - 0 . S * s igma * s i gma ) * dt+s i gma * e * s p . sqrt ( dt ) )
i f sT>ba r r i e r :
outSta 七 us = Fal se
inStatus=True
#pri nt ' s T = ' , s T
#prin 七 ' j = ' , j , ' ou t= ' , out
if outStatus = =True :
outTotal+ = p 4 f . bs_c a l l ( s 0 , x , T , r , s i gma )
e l se :
inTota l + =p 4 f . bs_ca l l ( s O , x , T , r , s i gma )
return outTotal /n_s imu l a t i on , inTotal /n_s imu l a t i on

输入 一 组 值来测 试 一 个 向 上触发无效的欧式看涨期权和 一个 向 上触发有效的欧式看涨


期权相加是否与 一 个普通 欧式看涨期权相 同。

s 0= 4 0 . # today stock p r i ce
x 40 .
= # exercise price
barrier = 4 2 # barrier level
T= 0 . 5 # ma 七 u r i t y in years
r=0 . 0 5 # ris k - f re e rate
s i gma = 0 . 2 # vo l at i lit y ( annu a l i z e d )
n s imulation= l O O # number o f s imul at i ons
upOutCa l l , upi nCa l l = up_c a l l ( s O , x , T , r , s i gma , n_s imulati on , ba r r i e r )
print ' upOutCa l l = ' , round ( upOu 七 Cal l , 2 ) , ' upinCa l l = ' , round (up i nCal l , 2 )
print ' Bl a c k- S choles c a l l ' , round ( p4 f . bs_cal l ( s 0 , x , T , r , s i gma ) , 2 )
1 1 .13 障 碍 式 期 权 的 平价 关 系 及 其 图 形 演 示 291

以下输出结果证 明 了前面所述的等价关系。

upCa l l = 0 . 8 upinCa l l= 1 . 9 6
Blac k-Scho l e s c a l l 2 . 7 6

以下代码使用蒙特 卡 罗 模 拟来以图形的方式表现这种等价关系。 为了使图形清晰, 我


们只绘制了 5 条模 拟 曲 线 。

import matplo t l ib . pyp l o t a s plt


import s c ipy a s sp
import p 4 f
s 0=9 . 1 5 # stock price at t ime z e r o
x=9 . 1 5 # exercise price
barrier = l 0 . 1 5 # barr i e r
T =0 . 5 # matu r i t y date ( i n yea r s )
n_steps = 3 0 # number o f s teps
r =0 . 0 5 # expected annual return
s i gma = 0 . 2 # volat i l i t y ( a nnual i z ed)
sp . random . seed ( 1 2 5 ) # seed ( )
n s imulation = 5 # number o f s imu lations

dt = T / n_s 七 eps
S = sp . zeros ( [ n_steps ] , dtype=float)
time_= range ( O , int ( n_s 七 eps ) , 1)
c = p4 f . bs_c a l l ( s 0 , x , T , r , s i gma )
sp . random . seed ( l 2 4 )
outTo 七 a l , inTotal= 0 . , 0 .
n out , n i n = 0 , 0

for j i n range ( O , n_s imulation ) :


S [O ] = s0
inS tatus=Fa l s e
outSta 七 us = True
for 1. 1.n t ime [ : - 1 ] :
e = sp . random . normal ( )
S [ i + l ] =S [ i ] * sp . exp ( ( r- 0 . 5 * p ow ( s i gma , 2 ) ) * dt+s igma * sp . s qrt (dt) * e )
i f S [ i + l ] >b a r r i e r :
outStatus = False
inSta 七 us = True
plt . plot ( 七 ime_ , S )
i f outStatus=True :
outTotal+ = c ; n out+ = l
else :
292 第 11 章 蒙 特 卡 罗 模 拟 和 期 权 定价

inTotal + = c ; n_i n+=l


S=sp . zeros ( i nt ( n_steps ) ) +ba r r i e r
p l t . pl o t ( time_, s , ' . - ' )
upOu七Ca l l = round ( outTotal /n_s imul a t i on , 3 )
up inCa l l=round ( inTota l / n_s imu l a t i on , 3 )
p l t . f i gtex七 ( 0 . 1 5 , 0 . 8 , ' S = ' + s t r ( s 0 ) + ' , X= ' +s t r ( x ) )
plt . f i gtext ( 0 . 1 5 , 0 . 7 6 , ' T= ' +s t r ( T ) + ' , r = ' + s t r ( r ) + ' , s igma== '
+ s 七 r ( s i gma ) )
pl t . f i gtext ( 0 . 1 5 , 0 . 6 , ' barr ier= ' + s t r (barr i e r ) )
pl t . f i gtext ( 0 . 4 0 , 0 . 8 6 , ' ca l l p r i c e = ' + s t r ( round ( c , 3 ) ) )
p l t . f i gtext ( 0 . 4 0 , 0 . 8 3 , ' up_and_out_call = ' + s t r ( upOutCa l l ) + ' ( = ' + s t r
( n_ou t ) + ' / ' + s t r ( n_s imul ation ) + ' * ' +s t r ( round ( c , 3 ) ) + ' ) ' )
p l t . f i gtext ( 0 . 4 0 , 0 . 8 0 , ' up_and_in_c a l l = ' + s t r ( up i nCa l l ) + ' ( = ' +str
( n_in ) + ' / ' + s t r ( n_s imu l a t i o n ) + ' * ' + s t r ( r ound ( c , 3 ) ) + ' ) ' )

plt . 七 i t l e ( ' Up-and-out and up-and- in p a r i 七 y ( # o f s imul a 七 i ons = %d ' %


n s imu l a 巨 o n + ' ) )
plt . x l abel ( ' Total number o f steps = ' + s 七r ( i n七 ( n_s 七ep s ) ) )
pl t . y l abel ( ' s t o c k p r i c e ' )
p l 七 . show ( )

是 0 . 63 美元。 有 一 条模 拟
模 拟的股票 价格曲 线如图 1 1 - 1 3 所示。 普通看涨期权的价格
曲 线 中 股票价格达到触发价格, 向上 触发无效的欧式看涨期权的价格
是 4/5 X 0 .6 3 , 而向上
触发有效的欧式看 涨期权的价格是 1 /5 X 0.63 。

u.o Up-and-out and up-and-in parity (# of simulations = 5 )


11.5

11.0

10.5 � barrier =lO.l




1
0
二 :>OlS

9
5

9.0

8,5

10 15 30
8.0
s

0
Total number of ste_!l_s =30
20 25

图 1 1-13
1 1 . 14 具有浮动 执行价格 的 回 望 式 期权 的 定价 293

1 1 .14 具有浮动执行价格 的 回 望式期 权 的 定价

回 望 式 期 权 的 价 值 与 标 的 股 票价格 的 历 史路径有关 , 因 此 它 们 也 是路径依赖 的 奇 异 期


权 。 有 一 类 回 望 式 期 权 具 有浮动 的 执 行 价 格 。 如 果 执 行 价 格 是 期 权有 效 期 内 标 的 股 票 价 格
的最低值, 一个看涨 期 权 的 收益 函 数 可 以 由 以 下 公 式 计 算 。

Payoff = Max( Sr - Smin , 0 ) = Sr - Smin C l l-18 )

下 面 的 Python 代 码 计 算 具 有浮 动 执 行 价 格 的 回 望 式 期 权 的 价 格 。

de f l o o kback_min_pri ce_as_s 七 r i ke ( s , T , r , s i gma , n_s imulation ) :


n_s teps = l O O
dt=T/n_s teps
total=O
for j in range ( n_simulation ) :
min_p r i c e = l O O O O O . # a ve r y big numb e r
sT = s
for i i n range ( i nt ( n_s 七 ep s ) ) :
e = sp . random . norma l ( )
s T * =sp . exp ( ( r - 0 . S * s i gma * s i gma ) *dt+ s i gma * e * s p . s qr七 ( d 七 ) )
i f s T<min_p r i c e :
min_price = sT
# p r int ' j = ' , j , ' i = ' , i , ' 七 otal= ' , total
t o t a l + =p 4 f . b s_c a l l ( s , min_p r i c e , T , r , s i gma )
return tota l / n s imul at i on

以 上 的 函 数 需 要用 到 SciPy 和 p4f 模块 , 必 须 在 调 用 函 数之 前 导 入 这 两 个 模块 , 代码
如下。

>>>import sc ipy as sp
>>>import p 4 f
>>>s= 4 0 . # today s to c k price
>>>T=0 . 5 # maturity i n years
>>>r = 0 . 0 5 # r i s k- f ree rate
>>>sigma=0 . 2 # vol a t i l i t y ( annua l i z e d )
>>>n_s imulation= l O O O # number o f s imu la 七 ions
>>>result=l ookback_min_pri ce_as_s t r i ke ( s , T , r , s igma , n_simu l a t ion )
>>>print ( ' lookback min price as s t r i ke = ' , round ( re s u l t , 3 ) )


运 行 以 上代码 次的结果如下。
294 第 11 章 蒙 特 卡 罗 模 拟 和 期 权定 价

lookback m i n p r i c e as s 七 r i ke = 5 . 3 0 4

1 1 . 1 5 使 用 Sobol 序 列 来提高效率

在应用蒙特 卡 罗 模 拟来解决金融相关问题时, 需要用到大量 的 随 机数, 尤其 对精度要


求 非 常高时。 例如, 在给期权定价时, 需要使用非常 小 的间隔来增 加期权价 格的估计值的
精确度。 因此, 蒙特卡 罗 模 拟的效率是 一 个非 常重要的考虑因素, 其 中
包括计算所需的时
间和资 源。 提高效率 的 一种方式是使用正 确 的 算 法来优化 我们的 代码。 另 一种方式是使用
更快、 更 好 的 随 机数生成器, Sobol 序列 是其 中之 一 。 Sobol 序列 属 于 所 谓 的低差异序列 ,
具有随机数的特性, 而且 更 均 匀 地分布。 可以从 几 个网站获得与 Sobol 序列 相关的 Python
代码, 比如在 http://people.sc.fsu.edu/-jburkardt/py_src/sobol/sobol.html 网 页 下 载 由 Corrado
Chisari 编写 的 名为 sobol_lib.py 的 Python 程序。 另 一 个相关的 网页是 https://github.conv
naught ! 01/sobol_seq 。

1 1 . 1 6 小结

本章讨论了几种不 同的 统计分布, 包括正态分布 、 标准正态分布、 对数正 态分布和泊


松分布等。 假设股票 价格服从 对数正态分布而回报 率服从 正态分布, 可以使用蒙特卡 罗模
拟来计算 欧式期权的 价格。 亚式期权在某些情 况下能够更 有效地完成 套期保值 的 作 用 。 奇
异 期权 比普通期权更 复杂, 因为奇异期权的 价格不 能 由 一 个数学公式来表达, 而普通期权
的 价 格可以用 Black-Scholes-Merton 公式来计算。 使用蒙特卡 罗 模 拟是给奇异期权定价的常
用办法。 最后还详细 讨论了为亚式期权和回望式期权定价的 Python 代码。

在下一 章, 将 讨论如何篮度股票价格的波动率。 标准方差和下偏 标准方差 ( LPSD) 是


常用的方法。 使用标准方差作为风险度量 的 一 个合理假设是股票回报 率服从 正态分布。 因
此, 下一 章介 绍 儿种检验正态性 的方法。 另外, 还用图表显示波动率 的集聚效应, 即高波
动率 的交易 日 扎堆出现, 而低波动率 的交易 日 也聚集在 一 起。 Engel ( 1982) 首次提出了 自
回 归 条件异方差 ( ARCH) 模型, 可以很好地用数学方法来刻 画这一 现象。 这是 Engel 获得
诺 贝尔经济学奖 的 主要工作。 Bollerslev ( 1986) 对 ARCH 模型加以扩展, 提出了广义 自 回
归 条件异方差 ( GARCH) 模型。 我们在下一章介 绍 并且 用 Python 演 示这些 模型。
练习题 295

练习题

I . 从 Yahoo! Finance 下 载 DELL\的每 日 价格 。 估 计 每 日 收 益 率 并 将 其 转 换 为 月 收 益 率 。


假 设 月 收 益 率 服 从正 态 分 布 , 用 DELL 的 月 收 益 率 的 均 值 和 标准方差来绘制 正 态 分 布 的 密
度 函 数 曲线。

2 . 调 试 以 下 代码 。

import s c i p y as sp
S O = 9 . 1 5 ; T =l ; n_s teps = l O ; mu = O . l S ; s i gma = 0 . 2
n s imu l a t i on = 1 0 ; dt =T /n_s teps
S = sp . zeros ( [ n_s 七eps ] , dtype = f l o a t )
x = range ( O , i n t ( n—steps ) , 1 )
for j i n range ( O , n_s imu l a t i o n ) :
S [ O] = SO
for i i n x [ : - 1 ] :
e=sp . random . normal ( )
S [ i +l ] =S [ i , j ] + S [ i ] * (mu- 0 . 5 *pow ( s i gma , 2 ) ) * d 七 + s i gma * S [ i ] * sp . s q r t ( d七 ) *e
plot ( x , S )
figtext ( 0 . 2 , 0 . 8 , ' S O = ' + s 七 r ( S O ) + ' , mu = ' + s t r (mu ) + ' , s i gma = ' + s t r ( s i gma ) )
figtext ( 0 . 2 , 0 . 7 6 , ' T = ' + str ( T ) + ' , s t ep s = ' + str ( i nt ( n_steps ) ) )
t i t l e ( ' S t o c k price ( number o f s imu la七ions = % d ' % n s imula七ion + ' ) ' )
x l abel ( ' To 七 a l number o f steps = ' + str ( n_step s ) ) )
ylabel ( ' s 七ock p r i c e ' ) ; show ( )

3 . 编写 一个 Python 程序来计算基于算术平 均 值 的 亚 式 均 价 期 权 的价格 。

4 . 编 写 一 个 Python 程序来计算基 于 几 何 平 均 值 的 亚式 均 价 期 权 的价格 。

5 . 编 写 一 个 Python 程序来计 算 向 上触碰生效 的 看 涨 障碍式 期权 的价格 。

6 . 编 写 一 个 Python 程序来计算 向 下 触碰无 效 的 看 跌 障 碍式 期 权 的 价格 。



7. 编写 个 Python 程序来展示 向 下 触碰无 效 的 障碍 式 期 权 和 向 下触碰生效 的 障碍 式
期 权 的 等 价关 系 。

8 . 编 写 一 个 Python 程序来使用 SciPy 模 块 的 permutation() 函 数 , 从过去 5 年 的 月 收益


率 中 可 重复地随机选择 1 2 个 月 收 益 率 。 使用 花旗集团 2009 年 1 月 1 日 到 20 1 4 年 1 2 月 3 1
日 之 间 的 月 收益率来 测 试你 的 程 序 。

9 . 编 写 一 个 Python 程序对 n 个 月 回报率运用 自 举算 法 ( 即 bootstrapping 算法 ) , 每 次


选择 m 个回报率 , 并 且 m> n 。
第 12 章
波 动 率和 GARCH 模型

金融风险往往来源于 未来的不确定性。 我们通常假设股票价格服从 对数正态分布, 因


而股票 回报率服从 正 态分布 。 基于此假设, 股 票 回报 率的标准方差 常用来量度 金融风险,
也称为波动率 。 股票回报 率 可以为正也可以为负, 但 我们不会把正的回报视为风险。 为了
更准 确地衡量风险, Sortino ( 1 983) 提出应该区分正负 回 报率, 并且用下偏 标准方差作为
金融风险的测 度 。 另外, 到 目 前为止, 我们一 直假设 回 报率的标准方差或波动率是 一 个常
数, 不会随时间而改变 。 这其 实并不正确 。 我们通常观察到波动率的集聚效应, 即高波动
率的交 易 日 扎堆 出现, 而低波动率的交 易 日 亦聚 在一 起 。 Engel ( 1 982 ) 首次提出 了 自 回 归
条件异方差 (ARCH ) 模型, 用数学方法来描述这一 现象 。 Bollerslev ( 1986) 对 ARCH 模
型加以扩展, 提 出 了 广义 自 回 归 条 件异方差 (GARCH) 模型。 本章的主要内容 如下。

• 基于正 态 假 设 下波动率的度量

• 检验正态分布假 设
• Sortino ( 1 983) 提出的下偏标准方差 ( LPSD)

• 检验两 个时期段的波动率是否相等
• Breuscb 和 Pagan C l 979) 的异方差检验

• 从 Yahoo! Finance 检 索期权数据

. 计算波动率微笑 曲 线 的斜度和偏度

• 自 回 归 条 件异方差 (ARCH) 模型
\

• 模 拟 ARCH C l ) 时间序列

• 广义 自 回 归 条件异方差 CGARCH ) 模型
12.2 检验正 态 分 布 297

• 模 拟 GARCH C 1 , 1 ) 时间序列

• 采用改 良的 garchSimO函数模 拟 GARCH(p, q) 模 型

• Glosten 、 Jagannathan 和 Runkle ( 1 993 ) 的 GJR_GARCH 模 型简介

1 2. 1 传统 的风险测度 - 标准方差

大多数金融教科书使用标准方差作为风险测度。 这基于一 个关键假设, 即 股票 回报率


服从 正态分布。 标准方差和方差都可用于衡量不确定性, 我们通常称标准方差为波动 率。
例如 IBM 的波动率为 20% , 通常是指其 年回报率的标 准方 差等于 20% 。 下面的代码以 IBM
为例来估计其 波动率。

import numpy a s np
from matp lotl i b . f inance impo rt quotes_h i st orical_yahoo_ochl as getData

t i c ke r = ' I BM '
begdate= ( 2 0 0 9 , 1 , 1 )
enddate = ( 2 0 1 3 , 1 2 , 3 1 )
p =getData ( t ic ker , begdate , enddate , as obj e c t=True , adj u s t e d =True )
ret = p . a c l o s e [ l : ] /p . a c l o s e [ : - 1 ) - 1
std_annu a l =np . s td ( ret ) * np . sqrt ( 2 5 2 )
print ( ' vo l a t i l i t y ( s td) = ' , round ( s 七 d_annual , 4 ) )

以下 输 出 显示 IBM 的年度波 动 率为 20.93% 。

>>>print ( ' vo l a t i l i t y ( s t d) = ' , round ( s td_annua l , 4 ) )


( ' vo l a t i l ity ( s td) = ' , 0 . 2 0 9 3 )
>>>

1 2.2 检验正态分布

Shapiro-Wilk 是常用的正态分布检验。 以下 代码用 Yahoo ! Finance 提供的最近 5


检验
年的数据来检验 I BM 的 日 回报率是否服从 正态分布。

f rom s c ipy imp o r t stats


f rom matp l o 七 l i b . f i nance impor t quotes_h i s t o r i c a l_yahoo_ochl as getData
import numpy a s np
t i cker = ' I BM '
298 第 12 章 波 动 率 和 GARCH 模 型

begdate= ( 2 0 0 9 , l , l )
enddate= ( 2 0 1 3 , 1 2 , 3 1 )
p =getData ( t icker , begdate , enddate , asobj ect=True , adj ust ed=True )
ret = p . a c l o s e [ l : ] /p . aclose [ : - 1 ] - l

print ( ' t i c ker = ' , t i c ke r , ' W- t e s 七 , and P-value ' )


print ( s 七a七 s . shapiro ( re 七 ) )

结 果 如 图 1 2- 1 所 示 。

('ticker=', 'IBM', 'W-test, and P-value')


(0.929502069950 I 038, 7 .266549629954468e-24)

图 1 2- 1

结 果 显 示 的 第 l 个值是检验统计 量 , 第 2 个值是其对应 的 p 值 。 这个 p 值非常接近于


o, 因 此拒绝零假 设 。 也就是说 , 这 些 数 据 证 明 IBM 的 日 回 报 率 不 服 从 正 态 分 布 。 还 可 以
应 用 Anderson-Darling 测 试 , 这 是 Kolmogorov-Smirnov 测 试 的 一 个 改进版 , 可 以 用 来检验
一 些 常 见 的 统 计 分 布 。 stats.anderso顶) 函 数 可 以 检 验 正 态 分 布 、 指 数 分 布 、 逻 辑 分 布 和

Gumbel 分 布 等 。 调 用 该 函 数 并 打 印 测 试 结 果 , 显 示 如 下 。

>>>>prin七 ( s tats . ande rson ( re 七 ) )


Ande rs onRe s u l t ( st ati s 七 ic=i n f , critical_value s=array ( [ 0 . 5 7 4 , 0 . 6 5 4 ,
0 . 7 8 5 , 0 . 9 1 5 , 1 . 0 8 9 ] ) , s i gnifi cance_leve l=array ( [ 1 5 . , 1 0 . , 5. ,
2.5, 1. ] ) )

这 里 显 示 3 组值 : Anderson-Darling 检验统计量 、 临 界 值 和 相 应 的 置信 水 平 , 如 1 5%、


1 0% 、 5%、 2.5%和 1 % 。 如 果选择 1 % 的 置信水平 , 即 第 3 组 的 最后 一 个 值 , 它对应 的 临 界

值 是 1 .089 , 即 第 2 组 的 最 后 个 值 。 由 于 输 出 的 检验 统 计 量 是 无 限 大 的 , 远 高 于 临 界值
1 .089 , 因 此拒 绝 零假 设 , 得 到 与 Shapiro-Wilk 测 试相 同 的 结 论 。
一 一
正态分布的 个 重 要 性 质 是 , 可 以 使 用 期 望 和 方差 , 即 阶和二阶矩 , 来完全确定整
个分布 函 数 。 给 定 n 个观 察 到 的 回 报 率 , 以 下 等 式给 出 了 它 们 的 前 4 阶矩 。 期 望 值 ( 平均
值 ) 的定义如下 。
n了] 曰
R,

-
R
µ

( 1 2- D
n

其 ( 样 本 ) 方差 由 以 下 等 式 定 义 。 标准方 差是方差 的 平 方 根 。
1 2 .2 检验正 态分布 299

f (R; 一 时
i=I
a- = ( 1 2-2 )
n-1

由 以 下 公 式 定 义 的 偏 度 表 示 分 布 是否倾斜到左边或右边 。 对 称 分 布 的 偏度等于 0 。

L (R; - 时
i=I
skew = ( 1 2-3 )
( n - 1)矿

峰度 反 映 了 极 值 的 影 响 。 以 下 公 式 给 出 了 计 算 峰 度 的两种 定 义 , 区 别在 千 是 否 减 去 3 。
在等式 ( 1 2-5 ) 中 减 去 3 的 原 因 是 , 所 有 正 态 分 布 的 峰度 值等 于 3 。

L (R; 一 对
i=l
kurtosis = 0 2-4 )
( n - 1)矿

I (R; - 时
( excess)kurtosis = -3 ( 1 2-5 )
(n - 1)矿

一些书把等式 C l 2-5 ) 计 算 的 结 果 称 为 超 额峰 度 。 不 过 , 相 当 多 的软件仍然把等式 ( 1 2-5 )


的计算结果 称 为 峰 度 , 因 此需 要特 别 留 意 软件包里 对 函 数 的 说 明 。 我 们 知 道 标 准 正 态 分 布
具 有 零 均 值 、 单位标准方差 、 零 偏 度 和 零 峰 度 ( 基于等式 C 1 2-5 ) 计 算 的 峰度 值 ) 。 图 1 2-2

中 的 输 出 验证 了 这 点。

from scipy import s t at s , random


import numpy as np
random . seed ( l 2 3 4 5 )

ret=random . n ormal ( 0 , 1 , 5 0 0 0 0 )
print ( ' mean = ' , np . mean ( re t ) )
print ( ' s td = ' , np . std ( re t ) )
print ( ' s kewness = ' , stats . s kew ( re t ) )
print ( ' kur 七 o s i s = ' , s tats . kur t o s i s ( re t ) )

('mean =', -0.001 8 1 05809899753 1 57 )


('std =', I .002778 1 4457448 1 )
('skewness=', -0.0 I 4974456637295455 )
('kurtosis=', -0.03657086582842339)
图 1 2-2
300 第 1 2 章 波 动 率 和 GARCH 模 型

以上 的均 值、 偏度和峰度都接近于零, 而标准方差接近于 1。 接下来, 计算标普 500


指数的 日 收益率的前 4 阶矩 。

fr om s c ipy impo r t stats


from matp l o t l i b . f i nance import quotes_h i s to r i c a l_yahoo_ochl a s getData
import numpy a s np

ticker= ' "GSPC '


begda te = ( l 9 2 6 , 1 , 1 )
endda te = ( 2 0 1 3 , 1 2 , 3 1 )
p = getData ( t i c ke r , begdate , enddate , asobj ect=Tru e , adj us ted=True )

ret = p . a c l o s e [ l : ] /p . a c l o s e ( : - 1 ] - 1
print ( ' S & P S O O n = ' , l en ( r e t ) )

p r i nt ( ' S & P S O O mean = ' , round (np . mean ( r e t ) , 8 ) )

p r i n t ( ' S & P S O O std ' , round ( np . s t d ( r e t ) , 8 ) )


=

print ( ' S & P S O O s kewne s s = ' , round ( s tats . s kew ( re t ) , 8 ) )


print ( ' S & P S O O kurtos i s = ' , round ( s ta七s . kurto s i s ( r e t ) , 8 ) )

以上 代码输出的 5 个值, 包括观察值的个数如图 12-3所示。


('S&PSOOn=', 1 6 1 02)
('S&P500mean=', 0.00033996)
(' S&P500std=', 0.0097 1 895 )
('S&P500skewness=', -0.65037674)
('S&P500kurtosis=', 2 1 .24850493 )

图 1 2-3

基于这些 数字, 可以得出结论: 标普 500 指数的 日 收益率向左边倾斜(偏度为负), 有


肥尾(峰度等于 21 .25, 远远大 于 0 )。

1 2.3 下偏标准方差

使用 回报率的标准方差来衡量风险的 一 个问题
是把正向的回 报 率也视为风险。 第 2 个
问题是以平均 值为中心来考虑偏差, 而 不是从 一 个固定的基准, 如无风险利率。 为了克服
这些缺点, S orti n o (1983)提出了下偏标准方差, 它定义为偏离无风险利 率的距 离平方 的
平 均值, 如下 式所示。
1 2.3 下 偏 标 准 方 差 301

L (R; - R/ )
2

i=I
LPSD = ' 其 中 R; - R1 > 0 C l 2-6 )
n-1

因为这个定义用到无风险利率, 所以生成 一个包括无风险利 率的 Fama-French 数据集。


首先, 从 http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library. html 下载每 日 数
据, 然 后解压缩并删 除 文本 文件末尾的非数据部分, 把最终的文本文件保存在 C:/temp/下,
并运行以下代码。

import date七 ime


impor 七 numpy as np
import pandas as pd
fi le=open ( " c : / t emp/ f f Dai l y . 七xt " , " r " )
da ta= fi l e . readl i n e s ( )
f= [ ]
index= [ ]

for i in range ( S , np . s i z e ( data ) ) :
t=data [ i ] . s p l i t ( )
t O_n=int ( t [ O ] )
y=int ( t O _n / 1 0 0 0 0 )
m= in七 ( t O_n / 1 0 0 ) - y * l O O
d=int ( 七 O_n ) - y * l O O O O-m* l O O
index . append ( da七et ime . dat e t ime ( y , m , d ) )
for j in range ( l , S ) :
k= float ( t [ j l )
f . append ( k / 1 0 0 )

n=len ( f )
f l =np . res hape ( f , [ n / 4 , 4 ] )
f f=pd . DataFrame ( f l , index=index , col umns= [ ' Mkt_Rf ' , ' SMB ' , ' HML ' , ' Rf ' ] )
f f . to_p i c k l e ( " c : /七emp / f f D a i l y2 . pkl " )

生成的数据集的名称为 ftDaily.pickle 。 可以用以上步骤 自 己生成这个数据集, 或者从


直接下载该数据集 。 可以用以下代码利用过去 5
http://canisius.edu/-yany/python/flDai ly.pk.I
年的数据 ( 2 009年 1 月 1 日 至 2 0 1 3年 1 2 月 3 1 日 ) 来估计 IBM 的 LPSD 。

import numpy as np
import pandas a s pd
from s cipy import s tats
from ma七pl o t l i b . f i n ance impo rt quotes h i s t o r i c a l yahoo ochl as getData
302 第 12 章 波 动 率 和 GARCH 模 型


t i c k e r = ' I BM '
begdate = ( 2 0 0 9 , 1 , 1 )
enddate = ( 2 0 1 3 , 1 2 , 3 1 )
p =getData ( t i c ke r , begdate , enddate , a s obj ect = True , adj usted=True )
r e t = p . a c l o s e [ l : ) /p . a c l o s e [ : - 1 ) 一 1
date_=p . date
x=pd . DataFrame ( data=ret , index=date [ 1 : ) , co l umns = [ ' re t ' ) )

f f=pd . read主 i c k l e ( ' c : /七emp / f f Dai l y . pkl ' )
final=pd . me r ge ( x , f f , l e f t—index = True , r i ght_index = T rue )

k=final . re t - fi n a l . RF
k2=k [ k< O ]
LPS D=np . std ( k2 ) * np . sqr七 ( 2 5 2 )
prin七 ( " LP S D= " , L P S D )
p r i n t ( ' L P S D ( annua l i z ed) for ' , t i c k e r , ' i s ' , round ( L P S D , 3 ) )

图 1 2-4 显示 IBM 的 LPSD 等千 1 4 .6% , 与上 一 节中显示的 20.9%有很大 的不 同。

( ' LPSD (annualized) for ', ' IBM', 'is ', 0. 1 46)

图 1 2-4

1 2.4 检验两个 时 间 段 的 波 动 率是否相 等

股票 市场在 1 987 年 1 0 月 曾经大 幅下跌, 我们想知道股票价格的波动率在 1 987 年市场


崩 溃之前和之 后是否相等。 这里以福特汽车公司 ( Ford Motor Corp , 股票代码 F ) 为例 ,
说 明 如何检验波动率 在两 个时间 段是否相等。 下面的 Python 代码定义一 个 ret_f() 函数从
Yahoo !Finance 下 载 福特汽车公司的每 日 价格数据, 并估算其 日 回报率。

import numpy as n p
import s c ipy as sp
耳np o r t pandas as pd
f rom matp l ot l i b . finance import quotes —hi s \o r i c a l —yahoo_ochl as getData

# i nput a rea
ticker= ' F ' # stock
begdat e l = ( l 9 8 2 , 9 , l ) # s t a r t ing date for p e r i od 1
endda t e l = ( 1 9 8 7 , 9 , 1 ) # ending date f o r pe r i od 1
1 2 .5 利 用 Breusch 和 Pagan ( 1 979 ) 方 法 检 验 异 方 差 303

begdat e 2 = ( 1 9 87 , 1 2 , l ) # s tarti n g date for period 2


enddate2= ( 1 9 92 , 1 2 , 1 ) * ending date for p e r i od 2

* de f i ne a fun c 七 i on
de f ret f ( t i c ke r , begdate , enddate ) :
p = getData ( ti c k e r , begdate , enddate , as obj e c t = True , adj us七e d= True )
re七 = p . aclose [ l : ) /p . a c l o s e ( : - 1 ] - l
dat e_=p . date
return pd . Da 七aFr ame ( data=re t , index=date [ l : ) , columns = [ ' r et ' ) )

# ca l l the above function twice
r e t l =ret_f ( 七i c ke r , begdate l , enddate l )
ret2=ret_f ( ti c ke r , begdate2 , e nddate2 )

* output
print ( ' S td period #1 vs . s七d p e r i od # 2 ' )
print ( round ( sp . s t d ( re t l . ret ) , 6 ) , r ound ( s p . s td ( r et2 . r e t ) , 6 ) )
print ( ' T value , p-value ' )
print ( sp . s tats . ba r 七 l e t t ( re t l . re t , ret2 . re t ) )

图 1 2-5 显示非常高的 T 值和接近于零的 p 值 。 这支持我们拒绝零假设, 也 就是 说 该股


票在这 两个期间的波 动 率 不相同。
Std period # I vs. std period # 2
( 0.0 1 98 1 , 0.0 1 79 1 5 )
T value , p-value
BartlettResult(statistic= l 2.747 I 07745 1 02099, pvaJue=0.000356560 1 0 1 45 1 59 1 5)

图 1 2-5

1 2.5 利 用 Breusch 和 Pagan ( 1 979 ) 方法检验异方差



Breusch 和 Pagan ( 1 979 ) 提 出 了 个方法用来测试来自 回 归的残 差 是 否 具有恒定的波
动率。 首先, 估计以 y 为 因 变 量 x 为自变量的线 性 回 归 。

y, = a + /Jx, + £:, ( 1 2-7 )

这里, a 是 截距, p 是系数, E:1 是 误 差项。 在得到误差项 ( 残差 ) 后, 运行第 2 个回 归


模型。

2

B, = y + r1 x, + v, ( 1 2-8 )
304 第 12 章 波 动 率 和 GARCH 模 型

用ft 来代表上 述 回 归 模型的拟合值 , Breu sch-P ang an ( 1 9 79)统计量可以用下面的公式


来计算。 该统计量服从具有 K 自 由度的 x 分布:
2

1 n
BP = — IJv: ( 12-9 )
2 i=I

下 面的例子是从 名为 lm.te st 的 R 软件包中改写而来 。 首先, 我们用随机数模 拟生成 X,


Y 1 和Y2 的时间序列 , x 是 自变量 , Yt 和Y2 是因
变量, Y 1 具有恒定方差(标准方差), Y2 的方
差(标准方差) 不是常数 。 以下是变量 x 的 1 00 个值 。

X = [ -1,1, -1,1, ..., -1,1] C l 2- 1 0)

然后, 生成两 个误差项序列 , 每 个具有 1 00 个随机值 。 序列 error1 的 100 个值服从标


准正态分布 , 即 具有零均值和单位标准方 差 。 序列 error2 的 1 00 个值服从均值为零 , 标准
方 差为 2 的正态分布 。 y, 和Yz 时间序列 定义如下 。

y, = x + errorl ( 12-11 )

y2 = X + e, _; [ i = 1,3, ..., 99] + e2,; [ i = 2, 4, 6, ...,100] C l 2- 1 2)

序列 Y2 的奇数项用到误差项 error1 , 而其 偶数项用到误差项 error2。 与 l m.te st 软件包


相关的更 多信息可以通过以下 6 个步骤获取 。
1 . 访问 htt p://www. r- pr joect. org 。

2 . 单击 D ow nl oad 按钮选择软件包下 的CRAN 。

3. 选择一 个 附近的服务器。
4. 单击屏幕左侧的包列 表。

5. 选择并搜索 lm. te st。

6. 单击链接并下载与 I m.te st 相关的 P DF 文件 , 以下是相关的 Pyth on 代码 。

import numpy as np
import s cipy as sp
import s tat smode l s . api as sm

de f breusch_pagan_te st ( y , x ) :
resul 七 s = sm . OLS ( y , x ) . f i t ( )
resid=r e s u l ts . re s i d
1 2.5 利 用 Breusch 和 Pagan ( 1 979 ) 方 法 检 验 异 方 差 305

n = l e n ( re s i d )
s i gma2 = sum ( r e s i d * * 2 ) /n
f = r e s i d * * 2 /s igma2 - 1
r e s u l t s 2 = sm . OLS ( f , x ) . fi t ( )
fv= r e s u l ts 2 . fi ttedvalues \
bp=0 . 5 * sum ( fv* * 2 )
df=resu l t s 2 . df mode l
p_va l ue = l - sp . s tats . chi . cdf ( bp , df )
return round ( b p , 6 ) , d f , round ( p_value , 7 )

sp . random . seed ( l 2 3 4 5 )
n= l O O
x= [ )
error l=sp . random . normal ( O , l , n )
e rror2=sp . random . norma l ( 0 , 2 , n )
for i in range ( n ) :
i f i % 2 == 1 :
x . append ( l )
else :
x . append ( - 1 )

yl=x+np . ar ray ( x ) + e r r o r l
y2=sp . ze r o s ( n )

for i in range ( n ) :
i f i 号 2==1 :
y2 [ i ) = x [ i ] + e r r o r l [ i )
else :
y2 [ i ] =x [ i ] +e rr o r 2 [ i )

print ( ' yl vs . x ( we expect to a ccept the nul l hypothes i s ) ' )


bp=breusch pagan test ( y l , x )

pr int ( ' BP value , df , p-value ' )
print ( ' bp = ' , bp )
bp =breus ch_pagan_te s t ( y2 , x )
pr int ( ' y2 vs . x ( we expec 七 to rj ect the nu l l hypo 七 hes i s ) ' )
print ( ' B P value , df , p-value ' )
print ( ' bp = ' , bp )

图 1 2-6 显示相应的结果 。 Y1 对 x 运行回 归的结果 显示残差值的方差或标准方差是不随


时间而变化的。 因 此, 我们接受零假设, 这与 YI 的生成模型吻合。 相反, Y2 对 x 运行回 归
306 第 12 章 波 动 率 和 GARCH 模 型

的结果 支持 我们拒绝零假设, 也就是说残差值的方差或标准方差是随时间而变化的, 这与


Y2 的生成模型也是吻合的。
y I vs. x (we expect to accept the null hypothesis)
BP value, df, p-value
hp = (0.596446. 1 .0, 0.5508776)
y2 VS. X (we expect to rJect the null hypothesis)
BP value, df, p-value
('hp =', (1 7.61 1 054, I .0, 0.0))

图 1 2-6

1 2.6 从雅虎财经 网 页检索期权数据

第 1 1 章讨论了如何用给定的一组参数值来估计 隐含波动率 。 如果希望获取 2014 年 2


月 到 期的 I BM 公司的期权数据, 使用以下 代码 。 以 p k l为 结尾的两个数据集 可以从
htt p://ca ni siu s.edu/-ya ny/ ython/c
p all sF eb2014. p k 和
l htt :p//ca ni siu s. edu/-ya ny/ ython/
p up t sFeb2014. pk l
下载。

import pandas a s pd
c a l l s =pd . r ead_p i c k l e ( " c : /temp / c a l ls Feb2 0 1 4 . pk l " )
p r i n t ( cal l s . head ( ) )
puts =pd . r ead_pick le ( " c : /t emp /puts Feb 2 0 1 4 . pk l " )
print ( put s . head ( ) )

输出结果 如 下 。
S t r i ke S ymbol Chg Bid Ask Vol Ope n Int
0 1 2 3 4

1 50 . 0 I BM1 4 0 2 2 2 C 0 0 1 5 0 0 0 0 0 . 00 2 8 . 20 3 1 . 8 5 2 17
1 60 . 0 I BM1 4 0 2 0 7 C 0 0 1 6 0 0 0 0 0 . 0 0 1 8 . 2 5 2 2 . 2 5 1 1
1 60 . 0 I BM 1 4 0 2 2 2 C O O 1 6 0 0 0 0 0 . 0 0 1 9 . 1 5 2 1 . 5 0 2 64
1 65 . 0 I BM 1 4 0 2 2 2C 0 0 1 6 5 0 0 0 0 . 0 0 1 4 . 6 5 1 6 . 65 1 57
170 . 0 I BM1 4 0 2 1 4 C 0 0 1 7 0 0 0 0 2 . 3 8 9 . 90 1 0 . 4 0 1 1 0 10
S 七 r i ke S ymbo l Chg B i d A s k Vol Open Int
0 1 2 3 4

1 00 . 0 I BM1 4 0 2 2 2 P0 0 1 0 0 0 0 0 0 . 0 NaN O . 03 16 16
1 05 . 0 I BM1 4 0 2 2 2 P 0 0 1 0 5 0 0 0 0 . 0 NaN O . Q.3 10 10
115. 0 I BM 1 4 0 2 2 2 P0 0 1 1 5 0 0 0 0 . 0 NaN O . 0 3 20 22
120 . 0 I BM1 4 0 2 2 2 P0 0 1 2 0 0 0 0 0 . 0 NaN O . 0 4 10 20
1 30 . 0 I BM1 4 0 2 2 2 P 0 0 1 3 0 0 0 0 0 . 0 NaN O . 0 4 68 203

以下代码从 Yah oo!Fi na nce 网 页分开来下载看涨期权和看跌期权的数据并生成 两 个. p k !


1 2.7 波 动 率 的 微 笑 曲 线和斜度 307

格式 的数据集 。

import pandas a s pd
c a l l s = pd . read_table ( " c : / temp / i bmCa l l s 2 7 j an2 0 1 7 . t xt " )
p r i n t ( c a l l s . head ( ) ) \
c a l l s . to_p i c kl e ( " c : /temp/ ibmCal l s 2 7 j an2 0 1 7 . p kl " )

puts = pd . read_t able { " c : / t emp / ibmCa l l s 2 7 j an2 0 1 7 . t xt " )


print ( put s . head ( ) )
puts . to_pi c k l e ( " c : / temp / ibmPuts 2 7 j an2 0 1 7 . pk l " )

以下为输 出 结果。
S t r i ke S ymbo l Chg Bid As k Vol Open In七
0 150 . 0 I BM1 4 0 2 2 2 C 0 0 1 5 0 0 0 0 0 . 00 2 8 . 20 3 1 . 8 5 2 17
1 1 60 . 0 I BM1 4 0 2 0 7 C 0 0 1 6 0 0 0 0 0 . 0 0 1 8 . 2 5 2 2 . 2 5 1 1
2 1 60 . 0 I BM1 4 0 2 2 2 C 0 0 1 6 0 0 0 0 0 . 0 0 1 9 . 1 5 2 1 . 5 0 2 64
3 165 . 0 I BM1 4 0 2 2 2 C 0 0 1 6 5 0 0 0 0 . 0 0 1 4 . 6 5 1 6 . 6 5 1 57
4 170 . 0 I BM1 4 0 2 1 4 C 0 0 1 7 0 0 0 0 2 . 3 8 9 . 90 1 0 . 40 l l O 10
S七rike S ymbol C h g B i d As k Vo l Open I n 七
0 1 2 3 4

100 . 0 I BM1 4 0 2 2 2 P 0 0 1 0 0 0 0 0 0 . 0 NaN O . 0 3 16 16


105 . 0 IBM1 4 0 2 2 2 P 0 0 1 0 5 0 0 0 0 . 0 NaN O . 0 3 10 10
1 15 . 0 I BM1 4 0 2 2 2 P 0 0 1 1 5 0 0 0 0 . 0 NaN O . 0 3 20 22
120 . 0 I BM1 4 0 2 2 2 P 0 0 1 2 0 0 0 0 0 . 0 NaN O . 0 4 10 20
130 . 0 I BM 1 4 0 2 2 2 P 0 0 1 3 0 0 0 0 0 . 0 NaN O . 0 4 68 203

1 2.7 波 动 率 的 微笑 曲 线和 斜度

每只股票本质上 应该只有 一 个波动率, 然而在估 计隐含波动率时, 使用不 同行使价格


的期权 可能得到不 同的 隐含波动率 。 也 就是说, 基千 实值期权, 虚值期权 和 在值期权 的 隐
含波动率可能有很大 不 同。 波动率对行使价格的函数关系呈微笑形状, 先
是下 降然后上 升 。
波动率 的斜度
是行使价格的函数单调 下 降或单调上 升 的函数 。 投资 者的情绪以及供求关系
对波动率 的 斜度有着根本性的 影 响 。 在任一 时刻, 波动率 的 微笑 曲 线 和斜度都可以为投资
者提供当时
是否偏好看涨期权或看 跌 期权 的 信息。

import datet ime


耳npor七 pandas as pd
import matp l o t l ib . pyplot as p l t
from ma tp l ot l i b . f i nance import quotes_h i s t o r i c a l_yahoo_o c h l as getData

# Step 1 : de f ine a func七ion
308 第 12 章 波 动 率 和 GARCH 模 型

de f imp l i e d vol call min ( S , X , T , r , c ) :


from s c ipy import l o g , exp, sqrt , stats
imp l i ed—vo l=l . O
min_va l u e= l O O O
for i i n range ( 1 0 0 0 0 ) :
s i gma=O . O O O l * ( i + l )
dl= ( l og ( S /X ) + ( r + s i gma * s i gma /2 . ) * T ) / ( si gm a * s qrt ( T ) )
d2 = d l - s i gma* sqrt ( T )
c2 = S * s tats . norm . cdf (dl ) - X * e xp ( - r * T ) * s ta七s . norm . cdf ( d2 )
abs_di f f =abs ( c 2 - c )
i f abs di f f<min va lue :
min value = abs di f f
imp l i ed_vo l = s i gma
k=i
return imp l i ed_vo l

# S tep 2 : i nput area
七icker = ' I BM '
r= 0 . 0 0 0 3 # e s t imate
begdate = da七et ime . da七e ( 2 0 1 0 , 1 , 1 ) # 七his i s arbitrary
enddate = datet ime . date ( 2 0 1 4 , 2 , 1 ) # February 2 0 1 4

# Step 3 : get cal l option da七a
c a l l s =pd . read_pickle ( " c : /t emp/cal l s Feb 2 0 1 4 . p k l " )
exp_date O=int ( ' 2 0 ' + cal l s . S ymbol [ O J [ len ( 七 i c k e r ) : 9 ] ) # f ind expi ring da七e

p = getDat a ( 七 i c ke r , begdate , enddat e , asobj ect = True , adj u s ted=True )
s=p . close [ - 1 ] # get current s七ock price
y=in七 ( exp—date 0 / 1 0 0 0 0 )
m=int ( e xp_date 0 / 1 0 0 ) - y * l O O
d=e xp_dat e 0 -y* l 0 0 0 0 -m* 1 0 0
exp_date=datet ime . da七e ( y , m , d) # get exact expiring da七e
T= ( e xp—date-e nddat e ) . days / 2 5 2 . 0 # T i n years

# S tep 4 : run a l oop 七 o e s t ima七e the imp l i ed vol a t i l i t y
n=len ( cal l s . Strike) # number o f s t r i k e
s t r i ke [ ]
= # 1.n 1. t i a l 1. z at1.on
impli ed vo l = [ ] # i n i t i a l i zation
call2= [ ] # i n i t i a l i zat ion
x o l d=O # u s ed when we choose the first s 七 r i ke

for i i n range ( n ) :
x=cal l s . S t r i ke [ i ]
1 2.8 波动率集聚效应 的 图形表 示 309

c= ( ca l l s . B i d [ i ] +call s . As k [ i ] ) /2 . 0
if C >0 :
p r i n t ( ' i= ' , i , ' , c= ' , c )
i f x ! =x o l d :
vol = imp l i e d_vol_cal l_mi n ( s , x , T , r , c )

s t r i ke . append ( x )
imp l i ed_vo l . append ( vo l )
ca1 1 2 . append ( c )
p r i n 七 x , c , vo l
x o ld=x

# S tep 5 : draw a smile
p l t . t i t l e ( ' S kewn e s s smi l e ( s kew) ' )
pl t . x l ab e l ( ' Exe r c i s e P r i c e ' )
pl t . ylabel ( ' Imp l ied Vol a t i l i t y ' )
pl t . plot ( s t r i k e , impl ied_vol , ' o ' )
plt . show ( )

如果多个相同行使价的期权给出不同的隐含波动率, 以上代码选择第1 个隐含波动率 。 另


一个方法是采用相同行使价格的几个隐含波动率的平均值。 波动率的微笑 曲 线如图 12-7 所示。

LO
Skewness smile (吐如)

09

0.8

右 0.7

I
06

Jo
s .
o., ,. ..
... . .
l
o.坛
160 170 180
Ex<IKIH Pric 愈
190 200 210

图 1 2-7

从 http://canisius.edu/-yany/python/callsFeb201 4.pkl 网 页 下 载 期权数据集并运行以上 代


码, 可以原样生成图 12-7。

1 2.8 波动率集聚效应 的 图 形表 示

股票 价格的
变化有一 个普遍存在的现象, 被称为波动率的集聚效应, 它是指价格
变化
310 第 12 章 波 动 率 和 GARCH 模 型

大 的 交 易 日 扎堆 出 现 , 而价格变化 小 的 交 易 日 也聚集在 一 起 。 以 下代码用 1 988 年 到 2006


年 间 S& P SOO 指 数 的 日 回报率来展示这个现象 。

impor 七 numpy as np
import matp lo t l ib . pyplot a s p l t
from matpl o 七 l ib . fi nance import quotes historica l yahoo ochl as getData

t i c ke r= ' " GSPC '
begdate= ( l 9 8 7 , l l , l )
endda te= ( 2 0 0 6 , 1 2 , 3 1 )

p = getData ( 七 i c ke r , begda t e , enddate , a s ob j ect =True , adj u s ted=True )
x=p . date [ l : ]
re七 = p . aclose [ l : ] /p . a c l o s e [ : - 1 ] - l

p l t . t i t l e ( ' I l l ustr at ion o f v o l a t i l i t y cluster i ng ( S & P S O O ) ' )
pl t . y l abe l ( ' D a i l y returns ' )
pl 七 . xlab e l ( ' Date ' )
pl t . plot ( x , r e 七 )
pl 七 . show ( )

以 上代码绘制 的 图 形如 图 12-8 所 示 。

0.06
Illustration of volatility clustering (S&PSOO)

0.04
o o -
0200020406
sEn1
a,�l

o -
!•O

o -
o

1990 1992 1994 1996 1998 2000 2002 2004 2006

图 1 2-8

1 2.9 ARCH 模型及 ARCH ( 1 ) 随机过 程 的 模拟

前 面 的 内 容 告 诉我们股票 回 报 率 的波动性 或 方 差 不 是 保 持 不 变 的 。 2003 年 诺 贝 尔 经 济


学 奖 得 主 Robert E ngle 提 出 了 ARCH 模 型 , 用 数学 方 法 来表现股 票 回 报 率 的 动 态 变 化 , 并
1 2.9 ARCH 模 型 及 ARCH ( I ) 随机过程 的 模 拟 311

且能够帮助 我们利用已经观察到的股 票 回报率来预测 未来的波 动 率 。 ARCH ( q ) 模型的数


学公式如下 。
q
a, + a。 + I a; e;_,
2
( 1 2- 1 3 )
\ i=I

这里, 式 是在 t 时刻的方差, Gj 是在 t -i 时刻的误差项的系数, a1 e�_1 是在 t - i 时刻的

误差项的平方, q 是误差项的阶数。 当 q 为 1 时, 有最
简单的 ARCH C l ) 过程如下。

a,-, = a + a, e,一 1
。 ( 1 2- 1 4 )
2

以下代码用来模 拟 一 个 ARCH C l ) 序列 。 这是 一 个好的练习, 可 以帮助更好地了解波


动率的集聚效应 。

import s c i py as sp
import matplo 七 l ib . pyplot as p l t

sp . random . seed ( l 2 3 4 5 )
n= l O O O # n i s the number of obs ervations
nl=lOO Jt we need to drop the f i r s t seve ral observations
n2=n+nl Jt sum of two numbers

a = ( 0 . 1 , 0 . 3 ) # ARCH ( 1 ) coe f fi cients alphaO and a lpha l , see Equation ( 3 )
er rors=sp . random . normal ( O , l , n2 )
t=sp . z eros ( n 2 )
七 [ O ] =sp . random . no rma l ( O , sp . sqrt ( a [ 0 ) / ( 1 -a [ l ) ) ) , l )

for i i n range ( l , n2 - l ) :
t [ i ) =err ors [ i ) * sp . s qr t ( a [ O ) +a [ l ) * t [ i - 1 ) * * 2 )
y=t [ n l - 1 : - 1 ] # drop the f i r s t n l obse rvat ions

plt . t i t l e ( ' ARCH ( 1 ) process ' )
x=range ( n )
plt . plot ( x , y )
plt . show ( )

图 1 2-9 显示一 个 模 拟生成的 ARCH ( 1 ) 序列 。 可 以看到 明 显的集聚效应, 即 价格变


化大 的交易 日 扎堆出现, 而价格变化小 的交易 日 也聚集在一 起 。
312 第 12 章 波 动 率 和 GARCH 模 型

1.5
ARCH (l) process

1.0 卜

0.5

0. 0

-0.5

-1.0

-1.5
200 400 600 800 1000

图 1 2-9

1 2. 1 0 GARCH ( 广义 ARCH ) 模型
广义 自 回 归 条件异方差 ( GARCH ) 是 ARCH 的重要扩展, 由 Bollerslev ( 1 986 ) 提 出 。
GARCH(p,q)模 型 的 数 学 公 式 如 下 。
q p
式 =a 。 + Ii=I ai 斗 +Li=I fJi=I CY,2一 l ( 1 2- 1 5 )

这 里 , 式 是在 t 时 刻 的 方 差 , q 是 误 差项 的阶数 , p 是方差 的 阶 数 , q。 是常数 , a; 是在


t -i 时 刻 的 误差项 的 系 数 , 队 是 在 t -i 时刻 的方差 的 系 数 。 显 然 , 最 简 单 的 GARCH 模型是
当 p 和 q 都 等 千 l 时 , 即 GARCH( l , 1 ) 。 它 的 数 学 公 式 如 下 :

aI = aO + aI E1 - 1 +/30-,2一l
2 2
( 1 2- 1 6 )

12. 10. 1 模拟 GARCH 随机过程


可 以 用 下 面 的代码模拟生成 一 个 GARCH ( 1 , 1 ) 序列 。

import s c ipy as sp
import matp l o 七 l ib . pyp l o t a s plt

sp . random . s e ed ( 1 2 3 4 5 )
n= l O O O # n i s 七 he number o f obs e rvations
nl=lOO # we need to drop the f i r s 七 seve r a l obs e rvations
n2=n+nl # sum of two numbers

1 2. 1 0 GARCH ( 广 义 ARCH ) 模 型 31 3

a= ( 0 . 1 , 0 . 3 ) it ARCH co e f f i c i e n t
alpha= ( 0 . 1 , 0 . 3 ) it GARCH ( 1 , 1 ) coe f f i c i e n t s alphaO a n d alpha l , s e e
it Equatio n ( 3 )
beta=0 . 2
e r rors=sp . random . n o rmal ( 0 , lv n2 )
t=sp . z eros ( n 2 )
七 [ O ) =sp . random . normal ( O , s p . sqrt ( a [ 0 ] / ( 1 - a [ l ] ) ) , 1 )


for i in range ( 1 , n2 - 1 ) :
t [ i ) =e r rors [ i ) * s p . sqrt ( al pha [ O ] +a lpha [ l ] * e r r o r s [ i - 1 ) * * 2 + b e t a * t
[ 七 1 ) * *2 )

y=t [ n l - 1 : - 1 ] it drop the f i r s t n l obs e rvations
plt . t i t l e ( ' GARCH ( 1 , 1 ) process ' )
x=ran ge ( n )
p l t . plot ( x , y )
p l t . show ( )

生成的 G ARCH C I , l ) 序列 如图 12-10 所示, 其 图形看起来与 ARCH( l )序列 的 图 形


非常相似。

GARCH ( 1 . 1 ) process

-l

-2

-3
0 200 400 600 800 1000

图 1 2- 1 0

12.10.2 采用改良的 garchSim()函数模拟 GARCH(p,q)模型


以下代码基于 一 个 称为 garchSim() 的 R函数, 它
包含在 由 Diethelm Wuertz 和 Yohan
Chalabi 包里。 可以用以下 步骤找到这个 R 软件包。
编写的名为 fGarch 的 R 软件
I . 访 问 http://www.r-project.org。

包下的CRAN 。
2 . 单击下 载软 件

3. 选择一 个 离 得近的服务 器 。
314 第 12 章 波 动 率 和 GARCH 模 型

4 . 单击屏 幕左侧的包列 表。

5. 选择一 个列 表并搜索 fgarch 。

6. 单击链接并 下 载与 fgarch 相关的 PDF 文件。 下面给出改写 后的 Python 代码 。

import scipy as sp
import numpy as np
import matp l ot l i b . pyplot as p l t

sp . random . seed ( 1 2 3 4 5 )
m= 2
n = l O O # n i s the number o f obs e rvations
nDrop=l O O # we need to drop 七he f i r s 七 s eve r a l observations
de l ta = 2
omega= l e - 6
a lpha= ( 0 . 0 5 , 0 . 0 5 )

beta = 0 . 8
mu , ma , a r = 0 . 0 , 0 . 0 , 0 . 0
gamma = ( 0 . 0 , 0 . 0 )
or der_ar = s p . s i z e ( a r )
orde r_ma=sp . s i z e (ma )
order_be七a=sp . s i z e ( beta)

order_a lpha =sp . s i z e ( a lpha )
z O =sp . random . s t andard_norma l (n +nDrop )
de lt ainv= l /delta
spec_l =np . a r ra y ( [ 2 ] )
spe c_2 = np . a r ray ( [ 2 ] )
spec_3=np . ar r ay ( [ 2 ] )
z = np . h s t a c k ( ( spec_l , z O ) )
t = np . z e r o s ( n +nDrop )
h = np . hstack ( ( spec_2 , 七 ) )
y = np . hstack ( ( spec_3 , t ) )
eps O = h * * de l tainv * z
for i in r ange ( m+ l , n +nDrop+m- 1 ) :
t l = s um ( alpha [ : : - l ] * ab s ( eps O [ i -2 : i ] ) ) # reve r s e

al pha =alpha [ : : - 1 ]
t2=eps 0 [ i - orde r_a lpha - 1 : i-1 ]
t 3=t 2 * t 2
t 4 =np . dot ( gamma , t 3 . T )
tS=sum (beta* h [ i- orde r_beta : i - 1 ] )
h [ i ] = omega+t l - t 4 + t S
12. 1 0 GARCH ( 广 义 ARCH ) 模 型 315

eps O [ i ] = h [ i ] * *delta inv * z [ i ]


t l O =ar * y [ 丘o rder_ar : i - 1 ]
t l l =ma * ep sO [ i - o rde r_ma : i - 1 ]
y [ i ] =mu+ s um ( t l O ) + s um ( 七 1 1 ) +ep s O [ i ]
garch = y [ nDr op+ l : ]


s i gma = h [ nDrop+l : ] * * 0 . 5
eps = epsO [ n Drop + l : ]
x=range ( l , l en ( garch) + l )

plt . plot ( x , garch, ' r ' )
p l t . p l ot ( x , s i gm a , ' b ' )
pl t . t i t l e ( ' GARCH ( 2 , 1 ) proce s s ' )
p l t . figtext ( 0 . 2 , 0 . 8 , ' omega = ' + s 七 r ( omega ) + ' , alpha = ' +s t r ( a lpha ) + ' , beta= '
+ s 七 r (beta ) )
p l 七 . f i gtext ( 0 . 2 , 0 . 7 5 , ' gamma = ' + s 七 r ( gamma ) )
p l t . f i gtext ( 0 . 2 , 0 . 7 , ' mu = ' + s 七 r (mu) + ' , ar = ' + s t r ( a r ) + ' , ma = ' +s 七 r ( ma ) )
pl t . show ( )

在 前 面 的 程序 中 , omega 是 公 式 中 的 常 数 , alpha 与 误 差 项 相 关 联 , beta 与 方 差 相 关 。


alpha[a, b] 中 有两项 , 其 中 a 用 于 t - 1 , 而 b 用 于 t -2 。 然 而 , epsO [t -2 : i] 中 的 两 项 分 别
代表 t -2 和 I - 1 。 因 为 alpha 和 epsO 彼 此 不 一 致 , 所 以 必 须颠倒 a 和 b 的顺序 。 这 就 是 使
用 alpha [ : : - 1 ] 的 原 因 。 由 于 mu , ar 和 ma 这几个值为 零 , garch 时 间 序 列 与 eps 相 同 。 因 此 ,

在 图 1 2- 1 1 中 只 显 示 两 个 时 间 序列 。 波 动 率 大 的 曲 线 对应于 garch , 而 另 条 曲 线对应于标
准方差。

GARCH(2,l) process

-l

-2

衬 20 40 60 80 100

图 1 2- 1 1

12.10.3 由 Glosten 、 Jagannanthan 和 Runkle ( 1993 ) 提 出 的


GJR_GARCH 模型简介

Glosten 、 Jagannathan 和 Runkle ( 1 993 ) 指 出 了 GARCH 模 型 中 的 不对 称 性 。 他们 建 议


316 第 12 章 波 动 率 和 GARCH 模 型

对模型加以改进。 GJR_GARCH( I , 1 , 1 ) 由 以下公式表达 。

式 = w + a吐 + 如嘉 + r 弘 1,-1 0 2- 1 7 )

其 中 l, -1 =0 , 当 61 _1 � o 时; I, 一1 = 1 , 当 6,-1 < 0 时。 以下代码来 自 Kevin Sheppard 的网 页 。

impor七 numpy as np
from numpy . linalg import i nv
import matp l o t l ib . pyp l o t as p l t
fr om matp l o t l i b . mlab import csv2rec
from s c ipy . optimi ze import fmin_s l s qp
from numpy import s i z e , log , p i , s um , d i f f , a r r a y , zeros , diag, dot , mat ,
asarray, s qr t

de f gj r_garch_ l i k e l ihood ( parameters , data , s i gma2 , ou七=None ) :
mu = pa ramet e rs [ O ]
omega = parame 七e rs [ l ]
al pha = pa rameters [ 2 ]
gamma = parameters [ 3 ]
beta = p a ramete rs [ 4 ]
T = s i z e ( data , 0 )
eps = data-mu
for t in xr ange ( l , T ) :
s igma2 [ t ] = ( omega+alpha * eps [ t - 1 ] * * 2 +gamma * ep s [ 七 一 1 ] * * 2 * ( eps [ t- 1 ]
< O ) +beta * s i gma2 [ t - 1 ] )
logl i k s = O . S * ( l og ( 2 * p i ) + log ( s i gma2 ) + eps * * 2 / s igma2 )
l o g l i k = sum ( l ogl i k s )
i f out i s None :
return logl i k
else :
return l og l i k , logl i k s , copy ( s i gma2 )

de f g j r constraint ( paramet e r s , data , s i gma2 , ou七 = Non e ) :
al pha = pa ramet e r s [ 2 ]
gamma = parameters [ 3 ]
beta = parameters [ 4 ]
return arra y ( [ 1 -a lpha-gan订na / 2 -beta ] ) # Constraint a lpha+gamma / 2 +beta<=l

de f hess i an_2 s i ded ( fu n , theta, arg s ) :


f = fun ( t he t a , *args )
h = l e - S * np . ab s ( thet a )
the七ah = theta + h
h = thetah-theta
1 2. 1 0 GARCH ( 广 义 ARCH ) 模 型 317

K = s i ze ( thet a , O )
h = np . diag ( h )
fp = z e r o s ( K )
fm = zeros ( K)
for i i n xr ange ( K ) : \
fp [ i ] = fun ( t heta+h [ i ) , * args )
fm [ i ) = fun ( theta-h [ i ) , * a r g s )
fpp = z e ros ( ( K , K ) )
fmm = z e ro s ( ( K , K ) )
for i in xra nge ( K ) :
for j i n x r ange ( i , K ) :
fpp [ i , j ] = fun ( theta + h [ i ] + h [ j ] , * a r g s )
fpp [ j , i ) = fpp [ i , j )
fmm [ i , j ) = fun ( theta-h [ i ) -h [ j ) , * a rgs )
fmm [ j , i J = fmm [ i , j J
hh = ( diag ( h ) )
hh = hh . re shape ( ( K , 1 ) )
hh = dot ( hh , hh . T )
H = z e r o s ( ( K , K) )
for i i n xra nge ( K ) :
for j i n xrange ( i , K ) :
H [ i, j ) = ( fpp [ i , j ) - fp [ i ) - fp [ j ) + f+ f - fm [ i ) - fm [ j ) + fmm [ i , j ) ) /hh
[ i , j J /2
H [j , i) = H [ i , j )
return H

编写 一 个 名为 GJR_GARCH() 的 函 数 , 用 来 包 含 所 有 初 始 值 、 约 束 和 边 界 条件 , 代
码如下。

de f GJR_GARCH ( r e t ) :
import numpy as np
import scipy . op豆m i z e as op
s t a rtV=np . a rray ( [ r e t . mean ( ) , ret . var ( ) * O . 0 1 , 0 . 0 3 , 0 . 0 9 , 0 . 9 0 ] )
f i nfo=np . f i n fo ( np . f l oa t 6 4 )
t= ( 0 . 0 , 1 . 0 )
bounds= [ ( - 1 O * ret . mean ( ) , l O * ret . mean ( ) ) , ( f in f o . eps , 2 * r e t . va r ( ) ) ,
七, t, t]
T = np . s i z e ( r e t , O )
s i gma2 = np . repeat ( re七 . var ( ) , T )
inV= ( ret , s i gma2 )
return op . fmi n_s l s qp ( g j r_garch_l i ke l ihood , s t a r tV, f_i eqc o n s =gj r_
con s t r a i n七 , bounds =bounds , a rgs = inV)
31 8 第 12 章 波 动 率 和 GARCH 模 型

为了便于重复运算结果, 使用 random.seed()函数来产生 固定的一组服从 均匀分布 的随


机数。

sp . r andom . s e e d ( 1 2 3 4 5 )
returns = sp . random . uni form ( - 0 . 2 , 0 . 3 , 1 0 0 )
tt=GJR_GARCH ( r eturns )

函数的运算结果 如图 1 2- 1 2
GJR_GARCH() 所示。
print(tt)
Optimization terminated successfully. (Exit mode 0)
Current function value: -54.0664733 1 28
Iterations: 1 2
Function evaluations: 94
Gradient evaluations: 1 2

图 1 2- 1 2

这 5 个输出结果的含义如表 1 2- 1 所示。

表 1 2-1

含义

描述优化程序的 退 出 模式
2

目 标 函 数 的最终值
3

迭代次数
4

目 标 函 数 计 算次数
5

梯 度 函 数 计算 次 数

程序的不同退出模 式如表 1 2-2 所示。

表 1 2-2

退 出 模式 说明

-I 需要 计算梯度 函 数 Cg 和 a )

优化 已成功终止

需 要 计 算 目 标 函 数 (f和 c)
2

等式约 束 的 个 数超过 自 变蜇的个数


练 习 题 319

续表

退 出 模式 说明

3 在 LSQ 子程序 中 超过 3*n 次迭代

不等式约 束条件不兼容

5 在 LSQ 子程序 中 矩 阵 E 是奇异矩阵

6 在 L S Q 子程序 中 矩 阵 C 是奇异矩阵

7 在 HFTI 子程序 中等 式约 束条件不足

8 线搜索 中 方 向 导 数 为 正

9 超 过 了 迭代次数 的 限 制

最终的运算结果如下 。

>>>pr int tt
[ 7 . 7 3 95 8 5 8 3 e - 0 2 6 . 65856138e-03 1 . 0 0 3 8 6 1 5 6e - 1 2 -1 . 671 15250e-12
6 . 6 1 9 4 7 97 7 e- 0 1 ]
>>>

1 2. 1 1 小结

本章 重点讨论了几 个问题, 特别 关注波动率的度量和 ARCH/GARCH 模型。 我们了解


到标 准方差作为波动率的度量, 是基于回报 率服从 正态发布这 个假设的。 接着, 学习 了几
个统计测试来检验这 个假 设是否成立, 包括 Shapiro-Wilk 检验和 Anderson-Darling 检验以
及如何 使用各种图表来显示股 票 回 报率的分布具有的肥尾特征 。 讨论如何通过比较两 个时
期的方差来检验波 动 率是否随时间变化, 并用 Python 代码来实现 Breusch-Pangan ( 1 9 79 )
异方差检验。 ARCH 和 GARCH 广泛用于 描述波动率如何随时间变化。 用随机模 拟方法演
示这些 模型的几 个简单形式, 如 ARCH( l )和 GARCH( l , l )模型 。 Kevin Sheppard 提供的
Python 代码可以用图形 演 示这些 模型, 还可以用来模 拟 GJR_GARCH C 1 , 1 , 1 ) 模型。

练习题

1 . 波动率的定义是 什么 ?

2 . 如何衡量风险(波 动 率 ) ?
320 第 12 章 波 动 率 和 GARCH 模 型

3. 标准方差 被广泛用来衡量风险是否有不当之处?

4. 如何测试股票 回报率是否服从 正态分布 ? 对于 给定的股票回报率集合, 测试它们是


否服从 正态分布。

5 . 下偏标准方差如何定义 ? 有什么应用?

6. 选择 5 只 股票, 如 DEL
L、I BM、 微软 ( M SFT )、 花旗集团 (C)和沃尔玛 (WMT)
,
并使用过去 3年的每 日数据比较它们的标准方差与LP SD 。

7. 股票的波 动 率是否随时间变化 ?
8. 使用 Breu sch-P ag an ( 1 9 79)方法来检验 I BM 日 回报率的分布是否随时间变化 。

9 . 如何检验股票的波 动 率是否随时间改变?

10. " 肥尾 分布有什么含义? 为什 么 要关注肥尾分布 ?


1 1 . 如何下 载 期权数据 ?

1 2 . ARCH ( l )模 型 如何定义 ? 有什么作用 ?

13. G ARCH ( l , l )模 型如何定义? 有什么作用 ?

1 4 . 使用 GARCH( l , l )模 型分析 DEL


L的 日 回报 率 。

1 5. 编写 一 个 Pytho n 程序用观察到的看跌期权的数据展示波动 率的斜度。


本书的孝习霎点:

缅写一个适用千个人理财和公司财务的金融计算器;

计算多种期权的价格 , 包括欧式期权、 美式期权、


均价期权、 回望式期权和障碍式期权等;

从网站抓取股票历史价格和其他经济金融数据 ;

计算个股或组合的 回 报率 、 方差和在险价值等
统计量 ;

构邃最优的投资组合;

计算隐含波动 率井绘制波动率的 微 笑 曲 线 ;

估计波动率的时间序列模型 ;

计算买卖价差等流动性指标 。

7
8
7
1
1—
5,
4—
5
7
7
3
1
s
B—
N

-11
0'

',_冒
,',
',

5

7
7
9

3
7
8
7
1
1

4
5

ISBN 978-7-1 1 5-45707-3


分类邃议 : 计算机 / 程序设计 / Python
定 价 : 79.00 元
人 民 邮 电 出版社网 址 : www.ptpress.com.cn

You might also like