using Dapper; using Org.BouncyCastle.Asn1.Mozilla; using Org.BouncyCastle.Ocsp; using Qdp.Foundation.Implementations; using System; using System.Collections.Generic; using System.Data.Common; using System.Linq; using System.Text; using System.Threading.Tasks; using YLErp.Abstract.DataProviders; using YLErp.DBModels; using YLErp.Model; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.Modules.MarketRiskMoudule.Dto; namespace YLErp.Modules.EodModule { /// /// 国联民生 希腊字母计算 /// public class GLMSGreeksHandleService { private readonly List calcInstrumentTypes = new List() { ConsGlobal.InstrumentType.TBonds, ConsGlobal.InstrumentType.CreditBonds, ConsGlobal.InstrumentType.OtherBonds, ConsGlobal.InstrumentType.RateYield,ConsGlobal.InstrumentType.BondIndex,ConsGlobal.InstrumentType.TBFutures }; private readonly List instrumentBondsTypes = new List() { ConsGlobal.InstrumentType.TBonds, ConsGlobal.InstrumentType.CreditBonds, ConsGlobal.InstrumentType.OtherBonds }; Dictionary _pDic = new Dictionary(); Dictionary _dDic = new Dictionary(); Dictionary _cDic = new Dictionary(); Dictionary _ytmDic = new Dictionary(); Dictionary _cfDic = new Dictionary(); //期货对应的债券代码 Dictionary _TFeaturesBondCodeDic = new Dictionary(); public void InitData(DateTime valueDate,List underlyingCodes) { var umDatas = DataCacheProvider.GetUnderlyingDataSource().AsQueryable().Where(p => underlyingCodes.Contains(p.UnderlyingCode) && calcInstrumentTypes.Contains(p.UnderlyingInstrumentType)).ToList(); if (umDatas == null || umDatas.Count == 0) { return; } using var db = DbContextFactory.GetYLDbContext(); var conn = db.Database.GetDbConnection(); var bondsUmCodes = umDatas.Where(p => instrumentBondsTypes.Contains(p.UnderlyingInstrumentType)).Select(p => p.UnderlyingCode).Distinct().ToList(); if (bondsUmCodes == null) { bondsUmCodes = new List(); } var bondIndexUmInnerCodes = umDatas.Where(p => ConsGlobal.InstrumentType.BondIndex.Equals(p.UnderlyingInstrumentType)).Select(p => p.InnerCode??0).Distinct().ToList(); if (bondIndexUmInnerCodes != null && bondIndexUmInnerCodes.Count > 0) { var querySql = "SELECT InnerCode,Duration1,Convexity1,YTM FROM bond_chinabondindexquote WHERE TradingDay = @ValueDate AND InnerCode IN @InnerCodes"; var bondIndexQuoteDatas = conn.Query(querySql, new { ValueDate = valueDate, InnerCodes = bondIndexUmInnerCodes }, commandTimeout: 1800).ToList(); if (bondIndexQuoteDatas != null && bondIndexQuoteDatas.Count > 0) { foreach (var item in bondIndexQuoteDatas) { var umCode = umDatas.First(d => d.InnerCode == item.InnerCode).UnderlyingCode; _dDic.Add(umCode, item.Duration1 != null ? (double)item.Duration1 : null); _cDic.Add(umCode, item.Convexity1 != null ? (double)item.Convexity1 : null); _ytmDic.Add(umCode, item.YTM != null ? (double)item.YTM : null); } } } var bondFeatureUmCodes = umDatas.Where(p => ConsGlobal.InstrumentType.TBFutures.Equals(p.UnderlyingInstrumentType)).Select(p => p.UnderlyingCode).Distinct().ToList(); if (bondFeatureUmCodes != null && bondFeatureUmCodes.Count > 0) { var tFeatureBondInnerCodeDic = GetTFeatureBondInnerCode(bondFeatureUmCodes, valueDate, conn); if (tFeatureBondInnerCodeDic != null && tFeatureBondInnerCodeDic.Count > 0) { var contractInnerCodeBondInnerCodeDic = new Dictionary(); foreach (var item in tFeatureBondInnerCodeDic) { var bondUm = DataCacheProvider.GetUnderlyingDataSource().AsQueryable().FirstOrDefault(p => p.InnerCode == item.Value); if (bondUm != null) { _TFeaturesBondCodeDic.Add(item.Key, bondUm.UnderlyingCode); bondsUmCodes.Add(bondUm.UnderlyingCode); } var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.Key); if (um.InnerCode != null) { contractInnerCodeBondInnerCodeDic.Add(um.InnerCode ?? 0, item.Value); } } if (contractInnerCodeBondInnerCodeDic.Count > 0) { var cfDatas = GetCFDatas(contractInnerCodeBondInnerCodeDic, conn); if (cfDatas != null && cfDatas.Count > 0) { foreach (var item in cfDatas) { var um = DataCacheProvider.GetUnderlyingDataSource().AsQueryable().FirstOrDefault(p => p.InnerCode == item.Key); if (um != null) { _cfDic.Add(um.UnderlyingCode, item.Value); } } } } } } if (bondsUmCodes != null && bondsUmCodes.Count > 0) { bondsUmCodes = bondsUmCodes.Distinct().ToList(); var datas = db.china_bond_valuation.AsNoTracking().Where(p => p.valuation_date == valueDate && bondsUmCodes.Contains(p.bond_id)).Select(p => new { p.bond_id, p.modi_dura, p.cnvxty, p.yield }).ToList(); if (datas != null && datas.Count > 0) { foreach (var item in datas) { _dDic.Add(item.bond_id, item.modi_dura != null ? (double)item.modi_dura : null); _cDic.Add(item.bond_id, item.cnvxty != null ? (double)item.cnvxty : null); _ytmDic.Add(item.bond_id, item.yield != null ? (double)item.yield : null); } } } underlyingCodes.AddRange(bondsUmCodes); underlyingCodes = underlyingCodes.Distinct().ToList(); var eodPriceProvier = new EodPriceProvider(valueDate); eodPriceProvier.Initialize(underlyingCodes); underlyingCodes.ForEach(e => { _pDic.Add(e, eodPriceProvier.GetPrice(e, SettlementTypeEnum.ClosePrice)); }); } public void Handle(EodPositionRisksDTO dto,underlying_manager um) { var calcDto = new GreeksCalcDto { Delta = dto.Delta, Gamma = dto.Gamma, Vega = dto.Vega, }; handle(calcDto, um); dto.Delta_r = calcDto.Delta_r; dto.Gamma_r = calcDto.Gamma_r; dto.Vega_r = calcDto.Vega_r; dto.Delta_r_1bp = calcDto.Delta_r_1bp; dto.Dv01 = calcDto.Dv01; dto.Gamma_r_1bp = calcDto.Gamma_r_1bp; dto.Vega_r_1bp = calcDto.Vega_r_1bp; dto.Vega_1bp = calcDto.Vega_1bp; } public void Handle(trade td,TradeValueResult calRes, underlying_manager um) { var calcDto = new GreeksCalcDto { Delta = calRes.Delta, Gamma = calRes.Gamma, Vega = calRes.Vega, }; handle(calcDto, um); calRes.Delta_r = calcDto.Delta_r; calRes.Gamma_r = calcDto.Gamma_r; calRes.Vega_r = calcDto.Vega_r; calRes.Delta_r_1bp = calcDto.Delta_r_1bp; calRes.Dv01 = calcDto.Dv01; calRes.Gamma_r_1bp = calcDto.Gamma_r_1bp; calRes.Vega_r_1bp = calcDto.Vega_r_1bp; calRes.Vega_1bp = calcDto.Vega_1bp; } private Dictionary GetTFeatureBondInnerCode(List underlyingCodes,DateTime valueDate,DbConnection conn) { var sql = "SELECT contractcode,deliverableinnercode,spread FROM fut_cgbderiv WHERE tradingday = @ValueDate AND pricetype = 3 AND (contractcode,irr) IN (SELECT contractcode,MAX(irr) FROM fut_cgbderiv WHERE tradingday = @ValueDate AND contractcode IN (@UmCodes) AND pricetype = 3 GROUP BY contractcode);"; var datas = conn.Query(sql, new { ValueDate = valueDate, UmCodes = underlyingCodes }, commandTimeout: 1800).ToList(); var res = new Dictionary(); if (datas != null && datas.Count > 0) { res = datas.GroupBy(p => p.contractcode).ToDictionary(p => p.Key, p => p.OrderBy(d => d.spread).First().deliverableinnercode); } return res; } private GLMSGreeksCalcArgs GetCalcArgs(string underlyingCode, string underlyingInstrumentType) { var res = new GLMSGreeksCalcArgs(); if (ConsGlobal.InstrumentType.RateYield.Equals(underlyingInstrumentType)) { return res; } if (ConsGlobal.InstrumentType.TBFutures.Equals(underlyingInstrumentType)) { var bondUnderlyingCode = _TFeaturesBondCodeDic.GetValueOrDefault(underlyingCode, null); if (!string.IsNullOrEmpty(bondUnderlyingCode)) { res.P = _pDic.GetValueOrDefault(bondUnderlyingCode, null); res.D = _dDic.GetValueOrDefault(bondUnderlyingCode, null); res.C = _cDic.GetValueOrDefault(bondUnderlyingCode, null); res.Ytm = _ytmDic.GetValueOrDefault(bondUnderlyingCode, null); } res.CF = _cfDic.GetValueOrDefault(underlyingCode, null); } else { res.P = _pDic.GetValueOrDefault(underlyingCode, null); res.D = _dDic.GetValueOrDefault(underlyingCode, null); res.C = _cDic.GetValueOrDefault(underlyingCode, null); res.Ytm = _ytmDic.GetValueOrDefault(underlyingCode, null); } var logger = LogFactory.GetLogger(); logger.Info($"希腊字母计算参数 - UnderlyingCode:{underlyingCode}, InstrumentType:{underlyingInstrumentType}, P:{res.P}, D:{res.D}, C:{res.C}, Ytm:{res.Ytm}, CF:{res.CF}"); return res; } private Dictionary GetCFDatas(Dictionary contractInnerCodeBondInnerCodeDic, DbConnection conn) { if (contractInnerCodeBondInnerCodeDic == null || contractInnerCodeBondInnerCodeDic.Count == 0) return new Dictionary(); var parameters = new DynamicParameters(); var tupleList = new List(); int idx = 0; foreach (var kvp in contractInnerCodeBondInnerCodeDic) { var cp = $"@C{idx}"; var bp = $"@B{idx}"; tupleList.Add($"({cp},{bp})"); parameters.Add(cp, kvp.Key); parameters.Add(bp, kvp.Value); idx++; } var sql = $@"SELECT infopubldate, contractinnercode, ibmarketinnercode, conversionfactors FROM fut_conversionfactors WHERE (contractinnercode, ibmarketinnercode) IN ({string.Join(",", tupleList)})"; var datas = conn.Query(sql, parameters, commandTimeout: 1800).ToList(); return datas.GroupBy(p => p.contractinnercode).ToDictionary(d => d.Key, d => { var res = d.OrderByDescending(p => p.infopubldate).First().conversionfactors; return res != null ? (double)res : (double?)null; }); } private void handle(GreeksCalcDto dto, underlying_manager um) { // 标准 Vega 的 1bp 变体:全资产计算,不受利率类过滤限制 dto.Vega_1bp = dto.Vega * 0.0001; if (!calcInstrumentTypes.Contains(um.UnderlyingInstrumentType)) { return; } var calcArgs = GetCalcArgs(um.UnderlyingCode, um.UnderlyingInstrumentType); if (ConsGlobal.InstrumentType.RateYield.Equals(um.UnderlyingInstrumentType)) { //利率收益率 dto.Delta_r = dto.Delta * -1; dto.Gamma_r = dto.Gamma; dto.Vega_r = dto.Vega; } else if (instrumentBondsTypes.Contains(um.UnderlyingInstrumentType)) { //利率债、信用债、其它债券 dto.Delta_r = dto.Delta * calcArgs.P * calcArgs.D; dto.Gamma_r = dto.Delta * calcArgs.P * calcArgs.C + (calcArgs.P * calcArgs.D) * (calcArgs.P * calcArgs.D) * dto.Gamma; dto.Vega_r = dto.Vega * calcArgs.D * calcArgs.Ytm; } else if (ConsGlobal.InstrumentType.BondIndex.Equals(um.UnderlyingInstrumentType)) { //债券指数 dto.Delta_r = dto.Delta * calcArgs.P * calcArgs.D; dto.Gamma_r = dto.Delta * calcArgs.P * calcArgs.C + (calcArgs.P * calcArgs.D) * (calcArgs.P * calcArgs.D) * dto.Gamma; dto.Vega_r = dto.Vega * calcArgs.D * calcArgs.Ytm; } else if (ConsGlobal.InstrumentType.TBFutures.Equals(um.UnderlyingInstrumentType)) { //国债期货 dto.Delta_r = dto.Delta * calcArgs.P * calcArgs.D / calcArgs.CF; dto.Gamma_r = dto.Delta * calcArgs.P * calcArgs.C / calcArgs.CF + (calcArgs.P * calcArgs.D / calcArgs.CF) * (calcArgs.P * calcArgs.D / calcArgs.CF) * dto.Gamma; dto.Vega_r = dto.Vega * calcArgs.D * calcArgs.Ytm; } dto.Delta_r_1bp = dto.Delta_r * 0.0001; dto.Dv01 = dto.Delta_r_1bp; dto.Gamma_r_1bp = dto.Gamma_r * 0.0001 * 0.0001; dto.Vega_r_1bp = dto.Vega_r * 0.0001; } } public class GLMSGreeksCalcArgs { //计算日的全价 public double? P { get; set; } public double? D { get; set; } public double? CF { get; set; } public double? C { get; set; } public double? Ytm { get; set; } } public class GreeksCalcDto { public double? Delta { get; set; } public double? Gamma { get; set; } public double? Vega { get; set; } /// /// Delta_R /// public double? Delta_r { get; set; } public double? Delta_r_1bp { get; set; } public double? Dv01 { get; set; } public double? Gamma_r { get; set; } public double? Gamma_r_1bp { get; set; } public double? Vega_r { get; set; } public double? Vega_r_1bp { get; set; } public double? Vega_1bp { get; set; } } public class ChinaBondIndexQuoteQueryDto { public long InnerCode { get; set; } public decimal? Duration1 { get; set; } public decimal? Convexity1 { get; set; } public decimal? YTM { get; set; } } public class TFeatureBondInnerCodeQueryDto { public string contractcode { get; set; } public long deliverableinnercode { get; set; } public decimal? spread { get; set; } } public class CFQueryDto { public DateTime infopubldate { get; set; } public long contractinnercode { get; set; } public long ibmarketinnercode { get; set; } public decimal? conversionfactors { get; set; } } }