当前位置: 首页 > news >正文

Java 对接印度股票数据源实现 http+ws实时数据

以下是使用 Java 对接 StockTV 印度股票数据源的完整实现,包括实时行情、K线数据、公司信息等功能。

1. 项目依赖

首先在 pom.xml 中添加必要的依赖:

<dependencies><!-- HTTP 客户端 --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.14</version></dependency><!-- JSON 处理 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.15.2</version></dependency><!-- WebSocket 客户端 --><dependency><groupId>org.java-websocket</groupId><artifactId>Java-WebSocket</artifactId><version>1.5.3</version></dependency><!-- 日志 --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.7</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>2.0.7</version></dependency>
</dependencies>

2. 配置类

package com.stocktv.india.config;import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;public class StockTVConfig {// API 基础配置public static final String BASE_URL = "https://api.stocktv.top";public static final String WS_URL = "wss://ws-api.stocktv.top/connect";// 印度市场特定配置public static final int INDIA_COUNTRY_ID = 14;public static final int NSE_EXCHANGE_ID = 46;public static final int BSE_EXCHANGE_ID = 74;// API Key - 请替换为实际的 API Keyprivate String apiKey;// HTTP 客户端private final CloseableHttpClient httpClient;private final ObjectMapper objectMapper;public StockTVConfig(String apiKey) {this.apiKey = apiKey;this.httpClient = HttpClients.createDefault();this.objectMapper = new ObjectMapper();}// Getterspublic String getApiKey() { return apiKey; }public CloseableHttpClient getHttpClient() { return httpClient; }public ObjectMapper getObjectMapper() { return objectMapper; }
}

3. 数据模型类

股票基本信息

package com.stocktv.india.model;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;import java.math.BigDecimal;@Data
public class Stock {@JsonProperty("id")private Long id;@JsonProperty("symbol")private String symbol;@JsonProperty("name")private String name;@JsonProperty("last")private BigDecimal lastPrice;@JsonProperty("chg")private BigDecimal change;@JsonProperty("chgPct")private BigDecimal changePercent;@JsonProperty("high")private BigDecimal high;@JsonProperty("low")private BigDecimal low;@JsonProperty("volume")private Long volume;@JsonProperty("open")private Boolean isOpen;@JsonProperty("exchangeId")private Integer exchangeId;@JsonProperty("countryId")private Integer countryId;@JsonProperty("time")private Long timestamp;@JsonProperty("fundamentalMarketCap")private BigDecimal marketCap;@JsonProperty("fundamentalRevenue")private String revenue;// 技术指标@JsonProperty("technicalDay")private String technicalDay;@JsonProperty("technicalHour")private String technicalHour;@JsonProperty("technicalWeek")private String technicalWeek;@JsonProperty("technicalMonth")private String technicalMonth;
}

K线数据

package com.stocktv.india.model;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;import java.math.BigDecimal;@Data
public class KLine {@JsonProperty("time")private Long timestamp;@JsonProperty("open")private BigDecimal open;@JsonProperty("high")private BigDecimal high;@JsonProperty("low")private BigDecimal low;@JsonProperty("close")private BigDecimal close;@JsonProperty("volume")private Long volume;@JsonProperty("vo")private BigDecimal turnover;
}

指数数据

package com.stocktv.india.model;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;import java.math.BigDecimal;@Data
public class Index {@JsonProperty("id")private Long id;@JsonProperty("name")private String name;@JsonProperty("symbol")private String symbol;@JsonProperty("last")private BigDecimal lastPrice;@JsonProperty("chg")private BigDecimal change;@JsonProperty("chgPct")private BigDecimal changePercent;@JsonProperty("high")private BigDecimal high;@JsonProperty("low")private BigDecimal low;@JsonProperty("isOpen")private Boolean isOpen;@JsonProperty("time")private Long timestamp;
}

API 响应包装类

package com.stocktv.india.model;import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;import java.util.List;@Data
public class ApiResponse<T> {@JsonProperty("code")private Integer code;@JsonProperty("message")private String message;@JsonProperty("data")private T data;
}@Data
class StockListResponse {@JsonProperty("records")private List<Stock> records;@JsonProperty("total")private Integer total;@JsonProperty("current")private Integer current;@JsonProperty("pages")private Integer pages;
}

4. HTTP API 客户端

