2 EasyLanguage ÔÏó×ÔÑ ¿Î Ì

You might also like

You are on page 1of 157

EASYLANGUAGE 对象自学

课程(译)

国信证券 TRADESTATION

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
0
重要信息及披露

TradeStation 致力于服务机构和量化投资者 TradeStation 致力于服务机构和


量化投资者。请知晓,量化交易一般不适用于资源受限、投资受限、交易经验受
限、低风险承受力或者无法承受低于 50,000 美元资本风险的投资者。
本书细致地讨论 TradeStation 如何帮助用户开发、测试以及优化交易策略。
但是 TradeStation 并不提供或推荐交易策略。我们只是为你提供设计策略、观察
策略历史表现的工具。我们相信这是重要信息,因此我们提醒你注意,一个交易
策略的历史仿真交易并不能保证它的未来交易成果。我们更没有推荐或招揽任何
外汇、期货、股票以及其他衍生品。本书所述仅限于举例,并不是推荐。
最后,本书涉及自动买入、卖出预警以及电子订单的处理、执行,请注意尽
管 TradeStation 用于交易策略的自动化并及时提交、发送、执行订单,但是偶尔
也会出现延迟,甚至由于市场波动、报价延迟、系统和软件出错、网络堵塞、电
力中断和其他因素导致失败。
TradeStation 所有权归属于 TradeStation 证券公司的子公司——TradeStation
技术有限公司所有。其他专题和 TradeStation 功能直接由 TradeStation 技术提供。
TradeStation® 和 EasyLanguage®为 TradeStation 技术有限公司注册商标。文中提
到的―TradeStation‖需联系上下文理解。
本书的价格图表仅用于举例,图表中的符号、分析并不代表推荐或担保。
期权风险披露
期权交易带有高风险。期权的买家和卖家应该熟悉期权交易理论和定价,并
且所有相关风险因素。
尽管准备这本书的过程中采取了所有防范措施,国信证券和 TradeStation Securities
不为使用在此包含的信息所产生的错误、遗漏或任何损害负责。

下载课程材料

www.tradestation.com/education/downloads/ELOBJECTS

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
i
EasyLanguage 对象自学课程(译)

目录
重要信息及披露................................................................................................................................ i
关于本书.......................................................................................................................................... iv
EasyLanguage 对象简介 ................................................................................................................. 1
学习使用 .......................................................................................................................................... 1
 EasyLanguage 代码编辑器............................................................................................... 2
 工具箱............................................................................................................................... 2
 组件盘............................................................................................................................... 5
 属性编辑器....................................................................................................................... 5
 EasyLanguage 字典........................................................................................................... 7
EasyLanguage 中的对象 .................................................................................................................. 8
什么是对象? .................................................................................................................................. 9
初始组件设置 .................................................................................................................................. 9
在代码中访问属性 ........................................................................................................................ 10
PriceSeriesProvider ......................................................................................................................... 12
◆课程例题 #1....................................................................................................................... 13
对象和函数 .................................................................................................................................... 16
价格集合 ........................................................................................................................................ 17
PriceSeriesProvider - Count 属性 ................................................................................................... 18
◆课程例题 #2....................................................................................................................... 18
输入和属性 .................................................................................................................................... 21
常见提供器(Provider)属性 ..................................................................................................... 21
◆课程例题 #3....................................................................................................................... 22
◆课程例题 #4....................................................................................................................... 25
方法 ................................................................................................................................................ 29
事件 ................................................................................................................................................ 31
 事件处理程序................................................................................................................. 31
设计器代码 .................................................................................................................................... 32
计时器 ............................................................................................................................................ 33
◆课程例题#5......................................................................................................................... 33
AccountsProvider(账户提供器) ............................................................................................ 37
 集合................................................................................................................................. 38
 查询定义和帮助............................................................................................................. 39
◆课程例题#6......................................................................................................................... 39
筛选属性(TokenList) .............................................................................................................. 43
+=加等号赋值运算符 .................................................................................................................... 44
PositionsProvider(仓位提供器) .......................................................................................... 45
◆课程例题 #7....................................................................................................................... 46
方法变量 ........................................................................................................................................ 49
◆课程例题 #8....................................................................................................................... 51
ToString() .................................................................................................................................... 54
OrdersProvider ............................................................................................................................ 55

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
ii
EasyLanguage 对象自学课程(译)
◆课程例题 #9....................................................................................................................... 56
LastBarOnChart ............................................................................................................................ 58
分析技术 - Initialized 和 Uninitialized 事件 ................................................................... 59
IntrabarPersist .......................................................................................................................... 59
OrderTicket .................................................................................................................................. 59
 激活下单对象................................................................................................................. 60
◆课程例题 #10..................................................................................................................... 61
 声明对象变量................................................................................................................. 66
 跟踪 Order Ticket 的委托单状态 ................................................................................... 67
BracketOrderTicket .................................................................................................................... 68
◆课程例题 #11..................................................................................................................... 69
MarketDepthProvider .................................................................................................................. 76
◆课程例题 #12..................................................................................................................... 77
QuotesProvider ............................................................................................................................ 80
◆课程例题 #13..................................................................................................................... 81
FundamentalQuotesProvider ...................................................................................................... 84
◆课程例题 #14..................................................................................................................... 85
Workbook(Excel) .......................................................................................................................... 89
◆课程例题 #15..................................................................................................................... 90
创建非组件对象 ............................................................................................................................ 95
Vector 集合 ................................................................................................................................... 96
◆课程例题 #16..................................................................................................................... 98
◆课程例题 #17................................................................................................................... 104
◆课程例题 #18................................................................................................................... 107
Using-(保留字) ....................................................................................................................... 110
窗体控件(Form Controls) .................................................................................................... 111
◆课程例题 #19................................................................................................................... 112
◆课程例题 #20................................................................................................................... 116
附加练习部分 .............................................................................................................................. 126
 撤销委托....................................................................................................................... 127
◆附加例题 #21................................................................................................................... 128
 DateTime ....................................................................................................................... 134
 TimeSpan....................................................................................................................... 135
◆附加例题 #22................................................................................................................... 136
 分析技术 - Unitialized 事件 ........................................................................................ 143
 Try-Catch ....................................................................................................................... 143
 XML 对象 ...................................................................................................................... 144
◆附加练习 #23................................................................................................................... 145

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
iii
EasyLanguage 对象自学课程(译)

关于本书

感谢购买EasyLanguage Objects - Home Study Course。

本课程的目标是帮助你更加熟悉EasyLanguage对象以及它们可以怎样被用于拓展你已经熟

悉的EasyLanguage代码。你将通过使用对象创建并检验若干独特的EasyLanguage指标来完成

熟悉对象的过程。

一个简单并一致的格式将贯穿全书: 一系列EasyLanguage元素和概念的介绍,后面跟着一

个或多个与概念相关的练习。

创建并输入每个练习,并按需将你的作品应用到图表或雷达屏中。

预备知识:

在尝试本课程内的练习之前,强烈建议你熟读“EasyLanguage学习课程”。你也可以通过从

编程手册或互联网上阅读一些关于面向对象编程的概念而获益。

本书的作用是,对在现有的EasyLanguage框架下访问市场数据和下单而设计的EasyLanguage

对象增强功能进行介绍。我们推荐用户在开始本课程之前理解并熟悉TradeStation平台。这

包括创建和管理图形分析、以及答题上的文件、窗口、工作区、及桌面的管理技巧。一个很

好的起点是国信TS大学:

http://www.guosen.com.cn/gxzq/tradestation/tradestationCollege.jsp?classid=0001

0002001200090001

无论是出于什么理由,你现在掌握了一门透彻的、进阶的课程,该课程将教你如何用

EasyLanguage来理解并编写包含对象、属性、方法的自定义分析技术和交易策略。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
iv
EasyLanguage 对象自学课程(译)

EasyLanguage 对象简介
自从推出以来, EasyLanguage 不断发展成为一款比传统编程语言更有效地帮助交易者分析

交易想法以及实现交易策略的编程语言。在 EasyLanguage 中加入对象是该语言最新的发展,

它提供了一系列增强了的语言元素和编辑工具来延伸 EasyLanguage 的能力和灵活性,同时

也能够轻松地和已经存在的代码融合。

这本书将向你介绍新的术语和工具来帮助你开始使用 EasyLanguage 的对象。不过,本书并

不是一本对面向对象编程进行总体介绍的书。通过一系列的代码案例,你将学习如何结合你

已经熟悉的 EasyLanguage 语句来使用 EasyLanguage 对象。无论你是否选择使用对象进行新

的 EasyLanguage 开发,请注意你已经存在的分析技术和策略将继续工作,不发生任何变化。

学习使用
学习一个科目的一种方法是去学习它的具体细节。比如,我们可以通过学习内燃机、转向联

动装置,以及其他复杂的机械类话题去了解汽车,或者我们可以就将汽车当做一个复杂精密

的机器然后学习驾驶它们。同样地,我们可以通过学习多态、封装、继承,及其他复杂的编

程概念去学习编程对象,或者我们可以直接接受“对象代表包含属性和方法的复杂程序”这

一事实,然后学会如何驾驭它们。

学习驾驶的第一步是熟悉我们的坐骑。这里,我们的坐骑是 TradeStation 开发环境以及能帮

助我们的几个面向对象的编辑工具,包括:

 EasyLanguage 编辑器

 工具箱

 组件盘

 属性编辑器

 EasyLanguage 字典

当使用 TradeStation 开发环境和 EasyLanguage 对象时,有几个你应该了解的新词汇。我们后

面将更详细地介绍对象术语,但是下列这些将帮助你开始学习:

 组件 - 从工具箱内获取的拖放对象

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
1
EasyLanguage 对象自学课程(译)
 对象 - 组件或其他对象的复制品

 类(Class) - 对象包含的特征和行为的蓝图

 属性 - 对象内的数据和信息

 点号 - 在代码中用于获取对象的属性和方法

 方法(Method) - 相当于 EasyLanguage 里的函数

 事件 - 有变动的通知

 Collections - 对象和对象数据的数据结构

 EasyLanguage 代码编辑器

EasyLanguage 开发环境是你在 EL 文件中输入并编辑 EasyLanguage 语句及代码评论的地方。

每当你开始在编辑器中打字,自动完成窗口会弹出,根据你输入的内容显示可能的选择。除

了显示常见的保留字和函数之外,自动完成窗口还会帮你选择你创建的对象的属性。很多新

对象相关属性将会在本书中提及。

例如,在一个代码编辑器内打开的 EL 文档中,输入字符"va",自动完成窗口会出现并高亮

单词"value1",因为这是"va"为首的第一个单词。再输入字母"r",高亮的单词变为"var"。再

输入字母"i",高亮单词换为"variable"。在任何时间段,按下回车键将会把高亮的单词放进

你的文档中。

 工具箱

工具箱选项卡位于代码编辑器的左边,它显示的是一列能够作为对象加载到你的 EL 文档中

的可用组件。一个对象把数据和程序结合成一个方便的程序包,这样你可以将它在 EL 代码

中作为属性和方法使用。设计工具箱组件是为了让你通过最少的编程向分析技术、策略和函

数中轻松添加对象。

可用组件(工具箱中)

 价格、基本面、报价,以及市场深度(Level II)数据

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
2
EasyLanguage 对象自学课程(译)
 账户数据

 委托单和仓位数据

 委托单 (下单)

 计时器

 Workbook(与 Excel 表格融合)

非组件对象(不在工具箱中)

 全局变量

 向量(数据收集)

 自定义 EL 窗口设计

 XML 数据库

 日期

 更多„„

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
3
EasyLanguage 对象自学课程(译)

要想在已经存在的 EasyLanguage 文档中添加组件,可以通过选择该组件的名称然后双击将

它放入代码编辑器中(参见“组件盘”)。在接下来的很多例子中,我们会使用工具箱向

EasyLanguage 文件中添加组件对象。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
4
EasyLanguage 对象自学课程(译)

 组件盘

在代码编辑器的底部是组件盘。它显示从工具箱中被添加进 EasyLanguage 文件的组件对象

的名称。默认情况下,这个名称由组件名和编号组成。

单个文档可以添加不同的组件,或者同一组件的多个实例。我们将在后面的例子中对此进行

更详细的讲解。

 属性编辑器

属性选项卡位于代码编辑器的右侧。它用来访问属性编辑器面板(见下),在这里你可以设

置或检查你的文档中特定组件的属性。要表明你想在属性编辑器里编辑哪个组件的属性,点

击组件盘里的组件名称,或者从属性编辑器顶部的下拉列表中选择名称。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
5
EasyLanguage 对象自学课程(译)

属性编辑器工具栏包含了数个不同的图标,这些图标可以让你在属性 窗格和事件 窗

格间选择,以及其他我们后面会提到的编辑工具。

在默认情况下显示的是属性窗格。属性列显示按类别分组的属性名称,数值列显示相应属性

的设置。类别和子类别可以通过点击 和 两个符号进行展开或折叠。时间窗格包含一

个事件列和一个数值列。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
6
EasyLanguage 对象自学课程(译)

默认情况下,当你在面板外点击时,面板会自动关闭并再次显示为一个选项卡。要想在你做

改动时保持面板打开,点击面板顶部的 图标。当你用完面板后,再点击 关闭面板。

注意:对象属性不要与设置指标样式、颜色、刻度轴的指标属性混淆。

 EasyLanguage 字典

同样位于代码编辑器右侧的字典选项卡用来访问字典面板。在字典面板中,你可以搜索

EasyLanguage 保留字和函数的概要,以及在 EasyLanguage 代码里的对象所代表的类和类成员

的信息(属性、方法、事件等等)。

默认情况中,对象窗格(位于字典面板左侧)显示库和命名空间的层级,它们包含了

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
7
EasyLanguage 对象自学课程(译)
EasyLanguage 的类和保留字。点击 和 图标,你可以浏览层级中的其他层。在对象窗格

中点击一个对象可以在右上角的成员窗格内看到相关条目。在成员窗格内点击一个条目可以

在右下角的描述窗格内显示这个条目的概要。在对象和成员窗格中,图标帮助确认对象或成

员的类型(参见 TradeStation 开发环境帮助了解更多关于图标的内容)。

例如(见上),在对象窗格的 easylanguage.ell 部分选择 Comparison and Loops,成员窗格显

示一列属于该类别的保留字,描述窗格内显示该类别的概要。

你也可以通过往字典面板左上角的搜索框里输入一个或多个单词来搜索字典里的条目。搜索

结果会显示在对象窗格内,在这里选择一个条目,该条目的概要会显示在描述窗格内。

当你读完本课程,对于对象和类更熟悉后,不妨花些时间浏览字典中的各种命名空间,看看

不同的类和它们的属性是怎么相互联系的。字典包含 EasyLanguage 支持的所有类、属性、

方法、时间和其他对象特征的参考资料。很多描述也含有通向 EasyLanguage 帮助话题的链

接,这些帮助话题概括了语言的功能和有关的对象元素。

EasyLanguage 中的对象
本课程的目的是向你介绍 EasyLanguage 对象的使用,
所以最明显的问题是,
“为什么用对象?”

简单来说,对象可以让你在 EasyLanguage 中做一些之前没法做的事情,而且至少能提供另

一种有着更大灵活度和更优秀结构的方法来做一些你在 EasyLanguage 中已经熟悉的事。

所以,什么是对象?最简单地说,一个对象代表一种特定类型的值,这些值你可以用一个用

户定义的名称在 EasyLanguage 代码中获取。等一下„„听起来很像变量的定义,不是吗?

事实上,这完全正确„„使用对象和使用变量很像。不过与传统变量不同的是,我们到目前

为止的 EasyLanguage 体验中,一个变量保存单个数值、字符串、或者布林值,而一个对象

变量代表一个集成了值和相关元素并据此执行的程序包。

在对象中,值被称为属性,可以被认为是针对对象的保留字和保留变量。被称为方法(Method)

的对象元素与 EasyLanguage 函数很相似,它与其他元素(例如运算符和事件)一起使用,

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
8
EasyLanguage 对象自学课程(译)
来执行针对对象的计算以及管理对象任务。

按照程序包的概念,属性和方法的名称总是与它们所属的对象一起写出来(后面的章节会详

述)。比如,一个对象由一个名为 myObject 的变量所代表,要想提到该对象的一个属性,需

要在变量名后面加上一个“.”再加上想要的属性名,就像下面这样:

Value1 = myObject.PropertyName;

由于对象是将数据和程序结合成一个便捷程序包的独立组件,要使用一个对象的属性值和方

法,你不必知道任何该对象内部的编程。这使得对象成为获取复杂数据结构(例如价格数据

流)或者处理复杂程序元素(例如窗口控制和事件)的理想选择。就对象来说,对象变量的

类型与它的类以及含有值的特定的包(这个包由一个被称为实例的独特的对象变量名所代表)

联系在一起。

什么是对象?
 组件的一个副本,它知道如何访问、返回和处理数据

 对象数据通过属性返回

 像变量一样,对象有一个描述性的名称

初始组件设置
首先,你要使用工具箱里的组件往 EasyLanguage 文档中添加对象,并用属性编辑器进行设

置。

大多数组件在你的分析技术或策略中开始收集数据或执行想要的功能之前需要一些初始设

置。例如,你想使用 PriceSeriesProvide 对象引用价格时需要先指定交易代码;想用 OrderTicket

对象下单时需要先指定账户号码。

本书中的课程例题将会在标题组件和属性编辑器设置下列举例题中每个组件你需要输入的

设置。这会帮助你熟悉那些当你在自己的分析技术和策略中使用组件时需要注意的属性。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
9
EasyLanguage 对象自学课程(译)

在代码中访问属性
一旦一个组件对象通过属性编辑器向你的文档中添加并进行设置之后,你将可以通过

EasyLanguage 代码访问对象的值。这通过在对象名和属性名称或想引用的方法之间使用点号

“.”来实现。对组件来说,对象的名称通常由组件的名称后跟着一个实例序号来表示(例:

PriceSeriesProvider1)。当你在对象名称后敲下一个“.”字符时,一列可用的属性 和方

法 就会在自动完成窗口中出现。当你输入更多属性名称的字符,列表内的选择也更加严

格。

当你在代码编辑器内的 PriceSeriesProvide1 后输入点号“.”


,自动完成窗口将会出现并提供

一列属性选择。

例如,接下来的语句读取一个 PriceSeriesProvider 对象的 Count 属性,并将它赋值给一个变

量。Count 属性返回历史区间(bar 数)的数值,该数值由一个特定的、名为 PriceSeriesProvider1

的组件对象的实例所代表。

Value1 = PriceSeriesProvide1.Count;

PriceSeriesProvider 的另一个属性是 Close 属性。但是,


与 Count 属性返回一个值所不同的是,

Close 属性代表一系列收盘价,从当前的 bar 开始一直到价格序列范围的第一根 bar。要访问

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
10
EasyLanguage 对象自学课程(译)
单独的一个收盘价你需要使用方括号[ ]指数运算符和一个指数。在此情况下,这个指数代表

相对于对象区间设置的多少根 bar 之前的数字。这和 EasyLanguage 里标准的 Close 保留字代

表 K 线图中相对于区间设置的多少根 bar 之前很类似。这种代表着一系列值通过方括号内的

指数来访问的属性被称为集合。更多关于此的知识在下一章节介绍。

Plot1(PriceSeriesProvide1.Close[0]);

在这个例子中,点号“.”之后的单词 Close[0]是名称为 PriceSeriesProvide1 的对象,该对象

代表在这个对象可用的收盘价集合之内的 0 根 bar 之前的收盘价。注意,与 EasyLanguage

的 Close 保留字不同的是,当提到一个这样的集合属性中的单独的收盘价时,你必须总是指

定一个指数[0]作为属性识别码的一部分。

一旦你往 EasyLanguage 代码里添加了属性参考后,你可以右键点击属性名然后从弹出的快

捷菜单里点击“„„的定义”(这里是“PriceSeriesProvide1.Close[0]的定义”
)来阅读选中对

象和相关属性的帮助主题。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
11
EasyLanguage 对象自学课程(译)

PriceSeriesProvider
PriceSeriesProvider 组件是一个对象,它包含了在一个历史数据的范围内,指定交易代码在

某个区间设置的实时和历史价格值。每个 PriceSeriesProvider 对象可以被视为一个虚拟的图

表,这个图表能访问有着相似名称的价格属性如 High,Low,Open,Close,Volume,Time

和 OpenInterest,这些价格可以用一个代表多少个 bar 以前的数字来引用。但是,与图表中

的数据不同的是,一个 PriceSeriesProvider 对象需要你预先决定你的分析技术需要访问的交

易代码和区间,这与你图表中的代码和区间设置互相独立。下面列举了一个

PriceSeriesProvider 的重要特征:

 访问任意代码的 bar 数据点

 Aligned historically with Data1 bars

 能够与一些标准 EL 函数一起使用

多个 PriceSeriesProvider 组件可以被包含在一个分析技术内,用以支持多数据分析而不必要

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
12
EasyLanguage 对象自学课程(译)
求组件的交易代码作为数据流包含在 K 线图或网格内。这意味着你可以用对象来创建多数据

指标在雷达屏中使用,并且可以使图表内设置多数据分析变得更简单。另外,你可以不依赖

图表和网格设置,选择访问 Tick(成交笔数)和 Volume(成交量)的相关值,包括上涨和

下跌的成交笔数以及上涨和下跌的成交量。

PriceSeriesProvider 也支持一个 Updated 事件,当一个标的价格发生变动时该事件会在

EasyLanguage 代码里触发。

◆课程例题 #1

目标:
(PriceSeriesProvider 收盘价指标)

 双击一个 PriceSeriesProvider 组件进入文档

 用属性编辑器设置组件对象属性

 从组件对象里绘制一个属性值

 理解 PriceSeriesProvider 数据和图表数据的不同

指标: $01_DailyBarClose

这个例子用一个 PriceSeriesProvider 组件在 30 分钟周期图上个访问并绘制每日收盘价。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
13
EasyLanguage 对象自学课程(译)
工作区:$01_DailyBarClose

建立图表

创建:30 分钟周期图

插入指标:$01_DailyBarClose

组件和属性编辑器

PriceSeriesProvide1:

Symbol: symbol (在Filters分类下)

IntervalType: daily (在Filters-Interval-General分类下)

IntervalSpan: 1 “ ”

Type years (在 Filters-Range-General分类下)

Years 2 “ ”

指标属性

刻度轴:与标的物数据相同

指标练习#1:'$01_DailyBarClose'

习惯说明:每个练习中你需要输入的 EasyLanguage 代码将会用 courier 字体显示。从其他

练习中复制的代码,或者组件自动插入的代码会有一个浅灰色背景。每当提及 EasyLanguage

保留字或函数,它们会被单引号括起来以识别(例:'EntryPrice')。每当提及一个课程联系

输入值或变量,它将会以斜体加以识别,例如 myInput。

创建一个新指标并将它命名为:#01_DailyBarClose。我们将用#命名惯例来将课程练习与课

程可以下载的案例(以$开头)区分开。

我们要做的第一件事就是点击代码编辑窗口左侧的工具箱选项卡,打开工具箱面板。找到

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
14
EasyLanguage 对象自学课程(译)
PriceSeriesProvider 组件,然后双击组件名进代码编辑器。默认名称 PriceSeriesProvide1 将会

出现在位于代码编辑窗口底部的组件盘内。

现在,点击代码编辑器右侧的属性选项卡,打开属性面板并确保 PriceSeriesProvider ① 是属

性编辑器顶部指定的组件。

在 Filters 分 类 下 , 展 开 Interval ( 周 期 ) 和 Range ( 范 围 ) 部 分 , 这 样 你 可 以 设 置

PriceSeriesProvide1 组件的初始值来指明收集什么数据。首先,在 Symbol(代码)属性旁输

入单词'symbol'②。在 Interval 下,把 IntervalType 改成 daily③,并把 IntervalSpan 值

改成 1④。然后,在 Range 下,把 Type 改成 years⑤并把 Years 值改为 2 ⑥.注意:Type

