java案例能否识别盘口异常变动?

wen java案例 12

用 Java 案例识别盘口异常变动

可以,Java 完全可以实现盘口(Level-2 行情)异常变动识别,下面给一个可运行的案例框架,涵盖常见异常类型和识别逻辑。

java案例能否识别盘口异常变动?


盘口异常的主要类型

异常类型 特征 判定思路
大单扫单 卖一至卖N被连续吃掉 主动买量骤增、委卖锐减
撤单异常 某价位挂单瞬间消失 挂单量环比突变
价差异常 买一卖一价差突然扩大/收窄 spread 突变
盘口失衡 委买委卖比例极端 order imbalance 阈值
压单/托单 单价位挂单量异常巨大 单档量偏离均值 N 倍
封板异动 涨停/跌停封单快速变化 封单量变化率

核心 Java 案例代码

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
// 1. 盘口快照
class OrderBook {
    long timestamp;
    int[] bidPrices = new int[10];   // 买1~买10 价格(分)
    long[] bidVols  = new long[10];  // 买1~买10 量
    int[] askPrices = new int[10];
    long[] askVols  = new long[10];
    long lastPrice;
    long lastVol;
}
// 2. 异常事件
class Anomaly {
    String code;
    String type;
    long timestamp;
    String detail;
    Anomaly(String c, String t, long ts, String d) {
        code = c; type = t; timestamp = ts; detail = d;
    }
    @Override public String toString() {
        return String.format("[%s] %s @%d : %s", code, type, timestamp, detail);
    }
}
// 3. 异常识别器
public class OrderBookAnomalyDetector {
    // 阈值(可配置)
    private static final double SINGLE_LEVEL_RATIO_THRESHOLD = 5.0; // 单档量/均值 > 5 倍
    private static final double IMBALANCE_THRESHOLD = 3.0;         // 委买/委卖 > 3 或 < 1/3
    private static final double SPREAD_SPIKE_RATIO = 2.5;          // 价差突然扩大 2.5 倍
    private static final double CANCEL_RATIO_THRESHOLD = 0.7;      // 单档量骤减 > 70%
    // 每只股票的历史快照,用于环比
    private final Map<String, OrderBook> lastBook = new ConcurrentHashMap<>();
    public List<Anomaly> detect(String code, OrderBook cur) {
        List<Anomaly> result = new ArrayList<>();
        OrderBook prev = lastBook.get(code);
        // --- (1) 单档挂单异动:某档量远超同侧均值 ---
        checkSingleLevelSpike(result, code, cur, cur.bidVols, "BID");
        checkSingleLevelSpike(result, code, cur, cur.askVols, "ASK");
        // --- (2) 盘口失衡:委买总量 / 委卖总量 ---
        long bidSum = Arrays.stream(cur.bidVols).sum();
        long askSum = Arrays.stream(cur.askVols).sum();
        if (askSum > 0) {
            double ratio = (double) bidSum / askSum;
            if (ratio > IMBALANCE_THRESHOLD) {
                result.add(new Anomaly(code, "BID_IMBALANCE", cur.timestamp,
                        String.format("委买/委卖=%.2f (买多)", ratio)));
            } else if (ratio < 1.0 / IMBALANCE_THRESHOLD) {
                result.add(new Anomaly(code, "ASK_IMBALANCE", cur.timestamp,
                        String.format("委买/委卖=%.2f (卖多)", ratio)));
            }
        }
        // --- (3) 价差异常扩大 ---
        int spread = cur.askPrices[0] - cur.bidPrices[0];
        if (prev != null) {
            int prevSpread = prev.askPrices[0] - prev.bidPrices[0];
            if (prevSpread > 0 && spread > prevSpread * SPREAD_SPIKE_RATIO) {
                result.add(new Anomaly(code, "SPREAD_SPIKE", cur.timestamp,
                        String.format("价差 %d->%d", prevSpread, spread)));
            }
        }
        // --- (4) 撤单异常:某档挂单量骤减 ---
        if (prev != null) {
            for (int i = 0; i < 10; i++) {
                checkCancel(result, code, cur.timestamp, "BID-" + (i+1),
                        prev.bidVols[i], cur.bidVols[i]);
                checkCancel(result, code, cur.timestamp, "ASK-" + (i+1),
                        prev.askVols[i], cur.askVols[i]);
            }
        }
        // --- (5) 大单扫单:成交价击穿多档 + 量放大 ---
        if (prev != null && cur.lastVol > 0) {
            double avgLastVol = Math.max(prev.lastVol, 1);
            if (cur.lastVol > avgLastVol * 5 && cur.lastPrice >= cur.askPrices[0]) {
                result.add(new Anomaly(code, "AGGRESSIVE_BUY", cur.timestamp,
                        "大单主动买 " + cur.lastVol));
            }
            if (cur.lastVol > avgLastVol * 5 && cur.lastPrice <= cur.bidPrices[0]) {
                result.add(new Anomaly(code, "AGGRESSIVE_SELL", cur.timestamp,
                        "大单主动卖 " + cur.lastVol));
            }
        }
        lastBook.put(code, cur);
        return result;
    }
    private void checkSingleLevelSpike(List<Anomaly> out, String code,
                                        OrderBook ob, long[] vols, String side) {
        double avg = Arrays.stream(vols).average().orElse(0);
        if (avg <= 0) return;
        for (int i = 0; i < vols.length; i++) {
            if (vols[i] > avg * SINGLE_LEVEL_RATIO_THRESHOLD) {
                out.add(new Anomaly(code, "LEVEL_SPIKE", ob.timestamp,
                        String.format("%s%d 量=%d 均值=%.0f", side, i+1, vols[i], avg)));
            }
        }
    }
    private void checkCancel(List<Anomaly> out, String code, long ts,
                              String tag, long prevVol, long curVol) {
        if (prevVol > 0 && curVol < prevVol * (1 - CANCEL_RATIO_THRESHOLD)) {
            out.add(new Anomaly(code, "CANCEL", ts,
                    String.format("%s %d->%d 撤单率=%.0f%%",
                            tag, prevVol, curVol, 100.0 * (prevVol - curVol) / prevVol)));
        }
    }
}

