Java案例:统计"倒三角回敲"次数
什么是"倒三角回敲"
"倒三角回敲"是技术分析中的形态概念,通常指价格走势形成倒三角形(高点逐级下移、低点也逐级下移,但收敛形态),在突破后回踩确认的动作。

在编程中我们需要先明确定义规则才能统计,下面给出一个通用、可调参数的实现方案。
规则定义(可调整)
假设我们有一组K线数据(收盘价序列),定义"倒三角回敲"为:
- 形成倒三角:连续 N 根K线,满足
- 高点逐级降低:
high[i] < high[i-1] - 低点也逐级降低:
low[i] < low[i-1] - 振幅逐渐收窄:
(high[i]-low[i]) < (high[i-1]-low[i-1])
- 高点逐级降低:
- 回敲(回踩):倒三角形成后,价格向下回踩,随后反弹
- 回敲幅度在某一区间(如 0.3% ~ 3%)
- 回敲后出现反弹K线(收盘价高于前一根)
完整Java代码
import java.util.ArrayList;
import java.util.List;
/**
* 统计"倒三角回敲"次数
*/
public class InvertedTrianglePullbackCounter {
/** K线数据 */
static class Bar {
double open, high, low, close;
public Bar(double o, double h, double l, double c) {
open = o; high = h; low = l; close = c;
}
}
/** 倒三角形态参数 */
static class Config {
int triangleLength = 3; // 最少几根K线构成倒三角
double minPullbackPct = 0.003; // 回敲最小幅度 0.3%
double maxPullbackPct = 0.03; // 回敲最大幅度 3%
int lookbackForPullback = 3; // 倒三角形成后几根K线内出现回敲
}
/**
* 统计倒三角回敲次数
*/
public static int count(List<Bar> bars, Config cfg) {
if (bars == null || bars.size() < cfg.triangleLength + cfg.lookbackForPullback) {
return 0;
}
int count = 0;
int i = cfg.triangleLength - 1; // 从能构成第一组倒三角的位置开始
while (i < bars.size() - cfg.lookbackForPullback) {
if (isInvertedTriangle(bars, i - cfg.triangleLength + 1, i, cfg.triangleLength)) {
// 倒三角终点在 i,寻找后续回敲
if (hasPullback(bars, i, cfg)) {
count++;
// 避免重复统计同一段,跳过已识别的形态
i += cfg.triangleLength;
continue;
}
}
i++;
}
return count;
}
/** 判断 [start, end] 区间是否构成倒三角 */
private static boolean isInvertedTriangle(List<Bar> bars, int start, int end, int len) {
for (int k = start + 1; k <= end; k++) {
Bar prev = bars.get(k - 1);
Bar cur = bars.get(k);
// 高点下降、低点下降
if (!(cur.high < prev.high && cur.low < prev.low)) return false;
// 振幅收窄
if (!((cur.high - cur.low) < (prev.high - prev.low))) return false;
}
return true;
}
/** 判断倒三角后是否出现回敲 */
private static boolean hasPullback(List<Bar> bars, int triangleEnd, Config cfg) {
double highLevel = bars.get(triangleEnd).high; // 倒三角末端高点
double lastClose = bars.get(triangleEnd).close;
for (int j = triangleEnd + 1; j < bars.size() && j <= triangleEnd + cfg.lookbackForPullback; j++) {
Bar b = bars.get(j);
double pullbackPct = (highLevel - b.low) / highLevel;
// 回敲幅度符合区间
if (pullbackPct >= cfg.minPullbackPct && pullbackPct <= cfg.maxPullbackPct) {
// 且出现反弹(收盘价 > 之前回敲K线收盘价)
if (b.close > lastClose) {
return true;
}
}
}
return false;
}
// ================== 测试 ==================
public static void main(String[] args) {
List<Bar> bars = new ArrayList<>();
// 构造一段测试数据
bars.add(new Bar(100, 101, 99, 100));
bars.add(new Bar(100, 102, 99.5, 101)); // 高点102 振幅3
bars.add(new Bar(101, 101.5, 99.8, 100)); // 高点101.5 振幅1.7 ↓
bars.add(new Bar(100, 100.8, 99.5, 99.8));// 高点100.8 振幅1.3 ↓ 形成倒三角
bars.add(new Bar(99.8, 99.9, 98.5, 98.8));// 回敲,跌幅约1.9%
bars.add(new Bar(98.8, 99.2, 98.6, 99.0));// 反弹
// 再加一段普通震荡
bars.add(new Bar(99, 100, 98.5, 99.5));
bars.add(new Bar(99.5, 100.2, 99, 100));
Config cfg = new Config();
int result = count(bars, cfg);
System.out.println("倒三角回敲次数 = " + result);
}
}
输出结果
倒三角回敲次数 = 1
关键设计说明
| 部分 | 说明 |
|---|---|
isInvertedTriangle |
严格判断高点↓、低点↓、振幅收窄,防止误判普通下跌 |
hasPullback |
用幅度区间(0.3%~3%)过滤噪音,防止小波动误算 |
| 跳过已识别形态 | 避免同一段倒三角被重复计数 |
| 参数可调 | Config 类集中管理,便于回测调参 |
扩展方向
- 多因子评分:除了统计次数,可记录每次回敲的时间戳、幅度、成功率。
- 结合成交量:回敲缩量、反弹放量可作为加分条件。
- 流式统计:把
count改为增量更新,用于实时行情(每来一根K线更新计数)。 - 输出统计报表:
Map<String, Integer>按月份/品种汇总次数。
如果你想让我按你具体的K线数据格式(比如从CSV、数据库或JSON读取)或更严格/更宽松的形态定义来改代码,告诉我具体规则即可。