using NPOI.SS.Formula.Functions; using YLErp.BLL.Calculation.V2; using YLErp.BLL.EodSettlement; using YLErp.Commons; using YLErp.CustomizedBizLogic; using YLErp.DBModels.Consts; using YLErp.DBModels.Helpers; using YLErp.Enums; using YLErp.Modules.CalculationModule; using YLErp.Modules.DataProviderModule; using YLErp.Modules.TradeDalModule; using YLErp.Modules.TradeModule; using YLErp.Modules.TradeModule.AccumulatorOptionModule; using YLErp.Modules.TradeModule.DealModule; using YLErp.Modules.TradeModule.OrderModule; using YLErp.Modules.VolatilityModule; using YLErp.QdpModule; namespace YLErp.Web.Controllers { public class trade_cashController : BaseController { readonly YLContext db = new YLContext(); public ActionResult executionTradeCash(string enid, bool isexpire = false, bool isUseApproval = false) { ViewBag.Title = "现金交割交易 | 执行交割"; var intid = DecryptInt(enid); var td = db.trade.Find(intid); if (td == null) { return Content("找不到现金交割交易"); } if (td.Warning) { new TradeDalService(CurUser).RollbackToBeforeSettle(td, valuedateBLL.ValueDate); } ViewBag.Trade = td; tradeBLL.SetFieldsByTradeType(td); if (td.TradeType == "亚式期权" && td.trade_asian_option != null && !EodPriceQueryService.CheckDbExists(td.trade_asian_option.AveragingPeriodStartDate ?? td.TradeDate.Value, valuedateBLL.ValueDate, td.UnderlyingInstrumentType, td.UnderlyingCode)) { return Content("该亚式期权没有获取到均价起算日之后的收盘价列表"); } var r = new TradeCashService(CurUser).ExecutionTradeCash(td); //r.SpotPrice = EodPriceQueryService.TryGetEodPrice(r.ValueDate, td.UnderlyingCode, out var eodPrice) // ? eodPrice.GetPrice(td.SettlementType) : DataCacheProvider.GetUnderlyingDataSource().GetPrice(r.UnderlyingId ?? 0); //需要审批或者复核的交易都会显示行权审核提交按钮 ViewBag.IsShowReCheckClose = ((valuedateBLL.SystemDate.CloseReCheck == 1) || (valuedateBLL.SystemDate.CloseReApprove == 1 && HasTradeProcess())) && td.TradeStatus != ConsTrade.行权待复核; ViewBag.IsReCheckConfirm = td.TradeStatus == ConsTrade.行权待复核; ViewBag.isUseApproval = isUseApproval; //复核时隐藏下面的字段,让用户手动输入验证 if (td.TradeStatus == ConsTrade.行权待复核) { r.ExtraAmount = null; r.FinalPrice = null; var tradeCash = db.trade_cash.Where(x => x.TradeId == td.id && (x.Action == "系统操作-行权费" || x.Action == "系统操作-平仓费") && x.ValidState == "InValid" && !x.IsDeleted).OrderByDescending(x => x.OptDate)?.FirstOrDefault(); r.IsExpire = tradeCash != null && tradeCash.ExerciseWay == TradeCashExerciseWayEnum.到期行权; if (td.TradeType == "亚式期权") { r.Strike = tradeCash.Strike; } if (isUseApproval) { r.FinalPrice = tradeCash.FinalPrice; r.Strike = tradeCash.Strike; r.UnwindType = tradeCash.UnwindType; r.UnwindNotional = tradeCash.UnwindNotional; r.UnwindPercentRate = tradeCash.UnwindPercentRate * 100; r.UnwindStockEqvNotional = tradeCash.UnwindStockEqvNotional; r.UnwindTradeAmount = tradeCash.UnwindTradeAmount; r.ExtraAmount = tradeCash.ExtraAmount; r.UnwindPrice = tradeCash.UnwindPrice; r.Amount = tradeCash.Amount; r.InitialAmount = r.Amount - (r.ExtraAmount ?? 0); } if (r.IsExpire == true) { r.UnwindType = "全部行权"; } ViewBag.IsExpire = r.IsExpire; } else { r.UnwindType = "全部行权"; r.IsExpire = isexpire; ViewBag.IsExpire = isexpire; } if (!string.IsNullOrEmpty(td.PairTrade)) { var pid = Convert.ToInt32(td.PairTrade); ViewBag.PairTrade = db.trade.Find(pid); } if (r != null) { r.InitialSpotPrice = r.InitialSpotPrice.OtcFormatValue(OtcFormatFlag.umprice); r.ValidStrike = r.ValidStrike.OtcFormatValue(OtcFormatFlag.umprice); r.OriginalStockEqvNotional = td.StockEqvNotionalReal; r.StockEqvNotional = TradeHelper.GetStockEqvNotionalReal(td.StockEqvNotional, td.ParticipationRate, td.AnnualizeFactor); r.UnwindStockEqvNotional = r.StockEqvNotional; r.IsUnwindStockEqvNotional = false; } return View(r); } public JsonResult checkEodPrice(string enid) { var intid = DecryptInt(enid); var td = db.trade.Find(intid); if (td == null) { return JsonError("找不到交易"); } var valueDate = valuedateBLL.ValueDate; if (PS.Config.Company == Configuration.CompanyEnum.厦门象屿 && td.SettlementType == SettlementTypeEnum.ReferencePrice) { valueDate = Modules.SpecialModule.XiaMenXiangYuHelper.GetRefernceValueDate(valueDate); } if (td.TradeDate > valueDate) { return JsonError("执行日期在交易起始日之前,操作失败"); } if (td.ExerciseMode == "European" && td.ExerciseDate > valueDate) { return JsonError("执行日期在交易到期日之前,操作失败"); } if (td.ExerciseDate != null && valueDate > td.ExerciseDate) { valueDate = td.ExerciseDate.Value; } if (QdpCalendarHelper.IsHoliday(valueDate)) { valueDate = QdpCalendarHelper.GetNonHolidayDefore(valueDate); } if (!EodPriceQueryService.TryGetSettlementEodPrice(valueDate, td.UnderlyingCode, out _)) { return JsonError($"交易日{valueDate:yyyy-MM-dd}的结算价或收盘价未找到!"); } return JsonSuccess(); } /// /// 计算到期收益 /// [HttpPost] public JsonResult CalcAmount(int enid, double finalPrice, double notional, bool isRefreshFinalPrice = false, double? strike = null) { var td = db.trade.Find(enid); var r = new trade_cash(); if (td == null) { return JsonError("计算错误"); } else { r.IsPossibleExec = true; var um = db.underlying_manager.FirstOrDefault(t => t.id == td.UnderlyingId); if (notional < td.Notional) { td.Notional = notional; td.StockEqvNotionalReal = (notional * td.SpotPrice) ?? 0; td.StockEqvNotional = TradeHelper.GetStockEqvNotional(td.StockEqvNotionalReal, td.ParticipationRate, td.AnnualizeFactor); } var valueDate = valuedateBLL.ValueDate; if (td.ExerciseDate != null && valueDate > td.ExerciseDate.Value) { valueDate = td.ExerciseDate.Value; } r.ValueDate = valueDate; SettlementCalcCommons.SetPossibleExec(r, td, finalPrice, isRefreshFinalPrice, strike: strike, finalPriceSettleDate: r.ValueDate); return JsonSuccess("计算成功", new { r.IsPossibleExec, r.Amount, r.FinalPrice, r.UnwindPrice }); } } [HttpPost] public JsonResult CalcMultyTradeAmount(int enid, double finalPrice) { var td = db.trade.Find(enid); if (td == null) { return JsonError("计算错误"); } else { double amount = 0; var childTrades = db.trade.Where(x => x.ParentTradeId == td.id).ToList(); foreach (var trade in childTrades) { var r = new trade_cash(); tradeBLL.SetFieldsByTradeType(trade); SettlementCalcCommons.SetPossibleExec(r, trade, finalPrice); amount += r.Amount; } return JsonSuccess("计算成功", new { IsPossibleExec = true, Amount = amount }); } } public double? CalcAmountOnly(int enid, double tradePrice) { var td = db.trade.Find(enid); var r = new trade_cash(); if (td != null) { tradeBLL.SetFieldsByTradeType(td); r.IsPossibleExec = true; var um = db.underlying_manager.FirstOrDefault(t => t.id == td.UnderlyingId); SettlementCalcCommons.SetPossibleExec(r, td, tradePrice); return r.Amount; } else { return 0; } } /// /// 执行合约/复核执行合约 /// [HttpPost] public JsonResult executionTradeCashJson(TradeCashReq req, string _Version) { if (req is null) { return JsonError("数据不能为空"); } var tc = new TradeCashService(CurUser).GetLastSettleInfo(req.TradeId); if (tc != null && tc.ValueDate > req.ValueDate) { return JsonError($"提交失败,了结日期不应早于{tc.ValueDate:yyyy-MM-dd},请重新操作"); } var result = new TradeCashService(CurUser).ExecutionTradeCash(req); setTradeExtensionInfo(result.Trade); if (!result.Success) { return JsonError(result.Message, result.Trade); } if (result.TradeCash != null && _Version == "V2") { var trade = result.Trade; new TradeExtendService(CurUser).SetTradeExtend(new[] { trade }); var text = TradeTerminationAbstractService.GetAbstractInfoText(result.TradeCash, trade, false); return JsonSuccess(result.Message, text); } return JsonSuccess(result.Message, result.Trade); } /// /// 日终执行批量行权到期 /// [HttpPost] public async Task ExeExpireTradeCashJson(TradeCashReq req) { var tc = new trade_cash(); await TryUpdateModelAsync(tc); new TradeExpireService(CurUser).ExeExpireTradeCash(req, tc); return JsonSuccess("执行成功", null); } /// /// 拒绝平仓审核 /// [MyAuthorize("交易管理-交易平仓审核")] [HttpPost] public JsonResult DenyReCheck(TradeCashReq req) { new TradeProcessService(CurUser).DenyReCheck(req); return JsonSuccess("提前终止拒绝成功"); } /// /// 平仓待复核提交 /// [HttpPost] public JsonResult CloseReCheck(TradeCashReq req, string _Version, bool isFromExercise = false) { var tc = new TradeCashService(CurUser).GetLastSettleInfo(req.TradeId); if (tc != null && tc.ValueDate > req.ValueDate) { return JsonError($"提交失败,了结日期不应早于{tc.ValueDate:yyyy-MM-dd},请重新操作"); } var result = new TradeCloseService(CurUser).CloseReCheck(req, isFromExercise); setTradeExtensionInfo(result.Trade); if (_Version == "V2") { var trade = result.Trade; new TradeExtendService(CurUser).SetTradeExtend(new[] { trade }); var text = TradeTerminationAbstractService.GetAbstractInfoText(result.TradeCash, trade, true); return JsonSuccess("提交审核成功", text); } return JsonSuccess("提交审核成功", result.Trade); } /// /// 行权待复核提交 /// [HttpPost] public JsonResult applyExerciseRecheck(TradeCashReq req, string _Version) { var tc = new TradeCashService(CurUser).GetLastSettleInfo(req.TradeId); if (tc != null && tc.ValueDate > req.ValueDate) { return JsonError($"提交失败,了结日期不应早于{tc.ValueDate:yyyy-MM-dd},请重新操作"); } var result = new TradeExerciseService(CurUser).ApplyExerciseRecheck(req); setTradeExtensionInfo(result.Trade); if (_Version == "V2") { var trade = result.Trade; new TradeExtendService(CurUser).SetTradeExtend(new[] { trade }); var text = TradeTerminationAbstractService.GetAbstractInfoText(result.TradeCash, trade, false); return JsonSuccess("提交审核成功", text); } return JsonSuccess("提交审核成功", result.Trade); } //交易平仓复核/交易平仓 [MyAuthorize("交易管理-交易平仓,交易管理-交易平仓审核")] [HttpPost] public JsonResult UnwindTradeJson(TradeCashReq req, string _Version) { try { var tc = new TradeCashService(CurUser).GetLastSettleInfo(req.TradeId); if (tc != null && tc.ValueDate > req.ValueDate) { return JsonError($"提交失败,了结日期不应早于{tc.ValueDate:yyyy-MM-dd},请重新操作"); } var result = new TradeUnwindService(CurUser).UnwindTrade(req); setTradeExtensionInfo(result.Trade); tradeBLL.SetFieldsByTradeType(result.Trade); if (result.ApprovalProcess) { return JsonSuccess("复核审批成功", result.Trade); } if (result.HasPairTrade) { return JsonSuccess("执行成功,配对交易平仓" + (result.PairTradeUnwindSuccess ? "执行成功" : "执行失败"), result.Trade); } if (_Version == "V2") { var trade = result.Trade; new TradeExtendService(CurUser).SetTradeExtend(new[] { trade }); var text = TradeTerminationAbstractService.GetAbstractInfoText(result.TradeCash, trade, true); return JsonSuccess("执行成功", text); } return JsonSuccess("执行成功", result.Trade); } catch (Exception ex) { LogFactory.GetLogger("平仓失败").Error("UnwindTradeJson", ex); return JsonError("平仓失败" + ex.Message); } } [HttpPost] public JsonResult GetPositionVol(TradeCashReq req) { var td = db.trade.Find(req.TradeId); if (td == null) { return JsonError("系统中没有此交易!"); } if (!req.ValueDate.HasValue) { req.ValueDate = valuedateBLL.ValueDate; } var vol = new VolatilityService(CurUser).GetTradeVol(td, req.ValueDate.Value); if (!PS.Config.IsTradeVol) { var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); var variety = DataCacheProvider.GetVariety(td.UnderlyingCode); var singleVol = new SingleVolReq() { VolType = "交易", Strike = td.Strike ?? 0, SpotPrice = req.SpotPrice ?? 0, TradeDate = req.ValueDate.Value, ExerciseDate = td.ExerciseDate ?? DateTime.Today, IsMoneynessOption = td.IsMoneynessOption, CallPut = td.CallPut == "看涨" ? "Call" : "Put", UnderlyingId = um.id, UnderlyingCode = um.UnderlyingCode, UnderlyingName = um.UnderlyingName, UnderlyingTypeId = variety.id, BaseVol = null, BidVar = null, AskVar = null, }; if (PS.Config.Is润和) { singleVol.TradeDate = req.ValueDate ?? DateTime.Today; } vol = SingleVolService.GetSingleVol(singleVol, UserId); } return JsonSuccess("", vol); } [HttpPost] public JsonResult GetImpliedUnWindVol(TradeCashReq req) { if (req == null) { return JsonError("实体不能为空!"); } if (!req.UnwindPrice.HasValue) { return JsonError("平仓单价不能为空"); } if (!req.FinalPrice.HasValue) { return JsonError("标的价格不能为空"); } var td = db.trade.Find(req.TradeId); if (td == null) { return JsonError("系统中没有此交易!"); } if (td.TradeType != "香草期权") { return JsonError("只支持香草期权获取波动率"); } if (!req.ValueDate.HasValue) { req.ValueDate = valuedateBLL.ValueDate; } if (req.TTM.HasValue) { td.TTMDays = req.TTM; } var vol = Modules.PricingModule.ReverseCalcService.GetImpliedUnWindVol(td, req.ValueDate.Value, req.UnwindPrice.Value, req.FinalPrice.Value, valuedateBLL.ValueDate > req.ValueDate); if (!vol.HasValue) { return JsonError("获取隐含波动率失败"); } return JsonSuccess("", vol); } public JsonResult tradeUnwindCalc(TradeCashReq req) { Dictionary resultDict = null; var tradeBLL = new tradeBLL(); var userId = CurUser.UserId.ToString(); //修改交易主表信息交易状态为已执行 var td = db.trade.AsNoTracking().FirstOrDefault(t => t.id == req.TradeId); if (td == null) { return JsonError("计算失败,找不到交易!", null); } if (!GlobalDicionary.SupportTradeTypes.Contains(td.TradeType)) { return JsonError(string.Format("计算失败,当前服务不支持{0}的计算!", td.TradeType), null); } if (td.Warning) { new TradeDalService(CurUser).RollbackToBeforeSettle(td, req.ValueDate ?? valuedateBLL.ValueDate); } try { if (!req.ValueDate.HasValue) { req.ValueDate = valuedateBLL.ValueDate; } tradeBLL.SetFieldsByTradeType(td); //这个方法会慢 resultDict = GetTradeUnwindCalc(req, td.Clone()); if (PS.Config.Is润和) { req.UnwindNotional = req.ActualUnwindNotional ?? 1; Dictionary resultDictVolPV = GetTradeUnwindCalc(req, td.Clone()); req.UnwindVol = req.MidVol; Dictionary resultDictMidPV = GetTradeUnwindCalc(req, td.Clone()); resultDict.Add("UnwindVolPV", resultDictVolPV["PV"]); resultDict.Add("MidPV", resultDictMidPV["PV"]); } return JsonSuccess("计算成功!", resultDict); } catch (Exception e) { LogFactory.GetLogger("tradeUnwindCalc出错").Error(e); return JsonError("计算出错!"); } } public Dictionary GetTradeUnwindCalc(TradeCashReq req, trade td) { Dictionary resultDict = null; var userId = CurUser.UserId.ToString(); if (req.UnwindNotional < td.Notional) { //平仓时都计算的平仓单价,将凤凰期权累积的票息金额处理成单份对应的票息金额 //20210728:涉及到部分平仓的话这个算法是有问题的 List HappenedObservations = null; switch (td.TradeType) { case "凤凰期权": HappenedObservations = td.trade_autocall.HappenedObservations; break; case "区间累积期权": HappenedObservations = td.trade_rangeaccrual.HappenedObservations; break; } if (HappenedObservations != null) { var spotPrice = Math.Abs(td.SpotPrice ?? 0); foreach (var x in HappenedObservations) { var notional = td.Notional; if (spotPrice > 1e-8) { notional = x.StockEqvNotional / spotPrice; } else if (td.StockEqvNotionalReal > 0) { notional = (td.OriginalNotional ?? 0) * x.StockEqvNotional / td.StockEqvNotionalReal; } if (notional > 0) { x.PaymentAmount /= notional; } } } td.Notional = req.UnwindNotional; //现金流交易在平仓时的份额即名义本金,现金流没有份额的概念 if (td.TradeType == "现金流交易") { td.StockEqvNotional = req.UnwindNotional; } } var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode); if (td.TradeType == "现金流交易") { udm = new underlying_manager(); } if (req.FinalPrice.HasValue) { udm.Price = req.FinalPrice; } udm.QuotationDate = req.ValueDate; //应该不需要这段逻辑,先注释掉:OTC-13391 //td.TradeDate = req.ValueDate; //td.StartDate = req.ValueDate; string fixing = null; //亚式期权 if (td.TradeType == "亚式期权" || td.StructureType == "亚式熊市价差") { fixing = AsianOptionFixingService.GetFixingString(req.ValueDate.Value, td); fixing = FixingService.AddOrReplaceLastDateSpotPrice(fixing, req.ValueDate.Value, udm.Price ?? 0.0); if (PS.Config.Is润和 && DateTime.Now.Hour < 15) { var index = fixing.IndexOf(req.ValueDate.Value.ToString("yyyy-MM-dd")); if (index >= 0) { fixing = fixing.Remove(index).TrimEnd(';'); } } } var ttm = req.TTM; if (!ttm.HasValue) { if (PS.Config.Is厦门象屿 && td.SettlementType == SettlementTypeEnum.ReferencePrice) { ttm = TradeCalcHelper.CalculateTTMDaysForXiangYu(req.ValueDate.Value, td.ExerciseDate.Value, udm.UnderlyingTypeId, td.ExerciseDate.Value == valuedateBLL.ValueDate); } else { ttm = TradeCalcHelper.CalculateTTMDays(req.ValueDate.Value, td.ExerciseDate.Value, udm.UnderlyingTypeId, td.ExerciseDate.Value == valuedateBLL.ValueDate); } } if (req.ValueDate < valuedateBLL.ValueDate) { new TradeHisDataService(CurUser).UpdateTradeWithHisData(td, req.ValueDate.Value); } try { if (td.TradeType == "累计期权") { var request = new OptionValueCalcRequest(valuedateBLL.SysRiskFreeRate()) { vols = new[] { req.UnwindVol ?? 0.0 }, spotPrices = new[] { udm.Price ?? 0.0 }, engineName = null, preciseTimeMode = req.ValueDate == valuedateBLL.ValueDate.Date,//与定价计算统一 pricingRequest = QdpPricingRequest.BASIC_PRICING, quadratureFastMode = true, timeToMaturityDays = ttm.Value, calcScenario = CalcScenarioEnum.Pricing }; var OptionValue = OptionCalculatorV2.GetOptionValueResult(req.ValueDate.Value, td, request, out _); //累计期权怕平仓时剩余的平仓观察日,需要根据已观察日进行区分,不依赖平仓日期来判断 var observations = db.autocall_observation.Where(x => x.TradeId == td.id); var startDate = td.TradeDate.Value; if (observations.Any()) { startDate = observations.Max(x => x.EndDate).AddDays(1); } //累计期权计算的pv是总额,所以这里要转换为单价 var dayCount = new TradeAccumulatorChangeService(CurUser).GetAccTradeUnwindDayCount(td.trade_accumulator_option.KOObservationDates, startDate, td.TradeDate, td.ExerciseDate); var count = td.trade_accumulator_option.AccumuTradeAmount * dayCount; if (count != 0) { OptionValue.Pv = OptionValue.Pv / count; } OptionValue.RoundedPv = OtcFormatHelper.FormatValue(OptionValue.Pv, 2); if (Math.Abs(OptionValue.DeltaInLots) < 1e-6 && count != 0) { OptionValue.DeltaInLots = OptionValue.Delta / count / udm.ContractSize; } resultDict = new Dictionary { { "PV", OptionValue.Pv }, { "DeltaInLots", OptionValue.DeltaInLots } }; } else if (td.TradeType == "自定义交易") { if (PS.Config.ErpElement.ExternalAPIForCustomCalcEnable) { td.StartDate = req.ValueDate.Value; var positionVol = VolatilityHelper.GetTradeVol(td, req.ValueDate.Value); var tempResult = TradeRiskCalcUtil.GetManualOptionValue(req.ValueDate.Value, td, udm.Price ?? 0, positionVol, true, CalcScenarioEnum.Pricing); if (tempResult.manual != null) { var underlying = Modules.DataCacheModule.DataCacheManager.GetUnderlyingDataSource().GetData(td.UnderlyingCode); var deltaInLots = TradeLotsCalc.CalcDeltaInLots(tempResult.optionValue.Delta, null, underlying); resultDict = new Dictionary { { "PV", tempResult.optionValue.Pv }, { "DeltaInLots", deltaInLots } }; } else { throw new Exception(PS.Config.ErpElement.ExternalAPIForCustomCalcEnable ? "失败:接口计算失败" : "失败:无法调用计算接口,请开启相应配置"); } } else { throw new ServiceException("计算失败,不支持自定义交易计算"); } } else { if (td.TradeType == "结构化产品") { using (var db = DbContextFactory.GetYLDbContext()) { td.MetaDic = db.TradeMeta.Where(p => p.TradeId == td.id).ToDictionary(g => g.MetaKey, g => g.MetaValue); } } var OptionValue = ValueCalculator.GetOptionValueResultV2( userId: userId, underlying: udm, trade: td, vols: new double[] { req.UnwindVol ?? 0.0 }, spotPrices: new double[] { udm.Price ?? 0.0 }, fixing: fixing, timeToMaturityDays: ttm.Value, preciseTimeMode: req.ValueDate == valuedateBLL.ValueDate.Date,//OTC-4198,与定价计算统一 request: QdpPricingRequest.BASIC_PRICING, calcScenario: CalcScenarioEnum.Pricing); if (td.TradeType == "雪球期权" && td.trade_snowball.PrepaymentUsed) { //OptionValue.Pv是根据td.notional算出来的 OptionValue.Pv -= td.Notional * (td.SpotPrice ?? 0) * (td.trade_snowball?.PrepaymentRatio ?? 0) * (td.BuySell == "卖出" ? -1 : 1); } resultDict = new Dictionary { { "PV", OptionValue.Pv }, { "DeltaInLots", OptionValue.DeltaInLots } }; } } catch { resultDict = new Dictionary { { "PV", 0 }, { "DeltaInLots", 0 } }; } return resultDict; } /// /// 获取累计期权平仓定价日的观察日期 /// /// 观察日期 /// 定价日期或平仓日期 /// 交易日期 /// 到期日期 /// public JsonResult GetAccTradeUnwindDayCount(string kOObservationDates, DateTime? valueDate, DateTime tradeDate, DateTime exerciseDate) { var service = new TradeAccumulatorChangeService(CurUser); var dayCount = service.GetAccTradeUnwindDayCount(kOObservationDates, valueDate, tradeDate, exerciseDate); return JsonSuccess("", dayCount); } public JsonResult tradeSwapUnwindCalcGet(TradeCashReq req) { Dictionary resultDict = null; var tradeBLL = new tradeBLL(); //修改交易主表信息交易状态为已执行 var td = db.trade.AsNoTracking().FirstOrDefault(t => t.id == req.TradeId); if (td == null) { return JsonError("计算失败,找不到交易!", null); } try { if (!req.ValueDate.HasValue) { req.ValueDate = valuedateBLL.ValueDate; } tradeBLL.SetFieldsByTradeType(td); //这个方法会慢 var tradeCashs = db.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= req.ValueDate); var tradeCashIds = tradeCashs.Select(x => x.id); var tradeCash = tradeCashs.OrderByDescending(y => y.id).FirstOrDefault(); var cashSwaps = db.trade_cash_swap.Where(x => x.TradeId == td.id && tradeCashIds.Contains(x.TradeCashId)).ToArray(); var tradeCashSwap = tradeCash != null ? cashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id) : null; //取最后一次手动收益; var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto); var lastManualCash = lastManualCashSwap != null ? tradeCashs.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null; var initialAmountGet = PayoffSwapCalcService.GetInitialAmountSwapGet(td, td.trade_swap, tradeCashSwap?.GetFinalPrice ?? td.trade_swap.GetSpotPrice ?? 0 , req.FinalPrice ?? 0, (td.OriginalStockEqvNotional ?? 0) * req.UnwindPercentRate, req.ValueDate.Value, tradeCash?.ValueDate); DateTime endDate; var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, req.ValueDate.Value, tradeCash, lastManualCash, td.trade_swap.IsPayFloatingProfit, out endDate); var extraAmountPay = PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.PaySwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * req.UnwindPercentRate); resultDict = new Dictionary { { "InitialAmount", initialAmountGet }, { "ExtraAmount", extraAmountPay } }; return JsonSuccess("计算成功!", resultDict); } catch (Exception e) { LogFactory.GetLogger("tradeSwapUnwindCalc").Error(e); return JsonError("计算出错!"); } } public JsonResult tradeSwapUnwindCalcPay(TradeCashReq req) { Dictionary resultDict = null; var tradeBLL = new tradeBLL(); //修改交易主表信息交易状态为已执行 var td = db.trade.AsNoTracking().FirstOrDefault(t => t.id == req.TradeId); if (td == null) { return JsonError("计算失败,找不到交易!", null); } try { if (!req.ValueDate.HasValue) { req.ValueDate = valuedateBLL.ValueDate; } tradeBLL.SetFieldsByTradeType(td); //这个方法会慢 var tradeCashs = db.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= req.ValueDate); var tradeCashIds = tradeCashs.Select(x => x.id); var tradeCash = tradeCashs.OrderByDescending(y => y.id).FirstOrDefault(); var cashSwaps = db.trade_cash_swap.Where(x => x.TradeId == td.id && tradeCashIds.Contains(x.TradeCashId)).ToArray(); var tradeCashSwap = tradeCash != null ? cashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id) : null; //取最后一次手动收益; var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto); var lastManualCash = lastManualCashSwap != null ? tradeCashs.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null; var initialAmountPay = PayoffSwapCalcService.GetInitialAmountSwapPay(td, td.trade_swap, tradeCashSwap?.PayFinalPrice ?? td.trade_swap.PaySpotPrice ?? 0 , req.FinalPrice ?? 0, (td.OriginalStockEqvNotional ?? 0) * req.UnwindPercentRate, req.ValueDate.Value, tradeCash?.ValueDate); DateTime endDate; var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, req.ValueDate.Value, tradeCash, lastManualCash, td.trade_swap.IsGetFloatingProfit, out endDate); var extraAmountGet = PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.GetSwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * req.UnwindPercentRate); resultDict = new Dictionary { { "InitialAmount", initialAmountPay }, { "ExtraAmount", extraAmountGet } }; return JsonSuccess("计算成功!", resultDict); } catch (Exception e) { LogFactory.GetLogger("tradeSwapUnwindCalc").Error(e); return JsonError("计算出错!"); } } public JsonResult ApplyUnwindSwapTrade(TradeCashReq req) { _ = new TradeUnwindService(CurUser).ApplyUnwindSwapTrade(req); return JsonSuccess("提交平仓审批成功!"); } public JsonResult UnwindSwapTrade(TradeCashReq req) { _ = new TradeUnwindService(CurUser).UnwindSwapTrade(req); return JsonSuccess("平仓成功!"); } public JsonResult ApplySwapTrade(TradeCashReq req) { _ = new TradeUnwindService(CurUser).ApplySwapTradeSettlement(req); return JsonSuccess("提交互换审批成功!"); } public JsonResult SwapTrade(TradeCashReq req) { _ = new TradeUnwindService(CurUser).SwapTrade(req); return JsonSuccess("互换成功!"); } public JsonResult SaveGroupTradeCash(SaveGroupTradeCashReq req) { new TradeUnwindService(CurUser).SaveGroupTradeCash(req); return JsonSuccess("保存成功!"); } //交易平仓复核/交易平仓 [MyAuthorize("交易管理-交易平仓,交易管理-交易平仓审核")] [HttpPost] public JsonResult UnwindParentTrade(SaveGroupTradeCashReq req) { new TradeUnwindService(CurUser).UnwindParentTrade(req); return JsonSuccess("复核成功!"); } public JsonResult DenyReCheckByParent(int tradeId) { new TradeProcessService(CurUser).DenyReCheckByParent(tradeId); return JsonSuccess("提前终止拒绝成功"); } [HttpPost] public JsonResult CheckFinishGroupTradeCash(int TcId) { var isFinished = !db.trade_cash_group_action.Any(x => x.ParentTradeCashId == TcId && x.Status == "待完成"); return Json(isFinished); } [HttpPost] public JsonResult FinishGroupTradeCash(int TcId) { new TradeUnwindService(CurUser).FinishGroupTradeCash(TcId); return Json("已完成"); } /// /// 导入了结(部分了结)交易 /// [MyAuthorize("交易管理-批量了结")] public ActionResult UploadFinishedTrades() { if (Request.Form.Files.Count < 1) { return JsonError("未获取上传文件"); } var file = Request.Form.Files[0]; var fileExt = Path.GetExtension(file.FileName); if (fileExt.ToLowerInvariant() != ".xlsx") { return JsonError("目前只支持xlsx格式的文件"); } using var stream = file.OpenReadStream(); new OtcTradeCloseService(CurUser).BatchCloseByImport(stream, out _, out _); return JsonSuccess(); } private void setTradeExtensionInfo(trade td) { if (td is null) { return; } //生成简要时需要的信息补全 if (td.TradeType == "合成价差期权") { td.SyntheticUnderlyingTipsInfo = synthetic_underlyingBLL.GetUnderlyingTipsInfo(td.UnderlyingCode); } var varietyQuery = from um in db.underlying_manager join va in db.variety on um.UnderlyingTypeId equals va.id where um.id == td.UnderlyingId select new VarietyDto { QuoteUnit = va.QuoteUnit }; var variety = varietyQuery.FirstOrDefault(); if (variety != null) { td.QuoteUnit = variety.QuoteUnit; td.QuoteUnitSingle = variety.QuoteUnitSingle; } } private bool HasTradeProcess() { return db.approvalprocess.Any(t => t.processType == "TradeProcess"); } } }