国际期货、黄金、石油数据 Java 对接文档
📋 文档概述
本文档详细介绍如何使用 Java 语言对接 StockTV 国际期货、黄金、石油等大宗商品数据源,包含完整的代码示例、数据模型和实时监控功能。
🚀 快速开始
环境要求
- JDK 8+
- Maven 3.6+
- 网络连接(可访问
api.stocktv.top)
项目依赖
<!-- 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>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
</dependencies>
🏗️ 核心架构
项目结构
src/main/java/com/stocktv/futures/
├── config/
│ └── FuturesConfig.java
├── model/
│ ├── FuturesContract.java
│ ├── CommodityData.java
│ ├── KLine.java
│ └── ApiResponse.java
├── client/
│ ├── FuturesHttpClient.java
│ ├── MarketHttpClient.java
│ └── FuturesWebSocketClient.java
├── service/
│ └── FuturesDataService.java
└── demo/
└── FuturesDemo.java
📦 核心代码实现
1. 配置类
package com.stocktv.futures.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
/**
* 期货数据配置类
*/
public class FuturesConfig {
// 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 String FUTURES_LIST = "/futures/list";
public static final String FUTURES_QUERY = "/futures/querySymbol";
public static final String FUTURES_KLINE = "/futures/kline";
// 外汇市场接口路径
public static final String MARKET_CURRENCY_LIST = "/market/currencyList";
public static final String MARKET_CURRENCY = "/market/currency";
public static final String MARKET_TODAY = "/market/todayMarket";
public static final String MARKET_CHART = "/market/chart";
public static final String MARKET_SPARK = "/market/spark";
// 主要商品代码
public static final String GOLD_SPOT = "XAUUSD=X";
public static final String SILVER_SPOT = "XAGUSD=X";
public static final String CRUDE_OIL = "CL=F";
public static final String BRENT_OIL = "BZ=F";
public static final String NATURAL_GAS = "NG=F";
public static final String COPPER = "HG=F";
// API Key
private final String apiKey;
// HTTP 客户端和JSON处理器
private final CloseableHttpClient httpClient;
private final ObjectMapper objectMapper;
public FuturesConfig(String apiKey) {
this.apiKey = apiKey;
this.httpClient = HttpClients.createDefault();
this.objectMapper = new ObjectMapper();
this.objectMapper.findAndRegisterModules();
}
// Getter方法
public String getApiKey() { return apiKey; }
public CloseableHttpClient getHttpClient() { return httpClient; }
public ObjectMapper getObjectMapper() { return objectMapper; }
}
2. 数据模型类
期货合约数据模型
package com.stocktv.futures.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 期货合约数据模型
*/
@Data
public class FuturesContract {
@JsonProperty("date")
private String date;
@JsonProperty("symbol")
private String symbol;
@JsonProperty("buy")
private BigDecimal buy;
@JsonProperty("sell")
private BigDecimal sell;
@JsonProperty("high_price")
private BigDecimal highPrice;
@JsonProperty("prev_price")
private BigDecimal previousPrice;
@JsonProperty("volume")
private BigDecimal volume;
@JsonProperty("name")
private String name;
@JsonProperty("time")
private String time;
@JsonProperty("low_price")
private BigDecimal lowPrice;
@JsonProperty("open_price")
private BigDecimal openPrice;
@JsonProperty("last_price")
private BigDecimal lastPrice;
@JsonProperty("chg")
private BigDecimal change;
@JsonProperty("chg_pct")
private BigDecimal changePercent;
/**
* 获取商品类型
*/
public CommodityType getCommodityType() {
if (symbol.contains("XAU")) return CommodityType.GOLD;
if (symbol.contains("XAG")) return CommodityType.SILVER;
if (symbol.contains("CL")) return CommodityType.CRUDE_OIL;
if (symbol.contains("NG")) return CommodityType.NATURAL_GAS;
if (symbol.contains("HG")) return CommodityType.COPPER;
return CommodityType.OTHER;
}
}
/**
* 商品类型枚举
*/
enum CommodityType {
GOLD("黄金"),
SILVER("白银"),
CRUDE_OIL("原油"),
BRENT_OIL("布伦特原油"),
NATURAL_GAS("天然气"),
COPPER("铜"),
OTHER("其他");
private final String chineseName;
CommodityType(String chineseName) {
this.chineseName = chineseName;
}
public String getChineseName() {
return chineseName;
}
}
商品现货数据模型
package com.stocktv.futures.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 商品现货数据模型
*/
@Data
public class CommodityData {
@JsonProperty("symbol")
private String symbol;
@JsonProperty("chg")
private String change;
@JsonProperty("chgPct")
private String changePercent;
@JsonProperty("name")
private String name;
@JsonProperty("lastPrice")
private String lastPrice;
// 今日市场数据
@JsonProperty("previous_close")
private String previousClose;
@JsonProperty("ask")
private String ask;
@JsonProperty("52week_range")
private String week52Range;
@JsonProperty("bid")
private String bid;
@JsonProperty("open")
private String open;
@JsonProperty("day_trange")
private String dayRange;
/**
* 获取数值形式的最后价格
*/
public BigDecimal getNumericLastPrice() {
try {
return new BigDecimal(lastPrice.replace("+", "").replace("%", ""));
} catch (Exception e) {
return BigDecimal.ZERO;
}
}
/**
* 获取数值形式的涨跌幅
*/
public BigDecimal getNumericChangePercent() {
try {
return new BigDecimal(changePercent.replace("+", "").replace("%", ""));
} catch (Exception e) {
return BigDecimal.ZERO;
}
}
}
K线数据模型
package com.stocktv.futures.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* K线数据模型(期货专用)
*/
@Data
public class FuturesKLine {
@JsonProperty("date")
private String date;
@JsonProperty("volume")
private Integer volume;
@JsonProperty("high")
private BigDecimal high;
@JsonProperty("s")
private String s;
@JsonProperty("low")
private BigDecimal low;
@JsonProperty("position")
private Integer position;
@JsonProperty("close")
private BigDecimal close;
@JsonProperty("open")
private BigDecimal open;
@JsonProperty("timestamp")
private Double timestamp;
/**
* 计算振幅
*/
public BigDecimal getAmplitude() {
if (open == null || open.compareTo(BigDecimal.ZERO) == 0) {
return BigDecimal.ZERO;
}
return high.subtract(low).divide(open, 4, BigDecimal.ROUND_HALF_UP)
.multiply(BigDecimal.valueOf(100));
}
}
API响应包装类
package com.stocktv.futures.model;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
* API通用响应包装类
*/
@Data
public class ApiResponse<T> {
@JsonProperty("code")
private Integer code;
@JsonProperty("message")
private String message;
@JsonProperty("data")
private T data;
/**
* 判断请求是否成功
*/
public boolean isSuccess() {
return code != null && code == 200;
}
}
/**
* 汇率转换数据
*/
@Data
class CurrencyConversionData {
@JsonProperty("conversions")
private Map<String, Map<String, BigDecimal>> conversions;
@JsonProperty("generatedAt")
private String generatedAt;
@JsonProperty("dataAsOf")
private String dataAsOf;
}
3. HTTP客户端实现
期货HTTP客户端
package com.stocktv.futures.client;
import com.fasterxml.jackson.core.type.TypeReference;
import com.stocktv.futures.config.FuturesConfig;
import com.stocktv.futures.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;
/**
* 期货数据HTTP客户端
*/
public class FuturesHttpClient {
private static final Logger logger = LoggerFactory.getLogger(FuturesHttpClient.class);
private final FuturesConfig config;
private final CloseableHttpClient httpClient;
public FuturesHttpClient(FuturesConfig config) {
this.config = config;
this.httpClient = config.getHttpClient();
}
/**
* 获取期货市场列表
*/
public List<FuturesContract> getFuturesList() throws IOException, URISyntaxException {
URI uri = new URIBuilder(config.BASE_URL + config.FUTURES_LIST)
.addParameter("key", config.getApiKey())
.build();
ApiResponse<List<FuturesContract>> response = executeGetRequest(uri,
new TypeReference<ApiResponse<List<FuturesContract>>>() {});
if (response.isSuccess()) {
logger.info("成功获取 {} 个期货合约", response.getData().size());
return response.getData();
} else {
throw new RuntimeException("获取期货列表失败: " + response.getMessage());
}
}
/**
* 查询特定期货品种
*/
public List<FuturesContract> queryFuturesSymbol(String symbol) throws IOException, URISyntaxException {
URI uri = new URIBuilder(config.BASE_URL + config.FUTURES_QUERY)
.addParameter("key", config.getApiKey())
.addParameter("symbol", symbol)
.build();
ApiResponse<List<FuturesContract>> response = executeGetRequest(uri,
new TypeReference<ApiResponse<List<FuturesContract>>>() {});
if (response.isSuccess()) {
logger.info("成功查询期货品种: {}", symbol);
return response.getData();
} else {
throw new RuntimeException("查询期货品种失败: " + response.getMessage());
}
}
/**
* 获取期货K线数据
*/
public List<FuturesKLine> getFuturesKLine(String symbol, String interval) throws IOException, URISyntaxException {
URI uri = new URIBuilder(config.BASE_URL + config.FUTURES_KLINE)
.addParameter("key", config.getApiKey())
.addParameter("symbol", symbol)
.addParameter("interval", interval)
.build();
ApiResponse<List<FuturesKLine>> response = executeGetRequest(uri,
new TypeReference<ApiResponse<List<FuturesKLine>>>() {});
if (response.isSuccess()) {
logger.info("成功获取期货 {} 的K线数据,共 {} 条", symbol, response.getData().size());
return response.getData();
} else {
throw new RuntimeException("获取期货K线数据失败: " + response.getMessage());
}
}
/**
* 通用GET请求执行方法
*/
private <T> T executeGetRequest(URI uri, TypeReference<T> typeReference) throws IOException {
HttpGet request = new HttpGet(uri);
logger.debug("执行期货API请求: {}", uri);
try (CloseableHttpResponse response = httpClient.execute(request)) {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
if (statusCode != 200) {
throw new IOException("HTTP请求失败,状态码: " + statusCode);
}
logger.debug("期货API响应: {}", responseBody);
return config.getObjectMapper().readValue(responseBody, typeReference);
}
}
/**
* 关闭HTTP客户端
*/
public void close() throws IOException {
if (httpClient != null) {
httpClient.close();
}
}
}
外汇市场HTTP客户端
package com.stocktv.futures.client;
import com.fasterxml.jackson.core.type.TypeReference;
import com.stocktv.futures.config.FuturesConfig;
import com.stocktv.futures.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;
import java.util.Map;
/**
* 外汇市场数据HTTP客户端
*/
public class MarketHttpClient {
private static final Logger logger = LoggerFactory.getLogger(MarketHttpClient.class);
private final FuturesConfig config;
private final CloseableHttpClient httpClient;
public MarketHttpClient(FuturesConfig config) {
this.config = config;
this.httpClient = config.getHttpClient();
}
/**
* 获取全球汇率列表
*/
public CurrencyConversionData getCurrencyList() throws IOException, URISyntaxException {
URI uri = new URIBuilder(config.BASE_URL + config.MARKET_CURRENCY_LIST)
.addParameter("key", config.getApiKey())
.build();
ApiResponse<CurrencyConversionData> response = executeGetRequest(uri,
new TypeReference<ApiResponse<CurrencyConversionData>>() {});
if (response.isSuccess()) {
logger.info("成功获取汇率数据");
return response.getData();
} else {
throw new RuntimeException("获取汇率列表失败: " + response.getMessage());
}
}
/**
* 获取实时汇率列表
*/
public List<CommodityData> getCurrencyRates(String countryType) throws IOException, URISyntaxException {
URIBuilder uriBuilder = new URIBuilder(config.BASE_URL + config.MARKET_CURRENCY)
.addParameter("key", config.getApiKey());
if (countryType != null) {
uriBuilder.addParameter("countryType", countryType);
}
URI uri = uriBuilder.build();
ApiResponse<List<CommodityData>> response = executeGetRequest(uri,
new TypeReference<ApiResponse<List<CommodityData>>>() {});
if (response.isSuccess()) {
logger.info("成功获取 {} 个汇率数据", response.getData().size());
return response.getData();
} else {
throw new RuntimeException("获取实时汇率失败: " + response.getMessage());
}
}
/**
* 获取当前商品信息(黄金、原油等)
*/
public CommodityData getTodayMarket(String symbol) throws IOException, URISyntaxException {
URI uri = new URIBuilder(config.BASE_URL + config.MARKET_TODAY)
.addParameter("key", config.getApiKey())
.addParameter("symbol", symbol)
.build();
ApiResponse<CommodityData> response = executeGetRequest(uri,
new TypeReference<ApiResponse<CommodityData>>() {});
if (response.isSuccess()) {
logger.info("成功获取商品数据: {}", symbol);
return response.getData();
} else {
throw new RuntimeException("获取商品信息失败: " + response.getMessage());
}
}
/**
* 获取K线图表数据
*/
public Object getChartData(String symbol, String interval) throws IOException, URISyntaxException {
URI uri = new URIBuilder(config.BASE_URL + config.MARKET_CHART)
.addParameter("key", config.getApiKey())
.addParameter("symbol", symbol)
.addParameter("interval", interval)
.build();
// 由于chart接口返回复杂结构,直接返回Object
ApiResponse<Object> response = executeGetRequest(uri,
new TypeReference<ApiResponse<Object>>() {});
if (response.isSuccess()) {
logger.info("成功获取图表数据: {}", symbol);
return response.getData();
} else {
throw new RuntimeException("获取图表数据失败: " + response.getMessage());
}
}
/**
* 获取汇率信息详情
*/
public Object getSparkData(String symbol, String interval) throws IOException, URISyntaxException {
URI uri = new URIBuilder(config.BASE_URL + config.MARKET_SPARK)
.addParameter("key", config.getApiKey())
.addParameter("symbol", symbol)
.addParameter("interval", interval)
.build();
ApiResponse<Object> response = executeGetRequest(uri,
new TypeReference<ApiResponse<Object>>() {});
if (response.isSuccess()) {
logger.info("成功获取汇率详情: {}", symbol);
return response.getData();
} else {
throw new RuntimeException("获取汇率详情失败: " + response.getMessage());
}
}
/**
* 通用GET请求执行方法
*/
private <T> T executeGetRequest(URI uri, TypeReference<T> typeReference) throws IOException {
HttpGet request = new HttpGet(uri);
logger.debug("执行市场API请求: {}", uri);
try (CloseableHttpResponse response = httpClient.execute(request)) {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
if (statusCode != 200) {
throw new IOException("HTTP请求失败,状态码: " + statusCode);
}
logger.debug("市场API响应: {}", responseBody);
return config.getObjectMapper().readValue(responseBody, typeReference);
}
}
/**
* 关闭HTTP客户端
*/
public void close() throws IOException {
if (httpClient != null) {
httpClient.close();
}
}
}
4. 服务层封装
package com.stocktv.futures.service;
import com.stocktv.futures.client.FuturesHttpClient;
import com.stocktv.futures.client.FuturesWebSocketClient;
import com.stocktv.futures.client.MarketHttpClient;
import com.stocktv.futures.config.FuturesConfig;
import com.stocktv.futures.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.stream.Collectors;
/**
* 期货数据服务
*/
public class FuturesDataService {
private static final Logger logger = LoggerFactory.getLogger(FuturesDataService.class);
private final FuturesHttpClient futuresClient;
private final MarketHttpClient marketClient;
private final FuturesWebSocketClient wsClient;
private final FuturesConfig config;
public FuturesDataService(String apiKey) {
this.config = new FuturesConfig(apiKey);
this.futuresClient = new FuturesHttpClient(config);
this.marketClient = new MarketHttpClient(config);
this.wsClient = new FuturesWebSocketClient(config);
}
/**
* 获取所有期货合约列表
*/
public List<FuturesContract> getAllFutures() {
try {
List<FuturesContract> futures = futuresClient.getFuturesList();
logger.info("成功获取 {} 个期货合约", futures.size());
return futures;
} catch (Exception e) {
logger.error("获取期货列表失败", e);
throw new RuntimeException("获取期货列表失败", e);
}
}
/**
* 获取贵金属期货数据
*/
public List<FuturesContract> getPreciousMetalsFutures() {
try {
List<FuturesContract> allFutures = getAllFutures();
return allFutures.stream()
.filter(f -> f.getCommodityType() == CommodityType.GOLD ||
f.getCommodityType() == CommodityType.SILVER)
.collect(Collectors.toList());
} catch (Exception e) {
logger.error("获取贵金属期货失败", e);
throw new RuntimeException("获取贵金属期货失败", e);
}
}
/**
* 获取能源期货数据
*/
public List<FuturesContract> getEnergyFutures() {
try {
List<FuturesContract> allFutures = getAllFutures();
return allFutures.stream()
.filter(f -> f.getCommodityType() == CommodityType.CRUDE_OIL ||
f.getCommodityType() == CommodityType.NATURAL_GAS)
.collect(Collectors.toList());
} catch (Exception e) {
logger.error("获取能源期货失败", e);
throw new RuntimeException("获取能源期货失败", e);
}
}
/**
* 获取黄金现货价格
*/
public CommodityData getGoldSpotPrice() {
try {
CommodityData goldData = marketClient.getTodayMarket(FuturesConfig.GOLD_SPOT);
logger.info("成功获取黄金现货价格: {}", goldData.getLastPrice());
return goldData;
} catch (Exception e) {
logger.error("获取黄金现货价格失败", e);
throw new RuntimeException("获取黄金现货价格失败", e);
}
}
/**
* 获取原油现货价格
*/
public CommodityData getCrudeOilPrice() {
try {
CommodityData oilData = marketClient.getTodayMarket(FuturesConfig.CRUDE_OIL);
logger.info("成功获取原油价格: {}", oilData.getLastPrice());
return oilData;
} catch (Exception e) {
logger.error("获取原油价格失败", e);
throw new RuntimeException("获取原油价格失败", e);
}
}
/**
* 获取主要商品价格
*/
public void getMajorCommoditiesPrices() {
try {
List<CommodityData> commodities = marketClient.getCurrencyRates(null);
List<CommodityData> majorCommodities = commodities.stream()
.filter(c -> c.getSymbol().contains("XAU") ||
c.getSymbol().contains("XAG") ||
c.getSymbol().contains("CL") ||
c.getSymbol().contains("NG"))
.collect(Collectors.toList());
logger.info("获取 {} 个主要商品价格", majorCommodities.size());
majorCommodities.forEach(this::logCommodityPrice);
} catch (Exception e) {
logger.error("获取主要商品价格失败", e);
throw new RuntimeException("获取主要商品价格失败", e);
}
}
/**
* 获取期货K线数据
*/
public List<FuturesKLine> getFuturesKLineData(String symbol, String interval) {
try {
List<FuturesKLine> klines = futuresClient.getFuturesKLine(symbol, interval);
logger.info("成功获取 {} 的K线数据,共 {} 条", symbol, klines.size());
return klines;
} catch (Exception e) {
logger.error("获取期货K线数据失败: {}", symbol, e);
throw new RuntimeException("获取期货K线数据失败: " + symbol, e);
}
}
/**
* 启动实时数据监控
*/
public void startRealTimeMonitoring() {
try {
wsClient.connect();
logger.info("期货实时数据监控已启动");
} catch (Exception e) {
logger.error("启动实时数据监控失败", e);
throw new RuntimeException("启动实时数据监控失败", e);
}
}
/**
* 停止实时数据监控
*/
public void stopRealTimeMonitoring() {
wsClient.close();
logger.info("期货实时数据监控已停止");
}
/**
* 记录商品价格
*/
private void logCommodityPrice(CommodityData commodity) {
String trend = commodity.getChangePercent().contains("+") ? "📈" : "📉";
logger.info("{} {}: {} ({})",
trend, commodity.getName(), commodity.getLastPrice(), commodity.getChangePercent());
}
/**
* 关闭服务
*/
public void close() {
try {
futuresClient.close();
marketClient.close();
wsClient.close();
logger.info("FuturesDataService已关闭");
} catch (Exception e) {
logger.error("关闭服务时发生错误", e);
}
}
}
6. 使用示例
package com.stocktv.futures.demo;
import com.stocktv.futures.model.CommodityData;
import com.stocktv.futures.model.FuturesContract;
import com.stocktv.futures.model.FuturesKLine;
import com.stocktv.futures.service.FuturesDataService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* 期货数据使用示例
*/
public class FuturesDemo {
private static final Logger logger = LoggerFactory.getLogger(FuturesDemo.class);
public static void main(String[] args) {
// 替换为您的实际 API Key
String apiKey = "您的API_KEY";
FuturesDataService futuresService = new FuturesDataService(apiKey);
try {
logger.info("=== StockTV 期货数据演示程序开始 ===");
// 1. 获取期货合约列表
demonstrateFuturesList(futuresService);
// 2. 获取贵金属数据
demonstratePreciousMetals(futuresService);
// 3. 获取能源数据
demonstrateEnergyFutures(futuresService);
// 4. 获取现货价格
demonstrateSpotPrices(futuresService);
// 5. 获取K线数据
demonstrateKLineData(futuresService);
// 6. 启动实时监控(可选)
// demonstrateRealTimeMonitoring(futuresService);
logger.info("=== 演示程序执行完成 ===");
} catch (Exception e) {
logger.error("演示程序执行失败", e);
} finally {
// 关闭服务
futuresService.close();
}
}
/**
* 演示期货合约列表
*/
private static void demonstrateFuturesList(FuturesDataService service) {
logger.info("\n1. 期货合约列表");
List<FuturesContract> futures = service.getAllFutures();
// 显示前10个合约
futures.stream().limit(10).forEach(contract -> {
String trend = contract.getChangePercent().doubleValue() >= 0 ? "🟢" : "🔴";
logger.info("{} {}: {}{} ({}{}%) - {}",
trend, contract.getSymbol(), contract.getLastPrice(),
contract.getChange().doubleValue() >= 0 ? "↑" : "↓",
contract.getChangePercent().doubleValue() >= 0 ? "+" : "",
contract.getChangePercent(), contract.getName());
});
}
/**
* 演示贵金属数据
*/
private static void demonstratePreciousMetals(FuturesDataService service) {
logger.info("\n2. 贵金属期货");
List<FuturesContract> metals = service.getPreciousMetalsFutures();
metals.forEach(contract -> {
String trend = contract.getChangePercent().doubleValue() >= 0 ? "🟢" : "🔴";
logger.info("{} {}: {}{} ({}{}%)",
trend, contract.getName(), contract.getLastPrice(),
contract.getChange().doubleValue() >= 0 ? "↑" : "↓",
contract.getChangePercent().doubleValue() >= 0 ? "+" : "",
contract.getChangePercent());
});
}
/**
* 演示能源期货
*/
private static void demonstrateEnergyFutures(FuturesDataService service) {
logger.info("\n3. 能源期货");
List<FuturesContract> energy = service.getEnergyFutures();
energy.forEach(contract -> {
String trend = contract.getChangePercent().doubleValue() >= 0 ? "🟢" : "🔴";
logger.info("{} {}: {}{} ({}{}%) - 成交量: {}",
trend, contract.getName(), contract.getLastPrice(),
contract.getChange().doubleValue() >= 0 ? "↑" : "↓",
contract.getChangePercent().doubleValue() >= 0 ? "+" : "",
contract.getChangePercent(), contract.getVolume());
});
}
/**
* 演示现货价格
*/
private static void demonstrateSpotPrices(FuturesDataService service) {
logger.info("\n4. 现货价格");
// 获取黄金现货
CommodityData gold = service.getGoldSpotPrice();
printCommodityInfo(gold, "黄金现货");
// 获取原油现货
CommodityData oil = service.getCrudeOilPrice();
printCommodityInfo(oil, "原油现货");
// 获取主要商品
service.getMajorCommoditiesPrices();
}
/**
* 演示K线数据
*/
private static void demonstrateKLineData(FuturesDataService service) {
logger.info("\n5. K线数据示例");
// 获取黄金K线数据
List<FuturesKLine> goldKlines = service.getFuturesKLineData("XAU", "1");
if (!goldKlines.isEmpty()) {
logger.info("黄金期货近期K线数据:");
goldKlines.stream().limit(5).forEach(kline -> {
logger.info("时间: {}, 开: {}, 高: {}, 低: {}, 收: {}, 振幅: {}%",
kline.getDate(), kline.getOpen(), kline.getHigh(),
kline.getLow(), kline.getClose(), kline.getAmplitude());
});
}
}
/**
* 演示实时监控
*/
private static void demonstrateRealTimeMonitoring(FuturesDataService service) {
logger.info("\n6. 启动实时监控");
service.startRealTimeMonitoring();
// 监控30秒
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
service.stopRealTimeMonitoring();
}
/**
* 打印商品信息
*/
private static void printCommodityInfo(CommodityData commodity, String description) {
if (commodity != null) {
String trend = commodity.getChangePercent().contains("+") ? "📈" : "📉";
logger.info("{} {}: {}", trend, description, commodity.getLastPrice());
logger.info(" 涨跌: {} ({})", commodity.getChange(), commodity.getChangePercent());
if (commodity.getBid() != null) {
logger.info(" 买卖盘: {} / {}", commodity.getBid(), commodity.getAsk());
}
if (commodity.getDayRange() != null) {
logger.info(" 当日区间: {}", commodity.getDayRange());
}
}
}
}
🎯 高级功能
商品价格监控器
package com.stocktv.futures.advanced;
import com.stocktv.futures.model.CommodityData;
import com.stocktv.futures.model.FuturesContract;
import com.stocktv.futures.service.FuturesDataService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 商品价格监控器
*/
public class CommodityPriceMonitor {
private static final Logger logger = LoggerFactory.getLogger(CommodityPriceMonitor.class);
private final FuturesDataService futuresService;
private final ScheduledExecutorService scheduler;
private final Map<String, BigDecimal> priceAlerts;
private final Set<String> monitoredSymbols;
// 监控配置
private final long checkIntervalSeconds = 60;
private final double alertThresholdPercent = 2.0;
public CommodityPriceMonitor(String apiKey) {
this.futuresService = new FuturesDataService(apiKey);
this.scheduler = Executors.newScheduledThreadPool(1);
this.priceAlerts = new HashMap<>();
this.monitoredSymbols = new HashSet<>();
// 默认监控主要商品
initializeDefaultMonitors();
}
/**
* 初始化默认监控列表
*/
private void initializeDefaultMonitors() {
monitoredSymbols.add("XAU"); // 黄金
monitoredSymbols.add("XAG"); // 白银
monitoredSymbols.add("CL"); // 原油
monitoredSymbols.add("NG"); // 天然气
monitoredSymbols.add("HG"); // 铜
logger.info("初始化监控 {} 个商品", monitoredSymbols.size());
}
/**
* 添加价格预警
*/
public void addPriceAlert(String symbol, BigDecimal targetPrice) {
priceAlerts.put(symbol, targetPrice);
logger.info("添加价格预警: {} - {}", symbol, targetPrice);
}
/**
* 开始监控
*/
public void startMonitoring() {
logger.info("开始商品价格监控,检查间隔: {}秒", checkIntervalSeconds);
scheduler.scheduleAtFixedRate(this::checkPrices, 0, checkIntervalSeconds, TimeUnit.SECONDS);
}
/**
* 停止监控
*/
public void stopMonitoring() {
scheduler.shutdown();
futuresService.close();
logger.info("商品价格监控已停止");
}
/**
* 检查价格变化
*/
private void checkPrices() {
try {
List<FuturesContract> currentFutures = futuresService.getAllFutures();
for (FuturesContract futures : currentFutures) {
String symbol = futures.getSymbol();
if (monitoredSymbols.contains(symbol)) {
checkPriceAlert(futures);
checkVolatilityAlert(futures);
}
}
// 检查现货价格
checkSpotPrices();
} catch (Exception e) {
logger.error("价格监控执行失败", e);
}
}
/**
* 检查价格预警
*/
private void checkPriceAlert(FuturesContract futures) {
BigDecimal targetPrice = priceAlerts.get(futures.getSymbol());
if (targetPrice != null) {
BigDecimal currentPrice = futures.getLastPrice();
BigDecimal difference = currentPrice.subtract(targetPrice).abs();
BigDecimal differencePercent = difference.divide(targetPrice, 4, BigDecimal.ROUND_HALF_UP)
.multiply(BigDecimal.valueOf(100));
if (differencePercent.compareTo(BigDecimal.valueOf(alertThresholdPercent)) <= 0) {
logger.warn("🚨 价格接近预警: {} 当前价 {} vs 目标价 {} (相差 {}%)",
futures.getSymbol(), currentPrice, targetPrice, differencePercent);
}
}
}
/**
* 检查波动率预警
*/
private void checkVolatilityAlert(FuturesContract futures) {
double changePercent = Math.abs(futures.getChangePercent().doubleValue());
if (changePercent > alertThresholdPercent) {
String direction = futures.getChangePercent().doubleValue() > 0 ? "上涨" : "下跌";
logger.warn("🚨 价格波动预警: {} {} {}%",
futures.getSymbol(), direction, changePercent);
}
}
/**
* 检查现货价格
*/
private void checkSpotPrices() {
try {
CommodityData gold = futuresService.getGoldSpotPrice();
CommodityData oil = futuresService.getCrudeOilPrice();
// 检查现货价格异常波动
checkSpotPriceVolatility(gold, "黄金现货");
checkSpotPriceVolatility(oil, "原油现货");
} catch (Exception e) {
logger.debug("获取现货价格失败: {}", e.getMessage());
}
}
/**
* 检查现货价格波动
*/
private void checkSpotPriceVolatility(CommodityData commodity, String name) {
if (commodity != null) {
try {
BigDecimal changePercent = commodity.getNumericChangePercent().abs();
if (changePercent.compareTo(BigDecimal.valueOf(alertThresholdPercent)) > 0) {
String direction = commodity.getChangePercent().contains("+") ? "上涨" : "下跌";
logger.warn("🚨 现货价格波动: {} {} {}%",
name, direction, changePercent);
}
} catch (Exception e) {
// 忽略转换错误
}
}
}
/**
* 获取监控报告
*/
public void printMonitoringReport() {
logger.info("=== 商品监控报告 ===");
logger.info("监控商品数量: {}", monitoredSymbols.size());
logger.info("价格预警数量: {}", priceAlerts.size());
logger.info("波动预警阈值: {}%", alertThresholdPercent);
}
}
⚡ 主要商品代码参考
| 商品类型 | 代码 | 说明 |
|---|---|---|
| 黄金 | XAU |
黄金期货 |
| 黄金现货 | XAUUSD=X |
黄金兑美元现货 |
| 白银 | XAG |
白银期货 |
| 白银现货 | XAGUSD=X |
白银兑美元现货 |
| 原油 | CL |
WTI原油期货 |
| 布伦特原油 | BZ |
布伦特原油期货 |
| 天然气 | NG |
天然气期货 |
| 铜 | HG |
铜期货 |
| 大豆 | ZS |
大豆期货 |
| 玉米 | ZC |
玉米期货 |
📊 时间间隔参数
期货时间间隔
1: 1分钟5: 5分钟15: 15分钟30: 30分钟60: 60分钟1d: 1天
外汇时间间隔
1m: 1分钟5m: 5分钟15m: 15分钟30m: 30分钟60m: 60分钟1h: 1小时1d: 1天1wk: 1周1mo: 1月
📞 技术支持
如果在使用过程中遇到问题,可以通过以下方式获取帮助:
- 查看日志: 启用DEBUG级别日志查看详细请求信息
- 检查网络: 确保可以正常访问
api.stocktv.top - 验证API Key: 确认API Key有效且具有相应权限
- 联系支持: 通过官方渠道获取技术支持

浙公网安备 33010602011771号