一条公式挂在副图上,一年只跳出两次,第一反应是把阈值调松。先别动阈值。做通达信公式信号放大之前,要把「信号少」拆开看:它不是一个问题,是三种不同的少凑在一起。条件本身定得太严,是第一种;写法只在 K 线穿越的那一根上成立,是第二种;取数窗口不够长,前面一段成立被截掉,是第三种。三类对应的改法不一样,混在一起动,改完连自己都说不清数量为什么变了。
下面按原因的拆解、三种放大手段、放大后的核对顺序来写。函数名与参数取值以本机公式编辑器里的函数列表为准,公式挂上副图之后,输出为真的根数以公式管理器里「测试公式」的结果为准。
一、信号少,先分清是哪一种少
动手之前先把两个数记下来。公式管理器里点「测试公式」,输出区给出每一根 K 线的取值,成立为真的根数可以数出来;选股器里跑一遍,结果列表给出的是被选中的标的条数。这两个数一个是「成立的根数」,一个是「命中的标的数」,含义不同。把它们抄在一边,作为改之前的基线。
第一种,条件太严。条件写成 A 与 B 同时成立,而 A 的成立区间与 B 的成立区间在时间上错开,交集就窄。这类少,把条件从「并且」换成「或者」,成立根数立刻上去。
第二种,事件式写法只在一根上成立。用 CROSS 写的穿越,只在从「不成立」变成「成立」的那一根上输出一次,之后状态保持为真,也不再输出。这类少不是条件严,是写法把一个连续的区间压成了一个点。
第三种,数据窗口不足。条件里带 REF(C, 20) 或者 BARSLAST,需要往前取够根数,样本区间从中间截断,或者停牌造成缺根,前面一段就算不出结果,落在窗口外的那部分被整段丢掉。
三种少各自对应一种改法。顺序是先认原因,再动手。认错原因,用调阈值去修窗口不足,数量上去了,可复现性也一起没了。
二、手段一:放宽阈值,去掉过滤
写通达信公式信号放大,顺手的做法是把阈值调松、把过滤条件删掉。阈值写成参数,改一处就够,其余部分不用跟着动。
{ 阈值参数化:只改一行 }
N := 20; { 窗口长度 }
K := 0.02; { 阈值,比值口径 }
MA1 := MA(C, N);
DIF := C / MA1 - 1;
SIG : DIF > K; { 阈值调小,SIG 成立的根数变多 }
{ 参数写在开头,改 K 不动其余 }
把 K 从 0.02 改成 0.01,SIG 成立的根数换一个数。删过滤条件同理:原本写着「成交额达到某个量,并且价差比大于某个比值」,把成交额那一支整段去掉,成立的根数也会上去,多出来的根落在哪一段,输出里看得见。
代价在两处。一是阈值本身是设定值,不是从样本里算出来的统计结论,调松之后成立的根里混进来别的东西,数量上去,可比性下来。二是可复现性:阈值是参数,参数不写进记录,两次统计用的数不同,数量就对不上。改之前把参数与样本区间抄在一边,改完先比数量增减,再看增减落在哪些根上。
三、手段二:从事件式改成状态式
事件式问的是「这一根有没有发生变化」,状态式问的是「这一根是否处于成立状态」。两支写法给出的输出形状不同。
{ 事件式:只在穿越那一根成立 }
AA := MA(C, 5);
BB := MA(C, 20);
EV : CROSS(AA, BB); { 只在由下穿上的那一根输出 1 }
{ 状态式:连续区间里每根都成立 }
AA := MA(C, 5);
BB := MA(C, 20);
ST : AA > BB; { 区间内每一根都输出 1 }
把 EV 换成 ST,同一段行情从「一个点」变成「一条线」。数量上去了,可数出来的东西换了:一段连续成立的区间,在状态式下被记成多根信号。同一段行情里的根数越长,状态式给出的数量比事件式多出越多。
统计的时候要把相邻的重复信号合起来算一次。做法是取到上一次成立的间隔,间隔小于某个根数的就并入同一段。
{ 合并相邻重复:间隔小于阈值并入同一段 }
T := 10; { 归并阈值,单位是根数 }
AA := MA(C, 5);
BB := MA(C, 20);
ST : AA > BB;
NEW : ST AND (BARSLAST(REF(ST, 1)) >= T); { 只标出每一段的起点 }
不合并直接数,同一段行情被记成多根,两段挨得很近的区间还会被算成两段。合并之后数出来的段数,才是「信号发生了几次」这个问题的答案。事件式与状态式给出的段数应当对得上,对不上,多半是归并阈值取得不一样,或者状态判定写的不是同一个条件。
代价就在这里:状态式让数量上去,但数量的含义从「发生次数」换成了「成立根数」。两个数都要留,各自标注清楚是什么,不能混着比。把根数当段数报出去,一段行情就成了好几段。
四、手段三:多周期或多条件取「或」
做通达信公式信号放大,还有一种做法是把多个条件用 OR 串起来,或者把多个周期各算一支再取或。条件数从一支加到两支,成立根数不是简单相加。
{ 多条件取或 }
C1 : CROSS(MA(C, 5), MA(C, 20));
C2 : CROSS(MA(C, 10), MA(C, 60));
MIX : C1 OR C2; { 任一成立即输出 }
两支条件在同一天同时成立,那一根只算一次;错开成立,各自记一次。同一条行情先满足 C1,隔几根又满足 C2,在「或」的口径下被记成两根。条件越多,同一段行情被拆开的可能越多。
多周期取或更明显。日线上算作一段的成立区间,在 60 分钟线上会拆成若干根;把两个周期的输出放进同一张表直接相加,同一条行情被重复计入。周期越短,拆出来的根越多。
处理办法与上一节一致:先按时间归并,再按条件去重。记录里写清楚每一根是哪一支条件、哪一个周期产生的,同一时间点上有几支条件同时成立时只保留一条。归并规则要和上一节的段数口径写成同一套,两处规则不同,段数还是对不上。
代价是条件数上去之后,同一段行情被重复计入的次数跟着上去,数量增长的幅度与「多加了几个条件」不成比例。只看总计,不看原始输出,会把这个重复当成真实的新增。
五、放大之后怎么核对
核对分三步走,顺序不能换。
第一步,固定样本区间。起止日期写死,两次统计用同一段。区间换了,数量不可比,这一处变化出在样本那一侧,与公式无关。
第二步,合并相邻重复信号之后再计数。用上一节的归并写法,把连续成立的区间压成一段,把「或」串起来的重复时间点去重,再去数段数。这一步做完,数量才是可比的,也才能和改之前的基线放在一起看。
第三步,把参数与合并规则写进记录表。
| 字段 | 取值示例 | 为什么要留这一列 |
|---|---|---|
| 公式名称 | 自编公式的命名 | 对齐改的是哪一支 |
| 样本区间 | 起止日期 | 区间不同则数量不可比 |
| K 线周期 | 日线 / 60 分钟线 | 周期决定同一段被拆成几根 |
| 阈值参数 | 比值口径的取值 | 参数是设定值,必须留档 |
| 写法 | 事件式 / 状态式 | 决定数的是根还是段 |
| 归并阈值 | 根数 | 合并规则不同则段数不同 |
| 条件组合 | 单条件 / 取或 | 标出重复计入来自哪一支 |
| 成立根数 | 输出为真的根数 | 状态式口径下的原始计数 |
| 归并后段数 | 合并重复后的段数 | 与根数配对才有意义 |
表里容易被省掉的是「写法」和「归并阈值」这两列。省掉写法,两次统计分不清数的是根数还是段数;省掉归并阈值,段数对不上时,无从判断差在规则还是差在参数。这两列补上,同一支公式的两份输出才有对齐的口径。
公式本身在「公式管理器」里维护,入口在功能菜单的公式系统下面;自编公式与备份落在安装目录的 T0002 下,备份目录是 gs_bak,记录表在同层另建一个文件夹存放,恢复公式备份时不会把它一起覆盖。
把阈值调松、把事件式改成状态式、把条件用「或」串起来,通达信公式信号放大动的都是信号的数量与计数口径,判定规则一个字没动。段数与根数对不上、两次统计不可比的时候,先问一句:这一次数的是「发生了几次」,还是「有几根成立」?这两者的差,就是放大手段本身留在记录里的痕迹。
站内还有 指标回测与风险验证 的条目,通达信公式编写教程 讲条件与函数的写法,信号拆解 讲把一支信号拆成几段,可对照查看。
本文只作技术研究口径,不涉及也不构成对任何标的的判断。
