Files
zszq-trs/YLErpDAL/Modules/CalculationModule/PayoffSwapCalcService.cs
T
2024-06-21 13:45:43 +08:00

669 lines
30 KiB
C#

using Qdp.Foundation.Implementations;
using YLErp.Abstract.DataProviders;
using YLErp.BLL;
using YLErp.Commons;
using YLErp.DBModels.Enums;
using YLErp.DBModels;
using YLErp.Modules.DataProviderModule;
using YLErp.Modules.EodModule;
using YLErp.QdpModule;
using NPOI.SS.Formula.Functions;
namespace YLErp.Modules.CalculationModule
{
/// <summary>
/// 收益互换计算服务
/// </summary>
public class PayoffSwapCalcService
{
/// <summary>
/// 因为互换涉及到多标的所以需要确保所有标的都可以找到价格
/// </summary>
private static IAggregatePriceProvider GetAutoPriceProvider(DateTime valueDate, IPriceProvider priceProvider, bool isEodSettlement)
{
if (priceProvider is IAggregatePriceProvider)
{
return (IAggregatePriceProvider)priceProvider;
}
if (isEodSettlement)
{
return new AggregatePriceProvider(priceProvider,
new EodPriceProvider(valueDate).GetPriceProvider(priceProvider is IEodPriceProviderWrap wrap ? wrap.SettlementType : SettlementTypeEnum.ClosePrice));
}
return new AggregatePriceProvider(priceProvider, DataCacheProvider.GetUnderlyingDataSource());
}
/// <summary>
///
/// </summary>
public static TradeValueResult CalcValue(int tradeId, DateTime valueDate, IPriceProvider priceProvider, bool isEodSettlement)
{
using (var db = DbContextFactory.GetYLDbContext())
{
var trade = db.trade.Find(tradeId);
if (trade == null)
{
return new TradeValueResult(false)
{
TradeId = tradeId,
FailReason = TradeValueFailReason.missingTrade,
ErrorMessage = "[收益互换]没有找到交易数据,tradeId:" + tradeId
};
}
return CalcValue(trade, valueDate, priceProvider, isEodSettlement);
}
}
public static TradeValueResult CalcValue(OtcTradeBase trade, DateTime valueDate, IPriceProvider priceProvider, bool isEodSettlement)
{
return CalcValueSingle(trade, valueDate, priceProvider, isEodSettlement);
}
/// <summary>
/// 互换收益PV计算 普通
/// </summary>
public static TradeValueResult CalcValueSingle(OtcTradeBase trade, DateTime valueDate, IPriceProvider priceProvider, bool isEodSettlement, double spotPrice = double.NaN)
{
if (trade is null)
{
throw new ArgumentNullException(nameof(trade));
}
if(double.IsNaN(spotPrice))
{
//因为互换涉及到多标的所以需要确保所有标的都可以找到价格
if (trade.StructureType== "多空组合")
{
spotPrice = 0;
}
else
{
priceProvider = GetAutoPriceProvider(valueDate, priceProvider, isEodSettlement);
if (!priceProvider.TryGetPrice(trade.UnderlyingCode, out spotPrice))
{
spotPrice = DataCacheProvider.GetUnderlyingDataSource().GetPrice(trade.UnderlyingCode);
}
}
}
using (var db = DbContextFactory.GetYLDbContext())
{
var client = DataCacheProvider.GetClientDataSource().GetData(trade.ClientId);
var rate = new EodCurrencyRateService(OptUserInfo.SystemUser).GetCurrencyRate(trade.QuoteCurrency, trade.SettlementCurrency, valueDate, seekPreday: !isEodSettlement);
var rateTradeDate = new EodCurrencyRateService(OptUserInfo.SystemUser).GetCurrencyRate(trade.QuoteCurrency, trade.SettlementCurrency, trade.TradeDate.Value, seekPreday: !isEodSettlement);
var lastEodSwap = GetEodSwapData(trade, db);
var pv = lastEodSwap.PostionValue;
var clientCashOut= db.ClientCashInCashOut.FirstOrDefault(x=>x.Action== "系统操作-期权费"&&x.TradeId== trade.id&&x.HappenDate<= valueDate) ;
var credit = db.credit.FirstOrDefault(x => x.CreditStartDate <= valueDate && x.CreditDeadLine >= valueDate && x.ClientId == trade.ClientId && x.ProcessStatus == "已审批");
var hasCredit = credit != null && credit.PFECredit > 0;
client_variety_marginrate clientVarietyMarginRate = new client_variety_marginrate
{
ClientId = trade.ClientId,
ClientName = trade.ClientName,
HighMarginRate = 1,
LowMarginRate = 1,
ValueDate = valueDate,
};
var OptionValue = new TradeValueResult
{
TradeId = trade.id,
Pv =Convert.ToDouble(pv),
ExtendInfo = new TradeValueResultExtend()
{
QuoteFloatingWinLoss =Convert.ToDouble(lastEodSwap.FloatingPnL),
FloatingWinLoss = Convert.ToDouble(lastEodSwap.FloatingPnL) * rate,
RealPnl = Convert.ToDouble(lastEodSwap.RealizedPnL) * rate,
QuoteCommission = clientCashOut?.Money??0,
Commission = (clientCashOut?.Money ?? 0) * rate,
QuoteAnnualFee = 0,
AnnualFee = 0,
QuotePv = Convert.ToDouble(pv),
QuoteIM = client.BoundSide == BoundSideEnum.南向 ? (trade.Notional * spotPrice * clientVarietyMarginRate.LowMarginRate) : (trade.StockEqvNotional * (hasCredit ? clientVarietyMarginRate.LowMarginRate : clientVarietyMarginRate.HighMarginRate)),
IM = (client.BoundSide == BoundSideEnum.南向 ? (trade.Notional * spotPrice * clientVarietyMarginRate.LowMarginRate) : (trade.StockEqvNotional * (hasCredit ? clientVarietyMarginRate.LowMarginRate : clientVarietyMarginRate.HighMarginRate))) * rate,
QuotePFE = client.BoundSide == BoundSideEnum.南向 ? trade.Notional * spotPrice * clientVarietyMarginRate.HighMarginRate : 0,
PFE = client.BoundSide == BoundSideEnum.南向 ? trade.Notional * spotPrice * clientVarietyMarginRate.HighMarginRate * rate : 0
},
RoundedPv = Convert.ToDouble(pv),
Delta = (lastEodSwap.MarketValueLong>0 ? 1 : -1) * trade.Notional,
Gamma = 0,
Vega = 0,
TradingDayTheta = 0,
CalendarDayTheta = 0,
Rho = 0,
DeltaCash = (lastEodSwap.MarketValueLong > 0 ? spotPrice : -spotPrice) * trade.Notional,
GammaCash = 0,
SpotPrice= spotPrice
};
return OptionValue;
}
}
/// <summary>
/// 构建eodswap
/// </summary>
/// <param name="tradeId"></param>
/// <param name="db"></param>
/// <returns></returns>
private static eod_swap GetEodSwapData(OtcTradeBase trade, YLContext db)
{
var eodSwap = new eod_swap();
var positions = db.swap_position.Where(x => x.PosiQuantity > 0 && !x.IsInitial && x.SwapTradeId == trade.id).ToList();
eodSwap.SwapTradeId = trade.id;
eodSwap.NotionalValueLong = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Long).Sum(s => s.PosiNotionalValue);
eodSwap.NotionalValueShort = positions.Where(x => x.PositionType == (int)PositionTypeFlag.Short).Sum(s => s.PosiNotionalValue);
eodSwap.NotionalValue = eodSwap.NotionalValueLong + eodSwap.NotionalValueShort;
var lastEod = db.eod_swap.Where(x => x.SwapTradeId == trade.id && x.ValueDate <= valuedateBLL.ValueDate).OrderByDescending(o => o.ValueDate).FirstOrDefault();
eodSwap.RealizedPnL = lastEod?.RealizedPnL ?? 0;
eodSwap.InterestPnL = lastEod?.InterestPnL ?? 0;
foreach (var item in positions)
{
decimal shortRatio = item.PositionType == (int)PositionTypeFlag.Long ? 1 : -1;//多空方向
int directionRatio = item.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;
var pv = item.PosiQuantity * shortRatio * item.ContractSize;
var pvNoPrice = item.PosiQuantity * item.ContractSize;
var data = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode);
if (data != null)
{
if (data.IsBond())
{
var bondPrice = EodPriceQueryService.GetBondPrice(valuedateBLL.ValueDate, data.UnderlyingCode);
var price = Convert.ToDecimal(bondPrice?.ClosePrice??0);
eodSwap.FloatingPnL = (price - item.PosiGrossPrice) * item.PosiQuantity * item.ContractSize * shortRatio * directionRatio;
}
}
if (shortRatio > 0)
{
eodSwap.MarketValueLong += pv;
}
else
{
eodSwap.MarketValueShort += pv;
}
eodSwap.NotionalValue += pvNoPrice;
}
eodSwap.PostionValue = lastEod?.PostionValue ?? 0;
return eodSwap;
}
/// <summary>
/// 获取互换固定收益PV
/// </summary>
/// <param name="trades"></param>
/// <param name="valueDate"></param>
/// <returns></returns>
public static Dictionary<int, double> GetFixedInterestRatePV(List<int> tradeIds, DateTime valueDate)
{
var result = new Dictionary<int, double>();
if (tradeIds == null || tradeIds.Count == 0)
{
return result;
}
List<trade_swap> tradeSwapList = null;
List<trade_cash> tradeCashList = null;
List<trade_cash_swap> tradeCashSwapList = null;
List<trade> tradeList = null;
List<eod_trade> eodTradeList = null;
using (var db = DbContextFactory.GetYLDbContext())
{
//tradeList = db.trade.AsNoTracking().Where(p => tradeIds.Contains(p.id)).ToList();
eodTradeList = db.eod_trade.AsNoTracking().Where(p => p.ValueDate == valueDate && tradeIds.Contains(p.TradeId)).ToList();
tradeSwapList = db.trade_swap.AsNoTracking().Where(p => tradeIds.Contains(p.TradeId)).ToList();
tradeCashList = db.trade_cash.AsNoTracking().Where(y => tradeIds.Contains(y.TradeId) && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= valueDate).ToList();
tradeCashSwapList = db.trade_cash_swap.AsNoTracking().Where(p => tradeIds.Contains(p.TradeId)).ToList();
}
if (tradeSwapList == null)
{
tradeSwapList = new List<trade_swap>();
}
if (tradeCashList == null)
{
tradeCashList = new List<trade_cash>();
}
if (tradeCashSwapList == null)
{
tradeCashSwapList = new List<trade_cash_swap>();
}
if (eodTradeList != null && eodTradeList.Count > 0)
{
tradeList = eodTradeList.Select(p => p.trade).ToList();
}
if (tradeList == null)
{
tradeList = new List<trade>();
}
if (tradeList.Count > 0)
{
foreach (var trade in tradeList)
{
var tradeSwap = tradeSwapList.FirstOrDefault(d => d.TradeId == trade.id);
if (tradeSwap == null)
{
continue;
}
var tradeCashs = tradeCashList.Where(y => y.TradeId == trade.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= valueDate);
var tradeCashIds = tradeCashs.Select(x => x.id);
var tradeCash = tradeCashs.OrderByDescending(y => y.id).FirstOrDefault();
var cashSwaps = tradeCashSwapList.Where(x => x.TradeId == trade.id && tradeCashIds.Contains(x.TradeCashId)).ToArray();
//var tradeCashSwap = tradeCash != null ? cashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id) : null;
//取最后一次手动收益;
var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto);
var lastManualCash = lastManualCashSwap != null ? tradeCashs.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null;
DateTime endDate;
double fixAmount = 0;
if (!tradeSwap.IsGetFloatingProfit)
{
var preSwapDate = GetSwapRateStartDate(trade, tradeSwap, valueDate, tradeCash, lastManualCash, tradeSwap.IsGetFloatingProfit, out endDate);
var extraAmountGet = GetExtraAmountBySwapRate(trade.ClientId, trade.TradeDate, tradeSwap.GetSwapTimeAndRate, preSwapDate, endDate, tradeSwap.AnnualDays ?? 0, trade.StockEqvNotional);
fixAmount += extraAmountGet;
}
if (!tradeSwap.IsPayFloatingProfit)
{
var preSwapDate = GetSwapRateStartDate(trade, tradeSwap, valueDate, tradeCash, lastManualCash, tradeSwap.IsPayFloatingProfit, out endDate);
var extraAmountPay = GetExtraAmountBySwapRate(trade.ClientId, trade.TradeDate, tradeSwap.PaySwapTimeAndRate, preSwapDate, endDate, tradeSwap.AnnualDays ?? 0, trade.StockEqvNotional);
fixAmount -= extraAmountPay;
}
result.Add(trade.id, fixAmount);
}
}
return result;
}
/// <summary>
/// 多空组合PV计算 子交易计算模式
/// </summary>
public static TradeValueResult CalcValue(OtcTradeBase trade, trade_swap trade_swap, List<trade_swap_detail> trade_swap_details, DateTime valueDate, IPriceProvider priceProvider, bool isEodSettlement)
{
if (trade_swap.SwapType == "多空组合")
{
using (var db = DbContextFactory.GetYLDbContext())
{
var tradeIds = trade_swap_details.Select(t => t.ChildTradeId).ToList();
var subTradeList = db.trade.Where(t => tradeIds.Contains(t.id)).ToList();
var resultList = new List<TradeValueResult>();
foreach (var subTrade in subTradeList)
{
var price = DataCacheProvider.GetUnderlyingDataSource().GetPrice(subTrade.UnderlyingCode);
var subResult = CalcValue(subTrade, valueDate, priceProvider, isEodSettlement);
resultList.Add(subResult);
}
var OptionValue = new TradeValueResult
{
TradeId = trade.id,
Pv = 0,
ExtendInfo = new TradeValueResultExtend()
{
QuoteFloatingWinLoss = 0,
FloatingWinLoss = 0,
QuoteCommission = 0,
Commission = 0,
QuoteAnnualFee = 0,
AnnualFee = 0,
QuotePv = 0,
QuoteIM = 0,
IM = 0,
QuotePFE = 0,
PFE = 0
},
RoundedPv = 0,
Delta = 0,
Gamma = 0,
Vega = 0,
TradingDayTheta = 0,
CalendarDayTheta = 0,
Rho = 0,
DeltaCash = 0,
GammaCash = 0
};
foreach (var valueResult in resultList)
{
OptionValue.Pv += valueResult.Pv;
OptionValue.ExtendInfo.QuoteFloatingWinLoss += valueResult.ExtendInfo.QuoteFloatingWinLoss;
OptionValue.ExtendInfo.FloatingWinLoss += valueResult.ExtendInfo.FloatingWinLoss;
OptionValue.ExtendInfo.QuoteCommission += valueResult.ExtendInfo.QuoteCommission;
OptionValue.ExtendInfo.Commission += valueResult.ExtendInfo.Commission;
OptionValue.ExtendInfo.QuoteAnnualFee += valueResult.ExtendInfo.QuoteAnnualFee;
OptionValue.ExtendInfo.AnnualFee += valueResult.ExtendInfo.AnnualFee;
OptionValue.ExtendInfo.QuotePv += valueResult.ExtendInfo.QuotePv;
OptionValue.ExtendInfo.QuoteIM += valueResult.ExtendInfo.QuoteIM;
OptionValue.ExtendInfo.IM += valueResult.ExtendInfo.IM;
OptionValue.ExtendInfo.QuotePFE += valueResult.ExtendInfo.QuotePFE;
OptionValue.ExtendInfo.PFE += valueResult.ExtendInfo.PFE;
OptionValue.RoundedPv += valueResult.RoundedPv;
OptionValue.DeltaCash += valueResult.DeltaCash;
}
return OptionValue;
}
}
else
{
return CalcValue(trade,valueDate, priceProvider, isEodSettlement);
}
}
/// <summary>
/// 计算互换利息
/// </summary>
public static double GetExtraAmountBySwapRate(int clientId, DateTime? tradeDate, string timeRate, DateTime startDate, DateTime valueDate, int annualDays, double stockEqvNotional)
{
if (valueDate == tradeDate && PS.Config.Company == Configuration.CompanyEnum.中金)
{
var client = DataCacheProvider.GetClientDataSource().GetData(clientId);
if (client.BoundSide == BoundSideEnum.北向)
{
startDate = startDate.AddDays(-1);
}
}
double extraAmountGet = 0;
var swapDates = GetSwapDatesBetween(timeRate, startDate, valueDate);
if (swapDates != null && swapDates.Any())
{
swapDates.ForEach(x =>
{
var itemDays = (x.DateTime - startDate).Days;
var itemRate = GetSwapRateByDate(timeRate, x.DateTime);
extraAmountGet += stockEqvNotional * itemRate * ((double)itemDays / annualDays);
startDate = x.DateTime;
});
}
if (startDate < valueDate)
{
var latestDays = (valueDate - startDate).Days;
var LatestRate = GetSwapRateByDate(timeRate, valueDate);
extraAmountGet += stockEqvNotional * LatestRate * ((double)latestDays / annualDays);
}
return extraAmountGet.Normalize().FormatValue(2);
}
/// <summary>
/// 获取计息开始日期,结束日期
/// </summary>
/// <param name="td"></param>
/// <param name="valueDate"></param>
/// <param name="tradeCash"></param>
/// <param name="lastManualCashSwap"></param>
/// <param name="floating"></param>
/// <param name="endDate"></param>
/// <returns></returns>
public static DateTime GetSwapRateStartDate(OtcTradeBase td, trade_swap tradeSwap, DateTime valueDate, trade_cash tradeCash, trade_cash lastManualCash, bool floating, out DateTime endDate)
{
var tradeStartDate = PS.Config.Company == Configuration.CompanyEnum.中金 ? td.TradeDate.Value : td.StartDate.Value;
var calcFirst = tradeSwap.RateCalcMode.StartsWith("1");//算头
var calcLast = tradeSwap.RateCalcMode.EndsWith("1");//算尾
DateTime startDate = calcFirst ? tradeStartDate.AddDays(-1) : tradeStartDate;
//如果valueDate超过了到期日,利息以到期日来计算
endDate = valueDate > td.ExerciseDate ? td.ExerciseDate.Value : valueDate;
//是否算尾
if (td.ExerciseDate == endDate && !calcLast)
{
endDate = endDate.AddDays(-1);
}
if (floating)
{
if(lastManualCash != null)
{
startDate = lastManualCash.ValueDate;
}
}
else if (tradeCash != null)
{
startDate = tradeCash.ValueDate;
}
return startDate;
}
/// <summary>
/// 获取计息开始日期,结束日期
/// </summary>
/// <param name="td"></param>
/// <param name="valueDate"></param>
/// <param name="tradeCash"></param>
/// <param name="lastManualCashSwap"></param>
/// <param name="floating"></param>
/// <param name="endDate"></param>
/// <returns></returns>
public static DateTime GetSwapRateStartDatePre(OtcTradeBase td, trade_swap tradeSwap, DateTime valueDate, trade_cash tradeCash, trade_cash_pre lastManualCash, bool floating, out DateTime endDate)
{
var tradeStartDate = PS.Config.Company == Configuration.CompanyEnum.中金 ? td.TradeDate.Value : td.StartDate.Value;
var calcFirst = tradeSwap.RateCalcMode.StartsWith("1");//算头
var calcLast = tradeSwap.RateCalcMode.EndsWith("1");//算尾
DateTime startDate = calcFirst ? tradeStartDate.AddDays(-1) : tradeStartDate;
endDate = valueDate;
if (td.ExerciseDate == endDate && !calcLast)
{
endDate = endDate.AddDays(-1);
}
if (floating)
{
if (lastManualCash != null)
{
startDate = lastManualCash.ValueDate;
}
}
else if (tradeCash != null)
{
startDate = tradeCash.ValueDate;
}
return startDate;
}
/// <summary>
/// 计算互换手续费
/// </summary>
/// <param name="tradePosition"></param>
/// <param name="tradeImport"></param>
/// <param name="tradeCash"></param>
/// <param name="isForGet"></param>
/// <returns></returns>
public static double GetCostFee(trade tradePosition, trade tradeImport, trade_cash tradeCash, bool isForGet, bool isOpenFee)
{
if (tradeImport.trade_swap == null)
{
throw new Exception($"该交易[{tradeImport.TradeNumber}]对应的trade_swap未赋值");
}
double costFee = 0;
if (isForGet)
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(tradeImport.UnderlyingCode);
costFee += (tradeImport.trade_swap.GetSingleFee ?? 0) * (tradeCash.UnwindNotional ?? 0) / underlying.ContractSize;
costFee += (tradeImport.trade_swap.GetUnAnnualRate ?? 0) * (tradeCash.UnwindNotional ?? 0) * (isOpenFee ? (tradePosition.SpotPrice ?? 0) : (tradeCash.FinalPrice ?? 0));
}
else
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(tradeImport.UnderlyingCode);
costFee += (tradeImport.trade_swap.PaySingleFee ?? 0) * (tradeCash.UnwindNotional ?? 0) / underlying.ContractSize;
costFee += (tradeImport.trade_swap.PayUnAnnualRate ?? 0) * (tradeCash.UnwindNotional ?? 0) * (isOpenFee ? (tradePosition.SpotPrice ?? 0) : (tradeCash.FinalPrice ?? 0));
}
return costFee.FormatValue(2);
}
/// <summary>
///
/// </summary>
public static double GetInitialAmountSwapGet(OtcTradeBase trade, trade_swap trade_swap, double lastFinalPrice
, double price, double stockEqvNotional, DateTime valueDate, DateTime? preSwapDate)
{
double? initialAmount;
if (trade_swap.IsGetFloatingProfit)
{
var annualRate = GetAnnualVarIncomeRate(trade_swap, valueDate, preSwapDate, trade.StartDate.Value, trade.ExerciseDate.Value);
initialAmount = GetInitialAmountSwap(lastFinalPrice, price
, (trade_swap.GetNotional ?? 0) * stockEqvNotional / trade.OriginalStockEqvNotional.Value
, trade_swap.GetLongShort, annualRate);
}
else
{
initialAmount = trade_swap.GetFixedProfit * stockEqvNotional / trade.OriginalStockEqvNotional;
}
return (initialAmount ?? 0).FormatValue(2);
}
/// <summary>
///
/// </summary>
public static double GetInitialAmountSwapPay(OtcTradeBase trade, trade_swap trade_swap, double lastFinalPrice
, double price, double stockEqvNotional, DateTime valueDate, DateTime? preSwapDate)
{
double? initialAmount;
if (trade_swap.IsPayFloatingProfit)
{
var annualRate = GetAnnualVarIncomeRate(trade_swap, valueDate, preSwapDate, trade.StartDate.Value, trade.ExerciseDate.Value);
initialAmount = GetInitialAmountSwap(lastFinalPrice, price
, (trade_swap.PayNotional ?? 0) * stockEqvNotional / trade.OriginalStockEqvNotional.Value
, trade_swap.PayLongShort, annualRate);
}
else
{
initialAmount = trade_swap.PayFixedProfit * stockEqvNotional / trade.OriginalStockEqvNotional;
}
return (initialAmount ?? 0).FormatValue(2);
}
/// <summary>
///
/// </summary>
/// <param name="lastFinalPrice"></param>
/// <param name="price"></param>
/// <param name="notional"></param>
/// <param name="longShort"></param>
/// <param name="annualVarIncomeRate">年化浮动收益率(为null表示非年化)</param>
/// <returns></returns>
public static double GetInitialAmountSwap(double lastFinalPrice, double price, double notional, string longShort, double? annualVarIncomeRate)
{
var amount = (price - lastFinalPrice) * notional.Normalize() * (longShort == "多头" ? 1 : -1);
return annualVarIncomeRate.HasValue ? amount * annualVarIncomeRate.Value : amount;
}
private static List<Date> GetSwapDatesBetween(string swapTimeAndRate, DateTime startDate, DateTime endDate)
{
var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(swapTimeAndRate);
var dates = customizedResults.Item1;
if (dates == null)
{
return null;
}
return dates.Where(x => x.DateTime > startDate && x.DateTime <= endDate).ToList();
}
public static double GetSwapRateByDate(string swapTimeAndRate, DateTime valueDate)
{
double swapRate = 0;
var customizedResults = QdpHelper.ParseAutocallCustomizedInfo(swapTimeAndRate);
var dates = customizedResults.Item1;
if (dates == null)
{
return swapRate;
}
var getSwapRates = customizedResults.Item2;
var latestDate = dates.Where(x => x.DateTime >= valueDate).OrderBy(x => x.DateTime).FirstOrDefault();
//展期情况互换利率获取最后一个日期的互换利率
if (latestDate == null)
{
latestDate = dates.Max();
}
if (getSwapRates != null && getSwapRates.Any())
{
swapRate = getSwapRates[GetDateIndex(dates, latestDate)];
}
return swapRate;
}
private static int GetDateIndex(Date[] source, Date value)
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
var index = 0;
foreach (var item in source)
{
if (item.DateTime == value.DateTime)
{
return index;
}
index++;
}
return -1;
}
/// <summary>
/// 获取互换交易变动收益年化率,返回null表示非年化
/// </summary>
/// <param name="trade_swap">互换交易</param>
/// <param name="valueDate">结算日期</param>
/// <param name="preSwapDate">上次互换日期</param>
/// <param name="tradeStartDate">交易开始日期</param>
/// <returns>返回null表示非年化</returns>
public static double? GetAnnualVarIncomeRate(trade_swap trade_swap, DateTime valueDate, DateTime? preSwapDate, DateTime tradeStartDate, DateTime exerciseDate)
{
if (trade_swap is null)
{
throw new ArgumentNullException(nameof(trade_swap));
}
//浮动收益是否年化
if (!trade_swap.AnnualVarIncome)
{
return null;
}
if (!trade_swap.AnnualDays.HasValue || trade_swap.AnnualDays < 1)
{
return null;
}
DateTime startDate;
if (preSwapDate != null)
{
startDate = preSwapDate.Value.AddDays(1);
}
else
{
//2021-05-11:浮动收益年化时,首日计息规则会影响到收益金额的计算
bool calcFirst = trade_swap.RateCalcMode.StartsWith("1");//算头
startDate = calcFirst ? tradeStartDate : tradeStartDate.AddDays(1);
}
var days = (valueDate - startDate.Date).Days + 1;
if (exerciseDate == valueDate && trade_swap.RateCalcMode.EndsWith("0"))
{
days -= 1;
}
if (days < 0)
{
days = 0;
}
return (double)days / trade_swap.AnnualDays.Value;
}
}
}