362 lines
14 KiB
C#
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("曲线保存成功");
|
|
}
|
|
}
|
|
}
|