属性位于 Years 属性上好几行,所以请确保在正确的行内输入数值。现在这个组件被设置成

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
15
EasyLanguage 对象自学课程(译)
获取 symbol 过去两年内每日的价格数据。

现 在 , 通 过 刚 刚 对 于 周 期 ( interval ) 和 区 间 ( range ) 的 设 置 , 你 就 能 够 将

PriceSeriesProvide1 组件在代码中作为一个对象来获取当前图中代码的价格了。

在这个例子中,我们将加上一个 Plot 语句来显示来自图表 bar 上的 PriceSeriesProvide1

对象的最后的收盘价。

要访问代码中一个对象的属性,在对象名称后跟着的对象属性名称之后输入点号‘.’,这

里我们输入‘.Close’。既然我们想用该属性显示当前的收盘价,我们在属性名称后加一

个‘[0]’来指明当前 bar 的收盘价。

plot1(PriceSeriesProvide1.Close[0], "Daily Close");

接着,将光标放在 EasyLanguage 文档的空白处,并右键点击,访问快捷菜单,然后选择快

捷菜单底部的“属性”。在指标属性对话框下的刻度轴选项卡上,将坐标轴设置改为刻度位

置:与标的物数据相同,来展示 bar 上的图。

验证指标。如果没有已经显示的话,你应该从视图-工具栏-输出打开打开 EasyLanguage 输

出栏。这可以让你看到任何验证错误以及纠正错误的有用信息。

对象和函数
分析市场数据时,使用以一系列价格为基础的计算结果很普遍,例如在一定数量的 bar 的收

盘价移动平均数。用老旧的 EasyLanguage 你可以用一个函数以及一个价格来实现它。

Value1 = Average(Close,10);

当前图表的 10 根 bar 的平均收盘价就被赋值给了 Value1。然后你就可以画出 Value1 的图,

或者将它用于其他计算和表达式中。这是可行的,因为保留字 Close 不单单代表现在的收盘

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
16
EasyLanguage 对象自学课程(译)
价,它含有从当前 bar 直到 MaxBarBack(可引用到的第一根 bar)的一系列 bar 的收盘价。

类似地,当不标有任何指数时,对象属性 PriceSeriesProvide1.Close 代表基于为价格序列指定

的周期和区间的一系列收盘价。下面将从 PriceSeriesProvide1 对象得出的 10 根 bar 的收盘价

平均数赋值给 Value2:

Value2 = Average(PriceSeriesProvide1.Close,10);

通常,一个包含一系列价格数值的对象或属性可以与一个类型是 numericseries 的函数输入

值组合起来使用。你可以通过在代码中右键点击函数名并选择“打开函数”来检查任何函数

的输入类型。

例如,看看 Average 函数的输入值(在下方显示)


,Price 输入值是一个 numericseries,它除

了可以接受有价格集合的对象,还可以接受包含历史值(例如开盘价,最高价,最低价,收

盘价等)的保留字。

Average 函数,前三行代码:

Inputs:

Price( numericseries ),

Length( numericsimple ) ;

价格集合
一个集合是一种对象(或属性)
,它很像 EasyLanguage 的数组,能保存多个值,可以通过指

数提及这些值。例如,一个价格属性,比如在 PriceSeriesProvider 对象的.Close 属性,可

以保存一系列组件指定的周期范围内的收盘价。就像前一个例题一样,你可以在属性名称后

用一个方括号[]和一个指数引用单个收盘价,比如可以用 PriceSeriesProvide1.Close[2],从

PriceSeriesProvide1 这个组件对象取两个周期以前的收盘价。

但是,当你去除方括号时,PriceSeriesProvide1.Close 属性引用组件的整个收盘价集合,并且

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
17
EasyLanguage 对象自学课程(译)
可 以 作 为 参 数 被 pass 给 任 何 接 受 数 列 的 EasyLanguage 函 数 。 例 如 , 下 面 根 据

PriceSeriesProvide1 对象计算并绘制了前 15 个周期的平均收盘价。

Plot1(Average(PriceSeriesProvide1.Close,15));

尽管我们将在后面深入讲解集合,现在你所需要知道的就是价格集合可以通过使用方括号和

表示多少根 bar 以前的指数返回单个价格值,或者可以不加方括号,作为一个价格序列被

pass 给一个函数。

PriceSeriesProvider - Count 属性
PriceSeriesProvider 组件由一个代码在规定的周期范围内的一系列价格组成。Count 属性告诉

你,随着指标浏览 K 线图上的历史 bar 或雷达屏的行,相对于当前 bar,在 PriceSeriesProvider

集合内有多少可用的历史价格。

为了确保你总能在 PriceSeriesProvider 中有足够价格历史来对一个价格集合进行计算,你应

该在执行计算代码前检查 Count 属性的值。例如,如果你想确保你有足够价格数据来计算一

个规定的移动平均线,你可以像下面一样使用 Count 属性:

Input: MovAvgLen(10);
If PriceSeriesProvide1.Count>MovAvgLen then
Plot2(Average(PriceSeriesProvide1.Close,MovAvgLen));

◆课程例题 #2

目标:
(MovAvg + Close Indicator)

 使用 PriceSeriesProvider 对象搭配标准 EasyLanguage 的‘Average’函数。

指标:
‘$02_DailyAvgClose’

这个指标使用 PriceSeriesProvider 组件在 bar 上访问并绘制一个 10 日移动均线。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
18
EasyLanguage 对象自学课程(译)

工作区: $02_DailyAvgClose

建立图表:

创建:30 分钟日内图

插入指标:$02_DailyAvgClose

组件和属性编辑器设置:

PriceSeriesProvide1:

Symbol: symbol (在Filters分类下)

IntervalType: daily (在Filters-Interval-General分类下)

IntervalSpan: 1 “ ”

Type years (在Filters-Range-General分类下)

Years 2 “ ”

指标练习#2:‘$02_DailyAvgClose’

习惯说明:每个练习中你需要输入的 EasyLanguage 代码将会用 courier 字体显示。从其他

练习中复制的代码,或者组件自动插入的代码会有一个浅灰色背景。每当提及 EasyLanguage

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
19
EasyLanguage 对象自学课程(译)
保留字或函数,它们会被单引号括起来以识别(例:'EntryPrice')。每当提及一个课程联系

输入值或变量,它将会以斜体加以识别,例如 myInput。

这 个 例 题 , 我 们 将以 课程 例 题 #1 中 创 建 的#01_DailyBarClose 指 标 开 始。将 它 另 存 为

#02_DailyAvgClose。我们将用#命名惯例来将课程练习与课程可以下载的案例(以$开头)区

分开。

既然 PriceSeriesProvide1 组件已经是你刚刚创建的指标的一部分,不用再次进行添加。但是,

如果你从头开始,你需要双击工具箱内的 PriceSeriesProvider 组件,将其放入文档内,并按

照上述“组件和属性编辑器设置”,用属性编辑器设置组件的 Symbol(代码)
、Interval(周

期)和 Range(区间)。

上一个例题的绘图语句显示一条将每个 PriceSeriesProvide1 的 bar 的最新收盘价与下一个相

连的线。记住,这与绘制保留字 Close 几乎一样,除了对象属性要求你在属性名后面用‘[0]’

指明当前的收盘价。

现在,让我们在原来的绘图语句前加一个移动平均数长度的输入声明:

input: MovAvgLen(10);

plot1(PriceSeriesProvide1.Close[0],"Daily Close");

接下来,我们将要加入第二幅绘图,此绘图展示了 PriceSeriesProvide1 组件集合内的收盘

价的移动平均线。我们将检查组件的.Count 属性来确保它包含足够的价格数据去进行计算。

Average 函数接受两个参数,第一个代表一系列价格,第二个代表从计算平均数开始处多少

根 bar 之前。使用 Close 属性(不加方括号)来引用基于 PriceSeriesProvide1 的周期和区

间设置的整个收盘价的集合。第二个参数指的是从当前价格开始多少个周期之前来计算移动

平均数。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
20
EasyLanguage 对象自学课程(译)
If PriceSeriesProvide1.Count > MovAvgLen then
plot2(Average(PriceSeriesProvide1.Close,MovAvgLen),"MovAvgLen");

验证指标。

输入和属性
除了在属性编辑器中把初始组件属性设置为一个特定值以外,你也可以将一个属性设置为用

一个 EasyLanguage 输入值作为它的值。这使你在应用分析技术或策略时能够改变输入值并

让组件使用这个值。

例如,当设置一个组件对象的 Symbol(代码)属性时,比如 PriceSeriesProvide1,你也许

会输入“000001.SZ”作为交易代码的值,这样每次运行你的分析技术时,组件将用你在属

性编辑器里指明的周期设置来访问 000001.SZ 的价格。假设你希望能够用输入值来改交易代

码,正如同你在编写标准 EasyLanguage 时那样。点击单词 Symbol 右边的“000001.SZ”


,接

着点击属性编辑器顶部的 图标。这么做会插入单词 iSymbol1 作为代码属性的值并添加

下面的输入语句到 EasyLanguage 代码中,使得输入了的交易代码名称成为默认值。

Input: string iSymbol1("000001.SZ");

注意如果你之前还没有在属性编辑器里设置交易代码值,iSymbol 的初始输入值会被设为“”

常见提供器(Provider)属性

一些工具箱组件在名字结尾含有单词“provider”。使用属性编辑器,你会发现他们都在

Common 分类下包含 Load 和 Realtime 属性。这些属性用来控制提供器(Provider)组件的

初始状态,两个的默认设置均为 True(真)。当为真时,Load 属性指挥提供器(Provider)

自动建立与分析技术或策略初次加载时有关的数据间的连接。比如,AccountsProvider 会

连接到与你指定账户有关的数据,PriceSeriesProvider 会连接指定交易代码的价格数据流,

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
21
EasyLanguage 对象自学课程(译)
等等。当为真时,Realtime 属性指挥提供器(provider)不断地请求相关数据的实时更新。

例 如 , PositionsProvider 根 据 所 请 求 的 交 易 代 码 的 实 时 价 格 变 化 计 算 新 仓 位 值 ,

MarketDepthProvider 会报告买、卖行情的实时变化,等等。

大部分情况下你不会需要修改这些设置;但是,如果你希望设置一个提供器(provider)组

件,让它在你的代码中某个条件出现时可以被激活,你可以在属性编辑器里设置 Load 和

Realtime 属性为 false(假),之后在代码中合适的地方再将它们设为 true(真)。还有,如

果你想从你的代码中改变一个已经加载的提供器(provider)的过滤(filter)属性设置,

你需要暂时将 Load 属性设为 false 来关闭数据连接,给 filter 赋新的值,然后把 Load 再

设回为 true,重新根据新的 filter 设置建立数据连接。

◆课程例题 #3

目标:
(RelStrengthRS)

 添加一个 Symbol(交易代码)属性输入

 在雷达屏中进行多数据分析

指标:
‘$03_RelStrengthRS’

这个指标用一对 PriceSeriesProvide 组件来计算规定天数内两个交易代码的百分比变化。

工作区:$03_RelStrengthRS

建立雷达屏:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
22
EasyLanguage 对象自学课程(译)
创建:雷达屏窗口,窗口内把代码周期设为每日

指标属性-网格样式:采用小数点后两位,将每个指标绘制到 Number

插入指标:$03_RelStrengthRS

组件和属性编辑器设置:

PriceSeriesProvide1:

Symbol: iSymbol1 (作为输入值添加)

IntervalType: daily (在Filters-Interval-General分类下)

IntervalSpan: 1 " "

Type years (在Filters-Range-General分类下)

Years 2 " "

指标练习 #3:‘$03_RelStrengthRS’

在这个指标中,我们把雷达屏中每行交易代码的表现和一个基准代码进行比较。这种多数据

分析在对象被引入前是无法在雷达屏中实现的。每行的交易代码的表现用标准的 Close 保留

字计算,但是基准交易代码的表现将会用来自 PriceSeriesProvider 组件对象的收盘价集合

来对一个参考代码进行计算。

创建一个新指标并命名:
‘#03_RelStrengthRS’

打开工具箱,找到 PriceSeriesProvider 组件,双击。默认名称 PriceSeriesProvide1 将出

现在代码编辑器窗口底部的组件盘内。

打开属性编辑器。点击单词 Symbol 右侧的空文本框,输入代码名“000001.SZ”作为我们的

参考代码。由于当我们将该指标应用于图表上时有可能会更改参考代码,我们将这个代码值

通过点击属性编辑器顶部的 工具栏图表按钮转变为一个输入值。在属性编辑器内,单词

iSymbol1 出现在 Symbol 旁边,并且应该可以看到下面的一行代码以及作为初始值的

“000001.SZ”被插入到 EasyLanguage 代码的顶部。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
23
EasyLanguage 对象自学课程(译)

Input: string iSymbol("000001.SZ");

还是在属性编辑器内,找到 Filters 分类并展开 Interval(周期)和 Range(区间)部分,

这样你可以设置 PriceSeriesProvide1 组件的初始值来指明收集哪个价格数据。


在 Interval

下,把 IntervalType 改为 daily,IntervalSpan 的值改为 1.然后,在 Range 下,把 Type

改为 years 并把 years 值改为 2。注意:Type 属性位于 Years 属性上好几行,所以请确保在

正确的行内输入数值。现在这个组件被设置成获取 symbol 过去两年内每日的价格数据。

在代码内,声明一个额外的变量,这个变量将默认使用多少根 bar 以前的数设置为表现回顾

值。

Input: LookBack(20);

声明三个变量来保存用来衡量每行交易代码表现百分比变化的计算结果,基准参考交易代码,

以及它们之间的相对差别。

Vars: SymbolPerf(0), BenchPerf(0), RelPerf(0);

接着我们计算当前交易代码以及基准交易代码的百分比变化。

当前行的交易代码的表现用保留字 Close 计算,


Close 和计算百分比变化的 bar 的范围一起,

作为一个参数被 pass 给 PercentChange 函数。

SymbloPerf = PercentChange(Close, LookBack);

基准交易代码用来自 PriceSeriesProvide1 对象的收盘价的集合进行计算。

BenchPerf = PercentChange(PriceSeriesProcvide1.Close,LookBack);

相对表现是两个代码的百分比变化的差值。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
24
EasyLanguage 对象自学课程(译)

Relperf = (SymbolPerf - BenchPerf);

最后,计算出来的值将被绘制成图。参考值都被乘以 100 来显示为一个百分数。

plot1(RelPerf * 100,"Rel Perf");

plot2(SymbolPerf * 100, "Sym Perf");

plot3(BenchPerf * 100, "Bench Perf");

验证指标。

将指标加载到周期为每日的雷达屏窗口内。

◆课程例题 #4

目标:(RelStrengthFixed)

 用多个 PriceSeriesProvider 组件

指标:
‘$04_RelStrengthFixed’

这个指标用一对 PriceSeriesProvider 组件来计算两个代码在规定天数内的百分比变化。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
25
EasyLanguage 对象自学课程(译)

工作区:$04_RelStrengthFixed

建立图形:

创建:30 分钟日内图

插入指标:$04_RelStrengthFixed

组件和属性编辑器设置:

PriceSeriesProvider1:

Symbol: iSymbol1 (在Filters分类下) (作为输入值添加)

IntervalType: daily (在Filters-Interval-General分类下)

IntervalSpan: 1 " "

Type years (在Filters-Range-General分类下)

Years 2 " "

PriceSeriesProvide2:

Symbol: symbol (图表或网格行内的交易代码)

IntervalType: daily (在Filters-Interval-General分类下)

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
26
EasyLanguage 对象自学课程(译)

IntervalSpan: 1 " "

Type years (在Filters-Range-General分类下)

Years 2 " "

指标练习 #4:‘$04_RelStrengthFixed’

这个指标与之前的例子很像,除了本指标的设计目标是使用一对周期均被设为每日的

PriceSeriesProvider 组件在一张图形上绘制相对表现。这让你可以将当前交易代码的每日

表现与基准交易代码的每日表现相比较,无论图形上的额周期设置是怎样的。

在这个例子中,让我们从课程例题#3 中创建的#03_DailyAvgClose 指标开始。将它另存为

#04_RelStrengthFixed。我们将用#命名惯例来将课程练习与课程可以下载的案例(以$开头)

区分开。

由于 PriceSeriesProvide1 组件已经是刚刚创建的指标的一部分,因此不需要再次添加。但

是,如果你是从头创建的话,在工具箱中双击 PriceSeriesProvider 组件将其添加到文档中,

并用属性编辑器为 PriceSeriesProvide1 组件按照本练习上述“组件和属性编辑器设置”的

内容设置它的 Symbol,Interval 和 Range 值。

接下来,我们从工具箱内添加第二个组件。找到 PriceSeriesProvider 组件,双击。在代码

编辑器窗口下方的组件盘里出现了第二个默认名称为 PriceSeriesProvide2 的组件。

选中 PriceSeriesProvide2 组件,进入代码编辑器。在 Symbol 属性旁,输入单词 symbol

来将该属性设置为当前图表中的交易代码。在 Filters 分类下,展开 Interval(周期)和

Range(范围)部分,这样你可以设置 PriceSeriesProvide2 组件的初始值来规定其收集的

价格数据。在 Interval 部分,把 IntervalType 改为 daily(每日)


,将 IntervalSpan 值改

为 1。然后,在 Range 下面,将 Type 改为 years 并将 Years 的值改为 2。第二个组件现在就

被设置为取 symbol(当前图表的交易代码)过去两年内每日的价格数据。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
27
EasyLanguage 对象自学课程(译)
我们将使用与练习#3 中相同的输入名称;但是,让我们把初始 LookBack 值设为‘8’

Input: string iSymbol1( "000001.SZ" );

Input: LookBack( 8 );

变量名称也会基于练习#3,但是,让我们把当前代码表现变量的名称改为 SymbolPerf。

Vars: SymbolPerf( 0 ), BenchPerf( 0 ), RelPerf( 0 );

计算当前交易代码和基准交易代码的百分比变化。我们把表现计算放在一个“if”语句中,

这个“if”语句会在每天的第一根 bar 计算每日的表现值。记住,我们将用刚刚创建的第二

个 Price Series Provider 组件取参考交易代码以每日为周期的收盘价,这样表现总是基于

两个提供器(provider)的每日周期,尽管图表的周期不一样。

当前交易代码表现用 PriceSeriesProvide2 组件对象内的收盘价集合计算的,在计算百分比

变化时,PriceSeriesProvide2 与回顾的 bar 数一起呗作为参数传递到 PercentChange 函数

中。基准交易代码的表现是用 PriceSeriesProvide1(基于输入值 iSymbol1)内的收盘价集

合以及同样的 PercentChange(百分率变化)回顾长度。

If Date <> Date[1] then begin


SymbolPerf = PercentChange(PriceSeriesProvide2.Close, LookBack) ;

BenchPerf = PercentChange(PriceSeriesProvide1.Close, LookBack);

end;

计算 base 和 reference 的百分比变化之间的相对表现之差。

RelPerf = SymbolPerf - BenchPerf;

绘制三个计算值,这次删除*100 语句,因为我们不需要在图表中把这些值作为百分数来绘

制。加一条零线作为第四个绘图,用来比较正表现或负表现值。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
28
EasyLanguage 对象自学课程(译)

Plot1(SymbolPerf , "Symbol Perf");

Plot2(BenchPerf , "Bench Perf");

Plot3(RelPerf , "Rel Perf");

Plot4(0);

右键点击指标文档,选择右键菜单底部的属性来访问指标属性对话框。选择刻度轴选项卡并

确认坐标轴设定为右侧坐标轴。

验证指标。

方法

方法是一个代码结构,这个代码结构包含了 EasyLanguage 文档本地的 EasyLanguage 语句。

方法在代码中被提及的方式和你在代码中提及函数的方式很像,但是因为它是本地的,它运

行得更快,并且允许你在分析技术或策略中直接向其他变量读取或写入。尽管方法与函数一

样,可以接受输入参数并返回一个值,一个不可返方法可以让你执行一系列语句而不要求返

回值,这使得一个方法可以像一些保留字一样独立地出现在代码中,而不需要将它赋值给一

个变量。下面是方法特征的概述:

 方法可以返回值

 方法可以有一个或多个参数

 方法可以修改标准的变量

 方法可以声明只在该方法内可见的本地变量

 方法通常比标准 EasyLanguage 变量要快

声明一个方法,要使用保留字 method 后接返回值类型,方法名称以及任何方法参数。方法

参数用括号括起来,用逗号分隔。即便没有参数,括号也是一定需要的。方法的主体包含一

个 begin/end 块,这个块中含有本地变量声明(如有)以及 EasyLanguage 语句。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
29
EasyLanguage 对象自学课程(译)

method void myMethod(int param1)

var: double localVar1, int localVar2

begin

{ EasyLanguage statements }

localVar1 = myObject.Close[0];

localVar2 = 10;

if param1<localVar2 then

plot1(localVar1);

end;

一个 void(不可返)的返回表明这个方法不返回值,空括号表明这个方法不需要参数。

当方法被调用时,方法内的代码被执行,而不必在每次分析技术或策略求值时执行。在下面

的例子中,当 Condition1(条件一)为真时,上述方法中的语句将被执行。这就像一个外

部函数;但是,这个方法对你的文档来说是本地的。当一段代码被调用多次但将它组织成一

个有名称的模块很有帮助时,方法通常会被使用。另外,方法会作为事件处理程序被使用,

且与对象的事件属性相关。

Value1 = 5;

If Condition1=True then

myMethod(Value1);

一个 EasyLanguage 文档的本地方法必须总是在 EasyLanguage 的 Input(输入)


,Vars(变

量),和 Arrays(数列)的声明之后并且在代码主体之前。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
30
EasyLanguage 对象自学课程(译)

事件

事件是指,当对象内一些值得关心的事发生时,对象向客户端程序(你的 EasyLanguage 代

码)提供通知的一种方法。事件最常见的用法之一是在程序图形控制中,例如一个按钮,当

用户点击按钮时程序收到通知。另一个例子是计时器控制在一段规定时间倒数到零时通知被

调用程序。下面是事件的一些特征:

 事件听取要发生或改变的事

 被触发后,事件调用事件处理方法

 事件处理方法内的代码被执行以处理一个事件

 在属性编辑器内,事件连接事件处理方法

但是,事件不需要仅仅被图形界面或计时器使用。很多 EasyLanguage 中的数据提供器组件

也支持事件并在对象相关的数据改变时提醒你,例如更新价格、仓位、或账户状态。在过去,

你也许必须要写一个轮询循环来寻找进来的数据中的变化,但是在对象事件的帮助下折可以

通过在分析技术或策略中添加事件处理方法来让它自动发生。

 事件处理程序

在 EasyLanguage 中,事件处理程序是当对象内一个相应事件发生时被调用的方法。在事件

处理方法里,你可以创造你自己的 EasyLanguage 语句来编写你的分析技术、函数或策略将

如何对一个事件作出反应。

要使一个事件处理方法可用,它必须与一个事件发生关联。在组件对象里,这可以通过使用

属性编辑器将方法与指定的事件相关联。例如,在一个 Timer(计时器)组件下,属性编辑器

内的 Event(事件)部分显示一个空白的 Elapsed 属性。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
31
EasyLanguage 对象自学课程(译)

双击 Elasped 将自动在 EasyLanguage 文档中创建一个事件处理方法,并将这个方法(这里

是 Timer1_Elapsed)与 Elapsed 时间相关联。现在,每当 Timer1 的 Elapsed 事件触发,你

向相关方法内添加的代码将被执行。如下所示,事件处理方法通常有一个 Sender 和 Args

参数。这些参数用来接收事件信息并且不该被用户编辑。

method void Timer1_Elapsed( elsystem.Object sender,

elsystem.TimerElapsedEventArgs args )

begin
{ Insert your EasyLanguage statements below }
end;

对组件来说,事件处理方法的名字通过使用属性编辑器与事件相关联。

对非组件对象来说,用下列格式在代码中给对象的事件属性指派事件处理方法的名称:

Object.EventName += Method_Name;

设计器代码
除了你使用 EasyLanguage 编辑器写的代码外,你的分析文档也可以包含关于每个组件的信

