简介:这份中文手册围绕文华财经麦语言程序化函数库编写,适合期货量化投资者、WH系列软件用户以及刚接触策略编写的开发者参考。麦语言采用积木式编程理念,将复杂算法封装为函数,配合金融统计库可支持较复杂的交易逻辑。包内为doc文档一份,共1个文件,压缩包约309KB,内容精炼便于查阅。目前已有3599人浏览学习。手册覆盖历史数据、跨周期与跨品种引用、盘口高频行情等常用函数,例如CLOSE/HIGH/LOW、REF/REFX、#IMPORT、MINPRICE、VOL,以及L2_BID1至L2_ASK5等一系列逐档买卖报价函数,并提供具体用法与示例。读者可借此快速掌握麦语言的基础语法与函数调用方式,提高策略编写与调试效率。
1. 麦语言函数手册到底在解决什么问题
很多人打开麦语言函数手册就蒙:函数几百个,每个都像英文单词缩写,但真到写策略的时候一个都想不起来。我见过不少做了几年手工交易的人,拿着手册照样写不出一个能稳定跑完回测的模型。问题不在识字,而在于没搞清这本手册不是一个语法字典,它描述的是这个语言在K线、分时和数据序列上全部可调用的能力。它回答的问题是“我想表达一个交易想法,该用哪个词”。如果你没有交易模型这东西,手册就是废纸;如果你正想把规则变成代码,这本手册就是你的对照表。读完这篇,你能从“翻手册”变成“查手册”,并且知道哪些坑是手册里不会写的。
2. 麦语言函数手册的检索逻辑:从命名到函数家族
2.1 前缀命名:看不懂函数时先看首字母
打开麦语言函数手册,第一感觉往往不是内容多,而是乱。其实它的编排有很强的规律:绝大多数函数的名字就是功能英文单词的缩写。MA是Moving Average,REF是Reference,HHV是Highest High Value,LLV是Lowest Low Value,CROSS就是交叉,COUNT就是计数。你不需要把几百个函数全背下来,先看首字母就能猜到它属于哪一类。比如你正在写均线策略,看到MA、EMA、SMA心里就有数了;你需要在历史K线之间挪位置,找带REF的函数;你要统计某个条件在最近N根里发生多少次,COUNT就在那等着。
我一般会先写一个小脚本把不熟悉的函数拉出来跑一遍,而不是只看文字解释:
MA10:=MA(CLOSE,10); // 最近10根收盘价的简单平均 HHV_MA10:=HHV(MA10,5); // 最近5根 MA10 的最高值 REF_HHV:=REF(HHV_MA10,1); // 再把上述最高值向前挪一根K线这段代码的逻辑是:先算出10周期均线,再取这条均线最近5根K线的最高值,最后整体向历史方向移动一根。HHV的第二个参数是窗口宽度,REF的第二个参数是位移量。对照手册你会发现,绝大多数函数都是“数据在前、周期或位移在后”的规律。记住这个习惯,你查手册时就不用来回翻参数表了。
命名还有一个隐藏好处:当你想实现“最近N天最高价突破前高”这种需求,直接想到HHV和REF的组合,根本不需要翻到“高级函数”里去碰运气。函数手册不是给你背的,是按规律检索的。如果某个函数的前缀你完全不认识,那大概率是特殊场景函数,比如画图、字符串处理、跨周期调用,先跳过不耽误主流程。
2.2 高频函数三张表:行情、运算、信号
我把麦语言函数手册里的常用内容压缩成三张表,覆盖新手写策略时九成以上的需求。这三张表分别是行情引用类、数值运算类、信号统计类。
| 类别 | 常用函数 | 参数格式 | 一句话用途 |
|---|---|---|---|
| 行情引用 | CLOSE / OPEN / HIGH / LOW / VOL | 无 | 取当前K线收盘、开盘、最高、最低、成交量 |
| 行情引用 | REF(X, N) | 数据X,位移N | 取N根K线前X的值 |
| 行情引用 | HHV(X, N) / LLV(X, N) | 数据X,窗口N | 取最近N根X的最高值/最低值 |
| 数值运算 | MA(X, N) | 数据X,周期N | 简单移动平均 |
| 数值运算 | EMA(X, N) | 数据X,周期N | 指数移动平均 |
| 数值运算 | SMA(X, N, M) | 数据X,周期N,权重M | 带平滑权重的均线 |
| 数值运算 | SUM(X, N) | 数据X,窗口N | 最近N根X合计 |
| 数值运算 | STD(X, N) | 数据X,窗口N | 标准差 |
| 信号统计 | CROSS(A, B) | 两条线A和B | A从下方穿越B成立 |
| 信号统计 | COUNT(条件, N) | 条件表达式,窗口N | 最近N根里条件成立次数 |
| 信号统计 | BARSLAST(条件) | 条件表达式 | 条件上次成立到今天隔了几根K线 |
| 信号统计 | VALUEWHEN(条件, X) | 条件,数据X | 条件最近一次成立时X的值 |
查表的顺序应该是:先判断我要做的是“取数”“算数”还是“判断信号”,再对应到类别。例如你想写“过去10天最高价突破上穿”,那第一优先级是HHV,第二是REF,第三是CROSS。如果某函数的参数是“条件”,那这个位置可以直接写比较式或逻辑组合,比如CLOSE>OPEN AND VOL>10000,不需要提前定义一个变量再传进去。
这类组合是麦语言函数手册里最容易理解的部分,但很多人倒在“手册里没有告诉你边界”。例如VOL在部分数据源里可能包含盘中实时值,和回测里的历史值口径不同;OPI(持仓量)类似。使用时要先确认你用的K线周期和复权方式,不要让数据源差异变成策略假象。
2.3 手册里查不到的执行约定:序列、常数和副作用
函数手册通常只给接口,不给执行过程,这是新手把它当黑匣子用的根本原因。麦语言的处理单位是“一整段K线序列”,绝大多数函数返回的不是单个数字,而是一条和K线对齐的序列。你在一个赋值句里写下MA(CLOSE,5),计算机会从第一根K线算到最后一根,每一根都得到一个均值。这个“逐根扫描”的机制,决定了绝大多数逻辑不能只看最后一根,而要看所有历史截面。
这里有个容易忽略的约定:用:=赋值不会画线,用:赋值会在主图上画线。很多新手在手册里找到“绘图函数”就结束阅读,结果漏掉了这个基础差异,导致临时计算变量把图搞得全是线。正确习惯是:中间计算一律用:=,只有想输出的结果才用:。
另一个约定是函数副作用。DRAWICON、DRAWTEXT这类函数会在图上画图标和文字,它们不影响信号和回测结果,但会让图面拥挤,也会在多次回测时拖慢运行。交易指令函数则有更明显的副作用:BK、SK不返回值,而是触发虚拟下单。若手册里某函数有“输出到主图/副图”“回测中生效”等标注,读手册时要特别留意,这些不是普通计算函数。
还有一类查不到的内容是执行顺序。连续赋值是从上到下依次计算的,但跨周期引用、循环语句和条件分支在不同版本里行为可能有差异。遇到同一段逻辑在不同窗口期结果不同,先不要怀疑函数写错,把赋值顺序调换一下观察差异,再用“模型测试报告”的日志位置去定位。这一条是经验,手册里不会写。
3. 用函数手册拼出第一张可运行指标:双均线与画图
3.1 从手册到K线图:双均线最小写法
我建议每个拿到麦语言函数手册的人,先不要写交易模型,先写一个能加载到行情图上的指标。因为指标是纯计算,没有委托逻辑,能立刻验证函数手册里的函数到底怎么用。最简双均线只要两行:
MA5:MA(CLOSE,5) COLORRED; // 输出5周期均线,红色 MA20:MA(CLOSE,20) COLORYELLOW; // 输出20周期均线,黄色注意这里用的是单个冒号:,表示把结果画到主图。CLOSE是整个K线序列,MA括号里第二个参数5是周期。如果你把其中一行改成MA5:=MA(CLOSE,5);,编译不会报错,但图上那条线会消失,因为赋值不画线。
跑通这个最小指标后,再往里面加中间变量:
MA5:=MA(CLOSE,5); // 计算5线但不画线 MA20:=MA(CLOSE,20); // 计算20线但不画线 DIFF:MA5-MA20,COLORRED; // 把差值画出来这段代码在双均线基础上增加了一个中间变量DIFF。用:=存中间值,用:输出最终结果。这样做的好处是你可以在编译环境里随时查看DIFF的数值和曲线,确认每个函数的返回值确实如手册所描述。
参数说明:MA的第一个参数“CLOSE”是行情序列,第二个“N”是周期,必须是正整数。你换成HIGH、LOW、VOL等都可以,因为它们同样是K线序列;但如果你传一个常数,比如MA(5,5),它会返回一个常数序列,这在少数函数组合里会导致后续统计函数结果异常。
3.2 参数怎么选:MA、EMA、SMA的分工
手册里均线函数有三个:MA、EMA、SMA。它们都带“周期”参数,但行为差别很大。MA是简单算术平均,每个数据权重相同;EMA是最新数据有更高权重的指数平均;SMA带第三个参数M,用来控制新数据对结果的修正力度。如果你只是想验证一套策略逻辑,用MA就够了;如果你想让信号反应更快,EMA更合适;如果你希望曲线在快和稳之间取个平衡,SMA值得实验。
下面这张对比代码可以直接放进编译环境:
MA5:=MA(CLOSE,5); // 简单平均 EMA5:=EMA(CLOSE,5); // 指数平均 SMA5:=SMA(CLOSE,5,2); // 平滑平均 A:MA5; B:EMA5; C:SMA5;三条线画出来会发现EMA5比MA5更贴近价格,SMA5的参数M决定其靠近MA5还是EMA5。这里的参数2是平滑权重,你改成1再改成4,曲线会明显变化。手册只会写“M为权重值”,不会告诉你哪一种适合你的品种。常见做法是打开行情图,把三条线叠在一起,用肉眼或者用“数值显示”面板对比你关心的转折点。
还有一组容易被忽略的参数在REF和HHV之间:REF(X,N)的N是向前位移,HHV(X,N)的N是窗口长度。两者的N方向完全不同。如果你写HHV(HIGH,5),结果是最近5根K线的最高值;如果你写REF(HIGH,5),结果是5根K线之前的最高价。它们经常一起出现,例如“五根K线前的5周期最高价”就是REF(HHV(HIGH,5),5)。这部分务必对着手册逐项核对,否则策略的入场点会整体偏移。
3.3 画图函数和提示函数:让每个函数“看得见”
我写指标一定会顺手加画图函数,因为它能把函数返回结果直接映射成视觉信号,比盯着数值高效得多。麦语言里最常用的是DRAWICON和DRAWTEXT,以及STICKLINE柱状线。
DIFF:=EMA(CLOSE,12)-EMA(CLOSE,26); // 快线 DEA:=EMA(DIFF,9); // 慢线 MACD:=2*(DIFF-DEA); // 柱值 STICKLINE(MACD>0,MACD,0,2,0),COLORRED; // 红柱 STICKLINE(MACD<0,MACD,0,2,0),COLORGREEN; // 绿柱 DRAWICON(CROSS(DIFF,DEA),DEA,1); // 金叉画图标 DRAWTEXT(CROSS(DEA,DIFF),DEA,'死叉'); // 死叉写文字这段代码是MACD柱状图的经典写法。STICKLINE第一个参数是“是否画柱”的条件,第二、三个参数是柱体上下边界;MACD大于0时从0到MACD画红柱,小于0时画绿柱。第4个参数是柱宽,第5个参数0表示实心,1表示空心。DRAWICON第一个参数是触发条件,第二个参数是图标定位在哪个数值位置,第三个参数是图标编号,编号对应的图形在手册的“绘图函数”章节有一张对照表。
DRAWTEXT的第三个参数是字符串,用单引号包裹。它不会影响计算,只是文字提示。我习惯把信号用DRAWTEXT标出来,因为它比图标更直白,能显示“金叉”“死叉”这样的字,调试时可以快速数一下一个区间里到底出现了几次信号。不要在一个模型里堆太多DRAWICON,否则图标重叠之后你会看出乱码一样的图形,排查起来更慢。
4. 把函数手册用进交易模型:信号、委托与频率控制
4.1 信号函数与指令函数:别把两个概念混着查
指标只是第一步,要用麦语言写真正的交易模型,必须分清“信号函数”和“指令函数”。信号函数负责判断条件,例如CROSS、COUNT、BARSLAST;指令函数负责发出委托动作,最常见的是BK、SK、BP、SP。BK代表买入开仓,SK代表卖出开仓,SP代表卖出平多仓,BP代表买入平空仓。手册通常会把这两组内容放在不同章节,但新手容易在“交易函数”里找条件,结果对着一个不返回值的指令函数不知道怎么传参数。
最小交易模型长这样:
DIFF:=EMA(CLOSE,12)-EMA(CLOSE,26); // 快线 DEA:=EMA(DIFF,9); // 慢线 CROSS(DIFF,DEA),BK; // 金叉买入开仓 CROSS(DEA,DIFF),SK; // 死叉卖出开仓这里的CROSS(DIFF,DEA),BK;是“当前K线金叉成立时发出买入开仓信号”,CROSS(DEA,DIFF),SK;是“死叉成立时发出卖出开仓信号”。SK在这里既可以是开空仓,也可以理解成反手信号。麦语言的模型逻辑是逐根K线扫描,信号成立的那根K线产生指令,并在后续K线按价格设置成交。
注意BK和SK作为指令函数,也可以被其他函数引用。例如BARSLAST(BK)返回上一次买入开仓信号到当前的K线根数,这在前面的章节里出现过。这一点很关键:指令函数在麦语言里会留下“历史信号”,信号统计函数可以拿它当普通条件用。很多人不理解为什么一个“动作函数”还能当条件,其实它就是“BK成立”这个布尔状态的别名。
回测时你还要关注委托价格设置。函数手册只负责“信号在哪个K线成立”,至于信号成交在开盘价、收盘价还是下根K线开盘价,是交易模型设置决定的。常见做法是把成交价设成“下一个K线开盘价”,避免用收盘价成交带来的未来函数嫌疑。血泪经验是:信号确认和成交时间错配,是回测收益看起来高但实盘完全对不上的头号原因。
4.2 止损止盈:用BARSLAST和VALUEWHEN做状态跟踪
止损止盈不能每次重新算,要记忆上一次开仓时的价格,最顺手的是VALUEWHEN和BARSLAST两个函数。VALUEWHEN(条件, X) 的用法是:条件最近一次成立时,取当时的X值。我常用它记录开仓价:
开仓价:=VALUEWHEN(BK,CLOSE); // 最近一次BK信号时的收盘价 止损价:=开仓价-20*MINDIFF; // 开仓价向下20个最小变动价位 止损:=CLOSE<止损价; // 最新收盘价跌破止损 止损,SP; // 发出平多仓信号这里MINDIFF是行情最近的最小变动价位,用开仓价减去20个最小变动单位作为固定止损。如果你做的是空头,方向反过来写:
开空价:=VALUEWHEN(SK,CLOSE); // 最近一次SK信号时的收盘价 止损价:=开空价+20*MINDIFF; // 开仓价向上20个最小变动价位 止损:=CLOSE>止损价; // 最新收盘价升破止损 止损,BP; // 发出平空仓信号参数说明:20是“回调多少个最小价位”,直接决定止损宽度,需要根据品种和周期调整。把20改成5会更敏感,改成60会更宽松。VALUEWHEN返回的是序列:从信号成立那根K线开始,这个值一直保持到下一次信号成立,所以你在后续任意一根K线上读它,拿到的都是“最近一次开仓价”,而不是当前价。
另一个组合是BARSLAST加REF。BARSLAST(条件) 返回“条件上一次成立距离现在多少根K线”,配合REF可以取到开仓那根K线的最高价或最低价:
开仓距离:=BARSLAST(BK); // 距上次BK信号隔了几根K线 最近高点:=REF(HIGH,开仓距离); // 取开仓那根K线的最高价注意,REF(HIGH,开仓距离)取的是开仓那根K线的最高价,而不是“最近N根最高价”。如果你想跟踪开仓后的最大浮盈,需要用HHV结合BARSLAST计算,这属于进阶写法,这里不展开。但记住一个原则:用BARSLAST定位事件发生的位置,再用REF取那个位置的历史数据。
止损触发条件我一般用收盘价而不是最低价。因为LOW是K线最低价,盘中瞬时打到你止损价又收回来,用最低价做条件会让回测里出现大量假止损。除非你本来就打算“只要盘中触碰就止损”,那应该考虑更低周期模型,而不是在日线或小时线上用LOW触发。
4.3 用COUNT和BARSLAST控制交易频率
交易模型里最烦人的问题是信号在短时间内重复发生,导致开仓次数失控。麦语言手册提供了两个天然适合做频率控制的函数:COUNT和BARSLAST。COUNT(条件,N) 统计最近N根K线里条件成立过几次;BARSLAST(条件) 告诉你条件最近一次成立距离现在有多远。
最简单的是“距离上次开仓不足10根K线不再开仓”:
金叉:=CROSS(DIFF,DEA); // 金叉条件 上次开仓:=BARSLAST(BK); // 距上次买入开仓的K线根数 允许:=上次开仓>=10; // 间隔够10根才允许开仓 开仓:=金叉 AND 允许; // 综合条件 开仓,BK; // 满足则买入开仓这里的10是“最小间隔周期数”。如果你交易的是15分钟K线,10根就是两个半小时;如果是日线,10根就是两周。参数没有统一标准,通常根据策略持仓周期设置。把10改成0,这个限制就取消。
如果你想限制“最近9根K线内最多只开一次仓”,可以用COUNT。注意这里有一个新手必踩的坑:COUNT会把当前K线的BK信号也统计进去。当前这根K线你正要发BK,COUNT(BK,9) 的结果已经包含了你这个信号,所以限制条件往往会把自己拦住。
正确的写法是先把当前K线信号去掉:
近9次:=COUNT(BK,9)-BK; // 去掉当前K线的BK信号 允许:=近9次<1; // 之前9根没有开仓信号才允许 开仓:=金叉 AND 允许; // 综合条件 开仓,BK; // 买入开仓减掉BK这一行是为了让当前K线的信号不参与历史统计。这是我在调试频率限制时踩过的坑:加上限制条件后模型反而一根信号都没有,排查到最后发现是COUNT把自己算进去了。手册里只会写COUNT统计“条件成立的次数”,不会提醒你当前K线处理。这类边界条件,建议每次写完都搭一个只有信号和标记的小模型,验证计数结果。
5. 麦语言函数手册常见问题排查:五个翻车现场
5.1 金叉写成大小比较,信号连续成立
现象:策略在回测里持仓时间特别长,只有第一次金叉产生开仓,之后所有该平仓的位置都没触发。翻看信号图,发现信号从某一根K线开始持续为真。
原因:有人把 CROSS(DIFF,DEA) 写成了 DIFF>DEA。CROSS只表示“由下穿到上”的这一瞬间,DIFF>DEA 则表示当前状态,只要DIFF还在DEA上方,它就是真的。交易模型判断的是“条件成立则执行”,于是指令信号会一直成立。
解决:凡是“金叉”“死叉”一律用CROSS函数。如果要用DIFF>DEA实现“上方持续运行”的逻辑,必须把它放在开仓之外的条件里,例如作为持仓过滤。检查顺序:先看是否用了CROSS,再看是否需要配合REF做位移。
5.2 COUNT把自己算进去,频控失效
现象:用COUNT(BK,N)<1做开仓频率限制,结果一个信号都没出来,或者永远开不了第二笔仓。
原因:当前K线满足BK时,COUNT(BK,N) 已经把当前这根K线的成立次数算进去了。你拿它判断“之前没有开仓”,实际它等于1,导致条件恒为假。
解决:写成COUNT(BK,N)-BK,先把当前K线信号剔除,再做比较。如果模型里用了中间变量,也可以先用昨天计数:=REF(COUNT(BK,N),1),但REF会额外引入K线位移,建议新手优先用减法写法。
5.3 用最低价触发止损,假止损成串
现象:回测报告里止损单特别多,但逐笔检查行情时发现很多次价格只是短暂触碰止损线就拉了回来。
原因:把CLOSE<止损价写成了LOW<止损价。最低价是K线极端值,盘中瞬时穿越不代表收盘确认,尤其在小时线和分钟线上,高低点经常刺穿后收回。
解决:默认用CLOSE判断止损。如果你确实想做盘中触碰止损,需要把模型周期降到触发逻辑能覆盖的级别,并用成交设置里的“限价单”配合,不要拿一个大周期K线里的LOW硬做盘中行为。
5.4 除零或空值污染整条线
现象:图上一段曲线从某根K线开始变成“无效值”,后续所有依赖它的函数输出消失,回测日志里出现告警。
原因:某个分母表达式计算结果为0或空值,例如用统计次数做分母,而前几根K线确实没有信号。麦语言对无效数的传播很“诚实”:一个函数返回无效数,使用它的上一级函数也跟着无效。
解决:给分母加保护:
分母:=COUNT(BK,20); // 统计次数 安全分母:=IF(分母=0,1,分母); // 分母为0时改成1 结果:=某统计值/安全分母; // 避免除零IF(条件, 条件为真时的值, 条件为假时的值) 在这里起到防除零作用。注意IF的三个参数会同时计算,所以如果第二个参数本身也会引发无效值,仍然要先把内部表达式保护起来。
5.5 REF位移和HHV窗口边界搞混
现象:想要“最近5根最高价”,写出来却在图上偏了几根;想引用上一根的最高价,结果引到了未来。
原因:HHV(HIGH,5) 取的是包括当前K线在内的最近5根最大HIGH;REF(HIGH,1) 取的是上一根K线的HIGH。两者方向含义完全不同。如果写成REF(HHV(HIGH,5),0),那就等价于HHV本身,没做任何位移。
解决:先明确你需要的边界。要引用“上一根K线往前数5根的最高价”,写REF(HHV(HIGH,5),1);要引用“上一根K线自身的最高价”,写REF(HIGH,1)。不要把窗口N和位移N当成同一个东西。调试时用DRAWTEXT把数值打印出来,对照手册的参数说明逐位确认。
以上五个翻车现场是我在跑麦语言策略时反复遇到的共性问题。你不需要背下所有函数参数,但最好把这几类边界条件当成默认检查项,每写一个函数就问一次:它返回序列还是常数?包含当前K线吗?参数里哪个是窗口、哪个是位移?
6. 拿函数手册当调试道具:信号验证和结果留存
6.1 用DRAWTEXT做一个信号指示灯
每次写完新模型,我都会先抽出核心条件,在图上用提示函数做一个“信号灯”。这样做的目的不是好看,而是快速判断信号数量、出现位置是否和手工盘感一致。示例:
DIFF:=EMA(CLOSE,12)-EMA(CLOSE,26); // 快线 DEA:=EMA(DIFF,9); // 慢线 金叉:=CROSS(DIFF,DEA); // 金叉条件 DRAWICON(金叉,LOW-10,1); // 金叉位置画图标 DRAWTEXT(金叉,LOW-10,'金'); // 金叉位置写文字金叉成立时,图标和文字会同时出现在K线下方。跑一段历史区间,数一数标记数量,再对照行情肉眼回看,比直接看资金曲线发现问题的速度快得多。
6.2 用VALUEWHEN留存每次信号的开仓价
信号标记确认后,我会再画一条“持仓收益率”曲线:
开仓价:=VALUEWHEN(金叉,CLOSE); // 最近一次金叉时的收盘价 持仓收益:=CLOSE/开仓价-1; // 按当前价计算浮动收益率 收益曲线:持仓收益,COLORRED; // 输出收益率曲线这里VALUEWHEN的两个参数分别是条件和数据,它会在金叉成立的那根K线记下当时的收盘价,后续一直沿用这个值,直到下一个金叉出现。算出的持仓收益是一条围绕0轴波动的曲线,如果策略逻辑稳定,它应该有来有回;如果它变成一根陡峭直线,通常意味着信号太少、单次盈亏过大,或者开仓价取值有问题。这个习惯帮我避免了不少“回测美好、实盘翻车”的尴尬。
我最早拿到麦语言函数手册,是从头开始背函数名,后来发现最该背的不是名字,而是每个函数返回的是序列还是常数、是条件还是数值。每次写新模型,先给信号画一个灯,再去做参数调整,最后才写交易细节。这个顺序已经成为我固定的调试习惯,希望帮到你。
本文还有配套的精品资源,点击获取