825 lines
32 KiB
C#
825 lines
32 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using System.Collections.Concurrent;
|
|
using System.Threading;
|
|
using YLErp.BLL.Eod;
|
|
using YLErp.DBModels;
|
|
using YLErp.Model.Enum;
|
|
using YLErp.Modules.ClientModule;
|
|
using YLErp.Modules.EodModule;
|
|
using YLErp.Modules.EodModule.QueryModule;
|
|
using YLErp.Modules.EodModule.SettlementModule;
|
|
using YLErp.Modules.FinancialModule;
|
|
using YLErp.Modules.TradeModule.DealModule;
|
|
using YLErp.Office;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Web.Controllers
|
|
{
|
|
public class eod_trade_valueController : BaseController
|
|
{
|
|
|
|
[MyAuthorize("结算管理-收盘操作")]
|
|
public ActionResult eodExec()
|
|
{
|
|
var config = PS.Config.GetSettlementConfig();
|
|
ViewData["EodHistory"] = GetEodHistoryData(null, 5);
|
|
return View("eodExecV2", config);
|
|
}
|
|
|
|
public Result SendMaturityEmail(DateTime settleDate)
|
|
{
|
|
var maturityDate = settleDate;
|
|
var a = 0;
|
|
//获取之后三个交易日
|
|
for (var i = 0; i < 3;)
|
|
{
|
|
a++;
|
|
maturityDate = maturityDate.AddDays(1);
|
|
if (!QdpCalendarHelper.IsHoliday(maturityDate))
|
|
{
|
|
i++;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
if (a >= 20)
|
|
{
|
|
throw new Exception("日历记录异常," + settleDate.ToString("yyyy-MM-dd") + "后未查找到有效的3个交易日!");
|
|
};
|
|
}
|
|
|
|
//获取交易
|
|
var query = (from trade in yldb.trade where trade.TradeStatus == "确认成交" && trade.ValidState != "InValid" && trade.ClientId != 0 && trade.MaturityDate > settleDate && trade.MaturityDate <= maturityDate select trade);
|
|
var tradeList = query.ToList();
|
|
if (tradeList != null && tradeList.Count > 0)
|
|
{
|
|
var clientIds = tradeList.Select(t => t.ClientId).ToList();
|
|
var clientList = ClientDataQueryService.GetClientsFromDB(t => clientIds.Contains(t.id));
|
|
if (clientList != null)
|
|
{
|
|
var errorClientList = new List<string>();
|
|
var errorMsg = new List<string>();
|
|
|
|
foreach (var client in clientList)
|
|
{
|
|
|
|
var clientTradeList = tradeList.Where(t => t.ClientId == client.id).ToList();
|
|
|
|
var bodyhtml = string.Empty;
|
|
|
|
bodyhtml += "<meta http-equiv='Content-Type' content='text/html;charset=utf-8'/>";
|
|
|
|
bodyhtml += $"<p><h1>近期到期交易列表</h1></p>";
|
|
bodyhtml += $"<p><h2>客户名称:{client.Name}</h2></p>";
|
|
bodyhtml += $"<p><h2>日期:{settleDate:yyyy-MM-dd}</h2></p>";
|
|
|
|
bodyhtml += "<table border='1'>";
|
|
bodyhtml += "<tr>";
|
|
bodyhtml += " <th> 交易编号</th>";
|
|
bodyhtml += " <th> 交易日期</th>";
|
|
bodyhtml += " <th> 交易方向 </th>";
|
|
bodyhtml += " <th> 标的代码 </th>";
|
|
bodyhtml += " <th> 结构类型</th>";
|
|
bodyhtml += " <th> 看涨看跌</th>";
|
|
bodyhtml += " <th> 行权方式</th>";
|
|
bodyhtml += " <th> 到期日</th>";
|
|
bodyhtml += " <th> 行权价</th>";
|
|
bodyhtml += " </tr>";
|
|
|
|
foreach (var trade in clientTradeList)
|
|
{
|
|
bodyhtml += " <tr>";
|
|
bodyhtml += $" <td>{trade.TradeNumber}</td>";
|
|
bodyhtml += $" <td>{(trade.TradeDate == null ? "" : trade.TradeDate.Value.ToString("yyyy-MM-dd")):F}</td>";
|
|
bodyhtml += $" <td>{trade.BuySell}</td>";
|
|
bodyhtml += $" <td>{trade.UnderlyingCode}</td>";
|
|
bodyhtml += $" <td>{trade.TradeType:F}</td>";
|
|
bodyhtml += $" <td>{("Call".Equals(trade.CallPut) ? "看涨" : "看跌")}</td>";
|
|
bodyhtml += $" <td>{trade.ExerciseModeCn:F}</td>";
|
|
bodyhtml += $" <td>{(trade.ExerciseDate == null ? "" : trade.ExerciseDate.Value.ToString("yyyy-MM-dd"))}</td>";
|
|
//股票类期权 行权价给实际行权价
|
|
if (trade.IsMoneynessOptionData)
|
|
{
|
|
bodyhtml += $" <td>{trade.Strike * (trade.SpotPrice ?? 0):F}</td>";
|
|
}
|
|
else
|
|
{
|
|
bodyhtml += $" <td>{trade.Strike:F}</td>";
|
|
}
|
|
bodyhtml += " </tr>";
|
|
}
|
|
bodyhtml += "</table>";
|
|
|
|
// 要向该客户的所有订阅了邮件通知的人员发送邮件
|
|
//var clientContactMails = db.clientduty.Where(x => x.ClientId == client.id && x.IsReceiveEmail.HasValue && x.IsReceiveEmail == 1).Select(x => x.Email).ToList();
|
|
var emails = ClientDataQueryService.GetClientEmails(client.id, false);
|
|
|
|
if (emails != null & emails.Any())
|
|
{
|
|
var sendMail = EmailHelper.SendMail(string.Join(";", emails), "近期到期交易列表", bodyhtml, true, null);
|
|
if (!string.IsNullOrEmpty(sendMail))
|
|
{
|
|
errorClientList.Add(client.Name);
|
|
if (!errorMsg.Contains(sendMail))
|
|
{
|
|
errorMsg.Add(sendMail);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//判断是否有发送失败的客户
|
|
if (errorClientList.Count > 0)
|
|
{
|
|
var msg = $"错误:{string.Join(",", errorClientList.ToArray())}发送报告时出错,{string.Join(",", errorMsg.ToArray())}。";
|
|
return new Result { success = false, msg = msg };
|
|
}
|
|
}
|
|
}
|
|
return new Result { success = false, msg = "发送客户" + settleDate.ToString("yyyy年MM月dd日") + "近期到期交易报告成功。" };
|
|
}
|
|
|
|
/// <summary>
|
|
/// 财务凭证
|
|
/// </summary>
|
|
public ActionResult FinancialStatements()
|
|
{
|
|
return View();
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public ActionResult FinancialStatementsQuery(FinancialStatementReq req)
|
|
{
|
|
var bll = new FinancialVoucherService(CurUser);
|
|
if (req == null)
|
|
{
|
|
return JsonError("请求实体不能为空");
|
|
}
|
|
|
|
var returnInfo = bll.GetFinancialStatements(req);
|
|
if (!returnInfo.Success)
|
|
{
|
|
return JsonError(returnInfo.Msg);
|
|
}
|
|
if (string.IsNullOrWhiteSpace(req.sidx))
|
|
{
|
|
returnInfo.Content = returnInfo.Content.OrderBy(f => f.AbstractTye).ToList();
|
|
}
|
|
var searchListResult = returnInfo.Content.AsQueryable().ToSearchList(req);
|
|
|
|
return Json(searchListResult);
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
/// <param name="req"></param>
|
|
/// <param name="exportType">0:导出当前,1:导出同业,2:导出非同业</param>
|
|
/// <returns></returns>
|
|
public FileStreamResult ExportFinancialVoucher(FinancialStatementReq req, int exportType = 0)
|
|
{
|
|
if (exportType < 0 || exportType > 2)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (req == null)
|
|
{
|
|
req = new FinancialStatementReq();
|
|
}
|
|
var bll = new FinancialVoucherService(CurUser);
|
|
|
|
if (exportType == 1)
|
|
{
|
|
req.IsSamePeer = SamePeerEnum.IsSamePeer.GetHashCode();
|
|
req.AbstractList = null;
|
|
}
|
|
else if (exportType == 2)
|
|
{
|
|
req.IsSamePeer = SamePeerEnum.NotSamePeer.GetHashCode();
|
|
req.AbstractList = null;
|
|
}
|
|
|
|
var returnInfo = bll.GetFinancialStatements(req);
|
|
if (!returnInfo.Success)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (returnInfo.Content == null || returnInfo.Content.Count == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (exportType == 0)
|
|
{
|
|
var fileDownloadName = $"场外期权财务凭证_{DateTime.Now:yyyyMMdd}.xlsx";
|
|
var excelReturn = returnInfo.Content.ListToExcel2(new Dictionary<string, string>
|
|
{
|
|
{"摘要", "Abstract"},
|
|
{"同业/非同业", "IsSamePeerDesc"},
|
|
{"借贷方向", "Children.DebitOrCreditDesc"},
|
|
{"会计科目", "Children.AccountingSubject"},
|
|
{"辅助核算单位", "Children.SupplementaryAcountingUnit"},
|
|
{"数据字段", "Children.DataField"},
|
|
{"备注", "Children.Remark"}
|
|
});
|
|
return File(new FileStream(excelReturn.FileName, FileMode.Open),
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileDownloadName);
|
|
}
|
|
|
|
if (exportType == 1 || exportType == 2)
|
|
{
|
|
var fileDownloadName = $"场外期权财务凭证{(exportType == 1 ? "(同业)" : "(非同业)")}_{DateTime.Now:yyyyMMdd}.xlsx";
|
|
var group = returnInfo.Content.GroupBy(f => f.AbstractTye).OrderBy(g => g.Key)
|
|
.ToDictionary(g => EnumHelper.GetDescriptionByName((FinancialVoucherAbstractEnum)g.Key),
|
|
g => g.ToList());
|
|
var excelReturn = group.GroupToExcel2(new Dictionary<string, string>
|
|
{
|
|
{"摘要", "Abstract"},
|
|
{"同业/非同业", "IsSamePeerDesc"},
|
|
{"借贷方向", "Children.DebitOrCreditDesc"},
|
|
{"会计科目", "Children.AccountingSubject"},
|
|
{"辅助核算单位", "Children.SupplementaryAcountingUnit"},
|
|
{"数据字段", "Children.DataField"},
|
|
{"备注", "Children.Remark"}
|
|
});
|
|
return File(new FileStream(excelReturn.FileName, FileMode.Open),
|
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileDownloadName);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
#region----收盘历史----
|
|
|
|
/// <summary>
|
|
/// 收盘历史
|
|
/// </summary>
|
|
public ActionResult EodHistory(int? year)
|
|
{
|
|
var datas = GetEodHistoryData(year);
|
|
|
|
return View(datas);
|
|
}
|
|
|
|
private IEnumerable<EodStatus> GetEodHistoryData(int? year, int maxRows = 0)
|
|
{
|
|
var today = DateTime.Today;
|
|
|
|
if (year == null || year < 1 || year > 3000)
|
|
{
|
|
year = today.Year;
|
|
}
|
|
var startDate = new DateTime(year.Value, 1, 1);
|
|
var endDate = new DateTime(year.Value, 12, 31);
|
|
var allEodStatus = new EodStatus[400];
|
|
var hasExtendVol = SettlementViewModel.HasExtendVol();
|
|
var dbQuery = yldb.eodStatus.Where(n => n.ValueDate >= startDate && n.ValueDate <= endDate);
|
|
if (maxRows > 0)
|
|
{
|
|
dbQuery = dbQuery.OrderByDescending(n => n.ValueDate).Take(maxRows);
|
|
}
|
|
var dbDatas = dbQuery.ToArray();
|
|
foreach (var data in dbDatas)
|
|
{
|
|
allEodStatus[data.ValueDate.DayOfYear] = data;
|
|
if (!hasExtendVol)
|
|
{
|
|
data.VolTypeFlag = (data.VolTypeFlag | VolTypeFlagEnum.ExtendVol) ^ VolTypeFlagEnum.ExtendVol;
|
|
data.VolTypeFlag_S = (data.VolTypeFlag_S | VolTypeFlagEnum.ExtendVol) ^ VolTypeFlagEnum.ExtendVol;
|
|
}
|
|
}
|
|
|
|
while (startDate <= endDate && startDate <= today)
|
|
{
|
|
if (!BLL.valuedateBLL.IsHoliday(startDate) && allEodStatus[startDate.DayOfYear] == null)
|
|
{
|
|
allEodStatus[startDate.DayOfYear] = new EodStatus { ValueDate = startDate, Status = "未执行" };
|
|
}
|
|
startDate = startDate.AddDays(1);
|
|
}
|
|
|
|
var retQuery = allEodStatus.Where(n => n != null).Reverse();
|
|
|
|
if (maxRows > 0)
|
|
{
|
|
retQuery = retQuery.Take(maxRows);
|
|
}
|
|
|
|
return retQuery.ToArray();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 修改收盘数据核对状态
|
|
/// </summary>
|
|
[MyAuthorize("结算管理-收盘数据核对")]
|
|
public JsonResult UpdateCheckStatus(string encryptId)
|
|
{
|
|
try
|
|
{
|
|
var intid = DecryptInt(encryptId);
|
|
|
|
var eodstatus = yldb.eodStatus.Find(intid);
|
|
|
|
if (eodstatus.Status != "已收盘")
|
|
{
|
|
return JsonSuccess("未收盘");
|
|
}
|
|
eodstatus.CheckStatus = true;
|
|
eodstatus.CheckDate = DateTime.Now;
|
|
|
|
if (PS.Config.Is润和)
|
|
{
|
|
new DongZhengEodTradePositionExportService(CurUser).ExportDongZhengZipFile(eodstatus.ValueDate);
|
|
}
|
|
|
|
yldb.SaveChanges();
|
|
|
|
return JsonSuccess("核对状态修改成功");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return JsonError("执行失败:" + ex.Message);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----eodExecV2----
|
|
|
|
/// <summary>
|
|
/// 保存收盘请求
|
|
/// </summary>
|
|
public JsonResult AjaxSaveEodTask(EodTaskSaveReq req, bool isDebug = false)
|
|
{
|
|
var debugging = isDebug && System.Diagnostics.Debugger.IsAttached;
|
|
if (!string.IsNullOrEmpty(req.DividendRateTypes)&&req.DividendRateTypes.Contains("采集"))
|
|
{
|
|
req.VolTypes += ",分红率0";
|
|
}
|
|
var task = new EodTaskSaveService(CurUser).SaveData(req, !debugging);
|
|
|
|
if (debugging)
|
|
{
|
|
EodTaskRunner.ExecuteDebugAsync(task);
|
|
}
|
|
|
|
return JsonSuccess();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 取消收盘任务
|
|
/// </summary>
|
|
public JsonResult AjaxCancelEodTask(int taskId)
|
|
{
|
|
new EodTaskSaveService(CurUser).CancelTask(taskId);
|
|
|
|
return JsonSuccess();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 继续执行/重新执行
|
|
/// </summary>
|
|
public JsonResult AjaxRestartEodTask(int taskId, bool resetAll = true, bool isDelayTrade = false)
|
|
{
|
|
new EodTaskSaveService(CurUser).RestartTask(taskId, resetAll, isDelayTrade);
|
|
|
|
return JsonSuccess();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 收盘任务报告
|
|
/// </summary>
|
|
public ActionResult AjaxGetTaskRunReport(bool firstTask = true)
|
|
{
|
|
var datas = new EodTaskQueryService(CurUser).GetEodTasksToShow(firstTask);
|
|
return PartialView("_eodTaskDetail", datas);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 收盘历史
|
|
/// </summary>
|
|
public ActionResult AjaxGetEodHistoryTable()
|
|
{
|
|
var datas = GetEodHistoryData(null, 5);
|
|
return PartialView("_EodHistoryTable", datas);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 执行汇率检查
|
|
/// </summary>
|
|
public JsonResult AjaxCheckCurrencyRae(DateTime date)
|
|
{
|
|
var result = new EodCurrencyRateService(CurUser).CheckEodCurrencyRateMissing(date);
|
|
|
|
return JsonSuccessData(result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 复制上日汇率
|
|
/// </summary>
|
|
public JsonResult AjaxCopyPreCurrencyRae(DateTime date)
|
|
{
|
|
var service = new EodCurrencyRateService(CurUser);
|
|
var changes = service.CopyPreCurrencyRate(date, out var preDate);
|
|
var result = service.CheckEodCurrencyRateMissing(date);
|
|
var resultMsg = $"目标日期'{date:yyyy-MM-dd}',上日日期:'{preDate:yyyy-MM-dd}',复制{changes}条,";
|
|
if (!string.IsNullOrEmpty(result.Error))
|
|
{
|
|
resultMsg += "重新检查后报错:" + result.Error;
|
|
}
|
|
if (result.HasMissing)
|
|
{
|
|
resultMsg += "重新检查后仍然缺失";
|
|
}
|
|
else
|
|
{
|
|
resultMsg += "重新检查后未缺失汇率";
|
|
}
|
|
return JsonSuccessData(new { result, resultMsg });
|
|
}
|
|
|
|
public object AjaxCheckSettlePrice(DateTime dateStart, DateTime dateEnd)
|
|
{
|
|
var NoPriceUnderlyings = new List<KeyValuePair<string, string>>();
|
|
var start = new DateTime(dateStart.Ticks);
|
|
while (dateEnd >= dateStart)
|
|
{
|
|
var umCodes = new EodCheckPriceService(CurUser).GetNoPriceUnderlyings(dateStart);
|
|
if (umCodes != null && umCodes.Count > 0)
|
|
{
|
|
foreach (var code in umCodes)
|
|
{
|
|
NoPriceUnderlyings.Add(new KeyValuePair<string, string>(dateStart.ToString("yyyy-MM-dd"), code));
|
|
}
|
|
}
|
|
dateStart = dateStart.AddDays(1);
|
|
}
|
|
//if (NoPriceUnderlyings.Count == 0)
|
|
//{
|
|
// return Json("价格无缺失");
|
|
//}
|
|
var bytes = new EodCheckPriceService(CurUser).exportNoPriceUnderlyings(NoPriceUnderlyings);
|
|
return File(bytes, xlsxMimeType, $"收盘价格缺失{start:yyyyMMdd}-{dateEnd:yyyyMMdd}.xlsx");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 执行期权观察状态
|
|
/// </summary>
|
|
public JsonResult AjaxSaveEodKnowInOut(EodTaskSaveReq req, bool isDebug = false)
|
|
{
|
|
try
|
|
{
|
|
List<DateTime> dts = QdpCalendarHelper.AllBizDays(req.StartDate, req.EndDate.AddDays(1));
|
|
|
|
foreach (var item in dts)
|
|
{
|
|
new Modules.EodModule.SettlementModule.EodCheckMonitoredTradeSingle(CurUser).ExecuteTask(item, req.ClientIds);
|
|
}
|
|
return JsonSuccess("执行成功");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return JsonError("执行失败:" + ex.Message);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检察当日异常标的
|
|
/// </summary>
|
|
public JsonResult AjaxCheckExerciseTradeUnderly(bool update = false)
|
|
{
|
|
|
|
if (!update)
|
|
{
|
|
var exerciseTradeUnderly = new TradeDelaySettlementService(CurUser).GetCacheExerciseTradeUnderly();
|
|
return JsonSuccess("", exerciseTradeUnderly);
|
|
}
|
|
else
|
|
{
|
|
var exerciseTradeUnderly = new TradeDelaySettlementService(CurUser).CheckExerciseTradeUnderly();
|
|
return JsonSuccess("", exerciseTradeUnderly);
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检察收盘时有需要延期的交易
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public JsonResult AjaxCheckEodExerciseTradeUnderly(DateTime dateStart, DateTime dateEnd)
|
|
{
|
|
bool isHaveDelayTrade = false;
|
|
string msg = "";
|
|
//只有当天收盘
|
|
if (dateStart == dateEnd && dateEnd == valuedateBLL.ValueDate)
|
|
{
|
|
var updownUnderly = new TradeDelaySettlementService(CurUser).GetDelayUnderlyIds(dateStart);
|
|
if (updownUnderly.Any())
|
|
{
|
|
isHaveDelayTrade = true;
|
|
msg = new TradeDelaySettlementService(CurUser).GetDelayTradeNumber(updownUnderly.ToList());
|
|
}
|
|
}
|
|
//其他
|
|
else
|
|
{
|
|
while (dateEnd >= dateStart)
|
|
{
|
|
var updownUnderly = new TradeDelaySettlementService(CurUser).GetDelayUnderlyIds(dateStart);
|
|
if (updownUnderly.Any())
|
|
{
|
|
isHaveDelayTrade = true;
|
|
break;
|
|
}
|
|
dateStart = dateStart.AddDays(1);
|
|
}
|
|
}
|
|
return JsonSuccess("成功", new { isHaveDelayTrade, msg });
|
|
}
|
|
|
|
/// <summary>
|
|
/// 继续执行/重新执行
|
|
/// </summary>
|
|
public JsonResult AjaxCheckRestartEodTaskTradeUnderly(int taskId)
|
|
{
|
|
var task = YLErp.Modules.DbContextFactory.GetYLDbContext().EodTask.FirstOrDefault(n => n.id == taskId);
|
|
|
|
if (task == null)
|
|
{
|
|
throw new ServiceException("任务数据已不存在");
|
|
}
|
|
switch (task.TaskState)
|
|
{
|
|
case EodTaskState.completed:
|
|
case EodTaskState.failure:
|
|
case EodTaskState.canceled:
|
|
case EodTaskState.interrupted: break;
|
|
case EodTaskState.running:
|
|
if (EodTaskRunner.LastTask?.id == taskId)
|
|
{
|
|
throw new ServiceException("任务正在运行中");
|
|
}
|
|
break;
|
|
default: throw new ServiceException("不符合重新执行的条件,任务当前状态:" + EodTaskHelper.GetEodTaskStateDesc(task.TaskState));
|
|
}
|
|
|
|
bool isHaveDelayTrade = false;
|
|
string msg = "";
|
|
|
|
DateTime dateStart = task.StartDate, dateEnd = task.EndDate;
|
|
//只有当天收盘
|
|
if (dateStart == dateEnd && dateEnd == valuedateBLL.ValueDate)
|
|
{
|
|
var updownUnderly = new TradeDelaySettlementService(CurUser).GetDelayUnderlyIds(dateStart);
|
|
if (updownUnderly.Any())
|
|
{
|
|
isHaveDelayTrade = true;
|
|
msg = new TradeDelaySettlementService(CurUser).GetDelayTradeNumber(updownUnderly.ToList());
|
|
}
|
|
}
|
|
//其他
|
|
else
|
|
{
|
|
while (dateEnd >= dateStart)
|
|
{
|
|
var updownUnderly = new TradeDelaySettlementService(CurUser).GetDelayUnderlyIds(dateStart);
|
|
if (updownUnderly.Any())
|
|
{
|
|
isHaveDelayTrade = true;
|
|
break;
|
|
}
|
|
dateStart = dateStart.AddDays(1);
|
|
}
|
|
}
|
|
return JsonSuccess("成功", new { isHaveDelayTrade, msg });
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
#region 互换持仓明细导入
|
|
|
|
public ActionResult eodTradeSwapMannual()
|
|
{
|
|
return View();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导入互换交易
|
|
/// </summary>
|
|
public ActionResult UploadEodTradeSwapMannual()
|
|
{
|
|
if (Request.Form.Files.Count == 0)
|
|
{
|
|
return JsonError("上传文件不存在");
|
|
}
|
|
var file = Request.Form.Files[0];
|
|
if (!Path.GetExtension(file.FileName).Equals(".xlsx", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return JsonError("请上传Excel(.xlsx)格式文件");
|
|
}
|
|
DateTime valuedate = Convert.ToDateTime(Request.Form["ValueDate"]);
|
|
using var inputStream = file.OpenReadStream();
|
|
new EodSwapPositionMannualImportService(CurUser).ImportEodSwapPositionMannualFromExcel(inputStream, valuedate, out var TotalNum, out var SuccessNum);
|
|
return Json(new
|
|
{
|
|
success = true,
|
|
totalNum = TotalNum,
|
|
successNum = SuccessNum,
|
|
});
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 历史标的交易收盘
|
|
[HttpGet]
|
|
[AllowAnonymous]
|
|
public JsonResult ExecuteEodPositionSettle()
|
|
{
|
|
try
|
|
{
|
|
string volType = "持仓";
|
|
bool useClosePrice = true;
|
|
|
|
// 1. 创建用户信息对象
|
|
var userInfo = OptUserInfo.SystemUser;
|
|
|
|
// 2. 获取 exchange_trade 表的最早和最晚交易日期
|
|
var valueDate = valuedateBLL.ValueDate;
|
|
var earliestTradeDate = yldb.ExchangeTrade.Where(et => et.IsValid)
|
|
.Min(et => (DateTime?)et.TradeDate) ?? valueDate;
|
|
var latestTradeDate = EodOperationBase.GetLastSettlementDate(valueDate);
|
|
|
|
// 计算预计处理的交易日数量
|
|
var estimatedDays = 0;
|
|
var tempDate = earliestTradeDate;
|
|
while (tempDate <= latestTradeDate)
|
|
{
|
|
estimatedDays++;
|
|
tempDate = BLL.valuedateBLL.GetNonHoliday(tempDate.AddDays(1));
|
|
}
|
|
|
|
// 3. 异步执行结算任务
|
|
var taskId = Guid.NewGuid().ToString();
|
|
|
|
// 初始化任务状态
|
|
var cancellationTokenSource = new CancellationTokenSource();
|
|
|
|
Task.Run(async () =>
|
|
{
|
|
try
|
|
{
|
|
await ExecuteEodPositionSettleAsync(userInfo, volType, useClosePrice, earliestTradeDate, latestTradeDate, taskId);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
LogFactory.GetLogger("日终持仓结算").Info($"异步日终持仓结算任务 {taskId} 已被取消");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("日终持仓结算").Error($"异步日终持仓结算任务 {taskId} 执行失败: {ex.Message}", ex);
|
|
}
|
|
});
|
|
|
|
return JsonSuccess($"日终持仓结算任务已启动,任务ID: {taskId},预计处理 {estimatedDays} 个交易日,从 {earliestTradeDate:yyyy-MM-dd} 到 {latestTradeDate:yyyy-MM-dd}。任务将在后台异步执行。");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return JsonError($"启动任务失败: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 异步执行日终持仓结算
|
|
/// </summary>
|
|
/// <param name="userInfo">用户信息</param>
|
|
/// <param name="volType">波动率类型</param>
|
|
/// <param name="useClosePrice">是否使用收盘价</param>
|
|
/// <param name="startDate">开始日期</param>
|
|
/// <param name="endDate">结束日期</param>
|
|
/// <param name="taskId">任务ID</param>
|
|
/// <returns></returns>
|
|
private async Task ExecuteEodPositionSettleAsync(OptUserInfo userInfo, string volType, bool useClosePrice,
|
|
DateTime startDate, DateTime endDate, string taskId)
|
|
{
|
|
var processedDates = new List<DateTime>();
|
|
var currentDate = startDate;
|
|
|
|
LogFactory.GetLogger("日终持仓结算").Info($"开始执行异步日终持仓结算任务 {taskId},从 {startDate:yyyy-MM-dd} 到 {endDate:yyyy-MM-dd}");
|
|
|
|
try
|
|
{
|
|
while (currentDate <= endDate)
|
|
{
|
|
|
|
LogFactory.GetLogger("日终持仓结算").Info($"任务 {taskId}: 正在处理日期 {currentDate:yyyy-MM-dd}");
|
|
|
|
|
|
// 创建结算请求对象
|
|
var request = new EodSettlementRequest(userInfo)
|
|
{
|
|
VolType = volType,
|
|
UseClosePrice = useClosePrice,
|
|
SettleDate = currentDate,
|
|
ClientIds = null,
|
|
DelayUnderlyIds = new List<int>()
|
|
};
|
|
|
|
// 获取结算配置
|
|
var settlementConfig = PS.Config.GetSettlementConfig();
|
|
|
|
// 获取取消令牌
|
|
CancellationToken cancellationToken = CancellationToken.None;
|
|
|
|
// 创建任务管理器
|
|
var taskManager = new SimpleTaskManager();
|
|
|
|
// 在Task.Run中执行CPU密集型操作
|
|
await Task.Run(() =>
|
|
{
|
|
// 创建结算上下文
|
|
var currentContext = new EodSettlementContextV2(request, settlementConfig, cancellationToken);
|
|
|
|
// 创建服务实例
|
|
var currentEodPositionService = new EodPositionSettleService(currentContext);
|
|
|
|
// 执行当前日期的结算
|
|
currentEodPositionService.Execute(volType, useClosePrice, taskManager);
|
|
});
|
|
|
|
processedDates.Add(currentDate);
|
|
currentDate = BLL.valuedateBLL.GetNonHoliday(currentDate.AddDays(1));
|
|
|
|
// 每处理一个日期后稍作延迟,避免过度占用系统资源
|
|
await Task.Delay(100);
|
|
}
|
|
LogFactory.GetLogger("日终持仓结算").Info($"异步日终持仓结算任务 {taskId} 执行完成,共处理了 {processedDates.Count} 个交易日");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("日终持仓结算").Error($"异步日终持仓结算任务 {taskId} 在处理日期 {currentDate:yyyy-MM-dd} 时发生错误: {ex.Message}", ex);
|
|
throw;
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
/// <summary>
|
|
/// 简单的任务管理器实现
|
|
/// </summary>
|
|
public class SimpleTaskManager : IAsyncTaskManager
|
|
{
|
|
/// <summary>
|
|
/// 设置任务步骤
|
|
/// </summary>
|
|
/// <param name="step">步骤描述</param>
|
|
public void SetTaskStep(string step)
|
|
{
|
|
// 可以在这里记录日志或更新进度
|
|
LogFactory.GetLogger("日终持仓结算").Info($"任务步骤: {step}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 等待任务完成
|
|
/// </summary>
|
|
/// <param name="tasks">要等待的任务数组</param>
|
|
public void WaitTasks(params Task[] tasks)
|
|
{
|
|
if (tasks is null || tasks.Length < 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (tasks.Any(n => n == null))
|
|
{
|
|
tasks = tasks.Where(n => n != null).ToArray();
|
|
|
|
if (tasks.Length < 1)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
foreach (var task in tasks)
|
|
{
|
|
task.ContinueWith(t =>
|
|
{
|
|
//!t.Exception.InnerExceptions.All(n => n is OperationCanceledException)
|
|
if (t.Exception != null)
|
|
{
|
|
LogFactory.GetLogger("日终结算").Error(t.Exception, "");
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
Task.WaitAll(tasks);
|
|
}
|
|
}
|
|
}
|