package com.stocktv.india.client;import com.fasterxml.jackson.core.type.TypeReference;
import com.stocktv.india.config.StockTVConfig;
import com.stocktv.india.model.*;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;public class StockTVHttpClient {private static final Logger logger = LoggerFactory.getLogger(StockTVHttpClient.class);private final StockTVConfig config;private final CloseableHttpClient httpClient;public StockTVHttpClient(StockTVConfig config) {this.config = config;this.httpClient = config.getHttpClient();}/*** 获取印度股票列表*/public List<Stock> getIndiaStocks(Integer pageSize, Integer page) throws IOException, URISyntaxException {URI uri = new URIBuilder(config.BASE_URL + "/stock/stocks").addParameter("countryId", String.valueOf(config.INDIA_COUNTRY_ID)).addParameter("pageSize", String.valueOf(pageSize)).addParameter("page", String.valueOf(page)).addParameter("key", config.getApiKey()).build();ApiResponse<StockListResponse> response = executeGetRequest(uri, new TypeReference<ApiResponse<StockListResponse>>() {});if (response.getCode() == 200) {return response.getData().getRecords();} else {throw new RuntimeException("API Error: " + response.getMessage());}}/*** 查询单个股票*/public List<Stock> queryStock(Long pid, String symbol, String name) throws IOException, URISyntaxException {URIBuilder uriBuilder = new URIBuilder(config.BASE_URL + "/stock/queryStocks").addParameter("key", config.getApiKey());if (pid != null) {uriBuilder.addParameter("id", String.valueOf(pid));}if (symbol != null) {uriBuilder.addParameter("symbol", symbol);}if (name != null) {uriBuilder.addParameter("name", name);}URI uri = uriBuilder.build();ApiResponse<List<Stock>> response = executeGetRequest(uri, new TypeReference<ApiResponse<List<Stock>>>() {});return response.getData();}/*** 批量查询多个股票*/public List<Stock> getStocksByPids(List<Long> pids) throws IOException, URISyntaxException {String pidsStr = String.join(",", pids.stream().map(String::valueOf).toArray(String[]::new));URI uri = new URIBuilder(config.BASE_URL + "/stock/stocksByPids").addParameter("key", config.getApiKey()).addParameter("pids", pidsStr).build();ApiResponse<List<Stock>> response = executeGetRequest(uri, new TypeReference<ApiResponse<List<Stock>>>() {});return response.getData();}/*** 获取印度主要指数*/public List<Index> getIndiaIndices() throws IOException, URISyntaxException {URI uri = new URIBuilder(config.BASE_URL + "/stock/indices").addParameter("countryId", String.valueOf(config.INDIA_COUNTRY_ID)).addParameter("key", config.getApiKey()).build();ApiResponse<List<Index>> response = executeGetRequest(uri, new TypeReference<ApiResponse<List<Index>>>() {});return response.getData();}/*** 获取K线数据*/public List<KLine> getKLineData(Long pid, String interval) throws IOException, URISyntaxException {URI uri = new URIBuilder(config.BASE_URL + "/stock/kline").addParameter("pid", String.valueOf(pid)).addParameter("interval", interval).addParameter("key", config.getApiKey()).build();ApiResponse<List<KLine>> response = executeGetRequest(uri, new TypeReference<ApiResponse<List<KLine>>>() {});return response.getData();}/*** 获取涨跌排行榜*/public List<Stock> getUpDownList(Integer type) throws IOException, URISyntaxException {URI uri = new URIBuilder(config.BASE_URL + "/stock/updownList").addParameter("countryId", String.valueOf(config.INDIA_COUNTRY_ID)).addParameter("type", String.valueOf(type)).addParameter("key", config.getApiKey()).build();ApiResponse<List<Stock>> response = executeGetRequest(uri, new TypeReference<ApiResponse<List<Stock>>>() {});return response.getData();}/*** 通用GET请求执行方法*/private <T> T executeGetRequest(URI uri, TypeReference<T> typeReference) throws IOException {HttpGet request = new HttpGet(uri);try (CloseableHttpResponse response = httpClient.execute(request)) {String responseBody = EntityUtils.toString(response.getEntity());logger.debug("API Response: {}", responseBody);return config.getObjectMapper().readValue(responseBody, typeReference);}}
}

5. WebSocket 实时数据客户端

