文华8 编译报错「未定义的变量」:八种成因逐个排查
这篇讲什么
文华8麦语言编译提示「未定义的变量」的八个真实成因:拼写不一致、引用写在定义之前、撞系统保留字、参数未在参数表声明、变量名含非法字符、注释吞掉定义、跨周期引用写法错,每种附错误写法与修正,并给出三步二分定位法。
先说结论:这条报错只有一类原因
「未定义的变量」的意思是:你在某一行引用了一个名字,但编译器按**从上到下**的顺序执行到这里时,这个名字还不存在。所以它一定对应两件事之一——压根没定义,或者定义了但编译器看不见。
前者是拼写和顺序问题,后者是命名冲突和语法遮挡问题。下面八种成因按「写作时最容易犯」到「最隐蔽」排列,按顺序对照基本能一次命中。
成因一:变量名拼写不一致
最典型也最好查。中途改过变量名、或者从别处复制粘贴一段代码时,引用处忘了跟着改:
MA20:MA(C,20);
MA60:MA(C,60);
// 这里引用的 MA30 从未定义过
CROSS(MA20,MA30),BK;
AUTOFILTER;把 MA30 改成 MA60 即可。变量名必须前后完全一致,包括下划线和数字后缀。建议养成习惯:变量名统一用「含义+周期」的固定格式(MA20、HH20、ATR26),改一处就不会漏。
成因二:引用写在定义之前
麦语言按行顺序解释,不存在「先引用后定义」的提前声明机制。把赋值行挪到引用行下面,立刻报错:
// 错误:CROSS 在 MA5 定义之前就用了
CROSS(MA5,MA20),BK;
MA5:MA(C,5);
MA20:MA(C,20);
AUTOFILTER;// 正确:所有中间变量先算完,最后统一写信号
MA5:MA(C,5);
MA20:MA(C,20);
CROSS(MA5,MA20),BK;
AUTOFILTER;写策略时把代码分成三段就不会出这个问题:第一段算指标、第二段定条件、第三段发指令。信号永远写在最后,中间变量永远在最前。
成因三:变量名撞了系统保留字
把 C、O、H、L、V、TIME、DATE、OPENINT 这类行情字段名当成自己的变量名,赋值会被系统忽略,后面的引用自然找不到你「定义」的那个值:
// 错误:V 是成交量字段,不能当变量名
V:=MA(C,5);
CROSS(C,V),BK;
AUTOFILTER;// 正确:换个名字
MA5:=MA(C,5);
CROSS(C,MA5),BK;
AUTOFILTER;口诀:单字母名一律不用,行情字段(O/H/L/C/V/AMOUNT/OPENINT/SETTLE/TIME/DATE)一律不用,交易指令名(BK/SP/SK/BP/BPK/SPK)一律不用。变量名至少两个字符,最好带语义。
成因四:参数没在参数表里声明
策略里想把周期做成可调的参数,就必须在模型的参数表里先设好名字和默认值。直接在代码里敲一个 N 当参数用,编译器不知道 N 是什么:
// 错误:N 没有在参数表中定义
MA_N:MA(C,N);
CROSS(C,MA_N),BK;
AUTOFILTER;解决办法是在模型编辑界面的参数表里加一行:名称 N、默认值 20、最小值 1、最大值 200。参数表设好之后,代码里的 N 就是一个合法名字,还能在加载模型时随时调。
这也是新手最容易混淆的一点:参数和变量是两套东西。参数走参数表,变量靠赋值得到,两者都不能「凭空出现」。
成因五:变量名含非法字符
合法变量名只能由字母、数字、下划线组成,并且不能以数字开头。以下几种都非法:
- 含空格:MA 5;
- 含中文:均线5;
- 含全角字母:MA5(输入法没切回半角,肉眼几乎看不出);
- 含连字符:MA-5(会被当成「MA 减 5」);
- 以数字开头:5MA。
全角字符是最阴的一种——字母看着一样,编译器认为是另一个字符,报错行还指不到它。如果代码是从网页、聊天框、文档里复制过来的,先整段丢进记事本再复制回来,能滤掉大部分不可见字符。
成因六:注释把变量定义一起吞掉了
调试时把一段代码注释掉,结果把里面的变量定义也注释了,后面的引用就悬空了:
// 调试时把这一段整体注释了,MA20 的定义也没了
// MA20:MA(C,20);
// TR:=MAX(MAX(H-L,ABS(REF(C,1)-H)),ABS(REF(C,1)-L));
CROSS(C,MA20),BK; // ← 报未定义的变量:MA20
AUTOFILTER;这类报错的迷惑性在于「我明明写过」。排查时不要只看报错行,把报错行上面 20 行整体扫一遍,确认变量定义那一行还在生效(没被注释前缀挡住)。
成因七:跨周期、跨品种引用的写法错
引用别的周期或别的模型的输出时,名字不是简单的变量名,必须带正确的引用前缀。前缀写错、周期写错、被引用模型没加载,都会表现为「未定义的变量」:
- 引用的模型没有先加载到同一张图表上;
- 周期参数写成了不存在的值(如 7 分钟这种非标准周期);
- 被引用模型里的变量名拼错,或该变量在你的模型里被重名覆盖。
排查顺序:先在图表上单独加载一次被引用的模型,确认它能正常出图,再回来检查引用写法。跨周期引用本质上是「借别人的计算结果」,前提是那个人真的在跑。
成因八:把「输出」和「赋值」搞混,引用到了另一层
麦语言里 : 是输出(画线到图表)、:= 是赋值(只在内部计算)。两者都能被后续引用,但混用时会出现看不懂的报错——比如在一条指令行后面接了赋值,或者把赋值写进了条件判断里:
// 错误:指令行不是变量,不能这样接
BK:=CROSS(MA5,MA20);
AUTOFILTER;// 正确:条件先算成变量,再用逗号接指令
COND:=CROSS(MA5,MA20);
COND,BK;
AUTOFILTER;这一条的详细规则见《麦语言 变量赋值 := 与 : 的区别》,写策略前花三分钟看一遍能省掉一半报错。
三步定位法:从报错行找到真凶
- 看行号但别信行号。报错行往往只是「最后一个受害者」,真凶在它前面。从报错行往上找最近的未定义名字,先在全文搜一遍这个名字,看它到底有没有被定义过。
- 二分注释。把报错行之后的代码全部注释掉,重新编译:还报错说明问题在报错行之前,不报错说明问题在之后。每次砍一半,三五轮就能锁定到具体几行。
- 单行验证。把可疑的赋值行单独留下、其余全注释,编译一次。能过就一行行往后放,第一个失败的位置就是真凶。
这三步加起来一般两分钟内能定位。不要靠盯着代码看——「未定义的变量」这种报错,肉眼扫十遍不如注释两行。
一个完整对照示例
下面这段代码把上面四个高频成因都踩了一遍,可以先自己找找错在哪:
// 有四处错误
V:MA(C,5); // ① 撞保留字
CROSS(C,MA20),BK; // ② MA20 还没定义
MA20:MA(C,N); // ③ N 未在参数表声明
ATR:=MA(TR,26); // ④ TR 从未定义
AUTOFILTER;// 修正后(N=20 已在参数表声明)
MA5:=MA(C,5);
MA20:=MA(C,N);
TR:=MAX(MAX(H-L,ABS(REF(C,1)-H)),ABS(REF(C,1)-L));
ATR:=MA(TR,26);
CROSS(MA5,MA20) && C>MA20,BK;
CROSSDOWN(MA5,MA20),SP;
AUTOFILTER;修正后的写法遵循了三个原则:中间计算一律用 :=(不往图上画多余线条)、所有变量定义在信号之前、变量名避开保留字并带上语义。这三条能挡掉大多数编译报错。
常见问题
报错行明明有定义,为什么还说未定义?
三个常见原因:定义那一行被注释掉了;定义用了非法字符导致实际名字和你看到的不是同一个;或者定义在报错行之后(顺序问题)。把定义行单独留下来编译一次就能确认。
变量名区分大小写吗?MA5 和 ma5 算同一个吗?
不要依赖大小写规则写代码。统一用大写字母加数字的命名风格(MA5、HH20、ATR26),既避免歧义,也让代码更好读。混用大小写是排查噩梦。
从网上复制的策略总是报未定义,是不是代码有问题?
多半是复制过程带进了全角字符或不可见空格。把代码先粘到系统记事本(不要用 Word 或网页编辑器),再复制回来,然后重新手敲变量名,能解决八成问题。
黑公网安备23010302002054号