273 lines
13 KiB
C#
273 lines
13 KiB
C#
using BaseOUDAL;
|
|
using YLErp.BLL;
|
|
using YLErp.Commons;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.EodModule;
|
|
using YLErp.Modules.RiskExposure;
|
|
using YLErp.Modules.RiskModule;
|
|
using YLErp.Modules.TradeModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.RiskHedgingModule
|
|
{
|
|
public class HedgeRiskMonitoringService : YLBaseService
|
|
{
|
|
private readonly ClientDBContext clientDB;
|
|
public HedgeRiskMonitoringService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
clientDB = DbContextFactory.GetClientDbContext(userInfo);
|
|
}
|
|
|
|
public HedgeRiskMonitoringService(YLBaseService baseService) : base(baseService)
|
|
{
|
|
}
|
|
|
|
public HedgeRiskMonitoringService(OptUserInfo optUser, YLContext dbContext) : base(optUser, dbContext)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 读取配置
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public HedgeRiskMonitoringReq ReadHedgeRiskMonitoringReportConfig()
|
|
{
|
|
HedgeRiskMonitoringReq result = null;
|
|
try
|
|
{
|
|
var cfg = DbContext.AppConfig.Where(O => O.PName == "HedgeRiskMonitoringConfig").FirstOrDefault();
|
|
if (cfg == null)
|
|
{
|
|
result = new HedgeRiskMonitoringReq();
|
|
cfg = new AppConfig()
|
|
{
|
|
PGroup = "Custom",
|
|
PName = "HedgeRiskMonitoringConfig",
|
|
PType = "string",
|
|
Remark = "风险对冲检测表配置",
|
|
CreateTime = DateTime.Now,
|
|
};
|
|
DbContext.AppConfig.Add(cfg);
|
|
cfg.PValue = result.ToJson();
|
|
DbContext.SaveChanges();
|
|
}
|
|
else
|
|
{
|
|
result = JsonHelper.ToObject<HedgeRiskMonitoringReq>(cfg.PValue);
|
|
}
|
|
}
|
|
catch { }
|
|
return result ?? new HedgeRiskMonitoringReq();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存配置
|
|
/// </summary>
|
|
/// <param name="req"></param>
|
|
public void SaveHedgeRiskMonitoringReportConfig(HedgeRiskMonitoringReq req)
|
|
{
|
|
try
|
|
{
|
|
var cfg = DbContext.AppConfig.Where(O => O.PName == "HedgeRiskMonitoringConfig").FirstOrDefault();
|
|
if (cfg == null)
|
|
{
|
|
cfg = new AppConfig()
|
|
{
|
|
PGroup = "System",
|
|
PName = "HedgeRiskMonitoringConfig",
|
|
PType = "string",
|
|
Remark = "风险对冲检测表配置",
|
|
CreateTime = DateTime.Now,
|
|
};
|
|
DbContext.AppConfig.Add(cfg);
|
|
}
|
|
cfg.PValue = req.ToJson();
|
|
cfg.OptDate = DateTime.Now;
|
|
DbContext.SaveChanges();
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public HedgeRiskMonitoringReportModel GetHedgeRiskMonitoringReportModel(DateTime endDate, HedgeRiskMonitoringReq req, RiskRequestModel reqRisk, EodPositionRisksReq eodPositionRisksReq, TradeMultiCloseQueryModel reqTradeMultiClose)
|
|
{
|
|
var hedgeRiskMonitoringReportModel = new HedgeRiskMonitoringReportModel();
|
|
|
|
//汇总
|
|
hedgeRiskMonitoringReportModel.QuotaTargetReport = new QuotaTargetReport()
|
|
{
|
|
QuotaStopLoss = req.quotaStopLoss,
|
|
QuotaCostRisk = req.quotaCostRisk,
|
|
QuotaPressureTest = req.quotaPressureTest,
|
|
QuotaCashDelta = req.quotaCashDelta,
|
|
QuotaContractTerm = req.quotaContractTerm,
|
|
QuotaUnderlyingConcentration = req.quotaUnderlyingConcentration,
|
|
QuotaStockEqvNotional = req.quotaStockEqvNotional,
|
|
QuotaMarginHold = req.quotaMarginHold,
|
|
};
|
|
|
|
if (PS.Config.ErpElement.UseOldEodPnLExplainer)
|
|
{
|
|
if (reqRisk?.EodSettlePriceMode == "结算价")
|
|
{
|
|
new Modules.RiskExposure.RiskExposureReportService<eod_trade_position_s>(UserInfo).GetPortfolioList<eod_trade_risk_s, eod_pnl_s>(reqRisk, out var riskCollectReport);
|
|
GetQuotaTargetReportByRiskCollect(endDate, hedgeRiskMonitoringReportModel.QuotaTargetReport, riskCollectReport, eodPositionRisksReq);
|
|
hedgeRiskMonitoringReportModel.RiskCollectReport = riskCollectReport;
|
|
}
|
|
else
|
|
{
|
|
new Modules.RiskExposure.RiskExposureReportService<eod_trade_position>(UserInfo).GetPortfolioList<eod_trade_risk, eod_pnl>(reqRisk, out var riskCollectReport);
|
|
GetQuotaTargetReportByRiskCollect(endDate, hedgeRiskMonitoringReportModel.QuotaTargetReport, riskCollectReport, eodPositionRisksReq);
|
|
hedgeRiskMonitoringReportModel.RiskCollectReport = riskCollectReport;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (reqRisk?.EodSettlePriceMode == "结算价")
|
|
{
|
|
new Modules.RiskExposure.RiskExposureReportService<eod_trade_position_hedgevol_s>(UserInfo).GetPortfolioList<eod_trade_risk_hedgevol_s, eod_pnl_hedgevol_s>(reqRisk, out var riskCollectReport);
|
|
GetQuotaTargetReportByRiskCollect(endDate, hedgeRiskMonitoringReportModel.QuotaTargetReport, riskCollectReport, eodPositionRisksReq);
|
|
hedgeRiskMonitoringReportModel.RiskCollectReport = riskCollectReport;
|
|
}
|
|
else
|
|
{
|
|
new Modules.RiskExposure.RiskExposureReportService<eod_trade_position_hedgevol>(UserInfo).GetPortfolioList<eod_trade_risk_hedgevol, eod_pnl_hedgevol>(reqRisk, out var riskCollectReport);
|
|
GetQuotaTargetReportByRiskCollect(endDate, hedgeRiskMonitoringReportModel.QuotaTargetReport, riskCollectReport, eodPositionRisksReq);
|
|
hedgeRiskMonitoringReportModel.RiskCollectReport = riskCollectReport;
|
|
}
|
|
}
|
|
//预付金监控报表
|
|
hedgeRiskMonitoringReportModel.BondMonitorReport = GetClientLatestBalance(endDate);
|
|
if (hedgeRiskMonitoringReportModel.BondMonitorReport.BondMonitorDetails.Count == 0)
|
|
{
|
|
hedgeRiskMonitoringReportModel.BondMonitorReport.BondMonitorDetails.Add(new BondMonitorDetail() { IsRiskEventToDay = "", IsAppened = "" });
|
|
}
|
|
|
|
var PositionRisklist = new EodPositionRisksQueryService(UserInfo).GetEodPositionRisksDataHandle(eodPositionRisksReq);
|
|
var PositionRisklist2 = PositionRisklist.Select(n => new ExpandoDictionary<string, string>(n)).ToArray();
|
|
//日终报表
|
|
hedgeRiskMonitoringReportModel.PositionRiskReport = PositionRisklist2;
|
|
|
|
var OptionSettlelist = new Modules.TradeModule.QueryModule.OtcOptionMultiCloseService(UserInfo).HandleExportDataToList(reqTradeMultiClose);
|
|
var OptionSettlelist2 = OptionSettlelist.Select(n => new ExpandoDictionary<string, string>(n.MetaDic)).ToArray();
|
|
//了结报表
|
|
hedgeRiskMonitoringReportModel.OptionSettleReport = OptionSettlelist2;
|
|
//预付金占用
|
|
var currMargin = DbContext.exchange_account.Any() ? DbContext.exchange_account.Sum(O => O.CurrMargin) : 0;
|
|
hedgeRiskMonitoringReportModel.QuotaTargetReport.MarginHold = currMargin == 0 ? 0 : currMargin / 10000;//万元
|
|
return hedgeRiskMonitoringReportModel;
|
|
}
|
|
|
|
|
|
public BondMonitorReport GetClientLatestBalance(DateTime? ValueDateTo, bool IsClientBalanceGap = false, bool IsGetOuterMarginGap = false, bool ParentFlag = false)
|
|
{
|
|
var ValueDateFrom = ValueDateTo;
|
|
var context = new Modules.EodModule.QueryModule.EodSettleInfoQueryContext(UserInfo);
|
|
var clientIds = context.GetClientIds();
|
|
var cb = BLL.EodSettlement.ClientBalanceUtility.GetClientBanlances(clientIds, ValueDateFrom.Value, ValueDateTo.Value, IsClientBalanceGap, IsGetOuterMarginGap, ParentFlag).ToList();
|
|
|
|
|
|
var bondMonitorReport = new BondMonitorReport
|
|
{
|
|
BondMonitorDetails = new List<BondMonitorDetail>()
|
|
};
|
|
var MarginOccupationPositiveNumber = cb.Where(x => x.MarginOccupation > 0).ToList();
|
|
foreach (var item in MarginOccupationPositiveNumber)
|
|
{
|
|
var c = new YLContext();
|
|
var bondMonitorDetail = new BondMonitorDetail();
|
|
var name = clientDB.client.FirstOrDefault(l => l.id == item.ClientId).Name;
|
|
bondMonitorDetail.ClientName = name;
|
|
bondMonitorDetail.DepositReceivable = item.MarginOccupation;
|
|
bondMonitorDetail.CreditAndClosingBalance = item.AmountFund + item.TotalCredit;
|
|
bondMonitorReport.BondMonitorDetails.Add(bondMonitorDetail);
|
|
}
|
|
bondMonitorReport.SumBondMonitor = MarginOccupationPositiveNumber.Sum(x => x.MarginOccupation);
|
|
return bondMonitorReport;
|
|
}
|
|
public void ReqDefaultHandle(DateTime endDate, out RiskRequestModel reqRisk, out EodPositionRisksReq eodPositionRisksReq, out TradeMultiCloseQueryModel reqTradeMultiClose)
|
|
{
|
|
//方顿-风险监测表-汇总数据开始日期需要为每年的第一个交易日
|
|
var startDate = new DateTime(valuedateBLL.ValueDate.Year, 1, 1);
|
|
for (var i = 1; i < 30; i++)
|
|
{
|
|
if (!QdpCalendarHelper.IsHoliday(startDate))
|
|
{
|
|
break;
|
|
}
|
|
startDate = startDate.AddDays(1);
|
|
}
|
|
reqRisk = new RiskRequestModel
|
|
{
|
|
EodSettlePriceMode = "收盘价",
|
|
ValueDateStart = startDate,
|
|
ValueDateEnd = endDate
|
|
};
|
|
|
|
eodPositionRisksReq = new EodPositionRisksReq
|
|
{
|
|
EodSettlePriceMode = "收盘价",
|
|
IsOnlyExport = false,
|
|
IsParentTrade = false,
|
|
VolType = "持仓",
|
|
needSettleData = false,
|
|
page = 0,
|
|
rows = 0,
|
|
ValueDate = endDate
|
|
};
|
|
|
|
reqTradeMultiClose = new TradeMultiCloseQueryModel { GetTotal = true };
|
|
;
|
|
//reqTradeMultiClose.PageIndex = 1;
|
|
//reqTradeMultiClose.PageSize = 25;
|
|
//reqTradeMultiClose.TradeStatus = "确认成交,新增待确认,修改待确认,审批中,已拒绝,已执行,已平仓,已到期,平仓待复核,行权待复核,互换待复核,提前终止拒绝";
|
|
reqTradeMultiClose.UnWindType = "全部";
|
|
reqTradeMultiClose.UseForwardASwap = true;
|
|
reqTradeMultiClose.UnwindDateStart = startDate;
|
|
reqTradeMultiClose.UnwindDateEnd = endDate;
|
|
}
|
|
|
|
public void GetQuotaTargetReportByRiskCollect(DateTime endDate, QuotaTargetReport quotaTargetReport, RiskCollectReport riskCollectReport, EodPositionRisksReq eodPositionRisksReq)
|
|
{
|
|
quotaTargetReport.StopLoss = riskCollectReport.PortfolioSum.Pnl / 10000;//单位为万元
|
|
quotaTargetReport.CashDelta = riskCollectReport.PortfolioSum.DeltaCash / 10000;//单位为万元
|
|
quotaTargetReport.StockEqvNotional = riskCollectReport.PortfolioSum.OtcStockEqvNotionalReal / 10000;//单位为万元
|
|
|
|
var req = new Modules.EodModule.eod_varReq
|
|
{
|
|
ValueDate = endDate,
|
|
PvPercent = 0.95,
|
|
IsNeedExport = false
|
|
};
|
|
var results = new Modules.EodModule.EodVaRService(UserInfo).GetEodVaR(req);
|
|
//风险价值
|
|
quotaTargetReport.CostRisk = results.Any() ? ((double?)Math.Abs(results.First().WinLoss) / 10000) : null;//单位为万元
|
|
//压力测试
|
|
var req2 = new Modules.ScenarioModule.ScenarioRequest
|
|
{
|
|
//req2.ConfigId = 13;
|
|
UseTradeDivendRate = true,
|
|
ValueDate = endDate,
|
|
VolType = "对冲",
|
|
RiskFreeRate = valuedateBLL.SysRiskFreeRate(),
|
|
SearchModel = new Modules.ScenarioModule.TradeScenarioSearchModel
|
|
{
|
|
UserAssets = eodPositionRisksReq.UserAssets,
|
|
UserClients = eodPositionRisksReq.UserClients,
|
|
PositionDate = endDate,
|
|
IsSelAll = true,
|
|
page = 1,
|
|
rows = 20,
|
|
sord = "asc"
|
|
}
|
|
};
|
|
var config = DbContext.ScenarioConfig.Where(O => O.ConfigName == "对冲风险压力测试").FirstOrDefault();
|
|
if (config == null)
|
|
{
|
|
throw new ServiceException("没有找到名为\"对冲风险压力测试\"情景分析配置");
|
|
}
|
|
var result = new Modules.ScenarioModule.ScenarioCalcService(UserInfo).Calculate(req2, config);
|
|
quotaTargetReport.PressureTest = result.ResultItems.Any() ? ((double?)Math.Abs(result.ResultItems.GroupBy(o => $"{o.xIndex}_{o.yIndex}").ToList().Select(o => o.Sum(O => O.PnL)).Min()) / 10000)/*单位为万元*/ : null;
|
|
}
|
|
}
|
|
}
|