diff --git a/AssetManager.Infrastructure/Services/MarketDataService.cs b/AssetManager.Infrastructure/Services/MarketDataService.cs
index c0d77e8..7c3eac9 100644
--- a/AssetManager.Infrastructure/Services/MarketDataService.cs
+++ b/AssetManager.Infrastructure/Services/MarketDataService.cs
@@ -70,12 +70,38 @@ public class MarketDataService : IMarketDataService
///
/// 获取加密货币实时价格
///
- /// 加密货币代码(如 BTCUSD)
+ /// 加密货币代码(如 BTC-USDT)
/// 加密货币价格信息
public async Task GetCryptoPriceAsync(string symbol)
{
- // 待接入 OKX API
- throw new NotImplementedException("加密货币数据源待接入 OKX API");
+ try
+ {
+ _logger.LogInformation($"Requesting crypto price for symbol: {symbol}");
+
+ // OKX 实时 ticker 接口,symbol 格式如 BTC-USDT
+ var url = $"https://www.okx.com/api/v5/market/ticker?instId={symbol}";
+ var response = await _httpClient.GetFromJsonAsync(url);
+
+ if (response == null || response.code != "0" || response.data == null || response.data.Count == 0)
+ {
+ throw new Exception($"No data found for {symbol}, code: {response?.code}, msg: {response?.msg}");
+ }
+
+ var latest = response.data[0];
+ return new MarketPriceResponse
+ {
+ Symbol = symbol,
+ Price = decimal.TryParse(latest.last, out var price) ? price : 0,
+ PreviousClose = decimal.TryParse(latest.sodUtc0, out var prevClose) ? prevClose : 0, // UTC0 开盘价作为昨日收盘价
+ Timestamp = DateTime.UtcNow,
+ AssetType = "Crypto"
+ };
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"Error getting crypto price for {symbol}");
+ throw;
+ }
}
///
@@ -133,14 +159,82 @@ public class MarketDataService : IMarketDataService
///
/// 获取加密货币历史数据
///
- /// 加密货币代码
+ /// 加密货币代码(如 BTC-USDT)
/// 时间周期
/// 数据点数量
/// 历史数据列表
public async Task> GetCryptoHistoricalDataAsync(string symbol, string timeframe, int limit)
{
- // 待接入 OKX API
- throw new NotImplementedException("加密货币数据源待接入 OKX API");
+ try
+ {
+ _logger.LogInformation($"Requesting crypto historical data for symbol: {symbol}, timeframe: {timeframe}, limit: {limit}");
+
+ // 转换 timeframe 为 OKX 支持的粒度
+ var bar = ConvertToOkxBar(timeframe);
+
+ // OKX K线接口
+ var url = $"https://www.okx.com/api/v5/market/candles?instId={symbol}&bar={bar}&limit={limit}";
+ var response = await _httpClient.GetFromJsonAsync(url);
+
+ if (response == null || response.code != "0" || response.data == null)
+ {
+ throw new Exception($"No data found for {symbol}, code: {response?.code}, msg: {response?.msg}");
+ }
+
+ var result = new List();
+ foreach (var item in response.data)
+ {
+ if (item.Length < 6) continue;
+
+ if (long.TryParse(item[0], out var ts) &&
+ decimal.TryParse(item[1], out var open) &&
+ decimal.TryParse(item[2], out var high) &&
+ decimal.TryParse(item[3], out var low) &&
+ decimal.TryParse(item[4], out var close) &&
+ decimal.TryParse(item[5], out var volume))
+ {
+ result.Add(new MarketDataResponse
+ {
+ Symbol = symbol,
+ Open = open,
+ High = high,
+ Low = low,
+ Close = close,
+ Volume = volume,
+ Timestamp = DateTimeOffset.FromUnixTimeMilliseconds(ts).UtcDateTime,
+ AssetType = "Crypto"
+ });
+ }
+ }
+
+ // 按时间升序排列
+ result = result.OrderBy(x => x.Timestamp).ToList();
+ return result;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, $"Error getting crypto historical data for {symbol}");
+ throw;
+ }
+ }
+
+ ///
+ /// 转换 timeframe 为 OKX 支持的 bar 格式
+ ///
+ private string ConvertToOkxBar(string timeframe)
+ {
+ return timeframe.ToLower() switch
+ {
+ "1min" => "1m",
+ "5min" => "5m",
+ "15min" => "15m",
+ "1h" => "1H",
+ "4h" => "4H",
+ "1d" => "1D",
+ "1w" => "1W",
+ "1m" => "1M",
+ _ => "1D"
+ };
}
///
@@ -195,3 +289,25 @@ internal class TiingoCryptoBar
public decimal? volume { get; set; }
public DateTime? date { get; set; }
}
+
+// OKX 响应模型
+internal class OkxTickerResponse
+{
+ public string code { get; set; }
+ public string msg { get; set; }
+ public List data { get; set; }
+}
+
+internal class OkxTickerData
+{
+ public string instId { get; set; }
+ public string last { get; set; }
+ public string sodUtc0 { get; set; } // UTC0 开盘价,作为昨日收盘价
+}
+
+internal class OkxCandlesResponse
+{
+ public string code { get; set; }
+ public string msg { get; set; }
+ public List data { get; set; }
+}