//客户选择组件 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: '' }; }; //标的选择组件 const vueUnderlying = function () { const _suggestionTpl = _.template($('#underlyingSuggestionTpl').html()); return { props: ['underlying'], data() { return { jqInput: null, autoctrl: null }; }, mounted() { var self = this; this.jqInput = $(this.$el).children(0); this.autoctrl = FastVue.autocomplete(this.jqInput, { valueField: 'Code', lookup(query, callback) { var arr = []; if (!query) { var varietyId = self.underlying.VarietyId; ylotc.underlyings.forEach(x => { (!varietyId || x.VarietyId === varietyId) && arr.push(x); }); } else { query = query.toUpperCase(); ylotc.underlyings.forEach(x => { if (x.Code.toUpperCase().indexOf(query) !== -1 || x.PinYin && x.PinYin.indexOf(query) !== -1 && !x.IsCombined) { arr.push(x); } }); } if (arr.length < 30) { arr = _.sortBy(arr, x => x.Code); } return arr; }, 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.changeInstrumentType(); 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); } }, //变更标的类型 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) { let self = this; var instTypeChanged = !!reqData.InstrumentType; !fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying()); main.post("/pricing/AjaxGetUnderlying", reqData).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: item.ColumnType !== 4 || (item.value || item.ColumnDefaultValue + "").indexOf("%") > 0 ? ((item.value || item.ColumnDefaultValue) + "") : (((item.value || item.ColumnDefaultValue) * 100) + "%") }; 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(), }, });