从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,472 @@
|
||||
using YLErp.Configuration;
|
||||
using YLErp.Modules.SystemModule;
|
||||
|
||||
namespace YLErp.Modules.EodModule.SettlementModule
|
||||
{
|
||||
/// <summary>
|
||||
/// EodTask数据保存服务
|
||||
/// </summary>
|
||||
public class EodTaskSaveService : YLBaseService
|
||||
{
|
||||
public EodTaskSaveService(OptUserInfo optUser) : base(optUser)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EodTaskSaveService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EodTask CancelTask(int taskId)
|
||||
{
|
||||
if (EodTaskRunner.Stop(taskId))
|
||||
{
|
||||
return EodTaskRunner.LastTask;
|
||||
}
|
||||
|
||||
var task = DbContext.EodTask.FirstOrDefault(n => n.id == taskId);
|
||||
|
||||
if (task == null)
|
||||
{
|
||||
throw new ServiceException("任务数据已不存在");
|
||||
}
|
||||
|
||||
if (task.TaskState >= EodTaskState.completed)
|
||||
{
|
||||
throw new ServiceException("当前任务状态:" + EodTaskHelper.GetEodTaskStateDesc(task.TaskState));
|
||||
}
|
||||
|
||||
task.OptId = UserId;
|
||||
task.OptName = UserName;
|
||||
task.OptTime = DateTime.Now;
|
||||
task.TaskState = EodTaskState.canceled;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
public EodTask RestartTask(int taskId, bool resetAll, bool isDelayTrade)
|
||||
{
|
||||
var task = DbContext.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));
|
||||
}
|
||||
|
||||
task.OptId = UserId;
|
||||
task.OptName = UserName;
|
||||
task.OptTime = DateTime.Now;
|
||||
task.TaskResult = string.Empty;
|
||||
task.TaskState = EodTaskState.pending;
|
||||
task.IsDelayTrade = isDelayTrade;
|
||||
|
||||
if (resetAll)
|
||||
{
|
||||
task.ValueDate = task.StartDate;
|
||||
DbContext.EodTaskDetail.RemoveRange(DbContext.EodTaskDetail.Where(n => n.TaskId == taskId));
|
||||
}
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存结算任务
|
||||
/// </summary>
|
||||
public EodTask SaveData(EodTaskSaveReq req, bool saveIntoDB)
|
||||
{
|
||||
if (req is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(req));
|
||||
}
|
||||
|
||||
var task = new EodTask
|
||||
{
|
||||
EndDate = req.EndDate,
|
||||
StartDate = req.StartDate,
|
||||
TaskEndTime = DateTime.Now,
|
||||
TaskStartTime = DateTime.Now,
|
||||
TaskResult = string.Empty,
|
||||
TaskState = EodTaskState.pending,
|
||||
PartFlag = req.PartFlag,
|
||||
ValueDate = req.StartDate,
|
||||
|
||||
PriceType = req.PriceType,
|
||||
VolTypes = req.VolTypes,
|
||||
|
||||
IsDelayTrade = req.IsDelayTrade,
|
||||
|
||||
CreatorId = UserId,
|
||||
CreatorName = UserName,
|
||||
CreateTime = DateTime.Now,
|
||||
|
||||
OptId = UserId,
|
||||
OptName = UserName,
|
||||
OptTime = DateTime.Now,
|
||||
};
|
||||
if (req.ClientIds != null)
|
||||
{
|
||||
task.ClientIds = String.Join(",", req.ClientIds);
|
||||
task.ListClientId = req.ClientIds;
|
||||
task.ClientNameStr = String.Join(",", ClientDataModelV1.GetAllOpenClient(isContainClosed: true).Where(l => task.ListClientId.Contains(int.Parse(l.Value))).Select(l => l.Text));
|
||||
}
|
||||
var result = CheckEodTask(task);
|
||||
|
||||
if (result.HasError)
|
||||
{
|
||||
throw new ServiceException(result.ErrorMsg);
|
||||
}
|
||||
|
||||
task.VolTypes = string.Join(",", result.VolTypes);
|
||||
|
||||
if (saveIntoDB)
|
||||
{
|
||||
DbContext.EodTask.Add(task);
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
internal CheckPreEodStatusResult CheckEodTask(EodTask req)
|
||||
{
|
||||
var result = new CheckPreEodStatusResult();
|
||||
|
||||
if (req.StartDate.Year < 2000)
|
||||
{
|
||||
return result.SetError(true, "收盘开始日期 必须填写");
|
||||
}
|
||||
|
||||
if (req.EndDate == DateTime.MinValue)
|
||||
{
|
||||
req.EndDate = req.StartDate;
|
||||
}
|
||||
else if (req.EndDate.Year < 2000)
|
||||
{
|
||||
return result.SetError(true, "收盘结束日期 必须填写");
|
||||
}
|
||||
|
||||
if (req.EndDate < req.StartDate)
|
||||
{
|
||||
return result.SetError(true, "收盘结束日期 必须大于或等于 收盘开始日期");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(req.VolTypes))
|
||||
{
|
||||
return result.SetError(true, "波动率类型 必须填写");
|
||||
}
|
||||
|
||||
if (req.PriceType < EodSettlePriceType.ClosePrice || req.PriceType > EodSettlePriceType.AllPrices)
|
||||
{
|
||||
return result.SetError(true, "价格模式 无效值");
|
||||
}
|
||||
|
||||
if (!EodTaskHelper.IsValidPartFlag(req.PartFlag))
|
||||
{
|
||||
return result.SetError(true, "部分结算 无效值");
|
||||
}
|
||||
|
||||
var valueDate = BLL.valuedateBLL.GetNonHoliday(req.StartDate);
|
||||
if (valueDate > req.EndDate)
|
||||
{
|
||||
return result.SetError(true, "收盘开始日期至收盘结束日期没有交易日");
|
||||
}
|
||||
|
||||
//波动率结算是否满足条件
|
||||
|
||||
var volTypes = req.VolTypes.Split(',').Where(n => !string.IsNullOrWhiteSpace(n)).ToArray();
|
||||
|
||||
if (!volTypes.Any())
|
||||
{
|
||||
return result.SetError(true, "波动率类型 必须填写");
|
||||
}
|
||||
|
||||
var volTypeFlag = VolTypeFlagEnum.None;
|
||||
var volTypeFlagList = new List<VolTypeFlagEnum>(6);
|
||||
|
||||
foreach (var voltype in volTypes)
|
||||
{
|
||||
var tempVolType = VolTypeFlagEnumHelper.GetVolTypeFlag(voltype);
|
||||
if (tempVolType == VolTypeFlagEnum.None && !string.IsNullOrWhiteSpace(voltype))
|
||||
{
|
||||
return result.SetError(true, "不能辨认的波动率类型:" + voltype);
|
||||
}
|
||||
|
||||
volTypeFlag |= tempVolType;
|
||||
volTypeFlagList.Add(tempVolType);
|
||||
}
|
||||
|
||||
if (volTypeFlag == VolTypeFlagEnum.None)
|
||||
{
|
||||
return result.SetError(true, "波动率类型 必须有值");
|
||||
}
|
||||
|
||||
var curEodStatus = new Lazy<EodStatus>(() =>
|
||||
{
|
||||
using (var db = DbContextFactory.GetYLDbContext())
|
||||
{
|
||||
return DbContext.eodStatus.FirstOrDefault(n => n.ValueDate == valueDate);
|
||||
}
|
||||
});
|
||||
|
||||
if (!volTypeFlag.HasFlag(VolTypeFlagEnum.PositionVol))
|
||||
{
|
||||
if (req.UseClosePrice() && (curEodStatus.Value == null || !curEodStatus.Value.VolTypeFlag.HasFlag(VolTypeFlagEnum.PositionVol)))
|
||||
{
|
||||
return result.SetError(false, $"结算日'{valueDate:yyyy-MM-dd}'需执行'收盘价+持仓波动率'结算");
|
||||
}
|
||||
|
||||
if (req.UseSettlePrice() && (curEodStatus.Value == null || !curEodStatus.Value.VolTypeFlag_S.HasFlag(VolTypeFlagEnum.PositionVol)))
|
||||
{
|
||||
return result.SetError(false, $"结算日'{valueDate:yyyy-MM-dd}'需执行'结算价+持仓波动率'结算");
|
||||
}
|
||||
}
|
||||
|
||||
//按优先级重新排序
|
||||
result.VolTypes = volTypeFlagList.OrderBy(n => n).Select(n => VolTypeFlagEnumHelper.GetSingleDesc(n)).ToArray();
|
||||
|
||||
//部分结算是否满足条件
|
||||
|
||||
if (req.PartFlag == "场外" || req.PartFlag == "场内")
|
||||
{
|
||||
if (req.UseClosePrice())
|
||||
{
|
||||
var missingVolTypes = GetMissingVolTypes(curEodStatus.Value?.VolTypeFlag ?? VolTypeFlagEnum.None, volTypeFlag);
|
||||
if (!string.IsNullOrEmpty(missingVolTypes))
|
||||
{
|
||||
return result.SetError(false, $"结算日'{valueDate:yyyy-MM-dd}'不能进行{req.PartFlag}部分结算,因未完成'收盘价+{missingVolTypes}波动率'的完整结算");
|
||||
}
|
||||
}
|
||||
|
||||
if (req.UseSettlePrice())
|
||||
{
|
||||
var missingVolTypes = GetMissingVolTypes(curEodStatus.Value?.VolTypeFlag_S ?? VolTypeFlagEnum.None, volTypeFlag);
|
||||
if (!string.IsNullOrEmpty(missingVolTypes))
|
||||
{
|
||||
return result.SetError(false, $"结算日'{valueDate:yyyy-MM-dd}'不能进行{req.PartFlag}部分结算,因未完成'结算价+{missingVolTypes}波动率'的完整结算");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//上一交易日是否满足条件
|
||||
|
||||
var preDate = BLL.valuedateBLL.GetNonHolidayDefore(valueDate.AddDays(-1));
|
||||
|
||||
var preEodStatus = DbContext.eodStatus.AsNoTracking().Where(n => n.ValueDate < valueDate && n.Status == "已收盘")
|
||||
.OrderByDescending(n => n.ValueDate).FirstOrDefault();
|
||||
|
||||
if (preEodStatus != null && string.IsNullOrEmpty(req.ClientIds))
|
||||
{
|
||||
if (preEodStatus.ValueDate < preDate)
|
||||
{
|
||||
return result.SetError(false, $"上一交易日'{preDate:yyyy-MM-dd}'未进行收盘,必须在上一交易日收盘后方能执行此次收盘任务");
|
||||
}
|
||||
|
||||
if (preEodStatus.ValueDate > preDate)
|
||||
{
|
||||
return result.SetError(false, $"是否存在日历变更?数据库中已执行的上一收盘日'{preEodStatus.ValueDate:yyyy-MM-dd}'并非交易日,请将开始日期调整为'{preDate:yyyy-MM-dd}'");
|
||||
}
|
||||
|
||||
//收盘价
|
||||
if (req.UseClosePrice() && !preEodStatus.VolTypeFlag.HasFlag(volTypeFlag))
|
||||
{
|
||||
var list = new List<string>();
|
||||
for (var i = 0; i < volTypeFlagList.Count; i++)
|
||||
{
|
||||
if (volTypeFlagList[i] != (volTypeFlagList[i] & preEodStatus.VolTypeFlag))
|
||||
{
|
||||
list.Add(volTypes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var str = string.Join(",", list);
|
||||
|
||||
return result.SetError(false, $"上一交易日'{preDate:yyyy-MM-dd}'未进行'收盘价+波动率({str})'收盘,必须在上一交易日收盘后方能执行此次收盘任务");
|
||||
}
|
||||
|
||||
//结算价
|
||||
if (req.UseSettlePrice() && !preEodStatus.VolTypeFlag_S.HasFlag(volTypeFlag))
|
||||
{
|
||||
var list = new List<string>();
|
||||
for (var i = 0; i < volTypeFlagList.Count; i++)
|
||||
{
|
||||
if (volTypeFlagList[i] != (volTypeFlagList[i] & preEodStatus.VolTypeFlag_S))
|
||||
{
|
||||
list.Add(volTypes[i]);
|
||||
}
|
||||
}
|
||||
var str = string.Join(",", list);
|
||||
|
||||
return result.SetError(false, $"上一交易日'{preDate:yyyy-MM-dd}'未进行'结算价+波动率({str})'收盘,必须在上一交易日收盘后方能执行此次收盘任务");
|
||||
}
|
||||
}
|
||||
|
||||
//分客户收盘
|
||||
if (!string.IsNullOrEmpty(req.ClientIds))
|
||||
{//分客户收盘时通过ClientBalanceDaily表确定该客户前一天是否收盘;
|
||||
var clientIds = req.ListClientId;
|
||||
var eodClientIds = DbContext.ClientBalanceDaily.Where(O => O.BalanceDate == preDate && clientIds.Contains(O.ClientId)).Select(O => O.ClientId).ToList();
|
||||
clientIds = clientIds.Except(eodClientIds).ToList();
|
||||
if (clientIds.Any())
|
||||
{//忽略掉收盘日之前没有出入金记录,授信记录和新交易的客户;
|
||||
var validClientIds =
|
||||
DbContext.credit
|
||||
.Where(O => clientIds.Contains(O.ClientId ?? 0) && O.CreditStartDate < valueDate).Select(O => O.ClientId ?? 0)
|
||||
.Union(
|
||||
DbContext.ClientCashInCashOut
|
||||
.Where(O => clientIds.Contains(O.ClientId ?? 0) && O.HappenDate < valueDate && O.ValidState != "InValid").Select(O => O.ClientId ?? 0))
|
||||
.Union(
|
||||
DbContext.trade.Where(O => clientIds.Contains(O.ClientId) && O.TradeDate < valueDate && O.ValidState != "InValid").Select(O => O.ClientId))
|
||||
.Distinct().ToArray();
|
||||
if (validClientIds.Any())
|
||||
{
|
||||
var clientNameList = validClientIds.Select(O => DataCacheProvider.GetClientDataSource().GetData(O).Name).ToList();
|
||||
return result.SetError(false, $"上一交易日'{preDate:yyyy-MM-dd}' 客户:{string.Join(",", clientNameList)} 未进行收盘,必须在上一交易日收盘后方能执行此次收盘任务");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private string GetMissingVolTypes(VolTypeFlagEnum existing, VolTypeFlagEnum expected)
|
||||
{
|
||||
if ((existing & expected) == expected)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var list = new List<string>();
|
||||
|
||||
if (expected.HasFlag(VolTypeFlagEnum.PositionVol) && !existing.HasFlag(VolTypeFlagEnum.PositionVol))
|
||||
{
|
||||
list.Add("持仓");
|
||||
}
|
||||
|
||||
if (expected.HasFlag(VolTypeFlagEnum.HedgeVol) && !existing.HasFlag(VolTypeFlagEnum.HedgeVol))
|
||||
{
|
||||
list.Add("对冲");
|
||||
}
|
||||
|
||||
if (expected.HasFlag(VolTypeFlagEnum.OpenVol) && !existing.HasFlag(VolTypeFlagEnum.OpenVol))
|
||||
{
|
||||
list.Add("开仓");
|
||||
}
|
||||
|
||||
if (expected.HasFlag(VolTypeFlagEnum.ExtendVol) && !existing.HasFlag(VolTypeFlagEnum.ExtendVol))
|
||||
{
|
||||
if (PS.Config.Company == CompanyEnum.光大光子)
|
||||
{
|
||||
list.Add("光证");
|
||||
}
|
||||
else if (PS.Config.Is格林大华 || PS.Config.Is伴兴)
|
||||
{
|
||||
list.Add("BidAskVol");
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add("未知");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(",", list);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class EodTaskSaveReq
|
||||
{
|
||||
/// <summary>
|
||||
/// 收盘开始日期
|
||||
/// </summary>
|
||||
public DateTime StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 收盘结束日期
|
||||
/// </summary>
|
||||
public DateTime EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 波动率类型
|
||||
/// </summary>
|
||||
public string VolTypes { get; set; }
|
||||
/// <summary>
|
||||
/// 分红率类型 交易、0 国元特有
|
||||
/// </summary>
|
||||
public string DividendRateTypes { get; set; }
|
||||
/// <summary>
|
||||
/// 1=收盘价,2=结算价,3=收盘价+结算价
|
||||
/// </summary>
|
||||
public EodSettlePriceType PriceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 客户
|
||||
/// </summary>
|
||||
public List<int> ClientIds { get; set; }
|
||||
/// <summary>
|
||||
/// 部分收盘标识
|
||||
/// </summary>
|
||||
public string PartFlag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否延期交易
|
||||
/// </summary>
|
||||
public bool IsDelayTrade { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
class CheckPreEodStatusResult
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool HasError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public bool IsFatalError { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string ErrorMsg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 根据优先级重新排序后的波动率集合
|
||||
/// </summary>
|
||||
public string[] VolTypes { get; set; }
|
||||
|
||||
public CheckPreEodStatusResult SetError(bool isFatalError, string errorMsg)
|
||||
{
|
||||
HasError = true;
|
||||
ErrorMsg = errorMsg;
|
||||
IsFatalError = isFatalError;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user