息,当一个组件被创建且属性被编辑好后该信息将自动帮你编好。该信息存在与一个特殊的

被称为设计器代码的只读页上,你可以通过代码编辑器的视图菜单访问。

设计器代码由系统创建,并每当你输入或改变一个组件的属性时在属性编辑器内更新。不能

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
32
EasyLanguage 对象自学课程(译)
直接用代码编辑器对它进行修改。

当你用属性编辑器创建一个事件,例如 Timer 对象的 Elapsed 事件,一个给组件事件指派事

件处理方法名称
(位于 EL 代码的主体部分)的 EasyLanguage 语句就被添加到设计器代码块。

timer1.elapsed += timer1_elapsed;

在上面的例子中,每当 Timer1 组件对象触发 Elapsed 事件,代码中的‘timer1_elapsed’方

法被调用,方法内的语句被执行。

目前来看,你不必去理解组件产生的设计器代码,但是它是一个很有趣的人资源,能够让我

们开始理解 EasyLanguage 对象是如何创建和操作的。

计时器

Timer(计时器)组件创造一个对象,它让你设置一个计时器,倒数规定的毫秒,并在时间

到期后调用事件处理方法。计时器可以被设置为每次到期后自动重新开始,这样事件处理程

序可以不断被调用。

◆课程例题#5

目标:
(Bar Countdown 指标)

 用工具箱组件创建一个计时器对象

 用属性编辑器创建一个事件

 在时间通知时运行一些 EasyLanguage 代码

指标:
‘$05_BarPcntLeft’

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
33
EasyLanguage 对象自学课程(译)
该指标只用一个 Timer 组件来设置一个每 1000 毫秒不断更新当日时间的计时器。1000 毫秒

=1 秒。

工作区:$05_BarPcntLeft

建立图表:

创建:一分钟图表

插入指标:$05_BarPcntLeft

组件和属性编辑器设置:

Timer1:

Interval : 1000 (在General分类下)

AutoReset: True " "

Enable: True " "

Elapsed: Timer1_Elapsed

指标练习#5:'$05_BarPcntLeft'

创建一个新指标并命名:
‘#05_BarPcntLeft’
。我们将用#命名惯例来将课程练习与课程可以

下载的案例(以$开头)区分开。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
34
EasyLanguage 对象自学课程(译)

点击代码编辑器窗口左侧的工具箱选项卡,双击 Timer 组件。默认名称 Timer1 将出现在代

码编辑器窗口底部的组件盘内。

现在,点击代码编辑器右侧属性选项卡,打开属性面板,确保 Timer1 在属性编辑器顶部是

被指定的组件。

在 Property(属性) 窗格 General 分类下,将 Interval(周期)设为 1000。这个值的单

位是毫秒,所以此时计时器被设为倒数一秒。在这个例子里,我们把 AutoReset 属性设为真,

这样计时器会每秒自动重置并重新倒数。另外,将 Enable 设为真,这样一旦分析技术应用

于分析窗口,计时器会开始运行。

接下来,通过点击 图标切换到 Event(事件)窗格下。你将会看到 Elapsed 列在 Event

(事件)列中,其值为空白。每当计时器倒数到 0,此时我们想调用事件处理方法,Elapsed

事件将被 Timer1 触发。双击事件名事件名称 Elapsed 来在代码编辑器内创建方法,并让新

的方法名添加进标题为 Value(值)的那一列中。

一个叫做 Timer1_Elapsed 的方法就被添加进你的文档了。记住,括号内事件处理程序的参

数自动生成,并且不该被用户移除或修改。你的 EasyLanguage 代码应该在 begin 和 end 语

句之间添加。

method void Timer1_Elapsed( elsystem.Object sender,

elsystem.TimerElapsedEventArgs args )

begin
{ Insert your EasyLanguage statements below }
end;

在 Timer1_Elapsed 方法语句上方,输入三个变量声明。第一个声明是 intrabarpersist

变量,它对当前 bar 的运行计时器事件的次数进行计数。这是一个 bar 内留存的变量,因为

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
35
EasyLanguage 对象自学课程(译)
它需要在每笔交易更新后保留每个新的值,而不是像普通变量一样被重置。第二个变量保存

最大计数器数值。第三个变量保存最后一个形成的 bar 的 bar 序号。

var: intrabarpersist iCounter(60), iMax(60), barnumb(0);

注意:记住变量声明语句总是被放在任何方法的上方。

在 Timer1_Elapsed 方法的 begin 和 end 语句中间,你将输入一个 if 语句,每当有一个计时

器事件这个语句就较少 iCounter 的值。你还将输入另一个 if 语句,它绘制 bar 计数器的柱

状图。

method void Timer1_Elapsed( elsystem.Object sender,

elsystem.TimerElapsedEventArgs args )

begin

If iCounter > 0 then

iCounter = iCounter-1;

If currentbar > barnumb then

PlotValues();

end;

添加另一个叫 PlotValues()的方法,当一个计时器事件发生时该方法被调用。第一张图

展示一个 bar 的剩余时间的百分比的柱状图。第二张和第三张图展示参考线来让指标保持

同样大小。

Method void PlotValues()

begin

plot1((iCounter/iMax)*100, "PctLeft");

end;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
36
EasyLanguage 对象自学课程(译)
代码最后一部分检查图中最后一根 bar 收盘没并且重置计数器和基于 bar 周期分钟数的最

大计数器数值。它也保存当前即将收盘的 bar 的序号,这样下一个图只在下一个 bar tick

之后被绘制出。

Once If Bartype = 1 then


iMax = Barinterval*60;

if LastBarOnChart then begin

if BarStatus( 1 ) = 2 then begin

plot1(0, "PctLeft");

iCounter = iMax;

barnumb = currentbar;

end;

end;

plot2(100, "100");

plot3(0, "zero");

验证指标。

AccountsProvider(账户提供器)
AccountsProvider 组件创建一个对象,这个对象让你指出你的实盘或模拟盘国信 TS 账号。

账户筛选属性被列在 AccountsProvider 对象的属性编辑器里,它被用来指明用户希望访问

哪个或哪些账户来获取数据。用规定的筛选条件,AccountsProvider 对象建立一个账户集

合,并将 Count(计数)属性设为集合内的元素数。根据默认设置,一个空白的 Accounts

(账户)筛选将从所有有效账户内收集账户信息。

Updated(更新)事件可以与 AccountsProvider 一起使用,这可以让你的代码在一个与任何

涉及到的账户相关的值发生改变时收到通知。当账户因为一个不在图表或网格中、但分析技

术或策略需要了解的交易代码而改变时,这尤为重要。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
37
EasyLanguage 对象自学课程(译)

在 EasyLanguage 代码中,通常会用 Count 属性在从账户集合中使用含序号的元素之前来确

定 AccountsProvider 是否找到账户。

AccountsProvider1 的 Account(账户)属性代表一个或多个账户(实际上是账户对象)的

集合,以及一系列可以从每个账户读取的属性。例如,要想引用集合中的第一个账户,可以

通过在提供器组件的 Account(账户)属性添加一个包含序数的方括号,此例为[0]。

AccountsProvider1.Account[0]

如果在属性编辑器内的 Accounts(账户)属性下仅指定一个账户号码,你的集合将包含

Account[0]的数据。但是,如果你要三个账户的数据(例如“SIM12345,SIM67890,SIM13579”)

第二个账号被引用为 Account[1],第三个为 Account[2]。下列语句从一个至少包含三个账

户的提供器里读取 Account[2](第三个账户)的 Unsettled 资金属性的值。

Value1 = AccountsProvider1.Account[2].UnsettledFund;

 集合

组件对象经常操纵项目的集合。例如,AccountsProvider 对象管理所有可使用账户(由账

户筛选规定)的集合。

下列语句显示集合中第一个账户(序号为 0)的账号:

Plot1(AccountsProvider1.Account[0].AccountID);

列于账户提供器的属性编辑器内的账户筛选属性被用来指明访问哪个或哪些账户。使用你指

明的筛选条件,账户提供器对象建立一个账户集合并将 Count(计数)属性设为集合元素数。

默认情况下,一个空白的账户筛选将收集所有有效账户的信息。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
38
EasyLanguage 对象自学课程(译)

 查询定义和帮助

有几种方法可以了解更多关于一个组件的属性和方法。例如在属性编辑器里,当你选择一个

组件属性,编辑器下方面板显示字典内属性的剪短说明。在描述窗格上方是一个写着 帮助

关于属性的链接,该链接将会指引用户去到组件所属类的帮助主题。帮助主题通常包含给定

类的一列属性、方法、事件和通向相关类和属性的链接。

在代码编辑器内,可以通过右键点击代码内提到的对象然后在右击菜单内选择 对象的定义

(D)...。这将直接引导你去对象类的帮助主题。

顺便说一句,如果右键单击属性名称,属性的定义...菜单项将带你去包含这个属性的类。

但是,需要留心一个属性可能与组件在不同的类中,因为很多属性从其他的类继承,并且它

们的定义会被包含在基类中。一个例子是.RTAccountNetWorth 属性,它从 AccountsProvider

组件中访问,但却是 Account 类的一个与组件的 Account[0]属性相关的成员。

◆课程例题#6

目标:
(账户损益指标)

 创建一个可以访问你权益类账户信息的对象

 使用 Count(计数)属性来检查是否有账户

 将提供器更名为一个更短的名字

指标:
‘$06_AccountPL’

本指标用一个 AccountProvider 组件访问特定权益类账户的值。账户的 Beginning-Day Net

Worth(首日净值)和 Real-Time Net Worth(实时净值)属性值的差值被计算出来并被绘

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
39
EasyLanguage 对象自学课程(译)
制成直方图。如果账户净值大于 0,图的颜色是绿色;如果净值小于 0,则为红色。

工作区:$06_AccountPL

建立图表:

创建:含 5 日价格数据的 5 分钟图

插入指标:$06_AccountPL

组件和属性编辑器设置:

AccP:

Name: AccP (改变组件名)

Accounts: iAccounts1 (作为输入值添加)

Updated: AccP_Updated

指标练习#6:
‘$06_AccountPL’

创建一个新指标,将它命名为‘#06_AccountPL’
。我们将用#命名惯例来将课程练习与课程

可以下载的案例(以$开头)区分开。

点 击 代 码 编 辑 器 左 侧 的 工 具 箱 选 项 卡 , 双 击 AccountsProvider 组 件 。 默 认 名 称

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
40
EasyLanguage 对象自学课程(译)
AccountsProvider1 组件将出现在代码编辑窗口底部的组键盘。

现在,点击代码编辑器右侧的属性选项卡,打开属性面板并确认 AccountsProvider1 是属性

编辑器顶部被选定的组件。

在属性编辑器顶部,选择 AccountsProvider1,找到 Name 属性,将值改为 AccP。这缩短了

组件对象的名称,这样写代码时可以少打点字。但是组件对象的特征和它的属性保持不变。

注意改后的名字现在出现在代码编辑器底部的组键盘内。

接着,点击 Accounts 属性右侧的空输入框,再点击属性编辑器顶部的 图标。单词

iAccounts1 将出现在 Accounts 旁。另外,你将会看到下面的一行被插入到 EasyLanguage

代码的顶部。

Input: string iAccounts1( "" );

在引号中间,输入 AccP 组件对象将会使用到的模拟账户。


当你索取一个 AccP 的账户属性时,

这就是它引用的账号。

Input: string iAccounts1( "SIM00000" );

声明另一个输入来指明账户的损益警告线。

Input: PLAlert( 500 );

我们声明一个变量来保存计算出来的账户利润。

var:AccountPL(0);

接下来,点击 图标切换到事件窗格。你将会看到 Updated 列在事件列中,值为空白。每

当你账户中任何值发生变化时,Updated 事件将被 AccountsProvider1 对象触发,并将调用

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
41
EasyLanguage 对象自学课程(译)
事件处理方法。双击事件名 Updated,创建一个新事件处理方法名。

一个名为 AccP_Updated 的事件处理方法自动添加到你的文档中。

method void AccP_Updated( elsystem.Object sender,

elsystem.TimerElapsedEventArgs args )

begin
{ Insert your EasyLanguage statements below }
end;

将 PlotValues()替换 begin 语句后自动生成的评论,PlotValues()可以调用一个方

法。

method void AccP_Updated( elsystem.Object sender,

tsdata.trading.AccountUpdatedEventArgs args )

begin

PlotValues();

end;

现在,创建一个每当账户更新事件发生时就计算并绘制账户损益的方法。它只会在图形最后

一根 bar 绘制,并且当提供器有收集到指定账户的数据时绘制。

Method void PlotValues()

begin

If LastBarOnChart and AccP.Count > 0 then begin

AccountPL = AccP.Account[0].RTAccountNetWorth –

AccP.Account[0].BDAccountNetWorth;

plot1(AccountPL,"AccountPL");

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
42
EasyLanguage 对象自学课程(译)
下面一系列语句,在损益为零时将净值绘图设为灰色,大于零时为绿色,小于零时为红色。

setplotcolor(1,LightGray);

If AccountPL > 0 then

setplotcolor(1,green);

If AccountPL < 0 then

setplotcolor(1,red);

end;

end;

plot2(0,"Zero");

plot3(PLAlert);

plot4(-PLAlert);

在文档属性里的图形式样选项卡上将 AccountPL 图的类型改为直方图。

验证指标。

注意:计算期货账户的账户损益的代码是:

{ AccountPL = AccP.Account[0].RTAccountEquity -

AccP.Account[0].BDAccountEquity; }

当你将这个指标应用于图表时,你应该检查输入设置并根据图中代码相应地改变账号和利润

预警值。例如,如果你绘制一个权益类交易代码,你应该将 iAccount1 的输入改成你的模

拟权益账号,将利润预警根据当前账号的净值做更改。

筛选属性(TokenList)
很多情况下,属性编辑器下的 Filter 部分内包含的属性期待一个含有逗号分开的值的字符

串,这就是 Token List。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
43
EasyLanguage 对象自学课程(译)

例如,PositionProvider 组件包含三个筛选(filter)属性,这些筛选属性用来缩小提供

器(provider)可能仓位的选项。假设你想为一组规定的交易代码收集仓位信息。设置 Symbol

(交易代码)属性来收集你账户内国信证券(002736),平安银行(000001)和中国联通(600050)

的仓位信息:

Accounts

Symbols "002736.SZ,000001.SZ,600050.SH"

Types

PositionProvider 对象返回你指定的三个交易代码的仓位,但不返回账户内其他代码的仓

位。另外,Types 和 Accounts 属性用来指明三支交易代码的仓位种类和所在账户也会返回

结果。但是,你可以轻松添加一列指定账户或仓位种类,结果将局限于只包含符合所有筛选

条件的那几个项目。例如,下面的筛选设置将找到两个账户中指定交易代码的多仓。

Accounts "123456,234567"

Symbols "002736.SZ,000001.SZ,600050.SH"

Types "long"

除了输入指定代码的名称,你也可以输入保留字 symbol(无括号),让代码筛选返回当前图

内或网格内的代码的仓位:

Symbols symbol

+=加等号赋值运算符
与对象一起新加入 EasyLanguage 的还有一些面向对象编程中常用的运算符。其中一个运算

符可以将一个表达式的的值加给一个变量,并不用在赋值语句两侧重复变量名。也可以说,

这个表达式加给结果。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
44
EasyLanguage 对象自学课程(译)

例如,下面的表达式:

result += 1

以及接下来的表达式是一样的

result = result + 1

除了 result 在第一个表达式中只指明并求值一次。下面,你将会看到这个运算符在时间

处理器的名称被复制给或加给一个事件属性。

PositionsProvider(仓位提供器)
PositionsProvider 组件创建一个能够让你引用一个过一列指定交易代码的仓位值的对象。

你也可以按照特定账户或仓位类型筛选这些对象。按照指定的 Symbols(交易代码),

Accounts(账户)和 Types(仓位类型)筛选条件,PositionsProvider 建立一个满足条件

的 集 合 , 并 将 Count 属 性 设 为 集 合 中 元 素 的 个 数 。 如 果 不 指 明 任 何 筛 选 条 件 ,

PositionsProvider 将建立一个包含所有代码、账号和类型的仓位的集合。

一个与 PositionsProvider 相关的 Updated 事件允许代码在引用的任何仓位相关的值发生变

化时收到通知。当仓位因为一个不在图表或网格中、但分析技术或策略需要了解的交易代码

而改变时,这尤为重要。

在代码中,通常会在尝试使用仓位集合内含序号的元素之前,用 Count 属性来判断

PositionsProvider 能否找到仓位。

例如,下面的代码展示了一些 PositionsProvider 集合内第一个仓位元素的仓位属性:

Plot1(PosProvider1.Position[0].OpenPL, "P/L");

Plot2(PosProvider1.Position[0].Quantity, "PosSize");

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
45
EasyLanguage 对象自学课程(译)
Plot3(PosProvider1.Position[0].AveragePrice, "AvgPx");

Plot4(PosProvider1.Position[0].InitialMargin, "I Margin");

Plot5(PosProvider1.Position[0].RequiredMargin, "R Margin");

◆课程例题 #7

目标:
(Position Value Indicator)

 用工具箱组件创建一个能读取仓位信息的对象。

 用属性编辑器初始化组件属性。

 绘制一条交易代码的仓位的值

指标:
‘$07_PosValue’

这个指标用 PositionsProvider 组件访问一条雷达屏或图表内交易代码的仓位的信息。如果

无仓位,将会显示“0”。

工作区:$07_PosValue

建立雷达屏窗口:

创建:任意周期

插入指标:$07_PosValue

组件和属性编辑器设置:

PosP:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
46
EasyLanguage 对象自学课程(译)

Name: PosP (改变组件名)

Symbol: symbol (在Filters分类下)

Updated: PosP_Updated

指标练习 #7:‘$07_PosValue’

创建一个新指标,将其命名为:#07_PosValue.

点 击 代 码 编 辑 窗 口 左 侧 的 工 具 箱 选 项 卡 , 双 击 PositionsProvider 组 件 。 默 认 名 称

PositionsProvider1 将出现在代码编辑器窗口底部的组件盘内。

现 在, 点击代 码编 辑器右 侧的 属性选 项卡, 打开 属性 面板并 确保在 属性 编辑 器顶部

PositionsProvider1 是指定组件。

将组件的 Name 属性改成较短的名称 PosP。

在 Filters 分类下,将 Symbol 属性设为保留字 symbol,这样提供器(provider)只会返回

当前交易代码的仓位。不要在 Accounts 和 Type 属性后填写任何内容,


这样提供器
(provider)

将在所有相关账户内寻找当前代码(symbol)
,例如不同的信用账户或现金账户。

现在你可以将 PosP 组件作为一个对象来使用,通过它访问当前图表或网格内的交易代码的

仓位信息。

接下来,通过点击 图标切换到属性编辑器的事件窗格。
你将看到 Updated 列在事件列下,

值为空。双击事件名称 Updated 来在 EasyLanguage 文档中创建一个事件处理方法,让新方

法的名字与属性相关。

一个名称为 PosP_Updated 的方法被添加进文档中。记住,括号内的事件处理程序的参数是

自动生成的,不应该被用户移除或修改。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
47
EasyLanguage 对象自学课程(译)

method void PosP_Updated( elsystem.Object sender,

tsdata.trading.PositionUpdatedEventArgs args )

begin

PlotValues();

end;

在 PosP_Updated 方法的 begin 和 end 语句中间插入一个 PlotValues()的调用。

此指标不要求输入值或变量。

接下来,创建 PlotValue()方法。

Method void PlotValues()

Begin

在 begin 之后第一个语句是一个 if 条件,读取组件的 Count 属性来检查当前交易代码是否

有仓位。如果当前交易代码不存在仓位,网格窗内它的值将是空白。如果有仓位,指标将绘

制三条正值。

if (PosP.Count > 0) then

begin

Plot1(PosP.Position[0].MarketValue, "Mkt Value");

Plot2(PosP.Position[0].Quantity, "Qty");

Plot3(PosP.Position[0].OpenPL, "P/L");

如果是正值,OpenPL 的颜色为绿色,如果是负值,OpenPL 为红色。

if PosP.Position[0].OpenPL >= 0 then

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
48
EasyLanguage 对象自学课程(译)
SetPlotColor(3,Green)

else

SetPlotColor(3,Red);

end

else

begin

如果当前代码无仓位,下面的代码将显示‘0’。

Plot1(0, "Mkt Value");

Plot2(0, "Qty");

Plot3(0, "P/L");

end;

end;

验证指标。

该指标为网格分析窗口设计的,例如雷达屏,并且会显示代码的任何仓位。但是,它也会在

图形的子图绘制仓位值,在这里指标的线用来读 Quantity,Market Value,以及 P/L

值最有用。

方法变量
在函数里声明变量,该变量只能在函数内使用。与之类似,你可以在一个方法内声明变量,

该变量是本地的,不能从方法以外访问。这些本地变量在方法每次运行时创建,在代码执行

过后消失。当对事件处理程序更新的值进行临时计算,或者像计数器以及下标这种只在方法

内需要的值时,本地变量很有用。你可以在一个方法内将本地变量与分析技术变量混合起来

使用且两个都可以被包含在计算中,但是,在退出方法后只有标准的分析技术变量的值会被

保存。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
49
EasyLanguage 对象自学课程(译)
方法内的本地变量声明语句与你已了解的标准变量声明语句很相似。但是,有两个重要的不

同:1)一个本地变量语句必须总是在变量名前面指定变量类别(int,double,bool 或

string);2)你不能在变量名称后给本地变量指定初始值。而且,由于你不能指望本地变量

有初始值,一个好想法就是在方法代码中 begin 和 end 之间,于使用本地变量进行计算前给

本地变量赋值。

method void myMethod()

var: int myIndex, double priceTotal;

begin
{EasyLanguage statements and calculations}
end;

变量类型复习:
Int = Integer(整数)- 没有小数点后数值的正数或负数
Double = Double Float(双精度浮点数)-有小数点后数值的正数或负数

Bool = Boolean(布尔值)- 真或假的条件

String = Text(文本)- 字母数字序列

NumToStr(num,dec)
用保留字 NumToStr 可以将数值转化为字符串来绘图。当你希望在数字的文本变体中控制

小数点后位数时,这很有用。

例如,如果你希望绘制 Order(委托)集合中第一个委托单集合的 LimitPrice 属性并且

只显示小数点后两位,使用 NumToStr 保留字,引用数字属性值作为第一个参数,指定小

数点后位数作为第二个参数。

Plot1(numtostr(ordersprovider1.Order[0].LimitPrice,2),"Limit");

注意,在网格应用中将数值转换为字符串意味着该列中所得到的值将不会按数值大小排序,

并且小数点后位数设置将不会被应用。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
50
EasyLanguage 对象自学课程(译)

◆课程例题 #8

目标:
(Position 和 Account Value 指标)

 结合不同组件

 使用工具箱组件,创建读取仓位和账户信息的对象

 使用属性编辑器,初始化组件属性

指标:
‘$09_PosValueAcct’

本指标使用 PositionProvider 和 AccountProvider 计算并以占账户总量百分比的形式显示

权益仓位的市值。如果没有仓位将显示‘0’

工作区:$08_PosValueAcct

建立雷达屏窗口:

创建:任意周期

注意:列出想监视仓位的交易代码

插入代码: $09_PosValueAcct

组件和属性编辑器设置:

PosP:

Name: PosP (改变组件名)

Symbol: symbol (在Filters分类下)

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
51
EasyLanguage 对象自学课程(译)

Updated: PosP_Updated

AccP:

Name: AccP (改变组件名)

指标练习 #8:‘$08_PosValueAcct’

这 个 例 子 , 我 们 将 从 课 程 例 题 #7 里 创 建 的 #07_PosValue 指 标 开 始 。 将 它 另 存 为

#08_PosValueAcct。

因为 PosP 组件已经是之前指标的一部分,你不需要再添加。但是,如果你从头开始的话,

需要双击工具箱内的 PositionsProvider 组件,并按照上面的组件和属性编辑器设置将

Symbol 和 Updated 事件用属性编辑器进行设置。

