AssetManager.API/AssetManager.Infrastructure/Services/MockMarketDataService.cs

126 lines
4.7 KiB
C#

using AssetManager.Models.DTOs;
using Microsoft.Extensions.Logging;
namespace AssetManager.Infrastructure.Services;
/// <summary>
/// Mock 市场数据服务(用于开发测试)
/// </summary>
public class MockMarketDataService : IMarketDataService
{
private readonly ILogger<MockMarketDataService> _logger;
public MockMarketDataService(ILogger<MockMarketDataService> logger)
{
_logger = logger;
}
public async Task<MarketPriceResponse> GetStockPriceAsync(string symbol)
{
_logger.LogInformation("Mock 获取股票价格: {Symbol}", symbol);
// 先拿历史数据,取最后一根 K 线收盘价作为 PreviousClose
var historicalData = await GetStockHistoricalDataAsync(symbol, "1d", 2);
decimal previousClose = historicalData.Count >= 1 ? historicalData[^1].Close : 0;
// Mock 价格:基于标的代码生成一个稳定的价格
decimal basePrice = symbol.GetHashCode() % 1000 + 50;
return new MarketPriceResponse
{
Symbol = symbol,
Price = basePrice,
PreviousClose = previousClose,
Timestamp = DateTime.UtcNow,
AssetType = "Stock"
};
}
public async Task<MarketPriceResponse> GetCryptoPriceAsync(string symbol)
{
_logger.LogInformation("Mock 获取加密货币价格: {Symbol}", symbol);
// 先拿历史数据,取最后一根 K 线收盘价作为 PreviousClose
var historicalData = await GetCryptoHistoricalDataAsync(symbol, "1d", 2);
decimal previousClose = historicalData.Count >= 1 ? historicalData[^1].Close : 0;
decimal basePrice = symbol.GetHashCode() % 50000 + 10000;
return new MarketPriceResponse
{
Symbol = symbol,
Price = basePrice,
PreviousClose = previousClose,
Timestamp = DateTime.UtcNow,
AssetType = "Crypto"
};
}
public Task<List<MarketDataResponse>> GetStockHistoricalDataAsync(string symbol, string timeframe, int limit)
{
_logger.LogInformation("Mock 获取股票历史数据: {Symbol}, {Timeframe}, {Limit}", symbol, timeframe, limit);
return Task.FromResult(GenerateMockData(symbol, "Stock", timeframe, limit));
}
public Task<List<MarketDataResponse>> GetCryptoHistoricalDataAsync(string symbol, string timeframe, int limit)
{
_logger.LogInformation("Mock 获取加密货币历史数据: {Symbol}, {Timeframe}, {Limit}", symbol, timeframe, limit);
return Task.FromResult(GenerateMockData(symbol, "Crypto", timeframe, limit));
}
/// <summary>
/// 生成 Mock K 线数据(模拟一个上升趋势 + 随机波动)
/// </summary>
private List<MarketDataResponse> GenerateMockData(string symbol, string assetType, string timeframe, int limit)
{
var data = new List<MarketDataResponse>();
var random = new Random(symbol.GetHashCode()); // 基于 symbol 的稳定随机数
// 基础价格:基于 symbol 生成
decimal basePrice = symbol.GetHashCode() % 500 + 100;
DateTime currentTime = DateTime.UtcNow;
// 根据 timeframe 转换为时间增量
TimeSpan increment = timeframe.ToLower() switch
{
"1min" => TimeSpan.FromMinutes(1),
"5min" => TimeSpan.FromMinutes(5),
"15min" => TimeSpan.FromMinutes(15),
"1h" => TimeSpan.FromHours(1),
"1d" => TimeSpan.FromDays(1),
"1w" => TimeSpan.FromDays(7),
"1m" => TimeSpan.FromDays(30),
_ => TimeSpan.FromDays(1)
};
// 倒序生成(从过去到现在)
for (int i = limit - 1; i >= 0; i--)
{
DateTime timestamp = currentTime - increment * i;
// 模拟上升趋势 + 随机波动
decimal trend = (limit - i) * 0.1m; // 上升趋势
decimal noise = (decimal)(random.NextDouble() - 0.5) * 2; // ±1 的随机波动
decimal close = basePrice + trend + noise;
// 生成 OHLC
decimal open = close + (decimal)(random.NextDouble() - 0.5) * 1;
decimal high = Math.Max(open, close) + (decimal)random.NextDouble() * 0.5m;
decimal low = Math.Min(open, close) - (decimal)random.NextDouble() * 0.5m;
decimal volume = (decimal)(random.NextDouble() * 1000000 + 100000);
data.Add(new MarketDataResponse
{
Symbol = symbol,
Timestamp = timestamp,
Open = open,
High = high,
Low = low,
Close = close,
Volume = volume,
AssetType = assetType
});
}
return data;
}
}