Files
zszq-trs/YLErpDAL/Modules/TradeModule/DealModule/SpreadOptionValidator.cs
T
2024-05-09 14:06:26 +08:00

158 lines
6.3 KiB
C#

using YLErp.BLL;
using YLErp.Model;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeModule.DealModule
{
/// <summary>
/// 价差期权数据验证
/// </summary>
public static class SpreadOptionValidator
{
/// <summary>
/// 验证价差期权数据
/// </summary>
public static string Validate(trade req)
{
var errorMsg = "";
SpreadOptionPayoff payoff = null;
try
{
payoff = new SpreadOptionPayoff(req.trade_spread_option.Payoff);
}
catch (ArgumentException e)
{
errorMsg = e.Message;
}
var numberOfUnderlyings = payoff.Weights.Length;
if (string.IsNullOrEmpty(errorMsg))
{
req.trade_spread_option.UnderlyingId1 = req.UnderlyingId;
req.trade_spread_option.UnderlyingAssetCode1 = req.UnderlyingCode;
req.trade_spread_option.TradeOpenVolatility1 = req.TradeOpenVolatility;
req.trade_spread_option.TradeCloseVolatility1 = req.TradeCloseVolatility;
req.trade_spread_option.NumOfSmoothingDays1 = req.NumOfSmoothingDays;
// remove redundant underlying ids/codes
if (numberOfUnderlyings == 2)
{
req.trade_spread_option.UnderlyingId3 = null;
req.trade_spread_option.UnderlyingId4 = null;
req.trade_spread_option.UnderlyingAssetCode3 = null;
req.trade_spread_option.UnderlyingAssetCode4 = null;
}
else if (numberOfUnderlyings == 3)
{
req.trade_spread_option.UnderlyingId4 = null;
req.trade_spread_option.UnderlyingAssetCode4 = null;
}
if (!req.trade_spread_option.UnderlyingId1.HasValue ||
string.IsNullOrEmpty(req.trade_spread_option.UnderlyingAssetCode1) ||
!req.trade_spread_option.UnderlyingId2.HasValue ||
string.IsNullOrEmpty(req.trade_spread_option.UnderlyingAssetCode2))
{
errorMsg = "标的ID和代码不能为空";
}
if (string.IsNullOrEmpty(errorMsg) && numberOfUnderlyings >= 3)
{
if (!req.trade_spread_option.UnderlyingId3.HasValue ||
string.IsNullOrEmpty(req.trade_spread_option.UnderlyingAssetCode3))
{
errorMsg = "标的ID和代码不能为空";
}
if (string.IsNullOrEmpty(errorMsg) && numberOfUnderlyings >= 4)
{
if (!req.trade_spread_option.UnderlyingId4.HasValue ||
string.IsNullOrEmpty(req.trade_spread_option.UnderlyingAssetCode4))
{
errorMsg = "标的ID和代码不能为空";
}
}
}
}
if (string.IsNullOrEmpty(errorMsg))
{
errorMsg = checkSpreadOptionVolatilitySettings(req, numberOfUnderlyings);
}
if (string.IsNullOrEmpty(errorMsg))
{
errorMsg = checkCorrelations(req.trade_spread_option);
}
return errorMsg;
}
private static string checkCorrelations(trade_spread_option spreadOption)
{
var errorMsg = "";
var ids = spreadOption.UnderlyingIds();
var codes = spreadOption.UnderlyingAssetCodes();
using (var db = DbContextFactory.GetYLDbContext())
{
for (int i = 0; i < ids.Length - 1 && string.IsNullOrEmpty(errorMsg); i++)
{
for (int j = i + 1; j < ids.Length && string.IsNullOrEmpty(errorMsg); j++)
{
if (correlationBLL.findCorrelation(ids[i], ids[j], db) == 0.0)
{
errorMsg = $"未设定{codes[i]}与{codes[j]}的相关性";
}
}
}
}
return errorMsg;
}
private static string checkSpreadOptionVolatilitySettings(trade req, int numberOfUnderlyings)
{
var errorMsg = checkVolatilitySetting(req.trade_spread_option.TradeOpenVolatility2,
req.trade_spread_option.TradeCloseVolatility2,
req.trade_spread_option.NumOfSmoothingDays2,
req.StartDate, req.ExerciseDate);
if (string.IsNullOrEmpty(errorMsg) && numberOfUnderlyings >= 3)
{
errorMsg = checkVolatilitySetting(req.trade_spread_option.TradeOpenVolatility3,
req.trade_spread_option.TradeCloseVolatility3,
req.trade_spread_option.NumOfSmoothingDays3,
req.StartDate, req.ExerciseDate);
}
if (string.IsNullOrEmpty(errorMsg) && numberOfUnderlyings >= 4)
{
errorMsg = checkVolatilitySetting(req.trade_spread_option.TradeOpenVolatility4,
req.trade_spread_option.TradeCloseVolatility4,
req.trade_spread_option.NumOfSmoothingDays4,
req.StartDate, req.ExerciseDate);
}
return errorMsg;
}
private static string checkVolatilitySetting(double? open, double? close, int? smoothing, DateTime? startDate, DateTime? exerciseDate)
{
if (open.HasValue && open.Value < 0)
{
return "开仓波动率不能小于0";
}
if (close.HasValue && close.Value < 0)
{
return "目标波动率不能小于0";
}
if (smoothing.HasValue)
{
if (smoothing.Value < 0)
{
return "平滑过渡天数不能小于0";
}
if (exerciseDate.HasValue && startDate.HasValue
&& smoothing > QdpCalendarHelper.GetNonHolidayDaysBetween(startDate.Value, exerciseDate.Value) + 1)
{
return "平滑过渡天数不能大于存续天数";
}
}
return "";
}
}
}