using Qdp.Foundation.Implementations; using Qdp.Pricing.Base.Enums; using Qdp.Pricing.Base.Implementations; using System.Runtime.CompilerServices; namespace YLErp.QdpModule { /// /// QDP观察条款帮助类 /// public static class QdpObservationHelper { #region----在一段日期中,使用固定的期限获取一组日期---- /// /// 在一段日期中,使用固定的期限获取一组日期 /// 主要可用于生成期权的观察日 /// /// /// /// /// public static DateTime[] GetDatesWithFixedTerm( DateTime startDate, DateTime endDate, string termStr, BusinessDayConvention bdc = BusinessDayConvention.None, bool alignEnd = false, string calcMode = "01") { if (!Term.IsTerm(termStr)) { return null; } return GetDatesWithFixedTerm(startDate, endDate, new Term(termStr), bdc, alignEnd, calcMode); } /// /// 在一段日期中,使用固定的期限获取一组日期 /// 主要可用于生成期权的观察日 /// /// alignEnd为false时,生成的日期是向开始日对齐,例如: /// startDate=2019-09-11, endDate=2019-12-26, term=1M, bdc=None /// 生成的日期序列为:2019-09-11,2019-10-11,2019-11-11,2019-12-11,2019-12-26 /// /// alignEnd为true时,生成的日期是想结束日对齐 /// 生成的日期序列为:2019-09-26,2019-10-26,2019-11-26,2019-12-26 /// /// /// /// 日期之前的间隔期限 /// 遇到节假日的调整规则 /// 生成的日期序列是否向结束日对齐 /// 是否包含开始日当天 /// public static DateTime[] GetDatesWithFixedTerm( DateTime startDate, DateTime endDate, Term term, BusinessDayConvention bdc = BusinessDayConvention.None, bool alignEnd = false, string calcMode = "01") { return alignEnd ? GetDatesWithFixedTermStartAlignEnd(startDate, endDate, term, bdc, calcMode) : GetDatesWithFixedTermStartAlignStart(startDate, endDate, term, bdc, calcMode); } private static DateTime[] GetDatesWithFixedTermStartAlignEnd( DateTime startDate, DateTime endDate, Term term, BusinessDayConvention bdc = BusinessDayConvention.None, string calcMode = "01") { var qdpStart = new Date(startDate); var qdpEnd = new Date(endDate); var dates = new List(); var calendar = CalendarImpl.Get("chn"); if (calcMode == "11")//算头算尾 { while (qdpEnd >= qdpStart) { dates.Add(qdpEnd); qdpEnd = term.Prev(qdpEnd); } } else if (calcMode == "10")//算头不算尾 { qdpEnd = term.Prev(qdpEnd); while (qdpEnd >= qdpStart) { dates.Add(qdpEnd); qdpEnd = term.Prev(qdpEnd); } } else if (calcMode == "01")//不算头算尾 { while (qdpEnd > qdpStart) { dates.Add(qdpEnd); qdpEnd = term.Prev(qdpEnd); } } else if (calcMode == "00")//不算头不算尾 { qdpEnd = term.Prev(qdpEnd); while (qdpEnd > qdpStart) { dates.Add(qdpEnd); qdpEnd = term.Prev(qdpEnd); } } //简单规则生成日期时,周期为空就用到期日 if (dates.Count == 0) { dates.Add(new Date(endDate)); } dates = dates.Select(d => calendar.Adjust(d, bdc)).Distinct().ToList(); dates.Reverse(); return dates.Select(x => x.DateTime).ToArray(); } private static DateTime[] GetDatesWithFixedTermStartAlignStart( DateTime startDate, DateTime endDate, Term term, BusinessDayConvention bdc = BusinessDayConvention.None, string calcMode = "01") { var qdpStart = new Date(startDate); var qdpEnd = new Date(endDate); var dates = new List(); var calendar = CalendarImpl.Get("chn"); if (calcMode == "11")//算头算尾 { while (qdpStart <= qdpEnd) { dates.Add(qdpStart); qdpStart = term.Next(qdpStart); } } else if (calcMode == "10")//算头不算尾 { while (qdpStart < qdpEnd) { dates.Add(qdpStart); qdpStart = term.Next(qdpStart); } } else if (calcMode == "01")//不算头算尾 { qdpStart = term.Next(qdpStart); while (qdpStart <= qdpEnd) { dates.Add(qdpStart); qdpStart = term.Next(qdpStart); } } else if (calcMode == "00")//不算头不算尾 { qdpStart = term.Next(qdpStart); while (qdpStart < qdpEnd) { dates.Add(qdpStart); qdpStart = term.Next(qdpStart); } } dates = dates.Select(d => calendar.Adjust(d, bdc)).Distinct().ToList(); //简单规则生成日期时,周期为空就用到期日 if (dates.Count == 0) { dates.Add(qdpEnd); } return dates.Select(x => x.DateTime).ToArray(); } /// /// 在一段日期中,使用固定的期限获取观察日字符串 /// /// /// /// /// public static string GetObservationDateString( DateTime startDate, DateTime endDate, string termStr, BusinessDayConvention bdc = BusinessDayConvention.None, bool alignEnd = false) { var dates = GetDatesWithFixedTerm(startDate, endDate, termStr, bdc, alignEnd); return string.Join(",", dates.Select(x => x.ToString("yyyy-MM-dd"))); } #endregion /// /// 为雪球返回默认的敲出观察日数据(按月观察) /// [MethodImpl(methodImplOptions: MethodImplOptions.AggressiveInlining)] public static DateTime[] GetDefaultKoObservationDatesForSnowbal(DateTime startDate, DateTime endDate) { return GetDatesWithFixedTerm(startDate, endDate, "1M", bdc: BusinessDayConvention.Following, alignEnd: true); } /// /// 为雪球返回默认的敲出观察日数据(按月观察) /// public static Date[] GetDefaultKoObservationDatesForSnowbalV2(DateTime startDate, DateTime endDate) { var monthlyDates = GetDefaultKoObservationDatesForSnowbal(startDate, endDate); return monthlyDates.Select(x => (Date)x).ToArray(); } public static DateTime[] GetDatesWithFixedTerm( DateTime startDate, DateTime endDate, string termStr, string calendarStr, BusinessDayConvention bdc = BusinessDayConvention.None, bool alignEnd = false, string calcMode = "01") { if (!Term.IsTerm(termStr)) { return null; } var calendarName = string.IsNullOrEmpty(calendarStr) ? "chn" : calendarStr.ToLower(); return GetDatesWithFixedTerm(startDate, endDate, new Term(termStr), calendarName, bdc, alignEnd, calcMode); } public static DateTime[] GetDatesWithFixedTerm( DateTime startDate, DateTime endDate, Term term, string calendarStr, BusinessDayConvention bdc = BusinessDayConvention.None, bool alignEnd = false, string calcMode = "01") { var calendarName = string.IsNullOrEmpty(calendarStr) ? "chn" : calendarStr.ToLower(); return alignEnd ? GetDatesWithFixedTermStartAlignEnd(startDate, endDate, term, calendarName, bdc, calcMode) : GetDatesWithFixedTermStartAlignStart(startDate, endDate, term, calendarName, bdc, calcMode); } private static DateTime[] GetDatesWithFixedTermStartAlignEnd( DateTime startDate, DateTime endDate, Term term, string calendarName, BusinessDayConvention bdc = BusinessDayConvention.None, string calcMode = "01") { var qdpStart = new Date(startDate); var qdpEnd = new Date(endDate); var dates = new List(); var calendar = CalendarImpl.Get(calendarName); if (calcMode == "11") { while (qdpEnd >= qdpStart) { dates.Add(qdpEnd); qdpEnd = term.Prev(qdpEnd); } } else if (calcMode == "10") { qdpEnd = term.Prev(qdpEnd); while (qdpEnd >= qdpStart) { dates.Add(qdpEnd); qdpEnd = term.Prev(qdpEnd); } } else if (calcMode == "01") { while (qdpEnd > qdpStart) { dates.Add(qdpEnd); qdpEnd = term.Prev(qdpEnd); } } else if (calcMode == "00") { qdpEnd = term.Prev(qdpEnd); while (qdpEnd > qdpStart) { dates.Add(qdpEnd); qdpEnd = term.Prev(qdpEnd); } } if (dates.Count == 0) { dates.Add(new Date(endDate)); } dates = dates.Select(d => calendar.Adjust(d, bdc)).Distinct().ToList(); dates.Reverse(); return dates.Select(x => x.DateTime).ToArray(); } private static DateTime[] GetDatesWithFixedTermStartAlignStart( DateTime startDate, DateTime endDate, Term term, string calendarName, BusinessDayConvention bdc = BusinessDayConvention.None, string calcMode = "01") { var qdpStart = new Date(startDate); var qdpEnd = new Date(endDate); var dates = new List(); var calendar = CalendarImpl.Get(calendarName); if (calcMode == "11") { while (qdpStart <= qdpEnd) { dates.Add(qdpStart); qdpStart = term.Next(qdpStart); } } else if (calcMode == "10") { while (qdpStart < qdpEnd) { dates.Add(qdpStart); qdpStart = term.Next(qdpStart); } } else if (calcMode == "01") { qdpStart = term.Next(qdpStart); while (qdpStart <= qdpEnd) { dates.Add(qdpStart); qdpStart = term.Next(qdpStart); } } else if (calcMode == "00") { qdpStart = term.Next(qdpStart); while (qdpStart < qdpEnd) { dates.Add(qdpStart); qdpStart = term.Next(qdpStart); } } dates = dates.Select(d => calendar.Adjust(d, bdc)).Distinct().ToList(); if (dates.Count == 0) { dates.Add(qdpEnd); } return dates.Select(x => x.DateTime).ToArray(); } public static ObservationSettleDateResult[] GetObservationAndSettleDates( DateTime startDate, DateTime endDate, string termStr, string calendarStr, int settlementRules, BusinessDayConvention bdc = BusinessDayConvention.None, bool alignEnd = false, string calcMode = "01") { if (!Term.IsTerm(termStr)) { return null; } var calendarName = string.IsNullOrEmpty(calendarStr) ? "chn" : calendarStr.ToLower(); var calendar = CalendarImpl.Get(calendarName); var term = new Term(termStr); DateTime[] observationDates = alignEnd ? GetDatesWithFixedTermStartAlignEnd(startDate, endDate, term, calendarName, bdc, calcMode) : GetDatesWithFixedTermStartAlignStart(startDate, endDate, term, calendarName, bdc, calcMode); var results = new List(); foreach (var obsDate in observationDates) { var settleDate = obsDate.AddDays(settlementRules); settleDate = calendar.Adjust(new Date(settleDate), bdc).DateTime; results.Add(new ObservationSettleDateResult { ObservationDate = obsDate, SettleDate = settleDate }); } return results.ToArray(); } } public class ObservationSettleDateResult { public DateTime ObservationDate { get; set; } public DateTime SettleDate { get; set; } } }