从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,937 @@
|
||||
using System.Text;
|
||||
using YLErp.Configuration;
|
||||
using YLErp.Modules.EodFileModule;
|
||||
using YLErp.Modules.EodModule.CompanySpecial;
|
||||
using YLErp.Modules.ExchangeOptionTradeModule;
|
||||
using YLErp.Modules.RiskModule;
|
||||
using YLErp.Modules.SystemModule;
|
||||
using YLErp.Modules.TradeDalModule;
|
||||
using YLErp.Modules.TradeModule.DealModule;
|
||||
|
||||
namespace YLErp.Modules.EodModule.SettlementModule
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static class EodTaskRunner
|
||||
{
|
||||
[ThreadStatic]
|
||||
static string TaskStep;
|
||||
|
||||
static InnerRunner _runner;
|
||||
|
||||
static readonly EodTaskReportInner _report;
|
||||
|
||||
static EodTaskRunner()
|
||||
{
|
||||
_report = new EodTaskReportInner();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 锁定对象
|
||||
/// </summary>
|
||||
public static object LockObj => _report;
|
||||
|
||||
/// <summary>
|
||||
/// 最后一次执行的任务
|
||||
/// </summary>
|
||||
public static EodTask LastTask => _report.EodTask;
|
||||
|
||||
/// <summary>
|
||||
/// 定时计划任务调用
|
||||
/// </summary>
|
||||
public static void Execute()
|
||||
{
|
||||
lock (_report)
|
||||
{
|
||||
if (_runner != null && _runner?.StopCountDown() > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_runner = new InnerRunner();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var db = DbContextFactory.GetYLDbContext())
|
||||
{
|
||||
EodTask t;
|
||||
var table = db.GetTableName<EodTask>();
|
||||
var startDate = DateTime.Today.AddDays(-3);
|
||||
var startDateStr = startDate.ToString(ConsGlobal.DateFormat);
|
||||
if (db.EodTask.Any(n => n.TaskStartTime > startDate && (n.TaskState == EodTaskState.running || n.TaskState == EodTaskState.canceling)))
|
||||
{
|
||||
var sql = $@"
|
||||
update {table} set {nameof(t.TaskState)}={(int)EodTaskState.canceled}
|
||||
where {nameof(t.TaskStartTime)}>'{startDateStr}' and {nameof(t.TaskState)}={(int)EodTaskState.canceling};
|
||||
update {table} set {nameof(t.TaskState)}={(int)EodTaskState.interrupted}
|
||||
where {nameof(t.TaskStartTime)}>'{startDateStr}' and {nameof(t.TaskState)}={(int)EodTaskState.running};";
|
||||
db.Database.ExecuteSqlRaw(sql);
|
||||
}
|
||||
}
|
||||
|
||||
_runner.Execute();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("日终结算").Error(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
var runner = _runner;
|
||||
_runner = null;
|
||||
runner?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 调试状态下调用
|
||||
/// </summary>
|
||||
public static Task ExecuteDebugAsync(EodTask eodTask)
|
||||
{
|
||||
if (eodTask is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(eodTask));
|
||||
}
|
||||
|
||||
lock (_report)
|
||||
{
|
||||
if (_runner != null && _runner?.StopCountDown() > 0)
|
||||
{
|
||||
throw new ServiceException("正在执行中");
|
||||
}
|
||||
|
||||
_runner = new InnerRunner();
|
||||
}
|
||||
|
||||
return Task.Run(() =>
|
||||
{
|
||||
_runner.Execute(eodTask);
|
||||
|
||||
}).ContinueWith(t =>
|
||||
{
|
||||
if (t.Exception != null)
|
||||
{
|
||||
LogFactory.GetLogger("日终结算").Error(t.Exception);
|
||||
}
|
||||
var runner = _runner;
|
||||
_runner = null;
|
||||
runner?.Dispose();
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止正在执行的任务
|
||||
/// </summary>
|
||||
public static bool Stop(long taskId)
|
||||
{
|
||||
if (_runner != null && _runner.CurTask?.id == taskId)
|
||||
{
|
||||
_runner.Stop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#region----任务运行报告----
|
||||
|
||||
class EodTaskReportInner
|
||||
{
|
||||
EodTask _eodTask;
|
||||
|
||||
readonly List<EodTaskDetail> _details;
|
||||
|
||||
public EodTaskReportInner()
|
||||
{
|
||||
_details = new List<EodTaskDetail>();
|
||||
}
|
||||
|
||||
public EodTask EodTask
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_eodTask == null/* || _eodTask.TaskStartTime < DateTime.Today*/)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var clone = _eodTask;
|
||||
|
||||
if (clone.TaskState == EodTaskState.running)
|
||||
{
|
||||
clone = _eodTask.Clone();
|
||||
clone.TaskEndTime = DateTime.Now;
|
||||
StopTaskDetail();
|
||||
}
|
||||
|
||||
clone.Details = _details.Count < 5 ? _details.AsEnumerable() : _details.Skip(_details.Count - 4).ToArray();
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
||||
private void StopTaskDetail()
|
||||
{
|
||||
if (_details.Count > 0)
|
||||
{
|
||||
var last = _details.Last();
|
||||
|
||||
last.ElapsedMilliseconds = (int)(DateTime.Now - last.StartTime).TotalMilliseconds;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartEodTask(EodTask eodTask)
|
||||
{
|
||||
if (eodTask != null)
|
||||
{
|
||||
_eodTask = eodTask;
|
||||
_details.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void StartTaskDetail(EodTaskDetail detail)
|
||||
{
|
||||
StopTaskDetail();
|
||||
|
||||
_details.Add(detail.Clone());
|
||||
}
|
||||
|
||||
public void SetErrorTips(string errorTips)
|
||||
{
|
||||
if (_eodTask != null && !string.IsNullOrWhiteSpace(errorTips))
|
||||
{
|
||||
_eodTask.ErrorTips += errorTips;
|
||||
}
|
||||
}
|
||||
|
||||
public void StopEodTask()
|
||||
{
|
||||
if (_eodTask != null)
|
||||
{
|
||||
StopTaskDetail();
|
||||
|
||||
_eodTask = _eodTask.Clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region----执行批量收盘----
|
||||
|
||||
class InnerRunner : YLBaseService
|
||||
{
|
||||
readonly CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
int _stopCountDown = int.MaxValue;
|
||||
|
||||
public InnerRunner() : base(OptUserInfo.SystemUser)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 正在运行的任务
|
||||
/// </summary>
|
||||
public EodTask CurTask { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 停止倒数计数
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int StopCountDown()
|
||||
{
|
||||
return _stopCountDown--;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 停止
|
||||
/// </summary>
|
||||
public void Stop()
|
||||
{
|
||||
if (CurTask != null && CurTask.TaskState < EodTaskState.completed)
|
||||
{
|
||||
CurTask.TaskState = EodTaskState.canceling;
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
_stopCountDown = 600;
|
||||
|
||||
try
|
||||
{
|
||||
//可能有ObjectDisposedException异常
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行
|
||||
/// </summary>
|
||||
public void Execute(EodTask eodTask = null)
|
||||
{
|
||||
if (eodTask == null)
|
||||
{
|
||||
eodTask = QueryFirstAvailableTask();
|
||||
}
|
||||
|
||||
CurTask = eodTask;
|
||||
|
||||
if (eodTask == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_report.StartEodTask(eodTask);
|
||||
|
||||
try
|
||||
{
|
||||
if (eodTask.ValueDate < eodTask.StartDate)
|
||||
{
|
||||
eodTask.ValueDate = eodTask.StartDate;
|
||||
}
|
||||
|
||||
eodTask.TaskStartTime = DateTime.Now;
|
||||
eodTask.TaskState = EodTaskState.running;
|
||||
|
||||
var settlementConfig = PS.Config.GetSettlementConfig();
|
||||
|
||||
if (settlementConfig.SkipLastPvCheck)
|
||||
{
|
||||
eodTask.StepFlag = 1;
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(eodTask.ClientIds))
|
||||
{
|
||||
eodTask.ListClientId = eodTask.ClientIds.Split(',').Select(l => int.Parse(l)).ToList();
|
||||
eodTask.ClientNameStr = String.Join(",", ClientDataModelV1.GetAllOpenClient(isContainClosed: true).Where(l => eodTask.ListClientId.Contains(int.Parse(l.Value))).Select(l => l.Text));
|
||||
}
|
||||
RunEodTask(eodTask, settlementConfig);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
try
|
||||
{
|
||||
//可能有ObjectDisposedException异常
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
catch { }
|
||||
|
||||
eodTask.SetFailure(ex.Messages());
|
||||
|
||||
LogFactory.GetLogger("收盘报错").Error(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (eodTask.TaskState < EodTaskState.completed)
|
||||
{
|
||||
eodTask.TaskState = EodTaskState.completed;
|
||||
}
|
||||
else if (eodTask.TaskState == EodTaskState.canceling)
|
||||
{
|
||||
eodTask.TaskState = EodTaskState.canceled;
|
||||
}
|
||||
|
||||
eodTask.TaskEndTime = DateTime.Now;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
_report.StopEodTask();
|
||||
}
|
||||
}
|
||||
|
||||
//根据波动率和价格模式进行步骤分解
|
||||
private void RunEodTask(EodTask eodTask, SettlementConfig settlementConfig)
|
||||
{
|
||||
var userInfo = new OptUserInfo(eodTask.OptId, eodTask.OptName, OptUserFrom.System);
|
||||
|
||||
var request = new EodSettlementRequest(userInfo)
|
||||
{
|
||||
VolType = null,
|
||||
UseClosePrice = true,
|
||||
SettleDate = eodTask.ValueDate,
|
||||
ClientIds = eodTask.ListClientId,
|
||||
};
|
||||
|
||||
request.IsDelayTrade = eodTask.IsDelayTrade;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(eodTask.PartFlag) && eodTask.PartFlag != "全部")
|
||||
{
|
||||
request.IsSettleOtcTrades = eodTask.PartFlag == "场外";
|
||||
request.IsSettleExchangeTrades = !request.IsSettleOtcTrades;
|
||||
}
|
||||
|
||||
var priceTypes = new[] { EodSettlePriceType.ClosePrice, EodSettlePriceType.SettlePrice };
|
||||
|
||||
//从开始日期递增执行到结束日期
|
||||
for (var i = 0; i < 10000; i++)
|
||||
{
|
||||
_cancellationTokenSource.Token.ThrowIfCancellationRequested();
|
||||
|
||||
eodTask.ValueDate = BLL.valuedateBLL.GetNonHoliday(eodTask.ValueDate);
|
||||
if (eodTask.ValueDate > eodTask.EndDate)
|
||||
{
|
||||
break;
|
||||
}
|
||||
DbContext.SaveChanges();
|
||||
|
||||
//检查任务是否可以正确执行
|
||||
var cloneTask = eodTask.Clone();
|
||||
cloneTask.StartDate = eodTask.ValueDate;
|
||||
var result = new EodTaskSaveService(this).CheckEodTask(cloneTask);
|
||||
if (result.HasError)
|
||||
{
|
||||
eodTask.SetError(result.IsFatalError, result.ErrorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
//准备执行
|
||||
request.SettleDate = eodTask.ValueDate;
|
||||
if (request.IsDelayTrade)
|
||||
{
|
||||
request.DelayUnderlyIds = new TradeDelaySettlementService(userInfo).GetDelayUnderlyIds(eodTask.ValueDate);
|
||||
}
|
||||
else
|
||||
{
|
||||
request.DelayUnderlyIds = new List<int>();
|
||||
}
|
||||
|
||||
//任务明细
|
||||
var detail = new EodTaskDetail
|
||||
{
|
||||
TaskId = eodTask.id,
|
||||
ValueDate = eodTask.ValueDate,
|
||||
StartTime = DateTime.Now,
|
||||
ElapsedMilliseconds = 0
|
||||
};
|
||||
_report.StartTaskDetail(detail);
|
||||
if (eodTask.id > 0)
|
||||
{
|
||||
DbContext.EodTaskDetail.Add(detail);
|
||||
}
|
||||
|
||||
foreach (var priceType in priceTypes)
|
||||
{
|
||||
if (eodTask.PriceType.HasFlag(priceType))
|
||||
{
|
||||
foreach (var volType in result.VolTypes)
|
||||
{
|
||||
request.VolType = volType;
|
||||
request.UseClosePrice = priceType == EodSettlePriceType.ClosePrice;
|
||||
var runner = new InnerTaskRunner(request.Clone(true), settlementConfig, _cancellationTokenSource);
|
||||
runner.Execute(out var elapsedMilliseconds);
|
||||
detail.ElapsedMilliseconds += (int)elapsedMilliseconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
new EodFileService(this.OptUser).GenerateFileAfterEod(eodTask.ValueDate);
|
||||
//执行下一日
|
||||
eodTask.ValueDate = eodTask.ValueDate.AddDays(1);
|
||||
eodTask.TaskEndTime = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查找第一个可用的任务
|
||||
/// </summary>
|
||||
private EodTask QueryFirstAvailableTask()
|
||||
{
|
||||
var startDate = DateTime.Today.AddDays(-3);
|
||||
|
||||
return DbContext.EodTask.Where(n => n.TaskStartTime > startDate && n.TaskState < EodTaskState.completed)
|
||||
.OrderBy(n => n.StartDate).ThenBy(n => n.id).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region----执行每日收盘----
|
||||
|
||||
class InnerTaskRunner : IAsyncTaskManager
|
||||
{
|
||||
readonly EodSettlementRequest _request;
|
||||
readonly EodSettlementContextV2 _context;
|
||||
readonly CancellationTokenSource _cancellationTokenSource;
|
||||
|
||||
public InnerTaskRunner(EodSettlementRequest request, SettlementConfig settlementConfig, CancellationTokenSource cancellationTokenSource)
|
||||
{
|
||||
_request = request ?? throw new ArgumentNullException(nameof(request));
|
||||
_cancellationTokenSource = cancellationTokenSource ?? throw new ArgumentNullException(nameof(cancellationTokenSource));
|
||||
_context = new EodSettlementContextV2(request, settlementConfig, _cancellationTokenSource.Token);
|
||||
}
|
||||
|
||||
public void Execute(out long elapsedMilliseconds)
|
||||
{
|
||||
var sw = new System.Diagnostics.Stopwatch();
|
||||
|
||||
_context.LogInfo("!!!!!!收盘!!!!!!");
|
||||
_context.LogInfo($"开始收盘:{_request.SettleDate:yyyy-MM-dd} + {_request.VolType} + {_request.GetPriceType()}");
|
||||
|
||||
sw.Start();
|
||||
|
||||
if (!_request.IsPartialSettlement)
|
||||
{
|
||||
AddOrUpdateEodStatus(_request, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateEodCheckStatus(_request);
|
||||
}
|
||||
|
||||
var execBasicTask = _request.VolType == "持仓" && _request.UseClosePrice;
|
||||
|
||||
Task[] tasks;
|
||||
|
||||
if (execBasicTask)
|
||||
{
|
||||
SetTaskStep("检查日终汇率");
|
||||
|
||||
if (PS.Config.ErpElement.SupportMultiCurrency)
|
||||
{
|
||||
new EodCheckCurrency(_context).Execute();
|
||||
}
|
||||
|
||||
tasks = new Task[3];
|
||||
|
||||
tasks[0] = Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("检查标的到期日");
|
||||
new EodCheckMaturityDate(_context).Execute();//t
|
||||
|
||||
SetTaskStep("合成篮子标的价格");
|
||||
new EodBasketPriceSaveService(_context).Execute();//t
|
||||
|
||||
if (PS.Config.ErpElement.SupportMultiCalendar)
|
||||
{
|
||||
SetTaskStep("为处于节假日的交易标的复制上日收盘价");
|
||||
new EodCopyPreSettlePrice(_context).Execute();
|
||||
}
|
||||
|
||||
SetTaskStep("检查标的结算价格缺失");
|
||||
new EodCheckSettlePrice(_context).Execute();//t
|
||||
|
||||
if (PS.Config.Is厦门象屿)
|
||||
{
|
||||
SetTaskStep("检查标的参考价格缺失");
|
||||
new EodCheckReferencePrice(_context).Execute();//t
|
||||
}
|
||||
});
|
||||
|
||||
if (_request.IsSettleOtcTrades)
|
||||
{
|
||||
tasks[1] = Task.Run(() =>
|
||||
{
|
||||
//SetTaskStep("合成多空组合流水");
|
||||
//new EodHandleSwapFlowService(_context).Execute();
|
||||
|
||||
SetTaskStep("检查当日交易");
|
||||
new EodCheckNewTrade(_context).Execute();//t
|
||||
|
||||
SetTaskStep("日终结算检查");
|
||||
new EodCheckVolService(_context).Execute();//t
|
||||
|
||||
SetTaskStep("合成互换交易");
|
||||
new TradeSwapFlowMoreCheck(_context).Execute();//t
|
||||
});
|
||||
}
|
||||
|
||||
if (_request.IsSettleOtcTrades)
|
||||
{
|
||||
tasks[2] = Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("汇率收盘结算");
|
||||
new EodCurrencyRateService(_request.UserInfo).HandleAmountByCurrencyRate(_context.SettleDate, _context.Request.ClientIds);//t
|
||||
});
|
||||
}
|
||||
|
||||
WaitTasks(tasks);
|
||||
if (_request.IsSettleOtcTrades)
|
||||
{
|
||||
tasks = new[]
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("检查期权观察状态1");
|
||||
new EodCheckMonitoredTrade(_context).ExecuteTask1(SetTaskStep);//t
|
||||
}),
|
||||
Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("检查期权观察状态2");
|
||||
new EodCheckMonitoredTrade(_context).ExecuteTask2(SetTaskStep);//t
|
||||
}),
|
||||
// Task.Run(() =>
|
||||
//{
|
||||
// SetTaskStep("定期结算互换收益");
|
||||
// new EodCheckMonitoredTrade(_context).ExecuteBalanceSwapProfit(SetTaskStep);//t
|
||||
//})
|
||||
Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("定期归档收益互换");
|
||||
new EodCheckMonitoredTrade(_context).ExecuteEodSwapPosition(SetTaskStep);//t
|
||||
})
|
||||
};
|
||||
|
||||
WaitTasks(tasks);
|
||||
|
||||
SetTaskStep("自动延期结算");
|
||||
new EodDelaySettlementTrade(_context).Execute(_report.SetErrorTips);//t
|
||||
|
||||
SetTaskStep("检查当日到期交易");
|
||||
new EodCheckMaturityTrade(_context).Execute();//t
|
||||
}
|
||||
if (PS.Config.Is山西固收)
|
||||
{
|
||||
new EodCheckMonitoredTrade(_context).CalculateMargin();
|
||||
new EodCheckMonitoredTrade(_context).ExecuteEodSwap();
|
||||
}
|
||||
tasks = new Task[4];
|
||||
|
||||
if (_request.IsSettleExchangeTrades)
|
||||
{
|
||||
//tasks[0] = Task.Run(() =>
|
||||
//{
|
||||
// if (_context.Request.ClientIds == null)
|
||||
// {
|
||||
// SetTaskStep("场内期权结算");
|
||||
// new ExchangeOptionSettlementService(_context.UserInfo).Execute(_context.SettleDate); //t
|
||||
// }
|
||||
//});
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (_request.IsSettleOtcTrades)
|
||||
{
|
||||
tasks[0] = Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("备份场外交易");
|
||||
SaveEodTrade(_context, _cancellationTokenSource.Token);//t
|
||||
});
|
||||
tasks[1] = Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("检查权利金应付日");
|
||||
new EodCheckPremiumPayDate(_context).Execute();//t
|
||||
});
|
||||
|
||||
if (_context.SettlementConfig.CalcForwradMargin)
|
||||
{
|
||||
tasks[2] = Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("远期预付金成本结算");
|
||||
new EodForwardMarginSettlement(_context).Execute();//t
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//敏感数据计算
|
||||
|
||||
|
||||
WaitTasks(tasks);
|
||||
}
|
||||
|
||||
SetTaskStep("日终持仓结算");
|
||||
|
||||
var eodPositionService = new EodPositionSettleService(_context);
|
||||
|
||||
eodPositionService.Execute(_request.VolType, _request.UseClosePrice, this);//t?
|
||||
|
||||
_context.LogInfo("结束任务:日终持仓结算");
|
||||
if (_request.IsSettleExchangeTrades)
|
||||
{
|
||||
if (_context.Request.ClientIds == null || !_context.Request.ClientIds.Any())
|
||||
{
|
||||
SetTaskStep("场内期权结算");
|
||||
new ExchangeOptionSettlementService(_context.UserInfo).Execute(_context.SettleDate); //t
|
||||
}
|
||||
}
|
||||
|
||||
if (execBasicTask)
|
||||
{
|
||||
//交易员结算:按簿记账户计算资金和盈亏等信息
|
||||
//new EodBookBalanceCalc(context).BookBalanceCalc();
|
||||
|
||||
SetTaskStep("结算客户资金");
|
||||
new EodClientBalanceCalc(_context).ClientBalanceCalc();
|
||||
|
||||
//客户资金买卖权分开算
|
||||
if (_context.SettlementConfig.CalcBuySell)
|
||||
{
|
||||
new EodClientBalanceCalcBS(_context.UserInfo).ClientBalanceByDay(_context.SettleDate, null);
|
||||
}
|
||||
_context.LogInfo("结束任务:结算客户资金");
|
||||
|
||||
if (PS.Config.ErpElement.UseSettleDataAcquisition)
|
||||
{
|
||||
SetTaskStep("配合数据采集,限额监控数据落地");
|
||||
var service = new QuotaMonitorService(_context.UserInfo);
|
||||
if (_context.IsCurrentDay)
|
||||
{
|
||||
service.EodSettlementExecute(_context.SettleDate);
|
||||
}
|
||||
|
||||
service.EodSensitiveDataCalc(_context);
|
||||
|
||||
_context.LogInfo("结束任务:限额监控数据落地");
|
||||
}
|
||||
|
||||
//todo:客户日终结算完成发送行权到期邮件提醒
|
||||
|
||||
tasks = new Task[2];
|
||||
|
||||
if (_request.IsSettleExchangeTrades)
|
||||
{
|
||||
tasks[0] = Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("准备次日数据");
|
||||
new EodDividenService(_context).Execute(eodPositionService.EodTradePositions);//t
|
||||
});
|
||||
}
|
||||
|
||||
if (_request.IsSettleOtcTrades)
|
||||
{
|
||||
tasks[1] = Task.Run(() =>
|
||||
{
|
||||
SetTaskStep("除权除息");
|
||||
var otcTrades = _context.OtcTrades.Where(t => !ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus)).ToList();
|
||||
var tradeIds = otcTrades.Select(O => O.id);
|
||||
var parentTradeIds = otcTrades.Where(O => O.ParentTradeId > 0 && !tradeIds.Contains(O.ParentTradeId)).Select(O => O.ParentTradeId).ToHashSet();
|
||||
if (parentTradeIds.Any())
|
||||
{
|
||||
using var db = DbContextFactory.GetYLDbContext();
|
||||
var parentTrades = new TradeDalService(_context.UserInfo).GetTradeOrEodTrade(parentTradeIds, _context.SettleDate);
|
||||
otcTrades.AddRange(parentTrades);
|
||||
}
|
||||
new EodDividenService(_context).Execute(otcTrades);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
WaitTasks(tasks);
|
||||
}
|
||||
|
||||
_cancellationTokenSource.Token.ThrowIfCancellationRequested();
|
||||
|
||||
//if (!_request.IsPartialSettlement)
|
||||
//{
|
||||
AddOrUpdateEodStatus(_request);
|
||||
//}
|
||||
|
||||
//兴证日终持仓数据上传数据中心的FTP服务器
|
||||
if (PS.Config.Company == CompanyEnum.兴证 && _context.IsCurrentDay)
|
||||
{
|
||||
Task.Run(() => XingZhengService.EodExecute(_context));
|
||||
}
|
||||
|
||||
//日终数据采集
|
||||
if (PS.Config.Company == CompanyEnum.长江)
|
||||
{
|
||||
Task.Run(() => ChangJiangService.EodExecute(_context, _request.VolType, _request.UseClosePrice ? "收盘价" : "结算价"));
|
||||
}
|
||||
|
||||
//东证
|
||||
if (PS.Config.Company == CompanyEnum.润和)
|
||||
{
|
||||
Task.Run(() => DongZhengService.EodExecute(_context));
|
||||
}
|
||||
|
||||
|
||||
//广发商贸
|
||||
if (PS.Config.Company == CompanyEnum.广发商贸 && _request.VolType == "对冲" && _request.UseClosePrice)
|
||||
{
|
||||
Task.Run(() => GuangFaService.EodExecute(_context));
|
||||
}
|
||||
|
||||
sw.Stop();
|
||||
|
||||
elapsedMilliseconds = sw.ElapsedMilliseconds;
|
||||
|
||||
_context.LogInfo($"结束收盘:{_request.SettleDate:yyyy-MM-dd} + {_request.VolType} + {_request.GetPriceType()},用时:{elapsedMilliseconds}毫秒");
|
||||
}
|
||||
|
||||
public void SetTaskStep(string step)
|
||||
{
|
||||
TaskStep = step;
|
||||
|
||||
_context.LogInfo("开始任务:" + step);
|
||||
|
||||
_cancellationTokenSource.Token.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
LogFactory.GetLogger("日终结算").Error(t.Exception, TaskStep);
|
||||
}
|
||||
|
||||
_context.LogInfo("结束任务:" + TaskStep);
|
||||
});
|
||||
}
|
||||
|
||||
_cancellationTokenSource.Token.ThrowIfCancellationRequested();
|
||||
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存日终场外交易数据
|
||||
/// </summary>
|
||||
private static void SaveEodTrade(EodSettlementContextV2 context, CancellationToken cancellationToken)
|
||||
{
|
||||
//在context中取OtcTrades时存在隐含赋值 MetaDic["from_eod_trade"] = "true"
|
||||
var otcTrades = context.InitOtcTrades(true);
|
||||
|
||||
var trades = otcTrades.Where(t => !t.MetaDic.ContainsKey("from_eod_trade")).ToList();
|
||||
var parentTradeIds = otcTrades.Where(x => x.ParentTradeId > 0).Select(x => x.ParentTradeId).ToHashSet();
|
||||
//解决测试环境中存在的交易重复问题(比如新功能的增加导致前置逻辑未来得及处理)
|
||||
foreach (var t in trades)
|
||||
{
|
||||
parentTradeIds.Remove(t.id);
|
||||
}
|
||||
using var db = DbContextFactory.GetYLDbContext();
|
||||
var eodGroupTradeIds = db.eod_trade.Where(x => parentTradeIds.Contains(x.TradeId) && x.ValueDate == context.SettleDate).Select(x => x.TradeId);
|
||||
var groupTrades = db.trade.AsNoTracking().Where(x => parentTradeIds.Contains(x.id) && !eodGroupTradeIds.Contains(x.id)).ToList();
|
||||
groupTrades.ForEach(x =>
|
||||
{
|
||||
EodSettleDataQueryService.ProcessTrade(context.SettleDate, new DataProviderModule.TradeCashDataProvider(), new DataProviderModule.TradeCashPreDataProvider(), x);
|
||||
});
|
||||
trades.AddRange(groupTrades);
|
||||
var tradeIds = trades.Select(O => O.id);
|
||||
//移除修改了分红率或无风险利率的交易,以更新收盘数据;
|
||||
db.eod_trade.RemoveRange(db.eod_trade.Where(O => tradeIds.Contains(O.TradeId) && O.ValueDate == context.SettleDate));
|
||||
|
||||
var sql = new StringBuilder("delete from ").Append(db.GetTableName<eod_trade>())
|
||||
.AppendFormat(" where ValueDate='{0}'", context.SettleDateStr)
|
||||
.Append(" and not exists(select * from trade where id=TradeId)");
|
||||
|
||||
db.Database.ExecuteSqlRaw(sql.ToString());
|
||||
|
||||
foreach (var t in trades)
|
||||
{
|
||||
if (!t.MetaDic.ContainsKey("from_eod_trade"))
|
||||
{
|
||||
db.eod_trade.Add(new eod_trade
|
||||
{
|
||||
ValueDate = context.SettleDate,
|
||||
TradeId = t.id,
|
||||
TradeNumber = t.TradeNumber,
|
||||
ClientId = t.ClientId,
|
||||
AssetId = t.AssetId,
|
||||
UnderlyingId = t.UnderlyingId,
|
||||
UnderlyingCode = t.UnderlyingCode,
|
||||
TradeStatus = t.TradeStatus,
|
||||
ParentTradeId = t.ParentTradeId,
|
||||
TradeType = t.TradeType,
|
||||
TradeJson = t.Serialize(context.SettleDate),
|
||||
OptDate = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
db.SaveChanges(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 新增或更新EodStatus表(重新执行收盘前重置)
|
||||
/// </summary>
|
||||
private static void AddOrUpdateEodStatus(EodSettlementRequest request, bool reset = false)
|
||||
{
|
||||
using var db = DbContextFactory.GetYLDbContext();
|
||||
var eodStatus = db.eodStatus.FirstOrDefault(n => n.ValueDate == request.SettleDate);
|
||||
|
||||
if (eodStatus == null)
|
||||
{
|
||||
eodStatus = new EodStatus
|
||||
{
|
||||
ValueDate = request.SettleDate,
|
||||
IsHoliday = true,
|
||||
OptDate = DateTime.Now,
|
||||
OptId = request.UserInfo.UserId,
|
||||
OptName = request.UserInfo.UserName,
|
||||
Status = string.Empty,
|
||||
StepStatus = string.Empty,
|
||||
VolTypeFlag = VolTypeFlagEnum.None,
|
||||
VolTypeFlag_S = VolTypeFlagEnum.None
|
||||
};
|
||||
db.eodStatus.Add(eodStatus);
|
||||
}
|
||||
if (request.VolType == "持仓" && request.UseClosePrice)
|
||||
{
|
||||
eodStatus.Status = String.Empty;
|
||||
}
|
||||
|
||||
eodStatus.OptDate = DateTime.Now;
|
||||
eodStatus.OptId = request.UserInfo.UserId;
|
||||
eodStatus.OptName = request.UserInfo.UserName;
|
||||
eodStatus.CheckStatus = null;
|
||||
eodStatus.CheckDate = null;
|
||||
|
||||
var volTypeFlag = VolTypeFlagEnumHelper.GetVolTypeFlag(request.VolType);
|
||||
|
||||
if (reset)
|
||||
{
|
||||
volTypeFlag = (eodStatus.VolTypeFlag | volTypeFlag) ^ volTypeFlag;
|
||||
|
||||
if (request.UseClosePrice)
|
||||
{
|
||||
eodStatus.VolTypeFlag = volTypeFlag;
|
||||
}
|
||||
else
|
||||
{
|
||||
eodStatus.VolTypeFlag_S = volTypeFlag;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
eodStatus.Status = "已收盘";
|
||||
|
||||
if (request.UseClosePrice)
|
||||
{
|
||||
eodStatus.VolTypeFlag |= volTypeFlag;
|
||||
}
|
||||
else
|
||||
{
|
||||
eodStatus.VolTypeFlag_S |= volTypeFlag;
|
||||
}
|
||||
}
|
||||
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
private static void UpdateEodCheckStatus(EodSettlementRequest request)
|
||||
{
|
||||
using var db = DbContextFactory.GetYLDbContext();
|
||||
var eodStatus = db.eodStatus.FirstOrDefault(n => n.ValueDate == request.SettleDate);
|
||||
if (eodStatus != null)
|
||||
{
|
||||
eodStatus.CheckStatus = null;
|
||||
eodStatus.CheckDate = null;
|
||||
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user