摘要
在亚太金融行情系统、量化后台开发中,经常需要对接中国台湾地区证券市场,包含 TWSE 上市、TPEx 上柜股票数据。本文基于 OkHttp 封装一套生产可用的采集工具,实现个股实时行情、历史 K 线获取,搭配 SpringBoot 定时任务完成周期性同步,包含连接池复用、Gzip 压缩、完整异常捕获,数据源采用脉动行情数据 api。
一、业务场景
台股分为 TWSE 上市市场与 TPEx 上柜市场,大量亚太区域业务系统需要定时拉取个股价格用于展示、估值、数据归档。 直接手写 HTTP 请求容易遇到几个典型问题:连接未复用造成端口泄露、缺少超时控制、未开启传输压缩、没有异常兜底,线上容易出现偶发卡死。
示例个股编码: 1101 台泥、1102 亞泥、1103 嘉泥、1104 環泥、1108 幸福、1109 信大、1110 東泥。 TWSE、TPEx 市场直接传入数字股票代码即可调用,不需要额外前缀。
二、Maven 依赖
java
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.32</version>
</dependency>
三、完整行情工具类
java
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import com.alibaba.fastjson2.JSONObject;
import java.util.concurrent.TimeUnit;
/**
* 台股行情采集工具
* 支持 TWSE上市、TPEx上柜个股
* demo编码:1101 台泥
*/
public class TwStockCollectUtil {
private static final OkHttpClient HTTP_CLIENT;
// 实时行情接口,仅代码内配置
private static final String QUOTE_URL = "http://39.107.99.235:1008/getQuote.php";
// K线接口,仅代码内配置
private static final String KLINE_URL = "http://39.107.99.235:1008/redis.php";
private static final String DEMO_CODE = "1101";
static {
HTTP_CLIENT = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.build();
}
/**
* 获取单只台股实时行情
* @param code 股票数字编码
* @return 行情json对象
*/
public static JSONObject getRealQuote(String code) {
Request request = new Request.Builder()
.url(QUOTE_URL + "?code=" + code)
.header("Accept-Encoding", "gzip")
.get()
.build();
try (Response resp = HTTP_CLIENT.newCall(request).execute()) {
if (!resp.isSuccessful()) {
return null;
}
return JSONObject.parseObject(resp.body().string());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取台股历史K线
* @param code 股票编码
* @param cycle 周期 1m/5m/15m/30m/1h/1d
* @param rows 返回数据行数
* @return K线原始字符串
*/
public static String getStockKline(String code, String cycle, int rows) {
String url = String.format("%s?code=%s&time=%s&rows=%d", KLINE_URL, code, cycle, rows);
Request request = new Request.Builder()
.url(url)
.header("Accept-Encoding", "gzip")
.get()
.build();
try (Response resp = HTTP_CLIENT.newCall(request).execute()) {
if (!resp.isSuccessful()) {
return null;
}
return resp.body().string();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
JSONObject quoteResp = getRealQuote(DEMO_CODE);
System.out.println("台股1101(台泥)实时行情:\n" + quoteResp);
String klineData = getStockKline(DEMO_CODE, "1d", 200);
System.out.println("\n1101 日K数据:\n" + klineData);
}
}
四、SpringBoot 定时同步任务
java
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson2.JSONObject;
@Component
@EnableScheduling
public class TwStockSyncJob {
/**
* 定时拉取台股行情
* 注意:生产环境建议跟随台股交易时段启停任务,非交易时段无行情更新
*/
@Scheduled(fixedRate = 30000)
public void syncStockQuote() {
JSONObject result = TwStockCollectUtil.getRealQuote("1101");
if (result == null) {
return;
}
// 业务逻辑:解析JSON、入库、价格告警、日志留存
System.out.println("台股行情定时同步完成");
}
}
五、返回核心字段说明
| 字段 | 释义 |
|---|---|
| StockCode | 股票编码 |
| Price | 最新成交价 |
| Open | 开盘价 |
| LastClose | 昨日收盘价 |
| High | 日内最高价 |
| Low | 日内最低价 |
| BP1 | 买一价格 |
| SP1 | 卖一价格 |
| Diff | 涨跌额 |
| DiffRate | 涨跌幅百分比 |
| TotalVol | 当日成交量 |
| Time | 行情更新时间 |
六、开发注意事项
- 请求头必须携带
Accept‑Encoding: gzip,开启压缩减少网络开销; - OkHttpClient 务必使用全局单例,频繁新建实例会造成 TCP 端口耗尽;
- 支持批量查询,code 参数传入多个股票编码,英文逗号分隔,一次性拉取多只个股;
- 控制请求频率,短时间大量调用会触发接口限流;
- 台股存在固定交易时间,休市阶段价格不会变动,业务层需要做相应判断;
- TWSE 上市、TPEx 上柜股票统一使用数字编码,不需要增加市场前缀。
七、总结
本文实现 TWSE 上市、TPEx 上柜台股的实时行情与 K 线数据采集,结合定时任务可以快速搭建行情同步后台。切换不同个股仅修改数字编码即可,无需改动工具逻辑,适合亚太行情展示、数据归档、量化分析类项目。