244 lines
11 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|