简介:这份资料是甘氏矩阵图价格推算的系统性汇编,面向股票、外汇、期货等领域的技术分析学习者与实战交易者,适合从入门到进阶的读者理解这一工具的原理与用法。资源共1个文件,为pdf格式,压缩包约4.01MB,方便在电脑或移动设备上随时翻阅。内容围绕甘氏理论展开,讲解如何把市场变化抽象为四方形数字矩阵,通过基数1出发的螺旋排列,以及角线、十字线所构成的关键数字,研判支撑压力区与多空动能区,并据此推算商品近中远期的价位区间。同时它也解释了矩阵图为何能弥补传统曲线与指标的盲点,帮助读者减少情绪与市场噪音对判断的干扰。目前已有340人学习,适合想以更简单直观方式把握市场节奏、寻找价格推算依据的读者参考。
1. 甘氏矩阵图价格推算在算什么:从一张螺旋数表到候选价位
假设手里只有一根日线:某标的从 24.60 起步,涨到 41.30 后横了六周,均线粘合,斐波那契回撤也画过了,下一个目标位怎么给?甘氏矩阵图给的是另一条路子——它把价格当成一个可编号的对象,塞进一张从中心 1 开始、逆时针向外的螺旋方阵里,先看价格落在第几环、第几度,再沿 45° 的整数倍往内外推,得到一串候选价位。
它不判断方向,也不承诺时间,只负责把「价格可能停在哪里」变成一份可枚举、可回测的清单。适合做波段和趋势的人,也适合想把江恩那套手绘功夫搬进代码的量化研究者。市面上流传的甘氏矩阵图价格推算资料,大多是汇编式的结论数表,页码翻烂也找不到反推公式,下面把公式、代码和参数标定一次讲透。
2. 甘氏矩阵图的数学骨架:螺旋编号、奇数平方与 45° 角度制
2.1 从中心 1 开始的螺旋:行列坐标怎么定
甘氏矩阵图(Square of Nine)最朴素的形式是一张 (2n+1) 阶方阵,中心放 1,然后按「右 1 步、上 1 步、左 2 步、下 2 步、右 3 步、上 3 步……」填充。这个步长序列 1,1,2,2,3,3,4,4 是骨架:每两条边组成完整的一环,第 n 环的边长恰好是 n。按这个规则,3 阶矩阵是:
5 4 3 6 1 2 7 8 92 在 1 的正右方,3 在 2 的正上方,9 落在右下角。这个布局是所有角度计算的基准。换一种起笔方向(比如从正上方开始)会让全部角度整体平移,推算出来的价位集合形状不变,只是编号习惯不同。常见做法是固定一种,别在同一个项目里混用两套。
2.2 奇数平方数为什么是环与环的分界
走完第 n 环,总格数正好是 (2n+1)²,所以第 n 环的最大数一定是奇数平方。这条性质决定了「环号」可以直接由价格反解出来,不用把矩阵真的一张张铺开。环与环之间的对应关系如下:
| 环号 n | 该环最大数 (2n+1)² | 该环格数 8n | 单格角度 | 矩阵阶数 |
|---|---|---|---|---|
| 0 | 1 | 1 | — | 1×1 |
| 1 | 9 | 8 | 45° | 3×3 |
| 2 | 25 | 16 | 45° | 5×5 |
| 3 | 49 | 24 | 45° | 7×7 |
| 4 | 81 | 32 | 45° | 9×9 |
| 10 | 441 | 80 | 45° | 21×21 |
注意最后一列的「单格角度」恒为 45°,与环号无关。原因是第 n 环有 8n 个格子,绕一圈是 360°,360/8n 再乘以 n 环的边长系数,最终仍然回到 45°。这条恒等式是后面所有角度公式的地基。
2.3 45° 一格:角度公式怎么推出来
规定 2 号格为 0°,逆时针为正。第 n 环的起始格是 (2n-1)²+1,它紧接在上一环末尾后面,而上一环末尾(奇数平方)落在 315° 上。于是环内第 k 格的角度就是 315° + 45°×k,再对 360° 取模。
import numpy as np def ring_of(v: float) -> int: """v 所在的环号,中心 1 记为第 0 环。""" if v <= 1: return 0 return int(np.ceil((np.sqrt(v) - 1) / 2 - 1e-9)) def angle_of(v: float) -> float: """v 在矩阵中的角度,2 号格为 0°,逆时针增加。""" n = ring_of(v) if n == 0: return 0.0 k = v - (2 * n - 1) ** 2 # 环内序号,取值 1 .. 8n return (315.0 + 45.0 * k) % 360.0ring_of用 sqrt 反解环号:环 n 的上界开方是 2n+1,减去 1 再除以 2 就是 n,1e-9是防止浮点误差把 9、25 这类边界值算到上一环。angle_of里k允许是小数,这样任意非整数价格也能算出连续角度,而不是粗暴取整。
2.4 精确走格与 sqrt 连续化:两条路线的差别
网络上的甘氏计算器大多用另一套写法:对价格开方,加减 0.125、0.25、0.375(分别对应 45°、90°、135°),再平方回去。这套写法把 sqrt(价格) 当成一个 360° 的圆,一整圈等于 1.0。
它和矩阵几何并不等价。在矩阵里,从第 n 环跨到第 n+1 环,开方值从 2n+1 变成 2n+3,差值是 2,不是 1。环内每格的 Δsqrt 约等于 1/(4n):n=2 时正好是 0.125,n=20 时已经掉到 0.0125。也就是说,0.125 这个常数只在第 2 环附近与矩阵吻合,环号一大就完全对不上,两套结果能差出一个数量级。
提示:选一套就一路走到底。要几何精确、能对着矩阵数格子的,用环号加角度公式;要跟老工具、老研报对数的,用 0.125 那套,但别声称它等价于矩阵。
3. 用 Python 实现甘氏矩阵图价格推算的最小可运行代码
3.1 生成矩阵:三十行搞定螺旋填充
矩阵本身只用于校验和可视化,价格推算走的是闭式公式,但先用代码把矩阵铺出来,才能确认环号和角度没算错。
def build_matrix(rings: int) -> np.ndarray: """生成 (2*rings+1) 阶甘氏矩阵图,中心为 1,方向顺序:右、上、左、下。""" size = 2 * rings + 1 mat = np.zeros((size, size), dtype=int) r = c = rings mat[r, c] = 1 val, length, d = 1, 1, 0 dirs = [(0, 1), (-1, 0), (0, -1), (1, 0)] # 右、上、左、下 while True: for _ in range(2): # 每条边长走两次,方向转一次 dr, dc = dirs[d % 4] for _ in range(length): r, c = r + dr, c + dc val += 1 mat[r, c] = val if val == size * size: return mat d += 1 length += 1 print(build_matrix(2))length从 1 开始,每走完两条边自增一次,正好复现 1,1,2,2,3,3 的边长序列。dirs的顺序决定了旋转方向,把它改成[(0,1),(-1,0),(0,-1),(1,0)]之外的排列,矩阵会镜像,角度基准也随之变化,所以这段不要随手改。
3.2 反查:任意价格落在第几环第几度
真实价格动辄几千,直接把 5000 塞进矩阵是没意义的,必须先除以一个价格步长step,换算成「格值」。5000 元、步长 10 元,格值就是 500,落在第 11 环,角度可算。
def gann_targets(price: float, step: float, levels: int = 6) -> dict: """把价格换算成格值,给出同角度向外和向内的候选目标价。""" v = price / step return { "ring": ring_of(v), "angle": round(angle_of(v), 1), "up": [round(c * step, 4) for c in ray_cells(v, levels, True)], "down": [round(c * step, 4) for c in ray_cells(v, levels, False)], } def ray_cells(v: float, levels: int = 6, outward: bool = True) -> list: """保持角度不变,向外(内)跨环,返回格值列表。""" out, cur = [], v sign = 1 if outward else -1 for _ in range(levels): n = max(ring_of(cur), 1) cur = cur + sign * 8 * n # 同角度跨一环,格值增加 8n if cur < 1: break out.append(cur) return out8 * n是核心常数。第 n 环环内第 k 格是 (2n-1)²+k,第 n+1 环同角度的格子是 (2n+1)²+k,两者相减正好是 8n。所以「同角度向外推一环」在格值上就是加 8n。相邻两环的价格比值是 ((n+1)/n)²:n=8 时约 1.27,n=20 时约 1.10,越往外越密,这是甘氏矩阵图的固有几何特征,不是参数没调好。
3.3 参数怎么设:层数、步长、方向
| 参数 | 含义 | 常用取值 | 影响 |
|---|---|---|---|
| step | 每个格值代表多少价格 | ATR(14)/2 或 1/100 价位量级 | 决定网格疏密,最关键 |
| levels | 向外推几环 | 4 ~ 8 | 太少给不出远端目标,太多全是噪声 |
| rings | 矩阵铺几层 | 只做校验时取 5 ~ 10 | 与推算无关,纯可视化 |
| 起笔方向 | 螺旋旋转朝向 | 右起、逆时针 | 全体角度平移,不改变集合形状 |
步长的选法:先看标的的 14 日 ATR。ATR 是 0.20 元的股票,step 取 0.10 元,基准价 24.60 元对应格值 246,落在第 8 环,相邻目标位间隔约 26%、23%、21%,节奏合理。若把 step 设成 0.01,格值变成 2460,环号升到 25,相邻目标位间隔降到 8% 左右,一串价位挤在一起,回测时几乎每根 K 线都能碰到其中一个,命中率必然虚高。
注意:不要为了让某个历史高点「刚好落在射线」上而反复回调 step。这是甘氏类工具最典型的过拟合方式,第 4 章的随机基准就是用来识破它的。
4. 实战:把甘氏矩阵图推算结果接到真实行情上
4.1 基点三选法:低点、高点、区间中值
同一个价格用不同基点算,出来的射线不一样。工程上常用三种起点,各自解决的问题不同。
第一种是摆动低点,用于推上方阻力,适合上升趋势中回踩结束的位置。第二种是摆动高点,用于推下方支撑,适合下跌中继的反弹判断。第三种是区间中值,比如 (最高+最低)/2,用于震荡区间内找中轴附近的密集位。
三种基点算出的价位往往互相印证。实战做法是把三组结果合并,落在 1.5 倍 step 以内的候选位归并成一个「价位簇」,簇的成员越多,说明这个位置在多个基点下都成立,权重越高。
def merge_levels(groups, tol): """把多组候选位按容差归并成价位簇,返回 (中心价, 成员数)。""" flat = sorted(x for g in groups for x in g) clusters, cur = [], [flat[0]] for x in flat[1:]: if x - cur[-1] <= tol: cur.append(x) else: clusters.append((round(sum(cur) / len(cur), 4), len(cur))) cur = [x] clusters.append((round(sum(cur) / len(cur), 4), len(cur))) return clusterstol取 1.5 倍 step 是经验值:太松会把相隔很远的价位糊在一起,太紧则归并没效果。返回的成员数是排序依据,成员数 3 以上的簇才值得挂单。
4.2 回测:触及率必须和随机基准比
光看「命中了几次」毫无意义,因为候选位越密,命中越多。必须同时算一个随机基准:候选位的总带宽占整个价格区间的比例。如果触及率只是略高于这个比例,说明这套网格没有超出随机水平的解释力。
def touch_rate(series, levels, tol, horizon): """未来 horizon 根 K 线内,每个候选位被触及的比例(不重叠窗口)。""" hit = tot = 0 for i in range(0, len(series) - horizon, horizon): w = series[i + 1:i + 1 + horizon] for lv in levels: tot += 1 if np.any(np.abs(w - lv) <= tol): hit += 1 return hit / tot if tot else 0.0 def null_rate(levels, series, tol): """随机基准:候选位带宽占价格区间之比。""" span = series.max() - series.min() return min(1.0, len(levels) * 2 * tol / span) # 超发比 = touch_rate / null_rate,低于 1.2 视为无优势horizon建议取 10 到 20,并且用不重叠窗口,否则相邻窗口高度相关,会把样本量虚增几倍。tol取 step 的一半。超发比这个指标比单看命中率靠谱得多:
| 指标 | 计算方式 | 参考阈值 | 说明 |
|---|---|---|---|
| 触及率 | 命中数 / 候选位总数 | — | 单独看没有意义 |
| 随机基准 | 候选位带宽 / 价格区间 | — | 密度越高基准越高 |
| 超发比 | 触及率 / 随机基准 | < 1.2 无优势 | 主判据 |
| 簇命中占比 | 成员数≥3 的簇命中数 / 总命中数 | > 0.5 可用 | 衡量筛选是否有效 |
跑一轮真实数据,把 levels 从 8 降到 4,再把 step 从 ATR/4 调到 ATR/2,你会看到触及率断崖式下跌而超发比反而上升——这就是「候选位变少、每个更有含金量」的正常反应。反过来,任何让触及率上涨但超发比不动甚至下降的调参,都是在往噪声里塞参数。
5. 标定与排错:让甘氏矩阵图推算结果能被证伪
5.1 用 ATR 校准步长,而不是死守 0.125
步长决定了环号,环号决定了射线间距,这是整条链路里唯一真正需要标定的参数。固定用 0.125 起步的写法,在不同价位量级的标的上会给出完全不同的疏密,根本无法横向比较。改成按波动率标定就稳了:
def auto_step(highs, lows, closes, k=0.5): """按 ATR(14) 反推价格步长,k 控制疏密。""" tr = np.maximum(highs[1:] - lows[1:], np.maximum(np.abs(highs[1:] - closes[:-1]), np.abs(lows[1:] - closes[:-1]))) atr = tr[-14:].mean() return round(atr * k, 6)k=0.5时,网格间距约等于半个 ATR,一个波段里通常能筛出三到五个有效簇;k=0.25更密,适合日内;k=1.0很稀,只适合大级别。这个写法还有一个好处:ATR 随波动率变化,步长跟着变,网格自动适配牛熊切换,不会在低波动期给出一堆永远碰不到的远端目标。
5.2 三类高频错误:基点漂移、环数不足、角度方向搞反
基点漂移最常见。回测时用窗口内的极值做基点,实盘却用固定日期,两者算出的射线完全不同,结果就是回测漂亮实盘失灵。正确做法是在窗口起始时刻锁定基点并写进状态,后面不再改。
环数不足体现在只在近端找目标。levels 取 2 时,能给的候选位太少,超发比看着很高其实是样本太小。建议至少 4 环,并且把超出价格区间 20% 以外的远端结果直接丢掉,而不是硬留着凑数。
角度方向搞反则是实现层面的。dirs的排列决定了矩阵是逆时针还是顺时针,ray_cells里的8n是加还是减决定了射线朝外还是朝内。验证方法很简单:拿矩阵图打印出来,手工数一遍 9 和 17 的角度是否同为 315°,对不上就是方向反了。这一步用build_matrix(3)输出后肉眼核对,比读十遍公式快。
还有一个隐性坑:ring_of在整数平方处会因浮点误差跨环。9、25、49 这些值必须落在第 1、2、3 环,若出现偏差,把1e-9调到1e-6再试。整条链路跑通之后,把 step 设成 ATR(14)/2 再跑第 4 章的回测循环,通常能看到超发比在 1.3 到 1.6 之间——那个数字才是这套东西真实的水平,也是继续调参的起点。
本文还有配套的精品资源,点击获取