diff --git a/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs b/YLErpDAL/Modules/EodModule/GLMSGreeksHandleService.cs index 97020691..3b39427e 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,363 @@ 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; + } + + 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 = 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.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); + } + } + } + + + } 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) + { + 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); + } + // + 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; + }); } - - public void Handle(trade td,TradeValueResult calRes) + private void handle(GreeksCalcDto dto, underlying_manager um) { - calRes.Delta_r = calRes.Delta * -1; + 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 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; } + } } 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 {