输入/搜索内容
1
关注
183
关注者
My语言商品期货量化交易教程:在优宽平台开始你的My语言量化之旅
原创教程
创建于 2024-01-02 09:10:54  更新于 2024-06-13 14:51:08
 0
 1838

img

一、基于优宽开始你的My语言量化之旅

My语言课程引言

大家好,从今天起,我们开始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视界和上期模拟,当申请好账号就可以直接使用;真实的账户我们需要看穿式监管的认证,才可以进行量化交易。在社区里,有两篇帖子详细介绍了交易所的配置步骤,大家可以查看一下。当我们配置完成交易所,交易所的具体标志会呈现出来。

《CTP商品期货SimNow模拟盘配置》

《商品期货看穿式监管API支持汇总》

最后一个部分是托管者的配置,托管者可以理解为我们的交易策略的执行者,负责复杂的数据请求、数据接收、网络链接、日志回传等等工作。托管者的详细配置步骤,在前面的课程中有提到过,大家可以看一下。当配置好以后,在托管者页面会显示配置完成的托管者名称。

《商品期货量化交易实践系列课程--托管者程序部署与Docker部署》

最后一步,我们就要建立My语言的实盘策略了。点击实盘,点击新建,定义实盘名称,选择k线周期,运行策略,刚才编写好的My语言策略,托管主机,交易类库里面可以使用默认的参数;交易平台可以选择一个仿真的账户,上期模拟。点击创建实盘,这样我们的My语言策略就可以对接市场,运行起来。在优宽平台运行运行实盘是很便宜的,每小时0.125元,一天3块钱,比大多数一手期货合约的手续费都低。

以上呢,就是在优宽平台完成的,一个My语言策略从策略编写,模拟回测到实盘运行的完整步骤。希望如此便捷的量化实盘的搭建过程,可以帮助到真心想入门量化学习的伙伴。虽然这一路可能会有很多的坎坷和困难,我们在后台会热心的帮助大家解决在量化学习中碰到的难题。当然平台也不是尽善尽美的,大家有问题,也可以提出宝贵的意见,我们的工程师也会尽力提升大家的量化体验。希望大家一起努力,砥砺前行。

二、My语言语法讲解(一)

上节课我们深入了解了My语言的特点,以及如何在优宽平台进行My语言策略的编写、回测和实盘的创建。现在,大家可能跃跃欲试,想要立即编写自己的My语言策略。然而,在此之前,我们还需要对My语言的语法结构进行深入的了解。只有在对My语言的语法有清晰的认识的基础上,我们的策略才能更加准确、高效地实现预期的目标。

在本节课中,我们将详细解析My语言的语法结构。大家也不用太过于担心,相对于python语言和JavaScript语言,My语言的语法规则更加清晰明了,专门针对交易领域的编程需求进行了优化。通过这些知识的学习,我们将能够更好地理解和运用My语言,为我们的策略编写提供坚实的语言基础。请注意,本节课的语法讲解内容对于编程大拿可能过于基础,大家可以根据自己的水平有选择性的跳过~~

第一个我们要认识的概念是变量,变量是电脑内存中开辟的一块用来存数据的空间,简单说就是用来保存数据的。

变量命名规则

每一个变量需要有一个合适的名称,这样在工作的过程当中可以实时的调取和安排任务。首先呢,我们来看一下变量的命名规则。在编写开始,我们首先要确定需要在半角输入法,也就是英文状态下状态下进行编写。在My语言中,我们可以使用中文对变量进行命名,这个时候可以使用中文输入法,比如设置优宽中文变量,但是这里的赋值符号是英文格式的“:=”,变量保存的数据是数值666,最后需要加上分号,也是英文格式的,这样一个变量就命名完成。如果我们使用中文格式的符号,我们运行一下会报错。

不过更加推荐的是使用英文加上下划线命名,这样更符合传统代码的书写习惯,这里使用youquant_index赋值为666。

mylang
优宽:=666; //优宽2:=666; youquant_index:=666;

需要注意的是,变量命名也是有一定规范的:不允许使用系统“保留字”(比如内置参数名或者函数名)。例如My语言的内置参数Close收盘价,和它的简写形式大写C,以及内在函数MA,这个是用来计算移动均值的函数等等。此外,变量的名称不能相互重复,也不允许纯数字或者数字开头。最后不允许很长,不同的系统长度限制不同。

数据类型

数据类型是一个基础的概念,在编写中当我们将一个明确的数据赋值给变量时,这个变量也就变成了数据自身的类型。我们来看下有哪些数据类型:

  • 数值类型
  • 字符串类型(str)
  • 布尔类型(boolean)

第一种数值类型我们最为熟悉,包括整数、浮点数(小数)。

mylang
// 整数 int:=2; // 小数 float:=3.1;

第二种字符串类型:必须使用''包裹。需要注意的是字符串类型不允许直接使用,需要配合函数输出到视图中。

比如我们不能直接设置一个变量是字符串,这样回测会直接报错,我们需要配合函数使用。这里的INFO是日志输出的作用,至于这个为什么会输出这么多字符呢,这就涉及到My语言专业的金融属性了,我们后续会为大家讲解。

mylang
//abd = 'youquant'; INFO(1,'youquant');

第三种数据类型是布尔类型,使用1(代表真)或者0(代表假)。例如:设置变量大写AB等于1大于10,这个判断是错误的,所以AB变量会返回0。这里我们使用INFO进行变量的输出,可以看到这里我们使用的变量是小写的ab,运行一下,可以看到返回的值都是0。所以在my语言当中,是不区分大小写的,所以我们需要格外注意一下。

mylang
AB:=1>10; INFO(1,ab);

我们知道金融的数据是一个时间流的数据,相对于在策略中不变化的常量,我们也可以使用变量的形式定义时刻变化的数据的存在。这里我们举例,使用constant定义数值常量1,使用newClose定义Close,close是my语言的内置变量,代表收盘价的最新价;newBu,布尔变量,定义最新的收盘价close是否大于开盘价open,也就是当前k线是否是阳线。运行一下代码,可以看到伴随时间流的更新,我们可以得出常量的值是不变的,数值变量和布尔变量都会随着时间的更新进行变化。

mylang
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收盘价。

mylang
newClose^^Close;
  • :

如果想画在副图上,使用冒号代表赋值并且输出到图(副图)中。这里赋值newClose_3000为Close收盘价减去3000。

mylang
newClose_3000:Close - 3000;
  • ..

两个英文等号给变量赋值并且显示变量名、数值在图表中,但是不画图到图表(主图、副图...)中。这里赋值newClose_100为Close收盘价减去100。可以看做图像的左下角显示设置的数值,但是不呈现相应的图像。

mylang
newClose_100..Close - 100;
  • :=

最后一个就是我们前面一直使用到的,冒号等号的形式,这个赋值的数值不输出到图(主图、副图)中,也不显示在状态栏表格中。可以看到在图表中都没有呈现。

mylang
newClose_200:=Close - 200;

数学运算操作符

这个我们比较熟悉,这是完成基本的算术运算符号,加减乘除。

mylang
addValue:= 1+1; // 返回 2 minusValue:= 2-1; // 返回 1 multiValue:= 2*2; // 返回 4 divValue:= 4/2; // 返回 2

逻辑判断操作符

这类操作符用在条件表达式中。用于判断变量之间的关系。具体的返回值是布尔类型的,不是true(1)、就是false(0)。

具体的包括:

操作符含义
>大于
<小于
>=大于等于
<=小于等于
=等于
<>不等于
&&(and)逻辑与
||(or)逻辑或

前面这六个是关系运算符,是双目运算符,用于判断两个数据之间的关系。我们可以举例示范一下:

mylang
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。

mylang
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符号会返回假。

mylang
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线数据的运行和返回机制可以更好的帮助我们进行函数的使用和具体指标的构建。

三、My语言语法讲解(二)

上节课我们讲到了常量和变量的概念。常量是在策略运行过程中一个不会变化的数值,而变量则会伴随策略进度的更新,发生实时的变化。而这个实时变化的数值,也就是大多数函数计算所使用的数据,叫做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最新价格。

