394 lines
16 KiB
C#
394 lines
16 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// 国联民生 希腊字母计算
|
|
/// </summary>
|
|
public class GLMSGreeksHandleService
|
|
{
|
|
private readonly List<string> calcInstrumentTypes = new List<string>() { ConsGlobal.InstrumentType.TBonds, ConsGlobal.InstrumentType.CreditBonds, ConsGlobal.InstrumentType.OtherBonds,
|
|
ConsGlobal.InstrumentType.RateYield,ConsGlobal.InstrumentType.BondIndex,ConsGlobal.InstrumentType.TBFutures };
|
|
|
|
private readonly List<string> instrumentBondsTypes = new List<string>() { ConsGlobal.InstrumentType.TBonds, ConsGlobal.InstrumentType.CreditBonds, ConsGlobal.InstrumentType.OtherBonds };
|
|
|
|
Dictionary<string, double?> _pDic = new Dictionary<string, double?>();
|
|
Dictionary<string, double?> _dDic = new Dictionary<string, double?>();
|
|
Dictionary<string, double?> _cDic = new Dictionary<string, double?>();
|
|
Dictionary<string, double?> _ytmDic = new Dictionary<string, double?>();
|
|
Dictionary<string, double?> _cfDic = new Dictionary<string, double?>();
|
|
//期货对应的债券代码
|
|
Dictionary<string, string> _TFeaturesBondCodeDic = new Dictionary<string, string>();
|
|
|
|
|
|
public void InitData(DateTime valueDate,List<string> 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<string>();
|
|
}
|
|
|
|
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<ChinaBondIndexQuoteQueryDto>(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<long, long>();
|
|
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<string,long> GetTFeatureBondInnerCode(List<string> 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<TFeatureBondInnerCodeQueryDto>(sql, new
|
|
{
|
|
ValueDate = valueDate,
|
|
UmCodes = underlyingCodes
|
|
}, commandTimeout: 1800).ToList();
|
|
var res = new Dictionary<string,long>();
|
|
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<GLMSGreeksHandleService>();
|
|
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<long, double?> GetCFDatas(Dictionary<long, long> contractInnerCodeBondInnerCodeDic, DbConnection conn)
|
|
{
|
|
|
|
if (contractInnerCodeBondInnerCodeDic == null || contractInnerCodeBondInnerCodeDic.Count == 0)
|
|
return new Dictionary<long, double?>();
|
|
|
|
var parameters = new DynamicParameters();
|
|
var tupleList = new List<string>();
|
|
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<CFQueryDto>(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; }
|
|
|
|
|
|
/// <summary>
|
|
/// Delta_R
|
|
/// </summary>
|
|
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; }
|
|
}
|
|
}
|