using System; using System.Threading.Tasks; using Volo.Abp; using Volo.Abp.Domain.Services; using Volo.Abp.EventBus.Local; using Yi.Framework.Bbs.Domain.Shared.Etos; using Yi.Framework.Stock.Domain.Entities; using Yi.Framework.Stock.Domain.Shared; using Yi.Framework.Stock.Domain.Shared.Etos; using Yi.Framework.SqlSugarCore.Abstractions; using Yi.Framework.Stock.Domain.Managers.SemanticKernel; using Yi.Framework.Stock.Domain.Managers.SemanticKernel.Plugins; namespace Yi.Framework.Stock.Domain.Managers { /// /// 股市领域服务 /// /// /// 处理股票交易相关业务,例如买入、卖出等 /// public class StockMarketManager : DomainService { private readonly ISqlSugarRepository _stockHoldingRepository; private readonly ISqlSugarRepository _stockTransactionRepository; private readonly ISqlSugarRepository _stockPriceRecordRepository; private readonly ISqlSugarRepository _stockMarketRepository; private readonly ILocalEventBus _localEventBus; private readonly SemanticKernelClient _skClient; public StockMarketManager( ISqlSugarRepository stockHoldingRepository, ISqlSugarRepository stockTransactionRepository, ISqlSugarRepository stockPriceRecordRepository, ISqlSugarRepository stockMarketRepository, ILocalEventBus localEventBus, SemanticKernelClient skClient) { _stockHoldingRepository = stockHoldingRepository; _stockTransactionRepository = stockTransactionRepository; _stockPriceRecordRepository = stockPriceRecordRepository; _stockMarketRepository = stockMarketRepository; _localEventBus = localEventBus; _skClient = skClient; } /// /// 购买股票 /// /// 用户ID /// 股票ID /// 购买数量 /// public async Task BuyStockAsync(Guid userId, Guid stockId, int quantity) { if (quantity <= 0) { throw new UserFriendlyException("购买数量必须大于0"); } // 通过stockId查询获取股票信息 var stockInfo = await _stockMarketRepository.GetFirstAsync(s => s.Id == stockId); if (stockInfo == null) { throw new UserFriendlyException("找不到指定的股票"); } string stockCode = stockInfo.MarketCode; // 根据实际字段调整 string stockName = stockInfo.MarketName; // 根据实际字段调整 // 获取当前股票价格 decimal currentPrice = await GetCurrentStockPriceAsync(stockId); // 计算总金额和手续费 decimal totalAmount = currentPrice * quantity; decimal fee = CalculateTradingFee(totalAmount, TransactionTypeEnum.Buy); decimal totalCost = totalAmount + fee; // 扣减用户资金 await _localEventBus.PublishAsync( new MoneyChangeEventArgs { UserId = userId, Number = -totalCost }, false); // 更新或创建用户持仓 var holding = await _stockHoldingRepository.GetFirstAsync(h => h.UserId == userId && h.StockId == stockId && !h.IsDeleted); if (holding == null) { // 创建新持仓 holding = new StockHoldingAggregateRoot( userId, stockId, stockCode, stockName, quantity, currentPrice); await _stockHoldingRepository.InsertAsync(holding); } else { // 更新现有持仓 holding.AddQuantity(quantity, currentPrice); await _stockHoldingRepository.UpdateAsync(holding); } // 创建交易记录 var transaction = new StockTransactionEntity( userId, stockId, stockCode, stockName, TransactionTypeEnum.Buy, currentPrice, quantity, fee); await _stockTransactionRepository.InsertAsync(transaction); // 发布交易事件 await _localEventBus.PublishAsync(new StockTransactionEto { UserId = userId, StockId = stockId, StockCode = stockCode, StockName = stockName, TransactionType = TransactionTypeEnum.Buy, Price = currentPrice, Quantity = quantity, TotalAmount = totalAmount, Fee = fee }, false); } /// /// 卖出股票 /// /// 用户ID /// 股票ID /// 卖出数量 /// public async Task SellStockAsync(Guid userId, Guid stockId, int quantity) { // 验证卖出时间 VerifySellTime(); if (quantity <= 0) { throw new UserFriendlyException("卖出数量必须大于0"); } // 获取用户持仓 var holding = await _stockHoldingRepository.GetFirstAsync(h => h.UserId == userId && h.StockId == stockId && !h.IsDeleted); if (holding == null) { throw new UserFriendlyException("您没有持有该股票"); } if (holding.Quantity < quantity) { throw new UserFriendlyException("持仓数量不足"); } // 获取当前股票价格 decimal currentPrice = await GetCurrentStockPriceAsync(stockId); // 计算总金额和手续费 decimal totalAmount = currentPrice * quantity; decimal fee = CalculateTradingFee(totalAmount, TransactionTypeEnum.Sell); decimal actualIncome = totalAmount - fee; // 增加用户资金 await _localEventBus.PublishAsync( new MoneyChangeEventArgs { UserId = userId, Number = actualIncome }, false); // 更新用户持仓 holding.ReduceQuantity(quantity); if (holding.Quantity > 0) { await _stockHoldingRepository.UpdateAsync(holding); } else { await _stockHoldingRepository.DeleteAsync(holding); } // 创建交易记录 var transaction = new StockTransactionEntity( userId, stockId, holding.StockCode, holding.StockName, TransactionTypeEnum.Sell, currentPrice, quantity, fee); await _stockTransactionRepository.InsertAsync(transaction); // 发布交易事件 await _localEventBus.PublishAsync(new StockTransactionEto { UserId = userId, StockId = stockId, StockCode = holding.StockCode, StockName = holding.StockName, TransactionType = TransactionTypeEnum.Sell, Price = currentPrice, Quantity = quantity, TotalAmount = totalAmount, Fee = fee }, false); } /// /// 获取股票当前价格 /// /// 股票ID /// 当前价格 public async Task GetCurrentStockPriceAsync(Guid stockId) { // 获取最新的价格记录 var latestPriceRecord = await _stockPriceRecordRepository._DbQueryable .Where(p => p.StockId == stockId) .OrderByDescending(p => p.CreationTime) .FirstAsync(); if (latestPriceRecord == null) { throw new UserFriendlyException("无法获取股票价格信息"); } return latestPriceRecord.CurrentPrice; } /// /// 计算交易手续费 /// /// 交易金额 /// 交易类型 /// 手续费 private decimal CalculateTradingFee(decimal amount, TransactionTypeEnum transactionType) { // 示例费率:买入0.1%,卖出0.2% decimal feeRate = transactionType == TransactionTypeEnum.Buy ? 0.001m : 0.002m; return amount * feeRate; } /// /// 验证卖出时间 /// /// 如果不在允许卖出的时间范围内 private void VerifySellTime() { DateTime now = DateTime.Now; // 检查是否为工作日(周一到周五) if (now.DayOfWeek == DayOfWeek.Saturday || now.DayOfWeek == DayOfWeek.Sunday) { throw new UserFriendlyException("股票只能在工作日(周一至周五)卖出"); } // 检查是否在下午5点到6点之间 if (now.Hour < 17 || now.Hour >= 18) { throw new UserFriendlyException("股票只能在下午5点到6点之间卖出"); } } /// /// 批量保存多个股票的最新价格记录 /// /// 价格记录列表 /// 保存的记录数量 public async Task BatchSaveStockPriceRecordsAsync(List priceRecords) { if (priceRecords == null || !priceRecords.Any()) { return; } // 验证数据 for (int i = 0; i < priceRecords.Count; i++) { var record = priceRecords[i]; if (record.CurrentPrice <= 0) { throw new UserFriendlyException($"股票ID {record.StockId} 的价格必须大于0"); } // 设置记录时间(当前时间加上i个小时),只记录到年月日小时 record.RecordTime = new DateTime(DateTime.Now.AddHours(i).Year, DateTime.Now.AddHours(i).Month, DateTime.Now.AddHours(i).Day, DateTime.Now.AddHours(i).Hour, 0, 0); // 计算交易额(如果未设置) if (record.Turnover == 0 && record.Volume > 0) { record.Turnover = record.CurrentPrice * record.Volume; } } await _stockPriceRecordRepository.InsertManyAsync(priceRecords); } public async Task SaveStockAsync(List stockModels) { if (stockModels == null || !stockModels.Any()) { return; } // 收集所有股票ID var stockIds = stockModels.Select(m => m.Id).ToList(); // 一次性查询所有相关股票信息 var stockMarkets = await _stockMarketRepository.GetListAsync(s => stockIds.Contains(s.Id)); // 构建字典以便快速查找 var stockMarketsDict = stockMarkets.ToDictionary(s => s.Id); // 将StockModel转换为StockPriceRecordEntity var priceRecords = new List(); foreach (var stockModel in stockModels) { if (stockModel.Values == null || !stockModel.Values.Any()) { continue; } // 从字典中查找股票信息,而不是每次查询数据库 if (!stockMarketsDict.TryGetValue(stockModel.Id, out var stockMarket)) { continue; } // 为每个价格点创建一个记录 foreach (var priceValue in stockModel.Values) { var priceRecord = new StockPriceRecordEntity { StockId = stockMarket.Id, CurrentPrice = priceValue, Volume = 0, // 可以根据实际情况设置 Turnover = 0, // 可以根据实际情况设置 PeriodType = PeriodTypeEnum.Hour }; priceRecords.Add(priceRecord); } } // 批量保存价格记录 if (priceRecords.Any()) { await BatchSaveStockPriceRecordsAsync(priceRecords); } } /// /// 生成最新股票记录 /// /// public async Task GenerateStocksAsync() { var question = """ 根据给出的模拟新闻,模拟生成多家股票未来价格 以下是近期新闻: ai势力逐步崛起 大量网红下岗 近期群星演唱会即将开幕 以下是多个股票: 伦敦股票:id:3a1886d5-1479-5402-3bcb-063e989898d1 最后一次价格:188.7 上海股票:id:3a1886d5-4393-606c-b040-52f1ef7d2158 最后一次价格:125.2 纽约股票:id:3a1886d5-6906-8f30-d955-198fbcfe4026 最后一次价格:185.5 根据上面信息,给每个股票返回未来24小时的股票价格,每个小时,整点为单位一条记录,一家共有24条,返回股票id 与 长度为24的价格列表 只用生成一次即可 """; await _skClient.ChatCompletionAsync(question,("StockPlugins","save_stocks")); } } }