简介麦语言函数手册是文华财经推出的程序化函数库参考文档面向使用文华平台进行量化策略开发的交易者与编程初学者帮助其快速查阅函数用法、理解模型编写逻辑。手册系统梳理了自编策略模型支持的各类函数涵盖历史数据引用如AVPRICE、SETTLE、CLOSE、HIGH、LOW、OPEN、OPI、引用函数REF、REFX、导入函数#IMPORT、价格函数MINPRICE与成交量函数VOL并延伸至日内高频数据引用如L2_BID1至L2_BID5、L2_ASK1至L2_ASK5等买卖盘价量函数每项均附用法说明与示例。资源包为1个doc文档大小约309KB结构紧凑、便于检索。目前已有3599人学习下载适合需要系统掌握麦语言函数体系、提升策略开发效率与代码质量的读者参考使用。1. 麦语言函数手册从零手搓一套可复现的指标脚本很多人第一次接触麦语言是在某个量化平台的公式编辑器里——想改一根均线参数结果被一堆REF、HHV、BARSLAST卡住翻遍平台自带的函数手册发现它只告诉你“这个函数返回周期内的最高值”却不告诉你当周期不足时它到底返回什么、能不能嵌套、在跨周期引用时会不会直接给你一个空值。麦语言函数手册真正的价值不是当字典查而是当施工图用它决定了你写的每一个指标、每一个条件单、每一个信号过滤逻辑能不能在实盘里稳定跑起来。这篇笔记面向两类人一类是刚拿到平台账号、想把自己的交易想法翻译成脚本的新手另一类是用过几个函数、但一遇到“信号闪烁”“回测漂亮实盘拉胯”就抓瞎的熟手。我会按“函数怎么分类 → 核心函数怎么用 → 参数怎么调 → 坑在哪 → 怎么验证”的顺序把手册里那些一笔带过的边界条件全部摊开讲。2. 麦语言函数体系拆解从数据引用到信号输出的四层结构麦语言的函数不是平铺的一张大表它内部有清晰的层次。你如果按“数据获取 → 数值计算 → 逻辑判断 → 信号输出”这四层去理解手册里那些散落的函数名就会自动归位。这一章先把体系讲透再落到具体函数的调用方式上。2.1 数据引用层OPEN、CLOSE、HIGH、LOW 与 REF 的周期语义数据引用层是所有指标的起点。麦语言里最基础的四个变量是OPEN、CLOSE、HIGH、LOW它们分别代表当前周期的开盘价、收盘价、最高价、最低价。这里有一个新手最容易翻车的点在盘中运行时CLOSE并不是“收盘价”而是“最新价”。只有K线走完它才等于真正的收盘价。这个差异直接导致同一个公式在盘中信号和盘后信号不一致。REF(X, N)是引用函数里最常用的一个意思是“引用 N 个周期前的 X 值”。比如REF(CLOSE, 1)就是上一根K线的收盘价。手册里通常只写“引用若干周期前的数据”但不会强调当 N 大于当前已有的K线数量时返回值是无效值通常表现为空或0而不是报错。这意味着你在上市初期的新品种上跑长周期均线前面几十根K线的计算结果全是无效的。# 模拟麦语言 REF 的周期引用逻辑Python 伪代码便于理解边界 def ref(series, n): series: 数据序列按时间从旧到新排列 n: 向前引用的周期数 返回与 series 等长的列表前 n 个位置为 None无效值 result [None] * len(series) for i in range(n, len(series)): result[i] series[i - n] return result # 示例对收盘价序列做 REF(CLOSE, 1) close [10.0, 10.2, 10.1, 10.5, 10.3] prev_close ref(close, 1) # 输出[None, 10.0, 10.2, 10.1, 10.5]上面这段伪代码说明了REF的边界行为前 N 个周期没有足够的历史数据返回无效值。在麦语言里这个无效值参与后续计算时可能导致整个条件判断失效。常见做法是配合ISNULL或VALID类函数做过滤或者在公式开头用BARSCOUNT(CLOSE) N做前置判断。参数设置上REF的第二个参数 N 必须是正整数常量不能是变量序列。如果你需要动态周期引用得用REFX或循环结构变通但那样会显著增加计算量。我一般会在公式里把 N 控制在 1 到 60 之间超过 60 的引用尽量改用MA或SUM这类聚合函数替代减少逐周期回溯的开销。2.2 数值计算层MA、EMA、SUM 与 STD 的选型差异数值计算层负责把原始价格序列转换成有意义的指标值。麦语言里最常被混用的四个函数是MA、EMA、SUM、STD。它们看起来都是“算一个数”但背后的数学定义和适用场景完全不同。MA(X, N)是简单移动平均把最近 N 个周期的 X 值加起来除以 N。它的特点是每个周期的权重相等对历史数据的变化反应迟钝。EMA(X, N)是指数移动平均近期数据权重更高反应更灵敏。手册里通常只给公式不告诉你在同样的 N 值下EMA的“等效窗口”大约是MA的 2 倍左右。也就是说EMA(CLOSE, 10)的平滑程度接近MA(CLOSE, 20)。如果你从MA切换到EMA而不调整参数信号频率会明显变化。SUM(X, N)是周期求和常用来计算成交量均线或累计涨幅。STD(X, N)是标准差用于布林带、波动率通道等指标。这里有一个参数陷阱STD的 N 如果设为 1标准差为 0布林带上下轨会重合导致信号完全失效。我一般把STD的 N 设为 20 或 26和MA的周期保持一致。# 对比 MA 与 EMA 在相同 N 下的响应差异 def ma(series, n): result [None] * len(series) for i in range(n - 1, len(series)): window series[i - n 1 : i 1] result[i] sum(window) / n return result def ema(series, n): result [None] * len(series) alpha 2 / (n 1) # 初始值用第一个有效数据填充 result[n - 1] sum(series[:n]) / n for i in range(n, len(series)): result[i] alpha * series[i] (1 - alpha) * result[i - 1] return result close [10 i * 0.1 for i in range(30)] ma10 ma(close, 10) ema10 ema(close, 10) # 对比最后几个值ema10 会比 ma10 更贴近最新价格选型建议趋势型指标如均线交叉优先用EMA因为它的滞后更小震荡型指标如布林带中轨优先用MA因为它的统计意义更直观。SUM适合成交量类累计值STD适合波动率类指标。不要在一个公式里混用MA和EMA做同一根均线的比较那样参数没有可比性。2.3 逻辑判断层CROSS、IF、BARSLAST 的组合用法逻辑判断层是把指标值转换成交易信号的关键。CROSS(A, B)表示 A 上穿 B返回布尔值。IF(COND, X, Y)是条件分支COND 为真时返回 X否则返回 Y。BARSLAST(COND)返回上一次 COND 为真到现在的周期数。这三个函数组合起来能表达绝大多数信号逻辑。CROSS有一个容易被忽略的细节它判断的是“当前周期 A B 且上一周期 A B”。如果 A 和 B 在上一周期相等当前周期 A 略大于 BCROSS也会触发。这在均线粘合后发散时会产生大量假信号。常见做法是加一个最小差值过滤比如CROSS(MA5, MA10) AND (MA5 - MA10) 0.01 * CLOSE。BARSLAST的返回值在条件从未满足时是无效值不是0。如果你用BARSLAST(COND) 5做过滤在 COND 从未满足的情况下这个判断可能直接失效。稳妥的写法是BARSLAST(COND) 5 AND BARSLAST(COND) 1000用一个上界把无效值排除掉。# 模拟 CROSS 与 BARSLAST 的组合信号 def cross(a, b): signals [False] * len(a) for i in range(1, len(a)): if a[i] b[i] and a[i-1] b[i-1]: signals[i] True return signals def barslast(cond): result [None] * len(cond) last_true None for i in range(len(cond)): if cond[i]: last_true i if last_true is not None: result[i] i - last_true return result # 示例金叉后 5 个周期内不再重复触发 ma5 [10, 10.1, 10.3, 10.5, 10.4, 10.2, 10.0] ma10 [10.2, 10.2, 10.2, 10.3, 10.3, 10.3, 10.3] golden cross(ma5, ma10) since_golden barslast(golden) # 过滤只在金叉当天或金叉后第 5 天之后才允许新信号 filtered [golden[i] and (since_golden[i] 0 or since_golden[i] 5) for i in range(len(golden))]参数说明CROSS的两个参数必须是序列不能是常量。IF的嵌套层数建议不超过 3 层否则可读性急剧下降。BARSLAST的参数是布尔序列返回值是周期数单位与K线周期一致。如果你在日线图上用BARSLAST返回值就是天数在分钟图上就是分钟数。2.4 信号输出层DRAWICON、PLOT 与条件单的对接方式信号输出层决定你的指标在图表上怎么显示以及能不能被条件单系统识别。DRAWICON(COND, PRICE, TYPE)在满足 COND 的K线位置画图标PLOT(X, NAME)画曲线。这两个函数主要影响可视化不直接影响交易。真正和交易对接的是条件单里的信号引用通常用SIGNAL或BUY/SELL类关键字。这里有一个实盘和回测差异的根源图表上的DRAWICON是“事后确认”的K线走完才画而条件单是“实时触发”的盘中价格触及就执行。如果你用CLOSE作为触发价盘中CLOSE是变动的可能导致同一根K线内反复触发。常见做法是用HIGH或LOW作为触发价或者加一个BARSTATUS判断当前K线是否已走完。# 模拟信号输出与条件单对接的过滤逻辑 def generate_signal(close, ma_fast, ma_slow, bar_status): bar_status: 0 表示K线未走完1 表示已走完 只在K线走完时输出信号避免盘中反复触发 signals [] for i in range(len(close)): if bar_status[i] 1 and ma_fast[i] ma_slow[i] and ma_fast[i-1] ma_slow[i-1]: signals.append({bar: i, action: BUY, price: close[i]}) else: signals.append(None) return signals参数说明DRAWICON的 TYPE 参数在不同平台取值不同常见的是 1 到 20 的整数对应不同图标。PLOT的 NAME 是字符串会显示在图表图例里。条件单对接时信号名称必须和平台后台配置的一致大小写敏感。我一般会在公式末尾加一行SIGNAL: COND, PRICE;作为统一输出口方便后续切换条件单类型。3. 用麦语言函数手册跑通第一个自定义指标从公式到图表这一章用一个完整的例子把前面讲的四层结构串起来。目标是写一个“均线趋势过滤 波动率突破”的指标能在图表上显示买卖点并且能导出信号用于回测。3.1 需求拆解均线趋势过滤 波动率突破的信号定义需求很具体当短期均线在长期均线上方且价格突破过去 20 个周期的最高价时产生买入信号当短期均线在长期均线下方且价格跌破过去 20 个周期的最低价时产生卖出信号。同时用 ATR 类波动率指标过滤掉波动过小的信号避免在横盘震荡里反复被扫。这个需求涉及四个函数MA算均线HHV算周期最高价LLV算周期最低价ATR算波动率。HHV(HIGH, N)返回 N 周期内最高价的最大值LLV(LOW, N)返回 N 周期内最低价的最小值。ATR在麦语言里通常用MA(MAX(MAX(HIGH-LOW, ABS(HIGH-REF(CLOSE,1))), ABS(LOW-REF(CLOSE,1))), N)来近似。3.2 公式编写变量命名、参数区与计算区的分离麦语言公式一般分三段参数区、变量区、计算区。参数区用INPUT声明可调参数变量区用VAR声明中间变量计算区写逻辑。下面是一个可运行的框架。# 麦语言公式框架伪代码展示结构 # 参数区 INPUT: FAST_N(5, 1, 60), SLOW_N(20, 1, 120), BREAK_N(20, 1, 60), ATR_N(14, 1, 60), ATR_MIN(0.005, 0.001, 0.05); # 变量区 VAR: MA_FAST, MA_SLOW, HH, LL, ATR_VAL, COND_BUY, COND_SELL; # 计算区 MA_FAST MA(CLOSE, FAST_N); MA_SLOW MA(CLOSE, SLOW_N); HH HHV(HIGH, BREAK_N); LL LLV(LOW, BREAK_N); ATR_VAL MA(MAX(MAX(HIGH - LOW, ABS(HIGH - REF(CLOSE, 1))), ABS(LOW - REF(CLOSE, 1))), ATR_N); # 信号条件 COND_BUY MA_FAST MA_SLOW AND CLOSE HH AND ATR_VAL / CLOSE ATR_MIN; COND_SELL MA_FAST MA_SLOW AND CLOSE LL AND ATR_VAL / CLOSE ATR_MIN; # 输出 DRAWICON(COND_BUY, LOW, 1); DRAWICON(COND_SELL, HIGH, 2); PLOT(MA_FAST, MA_FAST); PLOT(MA_SLOW, MA_SLOW);逻辑说明INPUT声明了五个参数括号里依次是默认值、最小值、最大值。VAR声明了中间变量避免重复计算。COND_BUY同时满足三个条件短期均线在长期均线上方、收盘价突破 20 周期最高价、ATR 占价格比例大于阈值。DRAWICON在买入信号位置画图标 1卖出信号画图标 2。参数说明FAST_N默认 5适合短线SLOW_N默认 20适合中短线。BREAK_N默认 20和SLOW_N一致减少参数数量。ATR_MIN默认 0.005即 0.5%过滤掉波动过小的信号。如果品种波动大可以调到 0.01如果波动小调到 0.003。3.3 参数调优FAST_N、SLOW_N、BREAK_N 的敏感度测试参数调优不是随便试几个数而是要有方法。我一般用“单参数扫描 固定其他参数”的方式观察信号数量和胜率的变化。下面是一个简单的扫描脚本框架。# 参数扫描框架Python 伪代码用于理解调优逻辑 def scan_fast_n(close, high, low, fast_range, slow_n20, break_n20): results [] for fast_n in fast_range: signals generate_signals(close, high, low, fast_n, slow_n, break_n) win_rate backtest(signals, close) results.append({fast_n: fast_n, signal_count: len(signals), win_rate: win_rate}) return results # 示例扫描 FAST_N 从 3 到 15 scan_results scan_fast_n(close, high, low, range(3, 16)) # 观察 signal_count 和 win_rate 的平衡点调优原则FAST_N越小信号越多但假信号也越多FAST_N越大信号越少但滞后越大。SLOW_N和BREAK_N一般保持 2 到 4 倍于FAST_N的关系。如果FAST_N调到 10 以上SLOW_N至少要 30否则均线交叉会非常频繁。BREAK_N不宜小于FAST_N否则突破条件太容易满足失去过滤意义。3.4 信号导出把指标条件转成可回测的信号序列图表上的图标不能直接回测需要把条件转成信号序列。麦语言里通常用SIGNAL关键字或者导出 CSV 后在外部回测。下面是一个导出信号序列的示例。# 导出信号序列伪代码 VAR: SIGNAL_TYPE; SIGNAL_TYPE IF(COND_BUY, 1, IF(COND_SELL, -1, 0)); # 在公式末尾输出 SIGNAL: SIGNAL_TYPE, CLOSE;逻辑说明SIGNAL_TYPE为 1 表示买入-1 表示卖出0 表示无信号。SIGNAL行把信号类型和触发价格一起输出平台回测引擎会按这个序列模拟成交。参数说明SIGNAL的第一个参数是信号类型第二个参数是触发价格。触发价格用CLOSE表示按收盘价成交用HIGH或LOW表示按最高价或最低价成交。回测时要注意滑点和手续费设置否则结果会偏乐观。4. 麦语言函数手册避坑指南五个让回测和实盘分道扬镳的细节这一章集中讲踩坑记录。每一条都是我在实际项目里遇到过的按“现象 → 原因 → 解决”写。4.1 坑一REF 引用未来数据导致回测虚高现象回测曲线非常漂亮年化收益高得离谱但实盘一跑就亏。原因公式里用了REF(CLOSE, -1)或类似写法引用了未来周期的数据。麦语言里REF的第二个参数如果是负数表示向后引用也就是引用未来数据。回测引擎在历史数据上会“偷看”未来价格导致信号提前触发。解决检查所有REF调用确保第二个参数为正整数。如果确实需要引用未来数据做其他计算用REFX并明确标注但不要用于交易信号。4.2 坑二HHV/LLV 在周期不足时返回无效值现象新品种上市初期指标值异常信号乱跳。原因HHV(HIGH, 20)在K线数量不足 20 根时返回的是无效值或 0导致后续比较逻辑出错。解决在公式开头加BARSCOUNT(CLOSE) 20的前置条件或者用IF(BARSCOUNT(CLOSE) 20, CLOSE, HHV(HIGH, 20))做兜底。常见做法是把HHV和LLV的周期参数设为变量根据BARSCOUNT动态调整。4.3 坑三CROSS 在均线粘合时频繁触发假信号现象均线走平时买卖信号密集出现手续费吃掉大部分利润。原因CROSS只判断上穿和下穿不判断差值大小。当两条均线数值接近时微小波动就会触发交叉。解决加最小差值过滤比如CROSS(MA5, MA10) AND ABS(MA5 - MA10) / CLOSE 0.002。或者改用MA5 MA10 AND REF(MA5, 1) REF(MA10, 1)并配合BARSLAST限制信号间隔。4.4 坑四盘中 CLOSE 变动导致条件单反复触发现象同一根K线内条件单被触发多次成交价格混乱。原因盘中CLOSE是最新价价格波动时CLOSE HH可能反复为真。解决在条件单里加BARSTATUS 1判断只在K线走完后触发。或者用HIGH作为触发价并设置“每根K线只触发一次”的平台选项。如果平台不支持就在公式里用BARSLAST(COND_BUY) 0做去重。4.5 坑五参数过度拟合导致样本外失效现象在历史数据上调出的“最优参数”换到另一段行情就失效。原因参数扫描时只看了总收益没有看信号分布和最大回撤。解决把数据分成训练集和验证集训练集调参验证集确认。参数数量控制在 3 个以内每个参数的取值范围不要太大。我一般会保留 2 到 3 组参数分别对应趋势行情和震荡行情实盘时根据市场状态切换。5. 进阶技巧用函数手册里的冷门函数做信号过滤与仓位管理这一章讲两个进阶用法。第一个是用FILTER函数做信号去重第二个是用TOPRANGE或BARSCOUNT做动态仓位管理。FILTER(COND, N)的作用是当 COND 为真时返回真并在接下来的 N 个周期内屏蔽后续的 COND 信号。这个函数在手册里通常只有一句话说明但实际用起来非常顺手。比如FILTER(CROSS(MA5, MA10), 5)表示金叉后 5 个周期内不再触发新的金叉信号。参数 N 一般设为信号平均间隔的一半左右。如果信号平均每 10 根K线出现一次N 设为 5 比较合适。# 用 FILTER 做信号去重 def filter_signal(cond, n): result [False] * len(cond) cooldown 0 for i in range(len(cond)): if cooldown 0: cooldown - 1 continue if cond[i]: result[i] True cooldown n return result # 示例金叉信号去重冷却期 5 个周期 golden cross(ma5, ma10) filtered_golden filter_signal(golden, 5)仓位管理方面BARSCOUNT(CLOSE)返回从第一根K线到当前的周期数。这个值可以用来做“上市初期减仓”的逻辑当BARSCOUNT(CLOSE) 60时仓位系数设为 0.5当BARSCOUNT(CLOSE) 60时仓位系数设为 1.0。这样在新品种波动剧烈时自动降低风险暴露。# 动态仓位系数 VAR: POS_RATIO; POS_RATIO IF(BARSCOUNT(CLOSE) 60, 0.5, 1.0); # 在信号输出时乘以仓位系数 SIGNAL: SIGNAL_TYPE * POS_RATIO, CLOSE;验证方法把加了过滤和仓位管理的信号序列和原始信号序列做对比回测。重点看三个指标信号数量减少比例、最大回撤变化、夏普比率变化。如果信号数量减少 30% 以上但夏普比率没有提升说明过滤条件太严可能把有效信号也滤掉了。我一般会保留过滤前后的两套信号实盘时先跑过滤后的观察一段时间再决定是否切换。最后说一个我自己的习惯每次写完一个指标先不急着上实盘而是把最近 3 年的数据分成 6 段每段半年逐段跑一遍。如果某一段的表现明显偏离其他段就回去检查那段时间的市场状态和参数适应性。这个习惯帮我省掉了不少后悔药。希望帮到你。本文还有配套的精品资源点击获取