Compare commits
2 Commits
7bf687323d
...
3768f6e747
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3768f6e747 | ||
|
|
0579e2f47a |
@ -2,6 +2,7 @@ using AssetManager.Data;
|
|||||||
using AssetManager.Data.Repositories;
|
using AssetManager.Data.Repositories;
|
||||||
using AssetManager.Models.DTOs;
|
using AssetManager.Models.DTOs;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace AssetManager.Infrastructure.Services;
|
namespace AssetManager.Infrastructure.Services;
|
||||||
|
|
||||||
@ -20,6 +21,9 @@ public class MarketDataService : IMarketDataService
|
|||||||
private readonly ITiingoMarketService _tiingoService;
|
private readonly ITiingoMarketService _tiingoService;
|
||||||
private readonly IOkxMarketService _okxService;
|
private readonly IOkxMarketService _okxService;
|
||||||
private readonly IMarketDataRepository _marketDataRepo;
|
private readonly IMarketDataRepository _marketDataRepo;
|
||||||
|
|
||||||
|
// 防止并发请求同一股票
|
||||||
|
private readonly ConcurrentDictionary<string, Task<MarketPriceResponse>> _pendingPriceRequests = new();
|
||||||
|
|
||||||
public MarketDataService(
|
public MarketDataService(
|
||||||
ILogger<MarketDataService> logger,
|
ILogger<MarketDataService> logger,
|
||||||
@ -39,9 +43,11 @@ public class MarketDataService : IMarketDataService
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取实时价格(自动根据资产类型路由到对应数据源)
|
/// 获取实时价格(自动根据资产类型路由到对应数据源)
|
||||||
|
/// 使用并发控制防止重复请求
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<MarketPriceResponse> GetPriceAsync(string symbol, string assetType)
|
public async Task<MarketPriceResponse> GetPriceAsync(string symbol, string assetType)
|
||||||
{
|
{
|
||||||
|
var cacheKey = $"{symbol.ToUpper()}_{assetType.ToUpper()}";
|
||||||
_logger.LogInformation("获取实时价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType);
|
_logger.LogInformation("获取实时价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType);
|
||||||
|
|
||||||
// 先查缓存
|
// 先查缓存
|
||||||
@ -60,7 +66,27 @@ public class MarketDataService : IMarketDataService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 缓存未命中,调用API
|
// 使用 GetOrAdd 模式防止并发重复请求
|
||||||
|
var priceTask = _pendingPriceRequests.GetOrAdd(cacheKey, _ => FetchPriceFromSourceAsync(symbol, assetType));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await priceTask;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// 请求完成后移除(无论成功失败)
|
||||||
|
_pendingPriceRequests.TryRemove(cacheKey, out _);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从数据源获取价格(内部方法)
|
||||||
|
/// </summary>
|
||||||
|
private async Task<MarketPriceResponse> FetchPriceFromSourceAsync(string symbol, string assetType)
|
||||||
|
{
|
||||||
|
_logger.LogInformation("从数据源获取价格: {Symbol}, 资产类型: {AssetType}", symbol, assetType);
|
||||||
|
|
||||||
MarketPriceResponse response;
|
MarketPriceResponse response;
|
||||||
string source;
|
string source;
|
||||||
|
|
||||||
|
|||||||
@ -657,15 +657,15 @@ public class PortfolioService : IPortfolioService
|
|||||||
{
|
{
|
||||||
if (DateTime.TryParse(request.TransactionDate, out var parsedDate))
|
if (DateTime.TryParse(request.TransactionDate, out var parsedDate))
|
||||||
{
|
{
|
||||||
// 如果只传了日期,时间部分默认用当前时间
|
transactionTime = parsedDate.Date;
|
||||||
transactionTime = parsedDate.Date + DateTime.Now.TimeOfDay;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!string.IsNullOrEmpty(request.TransactionTime))
|
// 组合时间部分
|
||||||
|
if (!string.IsNullOrEmpty(request.TransactionTime))
|
||||||
{
|
{
|
||||||
if (DateTime.TryParse(request.TransactionTime, out var parsedTime))
|
if (TimeSpan.TryParse(request.TransactionTime, out var parsedTime))
|
||||||
{
|
{
|
||||||
transactionTime = parsedTime;
|
transactionTime = transactionTime.Date + parsedTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -821,12 +821,16 @@ public class PortfolioService : IPortfolioService
|
|||||||
request.PortfolioId = portfolioId;
|
request.PortfolioId = portfolioId;
|
||||||
var response = await CreateTransaction(request, userId);
|
var response = await CreateTransaction(request, userId);
|
||||||
|
|
||||||
|
// 使用实际交易时间
|
||||||
|
var transactionDate = request.TransactionDate ?? DateTime.Now.ToString("yyyy-MM-dd");
|
||||||
|
var transactionTime = request.TransactionTime ?? DateTime.Now.ToString("HH:mm");
|
||||||
|
|
||||||
return new TransactionItem
|
return new TransactionItem
|
||||||
{
|
{
|
||||||
Id = response.Id,
|
Id = response.Id,
|
||||||
PortfolioId = portfolioId,
|
PortfolioId = portfolioId,
|
||||||
Date = DateTime.Now.ToString("yyyy-MM-dd"),
|
Date = transactionDate,
|
||||||
Time = DateTime.Now.ToString("HH:mm:ss"),
|
Time = transactionTime,
|
||||||
Type = request.Type,
|
Type = request.Type,
|
||||||
StockCode = request.StockCode,
|
StockCode = request.StockCode,
|
||||||
Amount = response.TotalAmount,
|
Amount = response.TotalAmount,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user