点击代码编辑器窗口左侧的工具箱选项卡,双击 AccountsProvider 组件。默认名称

AccountsProvider1 就会出现在代码编辑器窗口底部的组件盘内。

现在,点击代码编辑器窗口右侧的属性选项卡,打开属性面板并确保在属性编辑器顶部

AccountsProvider1 是被指定的组件。

将组件的 Name 属性改为更短的名称 AccP。

需要提醒的是,灰色部分的代码是从练习#7 中复制过来的。

method void PosP_Updated( elsystem.Object sender,

tsdata.trading.PositionUpdatedEventArgs args )

begin

PlotValues();

end;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
52
EasyLanguage 对象自学课程(译)

你将添加的第一行 EasyLanguage 代码将会是在方法标题和 begin 之间的变量声明。你将声

明两个本地变量,它们只在 PlotValues 方法内可见。记住,本地方法变量声明需要你指定

类型而且不接受默认值。

第一个变量用来计算当前代码仓位所占账户净值的百分比,第二个将会用来保存该仓位的

AccountID(账户号)。

Method void PlotValues()

var: double PcntOfAccount, string PosAccountID;

begin

if (PosP.Count > 0) then

begin

Plot1(PosP.Position[0].MarketValue, "Mkt Value");

Plot2(PosP.Position[0].Quantity, "Qty");

Plot3(PosP.Position[0].OpenPL, "P/L");

if PosP.Position[0].OpenPL>=0 then

SetPlotColor(3,Green)

else

SetPlotColor(3,Red);

下面的代码先通过检查 Accp 组件的 Count 属性来检查是否有账户可用,然后计算并以占

整个账户百分比的方式显示当前仓位市值。注意我们从 Position Provider(仓位提供

器)得到当前仓位的账户号并用账号来引用实时净值数据。

PosAccountID = PosP.Position[0].AccountID;
If AccP.Count>0 then begin
Value1 = PosP.Position[0].MarketValue;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
53
EasyLanguage 对象自学课程(译)
Value2 = AccP.Account[PosAccountID].RTAccountNetWorth;

PcntOfAccount = Value1/Value2;

Plot4(numtostr(PcntOfAccount*100,3)+" %","% of Acct");

end;

end

else

begin

Plot1(0, "Mkt Value");

Plot2(0, "Qty");

Plot3(0, "P/L");

Plot4("0","% of Acct");

end;

end;

验证指标。

这个指标被用于网格分析窗口中,如雷达屏,并会展示交易代码的仓位以及根据市值算出的

每个仓位所占指定账户的百分比。

ToString()
ToString()方法是将对象属性值转换为字符串的简便方法。这个方法经常被使用,它可以让

你在绘图中显示一个属性的数值或日期值,或者使用打印语句时不必担心属性类型。

例如,下面的绘图语句将产生一个运行错误,因为 Plot1 不知道如何显示所引用的

CurrentTime 属性,该属性为 DateTime 对象类型:

Plot1(elsystem.datetime.CurrentTime);

但是,在属性引用后面添加.toString()将自动把 CurrentTime 属性转化为一个可显示的字

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
54
EasyLanguage 对象自学课程(译)
符串,这个字符串可以在绘图中被绘制并可以用于打印语句中。

Plot1(elsystem.datetime.CurrentTime.toString());

OrdersProvider
OrdersProvider 允许用户根据指定筛选条件从一列规定的 TS 账户中使用实时和历史委托单

信息。这个信息与交易管理器内委托单选项卡上的信息很相似。Order 类描述一个指定委托

单可用的属性 (见下)。

你也可以通过筛选使结果中只包含特定账户、时间段、委托单编号以及委托单状态(例如,

已接收,已执行,已拒绝等)。通过使用用户对交易代码、账户、起止日期、委托单状态进

行指定的筛选条件,OrdersProvider 建立一个 Order 对象的集合,这个集合符合用户的条

件并且将 Count 属性设置为集合中的元素数。如果不指定任何筛选条件,OrdersProvider

将建立一个包含所有交易代码、账户、时间范围和委托状态的集合。

一个与 OrdersProvider 相关的 Updated 事件让你的代码在任何与所引用的委托相关的值发

生变动时接收到通知。例如,OrdersProvider 的特定实例的状态发生任何改变,都将触发

一个通知时间,这样你可以绘制改变的状态。当一个委托单因为一个交易代码发生改变,该

交易代码不在图表或网格中但你希望在分析技术或策略里了解该代码的信息时,这也很有用。

在尝试使用委托单集合内的标序元素之前使用 Count 属性来判断 OrdersProvider 能否找到

委托单,一直都是一个好想法。

例如,以下代码显示 OrdersProvider 集合内的第一个元素的多种 Orders 属性:

Plot1(OrdersProvider1.Order[0].AvgFilledPrice, "AvgFillPx");

Plot2(OrdersProvider1.Order[0].FilledQuantity, "FillQTY");

Plot3(OrdersProvider1.Order[0].State.ToString(), "State");

Plot4(OrdersProvider1.Order[0].LimitPrice, "LimitPx");

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
55
EasyLanguage 对象自学课程(译)
Plot5(OrdersProvider1.Order[0].Duration, "Duration");

注意:委托单集合按时间顺序排序,从 0(最新)到最早。

◆课程例题 #9

目标:(Order Status 指标)

 使用工具箱组件,创建一个读取你委托单信息的对象

 使用属性编辑器,初始化组件属性

 绘制委托单的数量,委托类型,和委托单状态

指标:‘$09_OrderStatus’

本指标使用一个 OrdersProvider 组件访问从图表或雷达屏提交的最后一个交易代码的信息。

如果一个交易代码没有任何下单活动,雷达屏的行将会是空白。

工作区:$09_OrderStatus

建立雷达屏窗口:

创建:任何周期

插入指标:$09_OrderStatus

组件和属性编辑器设置:

OrdersProvider1:

Symbols: symbol (在Filters分类下)

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
56
EasyLanguage 对象自学课程(译)

Updated: OrdersProvider1_Updated

指标练习 #9:‘$09_OrderStatus’

创建一个新指标并命名为:“#OrderStatus”。

点 击 代 码 编 辑 器 窗 口 左 侧 的 工 具 箱 选 项 卡 , 双 击 OrdersProvider 组 件 。 默 认 名

OrdersProvider1 将出现在代码编辑器窗口底部的组件盘内。现在,点击代码编辑器窗口右

侧的属性选项卡,打开属性面板,确认在属性编辑器顶部 OrdersProvider1 是被指定的组件。

将组件的 Name 属性改为更短的名字 OrdP。

在 Filters 分类下,将 Symbol 属性设置为保留字 symbol,这样提供器(provider)只会返

回当前交易代码的委托单状态信息。将 Accounts,Status 和 Order 属性留为空白,这样提

供器(provider)在所有账户内寻找任何当前交易代码的委托单。现在你就可以在代码中把

OrdP 组件作为一个对象使用来在网格或者图表中访问当前交易代码的仓位值。

接下来,点击 图标,切换到属性编辑器的事件窗格。你可以看到 Updated 列在事件列中,

没有值。双击事件名 Updated,这样在 EasyLanguage 文档中创建一个事件处理方法并让新

方法名与属性相关联。

一个叫 OrdP_Updated 的方法就被加进你的文档中了。就像之前提到的,事件处理程序括号

内的参数是自动生成的,不应被用户修改或移除。

给 PlotValue()插入一个方法调用。

method void OrdP_Updated( elsystem.Object sender,

tsdata.trading.OrderUpdatedEventArgs args )

begin

PlotValues();

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
57
EasyLanguage 对象自学课程(译)
end;

现在,按照如下代码创建 PlotValues(),包含一个可以绘制从 Order[0]里选定委托单状

态属性,属性代表集合内第一个和最近一个委托单。.Count 属性表示当前代码的实际委托

单状态项目数,但是,在这个例子中,我们只对第一个感兴趣。同样,注意在好几个绘图的

属性名后使用.tostring()方法,这可以将非文本值作为字符串显示在绘图状态行上。

Method void PlotValues() begin


If OrdP.Count>0 then begin

plot1(OrdP.Order[0].EnteredQuantity,"Quantity");

plot2(OrdP.Order[0].type.tostring(),"Type");

plot3(OrdP.Order[0].LimitPrice,"Limit Price");

plot4(OrdP.Order[0].state.tostring(),"State");

end;

end;

PlotValues();

验证指标。

该指标被用于网格分析窗口上,例如雷达屏,并会显示交易代码的任何下达的委托单。

LastBarOnChart
LastBarOnChart 函数被用来判断当前被评估的 bar 是否是图表中最后一根 bar。有时会写

需要创建并发送委托单的条件、这样它们就按实时价格条件而不是历史价格条件下单,这时

就很有用。

If LastBarOnChart and OrderCondition=true then


Orderticket1.send();

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
58
EasyLanguage 对象自学课程(译)
在这个例子中,一个为真的 OrderCondition 将只会在当前 bar 上发送委托单。

分析技术 - Initialized 和 Uninitialized 事件


当一个分析技术或策略被应用于你的图表或网格应用程序时,它可以自动触发初始化事件

(Initialized Event),该事件会在初次运行 EasyLanguage 代码时调用一个指定的事件处

理方法。类似地,一个未初始化事件(Uninitialized Event)在一个分析技术结束时被触

发,例如当它被从一个图标中移除或当平台关闭时。当你希望在分析技术中设置一些条件,

这些条件在分析技术第一次运行时被执行一次,且在分析技术的其他部分在该条 bar 上运行

之前,或者在分析技术关闭前最后执行,这些情况下会很有用。你可以通过从属性编辑器顶

部的下拉列表中选择 Analysis Technique 然后点击 图标切换至事件窗口来向任意分析

技术添加初始化事件或未初始化事件。在事件列你会找到一对事件, Initialized 和

Uninitialized。双击任意一个名字,将自动在你的 EasyLanguage 文档中创建一个名为

AnalysisTechnique_Initialized 或 AnalysisTechnique_UnInitialized 的事件处理方法

并会在属性编辑器内的 Value 列向那个方法中插入一个引用。只要将你的 EasyLanguage 语

句加入到新的事件方法,它们就会在每次分析技术或策略被加载或被卸载时执行一次。

IntrabarPersist
IntrabarPersist 是一个变量声明关键词,它用来创建可以每笔交易进行存储并更新值的

EasyLanguage 变量或数组。当你想对 bar 内每笔交易进行计数或保存可能在一根 bar 内改

变的条件的状态时,这尤其有用。默认情况下,变量值在每根 bar 的收盘时被保存。

Var: IntrabarPersist tickcount(0);

tickcount = tickcount + 1;

在这个例子中,变量 tickcount 可以数每根 bar 的全部交易笔数。

OrderTicket
OrderTicket 组件为指定交易代码产生 order ticket,并将委托直接通过你的 EasyLanguage

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
59
EasyLanguage 对象自学课程(译)
分析技术或策略发送到市场上。OrderTicket 对象支持大多数 order 参数,这些参数在从国

信 TradeStation 的下单栏手动下单时可用。就像手动下单,所有通过 OrderTicket 创建的

委托的状态将会和普通委托一起显示在交易管理器的委托单选项卡下。

设置一个 OrderTicket 组件通常按照与之前组件相同的步骤进行。首先用属性编辑器填入值。

一些属性,例如 Order Type(委托类型)和 Duration(委托期限)被设为默认值。其他的,

例如 Symbol(交易代码)、Symbol Type(交易资产)、Account(账户)、Quantity(数

量)和 Market Action(交易指令,比如 buy,sell 等)必须由用户输入来创建一个有效的

委托。当全部属性被设置好,在你的 EasyLanguage 代码中添加一个语句来用组件对象的

Send()方法进行下单,如下所示:

OrderTicket1.Send() ;

除了使用属性编辑器,当你想在发单前通过编程来决定交易代码、交易数量、交易方向等时,

你也可以直接在 EasyLanguage 代码里设置 OrderTicket 属性。无论哪种情况,为指定组件

调用 Send()方法将发送委托单。

OrderTicket1.Symbol = “XYZ”
OrderTicket1.Quantity = 200;

OrderTicket1.Action = tsdata.trading.orderaction.Buy;

OrderTicket1.Send() ;

 激活下单对象

为了避免从含有 OrderTicket 或其他 order 组件的分析技术或策略中的意外下单,你必须特

别地给每个将用来发单的分析技术或策略激活下单。在 EasyLanguage 可以产生委托单前,

通过进入每个分析技术或策略的设置-通用选项卡并勾选 Enable order placement objects

设置(选项卡中部)可以实现激活。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
60
EasyLanguage 对象自学课程(译)

注意:如果没有勾选并且指标试图发出委托单,一个运行错误将会出现。

◆课程例题 #10

目标:(市场委托单指标)

 创建一个 order ticket

 只在最后一根 bar 发出一笔委托单

 激活指标的下单对象设置

指标:‘$10_MarketOrder’

这个例子使用一个 OrderTicket 组件,根据一个简单的最低价或最高价的价格目标下单规则

下一个 Buy 市价单。一旦一笔委托发出,order active status flag 将被设置为 false。重

新加载指标会把指标重置来发送另一笔委托。

警告:这个指标将产生一个市价单——确保你没有登录实盘账户。该指标应该应用于虚拟

盘。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
61
EasyLanguage 对象自学课程(译)

工作区:$10_MarketOrder

建立图表:

创建:1 分钟周期图

刻度轴:与标的数据相同

插入指标:$10_MarketOrder

组件和属性编辑器设置:

OrderTicket1:

Symbol: symbol (输入保留字)

Account: iAccounts1 (将默认账户作为输入值添加)

Quantity: iQuantity1 (将想要的数量作为输入值添加)

Action: Buy

Type: Market

AnalysisTechnique:

Initialized: AnalysisTechnique_Initialized

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
62
EasyLanguage 对象自学课程(译)

指标练习 #10:‘$_MarketOrder’

创建一个新指标并命名为:‘#10_MarketOrder’。

点击代码编辑窗口左侧的工具箱选项卡,双击 OrderTicket 组件。默认名 OrderTicket1 将

出现在代码编辑器窗口底部的组件盘。

现 在, 点击代 码编 辑器右 侧的 属性选 项卡, 打开 属性 面板并 确保在 属性 编辑 器顶部

OrderTicket1 是被指定的组件。

在 Filters 分类下,将 Symbols 属性的值设置为保留字 symbol,这样提交的委托单就是当前

交易代码的委托了。

就像我们在前一个例子里做的一样,我们把账号作为一个输入值。在属性名 Account 旁边,

输入你的账号。然后,点击属性编辑器顶部的 图标,将其作为一个输入值。单词

iAccount1 将在属性编辑器内出现在 Account 旁,而且你将会看见下述代码被插入你的

EasyLanguage 代码顶部。这个输入值将会成为 OrderTicket1 组件的默认账号。接下来的几

个例子中,请再次检查当例题中产生委托单时你所使用的是模拟账号。

Input: string iAccount1( "SIM00000" );

还是在属性编辑器中,给这个模拟委托单输入默认 Quantity(数量)10000。与之前一样,

在属性编辑器顶部点击 图标,创建一个名为 iQuantity1 的输入值,它也会被添加到你

的代码中。

Input: int iQuantity1( 100000 );

在属性编辑器内,使用顶部的下拉列表,选择 Analysis Technique。点击 图标,切换到

事件窗格。你将看到事件列下的 Initialized,它的值为空白。双击事件名 Initialized 可

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
63
EasyLanguage 对象自学课程(译)
以在 EasyLanguage 代码中创建一个事件处理方法并让新的方法名与属性相关联。我们很快

就会向方法中添加代码。

method void AnalysisTechnique_Initialized( elsystem.Object

sender,

elsystem.InitializedEventArgs args )

begin
{ Insert your EasyLanguage statements below }
end;

现在你可以在代码中将 OrderTicket1 组件作为一个对象使用,在网格或图表中为当前代码

发出市价单。

在 EasyLanguage 代码中,让我们再加入一个当指标初次运行时代表委托单是否活跃的输入

值。

Input: OrderActive(True);

接下来我们为将在产生委托单的下单规则中用到的高价格目标和低价格目标声明变量。同样,

我们将创建一个 intrabarpersist 变量,该变量将允许我们控制下单规则什么时候激活

并允许委托单只被发送一次。

Vars: double HiTarget( 0 ), double LoTarget ( 0 ),

intrabarpersist AllowTradeFlag( True );

在 AnalysisTechnique_Initialized 方法中,我们首先通过使用保留字 Category 将要下单

的交易代码的资产类型(股票,期货)设置为当前交易代码的类型。然后我们将

AllowTradeFlag 变量的初始值设置为输入值 OrderActive 的值并在之后将 AllowTradeFlag

重置,这样一个委托单只被下单一次。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
64
EasyLanguage 对象自学课程(译)
method void AnalysisTechnique_Initialized( elsystem.Object

sender, elsystem.InitializedEventArgs args )

begin

OrderTicket1.SymbolType = Category;

AllowTradeFlag = OrderActive;

end;

创建一个绘制指标的值的方法。注意该方法中的绘制语句只有在方法 PlotValues()被调用

时执行。

Method void PlotValues() begin


Plot1(HiTarget,”High Target”);

Plot2(LoTarget,"Low Target");

Plot3(AllowTradeFlag.tostring(),"Active");

end;

在这个例子中,高价和低价目标根据前三根 bar 的最高价和最低价计算。这样我们的例子可

以在应用指标后迅速得到委托单条件。

HiTarget = HighestFC(High, 3)[1];

LoTarget = LowestFC(Low, 3)[1];

添加下列语句来在图表的每个 tick 上绘制值。

PlotValues();

通过接下来的代码,当现在的价格到达高价或低价价格目标并且当 AllowTradeFlag 变量的

值 在 图 表 最 后 一 根 bar 为 真 时 , 委 托 单 条 件 将 被 执 行 。 在 begin 后 的 语 句 用

OrderTicket1.send()方法下单。接下来的语句将 AllowTradeFlag 变量重置为 False,这样

直到图表刷新之前不会再下其他单。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
65
EasyLanguage 对象自学课程(译)

If ( ( Close <= LoTarget OR Close >= HiTarget ) AND

( LastBarOnChart AND AllowTradeFlag ) ) then begin

OrderTicket1.send();

AllowTradeFlag = False;

end;

验证指标。

打开图表并插入指标。

从图表中,打开设置#10_MarketOrder 对话框,选择常规选项卡。xxxx 勾选框需要在下单

前被选中,这样委托单才可以通过 EasyLanguage 代码产生。这个设置只在指标还应用于图

表时有效。如果删除指标之后再加载,你需要再次选中勾选框。

 声明对象变量

到目前为止,我们用的对象都是通过双击组件自动生成的。正如我们之前看到的,用来创建

并设置组件对象的 EasyLanguage 代码被附加在你的分析技术中的一个被称为“设计器生成

的代码”的隐藏代码块中,这个隐藏代码块可以通过代码编辑器的视图菜单访问。

例如,让我们看看使用 OrderTicket 组件的$10_MarketOrder 的“设计器生成的代码”。这

是头几行代码:

{ Components declaration (Designer generated code) }

var: tsdata.trading.OrderTicket OrderTicket1( NULL );

这 里 包 含 了 一 个 tsdata.trading.OrderTicket 类 型 的 变 量 声 明 , 该 变 量 名 为

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
66
EasyLanguage 对象自学课程(译)
OrderTicket1,默认值为‘NULL’。这个名字应该很熟悉,因为它是我们在组件编辑器

内设置的组件对象的名称,并且我们调用它来发单。不论是“设计器生成的代码”为你创建

的,还是你直接在分析技术代码中添加的,每个对象变量看起来都很相似,都是对象类型后

跟对象名称和一个初始值‘NULL’。

在下面的例子中,我们将用一个 Order 对象来跟踪一个委托单的状态。下面是一个可以让

你追踪一个 Order(委托单)的对象变量的变量声明:

Var: tsdata.trading.Order myOrder(null);

在本课程的后面,你将声明其他允许你创建并引用你自己的非组件对象的对象变量。

 跟踪 Order Ticket 的委托单状态

要跟踪一个委托单的状态,保存发出委托单实例到一个 Order 对象变量并创建一个事件处理

方法来自动通知指定委托单的任何状态的变化。下面描述了跟踪用 OrderTicket 发送的指定

委托单的状态所需要的步骤:

{ declare an Object variable named myOrder to hold an instance of

an Order object }

Var: tsdata.trading.Order myOrder(null);


{ method to handle Order update events }
Method void OrderStatusUpdate(elsystem.Object sender,

tsdata.trading.OrderUpdatedEventArgs args)

begin

Plot2(myOrder.State);

end;

{ copy the sent order to the object variable myOrder as an object

instance }

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
67
EasyLanguage 对象自学课程(译)
myOrder = OrderTicket1.Send();

{ associate the event handler method with the myOrder object }

myOrder.Updated += OrderStatusUpdate;

BracketOrderTicket
BracketOrderTicket 组件产生一个 bracket OCO 委托单,它由指定交易代码的两笔相同委

托方向(买,卖)的委托单组成,并且将组合起来的 OCO 委托从你的 EasyLanguage 分析技

术直接发单到市场。BracketOrderTicket 组件支持大部分从 TradeStation 下单栏的 OCO 按

钮手动下单时可用的委托单参数。

设置一个 BracketOrderTicket 组件通常遵循之前组件的步骤。首先用属性编辑器填入基本

的委托单值,例如 Symbol,Symbol Type(资产类型)


,Account,Quantity,和 Order Action

(例如买、卖等)
,这些都是创建一个有效委托单所需要的。另外,你需要指明 TargetType

和 ProtectionType 的限价和止损价。

当 所 有 属 性 被 设 置 好 后 , 通 过 使 用 Send() 方 法 在 EasyLanguage 代 码 中 添 加 一 个

BracketOrderTicket 组件的引用来下单。

就像手动下单一样,从 BracketOrderTicket 创建的所有委托单的状态将会与其他普通委托

单一起出现在交易管理器的委托单选项卡里。

BracketOrderTicket1.Send();

除了使用属性编辑器,你也可以在想要通过编程来在发单前决定交易代码、数量、交易方向、

限价止损价等时候,用 EasyLanguage 代码直接设置 BracketOrderTicket 属性。不管是哪种

情况,给指定的组件调用 Send()方法都提交订单。

BracketOrderTicket 1.Symbol = “XYZ”


BracketOrderTicket 1.Quantity = 100;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
68
EasyLanguage 对象自学课程(译)
BracketOrderTicket1.LimitPrice = myOrder.AvgFilledPrice + .05);

BracketOrderTicket1.StopPrice = myOrder.AvgFilledPrice - .05;

BracketOrderTicket 1.Action = tsdata.trading.orderaction.Sell;

BracketOrderTicket 1.Send() ;

◆课程例题 #11

目标:
(OSO Bracket Order 指标)

 创建一个 Bracket Order Ticket

 将一个 order ticket 与一个 Order(委托)对象关联并跟踪

 创建一个事件处理方法来跟踪 Order(委托)状态

 用一个打印日志(print log)来跟踪市价委托的状态直到委托被执行

指标:
‘$11_OSOBracketOrder’

这个指标使用一个 OrderTicket 和一个 BracketOrderTicket 组件根据指定的价格目标发送

一笔市价买单,并且当委托执行后发送一个 Sell(卖出)的 bracket OCO 委托来设定利润

目标和保护性的止损目标。委托状态在打印日志(print log)内显示。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
69
EasyLanguage 对象自学课程(译)

工作区:$11_OSOBracketOrder

建立图表窗口:

创建:1 分钟区间

刻度轴:与标的数据相同

插入指标:$11_OSOBracketOrder

组件和属性编辑器设置:

OrderTicket1:

Symbol: symbol (在Filters分类下)

Accounts: iAccounts1 (作为输入值添加)

Quantity: iQuantity1 (数量根据输入值决定)

Action: Buy

BracketOrderTicket1:

Symbol: symbol (在Filters分类下)

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
70
EasyLanguage 对象自学课程(译)

Accounts: iAccounts1 (作为输入值添加)

