//otcformat禁止千分位分组 window.otcformat.options.disableGrouping = true; //去掉MyJs.js中的数组扩展,防止某些js类库出错 delete Array.prototype.contains; delete Array.prototype.remove; //pageVue来自PricingModel对象序列化 //pageVue.TradeEdit属性来自TradeEditViewModel //pageVue额外定义的参数:getVolType() pageVue.DaysInYear = 365; //定价格式化(来自配置) const pricingFormat = otcformat.trading; //数字格式化 const consNumberFormat = Object.freeze(new function () { this.fixed2 = main.numberFormat(2); this.fixed3 = main.numberFormat(3); this.fixed4 = main.numberFormat(4); this.fixed5 = main.numberFormat(5); this.fixed6 = main.numberFormat(6); this.percent = main.numberFormat({ percent: true }); this.umpriceP = main.numberFormat(pricingFormat.umpriceP.precision + 2); this.volValueFmt = pageVue.VolMoreAccurate ? this.fixed6 : this.fixed4; this.ttmDaysFmt = pageVue.PrecisionOfMinuteInQuote ? this.fixed5 : this.fixed4; return this; }()); //基本输入格式 const inputFormatInteger = Object.freeze({ precision: 0, append: '' }); const inputFormatDouble2 = Object.freeze({ precision: 2, append: '' }); const inputFormatPercent = Object.freeze({ precision: 2, append: '%' }); const inputFormatPercentN = Object.freeze({ precision: 2, append: '%', negative: true }); const inputFormatPercent4 = Object.freeze({ precision: 4, append: '%' }); //权利金输入格式 const inputFormatPremiumRate = Object.freeze({ precision: pricingFormat.premiumRateP.precision, negative: true, append: '%' }); const inputFormatSinglePrice = Object.freeze({ precision: pricingFormat.tradeSinglePrice.precision, negative: true, append: '' }); const inputFormatTradePrice = Object.freeze({ precision: 2, negative: true, append: '' }); //波动率输入格式 const inputFormatVolPercent = Object.freeze({ precision: pageVue.VolMoreAccurate ? 4 : 2, append: '%' }); //名义本金输入格式 const inputFormatEqvNotional = Object.freeze({ precision: pricingFormat.StockEqvNotional.precision, append: '' }); //预付金率输入格式 const inputFormatMarginRate = Object.freeze({ precision: pricingFormat.marginRateP.precision, append: '%' }); //期初价格 const inputFormatSpot = Object.freeze({ precision: pricingFormat.umprice.precision, append: '' }); //交易方向 const consBuysellTypes = Object.freeze(pageVue.Company === "润和" ? [{ value: '卖出', text: '客户买入' }, { value: '买入', text: '客户卖出' }] : [{ value: '卖出', text: pageVue.CompanyName + '卖出' }, { value: '买入', text: pageVue.CompanyName + '买入' }]); //观察方式 const consMonitorTypes = Object.freeze([{ value: '离散', text: '离散' }, { value: '连续', text: '连续' }]); //补偿支付 const consRebateTypes = Object.freeze([{ value: 'AtHit', text: '立即' }, { value: 'AtEnd', text: '递延' }]); //亚式均价计算 const consAsiaPayoffType = Object.freeze([{ value: 'ArithmeticAverage', text: '算术平均' }, { value: 'GeometricAverage', text: '几何平均' }, { value: 'DiscreteArithmeticAverage', text: '算术平均(离散)' }, { value: 'EnhancedArithmeticAverage', text: '增强算术平均' }]); //是否选项 const consFalseAsYes = Object.freeze([{ value: false, text: '是' }, { value: true, text: '否' }]); const consTrueAsYes = Object.freeze([{ value: true, text: '是' }, { value: false, text: '否' }]); const consFalseAsNo = Object.freeze([{ value: false, text: '否' }, { value: true, text: '是' }]); const consIsDiscreteMonitored = Object.freeze([{ value: true, text: '离散' }, { value: false, text: '连续' }]); //敲出支付方式 const consKORebateTypes = Object.freeze([{ value: '0', text: '立即支付' }, { value: '1', text: '递延至期末支付' }]); //票息结算方式 const consCouponPayTypes = Object.freeze([{ value: '0', text: '产生时支付' }, { value: '1', text: '敲出时支付' }, { value: '2', text: '期末支付' }]); //障碍类型 const consBarrierTypes = Object.freeze(_.map(['上升敲入', '上升敲出', '下降敲入', '下降敲出', '双障碍敲入', '双障碍敲出'], x => new Object({ text: x, value: x }))); //二元类型 const consBinaryPayoffTypes = Object.freeze({ European: _.map(['CashOrNothing', 'AssetOrNothing'], x => new Object({ text: x, value: x })), American: _.map(['UpOneTouch', 'DownOneTouch', 'UpNoTouch', 'DownNoTouch', 'DoubleOneTouch', 'DoubleNoTouch'], x => new Object({ text: x, value: x })) }); const consRateType = Object.freeze([{ value: '0', text: '年化利率' }, { value: '1', text: '实际利率' }]); const consDepositType = Object.freeze([{ value: '0', text: '资金收益' }, { value: '1', text: '成本摊还' }]); const consRiskExposureType = Object.freeze([{ value: '0', text: '参与计算' }, { value: '1', text: '忽略' }]); //定价模型 const consEngineNames = Object.freeze({ Default: _.map(['解析解(默认)', '蒙特卡洛'], x => new Object({ text: x, value: x })), American: _.map(['解析解(默认)', '二叉树'], x => new Object({ text: x, value: x })), Autocall: _.map(['积分法(默认)', '蒙特卡洛'], x => new Object({ text: x, value: x })) }); //统计数据重置flags const resetSummaryFlags = Object.freeze({ all: 0, notional: 1, ten: 10, initialMargin: 11 }); function setTradeAmount(self) { var TradeAmountV = self.trade.AccumuTradeAmount; var dayCount = 0; if (self.trade.KOObservationDates) { dayCount = self.trade.KOObservationDates.split(";")[0].split(',').length; } else { var data = { alignEnd: "true", calcMode: "01", endDate: this.trade.ExerciseDate, holidayAdjustment: "Following", startDate: this.trade.TradeDate, termStr: "1D", }//获取区间观察日数量; main.post("/trade/GetObservationDateList", data, { async: false }).done( function (res) { dayCount = res.obj.length; } ); } TradeAmountV *= dayCount; self.trade.TradeAmountV = TradeAmountV; } //帮助类(只对trade对象进行处理) const tradeUtils = (function () { //IsMoneynessOption影响的字段映射 const consMoneynessFieldMap = Object.freeze({ BarrierLow: 'BarrierLow', BarrierHigh: 'BarrierHigh', StrikeHigh: 'StrikeHigh', HighStrike: 'HighStrike', KOBarrier: 'KOBarrier', KIBarrier: 'KIBarrier', CouponBarrier: 'CouponBarrier', SpreadStrike: 'SpreadStrike', SpreadStrike1: 'SpreadStrike1', SpreadStrikeAtKO: 'SpreadStrikeAtKO', SpreadStrikeAtKO1: 'SpreadStrikeAtKO1', UpperRange: 'UpperRange', LowerRange: 'LowerRange', Strike1: 'Strike1', Strike2: 'Strike2', Strike3: 'Strike3' }); //IsUsePremiumRate切换时绝对值与百分比的换算字段映射 const consUsePremiumRateFieldMap = Object.freeze({ Rebate: 'RebateRate', RebateHigh: 'RebateHighRate', CashOrNothingAmount: 'CashOrNothingAmountRate', CashOrNothingAmountHigh: 'CashOrNothingAmountHighRate' }); //现金流交易字段(涉及很多基本要素) const consCashFlowFields = Object.freeze(['MarginTemplateName', 'OptionType', 'SpotPrice', 'Strike', 'UnderlyingCode' , 'UnderlyingId', 'UnderlyingInstrumentType', 'PremiumRate', 'TradeAmount', 'TradeOpenVolatility', 'ExerciseMode' , 'MaturityDate']); //生成波动率类型转换函数 //波动率类型为‘交易’时,根据买入方向选择交易bid(买入)或者交易Ask(卖出)的波动率曲面计算; function _volTypeConvert(voltype, buysell) { return voltype !== "交易" ? voltype : buysell === "卖出" ? "报价Ask" : buysell === '买入' ? '报价Bid' : voltype; } //获取交易波动率 function _getTradeVol(trade, extOptions, varietyId) { if (trade.TradeType === "现金流交易") { return 0; } var result = { obj: NaN }; var VolType = _volTypeConvert(pageVue.getVolType(), trade.BuySell); var postData = _.extend({ VolType: VolType, Strike: trade.Strike, SpotPrice: trade.SpotPrice, TradeDate: trade.ValueDate || trade.TradeDate, ExerciseDate: trade.ExerciseDate, IsMoneynessOption: trade.IsMoneynessOption, CallPut: trade.OptionType === "看涨" ? "Call" : "Put", UnderlyingId: trade.UnderlyingId, UnderlyingCode: trade.UnderlyingCode, UnderlyingName: trade.UnderlyingName, UnderlyingTypeId: varietyId, BaseVol: null, BidVar: null, AskVar: null }, extOptions); if (!postData.TradeDate || !postData.ExerciseDate) { var msg = []; !postData.TradeDate && msg.push('缺少交易日期'); !postData.ExerciseDate && msg.push('缺少到期日期'); return $.Deferred(function () { var self = this; setTimeout(function () { self.resolve({ success: true, obj: '', msg: msg.join(',') }); }, 100); }).promise(); } return main.post("/pricing/AjaxGetVol", postData, { waitMe: false, alertFn: pageVue.SkewMapVol ? main.message : null }); } function _isNaN(val) { return isNaN(parseFloat(val)); } function checkDate(value) { let date = new Date(value); return date.valueOf(); } //检查交易数据是否可以用于计算或保存 function _checkTrade(trade, usedForSave, isShowActualExerciseDate) { var errorList = []; if (trade.TradeType === "现金流交易") { if (usedForSave && pageVue.TradeEdit) { if (!trade.AssetId) { errorList.push("簿记账户 必须填写"); } if (!trade.TraderId) { errorList.push("交易员 必须填写"); } if (!trade.ClientId) { errorList.push("客户名称 必须填写"); } } if (!trade.ExerciseDate) { errorList.push("期权到期日 必须填写"); } else if (trade.ExerciseDate < trade.TradeDate) { errorList.push("期权到期日 不能小于交易日期"); } if (trade.SettlementDate && trade.SettlementDate < trade.ExerciseDate) { errorList.push("期权结算日 不能小于到期日"); } if (isShowActualExerciseDate && pageData.showZheQi) { if (!trade.MetaDic['ActualExerciseDate']) { errorList.push("实际到期日期 必须填写"); } if (trade.MetaDic['ActualExerciseDate'] > trade.MaturityDate) { errorList.push("实际到期日期到期日必需在标的到期日之前"); } if (trade.TradeDate > trade.MetaDic['ActualExerciseDate']) { errorList.push("交易日应该在实际到期日期之前"); } } trade.ExerciseMode = ""; } else { if (!trade.UnderlyingId || trade.UnderlyingId === '0') { errorList.push("标的信息 必须填写"); } if (usedForSave && pageVue.TradeEdit) { if (!trade.AssetId) { errorList.push("簿记账户 必须填写"); } if (!trade.TraderId) { errorList.push("交易员 必须填写"); } if (!trade.ClientId) { errorList.push("客户名称 必须填写"); } } if (!trade.ExerciseDate) { errorList.push("期权到期日 必须填写"); } else if (trade.ExerciseDate < trade.TradeDate) { errorList.push("期权到期日 不能小于交易日期"); } if (trade.SettlementDate && trade.SettlementDate < trade.ExerciseDate) { errorList.push("期权结算日 不能小于到期日"); } if (isShowActualExerciseDate && pageData.showZheQi) { if (!trade.MetaDic['ActualExerciseDate']) { errorList.push("实际到期日期 必须填写"); } if (trade.MetaDic['ActualExerciseDate'] > trade.MaturityDate) { errorList.push("实际到期日期到期日必需在标的到期日之前"); } if (trade.TradeDate > trade.MetaDic['ActualExerciseDate']) { errorList.push("交易日应该在实际到期日期之前"); } } if (trade.TradeType !== '自定义交易') { if (pageVue.IsTradeVol) { if (!_.trim(trade.TradeOpenVolatility)) { errorList.push("成交波动率 必须填写"); } if (usedForSave && !_.trim(trade.TradeCloseVolatility)) { errorList.push("目标波动率 必须填写"); } if (!_.trim(trade.NumOfSmoothingDays)) { if (usedForSave && (pageVue.IsGuoJun || pageVue.SkewMapVol)) { errorList.push("平滑过渡天数 必须填写"); } else { trade.NumOfSmoothingDays = 1; } } else if (!/^\d+$/.test(trade.NumOfSmoothingDays)) { errorList.push("平滑过渡天数 只能为整数"); } } } if (trade.UnderlyingInstrumentType === "Stock" || trade.UnderlyingInstrumentType === "StockIndex") { if (!trade.Notional) { errorList.push("成交份额 必须填写"); } else if (trade.Notional < 0) { errorList.push("成交份额 不能小于0"); } if (!trade.StockEqvNotional) { errorList.push("名义本金 必须填写"); } if (!_.trim(trade.DividendRate)) { errorList.push("分红率 必须填写"); } } else { if (!trade.TradeAmount) { errorList.push("交易数量 必须填写"); } else if (trade.TradeAmount < 0) { errorList.push("交易数量 不能小于0"); } } //执行价格可以随意输入 if (!trade.Strike) { trade.Strike = 0; } //if (usedForSave && trade.TradeSinglePrice < 0) { // errorList.push("权利金 不能小于0"); //} if (!pageVue.TradeEdit && 0 === (parseFloat(trade.TTMDays) || 0)) { errorList.push("TTMDays 不能为0"); } switch (trade.TradeType) { case "障碍期权": { if (_isNaN(trade.BarrierLow)) { errorList.push("障碍价格 必须填写"); } if (!trade.BarrierType) { errorList.push("障碍类型 必须填写"); } else if (trade.BarrierType.startsWith("双") && _isNaN(trade.BarrierHigh)) { errorList.push("高障碍价格 必须填写"); } break; } case "双鲨期权": { if (_isNaN(trade.BarrierLow)) { errorList.push("障碍价格 必须填写"); } if (_isNaN(trade.BarrierHigh)) { errorList.push("高障碍价格 必须填写"); } break; } case "气囊结构": { if (_isNaN(trade.BarrierLow)) { errorList.push("障碍价格 必须填写"); } break; } case "二元期权": { if (trade.PayoffType !== "AssetOrNothing" && _isNaN(trade.IsUsePremiumRate ? trade.CashOrNothingAmountRate : trade.CashOrNothingAmount)) { errorList.push("补偿金额 必须填写"); } break; } case "雪球期权": { _isNaN(trade.KOBarrier) && errorList.push("敲出障碍价格 必须填写"); if (trade.PrepaymentUsed) { _isNaN(trade.KIBarrier) && !trade.IsInitialKnockedIn && errorList.push("敲入障碍价格 必须填写"); _isNaN(trade.SpreadStrike1) && errorList.push("敲入执行价格 必须填写"); !_.trim(trade.KOObservationDates, " ;,") && errorList.push("敲出观察频率 必须填写"); } else if (trade.KOPayoffType > 0) { //KOPayoffType可能为string类型 _isNaN(trade.SpreadStrikeAtKO1) && errorList.push("敲出行权价1 必须填写"); trade.KOPayoffType > 1 && _isNaN(trade.SpreadStrikeAtKO) && errorList.push("敲出行权价2 必须填写"); } break; } case "凤凰期权": { _isNaN(trade.KOBarrier) && errorList.push("敲出障碍价格 必须填写"); _isNaN(trade.KIBarrier) && errorList.push("敲入障碍价格 必须填写"); break; } case "亚式期权": { if (trade.StrikeType === 'Segmented' && trade.PayoffType !== 'EnhancedArithmeticAverage') { errorList.push("行权价类型为'分段式'时,均价计算类型必须为'增强算术平均'"); } if (trade.PayoffType === 'EnhancedArithmeticAverage' && trade.StrikeType === 'Floating') { errorList.push("均价计算类型为'增强算术平均'时,行权价类型不能为'浮动行权价'"); } if (trade.PayoffType === 'EnhancedArithmeticAverage' && trade.StrikeType != 'Floating' && !_isNaN(trade.EnhancedPrice) && trade.EnhancedPrice == 0) { errorList.push("均价计算类型为'增强算术平均'且行权价类型不为'浮动行权价'时,增强价格必须填写"); } break; } case "累计期权": { if (trade.AccumulatorStructureType == "1") { if (trade.PayoffType === "固定") { _isNaN(trade.Coupon) && errorList.push("票息1 必须填写"); _isNaN(trade.Coupon2) && errorList.push("票息2 必须填写"); } _isNaN(trade.Strike) && errorList.push("执行价格 必须填写"); _isNaN(trade.Strike2) && errorList.push("执行价格2 必须填写"); _isNaN(trade.Strike3) && errorList.push("执行价格3 必须填写"); _isNaN(trade.KOBarrier) && errorList.push("障碍价格 必须填写"); if (parseFloat(trade.Strike2) < trade.Strike) { errorList.push("执行价格2需要大于等于执行价格1"); } if (parseFloat(trade.Strike3) < parseFloat(trade.Strike2)) { errorList.push("执行价格3需要大于等于执行价格2"); } if (trade.OptionType == "看涨") { if (trade.Strike2 >= trade.KOBarrier || trade.Strike3 < trade.KOBarrier) { errorList.push("障碍价格需要大于执行价2小于等于执行价3"); } } else { if (trade.Strike > trade.KOBarrier || trade.Strike2 <= trade.KOBarrier) { errorList.push("障碍价格需要大于等于执行价1小于执行价2"); } } } else { if (trade.PayoffType === "固定") { _isNaN(trade.Coupon) && errorList.push("票息 必须填写"); } } break; } case "Risky期权": { if (_isNaN(trade.Strike1)) { errorList.push("执行价格1 必须填写"); } if (_isNaN(trade.Strike2)) { errorList.push("执行价格2 必须填写"); } if (_isNaN(trade.Strike3)) { errorList.push("执行价格3 必须填写"); } if (_isNaN(trade.ParticipationRate1)) { errorList.push("参与率1 必须填写"); } if (_isNaN(trade.ParticipationRate2)) { errorList.push("参与率2 必须填写"); } if (_isNaN(trade.ParticipationRate3)) { errorList.push("参与率3 必须填写"); } if (trade.Strike1 > trade.Strike2) { errorList.push("执行价格1 必须小于等于执行价格2"); } if (trade.Strike2 > trade.Strike3) { errorList.push("执行价格2 必须小于等于执行价格3"); } break; } } } return errorList; } //IsMoneynessOption切换处理,配置:consMoneynessFieldMap function _moneynessSwitch(trade) { let spotPrice = parseFloat(trade.SpotPrice) || 0; let isSpotZero = Math.abs(spotPrice) < 1e-4; let fmt = trade.IsMoneynessOption === "是" ? consNumberFormat.umpriceP : pricingFormat.umprice; if (trade.IsMoneynessOption === "是") { trade.Strike = isSpotZero || !_.trim(trade.Strike) ? 1 : fmt(trade.Strike / spotPrice); trade.EnhancedPrice = isSpotZero ? 1 : fmt(trade.EnhancedPrice / spotPrice); _.each(consMoneynessFieldMap, (perKey, absKey) => { var absValue = parseFloat(trade[absKey]); if (isSpotZero || !absValue) { trade[absKey] = '', trade[perKey] = ''; } else { trade[perKey] = fmt(absValue / spotPrice); } }); } else { //避免受到onChangeInstrumentType影响 trade.Strike = fmt(trade.Strike * spotPrice); trade.EnhancedPrice = fmt(trade.EnhancedPrice * spotPrice); _.each(consMoneynessFieldMap, (perKey, absKey) => { var perVal = parseFloat(trade[perKey]); if (isSpotZero || !perVal) { trade[absKey] = '', trade[perKey] = ''; } else { trade[absKey] = fmt(perVal * spotPrice); } }); } } //IsUsePremiumRate切换处理,配置:consUsePremiumRateFieldMap function _usePremiumRateSwitch(trade) { let spotPrice = Math.abs(parseFloat(trade.SpotPrice)) || 0; let isSpotZero = spotPrice < 1e-4; let fmt = trade.IsUsePremiumRate ? pricingFormat.premiumRate : pricingFormat.tradeSinglePrice; if (trade.IsUsePremiumRate) { trade.PremiumRate = isSpotZero ? '' : fmt(trade.TradeSinglePrice / spotPrice); _.each(consUsePremiumRateFieldMap, (perKey, absKey) => { var absValue = parseFloat(trade[absKey]); if (isSpotZero || !absValue) { trade[absKey] = '', trade[perKey] = ''; } else { trade[perKey] = fmt(absValue / spotPrice); } }); } else { trade.TradeSinglePrice = fmt(spotPrice * trade.PremiumRate); _.each(consUsePremiumRateFieldMap, (perKey, absKey) => { var perVal = parseFloat(trade[perKey]); if (isSpotZero || !perVal) { trade[absKey] = '', trade[perKey] = ''; } else { trade[absKey] = fmt(perVal * spotPrice); } }); } } //计算或保存时需要根据IsMoneynessOption转换隐含字段 //转换处理和moneynessSwitch正好反过来(如果字段不同,相同时不做转换) function _transforCalcOrSave(trade) { let spotPrice = Math.abs(parseFloat(trade.SpotPrice)) || 0; let isSpotZero = spotPrice < 1e-4; let IsMoneynessOption = trade.IsMoneynessOption === "是"; let fmt = IsMoneynessOption ? pricingFormat.umprice : consNumberFormat.umpriceP; _.each(consMoneynessFieldMap, (perKey, absKey) => { if (absKey !== perKey) { if (IsMoneynessOption) { //从百分比转换绝对值 var perVal = trade[perKey]; if (isSpotZero || !perVal) { trade[absKey] = ''; } else { trade[absKey] = fmt(perVal * spotPrice); } } else { //从绝对值转换百分比 var absValue = parseFloat(trade[absKey]); if (isSpotZero || !absValue) { /*trade[absKey] = '', */trade[perKey] = ''; } else { trade[perKey] = fmt(absValue / spotPrice); } } } }); fmt = trade.IsUsePremiumRate ? pricingFormat.tradeSinglePrice : pricingFormat.premiumRate; _.each(consUsePremiumRateFieldMap, (perKey, absKey) => { if (absKey !== perKey) { if (trade.IsUsePremiumRate) { //从百分比转换绝对值 var perVal = trade[perKey]; if (isSpotZero || !perVal) { trade[absKey] = ''; } else { trade[absKey] = fmt(perVal * spotPrice); } } else { //从绝对值转换百分比 var absValue = parseFloat(trade[absKey]); if (isSpotZero || !absValue) { /*trade[absKey] = '', */trade[perKey] = ''; } else { trade[perKey] = fmt(absValue / spotPrice); } } } }); } //为计算和保存准备交易数据 function _prepareTrades(trades, volType, usedForSave, isReject, isShowActualExerciseDate) { if (!Array.isArray(trades)) { throw '请确保参数有效:trades'; } //复制后检查交易数据 var checkResults = [], clones = []; trades.forEach(trade => { var clone = _.clone(trade); _transforCalcOrSave(clone); !('NoRiskRate' in clone) && (clone.NoRiskRate = 0); //skew模式下不传voltype则根据var处理 clone.VolType = pageVue.SkewMapVol ? '' : _volTypeConvert(volType, clone.buysell); clone.StartDate = clone.TradeDate; clones.push(clone); var errors = _checkTrade(clone, usedForSave, isShowActualExerciseDate); if (errors.length) { checkResults.push({ index: clone.CalcId, errors: errors }); } else if (clone.TradeType === "障碍期权") { clone.BarrierHigh && !clone.BarrierType.startsWith("双") && (clone.BarrierHigh = ''); clone.RebateHigh && !clone.BarrierType.startsWith("双障碍敲出") && (clone.RebateHigh = ''); clone.RebateHighRate && !clone.BarrierType.startsWith("双障碍敲出") && (clone.RebateHighRate = ''); } else if (clone.TradeType === "亚式期权") { clone.Strike && clone.StrikeType === "Floating" && (clone.Strike = ''); } else if (clone.TradeType === "累计期权") { if (pageData.ShowMultiplier) { let strikeGearingFactor = parseFloat(clone.StrikeGearingFactor); Number.isNaN(strikeGearingFactor) && (strikeGearingFactor = 1); if (clone.OptionType === '看涨') { clone.CallMultiplier = 1; clone.PutMultiplier = strikeGearingFactor; } else { clone.PutMultiplier = 1; clone.CallMultiplier = strikeGearingFactor; } } } else if (clone.TradeType === "雪球期权") { if (clone.IsInitialKnockedIn) { clone.KnockInOutStatus = "KnockedIn"; clone.KnockInOutDate = clone.TradeDate; } else { clone.KnockInOutStatus = null; clone.KnockInOutDate = null; } } if (pageData.showCCR) { clone.MetaDic["ccr_k"] = clone.ccr_k || "1"; clone.MetaDic["ignoreRiskExposure"] = clone.ignoreRiskExposure || "0"; } }); checkResults.length = isReject ? 0 : checkResults.length; //显示检查错误 if (checkResults.length) { let isTradeEdit = usedForSave var htmlResults = checkResults.map(x => { if (pageVue.TradeEdit) { return x.errors.map(x => '' + x + ''); } var errmsg = x.errors.join('
'); return `${x.index}${errmsg}`; }); $('#checkErrorTable').find('tbody').html(htmlResults.join()); $('#checkErrorModal').modal('show'); return false; } return clones; } //更改交易的资产类型时的处理 function onChangeInstrumentType(trade) { _.each(consMoneynessFieldMap, (perKey, absKey) => { trade[absKey] = '', trade[perKey] = ''; }); _.each(consUsePremiumRateFieldMap, (perKey, absKey) => { trade[absKey] = '', trade[perKey] = ''; }); } function _getEngineNames(trade) { if (trade.TradeType === '凤凰期权' || trade.TradeType === '雪球期权') { return consEngineNames.Autocall; } else if (trade.TradeType === '香草期权' && trade.ExerciseMode === 'American') { return consEngineNames.American; } else { return consEngineNames.Default; } } //变更预付金模板 function changeMarginTemplate(trade, tradeMarginTemplates) { if (trade.MarginTemplateName === "系统默认") { trade.MarginType = 0; trade.MarginRate = 0; trade.PositionMarginRate = 0; } else if (trade.MarginTemplateName === "无预付金") { trade.MarginType = 1; trade.MarginRate = 0; trade.PositionMarginRate = 0; } else { tradeMarginTemplates.forEach(x => { if (trade.MarginTemplateName === x.Name) { trade.MarginType = x.MarginType; trade.MarginRate = x.InitialMarginRatio; if (trade.MarginType == 3) { trade.PositionMarginRate = 0; } else { trade.PositionMarginRate = x.PositionMarginRatio; } } }); } } //变更亚式期权定价模型 function changeEngineName(trade) { if (trade.TradeType == "亚式期权" && trade.StrikeType != "Floating" && trade.PayoffType == 'EnhancedArithmeticAverage') { if (trade.Strike != trade.EnhancedPrice) { trade.EngineName = ""; return true; } } return false; } return { getTradeVol: _getTradeVol, checkTrade: _checkTrade, prepareTrades: _prepareTrades, moneynessSwitch: _moneynessSwitch, usePremiumRateSwitch: _usePremiumRateSwitch, onChangeInstrumentType: onChangeInstrumentType, getEngineNames: _getEngineNames, normalizeTrade(trade) { _.each(trade, (val, key) => { //标准化trade日期数据 typeof val === 'string' && key.endsWith('Date') && (trade[key] = val.substr(0, 10)); }); }, resetCashFlow(trade) { trade.IsUsePremiumRate = true; for (var f of consCashFlowFields) { trade[f] = ''; } trade.RateType || (trade.RateType = 0); trade.DepositType || (trade.DepositType = 0); }, resetRisky(trade) { trade.OptionType = "看涨" }, changeMarginTemplate: changeMarginTemplate, changeEngineName: changeEngineName }; }()); //交易字段管理 const tradeFieldMgr = (new function () { pageVue.Trade.EncryptId = ''; tradeUtils.normalizeTrade(pageVue.Trade); //默认数据(初次添加定价时使用) const DefaultData = { trade: pageVue.Trade, viewState: { variety: tradeHelper.getEmptyVariety(), underlying: tradeHelper.getEmptyUnderlying(), MaturityDate: null, VolState: 'system', VolLockState: 'system', CloseVolState: 'system', SpotPrice: 'system', TTMDays: 'system', InitialMargin: 'system', TradeOpenVolatility: 'system', NoRiskRate: 'system', DividendRate: 'system', TwoSideMargin: false, Observation: { hasValue: false, ObservationDates: '', ObservationNum: 1, ObservationUnit: 'D', ObservationHolidayType: 'Following', ObservationAlignEnd: true }, KOObservation: { hasValue: false, ObservationDates: '', KOObservationDates: '', ObservationNum: 1, ObservationUnit: 'D', CouponDayInterval: 0, ObservationHolidayType: 'Following', ObservationAlignEnd: true }, KOObservationSettle: { hasValue: false, ObservationDates: '', ObservationNum: 1, ObservationUnit: 'D', ObservationHolidayType: 'Following', ObservationAlignEnd: true }, synthetic: null, initFlag: '', AnnualizeFactor: { ttmDays: 0, daysInYear: pageVue.DaysInYear, refDays: 0 }, AnnualizeFactor2: { ttmDays: 0, daysInYear: pageVue.DaysInYear, refDays: 0 }, Extend: { TradingPlace: "柜台市场", ClearingAgency: "交易员方" }, TradeExtend: { Strike2: 0, Strike3: 0, Multiplier: 1, Multiplier2: 1, Multiplier3: 1 }, } }; this.defaultData = DefaultData; //期权基本要素字段(是否展示) const BasicFields = { ExerciseMode(trade) { switch (trade.TradeType) { default: return true; case '凤凰期权': case '雪球期权': case '自定义交易': case '现金流交易': case '区间累积期权': trade.ExerciseMode = "European"; return false; case '二元期权': return trade.ExerciseMode === "European" ? 1 : 11; } }, OptionType(trade) { switch (trade.TradeType) { default: return true; case '区间累积期权': case '自定义交易': case '双鲨期权': case '气囊结构': case '收益增强结构': case '现金流交易': return false; case '二元期权': return trade.ExerciseMode === 'European'; } }, SettlementType(trade) { return trade.TradeType !== '自定义交易'; }, DividendRate(trade) { return (trade.UnderlyingInstrumentType === 'Stock' || trade.UnderlyingInstrumentType === 'StockIndex'); }, }; //期权奇异字段配置 const OptionFields = Object.freeze({ "障碍期权": { BarrierOption: true, ObservationDates: '', ObservationDatesShow: '占位符', BarrierType: "上升敲入", BarrierLow: '', BarrierHigh: '', MonitorType: "离散", RebateType: "AtHit", Rebate: '', RebateRate: '', BarrierShift: '', RebateHigh: '', RebateHighRate: '', IsBarrierType: { init: '', visible(trade) { return trade.BarrierType === "双障碍敲出"; } }, //MonitorType替代了Discrete,BarrierLow替代了BarrierPrice,BarrierHigh替代了UpperBarrierPrice }, "双鲨期权": { DBSharkOption: true, ObservationDates: '', ObservationDatesShow: '占位符', MonitorType: '离散', BarrierLow: '', BarrierHigh: '', StrikeHigh: '', RebateType: 'AtHit', Rebate: '', RebateRate: '', RebateHigh: '', RebateHighRate: '' //MonitorType替代了Discrete }, "二元期权": { BinaryOption: true, PayoffType: '', ObservationDates: '', ObservationDatesShow: '占位符', BarrierHigh: '', MonitorType: "离散", RebateType: "AtHit", CashOrNothingAmount: '', CashOrNothingAmountRate: '', CashOrNothingAmountHigh: '', CashOrNothingAmountHighRate: '', PayoffTypeShow: { init: '', visible(trade) { return (trade.PayoffType || '').startsWith('Double'); } } //BarrierHigh替代了UpperBarrier }, "亚式期权": { AsiaOption: true, PayoffType: 'ArithmeticAverage', StrikeType: "Fixed", StrikeGearingFactor: 1, AveragingPeriodStartDate: pageVue.SysDate, SettleMode: "AtHit", EnhancedPrice: 0, }, "彩虹期权": { RainbowOption: true }, "合成价差期权": { ComSpreadOption: true }, "区间累积期权": { RangeAcc: true, ObservationDatesShow: true, ObservationDates: '', UpperRange: '', LowerRange: '', BonusRate: '' }, "凤凰期权": { AutoCall: true, IsFixedCoupon: false, Coupon: '', CouponBarrier: '', CouponPayType: 0, KOObservationDates: '', KOBarrier: '', ObservationDates: '', KIBarrier: '', IncludeCouponAfterKI: true, KIPayoffType: 1, SpreadStrike1: { init: '', visible(trade) { return trade.KIPayoffType > 0; } }, SpreadStrike: { init: '', visible(trade) { return trade.KIPayoffType === 2 || trade.KIPayoffType === 4; } }, beforeCheck(trade) { return { KIPayoffType: parseInt(trade.KIPayoffType) || 1 }; } }, "雪球期权": { SnowBall: true, KOBarrier: '', KOObservationDates: '', KOPayoffType: 0, KORebateType: 0, Coupon: '', CouponDayCount: "Act365", PrepaymentUsed: false, PrepaymentRatio: '0', PrepaymentInterestRate: '0', PrepaymentConvertCashRate: '0', CouponIncludeEndDate: true, EnhancedParticipationRate: '0', KIParticipationRate: '1', PrincipalProtectionRate: '0', KIObservationType: 1, showKnockinObservation: { init: false, visible(trade) { return !trade.IsInitialKnockedIn; } }, IsFixedCoupon: { init: false, visible(trade) { return trade.KOPayoffType === 0; } }, KORebate: { init: '', visible(trade) { return trade.KOPayoffType === 0; } }, AnnualizedPremiumRate: { init: '', visible(trade) { return trade.KOPayoffType === 0; } }, SpreadStrikeAtKO1: { init: '', visible(trade) { return trade.KOPayoffType > 0; } }, SpreadStrikeAtKO: { init: '', visible(trade) { return trade.KOPayoffType > 1; } }, KIBarrier: '', ObservationDates: '', KIPayoffType: 0, //SpreadStrike替代了SpreadStrikeAtMaturity SpreadStrike1: { init: '', visible(trade) { return trade.PrepaymentUsed || trade.KIPayoffType > 0 || trade.IsInitialKnockedIn; } }, SpreadStrike: { init: '', visible(trade) { return (trade.KIPayoffType === 2 || trade.KIPayoffType === 4); } }, PrepaymentUsing: { init: false, visible: (trade) => !!trade.PrepaymentUsed }, beforeCheck(trade) { if (trade.PrepaymentUsed) { trade.KOPayoffType = 0; trade.KIPayoffType = 0; trade.KORebateType = 0; trade.AnnualizedPremiumRate = ''; } return { KOPayoffType: parseInt(trade.KOPayoffType) || 0, KIPayoffType: parseInt(trade.KIPayoffType) || 0, IsInitialKnockedIn: !!trade.IsInitialKnockedIn, PrepaymentUsed: !!trade.PrepaymentUsed }; } }, "气囊结构": { AirBag: true, BarrierLow: '', KIParticipationRate: '', HasPayoffLimit: false, HighStrike: '', IsDiscreteMonitored: false //BarrierLow替代了Barrier }, "收益增强结构": { UnEnhance: true, AnnualizedEnhanceRate: '' }, "现金流交易": { Cashflow: true, ProfitRate: '', RateType: "0", DepositType: "0", PrepayRatio: '0' }, "自定义交易": { ObservationDatesShow: '占位符', Custom: true }, "累计期权": { Accumulator: true, PayoffType: '浮动', AccumulatorStructureType: '0', IsFixedCoupon: true, CouponDayCount: 'Act365', StrikeGearingFactor: 1, CallMultiplier: 1, PutMultiplier: 1, EarlyTerminate: false, SettlementMode: (ylotc.Company === '厦门象屿' ? '现金实物合并结算' : '现金当日'), KOObservationDates: '', CouponPercent: true, CouponPercent2: true, AccumuType: '', AccumuTradeAmount: '', ForwardPriceType: pageVue.ForwardPriceTypeCfg, ForwardDateType: (ylotc.Company === '中粮' ? '标的到期日' : (ylotc.Company === '厦门象屿' ? '标的交割月前一交易日' : '期权到期日')), SettlementMode2: (ylotc.Company === '厦门象屿' ? '现金实物合并结算' : '现金当日'), ForwardPriceType2: pageVue.ForwardPriceTypeCfg, ForwardDateType2: (ylotc.Company === '中粮' ? '标的到期日' : (ylotc.Company === '厦门象屿' ? '标的交割月前一交易日' : '期权到期日')), SettlementMode3: (ylotc.Company === '厦门象屿' ? '现金实物合并结算' : '现金当日'), ForwardPriceType3: pageVue.ForwardPriceTypeCfg, ForwardDateType3: (ylotc.Company === '中粮' ? '标的到期日' : (ylotc.Company === '厦门象屿' ? '标的交割月前一交易日' : '期权到期日')), ShowCouponOption: { init: '', visible(trade) { return trade.PayoffType === '固定'; } }, ShowSanDuanShi: { init: '', visible(trade) { return _.trim(trade.AccumulatorStructureType) === '1'; } } }, "Risky期权": { RiskyOption: true, ParticipationRate1: 1, ParticipationRate2: 1, ParticipationRate3: "", Strike1: '', Strike2: '', Strike3: '', } }); //期权字段状态 const OptionFieldState = _.reduce(OptionFields, (acc, cur) => { return _.reduce(cur, (acc, val, key) => { acc[key] = false; return acc; }, acc); }, {}); for (k of Object.keys(BasicFields)) { OptionFieldState[k] = true; } //浮窗标题状态 const FloatingTitleState = Object.assign({}, OptionFieldState); //获取标题状态 this.getTitleState = function (floating) { return floating ? FloatingTitleState : OptionFieldState; }; //重置字段状态 function __resetFieldState(trade, blreset) { let self = this; for ([k, v] of Object.entries(BasicFields)) { self[k] = v(trade); } let fields = OptionFields[trade.TradeType]; if (!fields) return; let chkobj = !blreset && fields.beforeCheck ? fields.beforeCheck(trade) || trade : trade; _.each(fields, (val, key) => { let blset = blreset && key in trade; if (typeof val === 'object') { self[key] = val.visible(chkobj); if (blset || !self[key]) { trade[key] = val.init; } } else { self[key] = true; blset && (trade[key] = val); } }); if (!blreset) return; if (trade.TradeType === '二元期权') { trade.PayoffType = trade.ExerciseMode === 'European' ? 'CashOrNothing' : 'UpOneTouch'; trade.RebateAnnualizedAtKO = trade.ExerciseMode !== 'European'; } else if (trade.TradeType === '现金流交易') { trade.IsUsePremiumRate = true; } else if (trade.TradeType === '累计期权') { trade.IsAnnualized = false; trade.ParticipationRate = ''; } else if (trade.TradeType === 'Risky期权') { trade.ParticipationRate = ''; trade.OptionType = "看涨" if (trade.IsMoneynessOption === '是') { trade.Strike3 = 1; } else { trade.Strike3 = trade.SpotPrice; } } } const AnnualCallControl = [null, 0]; //获取字段状态 this.getFieldState = function (floating) { let clone = Object.assign({}, OptionFieldState); //重置字段状态 clone.resetFieldState = function (trade, blreset) { __resetFieldState.call(this, trade, blreset); if (floating) { Object.assign(FloatingTitleState, this); } }; //交易类型变更时重置交易字段值和状态 clone.onTradeTypeChanged = function (trade, blReset, vueCaller) { let self = this, resetValue = !!blReset; let oldAnnualFlag = this.SnowBall || this.AutoCall; _.each(OptionFieldState, (val, key) => { self[key] = 0; resetValue && key in trade && !(key in BasicFields) && (trade[key] = ''); }); //这里更新可以避免不同期权类型相同字段的困扰 this.resetFieldState(trade, resetValue); //切换年化系数的两种表现形式 let newAnnualFlag = this.SnowBall || this.AutoCall; if (resetValue && (oldAnnualFlag ^ newAnnualFlag) === 1) { if ((AnnualCallControl[0] !== trade || AnnualCallControl[1] + 300 < new Date().getTime())) { AnnualCallControl[0] = trade; AnnualCallControl[1] = new Date().getTime(); if (newAnnualFlag) { trade.IsAnnualized2 = trade.IsAnnualized; trade.IsAnnualized = false; trade.AnnualizeFactor = null; trade.MetaDic['AnnualizeFactor'] = ''; } else { trade.IsAnnualized = trade.IsAnnualized2; trade.IsAnnualized2 = false; trade.AnnualizeFactor2 = null; trade.MetaDic['AnnualizeFactor2'] = ''; } } if (vueCaller) { var arr = [vueCaller.AnnualizeFactor, vueCaller.AnnualizeFactor2]; newAnnualFlag && arr.reverse(); Object.assign(arr[0], arr[1]); Object.assign(arr[1], { ttmDays: 0, daysInYear: pageVue.DaysInYear }); vueCaller.changeIsAnnualized(); } } }; //设置字段状态 clone.setFieldState = function (field, blvalue) { if (field in this) { this[field] = blvalue; floating && (FloatingTitleState[field] = blvalue); } }; return clone; }; this.initFieldValue = function (trade) { __resetFieldState(trade, true); }; _.each([pageVue.Trade, DefaultData, DefaultData.viewState], x => Object.freeze(x)); }()); const consSyntheticMap = {}; const consVueTrade = { data() { return { updateKey: { variety: 0, underlying: 0, client: 0, instrumentType: 0, KIPayoffType: 0 }, AnnualizeFactor: { ttmDays: 0, daysInYear: pageVue.DaysInYear, refDays: 0 }, AnnualizeFactor2: { ttmDays: 0, daysInYear: pageVue.DaysInYear, refDays: 0 } }; }, created() { if (this.trade.MetaDic['组合标的']) { this.viewState.synthetic = JSON.parse(this.trade.MetaDic['组合标的']); } this.AnnualizeFactor = this.viewState.AnnualizeFactor; this.AnnualizeFactor2 = this.viewState.AnnualizeFactor2; if (!this.floating) { //在修改或组合报价导入时带入年化系数 for (var key of ['AnnualizeFactor', 'AnnualizeFactor2']) { let meta = this.trade.MetaDic[key]; if (meta) { let index = meta.indexOf('/') if (index > 0) { this[key].ttmDays = parseFloat(meta.substring(0, index)) || 0; this[key].daysInYear = parseFloat(meta.substring(index + 1)) || pageVue.DaysInYear; } } } this.AnnualizeFactor.refDays = this.AnnualizeFactor2.refDays = this.getAnnualDays() || 0; } this.viewState.Observation.ObservationDates = this.trade.ObservationDates || ""; if (this.trade.KOObservationDates && (this.trade.TradeType === '雪球期权' || this.trade.TradeType === "累计期权" && this.trade.PayoffType === '固定')) { var arr = this.trade.KOObservationDates.split(';').filter(O => O); this.viewState.KOObservation.ObservationDates = [].concat(arr[0], this.trade.KOObservationSettleDates, arr[1], (arr[2] || "0")).join(';'); } else { this.viewState.KOObservation.ObservationDates = this.trade.KOObservationDates || ""; } this.viewState.KOObservationSettle.ObservationDates = this.trade.KOObservationSettleDates || ""; this.viewState.Extend.TradingPlace = this.trade.MetaDic["交易场所"] || ""; this.viewState.Extend.ClearingAgency = this.trade.MetaDic["清算机构"] || ""; if (pageData.showCCR) { this.trade.ccr_k = this.trade.MetaDic["ccr_k"] || "1"; this.trade.ignoreRiskExposure = this.trade.MetaDic["ignoreRiskExposure"] || "0"; } this.trade.StockEqvNotionalMax = null; this.trade.TradeAmountV = tradeHelper.getTradeAmountV(this.trade, this.trade.Notional, this.trade.CountRatio); }, methods: { getVol() { }, //变更买入卖出 changeBuySell(resetInitialMargin, initVol = true) { if (initVol) { this.getVol(); } this.changeBuySellEx(); if (resetInitialMargin) { this.trade.InitialMargin = null; } }, changeBuySellEx() { }, //变更资金类型 changeDepositType() { let trade = this.trade if (trade.DepositType === "0") { this.getNoRiskRate(); this.changeFieldState(); } else { trade.NoRiskRate = 0; this.changeFieldState(); } }, //变更行权模式 changeExerciseMode(flag) { if (this.trade.TradeType === '二元期权') { if (this.trade.ExerciseMode === 'European') { this.binaryPayoffTypes = consBinaryPayoffTypes.European; this.trade.PayoffType = 'CashOrNothing'; this.trade.MonitorType = this.trade.RebateType = ""; this.trade.RebateAnnualizedAtKO = false; } else { this.binaryPayoffTypes = consBinaryPayoffTypes.American; this.trade.PayoffType = 'UpOneTouch'; this.trade.MonitorType = "离散"; this.trade.RebateType = "AtHit"; } } if (flag !== 'TradeType') { this.getVol(); this.changeFieldState(); } this.refreshEngineNames(); }, //刷新定价模型名称 refreshEngineNames() { this.engineNames = tradeUtils.getEngineNames(this.trade); }, //获取组合标的价格 getSyntheticPrices(underlyingCode) { let self = this; main.post('/pricing/AjaxGetSyntheticPriceModel', { underlyingCode: underlyingCode }, false).done(function (resp) { self.viewState.synthetic = resp.obj; self.trade.SpotPrice = resp.obj.Price; }); }, //变更标的价格 changeSpotPrice(isUserInput) { this.viewState.SpotPrice = isUserInput ? "user" : "system"; let SpotPrice = this.trade.SpotPrice || 0; if (!SpotPrice || SpotPrice === '-') { SpotPrice = 0; } else { let precision = pricingFormat.umprice.precision || 0; if (precision < 2) precision = 2; let regex = new RegExp('^-?\\d*(\\.\\d{0,' + precision + '})?'); let match = regex.exec(SpotPrice); if (match) { if (match[0] !== SpotPrice) { this.trade.SpotPrice = match[0]; SpotPrice = parseFloat(match[0]); } } else { this.trade.SpotPrice = SpotPrice = 0; } } tradePricing.tradeCalc(this.trade, tradePricing.calcReason.SpotPrice2, this.viewState.variety.CountRatio); if (!pageVue.IsCheck) { this.getVol(true); } }, blurSpotPrice() { !this.trade.SpotPrice && (this.trade.SpotPrice !== 0) && (this.trade.SpotPrice = 0); }, //更改成交方式 changeIsUsePremiumRate() { tradeUtils.usePremiumRateSwitch(this.trade); if (this.trade.isTradePricePayType) { this.changeTradePrice(); } else if (this.trade.IsUsePremiumRate) { this.changePremiumRate(); } else { this.changeTradeSinglePrice(); } }, //变更相对行权价 changeIsMoneynessOption() { tradeUtils.moneynessSwitch(this.trade); this.changeKOBarrier(); }, //变更执行价格 changeStrike() { this.getVol(true); }, //变更敲入行权价1 changeSpreadStrike1() { this.trade.Strike = this.trade.SpreadStrike1; }, //获取标的价格 getSpotPrice(blSetStrike) { var self = this; return main.post("/pricing/AjaxGetUnderlyingPrice", { underlyingCode: this.trade.UnderlyingCode, tradeDate: this.trade.TradeDate }) .done(function (resp) { self.viewState.synthetic = consSyntheticMap[self.trade.CalcId] = resp.obj.synthetic; self.trade.SpotPrice = pricingFormat.umprice(resp.obj.price); if (blSetStrike === true && self.trade.IsMoneynessOption !== "是") { self.trade.Strike = self.trade.SpotPrice; if (self.trade.TradeType === "Risky期权") { self.trade.Strike3 = self.trade.SpotPrice; } } self.changeSpotPrice(false); }); }, //获取品种最小变动价格 getPriceTick() { return this.trade.UnderlyingInstrumentType === 'Stock' ? 0.01 : this.viewState.variety ? parseFloat(this.viewState.variety.PriceTick) || 0.1 : 0.1; }, //绝对值执行价格 showAbsStrike() { this.trade.IsMoneynessOption = "否"; tradeUtils.moneynessSwitch(this.trade); this.changeKOBarrier(); }, //百分比执行价格 showPercentStrike() { this.trade.IsMoneynessOption = "是"; tradeUtils.moneynessSwitch(this.trade); this.changeKOBarrier(); }, //变更交易日期 changeTradeDate(force, isFromUnderlying) { this.trade.ValueDate = this.trade.TradeDate; this.trade.StartDate = this.trade.TradeDate; if (!pageData.is厦门象屿 && this.trade.TradeType !== "Risky期权") { this.trade.PremiumPayDate = this.trade.TradeDate; } if (pageVue.IsCheck) return; this.getTTM(force); this.getNoRiskRate(); this.changeIsAnnualized(); if (!isFromUnderlying && pageData.is厦门象屿) { this.viewState.SpotPrice = "user"; this.getVol(); } else { this.viewState.SpotPrice = "system"; if (force !== 'import2') { this.getSpotPrice(true); } else { this.getVol(); } } if (this.trade.TradeType == "累计期权") { this.setTradeAmount(); } }, //变更定价日期 changeValueDate() { this.getTTM(true); }, //变更到期日期 changeExerciseDate() { if (pageData.is厦门象屿 || this.trade.TradeType === "Risky期权") { this.trade.PremiumPayDate = this.trade.ExerciseDate; } if (pageVue.IsCheck) return; this.getTTM(); this.getVol(); this.getNoRiskRate(); if (this.trade.TradeType == "累计期权") { this.setTradeAmount(); } }, //变更结算日期 changeSettlementDate() { this.changeIsAnnualized(); this.getTTM(); }, //更改权利金费率 changePremiumRate() { if (!this.trade.IsUsePremiumRate) { return; } tradePricing.tradeCalc(this.trade, tradePricing.calcReason.PremiumRate, this.viewState.variety.CountRatio); }, //更改权利金单价 changeTradeSinglePrice() { if (this.trade.IsUsePremiumRate) { return; } tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradeSinglePrice, this.viewState.variety.CountRatio); }, //显示权利金绝对值 showAbsPrice() { this.trade.IsUsePremiumRate = false; tradeUtils.usePremiumRateSwitch(this.trade); }, //显示权利金百分比 showPercentPrice() { this.trade.IsUsePremiumRate = true; tradeUtils.usePremiumRateSwitch(this.trade); }, //更改交易总额 changeTradePrice() { tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradePrice, this.viewState.variety.CountRatio); }, //更改交易份额 changeNotional(value) { (typeof value === 'number') && (this.trade.Notional = value); tradePricing.tradeCalc(this.trade, tradePricing.calcReason.Notional, this.viewState.variety.CountRatio); this.trade.InitialMargin = null; }, //更改有效交易数量 changeTradeAmount(value) { (typeof value === 'number') && (this.trade.TradeAmount = value); tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradeAmount, this.viewState.variety.CountRatio); this.trade.InitialMargin = null; }, //更改交易数量 changeTradeAmountV(value) { (typeof value === 'number') && (this.trade.TradeAmountV = value); tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradeAmountV, this.viewState.variety.CountRatio); }, changeAccumuTradeAmount(value) { (typeof value === 'number') && (this.trade.AccumuTradeAmount = value); this.trade.OriginalAccumuTradeAmount = this.trade.AccumuTradeAmount; this.setTradeAmount(); this.changeTradeAmountV(this.trade.TradeAmountV); }, setTradeAmount() { var TradeAmountV = this.trade.AccumuTradeAmount; var dayCount = 0; if (this.trade.KOObservationDates) { dayCount = this.trade.KOObservationDates.split(";")[0].split(',').length; } else { var data = { alignEnd: "true", calcMode: "01", endDate: this.trade.ExerciseDate, holidayAdjustment: "Following", startDate: this.trade.TradeDate, termStr: "1D", }//获取区间观察日数量; main.post("/trade/GetObservationDateList", data, { async: false }).done( function (res) { dayCount = res.obj.length; } ); } TradeAmountV *= dayCount; this.trade.TradeAmountV = TradeAmountV; }, //变更名义本金 changeStockEqvNotional(value) { (typeof value === 'number') && (this.trade.StockEqvNotional = value); if (this.trade.TradeType === "现金流交易") { return; } tradePricing.tradeCalc(this.trade, tradePricing.calcReason.StockEqvNotional, this.viewState.variety.CountRatio); this.trade.InitialMargin = null; }, //变更有效名义本金 changeStockEqvNotionalReal(value) { (typeof value === 'number') && (this.trade.StockEqvNotionalReal = value); tradePricing.tradeCalc(this.trade, tradePricing.calcReason.StockEqvNotionalReal, this.viewState.variety.CountRatio); this.trade.InitialMargin = null; }, //获取期权年化天数 getAnnualDays() { let dateFrom = _.trim(this.trade.TradeDate).substring(0, 10); let dateTo = _.trim(this.trade.SettlementDate).substring(0, 10); if (dateFrom && dateTo) { dateFrom = new Date(dateFrom).getTime(); dateTo = new Date(dateTo).getTime(); return 1 + (dateTo - dateFrom) / 1000 / 3600 / 24; } return false; }, //更改期权年化 changeIsAnnualized() { let IsAnnualized2 = this.fieldState.SnowBall || this.fieldState.AutoCall; if (!(IsAnnualized2 ? this.trade.IsAnnualized2 : this.trade.IsAnnualized)) { //|| pageVue.TradeEdit && this.AnnualizeFactor.ttmDays > 0 return this.changeAnnualizeFactor(); } let factor = this[IsAnnualized2 ? "AnnualizeFactor2" : "AnnualizeFactor"]; let days = this.getAnnualDays(); if (days !== false) { factor.ttmDays = factor.refDays = days; this.changeAnnualizeFactor(); } else { factor.refDays = 0; } }, //更改期权年化ttmday与参考日期间隔的差值 changeAnnualDayDiff(diff) { if (this.annualDayDiff !== diff) { this.AnnualizeFactor.ttmDays = this.AnnualizeFactor.refDays + diff; this.changeAnnualizeFactor(); } }, //更改期权年化ttmday与参考日期间隔的差值 changeAnnualDayDiff2(diff) { if (this.annualDayDiff2 !== diff) { this.AnnualizeFactor2.ttmDays = this.AnnualizeFactor2.refDays + diff; this.changeAnnualizeFactor(); } }, //更改期权年化 changeAnnualizeFactor() { let IsAnnualized2 = this.fieldState.SnowBall || this.fieldState.AutoCall; let propKey = IsAnnualized2 ? 'AnnualizeFactor2' : 'AnnualizeFactor'; let factor = IsAnnualized2 ? this.AnnualizeFactor2 : this.AnnualizeFactor; if (IsAnnualized2 ? this.trade.IsAnnualized2 : this.trade.IsAnnualized) { this.trade[propKey] = Math.abs(factor.ttmDays / factor.daysInYear); this.trade.MetaDic[propKey] = factor.ttmDays.toString() + '/' + factor.daysInYear.toString(); } else { this.trade[propKey] = 1; this.trade.MetaDic[propKey] = ''; factor.ttmDays = 0; factor.daysInYear = pageVue.DaysInYear; } this.changeEffectRatio(); }, //变更参与率/年化系数/保底收益率 changeEffectRatio() { if (this.trade.IsUsePremiumRate) { tradePricing.tradeCalc(this.trade, tradePricing.calcReason.StockEqvNotional, this.viewState.variety.CountRatio); } else { if (this.trade.TradeAmountV > 0) { tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradeAmountV, this.viewState.variety.CountRatio); } else { tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradeAmount, this.viewState.variety.CountRatio); } } this.trade.InitialMargin = null; }, changePrincipalSum() { tradePricing.tradeCalc(this.trade, tradePricing.calcReason.OriginalPrincipalSum, this.viewState.variety.CountRatio); this.trade.InitialMargin = null; }, //变更成交波动率 changeOpenVolatility() { this.viewState.VolState = "user"; }, //锁定成交波动率 lockVolState() { this.viewState.VolLockState = "lock"; this.viewState.VolState = "user"; }, //解除成交波动率锁定 unlockVolState() { this.viewState.VolLockState = "system"; this.viewState.VolState = "system"; }, //变更目标波动率 changeCloseVolatility() { this.viewState.CloseVolState = "user"; }, //变更TTMDays changeTTM() { this.viewState.TTMDays = "user"; if (pageData.is厦门象屿) { this.trade.NumOfSmoothingDays = this.trade.TTMDays >= 10 ? 5 : 0; } }, //获取交易日期和到期日期之间工作日的长度 getTTM(force, changeNumOfSmoothingDays = true) { if (force) { this.viewState.TTMDays = "system"; } var self = this; if (this.viewState.TTMDays !== 'user') { var data = { from: this.trade.ValueDate || this.trade.TradeDate, to: this.trade.ExerciseDate, varietyid: this.viewState.variety.id }; if (data.from && data.to) { main.post("/calendar/DaysInPeriod", data, false).done(function (resp) { self.trade.TTMDays = consNumberFormat.ttmDaysFmt(resp.obj); var days = Number.parseInt(self.trade.TTMDays); if (changeNumOfSmoothingDays && pageVue.NumOfSmoothingDaysCfg === 'TTM') { self.trade.NumOfSmoothingDays = days < 1 ? 1 : days; if (pageData.is厦门象屿) { self.trade.NumOfSmoothingDays = days >= 10 ? 5 : 0; } } if (pageData.is厦门象屿) { self.trade.NumOfSmoothingDays = days >= 10 ? 5 : 0; } }); } else { self.trade.TTMDays = ''; } } }, //变更初始预付金 changeInitialMargin() { this.viewState.InitialMargin = 'user'; this.resetSummary(resetSummaryFlags.initialMargin); }, //获取系统计算的初始预付金 getInitialMargin() { if (this.trade.TradeType === "自定义交易") { this.trade.ExtendInfo = this.setExtendInfo(this.trade); } //检查并转换数据 var trades = tradeUtils.prepareTrades([this.trade], pageVue.getVolType(), false); if (!trades) return; var self = this; main.post("/pricing/AjaxGetInitialMargin", { trade: trades[0] }) .done(function (resp) { if (pageVue.ClientUsedForCalc && pageVue.TwoSideMargin && !self.viewState.TwoSideMargin && resp.obj < 0 && !trades[0].ParentTradeId > 0) { self.trade.InitialMargin = 0; } else { self.trade.InitialMargin = pricingFormat.tradePrice(resp.obj); } self.viewState.InitialMargin = "system"; self.resetSummary(resetSummaryFlags.initialMargin); }); }, resetSummary() { }, //获取系统波动率 getTradeOpenVolatility(flag) { var self = this; var closeVol = this.trade.TradeCloseVolatility; tradeUtils.getTradeVol(this.trade, flag === 'user' ? { BidVar: this.trade.Var, AskVar: this.trade.Var, BaseVol: isNaN(closeVol) ? '' : closeVol } : {}, this.viewState.variety.id).done(function (resp) { var vol = resp.obj.vol; if (isNaN(vol)) { let msg = resp.msg || resp.message; return main.message("未获取到波动率: " + msg); } self.viewState.VolState = flag === 'user' ? "user" : "system"; self.viewState.VolLockState = flag === 'user' ? "lock" : "system"; var formatVol = consNumberFormat.volValueFmt(vol); if (pageVue.SkewMapVol) { self.trade.Var = resp.obj.var; self.trade.TradeOpenVolatility = formatVol; self.trade.TradeCloseVolatility = consNumberFormat.volValueFmt(resp.obj.baseVol); } else if (pageVue.IsTradeVol) { self.trade.TradeOpenVolatility = formatVol; } else { self.trade.Vol = formatVol; } }); }, //获取隐含波动率 getTradeImpliedVol(flag) { var self = this; if (!this.trade.OptionType) { return main.message("请填写看涨看跌"); } if (!this.trade.TradeDate) { return main.message("请填写成交日期"); } if (!this.trade.Strike) { return main.message("请填写执行价格"); } if (!this.trade.ExerciseDate) { return main.message("请填写到期日期"); } if (!this.trade.SpotPrice) { return main.message("请填写标的期初价格"); } if (!this.trade.TradeSinglePrice) { return main.message("请填写权利金"); } main.post("/pricing/GetImpliedVol", this.trade).done(function (res) { if (isNaN(res.obj)) { return main.message("未获取到波动率,请检查输入的数值"); } self.viewState.VolState = "user"; if (pageVue.IsTradeVol) { self.trade.TradeOpenVolatility = consNumberFormat.volValueFmt(res.obj); } else { self.trade.Vol = consNumberFormat.volValueFmt(res.obj);; } }); }, //获取目标波动率 getTradeCloseVolatility() { var self = this; if (pageVue.SkewMapVol) { self.viewState.CloseVolState = "system"; self.trade.TradeCloseVolatility = ""; return; } let over = pageVue.TradeCloseVolatilityCfg === 'Mid' ? { VolType: '交易' } : null; tradeUtils.getTradeVol(this.trade, over, this.viewState.variety.id).done(function (resp) { var vol = resp.obj.vol; if (isNaN(vol)) { return main.message("未获取到波动率"); } self.viewState.CloseVolState = "system"; self.trade.TradeCloseVolatility = consNumberFormat.volValueFmt(vol); }); }, //变更分红率 changeDividendRate() { this.viewState.DividendRate = 'user'; }, //获取分红率 getDividendRate() { if (!this.trade.TradeDate) { return main.alert("缺少交易日期"); } var self = this; var postData = { underlyingCode: this.trade.UnderlyingCode, tradeDate: this.trade.TradeDate, tradetype: this.trade.TradeType, optiontype: this.trade.OptionType }; main.post("/pricing/AjaxGetDividendRate", postData).done(function (resp) { self.trade.DividendRate = resp.obj; self.viewState.DividendRate = "system"; }); }, //变更无风险利率 changeNoRiskRate() { this.viewState.NoRiskRate = 'user'; }, //获取无风险利率 getNoRiskRate() { var self = this; if (this.trade.TradeType === "现金流交易" && this.trade.DepositType == 1) { return; } !pageVue.IsCheck && main.post("/pricing/AjaxGetNoRiskRate", { startDate: this.trade.TradeDate, endDate: this.trade.ExerciseDate }).done(function (resp) { self.trade.NoRiskRate = resp.obj.toFixed(4); self.viewState.NoRiskRate = "system"; }); }, calcSnowballAnnualPremium() { let trade = this.trade; let trades = tradeUtils.prepareTrades([trade], pageVue.getVolType(), false); if (!trades) return; var self = this; main.post("/pricing/AjaxCalcSnowballAnnualPremium", { trade: trades[0] }).done(function (resp) { trade.AnnualizedPremiumRate = resp.obj; }); }, calcKORebate() { let trade = this.trade; let trades = tradeUtils.prepareTrades([trade], pageVue.getVolType(), false); if (!trades) return; var self = this; main.post("/pricing/AjaxCalcSnowballKORebate", { trade: trades[0] }).done(function (resp) { trade.KORebate = resp.obj; self.changeRebate(); }); }, calcPhoenixCouponRate() { let trade = this.trade; let trades = tradeUtils.prepareTrades([trade], pageVue.getVolType(), false); if (!trades) return; var self = this; main.post("/pricing/AjaxCalcPhoenixCouponRate", { trade: trades[0] }).done(function (resp) { trade.Coupon = resp.obj; self.changeRebate(); }); }, //设置观察日 setObservationDates(observationId) { let isKO = observationId === '#KO'; let isKS = observationId === '#KS'; observationId = this.trade.CalcId + observationId; var startTime = _.trim(this.trade.TradeDate); var endTime = _.trim(this.trade.ExerciseDate); if (!startTime) { return main.alert("请输入交易日期"); } if (!endTime) { return main.alert("请输入到期日期"); } var obs = isKO ? this.viewState.KOObservation : (isKS ? (this.viewState.KOObservationSettle.hasValue ? this.viewState.KOObservationSettle : this.viewState.KOObservation) : this.viewState.Observation); var query = { observationNum: obs.ObservationNum, observationUnit: obs.ObservationUnit, observationHolidayType: obs.ObservationHolidayType, startTime: startTime, endTime: endTime, alignEnd: _.toString(obs.ObservationAlignEnd) !== "false", btnId: observationId, couponDayInterval: obs.CouponDayInterval, tradeType: this.trade.TradeType, ObservationFrequency: obs.ObservationFrequency }; query.Comments = isKO ? this.trade.MetaDic["ObservationRemark3"] : (isKS ? this.trade.MetaDic["ObservationRemark2"] : this.trade.MetaDic["ObservationRemark1"]); if (isKO && !this.viewState.hasObservationDates) { query.Comments = this.trade.MetaDic["ObservationRemark2"]; } var whith = 500; if (isKO) { query.title1 = "障碍价格"; query.title2 = "票息"; query.isTitle1Percent = this.trade.IsMoneynessOption === "是"; query.isTitle2Percent = true; query.defaultTitle1Value = this.trade.KOBarrier; query.defaultTitle2Value = this.trade.TradeType === "凤凰期权" ? this.trade.Coupon : this.trade.KORebate; if (this.trade.TradeType === "累计期权") { if (this.trade.PayoffType === '固定') { query.title2 = ""; query.defaultTitle2Value = this.trade.Coupon; query.showDate2 = true; query.date2Title = "结算日期"; query.showDate2OffsetControl = true; query.date2OffsetControlTitle = "结算日期间隔" whith += 20; } else { query.title2 = "" } } else if (this.trade.TradeType === "雪球期权") { query.dateTitle = "敲出观察日(T)"; if (_.toString(this.trade.KOPayoffType) === "0") { query.showDate2 = true; } query.date2Title = "票息支付日"; query.showDate2OffsetControl = true; query.date2OffsetControlTitle = "票息支付日间隔" whith += 20; } } query = $.param(query); sessionStorage.setItem(observationId + "_observationdates", obs.ObservationDates); layer.open({ type: 2, title: "设置自定义观察日", shadeClose: false, shade: 0.4, area: [whith + 'px', '560px'], content: "/trade/tradeObservationDates?" + query }); }, getObservationRate(observation) { if (!observation || !observation.hasValue) return ''; var observationRate = "", newUnit = ""; switch (observation.ObservationUnit) { case "D": newUnit = "天"; break; case "W": newUnit = "周"; break; case "M": newUnit = "月"; break; case "Y": newUnit = "年"; break; } observationRate = observation.ObservationNum + newUnit; if (newUnit !== "") { observationRate = "每" + observationRate; } return observationRate; }, //变更奇异期权字段状态 changeFieldState() { this.fieldState.resetFieldState(this.trade); }, //设置观察频率 setObservation(observationNum, observationUnit, observationHolidayType, observationDates, alignEnd, calcId, couponDayInterval, Comments, ObservationFrequency) { if (!calcId) return; let isKO = calcId.endsWith('#KO'); let isComments = Comments != ""; if (observationDates == "") { observationDates = null; } let observation = { ObservationNum: observationNum, ObservationUnit: observationUnit, ObservationHolidayType: observationHolidayType, ObservationAlignEnd: alignEnd, CouponDayInterval: couponDayInterval, ObservationFrequency: ObservationFrequency //报送观察频率 }; var self = this; _.each(observation, (val, key) => self.trade[key] = val); observation.hasValue = true; observation.ObservationDates = observationDates; if (isKO) { self.viewState.KOObservation = observation; if (observationDates != null && observationDates != "") { var dates = observationDates.split(';').filter(o => o); if (dates.length === 4) { self.trade.KOObservationDates = dates[0] + ";" + dates[2] + ";" + dates[3] + ";"; } else if (self.trade.TradeType === "累计期权") { if (self.trade.PayoffType === "固定") { self.trade.KOObservationDates = dates[0] + ";" + dates[2] + ";"; observation.ObservationDates = observationDates + ";0"; } else { self.trade.KOObservationDates = dates[0] + ";" + dates[1] + ";"; //既然累计期权的结算日期在浮动时需要和观察日相同,索性就总是当它存在,避免切换上端收益类型后,结算日期为空的情况发生; observation.ObservationDates = dates[0] + ";" + dates[0] + ";" + dates[1] + ";0"; } setTradeAmount(self); } else { self.trade.KOObservationDates = observationDates; } if (!this.viewState.hasObservationDates) { self.viewState.KOObservationSettle = _.clone(observation); if (dates.length === 4 || (self.trade.TradeType === "累计期权" && dates.length === 3)) { self.trade.KOObservationSettleDates = dates[1]; } else { self.trade.KOObservationSettleDates = dates[0]; } if (isComments || this.trade.MetaDic["ObservationRemark2"] != undefined) this.trade.MetaDic["ObservationRemark2"] = Comments; } else { if (isComments || this.trade.MetaDic["ObservationRemark3"] != undefined) this.trade.MetaDic["ObservationRemark3"] = Comments; } } else { self.trade.KOObservationDates = observationDates; } self.trade.MetaDic["敲出观察周期"] = observationNum + observationUnit + "|" + ObservationFrequency; } else if (calcId.endsWith('#KS')) { self.viewState.KOObservationSettle = _.clone(observation); self.trade.KOObservationSettleDates = observationDates; this.viewState.hasObservationDates = true; if (isComments || this.trade.MetaDic["ObservationRemark2"] != undefined) this.trade.MetaDic["ObservationRemark2"] = Comments; } else { self.trade.MetaDic["敲入观察周期"] = observationNum + observationUnit + "|" + ObservationFrequency; self.viewState.Observation = observation; self.trade.ObservationDates = observationDates; if (isComments || this.trade.MetaDic["ObservationRemark1"] != undefined) this.trade.MetaDic["ObservationRemark1"] = Comments; } }, //变更票息结算方式 changeCouponPayType() { this.trade.CouponPayType = parseInt(this.trade.CouponPayType) || 0; this.trade.IncludeCouponAfterKI = true; }, //变更交易场所 changeTradingPlace() { this.trade.MetaDic["交易场所"] = this.viewState.Extend.TradingPlace; }, //变更清算机构 changeClearingAgency() { this.trade.MetaDic["清算机构"] = this.viewState.Extend.ClearingAgency; }, changeMainProtocolCode() { this.getSupProtocolCode(); }, getMainProtocolCode() { $("#MainProtocolCode option").remove(); main.post("/Client/getMainProtocolCodes", { clientId: $("#ClientId").val() }, { async: false }).done(function (resp) { var obj = $("#MainProtocolCode"); _.forEach(resp, (v) => { obj.append(""); }) }); this.getSupProtocolCode() }, getSupProtocolCode() { $("#SupProtocolCode option").remove(); if ($("#MainProtocolCode").val()) { main.post("/Client/getSideProtocols", { mainProtocol: $("#MainProtocolCode").val() }, { async: false }).done(function (resp) { var obj = $("#SupProtocolCode"); _.forEach(resp, (v) => { obj.append(""); }) }); } }, changeMarginTemplate() { tradeUtils.changeMarginTemplate(this.trade, this.tradeMarginTemplates); }, //变更亚式期权行权价类型 changeStrikeType() { if (this.trade.StrikeType === 'Segmented') { this.trade.PayoffType = 'EnhancedArithmeticAverage'; } if (this.trade.StrikeType != "Floating" && this.trade.PayoffType == 'EnhancedArithmeticAverage' && $("#EnhancedPriceTitle")) { $("#EnhancedPriceTitle").show(); if (parseFloat(this.trade.EnhancedPrice) === 0) { this.trade.EnhancedPrice = this.trade.Strike; } } else if ($("#EnhancedPriceTitle")) { $("#EnhancedPriceTitle").hide(); } }, //变更亚式期权均价计算类型 changePayOffType() { if (this.trade.StrikeType != "Floating" && this.trade.PayoffType == 'EnhancedArithmeticAverage') { if ($("#EnhancedPriceTitle")) { $("#EnhancedPriceTitle").show(); } if (parseFloat(this.trade.EnhancedPrice) === 0) { this.trade.EnhancedPrice = this.trade.Strike; } } else if ($("#EnhancedPriceTitle")) { $("#EnhancedPriceTitle").hide(); } }, changeKOBarrier() { if (this.viewState.KOObservation.ObservationDates) { var arr = this.trade.KOObservationDates.split(';').filter(o => o); if (arr.length >= 3 || this.trade.TradeType === '累计期权') { let fmt = this.trade.IsMoneynessOption === "是" ? consNumberFormat.umpriceP : pricingFormat.umprice; var barrierStr = _.toString(this.trade.KOBarrier) ? fmt(this.trade.KOBarrier) : ''; var index = arr.length >= 3 ? arr.length - 2 : 1; var barrierArr = arr[index].split(','); var selfTrade = this.trade; barrierArr.forEach(function (v, i) { barrierArr[i] = barrierStr; }); arr[index] = barrierArr.join(','); this.trade.KOObservationDates = arr.join(';'); if (this.trade.TradeType === "雪球期权") { arr = [].concat(arr[0], this.trade.KOObservationSettleDates, arr[1], arr[2]); } else if (this.trade.TradeType === "累计期权" && this.trade.PayoffType === "固定") { arr = [].concat(arr[0], this.trade.KOObservationSettleDates, arr[1], (arr[2] || "0")); } this.viewState.KOObservation.ObservationDates = arr.join(';'); main.message("敲出障碍价格已同步"); } } }, changeRebate() { if (this.viewState.KOObservation.ObservationDates) { var arr = this.trade.KOObservationDates.split(';').filter(o => o); if (arr.length >= 3) { var rebateStr = pricingFormat.premiumRate(this.trade.TradeType === "凤凰期权" ? this.trade.Coupon : this.trade.KORebate) + "" var index = arr.length - 1; var rebateArr = arr[index].split(','); rebateArr.forEach(function (v, i) { rebateArr[i] = rebateStr; }); arr[index] = rebateArr.join(','); this.trade.KOObservationDates = arr.join(';'); if (this.trade.TradeType === "雪球期权") { arr = [].concat(arr[0], this.trade.KOObservationSettleDates, arr[1], arr[2]); } this.viewState.KOObservation.ObservationDates = arr.join(';'); main.message("票息已同步"); } } }, changePayoffType() { this.trade.AccumuType = ''; if (this.trade.TradeType === '累计期权') { if (this.trade.SettlementMode === '现金期末') { this.trade.PayoffType = '浮动'; } this.trade.EarlyTerminate = false; } if (this.trade.TradeType === '二元期权') { if (this.trade.ExerciseMode === 'European' || this.trade.PayoffType === 'DoubleNoTouch' || this.trade.PayoffType === 'UpNoTouch' || this.trade.PayoffType === 'DownNoTouch') { this.trade.RebateAnnualizedAtKO = false; } if (this.trade.PayoffType === 'AssetOrNothing') { this.trade.CashOrNothingAmountRate = ""; this.trade.CashOrNothingAmount = ""; } } this.fieldState.resetFieldState(this.trade); }, changeAccumulatorStructureType() { if (this.trade.AccumulatorStructureType == "1") { this.viewState.TradeExtend.Multiplier = 1; this.viewState.TradeExtend.Multiplier2 = 1; this.viewState.TradeExtend.Multiplier3 = 1; } this.changeFieldState(); } }, computed: { maxTradeDate() { let exerciseDate = this.trade.ExerciseDate; return exerciseDate;//&& exerciseDate <= pageVue.SysDate ? exerciseDate : pageVue.SysDate; }, observationRate() { return this.getObservationRate(this.viewState.Observation); }, koObservationRate() { return this.getObservationRate(this.viewState.KOObservation); }, koObservationSettleRate() { return this.getObservationRate(this.viewState.KOObservationSettle); }, inputFormatStrike() { let fmt = {}; if (this.trade.IsMoneynessOption === '是') { fmt.append = '%'; fmt.negative = false; fmt.precision = pricingFormat.umpriceP.precision; } else { fmt.append = ''; fmt.negative = true; fmt.precision = pricingFormat.umprice.precision; } return fmt; }, inputFormatSinglePriceOnly() { let underlying = this.viewState.underlying; let quoteUnit = underlying && underlying.QuoteUnitString ? "元/" + (this.viewState.synthetic ? "份" : underlying.QuoteUnitString) : ''; return { precision: pricingFormat.tradeSinglePrice.precision, negative: true, append: quoteUnit }; }, inputFormatSinglePrincipalOnly() { let underlying = this.viewState.underlying; let quoteUnit = underlying && underlying.QuoteUnitString ? "元/" + (this.viewState.synthetic ? "份" : underlying.QuoteUnitString) : ''; return { precision: pricingFormat.tradeSinglePrice.precision, negative: true, append: quoteUnit }; }, inputFormatTradeAmount() { let fmt = { precision: pricingFormat.notional.precision, append: '' }; let variety = this.viewState.variety; if (variety) { if (variety.InstrumentType === 'Stock' || !variety.QuoteUnit) { fmt.append = '股'; } else { var QuoteUnit = variety.QuoteUnit; var unit = QuoteUnit.substring(QuoteUnit.lastIndexOf('/') + 1).trim(); fmt.append = unit === "500千克" ? "吨" : unit || ''; } } return fmt; }, inputFormatTradeAmountV() { let fmt = { precision: pricingFormat.notional.precision, append: '' }; let variety = this.viewState.variety; if (variety) { if (variety.InstrumentType === 'Stock' || !variety.QuoteUnit) { fmt.append = '股'; } else { var QuoteUnit = variety.QuoteUnit; var unit = QuoteUnit.substring(QuoteUnit.lastIndexOf('/') + 1).trim(); fmt.append = unit === "500千克" ? "吨" : unit || ''; } } return fmt; }, inputFormatNotional() { let fmt = { precision: pricingFormat.notional.precision, append: '' }; let variety = this.viewState.variety; if (variety) { if (variety.InstrumentType === 'Stock' || !variety.QuoteUnit) { fmt.append = '股'; } else { fmt.append = '份'; } } return fmt; }, showExerciseMode() { switch (this.trade.TradeType) { case '彩虹期权': case '合成价差期权': case '双鲨期权': case '收益增强结构': this.trade.ExerciseMode = 'European'; return 1; case '凤凰期权': case '雪球期权': case '累计期权': case '自定义交易': case '现金流交易': case '区间累积期权': return 0; case '障碍期权': /*if ((this.trade.BarrierType || '').startsWith('双')) {*/ this.trade.ExerciseMode = 'European'; return 1; /* }*/ break; } return this.trade.ExerciseMode === 'European' ? 11 : 101; }, showOptionType() { switch (this.trade.TradeType) { case '现金流交易': this.trade.OptionType = ""; return false; case '区间累积期权': case '双鲨期权': case '气囊结构': case '收益增强结构': return false; case '二元期权': return this.trade.ExerciseMode === 'European'; default: return true; } }, //亚式行权价类型 consAsiaStrikeType() { let isAmerican = this.trade.ExerciseMode === 'American'; if (isAmerican && this.trade.StrikeType === 'Floating') { this.trade.StrikeType = 'Fixed'; } return isAmerican ? [{ value: 'Fixed', text: '固定行权价' }] : [{ value: 'Fixed', text: '固定行权价' }, { value: 'Floating', text: '浮动行权价' }, { value: 'Segmented', text: '分段式' }]; }, //亚式结算方式 consAsiaSettleModes() { if (this.trade.PayoffType == 'EnhancedArithmeticAverage' && !this.trade.SettleMode) { this.trade.SettleMode = 'AtHit'; } return consRebateTypes; }, //二元补偿支付类型 binaryRebateTypes() { if (this.trade.ExerciseMode === 'American' && this.trade.PayoffType === 'DoubleNoTouch') { this.trade.RebateType = 'AtEnd'; return [{ value: 'AtEnd', text: '递延' }]; } return consRebateTypes; }, //是否需要标的 needUnderlying() { return this.trade.TradeType !== '现金流交易'; }, annualDayDiff() { let diff = this.AnnualizeFactor.ttmDays - this.AnnualizeFactor.refDays; return diff < 0 ? diff.toString() : "+" + diff; }, annualDayDiff2() { let diff = this.AnnualizeFactor2.ttmDays - this.AnnualizeFactor2.refDays; return diff < 0 ? diff.toString() : "+" + diff; }, //雪球敲出赔付类别 snowballKOPayoffTypeEnums() { if (this.trade.OptionType === "看涨") { return [{ value: '0', text: '票息补偿' }, { value: '1', text: '敲出转看涨' }, { value: '2', text: '敲出转牛市价差' }]; } else { return [{ value: '0', text: '票息补偿' }, { value: '1', text: '敲出转看跌' }, { value: '2', text: '敲出转熊市价差' }]; } }, //雪球敲入到期支付类别 snowballKIPayoffTypeEnums() { let kiPayoffType = this.trade.KIPayoffType + ""; let isInitialKnockedIn = this.trade.IsInitialKnockedIn; if (this.trade.OptionType === "看涨") { switch (kiPayoffType) { case "0": if (isInitialKnockedIn) { this.trade.KIPayoffType = "1"; } break; case "1": case "2": break; case "3": this.trade.KIPayoffType = "1"; break; case "4": this.trade.KIPayoffType = "2"; break; default: this.trade.KIPayoffType = "0"; this.changeFieldState(); break; } if (isInitialKnockedIn) { return [{ value: '1', text: '敲入转看跌' }, { value: '2', text: '敲入转熊市价差' }]; } else { return [{ value: '0', text: '无' }, { value: '1', text: '敲入转看跌' }, { value: '2', text: '敲入转熊市价差' }]; } } else { switch (kiPayoffType) { case "0": if (isInitialKnockedIn) { this.trade.KIPayoffType = "3"; } break; case "3": case "4": break; case "1": this.trade.KIPayoffType = "3"; break; case "2": this.trade.KIPayoffType = "4"; break; default: this.trade.KIPayoffType = "0"; this.changeFieldState(); break; } if (isInitialKnockedIn) { return [{ value: '3', text: '敲入转看涨' }, { value: '4', text: '敲入转牛市价差' }]; } else { return [{ value: '0', text: '无' }, { value: '3', text: '敲入转看涨' }, { value: '4', text: '敲入转牛市价差' }]; } } }, //凤凰敲入到期支付类别 autocallKIPayoffTypeEnums() { let kiPayoffType = this.trade.KIPayoffType + ""; if (this.trade.OptionType === "看涨") { switch (kiPayoffType) { case "1": case "2": break; case "0": case "3": this.trade.KIPayoffType = "1"; break; case "4": this.trade.KIPayoffType = "2"; break; default: this.trade.KIPayoffType = "1"; this.changeFieldState(); break; } return [{ value: '1', text: '敲入转看跌' }, { value: '2', text: '敲入转熊市价差' }]; } else { switch (kiPayoffType) { case "3": case "4": break; case "0": case "1": this.trade.KIPayoffType = "3"; break; case "2": this.trade.KIPayoffType = "4"; break; default: this.trade.KIPayoffType = "3"; this.changeFieldState(); break; } return [{ value: '3', text: '敲入转看涨' }, { value: '4', text: '敲入转牛市价差' }]; } }, AccumulatorStructureTypeEnums() { return [{ value: '0', text: '标准' }, { value: '1', text: '三段式' }]; }, AccumulatorPayoffTypeEnums() { return [{ value: '浮动', text: '浮动' }, { value: '固定', text: '固定' }]; }, AccumulatorEarlyTerminateEnums() { return _.trim(this.trade.AccumulatorStructureType) && this.trade.AccumulatorStructureType.toString() == "1" ? [{ value: 'false', text: '否' }] : [{ value: 'false', text: '否' }, { value: 'true', text: '是' }]; }, AccumulatorIsFixedCouponEnums() { return [{ value: 'true', text: '否' }, { value: 'false', text: '是' }]; } } }; const tradePricing = {}; //tradeCalc,逻辑参见'交易数据互算' (function (global) { var _Precision = null; const consCalcReason = Object.freeze({ None: 0, SpotPrice: 1, Notional: 2, TradeAmount: 3, StockEqvNotional: 4, StockEqvNotionalReal: 5, TradePrice: 6, PremiumRate: 7, TradeSinglePrice: 8, Pv: 9, SpotPrice2: 11, TradeAmountV: 12, OriginalPrincipalSum: 13 }); function setPrecision(otcformat) { _Precision = { umprice: otcformat.umprice.precision, notional: otcformat.notional.precision, stockEqvNotional: otcformat.stockEqvNotional.precision, tradePrice: otcformat.tradePrice.precision, premiumRate: otcformat.premiumRate.precision, tradeSinglePrice: otcformat.tradeSinglePrice.precision }; } function tradeCalc(trade, reason, countRatio) { if (!trade) return; if (!_Precision) { if (!otcformat) throw 'missing otcformat'; setPrecision(otcformat.trading); } let isAutoCall = trade.TradeType === '雪球期权' || trade.TradeType === '凤凰期权'; let data = { reason: reason, countRatio: Math.abs(countRatio) || 1, spotPrice: Math.abs(trade.SpotPrice) || 0, principalRateWrite: trade.PrincipalRateWrite ? Math.abs(trade.PrincipalRateWrite) || 0 : 0, singlePrincipalWrite: trade.SinglePrincipalWrite ? Math.abs(trade.SinglePrincipalWrite) || 0 : 0, participationRate: _.trim(trade.ParticipationRate) ? Math.abs(trade.ParticipationRate) || 0 : 1, annualizeFactor: isAutoCall ? (trade.AnnualizeFactor2 ? Math.abs(trade.AnnualizeFactor2) || 0 : 1) : (trade.AnnualizeFactor ? Math.abs(trade.AnnualizeFactor) || 0 : 1), getAnnRate() { return isAutoCall ? this.participationRate : this.participationRate * this.annualizeFactor; }, //通过名义本金+期权费率计算权利金总额 getTradePriceByPremiumRate() { return tradeHelper.GetTradePriceByPremiumRate(trade.PremiumRate, trade.StockEqvNotional, this.participationRate , trade.OriginalPrincipalSum, isAutoCall ? 1 : this.annualizeFactor, trade.BuySell, trade.TradeType, true); }, //通过名义本金+期权单价计算权利金总额 getTradePriceBySinglePrice() { return tradeHelper.GetTradePriceBySinglePrice(trade.TradeSinglePrice, trade.StockEqvNotional, trade.Notional , trade.OriginalPrincipalSum, isAutoCall ? 1 : this.annualizeFactor, trade.BuySell, trade.TradeType, true); }, getNotionalEqv() { return isAutoCall ? trade.StockEqvNotional * this.participationRate : trade.StockEqvNotionalReal; }, //通过有效交易份额算交易数量 getTradeAmount(notional) { return _.round(notional / this.countRatio, 10); }, //通过有效交易份额算交易数量 getTradeAmountV(notional) { let annRate = this.getAnnRate(); return _.round((annRate ? notional / annRate : notional) / this.countRatio, _Precision.notional); } }; let instance = { data: data }; //期初标的价格(只受自身影响) instance.SpotPrice = function () { switch (data.reason) { case consCalcReason.SpotPrice: trade.SpotPrice = _.round(trade.SpotPrice, _Precision.umprice) || 0; data.spotPrice = Math.abs(trade.SpotPrice); break; case consCalcReason.SpotPrice2: data.reason = consCalcReason.SpotPrice; data.spotPrice = _.round(trade.SpotPrice, _Precision.umprice) || 0; data.spotPrice = Math.abs(data.spotPrice); break; } }; //交易份额/数量(受名义本金、期初价格影响) //特别说明:凤凰雪球的实际份额是非年化的,其他是年化折算后的 instance.Notional = function () { switch (data.reason) { case consCalcReason.Notional: trade.Notional = _.round(trade.Notional, _Precision.notional); trade.OriginalNotional = trade.Notional; trade.TradeAmount = data.getTradeAmount(trade.Notional); trade.TradeAmountV = data.getTradeAmountV(trade.Notional); break; case consCalcReason.TradeAmount: trade.TradeAmount = _.round(trade.TradeAmount, 10); trade.Notional = _.round(trade.TradeAmount * data.countRatio, 10); trade.OriginalNotional = trade.Notional; trade.TradeAmountV = data.getTradeAmountV(trade.Notional); break; case consCalcReason.TradeAmountV: trade.TradeAmountV = _.round(trade.TradeAmountV, _Precision.notional); trade.TradeAmount = _.round(trade.TradeAmountV * data.getAnnRate(), 10); trade.Notional = _.round(trade.TradeAmount * data.countRatio, 10); trade.OriginalNotional = trade.Notional; break; case consCalcReason.SpotPrice: //数量成交方式下数量是固定的,期初标的价格会导致名义本金变动 //名义本金成交方式下名义本金是固定的,期权标的价格的变动会导致交易份额变动 if (trade.IsUsePremiumRate) { let notional = data.spotPrice ? data.getNotionalEqv() / data.spotPrice : 0; trade.Notional = _.round(notional, _Precision.notional); trade.OriginalNotional = trade.Notional; trade.TradeAmount = data.getTradeAmount(trade.Notional); trade.TradeAmountV = data.getTradeAmountV(trade.Notional); } break; case consCalcReason.StockEqvNotional: { let notionalV = data.spotPrice ? trade.StockEqvNotional / data.spotPrice : 0; trade.Notional = _.round(notionalV * data.getAnnRate(), _Precision.notional); trade.OriginalNotional = trade.Notional; trade.TradeAmount = data.getTradeAmount(trade.Notional); trade.TradeAmountV = data.getTradeAmount(notionalV);//特殊使用 } break; case consCalcReason.StockEqvNotionalReal: { let eqv = trade.StockEqvNotionalReal; //凤凰雪球的交易份额非年化而有效名义本金年化所以需要膨胀 data.isAutoCall && data.annualizeFactor && (eqv /= data.annualizeFactor); let notional = data.spotPrice ? eqv / data.spotPrice : 0; trade.Notional = _.round(notional, _Precision.notional); trade.OriginalNotional = trade.Notional; trade.TradeAmount = data.getTradeAmount(trade.Notional); trade.TradeAmountV = data.getTradeAmountV(trade.Notional); } break; } }; //名义本金(受期初价格、数量/份额影响) //非名义本金变动原因,名义本金以有效名义本金为准 instance.StockEqvNotional = function () { let eqv = null, eqvReal = null; switch (data.reason) { case consCalcReason.Notional: if (isAutoCall) { eqv = data.participationRate ? trade.Notional * data.spotPrice / data.participationRate : 0; } else { eqvReal = trade.Notional * data.spotPrice; } break; case consCalcReason.TradeAmount: if (isAutoCall) { eqv = data.participationRate ? trade.TradeAmount * data.countRatio * data.spotPrice / data.participationRate : 0; } else { eqvReal = trade.TradeAmount * data.countRatio * data.spotPrice; } break; case consCalcReason.TradeAmountV: eqv = trade.TradeAmountV * data.countRatio * data.spotPrice; break; case consCalcReason.StockEqvNotional: eqv = trade.StockEqvNotional; break; case consCalcReason.StockEqvNotionalReal: eqvReal = trade.StockEqvNotionalReal; break; case consCalcReason.SpotPrice: //数量成交方式下数量是固定的,期初标的价格会导致名义本金变动 //名义本金成交方式下名义本金是固定的,期权标的价格的变动会导致交易份额变动 if (!trade.IsUsePremiumRate) { if (isAutoCall) { eqv = data.participationRate ? trade.Notional * data.spotPrice / data.participationRate : 0; } else { eqvReal = trade.Notional * data.spotPrice; } } break; } if (eqv !== null) { trade.StockEqvNotional = _.round(eqv, _Precision.stockEqvNotional); eqvReal = trade.StockEqvNotional * data.participationRate * data.annualizeFactor; trade.StockEqvNotionalReal = _.round(eqvReal, _Precision.stockEqvNotional); } else if (eqvReal !== null) { trade.StockEqvNotionalReal = _.round(eqvReal, _Precision.stockEqvNotional); let annParticipation = data.participationRate * data.annualizeFactor; eqv = annParticipation ? trade.StockEqvNotionalReal / annParticipation : 0; trade.StockEqvNotional = _.round(eqv, _Precision.stockEqvNotional); } }; //权利金费用(受期初价格、名义本金影响) instance.TradePrice = function () { switch (data.reason) { case consCalcReason.Notional: case consCalcReason.TradeAmount: case consCalcReason.TradeAmountV: case consCalcReason.StockEqvNotional: case consCalcReason.OriginalPrincipalSum: case consCalcReason.StockEqvNotionalReal: { let tradePrice = trade.IsUsePremiumRate ? data.getTradePriceByPremiumRate() : data.getTradePriceBySinglePrice(); return trade.TradePrice = _.round(tradePrice, _Precision.tradePrice); } case consCalcReason.TradePrice: { trade.TradePrice = _.round(trade.TradePrice, _Precision.tradePrice); let singlePrice = 0; let premiumRate = 0; if (trade.TradePrice > 0) { let tradePrice2 = (Math.abs(trade.TradePrice) || 0) - trade.OriginalPrincipalSum; if (tradePrice2 > 0) { singlePrice = trade.Notional ? tradePrice2 / trade.Notional : 0; let eqv = data.getNotionalEqv(); premiumRate = eqv ? tradePrice2 / eqv : 0; } } else { let tradePrice2 = (trade.TradePrice || 0) - trade.OriginalPrincipalSum * (trade.BuySell === "卖出" ? -1 : 1); singlePrice = trade.Notional ? tradePrice2 / trade.Notional : 0; let eqv = data.getNotionalEqv(); premiumRate = eqv ? tradePrice2 / eqv : 0; } trade.TradeSinglePrice = _.round(singlePrice, _Precision.tradeSinglePrice); trade.PremiumRate = _.round(premiumRate, _Precision.premiumRate); } return; case consCalcReason.Pv: { let singlePrice = 0; let premiumRate = 0; let tradePrice2 = (trade.TradePrice) || 0; singlePrice = trade.Notional ? tradePrice2 / trade.Notional : 0; premiumRate = data.spotPrice ? singlePrice / data.spotPrice : 0; trade.TradeSinglePrice = _.round(singlePrice, _Precision.tradeSinglePrice); trade.PremiumRate = _.round(premiumRate, _Precision.premiumRate); trade.TradePrice = _.round(tradePrice2 + trade.OriginalPrincipalSum, _Precision.tradePrice); } return; case consCalcReason.SpotPrice: if (trade.IsUsePremiumRate) { let singlePrice = trade.PremiumRate * data.spotPrice; trade.TradeSinglePrice = _.round(singlePrice, _Precision.tradeSinglePrice); let tradePrice = data.getTradePriceByPremiumRate(); trade.TradePrice = _.round(tradePrice, _Precision.tradePrice); } else { let premiumRate = data.spotPrice ? trade.TradeSinglePrice / data.spotPrice : 0; trade.PremiumRate = _.round(premiumRate, _Precision.premiumRate); let tradePrice = data.getTradePriceBySinglePrice(); trade.TradePrice = _.round(tradePrice, _Precision.tradePrice); } return; case consCalcReason.PremiumRate: { trade.PremiumRate = _.round(trade.PremiumRate, _Precision.premiumRate); let singlePrice = trade.PremiumRate * data.spotPrice; trade.TradeSinglePrice = _.round(singlePrice, _Precision.tradeSinglePrice); let tradePrice = data.getTradePriceByPremiumRate(); trade.TradePrice = _.round(tradePrice, _Precision.tradePrice); } return; case consCalcReason.TradeSinglePrice: { trade.TradeSinglePrice = _.round(trade.TradeSinglePrice, _Precision.tradeSinglePrice); let premiumRate = data.spotPrice ? trade.TradeSinglePrice / data.spotPrice : 0; trade.PremiumRate = _.round(premiumRate, _Precision.premiumRate); let tradePrice = trade.IsUsePremiumRate ? data.getTradePriceByPremiumRate() : data.getTradePriceBySinglePrice(); trade.TradePrice = _.round(tradePrice, _Precision.tradePrice); } return; } }; instance.OriginalPrincipalSum = function () { switch (data.reason) { case consCalcReason.TradeAmountV: trade.OriginalPrincipalSum = _.round(trade.TradeAmount * data.singlePrincipalWrite * countRatio, _Precision.tradePrice); trade.PrincipalRateWrite = trade.OriginalPrincipalSum / (trade.StockEqvNotional * (isAutoCall ? 1 : data.annualizeFactor)); break; case consCalcReason.StockEqvNotional: trade.OriginalPrincipalSum = _.round(trade.StockEqvNotionalReal * data.principalRateWrite * (isAutoCall ? 1 : data.annualizeFactor), _Precision.tradePrice); trade.SinglePrincipalWrite = trade.TradeAmount === 0 ? 0 : trade.OriginalPrincipalSum / trade.TradeAmount; break; } }; instance.CalcFns = (function () { switch (reason) { case consCalcReason.SpotPrice: case consCalcReason.SpotPrice2: return [this.SpotPrice].concat(trade.IsUsePremiumRate ? [this.Notional] : [this.StockEqvNotional, this.OriginalPrincipalSum, this.TradePrice]); case consCalcReason.Notional: case consCalcReason.TradeAmount: case consCalcReason.TradeAmountV: return [this.Notional, this.StockEqvNotional, this.OriginalPrincipalSum, this.TradePrice]; case consCalcReason.StockEqvNotional: case consCalcReason.StockEqvNotionalReal: return [this.StockEqvNotional, this.Notional, this.OriginalPrincipalSum, this.TradePrice]; case consCalcReason.TradePrice: case consCalcReason.Pv: case consCalcReason.PremiumRate: case consCalcReason.OriginalPrincipalSum: case consCalcReason.TradeSinglePrice: return [this.TradePrice]; default: return []; } }.call(instance)); instance.Execute = function () { this.CalcFns.forEach(x => x()); }; return instance; } tradePricing.calcReason = consCalcReason; //reason:consCalcReason tradePricing.tradeCalc = function (trade, reason, countRatio) { new tradeCalc(trade, reason, countRatio).Execute(); }; tradePricing.tradeCalc.setPrecision = function (otcformat) { otcformat && setPrecision(otcformat); }; }(window.tradePricing));