package com.stocktv.india.client;import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.stocktv.india.config.StockTVConfig;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.net.URI;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;public class StockTVWebSocketClient {private static final Logger logger = LoggerFactory.getLogger(StockTVWebSocketClient.class);private final StockTVConfig config;private final ObjectMapper objectMapper;private WebSocketClient webSocketClient;private CountDownLatch connectionLatch;public StockTVWebSocketClient(StockTVConfig config) {this.config = config;this.objectMapper = config.getObjectMapper();}/*** 连接WebSocket服务器*/public void connect() throws Exception {String wsUrl = config.WS_URL + "?key=" + config.getApiKey();URI serverUri = URI.create(wsUrl);connectionLatch = new CountDownLatch(1);webSocketClient = new WebSocketClient(serverUri) {@Overridepublic void onOpen(ServerHandshake handshake) {logger.info("WebSocket连接已建立");connectionLatch.countDown();}@Overridepublic void onMessage(String message) {try {handleMessage(message);} catch (Exception e) {logger.error("处理WebSocket消息时出错", e);}}@Overridepublic void onClose(int code, String reason, boolean remote) {logger.info("WebSocket连接已关闭: code={}, reason={}, remote={}", code, reason, remote);}@Overridepublic void onError(Exception ex) {logger.error("WebSocket连接错误", ex);}};webSocketClient.connect();// 等待连接建立if (!connectionLatch.await(10, TimeUnit.SECONDS)) {throw new RuntimeException("WebSocket连接超时");}}/*** 处理收到的消息*/private void handleMessage(String message) throws Exception {JsonNode jsonNode = objectMapper.readTree(message);// 解析实时行情数据if (jsonNode.has("pid")) {RealTimeData realTimeData = objectMapper.treeToValue(jsonNode, RealTimeData.class);onRealTimeData(realTimeData);} else {logger.info("收到消息: {}", message);}}/*** 处理实时行情数据 - 需要子类重写*/protected void onRealTimeData(RealTimeData data) {logger.info("实时行情: {} - 最新价: {}, 涨跌幅: {}%", data.getPid(), data.getLastNumeric(), data.getPcp());}/*** 发送消息*/public void sendMessage(String message) {if (webSocketClient != null && webSocketClient.isOpen()) {webSocketClient.send(message);}}/*** 关闭连接*/public void close() {if (webSocketClient != null) {webSocketClient.close();}}/*** 实时数据模型*/public static class RealTimeData {private String pid;private String lastNumeric;private String bid;private String ask;private String high;private String low;private String lastClose;private String pc;private String pcp;private String turnoverNumeric;private String time;private String timestamp;private Integer type;// Getters and Setterspublic String getPid() { return pid; }public void setPid(String pid) { this.pid = pid; }public String getLastNumeric() { return lastNumeric; }public void setLastNumeric(String lastNumeric) { this.lastNumeric = lastNumeric; }public String getBid() { return bid; }public void setBid(String bid) { this.bid = bid; }public String getAsk() { return ask; }public void setAsk(String ask) { this.ask = ask; }public String getHigh() { return high; }public void setHigh(String high) { this.high = high; }public String getLow() { return low; }public void setLow(String low) { this.low = low; }public String getLastClose() { return lastClose; }public void setLastClose(String lastClose) { this.lastClose = lastClose; }public String getPc() { return pc; }public void setPc(String pc) { this.pc = pc; }public String getPcp() { return pcp; }public void setPcp(String pcp) { this.pcp = pcp; }public String getTurnoverNumeric() { return turnoverNumeric; }public void setTurnoverNumeric(String turnoverNumeric) { this.turnoverNumeric = turnoverNumeric; }public String getTime() { return time; }public void setTime(String time) { this.time = time; }public String getTimestamp() { return timestamp; }public void setTimestamp(String timestamp) { this.timestamp = timestamp; }public Integer getType() { return type; }public void setType(Integer type) { this.type = type; }}
}

6. 服务类

package com.stocktv.india.service;import com.stocktv.india.client.StockTVHttpClient;
import com.stocktv.india.client.StockTVWebSocketClient;
import com.stocktv.india.config.StockTVConfig;
import com.stocktv.india.model.Index;
import com.stocktv.india.model.KLine;
import com.stocktv.india.model.Stock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.List;public class IndiaStockService {private static final Logger logger = LoggerFactory.getLogger(IndiaStockService.class);private final StockTVHttpClient httpClient;private final StockTVWebSocketClient webSocketClient;public IndiaStockService(String apiKey) {StockTVConfig config = new StockTVConfig(apiKey);this.httpClient = new StockTVHttpClient(config);this.webSocketClient = new StockTVWebSocketClient(config);}/*** 获取Nifty 50成分股*/public List<Stock> getNifty50Stocks() {try {// 获取前50只股票(实际应该根据Nifty 50成分股列表查询)return httpClient.getIndiaStocks(50, 1);} catch (Exception e) {logger.error("获取Nifty 50成分股失败", e);throw new RuntimeException(e);}}/*** 获取印度主要指数*/public List<Index> getMajorIndices() {try {return httpClient.getIndiaIndices();} catch (Exception e) {logger.error("获取印度指数失败", e);throw new RuntimeException(e);}}/*** 查询特定股票*/public List<Stock> getStockBySymbol(String symbol) {try {return httpClient.queryStock(null, symbol, null);} catch (Exception e) {logger.error("查询股票失败: " + symbol, e);throw new RuntimeException(e);}}/*** 获取股票K线数据*/public List<KLine> getStockKLine(Long pid, String interval) {try {return httpClient.getKLineData(pid, interval);} catch (Exception e) {logger.error("获取K线数据失败: pid=" + pid, e);throw new RuntimeException(e);}}/*** 获取涨幅榜*/public List<Stock> getGainers() {try {return httpClient.getUpDownList(1); // 1表示涨幅榜} catch (Exception e) {logger.error("获取涨幅榜失败", e);throw new RuntimeException(e);}}/*** 启动实时数据监听*/public void startRealTimeMonitoring() {try {webSocketClient.connect();logger.info("实时数据监听已启动");} catch (Exception e) {logger.error("启动实时数据监听失败", e);throw new RuntimeException(e);}}/*** 停止实时数据监听*/public void stopRealTimeMonitoring() {webSocketClient.close();logger.info("实时数据监听已停止");}
}

7. 使用示例

package com.stocktv.india.demo;import com.stocktv.india.service.IndiaStockService;
import com.stocktv.india.client.StockTVWebSocketClient;
import com.stocktv.india.model.Index;
import com.stocktv.india.model.KLine;
import com.stocktv.india.model.Stock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.List;public class IndiaStockDemo {private static final Logger logger = LoggerFactory.getLogger(IndiaStockDemo.class);public static void main(String[] args) {// 替换为实际的 API KeyString apiKey = "您的API_KEY";IndiaStockService stockService = new IndiaStockService(apiKey);try {// 1. 获取印度主要指数logger.info("=== 印度主要指数 ===");List<Index> indices = stockService.getMajorIndices();indices.forEach(index -> logger.info("{}: {} ({}{}%)", index.getName(), index.getLastPrice(), index.getChange().doubleValue() > 0 ? "+" : "", index.getChangePercent()));// 2. 获取Nifty 50成分股logger.info("\n=== Nifty 50成分股(示例)===");List<Stock> niftyStocks = stockService.getNifty50Stocks();niftyStocks.stream().limit(10).forEach(stock -> logger.info("{} ({}) : {} INR, 涨跌幅: {}%", stock.getSymbol(), stock.getName(), stock.getLastPrice(), stock.getChangePercent()));// 3. 查询特定股票logger.info("\n=== 查询RELIANCE股票 ===");List<Stock> relianceStock = stockService.getStockBySymbol("RELIANCE");if (!relianceStock.isEmpty()) {Stock stock = relianceStock.get(0);logger.info("Reliance Industries: {} INR, 成交量: {}", stock.getLastPrice(), stock.getVolume());}// 4. 获取K线数据logger.info("\n=== RELIANCE日K线数据 ===");if (!relianceStock.isEmpty()) {Long pid = relianceStock.get(0).getId();List<KLine> kLines = stockService.getStockKLine(pid, "P1D");kLines.stream().limit(5).forEach(kLine -> logger.info("时间: {}, 开: {}, 高: {}, 低: {}, 收: {}", kLine.getTimestamp(), kLine.getOpen(), kLine.getHigh(), kLine.getLow(), kLine.getClose()));}// 5. 获取涨幅榜logger.info("\n=== 今日涨幅榜 ===");List<Stock> gainers = stockService.getGainers();gainers.stream().limit(5).forEach(stock -> logger.info("{}: {} INR, 涨幅: {}%", stock.getSymbol(), stock.getLastPrice(), stock.getChangePercent()));// 6. 启动实时数据监听(可选)logger.info("\n=== 启动实时数据监听 ===");// stockService.startRealTimeMonitoring();// 保持程序运行一段时间Thread.sleep(30000);// 停止实时数据监听// stockService.stopRealTimeMonitoring();} catch (Exception e) {logger.error("演示程序执行失败", e);}}
}

8. 自定义实时数据处理

如果需要自定义实时数据处理逻辑,可以继承 StockTVWebSocketClient

package com.stocktv.india.custom;import com.stocktv.india.client.StockTVWebSocketClient;
import com.stocktv.india.config.StockTVConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class CustomWebSocketClient extends StockTVWebSocketClient {private static final Logger logger = LoggerFactory.getLogger(CustomWebSocketClient.class);public CustomWebSocketClient(StockTVConfig config) {super(config);}@Overrideprotected void onRealTimeData(RealTimeData data) {// 自定义实时数据处理逻辑if ("7310".equals(data.getPid())) { // RELIANCE的PIDlogger.info("RELIANCE实时行情 - 价格: {}, 涨跌幅: {}%, 成交量: {}", data.getLastNumeric(), data.getPcp(), data.getTurnoverNumeric());}// 可以在这里添加交易逻辑、报警逻辑等if (Double.parseDouble(data.getPcp()) > 5.0) {logger.warn("股票 {} 涨幅超过5%: {}%", data.getPid(), data.getPcp());}}
}

9. 配置说明

时间间隔参数

  • PT5M - 5分钟K线
  • PT15M - 15分钟K线
  • PT1H - 1小时K线
  • P1D - 日K线
  • P1W - 周K线
  • P1M - 月K线

排行榜类型

  • 1 - 涨幅榜
  • 2 - 跌幅榜
  • 3 - 涨停榜
  • 4 - 跌停榜

10. 注意事项

  1. API Key管理: 建议从配置文件或环境变量读取API Key
  2. 错误处理: 所有API调用都需要适当的异常处理
  3. 频率限制: 注意API的调用频率限制
  4. 连接管理: WebSocket连接需要处理重连逻辑
  5. 数据缓存: 对于不经常变化的数据可以实施缓存

这个完整的Java实现提供了对接印度股票数据源的所有核心功能,可以根据具体需求进行扩展和优化。

http://www.dtcms.com/a/494642.html

相关文章:

  • 建设网站分析报告陕西四通建设工程有限责任公司网站
  • 微信网站建设app公司WordPress邮箱注册慢
  • 【Qt】元对象系统:从实际开发中看QML/C++交互原理
  • 【MySQL】从零开始了解数据库开发 --- 数据表的索引
  • 设计模式篇之 策略模式 Strategy
  • 【HarmonyOS】并发线程间的通信
  • 2三、buildroot
  • 开源 C++ QT QML 开发(二十二)多媒体--ffmpeg编码和录像
  • 详细分析平衡树--红黑树(万字长文/图文详解)
  • 国产开源代码管理工具 GitPuk 安装+入门全流程解析
  • wordpress本地视频教程免费网站seo优化
  • 前端布局入门:flex、grid 及其他常用布局
  • Excel中将毫秒时间戳转换为标准时间格式
  • 传奇网站模板免费下载建立网站需要多少钱费用
  • 第2讲:Go内存管理机制深度解析
  • 【解决】mayfly-go 容器启动失败 —— failed to connect to mysql!
  • 基于STM32低功耗授时系统的硬件电路设计-上
  • 嵌入式软件架构--多窗口显示1(后台软件实现)
  • 牛商网网站建设企业网站开发建设
  • 软件供应链安全的革命:深度解析链图·SBOM管理服务平台的技术突破
  • QChart控件:图例QLegend
  • 【活动预告】2025斗拱开发者大会,共探支付与AI未来
  • 开源Filestash 搭建“多合一”文件管理器
  • Web3.0的底层引擎
  • 建设一个手机网站怎么制作网站生成图片
  • QEMU:如何组织与 I2C 设备的透明交互
  • 精密电子东莞网站建设技术支持视频网站建设类图
  • AI+大数据时代:从架构重构看时序数据库的价值释放——关键概念、核心技巧与代码实践
  • CoRL-2025 | VLM赋能高阶推理导航!ReasonNav:在人类世界中实现与人类一致的导航
  • ARM开发板基础与文件传输