using BaseOUDAL;
using DocumentFormat.OpenXml.Bibliography;
using ExcelDataReader.Log;
using YLErp.DBModels;
using YLErp.Helpers;
namespace YLErp.Modules.EodModule
{
///
/// 债券期间付息服务
///
public class BondPaymentService : YLBaseService
{
private static IYcLogger Log = LogFactory.GetLogger(nameof(BondPaymentService));
public BondPaymentService(OptUserInfo userInfo) : base(userInfo)
{
}
public SearchListResult SearchList(BondPaymentReq req)
{
var valueDtStart = req.ValueDateStart.Year > 2000 ? req.ValueDateStart : DateTime.Today.AddYears(-1);
var valueDtEnd = req.ValueDateEnd.Year > 2000 ? req.ValueDateEnd.AddDays(1) : DateTime.Today.AddYears(1);
var predicatUn = PredicateBuilder.Create(d => d.LaunchState == "1");
var predicatEoc = PredicateBuilder.Create(source => source.payment_date >= valueDtStart && source.payment_date < valueDtEnd);
if (!string.IsNullOrEmpty(req.DataSource))
{
predicatEoc = predicatEoc.And(d => d.channel_source.Contains(req.DataSource));
}
if (!string.IsNullOrEmpty(req.MarketName))
{
predicatUn = predicatUn.And(d => d.MarketName == req.MarketName);
}
if (!string.IsNullOrEmpty(req.UnderlyingCode))
{
predicatEoc = predicatEoc.And(d => d.underlyingCode.Contains(req.UnderlyingCode));
}
if (string.IsNullOrEmpty(req.sidx))
{
req.sidx = "payment_date";
req.sord = "desc";
}
var queryUn = DbContext.underlying_manager.Where(predicatUn).Select(n => new { n.id, n.MarketName, n.UnderlyingCode, n.UnderlyingName, n.UnderlyingInstrumentType, n.InnerCode });
var query = from un in queryUn
join source in DbContext.bondPayment.Where(predicatEoc) on un.UnderlyingCode equals source.underlyingCode
select new BondPaymentDto
{
id = source.id,
channel_source = source.channel_source,
MarketName = un.MarketName,
security_id = un.UnderlyingCode,
symbol = un.UnderlyingName,
coupon_rate = source.coupon_rate,
payment_date = source.payment_date,
payment_interest = source.payment_interest,
payment_parvalue = source.payment_parvalue,
create_time = source.create_time,
update_time = source.update_time
};
var result = query.ToSearchList(req);
return result;
}
public BondPayment SaveBondPayment(BondPayment req)
{
if (req is null)
{
throw new ArgumentNullException(nameof(req));
}
BondPayment dbmodel;
if (req.id == 0)
{
DbContext.bondPayment.Add(dbmodel = req);
}
else
{
dbmodel = DbContext.bondPayment.Find(req.id);
if (dbmodel == null)
{
throw new ServiceException("数据不存在");
}
UpdateChanges(dbmodel, req);
}
dbmodel.update_time = DateTime.Now;
DbContext.SaveChanges();
return dbmodel;
}
///
/// 获取某债券的期间付息情况集合
///
///
///
///
///
public List GetBondPayments(string underlyingCode, DateTime startDate, DateTime endDate)
{
var result = DbContext.bondPayment.Where(x => x.underlyingCode == underlyingCode && x.payment_date > startDate && x.payment_date <= endDate).AsNoTracking().ToList();
return result;
}
public List GetTargetDatePayments(string underlyingCode, DateTime targetDate)
{
var startDate = targetDate.Date;
var endDate = startDate.AddDays(1);
return DbContext.bondPayment.AsNoTracking().Where(x => x.underlyingCode == underlyingCode && x.payment_date >= startDate && x.payment_date < endDate).ToList();
}
///
/// 计算某债券某段时间的期间付息
///
/// 债券代码
/// 计息开始日
/// 计息结束日
/// 持仓数量
/// 多空方向
/// 收支方向
///
public decimal CalcPayment(
string underlyingCode,
DateTime startDate,
DateTime endDate,
decimal qty,
decimal longRatio,
decimal payDirection,
bool useBondPriceScale = true)
{
var payments = GetBondPayments(underlyingCode, startDate, endDate);
return CalcPayment(payments, qty, longRatio, payDirection, useBondPriceScale);
}
///
/// 计算某标的期间现金流。债券与 Stock/Fund 公司行为共用 bond_payment_info,
/// 但通过 useBondPriceScale 明确区分两种入库金额单位。
///
/// 期间付息集合
/// 持仓数量
/// 多空方向
/// 收支方向
///
/// 是否按债券报价的百分比口径换算。债券的 payment_interest 是每 100 元面值的票息,
/// 需要继续通过 BondPriceConverter 转成入库金额;Fund/Stock 的公司行为现金分红
/// 在 bond_payment_info 中按每 10 份存储,payment_interest * qty 已经是实际现金,
/// 不能再做一次 /100。默认 true 是为了保持所有历史债券调用方的原有口径。
///
///
public decimal CalcPayment(
List payments,
decimal qty,
decimal longRatio,
decimal payDirection,
bool useBondPriceScale = true)
{
var interest = payments.Sum(s => s.payment_interest ?? 0);
var paymentAmount = interest * qty;
// 债券:interest 为每 100 元面值的票息,×qty 后需 ÷100 转为实际金额。
// Fund/Stock 公司行为:interest 已由【同步任务】写成 GiveCashAmount/10,
// ×qty 就是“每 10 份派现额 × 持仓份额”,必须保留原金额,不能套债券的 /100。
var actualAmount = useBondPriceScale
? BondPriceConverter.ToStorage(paymentAmount)
: paymentAmount;
return actualAmount * longRatio * payDirection;
}
}
///
///
///
public class BondPaymentReq : BaseSearchReq
{
///
/// 数据来源
///
public string DataSource { get; set; }
///
/// 标的代码
///
public string UnderlyingCode { get; set; }
public DateTime ValueDateStart { get; set; }
public DateTime ValueDateEnd { get; set; }
// 市场
public string MarketName { get; set; }
}
public class BondPaymentDto : BondPayment
{
public string MarketName { get; set; }
}
}