使用示例

public class Demo {
    public static void main(String[] args) {
        OrderBookAnomalyDetector detector = new OrderBookAnomalyDetector();
        OrderBook ob1 = mockBook(10000, 10010, 500, 500);
        detector.detect("600000", ob1);   // 首笔只记录
        // 第二笔:卖档突然出现巨大挂单 + 价差扩大
        OrderBook ob2 = mockBook(10000, 10100, 500, 500);
        ob2.askVols[0] = 20000;
        List<Anomaly> list = detector.detect("600000", ob2);
        list.forEach(System.out::println);
    }
    static OrderBook mockBook(int bid1, int ask1, long v1, long v2) {
        OrderBook ob = new OrderBook();
        ob.timestamp = System.currentTimeMillis();
        for (int i = 0; i < 10; i++) {
            ob.bidPrices[i] = bid1 - i * 10;
            ob.askPrices[i] = ask1 + i * 10;
            ob.bidVols[i] = v1;
            ob.askVols[i] = v2;
        }
        ob.lastPrice = ask1;
        ob.lastVol = 100;
        return ob;
    }
}

输出示例:

[600000] LEVEL_SPIKE @... : ASK1 量=20000 均值=2450
[600000] SPREAD_SPIKE @... : 价差 10->100

工程化的关键点

  1. 数据源:通过行情网关(如 CTP、恒生、迅投 QMT、掘金、WebSocket 推送)拿到 Level-1/Level-2 快照,按股票分片推入检测器。
  2. 窗口统计:用滑动窗口(如最近 20 笔)计算均值和标准差,动态阈值(mean ± k*std)比固定阈值更稳。
  3. 性能:单机可处理数万只股票 tick,用 ConcurrentHashMap + 无锁结构;高频场景可用 Disruptor。
  4. 落库/告警:异常事件写入 Kafka/Redis,并触发风控或可视化告警。
  5. 回测验证:拿历史 tick 回放,统计各类异常与后续收益/波动的关系,防止误报。

局限与注意

  • 仅凭快照难以区分"大单成交"和"撤单"造成的盘口变化,需结合 逐笔委托 + 逐笔成交(Level-2)才更准确。
  • 单一阈值易误报,建议 多因子组合 + 机器学习(如孤立森林) 提升准确率。
  • 注意交易所 集合竞价、涨跌停封板 等特殊阶段的规则差异,需单独处理。

如果你需要,我可以进一步给出:逐笔委托撤单识别、滑动窗口 Z-score 动态阈值版本、或Spring Boot + Kafka 的完整接入方案。

友情链接

欧易欧易欧易欧易欧易欧易欧易欧易直播帮篮球控NBA帮比赛虎聊足球

抱歉,评论功能暂时关闭!

友情链接攻略窝 · 礼包窝 · 配置窝 · 换算窝 · 算法窝 · 查文窝 · 手册窝 · 问答窝 · 全文搜 · 手册库
相关站点礼包窝 · 查文窝