diff --git a/YLErpWeb/Views/trade/TradeEditV2.cshtml b/YLErpWeb/Views/trade/TradeEditV2.cshtml index f0ecffcf..5fad2564 100644 --- a/YLErpWeb/Views/trade/TradeEditV2.cshtml +++ b/YLErpWeb/Views/trade/TradeEditV2.cshtml @@ -93,14 +93,7 @@ - @if (PS.Config.Is润和) - { - - } - else - { - - } + diff --git a/YLErpWeb/wwwroot/Scripts/app/pricing/structure_dz.js b/YLErpWeb/wwwroot/Scripts/app/pricing/structure_dz.js deleted file mode 100644 index 6fdc2192..00000000 --- a/YLErpWeb/wwwroot/Scripts/app/pricing/structure_dz.js +++ /dev/null @@ -1,2663 +0,0 @@ -//客户选择组件 -const vueClient = function () { - return { - props: ['value'], - data() { - return { current: { id: 0, Name: '' } }; - }, - mounted() { - var self = this; - var id = parseInt(this.value); - if (id) { - this.current = _.clone(ylotc.clients.find(x => x.id === id)); - } - var width = 152; - for (var i = 0; i < ylotc.clients.length; i++) { - let ele = document.createElement('span') - ele.innerText = ylotc.clients[i].Name; - ele.style.fontSize = '14px'; - document.documentElement.append(ele); - var charLength = ele.offsetWidth + 28;//滚动条 - document.documentElement.removeChild(ele); - if (charLength > width) { - width = charLength - } - } - FastVue.autocomplete(this.$el, { - valueField: 'Name', searchField: ['Name', 'PinYin'], lookup: ylotc.clients, width: width, - onSelect(data) { - self.current = _.clone(data); - if (self.value !== data.id) { - self.value = data.id; - self.$emit('input', self.value); - } - $(self.$el).blur(); - } - }); - }, - watch: { - value(val, old) { - if (val !== old) { - var id = parseInt(val); - if (id !== this.current.id) { - this.current = _.clone(ylotc.clients.find(x => x.id === id) || { id: 0, Name: '' }); - } - $(this.$el).data('select', '').attr("placeholder", ''); - } - } - }, - destroyed() { - FastVue.autocomplete.dispose(this.$el); - }, - template: '' - }; -}; - -//品种选择组件 -const vueVariety = function () { - return { - props: ['variety'], - mounted() { - var self = this; - FastVue.autocomplete(this.$el, { - valueField: 'Name', searchField: ['Name', 'Code', 'PinYin'], - lookup: ylotc.varieties, - onSelect(data) { - if (self.variety !== data) { - self.$emit('change-variety', data); - } - } - }); - }, - destroyed() { - FastVue.autocomplete.dispose(this.$el); - }, - template: '' - }; -}; - -//期权类型选择组件 -const vueTradeType = function () { - return { - props: ['value'], - mounted() { - var self = this; - FastVue.autocomplete(this.$el, { - valueField: 'value', searchField: ['value', 'pinyin'], - lookup: optionTradeTypes, - onSelect(data) { - if (self.value !== data.value) { - self.value = data.value; - self.$emit('input', self.value); - } - } - }); - this.$el.value = this.value || ''; - }, - watch: { - value(val, old) { - if (val !== old) { - $(this.$el).val(this.value).data('select', '').attr("placeholder", ''); - } - } - }, - destroyed() { - FastVue.autocomplete.dispose(this.$el); - }, - template: '' - }; -}; - -//标的选择组件(EQD-7049:改为服务端搜索,不再依赖全量 ylotc.underlyings,避免十几万标的整段下载卡死) -//标的选择组件(EQD-7049:改为服务端搜索,不再依赖全量 ylotc.underlyings,避免十几万标的整段下载卡死) -const vueUnderlying = function () { - const _suggestionTpl = _.template($('#underlyingSuggestionTpl').html()); - // 标的缓存(同品种各实例共享):_cache 为最近一次服务端结果,_fresh 记录其对应的 品种|关键词, - // _seq 单调递增丢弃乱序/过期响应,_inflight 防同关键词重复请求(helper 收在函数内,避免全局绑定冲突) - const _cache = {}; - const _fresh = {}; - const _seq = {}; - const _inflight = {}; - function _fetch(varietyId, query, cb) { - var vid = varietyId || 0; - var q = query || ''; - var key = vid + '|' + q; - if (_inflight[key]) return; - var seq = (_seq[vid] = (_seq[vid] || 0) + 1); - _inflight[key] = true; - var postData = { - FilterCode: q.toUpperCase(), - VarietyId: vid, - MaxShowLength: 20, - BlackLimit: 1, - UseForTrading: true, - IncludeMatured: true, - CheckLaunch: true - }; - main.post('/frontdata/AjaxGetUnderlyingSelect', postData).done(function (res) { - delete _inflight[key]; - if (_seq[vid] !== seq) return; // 已有更新的关键词发起请求,丢弃本响应 - var arr = (res && (res.obj || res.data)) || []; - var norm = arr.map(function (x) { - return { - Code: x.Code, - Name: x.Name, - InstrumentType: x.InstrumentType, - VarietyId: x.VarietyId, - Disallow: !!x.Disallow, - IsCombined: !!x.IsSynthetic || !!x.IsBasket, - BlackWhiteState: x.BlackWhiteState || 0, - PinYin: x.PinYin || '' - }; - }); - _cache[vid] = norm; - _fresh[vid] = key; - cb && cb(norm, q); - }).fail(function () { - delete _inflight[key]; - }); - } - function _filter(list, query, varietyId) { - if (!query) return (list || []).slice(0, 20); - query = query.toUpperCase(); - return (list || []).filter(function (x) { - if (varietyId && x.VarietyId !== varietyId) return false; - if (x.IsCombined) return false; // 与原逻辑一致:搜索时排除组合标的 - return (x.Code && x.Code.toUpperCase().indexOf(query) !== -1) - || (x.PinYin && x.PinYin.toUpperCase().indexOf(query) !== -1); - }).slice(0, 20); - } - return { - props: ['underlying'], - data() { - return { jqInput: null, autoctrl: null }; - }, - mounted() { - var self = this; - this.jqInput = $(this.$el).children(0); - // EQD-7049:预拉默认20条(当前品种),获得焦点时由插件自身的 onValueChange 呈现 - _fetch(self.underlying.VarietyId, ''); - this.autoctrl = FastVue.autocomplete(this.jqInput, { - valueField: 'Code', - lookup(query) { - var varietyId = self.underlying.VarietyId; - var vid = varietyId || 0; - var key = vid + '|' + (query || ''); - if (_fresh[vid] === key) { - // 命中当前关键词的服务端结果:直接展示(服务端已按 StartsWith+品种/黑名单过滤,不再前端二次过滤) - return (_cache[vid] || []).slice(0, 20); - } - // 异步搜索。FastVue 包装的 lookup 只同步取返回值渲染,服务端结果到达后必须重新触发 - // onValueChange 才会显示;重走 lookup 时命中上面的 _fresh 分支直接返回,不会循环请求 - _fetch(varietyId, query, function (list, q) { - var inst = self.jqInput.autocomplete(); - if (!inst || !inst.visible) return; // 下拉已关闭:留待下次获得焦点时呈现 - if ((self.jqInput.val() || '').toLowerCase() !== q.toLowerCase()) return; // 输入已变化:等新关键词的响应 - inst.onValueChange(); - }); - // 过渡兜底:服务端响应到达前用旧缓存按关键词过滤,避免搜索期间下拉空白 - return _filter(_cache[vid] || [], query, varietyId); - }, - onSelect(data) { - if (self.underlying !== data) { - self.$emit('change-underlying', data); - } - self.jqInput.blur(); - }, - formatResult(suggestion, currentValue) { - return _suggestionTpl(suggestion.data); - } - }); - this.jqInput.val(this.underlying.Code); - }, - methods: { - showInput() { - this.jqInput.show().focus().next().hide(); - }, - hideInput() { - this.jqInput.hide().next().show(); - } - }, - computed: { - showName() { - return (this.underlying.InstrumentType === 'Stock' || this.underlying.InstrumentType === 'StockIndex') ? this.underlying.Name : ' '; - } - }, - destroyed() { - FastVue.autocomplete.dispose(this.jqInput); - }, - template: '
' + - '{{underlying.Code}}{{showName}}
' - }; -}; - -//预付金模板 -const vueMarginTemplateName = function () { - return { - props: ['value'], - data() { - return { autoCtrl: null }; - }, - mounted() { - var self = this; - this.autoctrl = FastVue.autocomplete(this.$el, { - valueField: 'Value', - searchField: ['Value'], - lookup: ylotc.tradeMarginTemplateItems, - onSelect(data) { - if (self.value !== data.Value) { - self.value = data.Value; - self.$emit('input', self.value); - } - } - }); - value = self.value || "系统默认"; - this.autoctrl.setData({ Text: value, Value: value }) - }, - watch: { - value(newVal, oldVal) { - if (newVal !== oldVal) { - let data = ylotc.tradeMarginTemplateItems.find(x => x.Value === newVal); - this.autoctrl.setData(data || { Text: "系统默认", Value: "系统默认" }) - } - } - }, - destroyed() { - FastVue.autocomplete.dispose(this.$el); - }, - template: '' - }; -} - -//计算结果字段 -const consCalcFields = Object.freeze(['TotalTradePrice', 'TotalDay1Pnl', 'TotalMargin', 'Pv', 'Delta', 'GammaCash', 'Vega', 'Theta', 'Rho']); - -var _trades, _tradeVues, _salesCommissionCtrl; -//交易保存 -const tradeSaver = (function () { - const needClient = !pageVue.ClientUsedForCalc; - - function showTradeView(items) { - let item = items.shift(); - if (!item) return; - let url = "/trade/tradeview?abstract=1&enid=" + item.EncryptId; - main.open("查看交易", url, { - end: function () { - showTradeView(items); - } - }); - } - - //保存 - function _save() { - if (!_trades) return; - let AssetId = parseInt($('#AssetId').data('id')); - let TraderId = parseInt($('#TraderId').data('id')); - let ClientId = parseInt($('#ClientId').data('id')); - if (!AssetId) { - return main.alert("未设置簿记账户"); - } - if (!TraderId) { - return main.alert("未设置交易员"); - } - if (needClient && !ClientId) { - return main.alert("未设置客户"); - } - let TradeNumber = $('#TradeNumber').val(); - let AssetBookName = $('#AssetId').val(); - let TraderName = $('#TraderId').val(); - let ClientName = $('#ClientId').val(); - let TradingPlace = $("#TradingPlace").val(); - let ClearingAgency = $("#ClearingAgency").val(); - let MainProtocolCode = $("#MainProtocolCode").val(); - let SupProtocolCode = $("#SupProtocolCode").val(); - let OpponentRole = $("#OpponentRole").val(); - let InitialAdvance = parseFloat($("#InitialAdvance").val()) || 0; - let PeriodAdvance = parseFloat($("#PeriodAdvance").val()) || 0; - let FontEarning = parseFloat($("#FontEarning").val()) || 0; - let ConfirmedLine = parseFloat($("#ConfirmedLine").val()) || 0; - let ConfirmedFloor = parseFloat($("#ConfirmedFloor").val()) || 0; - - let IsCentralClearing = $("#IsCentralClearing").val(); - let CentralClearingPaltform = $("#CentralClearingPaltform").val(); - let TradingPaltform = $("#TradingPaltform").val(); - let QuoteCurrency = $("#QuoteCurrency").val(); - - let salesCommission = _salesCommissionCtrl.getValue(); - _trades.forEach(x => { - x.AssetId = AssetId; - x.AssetBookName = AssetBookName; - x.TraderId = TraderId; - x.TraderName = TraderName; - x.TradeNumber = TradeNumber; - x.SalesCommission = salesCommission; - if (needClient) { - x.ClientId = ClientId; - x.ClientName = ClientName; - } - if (x.TradePremium) { - x.MetaDic["交易溢价"] = x.TradePremium; - } - x.MetaDic["交易场所"] = TradingPlace; - x.MetaDic["清算机构"] = ClearingAgency; - x.MetaDic["主协议编号"] = MainProtocolCode; - x.MetaDic["补充协议编号"] = SupProtocolCode; - - x.MetaDic["中央对手方清算"] = IsCentralClearing; - x.MetaDic["中央清算平台"] = CentralClearingPaltform; - x.MetaDic["交易平台"] = TradingPaltform; - - if (pageData.showCCR) { - //if (x.MarginType == 0) { - x.MetaDic["ccr_k"] = x.ccr_k || "0"; - //} - x.MetaDic["ignoreRiskExposure"] = x.ignoreRiskExposure || "0"; - } - x.TradeType === '现金流交易' && tradeUtils.resetCashFlow(x); - x.OpponentRole = OpponentRole; - x.QuoteCurrency = QuoteCurrency; - x.InitialAdvance = InitialAdvance; - x.PeriodAdvance = PeriodAdvance; - x.FontEarning = FontEarning; - x.ConfirmedLine = ConfirmedLine; - x.ConfirmedFloor = ConfirmedFloor; - x.IsUsePremiumRate = (x.IsUsePremiumRate == "" || x.IsUsePremiumRate == null) ? false : x.IsUsePremiumRate; - }); - main.post("/pricing/AjaxSaveTrades", { trades: _trades }).done(function (resp) { - if (pageVue.IsImport) { - let url = "#/trade/tradeview?abstract=1&enid=" + resp.obj[0].EncryptId; - layer.closeMe(url);//必须以#开头 - } else { - floatVue.hide(); - $('#modalTradeSave').modal('hide'); - showTradeView(resp.obj); - _.each(_tradeVues, x => x.remove(true)); - } - }); - } - - //保存 - function _saveTrades(tradeVues) { - _tradeVues = tradeVues; - if (!Array.isArray(_tradeVues)) { - throw "参数错误:tradeVues"; - } - if (!_tradeVues.length) { - return main.alert("请至少勾选一条交易"); - } - - _trades = _.flatMap(_tradeVues, x => x.datas).map(x => { - x.viewState.synthetic && (x.trade.MetaDic["组合标的"] = JSON.stringify(x.viewState.synthetic)); - return x.trade; - }); - _trades = tradeUtils.prepareTrades(_trades, pageVue.getVolType(), true); - if (_trades) { - $('#TradeNumber').val('').parent().toggle(_tradeVues.length === 1); - $('#modalTradeSave').modal('show'); - _setSalesman(); - if (pageVue.SecuritiesEnvironment && !pageVue.ClientUsedForCalc) { - var clientId = parseInt($('#ClientId').data('id')) || _trades[0].ClientId; - _getMainProtocolCode(clientId); - } - return true; - } - return false; - } - - function _setAutocomplete(elId, datas, initData, onSelectFn, width) { - initData = initData || datas[0] || {}; - FastVue.autocomplete(document.getElementById(elId), { - valueField: 'Name', searchField: ['Name', 'PinYin'], lookup: datas, width: width, - onSelect(data) { - $('#' + elId).data('id', data.id); - if (elId === "ClientId") { - if (!pageVue.ClientUsedForCalc) { - $("#IsCentralClearing").val(data.IsCentralClearing); - $("#CentralClearingPaltform").val(data.CentralClearingPaltform); - $("#TradingPaltform").val(data.TradingPaltform); - } - _setSalesman(); - } - onSelectFn && onSelectFn(data); - }, - zIndex: 300000 - }).setData(initData); - $('#' + elId).data('id', initData.id); - } - //保存组合交易 - function _saveGroupTrades(tradeVues) { - _tradeVues = tradeVues; - if (!Array.isArray(_tradeVues)) { - throw "参数错误:tradeVues"; - } - if (!_tradeVues.length) { - return main.alert("请至少勾选一条交易"); - } - - _trades = _.flatMap(_tradeVues, x => x.datas).map(x => { - x.viewState.synthetic && (x.trade.MetaDic["组合标的"] = JSON.stringify(x.viewState.synthetic)); - return x.trade; - }); - - var viewStates = _.flatMap(_tradeVues, x => x.datas).map(x => x.viewState).filter(x => x.variety && x.variety.Code); - - //验证分组交易是否是同标的同期初价格 - var underlyingId = 0; - var hasDiffUnderlying = false; - var spotPrice = 0; - var hasDiffPrice = false; - var tradeDate = null; - var exerciseDate = null; - var hasDiffTradeDate = false; - var buySell = groupVue.trade.BuySell; - var tradePrice = 0; - _trades.forEach(x => { - if (x.TradeType != "现金流交易") { - if (underlyingId && underlyingId != x.UnderlyingId) { - hasDiffUnderlying = true; - } - else { - underlyingId = x.UnderlyingId; - } - - if (spotPrice && parseFloat(spotPrice) != parseFloat(x.SpotPrice)) { - hasDiffPrice = true; - } - else { - spotPrice = x.SpotPrice; - } - - if (!buySell) { - buySell = x.BuySell; - } - } - - tradePrice += x.TradePrice * (x.BuySell == "卖出" ? 1 : -1); - - if (tradeDate != null && tradeDate != x.TradeDate) { - hasDiffTradeDate = true; - } - else { - tradeDate = x.TradeDate; - } - - if (exerciseDate == null || exerciseDate < x.ExerciseDate) { - exerciseDate = x.ExerciseDate; - } - }); - if (hasDiffUnderlying) { - main.alert("分组交易必须要保持相同的标的"); - return false; - } - if (hasDiffPrice) { - main.alert("分组交易必须要保持相同的期初价格"); - return false; - } - if (hasDiffTradeDate) { - main.alert("分组交易必须要保持相同的交易日期"); - return false; - } - - _trades = tradeUtils.prepareTrades(_trades, pageVue.getVolType(), true); - if (_trades) { - $('#TradeNumber').val('').parent().toggle(_tradeVues.length === 1); - groupVue.viewState = viewStates[0]; - groupVue.trade.TradeDate = tradeDate; - groupVue.trade.ExerciseDate = exerciseDate; - groupVue.trade.BuySell = buySell; - if (groupVue.trade.IsUsePremiumRate == null) { - groupVue.trade.IsUsePremiumRate = true - } - if (groupVue.trade.IsMoneynessOption == null) { - groupVue.trade.IsMoneynessOption = "是"; - } - groupVue.trade.IsTradePricePayType = true; - groupVue.trade.TradePrice = tradePrice * (buySell == "卖出" ? 1 : -1); - groupVue.changeIsUsePremiumRate(); - groupVue.trade.SpotPrice = spotPrice; - if (!groupVue.trade.StructureType) { - groupVue.trade.StructureType = "气囊结构"; - groupVue.trade.OptionType = "看涨"; - groupVue.trade.trade_airbag.Barrier = 0.8; - groupVue.trade.Strike = 1; - groupVue.trade.trade_airbag.NotKIParticipationRate = 1; - groupVue.trade.trade_airbag.KIParticipationRate = 1; - } - - - let stockEqvNotionalArrs = _trades.map((value, index, array) => { - return value.StockEqvNotional - }); - groupVue.trade.StockEqvNotional = Math.max(...stockEqvNotionalArrs); - groupVue.changeStockEqvNotional(); - $('#modalGroupTradeSave').modal('show'); - _setSalesman(); - return true; - } - return false; - } - - return { - saveTrades: _saveTrades, - saveGroupTrades: _saveGroupTrades, - init() { - _setAutocomplete('AssetId', ylotc.assetunits); - if (pageVue.CanSelectTrader) { - let trader = pageVue.Trade.TraderName ? ylotc.traders.find(x => x.Name === pageVue.Trade.TraderName) : null; - if (!trader) { - trader = { Name: "" } - } - _setAutocomplete('TraderId', ylotc.traders, { Name: trader.Name }); - } - if (!pageVue.ClientUsedForCalc) { - var width = 300; - for (var i = 0; i < ylotc.clients.length; i++) { - let ele = document.createElement('span') - ele.innerText = ylotc.clients[i].Name; - ele.style.fontSize = '14px'; - document.documentElement.append(ele); - var charLength = ele.offsetWidth + 28;//滚动条 - document.documentElement.removeChild(ele); - if (charLength > width) { - width = charLength - } - } - _setAutocomplete('ClientId', ylotc.clients, null, (pageVue.SecuritiesEnvironment ? _getMainProtocolCode : null), width); - } - - //组合标的控件 - synthenticPriceCtrl.init({ - getSynthetic(input) { - return consSyntheticMap[input.dataset.calcid]; - }, - setSynthetic(input, synthetic) { - var calcid = input.dataset.calcid; - _.each(pricingVue.getTradeVues(), x => !x.updateSynthetic(calcid, synthetic)); - } - }); - - //销售提成控件 - _salesCommissionCtrl = new SalesCommissionCtrl(document.getElementById('salesCommissionCtrl'), pageVue.SalesCommission); - - _setSalesman(); - - $('#btnSave').on('click', _save); - - $('#MainProtocolCode').on('change', _changeMainProtocolCode); - - $('#modalTradeSave').on('show.bs.modal', function () { - $('#TradeNumber').val(''); - _salesCommissionCtrl.reset(); - }); - } - }; -}()); - -//截图 -const screenshoter = (function () { - - var _layerIndex; - - function execute(tradeVue) { - - if (tradeVue == null) { - return; - } - - if (!tradeVue.floating) { - floatVue.show(tradeVue, true); - } - - var opts = { bgcolor: '#fff', width: tradeVue.datas.length * 200 + 140 }; - - var $fs = $('#for-screenshot'); - $fs.parent().children().addClass('for-screenshot'); - $fs.closest('.modal').css('margin-top', -999999); - - domtoimage.toPng($fs[0], opts).then(function (dataUrl) { - $('#screenshot-img').attr('src', dataUrl); - _layerIndex = layer.open({ - type: 1, closeBtn: 0, title: false, scrollbar: false, shadeClose: true, - area: ['auto', '50%'], content: $('#screenshot'), offset: '100px', - success: function (layero, index) { - setTimeout(function () { - let height = $('#screenshot-img').height(); - height > 100 && layero.children('.layui-layer-content').css('height', height + 100); - }, 100); - } - }); - try { - //chrome 定价页面生成截图时自动复制 - const blobInput = convertBase64ToBlob(dataUrl.replace("data:image/png;base64,", ""), 'image/png'); - const clipboardItemInput = new ClipboardItem({ 'image/png': blobInput }); - navigator.clipboard.write([clipboardItemInput]); - } - catch (e) { } - }).catch(function (error) { - main.alert('截图发生错误:' + error); - }).finally(function () { - $fs.closest('.modal').css('margin-top', 0); - $fs.parent().children().removeClass('for-screenshot'); - if (!tradeVue.floating) { - $('#floatModal').modal('hide'); - } - }); - } - - function closeShow() { - layer.close(_layerIndex); - } - - //保存截图 - function download() { - domtoimage.toBlob(document.getElementById('screenshot-img')) - .then(function (blob) { - moment().format(); - window.saveAs(blob, '报价' + moment().format('YYYYMMDDHHmmss') + '.png'); - }); - } - - return { - execute: execute, - download: download, - closeShow: closeShow - }; -}()); - -function convertBase64ToBlob(base64, type) { - var bytes = window.atob(base64); - var ab = new ArrayBuffer(bytes.length); - var ia = new Uint8Array(ab); - for (var i = 0; i < bytes.length; i++) { - ia[i] = bytes.charCodeAt(i); - } - return new Blob([ab], { type: type }); -} - -//#singleprice -const singlePricer = (function () { - - const _sumDatas = []; - - //datas:[{Pv,Notional}] - function _calcSinglePrice(datas) { - var result = _.reduce(datas, (acc, data) => { - if (Array.isArray(data)) { - _.each(data, item => { - acc.totalPv += parseFloat(item.Pv) || 0; - var notional = parseFloat(item.Notional) || 0; - if (acc.minNotional > notional) { - acc.minNotional = notional; - } - }); - } else if (data) { - acc.totalPv += parseFloat(data.Pv) || 0; - var notional = parseFloat(data.Notional) || 0; - if (acc.minNotional > notional) { - acc.minNotional = notional; - } - } - return acc; - }, { totalPv: 0, minNotional: Number.MAX_SAFE_INTEGER }); - var singlePrice = Math.abs(result.minNotional) < 1e-5 ? "0.00" - : pricingFormat.tradeSinglePrice(Math.abs(result.totalPv) / result.minNotional); - return pageVue.CompanyName + (result.totalPv >= 0 ? "付" : "收") + singlePrice; - } - - //重设统计单价 - function _reset() { - var singlePrice = _calcSinglePrice(_sumDatas); - $('#singleprice').text(singlePrice); - } - - const _debounceReset = _.debounce(_reset, 300); - - return { - //data:[{Pv,Notional}] - reset(index, data) { - _sumDatas[index] = !data || Array.isArray(data) ? data : [data]; - _debounceReset(); - }, - //datas:[{Pv,Notional}] - calcSinglePrice: _calcSinglePrice - }; -}()); - -//pageVue状态 -(function () { - - const viewState = { VolType: '交易', structureType: '' }; - - _.extend(pageVue, { - viewState: viewState, - getVolType() { return viewState.VolType; }, - setVolType(value) { viewState.VolType = value; }, - getStructureType() { return viewState.structureType; }, - setStructureType(value) { viewState.structureType = value; } - }); - - //冻结修改 - _.each([pageVue], x => Object.freeze(x)); -}()); - -//一个简单的事件总线 -const EventBus = (new function () { - - var _bus; - - function getBus() { - return _bus || (_bus = document.createElement('div')); - } - - //增加事件监听 - this.addEventListener = function (event, callback) { - getBus().addEventListener(event, callback); - }; - - //移除事件监听 - this.removeEventListener = function (event, callback) { - getBus().removeEventListener(event, callback); - }; - - //激发事件 - this.triggerEvent = function (event, detail = {}) { - getBus().dispatchEvent(new CustomEvent(event, { detail })); - }; - - //仅供调试用 - this.getEventListeners = function () { - return getEventListeners(getBus()); - }; -}()) - -//顶部组件 -const topVue = (function () { - return new Vue({ - el: '#pricing-top', - data: { - viewState: pageVue.viewState, - simpleMode: pageVue.SimpleMode, - calcMargin: pageVue.CalcMargin && pageVue.ShowInitialMargin, - calcAutocallGreeks: pageVue.CalcAutocallGreeks, - }, - mounted() { - - }, - methods: { - changeVolType() { - pricingVue.changeVolType(); - }, - addStructure(type, typeCn) { - pageVue.setStructureType(typeCn); - var url = "/trade/structureoptionV2?name=" + type; - main.open("添加策略", url, { area: ['500px', '800px'] }); - }, - normOtcTrade(td) { - td.PremiumPayDate = ''; - td.Notional = pricingFormat.notional(td.Notional); - td.TradeAmount = pricingFormat.notional(td.TradeAmount); - td.TradePrice = pricingFormat.tradePrice(td.TradePrice); - td.Day1Pnl = pricingFormat.tradePrice(td.Day1Pnl); - td.StockEqvNotional = pricingFormat.StockEqvNotional(td.StockEqvNotional); - td.StockEqvNotionalReal = pricingFormat.StockEqvNotional(td.StockEqvNotionalReal); - tradeUtils.normalizeTrade(td); - return td; - }, - importTrade() { - let tradeNumber = $('#importTradeNumber').val().trim(); - if (!tradeNumber) return; - var self = this; - main.post('/pricing/AjaxGetOtcTradeFull?tradeNumber=' + encodeURIComponent(tradeNumber)).done(function (resp) { - if (resp.obj) { - pricingVue.addTrade(self.normOtcTrade(resp.obj)); - } else { - main.alert('没有找到交易数据'); - } - }).always(function () { - - }); - }, - toggleSimpleMode() { - this.simpleMode = !this.simpleMode; - EventBus.triggerEvent('simpleMode.changed'); - main.post("/sysuserConfig/AjaxSaveOtcWebConfig", { name: 'Pricing_SimpleMode', value: this.simpleMode }, false); - }, - toggleCalcMargin() { - this.calcMargin = !this.calcMargin; - main.post("/sysuserConfig/AjaxSaveOtcWebConfig", { name: 'Pricing_CalcMargin', value: this.calcMargin }, false); - }, - toggleCalcAutocallGreeks() { - this.calcAutocallGreeks = !this.calcAutocallGreeks; - main.post("/sysuserConfig/AjaxSaveOtcWebConfig", { name: 'Pricing_CalcAutocallGreeks', value: this.calcAutocallGreeks }, false); - } - } - }) -}()); - -//统计组件 -const summaryVue = (function () { - - const _summaryDatas = []; - - const summary = _.reduce(consCalcFields, (acc, cur) => { - acc[cur] = 0; - return acc; - }, {}); - - //重设统计合计 - function _resetSummary() { - var datas = _.flatMap(_summaryDatas, x => x && x.length > 0 ? x : []); - var UnderlyingCode = ''; - var isSameCode = _.every(datas, x => { - return UnderlyingCode ? x.UnderlyingCode === UnderlyingCode : UnderlyingCode = x.UnderlyingCode; - }); - if (isSameCode) { - _.each(summary, (val, key) => { - summary[key] = 0; - }); - _.each(datas, data => - _.each(consCalcFields, field => summary[field] += parseFloat(data[field]) || 0) - ); - } else { - _.each(summary, (val, key) => { - summary[key] = 'NaN'; - }); - summary.Pv = summary.TotalMargin = summary.TotalTradePrice = summary.TotalDay1Pnl = summary.Rho = 0; - _.each(datas, data => { - summary.Pv += parseFloat(data.Pv) || 0; - summary.Rho += parseFloat(data.Rho) || 0; - summary.TotalMargin += parseFloat(data.TotalMargin) || 0; - summary.TotalTradePrice += parseFloat(data.TotalTradePrice) || 0; - summary.TotalDay1Pnl += parseFloat(data.TotalDay1Pnl) || 0; - }); - } - if (!pageVue.TwoSideMargin) { - //如果为负数,则显示0 - summary.TotalMargin < 0 && (summary.TotalMargin = 0); - } - } - - const _debounceReset = _.debounce(_resetSummary, 300); - - const _vue = new Vue({ - el: '#pricing-summary', - data: { - summary: summary - }, - computed: { - DeltaHands() { - var delta = this.summary.DeltaInLots; - return typeof delta !== 'number' ? delta - : (delta > 0 ? "卖" : "买") + pricingFormat.greek(Math.abs(delta)) + '手'; - } - }, - filter: { - greekFmt(val) { - return typeof val !== 'number' ? val : pricingFormat.greek(val); - } - } - }); - - return { - getVue() { - return _vue; - }, - //data:consCalcFields - reset(index, data) { - _summaryDatas[index] = !data || Array.isArray(data) ? data : [data]; - _debounceReset(); - } - }; -}()); - -//视图呈现器 -const renders = (function () { - - function _getHtml($tpl, removeClass) { - var html = $tpl.html(); - var $temp = $('
').append(html); - $temp.find(removeClass).remove(); - $temp.find('template').each(function () { - html = _getHtml($(this), removeClass); - $(this).html(html); - }); - return $temp.html(); - } - - //定价视图呈现器 - const title = Vue.compile(_getHtml($('#pricingItem_tpl'), '.pitem,.pitem-cash')); - const item = Vue.compile(_getHtml($('#pricingItem_tpl'), '.ptitle,.pitem-cash:not(.pitem)')); - const itemCash = Vue.compile(_getHtml($('#pricingItem_tpl'), '.ptitle,.pitem:not(.pitem-cash)')); - const items = Vue.compile($('#pricingItems_tpl').html() || ''); - - return { - title(forStatic) { - return forStatic ? title.staticRenderFns : title.render; - }, - item(forStatic) { - return forStatic ? item.staticRenderFns : item.render; - }, - itemCash(forStatic) { - return forStatic ? itemCash.staticRenderFns : itemCash.render; - }, - items(forStatic) { - return forStatic ? items.staticRenderFns : items.render; - } - }; -}()); - -//单个定价组件 -const vueTrade = function () { - return { - props: ['trade', 'viewState', 'calcResult', 'floating'], - data() { - return { - isTitle: false, - canEditEngineName: true, - ...consVueTrade.data(), - fieldState: tradeFieldMgr.getFieldState(this.floating), - tradeMarginTemplates: ylotc.tradeMarginTemplates, - binaryPayoffTypes: this.trade.ExerciseMode === 'European' ? - consBinaryPayoffTypes.European : consBinaryPayoffTypes.American, - engineNames: tradeUtils.getEngineNames(this.trade) - }; - }, - watch: { - 'trade.Notional': { - handler(newVal, oldVal) { - this.resetSummary(resetSummaryFlags.notional); - }, - immediate: false - }, - 'trade.TradeType': { - handler(newVal, oldVal) { - this.fieldState.onTradeTypeChanged(this.trade, oldVal, this); - this.changeEngineName(); - }, - immediate: true - }, - 'trade.ExerciseDate': { - handler(newVal, oldVal) { - this.trade.SettlementDate = newVal; - this.changeIsAnnualized(); - }, - immediate: false - }, - 'trade.UnderlyingInstrumentType': { - handler(newVal, oldVal) { - this.fieldState.setFieldState('DividendRate', (newVal === 'Stock' || newVal === 'StockIndex')); - }, - immediate: true - }, - 'trade.PayoffType': { - handler(newVal, oldVal) { - this.changeEngineName(); - }, - immediate: false - }, - 'trade.EnhancedPrice': { - handler(newVal, oldVal) { - this.changeEngineName(); - }, - immediate: true - }, - 'trade.StrikeType': { - handler(newVal, oldVal) { - this.changeEngineName(); - }, - immediate: false - } - }, - created: consVueTrade.created, - mounted() { - consSyntheticMap[this.trade.CalcId] = this.viewState.synthetic; - if (pageVue.ClientUsedForCalc) { - if (!this.trade.ClientId) { - ylotc.clients.length && (this.trade.ClientId = ylotc.clients[0].id); - if (this.trade.ClientId) { - this.changeClient(); - } - } else { - this.updateKey.client++; - } - } - this.$nextTick(function () { - switch (this.viewState.initFlag) { - case 'first': - this.viewState.initFlag = ''; - this.preloadDefaultUnderlying(); - break; - case 'import1': - case 'import2': - case 'template': - !this.floating && this.updateUnderlying({ UnderlyingCode: this.trade.UnderlyingCode }); - break; - } - }); - topVue.simpleMode && (this.trade.UnderlyingPrice = ''); - !this.floating && EventBus.addEventListener('simpleMode.changed', this.onSimpleModeChanged); - }, - methods: { - ...consVueTrade.methods, - //变更客户 - changeClient() { - this.$emit('change-client', this.trade.ClientId); - }, - synchTrade(setInitialMarginNull) { - this.$emit('synch-trade', this.trade, setInitialMarginNull); - }, - sumTotal() { - this.$emit('sum-total', this.trade); - }, - //变更期权类型 - changeTradeType() { - this.viewState.Observation.hasValue = false; - this.viewState.KOObservation.hasValue = false; - this.changeExerciseMode('TradeType'); - this.refreshEngineNames(); - if (this.trade.TradeType === "现金流交易") { - tradeUtils.resetCashFlow(this.trade); - } - }, - // EQD-7049:首腿自动预载默认类型标的。固收等环境下默认类型(Stock/CommodityFutures)可能没有 - // 已上线标的,后端必返回"标的信息缺失"——属可容忍场景,静默失败不弹窗,留待用户自选; - // 用户主动切换类型仍走 changeInstrumentType,查询失败正常提示 - preloadDefaultUnderlying() { - if (new Date().getTime() < this.updateKey.underlying + 300) return; - let instType = this.trade.UnderlyingInstrumentType; - this.viewState.variety = tradeHelper.getEmptyVariety(instType); - this.updateUnderlying({ InstrumentType: instType }, false, true); - }, - //变更标的类型 - changeInstrumentType() { - if (new Date().getTime() < this.updateKey.underlying + 300) return; - let instType = this.trade.UnderlyingInstrumentType; - this.viewState.variety = tradeHelper.getEmptyVariety(instType); - this.updateUnderlying({ InstrumentType: instType }); - this.synchTrade(); - }, - //变更标的品种 - changeVariety(variety) { - this.viewState.variety = variety; - this.updateUnderlying({ VarietyId: variety.id }); - this.synchTrade(); - }, - //变更标的 - changeUnderlying(underlying) { - if (underlying.Disallow) { - if (underlying.IsCombined) { - main.alert(underlying.BlackWhiteState === 1 ? "该组合中包含存在于黑名单的标的" : "该组合中包含不在白名单中的标的"); - } - else { - main.alert(underlying.BlackWhiteState === 1 ? "该标的存在于黑名单中" : "该标的不在白名单中"); - return; - } - } - this.viewState.underlying = underlying; - this.updateUnderlying({ UnderlyingCode: underlying.Code }, true); - this.changeEffectRatio(); - this.synchTrade(); - }, - //变更定价模型 - changeEngineName() { - // 增强亚式期权,在执行价格和增强价格不一致的情况下,默认只支持使用蒙特卡洛计算引擎 - if (tradeUtils.changeEngineName(this.trade)) { - this.canEditEngineName = false; - } else { - this.canEditEngineName = true; - } - }, - //更新标的 - updateUnderlying(reqData, fromSelect, silent) { - let self = this; - // EQD-7049:新建空白页未选标的/品种/类型时,跳过必然失败的后端默认标的查询,避免报“标的信息缺失” - var hasQueryKey = !!(reqData.UnderlyingCode || reqData.InstrumentType || reqData.VarietyId > 0); - if (!hasQueryKey) { - !fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying()); - return; - } - var instTypeChanged = !!reqData.InstrumentType; - !fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying()); - // silent:自动预载场景失败不弹窗(alertFn 置空+抑制网络错误提示),用户主动查询仍正常提示 - var req = main.post("/pricing/AjaxGetUnderlying", reqData, silent ? { alertFn: $.noop, suppressError: true } : undefined); - silent && req.fail(function (resp) { console.warn('预载默认标的失败(已忽略):', resp && resp.msg); }); - req.done(function (resp) { - let trade = self.trade; - let um = resp.obj.underlying; - if (!fromSelect) { - self.viewState.underlying = { - id: um.id, Code: um.UnderlyingCode, Name: um.UnderlyingName, - InstrumentType: um.UnderlyingInstrumentType, VarietyId: um.UnderlyingTypeId, - QuoteUnitString: um.QuoteUnitString - }; - } - self.updateKey.underlying = new Date().getTime(); - instTypeChanged || (instTypeChanged = trade.UnderlyingInstrumentType !== um.UnderlyingInstrumentType); - - trade.UnderlyingId = um.id; - trade.UnderlyingCode = um.UnderlyingCode; - trade.UnderlyingName = um.UnderlyingName; - trade.UnderlyingInstrumentType = um.UnderlyingInstrumentType; - trade.VarietyId = um.UnderlyingTypeId; - trade.CountRatio = um.CountRatio; - - self.viewState.variety = ylotc.varieties.find(x => x.id === um.UnderlyingTypeId) - || tradeHelper.getEmptyVariety(trade.UnderlyingInstrumentType); - self.updateKey.variety = new Date().getTime(); - - if (self.viewState.initFlag === 'import1') { - self.getTTM(false, false); - return self.viewState.initFlag = ''; - } - - if (self.viewState.initFlag === 'template') { - return self.viewState.initFlag = ''; - } - - trade.DividendRate = um.DividendRate; - self.viewState.synthetic = consSyntheticMap[trade.CalcId] = resp.obj.synthetic; - - //初始预付金 - trade.InitialMargin = 0; - - //加载结构化交易 - if (self.viewState.initFlag === 'import2') { - trade.SettlementDate = trade.ExerciseDate; - (trade.TradeOpenVolatility !== '') && (self.viewState.VolState = 'user'); - (trade.TradeCloseVolatility !== '') && (self.viewState.CloseVolState = 'user'); - self.changeTradeDate('import2'); - if (trade.PremiumRate !== '' || trade.TradeSinglePrice !== '') { - trade.PremiumRate !== '' ? self.changePremiumRate() : self.changeTradeSinglePrice(); - } else { - trade.PremiumRate = trade.TradeSinglePrice = trade.TradePrice = 0; - } - return self.viewState.initFlag = ''; - } - - //重置权利金 - trade.PremiumRate = trade.TradeSinglePrice = trade.TradePrice = 0; - - trade.SpotPrice = pricingFormat.umprice(um.Price); - - //重置视图状态 - _.each(tradeFieldMgr.defaultData.viewState, (val, key) => { - val === 'system' && (self.viewState[key] = "system"); - }); - - //根据标的类型切换,权益类默认名义本金成交方式 - if (um.UnderlyingInstrumentType === "Stock" || um.UnderlyingInstrumentType === "StockIndex") { - trade.IsUsePremiumRate = true; - //名义本金影响交易数量 - self.changeStockEqvNotional(1e6); - if (trade.IsMoneynessOption !== "是" || !trade.Strike) { - trade.Strike = pricingFormat.umprice(um.Price); - self.showPercentStrike(); - instTypeChanged = true; - } - } else { - trade.IsUsePremiumRate = false; - self.changeTradeAmount(instTypeChanged ? 1 : null); - if (trade.IsMoneynessOption === "是" || !trade.Strike) { - trade.Strike = "1"; - self.showAbsStrike(); - instTypeChanged = true; - } - } - - //如果资产大类变更则清除掉IsMoneynessOption和IsUsePremiumRate关联的字段值 - instTypeChanged && tradeUtils.onChangeInstrumentType(trade); - - //到期日ExerciseDate默认为1个月之后,股票到期日不显示 - trade.TradeDate = pageVue.SysDate; - trade.ExerciseDate = new moment(um.ExerciseDate).format("YYYY-MM-DD"); - trade.MaturityDate = new moment(um.MaturityDate || "2029-01-01").format("YYYY-MM-DD"); - trade.TradeDate > trade.ExerciseDate && (trade.TradeDate = trade.ExerciseDate); - self.changeTradeDate(true); - if (pageData.is厦门象屿) { - trade.PremiumPayDate = trade.ExerciseDate; - } - - //重置计算结果 - self.calcResult.reset(); - if (fromSelect) { - self.resetSummary(resetSummaryFlags.all); - } - }); - }, - //刷新波动率,影响波动率的属性:SpotPrice,Strike,TradeDate,ExerciseDate,UnderlyingId - getVol(debounce) { - if (this.trade.TradeType === "现金流交易") return; - if (pageVue.IsTradeVol) { - let flag = 0; - if (!pageVue.SkewMapVol) { - this.viewState.VolState !== 'user' && (flag |= 1); - this.viewState.CloseVolState !== 'user' && (flag |= 2); - if (flag === 0) return; - } else { - flag = 1 | 2; - } - if (debounce === true) { - if (!this.debounceGetVol) { - this.debounceGetVol = _.debounce(function (vue) { - (flag & 1) > 0 && vue.getTradeOpenVolatility(); - (flag & 2) > 0 && vue.getTradeCloseVolatility(); - }, 1000, { trailing: true }); - } - this.debounceGetVol(this); - } else { - (flag & 1) > 0 && this.getTradeOpenVolatility(); - (flag & 2) > 0 && this.getTradeCloseVolatility(); - } - } else if (this.viewState.VolState !== 'user') { - this.getTradeOpenVolatility(); - this.getTradeMidVolatility(); - } - this.synchTrade(); - }, - //重置统计数据 - resetSummary(flag) { - this.$emit('reset-summary', flag); - }, - //获取标的价格(计算用) - getUnderlyingPrice() { - var self = this; - return main.post("/pricing/AjaxGetUnderlyingPrice", { underlyingCode: this.trade.UnderlyingCode, tradeDate: this.trade.ValueDate }) - .done(function (resp) { - self.trade.UnderlyingPrice = pricingFormat.umprice(resp.obj.price); - self.synchTrade(); - }); - }, - //精简模式切换时的处理 - onSimpleModeChanged() { - this.trade.UnderlyingPrice = ''; - } - }, - computed: { ...consVueTrade.computed }, - components: { - 'vue-margintemplatename': vueMarginTemplateName(), - 'vue-niceselect': FastVue.vueNiceSelect(), - 'vue-variety': vueVariety(), - 'vue-tradetype': vueTradeType(), - 'vue-underlying': vueUnderlying(), - 'vue-datepicker': FastVue.vueDatePicker(), - 'vue-number-input': FastVue.vueNumberInput(), - 'vue-daycount': vueDayCount(), - 'vue-client': vueClient(), - }, - render: renders.item(), - staticRenderFns: renders.item(true), - destroyed() { - delete consSyntheticMap[this.trade.calcId]; - topVue.simpleMode && (this.trade.UnderlyingPrice = ''); - EventBus.removeEventListener('simpleMode.changed', this.onSimpleModeChanged); - } - }; -}; - -//单个定价组件(现金流) -const vueTrade2 = function () { - return { - props: ['trade', 'viewState', 'calcResult', 'floating'], - data() { - return { - isTitle: false, - ...consVueTrade.data(), - fieldState: tradeFieldMgr.getFieldState(this.floating), - }; - }, - watch: { - 'trade.ExerciseDate': { - handler(newVal, oldVal) { - this.trade.SettlementDate = newVal; - }, - immediate: false - } - }, - mounted() { - if (pageVue.ClientUsedForCalc) { - if (!this.trade.ClientId) { - ylotc.clients.length && (this.trade.ClientId = ylotc.clients[0].id); - if (this.trade.ClientId) { - this.changeClient(); - } - } else { - this.updateKey.client++; - } - } - this.fieldState.onTradeTypeChanged(this.trade, null, this); - this.trade.IsUsePremiumRate = true; - }, - methods: { - ...consVueTrade.methods, - //变更客户 - changeClient() { - this.$emit('change-client', this.trade.ClientId); - }, - synchTrade() { - this.$emit('synch-trade', this.trade); - }, - //重置统计数据 - resetSummary(flag) { - this.$emit('reset-summary', flag); - } - }, - computed: { ...consVueTrade.computed }, - components: { - 'vue-niceselect': FastVue.vueNiceSelect(), - 'vue-client': vueClient(), - 'vue-datepicker': FastVue.vueDatePicker(), - 'vue-number-input': FastVue.vueNumberInput(), - 'vue-daycount': vueDayCount(), - }, - render: renders.itemCash(), - staticRenderFns: renders.itemCash(true), - destroyed() { - - } - }; -}; - -//主视图定价头部拖动处理 -const mainDragScroll = dragScroll.create({ container: '.pricing-main', yscroll: false, throttle: _.throttle }); - -//定价组件组合 -function createVue(index, baseVue, floating) { - - var datas = baseVue.datas; - var fromLocal = baseVue.fromLocal === true; - - if (datas.length < 1) { - return main.alert('缺少数据'); - } - - var structureType = baseVue.combining && datas.length > 1 ? '结构化交易' : baseVue.structureType || ''; - - _.each(datas, (data, index2) => { - if (index2 > 0) { - data.trade.hideCommen = true; - } - data.trade.CalcId = index + '-' + (index2 + 1); - data.trade.ParentIndex = index; - - if (!data.calcResult) { - data.calcResult = { - sourceData: null, - reset(data) { - this.sourceData = data; - if (!data) { - _.each(consCalcFields, x => this[x] = ''); - } - } - }; - _.each(consCalcFields, x => data.calcResult[x] = ''); - } else if (baseVue.combining) { - data.calcResult = _.cloneDeep(data.calcResult); - } - - if (!data.trade.UnderlyingInstrumentType) { - data.trade.UnderlyingInstrumentType = pageVue.StockFirst ? 'Stock' : 'CommodityFutures'; - } - - data.trade.StructureType = structureType; - }); - - if (datas.length === 1) { - datas[0].trade.CalcId = index.toString(); - } - - var debounceFloatSinglePrice = _.debounce(singlePricer.calcSinglePrice, 300); - - var vue = new Vue({ - data: { - index: index, - datas: datas, - floating: floating, - isSelected: true, - structureType: structureType, - showFloatingIcon: !structureType || datas.every(x => x.trade.TradeType === '香草期权') - }, - computed: { - - }, - mounted() { - if (this.floating) { - var singlePrice = singlePricer.calcSinglePrice(this.convertForSinglePrice()); - singlePrice && $('#singleprice2').text(singlePrice); - } else { - pricingVue.onMountd(this); - } - }, - methods: { - getData(index) { - return this.datas[index || 0]; - }, - getVol() { - _.each(this.$children, x => x.getVol()); - }, - remove(blRemoveChain) { - this.$destroy(); - this.$el.remove(); - pricingVue.remove(this, blRemoveChain); - }, - saveTrade() { - tradeSaver.saveTrades([this]); - }, - showFloatVue() { - floatVue.show(this); - let td = this.getData(0); - setTimeout(function () {//交易详情页-定价增强价格不显示问题 - if (td && td.trade.TradeType == "亚式期权" && td.trade.StrikeType != "Floating" && td.trade.PayoffType == 'EnhancedArithmeticAverage') { - $("#EnhancedPriceTitle").show(); - } - }, 500); - }, - screenshot() { - screenshoter.execute(this); - }, - uncouple() { - pricingVue.uncouple(this); - }, - convertForSinglePrice() { - return _.reduce(this.datas, (result, data) => { - var sdata = data.calcResult.sourceData; - sdata && (result || (result = [])).push({ Pv: sdata.Pv, Notional: data.trade.Notional }); - return result; - }, null); - }, - //重置统计数据 - resetSummary(flag) { - //浮窗页面 - if (this.floating && flag < resetSummaryFlags.ten) { - var singlePrice = singlePricer.calcSinglePrice(this.convertForSinglePrice()); - singlePrice && $('#singleprice2').text(singlePrice); - } - //主页面 - if (this.isSelected) { - var data = this.datas[this.datas.length - 1]; - data.calcResult.TotalTradePrice = pageVue.GetTotalTradePrice(_.map(this.datas, x => x.trade)); - data.calcResult.TotalDay1Pnl = pageVue.GetTotalDay1Pnl(_.map(this.datas, x => x.trade)); - if (flag === resetSummaryFlags.initialMargin) { - data.calcResult.TotalMargin = pageVue.GetTotalMargin(_.map(this.datas, x => x.trade), this.structureType); - return summaryVue.reset(this.index, this.datas.map(x => x.calcResult)); - } - - singlePricer.reset(this.index, this.convertForSinglePrice()); - if (flag !== resetSummaryFlags.notional) { - summaryVue.reset(this.index, this.datas.map(x => x.calcResult)); - } - } - else if (flag === true) { - summaryVue.reset(this.index, null); - singlePricer.reset(this.index, null); - } - }, - setCalcResult(result) { - var data = _.find(this.datas, x => x.trade.CalcId === result.CalcId); - if (!data) { - return main.alert('系统错误'); - } - - var trade = data.trade; - - if (topVue.calcMargin && data.viewState.InitialMargin !== 'user') { - if (result.hasInitialMargin) { - trade.InitialMargin = parseFloat(result.initialMargin) + result.AccurateTradePrice * (trade.BuySell == "买入" ? -1 : 1); - } else { - trade.InitialMargin = 0; - } - } - - var calcResult = data.calcResult; - var contractSize = result.contractSize; - - trade.TTMDays = consNumberFormat.ttmDaysFmt(result.TTMDays); - trade.Day1Pnl = pricingFormat.tradePrice(result.Day1Pnl); - - //对象缩小为具体计算结果 - result = result.calcResult; - calcResult.reset(result); - - //用于统计 - calcResult.UnderlyingCode = trade.UnderlyingCode; - - if (trade.IsUsePremiumRate) { - trade.TradePrice = result.Pv * (trade.BuySell == "买入" ? 1 : -1); - if (trade.TradeType !== "现金流交易") { - //根据总额算出期权费率 - tradePricing.tradeCalc(trade, tradePricing.calcReason.Pv); - //由于期权费率会有精度损失,进行了四舍五入处理,需要再根据期权费率反算出期权费总额 - //因为录入交易时是根据期权费率作为标准的 - tradePricing.tradeCalc(trade, tradePricing.calcReason.PremiumRate); - } - } - else { - var pv = result.Pv * (trade.BuySell == "买入" ? 1 : -1); - trade.TradeSinglePrice = trade.Notional ? pv / trade.Notional : 0; - tradePricing.tradeCalc(trade, tradePricing.calcReason.TradeSinglePrice); - } - //result.Pv = (result.Pv < 0 ? -1 : 1) * trade.TradePrice; - - if (pageObj.IsPVIncludePrincipal && trade.OriginalPrincipalSum > 0) { - result.Pv += trade.OriginalPrincipalSum * (trade.BuySell === '卖出' ? -1 : 1); - } - - if (topVue.calcMargin) { - //非用户自己输入和非结构化交易 - if (data.viewState.InitialMargin !== 'user' && !trade.StructureType) { - //非双向追保交易员收预付金,预付金不能小于0;交易员买入,付期权费收预付金,预付金不能小于0;交易员卖出,收期权费付预付金,预付金不能大于0 - if (pageVue.ClientUsedForCalc && !data.viewState.TwoSideMargin && trade.InitialMargin < 0) { - trade.InitialMargin = 0; - } - else if (trade.BuySell == "卖出" && trade.InitialMargin > 0) { - trade.InitialMargin = 0; - } - else if (trade.BuySell == "买入" && trade.InitialMargin < 0) { - trade.InitialMargin = 0; - } - } - } else { - trade.InitialMargin = ''; - } - - //todo:光子模式下是否要重设TradeOpenVolatility的值 - // delta gamma 用手数,其它份额 Vega,pho份额*100 qdp用的是份额计算 - //现在计算的是数量 份额数量比 - //手数 = 交易数量 / 交易单位 (5吨 / 手) - //交易数量 = 份额 / 比率 - //手数 = 份额 / (比率 * 交易单位) - //TradeUnitValue 是手数对份额的比率 鸡蛋时为 10 - var variety = data.viewState.variety; - var fe_ration = 1; - !contractSize && (contractSize = variety && variety.ContractSize ? variety.ContractSize : 1); - calcResult.Pv = pricingFormat.tradePrice(result.Pv); - calcResult.Delta = pricingFormat.greek(result.Delta / contractSize); - calcResult.GammaCash = pricingFormat.greek(result.GammaCash); - calcResult.Theta = pricingFormat.greek(fe_ration * result.Theta); - calcResult.Vega = pricingFormat.greek(fe_ration * result.Vega); - calcResult.Rho = pricingFormat.greek(fe_ration * result.Rho * 100); - calcResult.TotalMargin = 0; - calcResult.TotalTradePrice = 0; - calcResult.TotalDay1Pnl = 0; - this.resetSummary(resetSummaryFlags.all); - this.sumTotal(trade); - if (data === this.datas[this.datas.length - 1]) { - calcResult.TotalMargin = pageVue.GetTotalMargin(_.map(this.datas, x => x.trade), this.structureType); - calcResult.TotalTradePrice = pageVue.GetTotalTradePrice(_.map(this.datas, x => x.trade)); - calcResult.TotalDay1Pnl = pageVue.GetTotalDay1Pnl(_.map(this.datas, x => x.trade)); - } - }, - changeClient(clientId) { - let client = null; - if (pageVue.ClientUsedForCalc && pageVue.TwoSideMargin) { - client = ylotc.clients.find(y => y.id === clientId); - } - _.each(this.datas, x => { - x.trade.ClientId = clientId; - x.trade.MarginOptionType = client.MarginOptionType; - x.viewState.TwoSideMargin = client && client.MarginOptionType === 1; - x.trade.MarginTemplateName = client.MarginOptionType === 3 ? "无预付金" : "系统默认"; - tradeUtils.changeMarginTemplate(x.trade, []); - }); - }, - updateSynthetic(calcId, synthetic) { - var index = this.datas.findIndex(x => x.trade.CalcId === calcId); - if (index < 0) return false; - this.datas[index].trade.SpotPrice = synthetic.Price; - this.$children[index].changeSpotPrice(true); - return true; - }, - copyThis() { - pricingVue.copyItem(this); - }, - synchTrade(trade, setInitialMarginNull) { - _.each(this.datas, x => { - //隐藏的组合公共属性字段赋值处理 - if (trade.ParentIndex > 0 && x.trade.ParentIndex == trade.ParentIndex && !trade.hideCommen) { - x.trade.ClientId = trade.ClientId; - x.trade.UnderlyingId = trade.UnderlyingId; - x.trade.UnderlyingCode = trade.UnderlyingCode; - x.trade.UnderlyingName = trade.UnderlyingName; - x.trade.UnderlyingInstrumentType = trade.UnderlyingInstrumentType; - x.trade.VarietyId = trade.VarietyId; - if (trade.StructureType != "蝶式组合") { - x.trade.TradeAmountV = trade.TradeAmountV; - x.trade.TradeAmount = trade.TradeAmount; - x.trade.Notional = trade.Notional; - x.trade.StockEqvNotional = trade.StockEqvNotional; - x.trade.StockEqvNotionalReal = trade.StockEqvNotionalReal; - } - x.trade.ExerciseMode = trade.ExerciseMode; - x.trade.TradeDate = trade.TradeDate; - if (trade.StructureType != "日历价差") { - x.trade.ExerciseDate = trade.ExerciseDate; - x.trade.SettlementDate = trade.SettlementDate; - } - x.trade.SpotPrice = trade.SpotPrice; - x.trade.UnderlyingPrice = trade.UnderlyingPrice; - x.trade.SettlementType = trade.SettlementType; - x.trade.NoRiskRate = trade.NoRiskRate; - x.trade.DividendRate = trade.DividendRate; - x.trade.TTMDays = trade.TTMDays; - x.trade.IsTTMSystem = trade.IsTTMSystem; - x.trade.IsAnnualized2 = trade.IsAnnualized2; - x.trade.MetaDic = trade.MetaDic; - x.trade.EngineName = trade.EngineName; - - x.trade.OriginalPrincipalSum = x.trade.IsUsePremiumRate ? - _.round(x.trade.StockEqvNotional * x.trade.PrincipalRateWrite * x.trade.AnnualizeFactor, otcformat.trading.tradePrice.precision) - : _.round(x.trade.Notional * x.trade.SinglePrincipalWrite, otcformat.trading.tradePrice.precision); - - x.trade.TradePrice = x.trade.IsUsePremiumRate ? - _.round(tradeHelper.GetTradePriceByPremiumRate(x.trade.PremiumRate, x.trade.StockEqvNotional, x.trade.ParticipationRate, - x.trade.OriginalPrincipalSum, x.trade.AnnualizeFactor, x.trade.BuySell, x.trade.TradeType, true), otcformat.trading.tradePrice.precision) - : _.round(tradeHelper.GetTradePriceBySinglePrice(x.trade.TradeSinglePrice, x.trade.StockEqvNotional, x.trade.Notional, - x.trade.OriginalPrincipalSum, x.trade.AnnualizeFactor, x.trade.BuySell, x.trade.TradeType, true), otcformat.trading.tradePrice.precision); - - if (setInitialMarginNull) { - x.trade.InitialMargin = null; - } - } - }); - - this.sumTotal(trade); - }, - sumTotal(trade) { - //第一条腿添加组合成交金额和组合预付金 - var totalTradePrice = 0; - var totalInitialMargin = 0; - _.each(this.datas, x => { - if (trade.ParentIndex > 0 && x.trade.ParentIndex == trade.ParentIndex) { - totalTradePrice += parseFloat(x.trade.TradePrice) * (x.trade.BuySell == "买入" ? -1 : 1); - totalInitialMargin += parseFloat(x.trade.InitialMargin); - } - }); - - _.each(this.datas, x => { - if (x.trade.ParentIndex == trade.ParentIndex) { - x.trade.TotalTradePrice = pricingFormat.tradePrice(totalTradePrice); - x.trade.TotalInitialMargin = pricingFormat.tradePrice(totalInitialMargin); - } - }); - } - }, - components: { - 'vue-trade': vueTrade(), - 'vue-trade2': vueTrade2(), - }, - destroyed() { - if (!this.floating && this.isSelected) { - summaryVue.reset(this.index, null); - singlePricer.reset(this.index, null); - } - }, - render: renders.items(), - staticRenderFns: renders.items(true) - }); - - if (!baseVue.combining && !baseVue.selfMount) { - if (vue.floating) { - vue.$mount($('
').appendTo('#pricing-items2').get(0)); - } else if (fromLocal) { - vue.$mount($('
').appendTo('#pricing-items').get(0)); - } else { - vue.$mount($('
').prependTo('#pricing-items').get(0)); - } - } - - !floating && mainDragScroll.reset(); - - return vue; -} - -function _setAutocomplete(elId, datas, initData, onSelectFn) { - initData = initData || {}; - if (elId === "GroupClientId") { - groupVue.trade.ClientId = initData.id; - groupVue.trade.ClientName = initData.Name; - } - else if (elId === "GroupAssetId") { - groupVue.trade.AssetId = initData.id; - groupVue.trade.AssetBookName = initData.Name; - } - else if (elId === "GroupTraderId") { - groupVue.trade.TraderId = initData.id; - groupVue.trade.TraderName = initData.Name; - } - - FastVue.autocomplete(document.getElementById(elId), { - valueField: 'Name', searchField: ['Name', 'PinYin'], lookup: datas, - onSelect(data) { - $('#' + elId).data('id', data.id); - if (elId === "ClientId" || elId === "GroupClientId") { - _setSalesman(); - } - onSelectFn && onSelectFn(data); - }, - zIndex: 300000 - }).setData(initData); - $('#' + elId).data('id', initData.id); -} - -function _setSalesman() { - if (pageVue.ClientUsedForCalc) { - var IsCentralClearing = $("#txtCurrentClient").attr("data-IsCentralClearing"); - var CentralClearingPaltform = $("#txtCurrentClient").attr("data-CentralClearingPaltform"); - var TradingPaltform = $("#txtCurrentClient").attr("data-TradingPaltform"); - $("#IsCentralClearing").val(IsCentralClearing); - $("#CentralClearingPaltform").val(CentralClearingPaltform); - $("#TradingPaltform").val(TradingPaltform); - } - if ($("#ClientId").data('id') && _salesCommissionCtrl) { - _salesCommissionCtrl.changeSalesmen($("#ClientId").data('id')); - _getMainProtocolCode($("#ClientId").data('id')); - } -} - -function _changeMainProtocolCode() { - _getSupProtocolCode(); -} - -function _getMainProtocolCode(client) { - $("#MainProtocolCode option").remove(); - if (client) { - let clientId = typeof client === 'object' ? client.id : client; - main.post("/Client/getMainProtocolCodes", { clientId: clientId }, { async: false }).done(function (resp) { - var obj = $("#MainProtocolCode"); - _.forEach(resp, (v) => { - obj.append(""); - }) - }); - } - _getSupProtocolCode() -} - -function _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(""); - }) - }); - } -} - -//定价组件 -const pricingVue = (function () { - - //创建定价标题组件 - function createTitleVue(el, floating) { - var vue = new Vue({ - el: el, - data: { - trade: {}, - isTitle: true, - floating: floating, - fieldState: tradeFieldMgr.getTitleState(floating) - }, - render: renders.title(), - staticRenderFns: renders.title(true) - }); - return vue; - } - - createTitleVue('#pricing-titles', false); - createTitleVue('#pricing-titles2', true); - - var _index = 1; - - //定价组件集合 - const _tradeVues = []; - - function __clear() { - if (!_tradeVues.length) return; - _index = 0; - _tradeVues.splice(0, _tradeVues.length).forEach(x => x.remove()); - $('#pricing-items').parent().floatingScroll('update'); - } - - //清空 - function clear(force) { - if (!_tradeVues.length) return; - if (force) { - __clear(); - } else { - main.confirmV2("确认清空吗?").done(__clear); - } - } - - //移除 - function remove(tradeVue, blRemoveChain) { - if (blRemoveChain && tradeVue.floating) { - var baseVue = _tradeVues.find(x => x.index === tradeVue.index); - baseVue && baseVue.remove(); - } - _.pull(_tradeVues, tradeVue); - $('#pricing-items').parent().floatingScroll('update'); - } - - //新增单腿 - function addTrade(trade, tradeType) { - if (_tradeVues && _tradeVues[0] && _tradeVues[0].getData().trade.StructureType) { - return main.alert('不能同时添加单笔交易和组合交易'); - } - _index += 1; - let baseVue = _tradeVues[0] || { datas: [tradeFieldMgr.defaultData] }; - if (trade && typeof trade === 'object') { - let viewState = _.cloneDeep(tradeFieldMgr.defaultData.viewState); - viewState.initFlag = 'import1'; - baseVue = { datas: [{ trade: trade, viewState: viewState }] }; - } else if (tradeType === "现金流交易") { - let data = tradeFieldMgr.defaultData; - data = { - trade: _.cloneDeep(data.trade), - viewState: _.cloneDeep(data.viewState) - }; - _tradeVues.length < 1 && (data.viewState.initFlag = 'first'); - data.trade.IsUsePremiumRate = true; - baseVue = { datas: [data] }; - trade = data.trade; - } - else { - let data = baseVue.datas[0]; - data = { - trade: _.cloneDeep(data.trade), - viewState: _.cloneDeep(data.viewState) - }; - _tradeVues.length < 1 && (data.viewState.initFlag = 'first'); - baseVue = { datas: [data] }; - trade = data.trade; - } - if (typeof tradeType === 'string' && trade.TradeType !== tradeType) { - trade.TradeType = tradeType; - tradeFieldMgr.initFieldValue(trade); - } else { - tradeFieldMgr.resetFieldState(trade); - } - - if (trade.TradeAmount && !trade.TradeAmountV) { - trade.TradeAmountV = tradeHelper.getTradeAmountV(trade); - } - let vue = createVue(_index, baseVue); - _tradeVues.unshift(vue); - if (pageVue.IsImport || !new Array('香草期权', '合成价差期权').includes(trade.TradeType)) { - floatVue.show(vue); - } - } - - //复制项目 - function copyItem(tradeVue) { - var arrIndex = _.indexOf(_tradeVues, tradeVue); - if (arrIndex < 0) { - throw '系统错误'; - } - _index += 1; - let baseVue = tradeVue; - baseVue = { datas: _.cloneDeep(baseVue.datas), structureType: baseVue.structureType, selfMount: true }; - var vue = createVue(_index, baseVue); - vue.$mount($('
').insertBefore(tradeVue.$el).get(0)); - _tradeVues.splice(arrIndex, 0, vue); - } - - //新增策略 - function addTrades(trades) { - if (_tradeVues && _tradeVues[0] && !_tradeVues[0].getData().trade.StructureType) { - return main.alert('不能同时添加单笔交易和组合交易'); - } - - var datas = _.map(trades, trade => { - trade = _.transform(trade, (result, val, key) => { - key in result && (result[key] = val); - }, _.cloneDeep(pageVue.Trade)); - if (trade.UnderlyingInstrumentType !== 'Stock' && trade.UnderlyingInstrumentType !== 'StockIndex') { - trade.StockEqvNotionalReal = pricingFormat.StockEqvNotional(trade.Notional * trade.SpotPrice); - trade.StockEqvNotional = trade.StockEqvNotionalReal; - } - else { - trade.StockEqvNotionalReal = trade.StockEqvNotional; - } - trade.SpotPrice = trade.UnderlyingPrice; - trade.NoRiskRate = null; - trade.DividendRate = 0; - trade.ParticipationRate = 1; - trade.AnnualizeFactor = 1; - if (pageVue.NumOfSmoothingDaysCfg === 'ONE' && pageVue.IsTradeVol) { - trade.NumOfSmoothingDays = 1; - } - tradeUtils.normalizeTrade(trade); - let viewState = _.cloneDeep(tradeFieldMgr.defaultData.viewState); - viewState.initFlag = 'import2'; - return { trade: trade, viewState: viewState }; - }); - - _index += 1; - var vue = createVue(_index, { datas: datas, structureType: pageVue.getStructureType() }); - _tradeVues.unshift(vue); - } - - //自由组合 - function combine() { - var comVues = _.filter(_tradeVues, x => x.isSelected); - if (comVues.length < 2) { - return main.alert('请选择至少两项进行组合!'); - } - var firstVue = comVues[0]; - var datas = _.flatMap(comVues.map(x => x.datas)); - if (pageVue.ClientUsedForCalc) { - var clientId = parseInt(datas[0].trade.ClientId); - if (!_.every(datas, x => parseInt(x.trade.ClientId) === clientId)) { - return main.alert('所选项客户必须一致!'); - } - } - var vue = createVue(firstVue.index, { combining: true, datas: datas, fromLocal: true }); - vue.$mount($('
').insertBefore(firstVue.$el).get(0)); - var index = _.indexOf(_tradeVues, firstVue); - _tradeVues[index] = vue; - _.pullAll(_tradeVues, comVues); - comVues.forEach(x => x.remove()); - } - - //取消组合 - function uncouple(tradeVue) { - if (!tradeVue || tradeVue.floating) { - throw '系统错误'; - } - var arrIndex = _.indexOf(_tradeVues, tradeVue); - if (arrIndex < 0) { - throw '系统错误'; - } - var index = _index += tradeVue.datas.length; - var map = _.map(tradeVue.datas, data => { - data.trade.hideCommen = false; - var vue = createVue(index--, { combining: true, datas: [data], fromLocal: true }); - vue.$mount($('
').insertBefore(tradeVue.$el).get(0)); - return vue; - }); - var args = [arrIndex, 1].concat(map); - Array.prototype.splice.apply(_tradeVues, args); - tradeVue.remove(); - } - - //波动率类型变更 - function changeVolType() { - _tradeVues.forEach(x => x.getVol()); - } - - //获取所有交易数据 - function getTrades() { - return _.flatMap(_tradeVues.map(x => x.datas)).map(x => x.trade); - } - - //录入交易 - function saveTrades() { - tradeSaver.saveTrades(_tradeVues.filter(x => x.isSelected)); - } - - //录入组合交易 - function saveGroupTrades() { - tradeSaver.saveGroupTrades(_tradeVues.filter(x => x.isSelected)); - } - - //定价计算 - function calcPrice(tradeVues) { - - !tradeVues && (tradeVues = _tradeVues); - - if (!tradeVues.length) { - return main.alert("请至少录入一个交易"); - } - - var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade); - - //检查并转换数据 - trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false); - - if (trades) { - let data = { - version: pageVue.CalcVersion, - trades: trades, calcMargin: topVue.calcMargin, - calcAutocallGreeks: topVue.calcAutocallGreeks - }; - main.post("/pricing/ajaxCalcPrices", data).done(function (resp) { - //tradeVues转换为calcId为key的字典 - var map = tradeVues.reduce((result, cur) => { - _.each(cur.datas, x => { - result[x.trade.CalcId] = cur; - }); - return result; - }, {}); - //设置计算结果 - _.each(resp.obj, item => { - map[item.CalcId].setCalcResult(item); - }); - }); - } - } - - //显示组合到期收益曲线图形 - function showPayoffLineChart(tradeVues) { - var selectVues = _.filter(_tradeVues, x => x.isSelected); - !tradeVues && (tradeVues = selectVues); - - if (!tradeVues.length) { - return main.alert("请至少录入一个交易"); - } - - var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade); - - //检查并转换数据 - trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false); - - window.sessionStorage.removeItem("pricing_payoff_line"); - if (trades) { - main.post("/pricing/GetTradesPayoffLine", { trades: trades }).done(function (resp) { - //resp.obj - window.sessionStorage.setItem("pricing_payoff_line", JSON.stringify(resp)); - window.open("/Statics/html/PayoffChart.html"); - }); - } - } - - //显示组合Pv曲线 - function showPvChart(tradeVues) { - var selectVues = _.filter(_tradeVues, x => x.isSelected); - !tradeVues && (tradeVues = selectVues); - - if (!tradeVues.length) { - return main.alert("请至少录入一个交易"); - } - - var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade); - - //检查并转换数据 - trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false); - - window.sessionStorage.removeItem("pricing_pv_line"); - if (trades) { - main.post("/pricing/GetTradesPvLine", { trades: trades }).done(function (resp) { - //resp.obj - window.sessionStorage.setItem("pricing_pv_line", JSON.stringify(resp)); - window.open("/Statics/html/PvChart.html"); - }); - } - } - - function showLifeLineChart(tradeVues) { - var selectVues = _.filter(_tradeVues, x => x.isSelected); - !tradeVues && (tradeVues = selectVues); - - if (!tradeVues.length) { - return main.alert("请至少选择一笔交易"); - } - - var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade); - - //检查并转换数据 - trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false); - - window.sessionStorage.removeItem("pricing_life_lines"); - if (trades) { - main.post("/pricing/GetTradesLifePvLine", { trades: trades }).done(function (resp) { - //resp.obj - window.sessionStorage.setItem("pricing_life_lines", JSON.stringify(resp)); - window.open("/Statics/html/PvLifeChart.html"); - }); - } - } - - //显示Greeks变化曲线 - function showGreeksChart(tradeVues) { - var selectVues = _.filter(_tradeVues, x => x.isSelected); - !tradeVues && (tradeVues = selectVues); - - if (!tradeVues.length) { - return main.alert("请至少选择一笔交易"); - } - - var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade); - - //检查并转换数据 - trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false); - - window.sessionStorage.removeItem("pricing_greeks_line"); - if (trades) { - main.post("/pricing/GetTradesGreeksForLifetime", { trades: trades }).done(function (resp) { - //resp.obj - window.sessionStorage.setItem("pricing_greeks_line", JSON.stringify(resp)); - window.open("/Statics/html/GreeksChart.html"); - }); - } - } - - //设置观察数据 - function setObservation(observationNum, observationUnit, observationHolidayType, observationDates, alignEnd, calcId, couponDayInterval) { - if (!calcId) return; - - let _data = null, calcId2 = calcId.replace(/#.*$/, ""); - - _.each(_tradeVues, vue => { - return !(_data = _.find(vue.datas, data => data.trade.CalcId === calcId2)); - }); - - _data && consVueTrade.methods.setObservation.apply(_data, arguments); - } - - function setStructure(value, calcId) { - if (!calcId) return; - - let _data = null, calcId2 = calcId + ""; - - _.each(_tradeVues, vue => { - return !(_data = _.find(vue.datas, data => data.trade.CalcId === calcId2)); - }); - - _data && consVueTrade.methods.setStructure.apply(_data, arguments); - } - - //对冲下单 - function hedgingOrder() { - var comVues = _.filter(_tradeVues, x => x.isSelected); - if (comVues.length < 1) { - return main.alert('请至少选择一项!'); - } - var datas = _.flatMap(comVues.map(x => x.datas)); - var instType = datas[0].trade.UnderlyingInstrumentType; - if (!_.every(datas, x => x.trade.UnderlyingInstrumentType === instType)) { - return main.alert('所选项标的类型必须一致!'); - } - var rd = _.reduce(datas, (acc, cur) => { - var code = cur.trade.UnderlyingCode; - var delta = acc[code]; - acc[code] = (delta || 0) + (parseFloat(cur.calcResult.Delta) || 0); - return acc; - }, {}); - var items = _.reduce(rd, (acc, value, key) => { - var index = acc.length / 2; - acc.push(''); - acc.push(''); - return acc; - }, []); - items.push(''); - $('#orderForm').html(items.join("")).submit(); - } - - //浏览器本地数据缓存 - const localData = (new function () { - if (pageVue.IsImport) { - this.save = $.noop; - this.load = $.noop; - return; - } - this.save = function () { - var vueDatas = _tradeVues.map(x => new Object({ - index: x.index, - structureType: x.structureType, - datas: x.datas.map(data => new Object({ trade: data.trade, viewState: data.viewState })) - })); - var data = { - index: _index, - VolType: pageVue.getVolType(), - SysDate: pageVue.SysDate, - vueDatas: vueDatas, - time: new Date().getTime() - }; - var json = JSON.stringify(data); - localStorage.setItem("pricing-structure-" + pageVue.UserId, json); - }; - this.load = function () { - //设置默认值 - var saveKey = "pricing-structure-" + pageVue.UserId; - var storage = localStorage.getItem(saveKey); - if (!storage) return; - var data = JSON.parse(storage); - if (pageVue.SysDate !== data.SysDate || - new Date().getHours > 18 && new Date(data.time).getHours() < 18) { - //需要清空缓存 - localStorage.removeItem(saveKey); - } - else { - _index = data.index; - pageVue.setVolType(data.VolType); - _.each(data.vueDatas, function (x) { - x.fromLocal = true; - var vue = createVue(x.index, x); - _tradeVues.push(vue); - }); - } - }; - }()); - - //持久化定价数据 - $(window).on('beforeunload', localData.save); - $(localData.load); - - return { - clear: clear, - remove: remove, - addTrade: addTrade, - copyItem: copyItem, - combine: combine, - changeVolType: changeVolType, - saveTrades: saveTrades, - saveGroupTrades: saveGroupTrades, - calcPrice: calcPrice, - showPayoffLineChart: showPayoffLineChart, - showPvChart: showPvChart, - showGreeksChart: showGreeksChart, - showLifeLineChart: showLifeLineChart, - getTradeVues(onlySelected) { - return onlySelected ? _tradeVues.filter(x => x.isSelected) : _tradeVues; - }, - getTradeVue(index) { return _tradeVues[index || 0]; }, - saveLocalData: localData.save, - setOption: addTrades, //用于和老版兼容 - setObservation: setObservation, - setStructure: setStructure, - uncouple: uncouple, - hedgingOrder: hedgingOrder, - onMountd(vue) { - _tradeVues.length && $('#pricing-items').parent().floatingScroll(); - }, - swap(oldIndex, newIndex) { - if (oldIndex === newIndex) return; - let vue = _tradeVues[oldIndex]; - _tradeVues.splice(oldIndex, 1); - _tradeVues.splice(newIndex, 0, vue); - }, - //新增模板 - addTemplate(tplItems) { - tplItems.forEach(x => { - x.datas.forEach(d => { - d.viewState = _.cloneDeep(tradeFieldMgr.defaultData.viewState); - d.viewState.initFlag = 'template'; - var client = ylotc.clients.find(y => y.id === d.trade.ClientId); - d.viewState.TwoSideMargin = client && client.MarginOptionType === 1; - }); - _index += 1; - var vue = createVue(_index, x); - _tradeVues.unshift(vue); - }); - } - }; -}()); - -//浮窗定价组件 -const floatVue = (function () { - var _tradeVue; - - //关闭浮窗 - function hide() { - if (_tradeVue) { - _tradeVue.remove(); - _tradeVue = null; - } - $('#floatModal').modal('hide'); - $(document.body).removeClass('has-float'); - if (pageVue.IsImport) { - layer.closeMe(); - } - } - - //显示浮窗index, trade, viewState - function show(baseVue, forScreenshot) { - _tradeVue && _tradeVue.remove(); - _tradeVue = createVue(baseVue.index, baseVue, true); - $(document.body).toggleClass('has-float', !forScreenshot); - $('#floatModal').modal('show'); - } - - function screenshot() { - screenshoter.execute(_tradeVue); - } - - return { - show: show, - hide: hide, - calcPrice() { - _tradeVue && pricingVue.calcPrice([_tradeVue]); - }, - saveTrade() { - _tradeVue && _tradeVue.saveTrade(); - }, - screenshot: screenshot, - getVue() { return _tradeVue; } - }; -}()); - -//dom ready function -$(function () { - tradeSaver.init(); - groupVue.init(); - //解决上层popover不能编辑的问题 - $('#floatModal').on('shown.bs.modal', function () { - $(document).off('focusin.modal'); - }); - $(".search-label").addClass("formlabel"); - $(".formlabel").addClass("search-label"); - var sortable = Sortable.create(document.getElementById('pricing-items'), { - handle: '.pricing-index-drag', - onEnd: function (evt) { - pricingVue.swap(evt.oldIndex, evt.newIndex); - }, - }); - if (pageVue.IsImport) { - let trade = _.cloneDeep(pageVue.Trade); - pricingVue.addTrade(trade); - setTimeout(function () {//交易详情页-定价增强价格不显示问题 - if (trade.TradeType == "亚式期权" && trade.StrikeType != "Floating" && trade.PayoffType == 'EnhancedArithmeticAverage') { - $("#EnhancedPriceTitle").show(); - } - }, 500); - } - - document.onkeydown = hotkey; - - //当onkeydown 事件发生时调用hotkey - function hotkey() { - var a = window.event.keyCode; - if ((window.event.keyCode == 81) && (event.altKey)) { - if (floatVue.getVue() === null || floatVue.getVue() === undefined) { - pricingVue.calcPrice(); - } else { - floatVue.calcPrice(); - } - } - else if ((window.event.keyCode == 87) && (event.altKey)) { - floatVue.screenshot(); - } - } -}); - -//用于和老版兼容 -window.vue = pricingVue; - -//兼容定价计算页面观察日设置 -var getObservationDatesSetting = pricingVue.setObservation; -var getStructureSetting = pricingVue.setStructure; - -//连离类型:障碍(Discrete),二元(MonitorType,美式) -//补偿类型:障碍(RebateType),二元(RebateType,美式) - -//定价模板 -var templateVue = (function () { - - if (pageVue.IsImport) return; - - var debounceSearch; - - return new Vue({ - el: '#modalTemplate', - data: { - saveMode: true, - saveData: { - name: '', - id: 0, - _override: false, - _CommonTemplate: true - }, - listData: [], - searchText: '' - }, - mounted() { - this.refreshList(); - debounceSearch = _.debounce(this.searchInner, 500); - }, - methods: { - showSave() { - let selVues = pricingVue.getTradeVues(true); - if (!selVues.length) { - return main.alert('请勾选要保存的定价数据'); - } - - //模板名称自动赋值 - let vueDatas = selVues.map(x => new Object({ - structureType: x.structureType, - datas: x.datas.map(data => new Object({ trade: data.trade })) - })); - var client = ylotc.clients.find(y => y.id === vueDatas[0].datas[0].trade.ClientId); - let arr = [vueDatas[0].structureType, client?.Name?.substring(0, 6), vueDatas[0].datas[0].trade.UnderlyingCode, vueDatas[0].datas[0].trade.TradeDate.split('-').join(''), vueDatas[0].datas[0].trade.Strike]; - for (var i = 0; i < arr.length; i++) { - //这里为过滤空的值 - //这里为过滤空的值 - if (!_.trim(_.toString(arr[i]))) { - arr.splice(i, 1); - i = i - 1; - } - } - let str = arr.join("-"); - - this.saveMode = true; - this.saveData.name = str; - this.saveData.json = ''; - $('#modalTemplate').modal('show'); - }, - showList() { - this.saveMode = false; - $('#modalTemplate').modal('show'); - }, - saveTemplate() { - let selVues = pricingVue.getTradeVues(true); - if (!selVues.length) { - return main.alert('没有可保存的定价数据'); - } - let name = (this.saveData.name).trim(); - if (!name) { - return main.alert('请填写模板名称'); - } - let self = this; - let vueDatas = selVues.map(x => new Object({ - structureType: x.structureType, - datas: x.datas.map(data => new Object({ trade: data.trade })) - })); - let dataJson = JSON.stringify(vueDatas); - main.post('/pricing/AjaxSaveTemplate/v2', { name, dataJson, _override: this.saveData._override, _CommonTemplate: this.saveData._CommonTemplate }).done(function () { - $('#modalTemplate').modal('hide'); - self.refreshList(); - self.searchInner(); - }); - }, - removeTemplate(sysUserConfigId) { - let $item = $(event.target).closest('.yt-template-item'); - if (!$item) { - return main.alert('系统错误,没有找到所选项'); - } - let self = this; - let index = $item.prevAll().length; - let names = [$item.children('a').text()]; - main.confirmPost('确认要删除所选项"' + names[0] + '"吗?', '/pricing/AjaxRemoveTemplate', { sysUserConfigId }).done(function () { - self.listData.splice(index, 1); - }); - }, - loadTemplate() { - let name = $(event.target).text(); - let TemplateType = $(event.target).next().text(); - function __do() { - pricingVue.clear(true); - main.post('/pricing/ajaxGetTemplate/v2', { name, TemplateType }).done(function (resp) { - let items = JSON.parse(resp.obj); - pricingVue.addTemplate(items); - $('#modalTemplate').modal('hide'); - }); - } - if (pricingVue.getTradeVues().length) { - main.confirm("加载自定义模板将清空页面现有交易,是否继续?", __do); - } else { - __do(); - } - }, - refreshList() { - let self = this; - this.searchText = ''; - main.post('/pricing/AjaxGetTemplateList').done(function (resp) { - self.listData = resp.obj.map(x => new Object({ id: x.id, name: x.ConfigName, show: true, UserId: x.UserId, ConfigType: x.ConfigType })); - }); - }, - searchInner() { - console.log('searchInner'); - let text = this.searchText ? this.searchText.toLowerCase() : ''; - this.listData.forEach(x => { - x.show = !text || x.name.toLowerCase().indexOf(text) >= 0; - }); - }, - searchList(action) { - if (action === 'reset') { - debounceSearch.cancel(); - this.searchText = ''; - this.searchInner(); - } else { - debounceSearch(); - } - } - } - }); -}()); - -const customNumberFormat = { precision: 6, negative: true, }; -const customNumberPercentFormat = { precision: 6, negative: true, append: '%' }; - -var groupVue = new Vue({ - el: '#modalGroupTradeSave', - data: { - viewState: pageVue.viewState, - ...consVueTrade.data(), - trade: ylotc.trade, - options: ylotc.options, - structureTypes: pageObj.structureTypes, - PropertyMap: pageObj.PropertyMap, - }, - computed: { ...consVueTrade.computed }, - methods: { - ...consVueTrade.methods, - closeModal: function () { - $('#modalGroupTradeSave').modal('hide'); - }, - saveGroupTrade: function () { - if (!_trades) return; - - _trades.forEach(x => { - x.AssetId = this.trade.AssetId; - x.AssetBookName = this.trade.AssetBookName; - x.TraderId = this.trade.TraderId; - x.TraderName = this.trade.TraderName; - x.TradeNumber = this.trade.TradeNumber; - x.SalesCommission = this.trade.salesCommission; - x.ClientId = this.trade.ClientId; - x.ClientName = this.trade.ClientName; - - if (x.TradePremium) { - x.MetaDic["交易溢价"] = x.TradePremium; - } - x.MetaDic["交易场所"] = this.trade.TradingPlace; - x.MetaDic["清算机构"] = this.trade.ClearingAgency; - x.MetaDic["主协议编号"] = this.trade.MainProtocolCode; - x.MetaDic["补充协议编号"] = this.trade.SupProtocolCode; - x.TradeType === '现金流交易' && tradeUtils.resetCashFlow(x); - }); - - this.setExtendInfo(); - main.post("/pricing/AjaxSaveGroupTrade", { trade: this.trade, subTrades: _trades }).done(function (resp) { - if (pageVue.IsImport) { - let url = "#/trade/tradeview?abstract=1&enid=" + resp.obj[0].EncryptId; - layer.closeMe(url);//必须以#开头 - } else { - floatVue.hide(); - $('#modalTradeSave').modal('hide'); - //showTradeView(resp.obj); - _.each(_tradeVues, x => x.remove(true)); - } - }); - }, - addNewProperty: function () { - this.PropertyMap[this.trade.StructureType].push({ isNew: true, ColumnName: "", ColumnDefaultValue: "", ColumnType: 0 });//0:文本 - }, - deleteProperty: function (index) { - this.PropertyMap[this.trade.StructureType].splice(index, 1); - }, - setExtendInfo: function () { - var propertyList = []; - this.PropertyMap[this.trade.StructureType].forEach((item, index) => { - var note = { name: item.name || item.ColumnName, value: PercentColumnText.displayText(item) }; - if (note.name) { - propertyList.push(note); - } - }); - this.trade.ExtendInfo = this.trade.StructureType == "气囊结构" ? null : JSON.stringify(propertyList); - return this.trade.ExtendInfo; - }, - changeStrucTureType: function () { - if (groupVue.trade.TradeType == "气囊结构") { - groupVue.trade.trade_airbag.KIParticipationRate = 1; - } - else { - groupVue.trade.OptionType = null; - groupVue.trade.Strike = null; - } - }, - changeBuySell: function () { - groupVue.trade.TradePrice *= -1; - groupVue.trade.Day1Pnl *= -1; - groupVue.trade.TradeSinglePrice *= -1; - groupVue.trade.PremiumRate *= -1; - }, - changeIsUsePremiumRate: function () { - if (groupVue.trade.IsUsePremiumRate) { - groupVue.changeStockEqvNotional(); - } - else { - groupVue.changeTradeAmount(); - } - }, - changeStockEqvNotional: function () { - var notional = Math.abs(groupVue.trade.StockEqvNotional / groupVue.trade.SpotPrice); - groupVue.trade.Notional = pricingFormat.notional(notional); - groupVue.trade.TradeAmount = pricingFormat.notional(notional / groupVue.viewState.variety.CountRatio); - groupVue.trade.TradeSinglePrice = pricingFormat.tradeSinglePrice(groupVue.trade.TradePrice / groupVue.trade.Notional); - groupVue.trade.PremiumRate = pricingFormat.premiumRate(groupVue.trade.TradePrice / groupVue.trade.StockEqvNotional); - }, - changeTradeAmount: function () { - var notional = groupVue.trade.TradeAmount * groupVue.viewState.variety.CountRatio; - groupVue.trade.Notional = pricingFormat.notional(notional); - groupVue.trade.StockEqvNotional = pricingFormat.stockEqvNotional(Math.abs(notional * groupVue.trade.SpotPrice)); - groupVue.trade.TradeSinglePrice = pricingFormat.tradeSinglePrice(groupVue.trade.TradePrice / groupVue.trade.Notional); - groupVue.trade.PremiumRate = pricingFormat.premiumRate(groupVue.trade.TradePrice / groupVue.trade.StockEqvNotional); - }, - init: function () { - _setAutocomplete('GroupAssetId', ylotc.assetunits, null, function (data) { - groupVue.trade.AssetId = data.id; - groupVue.trade.AssetBookName = data.Name; - }); - var traders = $.grep(ylotc.traders, function (e) { return e.Name == pageVue.Trade.TraderName; }); - _setAutocomplete('GroupTraderId', ylotc.traders, { Name: pageVue.Trade.TraderName, id: traders.length ? traders[0].id : 0 }, function (data) { - groupVue.trade.TraderId = data.id; - groupVue.trade.TraderName = data.Name; - }); - _setAutocomplete('GroupClientId', ylotc.clients, null, function (data) { - pageVue.SecuritiesEnvironment ? _getMainProtocolCode : null; - groupVue.trade.ClientId = data.id; - groupVue.trade.ClientName = data.Name; - }); - }, - changeOption: function () { - this.PropertyMap[this.trade.StructureType].forEach(d => { - if (d.ColumnName != undefined) { - d.name = d.ColumnName; - } - if (d.ColumnDefaultValue != undefined) { - d.value = d.ColumnDefaultValue; - } - }); - } - }, - components: { - 'vue-niceselect': FastVue.vueNiceSelect(), - 'vue-client': vueClient(), - 'vue-variety': vueVariety(), - 'vue-margintemplatename': vueMarginTemplateName(), - 'vue-tradetype': vueTradeType(), - 'vue-underlying': vueUnderlying(), - 'vue-datepicker': FastVue.vueDatePicker(), - 'vue-number-input': FastVue.vueNumberInput(), - 'vue-daycount': vueDayCount(), - }, -}); \ No newline at end of file diff --git a/YLErpWeb/wwwroot/Scripts/app/pricing/tradePricing_dz.js b/YLErpWeb/wwwroot/Scripts/app/pricing/tradePricing_dz.js deleted file mode 100644 index cfaa75c8..00000000 --- a/YLErpWeb/wwwroot/Scripts/app/pricing/tradePricing_dz.js +++ /dev/null @@ -1,2472 +0,0 @@ -//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 inputFormatEqvNotionalReal = Object.freeze({ precision: 10, 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 consCashAsPhysical = Object.freeze([{ value: 'Cash', text: 'Cash' }, { value: 'Physical', text: 'Physical' }]); -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 }); - -//帮助类(只对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' - }); - - //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.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 _checkTrade(trade, usedForSave) { - 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("期权结算日 不能小于到期日"); - } - - 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 (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("名义本金 必须填写"); - } - } - 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.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; - } - } - } - 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 ? 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) { - - 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); - 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; - } - } - } - if (pageData.showCCR) { - clone.MetaDic["ccr_k"] = clone.ccr_k || "1"; - clone.MetaDic["ignoreRiskExposure"] = clone.ignoreRiskExposure || "0"; - } - }); - - //显示检查错误 - 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; - } - } - }); - } - } - - 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); - }, - changeMarginTemplate: changeMarginTemplate - }; -}()); - -//交易字段管理 -const tradeFieldMgr = (new function () { - - pageVue.Trade.EncryptId = ''; - - tradeUtils.normalizeTrade(pageVue.Trade); - - //默认数据(初次添加定价时使用) - const DefaultData = { - trade: pageVue.Trade, - viewState: { - variety: tradeHelper.getEmptyVariety(), - underlying: tradeHelper.getEmptyUnderlying(), - ShowTitle: false, - VolState: 'system', - MidVolState: 'system', - CloseVolState: 'system', - SpotPrice: 'system', - TTMDays: 'system', - InitialMargin: 'system', - TradeOpenVolatility: 'system', - NoRiskRate: 'system', - DividendRate: 'system', - TwoSideMargin: false, - Structure: "", - CashOrPhysical: "Cash", - 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: "交易员方" } - } - }; - - this.defaultData = DefaultData; - - //期权基本要素字段(是否展示) - const BasicFields = { - ExerciseMode(trade) { - switch (trade.TradeType) { - default: return true; - 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'); - }, - ShowTotal(trade) { - return trade.StructureType; - } - }; - - //期权奇异字段配置 - 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, - 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: '', - 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.KIPayoffType > 0 || trade.IsInitialKnockedIn; } - }, - SpreadStrike: { - init: '', visible(trade) { return trade.KIPayoffType === 2 || trade.KIPayoffType === 4; } - }, - beforeCheck(trade) { - return { - KOPayoffType: parseInt(trade.KOPayoffType) || 0, - KIPayoffType: parseInt(trade.KIPayoffType) || 0 - }; - } - }, - "气囊结构": { - 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: '浮动', IsFixedCoupon: true, CouponDayCount: 'Act365', - StrikeGearingFactor: 1, CallMultiplier: 1, PutMultiplier: 1, EarlyTerminate: false, SettlementMode: '现金当日', - KOObservationDates: '', CouponPercent: true, AccumuType: '', AccumuTradeAmount: '' - }, - "结构化产品": { - Structure: true - } - }); - - //期权字段状态 - 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 FloatingTitleState; - //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 = ''; - } - } - - 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; - FloatingTitleState[field] = blvalue; - //floating && (FloatingTitleState[field] = blvalue); - } - }; - - return clone; - }; - - this.initFieldValue = function (trade) { - __resetFieldState(trade, true); - }; - - this.resetFieldState = function (trade) { - __resetFieldState(trade, false); - }; - - _.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 || ""; - - if (this.trade.TradeType === '结构化产品') { - this.viewState.Observation.ObservationDates = this.trade.MetaDic["observationDate"]; - this.viewState.Structure = this.trade.MetaDic["structures"]; - this.viewState.CashOrPhysical = this.trade.MetaDic["cashOrPhysical"]; - } - - 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); - - if (this.trade.TradeDate && this.trade.ExerciseDate) { - this.getday(); - } - - }, - methods: { - getVol() { }, - //变更买入卖出 - changeBuySell(resetInitialMargin) { - 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(); - this.synchTrade(); - }, - //刷新定价模型名称 - 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); - this.getVol(true); - this.synchTrade(); - }, - blurSpotPrice() { - !this.trade.SpotPrice && (this.trade.SpotPrice !== 0) && (this.trade.SpotPrice = 0); - }, - //更改成交方式 - changeIsUsePremiumRate() { - tradeUtils.usePremiumRateSwitch(this.trade); - }, - //变更相对行权价 - 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.PremiumPayDate }) - .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; - } - 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) { - this.trade.ValueDate = this.trade.TradeDate; - if (!pageData.is厦门象屿) { - this.trade.PremiumPayDate = this.trade.TradeDate; - } - if (pageVue.IsCheck) return; - this.getTTM(force); - this.getday(); - this.getVol(); - this.getNoRiskRate(); - this.changeIsAnnualized(); - force !== 'import2' && this.getSpotPrice(true); - this.synchTrade(); - }, - //变更定价日期 - changeValueDate() { - this.getTTM(true); - this.synchTrade(); - }, - //变更到期日期 - changeExerciseDate() { - if (pageData.is厦门象屿) { - this.trade.PremiumPayDate = this.trade.ExerciseDate; - } - if (pageVue.IsCheck) return; - this.getTTM(); - this.getday(); - this.getVol(); - this.getNoRiskRate(); - this.synchTrade(); - }, - //变更结算日期 - changeSettlementDate() { - this.changeIsAnnualized(); - this.getTTM(); - this.synchTrade(); - }, - //更改权利金费率 - changePremiumRate() { - tradePricing.tradeCalc(this.trade, tradePricing.calcReason.PremiumRate, this.viewState.variety.CountRatio); - this.sumTotal(); - }, - //更改权利金单价 - changeTradeSinglePrice() { - tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradeSinglePrice, this.viewState.variety.CountRatio); - this.sumTotal(); - }, - //显示权利金绝对值 - showAbsPrice() { - this.trade.IsUsePremiumRate = false; - tradeUtils.usePremiumRateSwitch(this.trade); - this.sumTotal(); - }, - //显示权利金百分比 - showPercentPrice() { - this.trade.IsUsePremiumRate = true; - tradeUtils.usePremiumRateSwitch(this.trade); - this.sumTotal(); - }, - //更改交易总额 - changeTradePrice() { - tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradePrice, this.viewState.variety.CountRatio); - this.sumTotal(); - }, - //更改交易份额 - changeNotional(value) { - (typeof value === 'number') && (this.trade.Notional = value); - tradePricing.tradeCalc(this.trade, tradePricing.calcReason.Notional, this.viewState.variety.CountRatio); - this.trade.InitialMargin = null; - this.synchTrade(true); - }, - //更改有效交易数量 - changeTradeAmount(value) { - (typeof value === 'number') && (this.trade.TradeAmount = value); - tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradeAmount, this.viewState.variety.CountRatio); - this.trade.InitialMargin = null; - this.synchTrade(true); - }, - //更改交易数量 - changeTradeAmountV(value) { - (typeof value === 'number') && (this.trade.TradeAmountV = value); - tradePricing.tradeCalc(this.trade, tradePricing.calcReason.TradeAmountV, this.viewState.variety.CountRatio); - this.synchTrade(true); - }, - changeAccumuTradeAmount(value) { - (typeof value === 'number') && (this.trade.AccumuTradeAmount = value); - - this.trade.OriginalAccumuTradeAmount = this.trade.AccumuTradeAmount; - this.trade.TradeAmountV = this.trade.AccumuTradeAmount; - this.changeTradeAmountV(this.trade.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; - this.synchTrade(true); - }, - //变更有效名义本金 - changeStockEqvNotionalReal(value) { - (typeof value === 'number') && (this.trade.StockEqvNotionalReal = value); - tradePricing.tradeCalc(this.trade, tradePricing.calcReason.StockEqvNotionalReal, this.viewState.variety.CountRatio); - this.trade.InitialMargin = null; - this.synchTrade(true); - }, - //获取期权年化天数 - 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; - } - this.synchTrade(); - }, - //更改期权年化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(); - this.synchTrade(); - }, - //变更参与率/年化系数/保底收益率 - 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"; - this.synchTrade(); - }, - //变更Mid波动率 - changeOpenMidVolatility() { - this.viewState.MidVolState = "user"; - this.synchTrade(); - }, - //变更目标波动率 - changeCloseVolatility() { - this.viewState.CloseVolState = "user"; - }, - //变更TTMDays - changeTTM() { - this.viewState.TTMDays = "user"; - this.trade.IsTTMSystem = false; - if (pageData.is厦门象屿) { - this.trade.NumOfSmoothingDays = this.trade.TTMDays >= 10 ? 5 : 0; - } - this.synchTrade(); - }, - //获取交易日期和到期日期之间工作日的长度 - getTTM(force, changeNumOfSmoothingDays = true) { - if (force) { - this.viewState.TTMDays = "system"; - this.trade.IsTTMSystem = true; - } - 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 = ''; - } - } - }, - getday() { - var self = this; - var data = { - from: this.trade.TradeDate || this.trade.ValueDate, - to: this.trade.ExerciseDate - }; - if (data.from && data.to) { - main.post("/calendar/GetDay", data, false).done(function (resp) { - var TradingDays = Number.parseInt(resp.obj.TradingDays); - var Weekdays = Number.parseInt(resp.obj.Weekdays); - var PublicHolidays = Weekdays - TradingDays; - self.trade.TradingDays = TradingDays; - self.trade.Weekdays = Weekdays; - self.trade.PublicHolidays = PublicHolidays; - }); - } else { - self.trade.Weekdays = ''; - self.trade.TradingDays = ''; - self.trade.PublicHolidays = ''; - } - }, - //变更初始预付金 - changeInitialMargin() { - this.viewState.InitialMargin = 'user'; - this.resetSummary(resetSummaryFlags.initialMargin); - this.sumTotal(); - }, - //获取系统计算的初始预付金 - getInitialMargin() { - if (this.trade.TradeType === "自定义交易") { - this.trade.TradeOpenVolatility = null; - this.trade.Vol = null; - } - //检查并转换数据 - 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) { - self.trade.InitialMargin = parseFloat(resp.obj) + self.trade.TradePrice * (self.trade.BuySell == "买入" ? -1 : 1); - //非双向追保交易员收预付金,预付金不能小于0;交易员买入,付期权费收预付金,预付金不能小于0;交易员卖出,收期权费付预付金,预付金不能大于0 - if (pageVue.ClientUsedForCalc && !self.viewState.TwoSideMargin && self.trade.InitialMargin < 0) { - self.trade.InitialMargin = 0; - } - else if (self.trade.BuySell == "卖出" && self.trade.InitialMargin > 0) { - self.trade.InitialMargin = 0; - } - else if (self.trade.BuySell == "买入" && self.trade.InitialMargin < 0) { - self.trade.InitialMargin = 0; - } - self.trade.InitialMargin = pricingFormat.tradePrice(self.trade.InitialMargin); - self.viewState.InitialMargin = "system"; - self.resetSummary(resetSummaryFlags.initialMargin); - self.sumTotal(); - }); - }, - 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"; - 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; - self.trade.Vol = formatVol; - } - else { - self.trade.Vol = formatVol; - } - }); - }, - //获取系统Mid波动率 - getTradeMidVolatility(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 Midvol = resp.obj.Midvol; - if (isNaN(Midvol)) { - let msg = resp.msg || resp.message; - return main.message("未获取到Mid波动率: " + msg); - } - self.viewState.MidVolState = flag === 'user' ? "user" : "system"; - var formatVol = consNumberFormat.volValueFmt(Midvol); - self.trade.MidVol = 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'; - this.synchTrade(); - }, - //获取分红率 - getDividendRate() { - if (!this.trade.TradeDate) { - return main.alert("缺少交易日期"); - } - var self = this; - var postData = { underlyingCode: this.trade.UnderlyingCode, tradeDate: this.trade.TradeDate }; - main.post("/pricing/AjaxGetDividendRate", postData).done(function (resp) { - self.trade.DividendRate = resp.obj; - self.viewState.DividendRate = "system"; - }); - }, - //变更无风险利率 - changeNoRiskRate() { - this.viewState.NoRiskRate = 'user'; - this.synchTrade(); - }, - //获取无风险利率 - 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'; - let isST = observationId === '#ST'; - 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; - } - } - - if (isST) { - query.title1 = "固定价格"; - query.title2 = "是否了结"; - query.title3 = "了结价格"; - query.isTitle2TrueFalse = true; - query.isTitle1Percent = this.trade.IsMoneynessOption === "是"; - query.isTitle2Percent = false; - query.isTitle3Percent = this.trade.IsMoneynessOption === "是"; - } - - 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; - }, - setStructureList() { - var query = { - structure: this.trade.MetaDic["structures"], - CalcId: this.trade.CalcId - }; - query = $.param(query); - layer.open({ - type: 2, title: "设置结构要素", shadeClose: false, shade: 0.4, - area: ['900px', '560px'], content: "/trade/StructureList?" + query - }); - }, - setcashOrPhysical() { - var cashOrPhysical = this.viewState.CashOrPhysical; - this.trade.MetaDic["cashOrPhysical"] = cashOrPhysical; - }, - //变更奇异期权字段状态 - changeFieldState() { - this.fieldState.resetFieldState(this.trade, false); - }, - //设置观察频率 - setObservation(observationNum, observationUnit, observationHolidayType, observationDates, alignEnd, calcId, couponDayInterval, Comments, ObservationFrequency) { - if (!calcId) return; - let isKO = calcId.endsWith('#KO'); - let isComments = Comments != ""; - 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; - 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 === "累计期权" && self.trade.PayoffType === "固定") { - self.trade.KOObservationSettleDates = dates[1]; - self.trade.KOObservationDates = dates[0] + ";" + dates[2] + ";"; - observation.ObservationDates = observationDates + ";0"; - } else { - self.trade.KOObservationDates = observationDates; - } - if (!this.viewState.hasObservationDates) { - self.viewState.KOObservationSettle = _.clone(observation); - if (dates.length === 4) { - 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; - } - - 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 if (calcId.endsWith('#ST')) { - self.viewState.Observation = observation; - this.trade.MetaDic["observationDate"] = observationDates; - if (isComments || this.trade.MetaDic["ObservationRemark1"] != undefined) this.trade.MetaDic["ObservationRemark1"] = 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; - } - }, - setStructure(value, calcId) { - this.trade.MetaDic["structures"] = value; - }, - //变更票息结算方式 - 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(); - } - }, - //亚式结算方式 - consAsiaSettleModes() { - if (this.trade.PayoffType == 'EnhancedArithmeticAverage' && !this.trade.SettleMode) { - this.trade.SettleMode = 'AtHit'; - } - return consRebateTypes; - }, - 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(','); - 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 === "累计期权" && arr.length >= 3) { - arr = [].concat(arr[0], this.trade.KOObservationSettleDates, arr[1], arr[2]); - } - 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.PayoffType = '浮动'; - } - } - - 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); - } - }, - computed: { - maxTradeDate() { - let exerciseDate = this.trade.ExerciseDate; - return exerciseDate;//&& exerciseDate <= pageVue.SysDate ? exerciseDate : pageVue.SysDate; - }, - structure() { - return ""; - }, - 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: 10, 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; - }, - inputFormatTradePrice() { - return { precision: 2, negative: true, grouping: true, append: '' }; - }, - inputFormatNotional() { - let fmt = { precision: 10, 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 '双鲨期权': - this.trade.ExerciseMode = 'European'; return 1; - 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: '分段式' }]; - }, - //二元补偿支付类型 - 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: '敲入转牛市价差' }]; - } - } - } -}; - -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: 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, 10); - } - else if (eqvReal !== null) { - trade.StockEqvNotionalReal = _.round(eqvReal, 10); - 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.StockEqvNotional * 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)); \ No newline at end of file