案例研究:纳斯达克市场回放(AIR和云存储)
原文链接:http://www.infoq.com/cn/articles/nasdaq-case-study-air-and-s3
斯达克市场回放程序(NASDAQ Market Replay)是纳斯达克官方推出的一个新工具,它可以回放和分析证券市场的活动。这个新工具是基于Adobe Flex和AIR平台建立的,并且利用Amazon简单存储服务(Amazon Simple Storage Service,S3)对历史市场数据进行持久化。S3和AIR的组合的部署模型很强大,并且只需要很少的内部基础设施的支持。AIR运行时是跑在客户端机器上的,因此其部署简单而健壮。利用Amazon S3可以省掉传统的中间层服务器,因为数据访问是通过Amazon的云(cloud)进行的。
用户可以通过市场回放程序实时模拟市场情况,了解任一时间点的最高出价和最低报价,定位并且查看微秒级别的事件。另外,投资者还可以对最佳成交原则和美国国家市场系统管理规则(Reg NMS)的执行情况进行监督。经纪人和交易员能复查交易发生那一刻的情况,及时发现问题所在,并分析是否有疏漏的机会。经纪人可以提供给客户经官方验证的交易回放,让客户对经纪人的业绩进行评估。
图1. 市场回放案例研究
问题域
投资者和交易员,不管是职业的还是业余的,经常问的一个问题是“到底发生了什么?”经纪人是否遵守了最佳交易原则和Reg NMS?交易员是否浪费了许多机会?为什么某散户拿到的交易价格与所期望的价格有差距?投资者、交易员和法规事务管员应该怎样回答这些问题呢?一个方法就是重新来过,回放当时的市场情况,慢镜似的查看某一秒甚至某一毫秒之内发生的事情。
纳斯达克市场回放程序利用的是纳斯达克官方验证过的数据,我们在很多情形下都可以用上它。下面就是其中的几个用例:
- 法规事务官员得到报告说某交易不符合Reg NMS或者其它最佳成交原则。此时这个官员就可以利用回放程序重新查看交易时候的具体情况,重建交易那一刻的报价,反复查看某一时间戳的失配,查看某一只持续了数毫秒的报价。一番分析之后,他就可以将纳斯达克的官方回放或者截屏发给客户或者相关监督官员来证实法规的遵守情况。
- 一个散户从其经纪人那得到交易信息,但是此交易的价格跟预期有一定距离,他非常想知道具体的情况。此投资者在一个金融门户利用回放程序查看交易回放,对经纪人的工作进行监督的同时也能对市场的整体情况有更好的把握。
- 经纪人呼叫中心接到客户有关交易价格的投诉。此时接线员就可以拿出印有纳斯达克标识的截屏,当然这个截屏是来自回放程序,用户了解了交易瞬间的情况后就可以做出自己的解读了。接线员可以给客户提供回放链接,在那里客户可以看到交易前后发生的事情。经纪人也可以在提供每个交易确认信息的同时提供这个链接。在这里,市场回放程序达到了减少话务量和每次呼叫时间的目的。
- 交易员,活跃的投资者或者超短线投资者可以通过研究一系列的市场事件,从而做出一个大的交易决策,或者交易员想弄清楚一个有趣的市场状况的本质。这个时候,市场回放就可以派上用场了,交易员利用它查看具体发生的情况,他还可以与其他的投资者共享回放,讨论交易技巧,互通有无。
总之,纳斯达克市场回放程序可以为各类投资者提供其需要的市场信息,让他们更好地了解市场上到底发生了些什么。
实现概览
市场回放这一项目于2008年2月正式上线,几乎与Adobe AIR 1.0 产品的官方发布同步。全部工作主要包括后台的数据处理和界面实现两部分,由一个十人组成的团队完成。由于选择了AIR和S3技术,这个项目由概念到产品上线仅仅花了六个月左右的时间。
客户端桌面程序用到了Adobe Flex, 运行在AIR运行时上。Adobe Flex是一个应用程序开发框架,利用此框架开发的程序在Flash Player上运行。基于Adobe AIR的桌面应用开发可以利用诸如HTML/CSS、 Ajax、 Flash和Flex等Web技术。除此之外,AIR还提供了离线应用支持,其桌面程序部署范式也比较简单。
S3为大容量数据提供了健壮的解决方案,它完全可以满足回放程序的需要。AIR程序运行于用户计算机,其数据部分来源于S3。由于此部署环境的独特性,不需要大规模的服务器基础设施就可以完成。
市场回放程序在很多方面都领先于其他一些类似的解决方案。例如:
- 与其它一些能显示指定时间点买卖盘记录的工具相比,由于应用了Adobe Flex和AIR技术,市场回放在易用性、可视性和回放功能上都要上一个档次。
- 与某一公司或厂商的内部市场数据相比,NASDAQ市场回放提供的是经过NASDAQ验证的数据,就数据来源上来说更直接可靠。
- 与利用历史报价数据库和昂贵的分析软件手动建立起来的买卖盘记录相比,NASDAQ市场回放程序速度更快,更廉价,出错的几率更小。
- 由于数据规模过于庞大,一些内部数据库的访问会变得缓慢,访问代价也逐渐提高,因此这些数据库会每十天到三十天被清理一次,而NASDAQ市场回放利用了S3这一廉价而扩展性极佳的文件系统,避免了频繁的清理工作。
AIR和S3的搭配使得数据获取和显示变得非常快捷。市场回放的主要功能之一便是让用户能看到任一时刻的综合买卖盘记录状态。其工作过程是首先从S3中迅速地载入新的买卖盘记录文件,然后由AIR更新用户界面,更新的过程充分利用了用户桌面的处理能力。由于显示下一个买卖盘记录状态无需等待服务器的计算和传输,用户在不同时刻间进行转换变得非常容易。
深入Adobe Flex和AIR
市场回放程序的一项基本功能是提供真实的市场活动回放,其效果跟一个交易人员在实时交易时看到的没有什么两样。为了能给出任何时刻的综合买卖盘记录,买卖盘记录更新信息的排序和聚合能力也是必不可少的。Flex界面提供的两个显示功能完全能满足这个需求:
- 时间图表(Time chart) :时间图表显示某一时间点的最高出价和最低报价信息,这些都是由报价数据计算得到的。
- 买卖盘记录(Order book) :买卖盘记录负责显示任一时刻买卖盘记录的状态,并且在回放中动态更新这些状态。
在程序中能显示数据的每一个细节是非常重要的,这就意味着必须能定位毫秒级别的报价更新。用户可以指定一个非常小的时间窗口来观察其中每一个数据元素。不仅如此,回放还要做到尽可能的慢,只有这样人的肉眼才能观察到所发生的一切。这么高的显示或者说可视化要求使得Adobe Flex成为不二之选。
在Flash运行时上进行部署最主要的优势来源于其对本地显示的支持,这也是市场回放程序中强大的可视化功能的基础。Adobe Flex是建立在Flash API基础之上的,它拥有显示通用可视化数据的一整套图形组件。这套图形组件及其他一些Flex组件,功能丰富并且具有很好的可扩展性。事实上,在市场回放程序中对标准的Flex图形组件做了扩展和定制。由于有了Flex自带的数据显示组件做基础,NASDAQ开发符合其特殊需求的定制化组件的速度相对来说要快多了。
Flex自带的图形组件相当好用。下面是一个MXML源文件的例子,代码里直接写入了一些假想的数据。MXML是一种说明式的XML标记,它是Flex框架的一部分,可用于Flex程序的编码。大家都知道ActionScript是核心的Flash Player编程语言,而MXML是建立在其基础上的一个抽象。
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
[Bindable]
private var stockDataAC:ArrayCollection = new ArrayCollection( [
{ Date: "25-Jul", Open: 40.55, High: 40.75, Low: 40.24, Close:40.31},
{ Date: "26-Jul", Open: 40.15, High: 40.78, Low: 39.97, Close:40.34},
{ Date: "27-Jul", Open: 40.38, High: 40.66, Low: 40, Close:40.63},
{ Date: "28-Jul", Open: 40.49, High: 40.99, Low: 40.3, Close:40.98},
{ Date: "29-Jul", Open: 40.13, High: 40.4, Low: 39.65, Close:39.95},
{ Date: "1-Aug", Open: 39.00, High: 39.50, Low: 38.7, Close:38.6},
{ Date: "2-Aug", Open: 38.68, High: 39.34, Low: 37.75, Close:38.84},
{ Date: "3-Aug", Open: 38.76, High: 38.76, Low: 38.03, Close:38.12},
{ Date: "4-Aug", Open: 37.98, High: 37.98, Low: 36.56,Close:36.69},
{ Date: "5-Aug", Open: 36.61, High: 37, Low: 36.48, Close:36.86} ]);
]]>
</mx:Script>
<mx:Panel title="Sample Visualization" height="100%" width="100%">
<mx:HLOCChart id="hlocchart" height="100%" width="100%"
paddingRight="5" paddingLeft="5"
showDataTips="true" dataProvider="{stockDataAC}">
<mx:verticalAxis>
<mx:LinearAxis baseAtZero="false" />
</mx:verticalAxis>
<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Date" title="Date"/>
</mx:horizontalAxis>
<mx:horizontalAxisRenderer>
<mx:AxisRenderer canDropLabels="true"/>
</mx:horizontalAxisRenderer>
<mx:series>
<mx:HLOCSeries openField="Open" highField="High"
lowField="Low" closeField="Close"/>
</mx:series>
</mx:HLOCChart>
</mx:Panel>
</mx:Application>
在这里,为了给出一个完整的例子,数据被直接写入源代码中。在市场回放应用的实现中,真实的数据是从Amazon S3中载入的。Flex的HLOCChart (High Low Open Close)组件会将这些数据还原成可视化的数据图表。最后得到的图表可以参考以下的截图。
图2. 视图样例
因为本地资源足以支撑大量的数据计算,因此Adobe AIR是回放程序中客户端的一个理想运行时环境。市场回放程序可以提供每笔交易在选定时间段的最高出价和最低报价以及全国范围内的最高出价和最低报价。为了给出这些结果,需要大量的数据和密集的计算处理。在服务器端处理用户的请求需要强大的服务器支持,不仅如此,请求来回也需要时间,用户在这期间能做的只是等待。Adobe AIR把大量的工作放在客户端桌面上进行,因此其需要的服务器端基础设施的支持非常少。
AIR可以不需要持续的网络支持就可以进行回放和分析,这是它提升用户体验的另一个方面。一旦从S3拿到数据文件,回放和计算就可以进行了,是否有互联网连接此时已经不重要了。这不仅对NASDAQ的客户有用,对NASDAQ的销售人员更是有帮助,因为要求每个客户那里都能上网简直就是一种奢望。
Adobe AIR和Flex对项目的启动起了至关重要的作用。它们为迅速并且高质量的结果显示提供了必不可少的工具。对显示提供最直接支持的就是Flex自带的组件,随着项目的不断演进,这些组件也在不断地被修改和定制,最终形成了完整的程序。
深入Amazon简单存储服务(S3)
之所以选择Amazon S3的原因,是因为市场回放程序需要一个廉价而且扩展性非常好的存储方式。要知道证券市场每天都会产生若干GB的交易数据。市场回放要存放每一个交易的细节数据并且在请求到达后能快速取回所需数据。
NASDAQ一开始制定的目标就是能在线保存数年的数据,并且能以合理的花费就能迅速地的得到全部所需数据,就这一点来说S3是非常令人满意的。有了S3的支持,在毫不牺牲性能的前提下,市场回放能为无数的的用户提供数量多达数十亿个的文件。
市场回放能够支持用户对数月或者数年前数据的请求,只要这些请求是遵规守法的。能迅速地得到所有的历史回放数据是一项非常重要的需求。S3已被证明可以持续地保持高速访问。
NASDAQ的原始数据是分布在各实时数据源处的,在将数据上载到S3之前,NASDAQ会将数据源处的数据格式转换成专为回放优化过的数据格式。这种专利的转换过程转换后得到的是非常简单高效的文本文件,并且这些文件是为快速上载和下载优化过的。文件里包含了所有的报价信息,AIR桌面客户端程序可以利用这些信息构造回放和分析过程的每一个细节。对整个产品来说,每天有成百上千的文件被上载到S3中。
市场回放的数据应用了一种短小精悍的、用逗号分隔的扁平的文件格式。S3的设计使得其可以快速可靠地存储和取回如此巨量的文件。这些文件拥有简单可读的格式,这一点从下边的例子中可以看出。文件名包含有股票代码、日期、文件中所含数据的开始时间等信息。开始的几行记录是每笔交易的初始最高出价和最低报价。接着是这些价格的变化信息。其中的字段包括:Exchange、sequence number、shares at bid、shares at offer、price of bid、price of offer、start time (milliseconds since midnight)、end time (milliseconds since midnight)。
M,7838954,300,100,39.81,200,40136513,42919007
I,8557803,0,0,0,0,40838710,44256757
W,10814573,200,200,40.63,40.99,42896510,42901353
D,10816233,800,100,40.57,40.86,42897527,42900730
C,10816354,100,100,40.79,40.83,42897590,42900667
P,10817504,200,300,40.79,40.83,42898433,42900667
Q,10817505,200,200,40.79,40.83,42898437,42900657
Q,10819570,200,200,40.79,40.84,42900657,42900657
Q,10819576,200,100,40.79,40.87,42900657,42900657
Q,10819577,200,100,40.79,40.88,42900657,42900657
组织和管理上百万的文件似乎是困难重重,然而扁平文件模型跟回放程序跟结合得非常好,因为每次回放或者分析都不需要很多数据就可以完成。这些数据就存放在一个易于管理的服务器文本文件上。程序自身会将用户的回放请求转换为文件名,然后向Amazon S3请求此文件,当请求返回时再对结果进行解析。回放程序目前还不支持跨多只股票或者大时间跨度等开放式查询,但可以对一只股票的所有交易细节进行观察和分析。
Amazon为S3的访问提供了REST和SOAP接口。Flex框架本身也支持访问REST和SOAP接口。除此之外,Google Code上有 一个名为as3awss3lib的开源API,它利用Action Script为AIR运行时与S3之间的交互提供了详尽的支持。
下面就是一个用as3awss3lib
访问文件的例子:
//sample method for init the downloading of a file
private function getFile():void {
//creates as3awss3lib wrapper with auth parameters
var s3Service:AWSS3 = new AWSS3(this.accessKey, this.secretAccessKey);
//add event handlers for async calls
s3Service.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
s3Service.addEventListener(AWSS3Event.ERROR, onError);
s3Service.addEventListener(AWSS3Event.OBJECT_RETRIEVED, onFileDownloaded);
//calls AWSS3 method to get file
s3Service.getObject(fileName, key);
}
//Event handler used file is returned
private function onFileDownloaded(e:AWSS3Event):void {
//get file details
var currentObject:Object = downloadQueue.shift();
var ext:String = mimeMap.getExtension(e.data.type);
var fileName:String = (ext != null && currentObject.key.indexOf(".") == -1) ?
currentObject.key + "." + ext : currentObject.key;
//save file to specified downloadLocation
var fs:FileStream = new FileStream();
fs.open(downloadLocation.resolvePath(fileName), FileMode.WRITE);
fs.writeBytes(e.data.bytes);
fs.close();
Alert.show("Your file(s) have been successfully downloaded.", "Success!", Alert.OK, null, null, null);
}
在这个例子中,"getFile"方法构造了as3awss3lib中类AWSS3的一个实例,并且利用"getObject"方法取回想要的文件。Flex中所有的远程服务都采用异步的方式。因此,getObject的调用也是异步的,AWSS3Event.OBJECT_RETRIEVED事件的处理器(handler) 被用来处理返回的结果。在以上代码中,返回的文件被保存并且利用警告对话框(Alert)告知用户。
在数据准备过程中,数据被分为许多个文件。每个文件只含有一只股票某一天中十分钟内的交易数据(所有的时间段都被标准化了,如9:25-9:35, 9:35-9:45等)。文件名包含数据的股票名称、日期和时间段信息,它是按照日期、股票代码和时间的顺序组合而成的。用户输入股票代码、日期和时间后,客户端程序将其拼装成一个文件名,然后向S3请求需要的文件。S3在快速取得文件和返回文件内容上是非常高效的。
选择Amazon S3除了技术优势外,它的价格模型也是决定性因素之一。它的价格是透明的和可预测的。你可以精确地预测操作所需要的花费,并且能做到实时监控。
对提交给S3的文件进行了精心设计再加上S3的廉价,决定了NASDAQ可以做到一直不进行数据卸载。S3上大部分花销都在数据提交和下载时候产生,将大量文件放在那里一个月不动其实是花不了多少钱的。
S3是按照市场回放所使用的容量收费的。因此NASDAQ就不用为了满足几个月甚至几年之后满负荷运转的需要,而花巨资去购买大量的硬件,这大大降低了市场回放程序的开发和启动成本。S3的可扩展性和价格模型使其可以按需扩容,不需要为了应对可能的用户增长加速而预留空间。
结论
NASDAQ市场回放最近会发布一个新的版本,在此版本中除了报价以外还会加入交易数据。这次发布会对程序做重要修改,包括:报价数据与交易数据的同步、重写图形接口、一个包括交易及其特征的列表、计算关于交易的一些数据。主要的更新在一个月左右的开发时间内就实现了,回放程序的架构和AIR及S3平台的的高品质和强大功能在此过程中充分显现了出来。此外,在AIR上进行版本的更新也很方便,因为其会在每次启动时检查和安装更新程序。NASDAQ市场回放程序的实现过程表明了一个数据驱动应用也能在有限的预算条件下快速地开发和部署,这真是一个令软件业界兴奋的时刻。这要归功于平台的不断发展进步,云计算出现和强大的客户端运行时。
有兴趣的读者可以到NASDAQ的DataStore(https://data.nasdaq.com/MR.aspx)上下载NASDAQ市场回放程序的免费试用版,也可到股票市场数据提供商例如经纪人或者金融门户、金融信息提供商处请求下载完整版程序。