Files
zszq-trs/YLErpWeb/Controllers/volatilityController.cs
2024-05-09 14:06:26 +08:00

362 lines
14 KiB
C#

using Newtonsoft.Json;
using System.Data;
using YLErp.BLL.Calculation;
using YLErp.Commons;
using YLErp.DBModels.Consts;
using YLErp.Modules.TQuoteModule;
using YLErp.Modules.VolatilityModule;
using YLErp.QdpModule;
using YLErp.QdpModule.Constants;
namespace YLErp.Web.Controllers
{
public class volatilityController : BaseController
{
/// <summary>
/// todo 保存多个类型的voltity
/// </summary>
public JsonResult SubmitSurface2(List<volatility> vols)
{
if (!CurUser.报价管理_波动率曲面修改)
{
return JsonError("没有保存权限");
}
var userVarietyIds = CurUser.GetUserVarietyIds().ToHashSet();
var unIdSet = vols.Select(n => n.UnderlyingId ?? 0).ToHashSet();
var unAuthCodes = DataCacheProvider.GetUnderlyingDataSource().AsQueryable()
.Where(n => unIdSet.Contains(n.id) && !userVarietyIds.Contains(n.UnderlyingTypeId))
.Select(n => n.UnderlyingCode).ToArray();
if (unAuthCodes.Any())
{
return JsonError("更新曲面失败,没有品种交易权限:" + string.Join(",", unAuthCodes));
}
try
{
foreach (var vv in vols)
{
vv.QuotationDate = valuedateBLL.ValueDate;
vv.UserGroup = CurUser.UserGroup;
vv.OptId = UserId;
vv.OptName = UserName;
}
var vollist = new VolatilitySaveService(CurUser).SaveVols(vols);
return JsonSuccess("更新曲面成功", vollist);
}
catch (Exception ex)
{
LogFactory.GetLogger(nameof(SubmitSurface2)).Error("更新曲面波动率", ex);
return JsonError("更新曲面失败," + ex.Message);
}
}
/// <summary>
/// 计算价格
/// </summary>
public JsonResult TQuote(TQuoteRequest req)
{
if (req.strikeInterval == 0)
{
return JsonError("执行价间隔不能为0!");
}
return JsonSuccess("", new TQuoteService(CurUser).Execute(req));
}
public JsonResult TQuoteWithCustomizedVol(TQuoteWithCustomizedVolRequest request)
{
return JsonSuccess("", new TQuoteService(CurUser).TQuoteWithCustomizedVol(request));
}
[MyAuthorize("报价管理-T型报价查看")]
public ActionResult t_table()
{
return View();
}
[MyAuthorize("报价管理-波动率曲面查看")]
public ActionResult today_volsurface_edit(int? uid, string voltype)
{
if (PS.Config.ErpElement.SkewMapVolConstruction && uid == null && voltype == null)
{
return RedirectToAction("index", "skewMap");
}
if (ConsUserGroup.HasGroup && string.IsNullOrEmpty(CurUser.UserGroup))
{
return ShowError("当前用户必须设置用户组以后才能访问此页面");
}
return today_volsurface_editV2();
}
[MyAuthorize("报价管理-波动率曲面查看")]
public ActionResult today_volsurface_editV2()
{
if (PS.Config.ErpElement.SkewMapVolConstruction)
{
return RedirectToAction("index", "skewMap");
}
if (ConsUserGroup.HasGroup && string.IsNullOrEmpty(CurUser.UserGroup))
{
return ShowError("当前用户必须设置用户组以后才能访问此页面");
}
var model = new VolsurfaceEditModel(CurUser);
return View("today_volsurface_editV2", model);
}
[MyAuthorize("报价管理-波动率曲面查看")]
public ActionResult riskFreeCurve()
{
return View();
}
public JsonResult get_underlyingvolsurface(string ucode, string voltype, DateTime systemdate)
{
var underlying = underlying_managerBLL.GetByCode(ucode);
//加入t型表格行权日时间
var tTableExecerizeDate = DateTime.Now.AddMonths(1).AddDays(-1);
if (underlying.MaturityDate < tTableExecerizeDate)
{
tTableExecerizeDate = underlying.MaturityDate.Value;
}
underlying.ExerciseDate = QdpCalendarHelper.GetNonHoliday(tTableExecerizeDate);
var request = new SingleVolatilityRequest
{
QuotationDate = systemdate,
UnderlyingCode = ucode,
TradeVolWithBidAsk = true,
UserGroup = CurUser.UserGroup,
VolType = voltype
};
var all_volatilities = new VolatilityQueryService(CurUser).GetVolatility(request, true);
var VolTypes = request.GetVolTypes().Select(O => new VolTypeState() { VolModelName = O }).ToList();
return JsonSuccess("获取波动率曲面成功", new { underlying, all_volatilities, VolTypes });
}
public ActionResult volsurfaceUpload()
{
var voldate = valuedateBLL.ValueDate;
ViewBag.Voldate = voldate.ToString("yyyy-MM-dd");
var r = new volatility();
return View(r);
}
public ActionResult UploadVolSurface(IFormFile file)
{
try
{
double.TryParse(Request.Form["Ask_Deviation"], out var ask_deviation);
double.TryParse(Request.Form["Bid_Deviation"], out var bid_deviation);
var quotationDate = Convert.ToDateTime(HttpContext.Request.Form["QuotationDate"]);
var overridByMainCode = "true".Equals(Request.Form["overridByMainCode"], StringComparison.OrdinalIgnoreCase);
using var stream = file.OpenReadStream();
var volList = new VolatilityImportReadService(CurUser).ImportFile(stream, new VolatilityImportReadModel
{
quotationDate = quotationDate,
Ask_Deviation = ask_deviation,
Bid_Deviation = bid_deviation,
volType = Request.Form["VolType"],
volSurfaceMode = Request.Form["VolSurfaceMode"],
ReviewDownLimit = ConsVolInfos.defReviewDownLimit,
ReviewUpLimit = ConsVolInfos.defReviewUpLimit,
UserGroup = CurUser.UserGroup
});
//保存更新波动率信息
if (volList.Count > 0)
{
var saveVols = new VolatilitySaveService(CurUser).SaveVols(volList, overridByMainCode);
if (saveVols.Count == 0)
{
return JsonError("导入失败,请检查交易和BidAsk的行权价及到期日是否一致,且波动率是否为正数");
}
}
else
{
return JsonError("没有导入波动率");
}
return JsonSuccessData(new { version = "v2", vol = volList.First(), underlyingCode = volList.First().ContractCode });
}
catch (Exception ex)
{
LogFactory.GetLogger<volatilityController>().Error("UploadFiles", ex);
return JsonError(ex.Message);
}
}
public ActionResult volsurfaceDown()
{
ViewBag.valueDate = valuedateBLL.ValueDate.ToString("yyyy-MM-dd");
volatility r = null;
return View(r);
}
[HttpPost]
public ActionResult downLoadVolSurfaceList(BatchVolatilityRequest req)
{
//获取角色有权限的
var varietyIds = CurUser.GetUserVarietyIds();
if (!varietyIds.Any(n => n > 0))
{
return ShowError("当前账户没有标的查看权限!");
}
req.VarietyIds = varietyIds;
req.UserGroup = CurUser.UserGroup;
//根据条件获取波动率数据
var volList = new VolatilityQueryService(CurUser).GetVolatilities(req, false);
if (volList == null || !volList.Any())
{
return ShowError("当前条件下未查找到波动率曲面数据!导出失败!");
}
var dt = VolatilityHelper.GetMatrix(volList);
var helper = new ExcelHelper();
var volType = "";
switch (req.VolType)
{
case "交易":
volType = "Mid";
break;
case "报价Bid":
volType = "Bid";
break;
case "报价Ask":
volType = "Ask";
break;
default:
volType = req.VolType;
break;
}
if (helper.DataTableToExcel(dt, volType, false, out var buffer) < 0)
{
return ShowError("导出失败!");
}
return File(buffer, "application/ms-excel", $"波动率曲面-{req.QuotationDate:yyyy-MM-dd}.xlsx");
}
/// <summary>
/// 获取某一标的的历史波动率曲线
/// </summary>
/// <param name="underlyingCode">合约代码</param>
/// <param name="valueDate">日期</param>
/// <param name="lookBackDays">计算波动率回溯的天数,可为30、60、90</param>
/// <returns></returns>
public JsonResult GetHistoricalVolCurve(string underlyingCode, DateTime valueDate, int lookBackDays)
{
var volPoints = VolCaculator.Instance.GetHistoricalVolCurvePoints(underlyingCode, valueDate, lookBackDays);
return Json(volPoints);
}
/// <summary>
/// 在用户设置的原始波动率曲面的点之间通过插值计算出更密集的点,以方便画出更准确的曲面图
/// </summary>
/// <param name="volSurface">原始波动率曲面</param>
/// <param name="interpolation">插值方法</param>
/// <returns></returns>
public JsonResult FillVolSurfaceInterpolatePoints(VolSurfacePoints[] volSurfaces, string interpolation)
{
var result = new Dictionary<string, object[][]>();
foreach (var vol in volSurfaces)
{
result[vol.SurfaceName] = VolCaculator.Instance.FillInterpolatePoints(vol.Points, interpolation);
}
return Json(result);
}
/// <summary>
/// 根据用户选择的期限,获得相应的波动率曲线的点,这些点除了包括原始的点之外,还包括通过插值计算出更密集的点
/// </summary>
/// <param name="volSurfaces">原始波动率曲面</param>
/// <param name="interpolation">插值方法</param>
/// <param name="expire">期限</param>
/// <returns></returns>
public JsonResult Fill2DVolSmileCurvePoints(VolSurfacePoints[] volSurfaces, string interpolation, string expire)
{
var result = new Dictionary<string, VolSmileCurve>();
foreach (var vol in volSurfaces)
{
result[vol.SurfaceName] = VolCaculator.Instance.FillVolSmileCurvePoints(vol.Points, interpolation, expire);
}
return Json(result);
}
/// <summary>
/// 获取某一标的的隐含波动率曲面。只对有场内期权的标的有效
/// </summary>
/// <param name="underlyingCode"></param>
/// <param name="valueDate"></param>
/// <returns></returns>
public JsonResult GetImpliedVolSurface(string underlyingCode, DateTime valueDate)
{
var underlying = underlying_managerBLL.GetByCode(underlyingCode);
//加入t型表格行权日时间
var tTableExecerizeDate = DateTime.Now.AddMonths(1).AddDays(-1);
if (underlying.MaturityDate < tTableExecerizeDate)
{
tTableExecerizeDate = underlying.MaturityDate.Value;
}
underlying.ExerciseDate = QdpCalendarHelper.GetNonHoliday(tTableExecerizeDate);
var VolTypes = ConsVolInfos.GetVolTypes("隐含")
.Select(O => new VolTypeState() { VolModelName = O }).ToList();
var volTypeList = VolTypes.Select(v => v.VolModelName).ToList();
var volatility = VolCaculator.Instance.GetImpliedVolSurface(underlyingCode, valueDate);
if (volatility == null)
{
return JsonError("获取隐含波动率失败。请确认该标的有场内期权且系统中有场内期权价格数据");
}
var all_volatilities = new List<volatility> { volatility };
return JsonSuccess("获取波动率曲面成功", new { underlying, VolTypes, all_volatilities });
}
public JsonResult GetRiskFreeCurve()
{
var curvePointData = valuedateBLL.RiskFreeCurveData;
if (string.IsNullOrWhiteSpace(curvePointData))
{
return JsonError("未查询到系统里有已设置的利率曲线,请重新设置");
}
var curvePoints = JsonConvert.DeserializeObject<List<SimpleIRCurvePoint>>(curvePointData);
return JsonSuccess("", curvePoints);
}
[HttpPost]
public ActionResult SaveRiskFreeCurve(List<SimpleIRCurvePoint> curvePoints)
{
var config = yldb.valuedate.FirstOrDefault(v => v.State == valuedate.当前使用);
config.RiskFreeCurveData = (curvePoints != null && curvePoints.Count > 0) ?
JsonConvert.SerializeObject(curvePoints.Where(p => !double.IsNaN(p.Rate)).ToList()) :
"";
config.UpdateTime = DateTime.Now;
yldb.SaveChanges();
valuedateBLL.ResetValueDate();
return JsonSuccess("曲线保存成功");
}
}
}