From 20ab0c5173fcebe8089e01717b8dd04602735625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=99=BE=E7=90=83?= Date: Sat, 7 Mar 2026 03:08:46 +0000 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8E=A5=E5=85=A5=20OKX=20=E5=8A=A0?= =?UTF-8?q?=E5=AF=86=E8=B4=A7=E5=B8=81=E6=95=B0=E6=8D=AE=E6=BA=90=EF=BC=88?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E4=BB=B7=E6=A0=BC+=E5=8E=86=E5=8F=B2K?= =?UTF-8?q?=E7=BA=BF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Services/MarketDataService.cs | 128 +++++++++++++++++- 1 file changed, 122 insertions(+), 6 deletions(-) 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; } +}