期货程序化环境下模型描述语言解释器的研究与设计
2018-08-15蒋哲远
刘 珂 蒋哲远
(合肥工业大学计算机与信息学院 安徽 合肥 230009)
0 引 言
随着计算机数据挖掘的迅速发展以及国内股指期货市场的推出,市场上各种各样的金融类产品越来越多,投资者的投资理念也愈发成熟和理性,并且逐渐地由主观交易转向客观交易,在这种形式下,期货程序化交易作为一种防范风险和提高风险可控性手段逐渐被应用到市场中。由于现代的程序化交易系统不可能直接处理相关程序,因此必须首先把源程序转换为相应的机器指令,然后再进行交易。
为满足不同领域的解释需求,众多学者在不同领域设计和开发了相应的解释器。文献[4]在工业机器人平台下开发了解释器,将解释器分为前端和后端,对机器人的指令能够准确地进行解释,其中前后端的分离使该解释器拥有较强的可移植性,但由于处理的数据集有限,因此该解释器不适合用于数据集庞大的解释环境中。文献[5]研究了开放式数控系统的NC代码解释器和模块化结构的设计和实现方法,该解释器中模块化的设计使其结构清晰、分工明确,利于解释器的开发,但对语法分析和错误处理的细节研究得不够深入,当源程序出现错误时不能够及时检测出,降低了解释的效率。文献[6]提出了设计分析器和解析器的方法,然而这些方法仅仅局限于理论上,并没有相关的实践来证明该方法的实用性。文献[7]解释了使用扩展的巴科斯范式表示的NC规范字典,这是嵌入式脚本语言工具,然该文献并没有考虑到语法规则的二义性,这给NC解释器带来了不确定性的代码分析。文献[9]针对解释器提出了一种字节码指针引导的间接转移预测技术,主要使用解释器特有的字节码指针值来区分不同的间接转移场景,并在解释器中插入引导指令来提升处理器对间接转移猜测的正确性,提高了解释器的性能,但由于对处理器内部的分支预测需进行定制,硬件实现开销较大。文献[10]建立了基于WinSock的远程控制系统,提出基于反射原理的解释器模式,实现了机器人远程面板或程序控制,且基于速度向量场的改进无碰轨迹规划算法,有效对静态与动态障碍物安全避障。文献[11]提出基于开放式数控平台的STEP-NC解释器,将定义的IInterpreter和ItaskGenerator接口封装到COM模块中,并采用多线程和共享内存技术来解释执行基于STEP_NC源文件,提高了解释器性能。文献[12]提出基于开放式架构和模块化标准的STEP架构,将映射的实体信息存入内存中,在运动控制模块采用插补算法控制机器。以上针对解释器设计与开发的相关研究中,前后端的分离技术以及模块化的设计使解释器各个模块分工明确而又相互协调工作,这大大提高了解释器的解释效率以及正确性。但由于对数据集的处理有限,且不需要实时的解释环境,如果在期货程序化交易环境下,面对大量不同合约的不同K线数据,交易者编写交易策略,在交易的过程中,如何对其进行解释并且触发相应的交易信号,快速准确地帮助交易者完成交易,并不能实时解释。同时由于目前成熟的程序化交易系统很少使用类C语言作为其开发语言,这使得用户对程序化交易使用的门槛变高。为了改善这一现状,参照模型描述语言的特点,本文使用标准C语言作为模型描述语言进行解释器的设计与实现[1],将整个代码解释过程分为各个功能模块,针对每个模块的实现方法进行了探讨,同时增加了回溯测试以及优化阶段,使其交易者可以编写合适交易合约以及市场的交易策略,减少其交易损失。
1 整体概念解释模型
本文的整体概念解释模型主要包括三大模块:中央管理模块、K线图分析模块以及解释模块。其中中央管理模块将K线数据和解释模块相互结合,根据交易策略,获取、分析相应的K线数据,并进行实时的解释执行,影响着交易策略的实时解释效率、成本代价,解释执行的时间性能或资源调度等性能。
K线图分析模块主要是针对不同类型的K线图进行解释分析。期货程序化交易过程中的K线图主要包含四个数据,即开盘价、收盘价、最高价以及最低价,所有的K线都是围绕这四个数据进行展开,反映了大致的状况和价格信息。在解释的过程中,由于用户会根据不同趋势、不同类型的K线图进行分析,然后编写相应市场以及合约的交易策略,并将交易策略交由解释模块进行实时解释执行。同时,在K线图分析模块中,根据交易策略会获取并存储相应市场以及合约的K线数据,解释模块在解释过程中会调用、处理K线数据,帮助其交易。
解释模块是根据用户编写的交易策略进行实时的解释。该模块首先会对其交易策略进行词法分析、语法语义分析,在语法语义分析中,会对词法分析输出的单词进行检查,判断是否符合语法规则。对于符合语法规则的单词进行分析,生成语法树,采用扩展的巴科斯范式EBNF(Extended Backus Normal Form)对编程语言进行描述,并且采用适当的优化手段来解决EBNF范式规则间的移进/归约以及归约/归约冲突[8],然后进入到回溯测试,测试该策略是否可以获取收益。若测试结果显示可以获取收益的话,即按照该交易策略的入市和离市信号进行交易,否则,对其进行优化。其整体的概念解释模型如图1所示。
基于该概念解释模型,本文开发了相应的解释器。交易者可以根据交易的风险控制原则或交易需求编写交易策略,然后交由计算机来进行解释,若控制条件被触发,计算机将自动执行该交易策略,完成交易。该过程不仅能够达到对风险的精细化控制,提高期货市场的运作效率,增加市场流动性,而且还可规避人性弱点,使投资者尽可能地从客观的角度看市场,以平和的心态进行交易决策。
2 解释模块的研究与设计
该解释模块主要包括五个子模块:词法分析模块、语法语义分析模块、交易策略模块、中间结果缓存模块以及错误处理模块,其中交易策略模块又包括交易策略执行模块、交易策略回溯测试模块、交易策略优化模块。整体的解释流程图如图2所示。
图2 解释模块流程图
由图2可知,本文将期货程序化交易环境下的市场需求和传统的C++解释器相互结合,在传统的C++解释器基础上,增加了交易策略模块,交易者可以在实战前进行模拟化测试,判断所编写的交易策略是否能够适应该市场和合约获取利润,同时提供了交易策略优化模块,针对亏损的交易策略进行优化。
2.1 词法分析
词法分析是解释器的基础阶段,其主要任务是根据符号表进行分析和识别单词,对交易策略源程序进行初级错误的检查,过滤掉源程序中的注释和空白符[2]。扫描源程序中的字符串,检查输入的程序中的字符是否合法,正确的输入返回一个对应的内部符号(记为Token),为下一阶段的语法分析做准备,错误的输入则调用错误函数进行处理,并给出相应的错误提示。下面给出了部分的规则集:
Letter[a-zA-Z]
Number[0-9]
IF return IF;
ELSE return ELSE;
THEN return THEN;
WHILE return WHILE;
FOR return FOR;
本文对程序化交易语言中的类C语言定义了清除的词法规则和语法规则,同时具有一般高级语言所需的部分,例如顺序、条件和循环控制语句结构。此外还在原有的基础上增加了在金融交易领域的重要功能,例如:交易指令、交易模型等。
2.2 语法语义分析
语法分析的主要任务是在词法分析的基础上,识别交易策略的各类语法成分,目的是检查词法分析阶段输出的Token是否符合语法规则,以保证程序各部分能有意义的结合在一起,最终生成语法树。该阶段以单词形式作为源程序进行分析,基本任务是根据语言的语法规则,分析源程序的语法结构,并在分析过程中,对源程序进行正确性的检查,最终分析结果是识别出无语法错误的语法成分[3]。
语义分析将分析各个控制结构的含义并进行相应的语义处理。主要有:确定标识符类型、类型检查、识别含义并做出相应的语义处理以及其他的静态语义检查。语法制导和翻译模式都在语法分析的基础上建立语法树,然后遍历语法树,按照语法树对语义规则进行计算。该模块以程序流程的中间描述作为输入,从语句块的第一语句开始解释执行,根据语句的不同类型进入不同的语句处理模块[4]。若当前语句解释执行成功则取下一条语句解释器,否则中断解释流程进入错误处理模块。
2.2.1 扩展的巴科斯范式
期货程序化交易采用“小语法、大函数”的模式构建交易模型。平台在执行固化交易模型时采取的是编译后直接运行的模式,而对于用户提供的交易策略公式实现平台的解释执行模式。期货程序化交易使用了简化的标准C语言来描述交易模型,配合平台本身已固化的丰富金融统计函数和交易公式、免费交易模型、授权许可交易模型,使投资者能很容易地掌握交易模型的编制,快速地构造出具有自动平开仓交易的复杂交易模型,并可动态地加载到自己编织的交易模型中,同时还支持DLL动态链接库的功能扩展。本文使用EBNF范式给出交易模型描述框架,部分EBNF范式如下所示:
其中“::=”代表了左部由右部定义;“|”为“或”;“{}”为其中的语法成分可以重复任意次数;“()”为其中成本的优先级。根据EBNF语法规则,语法分析器按照移进/规约原则分析读取的标记,每次读取一个没完成规约的标记时,就把该标记压入到内部的栈中,并切换到一种反映其刚读取标记的新状态;若该标记发现组成每条规则右侧的全部符号时,就把右侧符号弹出栈,将左侧符号压入栈中,并切换到栈上新符号的状态。
2.2.2 节点类的设计
在语法语义分析阶段,为了构建抽象语法树,为模型描述语言各种类型的节点设计的对应的类。图3展示了部分节点类的结构图,Lexer类主要作用在词法分析阶段,读取源程序,并识别各个单词符号;token类中储存识别的单词;Parser类中作用在语法语义分析阶段,读取token类中的每个token,针对文法进行语法语义分析;interpreter类中是解释相关的语义分析;最后的Excuter类主要是执行最后的指令。
图3 主要节点类图
2.2.3 语法树的构建
在语法语义分析过程中,最重要的就是如何构建抽象语法树[14],因此,本文以表达式的语法树构建为例进行描述,其他函数等语法树的构建过程类似。表达式语法树的构建相当于把表达式用后缀式表示,该过程将为每个运算符以及对象建立节点来为字表达式构造子树。其相应的伪算法如下:
begin
init_stack(S);
//S为保存运算数的栈
init_stack(F);
//F为保存运算符的栈
push_stack(F,‘#’);
while(p不等于’#’或者F栈顶元素不等于’#’的指针) do
if(p不是运算符) {为p建立节点,push_stack(S,p);p=p->next;}
else {top=stack_top(F);now=push_stack(F,p);
if(top p=p->next;} else if(top==now){pop_stack(F); p=p->next;} else if(top>now) {temp=pop_stack(F); pop_stack(F); a=pop_stack(S);pop_stack(S); b=pop_stack(S);pop_stack(S); //根据a,b,temp构建语法树,完毕后将temp压入S中;} end while; end; 对于求开盘价和收盘价之和的表达式SUM=OPEN+CLOSE,根据上述算法,可以得到其对应的语法树,如图4所示。 图4 语法树 在语法分析的过程中,构造出语法树,这样针对之后的解释阶段提供了清晰、统一的结构,提高了解释器的可维护性以及解释性能。 源程序经过词法分析、语法语义分析后,符合词法分析、语法语义分析的交易策略将会被进行回溯测试,确认该交易策略是否按照交易者的意图被正确地解释执行,产生正确的交易信号。如果结果显示该策略能够帮助交易者增加收益,则利用计算机和现代化网络系统,按照预先设置好的交易模型和规则,在模型条件被触发时,由计算机瞬间完成组合交易指令,实现自动下单等功能[15],否则,交易者可以对该交易策略进行修改、优化,使其适应该合约的交易场景,减少其损失。在该模块中,最重要的为交易策略回测阶段,图5为交易策略回测流程图。 图5 交易策略的回测阶段流程图 实时数据是来自各种K线数据源的标准化实时数据渠道,将每条实时的数据记录下来成为历史数据,然后进入到交易策略中,管理模块会安排整个交易策略以及输入分配的程序,将其分配给模型模块,根据模型模块的反馈结果在输入给操作模块进行查看以提供相应的操作命令。在此阶段中,模型模块和操作模块是所有交易策略中的两个重要的阶段。模型模块只需负责根据数据的输入,把预测的概率输出,而操作模块主要任务是处理模型模块给出的概率,决定该预测价格是要还是不要,同时管理当前的仓位,若合适的话,发送交易信号,触发相应的交易。将交易策略分为模型模块和操作模块的优点在于模型模块操作可以调用多个操作模块,同理,操作模块也可用在多个不同的模型模块上。 实时运行模块负责执行操作模块输出的命令,主要任务是将命令真正地操作起来,并且将反馈的报告提交给操作模块。虚拟运行模块即为一些虚拟交易场所。若使用历史数据操作交易策略的话,操作模块将会调用该模块。 该解释器支持的交易系统中的交易模型有以下几种:趋势类交易模型、震荡类交易模型、日内交易模型、跨合约、跨周期模型、头寸以及交易记录模型等,其中交易模型可能用到的函数有:线性函数、绘图函数、时间函数等。交易者可以创建自己的交易指令、技术指标、K线形态、特征走势、用户函数以及用户字段,同时也可以使用,修改系统内置的函数、字段、技术分析以及交易指令。 在交易策略回溯测试过程中,使用补偿比率、总盈利/总亏损、夏普指数等对风险调整收益进行评估。例如,补偿比例即通过算出风险比例以及补偿比例后,将总盈亏分成最大亏损幅度后进行计算。若该结果小于1,则表示风险较大,该交易策略不理想。反之,则可以获得比较稳定的收益,风险比较小。整个自动化交易过程不仅克服了心态的起伏和人类的弱点,还极大地分散了投资风险,以避免对最终的交易结果造成不必要的影响。 中间结果缓存主要保存在中间数据结构中,中间数据结构是整个解释器运行的基础,用于保存词法语法分析的中间结果,主要包括变量、程序流程和程序语句的中间描述,其生成过程在语法分析阶段完成。在内存数据库MMDB(Main Memory Database System)[13]系统设计时,广泛使用了现代操作系统提供的共享内存机制,系统初始化时将整个数据库装入一片共享内存区,运行时,应用进程可以把整个数据库或一部分映射到自己的虚地址空间进行直接访问。MMDB使得无论是对数据的读取还是写入,都能快速地进行,极大地提高数据的访问效率。 源代码经过上述部分的处理,会产生相应的目标指令,同时,在源程序被解释的过程中,不可避免地会出现某些意想不到的错误,为了尽可能避免影响解释的进程,需要尽早地检测到错误发生的位置并且试图进行校正。该解释器开发了错误处理模块,当发生错误时,能够及时地进行处理,并指出错误的位置。 针对期货程序化环境下,如何帮助交易者实时正确地解释交易策略,本文开发了标准C语言的解释器,并将其运用到期货程序化交易平台(SmartPTrader)中,其中交易者编写交易策略界面如图6所示。 图6 交易模型编辑界面 在图6所示的界面中,该交易模型支持以下几种类型:趋势类交易模型、震荡类交易模型、日内交易模型、套利交易模型等,同时交易者也可以编写自己的交易指令、技术指标、K线形态、特征走势、用户函数以及用户字段,也可以拷贝或者修改系统内置的函数、字段、技术分析或者交易指令。交易者编写好交易策略后将其运行,然后SmartPTrader平台内部的解释器会对交易策略进行解释,当交易条件被满足时,将会触发交易信号,完成交易。 如图7(a)、(b)中所示,在单个交易账户和多个交易账户下,无论是对同一合约的不同交易股数,还是相同交易股数的不同合约共同进行交易,交易策略被解释的时间都会随着数量的不断增长而增长,但其增长的速率确是逐渐平稳,且每次交易触发的时间都没有超过500 ms。这证明了该解释器能够在解释的过程中,准确快速地抓住交易机会,触发交易信号,满足了期货程序化交易环境下的解释性能。 (a) (b) 图7 时间性能 图8选取RU888橡胶合约进行交易。由此可得,随着交易次数的增加,交易策略在解释过程中的收益率表现良好,获得了较好的盈利。刚开始收益率为负,这是因为交易者对整个流程不太熟悉,从而导致结果不太稳定,但是随着交易次数的不断增加,收益也稳步增加。因此,该解释器适合应用与期货程序化交易环境中。 图8 交易盈利 本文以期货程序化交易为背景,首先提出了整体概念解释模型,且基于该模型,开发了C++语言解释器,通过对用户编写的交易策略源程序进行词法分析、语法语义分析等阶段,对其进行实时解释,当满足触发条件时,执行交易。本文下一阶段的任务是优化解释器的实时性能,使其承载更多交易合约和用户情况下,快速准确地实时解释交易策略并进行触发。2.3 交易策略处理
2.4 中间结果缓存
2.5 错误处理
3 实验验证
4 结 语