- 添加 EffectiveDate 字段用于标识真实除权生效日 - 实现公司行为价格系数和数量系数统一计算方法 - 增加基金除权回退和平仓基线恢复功能 - 完善除权日验证逻辑,确保真实除权日不早于股权登记日 - 重构平仓流程,支持按有效EOD基线重新计算损益和现金 - 添加基金拆合股和现金分红的特殊处理逻辑 - 增加单元测试验证各种公司行为场景下的正确性
140 lines
5.1 KiB
C#
140 lines
5.1 KiB
C#
using YLErp.Modules.TradeModule.DealModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Web.Controllers
|
|
{
|
|
public class ex_dividend_infoController : BaseController
|
|
{
|
|
/// <summary>
|
|
/// 查看股票除权除息信息
|
|
/// </summary>
|
|
public ActionResult underlying_dividend_info(string unid)
|
|
{
|
|
var intid = DecryptInt(unid);
|
|
var underlying = yldb.underlying_manager.Find(intid);
|
|
ViewBag.underlying = underlying;
|
|
return View();
|
|
}
|
|
|
|
[HttpPost]
|
|
public JsonResult ex_dividend_infoQuery(ex_dividend_infoReq req)
|
|
{
|
|
if (req is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(req));
|
|
}
|
|
if (string.IsNullOrWhiteSpace(req.UnderlyingCode))
|
|
{
|
|
throw new ArgumentNullException(nameof(req.UnderlyingCode));
|
|
}
|
|
if (string.IsNullOrWhiteSpace(req.sidx))
|
|
{
|
|
req.sidx = "ExDividendDate";
|
|
req.sord = "desc";
|
|
}
|
|
var query = new DividendService(CurUser).GetExDividendInfos(req.UnderlyingCode);
|
|
var sList = query.ToSearchList(req);
|
|
return Json(sList);
|
|
}
|
|
|
|
[HttpPost]
|
|
public JsonResult saveDividend(ex_dividend_info info)
|
|
{
|
|
try
|
|
{
|
|
if (info == null)
|
|
{
|
|
throw new FormatException("未收到参数");
|
|
}
|
|
if (string.IsNullOrWhiteSpace(info.UnderlyingCode)
|
|
|| info.ExDividendDate == null
|
|
|| info.EffectiveDate == null)
|
|
{
|
|
throw new FormatException("标的代码、股权登记日或真实除权日信息不存在!");
|
|
}
|
|
if (QdpCalendarHelper.IsHoliday(info.ExDividendDate.Value))
|
|
{
|
|
throw new FormatException("股权登记日不应为非交易日!");
|
|
}
|
|
if (QdpCalendarHelper.IsHoliday(info.EffectiveDate.Value))
|
|
{
|
|
throw new FormatException("真实除权日不应为非交易日!");
|
|
}
|
|
if (info.EffectiveDate.Value.Date < info.ExDividendDate.Value.Date)
|
|
{
|
|
throw new FormatException("真实除权日不应早于股权登记日!");
|
|
}
|
|
var status = new DividendService(CurUser).AddDividendInfos(new[] { info }, out var errMsg);
|
|
if (!status)
|
|
{
|
|
return JsonError(errMsg);
|
|
}
|
|
|
|
var query = from t in yldb.trade.AsNoTracking()
|
|
join tc in yldb.trade_cash.AsNoTracking()
|
|
on t.id equals tc.TradeId
|
|
where t.UnderlyingCode == info.UnderlyingCode && !tc.IsDeleted &&
|
|
t.ExerciseDate > info.ExDividendDate && t.TradeDate <= info.ExDividendDate &&
|
|
tc.ValueDate > info.ExDividendDate
|
|
select t.TradeNumber;
|
|
|
|
if (query.Any())
|
|
{
|
|
return JsonSuccess("保存成功,但系统中存在该股权登记日后了结的交易,请务必重新收盘!", info);
|
|
}
|
|
else //检查EodTrade
|
|
{
|
|
return JsonSuccess("保存成功", info);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return JsonError(ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpPost]
|
|
public JsonResult deleteDividend(int id, string underlyingCode, DateTime dividendDate)
|
|
{
|
|
var r = yldb.ex_dividend_info.Where(O => O.id == id && O.UnderlyingCode == underlyingCode && O.ExDividendDate.Value == dividendDate.Date && O.ValidStatus).FirstOrDefault();
|
|
if (r == null)
|
|
{
|
|
return JsonError("未找到有效的除权除息信息");
|
|
}
|
|
if (new DividendService(CurUser).checkDividendInfoExecuteStatus(r))
|
|
{
|
|
return JsonError("该条除权信息已被执行,不允许删除!");
|
|
}
|
|
else
|
|
{
|
|
r.ValidStatus = false;
|
|
r.DataSource = ExDividendDataSources.Manual;
|
|
r.OptId = CurUser.UserId;
|
|
r.OptName = CurUser.UserName;
|
|
r.OptDate = DateTime.Now;
|
|
yldb.SaveChanges();
|
|
return JsonSuccess("删除成功");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导入预付金参数
|
|
/// </summary>
|
|
public JsonResult ImportDividendInfo(IFormFile file)
|
|
{
|
|
if (Path.GetExtension(file?.FileName)?.ToLowerInvariant() != ".xlsx")
|
|
{
|
|
return JsonError("请上传xlsx格式文件");
|
|
}
|
|
else
|
|
{
|
|
using (var stream = file.OpenReadStream())
|
|
{
|
|
new DividendService(CurUser).ImportDividendInfos(stream);
|
|
}
|
|
}
|
|
return JsonSuccess("上传成功");
|
|
}
|
|
}
|
|
}
|