using Microsoft.Extensions.DependencyInjection; using System; using System.Linq; using System.Text; using YieldChain.Commons; using YLErp.Cache; using YLErp.Commons; using YLErp.DBModels; namespace YLErp.Modules.UnderlyingModule { /// /// 标的数据帮助类 /// public static class UnderlyingHelper { readonly static IYLCache ylCache; static UnderlyingHelper() { ylCache = YLServiceLocator.ServiceProvider.GetService(); } /// /// 获取组合标的品种对象 /// public static Variety GetSyntheticVariety() { var variety = DataCacheProvider.GetVarietyDataSource().AsQueryable() .FirstOrDefault(v => v.VarietyCode == "组合标的"); if (variety != null) { return variety; } lock (DataCacheProvider.GetVarietyDataSource()) { using (var db = DbContextFactory.GetYLDbContext()) { variety = db.variety.FirstOrDefault(n => n.VarietyCode == "组合标的"); if (variety != null) { return variety; } variety = new Variety() { VarietyCode = "组合标的", VarietyName = "组合标的", TradingMarketId = 0, TradeUnit = "1手/份", QuoteUnit = "元(人民币)/份", DeliveryType = "", HasNightMarket = false, ShortName = "组合标的", CommissionType = "固定", CloseTodayCommissionType = "固定", //UnderlyingInstrumentType = "CommodityFutures", VolatilityRate = "", VolatilityAdjust = 0, AssetType = "", OptId = 0, OptName = "系统", OptDate = DateTime.Now, }; db.variety.Add(variety); db.SaveChanges(); return variety; } } } /// /// 根据客户ID、标的代码和计算日期计算适用的保证金率 /// /// 客户ID /// 标的代码 /// 计算日期 /// 适用的保证金率配置,包含初始保证金率和维持保证金率 public static client_margin_detail GetApplicableMarginRate(int clientId, string underlyingCode, DateTime valueDate) { if (string.IsNullOrEmpty(underlyingCode)) return null; string cacheKey = $"Otc:ClientMarginRate:{clientId}:{underlyingCode}:{valueDate:yyyyMMdd}"; try { if (ylCache!=null) { // 1. 先查Redis var cacheDetail = ylCache.StringGetWithNoPrefix(cacheKey); if (cacheDetail != null) return cacheDetail; } // 2. 查数据库 string applicableTerm = GetApplicableMarginTerm(underlyingCode, valueDate); var marginConfig = GetClientMarginConfig(clientId, valueDate); if (marginConfig == null) return null; var marginDetail = GetMarginDetailByTerm(marginConfig.id, applicableTerm); // 3. 放入Redis if (marginDetail != null&& ylCache != null) { ylCache.StringSetWithNoPrefix(cacheKey, marginDetail,TimeSpan.FromHours(3)); } return marginDetail; } catch (Exception ex) { LogFactory.GetLogger("UnderlyingHelper").Error($"计算保证金率时发生异常: {ex.Message}", ex); return null; } } /// /// 获取客户保证金配置 /// /// 客户ID /// 估值日期 /// 客户保证金配置 private static client_margin_config GetClientMarginConfig(int clientId, DateTime valueDate) { try { using (var context = DbContextFactory.GetYLDbContext()) { // 查找指定日期有效的客户保证金配置 var config = context.clientMarginConfig .Where(c => c.client_id == clientId && c.value_date <= valueDate) .OrderByDescending(c => c.value_date) .FirstOrDefault(); // 找不到,查找通用的那条 if (config==null) { config = context.clientMarginConfig .Where(c => c.client_id == 0 && c.value_date <= valueDate) .OrderByDescending(c => c.value_date) .FirstOrDefault(); } return config; } } catch (Exception ex) { Console.WriteLine($"获取客户保证金配置时发生异常: {ex.Message}"); return null; } } /// /// 根据配置ID和期限获取保证金率详情 /// /// 配置ID /// 债券期限 /// 保证金率详情 private static client_margin_detail GetMarginDetailByTerm(int configId, string bondTerm) { try { using (var context = DbContextFactory.GetYLDbContext()) { var details = context.clientMarginDetail .Where(d => d.config_id == configId).ToList(); var detail = details.FirstOrDefault(d => d.bond_term == bondTerm); if (detail==null&& !string.IsNullOrEmpty(bondTerm)) { detail=details.FirstOrDefault(d => string.IsNullOrEmpty(d.bond_term)); } return detail; } } catch (Exception ex) { Console.WriteLine($"获取保证金率详情时发生异常: {ex.Message}"); return null; } } /// /// 获取篮子标的品种对象 /// public static Variety GetBasketVariety() { return DataCacheProvider.GetVarietyDataSource().AsQueryable() .FirstOrDefault(v => v.VarietyCode == "篮子标的") ?? new Variety { VarietyCode = "篮子标的", VarietyName = "篮子标的", QuoteUnit = "元(人民币)/股", TradeUnit = "100股/手" }; } /// /// 获取标的品种代码 例:BU,BU-CU /// /// /// public static string GetUnderlyingVarietyCode(string underlyingCode) { var ret = ""; var un = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); if (un != null) { if (un.UnderlyingType == "组合标的") { var synthetic = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(underlyingCode); if (synthetic != null) { var sb = new StringBuilder(); var va1 = DataCacheProvider.GetVariety(synthetic.UnderlyingCode1); var va2 = DataCacheProvider.GetVariety(synthetic.UnderlyingCode2); var va3 = DataCacheProvider.GetVariety(synthetic.UnderlyingCode3); var va4 = DataCacheProvider.GetVariety(synthetic.UnderlyingCode4); if (va1 != null) { sb.Append(va1.VarietyCode).Append('-'); } if (va2 != null) { sb.Append(va2.VarietyCode).Append('-'); } if (va3 != null) { sb.Append(va3.VarietyCode).Append('-'); } if (va4 != null) { sb.Append(va4.VarietyCode).Append('-'); } ret = sb.ToString().Substring(0, sb.Length - 1); } } else { var va = DataCacheProvider.GetVariety(un.UnderlyingCode); ret = va.VarietyCode; } } return ret; } /// /// 获取债券的期限,计算日期一定要小于原日期 /// /// 计算日期 /// 原日期 /// 返回3.12格式 public static double? getYearTerm(DateTime? calcDate, DateTime? sourceDate) { if (!calcDate.HasValue) { return null;//不限 } if (sourceDate.HasValue) { if (calcDate > sourceDate) { throw new ArgumentException("计算日期必须小于原日期", nameof(calcDate)); } //计算sourceDate与calcDate年限差 int yearDiff = sourceDate.Value.Year - calcDate.Value.Year; int monthDiff = sourceDate.Value.Month - calcDate.Value.Month; int dayDiff = sourceDate.Value.Day - calcDate.Value.Day; // 如果月差为负,说明还没到整年,需要向前借一年 if (monthDiff < 0) { yearDiff -= 1; monthDiff += 12; } // 如果天数为负,说明还没到整月,需要向前借一个月 if (dayDiff < 0) { monthDiff -= 1; if (monthDiff < 0) { yearDiff -= 1; monthDiff += 12; } } double yearTerm = yearDiff + monthDiff / 12.0; return yearTerm; } return null;//不限 } /// /// 根据标的发行年限和剩余期限计算适用保证金率 /// 规则表格: /// | 剩余期限(年) | 发行期限(年) | 则适用于 | /// |------------------|---------------|----------| /// | (0.00,2.00] | 不限 | 2年 | /// | (2.00,2.25] | <5 | 2年 | /// | (2.00,2.25] | >=5 | 5年 | /// | (2.25,5.00] | 不限 | 5年 | /// | (5.00,5.25] | <7 | 5年 | /// | (5.00,5.25] | >=7 | 10年 | /// | (5.25,25.00] | 不限 | 10年 | /// | (25.00,30.00] | 不限 | 30年 | /// /// 标的代码 /// 估值日期 /// 适用的保证金率期限,如果不适用则返回空字符串 public static string GetApplicableMarginTerm(string underlyingCode, DateTime valueDate) { if (string.IsNullOrEmpty(underlyingCode)) return ConsMarginTerm.Default; try { // 获取标的信息 var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode); if (underlying == null || !underlying.MaturityDate.HasValue) return ConsMarginTerm.Default; // 计算发行年限(从上市日期到到期日期) var issueTermYears = getYearTerm(underlying.OpenDate, underlying.MaturityDate); // 计算剩余期限(从估值日期到到期日期) var remainingTermYears = getYearTerm(valueDate, underlying.MaturityDate); // 根据业务规则确定适用的保证金率期限 return DetermineMarginTerm(issueTermYears, remainingTermYears); } catch (Exception ex) { // 记录异常日志 Console.WriteLine($"计算保证金率期限时发生异常: {ex.Message}"); return ConsMarginTerm.Default; } } /// /// 根据发行年限和剩余年限确定适用的保证金率期限 /// 规则表格: /// | 剩余期限(年) | 发行期限(年) | 则适用于 | /// |------------------|---------------|----------| /// | (0.00,2.00] | 不限 | 2年 | /// | (2.00,2.25] | <5 | 2年 | /// | (2.00,2.25] | >=5 | 5年 | /// | (2.25,5.00] | 不限 | 5年 | /// | (5.00,5.25] | <7 | 5年 | /// | (5.00,5.25] | >=7 | 10年 | /// | (5.25,25.00] | 不限 | 10年 | /// | (25.00,30.00] | 不限 | 30年 | /// 说明:发行年限为null或0时视为“不限” /// private static string DetermineMarginTerm(double? issueYears, double? remainingYears) { // (0.00,2.00]年 不限 2年 if (remainingYears > 0.00 && remainingYears <= 2.00) return ConsMarginTerm.TwoYear; // (2.00,2.25] <5 2年 if (remainingYears > 2.00 && remainingYears <= 2.25 && issueYears.HasValue && issueYears < 5) return ConsMarginTerm.TwoYear; // (2.00,2.25] >=5 5年 if (remainingYears > 2.00 && remainingYears <= 2.25 && issueYears.HasValue && issueYears >= 5) return ConsMarginTerm.FiveYear; // (2.25,5.00] 不限 5年 if (remainingYears > 2.25 && remainingYears <= 5.00) return ConsMarginTerm.FiveYear; // (5.00,5.25] <7 5年 if (remainingYears > 5.00 && remainingYears <= 5.25 && issueYears.HasValue && issueYears < 7) return ConsMarginTerm.FiveYear; // (5.00,5.25] >=7 10年 if (remainingYears > 5.00 && remainingYears <= 5.25 && issueYears.HasValue && issueYears >= 7) return ConsMarginTerm.TenYear; // (5.25,25.00] 不限 10年 if (remainingYears > 5.25 && remainingYears <= 25.00) return ConsMarginTerm.TenYear; // (25.00,30.00] 不限 30年 if (remainingYears > 25.00 && remainingYears <= 30.00) return ConsMarginTerm.ThirtyYear; // 其他情况返回默认 return ConsMarginTerm.Default; } } }