525 lines
20 KiB
C#
525 lines
20 KiB
C#
using YLErp.Abstract.DataProviders;
|
|
using YLErp.DBModels.Consts;
|
|
using YLErp.Modules.ApiModule;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.ExchangeOptionTradeModule;
|
|
using YLErp.Modules.ExchangeTradeModule;
|
|
using YLErp.Modules.RiskHedgingModule;
|
|
using YLErp.Modules.SystemModule;
|
|
using YLErp.Modules.TradeModule;
|
|
using YLErp.Modules.TradeRiskCalcModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Web.Controllers
|
|
{
|
|
/// <summary>
|
|
/// 风险对冲
|
|
/// </summary>
|
|
public class RiskHedgingController : BaseController
|
|
{
|
|
#region ----风险对冲2----
|
|
|
|
[MyAuthorize("风险控制-风险对冲")]
|
|
public ActionResult Index2(TradingRiskReqModel req)
|
|
{
|
|
var variDic = Modules.DataCacheModule.DataCacheManager.GetVarietyDataSource()
|
|
.AsQueryable().Select(n => new Variety { VarietyCode = n.VarietyCode, ShortName = n.ShortName })
|
|
.OrderBy(n => n.VarietyCode).ToDictionary(n => n.VarietyCode, StringComparer.OrdinalIgnoreCase);
|
|
|
|
var sortVarieties = new List<Variety>();
|
|
|
|
var model = new RiskHedgingViewModel(CurUser)
|
|
{
|
|
ReqModel = req ?? new TradingRiskReqModel
|
|
{
|
|
CalcDeltaRisk = AppHelper.TradeRiskCalcDeltaRisk
|
|
},
|
|
UnsortVarieties = variDic.Values,
|
|
SortVarieties = sortVarieties,
|
|
UserConfig = GetUserConfig(),
|
|
IsStock = req.Stock,
|
|
IsMainView = true
|
|
};
|
|
|
|
model.ReqModel.UseMarketForExOptions = model.UserConfig.UseMarketForExOptions;
|
|
|
|
//为参与排序的列表准备数据并从未参与排序的列表中去除参与排序的数据
|
|
var config = model.GetColumnConfig(CurUser.UserId, configcolumn_data.风险对冲V2排序);
|
|
if (!string.IsNullOrEmpty(config))
|
|
{
|
|
var sortVarietyCodes = config.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
foreach (var code in sortVarietyCodes)
|
|
{
|
|
if (variDic.ContainsKey(code))
|
|
{
|
|
sortVarieties.Add(variDic[code]);
|
|
variDic.Remove(code);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (PS.Config.IsUseHedgingRule)
|
|
{
|
|
var userId = CurUser.UserId;
|
|
model.AutoRules = yldb.trade_autorule.Where(n => n.OptId == userId && n.Enable).ToArray();
|
|
}
|
|
|
|
model.PreTradingDate = QdpCalendarHelper.PrevBizDayShift(valuedateBLL.ValueDate, offset: -1);
|
|
model.PreSettleDate = Modules.EodModule.EodDataHelper.GetPreSettleDate(valuedateBLL.ValueDate, VolTypeFlagEnum.HedgeVol);
|
|
model.UnderlyingAlerts = new UnderlyingPriceLimitService(CurUser).GetUnderlyingPirceLimits();
|
|
return View("index2", model);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 用于权益类风险对冲计算结果
|
|
/// </summary>
|
|
[MyAuthorize("风险控制-风险对冲")]
|
|
public ActionResult Index3(TradingRiskReqModel req)
|
|
{
|
|
req.Stock = true;
|
|
return Index2(req);
|
|
}
|
|
|
|
public ActionResult Index2Lite(TradingRiskReqModel req)
|
|
{
|
|
var model = new RiskHedgingViewModel(CurUser)
|
|
{
|
|
ReqModel = req ?? new TradingRiskReqModel
|
|
{
|
|
CalcDeltaRisk = AppHelper.TradeRiskCalcDeltaRisk
|
|
},
|
|
IsStock = req.Stock
|
|
};
|
|
return View("Index2", model);
|
|
}
|
|
/// <summary>
|
|
/// 根据波动率类型获取上一收盘日
|
|
/// </summary>
|
|
/// <param name="volType"></param>
|
|
/// <returns></returns>
|
|
public JsonResult AjaxPreSettleDateByVolType(string volType)
|
|
{
|
|
var volTypeFlagEnum = volType switch
|
|
{
|
|
"对冲" => VolTypeFlagEnum.HedgeVol,
|
|
"开仓" => VolTypeFlagEnum.OpenVol,
|
|
_ => VolTypeFlagEnum.PositionVol
|
|
};
|
|
var PreSettleDate = Modules.EodModule.EodDataHelper.GetPreSettleDate(valuedateBLL.ValueDate, volTypeFlagEnum);
|
|
return Json(PreSettleDate);
|
|
}
|
|
/// <summary>
|
|
/// 获取实时风险计算结果
|
|
/// </summary>
|
|
public ActionResult AjaxGetRiskCalcResult(TradingRiskReqModel req)
|
|
{
|
|
req.Normalize();
|
|
req.IncludeStock = AppHelper.ShowStockIndex2;
|
|
req.UserBookIds = GetUserAssetunitIds();
|
|
req.CalcDeltaRisk = AppHelper.TradeRiskCalcDeltaRisk;
|
|
req.UseMarketForExOptions = !PS.Config.Is光大光子 && GetUserConfig().UseMarketForExOptions;
|
|
|
|
var result = new TradingRiskReqService(CurUser).GetResult(req);
|
|
if (result == null)
|
|
{
|
|
return Json(new { rows = Enumerable.Empty<TradingRiskParameter>(), date = "" });
|
|
}
|
|
return Json(new
|
|
{
|
|
rows = result.TradeRiskList,
|
|
date = result.ValueDate.ToString("yyyy-MM-dd"),
|
|
calctimes = new[] { result.CalcStartTime, result.CalcEndTime },
|
|
message = result.Message
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取实时风险价格试算结果
|
|
/// </summary>
|
|
public ActionResult AjaxGetRiskPriceCalcResult(TradingRiskPriceCalcReqModel req)
|
|
{
|
|
req.Normalize();
|
|
req.UserBookIds = GetUserAssetunitIds();
|
|
|
|
if (req.Prices == null || req.Prices.All(n => string.IsNullOrEmpty(n.Code)))
|
|
{
|
|
return Content("{\"errcode\":1,\"errmsg\":\"参数错误\"}", "application/json");
|
|
}
|
|
|
|
foreach (var item in req.Prices)
|
|
{
|
|
item.Code = item.Code?.Trim();
|
|
}
|
|
|
|
if (AppHelper.RunTradeRiskCalcV2)
|
|
{
|
|
var result = new TradingRiskReqService(CurUser).GetPriceCalcResult(req);
|
|
if (result == null)
|
|
{
|
|
return Json(new { rows = Enumerable.Empty<TradingRiskParameter>(), date = "" });
|
|
}
|
|
return Json(new { rows = result.TradeRiskList, date = result.ValueDate.ToString("yyyy-MM-dd") });
|
|
}
|
|
else
|
|
{
|
|
var json = TapConsoleApiHelper.GetTradeRiskPriceCalcResults(req);
|
|
return Content(json, "application/json");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 对冲交易(股票、商品期货)的系统合成持仓和读取的持仓回报数据进行比对
|
|
/// </summary>
|
|
public ActionResult UploadPdfHedgePositions()
|
|
{
|
|
var files = Request.Form.Files;
|
|
|
|
if (files.Count == 0)
|
|
{
|
|
return JsonError("上传文件不存在");
|
|
}
|
|
|
|
var uploadFiles = files.Select(n => n.ToUploadFileModel()).ToArray();
|
|
|
|
var result = new HedgePositionCheckService(CurUser).CheckHedgePosition(uploadFiles, out var diffAccounts, out var unexistUmds);
|
|
|
|
return Json(new { result, diffAccounts, unexistUmds });
|
|
}
|
|
|
|
public ActionResult UploadDbfPositionAddDiff()
|
|
{
|
|
var files = Request.Form.Files;
|
|
|
|
if (files == null || files.Count == 0)
|
|
{
|
|
return JsonError("上传文件不存在");
|
|
}
|
|
|
|
var uploadFiles = files.Select(n => n.ToUploadFileModel()).ToArray();
|
|
|
|
var result = new HedgePositionCheckService(CurUser).CheckAndAddHedgePosition(uploadFiles, out var diffAccounts, out var unexistUmds);
|
|
|
|
return Json(new { result, diffAccounts, unexistUmds });
|
|
}
|
|
|
|
public ActionResult CompareExchangedOptionPosition()
|
|
{
|
|
var result = new HedgePositionCheckService(CurUser).CompareExchangedOptionPosition(out var message);
|
|
|
|
return Json(new { result, message });
|
|
}
|
|
|
|
public ActionResult CompareCommodityFuturePosition()
|
|
{
|
|
var result = new HedgePositionCheckService(CurUser).CompareCommodityFuturePosition(out var message);
|
|
|
|
return Json(new { result, message });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 对冲交易(股票、商品期货、场内期权)的系统合成持仓和读取的持仓回报数据进行比对
|
|
/// </summary>
|
|
public ActionResult DiffHedgePositions(bool isStock)
|
|
{
|
|
ViewBag.IsStock = isStock;
|
|
return View();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----对冲波动率/参与率/分红率
|
|
|
|
/// <summary>
|
|
/// 获取最新的对冲波动率
|
|
/// </summary>
|
|
public JsonResult AjaxGetHedgingVol(int? tradeId)
|
|
{
|
|
double? volValue = 0d;
|
|
|
|
if (tradeId > 0)
|
|
{
|
|
volValue = yldb.trade_hedge_vol.Where(n => n.TradeId == tradeId.Value).OrderByDescending(n => n.ValueDate)
|
|
.Select(n => (double?)n.TradeSavedVol).FirstOrDefault();
|
|
}
|
|
|
|
return JsonSuccessData(new { vol = volValue, volMoreAccurate = PS.Config.ErpElement.VolMoreAccurate });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取场内期权波动率
|
|
/// </summary>
|
|
public JsonResult AjaxGetExchangeOptionVol(string optionCode)
|
|
{
|
|
(double? vol, string useflag) result = (0, string.Empty);
|
|
|
|
if (!string.IsNullOrEmpty(optionCode))
|
|
{
|
|
var request = new ExchangeOptionVolRequest
|
|
{
|
|
VolType = null,
|
|
ValueDate = valuedateBLL.ValueDate,
|
|
OptionCode = optionCode,
|
|
UnderlyingPrice = null,
|
|
UnderlyingPriceProvider = new Lazy<IPriceProvider>(() => DataCacheProvider.GetUnderlyingDataSource()),
|
|
ExchangeOptionPriceProvider = new Lazy<IPriceProvider>(() => new ExchangeOptionPriceProvider()),
|
|
UserGroup = ConsUserGroup.DefaultGroup
|
|
};
|
|
|
|
var (volValue, volType) = new ExchangeOptionVolQueryService(CurUser).GetVolValue(request);
|
|
|
|
result = (volValue, volType == ExchangeOptionVolResultType.SavedFixVol ? "固定" : "");
|
|
}
|
|
|
|
return JsonSuccessData(new { result.vol, result.useflag, volMoreAccurate = PS.Config.ErpElement.VolMoreAccurate });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存对冲波动率
|
|
/// </summary>
|
|
public JsonResult AjaxSaveTradeHedgingVol(int tradeId, double value)
|
|
{
|
|
if (value < 0)
|
|
{
|
|
return JsonError("请设置合理的对冲波动率");
|
|
}
|
|
new TradeHisDataService(CurUser).SaveHedgeVol(tradeId, valuedateBLL.ValueDate, value);
|
|
return JsonSuccess();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存场内期权波动率
|
|
/// </summary>
|
|
public JsonResult AjaxSaveExOptionHedgingVol(string optionCode, double value, string saveflag)
|
|
{
|
|
var flag = saveflag == "固定" ? ExchangeOptionVolUseFlag.FixedValue : ExchangeOptionVolUseFlag.SystemOrImpliedVol;
|
|
new ExchangeOptionVolSaveService(CurUser).SaveExchangeOptionVol(optionCode, valuedateBLL.ValueDate, value, flag);
|
|
return JsonSuccess();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取衍生品交易分红率
|
|
/// </summary>
|
|
public JsonResult AjaxGetDividendRate(int tradeId)
|
|
{
|
|
var data = yldb.trade.Where(n => n.id == tradeId).Select(n => n.DividendRate).FirstOrDefault() ?? yldb.trade.Where(n => n.id == tradeId).Select(n => n.NoRiskRate).FirstOrDefault() ?? 0;
|
|
return JsonSuccessData(data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存衍生品交易分红率
|
|
/// </summary>
|
|
public JsonResult AjaxSaveDividendRate(int tradeId, double value)
|
|
{
|
|
if (value < 0)
|
|
{
|
|
return JsonError("请设置合理的分红率");
|
|
}
|
|
new TradeHisDataService(CurUser).SaveDividendRate(tradeId, valuedateBLL.ValueDate, value);
|
|
return JsonSuccess();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取衍生品交易无风险利率
|
|
/// </summary>
|
|
public JsonResult AjaxGetNoRiskRate(int tradeId)
|
|
{
|
|
var data = yldb.trade.Where(n => n.id == tradeId).Select(n => n.NoRiskRate).FirstOrDefault() ?? 0;
|
|
return JsonSuccessData(data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存衍生品交易无风险利率
|
|
/// </summary>
|
|
public JsonResult AjaxSaveNoRiskRate(int tradeId, double value)
|
|
{
|
|
if (value < 0)
|
|
{
|
|
return JsonError("请设置合理的无风险利率");
|
|
}
|
|
new TradeHisDataService(CurUser).SaveNoRiskRate(tradeId, valuedateBLL.ValueDate, value);
|
|
return JsonSuccess();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----根据自动对冲规则进行对冲----
|
|
|
|
public ActionResult Hedging(TradingRiskReqModel req)
|
|
{
|
|
req.Normalize();
|
|
req.IncludeStock = AppHelper.ShowStockIndex2;
|
|
req.UserBookIds = CurUser.GetAssetUnitIds();
|
|
IEnumerable<TradingRiskParameter> rows = null;
|
|
|
|
if (AppHelper.RunTradeRiskCalcV2)
|
|
{
|
|
var result = new TradingRiskReqService(CurUser).GetResult(req);
|
|
rows = result?.TradeRiskList ?? Enumerable.Empty<TradingRiskParameter>();
|
|
}
|
|
else
|
|
{
|
|
var json = TapConsoleApiHelper.GetTradeRiskResults(req);
|
|
var result = JsonHelper.Parse<TradeRiskResult>(json);
|
|
if (result.errcode != 0)
|
|
{
|
|
return Content("获取实时计算结果发生错误:" + result.errmsg);
|
|
}
|
|
rows = result?.rows ?? Enumerable.Empty<TradingRiskParameter>();
|
|
}
|
|
if (!rows.Any())
|
|
{
|
|
return Content("未获取到任何实时对冲数据");
|
|
}
|
|
|
|
if (PS.Config.IsUseHedgingRule)
|
|
{
|
|
new TradeAutoRuleService(CurUser).ApplyAutoRuleForHedging(UserId, rows);
|
|
}
|
|
|
|
var model = new RiskHedgingOrderModel
|
|
{
|
|
Items = rows.Select(n => new RiskHedgingOrderItem
|
|
{
|
|
DeltaInLots = n.DeltaInLots,
|
|
UnderlyingCode = n.UnderlyingCode
|
|
}).ToArray(),
|
|
InstType = rows.First().InstrumentType
|
|
};
|
|
|
|
return HedgingOrder(model);
|
|
}
|
|
|
|
class TradeRiskResult
|
|
{
|
|
public int errcode { get; set; }
|
|
|
|
public string errmsg { get; set; }
|
|
|
|
public IEnumerable<TradingRiskParameter> rows { get; set; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----风险对冲用户配置----
|
|
|
|
/// <summary>
|
|
/// 获取用户配置
|
|
/// </summary>
|
|
private RiskHedgingUserConfig GetUserConfig()
|
|
{
|
|
return new SysUserConfigService(CurUser).GetConfigData<RiskHedgingUserConfig>(Server.CacheProvider);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存配置
|
|
/// </summary>
|
|
public JsonResult AjaxSaveConfig(RiskHedgingUserConfig config)
|
|
{
|
|
new SysUserConfigService(CurUser).SaveData(config, Server.CacheProvider);
|
|
return JsonSuccess("保存成功");
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----对冲委托下单----
|
|
|
|
//对冲委托下单
|
|
public ActionResult HedgingOrder(RiskHedgingOrderModel model)
|
|
{
|
|
if (model is null || model.Items is null)
|
|
{
|
|
return ShowError("委托数据不能为空");
|
|
}
|
|
|
|
model.UserId = UserId.ToString();
|
|
|
|
//转换为整数值
|
|
foreach (var item in model.Items)
|
|
{
|
|
item.DeltaInLots = Convert.ToDouble((int)item.DeltaInLots);
|
|
}
|
|
|
|
switch (model.InstType)
|
|
{
|
|
case "Stock":
|
|
model.InstType = "stock";
|
|
break;
|
|
case "CommodityFutures":
|
|
model.InstType = "ctp";
|
|
break;
|
|
default:
|
|
return ShowError("标的类型不支持交易:" + model.InstType);
|
|
}
|
|
|
|
model.Token = Guid.NewGuid().ToString("N");
|
|
var signstr = string.Format("^{0}^sdfnFsa&dn@#4s叢dPP45oa!dnfaso00^{1}", UserId, model.Token);
|
|
model.Sign = YieldChain.Helpers.HashHelper.MD5(signstr);
|
|
|
|
return View("HedgingOrder", model);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----设置价格阈值----
|
|
|
|
public ActionResult SetPriceAlert(string code)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(code))
|
|
{
|
|
return View(new Modules.TradeRiskCalcModule.UnderlyingPriceChangeLimition());
|
|
}
|
|
var limit = new UnderlyingPriceLimitService(CurUser).GetUnderlyingPriceLimit(code);
|
|
return View(limit);
|
|
}
|
|
|
|
public JsonResult AjaxGetPriceAlert(string code)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(code))
|
|
{
|
|
return Json(new Modules.TradeRiskCalcModule.UnderlyingPriceChangeLimition());
|
|
}
|
|
var limit = new UnderlyingPriceLimitService(CurUser).GetUnderlyingPriceLimit(code);
|
|
return Json(limit);
|
|
}
|
|
|
|
public JsonResult SavePriceAlert(Modules.TradeRiskCalcModule.UnderlyingPriceChangeLimition limition)
|
|
{
|
|
new UnderlyingPriceLimitService(CurUser).SaveUnderlyingPriceLimit(limition);
|
|
return JsonSuccess("保存成功");
|
|
}
|
|
|
|
#endregion
|
|
/// <summary>
|
|
/// 子公司场外期权对冲风险监测表 页面
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public ActionResult HedgeRiskMonitoringView()
|
|
{
|
|
ViewBag.valueDate = valuedateBLL.ValueDate.ToString("yyyy-MM-dd");
|
|
ViewBag.HedgeRiskMonitoringConfig = new HedgeRiskMonitoringService(CurUser).ReadHedgeRiskMonitoringReportConfig();
|
|
return View();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导出子公司场外期权对冲风险监测表
|
|
/// </summary>
|
|
public ActionResult ExportHedgeRiskMonitoring(HedgeRiskMonitoringReq req, DateTime endDate)
|
|
{
|
|
new HedgeRiskMonitoringService(CurUser).ReqDefaultHandle(endDate, out var reqRisk, out var eodPositionRisksReq, out var reqTradeMultiClose);
|
|
reqRisk.BookIds = AssetUnitModel.IntersectAssetUnits(reqRisk.AssetIdGroupList, reqRisk.BookIds).ToList();
|
|
var service = new HedgeRiskMonitoringService(CurUser);
|
|
service.SaveHedgeRiskMonitoringReportConfig(req);
|
|
eodPositionRisksReq.UserAssets = CurUser.GetAssetUnitIds();
|
|
eodPositionRisksReq.UserClients = CurUser.GetClientIdsByCurUser(CurUser.交易管理_查看所有交易);
|
|
var hedgeRiskMonitoringReportModel = service.GetHedgeRiskMonitoringReportModel(endDate, req, reqRisk, eodPositionRisksReq, reqTradeMultiClose);
|
|
var fileDownloadName = $"子公司场外期权对冲风险监测表 {endDate:yyyyMMdd}.xlsx";
|
|
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/子公司场外期权对冲风险监测表.xlsx");
|
|
var generator = Office.ExcelModule.ExcelGenerator
|
|
.UseTemplateGenerator(templateFile).AddVariable(new { QuotaTargetReport = hedgeRiskMonitoringReportModel.QuotaTargetReport, BondMonitorReport = hedgeRiskMonitoringReportModel.BondMonitorReport, RiskCollectReport = hedgeRiskMonitoringReportModel.RiskCollectReport, positionRiskReport = hedgeRiskMonitoringReportModel.PositionRiskReport, optionSettleReport = hedgeRiskMonitoringReportModel.OptionSettleReport }).GenerateBytes(true);
|
|
|
|
return File(generator, "application/ms-excel", fileDownloadName);
|
|
}
|
|
|
|
}
|
|
} |