mylang
{"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个属性,分别是时间戳,高开低收,成交量和持仓量。

mylang
{"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机制的解释。

mylang
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线数据有一个更加清晰的认识,这样呢,对于下面麦语言中函数中数据的获取和计算理解的更加透彻。

在编程的世界里,“函数”其实就是一段实现了某种功能的代码。并且可以供其它代码调用,一般形式是这样的:

mylang
function(param1,param2,...)

首先我们定义函数的名称function,然后定义函数中使用到的参数,参数的个数可能为0个或者多个。通常而言函数都带有参数,当我们传入参数的时候需要确保传入的数据类型是符合的。

使用函数的时候我们需要了解函数基本定义,也就是调用该函数可以获得什么数据。这里可以获得的数据叫做「返回值」。“返回”顾名思义,就是「还回来」,值则代表「具体的数值」,那么返回值的意思即:可以拿到的数据。

返回值是怎样计算出来的呢?是利用我们传入函数的参数计算出来的,传入不同的参数可以得到不同的返回值。除了我们刚才讲到的REF向前引用的函数,我们举例示范一下MA函数,它代表计算一定周期内数据的均值,它包含两个参数:

mylang
MA(data,n);

第一个参数代表要引用的数据系列,可以使用高开低收等k线的属性,第二个参数代表向前引用的周期。这样呢,我们就可以根据参数获取到函数的不同返回结果。

我们举例示范一下,在MA函数中填写参数close和周期3,定义MA_3变量,并且使用两个上箭头的形式,在主图上呈现这个数值,并且使用INFO打印该变量。这里选择实时价模型。可以看到图像中,因为在两个周期内,不满足3根k线数量的要求,所以是空值,直到从第三个周期开始,才可以获取到具体的数值。大家也可以选择收盘价模型,看看图像有没有区别。

这是内置函数计算的结果,那么我们能不能手动实现呢?我们可以使用REF函数向前引用前两个值,手动的计算均值。这里我们示范一下,使用(REF(CLOSE,2) + REF(CLOSE,1) + CLOSE)/3,引用3个周期的收盘价,计算均值。

mylang
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函数的用法,在前面的课程中我们一直使用到进行打印的操作,其实这是优宽的一个系统函数,用来进行日志的输出,它的具体样式是这样的:

mylang
INFO(cond, param, ...);

这里的cond 为条件变量,当条件变量为真的时候进行日志的输出,后面可以添加多个参数。前面我们将条件这里都设置为1,所以都进行打印。下面我们示范条件为CLOSE > OPEN,也就是阳线的情况下输出收盘价,开盘价,两者差值,和字符变量“阳线”。这样,就可以根据我们的需要进行策略状态变量的实时打印。

mylang
INFO(CLOSE > OPEN, CLOSE, OPEN, CLOSE-OPEN, '阳线');

这里设置时间范围是晚上开盘21点到21点5分的时间,根据回测结果,可以看到只有在21点2分进行了日志的输出,返回在阳线情况下的收盘价,开盘价,两者差值和对应的字符。其他K线不是阳线,所以不进行输出。

实时数据引用

下面我们来看第一类,实时数据引用函数,这个前面我们使用的很多。需要注意的是,这类函数是不包含参数的。我们可以使用这类函数,返回实时k线中,和tick数据的不同属性。这些实时交易数据,可以帮助我们获取当前K线或者tick的状态,帮助我们进行交易指标的计算。

  • K线数据引用

除了我们前面使用到的收盘价,K线的其他属性开盘价,最高价,最低价,成交量,和持仓量我们也可以获取到。

mylang
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数据引用

实时数据也可以返回tick数据。包括5档的挂单价格以及对应的挂单量,还有NEW代表TICK 的最新价。因为tick是实时更新的,所以实时价模型更加适合。但是呢,我们不想一直打印,这里可以使用优宽的My语言另外一个系统函数EXIT,里面填入错误信息的标注,这样执行一遍策略的逻辑之后就会立即停止。我们运行看一下,可以看到,策略开始进行打印的操作,打印完成输出错误的信息。需要注意的是,并不是所有的品种都具有五档的行情,只有上期所和上海能源的品种才具有,其他交易所盘口数据只有一档,我们这里可以使用郑商所甲醇品种,可以看到只有一档的数据,其他档位的数据都返回空值;切换为上期所螺纹钢品种,可以看到五档的品种都可以看到。大家也可以到优宽的实时交易终端看下,这个窗口可以返回实时的tick盘口数据,可以看到分别切换上期所和郑商所的品种看下,分别有五档和一档的数据。

mylang
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元,我们就可以利用这两个单位进行具体品种的盈亏统计。

mylang
UNIT;//取数据合约的交易单位 MINPRICE;//数据合约的最小变动价位 INFO(1, UNIT, '交易单位'); INFO(1, MINPRICE, '最小变动价位');

逻辑判断函数

  • 条件函数

接下来我们讲解逻辑判断函数,逻辑判断函数在量化策略当中具有重要的作用。它允许我们在满足特定条件时执行具体的交易操作,或者根据一系列逻辑测试的结果来做出交易的决策。

首先我们讲解条件函数。在My语言中,条件函数IF,IFELSE和LOOP2,这三个用法是相同的,都可以在判断条件成立的情况下,返回A,否则返回B。这里我们判断条件是收盘价是否大于开盘价,变量A,A1和A2分别使用IF,IFELSE和LOOP2赋值为'阳线'或者'阴线',根据回测的结果可以看到这个值返回的结果是一致的,证明这三个函数用法相同。

mylang
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,可以看到可以根据我们的结果定义需要的信号值。

mylang
B:=IF(CLOSE>OPEN, CLOSE - OPEN >= 2, IFELSE(CLOSE - OPEN <= -2, -1, 0)); INFO(1, B, 'IF组合使用'); INFO(1, CLOSE - OPEN, '计算差值');

另外,条件判断函数支持变量循环引用前一周期自身变量,也就是支持下面这样的写法。如果k线为阳线,取当根K线的最高价最高价,否则取上一次是阳线的K线的最高价。

mylang
X2:=IF(ISUP,H,REF(X2,1)); INFO(1, X2, 'IF判断');

这里我们示范一下,首先打印是否是阳线,然后打印X2值。第一根k线不是阳线,所以X2值为空,第二根第三根是阳线,打印最新k线的最高价;第四第五根不是阳线,所以打印上一个是阳线的最高价。

接下来我们要补充一下条件语句:IF...THEN。在满足设置条件的时候,我们可以执行一系列的操作。具体格式是这样的:首先是IF和THEN语句设置条件,接着在BEGIN和END条件框里设置具体的操作。这里我们举一个简单的例子,在判断是阳线的情况下,使用INFO输出阳线信息,并打印两者之间的具体差值。

mylang
IF COND THEN BEGIN ACTION1; ACTION2; END IF CLOSE > OPEN THEN BEGIN INFO(1, '阳线'); INFO(1, CLOSE - OPEN,'差值'); END
  • 持续满足 vs. 存在满足

当在策略运行的过程中,我们需要统计一段周期内,某些信号是否满足的情况,除了使用上面的IF或者IFELSE对每根K线进行判断,我们也可以使用EVERY判断是否持续满足,或者EXIST判断是否存在满足。

mylang
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进行了相应的日志输出。

mylang
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语言中具体时间函数的使用。

mylang
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语言里可以实现哪些数理统计的操作,大家可以先留下一个印象,在具体策略的编写过程中,可以再来这里看下具体函数的用法。

我们首先来看数学函数,这里呢是按照字母排序罗列的,我们可以整理一下分为三类:

基本处理类:

  • ABS(X):返回X的绝对值
  • CEILING(X,Y):返回指定实数(X)在沿绝对值增大的方向上第一个能整除基数(Y)的值
  • FLOOR(X):向数值减小方向舍入
  • INTPART(X):取X的整数部分
  • ROUND(N,M):对数字N进行位数为M的四舍五入
  • SGN(X):取符号。若X>0返回1,若X<0返回-1,否则返回0
  • MAX(A,B):取最大值。取A,B中较大者
  • MAX1(A...P):在A到P中取最大值
  • MEDIAN(X,N):求X在N个周期内居于中间的数值
  • MEDIAN1(A,...,P):求A到P内居于中间的数值
  • MIN(A,B):取最小值。取A,B中较小者
  • MIN1(A...P):在A到P中取最小值
  • MOD(A,B):取模。返回A对B求模,也就是求余数
  • MODE(X,N):求X在N个周期内最常出现的值
  • RAND(X,Y):产生随机数的随机函数,返回范围在X到Y之间的随机数
  • RANGE(X,Y,Z):介于某个范围之内。表示X大于Y同时小于Z时返回1,否则返回0
  • REVERSE(X):取相反值,返回-X

指数函数类

  • CUBE(X):返回X的三次方
  • EXP(X):求e的X次幂
  • LN(X):求X的自然对数
  • LOG(X):求X的常用对数值
  • POW(X,Y):求X的Y次幂
  • SQUARE(X):求X的平方
  • SQRT(X):求X的平方根

三角函数类

  • SIN(X):求X的正弦值
  • ACOS(X):返回X的反余弦值
  • ASIN(X):返回X的反正弦值
  • ATAN(X):返回X的反正切值
  • COS(X):返回X的余弦值
  • TAN(X):返回X的正切值

以上呢,就是My语言中支持的数学函数,我们可以使用这些函数进行一些数理统计指标的计算,当然My语言中也包含一些数理统计的函数,接下来来看比较复杂的统计函数:

  • AVEDEV:平均绝对偏差,返回X在N周期内的平均绝对偏差
  • COEFFICIENTR/CORRELATION:相关系数,求X、Y在N个周期内的相关系数
  • COVAR:求X、Y在N个周期内的协方差
  • DEVSQ:计算数据X的N个周期的数据偏差平方和
  • FORCAST:求X的N周期线性回归预测值
  • KURTOSIS:求X在N个周期内的峰度系数
  • NORMPDF:返回参数为MU和SIGMA的正态分布密度函数在X处的值,一般设置均值是0,方差是1
  • SKEWNESS:求X在N个周期内的偏度系数
  • SLOPE:求X的N周期的线型回归的斜率
  • STD:求X在N个周期内的样本标准差
  • STDP:为X的N周期总体标准差
  • VAR:求X在N周期内的样本方差
  • VARP:求X的N周期总体方差

这些就是My语言支持的数理统计函数,可以进行基本的统计计算,下面我们来看下My语言的金融统计函数。

金融统计函数

金融价格的变化靠人为感觉是难以预测的,我们呢使用历史和实时的数据,去建立数学模型去预测未来的价格,这里面数学模型中使用到的各类经典金融指标计算,比如MACD,RSI,KDJ等等,所使用到的函数就是金融统计函数。我们来介绍一下My语言中包含的金融统计函数。

  • DMA:求X的动态移动平均,其中A必须小于1大于0
  • EMA:求N周期X值的指数加权移动平均(平滑移动平均)
  • EMA2:求N周期X值的线性加权移动平均(也称WMA)
  • EMAWH:这个用法同EMA是一致的
  • HARMEAN:求X在N个周期内的调和平均值
  • HHV:求X在N个周期内的最高值,这个包含当前k线
  • HV:求X在N个周期内(不包含当前k线)的最高值
  • HHVBARS:求N周期内X最高值到当前周期数
  • LLV:求X在N个周期内的最小值
  • LV:求X在N个周期内的最小值(不包含当前k线)
  • LLVBARS:求N周期内X最低值到当前周期数
  • MA:X在N个周期内的简单移动平均
  • MV:取A到P的均值
  • NUMPOW:自然数幂方和
  • SAR:返回抛物转向值
  • SMA:求X的N个周期内的扩展指数加权移动平均,M为权重
  • SMMA:当前K线上X在N个周期的通畅移动平均线
  • SORT:按升(降)序排列,取第POS个参数对应的值
  • SUM:求X在N个周期内的总和
  • SUMBARS:求累加到指定值的周期数
  • TRMA:求X在N个周期的三角移动平均值
  • TSMA:求X在N个周期内的时间序列三角移动平均

使用这些函数,我们就可以计算一些经典的指标,比如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的差值,这样MACD就可以获取到。

mylang
FASTLINE^^EMA(CLOSE,12); SLOWLINE^^EMA(CLOSE,26); DIF:FASTLINE-SLOWLINE,CIRCLEDOT; DEA:EMA(DIF,9); MACDDIFF:2*(DIF-DEA),COLORSTICK, IF(2*(DIF-DEA), COLORRED, COLORGREEN);

为了在图形中更好的呈现,我们将快线和慢线使用两个上箭头画在主图上,DIF,DEA,和MACDDIFF使用冒号在副图上进行呈现。另外,这里面可以给大家补充一下画图的函数,在优宽平台,支持的My语言画图函数有这些:

函数意义
CIRCLEDOT小圆点线
COLORSTICK画柱线(水平线为0)
DOT画虚线
VOLUMESTICK画柱线(水平线为最小值)
COLORRED红色

所以这里将DIF线使用小圆点线,MACDDIFF使用COLORSTICK以0为水平轴的柱线,然后使用不同的颜色进行线的呈现。这里比较特别的一点是,我们可以使用IF语句设置不同颜色的MACD柱,当MACD值为正的时候,设置为红色;否则设置为绿色,这样经典的MACD指标就使用My语言进行了复现。

我们继续金融统计函数的讲解,这里还具有一些函数可以帮助我们判断条件和周期的关系,比如BARSCOUNT,返回第一个有效周期到当前的周期数;BARSLAST,上一次条件COND成立到当前的周期数;BARSSINCE,第一个条件成立到当前的周期数;BARSSINCEN,统计N周期内第一次条件成立到当前的周期数;CONDBARS,取得最近的满足A、B条件的k线间周期数;COUNT,统计N周期中满足COND条件的周期数。使用这些函数,我们可以结合具体的条件,进行具体指标的设置。

我们可以举一个例子,如果要统计最近20天内大涨的天数,我们应该编写呢?大涨我们可以设定一个范围,如果实时的收盘价大于昨日的收盘价2%的时候,我们就定义为大涨。将这个条件设置好以后,我们使用COUNT统计一下20天内满足这个条件的天数。具体的代码可以这样编写:

mylang
DAZHANG: =CLOSE/REF(CLOSE,1) >1.02; INFO(1, COUNT(DAZHANG, 20), '大涨天数');

K线周期设置为天,品种这里我们选择纸浆,可以看到返回结果是1,证明在这20天内有1天涨幅是大于2%的。

辛苦大家听完这节课,介绍了这么多的函数。在我们前期课程了解数据返回机制的基础上,理解各个函数的数据获取和计算机制应该是比较清晰的。这些函数是我们进行金融指标计算和交易信号判断重要的组成部分,下节课在指标计算基础上,我们将要最后一部分,交易函数的使用。我们下节课再见。

六、交易函数(一)

前面的课程我们介绍了实时数据获取,条件逻辑判断,指标计算的函数,都是为了指标的计算和交易信号的判断,在获取交易信号以后,接下来我们就要来进行交易中最重要的一环,具体交易操作的执行。

交易指令

在My语言中,交易操作是通过交易函数来实现的。My语言具体的交易操作有下面七个指令。

B: BUY; S: SELL; K: 开; P:开

BK:基本下单指令,买入开仓,建立多头持仓

SP:基本下单指令,卖出平仓,平掉多头持仓

SPK:反手下单指令,卖平后卖开,多单转空单

SK:基本下单指令,卖出开仓,建立空头持仓

BP:基本下单指令,买入平仓,平掉空头持仓

BPK:反手下单指令,买平后买开,空单转多单

CLOSEOUT: 清仓指令

怎样记忆呢,其实My语言很有意思,它有点中西结合的味道。比如这里的B是英文Buy的简写,S是Sell的简写,K是中文“开”的简写,P是“平”的简写。所以进行组合买开BK是开多仓。平多仓我们需要将这两个字母取相反,B的相反是S,K的相反是P,所以是SP,卖出平仓。而SPK是先进行平多仓,再进行相反方向开仓,也就是开空,所以SPK是多转空。这就是多仓设置的逻辑。

对于空仓设置的逻辑我们也可以理解了,SK是卖出开仓,建立空头,取相反BP是平空,进而BPK是平空开多。

还有最后一个设置CLOSEOUT,是清仓,平掉所有方向的持仓。

这里的交易指令是可以添加参数的,代表具体下单的手数。例如“BK(2)”代表开了两手多仓。如果没有参数,就是用交易类库中的默认下单手数进行下单。

在My语言的交易函数中,有些地方需要注意。第一,My语言是不支持限价单的,也就是不能限制具体交易的价格;当我们需要限制下单价格的时候,我们可以写成条件的形式,如果满足价格限制的条件,再执行具体交易的操作,但是也有可能市场波动的因素,不能严格的执行。

第二,对于平仓这里,是没有“平今”和“平昨”区别的。我们直接使用就可以。

我们举例示范一下。我们建立一个简单的交易的模型。这里的开仓条件是如果不在距离收盘10分钟以内,并且收盘价大于开盘价,就进行开多仓;相反情况下,进行开空仓;如果时间到达收盘价10分钟内,我们就要平掉持有的多仓或者空仓。所以这里使用还可以写作CLOSEOUT平掉所有仓位。这里的AUTOFILTER是一开一平的模式,也就是一个方向开仓以后,不能继续加仓,只有平仓以后,才能继续开仓,这涉及到My语言的交易逻辑,我们稍后进行讲解。

mylang
C>O && TIME<1450,BK; C<O && TIME<1450,SK; TIME >= 1450,SP; TIME >= 1450,BP; // TIME>=1450,CLOSEOUT; AUTOFILTER;

因为My语言只能支持单向的持仓,所以在策略当中,也可以使用BPK,先平空仓再开多仓,和SPK先平多仓再开空仓,进行交易操作的执行。这里我们举一个简单的双均线策略。首先我们设置两条均线MA5,和MA10,当MA5上穿MA10的时候,我们进行平空开多;当MA5下穿MA10,进行平多开空。这里大家可能会有疑问,如果策略开始的时候,没有持有仓位,怎么进行平仓,其实这时候就是只进行开仓了,不进行平仓。

mylang
MA5^^MA(CLOSE, 5); MA10^^MA(CLOSE,10); CROSSUP(MA5, MA10), BPK; CROSSDOWN(MA5, MA10), SPK; AUTOFILTER;

交易控制函数

下面我们讲一下交易信号和具体交易操作执行逻辑的设置。交易操作是伴随交易信号的确定去执行的。对于不同的交易类型,我们需要对信号进行信号过滤或者重复执行的操作。我们可以通过交易控制函数设置交易信号和交易操作执行的逻辑。

AUTOFILTER

模型中通过写入AUTOFILTER函数来控制和实现一开一平的信号过滤,有多个开仓信号都满足条件的时候,取第一个信号作为有效信号,后面的k线上的同样信号将被过滤掉。

这里我们设置一个策略。首先计算两条均线,MA5和MA10,然后这里判断两个开仓条件,第一个条件是如果收盘价大于MA5,第二个是MA5大于MA10;在分别满足其中一个条件的情况下,使用INFO进行日志的输出,并使用BK进行多头的开仓;平仓条件是如果收盘价大于BKPRICEAV,这是多头持仓的平均价加上5,我们进行止盈;或者收盘价小于BKPRICEAV-5,进行止损,使用SP平掉所有的多头持仓数量,这个内置变量是BKVOL。

mylang
MA5:MA(CLOSE,5); MA10:MA(CLOSE,10); SIG1 := CROSSUP(C,MA5); SIG2 := CROSSUP(MA5,MA10); INFO(SIG1,'开仓条件1满足#FF0000'); INFO(SIG2,'开仓条件2满足#00FF00'); SIG1,BK; SIG2,BK; C>BKPRICEAV+10||C<BKPRICEAV-5,SP(BKVOL); //AUTOFILTER;

如果设置AUTOFILTER,触发BK后,只能触发SP,其它的BK信号被忽略,每根K线触发一次信号。回测这里我们设置k线周期为分钟,收盘价模型,结果这里看到,在相应条件满足情况下,每根k线产生一个信号,开仓只能进行1手,即使开仓条件2满足,或者开仓条件重复满足,也选择忽略。开仓过后,下一次的交易操作必然是平仓。平仓过后才可以进行下一次的开仓。在平仓过后,重置了模型状态。

这个就是AUTOFILTER,我们在策略当中使用的最多的模型,一开一平的模式。

我们可以对比尝试一下,不设置AUTOFILTER时。我们来看下回测结果。同样可以看到在具体条件满足的情况下,每根k线产生一个信号;这里不再限于必须是开仓平仓的模型,当两个条件都满足,就会进行两次的开仓操作;但是每条指令都只能执行一次,在某一指令开仓完成后,即使重复满足,也会选择忽略。但是有时候我们想要进行加仓的操作,需要重复执行某条指令,这时候我们就要使用下一种模式,TRADE_AGAIN。

TRADE_AGAIN

刚才上面的举例中,我们看到即使没有设置AUTOFILTER,但是每行交易指令在执行过后,是不能重复执行的,只有在平仓过后,重置模型状态,才可以重新执行相应的指令。怎样可以重复执行同一个命令行呢,我们可以设置 TRADE_AGAIN函数,它是具有参数的,具体的参数代表代表指令行可以进行几次的操作。

mylang
MA5:MA(CLOSE,5); INFO(CROSSUP(C,MA5),'开仓条件1满足#FF0000'); CROSSUP(C,MA5),BK; C>BKPRICEAV+5||C<BKPRICEAV-5,SP(BKVOL); TRADE_AGAIN(2);

这里我们设置满足条件1的情况下,我们进行开多仓;首先不设置TRADE_AGAIN函数,可以看到即使多次满足条件1,然而具体操作的执行只有1次;我们加上TRADE_AGAIN函数,参数设置为2,可以看到该行指令被执行了两次,第三次以后被选择忽视。这就是TRADE_AGAIN函数的作用。

MULTSIG

以上呢,我们使用的都是收盘价模型,一根k线产生1个指令,就是只有在K线更新完毕我们才执行交易的操作,我们也可以选择实时价模型。这里我们更改为是实时价模型,并使用实盘级的tick,可以看到在一根k线上(67)即使满足了多个开仓条件,只有在下一根k线满足的时候,才进行继续加仓的操作,这就是一根K线一个信号的模型;如果对于高频级的tick策略,我们想要实现一根K线多个信号的模型,可以使用MULTSIG函数。

mylang
MULTSIG(Sec1,Sec2,N,INTERVAL)

这里首先给大家介绍一下MULTSIG各个参数的含义,这里最重要的参数是N,代表一根K线上最大的信号个数;Sec1和Sec2代表开仓和平仓出信号后不复核的时间,可以直接设置为0就可以;INTERVAL是数据时间间隔,也可以填写为空值。

以前我们讲过,1根k线是由很多tick数据组成的;相对于收盘价模型,一根k线产生一个信号,实时价模型里,一个tick就会产生一个信号,所以更加灵敏。使用MULTSIG模型就可以执行tick级别的策略。

这里我们编写一个策略示范一下。需要注意的是,因为这里是在一根k线上重复执行某个指令行,所以MULTSIG要配合TRADE_AGAIN函数。这里我们在先前函数基础上,添加MULTSIG(0,0,5),代表有信号出现,立刻执行,每个k线上最多可以执行5次指令,配合TRADE_AGAIN(5)函数,我们运行一下。根据日志,在满足开仓条件下,在同一根k线,我们进行了5次的开仓操作,同样的平仓也是。

mylang
MA1:MA(CLOSE,5); MA2:MA(CLOSE,10); CROSSUP(MA1,MA2),BK; C>BKPRICE+10||C<BKPRICE-5,SP; MULTSIG(0,0,5); TRADE_AGAIN(5);

以上呢,就是我们在My语言中经常使用到的交易模式,大家可以根据自己策略的需要,选择合适的模式进行设置。另外,My语言还有一些内置函数和交易类库,都可以帮助我们进行交易的更多设置,我们下节课进行讲解。

七、交易函数(二)

上节课,我们讲到了My语言中基本的下单指令和交易模式。然而在下单完成以后,我们需要及时检查持仓的状态并进行相应的风险管理。因此,My语言还有一系列的交易状态检查函数,下面我们进行一下讲解。

信号函数

首先我们讲解一下对于多头开仓的信号记录函数。

  • BKVOL: 买开信号手数
  • BKPRICE: 返回数据合约最近一次买开信号价位
  • BKPRICEAV:返回数据合约多头开仓均价
  • BKHIGH:返回合约买开仓以来的最高价
  • BKLOW:返回数据合约买开仓以来的最低价

我们举例示范一下,这里我们设置开仓信号是收盘价大于5周期均线的时候,进行多头开仓,平仓信号是当收盘价大于开仓均价BKPRICEAV加上10,进行止盈,或者收盘价小于开仓均价减去10,进行止损,平仓的手数是所有的持仓数量,BKVOL。这里使用到了TRADE_AGAIN设置开仓指令可以执行3次。这里使用一系列的信号记录函数,具体的包括输出BKVOL,多头开仓手数;BKPRICE最近一次买开信号价位;BKPRICEAV,多头开仓均价;BKHIGH和BKLOW,返回开仓以来最高价和最低价。

mylang
MA1^^MA(CLOSE,5); CROSSUP(C,MA1),BK; INFO(1,BKVOL,'多头开仓手数#FF0000'); INFO(1,BKPRICE,'最近一次买开信号价位#00FF00'); INFO(1,BKPRICEAV,'多头开仓均价#0000FF'); INFO(1,BKHIGH,'开仓以来最高价#0000FF'); INFO(1,BKLOW,'开仓以来最低价#0000FF'); C>BKPRICEAV+10||C<BKPRICEAV-10,SP(BKVOL); TRADE_AGAIN(3);

可以看到,策略运行开始,没有进行开仓的时候,这几个值返回0;然后伴随开仓和加仓,这几个函数伴随策略的进度,返回相应的数值。

对于空头开仓的信号记录函数,相信大家也可以理解具体的含义,这些函数可以帮助我们实时检查策略的运行状态。

  • SKVOL: 卖开信号手数
  • SKPRICE: 返回数据合约最近一次卖开信号价位
  • SKPRICEAV:返回数据合约空头开仓均价
  • SKHIGH:返回合约卖开仓以来的最高价
  • SKLOW:返回卖开仓以来的最低价

接下来一系列函数用来判断上一个信号是否是具体的哪些指令,返回值是布尔值的形式,1代表真,0代表假。

  • ISLASTBK:判断上一个信号是否是 BK
  • ISLASTSK:判断上一个信号是否是 SK
  • ISLASTBP:判断上一个信号是否是 BP
  • ISLASTSP:判断上一个信号是否是 SP
  • ISLASTBPK:判断上一个信号是否是 BPK
  • ISLASTSPK:判断上一个信号是否是 SPK
  • ISLASTCLOSEOUT:判断上一个信号是否是 CLOSEOUT

还有一系列函数用来判断具体的信号距离当前k线的根数。

  • BARSBK:上一次买开信号位置
  • BARSSK:上一次卖开信号位置
  • BARSSP:上一次卖平信号位置
  • BARSBP:上一次买平信号位置

我们举例示范一下。这里我们使用日志输出上一次买开信号位置和卖平信号位置,根据日志可以看出:在没有执行相应信号之前,这两个函数返回的值是NaN,执行相应信号以后,就开始统计上一次信号执行位置距离当前k线的根数。

mylang
MA1^^MA(CLOSE,5); CROSSUP(C,MA1),BK; INFO(1,BARSBK,'上一次买开信号位置#FF0000'); C>BKPRICEAV+10||C<BKPRICEAV-10,SP(BKVOL); INFO(1,BARSSP,'上一次卖平信号位置#00FF00'); TRADE_AGAIN(3);

还有一系列函数可以帮助获取指令信号的位置,成交量和价格,具体包括:

  • REFSIG_PLACE(Sig,N):返回距离当根K线第N个固定的Sig信号的k线数目。
  • REFSIG_VOL(Sig,N):返回从当根K线开始倒数第N个固定的Sig信号的信号手数(反手指令取开仓手数)
  • REFSIG_PRICE(Sig,N):返回从当根K线开始倒数第N个固定的Sig信号的信号价位

这些函数有参数Sig和N,Sig是具体的信号,我们讲过的7个交易指令都可以使用,N是信号的位置。这些函数可以用来判断指定位置的具体指令的具体属性。

  • COUNTSIG(Sig,N):统计N周期内,某一具体信号的数量。信号可以为BK,SK,SP,BP,SPK,BPK,CLOSEOUT。
mylang
MA1^^MA(CLOSE,5); CROSSUP(C,MA1),BK; C>BKPRICEAV+10||C<BKPRICEAV-10,SP(BKVOL); INFO(1,REFSIG_PLACE(BK,1),'距离当前k线第一个BK信号的k线数目#FF0000'); INFO(1,REFSIG_VOL(BK,1),'距离当前k线第一个BK信号的开仓手数#FF0000'); INFO(1,REFSIG_PRICE(BK,1),'距离当前k线第一个BK信号的开仓价格#FF0000'); INFO(1,COUNTSIG(BK,3),'N周期内BK信号的数量#0000FF'); TRADE_AGAIN(3);

这里我们举例示范一下,分别使用REFSIG统计当前k线第一个BK信号的k线数目,手数和开仓价格,COUNTSIG统计三周期内BK信号的数量,可以看到,在策略开始,由于没有开仓,仅仅输出COUNTSIG函数的结果;在开仓以后,开始输出REFSIG的具体属性。大家可以根据这类的函数属性,制定一些需要的策略。

头寸函数

接下来我们来介绍一下My语言中的头寸函数,它可以帮助我们实时查看交易账户的资金状态。

  • MYVOL:取下单手数,多用于在加减仓模型加载多个合约的时候的手数计算。这是交易类库中的一个参数,这里我们可以进行修改。
  • MONEY:MONEY返回账户可用资金,用于仓位、手数等计算。
  • MONEYTOT:MONEYTOT返回当前账户权益,模型进行仓位控制、下单手数等资金管理时使用
  • MARGIN:杠杆率

我们编写代码示范一下:

mylang
C>1, BK; INFO(1, MYVOL, '下单手数'); INFO(1, MONEY, '可用资金'); INFO(1, MONEYTOT, '当前账户权益'); INFO(1, MARGIN, '杠杆率');

可以看到,在策略运行开始,返回默认的下单手数和杠杆率,没有开仓所以可以资金和当前账户权益是一致的;开仓以后,可用资金MONEY是初始的金额减去了保证金,加上仓位的盈亏;而当前MONEYTOT是包含保证金在内的,初始的金额加上仓位的盈亏。

交易类库

以上呢,就是My语言中的交易函数。在使用交易函数时,我们不得不提到My语言的交易类库。一个策略并不是仅有策略代码就可以运行的,我们还需要搭建策略运行的环境。这个类库就是脱离策略代码层面的,目的是将策略实际交易过程中所需的数值、参数和模式进行整合封装,从而让我们在回测系统模拟或实盘创建时能够方便地进行设置和配置。通过使用这个框架类库,我们可以更好地进行交易的设置,确保策略的稳定运行。

由于市场是瞬息万变的,策略在运行过程中可能会遇到各种突发情况,导致无法完美执行交易操作。因此,我们需要提前为这些情况做好设置和容错处理。My语言的交易类库正是为了满足这一需求而设计的,它提供了丰富的工具和功能,帮助我们应对市场的挑战。

需要注意的是,这里面有些参数是针对于其他金融市场的,我们使用默认值就好。

交易设置

我们来到回测页面来看下。第一个栏目是“交易设置”,其中的执行方式我们前面讲到过。

默认开仓手数:我们刚才提到过,如果对于BK,SK,BPK,SPK没有指定下单数量参数则按照该参数作为下单数量。

最大单次交易下单量:允许的单次下单的最大数量,如果设置的信号触发时下单量比较大,执行下单时会把订单拆分成小的订单分笔下单。

滑价点数(整数):主要用于设置下单交易吃单时加上或减去的溢价,例如当需要买入时,对手卖一的价格时10,我们下买单价格出11,此时11-10=1,多出的1元差价就是滑价,卖出相反,减价卖出的部分就是滑价,加滑价的目的是为了确保成交。需要注意的是,在商品期货交易中,不同品种有不同的priceTick(即一跳价格),系统会自动获取当前品种的priceTick,此时设置的滑价点数就是priceTick的倍数。

这里呢,也可以解释日志信息里,为什么我们看到这里的价格和下单的价格具有较大的差别,这里其实就是滑价点数。比如这里设置品种为铁矿石,滑价为5,当我们下单的时候,实时的卖一价ask是841,为了确保成交,我们需要使用卖一价ask加上,5乘以铁矿石的priceTick是0.5,等于2.5,所以挂单的价格是841加上2.5,843.5这是一个比较高的挂单价格,可以确保成交,并不是实际的成交价格。

变量最长周期数:保存的数据最长周期数,如果设置该参数为200,那么策略中计算的各种数据序列,例如均线、MACD指标线等,只保存最近200根K线上的数据。

期货设置

品种代码这里直接使用合约代码加上888,表示主力合约;或者代码加上000,表示指数合约,但是在具体交易的时候,回测系统和实盘都会映射到最新的主力合约代码上面,并且也会进行移仓换月的操作。

实盘选项

下单重试次数:下单如果没有成交(例如行情变化很快,滑价设置不大的情况,可能下单时,盘口已经移动了)。撤销订单重新下单,该参数控制重新下单的次数,超过次数不再下单,信号执行完毕。

账户同步时间(秒):读取账户数据的时间间隔。

盈亏统计间隔:My语言的收益统计是按时间间隔定时计算、打印当前的浮动盈亏。

失败重试(毫秒):该参数用于接口调用失败时,间隔多少时间重试。

推送通知:该参数勾选后,下单日志,策略中的推送消息会推送到当前账号设置的推送选项。优宽的推送选项可以在这里设置,点击这里的账号设置,选择推送设置,可以选择将实时的交易信息推送到移动端,邮箱或者webhook。

以上就是交易类库中的一些参数的设置,可以在回测系统和实盘里帮助我们更顺利的执行交易的策略。My语言的函数部分我们已经介绍完毕,听到这里的同学,我相信大家一定有十足的耐心和热情去打开量化交易的大门,从下节课开始,我们将真正的进入量化策略的编写部分,大家不要错过。

八、简单模型编写示例(一)

前面的课程,我们介绍了优宽平台支持的My语言函数,包括实时数据获取,信号指标计算,条件逻辑判断,交易函数等,这些函数基本构建了搭建一个策略需要的主体框架。从本节课开始,我们将从My语言一般模型编写开始,从一行行代码敲起来,打造自己的量化策略。大家在编写模型的过程中,如果遇到哪些问题也欢迎留言,我们也会热心解答。

在本节课中,我们讲解My语言简单模型的编写范例。内容包括K线形态的识别、经典指标的计算,以及常见的趋势类和震荡策略的编写。通过实际示例,我们将帮助大家了解My语言策略的编写逻辑和具体实践过程,为大家手动创建个性化策略提供指导。

K线形态的识别

首先,我们从K线形态的识别帮助大家进行量化策略的入门。K线图是历史和实时价格的趋势反应,通过研究K线的趋势规律,可以在一定程度上预测未来走向,也可以帮助判断多空双方的力量对比,进而为投资决策提供重要的参考。

K线图共有三部分组成:即上影线、下影线和实体三部分,上影线为最高价,下影线为最低价,实体由收盘价和开盘价构成。当收盘价高于开盘价时, 用阳线或红线来表示,当开盘价高于收盘价时,用阴线或黑线来表示。依据K线中开盘价,收盘价,最高价和最低价的关系,我们将K线的常见基本形态进行了不同的分类,具体的分法和命名的方式有很多,比如这里图中展示的十四种。

image

有不少的技术派的朋友都喜欢使用k线判断未来的走势,依靠我们的肉眼去观察各个K线的状态并判断确实需要一定的耐心和经验,而在量化语言的帮助下,我们可以自动的判断各个k线的属性,我们举个例子来看下。

光头光脚

第一类我们来看光头光脚类,这类k线的最高价和最低价,是和k线的收盘价或者开盘价一致的,也就是开盘就是最低价或者最高价,收盘就是最低价或者最高价,我们来看下怎样使用My语言进行判断。

mylang
// 光头光脚阳线 POS_HEAD := CLOSE = HIGH; POS_TAIL := OPEN = LOW; INFO( POS_HEAD && POS_TAIL, '涨幅',CLOSE/OPEN - 1,'光头光脚阳线'); // 光头光脚阴线 NEG_HEAD := CLOSE = LOW; NEG_TAIL := OPEN = HIGH; INFO( NEG_HEAD && NEG_TAIL, '涨幅',CLOSE/OPEN - 1,'光头光脚阴线');

这里首先设置光头光脚阳线,收盘价CLOSE是最高价,开盘价是最低价,在满足两项条件情况下,使用INFO进行输出,并计算了具体的涨幅。于此相反,我们也进行光头光脚阴线统计。

这类行情属于极端行情,我们使用比较有名的妖孽品种纯碱试一下,回测时间是去年的一年,可以看到在8月29号是一个极致的阴线,跌幅是6%,8月30号是一个极致的阳线,涨幅是7%,确实比较极端。可以看到,通过对比开盘价,收盘价,最低价和最高价之间的关系,我们就可以使用程序判断单根k线的不同状态。

以上呢,只是单根k线的形态,如果组合两根或者两根k线以上,总结出来了更多的k线形态。这些K线形态也可以使用量化语言进行鉴别。

image

跳空

跳空是两条相邻K线之间出现价格的大幅上涨或者下跌的情况,包括跳空高开和跳空低开。要问期货市场哪个品种出现的跳空次数最多,相信熟悉期货市场的朋友这个答案可以脱口而出,燃油。燃油的走势依赖于原油,而原油和国外的原油品种存在较大的相关性,但是因为国内外原油品种的开盘时间不同,国外累计的走势需要在国内开盘一瞬间完成,所以就造成燃油期货品种在开盘的一瞬间出现大幅跳空高开或者跳空低开的情况。我们使用My语言进行一下统计。

mylang
//跳空高开 PREHIGH := REF(HIGH, 1); INFO(OPEN > PREHIGH * 1.01, '幅度:',OPEN/REF(CLOSE, 1) - 1,'跳空高开#FF0000'); //跳空低开 PRELOW := REF(LOW, 1); INFO(OPEN < PRELOW * 0.99, '幅度:',OPEN/REF(CLOSE, 1) - 1,'跳空低开#00FF00');

通过比较两条K线的属性,大家有没有好的思路使用My语言进行定义跳空高开和跳空低开的情况。对了,可以使用REF函数,最新的开盘价大于上一根K线的最高价一定百分比的时候,我们定义为跳空高开;相反情况下,当最新的开盘价小于上一根K线的最低价一定百分比,定义为跳空低开。

这里我们统计跳空高开和跳空低开的情况。如果最新的开盘价大于上一周期的最高价乘以1.01的倍数,我们定义为跳空高开,并计算一下高开的幅度。对于跳空低开,定义开盘价小于上一根k线的最低价乘以0.99,打印低开的幅度。

我们来看一下结果,使用燃油期货,设置k线周期为1小时。可以看到在每天早上开盘9点第一根k线结束,10点的时候;或者晚上21点开盘,K线结束22点的时候,非常容易出现跳空高开和低开的情况,在其他的时间段行情都是比较平稳的。所以,喜欢对冲套利的朋友可以考虑一下燃油期货。

经典指标信号的计算

接下来我们来看下使用My语言进行一些经典指标的编写实例。前面课程在数理函数的讲解课程中,我们进行了MACD指标的编写。其实这些指标并不复杂,在我们了解指标计算原理的基础上,我们基本上都可以使用My语言进行实现。在指标计算的基础上呢,我们可以进行具体的信号判断,比如多头排列,金叉死叉,背离等。

多头排列 vs. 空头排列

多头排列和空头排列是在技术分析中经常用到的概念,它们涉及到市场中多头(买方)和空头(卖方)力量的相对关系。

多头排列具体指的是短期移动平均线在长期移动平均线的上方,这被认为是一个积极的信号,表明价格处于上涨的趋势。而短期移动均线处于长期均线下方的时候,认为价格处于下跌的趋势。

具体的均线周期和数量的选择,可以根据自身对于市场的理解进行决定,这里我们展示一下三均线多头排列和空头排列的My语言程序。

mylang
MA5 ^^ MA(CLOSE,5); MA10 ^^ MA(CLOSE,10); MA30 ^^ MA(CLOSE,30); POSLINE := MA5 > MA10 && MA10 > MA30; NEGLINE := MA5 < MA10 && MA10 < MA30; INFO(POSLINE, '多头排列#FF0000'); INFO(NEGLINE, '空头排列#00FF00');

这里分别设置三条均线,使用的周期是5,10和30,对于多头排列是短期大于中期,中期大于长期;空头排列刚好相反。

金叉 vs. 死叉

多头排列和空头排列可以判断实时的趋势,可以当我们想判断市场转折点进行入场的时候,金叉和死叉是比较适合的。

"金叉"和"死叉"是技术分析中常用的术语,用来描述两条移动平均线的相对位置关系。金叉发生在短期移动平均线从下方穿越长期移动平均线的时候。通常,这被视为一个买入信号,表明市场由跌势进入上涨趋势。死叉刚好相反,发生在短期移动平均线从上方穿越长期移动平均线的时候,表明市场即将进入下跌趋势。

mylang
MA5 ^^ MA(CLOSE,5); MA10 ^^ MA(CLOSE,10); MA30 ^^ MA(CLOSE,30); GOLDCROSS := CROSSUP(MA5, MA10) && CROSSUP(MA10, MA30); DEADCROSS := CROSSDOWN(MA5, MA10) && CROSSDOWN(MA10, MA30); INFO(GOLDCROSS, '金叉#FF0000'); INFO(DEADCROSS, '死叉#00FF00');

这里我们定义当短期上穿中期,中期上穿长期的时候,定义为金叉;反之定义为死叉,我们运行一下,发现没有符合条件的k线。这也是可以理解的,因为比较均线同时上穿或者下穿是比较难以满足的,我们可以改变一下代码。对于金叉当短期上穿中期的时候,只需要判断中期是否大于长期就可以;对于死叉当短期下穿中期的时候,需要判断中期是否小于长期。日志输出可以看到对应的金叉和死叉的信号。

mylang
MA5 ^^ MA(CLOSE,5); MA10 ^^ MA(CLOSE,10); MA30 ^^ MA(CLOSE,30); GOLDCROSS := CROSSUP(MA5, MA10) && MA10 > MA30; DEADCROSS := CROSSDOWN(MA5, MA10) && MA10 < MA30; INFO(GOLDCROSS, '金叉#FF0000'); INFO(DEADCROSS, '死叉#00FF00');

当然上面的只是基本的条件,这里我们还可以发挥主观能动性,添加一些成交量的条件,比如在出现金叉或者死叉的时候,是否成交量或者持仓量出现巨量的上涨或者下跌,大家可以试着判断一下。

顶背离 vs. 底背离

接下来我们来看一个概念背离。在技术分析中,"背离"是指价格走势和某种技术指标之间出现不一致的情况。背离可以分为两类:顶背离和底背离。

顶背离发生在价格创造新高而某个技术指标未能确认新高的情况下。通常,这被视为市场可能趋于疲软的信号。例如,价格形成新的高点,但相对强弱指数(RSI)或移动平均散度收敛指标(MACD)等技术指标未能跟随形成新高,甚至呈现下降趋势。

相对底背离发生在价格创造新低但是某些指标不跟随,甚至呈现上升趋势。因此背离可以作为出场信号的标志,我们使用My语言代码进行一下实现。

mylang
FASTLINE^^EMA(CLOSE,12); SLOWLINE^^EMA(CLOSE,26); DIF:FASTLINE-SLOWLINE,CIRCLEDOT; DEA:EMA(DIF,9); MACDDIFF:2*(DIF-DEA),COLORSTICK, IF(2*(DIF-DEA) > 0, COLORRED, COLORGREEN); TOPDIV := CLOSE > REF(CLOSE, 1) && MACDDIFF < REF(MACDDIFF, 1); BOTDIV := CLOSE < REF(CLOSE, 1) && MACDDIFF > REF(MACDDIFF, 1); INFO(TOPDIV, '顶背离#FF0000'); INFO(BOTDIV, '底背离#00FF00');

我们来看一下My语言的编写,首先使用我们先前讲过的MACD指标,计算MACD值。然后判断背离的情况,顶背离是收盘价大于上根k线的收盘价,也就是价格是上升的,但是MACD小于上根k线的值,定义为顶背离。底背离刚好相反,如果价格转为下降,但是MACD值出现上升,我们定义为底背离。这就是背离的一个基础版的定义。

背离可以作为一个出场的信号,这里我们结合上面的金叉和死叉的概念,在MACD出现金叉或者死叉我们进行入场开仓,出现背离进行相应的离场。这样一个策略的模型我们就搭建完成。我们来试着编写一下。

mylang
FASTLINE^^EMA(CLOSE,12); SLOWLINE^^EMA(CLOSE,26); DIF:FASTLINE-SLOWLINE,CIRCLEDOT; DEA:EMA(DIF,9); MACDDIFF:2*(DIF-DEA),COLORSTICK, IF(2*(DIF-DEA) > 0, COLORRED, COLORGREEN); TOPDIV := CLOSE > REF(CLOSE, 1) && MACDDIFF < REF(MACDDIFF, 1); BOTDIV := CLOSE < REF(CLOSE, 1) && MACDDIFF > REF(MACDDIFF, 1); INFO(TOPDIV, '顶背离#FF0000'); INFO(BOTDIV, '底背离#00FF00'); GOLDCROSS := CROSSUP(MACDDIFF, 0); DEADCROSS := CROSSDOWN(MACDDIFF, 0); INFO(GOLDCROSS, '金叉#FF0000'); INFO(DEADCROSS, '死叉#00FF00'); GOLDCROSS, BK; TOPDIV, SP; DEADCROSS, SK; BOTDIV, BP; AUTOFILTER;

这里我们选择走势比较平稳的玉米品种试一下,可以看到这个策略在去年比较平稳的情况下收益还是不错的。大家可以改编这个策略,添加更多的条件,针对于自己喜欢的品种,进行更多的尝试!

九、简单模型编写示例(二)

上节课我们学习了My语言中K线形态识别,以及一些技术指标的判断,并且最后利用这些技术指标编写了一个量化策略。本节课,我们将聚焦于量化交易中的三种重要策略类型:趋势类、通道类和震荡类策略。在了解这些策略概念的基础上,我们将学会怎样使用My语言进行实现。

趋势类策略

在量化交易中,趋势类策略是一种基于历史价格趋势的模型。通过对市场趋势的识别和预测,我们可以制定策略以追随并利用这些趋势。

趋势类策略在量化交易中具有显著的优点和一些明显的缺陷。首先,其主要优势在于能够较为准确地捕捉市场的明显趋势方向,使得交易者更容易在趋势初现时进入市场,从而获取更大的收益。这使趋势类策略在市场有明确趋势的时候能够灵活适应,并更好地把握市场机会。其适用性广泛,且操作相对简单,特别是使用基础技术指标如移动平均线等进行趋势判断的方法,易于理解和实施。

然而,趋势类策略也存在一些明显的缺陷。首先,受限于价格数据的延迟,特别是在使用长周期均线时,可能导致进场点相对滞后,错过一部分趋势初期的涨跌。在市场处于震荡阶段时,表现可能较差,因为趋势类策略更适用于明显趋势的市场,而在价格波动不明显时容易产生误判和频繁的交易信号。此外,在市场快速变化或出现剧烈波动时,趋势类策略可能无法迅速调整,导致无法灵敏地捕捉到短期内的趋势变化。

综合而言,趋势类策略在趋势明显的市场中表现出色,但在市场变化较为复杂的情况下,可能需要与其他类型的策略结合使用,以提高整体的交易效果。

趋势判断使用最多的技术指标之一就是均线,在前面My语言数理统计函数中,我们学过很多种均线,比如最简单的简单移动平均线(MA),指数移动平均线(EMA),加权移动平均线(WMA)等。这些均线可以通过对不同时间段内的价格数据进行平均计算,形成平滑的趋势线,从而更清晰地揭示市场价格的走势方向。

我们大致来说下这些均线的区别,简单移动平均线(MA)通过计算一定时间内的平均价格,每个价格的权重是一样的,用来平滑价格波动,使趋势更为明显。指数移动平均线(EMA)则更加注重近期价格的权重,对市场变化更为敏感。而加权移动平均线(WMA)则在计算均值时对不同时间点的价格给予不同的权重,更灵活地适应市场的变化。

这些均线不仅用于趋势的确认,还可作为制定买卖信号的依据。例如,上节课我们讲过,当短期均线上穿长期均线时,可能产生“金叉”信号,被视为买入时机;相反,当短期均线下穿长期均线时,可能产生“死叉”信号,被视为卖出时机。这些信号的生成有助于自动化交易决策,提高交易效率。

在制定趋势类策略时,除了均线外,还可以结合其他技术指标如MACD(移动平均散度收敛指标)、ADX(平均动向指数),RSI(随机强弱指标)等,以全面把握市场趋势的方向和强度。综合利用这些指标,我们能够更精准地捕捉并响应市场的趋势,从而实现更有效的量化交易策略。因此本节课我们讲的第一个模型就是均线结合RSI指标的模型。

RSI的原理很简单,就是通过一系列的数学运算,得出商品期货市场中买卖双方的力量强弱对比,从而预测未来价格的趋势方向。RSI指标的数值范围是0~100,但大部分都是在20~80之间波动,如果RSI的值超过80就说明该品种被过度买入,价格转向下跌的趋势较大。如果RSI的值低于20就说明该品种被过度卖出,价格容易出现反弹。RSI的计算过程还是非常简单,一句话可以概括为:在某个时间段价格上涨所产生的波动占整个波动的百分比。

My语言封装了设置期货合约和数据获取的指令,所以我们直接开始指标的计算。首先我们还是利用代码计算RSI指标,首先获取上根K线收盘价,然后计算收盘价与上根K线收盘价的差,在该差值与0之间取最大值,代表上涨的波动;接着计算收盘价与上根K线收盘价的差,取该差值绝对值,代表总体的波动;然后分别计算U和D的2周期平均值,这里的周期大家可以设置;通过计算U和D的比值,将比率乘以100,保证了其值范围在0~100之间,就获取到了RSI的值。然后我们计算EMA指标,这里使用到了内置函数EMA,但是EMA的均值周期这里我们设置为策略的参数。因为固定的参数并不适合于所有的品种,所以这里设置为策略的参数,放进模型中进行调参找到适合不同品种的参数。然后我们就可以计算交易信号了,当形成金叉,收盘价大于EMA均值,RSI小于20,定义为做多信号;反之死叉,并且RSI大于80,定义为做空信号。最后设置AUTOFILTER形成一开一平的交易模式。

mylang
// RSI值 YC := REF(C, 1); // 上根K线收盘价 U := MAX(C - YC, 0); // 计算收盘价与上根K线收盘价的差,在该差值与0之间取最大值 D := ABS(C - YC); // 计算收盘价与上根K线收盘价的差,取该差值绝对值 RS := SMA(U, 2, 1) / SMA(D, 2, 1); // 分别计算U和D的2周期平均值,计算U和D的比值 RSI : RS * 100; // 将比率乘以100,保证了其值范围在0~100之间 // 均值 EMAVALUE ^^ EMA(CLOSE, meanPeriod); // 交易操作 CLOSE > EMAVALUE AND RSI < 20, BPK; //平空开多 CLOSE < EMAVALUE AND RSI > 80, SPK; //平多开空 AUTOFILTER;

模型代码写好以后,设置交易品种为玉米,这里重点我们来看下怎样进行调参。设置调参范围是5到30,以5为步长,我们来看下不同参数下的模型收益如何,可以看到,模型在参数为15时,获得了最高的收益。但是我们也不能直接应用于这个参数到实盘当中,我们需要回测更长的时间,检验模型的健壮性。

通道类策略

通道类策略在量化交易中是基于价格波动通道的模型。这种策略认为价格在一定通道内波动属于正常区间,当价格突破边界的时候,进行交易来获取利润,所以可以认为是一个突破策略。因此通道类策略的要点包括:

  1. 通道确定: 利用历史价格数据,通过计算价格的波动范围、支撑与阻力水平等,确定市场的交易通道。

  2. 突破交易: 在价格突破通道底部的时候进行卖出,在价格突破通道顶部进行买入。这要求交易者在波动通道中敏锐地把握价格的波动特征。

  3. 动态调整交易范围: 随着市场波动性的变化,通道的宽度也可能发生变化。因此,通道类策略需要能够动态调整交易通道的范围,以适应市场的变化。

通道类策略相比于一些复杂的量化交易策略,通道类策略较为简单直观。通过对历史价格的波动范围进行分析,可以相对容易地确定交易通道。并且由于基本思想是在价格突破通道时进行交易,执行通道类策略相对较为简单。交易者可以根据事先设定好的规则和参数执行交易。因此通道类策略可以帮助交易者捕捉市场快速波动的机会,从而在较短时间内获取利润。

但是通道类策略也存在一些缺陷,通道类策略的性能高度依赖于市场的波动性,如果市场进入低波动期或高波动期,通道的宽度可能需要调整。这要求策略需要能够敏感地捕捉市场波动性的变化。并且在市场存在噪声时,价格可能会在通道内频繁波动,导致假信号。这可能使得通道类策略容易受到噪声的干扰,执行不准确。

通道类比较著名的策略包括唐奇安通道和布林带通道策略。唐奇安通道使用的是固定周期内的最高价和最低价作为上下轨,当突破上下轨的时候进行买入和卖出的操作。布林带通道是使用一段周期内的价格作为均线,然后波动范围的计算是一段时间内的标准差,然后使用均线加减2倍标准差,作为通道的上下轨,所以通道的宽度更加灵活,可以较快的反应价格变化的趋势。本节课我们就来使用My语言进行布林带通道策略的实现。

首先我们计算均线和标准差,这里使用到了两个策略参数,N1是均线周期,N2是标准差周期,然后我们就可以利用均值加减两倍差作为上限和下限,当收盘价向上突破上限的时候,定义为做多信号;当收盘价下穿下限,定义为做空信号。最后使用两个信号进行开平仓的操作。

mylang
//布林带通道 MAVALUE:=MA(CLOSE,N1); //均线 STDVALUE:=STD(CLOSE,N2); //标准差 UPLINE ^^ MAVALUE+2*STDVALUE; //布林带上限 BOTLINE ^^ MAVALUE-2*STDVALUE; //布林带下限 //交易信号 LONGSIG:=CROSSUP(CLOSE,UPLINE);// 平空开多条件 SHORTSIG:=CROSSDOWN(CLOSE,BOTLINE); //平多开空条件 //交易操作 LONGSIG,BPK; SHORTSIG,SPK; //过滤函数 AUTOFILTER;

这就是一个简单的布林带策略,当然这个策略也可以进行更多的拓展,比如这里的平仓条件我们可以设置的更加稳妥一点,当最新的收盘价到达均线的时候就进行平仓,不需要等到突破的时候再进行操作。大家可以尝试一下。

震荡类策略

震荡类策略是一种适用于市场无明显趋势的情况下的模型。该策略认为价格会在一定范围内反复震荡,交易者可以在波动的底部买入、在波动的顶部卖出。所以震荡类策略背后的原理是均值回归的思想。所以这和上面的通道突破类策略类似,假设价格波动的范围在一定的区间,但是更多的是假设均值要进行回归。

这种策略的优势在于其相对简单直观,能够捕捉到市场短期内的震荡行为,特别适用于横盘市场。然而,它在面对明显趋势的市场时可能表现较差,容易受到噪声的干扰,而且对于参数的选择相当敏感。此外,由于强调价格回归到均值,可能错过长期趋势行情,需要在使用时谨慎权衡其优缺点,并结合风险管理策略进行合理的参数选择和执行。

所以在上一个通道策略的基础上,我们可以进行修改,将它改变成为一个震荡类策略。大家想下有没有具体的思路。好的,下面我们用代码进行一下实现。

同样的计算出来上轨UPLINE,中轨MAVALUE,下轨DOWNLINE,但是具体开平仓的逻辑我们需要改变一下。当价格下穿下轨的时候,我们预测价格会回归到均值,所以进行开多,所以当价格回归到均值我们进行平多;与此相返,当价格上穿上轨进行做空,直到回归均线,我们进行平空。

但是这个模型面临一个问题,我们能假设价格一直是平稳运行的吗?呈现趋势单边上涨或者下跌行情的时候,我们会面临比较大的亏损。所以我们需要添加一个前置条件,当标准差小于一定阈值,证明最近走势比较平稳我们再进行开仓的操作。所以添加一个前置条件,标准差需要小于一个参数阈值,这里设置为策略参数,在开仓的条件中增加这个标准差的限制条件。这样一个可以避免趋势行情的震荡类策略我们就设置完成。

mylang
//布林带 MAVALUE ^^ MA(CLOSE,N1); STDVALUE:=STD(CLOSE,N2); UPLINE ^^ MAVALUE+2*STDVALUE; BOTLINE ^^ MAVALUE-2*STDVALUE; //交易条件 LONGSIG:=CROSSDOWN(CLOSE,BOTLINE); //开多条件 COVERLONGSIG:=CROSSUP(CLOSE,MAVALUE);//平多条件 SHORTSIG:=CROSSUP(CLOSE,UPLINE);// 开空条件 COVERSHORTSIG:=CROSSDOWN(CLOSE,MAVALUE); //平空条件 //交易系统: STDVALUE < STDTHRE && LONGSIG,BK; COVERLONGSIG,SP; STDVALUE < STDTHRE && SHORTSIG,SK; COVERSHORTSIG,BP; //过滤函数 AUTOFILTER;

在量化交易中,趋势类、通道类和震荡类策略各具特色,适用于不同的市场状况。有效的量化模型需要结合市场数据、技术指标和风险管理,灵活运用这些策略,这样呢才可以在复杂多变的市场环境中取得稳健的交易收益。

十、My语言商品期货量化交易教程:复杂模型编写示例(一)

上节课程我们讲解了My语言中简单模型的编写示范,在讲解的简单模型当中,使用的大多数都是单一K线周期的,单个或者两个指标的策略模型。但是在实际的交易中,市场变化复杂,很难使用简单的模型去模拟所有的市场变化,所以更多的时候,我们需要多个周期,多个指标去判断市场的趋势,并且在交易过后,我们需要止盈止损的措施在获取更多收益的同时,及时止损,防止扛单等遭受更多损失的风险管理措施。这样才是一个合乎标准的实盘级策略。本节课程,我们就来讲解复杂模型的编写示例。

麦语言与JavaScript语言混合编程

在My语言课程导入部分我们有提到过,在优宽平台,量化策略可以在My语言的基础上,还可以召唤JavaScript大法,自定义功能模块,帮助复杂模型中指标的获取和计算。下面我们来看下怎样操作。

我们来举一个在My语言中使用Js自定义功能模块的例子。

mylang
%% scope.TEST = function(obj) { return obj.val * 100; } %% 收盘价:C; 收盘价放大100倍:TEST(C); 上一个收盘价放大100倍:TEST(REF(C, 1)); INFO(1, 收盘价, '收盘价'); INFO(1, 收盘价放大100倍, '收盘价放大100倍'); INFO(1, 上一个收盘价放大100倍, '上一个收盘价放大100倍');

首先我们需要%%符号定义Js功能模块,这里面可以调用优宽量化的任何API。这里面scope是一个对象,可以添加属性,比如这里我们添加TEST函数为scope的一个属性。在这个TEST函数里,参数是obj,返回结果是obj.val的100倍结果。

接着在My语言代码部分就可以调用这个属性引用的匿名函数。比如这里定义第一个变量是收盘价,然后使用Js模块中的TEST函数获取收盘价的100倍,最后一个变量也是使用TEST,但是参数是上一个收盘价。然后我们使用INFO函数打印出来函数返回的结果。可以在日志里,我们可以看到返回了相应的结果。

这就是在My语言中使用Js自定义功能模块的一个简单例子。除了自定义属性,这里的scope对象还由一些固定的属性,这里给大家讲解一下。

  • scope.getRefs(obj)

第一个getRefs,调用scope.getRefs(obj)会返回传入的obj对象的数据。这里我们举例定义TEST2函数,在这个函数内,参数是obj,使用arr定义getRefs返回的结果,然后使用log进行打印。在My语言当中,使用TEST2函数,当填写参数为收盘价的时候,TEST2函数会返回这个K线数据的所有的收盘价。但是由于使用了throw "stop"中断程序。所以返回结果变量arr只包含了第一根Bar的收盘价。

mylang
%% scope.TEST2 = function(obj){ var arr = scope.getRefs(obj) Log("arr:", arr) throw "stop" return } %% TEST2(C);
  • scope.bars

Scope.bars在JavaScript代码块中访问所有K线bar。这里我们定义TEST3函数,当我们想要判断最新的一根K线,所以它的索引位置是bars.length - 1,判断它的开盘价是否大于收盘价,也就是当前是否是阴线。如果是,返回数值1,如果不是返回数值0。根据回测结果,可以看到返回相应的阴线判断。

mylang
%% scope.TEST3 = function(){ var bars = scope.bars return bars[bars.length - 1].Open > bars[bars.length - 1].Close ? 1 : 0 // 只能返回数值 } %% //arr:TEST3; //arr:TEST3(); INFO(1, arr, 'TEST3结果');

这里需要注意的一点是,因为TEST3是不包括参数的,所以使用TEST3加上括号的形式,会直接报错。

  • scope.bar

相对于scope.bars返回所有k线,scope.bar只返回当前k线。

mylang
%% scope.TEST4 = function(){ var bar = scope.bar return bar.Open > bar.Close ? 1 : 0 } %% avg^^TEST4; INFO(1, arr, 'TEST4结果');

这里同样的判断当前K线开盘价是否大于收盘价,可以看到和上面返回一致的结果。

  • scope.symbol
    返回当前交易品种名称字符串。

  • scope.canTrade
    标记当前是否可以交易

以上的就是麦语言与JavaScript语言混合编程的例子,相对而言,Js语言更加灵活,可以实现更多的功能。如果大家熟悉Js语言,在My语言中我们可以编写更多简便的函数,帮助更好的进行策略的实现。

mylang
%% scope.MACD = function(){ var MACD = TA.MACD(scope.bars, 12, 26, 9) return MACD[2][scope.bars.length - 1] } %% MACDVALUE:MACD; //返回MACD最新值 INFO(1, MACDVALUE, 'MACDVALUE');

这里我们示范一个计算MACD的例子,在My语言中,由于不包含MACD的内置函数,所以我们需要手动的进行计算。而在优宽的Js语言当中,对于MACD内置函数进行了封装,所以我们可以直接调用。这里在Js功能块中,使用内置函数TA.MACD,参数填写K线scope.bars,具体的周期设置为12,26和9,然后最后的返回是MACD第三个数组是MACD的值,最新的索引是scope.bars.length - 1。这样打印出来可以获取到实时更新的MACD值。在熟悉优宽平台Js语言基础上,相对于使用原生的My语言计算确实很方便快捷。

多周期引用

第二部分我们来看多周期引用。在有些量化策略当中,比如多周期均线共振策略,我们不仅要利用当前设置的周期,有时候我们还需要当前周期以外的周期,进行一些指标的计算和判断。这个时候我们可以使用My语言的多周期引用。我们来看下怎样设置。

我们知道My语言的固定周期是在这里设置的,这里设置好以后,我们获取的周期都是固定设置的频率。在策略当中,我们想获取不同周期的时候。
在My语言中,可以这样设置。

mylang
#IMPORT [MIN,周期,公式名] AS 变量值

这里通过IMPORT引用公式。第一个参数是时间周期,这个命令中的中的MIN意思为分钟级别,还可以支持HOUR小时和DAY日级别的。这里需要注意的是,底层k线的设置需要比定义k线的周期要小,否则获取不到定义周期的k线。然后第二个参数是具体周期的数值,填写是数字的形式;第三个周期是公式名,使用获取到的周期进行一些公式的计算,这里的公式我们需要另外设置。这里的格式需要注意一下,使用井号开头,最后没有分号。例如这里设置底层周期是1分钟,当我们想要获取15分钟周期K线,可以这样设置。填写参数MIN,15,公式暂且命名为TEST,变量值定义为15。

在我们获取到不同周期的k线以后,当需要进行指标计算的时候,这里的计算公式就是要通过“#EXPORT TEST ”和“#END”进行定义。需要注意格式,在这函数体内,填写具体计算的公式。例如这里定义MEAN20函数,计算指定周期收盘价的EMA的均线值,这里的EMA周期设置为20。

mylang
#EXPORT TEST MEAN20:EMA(C, 20); #END // 结束

然后我们就可以获取到15分钟周期均线的EMA20的值了,通过这样编写,VAR15.MEAN20。这样呢,就是一个获取不同周期进行指标计算的例子。

结合以上这两个命令,下面我们举例示范一个多周期共振策略的例子。多周期共振是指两个或者两个以上不同周期的均线均发生多头排列,比如这里的红色线代表小周期,绿色系代表大周期,两个周期内短周期均线大于长周期均线,代表上涨的趋势强烈,这个时候可以进行入场做多;当发生空头排列,就是两个不同周期内,短周期均线都小于长周期周期,这个时候下跌的趋势强烈,进行入场做空。

所以在这个策略当中,我们需要获取不同周期的K线,在My语言代码中,这里使用IMPORT分别定义,一个5分钟周期,作为小周期,和30分钟周期,作为大周期,定义变量名为VARSHORT和VARLONG。另外,我们需要定义公式TEST,使用“#EXPORT”和“#END”定义两个公式,计算不同周期内的短线和长线均值,这里分别计算指定周期的EMA均值,设置周期数分别为5和10,定义为MEANSMALL和MEANBIG。

接下来我们就可以不同周期的不同均值计算公式进行指标的确定了,这里分别定义了小周期短线,小周期长线,大周期短线和大周期长线。

然后我们可以判断两个周期的多头排列和空头排列了。当大周期短线大于长线的时候,当发生小周期短线上穿小周期长线的时候,我们可以及时入场,定义为做多信号LONGSIG;相反情况下,大周期短线小于大周期的长线,并且小周期的短线下穿小周期长线的时候,定义为做空信号SHORTSIG。

然后我们定义平多和平空的信号,当多头排列结束,为了防止频繁的不稳定的信号,这里我们定义为比较稳重的的大周期的短线下穿长线的时候,进行平多;当空头排列结束,大周期短线上穿长线,进行平空。这样呢,就是一个多周期共振的策略模版。大家可以根据这个思路进行更多策略的完善。

mylang
// #EXPORT扩展语法,以#END结束标记为一个公式,可以声明多个 #EXPORT TEST MEANSMALL:EMA(C, 5); MEANBIG:EMA(C, 10); #END // 结束 #IMPORT [MIN,5,TEST] AS VARSHORT // 引用公式,K线周期用5分钟 #IMPORT [MIN,30,TEST] AS VARLONG // 引用公式,K线周期用30分钟 SHORTSMALL ^^ VARSHORT.MEANSMALL, COLORRED; //小周期短线 SHORTBIG ^^ VARSHORT.MEANBIG, COLORRED, DOT; //小周期长线 LONGSMALL ^^ VARLONG.MEANSMALL, COLORGREEN; //大周期短线 LONGBIG ^^ VARLONG.MEANBIG, COLORGREEN, DOT; //大周期长线 LONGSIG := CROSSUP(SHORTSMALL, SHORTBIG) && LONGSMALL > LONGBIG; //多头均线共振 SHORTSIG := CROSSDOWN(SHORTSMALL, SHORTBIG) && LONGSMALL < LONGBIG; //空头均线共振 COVERLONGSIG := CROSSDOWN(LONGSMALL, LONGBIG); //小周期下跌突破,平多头 COVERSHORTSIG := CROSSUP(LONGSMALL, LONGBIG); //小周期上涨突破,平空头 LONGSIG, BK; //开多 SHORTSIG, SK; //开空 COVERLONGSIG, SP; //平多 COVERSHORTSIG, BP; //平空 AUTOFILTER;

以上呢,就是My语言中JavaScript语言混合编程和多周期引用的例子,希望带给大家更多的启发,帮助开发出更多有效的策略,如果哪里存在疑问,欢迎进行留言,我们也会热心的进行解答。

十一、My语言商品期货量化交易教程:复杂模型编写示例(二)

大家好,上节课我们学习了My语言中Js语言增强和多周期策略的设置,这都是在优宽平台进行复杂策略编写所要使用的一些方法和设置,今天我们讲解My语言复杂模型编写第二部分的课程。本节课首先我们讲解一下My语言中止盈止损的设置。

止盈止损设置

交易界有句老话:“会买是徒弟,会卖是师傅”。顾名思义怎么卖比怎么买更难,因为在买入的时候只需要判断行情是否开始就可以了;但是一旦买进之后,不但需要判断行情是否转向,还需要时刻控制风险。相信很多交易者都经历过过山车的行情,明明上车了最后还是以小赚甚至亏损的结果出局。或者本来可以以小亏出局,结果从小亏损积累成大亏损。所以从这点看,卖出比买入更为重要。

简单的说,卖出无非是两种情况:止盈和止损。如果运气很好,买入方向是正确的,这时就要考虑止盈的问题,否则可能账面上赚到了钱,没有在合适的位置获利了结,最后平亏出局。如果运气不好,买入和方向和市场的走势不一致,这时就要考虑止损了,或者在开仓买入之前就应该考虑好止损的位置,否则小亏损会积累成大亏损。

前面的一系列我们编写的策略大多数使用的是指标进行开仓和平仓的操作,但是在一定程度上,指标具有滞后性,并且也不能判断实时的盈亏,所以对于平仓的条件,我们可以进行止盈止损的设置。

本节课我们介绍两种止盈止损的设置,也是使用较多的,包括固定止盈止损和移动止盈止损。

固定止盈止损

固定止盈止损很好理解,就是在开仓以后,采用固定点数或者固定比例进行平仓的设置。我们来看下在策略中怎样设置。

mylang
// 固定点数 MA1 ^^ MA(C, 5); MA2 ^^ MA(C, 10); CROSSUP(MA1, MA2), BK; CROSSDOWN(MA1, MA2), SK; 多头止盈价格 := BKPRICE + PROFITNUMBER * MINPRICE; 多头止损价格 := BKPRICE - LOSSNUMBER * MINPRICE; 空头止盈价格 := SKPRICE - PROFITNUMBER * MINPRICE; 空头止损价格 := SKPRICE + LOSSNUMBER * MINPRICE; C > 多头止盈价格 || C < 多头止损价格, SP; C < 空头止盈价格 || C > 空头止损价格, BP; AUTOFILTER;

首先我们来看固定点数的止盈止损设置,这里需要两个策略参数,分别是PROFITNUMBER止盈系数,和LOSSNUMBER止损系数。在这个策略当中,开仓条件使用双均线进行判断,然后我们就可以根据多头开仓价格BKPRICE,和空头开仓价格SKPRICE,设置相应的多头和空头的止盈止损价格。逻辑这里是比较清晰的,对于多头止盈,使用多头开仓价格加上止盈点数乘以价格最小变动单位,我们有提到过,不同合约的MINPRICE是不同的;多头止损是多头开仓价格减去止损系数乘以MINPRICE。空头的止盈和止损就是使用空头开仓价格减去和加上止盈和止损的价格。

最后当判断收盘价达到止盈价格或者止损价格的时候,我们进行相应的平仓就可以。这就是固定点数的止盈止损方法。关于固定比例的止盈止损方法,相信大家也都可以理解了。通过设置止盈百分比和止损百分比,然后对应的设置止盈价格和止损价格,最后进行相应的条件平仓就可以。

mylang
MA1 ^^ MA(C, 5); MA2 ^^ MA(C, 10); CROSSUP(MA1, MA2), BK; CROSSDOWN(MA1, MA2), SK; 多头止盈价格 := BKPRICE * (1 + PROFITPERCENT/1000); 多头止损价格 := BKPRICE * (1 - PROFITPERCENT/1000); 空头止盈价格 := SKPRICE * (1 - LOSSPERCENT/1000); 空头止损价格 := SKPRICE * (1 + LOSSPERCENT/1000); C > 多头止盈价格 || C < 多头止损价格, SP; C < 空头止盈价格 || C > 空头止损价格, BP; AUTOFILTER;

移动止盈止损

固定的比例或者点位进行止盈止损有时候太过于死板。当我们主动止盈时,可能会遇到一大波行情,只赚到其中一小部分就错过了后续更大的利润。虽然这样的交易并不亏损,但心理上会有一种错失良机的遗憾感。为了解决这个问题,移动止盈止损策略采用了浮动止损的方法,就是在获得不同级别的浮动盈利之后,开启下一级主动止损模式。这样一方面可以持续享受较高的浮动盈利,同时也不断提高止损点位,用来实现更多盈利的目标。

我们来看下怎样实现。这里同样设置止盈系数和止损系数。开仓同样使用均线交叉,对于平仓,这里我们设置了两个条件。

对于多头,在最新的收盘价小于开仓价格的情况下,证明是亏损的状态,平仓条件是当最新的收盘价小于开仓价格减去止损的系数,这样可以保证止损的范围不会持续扩大;而当最新的收盘价大于开仓价格的时候,我们可以进行移动止盈价格的设置,这里我们参考的移动指标是开仓以来的最高价BKHIGH,我们当然期待它是不断上升的,但是当回撤到一定范围的时候,证明趋势的可能转换,我们需要进行止盈平仓;所以在判断收盘价大于开仓价的情况下,当收盘价回撤到开仓以来的最高价BKHIGH减去止盈系数的时候,我们进行平仓的操作。

对于空头的设置,大家也是同样可以理解了。

mylang
MA1 ^^ MA(C,5); MA2 ^^ MA(C,10); LONGSIG:=CROSSUP(MA1,MA2); SHORTSIG:=CROSSUP(MA2,MA1); COVERLONGSIG:=C<BKPRICE-LOSSNUMBER||(C>BKPRICE&&C<BKHIGH-PROFITNUMBER); COVERSHORTSIG:=C>SKPRICE+LOSSNUMBER||(C<SKPRICE&&C>SKLOW+PROFITNUMBER); LONGSIG,BK; COVERLONGSIG,SK; SHORTSIG,SP; COVERSHORTSIG,BP; AUTOFILTER;

以上呢,就是使用比较多的固定止盈止损和移动止盈止损的设置,当然大家还可以进行更多的止盈止损设置。比如使用实时的波动率动态的设置止盈上限和止损下限等,大家有好的想法都可以提出来,这边呢,会争取帮助大家进行实现。

恒温器择时策略研究

第二部分呢,我们来讲解一个完整的My语言复杂策略的编写。我们将从策略的思路提出,逻辑的理顺,整体框架的构建,具体的逻辑编写,以及止盈止损等方面开始逐一的阐述,帮助大家从自己的交易理念出发,从0开始一个策略的编写。

前面的课程我们讲过,价格的走势基本分为两种:趋势行情和震荡行情,所以有相关的趋势策略和震荡策略。趋势策略有点像放长线钓大鱼,它关注的市场趋势的整体变化,从而获取长期的利润;而震荡策略更关注的从平稳的震荡行情中不断收获小额利润,从而积少成多。但是单纯的趋势策略可能在震荡的行情中频繁的开平仓造成利润的磨损;而单一的震荡策略也有可能在碰到一次强烈的趋势行情中损失掉所有的利润。那么有没有一种策略可以结合这两种行情的优势,并且避免不同行情的损失吗?恒温器择时策略考虑一下。恒温器择时交易策略,可以在趋势行情中采用趋势策略,在震荡行情中采用震荡策略。这有点像汽车换挡,而决定换挡时机的因素,则是以潮汐指数(CMI)为评判标准,对当前的行情进行一个较为合理的划分。我们来看下CMI的计算公式。CMI的原始公式是使用收盘价减去29日前的收盘价的绝对值,然后,除以30日内的最高价减去30日内的最低价。

mylang
CMI:=ABS(C-REF(C,29))/(HHV(H,30)-LLV(L,30))*100;

一般来说 CMI 的值在0~100区间,值越大,趋势越强。当 CMI 的值小于20时,策略认为市场处于震荡模式;当 CMI 的值大于等于20时,策略认为市场处于趋势模式。整个策略架构,可以简化的写成下面这样:如果 CMI < 20,执行震荡策略;如果 CMI ≥ 20,执行趋势策略。但是CMI里面的参数是属于比较经典的参数,在那些年代,市场趋势的转换还是比较平稳,但是在如今的年代市场的趋势转换的,比较快,所以我们可以将这里的CMI期间参数和CMI阈值参数设置成为策略参数的形式,在回测模式中进行调参,获取更好的结果,另外这个策略当中可能会有很多组参数,进行分组,我们可以这样添加,使用括号问号加上分组命名。

mylang
// 计算CMI指标用以区分震荡市与趋势市 CMI: ABS(C-REF(C,CMIPERIOD-1))/(HHV(H,CMIPERIOD)-LLV(L,CMIPERIOD))*100;

这就是策略的架构,剩下的就是把震荡策略的内容和趋势策略的内容,填充到这个框架里面。接下来我们来看震荡策略的设置。前面的课程我们使用了布林带均值回归的策略。今天我们来看另一种震荡策略设计。在震荡市场中,通常存在一种现象:如果今天价格上涨的话,那么明天的价格下跌的概率更大。而今天价格如果下跌的话,那么明天的价格上涨的概率更大,而这也正是震荡市场的特性。所以这里首先定义一个关键价格(最高价+最低价+收盘价的平均值)。如果当前价格大于关键价格,那么明天应该震荡看空。相反的,如果当前价格小于关键价格,那么明天应该震荡看多。于是震荡看多和震荡看空的阈值应该是不一致的,接下来我们进行设置。下跌和上涨的概率是不一致的,我们呢,直接做多或者做空是不合适的,但是我们可以调整做多和做空的阈值。当下跌概率更大,我们调小做空阈值,调大做多阈值;上涨概率更大,调大做空阈值,调小做多阈值。这样设置可以有更多的可能性进行对应方向的开仓,但是如果满足相反方向开仓的情况下,证明趋势的转换,我们也可以及时抓住。

这里阈值计算需要一个ATR指标。我们来计算一下。

mylang
TR:=MAX(MAX((HIGH-LOW),ABS(REF(CLOSE,1)-HIGH)),ABS(REF(CLOSE,1)-LOW)); ATRVALUE:=MA(TR,ATRPERIOD);

ATR是TR的移动均值,TR是取当前交易日的最高价和最低价,前一交易日的收盘价和最高价,和前一日收盘价和最低价三者的差值中的最大值作为TR值。然后取TR的移动平均就是ATR值。

接下来我们来看做多和做空阈值的计算。做多的阈值LEP,在C>KOD,震荡看空,做多的阈值设置大一点,使用开盘价加上0.75乘以ATRVALUE,否则震荡看多,做多的阈值设置的小一点,使用开盘价加上0.5乘以ATRVALUE。

做空的阈值SEP,在C>KOD,震荡看空,做空的阈值设置小一点,开盘价减去0.5乘以ATRVALUE,否则震荡看多,做空的阈值设置的大一点,开盘价减去0.75乘以ATRVALUE。

mylang
// 定义关键价格 KOD:=(H+L+C)/3; LEP:=IFELSE(C>KOD,O+ATR10*0.75,O+ATR10*0.5); //做多阈值 SEP:=IFELSE(C>KOD,O-ATR10*0.5,O-ATR10*0.75); //做空阈值

另外为了防止假突破,导致策略来回止损,因此加入了一个最高价与最低价3日均线滤网来避免这种情形。

mylang
// 定义最高价与最低价3日均线 AVG3HI:=MA(H,3); AVG3LO:=MA(L,3); LEP1:=MAX(LEP,AVG3LO); SEP1:=MIN(SEP,AVG3HI);

这里的逻辑设置可能比较绕一点,大家可以暂停一下,慢慢思考一下。阈值设置完成,接下来我们就来设置震荡策略的逻辑了。首先设置开仓,这里都需要前置条件CMI小于CMI阈值,表明处于震荡行情当中,然后当最新收盘价大于做多阈值,进行多头开仓BK;反之小于做空阈值,进行空头开仓SK。对于平仓的设置,我们可以采用移动止盈止损的设置,等下面趋势部分开仓完成,我们一起进行设置。

mylang
// 震荡策略逻辑 CMI<CMITHRESHOLD&&C>=LEP1,BK; CMI<CMITHRESHOLD&&C<=SEP1,SK;

接下来我们来看趋势部分的设置。这里的趋势部分为了节省大家的脑力,这里我们使用先前讲过的布林带策略。首先计算均线,然后是上下限。在满足CMI大于CMI阈值的情况下,如果最新收盘价大于布林带上限,证明趋势突破,我们进行多头开仓;否则小于下限,进行空头开仓。

mylang
// 计算均线 MAVALUE:=MA(C,MAPERIOD); // 计算布林带上下限 UPBAND:=MAVALUE+STD(C,STDPERIOD)*STDMUL; DNBAND:=MAVALUE-STD(C,STDPERIOD)*STDMUL; // 趋势策略逻辑 CMI>=CMITHRESHOLD && C>=UPBAND,BK; CMI>=CMITHRESHOLD&& C<=DNBAND,SK;

最后一部分我们进行课程前面一部分讲过的移动止盈止损的设置进行平仓的操作。这样呢,就是一个完整策略的编写过程,当然后续我们还可以进行很多工作,比如这里参数的调优,还有根据不同品种进行策略逻辑的优化。这些都是需要大家在实际的策略编写当中所要思考的事情。

mylang
// 止盈止损设置 C<BKPRICE-LOSSNUMBER||(C>BKPRICE && C<BKHIGH-PROFITNUMBER), SP; C>SKPRICE+LOSSNUMBER||(C<SKPRICE && C>SKLOW+PROFITNUMBER), BP; AUTOFILTER;

至此呢,My语言的课程已经全部讲述完毕,很感谢大家的倾听。大家后续可以在优宽平台进行更多的My语言策略的尝试,如果有遇到哪些问题,欢迎大家留言,我们将热心为大家提供更多的帮助,希望大家一起加油,共同进步。

评论
全部评论 (0)
暂无数据
暂无数据
  • 1
iPhone 下载
社区
回测系统
© 2015 - ∞ YouQuant 豫ICP备19046564号