当前位置: 首页 > 新闻 > 信息荟萃
编号:3682
解密金融数据.pdf
http://www.100md.com 2020年3月10日
第1页
第5页
第12页
第28页
第34页
第194页

    参见附件(19937KB,329页)。

     解密金融数据是作者贾斯汀·保利写的关于金融数据的书籍,主要讲述了在金融市场获取金融数据的三种途径,将数据进行金融分析,最后对这些公司的投资数据进行总结报告。

    解密金融数据内容提要

    本书分为三大部分:获取金融数据、金融数据分析和创建金融报告。每一部分都有一些操作性比较强的目标。第一部分(第2~4章)介绍如何用彭博(Bloomberg)和Markit获取和存储与股票、指数、债券和银行贷款有关的金融数据。第二部分(第5~8章),本部分将第一部分收集到的金融数据放入具体的背景环境中进行金融分析。第三部分(第9章和第10章)整合了第一部分和第二部分的内容,教你如何对各个公司和投资组合创建分析报告。本书关注三个重要金融市场:股票、企业债券和企业贷款。尽管如此,你可以将在本书中学到的内容直接应用到其他市场,比如结构化产品、市政债券等。

    解密金融数据作者信息

    贾斯汀·保利(Jstin Pauley)是Brigade Capital Management公司的一名高级结构化信贷分析师。他在该公司的工作职责包括进行投资推荐、执行交易、开发用于分析和评估复杂投资的系统。在加入Brigade公司之前,他是苏格兰皇家银行的策略总监,负责向投资者发布月度报告和开发债券分析系统。《结构化金融期刊》曾对他进行了报道,后被《华尔街日报》和《彭博新闻》引用,他还在众多金融会议中进行过演讲。

    朱轩彤:清华大学硕士,中国社会科学院数量经济与技术经济研究所博士生,专注于技术经济及管理研究。在政府及国际组织有丰富的工作经验。

    董宁:智链ChainNova CEO,北京大学新一代信息技术研究院金融科技研究中心主任。原IBM大中华区IT经济学负责人,IBM区块链社区发起人。

    解密金融数据章节目录

    第1章 简介

    1.1 概览

    1.1.1 第一部分:获取金融数据

    1.1.2 第二部分:金融数据分析

    1.1.3 第三部分:创建金融报告

    1.2 金融市场

    1.2.1 股票

    1.2.2 企业贷款(银行贷款、杠杆贷款)

    1.2.3 企业债券

    1.3 三种途径

    1.3.1 途径1:Microsoft Excel

    1.3.2 途径2:Microsoft Access

    1.3.3 途径3:C#

    1.4 线上文件

    1.5 本章小结

    第2章 组织金融数据

    2.1 途径1:Excel

    2.1.1 Excel区域与Excel表

    2.1.2 增加引用列

    2.1.3 数据验证

    2.2 途径2和3:Access中的表格

    2.3 本章小结

    第3章 彭博

    3.1 确定字段

    3.1.1 鼠标滑动

    3.1.2 FLDS屏幕

    3.1.3 彭博函数构造器和在Excel中发现字段

    3.1.4 如果其他都失败了……

    3.2 Excel案例

    3.2.1 提取单一字段(BDP)

    3.2.2 提取批量数据(BDS)

    3.2.3 提取历史数据(BDH)

    3.3 用于比较的有价证券

    3.3.1 指数

    3.3.2 对等有价证券

    3.3.3 关于有价证券

    3.4 途径1和2:Excel和Access

    3.4.1 企业债券、贷款和指数

    3.4.2 公司工作表

    3.4.3 引用和重写

    3.5 途径3:彭博C#API

    3.5.1 设置Microsoft Access以用于C#

    3.5.2 彭博C#API

    3.5.3 基本引用示例

    3.5.4 基本历史示例

    3.5.5 填入Access数据库

    3.6 本章小结

    第4章 IHS Markit:大企业数据

    4.1 企业贷款

    4.1.1 数据请求

    4.1.2 贷款信息

    4.1.3 贷款定价、金融和分析

    4.2 企业和主权债券

    4.3 途径1:在Excel中存储Markit信息

    4.4 途径2:将Markit数据导入Microsoft Access

    4.5 途径3:用C#导入Markit数据

    4.6 本章小结

    第5章 金融数据分析

    5.1 数据真实性

    5.1.1 检查数据

    5.1.2 样本规模

    5.1.3 异常值

    5.2 投资组合

    5.2.1 投资组合工作表

    5.2.2 投资组合数据库表

    5.3 连接Excel工作表和Microsoft Access

    5.4 留存记录

    5.4.1 途径1:Excel

    5.4.2 途径2:Microsoft Access

    5.4.3 途径3:C#

    5.5 本章小结

    第6章 相对价值分析

    6.1 途径1:Excel

    6.1.1 Excel中的相关性与回归

    6.1.2 对等组

    6.1.3 评级

    6.1.4 统计工作表

    6.1.5 并排比较

    6.1.6 指数

    6.1.7 加权Z值

    6.2 途径2:Access

    6.2.1 Access中的相关性和回归

    6.2.2 Access中的中位数

    6.3 途径3:C#

    6.3.1 相关性和回归

    6.3.2 对等组

    6.3.3 评级

    6.3.4 统计表

    6.3.5 并排比较

    6.3.6 加权Z值

    6.4 本章小结

    第7章 组合风险分析

    7.1 途径1:Excel

    7.1.1 方差、波动性和标准差

    7.1.2 带历史或预期收益的夏普比率

    7.1.3 投资组合分解

    7.1.4 警告标志

    7.2 途径2:Access

    7.2.1 投资组合分解

    7.2.2 警告标志

    7.3 途径3:C#

    7.3.1 历史或预测收益的夏普比率

    7.3.2 投资组合分解和警告标志

    7.4 本章小结

    第8章 市场分析

    8.1 途径1:Excel

    8.1.1 新发放贷款分析

    8.1.2 再融资

    8.1.3 价格历史

    8.2 途径2和3:Access和C#

    8.2.1 新发放贷款分析

    8.2.2 再融资

    8.2.3 价格历史

    8.2.4 更进一步

    8.3 本章小结

    第9章 创建报告

    9.1 途径1:Excel

    9.2 途径2:Microsoft Access

    9.3 途径3:C#和SSRS

    9.4 本章小结

    第10章 投资组合报告

    10.1 监测业绩和风险

    10.2 途径1:Microsoft Excel

    10.2.1 计算收益

    10.2.2 投资组合报告

    10.3 途径3:C#和SSRS

    10.4 本章小结

    解密金融数据截图

    目录

    O’Reilly Media,Inc.介绍

    业界评论

    本书赞誉

    译者序

    前言

    第1章 简介

    1.1 概览

    1.1.1 第一部分:获取金融数据

    1.1.2 第二部分:金融数据分析

    1.1.3 第三部分:创建金融报告

    1.2 金融市场

    1.2.1 股票

    1.2.2 企业贷款(银行贷款、杠杆贷款)

    1.2.3 企业债券

    1.3 三种途径

    1.3.1 途径1:Microsoft Excel

    1.3.2 途径2:Microsoft Access1.3.3 途径3:C

    1.4 线上文件

    1.5 本章小结

    第2章 组织金融数据

    2.1 途径1:Excel

    2.1.1 Excel区域与Excel表

    2.1.2 增加引用列

    2.1.3 数据验证

    2.2 途径2和3:Access中的表格

    2.3 本章小结

    第3章 彭博

    3.1 确定字段

    3.1.1 鼠标滑动

    3.1.2 FLDS屏幕

    3.1.3 彭博函数构造器和在Excel中发现字段

    3.1.4 如果其他都失败了……

    3.2 Excel案例

    3.2.1 提取单一字段(BDP)

    3.2.2 提取批量数据(BDS)3.2.3 提取历史数据(BDH)

    3.3 用于比较的有价证券

    3.3.1 指数

    3.3.2 对等有价证券

    3.3.3 关于有价证券

    3.4 途径1和2:Excel和Access

    3.4.1 企业债券、贷款和指数

    3.4.2 公司工作表

    3.4.3 引用和重写

    3.5 途径3:彭博CAPI

    3.5.1 设置Microsoft Access以用于C

    3.5.2 彭博CAPI

    3.5.3 基本引用示例

    3.5.4 基本历史示例

    3.5.5 填入Access数据库

    3.6 本章小结

    第4章 IHS Markit:大企业数据

    4.1 企业贷款

    4.1.1 数据请求4.1.2 贷款信息

    4.1.3 贷款定价、金融和分析

    4.2 企业和主权债券

    4.3 途径1:在Excel中存储Markit信息

    4.4 途径2:将Markit数据导入Microsoft Access

    4.5 途径3:用C导入Markit数据

    4.6 本章小结

    第5章 金融数据分析

    5.1 数据真实性

    5.1.1 检查数据

    5.1.2 样本规模

    5.1.3 异常值

    5.2 投资组合

    5.2.1 投资组合工作表

    5.2.2 投资组合数据库表

    5.3 连接Excel工作表和Microsoft Access

    5.4 留存记录

    5.4.1 途径1:Excel

    5.4.2 途径2:Microsoft Access5.4.3 途径3:C

    5.5 本章小结

    第6章 相对价值分析

    6.1 途径1:Excel

    6.1.1 Excel中的相关性与回归

    6.1.2 对等组

    6.1.3 评级

    6.1.4 统计工作表

    6.1.5 并排比较

    6.1.6 指数

    6.1.7 加权Z值

    6.2 途径2:Access

    6.2.1 Access中的相关性和回归

    6.2.2 Access中的中位数

    6.3 途径3:C

    6.3.1 相关性和回归

    6.3.2 对等组

    6.3.3 评级

    6.3.4 统计表6.3.5 并排比较

    6.3.6 加权Z值

    6.4 本章小结

    第7章 组合风险分析

    7.1 途径1:Excel

    7.1.1 方差、波动性和标准差

    7.1.2 带历史或预期收益的夏普比率

    7.1.3 投资组合分解

    7.1.4 警告标志

    7.2 途径2:Access

    7.2.1 投资组合分解

    7.2.2 警告标志

    7.3 途径3:C

    7.3.1 历史或预测收益的夏普比率

    7.3.2 投资组合分解和警告标志

    7.4 本章小结

    第8章 市场分析

    8.1 途径1:Excel

    8.1.1 新发放贷款分析8.1.2 再融资

    8.1.3 价格历史

    8.2 途径2和3:Access和C

    8.2.1 新发放贷款分析

    8.2.2 再融资

    8.2.3 价格历史

    8.2.4 更进一步

    8.3 本章小结

    第9章 创建报告

    9.1 途径1:Excel

    9.2 途径2:Microsoft Access

    9.3 途径3:C和SSRS

    9.4 本章小结

    第10章 投资组合报告

    10.1 监测业绩和风险

    10.2 途径1:Microsoft Excel

    10.2.1 计算收益

    10.2.2 投资组合报告

    10.3 途径3:C和SSRS10.4 本章小结

    第11章 结论

    附录A 表格参考O’Reilly Media,Inc.介绍

    O’Reilly Media通过图书、杂志、在线服务、调查研究和会议等方式传播创

    新知识。自1978年开始,O’Reilly一直都是前沿发展的见证者和推动者。超级极

    客们正在开创着未来,而我们关注真正重要的技术趋势——通过放大那些“细微的

    信号”来刺激社会对新科技的应用。作为技术社区中活跃的参与者,O’Reilly的

    发展充满了对创新的倡导、创造和发扬光大。

    O’Reilly为软件开发人员带来革命性的“动物书”;创建第一个商业网站

    (GNN);组织了影响深远的开放源代码峰会,以至于开源软件运动以此命名;创立

    了Make杂志,从而成为DIY革命的主要先锋;公司一如既往地通过多种形式缔结信

    息与人的纽带。O’Reilly的会议和峰会集聚了众多超级极客和高瞻远瞩的商业领

    袖,共同描绘出开创新产业的革命性思想。作为技术人士获取信息的选择,O’Reilly现在还将先锋专家的知识传递给普通的计算机用户。无论是通过书籍出

    版,在线服务或者面授课程,每一项O’Reilly的产品都反映了公司不可动摇的理

    念——信息是激发创新的力量。

    业界评论

    “O’Reilly Radar博客有口皆碑。”

    ——Wired

    “O’Reilly凭借一系列(真希望当初我也想到了)非凡想法建立了数百万美

    元的业务。”

    ——Business 2.0

    “O’Reilly Conference是聚集关键思想领袖的绝对典范。”

    ——CRN

    “一本O’Reilly的书就代表一个有用、有前途、需要学习的主题。”

    ——Irish Times

    “Tim是位特立独行的商人,他不光放眼于最长远、最广阔的视野并且切实地按

    照Yogi Berra的建议去做了:‘如果你在路上遇到岔路口,走小路(岔路)。’回

    顾过去Tim似乎每一次都选择了小路,而且有几次都是一闪即逝的机会,尽管大路也

    不错。”

    ——Linux Journal

    本书赞誉

    只有最佳运用信息的金融分析师才能超越同行。在《解密金融数据》一书中,本书作者手把手教你如何获得这种宝贵的优势。

    ——Thomas Majewski,Eagle Point Credit Management公司合伙人

    《解密金融数据》是在金融领域进行海量信息分析的有效工具,为想运用当今

    技术加强决策并在市场中占据优势地位的专业人士提供了无价指导。本书作者是结

    构化金融领域的领军人物。他的洞见来源于他利用当今科技分析经验数据的能力。

    ——David Trepanier,CFA,美国某著名金融机构的CLO结构化产品总监

    真正有天赋的金融分析师是很少的,只有很小一部分才懂得利用科技。贾斯汀·

    保利是在两方面都非常出色的少数人之一。他在有效获取和管理数据方面的能力超

    群,还能利用这些数据进行清晰简明的分析。

    ——David Preston,CFA,Wells Fargo Securities公司董事总经理、CLO和商

    业ABS研究总监

    在进行金融数据分析时,技术工具的重要性不言而喻。贾斯汀·保利是结构化产

    品市场的领军人物,很大程度上是因为他有深厚的技术功底。在《解密金融数据》

    一书中,作者讲述的获取金融数据的方法是其他地方都没有讲过的,因此很有价

    值。本书几乎能使任何分析师受益,不管你有没有技术基础。

    ——Dylan Ross,Brigade Capital Management公司合伙人

    译者序

    21世纪,大数据挖掘和处理已经成为时代的潮流。信息属性强大的金融数据能

    够为金融分析预测提供强有力的支持。然而由于数据挖掘处理涉及很多计算机应用

    技术,很多金融行业从业者或者相关人士已经感觉到自己跟不上数据时代的脚步,特别是非计算机技术专业的人士对挖掘、处理大数据感到十分挠头。甚至在一些金

    融企业中,购买的金融数据库可能只在后台支持部门使用,前台业务部门的人由于

    不知道如何挖掘处理数据而放弃了使用。因此,大家迫切需要简单实用的辅导材

    料,帮助他们走出困境。

    本书就是一本内容系统、浅显易懂、关注实操的书。非计算机专业的人士即使

    只有比较初步的Microsoft Excel或Access知识,在阅读学习本书后也能很容易地

    掌握在彭博和IHS Markit等金融数据系统中搜索有用信息并进行分析汇总的方法。

    针对有计算机技术基础的人,本书还提供了C编码,以此满足更多读者的需求。

    本书具有以下特点:

    1.全书讲解方式简单直接,内容和语言没有晦涩难懂的感觉,读者完全不用担心自己的计算机技术基础,非计算机技术专业的人士阅读学习没有压力。

    2.实际操作性极强,方便自学,从如何导入数据到如何编码,本书都给出了具

    体的操作步骤和实例,可以直接拿来使用。

    3.内容全面丰富,涉及数据搜索、分析到编制相关报告,深度和广度兼顾,是

    一本“工具红宝书”。

    从金融科技的角度看,科技将服务金融业务、引领金融创新、驱动金融变革。

    但是归根结底,科技是要为人服务的,包括从事金融业的人,不能用烦琐的科技束

    缚了金融从业者或相关人士的手脚。我们的目标是为你提供一本简单易学的金融数

    据挖掘处理“工具红宝书”,希望这本书能够帮助你从金融数据“小白”成长为行

    家里手!

    译者

    前言

    如果你在书店打开了这本书,正在犹豫这本书是否适合你,那么让我来帮你分

    析:

    ·本书能帮助你将来自于彭博和IHS Markit的金融数据与自己的观点结合起来进

    行分析,并用Microsoft Excel制作专业的分析报告,而不需要进行编程或者IT部

    门的协助。

    ·本书会一步一步地指导你快速制作出专业化的市场信息报告,其中包括历史财

    务信息、比较分析和相对价值。

    ·对于资产组合经理来说,本书展示了如何制作一份专业的资产组合总结报告,其中对资产组合的业绩、成长性、风险调整后收益和组成等进行了高度概括。

    ·如果你是程序员,或者可能成为程序员,本书还介绍了如何使用C实现相同的

    功能。

    ·我并非学术人员,所以关注“实战”。你需要的基础知识仅仅是金融知识和Excel知识。你不需要有任何编程、VBA或高等数学基础。

    我一直喜欢计算机科学,所以不奇怪我的第一份工作是在Wachovia(现为

    Wells Fargo)公司做程序员。不过在我的职业生涯早期,我就意识到了有些重要

    的东西会指引我走向完全不同的职业道路。我认识到我运用科技获取和分析数据的

    能力在IT部门以外的其他领域(例如金融领域)能发挥更大的作用。

    做了三年程序员之后,我转入银行研究部门,用我的计算机技术挖掘财富市场

    上的海量信息,并与内部消息相结合。这些技术使我比其他分析师有更大的优势,我成为苏格兰皇家银行的策略总监,之后我又成为位于纽约的Brigade Capital

    Management公司的高级结构化信贷分析师。在Brigade公司,我用计算机技术对投

    资进行估值,并体现了很大优势。

    在我的职业生涯中,我不时地会教许多同事一些有用的计算机技术。在教他们

    的过程中,我了解到即使你不懂编程,也能够深入彭博屏幕的背后做很多分析工

    作。你需要的基础知识不过是金融行业雇佣的大多数人已经掌握的知识、分析思维

    和使用Excel的经验(当然,还需要本书)。本书还照顾到程序员的需求,本书没有

    费时费力地讲解API文档,而是用许多有用的C案例展示如何从彭博和IHS Markit

    获取市场数据,用Math.Net开源库进行金融分析,用SQL Server Reporting

    Services(SSRS)自动生成专业化的报告。

    我写本书的目的就是教更多人使用这些技术,帮助人们使自己的简历在厚厚的

    简历堆中脱颖而出。

    本书排版约定

    本书中的不少代码都被拆成几行写,这是由于印刷页面的限制。如果你在系

    统中运行代码就无须分行。

    斜体字(Italic)

    表示新的术语、链接、电子邮箱地址、文件名和文件扩展名。

    等宽字体(Constant width)用于程序清单,也用于在段落中引用程序元素,例如变量名、函数名、数据

    库、数据类型、环境变量、程序语句和关键词。

    加粗等宽字体(Constant width bold)

    表示应该由用户输入的命令或者其他文字信息。

    斜体的等宽字体(Constant width italic)

    表示此处应该替换为由用户提供的数值,或者根据上下文确定的数值。

    这个图标表示一个通用的注释。

    这个图标表示警告。

    使用代码示例

    可以在http:bit.lyunlockFD_examples上下载辅助资料(代码示例、练

    习等)

    本书的目标是切实好用,帮助你完成工作。原则上,如果本书提供了代码,你

    就可以在你的程序和文档中使用。除非你要大范围复制代码,否则不用与我们联系

    要求获得许可。例如,使用本书中的几大段代码不需要许可。售卖O’Reilly出版

    社的书的案例光盘需要许可。回答问题时,引用本书或本书中的案例不需要许可。

    在你的产品文档中大量使用本书中的示例代码需要许可。

    我们赞赏但不要求注明引用。引用通常包括书名、作者、出版商和ISBN。例

    如“Unlocking Financial Data by Justin

    Pauley(O’Reilly).Copyright 2018Justin Pauley,978-1-491-97325-

    7”。

    如果你觉得自己使用代码示例的范围超出公平使用或上述许可的范围,请联系

    permissions@oreilly.com。

    Safari在线图书Safari Books Online针对企业、政府、教育机构和个人提供了不同的购买计

    划,你可根据实际需求进行选购。

    用户可以访问上千种图书、培训视频、学习路径、互动教材和专业的播放列

    表,这些内容来自超过250个出版商,包括O’Reilly Media、哈佛商业评论、Prentice Hall Professional、Addison-Wesley Professional、Microsoft

    Press、Sams、Que、Peachpit Press、Adobe、Focal Press、Cisco Press、John Wiley&Sons、Syngress、Morgan Kaufmann、IBM Redbooks、Packt、Adobe Press、FT Press、Apress、Manning、New Riders、McGraw-Hill、Jones&Bartlett和Course Technology等。关于Safari在线图书的更多信息,请

    访问http:oreilly.comsafari。

    联系方式

    美国:

    O’Reilly Media,Inc.

    1005Gravenstein Highway North

    Sebastopol,CA 95472

    中国:

    北京市西城区西直门南大街2号成铭大厦C座807室(100035)

    奥莱利技术咨询(北京)有限公司

    我们有个关于本书的网页,上面有勘误表,示例和所有的附加信息。可以通过

    以下链接访问:http:bit.lyunlockingFinancialData_1e。

    关于本书的评论和技术问题,请发邮件给bookquestions@oreilly.com。

    关于本书的更多信息,如教程、会议、新闻,请参见网站:

    http:www.oreilly.comhttp:www.oreilly.com.cn

    致谢

    本书献给我的妻子Emily Pauley。特别感谢对本书贡献了宝贵时间和支持的

    人;没有你们我无法完成本书(排名不分先后):Alex Belgrade、Scott

    Moore、Jeana Curro、Dan Bleicher、Matt Perkal、Sumit Sablok和Tom

    O’Shea。

    第1章 简介

    金融分析师的工作简单说就是找出有价证券的价值,有价证券包括股票、贷

    款、债券,甚至房地产贷款的债券化投资组合等。换句话说,金融分析师需要确定

    他买卖一种有价证券的价格。确定价格没有统一的方法、模型或者公式,因为每笔

    投资都是不同的。然而,估值过程通常包括以下两个重要步骤:

    ·分析师需要详细、彻底地了解每笔潜在投资,分辨出各种投资方式的细微差

    别,以及赚钱和赔钱的概率。

    ·风险调整后的收益结果与其他的潜在投资进行比较,以确定给定投资的估值到

    底是高了、低了,还是合理。

    不是简单地对每个有价证券进行一次估值;投资必须进行持续估值。在经济高

    度全球化的今天,投资风险持续变化,大宗商品价格变动、政府监管措施、自然灾

    害、消费者敏感程度以及其他数不清的因素都可能对投资风险产生影响。同理,即

    使有些因素并没有直接影响一个有价证券,但是它们可能使一项投资与其他投资相

    比看上去更便宜或者更昂贵。

    对有价证券进行估值的过程是复杂的,耗费大量时间,还需要分析大量金融数

    据。大部分金融数据是由发行有价证券的公司或者相关银行提供的,因此并不总是

    能提供完整、准确的情况。更重要的是,大部分公司都有海量金融数据,这些数据

    虽然能帮助估值,但是技术部门以外的人不知道如何获取数据,甚至不知道数据的

    存在。本书将带你超越彭博终端,解密彭博数据的真实潜力。本书仅仅使用Excel(而

    不用任何编程技术)展示如何获取彭博屏幕背后的数据,按照你的意愿组织数据,并服务于你对投资的决策考虑。本书还介绍如何从IHS Markit获取金融信息,IHS

    Markit是企业债券和贷款数据(特别是定价)的最佳数据源之一。许多银行、资管

    经理、对冲基金订购了Markit数据,但是大部分数据都用于支撑内部或后台系统,却很少到达分析师手中。

    除了展示如何获取金融信息外,本书第二部分介绍如何进行数据分析。该部分

    教你利用金融数据,通过分析贷款、保险和再融资的价格变动趋势,确定相对价

    值,测量投资组合风险,计算有价证券之间的相关性并研判市场趋势。

    最后,我们将把数据、分析与你的观点结合起来,根据个人意愿创建定制报

    告。与千篇一律的报告不同,你的报告会将一个公司的业绩与你自己设定的对等

    组、你认为有价值的对应基准指数或者你认为有价值的金融字段和计算进行比较。

    尽管这些内容(数据获取、分析和报告)都可以用简单的方法自动实现、维护

    和更新,不需要进行编程,不过本书还是为程序员或者潜在程序员提供了使用C编

    程语言的方法。数据和信息在所有的行业都是宝贵的,在金融行业尤甚,程序开发

    人员写代码、查询数据库的能力可以使他比分析师更有价值。本书中有很多案例,告诉你如何获取金融信息,对大型数据集进行不同种类的简单金融分析,并使用

    SSRS(不用SQL Server)创建金融报告。如果你对介于Excel和C之间的方法感兴

    趣,我们还介绍了如何使用Microsoft Access数据库。

    本章具体介绍本书的各个部分,特别是理念和目标。并根据投资类型(股票、债券和贷款),分别介绍如何使用本书。

    1.1 概览

    本书分为三大部分:获取金融数据、金融数据分析、创建金融报告。每一部分

    都有明确且实用的目标。

    1.1.1 第一部分:获取金融数据

    第一部分(从第2章到第4章)介绍如何用彭博(Bloomberg)和Markit获取、存储金融数据,如股票、指数、债券和银行贷款等。从彭博和Markit系统中获取这

    些信息,你将可以:

    ·获取彭博屏幕上看不到的额外信息。

    ·创建包含企业数据的表,以便一起比较多个公司、债券或贷款。

    ·在大部分可交易企业债券和贷款市场中查询每日价格和机构信息。

    ·根据个人偏好,仅显示重要的内容。

    ·使用其他来源,重写错误或缺失信息。

    ·根据个人观点,对公司进行分类,建立合适的对等组(peer groups)。

    ·把彭博和Markit数据与你的计算和观点相结合。

    学完该部分后,你能灵活分解和运用金融数据,灵活性远超使用彭博终端。此

    外,第3章的技巧能保证你用易于维护的方式存储数据,并与其他数据集相结合。

    1.1.2 第二部分:金融数据分析

    第二部分(从第5章到第8章)将第一部分收集到的金融数据放入具体的背景环

    境中进行金融分析。第二部分先将某个有价证券与对等有价证券进行比较,然后检

    测投资组合的风险水平,最后与更广阔的市场趋势相结合。使用该部分介绍的技

    术,你将可以:

    ·用相关性和回归确定两个有价证券(或指数)之间的关系。

    ·将各个有价证券的业绩与有类似风险和收益性质的有价证券对等组进行比较。

    ·用加权Z值(Z-score)对有价证券的相对业绩进行排序。

    ·通过计算方差、标准差和夏普比率(Sharpe ratio),测量投资组合风险调

    整后的收益。

    ·把投资组合“划分”成几个组,以关注看不见的内容和趋势。·用不同的标准建立投资组合门槛,以关注风险。

    ·用Markit数据发现对价格、新发放息差和再融资有意义的趋势。

    学完该部分后,你能把第一部分介绍的数据库加以应用,进行观点、风险和趋

    势分析。此外,第6章中描述的方法将告诉你如何保存历史,发现用第一部分的知识

    获取到的数据库存在的特殊问题。

    1.1.3 第三部分:创建金融报告

    第三部分(第9章和第10章)结合了第一部分和第二部分的内容,教你如何对各

    个公司和投资组合创建分析报告。在该部分中,我们将学习把前面的章节中用到的

    数据和分析,按照你的意愿进行展示并绘制图表。该部分将展示如何:

    ·为每个公司创建一份两页长的分析报告(活页,tear sheet),其中内容包括

    重要的历史金融数据、自定义备注、与对等公司的价值比较和分析师研究出来的价

    格趋势等。

    ·用一个投资组合或一个指数的历史收益,计算时间加权(几何)投资组合收

    益、年化投资组合收益、年化投资组合标准差和夏普比率。

    ·创建一份两页长的投资组合摘要报告,其中包括高度概括的投资组合业绩、增

    长、风险调整后的收益和投资产品组成。

    学完该部分后,你就能从下拉菜单选择一个公司名,然后马上就能创建一个定

    制专业公司报告,而不用进行编程。此外,你还能针对投资组合的业绩绘制图表,并将其业绩与基准进行风险和收益比较。

    1.2 金融市场

    本书关注三个重要金融市场:股票、企业债券和企业贷款。尽管如此,你可以

    将在本书中学到的内容直接应用到其他市场,比如结构化产品、市政债券等。

    1.2.1 股票本书中的很大篇幅都关注股票市场。本书第一部分展示如何用彭博数据创建一

    个有基本数据和技术数据(转换成使用单一货币)的表。因为是在Excel里,所以你

    可以很容易地用自己的输入内容对彭博数据进行补充。例如,通过增加自己的类型

    列,你可以对相似的公司进行正确的分组,而非依靠传统的行业分类信息(有可能

    是误导信息)。此外,彭博有海量金融企业数据。本书教你如何找到想寻找的确切

    信息,而不用对着每个公司数十屏幕的资料狂翻一气。下面仅是部分字段:

    ·领域、行业、子行业。

    ·流通股中短期利率所占的比重。

    ·标准普尔和穆迪评级。

    ·市值、企业价值、EPS。

    ·总债务、净债务、总债务EBITDA。

    ·股息收益率、十二个月总收益。

    ·三个月和今年迄今价格变动(%)。

    ·利息备付、自由现金流(FCF),自由现金流总债务。

    ·信用违约交换息差。

    ·买入卖出持有建议。

    ·毛利、滚动市盈率EBITDA。

    ·历史金融数据。

    本书第二部分教你如何计算两个公司之间或者一个公司与一个对标指数(基准

    指数)之间的关系(相关性和Beta)。还介绍如何对Excel公司表中每个自定义的

    分类添加业绩数据中位数。你可以使用业绩数据中位数,将每个公司的业绩与其对

    等组进行比较。

    本书第三部分教你如何设计公司报告,而不是依靠第三方提供的报告。定制报告的优势就是可以使用自己想用的字段、备注和计算。

    1.2.2 企业贷款(银行贷款、杠杆贷款)

    与股票一样,本书第一部分从彭博提取一系列有用的字段,存入Excel(或

    Access),包括:

    ·利差、下限、指数。

    ·到期日。

    ·穆迪和标准普尔机构评级。

    ·今年迄今和三个月价格变化。

    ·贴现差额、收益率。

    ·下一个提前赎回日、赎回价格。

    然而和股票不一样的是,本书第一部分展示如何从IHS Markit获取贷款数据,其中的贷款信息可以说是丰富的。此外,Markit数据涵盖了大部分可交易的贷款,而不是少量数据。每笔贷款的每日贷款价格,结合每笔贷款的机构信息,使我们能

    够了解整体贷款趋势,例如某个行业的贷款趋势。如下是一些Markit贷款机构数

    据:

    ·发行人、行业、机构类型。

    ·发起人、牵头行、管理行。

    ·规模、利差、下限、OID。

    ·CUSIP。

    ·留置权类型(第一留置权第二留置权等)。

    ·不包含借方保护条款的高风险贷款标示(Cov-Lite Flag)。·穆迪和标准普尔机构评级。

    ·发行日期、交割日期、到期日期。

    在第二部分,贷款分类取决于母公司的分类以及风险和收益性质,例如“Short

    CCC”代表评级为CCC的短期贷款。根据对等组的中位数对贷款进行排序。除了机构

    层面的信息和价格,Markit提供本书第二部分用到的再融资信息判断趋势,例如分

    行业的息差收窄或扩大。

    1.2.3 企业债券

    和股票一样的是,在彭博中有大量企业债券数据可以将其抽取出来放入

    Excel(或者Access)表。一些字段包括:

    ·票面利息。

    ·到期日。

    ·穆迪和标准普尔机构评级。

    ·YAS利差和YAS收益率(参见彭博YAS屏幕)。

    ·今年迄今和三个月价格变化。

    ·可赎回标示、下一个提前赎回日、下一次赎回价格。

    和贷款一样,债券也归到第二部分。每个分类的中位数值结果之后都用作该分

    类每个债券的基准值。

    1.3 三种途径

    本书的理念有三种不同的实现方法(途径),从技术难度角度说,从易到难的

    排序是:Excel、Microsoft Access和C。由于各章的理念相互依存,所以要做好

    实践。本书会用“途径”专门指明某种方法,便于你找到对应方法。

    由于大多数人熟悉Excel,因此本书大部分章节使用Excel作为主要数据处理手段。Microsoft Access途径是建立在Excel途径基础之上的,要先把数据库连接到

    Excel工作簿,然后在Access数据库中查询数据,这可避免使用复杂的Excel公式。

    C途径用代码从第三方系统(彭博和Markit)提取数据,在Microsoft Access中

    存储数据并分析,使用SSRS生成报告。

    每章都会采用三种途径,有两个原因。第一个原因是本书的目标读者不同。使

    用Excel很多年的金融分析师可能从来没使用过数据库,或者没写过一行代码。而对

    于程序员来说,有很多获取、操作和存储数据的方法比Excel更直接。第二个原因是

    鼓励从没有使用过数据库或者没写过代码的人试一试。尽管本书不教授如何查询数

    据库或者编写程序,你可以结合本书与教授如何查询数据库或者编写程序的书(例

    如Jennifer Greene和Andrew Stellman写的《Head First C》

    (O’Reilly))一起深度学习。此外,初次涉及编程的人员可以使用Excel实例以

    便更好地理解C代码。下面列出了每种途径的优缺点。

    1.3.1 途径1:Microsoft Excel

    无论你是分析师、程序员、科学家、会计或者其他职业,只要你和数字打交

    道,都可能用到Excel。Excel是市场上最强大、灵活、受欢迎的分析程序之一。它

    除了拥有大量实用函数之外,Excel的界面也适合大众使用。然而,它与Access和

    C相比还有一些不足:

    ·尽管Excel处理几千行数据没问题,但是如果数据量很大,计算效率就不高

    了。数据的行数或者列数过多可能导致效率下降,甚至宕机。

    ·Excel公式可能很快就会变得复杂冗长,难以阅读。仅仅进行最基本的运算就

    可能用到多个内函数和数组函数。

    ·尽管Excel公式是动态的,但是很难维持。随便插入一列就可能使某些公式出

    现错误而难以察觉。

    ·在出问题的时候,动态的长公式难以进行调试。

    1.3.2 途径2:Microsoft Access尽管Microsoft Access就是Microsoft的企业版数据库软件SQL Server的简

    化版,但是几乎所有人都可以不必求助于IT部门就能用上Access。Access是一个很

    棒的数据库应用,能方便地连接到Excel,导入逗号分隔值(CSV)文件,或者你自

    己的、长达数百万行的表(最大约2GB)。如果你从来没使用过数据库,也不会觉得

    Access比Excel更难。和Excel一样,数据存储在类似于Excel工作表的数据库表格

    里,但是数据库的列更有条理(定义为日期、文本、数字等)。然而,Access用一

    种很简单的语言分割处理数据,而非使用很长的Excel公式,那种语言被命名为结构

    化查询语言(Structured Query Language,SQL),既方便使用,又方便读取。

    你可以用SQL从多个表连接数据,而且可以包括许多与Excel相同的集合函数(平均

    值、最大值、最小值、标准差等)。查询2017年出版的书籍数量,可用如下简单的

    查询方式:

    SELECT COUNT() FROM Books WHERE Year(PublicationDate) = 2017

    在本书中,用途径2的人需要先用Excel从彭博获取数据,然后把Excel工作表

    连接到Access再进行查询。能够简便查询数据的能力使Access很强大。然而,Access也有缺点:

    ·其内置报告函数比Excel弱很多。除了不直观之外,还缺少Excel具备的画图函

    数。

    ·Access没有Excel那么灵活。使用Access无法直接在单元格中输入公式,也不

    能在数据表旁边直接插入图表。

    ·查询前一行的值可能比想象得更复杂。

    ·查询结果不像Excel那样容易排格式。

    ·尽管Access可以容易地连接到Excel表格获取彭博数据,但是它却不能连接到

    彭博。

    ·SQL查询尽管可以阅读,但也可能变得冗长复杂。

    1.3.3 途径3:CC(读音为“C sharp”)是使用Microsoft.NET Framework的一种编程语

    言。尽管C函数强大,但也能简单易学。此外,还有Microsoft的Visual Studio

    集成开发环境(Integrated Development Environment,IDE),这是一种写代

    码的工具,可以用它创建漂亮的应用。与Access和Excel不同,C不受表、行、列

    的限制。它可以从Excel、Access、网站、email、彭博、文本文件或者差不多任何

    东西里获取数据。C可以接入无穷多的数学、科学和金融函数。可将数据和计算传

    送给SSRS,用几行代码就可以产生漂亮的报告,然后转换成PDF或Excel文件。最

    后,因为C创建应用,所以可以用它更新数据、创建报告,甚至发送邮件。尽管如

    此,C也有其缺点:

    ·C需要的前台工作比Excel多。用C从彭博获取数据需要编写多行代码,而

    Excel只需要一个简单的公式。

    ·SSRS是与C结合使用的报告工具,功能很强大;然而,它没有Excel那么简单

    灵活。

    ·在工作电脑上安装C(.NET)可能需要IT部门协助并获得特殊许可。

    ·尽管C是比较简单的编程语言,但是学习来也要经历学习曲线。和其他编程语

    言一样,C也有自己的语法和细微差别。

    尽管我们鼓励你探索新技术,不过概念比实现更重要;用最适合你、最契合你

    的实际情况的技术就好了。

    1.4 线上文件

    你可以从O’Reilly出版社的网站上下载全套Excel工作表、Access数据库和

    C代码,然后根据具体情况修改使用。这样你就不用全部重新开始。然而,你还是

    需要明白每个步骤的意义,这样才能不犯错误。而且由于版权问题,本书也不能提

    供所有数据(特别是Markit的数据),因此有些数据并非真实的。

    可以从http:bit.lyunlockFD_examples下载文件。

    1.5 本章小结在最终作出投资决策时,最重要的是分析师的信念。没人能教会你信念,信念

    来自于多年的经验——挣钱(有时也赔钱)。要知道一些数字是否有意义,或者有

    些公司的CFO是否确切地回答关于受益的问题,是需要经验的。世界上所有的数据和

    分析加起来也不能铸成信念,本书的目的是帮你在指端收集更多信息,以支持你铸

    成信念,发现更多的投资想法。

    第2章 组织金融数据

    数据!数据!数据!没有黏土做不了砖。

    ——福尔摩斯

    尽管马上就从彭博等来源获取金融数据很有吸引力,先坐下来想一想你打算把

    数据存在哪里,这样做绝对是“磨刀不误砍柴工”。做个规划或者方案是重要的一

    步,因为杂乱无章的数据很快就会难以更新,或者容易出错。例如,一个用于追踪

    学生、教师和课程的Microsoft Excel工作簿或Access数据库。如果每个班的老师

    都是用姓名作标识,然后老师结婚改了姓,那么与她的名字相关的所有信息都得更

    新。如果出现一点小状况,就可能出现大问题。如果学校足够大,就可能有两位老

    师重名,排课和发工资都可能出现问题。

    为了解决这个问题,需要把数据存储在所谓的“第三范式”。简而言之,我们

    要为每套数据创建一个数据库或者一张Excel表(例如学生们一张表、老师们一张

    表、各个课程一张表等)。这些工作表(worksheet)或表(table)中的列只包含

    分属于各自实体的属性。这称为“有”(has-a)关系。这样,所有信息和属性就不

    会重复了。例如,一个教师的全名只会出现在Teacher表中,因为教师“有”姓

    名。Class表包含关于课程(例如生物、数学等)的信息,不应包含教师姓名列,因

    为这将导致信息重复。

    然而,这就产生了如何把教师分派到课程的问题,因为每个课程“有”教师。

    当你需要一张表引用另一表中的一个实体(教师、学生等),就要使用主关键字

    (Primary Key)。主关键字是一个永远不会改变的唯一标识符,例如教师证号码

    (Teacher ID)或者社保号码,它标示出表中某个独一无二的行。因为唯一标识符

    永远不会改变,我们可以用它在Class表中作为引用(reference),也称为外关键字(Foreign Key),以引用Teacher表的一个教师。因为Class表用主关键字引用

    教师,如果教师改名的话,只更新Teacher表就行了。尽管这听起来可能有点复

    杂,你需要记住不应把同样的数据存储在多个地方。

    本章展示如何在Excel和Access中创建这些例表,并带你学习如何正确地存储

    和获取信息。

    2.1 途径1:Excel

    2.1.1 Excel区域与Excel表

    Excel是一个很棒、很灵活的工具,因为可以把数据和公式放在工作表中的任何

    地方。然而,如果不增加一些结构,公式可能就会难以阅读,而且还会产生不易发

    觉的错误。有人就因为模型中的毛病损失了钱财或丢了工作。避免这些问题的一种

    方法是将Excel区域(range)转换为Excel表(table)。

    在一张Excel工作表中,任何相互连接的单元格群组都是一个Excel区域。

    Excel区域所受的限制很少;它既可以是一个单元格,也可以是整张工作表。另一方

    面,Excel表是在Excel区域上增加了列标题,并提供命名引用。例如,如果在

    Excel工作簿上随便一个位置存放了一个学生表单,那么数学生个数的公式如下所

    示:

    =COUNTA(A1:A14)

    如果列移动了或者增加了新的行,可能公式就不能查出正确的行数。然而,如

    果把Excel区域转换成Excel表,命名为“Student”,公式如下所示:

    =COUNTA(Student[StudentID])

    在这种情况下,你可以完全确信表里包括了所有学生。用下面的步骤填入Excel

    区域,并转换为Excel表:

    1.第2行的A至E列分别命名为:StudentID、FirstName、LastName、DateOfBirth和Sex。2.从第3行到第8行,增加与列标题对应的学生数据。

    3.选择第1步和第2步创建的Excel区域中的每一个单元格。

    4.在Excel功能区上,在Home键上,选择“Format as Table”(或者按

    Ctrl+T组合键)。确保在“My table has headers”框上打钩,然后点击OK。

    图2-1显示的是几个Excel表,我们用这些表讨论第三范式和存储数据的正确方

    式。

    把Excel区域转换为Excel表,除了增加彩色格式之外,还使每个列标题旁边的

    下拉式控件变得可用。此外,右击Excel表并从Table选项中选择Totals Row,就

    能在Excel表中添加一个合计行(Total Row),你就能为每列选择一个聚合函数功

    能了(见图2-2)。图2-1:Excel表示例

    图2-2:Total行的下拉式菜单

    命名表格是很重要的。方法是点击表中任意单元格,然后在函数区上,点击

    Design,然后在左上角的Table Name文本框中输入一个名字(如Student)。将图

    2-1中的表命名为:Student、Teacher、Class和Enrollment。命名表格之所以很

    重要,因为这让引用每个Excel表的公式变得更加便于读写。在本章中的后续部分,将会介绍这个内容。

    2.1.2 增加引用列

    根据图2-1,示例中的数据分成四个表格:Student、Teacher、Class和

    Enrollment。Student表包含每个学生的所有属性,包括唯一标识符

    (StudentID)作为主关键字。同理,Teacher表包含每个教师的所有属性,包括唯

    一标识符和主关键字(TeacherID)。

    Class表开头很像Student和Teacher表,包含每个课程的属性,包括主关键字

    (ClassID)。然而,因为一个课程“有”教师,所以它包括Teacher表的主关键字列(TeacherID),以引用该课程的教师。包含来自于另一个表的主关键字的列,称为外关键字(Foreign Key)。Enrollment表(包括每个课程学生的表单)有两

    个外关键字:ClassID(确认学生课程的班级)和StudentID(确认参加课程的学

    生)。此外,因为根据定义Enrollment表每行都是唯一的(一个学生不能两次在同

    一个课程),可以让ClassID和StudentID二者共同作为主关键字,以标识一个唯一

    的行。当两列或更多列共同组成一个主关键字,称为复合关键字(Composite

    Key)或者复合主关键字(Composite Primary Key)。

    然而在Excel中,如果不得不引用好几张表才能确认教师、课程和学生名,就有

    点恼人了。所以,我们采用INDEX和MATCH函数,用主关键字和外关键字从一张表到

    另一个表增加列。重要的是,我们并非向其他表增加属性本身,这样会产生数据冗

    余;我们增加的是引用或连接。如果更新原始表中的数据,所有对该数据的引用也

    会自动更新。

    尽管许多Excel用户熟悉VLOOKUP函数,传统上它用一个数据集里的标识符“查

    询”另一个数据集里的信息,但是VLOOKUP的功能其实不如INDEX和MATCH函数结合

    使用。VLOOKUP的主要缺陷是依赖于列的顺序和位置。使用VLOOKUP时,你想查找的

    信息必须位于lookup值的右侧。此外,如果增加、删除、移动列,就可能导致

    VLOOKUP偏好错误的单元格,由此导致重大错误。这些错误在使用INDEX和MATCH函

    数时不会出现。向TeacherID外关键字与Teacher列的TeacherID主关键字相匹配的

    Class表增加教师姓名的公式,如下所示:

    =INDEX(Teacher[FirstName],MATCH([TeacherID],Teacher[TeacherID],0))

    把公式分解一下,INDEX函数有两个参数:列名和行号。INDEX函数返回该行该

    列交叉的那个单元格的值。MATCH函数有三个参数:查询值、要搜索的列和匹配类型

    (匹配类型应当一直为零)。MATCH函数返回包含查询值的行号。在Class表

    TeacherID列与Teacher表TeacherID列相匹配的前提下,INDEX函数返回Teacher

    表FirstName列的内容。你还可以把它与姓相结合:

    =INDEX(Teacher[FirstName],MATCH([TeacherID],Teacher[TeacherID],0))

    INDEX(Teacher[LastName],MATCH([TeacherID],Teacher[TeacherID],0))本公式向Enrollment表中添加一列,用ClassID展示Class表中的Title:

    =INDEX(Class[Title],MATCH([ClassID],Class[ClassID],0))

    本公式向Enrollment表添加学生的全名:

    =INDEX(Student[FirstName],MATCH([StudentID],Student[StudentID],0))

    INDEX(Student[LastName],MATCH([StudentID],Student[StudentID],0))

    本公式向Enrollment表添加学生的性别:

    =INDEX(Student[Sex],MATCH([StudentID],Student[StudentID],0))

    注意,如果你改变了任何源信息(学生或教师姓名),使用INDEX和MATCH引用

    的单元格会自动更新。尽管这看上去有点复杂,你越用就会越熟练。此外,Excel有

    很棒的自动补全功能,边打字边可以从字段表单中进行选择。

    除了向Excel表增加引用列之外,有时增加包含总结式信息的列也是有用的。例

    如,这可能包括向Class表增加每班学生数量列,或者向Teacher表增加每班教师数

    量列。用命名的Excel表和列,向Class表增加学生数量列非常容易,具体如下:

    =COUNTIF(Enrollment[ClassID],[@ClassID])

    或者再进一步,计算每班女学生的数量:

    =COUNTIFS(Enrollment[ClassID],[ClassID],Enrollment[Student''s

    Sex],F)

    注意,在Excel表中复制粘贴而来的公式是不同的。在Excel区域中,复制和粘

    贴会导致公式被更新,引用的列会根据粘贴位置而相对变化。而在Excel表中,复制

    和粘贴单元格会导致使用确切的公式。要锁定某单元的公式用于拖动(而非在公式

    中用s),你需要像Class[[ClassID]:[ClassID]]这样引用单元格,而非单纯

    用[ClassID]。

    2.1.3 数据验证要保证主关键字和外关键字是正确的,这很重要。如果一个课程里有某个

    TeacherID并不存在于Teacher表中,就很糟糕了。幸运的是,Excel有一种数据验

    证(Data Validation)工具,能够帮助维护这些关系。Excel的数据验证工具强

    制使一个单元格包含来自于某个表单的值,还能关注到表单发生变化以及外关键字

    不再匹配的情况。

    然而不幸的是,数据验证工具只适用于已命名的区域,而不适用于表列名。用

    下面的步骤添加一个已命名的区域,连接到Teacher表中的TeacherID列。

    1.在函数区上,点击Formulas选项卡。在Defined Names组中,点击Define

    Name。

    2.在Name旁边输入TeacherIDs,在“Refers to”旁边输入

    =Teacher[TeacherID],然后点击OK。

    然后,用下面的步骤为Class表TeacherID外关键字列增加数据验证。

    3.在Class Excel表中,选择TeacherID列对应的那几行。

    4.在函数区上点击Data选项卡,在Data Tools组中点击Data Validation,然后选择Data Validation。

    5.选择Allow下拉菜单下面的List。取消勾选Ignore blank。把Source设置

    为=TeacherIDs,然后点击OK。

    结果是Class表中每个TeacherID单元格中有一个下拉框,这样你就只能选择

    Teacher表中存在的TeacherID。此外,点击Data Validation下拉菜单中Circle

    Invalid Data,Excel会在不正确的外关键字上画一个红色的圈。图2-3展示了红

    色的圈和下拉式数据验证功能。图2-3:Excel数据验证功能

    2.2 途径2和3:Access中的表格

    在涉及数据结构和表格之间的关系时,Microsoft Access比Excel严谨得多。

    本节展示如何在Access中创建表,在表之间建立联系,并用查询把数据结合起来。

    本节使用的部分例子与2.1节的Excel例子相同,推荐你也阅读2.1节。

    第一步是与图2-1一样的图表。在Design模式下,为每张表增加列,把主关键

    字列(StudentID、TeacherID等)的数据类型设置为Number。右击Primary Key

    列,然后选择要建立的主关键字,使这些列成为各个对应表的主关键字。不需要对

    外关键字(如Class表中的TeacherID)进行任何处理。

    然后在表中填上数据,在函数区上,点击Database Tools,然后点击

    Relationships。把外关键字从一张表拖到其他表的对应主关键字处(如将Class

    表中的TeacherID拖到Teacher表中的TeacherID处)。在Edit Relationships对

    话框(见图2-4)中,选择Enforce Referential Integrity,以确保外关键字与

    主关键字匹配。图2-4:Access中的Edit Relationships对话框

    当所有的关系都建立起来之后,Relationships选项卡应该看起来像图2-5这

    样。如果你试图向Class表添加一行,其中的TeacherID却并不存在于Teacher表

    中,那么这些关系会导致错误。图2-5:Access中的表格关系

    用查询连接数据

    对于不熟悉SQL的人来说,听说要学习SQL有点吓人,实际上它比你想的简单得

    多;甚至比在本书中的一些复杂的Excel公式还简单。尽管本书简要介绍了如何使用

    SQL,仍推荐阅读Thomas Nield写的《Getting Started with SQL》一书

    (O’Reilly出版社)。如下是SQL查询基本语法:

    SELECT Column1, Column2, Column3 from TableName;该查询将展示TableName表中列1至列3每行的内容。还可以添加一个WHERE子

    句,进一步过滤一些结果。例如,如下将从Enrollment表返回ClassId为365595的

    所有StudentID:

    SELECT StudentID from Enrollment WHERE ClassId=365595

    你还可以使用JOIN语句把多张表连接起来。例如,修改前一个查询,以包含

    Student表中该学生的姓和名,Student表的StudentID外关键字与Student表的主

    关键字匹配,用如下带内连接(INNER JOIN)的查询:

    SELECT E.StudentID, S.FirstName as [Student's First Name],S.LastName as [Student's Last Name] From Enrollment E INNER JOIN

    Student S on S.StudentID=E.StudentID WHERE ClassId=365595

    SQL查询对于回答复杂问题是很有力的工具。尽管SQL查询可能有点复杂,但是

    读着就比较容易理解的,不像有些Excel公式那样令人费解。如下查询将Class表与

    Teacher表连接起来,展示教师姓名和课程信息。此外,用子查询提取每班的学生

    数和女学生数:

    SELECT C.ClassID, C.Title, C.DateTime, C.Location, T.FirstName

    as [Teacher's First Name], T.Lastname as [Teacher's Last Name],(Select count() from Enrollment E where E.ClassID=C.ClassID) as [

    of Students], (Select count() from Enrollment E inner join Student

    S on S.StudentID=E.StudentID where E.ClassID=C.ClassID and

    S.Sex='F' ) as [ of Female Students] from Class C INNER JOIN

    Teacher T on T.TeacherID=C.TeacherID

    2.3 本章小结

    在本章中,我们讲到了预先对数据架构进行规划是很重要的,规划能够让你的

    数据组织合理,避免未来出现让人头痛的麻烦。一个良好的架构应当用一个唯一标

    识符(主关键字)来标示一个有价证券及其属性,并引用该唯一标识符,而非重复

    其属性(“第三范式”)。为金融数据找到唯一标识符可能并不太容易;最好是大

    部分时间都用该标识符,以保持一致。无论你用什么途径,Excel还是MicrosoftAccess,所用的架构都是相同的。在第3章中,我们将介绍如何提取彭博数据,存

    入Excel和Access中。

    第3章 彭博

    Bloomberg Professional(也称为彭博终端)是金融分析师最有用的工具之

    一。然而,尽管彭博终端本身有许多功能,但是其灵活程度和分析能力不及

    Microsoft Excel和Access。在本章中,我们用彭博提供的金融数据结合Excel、Access的灵活性,创建一个强大的分析工具。此外,彭博有Excel Add-in函数,还有完整的.NET API,方便获取其金融数据。

    我们将探索Excel Add-in和.NET API的常用特性;对于其他特性请查阅

    DAPI上的彭博文档。

    从彭博获取的数据是供个人使用的。扩散这些数据可能违反服务使用规则。

    此外,每天或每月能从彭博获取的有价证券和字段数量是有限制的。想获得更多信

    息,请参见彭博文档(DAPI)或咨询彭博业务代表(BREP)。

    在开始前需要发出一点警告:尽管彭博公司会甄别验证数据,但是仍然有些彭

    博信息可能是不正确的。然而,这不能成为你的分析不正确的理由。在本书后面,我们将讨论从大数据集合中识别和剔除不良数据的技术,但是只能手动审查数据以

    保证准确性,没有别的办法。如果你认为一些彭博数据不正确,请联系Bloomberg

    Help,以便该公司为你和其他用户修补数据。尽管如此,不要让数据可能不正确的

    想法吓坏你,不正确数据是小概率事件,而且在处理金融数据时,如果你想事事完

    美,那么可能一事无成。

    3.1 确定字段

    将彭博数据放入Excel或其API的第一步是,确定你想获取什么字段。幸运的

    是,确定字段有几个简单的方法。

    3.1.1 鼠标滑动在许多彭博屏幕中,你可以滑动鼠标,展示对应彭博字段的工具提示。例如,运行AAPL US Equity DES,提取Apple公司的描述屏幕,然后把光标指

    向“52Wk H”(52周以来高股价);会出现一个工具框,提示你相应的Excel字段

    ID是HIGH_52WEEK,如图3-1所示。

    图3-1:展示Excel字段ID的工具提示

    标签可能不太明确,所以需要用FLDS命令再检查一下定义,详见下节。

    3.1.2 FLDS屏幕

    彭博允许用户用FLDS屏幕搜索字段。要打开FLDS屏幕,首先挑选一个有价证券

    (例如Nokia FH Equity),然后用FLDS。打开FLDS屏幕之后,用查询

    文本框搜索一个字段(例如搜索“market cap”(市值),如图3-2所示。这个方

    法比鼠标滑动法更好,因为字段数量众多,查询能够提取出的字段比在工具提示框找到的更有用。例如,在描述屏幕(Excel字段ID:CUR_MKT_CAP)上把鼠标滑动

    到Mkt Cap上,不会显示Currency Adjusted Market Cap字段(Excel字段ID:

    CRNCY_ADJ_MKT_CAP),该字段可以用不同的货币提取市值(见图3-2)。如果你

    要比较的两个公司属于不同地区,调整货币单位就是很重要的。此外,FLDS屏幕显

    示每个字段的现值,使你更容易找到想要的字段。FLDS屏幕的另一个优点是能从彭

    博直接把字段拖倒你的Excel工作表中去(需要在Options下选用该功能)。

    图3-2:FLDS屏幕

    更重要的是,在FLDS屏幕中,你可以点击一个字段,查看更详细的描述和可选

    重写(overrides)(见图3-3)。在进行分析之前,阅读每个字段的描述是很重要

    的。例如,你可以用EQY_FUND_CRNCY(见图3-3)在请求CRNCY_ADJ_MKT_CAP时重

    写货币。在本章后面将探讨重写问题。图3-3:彭博字段描述

    3.1.3 彭博函数构造器和在Excel中发现字段

    用彭博Office工具,你能用直观的菜单从Excel直接获取FLDS屏幕的功能。在

    Excel的函数区上,点击彭博选项卡,然后在Create group中,点击Function

    Builder,如图3-4所示。

    图3-4:Excel功能区上的彭博控件函数构造器(Function Builder)有许多有用的函数,但是这里仅关注

    Bloomberg Data Point(BDP)函数。在本章后面会更详细地介绍BDP函数,它从

    彭博中提取一个单一数据点。选择BDP之后,你可以用Function Builder搜索一个

    有价证券和字段,见图3-5。

    图3-5:Excel中的彭博函数构造器

    或者用彭博字段搜索(Field Search)浏览字段库,在Excel的Bloomberg控

    件上,在Tools群中,选择Find Fields按钮(见图3-6)。尽管可以按类别下拉,但是用FLDS屏幕更方便查询,因为它将可用字段按热门程度进行排序。

    现在你明白使用Field Search和Function Builder很容易,但是不要直接把

    本章的其余部分越过去。下面几节展示几个不用将彭博字段硬编码成Excel公式,就

    能提取数据的简单方式。这将保证你的工作表和数据库表更容易维护,可以用于第5

    章和第9章。图3-6:Excel中的彭博字段搜索对话框

    3.1.4 如果其他都失败了……

    如果在Excel你还不能找到你要寻找的字段,那么就在Bloomberg选项卡上点击

    Live Help,向彭博的在线帮助团队寻求帮助。你还可以在彭博中点击HELP

    幕上的Live Help按钮。

    3.2 Excel案例

    在处理工作表和数据库表之前,先看看如何将数据提取到Excel的过程。即使你

    只打算用C获取彭博数据,用Excel也是理解多种彭博函数的有效办法。

    3.2.1 提取单一字段(BDP)如前所述,可以使用彭博的BDP函数,用一个彭博字段获取某数据点,例如价格

    或者评级。BDP函数的参数简单明了:

    =BDP(Security,Field,Option 1, Option 2,...Option N)

    可以对Security实参用不同标识符。例如,可以用企业债券的ISIN、CUSIP或者Bloomberg ID Number,例

    如“US103186AA06Corp”“103186AA0Corp”或者“EK1711978Corp”。

    用Open Text Corporation(OTC CN Equity)公司作为一个例子,首

    先用如下Excel公式提取当前市值:

    =BDP(OTC CN Equity, CUR_MKT_CAP)

    该Excel公式会返回相同的数字,在DES屏幕上将OTC CN Equity命名为

    Mkt Cap(不过DES彭博屏幕返回的市值是以百万计,而Excel公式返回完整、未经

    格式处理的数字)。根据CUR_MKT_CAP的FLDS屏幕描述,市值按照公司的计价货币

    显示。可以用如下Excel公式提取货币:

    =BDP(OTC CN Equity,QUOTED_CRNCY)

    本公式返回加拿大元汇兑代码CAD。可以在彭博上用FXTF找到一个FX

    tickers表单。可以用美元提取Open Text公司的市值,或者提供一个重写

    (override)字段,或者用汇率。调整货币单位所使用的override字段应为

    EQY_FUND_CRNCY,见CRNCY_ADJ_MKT_CAP字段描述屏幕(图3-3)。要使用该重写

    字段,你可以向BDP函数添加两个实参(第一个实参是我们正在改写的字段,第二个

    字段是值),或者使用格式OVERRIDE_FIELD=OVERRIDE_VALUE。例如,要在Excel

    中用美元显示Open Text公司的市值,下面两种方式都可以:

    =BDP(OTC CN Equity, CRNCY_ADJ_MKT_CAP, EQY_FUND_CRNCY,USD)

    或者

    =BDP(OTC CN Equity, CRNCY_ADJ_MKT_CAP,EQY_FUND_CRNCY=USD)

    如CRNCY_ADJ_MKT_CAP的字段描述屏幕所述,返回的数值单位是百万。如果你

    想改变返回市值的格式,用表单中列出的其他override字段(见图3-3),如

    SCALING_FORMAT。在字段描述屏幕点击SCALING_FORMAT,显示可用选项。下面的

    Excel公式将格式转换为基准单位(UNT),而不是百万:

    =BDP(OTC CN Equity, CRNCY_ADJ_MKT_CAP,EQY_FUND_CRNCY=USD, SCALING_FORMAT=UNT)

    或者可以在Excel中提取“CAD to USD”汇率,并调整市值,而不用override

    字段。做法是用如下公式提取CADUSD Spot Exchange Rate(是彭博中的另一个有

    价证券,用CADUSD Curncy)的PX_LAST字段:

    =BDP(CADUSD Curncy,PX_LAST)

    你可能已经注意到有两个结果不匹配(一是CRNCY_ADJ_MKT_CAP公式,二是

    CUR_MKT_CAP的结果和加拿大元兑美元汇率)。这可能是因为定价源不同。

    彭博为有价证券提供多种定价源。你需要明白你在使用哪种或哪些定价源。

    你可以到PCS浏览定价源或者用BDP公式提取PRICING_SOURCE字段。此

    外,QFX为不同的货币定价源提供说明,PCSS为其他定价源提供说明。

    重写默认定价源,并用彭博综合利率(Composite Rate,CMP)对伦敦货币市

    场(CMPL)提取CADUSD汇率,要用如下公式,在有价证券实参上增加CMPL:

    =BDP(CADUSD CMPL Curncy,PX_LAST)

    对于其他有价证券,例如企业债券,在有价证券实参内用“@”符号重写默认定

    价源:

    =BDP(US103186AA06@BVAL Corp,PX_BID)

    表3-1包括彭博的PCSS屏幕的基本总结。

    表3-1:定价源摘要最后一个需要讲解的BDP可选实参是Fill。如果请求某个有价证券没有的字

    段,就默认返回NA NA。Fill实参将不能完成的请求的返回值修改为你提供

    的值。例如,请求一个非上市企业(如Dell)的CUR_MKT_CAP将返回NA NA,但你可以用如下公式将它改为一个简单的破折号(-):

    =BDP(DELL US Equity,CUR_MKT_CAP,Fill=-)

    为了返回一个空的单元格,将实参设为B(Fill=B)。

    3.2.2 提取批量数据(BDS)

    你可能已经注意到FLDS屏幕有时在Value列显示Show Bulk Data;这表示该字

    段将返回多个值。例如,Microsoft(MSFT US Equity)公司的FLDS屏幕中

    在BLOOMBERG_PEERS旁边显示Show Bulk Data。点击Show Bulk Data显示彭博专

    有算法得到多个公司名称。用BDS函数把该表单提取到Excel中,BDS函数与BDP函数

    语法相似:

    =BDS(Security,Field,Option 1, Option 2,...Option N)

    与BDP函数不同,BDS函数将提取多个行或列的数据,还有几个不同的选项。

    BDS返回的表单将覆盖现有单元格中的数据,所以确保你把函数放入空白区

    域。

    可以用DIRECTION参数指明返回值的显示是水平的还是垂直的(默认为垂直

    的)。要按照水平格式返回Microsoft公司的BLOOMBERG_PEERS,用如下公式:=BDS(MSFT US Equity,BLOOMBERG_PEERS,DIRECTION=HORIZONTAL)

    SORTASC(升序)、SORTDESC(降序)参数控制返回数据的顺序。你可以把这

    些参数设为列数或列名(把HEADERS参数设为Y)。例如,要按字母顺序返回

    BLOOMBERG_PEERS数据用

    =BDS(MSFT US Equity,BLOOMBERG_PEERS,SORTASC=1)

    或者

    =BDS(MSFT US Equity,BLOOMBERG_PEERS,SORTASC=Peer Ticker)

    STARTROW、ENDROW、STARTCOL和ENDCOL参数限制返回的数据。如果把

    STARTROW设为3,前两行就从返回数据中排除了。同理,如果把ENDROW设为4,第四

    行之后的内容就从返回数据中排除了。结合使用这些参数,例如把STARTROW设为

    2,ENDROW设为2,将只获取表单中的第二个元素。你可以将这些参数与SORTASC和

    SORTDESC参数结合使用。例如,要获取前两个BLOOMBERG_PEERS,按字母顺序排

    列,用如下公式:

    =BDS(MSFT US Equity,BLOOMBERG_PEERS,SORTASC=1,ENDROW=2)

    在本段里,主参数用加粗字体强调。参见附录表A-2。

    AGGREGATE参数将BDS结果合并至一个单元格中。你可以将它与SEPARATOR参数

    结合使用。SEPARATOR参数的有效值包括:B(空白)、C(逗号)或SC(分号)。

    例如,如下公式在一个单元格内返回前两个BLOOMBERG_PEERS,用分号分隔:

    =BDS(MSFT US

    Equity,BLOOMBERG_PEERS,ENDROW=2,AGGREGATE=Y, SEPARATOR=SC)

    要把Microsoft的最后三次分红提取到一个单元格中,首先用如下公式显示

    Microsoft的分红历史:

    =BDS(MSFT US Equity,DVD_HIST_ALL,HEADERS=Y)

    图3-7显示结果。图3-7:用BDS显示分红历史

    第二,添加SORTDESC=Record Date,确保结果排序正确:

    =BDS(MSFT US

    Equity,DVD_HIST_ALL,HEADERS=Y,SORTDESC=Record Date)

    第三,删除所有行,仅保留前三行,增加ENDROW=3。还要删除HEADERS参

    数,因为那也会被包含在行数统计中:

    =BDS(MSFT US Equity,DVD_HIST_ALL,SORTDESC=Record

    Date,ENDROW=3)

    第四,用Startcol和Endcol分离Dividend Amount列(第五列):

    =BDS(MSFT US Equity,DVD_HIST_ALL,SORTDESC=Record

    Date,ENDROW=3, STARTCOL=5,ENDCOL=5)

    最后,用AGGREGATE和SEPARATOR参数将数据合并到一个单元格中,用逗号分

    隔:=BDS(MSFT US Equity,DVD_HIST_ALL,SORTDESC=Record

    Date,ENDROW=3,STARTCOL=5,ENDCOL=5,AGGREGATE=Y,SEPARATOR=C)

    要用Excel SUM函数把最后三个收益加起来,用ARRAY参数把结果转换成Excel

    数组,这样可以使用Excel聚合函数,例如AVERAGE或MEDIAN。与其他Excel数组函

    数一样,必须在输入后同时按Ctrl+Shift+Enter键:

    =SUM(BDS(MSFT US Equity,DVD_HIST_ALL,SORTDESC=Record

    Date,ENDROW=3, STARTCOL=5,ENDCOL=5,ARRAY=TRUE))

    最后一个要讲的参数是PCS,它改变定价源。例如,要把定价源设为BGN,就

    把PCS=BGN添加到BDS公式中去。

    3.2.3 提取历史数据(BDH)

    除了提取一个有价证券最新的金融数据,你可以用Excel BDH函数提取历史数

    据。如果是按字段描述屏幕标示的,历史值就可以获得。与BDP和BDS函数一样,BDH的前两个实参是SECURITY和FIELD。要提取某一天一个字段的值,唯一可以添加

    的实参是你请求的日期。例如,用如下公式提取Apple公司2015年7月1日的股票价

    格:

    =BDH(AAPL US Equity,PX_LAST,712015)

    然而,要提取某一段时间的历史数据,请提供一个起始日期和结束日期。例

    如,用如下公式提取Apple公司2014年6月2日到2014年6月30日之间的股票价格:

    =BDH(AAPL US Equity,PX_LAST,622014,6302014)

    清除BDH公式下面的所有数据是个好主意,以保证不误写或者错误地合并任何

    内容。

    一个特定日期的格式(例如在上一个例子中)应当与你的电脑默认设置的一致

    (美国一般用MMDDYYYY,欧洲一般用DDMMYYYY)。结束日期用空字符串

    就默认为今天。日期实参是灵活的,除了特定日期,该实参还允许用不同的日期类型和相对日

    期。共有三种不同的日期类型:财政年度(Fiscal,F)、日历年度(Calendar,C)或者实际年度(Actual,A),可以参见表3-2。你还可以用这些日期类型表示

    特定的相对日期,例如-1AW表示一周以前。

    表3-2:彭博日期类型

    Fiscal代表某个公司的财政年度。例如,用如下公式提取Plantronics公司

    PLT US Equity从2016年6月30日开始的2016财年第一季度历史股票价格,而

    很多公司的财年始于三月:

    =BDH(PLT US Equity,PX_LAST,FQ1 2016,)

    Calendar和Actual日期类型有所不同。对于Actual类型,-1AW代表恰好七

    天之前;-1AY代表恰好一年之前,以此类推。而另一方面对于Calendar类

    型,-1CW代表上周开始的前一个活跃日,-1CY代表去年开始的前一天。

    作为一个例子,如下公式会在2016年6月13日开始至2016年9月13日的三个月或

    一个季度。

    =BDH(AAPL US Equity,PX_LAST,-1AQ,9132016)

    而如下公式会在2016年3月31日开始,也就是前一个季度之前那天(9月13日在

    第三季度,4月在第二季度)。

    =BDH(AAPL US Equity,PX_LAST,-1CQ,9132016)

    BDH会默认只返回交易日的值,由此跳过市场关闭的假日。然而,并不是所有市

    场都是用相同的节假日日历,彭博会使用与证券交易所对应的日历。例如,Apple(AAPL US Equity)公司从2016年7月1日到7月10日的历史价格不包括7月4日,因为当天是美国的非交易日。然而,Lloyds Banking Group(LLOY LN

    Equity)会显示7月4日的值,因为当天是伦敦的交易日。想要按照美国的交易

    日显示Lloyds公司的历史价格,按照如下方法添加CDR参数:

    =BDH(LLOY LN

    Equity,PX_LAST,712016,7102016,CDR=US)

    完整日历代码参见CDR。或者,要指明返回的日子(不管是不是假日)用

    DAYS参数。除了把交易日的默认值设为T,你还可以把DAYS参数在周末设为W,在全

    年所有日期设为A。例如,如下公式将展示Apple公司从7月1日到7月10日的股票历

    史价格,包括周末和节日(7月4日):

    =BDH(AAPL US

    Equity,PX_LAST,712016,7102016,DAYS=A)

    因为市场在周末和节假日关闭,BDH会自动使用上个交易日的值。要调整该做

    法,就把Fill参数换成如下之一:

    C、P或Previous

    与默认一样,用前面最后一个可用日期的值。

    N、E或Error

    显示错误信息。

    F

    用下一个可用日期的值。

    B或Blank

    显示一个空白单元格。

    NA

    返回一个Excel NA错误。PNA

    用前一日期的值(如有),否则返回一个Excel NA错误。

    或者输入文本,例如“Market Closed”,如下所示:

    =BDH(AAPL US

    Equity,PX_LAST,712016,7102016,DAYS=A, FILL=Market

    Closed)

    在本节中,主要参数都用加粗字体表示。还可参见附录中的表A-4。

    默认数据显示频率是每日,不过如果想调整显示频率,就设置PERIOD参数。你

    可以把PERIOD参数设置成表3-2中列出的日期类型。例如,下面的公式展示Apple公

    司从2016年1月到2016年9月每月15日的股票收盘价格。

    =BDH(AAPL US

    Equity,PX_LAST,1152016,9152016,PERIOD=AM)

    你可以将PERIOD参数与相对日期结合,显示Apple公司从今年年初以来每月月

    末的股票价格:

    =BDH(AAPL US Equity,PX_LAST,-CY,,PERIOD=CM)

    此外,请求价格字段时,用QUOTE参数显示一个特定时段的每日平均价格,而非

    收盘价,例如:

    =BDH(AAPL US Equity,PX_LAST,-CY,,PERIOD=CM,QUOTE=A)

    2014年6月9日周一,Apple公司的股价在1拆7之后从645.57美元降到92.70美

    元。然而,BDH显示Apple公司在2014年6月9日的收盘股价记录是92.2243美元。这

    是因为彭博对公司剥离、股票分拆合并、股票分红和附权发行自动进行调整。如果

    你不想要自动调整,用DPDF屏幕重新设置参数,或者把CAPCHG参数设为N,如

    下所示:

    =BDH(AAPL USEquity,PX_LAST,612014,6102014,CAPCHG=N)

    此外,DPDF屏幕有调整Normal Cash Dividends和Abnormal Cash

    Dividends的选项。要在BDH函数中重写这些功能,将CSHADJNORMAL或

    CSHADJABNORMAL设置为Y或N。或者把USEDPDF参数设为N,忽略所有的DPDF偏好。

    要调整返回值的货币,把FX参数设为货币代码,例如FX=USD或FX=CAD。

    彭博还包括几个参数,可用于修改显示值的方式。POINTS控制返回天数的最大

    值,例如POINTS=5只返回五天。默认日期显示是升序排列,不过如果想让日期显

    示降序排列,就将SORT参数设置为D(代表descending,降序)。BDH函数与BDS函

    数一样,也可用DIRECTION、ARRAY和PCS参数。然而在使用APPAY参数时,你可能

    想将它与DATES参数结合使用。设置Dates=HIDE将返回的值不包括日期列。最

    后,在使用PX_LAST时,一些固定收益产品显示收益而非价格;想要改成PRICE的

    话,将QUOTETYPE改为P,代表价格。

    3.3 用于比较的有价证券

    评价有价证券的业绩并不是孤立的过程,需要放入一定的背景中进行评估。换

    句话说,要了解一个债券或股票的业绩,必须与其同类进行多维度的比较。准确选

    择进行对比的同类名单很重要,尽管有很多现成的方案,但是自动选择也过于片面

    了。根据你的分析情况,可将Apple公司的股票业绩与NASDAQ指数、SP 500指

    数,或者你自己选定的某个企业组的指数进行比较。此外,你的样本集中的有价证

    券数量也很重要,证券数量过少可能导致结果不明显;证券数量过多可能导致错误

    结果。

    本节介绍多种指数及如何找到可比较的有价证券的方法。

    3.3.1 指数

    彭博上可以查看知名股票指数,例如标准普尔500指数(SPX Index)、道

    琼斯工业平均指数(INDU Index)、NASDAQ综合指数(CCMP Index)和

    罗素2000指数(RTY Index)。每个指数都不同,其中包含的企业数量从30个

    到5000个不等。例如,Wilshire 5000指数(W5000Index)包含了几乎所有总部在美国的公开上市企业。此外,还有几个仅包含部分公司的“子指数”,其中

    一些是彭博创造的。例如,罗素3000科技指数(RGUST Index)是罗素3000指

    数中科技公司的资本化加权指数。

    除了常见指数,2016年8月24日,彭博收购了Barclays Risk Analytics and

    Index Solutions有限公司,这样彭博客户就能获取大量以彭博和巴克莱

    (Barclays)共同命名的指数数据。要浏览不同指数,用IN。例如,Bloomberg Barclays US Corporate High Yield Bond Index包含2152只以美

    元标价的高收益固定利率企业债券。

    对于一个更有针对性的指数,可尝试进行搜索。简单搜索“Bloomberg HY

    Technology”可能返回Bloomberg USD High Yield Corporate Bond Index

    Technology(BUHYTE Index),这是按照一定规则设计的、由科技公司公开

    发行的高收益固定利率美元企业债券的市值加权指数。

    或者,几家大银行和金融机构在彭博客户端为客户提供定制指数。美林银行的

    客户可以获得该银行的US High Yield Technology Index(H0TY Index)

    以及其他很多指数信息。

    有两种简易方法把指数的成分股名单放入Excel。方法一是用MEMB,并在

    Output选项下选择Excel;方法二是用BDS公式提取INDX_MEMBERS字段:

    =BDS(BUHYTE Index,INDX_MEMBERS)

    有时,Excel导出工具或者BDS函数返回的有价证券标识符会与你的分析所用到

    的标识符有所不同。例如,前面用于提取指数成员的公式例子返回了一个彭博唯一

    标识符(例如“COLW3497804”)组成的表单,而不是ISIN组成的表单。要保持一

    致性,用BDP函数提取你更喜欢的标识符。尽管并不总是如此,有时返回的标识符有

    前缀,必须在传递给BDP函数之前删除掉。在这种情况下,必须用Excel

    SUBSTITUTE函数,删除每个标识符中的CO,再增加Corp,使其成为一个有效

    的标识符。如下公式将正确的Security字段传递给BDP函数,以获取

    ISIN(ID_ISIN):

    =BDP(SUBSTITUTE(N4,CO,,1) Corp,ID_ISIN) 注意: 单元格N4包含ID COLW3497804

    3.3.2 对等有价证券

    之前讨论过如何使用BDS函数获取某有价证券的对等组,彭博专有算法用下面的

    公式:

    =BDS(MSFT US Equity,BLOOMBERG_PEERS)

    在确定可比较有价证券方面,算法还远远不完美。幸运的是,彭博提供一个屏

    幕,显示有价证券之间的相关性。图3-8显示Microsoft(MSFT US Equity)

    公司的Peer Correlation(PC)屏幕(PC)。PC屏幕是一种有用的方法,用

    来发现有一定相关性的有价证券和指数。

    图3-8:Microsoft公司的Peer Correlation屏幕3.3.3 关于有价证券

    Related Securities(RELS)屏幕提供了关于选中的有价证券的发行商

    的详细概览。如First Data Corp公司的Related Securities屏幕所示,该公司

    有好几个债券(见图3-9)。

    图3-9:First Data Corp公司的Related Securities屏幕

    只要点击“Corporates by Company”,就会出现First Data Corp公司发行

    的有价证券名单,根据有价证券类型分成几个选项卡。注意,如图3-10所示,结果

    按照关联度排序(如第一列的Relevance Indicator图标所述)。基于彭博专有算

    法的Relevance Indicator能保证大多数相关有价证券被包含在你的分析中。图3-10:根据相关度检索的First Data Corp公司债券

    3.4 途径1和2:Excel和Access

    本节介绍创建一个新的工作簿的步骤,该工作簿中有公司、企业债券、贷款和

    指数工作表。通过把数据从彭博提取到这些工作表中,就将大量信息放到了你的指

    尖。此外,这些工作表也用于本书第二部分分析数据章节。如果你用途径2,本节创

    建的工作表与第5章中的Microsoft Access相关。

    下面的表中选出的字段列用于展示一些金融数据的基本类型。这些仅是彭博

    提供的数据中的沧海一粟。

    3.4.1 企业债券、贷款和指数

    首先,我们创建一个新的工作簿,命名为Bond。然后使用表3-3填入新工作表

    的前两行。表3-3包括四列:Excel列字母;存储在第一行的彭博字段(又名

    Mnemonic);存储在第二行的人类可阅读的数据描述;引用的彭博字段描述。例

    如,单元格C1应当包含BOND_TO_EQY_TICKER,单元格C2应当包含CompanyID。同

    理,单元格D1应当包含SECURITY_DES,单元格D2应当包含“SecurityDescription”。注意彭博字段不区分大小写。填完Excel区域(A1至T2)之后,将仅包括第二行用到的单元格(A2至T2)的Excel区域转换为一个Excel表,命名为

    Bond。

    表3-3:Bond作表列和彭博映射

    Bond表结果如图3-11所示。

    为了把所有信息串起来,需要给每个债券、贷款、公司等设置一个唯一标识符。毕竟,如果不能用公司所在行业就检索出债券,本书就没什么用了,因为该信

    息在另一张工作表上。不幸的是,为每个有价证券设置一个唯一标识符很富于挑战

    性。例如,某个企业债券可能是在既符合Regulation S(Reg S)又符合Rule

    144a的条件下发行的,由此可以有两套标识符(144a国际证券识别编码

    (International Securities Identification Number,ISIN)和美国统一证

    券辨认委员会(Committee on Uniform Security Identification

    Procedures,CUSIP)以及Reg S ISIN和CUSIP)。

    图3-11:初步排版之后的Bond工作表

    还有更复杂麻烦的,尽管所有标识符引用同一个债券,不同的基金对于投资于

    144a系列和Reg S系列有不同的规则。由此,采用144a和Reg S规则的价格和流动

    性可能会有不同。此外,股票也存在类似的情况,因为未上市企业没有股票代码,上市企业在不同交易所可能有不同的股票代码。尽管没有完美的解决方案,只要保

    持一致就不会出乱子。在本书中的唯一标识符,对企业债券用144a ISIN,对公司

    用股票代码,对贷款用彭博标识符。注意,CUSIP是CUSIP Global Services的授

    权产品,在数据库里使用CUSIP可能需要获得授权。

    用表3-3的排版,在Bond工作表A列的BondID标题下列出企业债券的144a

    ISIN。可以包含同一个公司发行的不同债券,但是记住不能用重复的ISIN。然后,添在第二列BBID上加一个公式,把ISIN转换为彭博能识别的有价证券。如前所述,在债券的ISIN之后简单添加Corp,使其成为一个有效的彭博标识符,如下所示:

    =[@BondID] Corp注意“Corp”之前的空格。这个空格很重要,结果看起来是这个样子

    的:“US004498AA90Corp”。在BBID列有一系列彭博标识符之后,就可以将彭博

    数据提取到工作表中了。在CompanyID列标题下的单元格C3中输入如下公式:

    =BDP(Bond[@[BBID]:[BBID]], C1, Fill=-)

    用Bond[@[BBID]:[BBID]]这样的公式来确定表和列,而非仅仅用[@BBID],这样就锁定了单元格引用,可以被复制或者拖到工作表的其他部分。说明一下,没

    有单元格引用的公式如下所示:

    =BDP(US004498AA90 Corp,BOND_TO_EQY_TICKER,Fill=-)

    如前所述,公式从彭博中对每个债券提取BOND_TO_EQY_TICKER字段。

    BOND_TO_EQY_TICKER将返回债券发行人的股票代码(或者第一层母公司的股票代

    码及股票基础信息)。后面我们会用该数据为Company工作表提供一个公司表单。

    引用彭博字段,而不是直接把它硬编码成Excel BDP公式有三点好处。首先,列在

    每行上面可以迅速查找当前字段,而且只要改一个单元格就能换到另一个字段。其

    次,使用引用可以很方便地插入一列增加另一个字段,并在第一行放上彭博字段。

    最后,使用相同的公式减少犯错误的概率。

    Bond工作表显示应该如图3-12所示(正在编辑单元格D3,以显示公式)。

    图3-12:带彭博数据的Bond工作表你可以在Excel中选择A列,在重复的单元格上增加条件格式,然后在函数区

    Home键上,单击Conditional Formatting,指向Highlight Cell Rules,然后

    选择Duplicate Values。

    Loan工作表的创建与Bond工作表基本一模一样,除了有一处不同:用

    Bloomberg ID Numbers(例如Zebra Technology公司定期贷款B

    用“BL2015081”),而非ISIN。如果你持续将BBID列的值设为一个有效的彭博标

    识符,你可以将一个不同的标识符作为Loan表的主关键字。用表3-4的前两列填入

    Loan工作表的前两列。将第二行转换为Excel表,命名为Loan。用与Bond表相同的

    公式填入其余的单元格。

    表3-4:Loan工作表列和彭博映射

    表3-4:Loan工作表列和彭博映射(续)创建一个Index工作表,命名为IDX(不是“Index”,因为该词在Microsoft

    Access中是保留词汇)。Index工作表与Loan工作表基本一样,除了一点:

    用“SPX Index”中的“Index”,而不用“BL2015081Corp”中BBID列

    的“Corp”。用表3-5的前两列填入IDX工作表的前两列。把第二行转换为Excel

    表,命名为“IDX”。用与Bond表中相同的公式填入其余的单元格。

    表3-5:IDX工作表列和彭博映射3.4.2 公司工作表

    Company(公司)工作表与Bond、Loan和IDX工作表有几处不同。首先,因为

    许多都是估计值,因此好几列中都需要货币重写(currency override)。其次,尽管大部分彭博列包含相同的公式,但是五年CDS费率需要一点修正,后面再讨论。

    最后,Company工作表包含一个需要手动填写(不是自动从彭博下载的)Category

    列和一个从其他彭博列衍生的Net DebtEBITDA列。

    创建一个新的工作表,命名为Company,在单元格A1写上Currency(货币),在单元格B1写上USD(美元)。后面,我们会在彭博公式中引用B1单元格,以确保

    所有美元金额的单位都是USD。

    然后用表3-6的字段填入第二行和第三行的列。例如,单元格C2应包

    含“NAME”字样,单元格C3应包含“CompanyName”字样。同理,单元格E2应包

    含“GICS_SECTOR_NAME”字样,单元格E3应包含“Sector”字样。单元格A2和B2

    应为空。把第3行的单元格转换为名叫“Company”的Excel表。带星号()的列用

    货币重写,见本节后面的内容。

    表3-6:Company工作表列和彭博映射表3-6:Company工作表列和彭博映射(续)你可能已经注意到,一些列(例如Moody’sRating和Price)存在于多张表

    中,这与我之前说的在不同位置存储相同的信息是矛盾的。然而在这些情况下,Moody’sRating列在Company表中表示Moody’sCorportate Family

    Rating(穆迪企业家族评级),在Bond表中表示Moody’sissue rating(穆迪发

    行评级)。类似地,Price列在Company表中表示该公司的股票价格,而在Loan表中

    表示该公司的贷款价格。如果你觉得容易混淆,当然可以使用更精确的列名,例

    如“Loan Price”和“Bond Price”。然后,在A列的CompanyID列标题下输入你的公司股票名称缩写表单。该表单至

    少应当包括Bond和Loan工作表中CompanyID列的全部股票名称缩写。然后,在

    CompanyID列最后填上Equity,用如下公式在BBID列创建一个有效的彭博标识

    符:

    =[@CompanyID] Equity

    需要再次注意“Equity”字样之前的空格,这样单元格应该看起来像“SVR US

    Equity”。然后,构建一个与Bond和Loan工作表使用的类似的BDP函数,除了如前

    所述添加货币重写。从第一行CompanyName标题下开始的每个单元格,除了四列

    (Net DebtEBITDA、5yr CDS Spread、Category和Company Comments),应

    当包含:

    =BDP(Company[@[BBID]:[BBID]], C2,EQY_FUND_CRNCY,B1,Fill=-

    )

    为了清晰起见,不含引用时该公式如下所示:

    =BDP(SVR US Equity, NAME,EQY_FUND_CRNCY,USD,Fill=-)

    尽管彭博字段NAME没有也不需要货币重写,但是也不会导致什么问题,并且它

    还允许在大多数列用统一的公式。最后是Net DebtEBITDA列,展示如何包含一个

    不从彭博提取数据的列。该列的公式是Net Debt列除以TTM EBITDA列(EBITDA列

    不是空白时):

    =IF([@[TTM EBITDA]]<>-,[@[Net Debt]][@[TTM EBITDA]],-)

    信用违约互换(Credit Default Swap,CDS)是一种超出本书范围的、复杂

    的信用衍生工具。可以这么说,CDS是对债券(或其他有价证券)进行的保险,投资

    者可以买(例如,得到风险保护)或者卖(例如,为别人提供风险保护)。风险保

    护的成本(即息差)是市场对公司业绩预测的重要指标。在其他条件一样的情况

    下,CDS费率越大,潜在风险越大。用5yr CDS Spread Ticker列的彭博字段

    CDS_SPREAD_TICKER_5Y查询五年期CDS的名称缩写,如果存在,在5yr CDS

    Spread列输入如下公式获取CDS费率:=IF([@[5yr CDS Spread Ticker]]=-,, BDP([@[5yr CDS Spread

    Ticker]] Corp, PX_LAST,Fill=-))

    与Bond和Loan工作表一样,主关键字(CompanyID)需要是唯一的。你可以按

    照前面Bond工作表中讲到的方法对重复之处突出显示。此外,在Category列填上每

    个公司的正确分类。

    尽管大部分列来自于彭博,最重要的信息其实来自于你。例如,彭博会告诉

    你,根据全球行业分类标准(Global Industry Classification Standard,GICS),Apple是一家“技术硬件、存储和周边产品”(Technology Hardware,Storage,and Peripherals)公司。然而,彭博还会告诉你Western Digital是

    一家“技术硬件、存储和周边产品”公司,尽管两家公司差别很大。作为分析师,你自己必须拥有良好的判断,来确定进行业绩对比的不同公司究竟属于哪个类别。

    除了你自己进行分类之外,将数据与主观思考结合也将使你的分析更加强大。例

    如,彭博不能告诉你该公司的CFO有多坦诚,也不能告诉你是不是该相信该公司的预

    测。

    3.4.3 引用和重写

    下面的内容涉及从其他表引用相关信息,以及重写缺失的或错误的彭博信息。

    引用

    然后,我们修改工作表,从其他工作表导入列,例如包括Bond工作表中的公司

    全名(CompanyName)。尽管最常用的办法是Excel VLOOKUP函数,VLOOKUP还是

    有几个问题,见第2章。一个更好(但是有一点点复杂)的解决方案是结合Excel

    INDEX和MATCH函数。MATCH函数在一个区域搜索一个值,并返回其头寸。INDEX函

    数返回在某个头寸下一个单元格的值。在Bonds表增加一列,命名为“Company

    Name”,用如下公式:

    =INDEX(Company[CompanyName],MATCH([@CompanyID],Company[CompanyID],0))

    你可以在其他工作表随意增加多个引用,但是应当用不同颜色或者字体加粗等

    方式标明该数据来源于另一个工作表。还可以或者用数据验证(见第2章),或者在Bond和Loan工作表包含一个标明CompanyID是否存在于Company工作表中的列。如

    果在Company工作表中找到该公司,则如下公式返回TRUE;否则返回FALSE:

    =NOT(ISERROR(VLOOKUP([@CompanyID],Company[CompanyID],1,FALSE)))

    重写

    如果你发现缺失或者不正确的数据,直接更新工作表和替换彭博公式都将导致

    混乱。那么怎么处理呢?你可以创建重写工作表(Bond Override、Loan

    Override、Company Override),修改彭博返回的数据(或增加缺失数据)。这

    些重写工作表将包含你想修改的信息。

    为Bond工作表创建一个重写,首先创建一个新的工作表,命名为Bond

    Override。然后在第一行的A和B列,分别增加列标题BondID和Override Date。

    然后,在第一行增加Bond表中的其他列标题,使它们可以被重写。然后,选择带列

    标题(包括BondID和Override Date)的单元格,并转换成Excel表(见第2章),命名为BondOverride。

    要适应重写表,需要改变Bond工作表中的BDP函数公式。创建一个不依赖于列

    顺序的公式可能有点复杂。

    对CompanyID的现有BDP公式

    =BDP(Bond[@[BBID]:[BBID]], C1, Fill=-)

    将变为:

    =IF(IFERROR(VLOOKUP(Bond[@[BondID]:[BondID]],BondOverride,MATCH(Bond[[Headers],[CompanyID]],BondOverride[Headers],0),FALSE),)=,BDP(Bond[@[BBID]:[BBID]], C1, Fill=-),VLOOKUP(Bond[@[BondID]:[BondID]],BondOverride,MATCH(Bond[[Headers],[CompanyID]],BondOverride[Headers],0),FALSE))

    那可能看起来有点复杂,但分解之后其实挺简单的。如果BondID不存在于BondOverride表中,或者如果BondOverride表中对应的CompanyID单元格(无论

    该单元格在哪一列)是空白的,公式将显示原始BDP函数的结果。

    在第一部分中,公式在BondOverride表中搜索BondID(用VLOOKUP,因为我们

    始终知道列的位置),并返回与Bond表CompanyID列有相同列名的列的数据(用之

    前我们介绍过的MATCH函数)。如果导致错误(因为该列不存在,或者找不到

    BondID),将返回一个空白单元格。

    然后,如果第一部分返回一个空白单元格,IF函数将返回原BDP函数的结果;否

    则,返回VLOOKUP的结果。调整后,BondOverride表上增加的行中的数据将出现在

    Bonds工作表上。对于贷款和公司增加重写工作表的过程是一样的。

    3.5 途径3:彭博CAPI

    彭博提供一个功能强大的API,你可以用它在C中获取之前在Excel中获取的信

    息。

    3.5.1 设置Microsoft Access以用于C

    第一步,我们在Access中创建一个新的数据库。在这个数据库中创建四张表:

    Company、Bond、Loan和IDX。这些表将包含来自彭博的信息。第五张表用于将彭

    博字段的映射存储到数据库表和列中。

    第二步,用表3-7中的模式创建Company表。将下表中带星号()的列设为主

    关键字。

    在Microsoft Access中,当你将数据类型设为数字(Number),你需要在

    属性窗口将字段规模(Field Size)设为Double。

    表3-7:Company表设计表3-7:Company表设计(续)

    第三步,用表3-8描述的模式创建Bond表。

    表3-8:Bond表设计第四步,用表3-9中的模式创建Loan表。

    表3-9:Loan表设计

    第五步,用表3-10中的模式创建Index表。

    表3-10:Index表设计第六步,创建一个表,命名为Map,其中包含字段和我们的数据库表之间的映射

    (见表3-11)。DestTable和DestCol二者应共同被设为主关键字(即复合主关键

    字)。

    表3-11:Map表设计

    最后,插入表3-12中的行。在本节后续部分,我们会讨论该映射将如何把彭博

    数据动态加载到你的Access数据库中。

    表3-12:Map表数据表3-12:Map表数据(续)表3-12:Map表数据(续)

    3.5.2 彭博CAPI

    在本节中,我们讨论使用彭博的桌面API(C语言编写)。本节介绍如何获取引

    用数据(类似于Excel中的BDP)和历史数据(类似于Excel中的BDH)。最后,展示如何填入Access数据库。对于其他更高级的内容,彭博在WAPI屏幕上提供很多

    与其他API功能相关的文档。本节的大部分内容来自于彭博提供的示例和文档。

    提醒一下,你会受到数据限制,因此建议不要对静态数据进行重复请求。

    在写代码之前,访问彭博的WAPI屏幕,选择API Download Center,下

    载API库。点击桌面API旁边的Download按钮,保存并解压相关文件,一般存到C:

    \blp。

    然后在Visual Studio中,右击你的项目,选择增加引用(Add

    Reference),创建一个新的C控制台应用(console application)。浏览C:

    \blp\DAPI\APIv3\DotnetAPI\v3.10.1.2\lib(使用其他版本或本地blp文件夹

    时你可能需要调整),然后添加一个引用至Bloomberglp.Blpapi.dll。

    然后在Program.cs文件中,增加正确的using指令,以在代码中引用

    Bloomberg类:

    using Event = Bloomberglp.Blpapi.Event; using Element =

    Bloomberglp.Blpapi.Element; using Message =

    Bloomberglp.Blpapi.Message; using Name = Bloomberglp.Blpapi.Name;

    using Request = Bloomberglp.Blpapi.Request; using Service =

    Bloomberglp.Blpapi.Service; using Session =

    Bloomberglp.Blpapi.Session; using SessionOptions =

    Bloomberglp.Blpapi.SessionOptions; using InvalidRequestException =

    Bloomberglp.Blpapi.InvalidRequestException; using Datetime =

    Bloomberglp.Blpapi.Datetime;

    彭博推荐用GetElement和GetValue方法预先计算哈希值,也就是在Program类

    中加入如下代码:

    class Program { private static readonly Name SECURITY_DATA =

    new Name(securityData); private static readonly Name SECURITY =

    new Name(security); private static readonly Name FIELD_DATA = new

    Name(fieldData); private static readonly Name RESPONSE_ERROR =new Name(responseError); private static readonly Name

    SECURITY_ERROR = new Name(securityError); private static readonly

    Name FIELD_EXCEPTIONS = new Name(fieldExceptions); private static

    readonly Name FIELD_ID = new Name(fieldId); private static

    readonly Name ERROR_INFO = new Name(errorInfo); private static

    readonly Name CATEGORY = new Name(category); private static

    readonly Name MESSAGE = new Name(message);

    最后,要在Program类的一个实例中,而非静态的Main函数中运行代码,就需

    要创建一个方法,在Program类中命名为BasicExample,从Main方法调用它:

    static void Main(string[] args) { Program p = new Program;

    p.BasicExample; }

    3.5.3 基本引用示例

    BasicExample方法与彭博建立了关系,并发送数据请求到彭博的引用数据服

    务。来自彭博的引用数据服务的回复在下面介绍的ProcessResponse方法中进行处

    理。用API与彭博建立关系分成两个步骤,首先如下面的BasicExample方法代码示

    例所示,程序必须建立一个连接至你的彭博终端的会话控制(session),然后

    session代码用于获取彭博的一项服务。

    所有的彭博数据都必须从其“服务”(service)之一获取。在引用数据时,使用其refdata服务。BasicExample方法尝试用OpenService方法打开refdata服

    务,如果成功就用GetService方法获取Service对象。

    然后,用Service对象的CreateRequest方法(其中包含要获取的有价证券和

    字段的表单),代码会创建一个Request对象。彭博推荐将多个有价证券和字段请

    求打包发送,而非发送多个请求。

    然后,把有价证券贴到Request对象的字段元素上,使代码在请求中增加一个

    有价证券表单。指定有价证券可以有多重方式;下面的代码示例展示如何用CUSIP引

    用债券,如何用股票名称缩写引用公司。类似

    于“cusip”和“ticker”,“isin”或“bbgid”也可用于识别债券,分别用的是ISIN或彭博全局标识符(Bloomberg Global Identifier)。

    然后,把字段贴到Request对象的field元素上,使请求增加字段。API用的字

    段名与Excel BDP函数一样。

    如这个例子所示,要重写一个字段,例如把CRNCY_ADJ_MKT_CAP按欧元计价,把字段贴到Request对象的overrides元素上,并在发送请求前设置fieldId和

    value。

    然后,代码发送请求至彭博,并捕获任何非法请求异常。

    发送请求之后,代码用NextEvent方法轮询(poll)Session对象,寻求反

    馈。对于较大的请求来说,API有可能返回部分反馈(partial response),在这

    种情况下应当继续轮调Session对象。然而,在API发送回一个非部分反馈(或者会

    话状态反馈为结束)之后,结束轮询并结束会话。在收到任何反馈之后,把事件传

    递给ProcessResponse方法(后面会介绍)。

    让我们看看代码:

    private void BasicExample { Establish a Bloomberg Session,otherwise display error and exit SessionOptions sessionOptions =

    new SessionOptions; Session session = new Session; bool

    sessionStarted = session.Start; if (!sessionStarted) {

    System.Console.Error.WriteLine(Failed to start session.); return;

    } Open RefData Bloomberg Service if

    (!session.OpenService(blprefdata)) {

    System.Console.Error.WriteLine(Failed to open blprefdata);

    return; } Service refDataService =

    session.GetService(blprefdata); Create new request Request

    request = refDataService.CreateRequest(ReferenceDataRequest);

    Add securities to request Element securities =

    request.GetElement(securities);

    securities.AppendValue(tickerAAPL US Equity);

    securities.AppendValue(cusip319963BP8); Add Bloomberg Fieldsto request Element fields = request.GetElement(fields);

    fields.AppendValue(CRNCY_ADJ_MKT_CAP);

    fields.AppendValue(PX_LAST); Adding override to request

    following 4 statements set EQY_FUND_CRNCY=EUR Element overrides =

    request[overrides]; Element override1 =

    overrides.AppendElement; override1.SetElement(fieldId,EQY_FUND_CRNCY); override1.SetElement(value, EUR); Send

    Request try { session.SendRequest(request, null); } catch

    (InvalidRequestException e) {

    System.Console.WriteLine(e.ToString); } While we haven't

    errored or retrieved entire response bool done = false; while

    (!done) { Event eventObj = session.NextEvent; A partial

    response will be followed by more partial responses or completed

    response if (eventObj.Type == Event.EventType.PARTIAL_RESPONSE) {

    ProcessResponse(eventObj); } Most of the time, you just get a

    completed response else if (eventObj.Type ==

    Event.EventType.RESPONSE) { ProcessResponse(eventObj); done = true;

    } else { foreach (Message msg in eventObj) {

    System.Console.WriteLine(msg.AsElement); if (eventObj.Type ==

    Event.EventType.SESSION_STATUS) { if

    (msg.MessageType.Equals(SessionTerminated)) { done = true; } } }

    } } session.Stop; }

    下一个方法是ProcessResponse方法。该方法处理前面提到的BasicExample

    方法中返回的彭博数据。在传递给ProcessResponse方法的Event对象中,有一系

    列Message对象。每个Message对象可以包含一个错误(表示请求失败),或者一个

    有价证券元素集合。每个有价证券元素包含一个错误(表示该有价证券有问题),或者一个字段集合和一个字段错误集合(可能有)。ProcessResponse函数应循环

    访问这些不同的集合,以获得返回值。

    如果信息没有错误,代码将循环访问每个有价证券元素,提取返回字段的表

    单,并循环访问。尽管下面的代码将字段的值作为字符串检索,也有作为其他数据

    类型的方法(在本章后面讨论)。最后,对每个有价证券元素,检查是否有一个字段异常的集合并显示。

    代码如下:

    private void ProcessResponse(Event eventObj) { Responses can

    contain multiple messages foreach (Message msg in eventObj) { if

    the message is an error, display and continue if

    (msg.HasElement(RESPONSE_ERROR)) { Element error =

    msg.GetElement(RESPONSE_ERROR); Console.WriteLine(Request failed:

    + error.GetElementAsString(CATEGORY) + ( +

    error.GetElementAsString(MESSAGE) + )); continue; } For each

    of the requested securities in the response Element securities =

    msg.GetElement(SECURITY_DATA); for (int i = 0; i <

    securities.NumValues; ++i) { Create references for security

    object and ticker Element security =

    securities.GetValueAsElement(i); string ticker =

    security.GetElementAsString(SECURITY); If security has error,display and continue if (security.HasElement(securityError)) {

    Element error = security.GetElement(SECURITY_ERROR);

    Console.WriteLine(Security Error: +

    error.GetElementAsString(CATEGORY) + ( +

    error.GetElementAsString(MESSAGE) + )); continue; } For each

    field in request Display data from Bloomberg Element fields =

    security.GetElement(FIELD_DATA); if (fields.NumElements > 0) { for

    (int j = 0; j < fields.NumElements; ++j) { Element field =

    fields.GetElement(j); System.Console.WriteLine(field.Name + \t\t

    + field.GetValueAsString); } } If there were exceptions with

    particular fields Display them Element fieldExceptions =

    security.GetElement(FIELD_EXCEPTIONS); if

    (fieldExceptions.NumValues > 0) { for (int k = 0; k <

    fieldExceptions.NumValues; ++k) { Element fieldException =

    fieldExceptions.GetValueAsElement(k); Element error =

    fieldException.GetElement(ERROR_INFO); Console.WriteLine(FieldException: + fieldException.GetElementAsString(FIELD_ID) + +

    error.GetElementAsString(CATEGORY) + ( +

    error.GetElementAsString(MESSAGE) + )); } } } } }

    3.5.4 基本历史示例

    为了仿真Excel BDH函数和提取彭博字段信息历史需要一些调整。首先,在

    Program类的主体中增加date的预先计算好的哈希值:

    private static readonly Name DATE = new Name(date);

    然后,对请求声明进行如下修改:

    Request request =

    refDataService.CreateRequest(HistoricalDataRequest);

    然后,对历史请求设置几个额外的实参。在本章之前的部分中,我们讨论了BDH

    函数的几个实参。对等的API实参参见表3-13。

    表3-13:历史请求的API实参

    表3-13:历史请求的API实参(续)在发送请求之前,在BasicExample函数中,把Request对象的startDate和

    endDate字段设为“YYYYMMDD”日期格式:

    request.Set(startDate, 20140601); request.Set(endDate,20140625);

    和Excel一样,可以在Request对象中将periodicitySelection字段设为

    DAILY、WEEKLY、MONTHLY、QUARTERLY或YEARLY:

    request.Set(periodicitySelection, DAILY);

    整个方法代码如下:

    private void HistoryExample { SessionOptions sessionOptions =

    new SessionOptions; Session session = new Session; bool

    sessionStarted = session.Start; if (!sessionStarted) {

    System.Console.Error.WriteLine(Failed to start session.); return;

    } if (!session.OpenService(blprefdata)) {

    System.Console.Error.WriteLine(Failed to open blprefdata);return; } Service refDataService =

    session.GetService(blprefdata); Use HistoricalDataRequest

    Request request =

    refDataService.CreateRequest(HistoricalDataRequest); Element

    securities = request.GetElement(securities);

    securities.AppendValue(tickerMSFT US Equity);

    securities.AppendValue(tickerAAPL US Equity); Element fields =

    request.GetElement(fields); fields.AppendValue(PX_LAST);

    fields.AppendValue(PX_OPEN); Set Dates and period

    request.Set(startDate, 20140601); request.Set(endDate,20140612); request.Set(periodicitySelection, DAILY); try {

    session.SendRequest(request, null); } catch

    (InvalidRequestException e) {

    System.Console.WriteLine(e.ToString); } bool done = false; while

    (!done) { Event eventObj = session.NextEvent; if (eventObj.Type

    == Event.EventType.PARTIAL_RESPONSE) {

    ProcessHistoryResponse(eventObj); } else if (eventObj.Type ==

    Event.EventType.RESPONSE) { ProcessHistoryResponse(eventObj); done

    = true; } else { foreach (Message msg in eventObj) {

    System.Console.WriteLine(msg.AsElement); if (eventObj.Type ==

    Event.EventType.SESSION_STATUS) { if

    (msg.MessageType.Equals(SessionTerminated)) { done = true; } } }

    } } session.Stop; }

    因为对历史数据请求的反馈不完全等同于对引用数据请求的反馈,因此你需要

    在while循环中将函数调用从ProcessResponse改为ProcessHistoryResponse。

    ProcessHistoryResponse方法看起来很像ProcessResponse方法,但是两者

    有几处不同。一是与引用反馈不同,历史数据反馈中的SECURITY_DATA元素不是一

    个数组:它包括一个有价证券。二是FIELD_DATA包括一个值和一个日期。

    代码将在FIELD_DATA集中循环,其中包含每天一个元素。在那些元素中的每一

    个都是每个请求字段的另一个Element集,包括日期本身。因为日期是元素集的一部分,它按照名称提取,并且在循环至其他字段的其他元素集时被忽略。

    如下是完整代码:

    private void ProcessHistoryResponse(Event eventObj) { foreach

    (Message msg in eventObj) { if (msg.HasElement(RESPONSE_ERROR)) {

    Element error = msg.GetElement(RESPONSE_ERROR);

    Console.WriteLine(Request failed: +

    error.GetElementAsString(CATEGORY) + ( +

    error.GetElementAsString(MESSAGE) + )); continue; } Element

    securityData = msg.GetElement(SECURITY_DATA); string security =

    securityData.GetElement(SECURITY).GetValueAsString;

    Console.WriteLine(security); Element fieldData =

    securityData.GetElement(FIELD_DATA); if (fieldData.NumElements > 0)

    { for (int i = 0; i < fieldData.NumElements; i++) { Element element

    = fieldData.GetValueAsElement(i); Pull the date from the returned

    field and display Datetime date =

    element.GetElementAsDatetime(DATE);

    Console.WriteLine(date.ToSystemDateTime.ToShortDateString);

    For the remaining fields (not DATE), display. for (int f = 0; f <

    element.NumElements; f++) { Element field = element.GetElement(f);

    if (!field.Name.Equals(DATE)) { Console.WriteLine(field.Name + =

    + field.GetValueAsString); } } } } } }

    3.5.5 填入Access数据库

    在本节中,我们学习用彭博API填入数据库表。本节的代码在各自的表中循环访

    问债券、贷款和企业信息,并从彭博API中请求Map表中列出的彭博字段。Map表还

    包括对应列,用于存储来自彭博的信息结果。

    开始之前

    在开始之前,需要强调几点。首先,把C连接到Microsoft Access,你需要

    安装OleDb驱动程序,版本要和你的Microsoft Access版本匹配。例如,用Microsoft.ACE.OLEDB.12.0连接Microsoft Access 2016。

    然后,在Visual Studio中为控制台应用创建一个新的C解决方案,并在项目

    目录中输入你的Access数据库副本。然后用项目目录中的数据库文件,在Bond、Loan、Index和Company表中填入适当的标识符。在每张表中,填入主关键字列和

    BBID列,方法是或者手动填入标识符,或者从Excel中粘贴复制(提示:从Excel中

    复制几行,然后在Access的Home键上点击Paste,然后点击Paste Append)。把

    每个表中的其他列留成空白;它们都将用API填充数据。

    创建类型数据集

    有很多方法能够将C代码连接到数据库,但是我喜欢用类型数据集,因为它简

    单,代码容易读,而且将数据库查询与代码进行了分隔。在Visual Studio中,右

    击你的项目,选择Add,选择New Item,然后选择DataSet。将新数据集命名为

    ADS.xsd。然后,在Server Explorer面板上,右击Data Connections并选择Add

    Connection。选择Microsoft Access Database File作为数据源,点

    击“Database file name”旁边的Browse按钮。然后,在项目目录上选择Access

    数据库文件,然后点击OK。接下来,在Server Explorer面板上,浏览并选择

    Tables文件夹中的表,并把它们拖动到你的新数据集中。你的数据集应该如图3-13

    所示。图3-13:ADS数据集

    代码

    该项目类似于我们用来获取引用数据的项目。首先增加与blp目录中的彭

    博.dll相同的引用,增加相同的using指令,增加相同的预先计算好的Name对象。

    在如下代码中,调用了Run方法,从Access填入数据集,提取债券、贷款和企业的

    数据,然后更新数据库:

    using Event = Bloomberglp.Blpapi.Event; using Element =Bloomberglp.Blpapi.Element; using Message =

    Bloomberglp.Blpapi.Message; using Name = Bloomberglp.Blpapi.Name;

    using Request = Bloomberglp.Blpapi.Request; using Service =

    Bloomberglp.Blpapi.Service; using Session =

    Bloomberglp.Blpapi.Session; using DataType =

    Bloomberglp.Blpapi.Schema.Datatype; using SessionOptions =

    Bloomberglp.Blpapi.SessionOptions; using InvalidRequestException =

    Bloomberglp.Blpapi.InvalidRequestException; using System.Data;

    namespace Path3_Load { class Program { private ADS DS = new ADS;

    private static readonly Name SECURITY_DATA = new

    Name(securityData); private static readonly Name SECURITY = new

    Name(security); private static readonly Name FIELD_DATA = new

    Name(fieldData); private static readonly Name RESPONSE_ERROR =

    new Name(responseError); private static readonly Name

    SECURITY_ERROR = new Name(securityError); private static readonly

    Name FIELD_EXCEPTIONS = new Name(fieldExceptions); private static

    readonly Name FIELD_ID = new Name(fieldId); private static

    readonly Name ERROR_INFO = new Name(errorInfo); private static

    readonly Name CATEGORY = new Name(category); private static

    readonly Name MESSAGE = new Name(message); static void

    Main(string[] args) { Program p = new Program; p.Run; } private

    void Run { FillDataSet; RunBonds; RunLoans; RunCompanies;

    RunIndex; int rowc= UpdateDataSet; }

    FillDataSet方法比较简单,它用TableAdapterManager从Access填充数据

    集:

    private void FillDataSet { using

    (ADSTableAdapters.TableAdapterManager tm = new

    ADSTableAdapters.TableAdapterManager{ tm.BondTableAdapter = new

    ADSTableAdapters.BondTableAdapter; tm.LoanTableAdapter = new

    ADSTableAdapters.LoanTableAdapter; tm.CompanyTableAdapter = new

    ADSTableAdapters.CompanyTableAdapter; tm.IndexTableAdapter = newADSTableAdapters.IndexTableAdapter; tm.MapTableAdapter = new

    ADSTableAdapters.MapTableAdapter;

    tm.BondTableAdapter.Fill(DS.Bond);

    tm.LoanTableAdapter.Fill(DS.Loan);

    tm.CompanyTableAdapter.Fill(DS.Company);

    tm.IndexTableAdapter.Fill(DS.Index);

    tm.MapTableAdapter.Fill(DS.Map); tm.Connection.Close; } }

    在RunBonds方法中,循环访问数据库中的债券表单,将用于引用每个债券的有

    价证券标识符和对应的债券数据行填入一个Dictionary对象(secIds)。然后用

    Map表,将用于存储被请求信息的彭博字段和对应目标列填入另一个Dictionary对

    象(fields)。最后,将两个Dictionary对象传递给一个通用函数FetchData,由

    该类函数运行实际请求:

    private void RunBonds { Dictionary secIds =

    new Dictionary; Dictionary

    fields = new Dictionary; foreach (ADS.BondRow

    bond in DS.Bond) { secIds.Add(isin + bond.BondID,bond); }

    foreach (ADS.MapRow map in DS.Map.Where(x => x.DestTable ==

    Bond)) { fields.Add(map.BloombergFLD, map.DestCol); }

    FetchData(secIds, fields, Bond); }

    FetchData方法创建一个彭博会话,得到引用数据服务的一个实例,从两个

    Dictionary对象(secIds和fields)向彭博请求增加有价证券标识符和字段表

    单,并发送请求。该方法还接受一个KeyValuePair的可选数组,以增加重写(后面

    用于获取公司数据)。最后,该方法轮询Session代码寻求反馈,在得到反馈或部

    分反馈时将Event代码以及Dictionary对象和表名传递至ProcessResponse方法:

    private void FetchData( Dictionary secIds,Dictionary fields, string table, params

    KeyValuePair[] overrides) { Open session and

    service Session session = new Session; bool sessionStarted =

    session.Start; if (!sessionStarted) {System.Console.Error.WriteLine(Failed to start session.); return;

    } if (!session.OpenService(blprefdata)) {

    System.Console.Error.WriteLine(Failed to open blprefdata);

    return; } Service refDataService =

    session.GetService(blprefdata); Create request Request

    request = refDataService.CreateRequest(ReferenceDataRequest);

    add each security to the request Element securities =

    request.GetElement(securities); foreach (string id in

    secIds.Keys) { securities.AppendValue(id); } add each field to

    the request Element requestedFields = request.GetElement(fields);

    foreach (string field in fields.Keys) {

    requestedFields.AppendValue(field); } Optionally, if there are

    overrides, add them to request if (overrides != null) { Element

    overrideElement = request[overrides]; foreach

    (KeyValuePair or in overrides) { Element o =

    overrideElement.AppendElement; o.SetElement(fieldId, or.Key);

    o.SetElement(value, or.Value); } } send the request try {

    session.SendRequest(request, null); } catch

    (InvalidRequestException e) {

    System.Console.WriteLine(e.ToString); } Process the response

    bool done = false; while (!done) { Event eventObj =

    session.NextEvent; if (eventObj.Type ==

    Event.EventType.PARTIAL_RESPONSE) { ProcessResponse(eventObj,fields, table, secIds); } else if (eventObj.Type ==

    Event.EventType.RESPONSE) { ProcessResponse(eventObj, fields,table, secIds); done = true; } else { foreach (Message msg in

    eventObj) { System.Console.WriteLine(msg.AsElement); if

    (eventObj.Type == Event.EventType.SESSION_STATUS) { if

    (msg.MessageType.Equals(SessionTerminated)) { done = true; } } }

    } } session.Stop; }

    ProcessResponse方法用来自彭博反馈的数据填入Dictionary对象secIds。随着ProcessResponse循环至被请求数据,它用被请求的股票代码缩写查询在

    RunBonds方法中创建的secIds Dictionary的DataRow。

    然后,代码提取返回字段的表单,用该字段的Dictionary获取对应的

    DataTable列,然后将DataRow对象的内容清空(即设为null)。然后,代码检查

    彭博返回的字段的“Datatype”属性,以确定获取返回值的恰当方法。例如,如果

    field.DataType被设置为DataType.FLOAT64,那么它就用

    field.GetValueAsFloat64方法;如果field.DataType被设置为

    DataType.DATETIME,那么它就用Field.GetValueAsDatetime方法。在将

    DataRow中的列设置成返回值之前,还要检查ADS数据集中的DataColumn是否会接

    受返回的数据类型值:

    private void ProcessResponse( Event eventObj,Dictionary fields, string table, Dictionary secIds ) { foreach (Message msg in eventObj) { if

    (msg.HasElement(RESPONSE_ERROR)) { Element error =

    msg.GetElement(RESPONSE_ERROR); Console.WriteLine(Request failed:

    + error.GetElementAsString(CATEGORY) + ( +

    error.GetElementAsString(MESSAGE) + )); continue; } Element

    securities = msg.GetElement(SECURITY_DATA); for (int i = 0; i <

    securities.NumValues; ++i) { Element security =

    securities.GetValueAsElement(i); if

    (security.HasElement(securityError)) { Element error =

    security.GetElement(SECURITY_ERROR); Console.WriteLine(Security

    Error: + error.GetElementAsString(CATEGORY) + ( +

    error.GetElementAsString(MESSAGE) + )); continue; } Element

    fieldExceptions = security.GetElement(FIELD_EXCEPTIONS); if

    (fieldExceptions.NumValues > 0) { for (int k = 0; k <

    fieldExceptions.NumValues; ++k) { Element fieldException =

    fieldE ......

您现在查看是摘要介绍页, 详见PDF附件(19937KB,329页)