Quantity: iQuantity1 (数量根据输入值决定)

Action: Sell

TargetType: Limit

ProtectionType: StopMarket

Analysis Technique:

Initialized: AnalysisTechnique_Initialized

指标练习#11:‘$11_OSOBracketOrder’

这个例题,我们将从在课程例题#10 内创建的#10_MarketOrder 指标开始。将其另存为

#11_OSOBracketOrder.

由于 OrderTicket1 组件已经是你之前创建的指标的一部分,你不需要再添加一遍。但是,

如果你从头开始的话,你需要双击工具箱内的 OrderTicket 组件,并按照上述组件和属性编

辑器设置的内容设置 Symbol,Symbol Type,Accounts,Quantity,Action 和 Type 的值。

点击代码编辑器窗口左侧的工具箱选项卡,双击 BracketOrderTicket 组件。默认名称

BracketOrderTicket1 将出现在代码编辑器窗口底部的组键盘内。

现在,点击代码编辑器右侧的属性选项卡,打开属性面板,确保在属性编辑器顶部,

BracketOrderTicket1 是指定的组件。

在 Filters 分类下,将 Symbol 属性设置为保留字 symbol,这样 bracket order 将会给当前

代码下单。

点击 Account 属性旁边的空白文本框,然后点击右侧的向下的箭头,从下拉列表内选择

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
71
EasyLanguage 对象自学课程(译)
iAccount1。这和我们市价 order ticket 所用的是同一个模拟账号。同样,用一样的方法,

点击空白文本框右侧将 Quantity 属性设为 iQuantity。

还是在属性编辑器内,将 Action 属性设为 Sell。然后将 TargetType 设为 Limit,将

ProtectionType 设为 StopMarket 来指明当我们下 Bracket Sell 委托单时在市价上方和下

方所下单的委托类型。

回到我们的 EasyLanguage 代码,在之前声明过的输入之后给 bracket amount 添加一个添加

一个新的输入,这个输入将会用来给上面的和下面的 bracket 委托设置价格。

Input: int iQuantity1( 100000 );

Input: string iAccount1( "SIM00000" );

Input: OrderActive(TRUE);

Input: BracketAmt(.001);

接下来,声明一个新的 intrabarpersist 变量,该变量会在一个 bracket 委托发出后告诉我

们,这样 bracket 委托只产生一次。

Vars: double HiTarget( 0 ), double LoTarget ( 0 ),

intrabarpersist AllowTradeFlag( True ) ,

intrabarpersist BracketSent( FALSE );

同样,声明一个对象变量,该变量被用来引用在市价单发出时创建的市价单对象。

Var: tsdata.trading.Order MyOrder(null);

在 AnalysisTechnique_Initialized 方法中,添加一个将 bracket order 交易代码类型设置

为当前交易代码类型的语句,就像前一个例题一样。记住,当你在分析技术的属性编辑器内

双击事件名 Initialized 时 AnalysisTechnique_Initialized 方法会自动创建(参考例题

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
72
EasyLanguage 对象自学课程(译)
10)。

method void AnalysisTechnique_Initialized( elsystem.Object

sender,

elsystem.InitializedEventArgs args )

begin

OrderTicket1.SymbolType = Category;

BracketOrderTicket1.SymbolType = Category;

AllowTradeFlag = OrderActive;

end;

现在,我们创建一个允许我们跟踪市价单和 bracket 单状态的新方法。在这个例题的后面

我们将这个方法与一个委托单状态事件相关联。在 begin 语句前声明一个名为 myStatus

的本地方法变量来保存状态信息字符串。

Method void OrderStatusUpdate(elsystem.Object sender,

tsdata.trading.OrderUpdatedEventArgs args)

var: string myStatus;

begin

下面的一组方法内语句将建立委托单状态信息字符串并显示在打印日志中。

myStatus = myOrder.State.tostring();

myStatus = myStatus + " " + myOrder.OrderID;

myStatus = myStatus + " - " + myOrder.Action.tostring();

myStatus = myStatus + " " + myOrder.FilledQuantity.tostring();

myStatus = myStatus + " " + symbol;

print(myStatus);

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
73
EasyLanguage 对象自学课程(译)
下面的语句只在市价单执行后执行一次。将 bracket 价格分别设为高于和低于市价单执行

价格,然后 bracket 委托单被发出。BracketSent 状态变量被设为 True(真)这样

Bracket 委托单只在这一次被下达。最后,bracket 委托单状态信息将被显示在打印日志

中。

If BracketSent = False AND


myOrder.State = tsdata.trading.orderstate.filled then begin
BracketOrderTicket1.LimitPrice =
myOrder.AvgFilledPrice + BracketAmt;
BracketOrderTicket1.StopPrice =
myOrder.AvgFilledPrice - BracketAmt;

BracketOrderTicket1.Quantity = iQuantity1;

BracketOrderTicket1.Send();

BracketSent = True;

print("Bracket order sent - ",

BracketOrderTicket1.LimitPrice.tostring(),

" ", BracketOrderTicket1.StopPrice.tostring() );

end;

用一个 end 语句完成方法。

end;

这里是前一个例题中用来绘制指标值和发出一开始的市价单的代码。

Method void PlotValues() begin


Plot1(HiTarget, "High Target");

plot2(LoTarget,"Low Target");

plot3(AllowTradeFlag.tostring(),"Active");

end;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
74
EasyLanguage 对象自学课程(译)

HiTarget = HighestFC(High, 3)[1];

LoTarget = LowestFC(Low, 3)[1];

PlotValues();

If ((Close <= LoTarget OR Close >= HiTarget ) AND


(LastBarOnChart AND AllowTradeFlag)) then begin

但是,在这个例题中我们创建一个允许我们在订单被发出、接收和执行时进行跟踪的订单对

象。我们通过将 OrderTicket1.Send()方法返回的委托单对象赋值给我们早先声明的

MyOrder 对象变量。然后,我们将之前创建的 OrderStatusUpdate 事件处理方法与 MyOrder

对象的 Updated 事件相关联,这样每当委托单状态改变时我们可以将委托单状态打印并在市

价单执行时发送 bracket 单。

MyOrder = OrderTicket1.Send();

MyOrder.Updated += OrderStatusUpdate;

AllowTradeFlag = False;

end;

验证指标。

在图形中插入指标。

来到设置#11_OSOBracketOrder 对话框,选择常规选项卡。在你的 EasyLanguage 代码可以

生成委托单之前,标有启用下单对象的勾选框需要被勾选。你可以一次性为雷达屏所有行打

开此功能,也可以逐行单独打开。这个设置只在指标还应用于雷达屏时有效。如果删除指标

之后再加载,你需要再次选中勾选框。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
75
EasyLanguage 对象自学课程(译)

MarketDepthProvider
MarketDepthProvider 组件创建一个对象,这个对象让你引用更新后的包含特定代码买卖报

价和买卖 level 的市场深度数据集合。该信息与国信 TradeStation 的市场深度窗口内的信

息相似。

市场深度集合:

 买价和卖价

 买入 level 和卖出 level

 参与者

Bids(买价)和 Ask(卖价)集合属性允许你访问参与者(ECNs)列出来的股数。BidLevel

和 AskLevel 集合属性允许你访问所有参与者在特定价格的混合数据。Participants(参与

者)属性集合允许你为一个独特的 participant 访问全部。

General 属性让你控制收集买卖报价的 level 数以及是否在提供的数据里包含具体的 ECN

book 数据和 Level II 数据。

Updated 事件以和 MarketDepthProvider 一起用,这样在一个与任何引用的市场深度数据相

关联的值变动时你会被通知。

在你的代码中,你通常会在试图访问这些数据集合内的有序号的元素前,用 Count 属性来决

定买卖报价项目的数量或买卖 level 的深度。

MarketDepthProvider 将信息储存在五个数据集合中:

Bids & Asks – 给每行标序号:

(marketdepthprovide1.Bids[row].Price)

Bid Levels & Ask Levels – 给每个价格水平标序号:

(marketdepthprovide1.Asklevels[lvl].TotalSize)

Participants – 给每个Participant标序号:

(marketdepthprovide1.Participants[par].Bids.Count)

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
76
EasyLanguage 对象自学课程(译)

◆课程例题 #12

目标:
(市场深度指标)

 用一个工具箱组件来创建一个在一定买价卖价水平上计算并显示股数或合约总数

的对象

 根据价格水平访问市场深度数据

 循环总计不同水平的买单数量和卖单数量

指标:
‘$12_TotalBidAskSize’

这个雷达屏指标使用 MarketDepth 组件来显示指定市场深度价格水平的总买单数量和卖

单数量。

工作区:$12_MarketDepth

建立雷达屏窗口:

创建:五分钟周期

插入指标:$12_TotalBidAskSize

组件和属性编辑器设置:

MDP:

Name: MDP (改变组件名)

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
77
EasyLanguage 对象自学课程(译)

Symbol: symbol (设置为代码)

MaximumLevelCount: iMaximumLevelCount1 (作为Int输入值添加)

Updated: MDP_Updated

指标练习#12:‘$12_TotalBidAskSize’

创建一个新指标并命名为:#12_TotalBidAskSize

点 击 代 码 编 辑 器 窗 口 左 侧 的 工 具 箱 选 项 卡 , 双 击 OrdersProvider 组 件 。 默 认 名

MarketDepthProvider1 将出现在代码编辑器窗口底部的组键盘内。

现在,点击代码编辑器窗口右侧的属性选项卡,打开属性面板并确保在属性编辑器顶部

MarketDepthProvider1 是被选中的组件。

将组件的 Name 属性改为较短的名字 MDP。

在 Filters 分类下,将 Symbol 属性设为 symbol,这样提供器(provider)只会返回当前代

码的市场深度信息。将 MaximumLevelCount 属性设为一个名为 iMaximumLevelCount1 的输入

值。相匹配的输入值声明被加进你的 EasyLanguage 文档中。

点击事件图标,并双击 Updated 事件来在你的文档中创建一个事件方法。

在你的 EasyLanguage 文档中现在有一个输入值声明语句和一个事件处理方法。将默认输入

参数改为“3”。在处理方法中加入一个调用语句 PlotValues()。

Input: int iMaximumLevelCount1( 3 );

method void MDP_Updated( elsystem.Object sender,

tsdata.marketdata.MarketDepthUpdatedEventArgs args )

begin

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
78
EasyLanguage 对象自学课程(译)
PlotValues();

end;

现在,创建一个 PlotValues 方法,它将在 begin 语句前包含三个本地变量。第一个在总

计买单数量和卖单数量时被用来作为循环计数器。两个本地变量会累计

MarketDepthProvider 组件要求的总的买和卖的市场深度(数量)。

Method void PlotValues()

var: int level, int AskDepthTot, int BidDepthTot;

begin

下面一组语句将加总从组件对象得到的买价和卖价水平的买卖单数量。首先,将买和卖的总

数变量设为 0。然后,通过测试来检查提供器(provider)是否含有足够的买价水平(bid

levels)去给你在 iMaximumLevelCount1 输入中指定的最大水平数(levels)计算

加总。如果足够的话,在一个循环中把每个买价水平的数量加入总计。给卖价水平创建一个

同等的 if 和 for 循环。

AskDepthTot = 0;

BidDepthTot = 0;

If MDP.bidlevels.count >= iMaximumLevelCount1 then


For level = 0 to iMaximumLevelCount1 – 1 begin
BidDepthTot += MDP.bidlevels[level].totalsize;

End;

If MDP.asklevels.count >= iMaximumLevelCount1 then


For level = 0 to iMaximumLevelCount1 - 1 begin
AskDepthTot += MDP.asklevels[level].totalsize;

end;

绘制总数,如果买单总数大于卖单总数,将买单数量绘图的背景颜色设置为绿色,如果卖单

总数大于买单总数则将卖单数量绘图的背景颜色设置为红色。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
79
EasyLanguage 对象自学课程(译)

Plot1(BidDepthTot,"Bid Size");

Plot2(AskDepthTot,"Ask Size");

If (BidDepthTot > AskDepthTot) then begin


setplotbgcolor(1,darkgreen);

setplotbgcolor(2,black);

end

Else begin

setplotbgcolor(2,darkred);

setplotbgcolor(1,black);

end;

end;

验证指标。

在雷达屏中加载指标。

QuotesProvider
QuotesProvider 组件创建一个让你引用指定交易代码的报价字段 quote field(快照

snapshot)的对象。报价字段值可能会根据实时更新,但没有历史数据可用。

在属性编辑器中,Symbol 属性必须指明你想要报价的交易代码并且 Fields 属性必须包含一

个由逗号分隔的一列字段名供查询。这两者都是必须填写的筛选属性。只有必须填写的报价

字段(例如,“AskSize,DailyLimit”)在给定的 QuotesProvider 对象的中可用。

要访问报价字段值,使用 QuotesProvider 的 Quote["Name"]属性以及所请求字段的数据值

类型(doublevalue, stringvalue, datevalue 等等),例如:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
80
EasyLanguage 对象自学课程(译)
plot1(QuotesProvider1.Quote["Ask"].doublevalue,"Ask");

报价字段价格通常被引用为 DoubleValue,
成交量、交易规模值通常作为 IntegerValue,

日期和时间通常作为 DateValue,名称、描述通常为 StringValue。QuoteFields 类

帮助主题列出可用的报价字段名以及和它们相关的数据值类型。报价字段的值类型也显示在

指定字段名的 EL 字典描述窗格的 Example 部分。

一个与 QuotesProvider 相关的 Updated 事件让你的代码在与任何引用的报价字段相关

的值改变时收到通知。当你询问一个不在你的图表或网格中、但需要在分析技术或策略中使

用的代码的报价时,这个功能尤其有用。

像其他提供器(provider)一样,在尝试使用集合内有序号的元素前,用 Count 属性来

决定 QuotesProvider 能不能找到报价。

◆课程例题 #13

目标:
(报价指标)

 用 QuotesProvider 对象访问报价(快照)数据

 建立一个供访问的报价字段(Quote Fields)的令牌列表(token list)

 使用一个“value”属性读取并绘制一个报价字段的适当的值类型

指标:“$13_Quotes”

这个指标用 QuotesProvider 组件访问报价字段数据。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
81
EasyLanguage 对象自学课程(译)
工作区:$13_Quotes

建立雷达屏窗口:

创建:5 分钟区间

插入指标:$13_Quotes

组件和属性编辑器设置:

QP:

Name: QP (改变组件名)

Symbol: symbol (在Filters分类下)

Fields: “last,tradevolume,tradetime”

Updated: QP_Updated

指标练习 #13:“$13_Quotes”

创建一个新的指标并命名为"#13_Quotes"。

点击代码编辑器窗口左侧的工具箱选项卡,双击 QuotesProvider 组件。默认名称

QuotesProvider1 将出现在代码编辑器窗口底部的组件盘内。现在,点击代码编辑器右

侧的属性选项卡,打开属性面板,确保 QuotesProvider1 是属性编辑器顶部指定的组件。

将组件的 Name 属性改为短名称 QP。

在 Filters 分类下,将 Symbol 属性设为保留字 symbol,这样提供器(provider)只

会返回图表或网格内当前交易代码的报价信息。将 Fields 字段设置为文本字符串“last,

tradevolume, tradetime”,这个字符串用来指明从交易代码获取的报价字段(Quote

fields)。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
82
EasyLanguage 对象自学课程(译)
一 列 可 用 的 报 价 字 段 名 称 和 数 据 类 型 可 以 在 字 典 和 EasyLanguage 对 象 引 用 里

QuoteFields 帮助主题内的 QuoteFields 类下找到。你现在可以在代码中将 QP 组件作

为对象使用,来访问图表或网格内当前交易代码的值。

接下来,点击 图标切换到事件窗格。你将可以看到 Updated 列于事件列中,其值为空

白。双击事件名 Updated,在 EasyLanguage 文档中创建一个事件处理方法并将新方法

名称与属性联系起来。

一个叫做 QP_Updated 的方法被加进文档中了。事件处理器括号内的参数是自动生成的并

不应该被删除或改动。

在事件处理方法中,将 begin 语句后自动生成的评论用一个调用 PlotValues()方法的语

句代替。

method void QA_Updated( elsystem.Object sender,

tsdata.marketdata.QuoteUpdatedEventArgs args ) begin

PlotValues();

end;

现在,在方法中添加下列语句,这些语句将绘制报价集合内指定的报价字段。要读取特定报

价值,你还需要为三个绘图中的每一个在 Quote["fieldname"]后添加合适的属性类型(即

doublevalue, integervalue 等 等 ) 。 参 考 字 典 或 EasyLanguage 对 象 引 用 帮 助 里 的

QuoteFields 类来看一列字段名和数据类型。例如,在看 QuoteFields 里的 Last 字段名的

字典解释时,参考描述项目底部的 Example 来看一个显示.doublevalue 数据类型的代码片

段。

Method void PlotValues() begin


plot1(QP.Quote["Last"].doublevalue,"Last");

plot2(QP.Quote["TradeVolume"].integervalue,"Volume");

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
83
EasyLanguage 对象自学课程(译)
plot3(QP.Quote["TradeTime"].datevalue.tostring(),"Time");

end;

PlotValues();

验证指标。

在雷达屏中加载指标。

FundamentalQuotesProvider
FundamentalQuotesProvider 组件创建一个让你引用指定交易代码的基本面引用字段

值的对象。基本面引用字段值通常不会实时更新并且有的可以让你提到之前报告周期的值。

在属性编辑器中,Symbol 属性必须指明你希望检索基本面的代码并且 Fields 属性必须包

含一列逗号分隔的基本面字段名供查询。两者都是必填筛选属性。只有要求的字段(例如

“sbbf,snpm,sgrp”)会在一个给定的 FundamentalQuotesProvider 对象中可用。

要访问基本面数据字段值,使用 FundamentalQuotesProvider 的 Quote["Name"]属

性以及要求字段的数据值类型(doublevalue, stringvalue, datevalue 等)还有

多少个报告周期之前(用[0]表示最近的周期),例如:

plot1(FundamentalQuotesProvider1.Quote["SBBF"].doublevalue[0],

"EPS");

注意基本面字段的值类型后的方括号内多少周期前的序数是必需的,即使指定字段不报告历史值。

价格通常以 DoubleValue 来引用,数量值(包括成交量和交易量)作为 IntegerValue,日

期和时间作为 DateValue,名称、描述作为 StringValue。基本面 QuotesFields 类帮助主题

列出可用的基本面数据字段名以及他们相应的数据值类型。一个基本面字段的值类型也被展

示在 EL 字典描述窗格中。

一个与 FundamentalQuotesProvider 相关联的 Updated 事件让你的代码可以在引用的字段发

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
84
EasyLanguage 对象自学课程(译)
生改变时收到通知。在你请求的交易代码不在你的图表或网格中,但是你的分析技术或策略

需要了解时,这尤其重要。

与其他提供器(provider)一样,在试着从集合中访问一个标有序号的元素前,用 Count

属性来判断 FundamentalQuotesProvider 有没有找到任何报价。

◆课程例题 #14

目标:(Fundamental Quotes 指标)

 使用工具箱组件来创建一个为指定交易代码显示基本面报价值的对象

 访问 Historical Fundamental Data

 用属性编辑器指定要查询的基本面字段。

指标:$14_FundQuotes

这个指标用一个 FundamentalQuotesProvider 组件从几个 Fundamental Quote 字段获取数据。

它还为每个代码计算并绘制实时市盈率。

工作区:$14_FundQuotes

建立雷达屏窗口:

创建:30 分钟周期

插入指标:$14_FundQuotes

组件和属性编辑器设置:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
85
EasyLanguage 对象自学课程(译)
FQP:

Name: FQP (改变组件名)

Symbol: symbol (在Filters分类下)

Fields: "sbbf,yield,price2bk,f_lstupdat ”

Updated: FQP_Updated

指标练习#14:$14_FundQuotes

创建一个新指标并命名为#14_FundQuotes

点击代码编辑器窗口左侧的工具箱选项卡,双击 FundamentalQuotesProvider 组件。

默认名 FundamentalQuotesP1 将出现在代码编辑器底部的组件盘内。

现在,点击代码编辑器右侧的属性 tab 页,打开属性面板并确保 FundamentalQuotesP1

是属性编辑器顶部指定的组件。

将组件的 Name 属性改为短名 FQP。

在 Filters 分类下,将 Symbol 属性设为保留字 symbol,这样提供器只会返回图表或网

将 Fields 属性设为文本字符串“sbbf, yield, price2bk,


格内当前代码的基本面数据。

f_lstupdat”,这指定了从交易代码请求的 Fundamental Quotes 字段。一列表的可

用 基 本 面 字 段 名 和 数 据 类 型 可 以 在 字 典 里 的 FundamentalQuoteFields 类 下 和

EasyLanguage 对象引用里的 FundamentalQuoteFields 帮助主题下找到。

你现在可以将 FQP 组件作为你代码中的一个对象来使用,去访问网格或图表内当前交易代

码的值了。

接下来,点击 图标,切换到事件窗格。你将会看到 Updated 列在“事件”列下,值为

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
86
EasyLanguage 对象自学课程(译)
空白。双击事件名 Updated,在你的 EasyLanguage 文档中创建一个事件处理方法,并

将新方法名与属性相关联。

一个名为 FQP_Updated 的方法被添加到你的文档中。事件处理方法括号内的参数是自动

生成的,不应被移除或改动。

在事件处理方法中,将 begin 语句后自动生成的评论替换为 PlotValues()方法的调用语

句。

method void FQP_Updated( elsystem.Object sender,

tsdata.marketdata.FundamentalQuoteUpdatedEventArgs args )

begin

PlotValues();

end;

现在,在方法内添加下面的语句,这些语句会从组件的 Quote 集合中绘制指定基本面引用

字段。这一次我们引用 Quote 集合中的每一个元素,用与早先设置的 Filed filter 属

性内排列顺序相匹配的数字序数进行引用,“0”代表第一个元素等等。与之前例题一样,

你需要为五个绘图中的每个 Quote[n]添加合适的属性值类型。因为基本面引用可以包括之

前报告周期里的历史值,你还需要为每个值用表示“多少周期前”的方括号指明引用的是哪

个周期。要想了解字段名和数据类型,参考字典中的 FundamentalQuoteFields 类或

EasyLanguage 对象引用帮助。例如,在帮助主题中搜索“SBBF”(Basic EPS)显示

数据类型为 double,意味着你需要在 quote 后添加 DoubleValue[0]这样才能够读取最

近的 SBBF 的 quote。如果没有指明 Quote 的数据类型或者“多少周期前”,很可能会出

现运行错误。

Method void PlotValues()

begin

If FQP.Count > 0 then begin

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
87
EasyLanguage 对象自学课程(译)
if FQP.HasQuoteData(0) then

Plot1(FQP.Quote[0].DoubleValue[0],"EPS");

接下来访问并绘制一个周期前的市盈率。

if FQP.HasQuoteData(0) then

Plot2(FQP.Quote[0].DoubleValue[1],"Prev EPS");

然后,我们绘制当前周期的剩余字段。

if FQP.HasQuoteData(1) then

Plot4(FQP.Quote[1].DoubleValue[0],"DivYield %");

if FQP.HasQuoteData(2) then

Plot5(FQP.Quote[2].DoubleValue[0],"Px/Bk");

if FQP.HasQuoteData(3) then

Plot6(FQP.Quote[3].DateValue[0].tostring(),"UpDate");

If Plot1 > Plot2 then

SetPlotColor(1, Cyan)

else

SetPlotColor(1, Magenta);

end;

end;

最后,我们根据当前价格计算并绘制实时市盈率。然后添加另一个 PlotValue 调用,这样

值会在每次 tick 更新时绘制。

if FQP.Count > 0 AND FQP.Quote[0].DoubleValue[0] > 0 then

Plot3(Last / FQP.Quote[0].DoubleValue[0], "RT P/E" );

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
88
EasyLanguage 对象自学课程(译)

PlotValues():

验证指标。

在雷达屏中插入指标。

Workbook(Excel)
Workbook 组件创建一个对象,该对象让你在分析技术和微软 Excel 电子表格内的外部工作

