Files
zszq-trs/YLErpDAL/Modules/VolatilityModule/VolatilityService.cs
2024-05-09 14:06:26 +08:00

244 lines
11 KiB
C#

using BaseOUDAL;
using Qdp.Pricing.Base.Implementations;
using Qdp.Pricing.Library.Equity.Engines.Analytical;
using YLErp.BLL;
using YLErp.Model;
using YLErp.QdpModule;
namespace YLErp.Modules.VolatilityModule
{
/// <summary>
/// 波动率处理服务
/// </summary>
public class VolatilityService : YLBaseService
{
public VolatilityService(OptUserInfo userInfo) : base(userInfo)
{
}
public double GetTradeVol(trade trade, DateTime date)
{
TradeVolatility tradeVol = null;
using (YLContext ylDb = new YLContext())
{
tradeVol = ylDb.TradeVolatility.Where(n => n.TradeId == trade.id && n.ValueDate <= date)
.OrderByDescending(O => O.ValueDate).FirstOrDefault();
}
return GetTradeVol(trade, tradeVol, date);
}
public void GetTradeVol(List<trade> trades, DateTime date)
{
Dictionary<int, TradeVolatility> volDic = new Dictionary<int, TradeVolatility>();
List<int> ids = trades.Where(t => !ConsTrade.TradeTypesForHedge.Contains(t.TradeType) && t.StartDate <= date).Select(O => O.id).ToList();
using (YLContext ylDb = new YLContext())
{
var tempQuery = DbContext.TradeVolatility.Where(O => O.ValueDate <= date && ids.Contains(O.TradeId));
if (tempQuery.Any())
{
var groupQuery = tempQuery.GroupBy(O => O.TradeId).Select(n => new { TradeId = n.Key, ValueDate = n.Max(m => m.ValueDate) });
var query = from a in DbContext.TradeVolatility
join b in groupQuery on new { a.TradeId, a.ValueDate } equals new { b.TradeId, b.ValueDate }
select a;
volDic = query.ToDictionary(K => K.TradeId);
}
}
foreach (var t in trades)
{
if (t.StartDate > date || ConsTrade.TradeTypesForHedge.Contains(t.TradeType))
{
continue;
}
volDic.TryGetValue(t.id, out var tradeVol);
t.Vol = GetTradeVol(t, tradeVol, date);
}
}
private double GetTradeVol(trade trade, TradeVolatility tradeVol, DateTime date)
{
var daycountMode = PS.Config.ErpElement.SmoothingDaycountMode == Configuration.Enums.SmoothingDaycountMode.CalendarDay
? Qdp.Pricing.Base.Enums.DayCountMode.CalendarDay
: Qdp.Pricing.Base.Enums.DayCountMode.TradingDay;
if (tradeVol == null)
{
try
{
return AnalyticalOptionTradeVolInterp.tradeVolLinearInterp(
new Qdp.Foundation.Implementations.Date(date),
trade.TradeOpenVolatility ?? 0,
trade.TradeCloseVolatility ?? 0,
new Qdp.Foundation.Implementations.Date(trade.StartDate ?? DateTime.Today),
new Qdp.Foundation.Implementations.Date(trade.ExerciseDate ?? DateTime.Today),
trade.NumOfSmoothingDays ?? 0,
daycountMode,
CalendarImpl.Get("chn"));
}
catch
{
return double.NaN;
}
}
else
{
return AnalyticalOptionTradeVolInterp.tradeVolLinearInterp(
new Qdp.Foundation.Implementations.Date(date),
tradeVol.TradePositionVolatility ?? 0,
tradeVol.TradeCloseVolatility ?? 0,
new Qdp.Foundation.Implementations.Date(tradeVol.ValueDate),
new Qdp.Foundation.Implementations.Date(trade.ExerciseDate ?? DateTime.Today),
tradeVol.NumOfSmoothingDays ?? 0,
daycountMode,
CalendarImpl.Get("chn"),
includeStartDate: tradeVol.IsFromTradeAdd);
}
}
/// <summary>
/// 从数据库中查询波动率信息(此处的userGroup参数允许为NULL)
private IQueryable<volatility> _getVolQuery(DateTime date, IEnumerable<string> codes, IEnumerable<string> volTypes = null, string userGroup = null)
{
codes = codes.ToHashSet();
if (volTypes == null)
{
volTypes = DbContext.volatility.Select(O => O.VolType).GroupBy(O => O).Select(O => O.Key).ToList();
}
var queryGroup = (from vol in DbContext.volatility
where vol.QuotationDate <= date
&& codes.Contains(vol.ContractCode)
&& (userGroup == null || vol.UserGroup == userGroup)
&& volTypes.Contains(vol.VolType)
group vol by new { vol.QuotationDate, vol.ContractCode, vol.UserGroup, vol.VolType } into grp
select grp.Key);
var queryKey = queryGroup.GroupBy(O => new { O.ContractCode, O.UserGroup, O.VolType }).Select(O => new { O.Key.ContractCode, O.Key.UserGroup, O.Key.VolType, QuotationDate = O.Max(M => M.QuotationDate) });
return from vol in DbContext.volatility.AsNoTracking()
join dict in queryKey
on new { vol.QuotationDate, vol.ContractCode, vol.UserGroup, vol.VolType } equals new { dict.QuotationDate, dict.ContractCode, dict.UserGroup, dict.VolType }
select vol;
}
/// <summary>
/// 从数据库中查询波动率信息(此处的userGroup参数允许为NULL)
private IQueryable<volatility> _getVolQuery(DateTime startDate, DateTime endDate, IEnumerable<string> codes, IEnumerable<string> volTypes = null, string userGroup = null)
{
codes = codes.ToHashSet();
if (volTypes == null)
{
volTypes = DbContext.volatility.Select(O => O.VolType).GroupBy(O => O).Select(O => O.Key).ToList();
}
var query = from vol in DbContext.volatility.AsNoTracking()
where vol.QuotationDate >= startDate
&& vol.QuotationDate <= endDate
&& codes.Contains(vol.ContractCode)
&& (userGroup == null || vol.UserGroup == userGroup)
&& volTypes.Contains(vol.VolType)
select vol;
return _getVolQuery(startDate, codes, volTypes, userGroup).Union(query);
}
/// <summary>
/// 查询volatility
/// </summary>
public SearchListResult<volatility> SearchList(VolatilityReq req)
{
IEnumerable<string> codes = null;
if (req.UnderlyingId != null)
{
codes = new[] { underlying_managerBLL.GetById(req.UnderlyingId.Value).UnderlyingCode };
}
if (!string.IsNullOrEmpty(req.UnderlyingName))
{
codes = new[] { underlying_managerBLL.GetQuery().Where(O => O.UnderlyingName == req.UnderlyingName).FirstOrDefault().UnderlyingCode };
}
if (!string.IsNullOrEmpty(req.ContractCode))
{
codes = new[] { req.ContractCode };
}
if (req.QuotationDate == null || req.QuotationDate?.Year <= 2000)
{
if ((req.QuotationDateStart == null || req.QuotationDateStart?.Year < 2000) && (req.QuotationDateEnd == null || req.QuotationDateEnd?.Year < 2000))
{
req.QuotationDate = SystemValueDate;
req.QuotationDateStart = SystemValueDate;
req.QuotationDateEnd = req.QuotationDateStart;
}
else if (req.QuotationDateStart == null || req.QuotationDateStart?.Year < 2000)
{
req.QuotationDateStart = req.QuotationDateEnd;
}
else if (req.QuotationDateEnd == null || req.QuotationDateEnd?.Year < 2000)
{
req.QuotationDateEnd = SystemValueDate;
}
if (req.QuotationDateStart >= req.QuotationDateEnd)
{
req.QuotationDateEnd = req.QuotationDateStart;
}
}
if (codes == null)
{
codes = (from temp in underlying_managerBLL.GetQuery()
where temp.LaunchState == "1"
select temp.UnderlyingCode).ToList();
}
IQueryable<volatility> query = null;
if (req.QuotationDate != null && req.QuotationDate.Value > DateTime.MinValue)
{
query = _getVolQuery(req.QuotationDate.Value, codes, userGroup: req.UserGroup);
}
else
{
query = _getVolQuery(req.QuotationDateStart.Value, req.QuotationDateEnd.Value, codes, userGroup: req.UserGroup);
}
if (!string.IsNullOrEmpty(req.VolType))
{
query = query.Where(d => d.VolType.Contains(req.VolType));
}
if (req.OptId != null)
{
query = query.Where(d => d.OptId == req.OptId);
}
if (!string.IsNullOrEmpty(req.OptName))
{
query = query.Where(d => d.OptName.Contains(req.OptName));
}
req.sidx = "QuotationDate";
req.sord = "asc";
var tempSearchList = query.ToSearchList(req);
List<DateTime> dates = QdpCalendarHelper.AllBizDays(req.QuotationDateStart.Value, req.QuotationDateEnd.Value.AddDays(1));
List<volatility> vols = new List<volatility>();
var firstVol = tempSearchList.rows.FirstOrDefault();
if (firstVol != null)
{
foreach (var item in dates)
{
var vol = tempSearchList.rows.FirstOrDefault(O => O.QuotationDate == item);
if (vol == null && firstVol.QuotationDate < item)
{
vol = firstVol.Clone(item);
}
else
{
firstVol = vol;
}
vols.Add(vol);
}
tempSearchList.records = vols.Count;
tempSearchList.rows = vols;
}
return tempSearchList;
}
}
}