diff --git a/AssetManager.Infrastructure/Services/MarketDataService.cs b/AssetManager.Infrastructure/Services/MarketDataService.cs
index 3b155de..6b50a81 100644
--- a/AssetManager.Infrastructure/Services/MarketDataService.cs
+++ b/AssetManager.Infrastructure/Services/MarketDataService.cs
@@ -39,7 +39,7 @@ public class MarketDataService : IMarketDataService
}
///
- /// 获取股票实时价格
+ /// 获取股票实时价格(使用腾讯财经接口,免费无限制,支持盘前盘后)
///
/// 股票代码
/// 股票价格信息
@@ -47,36 +47,81 @@ public class MarketDataService : IMarketDataService
{
try
{
- _logger.LogInformation($"Requesting stock price for symbol: {symbol}");
+ _logger.LogInformation($"Requesting stock price for symbol: {symbol} (腾讯财经接口)");
- // Tiingo 日线最新价格端点(取最近1条)
- var url = $"https://api.tiingo.com/tiingo/daily/{symbol}/prices?token={_tiingoApiKey}";
- var response = await _httpClient.GetFromJsonAsync>(url);
+ // 腾讯财经美股接口:前缀us,小写代码
+ var url = $"http://qt.gtimg.cn/q=us{symbol.ToLower()}";
+ var response = await _httpClient.GetStringAsync(url);
- if (response == null || response.Count == 0)
+ if (string.IsNullOrEmpty(response) || !response.Contains("~"))
{
- throw new Exception($"No data found for {symbol}");
+ throw new Exception($"腾讯财经接口返回无效数据,标的: {symbol}");
}
- var latest = response[^1];
- decimal? prevClose = response.Count >= 2 ? response[^2].close : null;
+ // 解析返回数据
+ var parts = response.Split('"')[1].Split('~');
+ if (parts.Length < 36)
+ {
+ throw new Exception($"腾讯财经返回字段不足,标的: {symbol}");
+ }
+
+ // 提取字段:[3]=最新价 [4]=昨收价
+ if (!decimal.TryParse(parts[3], out var currentPrice) || currentPrice <= 0)
+ {
+ throw new Exception($"解析最新价失败,标的: {symbol},返回值: {parts[3]}");
+ }
+
+ if (!decimal.TryParse(parts[4], out var prevClose) || prevClose <= 0)
+ {
+ prevClose = currentPrice; // 解析失败用当前价当昨收
+ }
return new MarketPriceResponse
{
Symbol = symbol,
- Price = latest.close ?? 0,
- PreviousClose = prevClose ?? 0,
- Timestamp = latest.date ?? DateTime.UtcNow,
+ Price = currentPrice,
+ PreviousClose = prevClose,
+ Timestamp = DateTime.UtcNow,
AssetType = "Stock"
};
}
catch (Exception ex)
{
- _logger.LogError(ex, $"Error getting stock price for {symbol}");
- throw;
+ _logger.LogError(ex, $"腾讯财经接口获取价格失败,标的: {symbol},降级使用Tiingo接口");
+ // 降级使用Tiingo接口
+ return await GetStockPriceFromTiingoAsync(symbol);
}
}
+ ///
+ /// 从Tiingo获取股票价格(降级用)
+ ///
+ private async Task GetStockPriceFromTiingoAsync(string symbol)
+ {
+ _logger.LogInformation($"Requesting stock price for symbol: {symbol} (Tiingo接口)");
+
+ // Tiingo 日线最新价格端点(取最近1条)
+ var url = $"https://api.tiingo.com/tiingo/daily/{symbol}/prices?token={_tiingoApiKey}";
+ var response = await _httpClient.GetFromJsonAsync>(url);
+
+ if (response == null || response.Count == 0)
+ {
+ throw new Exception($"No data found for {symbol}");
+ }
+
+ var latest = response[^1];
+ decimal? prevClose = response.Count >= 2 ? response[^2].close : null;
+
+ return new MarketPriceResponse
+ {
+ Symbol = symbol,
+ Price = latest.close ?? 0,
+ PreviousClose = prevClose ?? 0,
+ Timestamp = latest.date ?? DateTime.UtcNow,
+ AssetType = "Stock"
+ };
+ }
+
///
/// 获取加密货币实时价格
///