簿之间建立连接。

在属性编辑器内,FileName 筛选属性必须指明一个在你电脑上已存在的 Excel 电子表格文

件的完整路径和文件名。其他筛选属性用来决定建立连接的额外设置,例如电子表格是否可

以在其他分析技术间共享或者完成后是否在电子表格上保存数据。

Workbook 组件让你在电子表格文件内查阅特定页面的表格,并使用所引用表格的 Cells 属

性从一个特定单元格的行和列来读取或写入。

例如,下面的语句向使用 FileName 属性引用的一个名为“Prices”的选项卡(表格)的第

二列第四行的单元格内写入数字 123.45:

Workbook1[“Prices”].Cells[2,4] = 123.45;

同样,下一个语句读取同一个“Prices”选项卡(表格)的第三列第四行内的数值并将它赋

值给 Value1:

Value1 = Workbook1[“Prices”].CellsAsDouble[3,4];

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
89
EasyLanguage 对象自学课程(译)
我们用 CellAsDouble 属性从单元格读取来确保单元格里的任何数值(或空白值)都会被读

取。但是,如果单元格内包含一条文本信息,语句将会产生错误,因为单元格的数据类型不

匹配。

注意,要使用 Workbook 组件,你必须在电脑上安装微软 Excel 软件并且必须在 FileName

属性引用的文件夹地址已经创建电子表格文件。

往 Excel 内写入值

wkbk[“sheet name”].Cells[Col, Row] = 25.50;

wkbk[“AcctPL”].Cells[5,10] = 25.50;

从 Excel 内读取值

Value1 = wkbk[“sheet name”]. CellsAsDouble[Col, Row] ;

Value1 = wkbk[“AcctPL”]. CellsAsDouble[5,10] ;

保存电子表格数据:

如果你用 EasyLanguage 修改一个表格并且希望在关闭分析技术后保存这些改变,你可以

设置对象属性“SaveOnClose = TRUE”。

◆课程例题 #15

目标:(Excel 指标)

 引用一个之前建好的 Excel 工作簿

 向 Excel 电子表格内写入更新后的值

 从电子表格内读取计算后的值

指标:“$_Excel”

这个指标用一个 Workbook 组件来与雷达屏或图形分析窗口内的指定 Excel 电子表格沟通。

注意:该指标只有在你的电脑上安装了 Excel 的情况下可用。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
90
EasyLanguage 对象自学课程(译)

工作区:$15_Excel

建立图形:

创建:30 分钟周期

插入指标:$15_Excel

组件与属性编辑器设置:

WkBk:

Name: WkBk (改变组件名)

FileName: “c:\exceldemo.xls” (在Filters分类下)

AccP:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
91
EasyLanguage 对象自学课程(译)

Name: AccP (改变组件名)

Accounts: iAccount1

Updated: AccP_Updated

PosP:

Name: PosP (改变组件名)

Symbols: symbol

Updated: PosP_Updated

指标练习 #15:“$15_Excel”

创建新指标并将它命名为:“#15_Excel”。

点 击 代 码 编 辑 窗 口 左 侧 的 工 具 箱 选 项 卡 , 双 击 以 下 三 个 组 件 : Wrokbook ,

AccountsProvider , 和 PositionsProvider 。 默 认 名 Workbook1 ,

AccountsProvider,PositionsProvider1 将出现在代码编辑窗口底部的组键盘内。

现在,点击代码编辑窗口右侧的属性选项卡,打开属性面板并确保属性编辑器顶部的

Workbook1 是指定组件。将组件的 Name 属性改为短名 Wkbk。在 Filters 分类下,将

FileName 属性设置为 c:\exceldemo.xls,这样 Workbook 知道与哪个 Excel 文件沟通。你

现在可以将 Wkbk 组件作为对象在你的代码中使用来访问网格或图表内当前代码的值。

在属性编辑器顶部选择 AccountsProvider1。将组件的 Name 属性改为短名 AccP。切换到属

性编辑器的“事件”图标并双击 Updated 来在文档中创建一个 AccP 事件处理方法。这个方

法在每次一个 Account 值发生变化时被调用。

在属性编辑器顶部选择 PositionsProvider1。将组件的 Name 属性改为短名 PosP。切换到属

性编辑器的“事件”图标并双击 Updated 来在文档中创建一个 PosP 事件处理方法。这个方

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
92
EasyLanguage 对象自学课程(译)
法在每次你的一个仓位发生变化时被调用。

在文档顶部,创建两个变量。第一个指明电子表格中你引用的选项卡。第二个保存电子表格

内计算出来的总仓位损益并用 EasyLanguage 代码读取。

Var: WBTab( "Demo" ), TotalPL( 0 );

在 AccP 事件处理方法内我们添加一系列语句,这些语句将提供器(provider)集合里第一

个 Account 的数个属性写入电子表格第六行的头四列。像之前一样,首先测试检查 AccP 组

件是否包含账户数据。注意每个 WkBk 引用包括了你希望向其中写入的单元格所在电子表格

选项卡的名字(从 WBTab 变量里)。

method void AccP_Updated( elsystem.Object sender,

tsdata.trading.AccountUpdatedEventArgs args )

begin

if (AccP.Count > 0) then

begin

WkBk[WBTab].Cells[1, 6] = AccP[0].AccountID;

WkBk[WBTab].Cells[2, 6] =

AccP[0].RTDayTradingBuyingPower;

WkBk[WBTab].Cells[3, 6] = AccP[0].RTRealizedPL;

WkBk[WBTab].Cells[4, 6] = AccP[0].RTUnrealizedPL;

end;

end;

在 PosP 事件处理方法中,我们添加一系列语句,向电子表格内第 11 到 20 行的头四列内写

入提供器(provider)集合里每个仓位的数个属性。

method void PosP_Updated( elsystem.Object sender,

tsdata.trading.PositionUpdatedEventArgs args )

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
93
EasyLanguage 对象自学课程(译)
var: int it;

begin

for it = 0 to PosP.Count - 1

begin

WkBk[WBTab].Cells[1, 11 + it] = PosP[it].Symbol;

WkBk[WBTab].Cells[2, 11 + it] = PosP[it].Quantity;

WkBk[WBTab].Cells[3, 11 + it] = PosP[it].AveragePrice;

WkBk[WBTab].Cells[4, 11 + it] = PosP[it].OpenPL;

end;

这个例子假设我们的仓位不超过 10 个。写入已存在仓位数据后将添加一行空白单元格以确

保当一个仓位从集合中移除后之前的行不再显示。

WkBk[WBTab].Cells[1, 11 + it ] = "";

WkBk[WBTab].Cells[2, 11 + it ] = "";

WkBk[WBTab].Cells[3, 11 + it ] = "";

WkBk[WBTab].Cells[4, 11 + it ] = "";

第 21 行第 4 列的单元格包含一个将第 11 到第 20 行的第四列加总的公式。这个计算后的值

从电子表格内被读取,保存在 TotalPL 变量中并被实时绘制。

TotalPL = WkBk[WBTab].CellsAsDouble[4, 21];

If LastBarOnChart then

plot1(TotalPL, "TotalP&L");

end;

最后,一条零线将被显示出来,作为划分损益正负的参照。

Plot2(0);

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
94
EasyLanguage 对象自学课程(译)

最后这部分附加代码让 Plot1 可以在市场关闭时显示。

If LastBarOnChart then begin


TotalPL = WkBk[WBTab].CellsAsDouble[4, 21];

plot1(TotalPL, "TotalP&L");

end;

验证指标。

向一个图表内插入指标。

创建非组件对象
不是所有的对象都是通过工具箱创建的。你可以通过声明对象变量并将对象的实例赋值给变

量来向代码中添加对象。对象变量和新对象实例的类型 type(类 class)必须一致。创建

一个对象的新实例并赋值给对象变量的过程也被称为实例化 instantiation。

尽管不是必须的,不过当 EasyLanguage 代码通过使用一个由分析技术的 Initialize

事件触发的 AnalysisTechnique_Initialized 方法(在属性编辑器内设置)第一次运

行时,创建新的对象实例很常见。

非组件对象的例子包括:Collections,Win Forms,和 XML Databases。

New
保留字 new 在赋值语句中被用于创建一个指定类(类型)对象的实例(或 copy)并调用该

类的构造器。单词 new 出现于等号(=)右侧,位于类的类型(class type)之前。新创

建的对象被赋值给之前声明的相同类类型(class type)的对象变量。

例如,下面的代码为一个名为 vectorname 的 vector 对象声明变量,并将一个 Vector

类型的对象的新实例赋值给该变量:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
95
EasyLanguage 对象自学课程(译)

var: elsystem.collections.Vector vectorname(null);

vectorname = New elsystem.collections.Vector;

注意在变量声明内使用的 Vector 类类型和新对象实例的创建包括对于类在字典中定位的完

整的命名空间引用。

Create()
Create()方法也可以用于创建指定类(类型)的对象的实例并调用该类的构造器。Create()

方法是保留字 new 的备选,并且当一个新的对象要求传递初始化参数作为 Create()方法的

一部分时经常被使用。

例 如 , 下 面 的 代 码 为 一 个 名 为 gdname 的 全 局 字 典 对 象 声 明 变 量 并 且 将 一 个 新 的

GlobalDictionary 类型的对象实例赋值给变量。注意这个 Create()方法接受额外的参数,

在这个例子中这些额外参数指明 GlobalDictionary 可以在不同的分析窗口类型之前被共享

并且有一个独特的共享名。

var: elsystem.collections.GlobalDictionary gdname(null);

gdname=elsystem.collections.GlobalDictionary.Create(true,"IDst

ring")

Vector 集合
Vector 被用于保存一系列值作为被命名集合的有序数的元素。这与 EasyLanguage array 类

似;但是,vector 有额外的能力,例如多种向集合中插入值的方法以及在集合内存储元素

(如对象)的能力。

大部分我们到目前使用过的对象都是通过在工具箱内双击组件创建的。要创建一个 vector,

或任何非组件对象,你首先需要声明一个合适类型的变量并将同样类型对象的新实例赋值给

变量。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
96
EasyLanguage 对象自学课程(译)

例 如 , 这 里 是 一 个 名 为 myValues 的 变 量 的 声 明 语 句 , 该 变 量 被 作 为

elsystem.collection.Vector 类型创建,初始值为 null。注意创建对象变量时初始值总是

为 null。

var: elsystem.collections.Vector myValues(null);

下一步是将新的 Vector 对象的实例(copy)赋值给变量。这可以在代码中任何地方进行,

但是通常在代码运行的开端处进行,如下所示:

method void AnalysisTechnique_Initialized( elsystem.Object

sender, elsystem.InitializedEventArgs args )

begin

myValues = New elsystem.collections.Vector;

end;

一旦被创建后,Vector 的长度可以根据你在任何位置添加或删减数据而相应地增长或缩短。

Vector 可以和一些核心 EL 函数一起使用来取集合内数值的平均数或总和。Vector 集合内的

第一个元素的序数为 0.

向 Vector 内添加数据元素:

Push_Back – 向 Vector 集合最末端添加一个元素


vectorname.Push_Back( 25.50);

Insert - 在 Vector 集合的指定位置添加元素,将其他元素的序数向后推一位。

vectorname.Insert(Index, 25.50);

向 Vector 内移除数据元素:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
97
EasyLanguage 对象自学课程(译)
Pop_Back – 将Vector集合最末端元素移除

vectorname.Pop_Back();

Erase – 移除指定位置元素并将其他元素向前移一位
vectorname.Erase(Index);

vectorname.Erase(iStart, iEnd);

Clear - 将 Vector 内全部数据元素删除


vectorname.Clear();

从 Vector 访问数据元素:

Value1 = vectorname[index];

在函数内使用 Vectors:

Value1 = Highest(vectorname, vectorname.count);

◆课程例题 #16

目标:(Vector 指标)

 直接在代码中创建一个新的 vector 对象实例

 向 vector 中添加值

 访问 vector 中的值

 在标准的 EL 函数中使用 vector 集合

指标:“$16_Vector”

该指标用一个 Vector 集合为图表中指定数目的关键反转形态存储低图条价格,并且在图表

上将低价平均值作为结果绘制在图表上。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
98
EasyLanguage 对象自学课程(译)

工作区:$16_Vector

建立图形分析窗口:

创建:30 分钟周期

插入指标:$16_Vector

组件和属性编辑器设置:

无组件

Analysis Technique:

Initialized: AnalysisTechnique_Initialized

指标属性:

刻度轴:与标的数据相同

图表类型:将第一个绘图设置为 Point 类型

指标练习 #16:“$16_Vector”

创建新指标并命名为“#16_Vector”.

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
99
EasyLanguage 对象自学课程(译)
到现在,我们在例题中用组件创建对象。这个例子我们将用非组件对象 Vector,它和

EasyLanguage 的 array 很相似,但是与 array 不同的是 vector 让我们向集合中任何元素添

加数据并且更轻松地管理它的长度。

首先,声明一个在 vector 中将用到的定义元素最大数的输入值。

input: VectorMax(5);

接下来,我们创建一个用于保存 Vector 对象的对象变量。对象变量用对象基于的类类型

进行声明,这个例子中对象类型用完成的类名称 elsystem.collections.Vector 来指明。对

象变量的名称是 AvgLow,所有对象变量的初始值为 null。

var: elsystem.collections.Vector AvgLow(null);

第二个变量是一个用来辨认关键反转发生的真假值。

var: KR(False);

接下来,在属性编辑器内点击事件图标,双击 Initialized 来创建一个在指标第一次执行时

只执行一次的事件处理方法。

在 AnalysisTechnique_Initialized 方法内你将添加一个语句创建一个 Vector 对象的 New

实例(同样使用完整类类型名 class type name)并将它赋值给对象变量 AvgLow.如果回头

看看之前例子中包括了组件创建对象的设计器生成代码,你会看到用过的每个组件对象类似

的赋值语句。

method void AnalysisTechnique_Initialized( elsystem.Object

sender,

elsystem.InitializedEventArgs args )

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
100
EasyLanguage 对象自学课程(译)
begin

AvgLow = New elsystem.collections.Vector ;

end;

每当找到一个关键反转形态,即当前图条的最低价低于之前三根图条并且当前图条的收盘价

高于之前一根图条的收盘价,下面的语句将会把 KR 设为 True。如果形态没有找到,KR 被设

置为 False。

KR = ( Low < Lowest( Low, 3 )[1] and Close > Close[1] );

如果关键反转形态找到了,用 Insert()方法向 vector 对象 AvgLow 中加入新值。这里,

它把当前图条的最低价作为 vector 的第 0 个元素添加。这里需要特别注意的是,最近添

加的值总是作为 vector 的第 0 个元素添加,之前的值自动向后移动一位。一旦 vector

内的项目数超过指定的最大值,Pop_Back()方法被用于移除最后的项目这样集合内的项目

数总是小于等于 VectorMax。一旦 vector 被更新后,当前图条的最低价被绘制。右键点

击文档,进入 Chart Style 选项卡,将“KR BAR”的 Type 值改为带有增加 Weight 的

Point,这样在关键反转被找到处就会出现一个粗点。

if KR then begin

AvgLow.insert(0,Low);

If AvgLow.Count > VectorMax then


AvgLow.pop_back();

Plot1(Low, "KR BAR");

end;

最后,
如果 vector 内存在任何项目,
我们将之前 vector 内的最低价的平均值绘制为一条线,

这条线代表根据当前关键反转所下委托的建议止损出逃价格。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
101
EasyLanguage 对象自学课程(译)
If AvgLow.Count = VectorMax then
plot2(Average(AvgLow,VectorMax),"KR Avg Low");

右键点击文档,将 KR BAR 的绘图类型改为 point。

验证指标。

在图表内插入指标。

Global Dictionary Collection


全局字典(Global Dictionary)被用来保存不同窗口间分析技术共享的值(或对象)。通

过 key/value 组合,值可以被添加进 GlobalDictionary,其中 key 是字典中项目的名称(例

如“mySymbol”),value 是任何可以被保存和用 key 名称重新取得的数值、字符串、布尔

值或对象。

大多数我们到目前为止使用过的对象都是通过双击工具箱内组件创建。要创建一个非组件对

象,首先需要声明一个正确类型的变量,然后将相同类型的对象的新实例赋值给变量。

例 如 , 这 里 是 一 个 名 为 myGD 的 变 量 的 声 明 语 句 , 该 变 量 创 建 的 类 型 是

elsystem.collection.GlobalDictionary,初始值为 null。

var: elsystem.collections.GlobalDictionary myGD(null);

接下来,一个新的 GlobalDictionary 对象的实例被创建并被赋值给 myGD 变量。

myGD = elsystem.collections.GlobalDictionary.Create();

不加任何参数使用 Create()方法将创建一个相同窗口类型(图形分析、雷达屏等)内运行

的分析技术共享的默认(未命名)的 GlobalDictionary。每个向这个默认全局字典读取或

写入的分析技术需要一个对象变量,这个对象变量被同样的空白 Create()方法创建的

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
102
EasyLanguage 对象自学课程(译)
GlobalDictionary 实例赋值。

作为备选,两个参数的方法 Create(shareType,shareName)可以被用来创建一个在不同窗口

类型间(例如一个图形分析和一个雷达屏)共享的 GlobalDictionary 对象并且用特定名称

来避免使用默认字典可能发生的冲突。每个向这个命名的全局字典内读取或写入的分析技术

需要一个用 Create(shared,name)方法创建的、有着同样 true/false 和 share name 参数的

GlobalDictionary 的对象实例。下列语句创建一个在不同窗口类型间用一个共享名工作的

GlobalDictionary 实例。

myGD = elsystem.collections.GlobalDictionary.Create(TRUE,

“GD_sharedname");

如果 key 还不存在,向 GlobalDictionary 中添加一个 value。

If myGD.Contains(“keyname”) = false then


myGD.Add("keyname", initialvalue);

一旦 key 被添加进字典中,与 key 相关联的 value 可以用 Items["keyname"]属性改变或回

读。注意当读取字典值的时候 Items[]值需要用正确的数据类型被赋值给一个变量。

改变一个与已存在 GlobalDictionary key 相关联的值


If myGD.Contains(“keyname”) then
myGD.Items[“keyname“] = newvalue;

读取一个与已存在 GlobalDictionary key 相关联的值


If myGD.Contains(“keyname") then
value1 = myGD.Items[“keyname”] astype type;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
103
EasyLanguage 对象自学课程(译)

◆课程例题 #17

目标:(GDWrite)

 创建一个 GlobalDictionary 对象,在任何类型的分析窗口间共享值

 给 GlobalDictionary 一个特定的共享名称

 向全局字典中写入值

指标:“$17_GDWrite”

这个例子用一个 GlobalDictionary 对象往全局字典中写入信息,这些信息可以被使用

Global Dictionary 的其他分析技术访问。

工作区:$17_GDWrite

建立图形窗口:

创建:日线图

插入指标:$17_GDWrite

组件和属性编辑器设置:

无组件

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
104
EasyLanguage 对象自学课程(译)

分析技术:

Initialized: AnalysisTechnique_Initialized

指标练习 #17:“$17_GDWrite”

创建一个新指标并命名:"#17_GDWrite"

在这个例子中,我们用一个叫 GlobalDictionary 集合的非组件对象并向全局字典内写入一

对值,该值可以被其他从相同全局字典读取值的分析技术读取。

首先,声明一个输入值,规定回看时间长度,这个时间长度将在计算基准代码收盘价的百分

比变动时会遇到。

Input: int LookBack( 20 );

然后,声明一个用来引用全局字典实例的对象变量,以及另一个表示计算基准代码表现值的

变量。

Var: elsystem.collections.GlobalDictionary GD(null),

double BenchPerf( 0 );

接下来,在属性编辑器内选择 Analysis Technique,点击事件图标,双击 Initialized 创

建一个只在分析技术第一次运行时执行一次的事件处理方法。

在 AnalysisTechnique_Initialized 方 法 内 , 添 加 一 个 语 句 , 它 包 括 一 个 双 参 数

GlobalDictionary Create 方法并且将新的“myAll”实例赋值给对象变量 GD。

method void AnalysisTechnique_Initialized( elsystem.Object

sender,

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
105
EasyLanguage 对象自学课程(译)
elsystem.InitializedEventArgs args )

begin

GD=elsystem.collections.GlobalDictionary.Create(true,"myAll

");

接下来的一系列语句检查字典内是否已经包含项目名“TopSymbol”(如果另一个 GDWrite

指标在别处运行的话就有可能)。如果该项目不存在,将它和相关的“TopValue”项目添加

进字典。记住,因为这些 EasyLanguage 语句在 AnalysisTechnique_Initialized 方法中,

它们只在分析技术加载时执行。

If GD.Contains("TopSymbol") = false then begin


GD.Add("TopSymbol","");

GD.Add("TopValue",BenchPerf);

end;

end;

一旦图表被加载并到达最后一根图条,下面的语句被执行。它们根据回看时长内收盘价的百

分 比变 化计算 基准 交易代 码的 表现, 将基准 表现 值和 交易代 码名赋 值给 之前 创建的

GlobalDictionary 项目,并从字典中绘制刚刚保存的基准值。第二幅绘图显示一条参考零

线。因为该代码是指标主体的一部分,表现值在每笔交易都进行计算并写入全局字典。

If LastBarOnChart then begin


BenchPerf = PercentChange(Close, LookBack) * 100;

GD.Items["TopValue"] = BenchPerf;

GD.Items["TopSymbol"] = symbol;

plot1(GD.Items["TopValue"] astype double,"Bench Perf");

end;

Plot2(0);

验证指标。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
106
EasyLanguage 对象自学课程(译)

在 30 分钟图形分析上插入指标。

◆课程例题 #18

目标:(GDRead Indicator)

 从另一个分析技术引用 GlobalDictionary 对象

 从指定全局字典中读取更新过的值

指标:“$18_GDRead”

该指标使用一个 GlobalDictionary 对象,每当全局字典的信息改变时从一个分析技术的全

局字典内读取信息。?????

工作区:$18_GDRead

建立雷达屏窗口:

创建:每个交易代码周期均为一日

插入指标:$18_GDRead

组件和属性编辑器设置:

无组件

分析技术:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
107
EasyLanguage 对象自学课程(译)

Initialized: AnalysisTechnique_Initialized

指标练习 #18:“$18_GDRead”

创建一个新指标并命名“#18_GDRead”。

在这个例子中,我们创建对前一个练习中相同 GlobalDictionary 对象的引用,不过这一次

我们在基准表现值每次被其他分析技术改变时读取。

为了少打一些字,你可以从前一个例子中复制输入和变量声明,然后加上保存另外两个表现

值的变量声明以及字典内的基准交易代码名。

Input: int LookBack( 20 );

Var: elsystem.collections.GlobalDictionary GD(null),

double BenchPerf(0), SymRowPerf(0), RelPerf(0),

string BenchSymbol("");

像之前一样,在交易管理器里,选择分析技术,点击事件图标,双击 Initialized 创建一个

只在分析技术初次运行时执行一次的事件处理方法。

在 AnalysisTechnique_Initialized 方法中我们向 GlobalDictionary 中添加相同的两个参

数,然后创建一个引用“myAll”共享字典的方法赋值。接着,将全局字典的两个事件与一

个在全局字典项目被添加或值改变时被调用的处理方法相关联。

method void AnalysisTechnique_Initialized( elsystem.Object

sender,

elsystem.InitializedEventArgs args )

begin

GD =

elsystem.collections.GlobalDictionary.Create(true,"myAll");

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
108
EasyLanguage 对象自学课程(译)
GD.ItemAdded += Global_ItemChanged;

GD.ItemChanged += Global_ItemChanged;

end;

下面的方法必须手动输入,因为创建非组件对象没有自动生成的办法。它将调用 PlotValue

方法,在全局字典项目改变时显示。

method void Global_ItemChanged( elsystem.Object sender,

elsystem.collections.itemprocessedEventArgs args )

begin

PlotValues();

end;

在 PlotValue()方法中,添加语句来从字典中获取基准交易代码名和表现值,前提是它们存

在(如果不存在,这意味着 GD_Write 指标还没有运行)。

Method void PlotValues()

begin

If GD.Contains("TopValue")=true then begin

BenchPerf = GD.Items["TopValue"] astype double;

BenchSymbol = GD.Items["TopSymbol"] astype string;

end;

下面的语句根据回看区间内的收盘价计算雷达屏当前行内交易代码表现。后面接着第二个语

句,这个语句计算当前交易代码与基准交易代码之间表现的差值。

SymRowPerf = PercentChange(Close, LookBack) * 100;

RelPerf = SymRowPerf - BenchPerf;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
109
EasyLanguage 对象自学课程(译)
绘制基准交易代码名和相关表现值。

Plot1(BenchSymbol, "Bench Sym");

Plot2(BenchPerf, "Bench Perf");

Plot3(SymRowPerf, "SymRow Perf");

Plot4(RelPerf, "Rel Perf");

end;

由于表现值是基于全局字典基准值的改变或者来自当前行交易代码值的更新,在你的代码主

体内会有一个额外的 PlotValues()方法调用。

PlotValues();

验证指标。

在雷达屏中插入指标。向雷达屏中添加一组交易代码,把交易代码周期改为 30 分钟以匹配

图表中的基准周期。将图形分析窗口与雷达屏窗口联动,这样在雷达屏中点击一条交易代码

就可以改变图表中的基准交易代码。

Using-(保留字)
保留字 Using 允许你在 EasyLanguage 代码中引用对象类名而不必每次都输入完整的命

名空间部分。

例如,当创建 form 的时候你需要为每个控制的每个变量声明对象类型,例如:

vars: elsystem.windows.forms.Form form1(Null),

elsystem.windows.forms.Button button1( Null ),

elsystem.windows.forms.TextBox textbox1( Null );

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
110
EasyLanguage 对象自学课程(译)
保留字“using”让你所指明对象类型的命名空间部分可以被假定,这样在每个声明中只有

对象类型自己需要被指定,如下所示:

using elsystem.windows.forms;

vars: Form form1(Null),

Button button1( Null ),

TextBox textbox1( Null );

窗体控件(Form Controls)
EasyLanguage 的 Forms 类让你可以创建对象,该对象可以生成独立窗口作为分析技术或

策略的一部分。窗体(Form)对象由容器控制(例如窗体,组,面板)组成,他们用来分组

并显示基础控制(例如按钮,文字区,up/count numeric spinners,组合框,以及更多)。

 Form 窗口在分析技术或策略中创建并激活

 窗体控件让你与 TradeStation 分析窗口建立互动

 每个容器的属性和控制对象可以通过 EasyLanguage 访问

多种外形控制的每一个都可以通过给大小、地址、标签以及特定功能设置对象属性在初始方

法中进行设置。

窗体容器 Form Containers

 窗体 - 一个放置窗体相关的控制和容器的窗口

 面板 - 一个窗体内区域,用于在外观上组织一系列控件

 Group Box - 一块用于在外观上将一系列窗体控件分组的区域

窗体控件 Form Controls

 按钮 - 一个用于生成用户点击事件并调用处理方法的按钮

 复选框 - 一个小方框,可以被用户勾选或取消勾选。单击时它们发送事件,调用

一个用于检查勾选或未勾选状态的方法。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
111
EasyLanguage 对象自学课程(译)
 组合框 - 在下拉列表中向用户显示一个项目列表,用户作出选择时发送事件。

 标签 - 在窗体上显示不可编辑的文本。它们可以用于提供说明或标识周围的控件。

 ListView - 以多列格式显示文本项的集合。用户作出选择时,它们发送事件。

 NumericUpDown - 显示数值,并且,通过使用上下箭头,用户可以以预定义的步骤

值对数值进行快速的递增或递减。

 单选按钮 - 通常放在两个或更多组中,允许用户从一组互斥选项中进行选择。单

选按钮可以在单击时发送事件,也可以在运行时查询它们的状态。

 文本框 - 显示一个可以由用户进行编辑的字符串。

◆课程例题 #19

目标:(Forms 指标)

 创建一系列在弹窗中显示的窗体控件对象

 将事件赋值给由你的代码处理的特定控件

指标:“$19_Simple_Form”

这个例子展示如何用按钮点击改变窗体内的文本

工作区:$19_Simple Form

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
112
EasyLanguage 对象自学课程(译)

建立图形分析窗口:

创建:30 分钟周期

插入指标:$19_Simple Form

组件和属性编辑器设置:

无组件

分析技术:

Initialized: AnalysisTechnique_Initialized

指标练习 #19:$19_SimpleForm

创建一个新指标并命名:#19_SimpleForm。

要想不为每个对象类型引用输入完整的命名空间路径,我们用一个 using 语句指明假定命名

空间。在这里,由于我们将用 Forms 对象,所有我们打算引用的对象将会在 EasyLanguage

对象阶级的 elsystem.window.forms 命名空间部分之内。

using elsystem.windows.forms;

接下来,声明三个对象变量,用来保存我们将会在这个例子中用到的三个窗体控件。这些控

件包括一个含有按钮控件和文本控件的窗体容器。

vars: Form form1( Null ),

Button button1( Null ),

TextBox textbox1( Null );

创建一个分析技术初始化方法,该方法包含只在分析技术第一次运行时执行的语句。用属性

编辑器访问分析技术的事件并双击 Initialized 事件来创建方法。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
113
EasyLanguage 对象自学课程(译)

method void AnalysisTechnique_Initialized( elsystem.Object

sender,

elsystem.InitializedEventArgs args )

begin

在 begin 语句后,我们给每个控件创建一个实例并将它赋值给相应的对象变量。对大多数窗

体控件来说,create 方法用来指定控件显示的初始文本以及控件宽高的像素数。例如,form1

控件(即用来显示其他控件的窗口)的宽度为 300 个像素,高度为 120 个像素,窗口标题栏

显示“Simple Form”。

form1 = form.create("Simple Form", 300, 120);

button1 = button.create("Press the Button", 100, 25 );

textbox1 = textbox.create("Text before pressing button",200,25);

在指定每个控件的尺寸和初始文本后,我们需要指定控件在窗体容器中的位置。这里,左上

角的按钮将从窗体左侧缩进 30 像素,离窗体顶部 10 像素。类似地,文本框控件将缩进 30

像素并离窗体顶部 40 像素。

button1.Location( 30,10 );

textbox1.Location( 30, 40 );

许多控件支持特定事项发生时进行通知的事件,特定的事项包括但不限于点击控件或控件的

一个元素。这里,我们将名为 OnButtonClick 的事件处理方法设置为对 button1 点击事

件回应。重要的是每次按钮被按,相关方法的代码将被执行。

button1.Click += OnButtonClick;

一旦控件被创建、指定位置、并设置好对事件进行回应,我们将它们添加进窗体容器中并展

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
114
EasyLanguage 对象自学课程(译)
示内含位于指定位置的控件的窗体窗口。

form1.AddControl(button1);

form1.AddControl(textbox1);

form1.Show();

end;

现在创建一个事件方法,每当窗体内按钮被点击时该事件方法被调用。该方法参数与其他任

何窗体控件事件处理器通常一样,你可以将它用作其他窗体控件事件处理器的模板。

method void OnButtonClick(elsystem.Object sender,

elsystem.EventArgs args )

begin

接下来的语句会在按钮被按后改变按钮和文本框内的文本。注意我们是如何用按钮文本来判

断状态,并为下一个按钮点击事件设置新按钮文本的。

If button1.Text = "Press the Button" then begin


textbox1.Text = "Text after the button has been Pressed";

button1.Text = "Button Pressed";


End else begin
textbox1.Text = "You Pressed it Again";

button1.Text = "Press the Button";

end;

end;

验证指标,并在图表内插入指标。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
115
EasyLanguage 对象自学课程(译)

◆课程例题 #20

目标:(Forms 指标)

 创建一系列以弹窗显示的窗体控件对象

 将时间赋值给操纵一对趋势线的特定控件

指标:“$20_TrendLine S&R”

该指标在自定义弹窗中用窗体控件改变图表中一对趋势线的位置和样式。

工作表:$20_TrendLine S&R

建立图形分析窗口:

创建:30 分钟周期

插入指标:$20_TrendLine S&R

组件和属性编辑器设置:

无组件

无属性设置

分析技术:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
116
EasyLanguage 对象自学课程(译)

Initialized: AnalysisTechnique_Initialized

指标练习 #20:“$20_TrendLine S&R”

创建一个新指标并命名:#20_TrendLineS&R。

这个例子比上一个简单的按钮和文本框练习要长很多并看起来更复杂,但是主要区别在于创

建的窗体控件的数量和多种对窗体控件事件反馈的事件处理方法。

不论有多少个控件,创建一个控件窗口(容器)并在其中使用控件(按钮、标签、组合框)

共有七个步骤。这些步骤包括:1)为每个控件声明对象变量,2)给每个控件(包括初始文

本和大小)创建新的实例,3)在窗体容器内设置控件位置,4)为控件设置其他参数,5)

