From 3f6c060b4c1377172075684ad7ebdc32242ac674 Mon Sep 17 00:00:00 2001 From: yexuzhong <120511780@qq.com> Date: Mon, 3 Aug 2026 16:13:40 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=9B=BD=E8=81=94=E6=B0=91=E7=94=9F=20=20g?= =?UTF-8?q?reek=E8=AE=A1=E7=AE=97=2040%?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EodModule/GLMSGreeksHandleService.cs | 288 +++++++++++++++++- .../Modules/PricingModule/PriceCalcService.cs | 4 +- 2 files changed, 282 insertions(+), 10 deletions(-) diff --git a/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs b/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs index 97020691..1baf43e8 100644 --- a/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs +++ b/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs @@ -1,10 +1,19 @@ +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 { @@ -13,29 +22,292 @@ 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 _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; + } + + var eodPriceProvier = new EodPriceProvider(valueDate); + eodPriceProvier.Initialize(underlyingCodes); + underlyingCodes.ForEach(e => { + _pDic.Add(e, eodPriceProvier.GetPrice(e, SettlementTypeEnum.ClosePrice)); + }); + 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.Count > 0) + { + 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.convexity, + 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.convexity != null ? (double)item.convexity : null); + _ytmDic.Add(item.bond_id, item.yield != null ? (double)item.yield : null); + } + } + } + + 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); + } + var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.Key); + if (um.InnerCode != null) + { + contractInnerCodeBondInnerCodeDic.Add(um.InnerCode ?? 0, item.Value); + } + } + if (tFeatureBondInnerCodeDic.Count > 0) + { + + } + } + } + + + } public void Handle(EodPositionRisksDTO dto,underlying_manager um) { - //对Delta_r Delta_r_1bp Dv01 Gamma_r Gamma_r_1bp Vega_r Vega_r_1bp - - if ("GB10".Equals(um.UnderlyingCode)) + var calcDto = new GreeksCalcDto { - dto.Delta_r = dto.Delta * -1; + 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; + } + + + 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; + } + + + 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) + { + if (ConsGlobal.InstrumentType.RateYield.Equals(underlyingInstrumentType)) + { + return null; + } + return new GLMSGreeksCalcArgs + { + + }; + } + + private Dictionary GetCFDatas(Dictionary contractInnerCodeBondInnerCodeDic, DbConnection conn) + { + var sql = "SELECT infopubldate,contractinnercode,ibmarketinnercode,conversionfactors FROM fut_conversionfactors WHERE (contractinnercode,ibmarketinnercode) IN ((2059453,477500));"; + return null; + } + + private void handle(GreeksCalcDto dto, underlying_manager um) + { + 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; + } - public void Handle(trade td,TradeValueResult calRes) - { - calRes.Delta_r = calRes.Delta * -1; + 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 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; } + } } diff --git a/YLErpDAL/Modules/PricingModule/PriceCalcService.cs b/YLErpDAL/Modules/PricingModule/PriceCalcService.cs index 5e59a00c..c6240b8d 100644 --- a/YLErpDAL/Modules/PricingModule/PriceCalcService.cs +++ b/YLErpDAL/Modules/PricingModule/PriceCalcService.cs @@ -530,8 +530,8 @@ namespace YLErp.Modules.PricingModule } } - - greeksHandleService.Handle(td, calcResult); + + greeksHandleService.Handle(td, calcResult, underlying); results.Add(new CalcOptionPriceResult { From b41346240cef6946d07aa2a36a59eacb5dc9b4d4 Mon Sep 17 00:00:00 2001 From: yexuzhong <120511780@qq.com> Date: Mon, 3 Aug 2026 16:40:40 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=80=BA=E5=88=B8=E6=9C=9F=E8=B4=A7=20=20g?= =?UTF-8?q?reek=E8=AE=A1=E7=AE=97=E6=95=B0=E6=8D=AE=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EodModule/GLMSGreeksHandleService.cs | 127 ++++++++++++++---- 1 file changed, 99 insertions(+), 28 deletions(-) diff --git a/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs b/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs index 1baf43e8..3b39427e 100644 --- a/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs +++ b/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs @@ -31,6 +31,7 @@ namespace YLErp.Modules.EodModule Dictionary _dDic = new Dictionary(); Dictionary _cDic = new Dictionary(); Dictionary _ytmDic = new Dictionary(); + Dictionary _cfDic = new Dictionary(); //期货对应的债券代码 Dictionary _TFeaturesBondCodeDic = new Dictionary(); @@ -51,24 +52,9 @@ namespace YLErp.Modules.EodModule 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.Count > 0) + if (bondsUmCodes == null) { - 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.convexity, - 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.convexity != null ? (double)item.convexity : null); - _ytmDic.Add(item.bond_id, item.yield != null ? (double)item.yield : null); - } - } + bondsUmCodes = new List(); } var bondIndexUmInnerCodes = umDatas.Where(p => ConsGlobal.InstrumentType.BondIndex.Equals(p.UnderlyingInstrumentType)).Select(p => p.InnerCode??0).Distinct().ToList(); @@ -107,6 +93,7 @@ namespace YLErp.Modules.EodModule if (bondUm != null) { _TFeaturesBondCodeDic.Add(item.Key, bondUm.UnderlyingCode); + bondsUmCodes.Add(bondUm.UnderlyingCode); } var um = DataCacheProvider.GetUnderlyingDataSource().GetData(item.Key); if (um.InnerCode != null) @@ -114,9 +101,42 @@ namespace YLErp.Modules.EodModule contractInnerCodeBondInnerCodeDic.Add(um.InnerCode ?? 0, item.Value); } } - if (tFeatureBondInnerCodeDic.Count > 0) + 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.convexity, + 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.convexity != null ? (double)item.convexity : null); + _ytmDic.Add(item.bond_id, item.yield != null ? (double)item.yield : null); } } } @@ -181,22 +201,66 @@ namespace YLErp.Modules.EodModule return res; } - private GLMSGreeksCalcArgs GetCalcArgs(string underlyingCode,string underlyingInstrumentType) + private GLMSGreeksCalcArgs GetCalcArgs(string underlyingCode, string underlyingInstrumentType) { + var res = new GLMSGreeksCalcArgs(); if (ConsGlobal.InstrumentType.RateYield.Equals(underlyingInstrumentType)) { - return null; + return res; } - return new GLMSGreeksCalcArgs + 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); + } + // + return res; } - private Dictionary GetCFDatas(Dictionary contractInnerCodeBondInnerCodeDic, DbConnection conn) + private Dictionary GetCFDatas(Dictionary contractInnerCodeBondInnerCodeDic, DbConnection conn) { - var sql = "SELECT infopubldate,contractinnercode,ibmarketinnercode,conversionfactors FROM fut_conversionfactors WHERE (contractinnercode,ibmarketinnercode) IN ((2059453,477500));"; - return null; + + 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) @@ -206,8 +270,6 @@ namespace YLErp.Modules.EodModule return; } - - var calcArgs = GetCalcArgs(um.UnderlyingCode, um.UnderlyingInstrumentType); if (ConsGlobal.InstrumentType.RateYield.Equals(um.UnderlyingInstrumentType)) @@ -310,4 +372,13 @@ namespace YLErp.Modules.EodModule 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; } + } }