📋 文檔概述
本文檔詳細介紹如何使用 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有效且具有相應權限
- 聯繫支持: 通過官方渠道獲取技術支持