将事件方法与控件相关联,6)向容器内添加控件,7)显示控件窗口。

像之前一样,我们为每个假定命名空间添加一个 using 语句,这样在声明对象变量或创建对

象实例的时候将需要重复输入每个对象类型命名空间部分的工作减少到最小。

Using elsystem.windows.forms;

Using elsystem.drawing;

首先,我们声明一系列对象变量用于引用窗体控件对象和它们的属性。这是创建一个窗体的

七个基本步骤中的第一步。

vars: Form form1(Null),

Panel panel1( Null ),

Button button1( Null ),

NumericUpDown spinner1( Null ),

Label label1( Null ),

Label label2( Null ),

Label label3( Null ),

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
117
EasyLanguage 对象自学课程(译)
Label label4( Null ),

Label label5( Null ),

Label label6( Null ),

RadioButton radio1 ( Null ),

RadioButton radio2 ( Null ),

RadioButton radio3 ( Null ),

CheckBox checkbox1( Null ),

CheckBox checkbox2( Null ),

ComboBox combobox1( Null );

接下来,我们声明两个数字变量来跟踪我们将会添加到图表中的趋势线的高位和地位。

vars: TL_High(0.0),TL_Low(0.0);

一个分析技术初始化方法(initialized method)会被创建,它包含了只在分析技术第

一次运行时执行的语句。因为我们只需要执行一次窗体创建和初始化语句,使用初始化方法

是一个理想的选择。使用属性编辑器来访问分析技术的事件,双击 Initialized 事件来

创建一个方法。

method void AnalysisTechnique_Initialized( elsystem.Object

sender,

elsystem.InitializedEventArgs args )

begin

在方法内的第一部分语句中,我们将创建每一个窗体控件对象的实例,包括任何初始文本和

控件的宽度高度,并将它们赋值给对应控件的对象变量。这是创建窗体七步骤的第二步。

form1 = Form.create("TrendLine Support & Resistance",330,200);

panel1 = Panel.create(295,130);

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
118
EasyLanguage 对象自学课程(译)

button1 = Button.create("Reset All", 60, 25 );

spinner1 = NumericUpDown.create(60,25);

label1 = Label.create(symbol,80,18);

label2 = Label.create("Increment +/-",80,18);

label3 = Label.create("Thickness:",60,18);

label4 = Label.create("R: 123.45",60,18);

label5 = Label.create("S: 123.45",60,18);

label6 = Label.create("Brightness",60,18);

radio1 = RadioButton.create("Thin",45,25);

radio2 = RadioButton.create("Medium",65,25);

radio3 = RadioButton.create("Heavy",65,25);

checkbox1 = CheckBox.create("Extend to Left",100,18);

checkbox2 = CheckBox.create("Extend to Right",100,18);

combobox1 = ComboBox.create("",100,22);

然后,我们通过指定在容器内控件左上角的偏移 x、y 来确定每个控件的相对位置。这是创

建一个窗体七个步骤的第三步。

panel1.Location(10,25);

button1.Location(220,95);

spinner1.Location(90,10);

label1.Location(20,5);

label2.Location(20,15);

label3.Location(20,39);

label4.Location(160,15);

label5.Location(230,15);

label6.Location(20,100);

radio1.Location(90,35);

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
119
EasyLanguage 对象自学课程(译)
radio2.Location(145,35);

radio3.Location(215,35);

checkbox1.Location(20,65);

checkbox2.Location(130,65);

combobox1.Location(90,98);

下面的语句为控件设置额外的属性,例如它们的初始显示值或外观。这是创建窗体七个步骤

的第四步。要想获取特定控件可用属性的更多信息,参考 EasyLanguage 字典或者帮助主

题。

label4.ForeColor = Color.Red;

label5.ForeColor = Color.Blue;

panel1.BorderStyle = 1;

spinner1.DecimalPlaces = 2;

spinner1.TextAlign = 2;

spinner1.Increment = .05;

spinner1.Value = .05;

radio1.Checked = true;

checkbox1.Checked = false;

checkbox2.Checked = false;

combobox1.AddItem("Lighter");

combobox1.AddItem("Normal");

combobox1.AddItem("Darker");

combobox1.SelectedIndex = 1;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
120
EasyLanguage 对象自学课程(译)
接下来,我们将事件处理器与多个控件事件相关联,比如当它们被点击或一个控件值改变时。

这是创建窗体七个步骤的第五步。每个事件如何使用的更多信息将会在这个事件中我们检查

事件处理方法时提到。

button1.Click += OnButtonClick;

spinner1.ValueChanged += SpinnerClick;

radio1.Click += Resize_TrendLine;

radio2.Click += Resize_TrendLine;

radio3.Click += Resize_TrendLine;

CheckBox1.Click += Extend_TrendLine;

CheckBox2.Click += Extend_TrendLine;

ComboBox1.SelectedIndexChanged += ChangeColor;

一旦每个控件的属性(大小,位置,初始值,和事件)设定好后,它们就可以被添加进窗体

容器内了。在这个例子中,我们用一个调用面板的临时容器来聚合并持有大部分控件,然后

我们将面板加进下方的窗体窗口容器中。用一个二级容器(例如面板)聚合控件的优势在于,

我们可以轻松地在窗口内将整组控件作为一个整体进行移动,或者复制整个面板以及它其中

的控件并粘贴到另一个窗体中,而不必重新给每个控件排位置。一旦控件被添加到面板中,

一个单独的标签被添加到窗体的顶部,它后面跟着一整个面板容器。这是创建窗体七个步骤

中的第六步。

panel1.AddControl(button1);

panel1.AddControl(spinner1);

panel1.AddControl(label2);

panel1.AddControl(label3);

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
121
EasyLanguage 对象自学课程(译)
panel1.AddControl(label4);

panel1.AddControl(label5);

panel1.AddControl(label6);

panel1.AddControl(radio1);

panel1.AddControl(radio2);

panel1.AddControl(radio3);

panel1.AddControl(checkbox1);

panel1.AddControl(checkbox2);

panel1.AddControl(combobox1);

form1.AddControl(label1);

form1.AddControl(panel1);

在展示窗体窗口之前,它的位置被设定在从屏幕左数 100 个像素、


从屏幕上数 100 个像素,

这样它总是在屏幕上同样的位置出现。窗体属性 TopMost 被设为真,这样窗体窗口浮于其

他窗口上方,而不用当窗体外一个区域被点击后跳到其他窗口后面。这完成了创建和显示一

个自定义窗体窗口的第七步。

form1.Location(100,200);

form1.TopMost = true;

form1.show();

最后,当图表开始计算,一对趋势线在图表左侧远端被创建,每根趋势线的 ID 也被保存。

上趋势线(阻力线)初始颜色被设为红色,下趋势线(支撑线)初始颜色被设为绿色。另外,

因为趋势线会被复位到图表最后一根图条,你会看见它们在这个初始位置。

TL_High = TL_New(Date[10], Time[10], High, Date, Time, High);

TL_Low = TL_New(Date[10], Time[10], Low, Date, Time, Low);

TL_SetColor(TL_High,RGB(255,0,0));

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
122
EasyLanguage 对象自学课程(译)
TL_SetColor(TL_Low,RGB(0,0,255));

end;

接下来,我们开始创建处理每个窗体控件事件的方法。

第一个是回应点击标有“Reset All”的按钮的方法。这个方法中是一个语句,它发出一

个特殊类型的异常信息来使得图表重新加载、窗体控件被重置。

Method void OnButtonClick(elsystem.Object sender,

elsystem.EventArgs args )

begin

throw elsystem.RecalculateException.Create("");

end;

用 默 认 的 sender 和 args 参 数 , 为 窗 体 控 件 事 件 处 理 程 序 创 建 一 个 名 叫

Resize_Trendline 的 方 法 ( 与 前 一 个 方 法 一 样 ) 。 声 明 两 个 本 地 变 量 : 一 个 是

RadioButton 类型的对象变量,另一个是整数。

这方法用 sender 参数获取选中的单选按钮(radio button)然后读取按钮的文本来决

定选中按钮的厚度样式并向 TL_SetSize 传递新的厚度值来改变图表内的上趋势线和下趋

势线的样式。每个单选按钮控件决定趋势线的厚度样式,设置为“Thin”,“Medium”或

“Heavy”。

Method void Resize_TrendLine ( elsystem.Object sender,

elsystem.EventArgs args )

var: RadioButton rButton, int TLSize;

begin

rButton = sender astype RadioButton;

TLSize = 0;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
123
EasyLanguage 对象自学课程(译)

Switch (rButton.Text)

Begin

Case "Thin":

TLSize = 0;

Case "Medium":

TLSize = 2;

Case "Heavy":

TLSize = 4;

End;

TL_SetSize(TL_High,TLSize) ;

TL_SetSize(TL_Low,TLSize) ;

end;

创建 ChangeColor 方法来处理从 ComboBox1 的下拉控件中选取颜色。Case 语句读取选

中 的 ComboBox 项 目 的 序 数 值 并 将 上 、 下 趋 势 线 的 颜 色 设 定 为 合 适 的 RGB

(red-green-blue,红绿蓝)值。

Method void ChangeColor( elsystem.Object sender,

elsystem.EventArgs args )

begin

Switch (combobox1.SelectedIndex)

Begin

Case 0:

TL_SetColor(TL_High,RGB(255,127,127));

TL_SetColor(TL_Low,RGB(127,127,255));

Case 1:

TL_SetColor(TL_High,RGB(255,0,0));

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
124
EasyLanguage 对象自学课程(译)
TL_SetColor(TL_Low,RGB(0,0,255));

Case 2:

TL_SetColor(TL_High,RGB(127,0,0));

TL_SetColor(TL_Low,RGB(0,0,127));

End;

end;

创建 Extend_Trendline 方法来处理复选框控件的选择并根据所选复选框所对应的状态

设置两条趋势线左右延伸值。

method void Extend_TrendLine( elsystem.Object sender,

elsystem.EventArgs args )

begin

TL_SetExtLeft(TL_High,checkbox1.checked);

TL_SetExtLeft(TL_Low,checkbox1.checked);

TL_SetExtRight(TL_High,checkbox2.checked);

TL_SetExtRight(TL_Low,checkbox2.checked);

end;

创建 SpinnerClick 方法来处理数值增减(spinner1)控件的值的改变。这个数值通过

点击上/下微调箭头或在控件数字框内输入新值来改变。新值被传递到另一个更新趋势线的

方法。

method void SpinnerClick( elsystem.Object sender,

elsystem.EventArgs args )

begin

Show_TrendLine(spinner1.value);

end;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
125
EasyLanguage 对象自学课程(译)
Show_TrendLine 方法用来在窗体上显示支撑位和阻力位,并根据 myNum 方法输入参数,

重新在之前图条的 mid-price 上方和下方绘制趋势线。上(阻力)趋势线和下(支撑)趋

势线分别被绘制在 mid-price 上方和下方,距离为偏移量 myNum。每根趋势线在不被延

展的时候均为 10 根图条的宽度。

Method void Show_TrendLine(double myNum)

var: double midprice;

begin

MidPrice = (High[1]+Low[1]) * .5;

Label4.Text = "R: " + NumToStr(MidPrice+MyNum,2);

Label5.Text = "S: " + NumToStr(MidPrice-MyNum,2);

TL_SetEnd(TL_High, Date, Time, MidPrice+myNum);

TL_SetBegin(TL_High, Date[10], Time[10], MidPrice+myNum);

TL_SetEnd(TL_Low, Date, Time, MidPrice-myNum);

TL_SetBegin(TL_Low, Date[10], Time[10], MidPrice-myNum);

end;

我们还想根据实时价格变化更新趋势线位置,所以我们添加一个语句在最后一根图条的每个

价格 tick 调用趋势线绘制方法。

If LastBarOnChart then Show_TrendLine(spinner1.value);

验证指标。

在图表内插入指标。

附加练习部分
国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
126
EasyLanguage 对象自学课程(译)
下面的部分包括附加例题。这些例题将早先介绍的组件和对象与你在继续探索

EasyLanguage 对象的潜能时会感到有用的项目进行了结合。

 撤销委托

待成交委托可以通过 Order 对象的 Cancel()方法进行撤单。访问特定交易代码的待成交

委托的一个常用方法是用 OrdersProvider 为当前交易代码组件创建一个“received

(收到)”委托单的集合。集合内第一个委托单是最近的未成交委托。在该委托的标识符后

加上 Cancel()方法将取消该委托。

OrdersProvider.Order[0].Cancel();

要取消同一交易代码的所有未成交委托,只要简单地循环交易代码的所有“received”委

托单并在每个委托标识符后使用 Cancel()方法。

要想撤掉-替换,你只需用上述方法撤销想撤的委托,然后在新价格发出另一个

OrderTicket。

限价单

任何 OrderTicket 组件都允许你提交限价单。例如,通过 OrderTicket 组件你可以用

属性编辑器来设置委托单参数,
将委托单的 Type 设为 Limit 以及一个特定的 LimitPrice。

然后,用 OrderTicket 的 Send()方法提交限价单。

OrderTicket1.Send();

或者,你可以在发送前直接在代码中修改之前设定的 OrderTicket 的委托单参数,例如:

OrderTicket1.Type= tsdata.trading.OrderType.Limit;

OrderTicket1.LimitPrice = Close - .10;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
127
EasyLanguage 对象自学课程(译)
OrderTicket1.Send();

◆附加例题 #21

目标:(Limit Order - Cancel)

 创建一个简单的订单窗口,它可以提交并撤销一个限价单

 撤销限价单

指标:“$21_LimitCancel”

这个指标用一个 OrderTicket 和 OrdersProvider,从窗体中下一个买入限价单,并允

许撤销待成交委托。

警告:这个指标将产生限价单,确保你没有登录实盘账户。本指标只应被应用于模拟账户。

工作区:$21_LimitCancel

建立图表窗口:

创建:5 分钟区间

插入指标:$21_LimitCancel

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
128
EasyLanguage 对象自学课程(译)
组件和属性编辑器设置:

OrderTicket1:

Symbol: symbol (reserved word for current symbol)

Accounts: iAccounts1 (add default Account as an Input)

Quantity: iQuantity1 (add order Quantity as an Input)

Action: buy

Type: limit

OrdersProvider:

Load : false (IMPORTANT - start with component turned off)

Symbols: symbol (reserved word for current symbol)

Accounts: iAccounts1 (use the same Account Input)

Updated: OrdersProvider1_Updated

Analysis Technique:

Initialized: AnalysisTechnique_Initialized

指标练习#21: $21_LimitCancel

创建一个新指标,将它命名为“#21_LimitCancel”。

本例题结合之前用过的数个组件和对象。

添加一个名为 OrderTicket1 对象的 OrderTicket 组件。

添加一个名为 OrdersProvider1 对象的 OrdersProvider 组件。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
129
EasyLanguage 对象自学课程(译)
使用属性编辑器,按上述要求设置 OrderTicket1 的属性,包括输入初始委托数目 10000

和你的模拟账号。下面两行在你创建输入时被添加进代码中:

Input: int iQuantity1( 100000 );

Input: string iAccount1( "SIM00000" );

使用属性编辑器,按上述要求设置 OrdersProvider1 的属性。为 Updated 事件创建一

个处理方法。注意:确保将 Load 属性设为 false,防止委托单状态事件在窗体元素被创

