多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

指标公式源码从入门到实战:读懂、修改、自建自己的指标库

指标公式源码从入门到实战:读懂、修改、自建自己的指标库 平时在论坛上看到“指标公式源码下载”“最全指标公式源码”这类帖子我第一反应就是又一个朋友要踩坑了。指标公式这个东西真正的问题从来不是“资源不够全”而是“下载了一堆却没几个能用、敢用、看得懂”。我自己刚接触技术指标那会儿也是收集了好几个“几百KB的公式大全”结果导入后要么红红绿绿画满屏要么出现完全看不懂的交叉信号最后能稳定留在常用栏里的反而是自己一行行写出来的那几个。这篇想把指标公式源码这件事从原理到实操完整讲透。不搞玄学不做资源搬运核心解决三件事指标公式语言和C语言思路到底怎么对应常用指标源码应该怎么读懂和修改以及导入后各种报错、信号漂移、参数陷阱怎么排查。看完之后你大概率不会再惦记网上那些“最全源码包”因为你已经有能力整理出一套真正属于自己的指标库了。1. 先别急着找“最全”源码包指标公式源码其实就这回事1.1 指标公式在算什么所有技术指标本质都在干一件事把已经发生的价格数据通过一套确定的数学规则变成一条或多条曲线帮助你有条理地观察市场状态。K线图上每一根K线都有开、高、低、收、量五个基本数据行情软件的公式语言把这些数据当作内置的序列变量比如 CLOSE 代表收盘价序列、VOL 代表成交量序列公式写的每一行都是在这些序列上做运算。这里最关键的认识是主流行情软件的公式语言并不是C语言那样的通用编程语言而是一种面向序列的脚本语言。它把“遍历每一根K线做计算”这件事封装掉了你不需要写 for 循环只需要声明“我要算 EMA(CLOSE,12)”系统就会自动对每一根K线执行同样的递推计算。所以很多人问“指标公式C语言源码下载”方向其实偏了——你不需要找C语言版本的指标源码因为公式语言本身就是一套更简单的、专门干这行的脚本倒是如果你看得懂C语言写出来的计算逻辑反过来能帮你判断一个指标源码到底靠不靠谱。1.2 “最全公式包”为什么往往不好用网上下载的所谓“最全指标公式源码”打开一看通常有几百个公式文件名五花八门。这类包常见三个问题第一来源混杂不同作者对同一种指标给的定义不一样参数也不同你导入之后会发现好几个公式画出来的线差不多但又都有微妙区别。第二大量公式用到了未经说明的后续数据函数也就是常说的“未来函数”历史图上信号漂亮得惊人实盘却对不上。第三数百个公式里没有注释、没有分类说明一旦报错或信号异常你根本不知道从哪查起。所以我的建议非常直接把“最全”当成背景把注意力放在“能看懂其中十几二十个经典指标”上。真正值得下载和保存的是你能读懂每一行含义、知道它用什么数据、能解释它极限条件下表现的源码。剩下的迟早会被你从指标列表里删除。2. 把C语言思路翻译成指标公式语言靠这张对照表就够了2.1 两者编程思维的差异如果你有C语言或者其他通用变成语言的基础学指标公式语言会非常快但需要先完成一个思维转换。C语言要考虑变量声明、循环边界、函数返回、内存管理指标公式语言则把大量底层细节隐藏了你只需要描述“数据是什么、怎么变换、画什么”。C语言概念指标公式语言对应说明全局数组内置序列变量CLOSE、HIGH、LOW、VOL等系统已按K线顺序排好for循环不需要写序列函数自动对每根K线计算一遍函数调用同名/类似函数MA、EMA、REF、LLV、HHV、STD、ABS等if/else 条件IF(条件, 值1, 值2)返回两个值之一条件为真取前值临时变量中间变量:用 : 赋值的行不会画线只用于后续计算主函数返回值不带 : 的语句不带冒号等号的表达式会直接绘制输出void函数副作用DRAW系列绘图函数用于画图标、文字、线段不参与数值计算看这张表你就明白指标公式语言是把C语言里“最常用的循环数组操作”模板化了的领域语言。你不需要从零管理数据生命周期只需要把数学表达式按它的语法写清楚。2.2 拿MACD举例两种语言各写一遍MACD的核心计算是EMA指数移动平均。在C语言里如果要手写一个12周期EMA通常是这样#define N 12 float alpha 2.0f / (N 1); float ema[100]; ema[0] close[0]; for (int i 1; i 100; i) { ema[i] alpha * close[i] (1 - alpha) * ema[i - 1]; }而换成指标公式语言同样的逻辑只需要一行DIF: EMA(CLOSE, 12) - EMA(CLOSE, 26);这里EMA(CLOSE,12)内部干的事就是上面的C语言循环。系统对每根K线都算出一个EMA值形成一条完整的曲线。完整的MACD公式是这样的DIF: EMA(CLOSE, 12) - EMA(CLOSE, 26); DEA: EMA(DIF, 9); MACD: 2 * (DIF - DEA), COLORSTICK;第一行算快慢线的差值第二行把DIF再做一次9周期EMA得到信号线第三行把两者差值的两倍以红绿柱形式画出来乘以2是为了让柱子在视觉上更清楚其实不乘影响也不大。读源码时最要紧的就是分清哪些行在算数据、哪些行只是改变颜色和显示方式。2.3 参数和中间变量的基础语法指标公式语言里: 和 : 的区别特别重要。用 MA5: MA(CLOSE,5); 这种带冒号的写法意思是不光计算MA5这个序列还要把它画在K线图上。而如果写成 MA5: MA(CLOSE,5);则表示只计算、不画线后面你可以在别的公式行里引用它。作图时如果想叠加多条均线每条都用冒号写出如果只是想算一个中间值供后面判断用就用 : 隐藏掉。我见过不少新手把每个中间变量都写成画线语句结果屏幕上全是线根本没法看这一点在调试时要格外留意。参数用法也值得提一次。公式里常见的 N、M、P 这类参数可以在指标公式的“参数设置”区域里声明比如 N 默认值12最小值1最大值100步长1。设成参数的好处是你不用改源码就能在软件界面上拖动调整周期还能顺手做参数对比测试。不过参数越多后面过拟合的风险就越大这个在第5章会展开讲。3. 高频常用指标源码逐个拆解不背代码看懂逻辑3.1 均线家族MA、EMA的实现最简单也最常用的源码两条均线足矣MA5: MA(CLOSE, 5); MA10: MA(CLOSE, 10);是算术平均每个K线权重大小相同。EMA则是指数加权最近的数据权重更大反应更快。这也是为什么很多短线指标喜欢用EMA而不是MA因为在震荡行情里EMA能更快地贴近价格变化。公式里如果你想直接画EMA写法是EMA_FAST: EMA(CLOSE, 12); EMA_SLOW: EMA(CLOSE, 26);均线类指标的核心应用是看排列状态短期均线在长期均线上方且都有向上斜率通常代表强势状态反过来则偏弱。但源码本身不包含任何“信号”它只是忠实描述两条平均线的位置关系怎么做买卖判断依然是你自己的策略指标永远只是工具。3.2 摆动类KDJ、RSI、CCIKDJ是使用频率极高的摆动指标。经典源码长这样RSV: (CLOSE - LLV(LOW, 9)) / (HHV(HIGH, 9) - LLV(LOW, 9)) * 100; K: SMA(RSV, 3, 1); D: SMA(K, 3, 1); J: 3 * K - 2 * D;RSV的含义是“当前收盘价在过去9个周期的高低区间里处于什么位置”如果结果是100说明收盘价就在最高价位置结果是0就在最低价位置。这里LLV是过去N周期最低值HHV是过去N周期最高值。K和D是对RSV做两次平滑用来滤掉单根K线的抖动J线则是K和D的偏离度放大所以在极端行情里J会冲得很高或跌得很低很多人拿它判断超买超卖。RSI的源码思路和KDJ不太一样它比较的是涨跌幅度LC : REF(CLOSE, 1); RSI1: SMA(MAX(CLOSE - LC, 0), 14, 1) / SMA(ABS(CLOSE - LC), 14, 1) * 100;意思是过去14个周期里上涨部分的平均值占整体波动涨加上跌的比例。如果一直在涨RSI接近100如果一直跌接近0。注意它用了SMA而不是MA这是变种形态。网上有不少“RSI多头排列”的写法本质就是在RSI1、RSI2、RSI3三条曲线之间做位置判断但只要你读懂了底层公式自己组合也不难。CCI是另一个有意思的摆动指标它衡量价格偏离统计平均值的程度TYP : (HIGH LOW CLOSE) / 3; CCI: (TYP - MA(TYP, 14)) / (0.015 * AVEDEV(TYP, 14));分母用AVEDEV平均绝对偏差而不是标准差这是CCI和布林带用STD的关键区别。平均绝对偏差对极端值的敏感度比标准差要低所以CCI的超买超卖阈值习惯上用正负100、正负200这样的固定数来区分强弱。读这类源码的时候多看一眼分母选用的统计量你就能理解这个指标为什么在某些行情里表现比别的指标更平滑。3.3 通道与波动类BOLL、ATR布林带的源码几乎全网统一但也最容易被人误解MID: MA(CLOSE, 20); UPPER: MID 2 * STD(CLOSE, 20); LOWER: MID - 2 * STD(CLOSE, 20);它说的是以20周期均线为中心上下各扩展两个标准差形成一个动态通道。很多人把它理解成“上轨突破会涨”这是错误用法。通道宽窄反映的是波动率震荡越剧烈标准差越大轨道越宽市场越平静轨道越窄。真正有意思的信号是“轨道收窄后的放大”那意味着波动率在压缩后可能转向扩张但方向不定光靠布林带无法判断。所以布林带通常还要配合价格行为或量能一起看。ATR则是纯波动率指标不关心方向TR : MAX(MAX(HIGH - LOW, ABS(HIGH - REF(CLOSE,1))), ABS(LOW - REF(CLOSE,1))); ATR: MA(TR, 14);TR的含义是“真实波幅”它取三种波幅的最大值当日最高与最低的差、当日最高与昨收的差、当日最低与昨收的差。为什么要这么复杂因为如果今天跳空高开最高到最低的距离可能没反映出缺口所以要把昨收拉进来比较。ATR不给你买卖信号它的价值是用来设定止损幅度和仓位大小——波动率大的时候止损距离就该放宽不然很容易被正常波动扫掉。3.4 量能类OBV、VROBV试图把成交量与价格涨跌方向关联起来源码看起来像在写账本OBV: SUM(IF(CLOSE REF(CLOSE,1), VOL, IF(CLOSE REF(CLOSE,1), -VOL, 0)), 0);收盘价上涨时成交量记为正下跌记为负平盘记0然后累计求和形成一条能量曲线。它反映的是资金是在主动流入还是主动流出的一个粗略度量。源码里SUM(...,0)表示从第一根K线开始滚动累加0表示不限制周期数全部累加。VR成交量比率是另一种量能指标它把成交量分成上涨日、下跌日和平盘日三堆TH : SUM(IF(CLOSE REF(CLOSE,1), VOL, 0), 26); TL : SUM(IF(CLOSE REF(CLOSE,1), VOL, 0), 26); EQ : SUM(IF(CLOSE REF(CLOSE,1), VOL, 0), 26); VR: (TH EQ / 2) / (TL EQ / 2) * 100;它是上涨成交量与下跌成交量的比值再对平盘量折中处理可以反映一段时间内市场买卖力量是否失衡。源码逻辑很直白难的是解读——VR高到底意味着上涨动能强还是风险累积不同环境结论差异很大用它时最好结合价格位置、大盘环境一起看。4. 指标导入后的疑难杂症报错、不显示、信号漂移4.1 导入报错的四类典型原因自己写或者从网络下载的公式导入时报错是最常遇到的第一道坎。根据我接触过的案例几乎都能归成四类。一是全角半角符号混用。中文输入法状态下打成全角括号、全角分号公式语言的解析器认不出来。这类报错最隐蔽因为肉眼几乎看不出区别解决方法是把出错行剪切后切到英文输入法重新敲一遍符号再粘贴回去。二是函数名拼写错误。指标公式语言的大部分函数名对大小写不敏感但拼写必须准确比如 AVEDEV 容易手滑写成 AAVEDEVSTD容易写成STDEV。报错信息通常会告诉你“未定义函数”这时候先别急着怀疑软件去对照函数列表检查拼写。三是变量名与保留函数冲突。有人习惯给中间变量起名 MA、HHV、REF之类结果和系统函数重名了导致计算逻辑混乱或直接报错。给变量命名时尽量用带前缀的名字比如 MyMA、TempHigh 这种避开内置关键字。四是参数数量对不上。每个函数都有固定的参数个数比如 ABS(X) 只有一个参数写两个参数必报错。HHV(X,N)必须有NN不能省略也不能用小数。这里建议养成一个习惯每写一个新函数先查一眼函数说明确认参数类型和数量。4.2 信号不显示与画线异常公式能成功导入但图形上就是没信号这类问题也很常见。排查顺序通常是这样的先检查是不是用了 DRAWICON、DRAWTEXT 或 STICKLINE 这类绘图函数。绘图函数需要配合条件表达式如果条件永远不成立也就是返回值为0自然什么都不会画。这时候可以在源码里临时加一行输出调试值比如把条件表达式本身画出来看看它到底在什么数值范围里波动马上就能发现是阈值设太高还是数据源选错。再检查坐标范围。有些指标数值动辄几千有些却长期卡在0到1之间如果和主图价格坐标混在一起可能被压扁到几乎看不见。这时把指标放在独立的副图区域或者调整坐标上下限就好。还有一种容易被忽略的情况是在同一公式里写了两条不相关的向量一条的值域极大另一条的值域极小软件为了容纳大值域自动把坐标拉宽小数曲线在视觉上就成了一根贴地的横线。这不算逻辑错误但会严重影响观察解决办法是把两条曲线的数值统一做缩放或者干脆分成两个指标。4.3 未来函数和信号漂移别让历史图骗了你这是我认为所有指标使用中最重要的一个坑。所谓未来函数简单说就是“在计算当前K线信号时用到了当前K线结束之后才会最终确定的数据”。最常见的非故意未来用法出现在最高价、最低价上。比如 KDJ 里的 RSV 用了 HHV(HIGH,9)如果当前K线还没收盘黄色线还在变化最高价就地会被不断刷新RSV数值也会来回跳动。你在复盘历史图时看到的是每根K线都取到了最终确定值所以信号看起来非常准确但实盘里你在盘中看到的信号和复盘时看到的信号很可能不是同一个。这就是信号闪烁。更严重的未来函数是某些函数或函数组合真的会引用后续K线数据比如 PEAK、TROUGH、ZIG 这一类波浪类函数在历史图上是完美的实盘却永远无法复现。我的态度很明确如果你要做的是可复现信号凡是用到这类函数的公式直接标记“仅作历史观察”绝对不要拿来做预警或选股条件。排查未来函数有个简单办法在源码里搜索 HHV、LLV、PEAK、TROUGH、ZIG、BACKSET 这些高频名字然后逐个检查它引用的数据源是不是已经确定的。如果没法判断就用一个笨办法——把最新一根K线手动改成极端值看指标整条曲线会不会整段平移如果会说明有函数在等后续数据确认。5. 从下载到自建一套可以长期维护的指标源码库5.1 目录、命名和注释源码也要工程化网上源码包最大的问题不是代码不好而是几乎没有任何工程规范。真正想长期用指标建议从第一天开始就按工程化的方式管理自己的指标目录。我的习惯是把指标按用途分成几类趋势类、摆动类、量能类、波动类、综合策略类。每个指标的文件名用“类别_指标名_关键参数”这样的格式比如“Momentum_KDJ_Custom_9_3_3”。这样看文件名就知道是什么、在哪里、参数是多少。指标源码内部每行都要写清注释尤其要标记“数据来源是否确定”凡是用了可能闪烁的函数的行必须醒目标注一个 WARN 前缀方便以后排查。这样管理有个直接好处几个月后回头看一个公式不用靠回忆猜它当年想干什么。很多人的指标库之所以越来越废就是因为代码里没有一行注释最后连作者自己都看不懂了。5.2 参数测试先想清楚逻辑再谈优化参数是写指标绕不开的话题。KDJ的9、3、3MACD的12、26、9这些都是经验默认值不等于说在你的标的上它们就是最优的。我的参数测试流程是这样的先固定逻辑把所有参数先放到一个巨大的范围里跑一遍观察信号分布是不是合理。比如你在测试一个均线交叉策略参数从5到200每隔5取一个看哪个区间信号密度还能接受。选定区间后再做小步长的精细调节重点观察信号是否过于密集或极度稀疏以及关键转折点前后信号是否稳定。这里最需要提防的是过拟合。过度优化指标参数让它完美适配历史的一段行情得到的往往是“只在统计上好看、实盘里一塌糊涂”的结果。我的避坑经验是如果一组参数在历史行情里好到让你不敢相信那大概率是过拟合了反而应该选择在多个不同市场环境下都表现平庸但一致的参数因为平庸说明它没有紧盯某一轮特定行情。参数和逻辑之间的关系是参数服从逻辑。当你发现某个参数从8调到9策略结果天翻地覆问题多半不是参数而是底层逻辑本身太脆弱。先用固定参数把逻辑跑通再去碰参数这个顺序别搞反。5.3 把指标用起来预警、选股与组合信号源码写好了、参数测完了指标真正有价值的场景是把它嵌进预警或选股流程。很多公式是画线型指标只能看无法直接触发提醒这时候需要把输出转换成条件表达式。比如你想在 KDJ 的 J 值小于0且拐头向上时收到提醒可以在公式最后写BUY_SIGNAL: J 0 AND REF(J, 1) REF(J, 0) AND J REF(J, 1);这种条件输出可以供预警系统直接使用。这里 REF(J,0) 就是当前J值REF(J,1) 是前一根K线的J值你的逻辑说清楚后写成公式不复杂。我更建议的组合方式是不依赖单一指标而是把不同维度的指标信号合流。比如趋势方向看均线排列波动率看ATR超买超卖看KDJ三者同时满足条件才触发提醒。组合信号可以有效过滤掉大量由单一指标产生的噪声信号代价是会过滤掉一部分机会但从实操体验看长期保持记录和复盘价值更高。我个人保存的指标数量从来不超过10个每增加一个新指标必须能说清楚它和已有指标在逻辑上的区别说不出来就不保留。最后再说一个我这些年反复踩出来的体会技术指标源码本质上是一套用数学语言描述市场状态的工具它不等于收益保证更不是所谓“擒涨停神器”。指望下载一个公式就开始言行一致地赚钱方向从一开始就错了。真正能沉淀下来的是你理解算法原理、动手修改参数、在无数次回测与实盘对比中打磨出来的那一小撮可信信号。把源码当阅读理解材料而不是当万能钥匙你会在指标这条路上走得比绝大部分人都远。
返回列表