对接印度股票数据获取印度股市列表、查询特定股票行情以及 K 线历史数据

0 阅读3分钟

本代码采用 Spring Boot 3.x + OkHttp3 + Jackson 技术栈,重点展示了如何获取印度股市列表、查询特定股票行情以及 K 线历史数据。代码遵循生产级规范,包含完整的异常处理、配置分离和详细注释。

1. 核心数据模型 (POJO)

首先定义通用的响应结构和股票行情数据模型。

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import java.util.List;

/**
 * 通用响应包装类
 */
@Data
public class ApiResponse<T> {
    private int code;
    private String message;
    private T data;
}

/**
 * 股票行情数据模型
 */
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class StockQuote {
    private Long id;           // 产品唯一标识 (PID)
    private String name;       // 股票名称
    private String symbol;     // 股票代码
    private Double last;       // 最新价
    private Double high;       // 最高价
    private Double low;        // 最低价
    private Double chg;        // 涨跌额
    private Double chgPct;     // 涨跌百分比
    private Long time;         // 时间戳
    private String flag;       // 国家简称 (印度为 IN)
    private Integer countryId; // 国家ID (印度为 14)
}

/**
 * K线数据模型
 */
@Data
public class KlineData {
    private Long time;
    private Double open;
    private Double high;
    private Double low;
    private Double close;
    private Long volume;
}

2. 业务服务类 (Service)

封装 OkHttp 调用逻辑,专门针对印度市场(countryId=14)进行优化。

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

@Service
public class IndiaStockService {

    private final OkHttpClient httpClient;
    private final ObjectMapper objectMapper;
    
    // 配置参数
    private static final String BASE_URL = "https://api.stocktv.top";
    private static final String API_KEY = "您的API_KEY"; // 请联系官方获取
    private static final String INDIA_COUNTRY_ID = "14"; // 印度国家标识

    public IndiaStockService(OkHttpClient httpClient, ObjectMapper objectMapper) {
        this.httpClient = httpClient;
        this.objectMapper = objectMapper;
    }

    /**
     * 获取印度股市列表
     * @param page 页码
     * @param size 每页数量
     */
    public List<StockQuote> getIndiaMarketList(int page, int size) {
        HttpUrl url = HttpUrl.parse(BASE_URL + "/stock/stocks").newBuilder()
                .addQueryParameter("countryId", INDIA_COUNTRY_ID)
                .addQueryParameter("page", String.valueOf(page))
                .addQueryParameter("pageSize", String.valueOf(size))
                .addQueryParameter("key", API_KEY)
                .build();

        return executeRequest(url, new TypeReference<ApiResponse<PaginationData<StockQuote>>>() {})
                .map(res -> res.getData().getRecords())
                .orElse(Collections.emptyList());
    }

    /**
     * 获取 K 线历史数据
     * @param pid 股票产品ID
     * @param interval 时间周期 (PT1M, PT1H, P1D 等)
     */
    public List<KlineData> getStockKline(Long pid, String interval) {
        HttpUrl url = HttpUrl.parse(BASE_URL + "/stock/kline").newBuilder()
                .addQueryParameter("pid", String.valueOf(pid))
                .addQueryParameter("interval", interval)
                .addQueryParameter("key", API_KEY)
                .build();

        return executeRequest(url, new TypeReference<ApiResponse<List<KlineData>>>() {})
                .map(ApiResponse::getData)
                .orElse(Collections.emptyList());
    }

    /**
     * 通用 HTTP 请求执行与异常处理
     */
    private <T> java.util.Optional<T> executeRequest(HttpUrl url, TypeReference<T> typeReference) {
        Request request = new Request.Builder().url(url).get().build();
        
        try (Response response = httpClient.newCall(request).execute()) {
            if (!response.isSuccessful() || response.body() == null) {
                // 此处应接入日志系统记录错误
                return java.util.Optional.empty();
            }
            
            String body = response.body().string();
            return java.util.Optional.ofNullable(objectMapper.readValue(body, typeReference));
        } catch (IOException e) {
            // 异常处理逻辑,如重试或报警
            e.printStackTrace();
            return java.util.Optional.empty();
        }
    }
}

3. 技术要点说明

  1. 参数规范化:针对印度市场,代码中硬编码了 countryId = 14,确保所有请求均精准定位到印度证券交易所(NSE/BSE)的数据。
  2. 资源管理:使用 Java 7+ 的 try-with-resources 确保 Response 对象在使用完毕后及时关闭,防止 Socket 连接泄漏。
  3. 健壮性
  • 引入 Jackson@JsonIgnoreProperties(ignoreUnknown = true),避免 API 升级增加新字段时导致反序列化崩溃。
  • 通过 ApiResponse<T> 统一处理 API 的业务状态码(code: 200)。
  1. 可扩展性:提供了通用的 executeRequest 私有方法,方便后续快速增加“涨跌榜”、“IPO日历”等新接口的对接。

4. 快速运行建议

  • 依赖:在 pom.xml 中添加 okhttp (4.x), jackson-databind, 和 lombok
  • Key 获取:必须联系 API 提供方获取有效的 key,否则请求将返回认证失败。
  • 频率限制:生产环境下建议对调用增加速率限制(Rate Limiting),并针对行情数据增加本地缓存(如 Redis),以减少 API 消耗和提升响应速度。