[TOC]
大家好,从今天起,我们开始My语言的学习。My语言是优宽平台开发的一套,对麦语言的兼容并增强的一种程序化交易语言。My语言很有意思,它倡导的是积木式的编程理念,把复杂算法封装到一个个的函数里,采用“小语法,大函数”的构建模式,所以代码量大大缩减。语法虽然简单,但是配合专门的程序化数据结构,和丰富的金融统计函数库,同样可以支持逻辑复杂的金融应用。在进行代码编写的过程中,我们可以通过把算法封装到一个个函数里,只需要像“积木式”的调用这一行行函数,就可以轻松实现策略逻辑。
我们可以举例示范一下分别使用JavaScript语言和My语言,进行一个完整交易策略的编写过程。这里我们展示一下著名的Dual Thrust策略,这个策略的思路并不复杂,通过监测实时的价格突破上轨或者下轨的时候,进行相应的交易操作。在策略代码中,首先设置目标合约,这里我们设置为甲醇的主力合约,获取k线数据,然后利用k线数据进行信号计算,在DT策略当中,利用k线计算出来上轨和下轨,当实时的价格突破上轨或者下轨的时候,确定入场开仓和出场平仓的信号;根据信号执行具体交易的操作,并且为了实时展示交易的状态,我们还需要加上信号指标的绘制和具体持仓的统计,以及收益的动态展示。这样一套流程下来呢,使用JavaScript语言编写各个功能模块的函数大概需要180行的代码,而使用My语言,可以直接调用函数,就像搭积木一样,10行代码就可以完成DT策略的编写。我们回测运行一下,可以看到My语言实现了同样的功能。
这是因为My语言作为专业的交易语言,对很多的接口和函数进行了封装,比如合约设置,数据的获取,收益展示和图表的展示,这些功能对于JavaScript语言和python语言来说,我们需要使用底层的代码进行实现。而在My语言当中,后台高度封装的功能模块,在调用以后会自动帮我们进行呈现,我们呢,只需要更加关注于策略逻辑的设置和具体交易的操作,这样呢,大大的简化了代码的编写难度和数量。在同时,My语言可以与其它编程语言进行兼容,使得策略可以在My语言的基础上,还可以召唤JavaScript大法,自定义功能模块。通过集这些编程语言优势于一身,所以My语言很适合用于入门级程序化交易。
当然一个语言也并不是完美的,作为高度封装的语言,My语言的灵活性会受到一定的限制,和Pine语言一样,My语言只支持单一方向的持仓,策略的品种也只能为单品种,因此我们在搭建量化策略的时候,需要考虑到不同语言的局限。
在优宽平台,已经支持My语言,并且也可以支持期货实盘的运行,一年实盘的花费大概在千元左右;并且优宽也拥有完整的策略研究和回测的平台,在这里学习测试My语言策略是完全免费的,所以对于量化新手同学和My语言的老玩家都是非常适合的。因此,本系列的课程我们将在优宽平台从零开始My语言的学习,话不多说,我们直接开始吧。
注意:优宽平台的My语言并不能支持所有麦语言的函数,因此,当移植文华麦语言策略到优宽平台的时候,我们需要进行一定的改写和完善。
首先我们进入优宽平台,需要注意的是国内站cn,支持商品期货的交易,注意不是国际站com,两个平台面对的交易市场是不一样的。在注册完成账号以后点击登录。作为一个多功能开放的量化平台,这里有策略广场,有很多的策略让我们回测,验证和改造,实盘围观,包含对接真实市场的量化实盘交易,文库中会及时更新前沿的量化知识,社区里大家可以提问量化的知识和问题,我们的量化大佬会及时的帮助大家解决大家的疑问,在线公开课里面包含了我们自主开发的量化课程,适合于不同语言不同层次的量化选手,API文档里包含了优宽平台具体使用的方法,这些资源呢,可以帮助我们学习观摩多种语言,包括python,pine,JavaScript语言,My语言等等的,多种金融市场包括商品期货,期权,股票等量化知识和策略,重点是,都是免费的,大家可以自由的探索和学习。
怎样编写策略呢,可以看到左边栏有一系列的类目,可以帮助我们进行策略的编写,回测和实盘的运行。在量化分析起始的阶段,我们首先进行模拟策略的学习和编写,等到后续策略测试成熟,我们搭建实盘对接真实的市场进行量化交易。
我们进入策略的编写页面,这里的快捷入口点击新建策略。可以看到这里有很多的语言选择,这里的语言选择为My语言,我们就要在这里开始My语言的学习。可以看到这里有一个策略样例,如果我们想查看这个样例策略的运行效果。这里有模拟回测的系统,点击“开始回测”,到达配置参数页面,这里我们定义策略的参数,比如回测时间,k线周期,平台等,点击添加平台;点开My语言交易类库,可以看到具体的交易设置,期货选项,实盘选项等,方便My语言的交易操作,这里的参数我们后续会为大家进行详细的介绍。我们这里选择默认的甲醇主力合约,点击开始回测。不需要进行额外的api设置或者回测环境的搭建,可以看到我们的策略直接获取数据就实时的运行起来。这样呢,就可以立即检验策略代码的运行成果。运气不太好,我们的示范策略在甲醇期货品种上吃了一点小亏。不过随着我们知识的学习和策略的完善,我相信大家一定可以开发出更好的策略。
当我们测试完成一个策略,我们定义它的名称,然后进行保存到我们的策略库里面。以上就是我们策略的编辑页面,可以看到相对于其他的My语言量化交易软件,我们的页面比较简洁,使用更加简单,并且模拟策略的编写和运行一直是免费的,大家可以将自己的交易思想和理念编写成为各种量化策略,然后进行模拟系统的回测,等到策略运行无误,第二步就可以运行到仿真实盘,仿真的实盘是使用模拟的交易所账户,比如N视界,上期模拟,对接市场进行的模拟实时交易,可以检验策略在市场中的健壮性和盈利的稳定性;第三步等到策略真正的验证成熟,我们可以使用我们的策略,对接真实的市场开始真正的考验。但是我们还是要记得,金融有风险,入市需谨慎。
怎样应用我们的策略配置仿真或者真实的实盘呢?在优宽平台,实盘运行是需要三大件的。刚才的策略,作为最重要的一环我们已经编写完毕,接下来我们需要进行交易所和托管者的配置。交易所就是我们仿真账号和真实账户开户的交易所,仿真账号我们刚才提到,可以使用N视界和上期模拟,当申请好账号就可以直接使用;真实的账户我们需要看穿式监管的认证,才可以进行量化交易。在社区里,有两篇帖子详细介绍了交易所的配置步骤,大家可以查看一下。当我们配置完成交易所,交易所的具体标志会呈现出来。
最后一个部分是托管者的配置,托管者可以理解为我们的交易策略的执行者,负责复杂的数据请求、数据接收、网络链接、日志回传等等工作。托管者的详细配置步骤,在前面的课程中有提到过,大家可以看一下。当配置好以后,在托管者页面会显示配置完成的托管者名称。
《商品期货量化交易实践系列课程--托管者程序部署与Docker部署》
最后一步,我们就要建立My语言的实盘策略了。点击实盘,点击新建,定义实盘名称,选择k线周期,运行策略,刚才编写好的My语言策略,托管主机,交易类库里面可以使用默认的参数;交易平台可以选择一个仿真的账户,上期模拟。点击创建实盘,这样我们的My语言策略就可以对接市场,运行起来。在优宽平台运行运行实盘是很便宜的,每小时0.125元,一天3块钱,比大多数一手期货合约的手续费都低。
以上呢,就是在优宽平台完成的,一个My语言策略从策略编写,模拟回测到实盘运行的完整步骤。希望如此便捷的量化实盘的搭建过程,可以帮助到真心想入门量化学习的伙伴。虽然这一路可能会有很多的坎坷和困难,我们在后台会热心的帮助大家解决在量化学习中碰到的难题。当然平台也不是尽善尽美的,大家有问题,也可以提出宝贵的意见,我们的工程师也会尽力提升大家的量化体验。希望大家一起努力,砥砺前行。
上节课我们深入了解了My语言的特点,以及如何在优宽平台进行My语言策略的编写、回测和实盘的创建。现在,大家可能跃跃欲试,想要立即编写自己的My语言策略。然而,在此之前,我们还需要对My语言的语法结构进行深入的了解。只有在对My语言的语法有清晰的认识的基础上,我们的策略才能更加准确、高效地实现预期的目标。
在本节课中,我们将详细解析My语言的语法结构。大家也不用太过于担心,相对于python语言和JavaScript语言,My语言的语法规则更加清晰明了,专门针对交易领域的编程需求进行了优化。通过这些知识的学习,我们将能够更好地理解和运用My语言,为我们的策略编写提供坚实的语言基础。请注意,本节课的语法讲解内容对于编程大拿可能过于基础,大家可以根据自己的水平有选择性的跳过~~
第一个我们要认识的概念是变量,变量是电脑内存中开辟的一块用来存数据的空间,简单说就是用来保存数据的。
每一个变量需要有一个合适的名称,这样在工作的过程当中可以实时的调取和安排任务。首先呢,我们来看一下变量的命名规则。在编写开始,我们首先要确定需要在半角输入法,也就是英文状态下状态下进行编写。在My语言中,我们可以使用中文对变量进行命名,这个时候可以使用中文输入法,比如设置优宽中文变量,但是这里的赋值符号是英文格式的“:=”,变量保存的数据是数值666,最后需要加上分号,也是英文格式的,这样一个变量就命名完成。如果我们使用中文格式的符号,我们运行一下会报错。
不过更加推荐的是使用英文加上下划线命名,这样更符合传统代码的书写习惯,这里使用youquant_index赋值为666。
优宽:=666;
//优宽2:=666;
youquant_index:=666;
需要注意的是,变量命名也是有一定规范的:不允许使用系统“保留字”(比如内置参数名或者函数名)。例如My语言的内置参数Close收盘价,和它的简写形式大写C,以及内在函数MA,这个是用来计算移动均值的函数等等。此外,变量的名称不能相互重复,也不允许纯数字或者数字开头。最后不允许很长,不同的系统长度限制不同。
数据类型是一个基础的概念,在编写中当我们将一个明确的数据赋值给变量时,这个变量也就变成了数据自身的类型。我们来看下有哪些数据类型:
第一种数值类型我们最为熟悉,包括整数、浮点数(小数)。
// 整数
int:=2;
// 小数
float:=3.1;
第二种字符串类型:必须使用’'包裹。需要注意的是字符串类型不允许直接使用,需要配合函数输出到视图中。
比如我们不能直接设置一个变量是字符串,这样回测会直接报错,我们需要配合函数使用。这里的INFO是日志输出的作用,至于这个为什么会输出这么多字符呢,这就涉及到My语言专业的金融属性了,我们后续会为大家讲解。
//abd = 'youquant';
INFO(1,'youquant');
第三种数据类型是布尔类型,使用1(代表真)或者0(代表假)。例如:设置变量大写AB等于1大于10,这个判断是错误的,所以AB变量会返回0。这里我们使用INFO进行变量的输出,可以看到这里我们使用的变量是小写的ab,运行一下,可以看到返回的值都是0。所以在my语言当中,是不区分大小写的,所以我们需要格外注意一下。
AB:=1>10;
INFO(1,ab);
我们知道金融的数据是一个时间流的数据,相对于在策略中不变化的常量,我们也可以使用变量的形式定义时刻变化的数据的存在。这里我们举例,使用constant定义数值常量1,使用newClose定义Close,close是my语言的内置变量,代表收盘价的最新价;newBu,布尔变量,定义最新的收盘价close是否大于开盘价open,也就是当前k线是否是阳线。运行一下代码,可以看到伴随时间流的更新,我们可以得出常量的值是不变的,数值变量和布尔变量都会随着时间的更新进行变化。
constant:=1;
newClose:=Close;
newBu:=Close > Open;
INFO(1,constant,'常量');
INFO(1,newClose,'数值变量');
INFO(1,newBu,'布尔变量');
了解完变量的命名规则和数据的类型以后,我们来看下具体操作符的使用。操作符将函数连接成为模型,操作符分为定义变量操作符,数学运算操作符和逻辑判断操作符。
定义变量操作符用于给某个变量赋值,刚才我们使用到的都是“:=”符号,其实除了这种符号,还有其他的赋值符号我们可以使用。在讲解不同类型的赋值符号之前,我们首先需要了解不同的赋值符号是和My语言的画图系统相关的。我们呈现一个主图和幅图的图像,这里上面的k线图呢,就是主图,主图上面可以画一些指标,比如画出每一根k线的收盘价,可以看到在主图k线图进行呈现;而幅图用来呈现和主图数值范围不一致的指标,比如我们想画收盘价减去3000,如果我们画在主图上,这样主图的y轴就不是2300,而是从-600左右开始,画面会出现协调不一致的情况,所以我们可以使用幅图的形式,这样可以更清晰的看到不同的指标变化情况。这里关于指标在主图,副图或者在图像上不呈现指标,就涉及到定义变量的操作符。
^^
首先我们来看在主图上进行指标的赋值和绘制,两个上箭头符号给变量赋值并且输出到主图中。这里赋值newClose为Close收盘价。
newClose^^Close;
:
如果想画在副图上,使用冒号代表赋值并且输出到图(副图)中。这里赋值newClose_3000为Close收盘价减去3000。
newClose_3000:Close - 3000;
..
两个英文等号给变量赋值并且显示变量名、数值在图表中,但是不画图到图表(主图、副图…)中。这里赋值newClose_100为Close收盘价减去100。可以看做图像的左下角显示设置的数值,但是不呈现相应的图像。
newClose_100..Close - 100;
:=
最后一个就是我们前面一直使用到的,冒号等号的形式,这个赋值的数值不输出到图(主图、副图)中,也不显示在状态栏表格中。可以看到在图表中都没有呈现。
newClose_200:=Close - 200;
这个我们比较熟悉,这是完成基本的算术运算符号,加减乘除。
addValue:= 1+1; // 返回 2
minusValue:= 2-1; // 返回 1
multiValue:= 2*2; // 返回 4
divValue:= 4/2; // 返回 2
这类操作符用在条件表达式中。用于判断变量之间的关系。具体的返回值是布尔类型的,不是true(1)、就是false(0)。
具体的包括:
操作符 | 含义 |
---|---|
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
= | 等于 |
<> | 不等于 |
&&(and) | 逻辑与 |
||(or) | 逻辑或 |
前面这六个是关系运算符,是双目运算符,用于判断两个数据之间的关系。我们可以举例示范一下:
rv1:=2>1; // 返回true,1
rv2:=2<1; // 返回false,0
rv3:=9>=10; // 返回false,0
rv4:=9<=10; // 返回true,1
rv5:= 9=10; // 返回false,0
rv6:=9<>10; // 返回true,1
当用来判断多个条件的时候,我们可以使用&&或者and符号判断不同条件同时成立的情况,只有多个条件同时成立的话,会返回true;只要其中有一个条件不成立,就返回false:
另外一种情况,||
逻辑非,在多个条件中只要有一个条件成立就可以返回1,如果都不成立,返回false0。
rv7:=9<10 && 10<11; // 返回true,1
rv8:=9<10 && 10>11; // 返回false,0
rv9:=9<10 || 10<11; // 返回true,1
rv10:=9>10 || 10>11; // 返回false,0
操作符使用的时候一般有顺序的,使用()
运算符,在计算时会先计算括号内的表达式。比如下面第一个虽然前两个条件不成立,但是最后一个条件成立,所以OR运算符会返回1true;第二种情况会先进行括号里的逻辑或的判断,为真,但是和括号外的条件判断的时候,由于第一个条件不成立,所以AND符号会返回假。
rv11:=1>2 AND 2>3 OR 3<5; // 返回true,1
rv12:=1>2 AND (2>3 OR 3<5); // 返回false,0
以上呢,就是My语言语法中变量的命名规则,数据结构的讲解和操作符的讲解,希望对于新入门的量化爱好者起到一些帮助。下一节课我们讲解函数的概念,但是使用函数之前,我们首先需要了解一下K线的概念,因为我们大多数的函数都是基于k线的计算,所以了解k线数据的运行和返回机制可以更好的帮助我们进行函数的使用和具体指标的构建。
上节课我们讲到了常量和变量的概念。常量是在策略运行过程中一个不会变化的数值,而变量则会伴随策略进度的更新,发生实时的变化。而这个实时变化的数值,也就是大多数函数计算所使用的数据,叫做K线。
K线对于我们来说,可能既陌生有熟悉。我们知道每一根k线有高开低收四个价格,如果收盘价大于开盘价,那么柱体会呈现红色,如果收盘价小于开盘价,那么柱体会呈现绿色。那么大家了解k线高开低收的这四个价格是怎样合成的吗,如果我们选择不同的k线周期,k线的数量和数值也会发生不同的变化,另外,我们实时观看的k线其实并不是固定不变的,它是在实时发生变化的。因此本节课我们就首先了解一下k线。
世上本没有K线,返回的ticker多了,也便合成了K线。其实k线就是通过一个个ticker数据合成的。大家都知道,在期货市场,毫秒之间就可能会发生成千上万笔交易,交易所将每一笔交易的数量和方向进行返回不太现实,于是我们拿到的数据,其实是一个撮合的数据,一般是一秒返回2个左右,每一个ticker会返回从上一个ticker数据到本根ticker之间的数据,大概是500毫秒的交易撮合数据。这是我们实时获取的ticker数据信息,可以看到有info具体的盘口信息,这是螺纹钢上期所的品种,所以具有五档的行情,然后这里的open开盘价,high最高价,low最低价,volume成交量,OpenInterest持仓量,这些属性都是开盘至今的数值;还有实时的sell卖价,buy买价和last最新价格。
{"Info":{"BidVolume2":1427,"BidPrice4":4028,"reserve1":"rb2405","LastPrice":4031,"LowestPrice":3990.0000000000005,"SettlementPrice":1.7976931348623157e+308,"PreDelta":1.7976931348623157e+308,"BidPrice1":4031,"AskVolume4":3529,"ActionDay":"20231227","ExchangeID":"","BidVolume1":351,"BidVolume5":334,"AskPrice5":4036,"AveragePrice":40125.00993800394,"BidPrice3":4029,"BidPrice5":4027,"ClosePrice":1.7976931348623157e+308,"AskPrice3":4034,"AskVolume3":1307,"AskVolume5":1359,"InstrumentID":"rb2405","PreClosePrice":4023,"OpenPrice":4023,"Turnover":41344328740,"CurrDelta":1.7976931348623157e+308,"BidPrice2":4030,"AskVolume2":1252,"UpdateTime":"14:30:38","AskVolume1":537,"reserve2":"","PreSettlementPrice":4021,"PreOpenInterest":1460390,"HighestPrice":4034,"OpenInterest":1466088,"UpperLimitPrice":4222,"BidVolume3":687,"Volume":1030388,"AskPrice2":4033,"AskPrice4":4035,"BandingLowerPrice":0,"BandingUpperPrice":0,"TradingDay":"20231227","LowerLimitPrice":3819,"UpdateMillisec":500,"AskPrice1":4032,"BidVolume4":1497,"ExchangeInstID":""},
"Open":4023,
"High":4034,
"Low":3990.0000000000005,
"Sell":4032,
"Buy":4031,
"Last":4031,
"Volume":1030388,
"OpenInterest":1466088,
"Time":1703658638500}
接着我们来看下k线数据的结构。可以看到一共有7个属性,分别是时间戳,高开低收,成交量和持仓量。
{"Time":1703646000000,"Open":4017.0000000000005,"High":4029.0000000000005,"Low":4010,"Close":4022,"Volume":92471,"OpenInterest":1442863}
那么怎样利用tick数据进行k线数据的合成呢,如果说ticker数据是一条汹涌不停歇的河流,我们的k线数据就是对这条河流的切分,如果是1分钟k线,我们就使用time时间戳,将开盘以来的时间流划分成一分钟的时间等分,然后统计这一分钟内的ticker数据的开盘价,收盘价,最低价计,最高价,和成交量,而持仓量使用最新返回的持仓总量就可以,于是k线的7个属性我们就获取完毕。一个时间段切分完,我们获取一根完整固定不变的k线数据,然后下一个时间段k线数据的合成还在继续,由于还没有达到一个完整的k线时间段,所以最新返回的ticker数据将会持续改变k线的最高价,最低价,收盘价,成交量和持仓量数据,而开盘价和时间戳在该时间段开始的时候就已经确定下来。
这样对ticker数据进行不同的划分,比如1分钟,5分钟,或者1小时等,我们就可以获取到不同k线周期的数据。以上呢,就是k线合成的方法和奥秘。
麦语言的策略执行逻辑就是根据k线周期的更新,进行策略逻辑的处理,包括具体数据的获取,指标的计算和交易操作的进行。所以当我们设置不同的k线周期,我们策略执行的周期也是不同的,所以上节课我们提到的为什么INFO日志输出会打印出来很多数值,就是因为根据k线周期的更新执行的策略逻辑。
另外还需要注意的一点是,我们是否一定要等到一根k线更新完毕才执行策略的逻辑呢,当然不是必须的。这里涉及到onbar机制和ontick机制的区别,也就是在策略中,是否根据k线更新完毕进行具体逻辑的执行。打开My语言交易类库,这里的交易设置有执行方向,包括收盘价模型和实时价模型。收盘价模型是onBar机制的,就是一根k线完全走完,我们才进行相应策略逻辑的处理。
我们举例示范一下,这里我们设置时间范围是上午9点到9点5分,使用实时价模型。策略的具体内容是使用INFO输出字符“K线更新”,后面添加红色标注,然后输出变量上根k线收盘价,使用REF函数,这是My语言的一个内置函数,用来进行向前引用,括号里面填写CLOSE和周期1,就可以输出上根k线的收盘价数值;最后输出本根k线收盘价Close。根据回测结果可以看到,可以看到,在1分钟时间完整过去,9点1分1秒,我们输出K线更新,实时的k线数据,9点整到9点01分的收盘价2580,至于9点之前那一分钟,REF(C,1)
的收盘价,由于不是开盘时间,是空值,所以没有进行返回。然后又一分钟过去,9点2分,可以看到这里获取到了上一周期的收盘价和本周期的收盘价,可以看到上一周期的收盘价和9点01分的收盘价是一致的。这样依次轮询,直到9点4分,最后一根完整k线完成,因为9点5分还没有到达,所以不是一根完整的k线,所以最后的k线时间是9点4分1秒。这就是一个收盘价模型。只有在一根k线完整结束以后,才会执行策略的逻辑。这就是onbar机制的解释。
INFO(1,1,'常量');
INFO(1,REF(CLOSE, 1),'上根k线收盘价');
INFO(1,CLOSE,'本周期收盘价');
下面我们来看下实时价模型,运行相同的代码。可以看到策略同样是从9点起开始运行,但是相对于onbar机制需要等待k线周期完毕,在ontick机制下,在一个k线周期内,每当新的数据更新,我们就执行一遍策略的逻辑,不用等待k线周期的完成,那么什么时候k线的数值可以固定下来呢,也是需要等待k线周期完毕。所以同样的,在第一分钟,是没有上一分钟收盘价的,而本周期的k线没有走完,所以实时返回的收盘价也在周期内发生改变。直到到达第二分钟,可以看到上根k线的收盘价固定了下来,而本周期的收盘价是一直发生改变的。这就是onBar机制和onTick机制的区别。
而至于这里的实盘级tick和模拟级tick,实盘级tick是真实的实盘级别的tick,切近真实的市场,所以数量很多,但是回测的速度也是比较慢的,并且每个合约最多可以使用50M的数据;模拟级tick是根据一分钟k线模拟而成的,k线数量比较少,回测的速度也比较快。当我们编写高频策略的时候,我们可以实盘级Tick和实时价模型,当编写趋势策略的时候,可以选择模拟级Tick和收盘价模型,不过也不是绝对的,大家需要根据自己策略的需要进行合理的选择。
理解完上面的知识以后,我们就可以对k线数据有一个更加清晰的认识,这样呢,对于下面麦语言中函数中数据的获取和计算理解的更加透彻。
在编程的世界里,“函数”其实就是一段实现了某种功能的代码。并且可以供其它代码调用,一般形式是这样的:
function(param1,param2,...)
首先我们定义函数的名称function,然后定义函数中使用到的参数,参数的个数可能为0个或者多个。通常而言函数都带有参数,当我们传入参数的时候需要确保传入的数据类型是符合的。
使用函数的时候我们需要了解函数基本定义,也就是调用该函数可以获得什么数据。这里可以获得的数据叫做「返回值」。“返回”顾名思义,就是「还回来」,值则代表「具体的数值」,那么返回值的意思即:可以拿到的数据。
返回值是怎样计算出来的呢?是利用我们传入函数的参数计算出来的,传入不同的参数可以得到不同的返回值。除了我们刚才讲到的REF向前引用的函数,我们举例示范一下MA函数,它代表计算一定周期内数据的均值,它包含两个参数:
MA(data,n);
第一个参数代表要引用的数据系列,可以使用高开低收等k线的属性,第二个参数代表向前引用的周期。这样呢,我们就可以根据参数获取到函数的不同返回结果。
我们举例示范一下,在MA函数中填写参数close和周期3,定义MA_3变量,并且使用两个上箭头的形式,在主图上呈现这个数值,并且使用INFO打印该变量。这里选择实时价模型。可以看到图像中,因为在两个周期内,不满足3根k线数量的要求,所以是空值,直到从第三个周期开始,才可以获取到具体的数值。大家也可以选择收盘价模型,看看图像有没有区别。
这是内置函数计算的结果,那么我们能不能手动实现呢?我们可以使用REF函数向前引用前两个值,手动的计算均值。这里我们示范一下,使用(REF(CLOSE,2) + REF(CLOSE,1) + CLOSE)/3
,引用3个周期的收盘价,计算均值。
MA_3:=MA(C, 3);
HAND_MA_3:=(REF(CLOSE,2) + REF(CLOSE,1) + CLOSE)/3;
INFO(1, MA_3, 'MA_3');
INFO(1, HAND_MA_3, 'HAND_MA_3');
根据返回的结果可以看到,内置函数MA和手动计算函数HAND_MA_3两者的值是一致的。希望这个例子可以帮助大家更好的理解麦语言中函数的计算规则。另外,当函数库里面不存在我们需要的指标的时候,我们可以根据对于k线的理解,自己编制函数进行指标的计算和获取。
通过课程前面讲到的k线获取机制,我们就可以对这些函数的返回结果有一个更加清晰的认识。My语言作为专业的程序化函数库,其包含的函数有上百个之多,因此了解My语言中函数中数据的计算以及返回机制,对我们在策略当中计算交易指标,确定交易信号有着重要的作用。当然My语言中函数的种类和使用技巧还有很多,我们下一节将继续讲解My语言中函数具体的应用范例。
上节课,我们讲解了函数运算背后的k线运行机制,方便我们了解在My语言中,怎样更好的利用函数获取数据并进行指标的计算。My语言作为一个专业的金融程序化函数库,包含很多种类的函数,可以方便我们进行金融数据的实时获取,各类指标的计算,交易信号的判断,交易操作的执行以及策略状态的实时展示,以上呢,也是一个完整策略的搭建流程。所以合理的使用函数可以方便的帮助我们进行量化策略的构建。下面,我们将挑选一些函数类别为大家进行重点的讲解。在讲解的过程中,会涉及到一些金融的知识,会为大家进行一些补充,如果哪里有疑问的话,大家可以留下弹幕或者评论,我们也将热心解答。
在讲解之前,首先我们介绍一下INFO函数的用法,在前面的课程中我们一直使用到进行打印的操作,其实这是优宽的一个系统函数,用来进行日志的输出,它的具体样式是这样的:
INFO(cond, param, ...);
这里的cond 为条件变量,当条件变量为真的时候进行日志的输出,后面可以添加多个参数。前面我们将条件这里都设置为1,所以都进行打印。下面我们示范条件为CLOSE > OPEN
,也就是阳线的情况下输出收盘价,开盘价,两者差值,和字符变量“阳线”。这样,就可以根据我们的需要进行策略状态变量的实时打印。
INFO(CLOSE > OPEN, CLOSE, OPEN, CLOSE-OPEN, '阳线');
这里设置时间范围是晚上开盘21点到21点5分的时间,根据回测结果,可以看到只有在21点2分进行了日志的输出,返回在阳线情况下的收盘价,开盘价,两者差值和对应的字符。其他K线不是阳线,所以不进行输出。
下面我们来看第一类,实时数据引用函数,这个前面我们使用的很多。需要注意的是,这类函数是不包含参数的。我们可以使用这类函数,返回实时k线中,和tick数据的不同属性。这些实时交易数据,可以帮助我们获取当前K线或者tick的状态,帮助我们进行交易指标的计算。
除了我们前面使用到的收盘价,K线的其他属性开盘价,最高价,最低价,成交量,和持仓量我们也可以获取到。
CLOSE;//取得当前K线图的收盘价,简写 C
OPEN;//取得当前K线图的开盘价,简写 O
HIGH;//取得当前K线图的最高价,简写H
LOW;//取得当前K线图的最低价,简写L
VOL;//取得当前K线图的成交量
OPI;//取得当前K线图的总持仓量
INFO(1,'K线更新##FF0000')
INFO(1, CLOSE, '收盘价');
INFO(1, OPEN, '开盘价');
INFO(1, HIGH, '最高价');
INFO(1, LOW, '最低价');
INFO(1, VOL, '成交量');
INFO(1, OPI, '持仓量');
实时数据也可以返回tick数据。包括5档的挂单价格以及对应的挂单量,还有NEW代表TICK 的最新价。因为tick是实时更新的,所以实时价模型更加适合。但是呢,我们不想一直打印,这里可以使用优宽的My语言另外一个系统函数EXIT,里面填入错误信息的标注,这样执行一遍策略的逻辑之后就会立即停止。我们运行看一下,可以看到,策略开始进行打印的操作,打印完成输出错误的信息。需要注意的是,并不是所有的品种都具有五档的行情,只有上期所和上海能源的品种才具有,其他交易所盘口数据只有一档,我们这里可以使用郑商所甲醇品种,可以看到只有一档的数据,其他档位的数据都返回空值;切换为上期所螺纹钢品种,可以看到五档的品种都可以看到。大家也可以到优宽的实时交易终端看下,这个窗口可以返回实时的tick盘口数据,可以看到分别切换上期所和郑商所的品种看下,分别有五档和一档的数据。
ASK1;//取得 TICK 的卖一价
ASK1VOL;//取得 TICK 的卖一量
ASK2;//取得 TICK 的卖二价
ASK2VOL;//取得 TICK 的卖二量
ASK3;//取得 TICK 的卖三价
ASK3;//取得 TICK 的卖三量
ASK4;//取得 TICK 的卖四价
ASK4VOL;//取得 TICK 的卖四量
ASK5;//取得 TICK 的卖五价
ASK5VOL;//取得 TICK 的卖五量
NEW;//取得 TICK 的最新价
INFO(1, ASK1, '卖一价');
INFO(1, ASK1VOL, '卖一量');
INFO(1, ASK2, '卖二价');
INFO(1, ASK2VOL, '卖二量');
INFO(1, ASK3, '卖三价');
INFO(1, ASK3VOL, '卖三量');
INFO(1, ASK4, '卖四价');
INFO(1, ASK4VOL, '卖四量');
INFO(1, ASK5, '卖五价');
INFO(1, ASK5VOL, '卖五量');
INFO(1, NEW, '最新价');
除了实时k线和tick数据,我们也可以获取合约品种的信息,包括品种合约的交易单位UNIT,比如螺纹钢合约一手是10吨,而玻璃是1手20吨,铁矿石呢是100吨;最小变动单位MINPRICE是价格每次变化跳动的幅度,大多数品种,比如螺纹钢,玻璃等价格跳动单位是1,而由一些品种比如纸浆跳动单位是2,铁矿石是0.5,使用交易单位乘以价格变动单位,就是每次价格变动带来实际的盈利变化,比如螺纹钢1乘以10,是10元钱,玻璃呢是1乘以20是20元,我们就可以利用这两个单位进行具体品种的盈亏统计。
UNIT;//取数据合约的交易单位
MINPRICE;//数据合约的最小变动价位
INFO(1, UNIT, '交易单位');
INFO(1, MINPRICE, '最小变动价位');
接下来我们讲解逻辑判断函数,逻辑判断函数在量化策略当中具有重要的作用。它允许我们在满足特定条件时执行具体的交易操作,或者根据一系列逻辑测试的结果来做出交易的决策。
首先我们讲解条件函数。在My语言中,条件函数IF,IFELSE和LOOP2,这三个用法是相同的,都可以在判断条件成立的情况下,返回A,否则返回B。这里我们判断条件是收盘价是否大于开盘价,变量A,A1和A2分别使用IF,IFELSE和LOOP2赋值为’阳线’或者’阴线’,根据回测的结果可以看到这个值返回的结果是一致的,证明这三个函数用法相同。
IF(COND,A,B)
IFELSE(COND,A,B)
LOOP2(COND,A,B)
A:=IF(CLOSE>OPEN, '阳线', '阴线');
A1:=IFELSE(CLOSE>OPEN, '阳线', '阴线');
A2:=LOOP2(CLOSE>OPEN, '阳线', '阴线');
INFO(1, A, 'IF');
INFO(1, A1, 'IFELSE');
INFO(1, A2, 'LOOP2');
除了简单的判断一个条件,我们也可以组合使用判断多个条件。当我们判断阳线和阴线的时候,除了单纯判断收盘价是否大于开盘价,我们也可以设置收盘价和开盘价的差值。这里前面的第一个条件是收盘价是否大于开盘价,然后接着判断收盘价和开盘价的差值是否大于等于2,如果满足,会返回1,代表true;在其他情况下,我们接着进行判断,如果两者差值小于等于-2的时候,定义返回值为-1。然后对于其他的情况,就是开盘价和收盘价的差值绝对值的范围小于等于1,我们设置为0,代表开盘价和收盘价不存在显著的差别。我们打印一下,可以看到当差值大于等于2的时候,返回值为1,差值为小于等于-2的时候,返回值为-1,其他情况,返回值为0,可以看到可以根据我们的结果定义需要的信号值。
B:=IF(CLOSE>OPEN, CLOSE - OPEN >= 2, IFELSE(CLOSE - OPEN <= -2, -1, 0));
INFO(1, B, 'IF组合使用');
INFO(1, CLOSE - OPEN, '计算差值');
另外,条件判断函数支持变量循环引用前一周期自身变量,也就是支持下面这样的写法。如果k线为阳线,取当根K线的最高价最高价,否则取上一次是阳线的K线的最高价。
X2:=IF(ISUP,H,REF(X2,1));
INFO(1, X2, 'IF判断');
这里我们示范一下,首先打印是否是阳线,然后打印X2值。第一根k线不是阳线,所以X2值为空,第二根第三根是阳线,打印最新k线的最高价;第四第五根不是阳线,所以打印上一个是阳线的最高价。
接下来我们要补充一下条件语句:IF…THEN。在满足设置条件的时候,我们可以执行一系列的操作。具体格式是这样的:首先是IF和THEN语句设置条件,接着在BEGIN和END条件框里设置具体的操作。这里我们举一个简单的例子,在判断是阳线的情况下,使用INFO输出阳线信息,并打印两者之间的具体差值。
IF COND THEN
BEGIN
ACTION1;
ACTION2;
END
IF CLOSE > OPEN THEN
BEGIN
INFO(1, '阳线');
INFO(1, CLOSE - OPEN,'差值');
END
当在策略运行的过程中,我们需要统计一段周期内,某些信号是否满足的情况,除了使用上面的IF或者IFELSE对每根K线进行判断,我们也可以使用EVERY判断是否持续满足,或者EXIST判断是否存在满足。
EVERY(COND,N)//判断N周期内,是否一直满足COND条件。若满足函数返回值为1,不满足函数返回值为0;
EXIST(COND,N)// 判断N个周期内是否有满足COND的条件;
需要注意的是,这里的N是包含当前k线的;若N是有效数值,但前面没有那么多K线,或者N为空值,代表条件不满足,函数返回值为0;另外N可以是变量。
例如我们举例:使用EVERY判断三个连续周期收盘价连续大于1000,或者三个连续周期收盘价连续大于开盘价;使用EXIST判断三个连续周期内,是否存在收盘价连续大于1000,或者三个连续周期内,是否存在收盘价连续大于开盘价。可以看到,前两根k线由于数量不足,所以没有进行打印,后续收集够足够的数量,根据我们的需要,INFO进行了相应的日志输出。
INFO(EVERY(CLOSE>1000,3), '三个连续周期收盘价连续大于1000#FF0000');
INFO(EVERY(CLOSE>OPEN,3), '三个连续周期收盘价连续大于开盘价#FF0000');
INFO(EXIST(CLOSE>1000,3), '三个周期内存在收盘价大于1000#00FF00');
INFO(EXIST(CLOSE>OPEN,3), '三个周期内存在收盘价大于开盘价#00FF00');
当编写突破策略的时候,我们经常需要判断最新的价格,是否上穿或者下穿压力线或者支撑线,当我们需要判断这些不同指标之间的交叉状态,我们可以使用一些逻辑判断的函数。
BETWEEN(X,Y,Z) //表示X是否处于Y和Z之间,成立返回1(Yes),否则返回0(No);
CROSS(A,B)//表示A从下方向上穿过B,成立返回1(Yes),否则返回0(No);
CROSSDOWN(A,B)//表示当A从上方向下穿B,成立返回1(Yes),否则返回0(No);
CROSSUP(A,B)//表当A从下方向上穿过B,成立返回1(Yes),否则返回0(No)
这些函数的逻辑还是比较容易理解的,我们将在具体的策略讲解中进行进一步的使用。
另外,还有一些逻辑判断的函数,比如BARSTATUS,返回当前周期的位置状态;BARSLASTCOUNT;从当前周期向前计算,统计连续满足条件的周期数;ISCONTRACT,当前是否为指定的合约;ISDOWN,是否是阴线;ISEQUAL,是否是平盘;ISLASTBAR,判断该周期是否为最后一根 K 线;ISNULL,判断空值;ISUP,当前是否是阳线;LAST,判断过去N1到N2周期内,是否一直满足COND条件;LONGCROSS,表示A在N个周期内都小于B,本周期A从下向上穿越B;NOT,取非;NULL,返回空值;VALUEWHEN,当条件成立时,取X的当前值。如果条件不成立,则取上一次条件成立时X的值。这些函数我们将在具体的策略编写中进行讲解,大家可以在优宽社区找到这篇优宽量化My语言(Mylang)文档,这里面包含了优宽支持的My语言函数,大家在策略编写的时候进行查阅。
本节课呢,我们讲解了实时数据获取函数和条件判断的函数,这些对于交易指标的计算具有重要的作用。下节课,我们将继续讲解信号指标所要使用的函数。我们下节课再见。
本节课我们继续函数类别的讲解。这些实际函数的讲解可能会比较枯燥,大家也不用太过于担心需要记住每一个函数的用法,我们可以首先留意每一个函数功能的用法,然后在具体策略判断的时候,我们可以查询这份文档,找到需要使用函数的用法,这样熟能生巧,大家慢慢的会成为一个My语言的编程高手。
这节课我们第一个要介绍的函数是时间函数。时间函数是我们策略中重要的一部分,大家都知道,开盘的时候,价格变动比较大,这时候贸然的进行开平仓的操作会承担比较大的风险,所以我们可以时间函数跳过这一段时间。另外,当我们做日内策略的时候,我们需要在收盘时候,平掉所有的仓位,我们也可以使用时间函数。下面我们来看My语言中具体时间函数的使用。
INFO(1, BARPOS, 'BARPOSK线位置');
INFO(1, DAYBARPOS, 'DAYBARPOS当前K线BAR位置');
INFO(1, PERIOD, 'PERIOD周期数');
INFO(1, DATE, 'DATE日期函数');
INFO(1, TIME, 'TIMEK线的时间');
INFO(1, YEAR, 'YEAR年份');
INFO(1, MONTH, 'MONTH月份');
INFO(1, DAY, 'DAY');
INFO(1, HOUR, 'HOUR');
INFO(1, MINUTE, 'MINUTE');
INFO(1, WEEKDAY, 'WEEKDAY');
INFO(1, CLOSEMINUTE, 'CLOSEMINUTE距离收盘前的分钟数');
这里为了展示这些函数的具体用法,我们建立一个实盘看下各个函数的返回结果,k线周期设置为1分钟。 第一个BARPOS返回当前K线的位置,可以看到策略开始,当前k线的位置是599,而不是从1开始。这里需要为大家解释下,对于一些指标计算我们是需要一定数量要求的,让我们等待收集够足够的数量再进行策略的运行肯定是不合适的,所以策略开始的时候会返回一定数量的K线帮助我们进行指标的计算。但是返回的k线有时候会包含上一个开盘日的数据,统计在今日开盘日内,当前K线BAR位置可以使用DAYBARPOS,可以看到是当前k线位置是234,是从昨天晚上9点开盘以来计数的。
PERIOD返回的是k线周期数,它的单位是分钟,这里我们设置1分钟为周期,所以返回值是1。DATE返回的是日期函数,24年1月3号。
TIME是取K线的时间,需要注意的是,这个返回的不是实时的时间,返回的是当前k线的时间戳,根据不同的k线周期,1分钟,TIME的刻度也是1分钟为间隔,如果是5分钟,TIME的间隔也是5分钟。另外,TIME函数在秒周期使用时返回六位数的形式,就是时分秒:HHMMSS,在其他周期上显示为四位数的形式,小时和分钟,即:HHMM。TIME函数只能加载在日周期以下的周期中,在日周期及日周期以上的周期中该函数返回值始终为1500,也就是下午的收盘时间3点整。所以使用TIME判断当前的时间会有很多的限制条件,所以我们可以使用下面的一系列函数。
YEAR年份,MONTH月份,DAY具体日期,HOUR小时,MINUTE分钟,WEEKDAY,星期天数,可以很方便的使用这些函数进行时间的判断。CLOSEMINUTE返回离收盘前的分钟数,也就是距离下午三点钟的分钟数。使用这个可以很方便的判断当前距离收盘的截止时间,方便进行日内平仓的操作。
接下来我们来看数理统计函数。在指标运算的时候,我们经常需要一些数理统计的计算,这样呢,就可以结合我们自己的数理统计学知识,理解一些经典指标的计算过程,并在此基础上根据自己的交易经验,自己开发一些有效的量化指标。我们大致来看下在My语言里可以实现哪些数理统计的操作,大家可以先留下一个印象,在具体策略的编写过程中,可以再来这里看下具体函数的用法。
我们首先来看数学函数,这里呢是按照字母排序罗列的,我们可以整理一下分为三类:
以上呢,就是My语言中支持的数学函数,我们可以使用这些函数进行一些数理统计指标的计算,当然My语言中也包含一些数理统计的函数,接下来来看比较复杂的统计函数:
这些就是My语言支持的数理统计函数,可以进行基本的统计计算,下面我们来看下My语言的金融统计函数。
金融价格的变化靠人为感觉是难以预测的,我们呢使用历史和实时的数据,去建立数学模型去预测未来的价格,这里面数学模型中使用到的各类经典金融指标计算,比如MACD,RSI,KDJ等等,所使用到的函数就是金融统计函数。我们来介绍一下My语言中包含的金融统计函数。
使用这些函数,我们就可以计算一些经典的指标,比如MACD指标。MACD称为异同移动平均线,是从双指数移动平均线发展而来的,由快的指数移动平均线(EMA12)减去慢的指数移动平均线(EMA26)得到快线DIF,再用2×(快线DIF-DIF的9日加权移动均线DEA)得到MACD柱。所以MACD指标是由两线一柱组合起来形成,快速线(白色线)为DIF,慢速线(黄色线)为DEA,柱状图为MACD。我们呢,可以使用My语言函数进行实现。
在MACD指标中,使用的均线指标都是EMA,快线和慢线的指标分别是12和9,大家也可以设置别的周期;然后计算DIF,快线和慢线的差值,接着计算DEA,DIF的9日EMA值;最后使用2乘以DIF和DEA的差值,这样M