Spring Boot 对接多市场行情数据接口的踩坑记录

背景

最近有个需求:做一个跨市场行情看板,需要同时展示印度、马来西亚、日韩等几个海外市场的股票列表和涨跌排行,再加一个 BTC/ETH 的实时价格面板。

本来想分头找数据源,后来图省事直接用了一个接口聚合的。刚好整理下对接过程中的几个点和踩过的坑。

接口概览

Base URL 是 https://api.stocktv.top,鉴权方式就是 URL 加一个 key 参数,所有响应 JSON,结构统一是 {code, message, data}

我用到的就四个接口:

  • /stock/stocks --- 按国家拉股票列表,带分页
  • /stock/updownList --- 涨跌排行榜
  • /crypto/lastPrice --- 加密货币最新报价
  • /market/currency --- 外汇汇率列表

官网文档地址:https://pao.stocktv.top/


1. 股票列表接口

复制代码
GET /stock/stocks?countryId=14&pageSize=10&page=1&key=YOUR_KEY

参数很简单:countryId(国家ID)、pageSizepage

这里 countryId 需要提前知道。当时查文档发现支持的几个国家 ID:

countryId 国家 标识
14 印度 IN
42 马来西亚 MY
韩国、日本、美国等 ... ...

返回结构:

json 复制代码
{
  "code": 200,
  "data": {
    "records": [
      {
        "symbol": "TCS",
        "name": "Tata Consultancy Services Ltd",
        "last": 3890.55,
        "chg": 25.30,
        "chgPct": 0.65,
        "high": 3910.00,
        "low": 3865.20,
        "volume": 2345678,
        "open": false,
        "technicalDay": "strong_buy",
        "performanceYtd": 12.5,
        "countryNameTranslated": "India"
      }
    ],
    "total": 1000,
    "size": 10,
    "current": 1,
    "pages": 100
  }
}

数据比较全,基本面和业绩统计都在一条记录里了。不过注意 open 字段是 boolean,拿到后需要处理一下开盘/收盘状态的展示逻辑。


2. 涨跌排行榜

复制代码
GET /stock/updownList?countryId=14&type=1&key=YOUR_KEY

type 取值:1 涨幅榜、2 跌幅榜、3 涨停榜、4 跌停榜,默认返回前 50 条。

返回字段和股票列表接口基本一致,可以直接复用同一个 DTO:

java 复制代码
@Data
public class StockItem {
    private Long id;
    private String symbol;
    private String name;
    private Double last;
    private Double chg;
    private Double chgPct;
    private Double high;
    private Double low;
    private Long volume;
    private Boolean open;
    private String technicalDay;
    private String technicalWeek;
    private Double performanceYtd;
    private String countryNameTranslated;
    private String flag;
    // getters/setters 省略
}

3. 加密货币价格

获取 BTC 和 ETH 的 USDT 交易对最新价:

复制代码
GET /crypto/lastPrice?symbols=BTCUSDT,ETHUSDT&key=YOUR_KEY

最多一次传 100 个交易对,逗号分隔。返回非常轻量:

json 复制代码
{
  "code": 200,
  "data": [
    { "symbol": "BTCUSDT", "price": "66630.20" },
    { "symbol": "ETHUSDT", "price": "3307.74" }
  ]
}

4. Spring Boot 中的封装

java 复制代码
@Service
public class MarketDataService {

    private final RestTemplate restTemplate = new RestTemplate();
    private static final String BASE_URL = "https://api.stocktv.top";
    private final String apiKey;

    public MarketDataService(@Value("${market.api.key}") String apiKey) {
        this.apiKey = apiKey;
    }

    public JsonNode getStockList(int countryId, int page, int pageSize) {
        String url = String.format(
            "%s/stock/stocks?countryId=%d&page=%d&pageSize=%d&key=%s",
            BASE_URL, countryId, page, pageSize, apiKey
        );
        return restTemplate.getForObject(url, JsonNode.class);
    }

    public JsonNode getUpDownList(int countryId, int type) {
        String url = String.format(
            "%s/stock/updownList?countryId=%d&type=%d&key=%s",
            BASE_URL, countryId, type, apiKey
        );
        return restTemplate.getForObject(url, JsonNode.class);
    }

    public JsonNode getCryptoPrices(String... symbols) {
        String symbolStr = String.join(",", symbols);
        String url = String.format(
            "%s/crypto/lastPrice?symbols=%s&key=%s",
            BASE_URL, symbolStr, apiKey
        );
        return restTemplate.getForObject(url, JsonNode.class);
    }
}

5. 踩过的坑

  1. 开盘状态字段open 是 boolean,直接 Boolean.getBoolean() 拿不到,得用 asBoolean()(Jackson JsonNode)或注意 getter 命名。
  2. 涨跌幅需拼接 % :WebSocket 推送里 pcp 字段返回的数值不含百分号,前端渲染时要自己拼。
  3. K 线 interval 命名 :股票用的是 P1DPT15M 这种 ISO 8601 Duration 格式,外汇和加密货币用的是 5m1h 这种短格式,别搞混了。

附:其他可用的接口

除了上面我用到的,这个接口还提供了:

  • K 线/stock/kline?pid=&interval= --- 支持 PT5M ~ P1M
  • IPO 日历/stock/getIpo?countryId=
  • 公司信息/stock/companies?countryId=
  • 国际新闻/stock/news?pageSize=&page=
  • 外汇/market/currencyList/market/chart
  • 期货/futures/list/futures/kline
  • 加密货币完整数据/crypto/getKlines/crypto/getTrades
  • WebSocket 实时推送wss://ws-api.stocktv.top/connect?key=

有需要可以直接看文档,或者 联系获取 Key