建之前访问窗体元素。

在属性编辑器内,选择 Analysis Technique 并为 Initialized 事件创建一个处理方

法。

为窗体和交易命名空间添加语句来减少必须打出空间全名的需要。

using elsystem.windows.forms;

using tsdata.trading;

为主窗体声明对象变量以及三个控件,包括一个文本框,一个标签,一个按钮。

vars: Form form1( Null ),

TextBox OrderPx( Null ),

Label label1 ( Null ),

Button button1( Null );

在 AnalysisTechnique_Initialized 方法中,为一个窗体创建对象,窗体中包含设置

限价的控件和发单或撤单的按钮。一旦限价单被产生之后,“Send”(发单)按钮将被重

新标为“Cancel/Replace”(撤单/改单)。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
130
EasyLanguage 对象自学课程(译)
method void AnalysisTechnique_Initialized( elsystem.Object

sender,

elsystem.InitializedEventArgs args )

begin

form1 = form.create("Limit Order", 250, 120);

form1.location(200,200);

form1.topmost = true;

OrderPx = TextBox.create("",50,20);

label1 = label.create("Set Limit Price:",90,20);

button1 = button.create("Place Buy Limit Order", 140, 25 );

OrderPx.Location( 100,10 );

label1.Location(10,12);

button1.Location( 40,40 );

将按钮与事件处理方法相关联,给窗体添加控件,将初始文本框文本值设为当前 inside

bid,在窗体内显示图表。

button1.Click += OnButtonClick;

OrderPx.Text = NumtoStr(InsideBid,5);

form1.AddControl(OrderPx);

form1.AddControl(label1);

form1.AddControl(button1);

form1.show();

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
131
EasyLanguage 对象自学课程(译)

将 OrdersProvider 的 Load 属性设置为 true,这样既然委托单状态事件已被创建,当

设为 true 后它就可以更新窗体。

OrdersProvider1.Load = true;

一个 ReplotButton 方法的调用语句被添加到 AnalysisTechnique_Initialized 方

法并且添加到 OrdersProvider1_Updated 事件处理方法下。

ReplotButton();

end;

添加 OrdersProvider1_Updated 方法。

method void OrdersProvider1_Updated( elsystem.Object sender,

tsdata.trading.OrderUpdatedEventArgs args )

begin

ReplotButton();

end;

ReplotButtons 方法用来根据限价单是否活跃设置按钮的文本。Count 属性大于 0 代表

一个委托单待成交,我们可以检查它是否被接收以及是否为限价委托。如果是,那么按钮文

本被设置为“Cancel Order (撤销订单)”。如果限价单是活跃的,那么将文本框文本

设置为限价单价格,如果没有待成交委托,那么按钮文本被设为“Place Buy Limit Order

(提交买入限价单)”。

Method void ReplotButton()

begin

if OrdersProvider1.Count > 0 AND

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
132
EasyLanguage 对象自学课程(译)
OrdersProvider1.Order[0].State = OrderState.received AND

OrdersProvider1.Order[0].Type = OrderType.limit

then begin

button1.Text = "Cancel Order";

OrderPx.Text=

NumtoStr(OrdersProvider1.Order[0].LimitPrice,5);

end

else begin

button1.Text = "Place Buy Limit Order";

end;

end;

最后,创建一个 OnButtonClick 方法来处理按钮点击。选择 button1 文本来决定发什么

委托单,并确保文本完全匹配。如果最近委托是活跃的限价单,一个按钮点击之后,撤单命

令被发送。如果没有活跃限价单,一个价格为在文本框内指定价格的买入限价单将被发送去

市场。

method void OnButtonClick( elsystem.Object sender,

elsystem.EventArgs args )

begin

If LastBarOnChart then begin

if button1.Text = "Cancel Order" AND

OrdersProvider1.Count > 0 AND

OrdersProvider1.Order[0].State = OrderState.received AND

OrdersProvider1.Order[0].Type = OrderType.limit

then

OrdersProvider1.Order[0].Cancel();

If button1.Text = "Place Buy Limit Order" then begin

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
133
EasyLanguage 对象自学课程(译)
orderticket1.SymbolType = Category;

orderticket1.LimitPrice = StrtoNum(OrderPx.Text);

orderticket1.Quantity = iQuantity1;

orderticket1.send();

end;

end;

end;

验证代码。

在图表内插入指标。

 DateTime

一个 DateTime 对象代表时间上的一个瞬间,用一个日期和一天中的时间表示。值的范围

从 12:00:00 AM,1 月 1 日,公元 0001 到 11:59:59 PM,12 月 31 日,公元 9999 年。

除了能够读取当前日期和时间,一系列属性和方法也被提供,这样你可以轻松地通过任何你

选择的方法设置并显示日期和时间。

Var: DateTime myDateTime(null);

// 根据字符串值设置日期和时间,用另一种格式显示

myDateTime.Value = “12/10/2011 9:35pm” // 设置用户指定的日期和时间

plot1(myDateTime.Format(("%m-%d-%y %H:%M")); // 显示为 12-10-11

21:35

myDateTime = elsystem.datetime.Now // 获取电脑的日期和时间

myDateTime = elsysetm.datetime.CurrentTime // 只获取当前时间

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
134
EasyLanguage 对象自学课程(译)
myDateTime = elsystem.datetime.Today // 获取当前日期,不带时间

 TimeSpan

一个 TimeSpan 对象代表一个时间区间,这个时间区间用来测量日期/时间值之间的天数、

小时数、分钟数、秒数。你可以用一个时间段(time span)来保存两个日期和时间之间

的差值,或者你可以从一个已经存在的日期/时间加上(或减去)一段时间段来指定一个新

的日期/时间。

例如,

Var: TimeSpan myTimeSpan(null), DateTime myDateTime(null);

// 向当前日期加上5天

myTimeSpan.TotalDays = 5

myDateTime = elsystem.datetime.Today + myTimeSpan;

// 计算当前时间和收盘前5分钟之间的时间差

myDateTime.Value = “3:55pm”

myTimeSpan = myDateTime - elsystem.DateTime.CurrentTime;

TokenList

TokenList 对象代表一个值的集合,
它可以通过一个包含逗号分隔的一列单词或数字创建,

或者通过用 Add 属性添加值。

例如,你可以创建一个包含四个交易代码的 TokenList 并从得到的集合中用标上序号的属

性访问任何值。

Var: TokenList myList(null);

myList = TokenList.Create(“msft,csco,dell,ibm”); //向TokenList

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
135
EasyLanguage 对象自学课程(译)
中加载值

print( myList.Item[1] ); // 打印第二个项目“csco”

◆附加例题 #22

目标:(AlarmClock)

 根据用户提供的时间(或日期和时间)创建一对闹钟

指标:$22_AlarmClock

该指标用 DateTime 和 TimeSpan 对象获取当前时间和一个目标时间(可选择日期)之间

的时间差值。它设定一个在目标时间到后调用事件方法的倒数计时器。

工作区:$22_AlarmClock

建立窗口:

创建:图表或雷达屏

插入指标:$22_AlarmClock

组件和属性编辑器设置:

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
136
EasyLanguage 对象自学课程(译)
Timer1:

Interval : 1000 (default value)

AutoReset: True " "

Enable: False (start with timer off)

Elapsed: Timer1_Elapsed

Timer2:

Interval : 1000 (set to count once a second)

AutoReset: True " "

Enable: True (start timer with indicator)

Elapsed: Timer2_Elapsed

AnalysisTechnique:

Initialized: AnalysisTechnique_Initialized

指标练习 #21: $22_AlarmClock

创建一个新指标并命名为:#22_AlarmClock。

添加一个名为 Timer1 的 Timer 组件。添加另一个名为 Timer2 的 Timer 组件.

使用属性编辑器,按上述要求设置 Timer1 和 Timer2 的属性,包括为每个 Elapsed 事件

添加一个处理方法。注意 Timer1 一开始不会被启用。

使用属性编辑器,选择 AnalysisTechnique 并为 Initialized 事件创建一个处理方法。

为两个目标时间创建输入。目标时间可以包括一个可选填的日期,例如“8/22/2012

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
137
EasyLanguage 对象自学课程(译)
。第一个目标应该是较早的时间(或日期)
9:25am” ,因为第二个目标时间只会在第一个目

标时间到期后被评估。默认情况下,目标时间被设在常规开盘和收盘时间前的五分钟。

input: string TargetTime1("9:25am"), string TargetTime2("2:55pm");

声明对象变量来保存目标时间,到目标时间的初始时间差,以及闹钟时间的列表。尽管本例

题只用两个闹钟,你可以轻松地向列表对象中添加其他时间。

var: elsystem.DateTime myAlarmTime(null),

elsystem.TimeSpan myTimeSpan(null),

tsdata.common.TokenList myAlarmList(null),

为闹钟时间到后播放的声音文件名以及闹钟列表中活跃闹钟的序数声明两个额外变量。

string AlarmSound("alarmclockbeep.wav"),

intrabarpersist int myAlarmIndex(0);

在 Initialized 方法中,将闹钟列表创建为 TokenList 对象的一个实例,并用第一个目

标时间作为列表的初始值。使用加等运算符将第二个目标时间附加到闹钟列表中。注意:如

果你选择添加额外时间,就在此处进行添加。

method void AnalysisTechnique_Initialized( elsystem.Object

sender, elsystem.InitializedEventArgs args )

begin

myAlarmList = tsdata.common.TokenList.create(TargetTime1);

myAlarmList += TargetTime2;

使用 GetAlarmTime 来获取列表中下一个还没到的目标时间。用 GetAlarmSpan 来计算

当前时间和目标时间之间的时间差。然后,用 SetAlarm 来设置并激活闹钟倒数。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
138
EasyLanguage 对象自学课程(译)

myAlarmTime = GetAlarmTime(myAlarmList);

myTimeSpan = GetAlarmSpan(myAlarmTime);

SetAlarm(myTimeSpan);

end;

然后,向与 Timer1 相关联的事件处理方法中添加下面的语句。当时间到后,它会在打印

日志中打印出闹钟时间,播放输入中指定的声音文件,并设置下一个闹钟时间段。

method void Timer1_Elapsed( elsystem.Object sender,

elsystem.TimerElapsedEventArgs args )

begin

print("ALARM sounded at - ",

elsystem.datetime.currenttime.tostring());

condition1 = playsound(AlarmSound);

myAlarmTime = GetAlarmTime(myAlarmList);

myTimeSpan = GetAlarmSpan(myAlarmTime);

SetAlarm(myTimeSpan);

end;

Timer2_Elapsed 方法每一秒执行一次。它获取下一个闹钟目标的时间段并建立一个含有

剩余天数、小时数、分钟数、秒数的字符串,或一条表示所有闹钟均过期的信息。

method void Timer2_Elapsed(elsystem.Object sender,

elsystem.TimerElapsedEventArgs args)

var: string TimeLeft, elsystem.TimeSpan TS;

begin

TS = GetAlarmSpan(myAlarmTime);

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
139
EasyLanguage 对象自学课程(译)

If myTimeSpan.TotalSeconds > 0 then

TimeLeft = TS.Days.tostring() + "d "

+ TS.Hours.tostring() + "h "

+ TS.Minutes.tostring() + "m "

+ TS.Seconds.tostring() + "s "

Else

TimeLeft = "No alarms active";

第一幅绘图显示剩余时间。

plot1(TimeLeft,"Count Down");

第二幅绘图显示实际目标时间以及目标数 T。

If myAlarmTime.ELDateTimeEx>=1 then

plot2(myAlarmTime.format("%m/%d/%y %H:%M T"

+ myAlarmIndex.tostring()),"Target")

else

plot2(myAlarmTime.format("%H:%M T"

+ myAlarmIndex.tostring()),"Target");

end;

创建一个方法,该方法将时间段(剩余时间)转换为毫秒,赋值给 Timer1 计数器 Interval

属性,并将 timer 打开。如果剩余时间小于 1 秒(<1000ms),timer 被关闭。

method void SetAlarm(elsystem.TimeSpan myTimeSpan)

begin

Timer1.Interval = myTimeSpan.TotalMilliseconds;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
140
EasyLanguage 对象自学课程(译)
If Timer1.Interval < 1000 then

Timer1.Enable = false

Else

Timer1.Enable = true;

end;

GetAlarmTime 方法返回一个代表下一个闹钟目标时间的对象。第一个语句创建一个名为

myAlarmTime 的 DateTime 对象。For 循环会一次循环列表中的闹钟时间(token list

里的字符串)并用 DateTime.Parse 方法将闹钟字符串转换为一个 date time 对象。

method elsystem.DateTime GetAlarmTime(tsdata.common.tokenlist

myAlarmList)

begin

myAlarmTime = elsystem.DateTime.Create();

For myAlarmIndex = 0 to myAlarmList.Count-1 begin

myAlarmTime =

elsystem.datetime.Parse(myAlarmList[myAlarmIndex]);

调用 GetAlarmSpan 会获取剩余时间并且如果时间段是一个正数将返回闹钟时间。如果找

不到正值时间段,返回一个空白闹钟时间。

myTimeSpan = GetAlarmSpan(myAlarmTime);

If myTimeSpan.TotalSeconds>0 then begin

myAlarmIndex = myAlarmIndex + 1;

Return myAlarmTime;

end;

end;

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
141
EasyLanguage 对象自学课程(译)
return myAlarmTime;

end;

GetAlarmSpan 方法返回一个代表现在和 myAlarmTime 之间剩余时间的对象。第一个语

句创建一个名为 myTimeSpan 的 TimeSpan 对象。如果到下一个闹钟的天数大于等于 1,

时间段将被用完整的日期和时间的方式计算。如果只有时间部分,时间段从当前时间开始计

算。

method elsystem.TimeSpan GetAlarmSpan(elsystem.DateTime

myAlarmTime)

begin

myTimeSpan = elsystem.TimeSpan.Create();

If myAlarmTime.ELDateTimeEx >= 1 then

myTimeSpan = myAlarmTime - elsystem.datetime.now

Else if myAlarmTime.ELTime > 0 then

myTimeSpan = myAlarmTime - elsystem.datetime.currenttime;

Return myTimeSpan;

end;

验证指标。

在图表或雷达屏中插入指标。使用输入值改变闹钟时间。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
142
EasyLanguage 对象自学课程(译)

 分析技术 - Unitialized 事件

一个分析技术(Analysis Technique)的 Unitialized 事件被用来调用一个事件处理

方法,该方法包含在分析技术计算结束前执行的代码。

AnalysisTechnique_Uninitialized 事件处理方法可以被用来在分析技术关闭前保

存数据,或执行任何可能被要求运行的清理代码。这在分析技术被更新后,被从分析窗口内

移除后,或在窗口、工作区、桌面被关闭后均可能发生。但是,如果出现异常错误,有时候

uninitialized 事件处理方法不会被调用。

 Try-Catch

Try-Catch 码块被用来在 Try 码块内测试一系列代码语句的执行这样你可以在 Catch 码

块中处理任何失败、错误或异常。

例如,当从一个组件中访问数据时你可能会想测试一个预料中的错误条件。如果特定条件发

生,你可以立一个后面可用的 flag 来防止更多计算或者向用户打印一个自定义信息。

try

Value1 = FQ1.Quote[FundamentalField].DoubleValue[0] ;

OkToCalculate = true ;

catch ( NoFundamentalDataAvailableException NFDEx )

OkToCalculate = false ;

Print( "NMF - No fundamental value for primary symbol." ) ;

end ;

或者,你可能会想通过测试文件读取语句的成功与否并在文件不存在时创建一个来判断文件

是否存在。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
143
EasyLanguage 对象自学课程(译)
try

doc.Load(“c:filename”); // 尝试读取一个文件

catch(elsystem.io.filenotfoundexception ex)

doc.Save(“c:filename”); // 如果没找到,创建文件

end;

 XML 对象

EasyLanguage 支持一系列允许你创建 XML 数据结构、保存进文件并在之后进行读取的对

象。EasyLanguage 中的 XML 对象基于常用的 XML Document Object Model,它包含

节点,元素,属性,以及其他余 XML 数据层次相关的项目。

XML 的基本建立码块是元素,它由放置在一对标签中间的数据组成。开始标签由一对包含元

素名的尖括号组成,例如<symbol>,结束标签也一样,不过需要在元素名前加上额外的斜

杠,例如</symbol>。

一个 XML 数据结构有多个元素组成,每个元素都代表数据,这些数据可以是单个一条信息,

例如一个单词或数字,也可以是其他有附加数据的子元素。在 EasyLanguage 中,有 XML

对象来创建元素,在数据结构中添加或删减元素,并且在元素内读取或写入数据。

例如,下面的 XML 数据结构由一个包含了内含三个相关数据元素(name, date, price)

的 symbol 元素的根(root)元素组成。

<root>

<symbol>

<name>MSFT</name>

<date>9/10/2011</date>

<price>34.56</price>

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
144
EasyLanguage 对象自学课程(译)
</symbol>

<root>

另外,一个开始标签可以包含位于尖括号内的额外信息,这被称为属性。例如,下面的代码

包含两个 step 元素,第一个元素有一个数字 1 的属性,第二个有一个数字 2 的属性。

<root>

<step number=”1”>First Item</step>

<step number=”2”>Second Item</step>

</root>

◆附加练习 #23

目标:(XMLPersist 指标)

 创建一个 XML 文件来在指标重新计算时保存并恢复数据

指标:$23_XMLPersist

该指标在一个指标退出或刷新(uninitialized)并在指标重新开始(Initialized)

后可以回读时,用 XML 对象来保存当前交易代码的信息到一个 XML 文件中。例如,这允许

你留存那些当前指标中含有的并且下次运行时你希望能够记住的交易代码值。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
145
EasyLanguage 对象自学课程(译)

工作区:$23_XMLPersist

建立窗口:

创建:30 分钟区间

插入指标:$23_XMLPersist

组件和属性编辑器设置:

无组件

AnalysisTechnique

Initialized: AnalysisTechnique_Initialized

Uninitialized: AnalysisTechnique_UnInitialized

使用说明:

当你第一次将指标应用到一个新的图表或代码上时,指标的状态行将只会显示代码名,没有

另外的信息。当你退出图表,或按下 Ctrl+R 来刷新图表,收盘价连同当前时间和日期被

保存到 XML 文件。当下一次交易代码被绘制在图表上时,XML 文件内保存的价格和时间就

显示在子图的状态行交易代码名后面了。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
146
EasyLanguage 对象自学课程(译)

指标练习#23:$23_XMLPersist

创建一个新指标并命名:#23_XMLPersist。

为 XML 命名空间添加一个 using 语句,这样就不用打出 XML 对象全名了。

using elsystem.xml;

为一系列将会用来在外部 XML 文件中创建并处理数据的 XML 对象声明对象变量。

var: XmlDocument doc(null),

XmlElement root(null),

XmlElement eLevel1(null),

XmlElement eLevel2(null),

XmlNode nNode(null);

声明另一个将被用于测试 XML 数据文件是否存在的变量。如果不存在,文件需要被创建。

Var: bool filefound(false);

为 XML 文件名声明一个输入值。

input: string xmlFileName("C:\RefSym.xml");

使用属性编辑器,选择 AnalysisTechnique 并为 Initialized 事件创建一个处理方法。

然后,为 Uninitialized 事件创建另一个处理方法,它将在我们推出或重新计算一个分

析技术时被调用。

在 Initialized 方法中,创建一个 xml 文件对象实例并将找到文件的 flag 设为 true。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
147
EasyLanguage 对象自学课程(译)

method void AnalysisTechnique_Initialized( elsystem.Object

sender,

elsystem.InitializedEventArgs args )

begin

doc = new xmldocument;

filefound = true;

接下来,我们将用 Try-Catch 语句检查 XML 文件是否已经存在。如果 Try 子句里的

doc.Load 调用失败,那么在 catch 子句找到文件 flag 被设为 false。

try

doc.Load(xmlFileName);

catch(elsystem.io.filenotfoundexception ex)

filefound = false;

end;

如果文件没有找到,我们通过顶一个名为“data”的 root 对象进行创建并保存到新的 XML

文件中。

If filefound = false then

Begin

root = doc.CreateElement("data");

doc.AppendChild(root);

doc.Save(xmlFileName);

End

如果文件已经存在,将文件的 XML 结构读取到 root 对象中。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
148
EasyLanguage 对象自学课程(译)
Else

Begin

root = doc.DocumentElement;

end;

FindSymbol 方法返回包含当前交易代码数据的节点。如果交易代码之前没有被用过或者

文件刚刚被创建,数据为空。

nNode = FindSymbol();

end;

当指标被关闭,例如当退出 TradeStation 或者不论什么时候当指标被重新计算比如图表

刷新时,AnalysisTechnique_UnInitialized 方法被执行。在这个方法中添加一个

SaveSymbol()的调用。

method void AnalysisTechnique_UnInitialized( elsystem.Object

sender, elsystem.UnInitializedEventArgs args )

begin

SaveSymbol();

end;

在 SaveSymbol 方法中我们将更新我们想保存的数据并在 XML 文件中写出数据,这个例子

中是当前的日期/时间以及收盘价。

Method void SaveSymbol()

begin

nNode.Item["date"].InnerText =

elsystem.datetime.now.Format("%m-%d-%Y %H:%M");

nNode.Item["price"].InnerText = Close.tostring();

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
149
EasyLanguage 对象自学课程(译)
doc.Save(xmlFileName);

end;

FindSymbol 方法被用于寻找保存代码的数据,或为新代码创建空白数据,并为要求的数

据返回 XML 节点。头两个本地变量被用来寻找并保存于当前交易代码匹配的元素的序数。

接下来的本地变量声明一个保存可供查询的一列 symbol 元素的 XML 对象。最后的变量保

存包含方法返回的代码数据的节点。

Method xmlNode FindSymbol()

var: int iIndex, int sNumb, XmlNodeList tList, XmlNode tNode;

begin

头几个语句获取一列一级 symbol 元素并在列表中循环通过来检查是否有任何 name 次元素

与当前代码匹配。如果找到的话,变量 sNumb 被设为代码(symbol)元素的序数。

tList = root.GetElementsByTagName("symbol");

sNumb = -1;

for iIndex = 0 to tList.count-1 begin

If tList.ItemOf[iIndex].Item["name"].innertext=symbol then

sNumb = iIndex;

end;

如果交易代码没有在列表中找到,一个名字、日期和价格附加为二级子元素的新的 symbol

元素被创建。新的 symbol 元素结构被附加给 root 并保存到文件。

If sNumb = -1 then begin

eLevel1 = doc.CreateElement("symbol");

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
150
EasyLanguage 对象自学课程(译)
eLevel2 = doc.CreateElement("name");

eLevel2.innertext = symbol;

eLevel1.AppendChild(eLevel2);

eLevel2 = doc.CreateElement("date");

eLevel1.AppendChild(eLevel2);

eLevel2 = doc.CreateElement("price");

eLevel1.AppendChild(eLevel2);

root.AppendChild(eLevel1);

doc.Save(xmlFileName);

新创建的代码元素结构被赋值给本地方法对象 tnode,或者如果代码之前就存在,tnode

被设置为标有序数的代码元素。方法的返回值被设给节点。

tNode = eLevel1;

end

Else begin

tNode = tList.ItemOf[sNumb];

End;

Return tNode;

end;

最后,创建一个绘制当前节点值的方法。对已经存在或已经刷新的交易代码来说,日期和价

格会显示为保存过的值。注意对 PlotValues()的调用是你的 EasyLanguage 代码主体

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
151
EasyLanguage 对象自学课程(译)
的唯一语句。

Method void PlotValues()

begin

plot1(nNode.Item["name"].Innertext,”Symbol”);

plot2(nNode.Item["date"].InnerText,”Saved Date”);

plot3(nNode.Item["price"].InnerText,”Saved Price”);

end;

PlotValues();

验证指标。

在图表中插入指标。你会发现新创建的 XML 文件被添加到指定路径并且会包含当前交易代

码的初始 XML 数据。

国信证券交易服务团队翻译 联系邮箱:tradestation@guosen.com.cn
152

You might also like