const consDateFormat = new moment().format("YYYY-MM-DD"); const consHedgingTradeTypes = ["商品期货", "商品现货", "股票", "场内期权"]; const consHedgingTradeTypes2 = ["商品期货", "商品现货", "股票"]; const consDisablePingCangStates = ["修改待确认", "新增待确认", "平仓待复核", "行权待复核", "已平仓", "已到期", "已执行", "审批中"]; const consEnableConfirmStates = ["新增待确认", "修改待确认", "未确认", "Unwind"]; const consDisablePingCangTradeTypes = ["商品期货", "商品现货", "股票", "场内期权"]; const consOpenOperationRender = _.template($('#subOperationTpl').html() || ' '); const consPriceRenderU1 = _.template(($('#priceCalcTU1').html() || '').trim().replace(/[\r\n]+\s+/g, '') || ' '); const consPriceRenderU2 = _.template(($('#priceCalcTU2').html() || '').trim().replace(/[\r\n]+\s+/g, '') || ' '); const consPriceRenderV1 = _.template(($('#priceCalcTV1').html() || '').trim().replace(/[\r\n]+\s+/g, '') || ' '); const consPriceRenderV2 = _.template(($('#priceCalcTV2').html() || '').trim().replace(/[\r\n]+\s+/g, '') || ' '); const $jqDropdown = $('#jq-dropdown-1'); const consOptions = Object.freeze({ showDeltaT1: page.company === '光大光子' || page.company === '润和' }); var isUserUpdateIsSumHedging = false; //品种字典(品种代码作为key) const consVarietyMap = _.reduce(ylotc.varieties, (acc, cur) => { acc[cur.Code] = cur; return acc; }, {}); //标的板块字典 const consBlockMap = {}; //权益风险对冲处理 if (page.isStock) { var blockMap = _.reduce(ylotc.underlyingBlocks, function (result, value) { result[value.id.toString()] = value.Name; return result; }, {}); _.reduce(ylotc.underlyings, function (result, value) { result[value.Code] = [''].concat(value.Blocks.map(x => blockMap[x.toString()] || '其它')); return result; }, consBlockMap); } //数字格式化常量 const consNumberFormat = (function () { return { fixed2: main.numberFormat(2) , fixed0G: main.numberFormat(0, { grouping: true }) , fixed2G: main.numberFormat(2, { grouping: true }) //带千分位分隔的2位小数格式化 , fixed4G: main.numberFormat(4, { grouping: true }) //带千分位分隔的4位小数格式化 , fixed2P: main.numberFormat(2, { percent: true }) //带百分号的2位小数格式化 , fixed4P: main.numberFormat(4, { percent: true }) //带百分号的4位小数格式化 , umprice: main.numberFormat(page.isStock ? 3 : 2, { grouping: true }), //标的价格 //权利金 tradeSinglePrice: main.numberFormat(2, { grouping: true }), //成交总额,Pv, Pnl tradePrice: main.numberFormat(0, { grouping: true }), //份额 notional: main.numberFormat(2, { grouping: true }), //名义本金 StockEqvNotional: main.numberFormat(3), //期权费率 premiumRate: main.numberFormat(4), //期权费率% premiumRateP: main.numberFormat({ precision: 2, percent: true }), //希腊值 greek: main.numberFormat(2, { grouping: true }) }; }()); //过滤条件存储 const consStorageKey = page.isStock ? "realtimeRiskFilter_s" : "realtimeRiskFilter"; //已过期标的累积总盈亏重置 const consRiskAccPnlReset = (new function () { this.resetVCodes = []; if (page.company === '兴证') { this.resetVCodes = ['IC', 'AU']; } this.doReset = function (rowData) { if (this.resetVCodes.length && (rowData.UnderlyingCode || '').startsWith('$$') && this.resetVCodes.includes(_.trim(rowData.VarietyCode))) { rowData.AccruedTotalPnl = 0; } }.bind(this); }()); //是否广汽资本 const IsGuangQiZiBen = page.company === "广期资本"; const IsTianShi = page.company === "天示"; const IsDongZhengRunHe = page.company === "润和"; const IsHongTa = page.company === "红塔众鑫"; //jqGrid管理 const jqGridMgr = (function (page) { //主要用于品种数据和定价数据的状态跟踪 //枚举:1 品种,2 展开,4 标的价格试算, 8 品种价格试算 const ConsVariety = 1, ConsExpand = 2, ConsFixPrice = 4, ConsFixPriceV = 8; const $mainGrid = jQuery("#listGridMain"), $subGrid = $("#listGridSub"); const _postData = Object.assign({ VolType: page.VolType }, page.postData); !_postData.VolType && (_postData.VolType = page.VolType); const utils = (function () { const _instance = {}; const _mainPs = { scroll: null, container: null }; const _subPs = { scroll: null, container: null }; //映射已经保存下来的列配置 _instance.mapSavedColModel = function (savedData, originals) { if (!savedData) return originals; var columndata = savedData; if (!_.isArray(columndata)) { columndata = JSON.parse(savedData); if (!_.isArray(columndata)) return originals; } if (!columndata.length) return; _.each(originals, function (value, index) { value.$index = index; if (value.hidden2) { value.hidden = true; } else if (!value.optionHide) { index = columndata.findIndex(dd => dd.name === value.name); if (index >= 0) { value.hidden = columndata[index].hidden; value.$index = index; } } }); return _.sortBy(originals, x => x.$index); }; //设置主从表格的页面区域 _instance.setGridArea = function (initScroll) { function perfectScroll(gviewId) { var $hdiv = $(gviewId).find('.ui-jqgrid-hdiv').addClass('ui-jqgrid-hdiv-fixed'); const ps = new PerfectScrollbar(gviewId, {}); $(gviewId).on('ps-scroll-y', function () { var top = $(this).offset().top - $(this).find('.ui-jqgrid-bdiv').offset().top; $hdiv.css('top', top + 'px'); }); return ps; } var width = $('#mainCont').width(); var height = $(window).height() - (page.isMainView ? 105 : 35); var areaSettings = [ { gridId: 'listGridMain', width: width, height: 0 }, { gridId: 'listGridSub', width: width, height: 0 } ]; if (page.isMainView) { areaSettings[0].height = height; } else { areaSettings[1].height = height - 36; } areaSettings.forEach(function (item) { if (!$('#' + item.gridId).length) return; const gviewId = '#gview_' + item.gridId; $('#gbox_' + item.gridId + ',' + gviewId).width(item.width).height(item.height); if (initScroll) { var ps = perfectScroll(gviewId); if (item.gridId === 'listGridMain') { _mainPs.scroll = ps; _mainPs.container = gviewId; } else { _subPs.scroll = ps; _subPs.container = gviewId; } } var width = item.width - 2; var $hdiv = $(gviewId).children('.ui-jqgrid-hdiv'); if ($hdiv.width() < width) { $hdiv.width(width); $(gviewId).children('.ui-jqgrid-bdiv').width(width); $hdiv.children('.ui-jqgrid-sdiv').width(width); $('#gbox_' + item.gridId).find('table').width(width); } else { var minw = $hdiv.width() + 'px'; var $t = $hdiv.find("table").css('min-width', minw); $t.parentsUntil('.ui-jqgrid-hdiv').css('min-width', minw); var $bdiv = $(gviewId).children('.ui-jqgrid-bdiv'); minw = $bdiv.width() + 'px'; $t = $bdiv.find("table").css('min-width', minw); $t.parentsUntil('.ui-jqgrid-bdiv').css('min-width', minw); } }); }; //更新主表滚动条 _instance.updateMainScroll = function () { if (_mainPs.container) { _mainPs.scroll.update(); $(_mainPs.container).scrollTop(0); } }; //更新明细表滚动条 _instance.updateSubScroll = function () { if (_subPs.container) { _subPs.scroll.update(); $(_subPs.container).scrollTop(0); } }; return _instance; }()); var _priceCalcMap = {}; //主列表和明细弹窗的价格试算使用统一的字典 if (page.isMainView) { window.getPriceCalcMap = function () { return _priceCalcMap; }; } else if (parent.getPriceCalcMap) { _priceCalcMap = parent.getPriceCalcMap(); } const updateLock = (function () { const _instance = {}; var _lastLoadingTime = 0; _instance.update = function (time) { _lastLoadingTime = time || new Date().getTime(); }; _instance.canUpdate = function (time) { return _lastLoadingTime < time; }; return _instance; }()); const greeksFormat = consNumberFormat.greek; //希腊字母格式化 //明细子表 function subGrid() { const _grid = $subGrid; var _dataMap = {}, _dataRows = []; const _orderModel = { colName: null, order: null }; const intFormat = function (val) { return parseInt(val) || 0; }; const strikeFormat = consNumberFormat.umprice; const dateFormat = function (val) { return val ? val.substring(0, 10) : ''; }; const callputFormat = function (val) { return val === "Call" ? "看涨" : val === "Put" ? "看跌" : ""; } //过滤跟踪类 function filterTrace() { const _traceSettings = [ { key: 'TradeDate', set: new Set(), oldSet: null, hasNew: false, format: dateFormat }, { key: 'ExerciseDate', set: new Set(), oldSet: null, hasNew: false, format: dateFormat }, { key: 'ClientId', set: new Set(), oldSet: null, hasNew: false, format: null }, { key: 'Strike', set: new Set(), oldSet: null, hasNew: false, format: strikeFormat, sortBy: function (x) { return _.padStart(x, 10); } }, { key: 'OriginalNotional', set: new Set(), oldSet: null, hasNew: false, format: intFormat, sortBy: function (x) { return _.padStart(x, 10); } }, { key: 'TradeType', set: new Set(), oldSet: null, hasNew: false, format: null }, { key: 'CallPut', set: new Set(), oldSet: null, hasNew: false, format: callputFormat }, ]; const _clientMap = {}; //解析行数据并合并到过滤条件中 function _parseRow(rowData) { /* if (consHedgingTradeTypes2.includes(rowData.TradeType)) return;*/ _traceSettings.forEach(function (x) { var key = rowData[x.key]; x.format && (key = x.format(key)); if (!key) return; if (x.set.has(key)) { x.oldSet.delete(key); } else { x.set.add(key); x.hasNew = true; } }); rowData.ClientId && (_clientMap[rowData.ClientId] = rowData.ClientName); } const reducer = (accumulator, currentValue) => accumulator + currentValue; //应用过滤条件到页面下拉选项中 function _applyTrace(setting) { var update = setting.hasNew || setting.oldSet.size; if (update) { setting.oldSet.forEach(y => setting.set.delete(y)); var arr = []; setting.set.forEach(x => arr.push(x)); if (setting.sortBy) { arr = _.sortBy(arr, setting.sortBy); } else { arr.sort(); } var $sel = $('#sel' + setting.key); var selVal = $sel.val(); var html = ''; if (arr.length) { if (setting.key === 'ClientId') { html += arr.map(x => ``).reduce(reducer); } else { html += arr.map(x => ``).reduce(reducer); } } $sel.html(html); } } this.setTrace = function () { _traceSettings.forEach(function (x) { x.oldSet = new Set(); x.hasNew = false; x.set.forEach(y => x.oldSet.add(y)); }); return { parseRow: _parseRow, updateView: function () { _traceSettings.forEach(_applyTrace); } }; }; } const _filterTrace = new filterTrace(); //过滤操作类 function filter() { function filterModel(key, matchType) { const _instance = { key: key, value: '' }; //设置过滤值 _instance.setValue = function () { var val = $('#sel' + key).val(); if (val) { switch (matchType) { case 'int': val = intFormat(val); break; case 'like': val = val.toLowerCase(); break; } } _instance.value = val; }; //设置匹配函数 var _match = x => _instance.value === x; switch (matchType) { case 'int': _match = x => _instance.value === parseInt(x); break; case 'strike': _match = x => _instance.value === strikeFormat(x); break; case 'date': _match = x => x && _instance.value === x.substring(0, 10); break; case 'like': _match = x => x && x.toLowerCase().indexOf(_instance.value) >= 0; break; case 'callput': _match = x => _instance.value === callputFormat(x); break; } _instance.match = function (x, k) { return !_instance.value && _instance.value !== 0 || _match(x); }; return _instance; } const _filterModels = [ new filterModel('TradeNumber', 'like'), new filterModel('ClientId', 'int'), new filterModel('TradeDate', 'date'), new filterModel('ExerciseDate', 'date'), new filterModel('BuySell', 'string'), new filterModel('Strike', 'strike'), new filterModel('OriginalNotional', 'int'), new filterModel('TradeType', 'string'), new filterModel('CallPut', 'callput'), ]; this.setModel = function () { _filterModels.forEach(x => x.setValue()); }; this.match = function (rowData) { return _filterModels.every(x => x.match(rowData[x.key], x.key)); }; } const _filter = new filter(); //初始化从表 this.init = function () { //交易操作 function showSubToolName(cellValue, options, rowObject) { if (cellValue === "汇总") { return '汇总'; } if (consHedgingTradeTypes.includes(rowObject.TradeType)) { var onclick = `subView.historytradeView('${rowObject.UnderlyingCode}','${rowObject.TradeType}','${rowObject.BookId}','${rowObject.ExchangeOptionCode || ''}')`; return ''; } var minMaturityDay = rowObject.MaturityWorkDay; var minRealDay = rowObject.MaturityDay; var pictures = ['red', 'red', 'yellow', 'green']; var picture = pictures[minMaturityDay] || ''; if (picture) { picture = ``; } var tradeType = rowObject.TradeType; if (tradeType === "结构化交易") { tradeType = rowObject.StructureType; } onclick = `subView.openOperation('${rowObject.EncryptId}','${rowObject.StructureType}','${tradeType}','${rowObject.TradeStatus}','${rowObject.ExerciseDate}','${rowObject.TradeId}','${rowObject.ExerciseModeCn}','${rowObject.TradeNumber || ''}','${rowObject.UnderlyingCode}')`; return picture + ''; } //结构类型 function showTradeType(cellValue, options, rowObject) { if (rowObject.TradeType === "结构化交易") { var showTable = tradelistBase.setStructTable(rowObject); return `${showTable}`; } return rowObject.StructureType && rowObject.StructureType !== '结构化交易' ? rowObject.StructureType : rowObject.TradeType; } //看涨看跌 function showCallPut(cellValue, options, rowObject) { if (consHedgingTradeTypes2.includes(rowObject.TradeType)) return ''; if (rowObject.TradeType === "远期") { return cellValue === "Call" ? "多头" : cellValue === "Put" ? "空头" : ""; } else { return cellValue === "Call" ? "看涨" : cellValue === "Put" ? "看跌" : ""; } } //期权现价 function premiumRate(cellValue, options, rowObject) { return rowObject.InitSpotPrice ? (rowObject.Notional ? (rowObject.NPv || 0) / rowObject.Notional : 0) / rowObject.InitSpotPrice : NaN; } function getPvPerShare(cellValue, options, rowObject) { if (excludeHedge2(cellValue, options, rowObject)) return ''; if (rowObject.IsPremiumRate) { return consNumberFormat.premiumRateP(premiumRate(cellValue, options, rowObject)); } return rowObject.Notional ? consNumberFormat.tradeSinglePrice((rowObject.NPv || 0) / rowObject.Notional) : 0; } //对冲波动率% function hvolfloatFormat(cellValue, options, rowObject) { if (consHedgingTradeTypes2.includes(rowObject.TradeType)) return ''; return '' + hedgeVolFormat(cellValue) + ''; } //当前波动率% function cvolfloatFormat(cellValue, options, rowObject) { if (consHedgingTradeTypes2.includes(rowObject.TradeType)) return ''; if (rowObject.TradeType !== '场内期权' || page.VolType === '交易曲面') return hedgeVolFormat(cellValue); return '' + hedgeVolFormat(cellValue) + ''; } //日期 function dateFormat(cellValue, options, rowObject) { return cellValue ? cellValue.substring(0, 10) : ''; } //排除对冲交易类型 function excludeHedge2(cellValue, options, rowObject) { if (!!rowObject && consHedgingTradeTypes2.includes(rowObject.TradeType)) return ''; } function strikeFormat(cellValue, options, rowObject) { return ["商品期货", "商品现货", "股票"].includes(rowObject.TradeType) ? "" : consNumberFormat.umprice(cellValue); } const premiumPercentFormat = consNumberFormat.premiumRateP; const tradeSinglePriceFormat = consNumberFormat.tradeSinglePrice; function premiumFormat(cellValue, options, rowObject) { return (rowObject.IsPremiumRate ? premiumPercentFormat : tradeSinglePriceFormat)(cellValue, options, rowObject); } //成交份额|手数 const notionalFormat = consNumberFormat.notional; const curVolFormat = main.numberFormat(2, { percent: true, prefmt: excludeHedge2, rounded: false }); //当前波动率 const hedgeVolFormat = main.numberFormat(2, { percent: true, rounded: false }); //对冲波动率 //分红率 function dividendRateFormat(cellValue, options, rowObject) { if (consHedgingTradeTypes.includes(rowObject.TradeType)) return ''; return '' + hedgeVolFormat(cellValue) + ''; } //无风险利率 function noRiskRateFormat(cellValue, options, rowObject) { if (consHedgingTradeTypes.includes(rowObject.TradeType)) return ''; return '' + hedgeVolFormat(cellValue) + ''; } //交易方向 function buysellFormat(cellValue, options, rowObject) { return consHedgingTradeTypes2.includes(rowObject.TradeType) ? '' : cellValue; } var colModelSub = [ { name: 'TradeId', hidden: true, optionHide: true }, { name: 'TradeFlag', hidden: true, optionHide: true }, { name: 'EncryptId', label: '交易操作', width: 90, formatter: showSubToolName, optionHide: true, align: 'center', sortable: false }, { name: 'UnderlyingCode', label: '标的资产', optionHide: false, align: 'center' }, { name: 'SpotPrice', label: '标的价格', formatter: consNumberFormat.umprice, optionHide: false }, { name: 'ExchangeOptionCode', label: '期权代码', hidden: true, optionHide: true, align: 'center' }, { name: 'ExerciseModeCn', label: '行权方式', align: 'center' }, { name: 'TradeType', label: '结构类型', formatter: showTradeType, align: 'center' }, { name: 'CallPut', label: '看涨看跌', formatter: showCallPut, align: 'center' }, { name: 'ExerciseDate', label: '到期日期', width: 90, formatter: dateFormat, align: 'center' }, { name: 'OriginalNotionalV', label: '成交份额', width: 70, formatter: notionalFormat }, { name: 'OriginalNotional', label: '有效成交份额', width: 90, formatter: notionalFormat }, { name: 'Strike', label: '执行价格', width: 70, formatter: strikeFormat }, { name: 'Premium', label: '权利金', formatter: premiumFormat, sortable: false }, { name: 'PvPerShare', label: '市值单价', formatter: getPvPerShare, sortable: false }, { name: 'Pv', label: '市值总额', formatter: otcformat.trading.tradePrice }, { name: 'PvContainsKnockOut', label: '市值总额*', formatter: otcformat.trading.tradePrice, hidden: true }, { name: 'Tv', label: '时间价值', formatter: main.numberFormat(2, { prefmt: excludeHedge2 }) }, { name: 'OpenVol', label: '开仓波动率', width: 90, formatter: curVolFormat }, { name: 'Vol', label: '当前波动率', width: 90, formatter: cvolfloatFormat, hidden: page.VolType === '对冲' }, { name: 'ExercisePnl', label: '行权盈亏', formatter: consNumberFormat.tradePrice }, { name: 'DailyPnl', label: '当日盈亏', formatter: consNumberFormat.tradePrice }, { name: 'TotalPnl', label: '总估值盈亏', width: 90, hidden: true, formatter: consNumberFormat.tradePrice }, { name: 'AccruedTotalPnl', label: '累积总盈亏', width: 90, hidden: true, formatter: consNumberFormat.tradePrice }, { name: 'PnlWithHedge', label: '对冲盈亏', width: 92, formatter: consNumberFormat.tradePrice }, { name: 'TotalPnlWithHedge', label: '对冲总盈亏', width: 92, formatter: consNumberFormat.tradePrice }, { name: 'DeltaInLots', label: 'Delta手数', width: 90, formatter: consNumberFormat.notional }, { name: 'DeltaInLotsContainsKnockOut', label: 'Delta手数*', width: 90, formatter: consNumberFormat.notional, hidden: true }, { name: 'CompanyObj.PositionAdjustLots', label: '调仓手数', width: 90, formatter: consNumberFormat.notional, hidden: !IsTianShi, optionHide: !IsTianShi }, { name: 'CompanyObj.RiskDegree', label: '风险度', width: 90, formatter: consNumberFormat.fixed2P, hidden: !IsTianShi, optionHide: !IsTianShi }, { name: 'GammaInLots', label: 'Gamma手数', width: 96, formatter: consNumberFormat.notional }, { name: 'GammaInLotsContainsKnockOut', label: 'Gamma手数*', width: 96, formatter: consNumberFormat.notional, hidden: true }, { name: 'Delta', width: 70, formatter: greeksFormat }, { name: 'SA_Delta', width: 90, formatter: greeksFormat }, { name: 'Gamma', width: 70, formatter: greeksFormat }, { name: 'Theta', width: 70, formatter: greeksFormat }, { name: 'Vega', width: 70, formatter: greeksFormat }, { name: 'DeltaCash', label: 'Delta现金', width: 90, formatter: consNumberFormat.tradePrice }, { name: 'Rho', width: 70, formatter: greeksFormat }, { name: 'GammaCash', label: ylotc.Company === "国贸启润" ? "1%gammacash" : "GammaCash", width: 110, formatter: consNumberFormat.tradePrice }, { name: 'TradeNumber', label: '交易编号', width: 150, align: 'left' }, { name: 'ClientName', label: '客户名称', align: 'left' }, { name: 'LotsNewInfo', label: '持仓手数', formatter: notionalFormat }, { name: 'Lots', label: '有效成交手数', formatter: notionalFormat }, { name: 'BuySell', label: '交易方向', align: 'center', formatter: buysellFormat }, { name: 'TradeDate', label: '交易日期', width: 90, formatter: dateFormat, align: 'center' }, { name: 'TradeSavedVol', label: '对冲波动率', width: 96, formatter: hvolfloatFormat, hidden: !page.showTradeSavedVol, optionHide: !page.showTradeSavedVol, align: 'center' }, { name: 'DividendRate', label: '分红率', width: 96, formatter: dividendRateFormat, align: 'center' }, { name: 'NoRiskRate', label: '无风险利率', width: 96, formatter: noRiskRateFormat, align: 'center' } ]; if (consOptions.showDeltaT1) { let index = colModelSub.findIndex(x => x.name === 'Delta') + 1; colModelSub.splice(index, 0, { name: 'DeltaT1Lots', label: 'Delta(T+1)', width: 70, formatter: greeksFormat }); } if (IsGuangQiZiBen) { colModelSub.push({ name: 'CompanyObj.DeltaAdjust', label: '调整Delta暴露', width: 100, formatter: greeksFormat }); colModelSub.push({ name: 'CompanyObj.GammaAdjust', label: '调整Gamma暴露', width: 100, formatter: greeksFormat }); } colModelSub = utils.mapSavedColModel(page.subSavedColData, colModelSub); colModelSub.forEach(function (x) { if (x.name === 'TradeSavedVol') x.hidden = page.VolType !== '对冲'; else if (x.name === 'Vol') x.hidden = page.VolType === '对冲'; }); var jqGridOptions = { datatype: "local", height: 300, cmTemplate: { width: 80, align: 'right', sortable: true }, colModel: colModelSub, rowNum: -1, loadui: 'disable', gridview: true, rowattr: function (rd) { if (rd.TradeType === '商品期货' || rd.TradeType === '场内期权' || rd.TradeType === '商品现货' || rd.TradeType === '股票') { return { "class": "yl-grid-hedging" }; } else if (rd.TradeFlag === 299) { return { "class": "yl-grid-yuanqi" }; } }, onSortCol: function (index, iCol, sortorder) { _orderModel.colName = index; _orderModel.order = sortorder; _reloadData(); return 'stop'; }, //autowidth: false, //shrinkToFit: false, footerrow: true, viewrecords: true, //onPaging: onJqgridPaging }; _grid.jqGrid(jqGridOptions); }; //对给定列数据进行排序 function _orderRows(rows) { const arrs = _.partition(rows, x => x.TradeId > 0 || x.TradeType === '场内期权'); if (_orderModel.colName) { arrs[0] = _.orderBy(arrs[0], [_orderModel.colName], [_orderModel.order]); } else { arrs[0] = _.sortBy(arrs[0], function (x) { return (x.TradeId < 1 ? '1_' : '0_') + x.UnderlyingCode + x.ExerciseDate + x.TradeNumber; }); } arrs[1] = _.sortBy(arrs[1], x => x.UnderlyingCode + x.ExerciseDate); return _.concat(arrs[0], arrs[1]); } //对明细子表重新加载数据(带排序过滤) function _reloadData() { updateLock.update(); var rows = _orderRows(_dataRows); _grid.jqGrid('clearGridData'); var sumData = { OriginalNotionalV: 0, OriginalNotional: 0, Pv: 0, PvContainsKnockOut: 0, Tv: 0, ExercisePnl: 0, DailyPnl: 0, TotalPnl: 0, AccruedTotalPnl: 0, PnlWithHedge: 0, TotalPnlWithHedge: 0, DeltaInLots: 0, DeltaInLotsContainsKnockOut: 0, GammaInLots: 0, GammaInLotsContainsKnockOut: 0, Delta: 0, SA_Delta: 0, Gamma: 0, Theta: 0, Vega: 0, DeltaCash: 0, Rho: 0, GammaCash: 0, LotsNewInfo: 0, Lots: 0, } let isSumHedging = $("#isSumHedging").prop('checked') _.each(rows, function (data) { if (!_filter.match(data)) return; data.PvPerShare = new Date(); var rowid = data.TradeId > 0 ? data.TradeId + '' : data.ExchangeOptionCode || data.UnderlyingCode; _grid.jqGrid('addRowData', rowid, data); sumRowData(sumData, data, isSumHedging); }); utils.updateSubScroll(); footerData(sumData); } //var sumData = { // SpotPrice: 0, // OriginalNotionalV: 0, // OriginalNotional: 0, // Strike: 0, // Pv: 0, // Tv: 0, // ExercisePnl: 0, // DailyPnl: 0, // TotalPnl: 0, // AccruedTotalPnl: 0, // PnlWithHedge: 0, // TotalPnlWithHedge: 0, // DeltaInLots: 0, // GammaInLots: 0, // Delta: 0, // SA_Delta: 0, // Gamma: 0, // Theta: 0, // Vega: 0, // DeltaCash: 0, // Rho: 0, // GammaCash: 0, // LotsNewInfo: 0, // Lots: 0, //} function sumRowData(sumData, data, isSumHedging) { //如果包含场内,否则只计算场外期权的加和 if (isSumHedging || (data.TradeType !== "场内期权" && data.TradeType !== '商品期货')) { sumData.OriginalNotionalV += $.isNumeric(data.OriginalNotionalV) ? parseFloat(data.OriginalNotionalV) : 0; sumData.OriginalNotional += $.isNumeric(data.OriginalNotional) ? parseFloat(data.OriginalNotional) : 0; sumData.Pv += $.isNumeric(data.Pv) ? parseFloat(data.Pv) : 0; sumData.PvContainsKnockOut += $.isNumeric(data.PvContainsKnockOut) ? parseFloat(data.PvContainsKnockOut) : 0; sumData.Tv += $.isNumeric(data.Tv) ? parseFloat(data.Tv) : 0; sumData.ExercisePnl += $.isNumeric(data.ExercisePnl) ? parseFloat(data.ExercisePnl) : 0; sumData.DailyPnl += $.isNumeric(data.DailyPnl) ? parseFloat(data.DailyPnl) : 0; sumData.TotalPnl += $.isNumeric(data.TotalPnl) ? parseFloat(data.TotalPnl) : 0; sumData.AccruedTotalPnl += $.isNumeric(data.AccruedTotalPnl) ? parseFloat(data.AccruedTotalPnl) : 0; sumData.PnlWithHedge += $.isNumeric(data.PnlWithHedge) ? parseFloat(data.PnlWithHedge) : 0; sumData.TotalPnlWithHedge += $.isNumeric(data.TotalPnlWithHedge) ? parseFloat(data.TotalPnlWithHedge) : 0; sumData.DeltaInLots += $.isNumeric(data.DeltaInLots) ? parseFloat(data.DeltaInLots) : 0; sumData.DeltaInLotsContainsKnockOut += $.isNumeric(data.DeltaInLotsContainsKnockOut) ? parseFloat(data.DeltaInLotsContainsKnockOut) : 0; sumData.GammaInLots += $.isNumeric(data.GammaInLots) ? parseFloat(data.GammaInLots) : 0; sumData.GammaInLotsContainsKnockOut += $.isNumeric(data.GammaInLotsContainsKnockOut) ? parseFloat(data.GammaInLotsContainsKnockOut) : 0; sumData.Delta += $.isNumeric(data.Delta) ? parseFloat(data.Delta) : 0; sumData.SA_Delta += $.isNumeric(data.SA_Delta) ? parseFloat(data.SA_Delta) : 0; sumData.Gamma += $.isNumeric(data.Gamma) ? parseFloat(data.Gamma) : 0; sumData.Theta += $.isNumeric(data.Theta) ? parseFloat(data.Theta) : 0; sumData.Vega += $.isNumeric(data.Vega) ? parseFloat(data.Vega) : 0; sumData.DeltaCash += $.isNumeric(data.DeltaCash) ? parseFloat(data.DeltaCash) : 0; sumData.Rho += $.isNumeric(data.Rho) ? parseFloat(data.Rho) : 0; sumData.GammaCash += $.isNumeric(data.GammaCash) ? parseFloat(data.GammaCash) : 0; sumData.LotsNewInfo += $.isNumeric(data.LotsNewInfo) ? parseFloat(data.LotsNewInfo) : 0; sumData.Lots += $.isNumeric(data.Lots) ? parseFloat(data.Lots) : 0; } } function footerData(sumData) { _grid.footerData("set", { EncryptId: "汇总", OriginalNotionalV: sumData.OriginalNotionalV, OriginalNotional: sumData.OriginalNotional, Premium: sumData.Premium, PvPerShare: sumData.PvPerShare, Pv: sumData.Pv, PvContainsKnockOut: sumData.PvContainsKnockOut, Tv: sumData.Tv, ExercisePnl: sumData.ExercisePnl, DailyPnl: sumData.DailyPnl, TotalPnl: sumData.TotalPnl, AccruedTotalPnl: sumData.AccruedTotalPnl, PnlWithHedge: sumData.PnlWithHedge, TotalPnlWithHedge: sumData.TotalPnlWithHedge, DeltaInLots: sumData.DeltaInLots, DeltaInLotsContainsKnockOut: sumData.DeltaInLotsContainsKnockOut, GammaInLots: sumData.GammaInLots, GammaInLotsContainsKnockOut: sumData.GammaInLotsContainsKnockOut, Delta: sumData.Delta, SA_Delta: sumData.SA_Delta, Gamma: sumData.Gamma, Theta: sumData.Theta, Vega: sumData.Vega, DeltaCash: sumData.DeltaCash, Rho: sumData.Rho, GammaCash: sumData.GammaCash, LotsNewInfo: sumData.LotsNewInfo, Lots: sumData.Lots }); $(".ui-jqgrid-ftable").width($(".ui-jqgrid-htable").width()); } //更新明细子表数据(和主表不联动时使用此方法) this.updateDataRows = function (rows) { _dataRows = _.flatMap(rows, x => { var y = _priceCalcMap[x.UnderlyingCode]; return (y && y.viewList ? y : x).viewList || []; }); _dataRows = _orderRows(_dataRows); var preRowId = '', dataMap = {}, rowIds = _grid.jqGrid('getDataIDs'); var trace = _filterTrace.setTrace(); var sumData = { OriginalNotionalV: 0, OriginalNotional: 0, Pv: 0, PvContainsKnockOut: 0, Tv: 0, ExercisePnl: 0, DailyPnl: 0, TotalPnl: 0, AccruedTotalPnl: 0, PnlWithHedge: 0, TotalPnlWithHedge: 0, DeltaInLots: 0, DeltaInLotsContainsKnockOut: 0, GammaInLots: 0, GammaInLotsContainsKnockOut: 0, Delta: 0, SA_Delta: 0, Gamma: 0, Theta: 0, Vega: 0, DeltaCash: 0, Rho: 0, GammaCash: 0, LotsNewInfo: 0, Lots: 0, } if (!page.isSumOnlyOTC && !isUserUpdateIsSumHedging) { $("#isSumHedging").prop("checked", true); } let isSumHedging = $("#isSumHedging").prop('checked'); _.each(_dataRows, function (data) { trace.parseRow(data); if (!_filter.match(data)) return; data.PvPerShare = new Date(); let rowid = data.TradeId > 0 ? data.TradeId + '' : data.ExchangeOptionCode || data.UnderlyingCode; let index = rowIds.indexOf(rowid); dataMap[rowid] = data; if (index < 0) { _grid.jqGrid('addRowData', rowid, data, preRowId ? 'after' : 'first', preRowId); } else { rowIds[index] = null; _grid.jqGrid('setRowData', rowid, data); } preRowId = rowid; sumRowData(sumData, data, isSumHedging); }); trace.updateView(); _dataMap = dataMap; //清除失效数据 _.each(rowIds, function (rowid) { rowid && _grid.jqGrid('delRowData', rowid); }); $("tr.jqgrow", _grid).css("cursor", "default"); footerData(sumData); }; //根据rowid获取子表数据 this.getData = function (rowid) { return _dataMap[rowid]; }; //执行过滤数据 this.filterData = function () { _filter.setModel(); _reloadData(); }; } const _subGrid = new subGrid(); //主表 function mainGrid() { const _grid = $mainGrid; //用于判断品种分组合并时字段是否需要求和 let arr = ['ExercisePnl', 'TotalPnl', 'AccruedTotalPnl', 'DailyPnl', 'Theta', 'Pv', 'PvContainsKnockOut', 'HedgePv', 'Tv', 'DeltaInLots', 'DeltaInLotsContainsKnockOut', 'HedgeDeltaLots', 'GammaInLots', 'GammaInLotsContainsKnockOut', 'Vega', 'Rho', 'Delta', 'HedgeDelta', 'SA_Delta', 'DeltaCash', 'DeltaCash2', 'Gamma', 'DdeltaDt', 'DdeltaDvol', 'DvegaDt', 'DvegaDvol', 'GammaCash', 'DeltaCustom', 'GammaCustom']; page.volAdjust && arr.push('DeltaAdjust') && arr.push('GammaAdjust'); page.isStock && arr.push('SpotPrice') && arr.push('SpotPriceChangePercent'); IsHongTa && arr.push('ThetaNet'); if (consOptions.showDeltaT1) { let index = arr.indexOf('Delta') + 1; arr.splice(index, 0, 'DeltaT1Lots'); } const varietyGroupSumObj = Object.freeze(_.zipObject(arr, _.fill(Array(50), 0))); var _dataMap = {}, _dataRows = []; const _orderModel = { colName: null, order: null }; const _footerData = { VarietyCode: '$$foot', rowFlag: 0 }; //初始化主表 this.init = function () { //标的代码 function underlyingFormat(cellValue, options, rowObject) { var tipText = '', varietyFlag = ''; if (rowObject.rowFlag & ConsVariety) { varietyFlag = '$$'; if (!page.isStock) { var variety = consVarietyMap[rowObject.UnderlyingCode.trimEnd()] || { Name: rowObject.UnderlyingCode, TradeUnit: 'NA', QuoteUnit: 'NA' }; tipText = variety.Name + ',合约乘数:' + variety.TradeUnit + ",报价单位:" + variety.QuoteUnit; } } else if (!page.isStock) { tipText = ylotc.getUnderlying(rowObject.UnderlyingCode, 'Name') || ''; } return `${cellValue}`; } //DailyPnl function dailyPnlFormat(cellValue, options, rowObject) { var formatVal = consNumberFormat.tradePrice(cellValue); var style = cellValue < 0 ? 'color:green' : cellValue > 1e-5 ? "color:red" : ''; return `${formatVal}`; } //标的价格 function spotPriceFormat(cellValue, options, rowObject) { if (cellValue === '') return; var isVarietyRow = rowObject.rowFlag & ConsVariety; var formatVal = consNumberFormat.umprice(cellValue); var percent = rowObject.SpotPriceChangePercent; var style = percent < 0 ? 'color:green;' : percent > 1e-5 ? "color:red;" : 'color:inherit;'; if (isVarietyRow) { return page.isStock ? rowObject.rowFlag & ConsExpand ? ' ' : `${formatVal}` : rowObject.rowFlag & ConsFixPriceV ? consPriceRenderV2({ price: formatVal, UnderlyingCode: rowObject.UnderlyingCode }) : consPriceRenderV1({ style: style, UnderlyingCode: rowObject.UnderlyingCode, formatVal: rowObject.rowFlag & ConsExpand ? ' ' : formatVal }); } if (rowObject.rowFlag & ConsFixPriceV) { return `${formatVal}`; } return rowObject.rowFlag & ConsFixPrice ? consPriceRenderU2({ price: cellValue, UnderlyingCode: rowObject.UnderlyingCode }) : consPriceRenderU1({ style: style, UnderlyingCode: rowObject.UnderlyingCode, formatVal: formatVal }); } //涨跌幅 function spotPriceChangePercentFormat(cellValue, options, rowObject) { if (cellValue === '' || (rowObject.rowFlag & ConsVariety) && (rowObject.rowFlag & (ConsExpand | ConsFixPriceV))) { return ''; } var formatVal = consNumberFormat.fixed2P(cellValue); var style = cellValue < 0 ? 'color:green' : cellValue > 1e-5 ? "color:red" : ''; return `${formatVal}`; } //Delta风险敞口 function deltaRiskFormat(cellValue, options, rowObject) { return rowObject.rowFlag & ConsVariety ? consNumberFormat.fixed2P(cellValue) : ''; } //行勾选 function checkboxFormat(cellValue, options, rowObject) { return rowObject.rowFlag & ConsVariety ? '' : ''; } //展开折叠 function expandFormat(cellValue, options, rowObject) { var fa = rowObject.rowFlag & ConsExpand ? ' fa-minus' : ''; if (rowObject.VarietyCode === '$$foot') { return ``; } return rowObject.rowFlag & ConsVariety ? `` : ''; } //场外Pv格式化 function otcPvFormat(cellValue, options, rowObject) { return consNumberFormat.tradePrice(rowObject.Pv - (rowObject.HedgePv || 0)); } //场外Delta格式化 function otcDeltaFormat(cellValue, options, rowObject) { return greeksFormat(rowObject.Delta - (rowObject.HedgeDelta || 0)); } let hidden_unm = !page.isStock && !page.IncludeStock; let colModel = [ { name: 'rowFlag', label: ' ', width: 30, optionHide: true, formatter: expandFormat, hidden: !page.isMainView, align: 'center' }, { name: 'VarietyCode', label: '品类', width: 30, hidden: true, optionHide: true, align: 'center' }, { name: 'UnderlyingCode', label: '标的代码', width: 100, optionHide: true, formatter: underlyingFormat, title: false, align: 'center', sortable: true }, { name: 'UnderlyingName', label: '标的名称', optionHide: hidden_unm, hidden: hidden_unm, hidden2: hidden_unm, width: 130, align: 'center' }, { name: 'SpotPrice', label: '标的价格', formatter: spotPriceFormat, sortable: true }, { name: 'SpotPriceChangePercent', label: '涨跌幅', width: 95, formatter: spotPriceChangePercentFormat, sortable: true }, { name: 'DeltaPercent', label: 'Delta%', width: 90, formatter: consNumberFormat.premiumRateP }, { name: 'ExercisePnl', label: '行权盈亏', width: 120, formatter: consNumberFormat.tradePrice }, { name: 'DailyPnl', label: 'DailyPnl', width: 120, formatter: dailyPnlFormat, sortable: true }, { name: 'TotalPnl', label: 'TotalPnl', width: 120, formatter: consNumberFormat.tradePrice }, { name: 'AccruedTotalPnl', label: '累积总盈亏', width: 120, formatter: consNumberFormat.tradePrice, sortable: true }, { name: 'Pv', label: 'Pv', width: 120, formatter: consNumberFormat.tradePrice, sortable: true }, { name: 'PvContainsKnockOut', label: 'Pv*', width: 120, formatter: consNumberFormat.tradePrice, sortable: true, hidden: true }, { name: 'OtcPv', label: '场外Pv', width: 120, formatter: otcPvFormat, sortable: true }, { name: 'HedgePv', label: '对冲Pv', width: 120, formatter: consNumberFormat.tradePrice, sortable: true }, { name: 'Tv', label: '时间价值', width: 120, formatter: consNumberFormat.fixed0G, hidden: !page.isStock, optionHide: !page.isStock }, { name: 'DeltaInLots', label: 'Delta手数', width: 100, formatter: consNumberFormat.notional, sortable: true }, { name: 'DeltaInLotsContainsKnockOut', label: 'Delta手数*', width: 100, formatter: consNumberFormat.notional, sortable: true, hidden: true }, { name: 'HedgeDeltaLots', label: '对冲Delta手数', width: 100, formatter: consNumberFormat.notional, sortable: true }, { name: 'GammaInLots', label: 'Gamma手数', width: 100, formatter: consNumberFormat.notional }, { name: 'GammaInLotsContainsKnockOut', label: 'Gamma手数*', width: 100, formatter: consNumberFormat.notional, hidden: true }, { name: 'Vega', formatter: greeksFormat }, { name: 'Theta', formatter: greeksFormat }, { name: 'Rho', hidden: true, formatter: greeksFormat }, { name: 'Delta', width: 120, hidden: true, formatter: greeksFormat, sortable: true }, { name: 'OtcDelta', label: '场外Delta', width: 120, hidden: true, formatter: otcDeltaFormat, sortable: true }, { name: 'HedgeDelta', label: '对冲Delta', width: 120, hidden: true, formatter: greeksFormat, sortable: true }, { name: 'SA_Delta', width: 120, hidden: true, formatter: greeksFormat }, { name: 'DeltaCash', label: 'Delta现金', width: 120, hidden: true, formatter: consNumberFormat.tradePrice }, { name: 'Gamma', width: 90, hidden: true, formatter: greeksFormat }, { name: 'DdeltaDt', width: 90, hidden: true, formatter: greeksFormat }, { name: 'DdeltaDvol', width: 105, hidden: true, formatter: consNumberFormat.fixed2G }, { name: 'DvegaDt', width: 90, hidden: true, formatter: greeksFormat }, { name: 'DvegaDvol', width: 105, hidden: true, formatter: consNumberFormat.fixed2G }, { name: 'GammaCash', width: 100, hidden: true, formatter: consNumberFormat.tradePrice } ]; if (page.viewMode === '1') { const colNames = ['SpotPrice', 'SpotPriceChangePercent', 'DailyPnl', 'AccruedTotalPnl', 'DeltaInLots', 'HedgeDeltaLots', 'GammaInLots', 'Vega', 'Theta', 'Rho']; colModel.forEach(function (x) { x.hidden = x.optionHide ? x.hidden : colNames.indexOf(x.name) < 0; }); } if (page.volAdjust) { colModel.push({ name: 'DeltaAdjust', label: 'Delta调整', width: 120, formatter: greeksFormat }); colModel.push({ name: 'GammaAdjust', label: 'Gamma调整', width: 120, formatter: greeksFormat }); } if (page.deltaRisk) { colModel.push({ name: 'DeltaRiskNet', label: 'Delta风险敞口(轧差)', width: 135, formatter: deltaRiskFormat }); colModel.push({ name: 'DeltaRiskAbs', label: 'Delta风险敞口(绝对)', width: 135, formatter: deltaRiskFormat }); } if (IsGuangQiZiBen) { colModel.push({ name: 'CompanyObj.DeltaAdjust', label: '调整Delta暴露', width: 105, formatter: greeksFormat }); colModel.push({ name: 'CompanyObj.GammaAdjust', label: '调整Gamma暴露', width: 105, formatter: greeksFormat }); } if (ylotc.Company === "国贸启润") { colModel.push({ name: 'DeltaCustom', label: 'Delta限额比例', width: 120, formatter: consNumberFormat.premiumRateP, sortable: true }); colModel.push({ name: 'GammaCustom', label: '调整GammaCash', width: 120, formatter: greeksFormat, sortable: true }); } if (IsDongZhengRunHe) { function otcDeltaCash2Format(cellValue, options, rowObject) { return consNumberFormat.tradePrice(cellValue); } colModel.push({ name: 'DeltaCash2', label: 'DeltaCash限额', width: 105, formatter: otcDeltaCash2Format }); } if (IsHongTa) { colModel.push({ name: 'ThetaNet', label: 'Theta(轧差)', formatter: greeksFormat, sortable: false }); } if (consOptions.showDeltaT1) { let index = colModel.findIndex(x => x.name === 'Delta') + 1; colModel.splice(index, 0, { name: 'DeltaT1Lots', label: "Delta(T+1)", width: 120, formatter: greeksFormat, sortable: true }); } colModel = utils.mapSavedColModel(page.mainSavedColData, colModel, page.configcolumn_mainlist); const jqGridOptions = { datatype: "local", height: 500, cmTemplate: { width: 80, align: 'right', sortable: false }, align: 'center', colModel: colModel, rowNum: -1, loadui: 'disable', //add时生效(折叠是删行操作,故展开时生效) rowattr: function (rd) { if (rd.rowFlag & ConsVariety) { return { "class": "yl-grid-variety" }; } else { return { "class": "yl-grid-underlying" + (rd.rowFlag & ConsFixPrice ? " yl-fixed-price" : "") + (rd.rowFlag & ConsFixPriceV ? " yl-fixed-priceV" : "") }; } }, resizeStop: utils.setGridArea, footerrow: true, gridview: true, userDataOnFooter: false, hoverrows: false, beforeSelectRow: function (rowid, e) { if ($(e.target).prev().length < 1) { return false; } return true; }, ondblClickRow: function (rowid, iRow, iCol, e) { iCol > 0 && jqGridEventHandler.showSubViewPage(rowid); }, onSortCol: function (index, iCol, sortorder) { _orderModel.colName = index; _orderModel.order = sortorder; _grid.jqGrid('clearGridData', true); _ajaxUpdate(); return 'stop'; } }; return _grid.jqGrid(jqGridOptions); }; function _removeRowClass(rowid, classNames) { let tr = _grid[0].rows.namedItem(rowid); $(tr).removeClass(classNames); } //主表数据分组合并 function _groupingData(rows) { //对品种分组 var sortable = page.mainSortable; if (sortable && sortable.length) { rows = _.sortBy(rows, function (x) { var index = _.indexOf(sortable, x.VarietyCode.trim()); return index < 0 ? '1' + x.VarietyCode : _.padStart('' + index, 5, '0'); }); } //对每一行数据进行处理 let eachRowFns = [consRiskAccPnlReset.doReset]; if (page.blockType) { eachRowFns.push(x => { consBlockMap[x.UnderlyingCode] && (x.VarietyCode = consBlockMap[x.UnderlyingCode][page.blockType]); }); } rows.forEach(x => eachRowFns.forEach(y => y(x))); _.assign(_footerData, varietyGroupSumObj, { CompanyObj: { DeltaAdjust: 0, GammaAdjust: 0 } }); var varietyGroup = _.groupBy(rows, x => x.VarietyCode); rows = []; _.forIn(varietyGroup, function (urows, key) { let calcData = page.isStock ? null : _priceCalcMap[key]; let gdata = calcData || _dataMap[key] || { rowFlag: ConsVariety, UnderlyingCode: key, VarietyCode: '$$group', SpotPrice: 0 }; //在这里对urows排序; gdata.$rows = _orderRows(urows); //股票品种行不需要价格 let rows2 = sumVariety(gdata, page.isStock ? 'stock' : calcData); _.forIn(gdata, function (val, name) { if (name in varietyGroupSumObj) { _footerData[name] += val || 0; } }); ////delta定制 品种 取绝对值 gdata.DeltaCustom = Math.abs(gdata.DeltaCustom); if (IsGuangQiZiBen && gdata.CompanyObj) { _footerData.CompanyObj.DeltaAdjust += gdata.CompanyObj.DeltaAdjust || 0; _footerData.CompanyObj.GammaAdjust += gdata.CompanyObj.GammaAdjust || 0; } rows.push(gdata); rows = rows.concat(rows2); !page.isStock && _.remove(gdata.$rows, x => x.UnderlyingCode.startsWith('$$')); }); _footerData.SpotPrice = ''; _footerData.SpotPriceChangePercent = ''; _footerData.OtcPv = _footerData.OtcDelta = new Date(); //delta定制 总汇总 取绝对值 _footerData.DeltaCustom = Math.abs(_footerData.DeltaCustom); return rows; } //根据标的代码筛选 function _filterByUnderlyingCode(rows) { var umCode = $('#selectUnderlying2').val(); if (!umCode) { rows.forEach(x => x.rowFlag = 0); return rows; } return _.filter(rows, x => x.UnderlyingCode === umCode); } //其它品种合并字段(定制字段处理) const otherSumVarietyData = Object.freeze({ SpotPrice: 0, DeltaPercent: 0, StockEqvNotional: 0, DeltaRiskAbs: 0, DeltaRiskNet: 0 }); //合计品种行的值(gdata必须有$rows属性) function sumVariety(gdata, spotPriceOk) { gdata = _.assign(gdata, varietyGroupSumObj, { CompanyObj: { DeltaAdjust: 0, GammaAdjust: 0 } }, otherSumVarietyData, spotPriceOk ? { SpotPrice: gdata.SpotPrice } : null); let rows = [], variety = page.isStock ? null : consVarietyMap[gdata.UnderlyingCode.trimEnd()]; _.forEach(gdata.$rows, function (data) { if (data.UnderlyingCode.startsWith('$$')) { gdata.AccruedTotalPnl += data.AccruedTotalPnl; return; } data = _priceCalcMap[data.UnderlyingCode] || data; if (page.volAdjust && variety) { var volAdjust = variety.VolAdjust; data.DeltaAdjust = volAdjust ? volAdjust * data.Delta * data.SpotPrice / 16 : 0; data.GammaAdjust = volAdjust ? Math.pow(volAdjust * data.SpotPrice / 16, 2) * data.Gamma / 2 : 0; } if (page.deltaRisk && variety && data.Notionals && data.Notionals.length) { gdata.DeltaRiskAbs += data.Notionals[0] || 0; gdata.DeltaRiskNet += data.Notionals[1] || 0; } if (IsGuangQiZiBen && data.CompanyObj) { gdata.CompanyObj.DeltaAdjust += data.CompanyObj.DeltaAdjust || 0; gdata.CompanyObj.GammaAdjust += data.CompanyObj.GammaAdjust || 0; } //delta定制 标的 计算 data.DeltaCustom = data.DeltaCash / data.StockEqvNotional; //统计属性循环处理 _.forIn(data, function (val, name) { if (name in varietyGroupSumObj) { gdata[name] += parseFloat(val) || 0; } }); var DeltaPercent = parseFloat(data.DeltaPercent); var StockEqvNotional = parseFloat(data.StockEqvNotional); if (DeltaPercent && StockEqvNotional) { gdata.DeltaPercent += DeltaPercent * StockEqvNotional; } data.rowFlag |= gdata.rowFlag & ConsExpand; gdata.StockEqvNotional += StockEqvNotional || 0; if (!spotPriceOk) { spotPriceOk = Math.abs(data.Pv) > 0.00001; if (spotPriceOk || !gdata.SpotPrice) { gdata.SpotPrice = data.SpotPrice; gdata.SpotPriceChangePercent = data.SpotPriceChangePercent; } else { gdata.SpotPriceChangePercent = 0; } } data.OtcPv = data.OtcDelta = new Date(); rows.push(data); }); if (gdata.StockEqvNotional !== 0) { gdata.DeltaPercent = gdata.DeltaPercent / gdata.StockEqvNotional; } if (variety) { var countRatio = variety.CountRatio || 1; if (gdata.DeltaRiskAbs) { gdata.DeltaRiskAbs = gdata.Delta / gdata.DeltaRiskAbs / countRatio; } if (gdata.DeltaRiskNet) { gdata.DeltaRiskNet = gdata.Delta / gdata.DeltaRiskNet / countRatio; } } if (page.isStock) { gdata.SpotPrice /= rows.length; gdata.SpotPriceChangePercent /= rows.length; } gdata.OtcPv = gdata.OtcDelta = new Date(); if (IsDongZhengRunHe) { gdata.DeltaCash2 = Math.abs(gdata.DeltaCash2); } return rows; } //对给定列数据进行排序 function _orderRows(rows) { let arrs = rows; if (_orderModel.colName) { arrs = _.orderBy(arrs, [_orderModel.colName], [_orderModel.order]); } return arrs; } //更新主表数据(数据来源于Ajax请求) this.updateDataRows = function (rows, isAjax) { if (!rows) return; isAjax && (_dataRows = rows); if (page.isMainView) { page.onMainData(rows); rows = _filterByUnderlyingCode(rows, isAjax); rows = _groupingData(rows); _grid.jqGrid('footerData', 'set', _footerData);//底部行 } var preRowId = ''; const rowIdSet = new Set(_grid.jqGrid('getDataIDs')), deltaRiskMap = {}; _.each(rows, function (data, i) { data.$index = i; var rowid = data.UnderlyingCode; _dataMap[rowid] = data; if (_priceCalcMap[rowid]) { return; } if (page.UnderlyingAlerts) { _.each(page.UnderlyingAlerts, function (um, l) { if (um.UnderlyingCode === data.UnderlyingCode) { um.nowPrice = data.Price || data.SpotPrice; } }); } var varietyFlag = data.rowFlag & ConsVariety; if (varietyFlag || data.rowFlag & ConsExpand) { if (rowIdSet.has(rowid)) { _grid.jqGrid('setRowData', rowid, data); } else { _grid.jqGrid('addRowData', rowid, data, preRowId ? 'after' : 'first', preRowId); } preRowId = rowid; if (page.deltaRisk && varietyFlag && data.DeltaRiskAbs > 0.2) { deltaRiskMap[rowid] = '1'; } } else { _grid.jqGrid('delRowData', rowid); } }); priceAlertInit(); var $trs = $("tr.jqgrow", _grid).css("cursor", "default"); if (page.deltaRisk) { $trs.each(function () { $(this).hasClass('yl-grid-variety') && $(this).toggleClass('deltarisk-danger', !!deltaRiskMap[$(this).attr("id")]); }); } if (_grid.offset().top + _grid.height() < 10) { utils.updateMainScroll(); } }; //主表品种组展开或折叠 this.toggleExpand = function (varietyCode) { var rows, preRowId = '', expand = false; if (varietyCode === '$$全部$$') { $(_grid[0].rows).removeClass('ui-state-highlight'); expand = !(_footerData.rowFlag & ConsExpand); _footerData.rowFlag = expand ? ConsExpand : 0; _grid.jqGrid("footerData", 'set', _footerData); rows = _.sortBy(_.map(_dataMap), x => x.$index); } else { let gdata = _dataMap[varietyCode]; expand = !(gdata.rowFlag & ConsExpand); rows = _.map(gdata.$rows); rows.unshift(gdata); } const rowIdSet = new Set(_grid.jqGrid('getDataIDs')); _.each(rows, function (data) { var rowid = data.UnderlyingCode; data = _priceCalcMap[rowid] || data; data.rowFlag |= ConsExpand; expand || (data.rowFlag ^= ConsExpand); if (data.rowFlag & ConsVariety || expand) { if (rowIdSet.has(rowid)) { _grid.jqGrid('setRowData', rowid, data); } else { _grid.jqGrid('addRowData', rowid, data, preRowId ? 'after' : 'first', preRowId); } preRowId = rowid; } else { _grid.jqGrid('delRowData', rowid); } }); if (!expand && varietyCode === '$$全部$$') { utils.updateMainScroll(); } return expand; }; //根据rowid获取主表数据 this.getData = function (rowid) { return _dataMap[rowid]; }; //刷新价格试算(影响顶部统计行和品种统计行) function _refreshPriceCalc(varietyCode, forVariety) { var gdata = _dataMap[varietyCode]; var gdataOld = _.clone(gdata); var rows = sumVariety(gdata, true); var fixedPrice = 0; _.each(rows, function (data, i) { _grid.jqGrid('setRowData', data.UnderlyingCode, data); forVariety || fixedPrice || (fixedPrice = data.rowFlag & ConsFixPrice); }); _grid.jqGrid('setRowData', varietyCode, gdata); _.forIn(gdata, function (val, name) { if (name in varietyGroupSumObj) { _footerData[name] += val - gdataOld[name] || 0; } }); _footerData.SpotPrice = ''; _footerData.SpotPriceChangePercent = ''; _footerData.OtcPv = _footerData.OtcDelta = new Date(); _grid.jqGrid('footerData', 'set', _footerData); if (!forVariety) { //折叠后如果存在标的的价格试算,品种行亮色显示 gdata.rowFlag |= ConsFixPrice; if (!fixedPrice) { _removeRowClass(varietyCode, 'yl-fixed-price'); gdata.rowFlag ^= ConsFixPrice; } } } //显示价格试算 this.showPriceCalc = function (code, isVariety) { debugger; if (isVariety) { let gdata = _dataMap[code]; _priceCalcMap[code] = gdata; let expand = gdata.rowFlag & ConsExpand, preRowId = code; if (gdata.rowFlag | ConsFixPrice) { _removeRowClass(code, 'yl-fixed-price'); gdata.rowFlag ^= ConsFixPrice; } gdata.rowFlag |= ConsFixPriceV | ConsExpand; gdata.SpotPrice = 0; _grid.jqGrid('setRowData', code, gdata, 'yl-fixed-priceV expand'); gdata.$rows.forEach(x => { _priceCalcMap[x.UnderlyingCode] = x; x.rowFlag = ConsFixPriceV; x.$SpotPrice = x.SpotPrice; if (expand) { _grid.jqGrid('setRowData', x.UnderlyingCode, x, 'yl-fixed-priceV'); } else { _grid.jqGrid('addRowData', x.UnderlyingCode, x, 'after', preRowId); } preRowId = x.UnderlyingCode; }); } else { //使用clone与原始列表数据脱离关系 let data = _.assign({}, _dataMap[code]); if (data.rowFlag & ConsFixPriceV) return; data.rowFlag |= ConsFixPrice; _priceCalcMap[code] = data; _grid.jqGrid('setRowData', code, data, 'yl-fixed-price'); _grid.jqGrid('setRowData', data.VarietyCode, null, 'yl-fixed-price'); _dataMap[data.VarietyCode].rowFlag |= ConsFixPrice; } }; //更新价格试算数据(rowid为标的代码或品种代码) this.updatePriceCalc = function (code, isVariety, ajaxRows) { if (!ajaxRows || !_priceCalcMap[code]) return; updateLock.update(); if (isVariety) { ajaxRows.forEach(x => { var calcData = _priceCalcMap[x.UnderlyingCode]; x.rowFlag = ConsFixPriceV | ConsExpand; x.$SpotPrice = calcData.$SpotPrice; _priceCalcMap[x.UnderlyingCode] = x; }); _refreshPriceCalc(code, true); } else { let rowData = ajaxRows[0]; rowData.rowFlag = ConsFixPrice; _priceCalcMap[code] = rowData; _refreshPriceCalc(rowData.VarietyCode); } }; //移除价格试算(rowid为标的代码或品种代码) this.removePriceCalc = function (code, isVariety) { let data = _priceCalcMap[code]; _priceCalcMap[code] = null; if (isVariety) { data.rowFlag = (data.rowFlag | ConsFixPriceV) ^ ConsFixPriceV; _grid.jqGrid('setRowData', code, data); data.$rows.forEach(x => { _priceCalcMap[x.UnderlyingCode] = null; x.rowFlag = (x.rowFlag | ConsFixPriceV) ^ ConsFixPriceV; }); } else { code = data.VarietyCode; data.rowFlag = (data.rowFlag | ConsFixPrice) ^ ConsFixPrice; } _refreshPriceCalc(code); }; //根据品种代码准备价格试算数据{Code,Price} this.prepareCalcPricesByVariety = function (varietyCode, calcPrice) { var gdata = _priceCalcMap[varietyCode]; if (gdata) { gdata.SpotPrice = calcPrice; return gdata.$rows.map(x => { var calcData = _priceCalcMap[x.UnderlyingCode]; return calcData ? { Code: x.UnderlyingCode, Price: calcData.$SpotPrice + calcPrice } : {}; }); } alert('不支持计算:' + varietyCode); }; //重新排序 this.resort = function () { _reset(); _throttleUpdate(); }; //重置 function _reset(flag) { _footerData.rowFlag = 0; _grid.jqGrid('clearGridData', true); _dataMap = {}; _priceCalcMap = {}; } //重置 this.reset = _reset; //获取主表中所有标的代码 this.getUnderlyingCodes = function () { return _.reduce(_dataMap, function (result, item) { item.VarietyCode === '$$group' || result.push({ id: item.UnderlyingId, Code: item.UnderlyingCode, Search: item.UnderlyingCode.toUpperCase() }); return result; }, []); }; //获取主表中所有标的名称 this.getUnderlyingLookup = function () { return _.reduce(_dataRows, function (result, item) { if (item.VarietyCode !== '$$group') { let text = item.UnderlyingCode; if (item.UnderlyingCode !== item.UnderlyingName) { text = text + ' ' + item.UnderlyingName; } result.push({ code: item.UnderlyingCode, text: text, pinyin: item.UnderlyingName ? pinyinUtil.getFirstLetter(item.UnderlyingName) || '' : '' }); } return result; }, []); }; //获取数据 this.getDatas = function (predicate) { return _.filter(_dataMap, predicate) || []; }; //前端更新 this.frontUpdateData = function () { _reset(); _mainGrid.updateDataRows(_dataRows, false); var group = $("#listGridMain a[onclick]"); if ($('#selectUnderlying2').val() && group.length > 0) { group[0].click(); } } } const _mainGrid = new mainGrid(); var _lastMainCalcTime = ''; //从服务端更新数据 const _ajaxUpdate = function (forceUpdate = true) { var loadingTime = new Date().getTime(); $('#nprogress').data('time', loadingTime).show(); let postData = _.clone(_postData); if (page.isMainView) { postData.ForceUpdate = !!forceUpdate; forceUpdate && (_lastMainCalcTime = ''); postData.CalcStartTime = _lastMainCalcTime; postData.ValueTime = $('#ValueTime').val(); } $.post("/RiskHedging/AjaxGetRiskCalcResult", postData).done(function (resp) { ('errcode' in resp) && !resp.errmsg && (resp = resp.data); if (resp.rows) { //解决数据先请求后到达的情况或部分并发问题 if (!updateLock.canUpdate(loadingTime)) return; updateLock.update(loadingTime); if (page.isMainView) { _lastMainCalcTime = resp.calctimes && resp.calctimes.length ? resp.calctimes[0] : ''; _mainGrid.updateDataRows(resp.rows, true); $('#tradingdate').html(resp.date || ''); $('#showTimestamp').text(page.showTimestamp ? _lastMainCalcTime : ''); } else { _subGrid.updateDataRows(resp.rows); } } else { console.log(resp); } }).always(function () { if ($('#nprogress').data('time') === loadingTime) { $('#nprogress').hide(); } }); }; //更新数据 const _throttleUpdate = _.throttle(_ajaxUpdate.bind(this, false), 3000, { leading: true, trailing: false }); //数据筛选(主列表页面) function mainFilter(postData) { if (!postData) postData = {}; _mainGrid.reset(); _.assign(_postData, postData); localStorage.setItem(consStorageKey, JSON.stringify(postData)); _ajaxUpdate(); } //行列设置 function showcolumnChooser(isSub) { event.preventDefault(); if (isSub) { main.showsubcolumnChooser($subGrid, page.configcolumn_sublist, { liteOnly: true, expandSubs: 'none' }); } else { main.showcolumnChooser($mainGrid, page.configcolumn_mainlist, { liteOnly: true, expandSubs: 'none' }); } return false; } //内部事件处理方法 function innerEventHandler() { //展开jqgrid中品种下所有标的数据 this.toggleExpandVariety = function (varietyCode) { let expand = _mainGrid.toggleExpand(varietyCode); $($mainGrid[0].rows.namedItem(varietyCode)).toggleClass('expand', expand); }; //全部展开折叠 this.toggleExpandAll = _.throttle(function () { let expand = _mainGrid.toggleExpand('$$全部$$'); $mainGrid.find('.yl-grid-variety').toggleClass('expand', expand); }, 600, { leading: true, trailing: false }); //显示子列表页面 this.showSubViewPage = function (rowid) { var data = _mainGrid.getData(rowid); var customPostData = { norefresh: data.rowFlag & ConsFixPrice || !$('#realtimeRefreshCheck').prop('checked') ? '1' : '' }; var title = ''; if (data.rowFlag & ConsVariety) { if (page.isStock && page.blockType) { title = '板块--' + data.UnderlyingCode; customPostData.SubListCode = '$,' + _mainGrid.getDatas(x => x.VarietyCode === data.UnderlyingCode).map(x => x.UnderlyingCode).join(','); } else { title = '品种--' + data.UnderlyingCode; customPostData.SubListCode = "$$" + _.trimEnd(data.UnderlyingCode, '\t'); } } else { customPostData.SubListCode = data.UnderlyingCode; title = '标的--' + _.trimEnd(data.UnderlyingCode, '\t'); } var postData = _.assign({}, _postData, customPostData); var index = layer.open({ type: 2, min: false, title: title, shadeClose: true, maxmin: true, area: ['98%', '60%'], content: "Index2Lite?" + $.param(postData, true) }); //最大化按钮用于跳转到新页面 var $l = $('#layui-layer' + index); var $m = $l.children('.layui-layer-setwin').find('.layui-layer-max'); var $n = $m.clone().insertAfter($m).on('click', function () { var $form = $('#formNew').html(''); _.forIn(postData, function (val, key) { if (key === 'VarietyIds' || key === 'UnderlyingIds' || key === 'norefresh') return; if (!_.isArray(val)) val = [val]; _.each(val, function (x) { x && $(``).appendTo($form); }); }); $form.submit(); layer.close(index); }); $n.prevAll().remove(); }; //显示对冲波动率|分红率|参与率更新 function __showUpdate(rowid, wrapId, type) { var rowData = _subGrid.getData(rowid); if (!rowData) return main.alert('系统错误'); var title = '', desc = '', tid = ''; if (rowData.ExchangeOptionCode) { tid = rowData.ExchangeOptionCode; title = "设置场内期权波动率"; desc = '期权编码: ' + rowData.ExchangeOptionCode; wrapId = "volSetting_ExOption"; } else if (rowData.TradeId > 0) { tid = rowData.TradeId; title = '设置' + type; desc = '交易编号: ' + (rowData.TradeNumber || '') + ', 标的代码: ' + rowData.UnderlyingCode; } else { return main.alert('参数错误:tid'); } var $wrap = $('#' + wrapId); var $input = $wrap.find('input[type="number"]').data('tid', tid); $wrap.find('.desc').html(desc); var url = '/riskHedging/'; var postData = { tradeId: rowData.TradeId, optionCode: tid }; if (rowData.ExchangeOptionCode) { url += 'AjaxGetExchangeOptionVol'; } else { switch (type) { case '分红率': url += 'AjaxGetDividendRate'; break; case '无风险利率': url += 'AjaxGetNoRiskRate'; break; case '对冲波动率': url += 'AjaxGetHedgingVol'; break; default: return main.alert("参数错误:type"); } } main.post(url, postData).done(function (resp) { resp = resp.obj; let value; if (type.includes("波动率")) { value = otcformat.flex(resp.vol * 100, 2, resp.volMoreAccurate ? 4 : 2); if (rowData.ExchangeOptionCode) { let isVolsurface = resp.useflag !== '固定'; $input.prop('readonly', isVolsurface); $wrap.find('input[type="checkbox"]').prop('checked', isVolsurface); } } else { value = consNumberFormat.fixed2(resp * 100); } $input.val(value).data('preValue', value); }); layer.open({ type: 1, title: title, area: '350px', content: $wrap }); } //显示对冲波动率更新 this.showUpdateHedgingVol = function (rowid) { if (page.VolType !== '对冲') return; __showUpdate(rowid, 'hedingVolSetting', '对冲波动率'); }; //显示当前波动率更新 this.showUpdateCurVol = function (rowid) { __showUpdate(rowid, '', '当前波动率'); }; //显示分红率更新 this.showUpdateDividendRate = function (rowid) { __showUpdate(rowid, 'dividendRateSetting', '分红率'); }; //显示无风险利率更新 this.showUpdateNoRiskRate = function (rowid) { __showUpdate(rowid, 'noRiskRateSetting', '无风险利率'); }; //显示价格试算输入 this.showPriceCalcInput = function (code, isVariety) { _mainGrid.showPriceCalc(code, isVariety); }; //执行价格试算 this.execPriceCalc = function (code, isVariety) { var price = parseFloat($(event.target).val()) || 0; var prices = [{ Code: code, Price: price }]; if (isVariety) { prices = _mainGrid.prepareCalcPricesByVariety(code, price); } prices = { Prices: prices }; var postData = _.assign({}, _postData, prices); main.post("AjaxGetRiskPriceCalcResult", postData).done(function (resp) { ('errcode' in resp) && !resp.errmsg && (resp = resp.data); var rows = resp.rows; if (!rows || !rows.length) { return main.alert("定价试算失败:" + (resp.errmsg || '计算结果为空')); } else { _mainGrid.updatePriceCalc(code, isVariety, rows); } }); }; //移除价格试算 this.removePriceCalc = function (code, isVariety) { if (isVariety) { let $e = $(event.target).closest('td').html('').closest('tr').removeClass('yl-fixed-priceV'); $e.nextUntil(".yl-grid-variety").removeClass('yl-fixed-priceV'); } else { $(event.target).closest('tr').removeClass('yl-fixed-price'); } _mainGrid.removePriceCalc(code, isVariety); }; } //初始化 function init() { _mainGrid.init(); _subGrid.init(); $('#volSetting_ExOption').find('input[type="checkbox"]').on('change', function (e) { $('#volSetting_ExOption').find('input[type="number"]').prop('readonly', $(e.target).prop('checked')); }); $('div.ui-jqgrid-sdiv', "#gbox_listGridMain").appendTo($('div.ui-jqgrid-hdiv', "#gbox_listGridMain")); page.isMainView && $('#gbox_listGridSub').hide(); utils.setGridArea(true); $(window).on('resize.jqGrid', function () { utils.setGridArea(); }); } return { init(eventHandler) { _.assign(eventHandler, new innerEventHandler()); window.jqGridEventHandler = eventHandler; init(); }, mainFilter: mainFilter, updateData(resetFlag) { resetFlag && _mainGrid.reset(resetFlag); if (resetFlag === 'block') { //切换板块更新 _ajaxUpdate(); } else { _throttleUpdate(); } }, showcolumnChooser: showcolumnChooser, getPostData(rowid) { var postData = _.extend({}, _postData); if (rowid) { var data = _mainGrid.getData(rowid); if (data.rowFlag & ConsVariety) { if (page.isStock && page.blockType) { postData.block = data.UnderlyingCode; postData.SubListCode = "$," + _mainGrid.getDatas(x => x.VarietyCode === data.UnderlyingCode).map(x => x.UnderlyingCode).join(','); } else { postData.SubListCode = "$$" + data.UnderlyingCode; } } else { postData.SubListCode = data.UnderlyingCode; } } return postData; }, getPreSettleDate(volType) { $.get("/RiskHedging/AjaxPreSettleDateByVolType?volType=" + volType).done(function (res) { let preSettleDate = res; if (preSettleDate < page.PreTradingDate) { $("#noSettleDiv").show(); } else { $("#noSettleDiv").hide(); } }); }, subGridFilter: _subGrid.filterData, mainGridSort: _mainGrid.resort, getUnderlyingCodes: _mainGrid.getUnderlyingCodes, getUnderlyingLookup: _mainGrid.getUnderlyingLookup, filterData: _mainGrid.filterData, frontUpdateData: _mainGrid.frontUpdateData, getPriceData(code) { return _priceCalcMap[code || '']; } }; }(page)); //子页面 const subView = (function (jqGridMgr) { const instance = {}; //保存对冲波动率|分红率|无风险利率 function __saveTradeValue(wrapId, type) { var $input = $('#' + wrapId).find('input'); var tid = $input.data('tid'); if (!tid) return main.alert('JS程序错误'); var value = parseFloat($input.val()) / 100; if (isNaN(value) || value < 0) { return main.alert('请设置合理的' + type); } var preValue = parseFloat($input.data('preValue')); //相同对冲波动率数据不必提交 if (Math.abs(preValue - value) < 0.00001) return; var $e = $(event.target).prop('disabled', true); var url = '/RiskHedging/'; var postData = { tradeId: tid, value: value }; switch (type) { case '对冲波动率': url += "AjaxSaveTradeHedgingVol"; postData = { tradeId: tid, value: value }; break; case '分红率': url += "AjaxSaveDividendRate"; break; case '无风险利率': url += "AjaxSaveNoRiskRate"; break; default: return main.alert('程序错误'); } main.post(url, postData).done(function (res) { layer.closeAll(); layer.msg('保存成功'); setTimeout(jqGridMgr.updateData, 3000); setTimeout(jqGridMgr.updateData, 6000); }).always(function () { $e.prop('disabled', false); }); } //保存对冲波动率 instance.saveHedgingVol = function () { __saveTradeValue('hedingVolSetting', '对冲波动率'); }; //保存场内期权动率 instance.saveExOptionVol = function () { let $wrap = $('#volSetting_ExOption'); let $volInput = $wrap.find('input[type="number"]'); let tid = $volInput.data('tid'); if (!tid) return main.alert('JS程序错误'); let saveFlag = $wrap.find('input[type="checkbox"]').prop('checked') ? "" : "固定"; let value = parseFloat($volInput.val()) / 100; if (isNaN(value) || value < 0) { if (saveFlag === "固定") return main.alert('请设置合理的场内期权波动率'); value = 0; } let $e = $(event.target).prop('disabled', true); let url = '/RiskHedging/AjaxSaveExOptionHedgingVol'; let postData = { optionCode: tid, value: value, saveflag: saveFlag }; main.post(url, postData).done(function (res) { layer.closeAll(); layer.msg('保存成功'); setTimeout(jqGridMgr.updateData, 3000); setTimeout(jqGridMgr.updateData, 6000); }).always(function () { $e.prop('disabled', false); }); }; //保存分红率 instance.saveDividendRate = function () { __saveTradeValue('dividendRateSetting', '分红率'); }; //保存无风险利率 instance.saveNoRiskRate = function () { __saveTradeValue('noRiskRateSetting', '无风险利率'); }; //下拉框过滤明细子表数据 instance.selectFilterSubGrid = function () { jqGridMgr.subGridFilter(); }; //用于交易编号 const throttleFilterSubGrid = _.throttle(jqGridMgr.subGridFilter, 1500); //输入框过滤明细子表数据 instance.inputFilterSubGrid = function () { throttleFilterSubGrid(); }; //单选框过滤明细子表数据 instance.IsSumHedgingFilterSubGrid = function () { isUserUpdateIsSumHedging = true; jqGridMgr.subGridFilter(); }; //下拉框过滤明细子表数据 instance.resetFilterSubGrid = function () { $('#sublistSearchBox').find('input,select').val(''); if (page.isSumOnlyOTC && !isUserUpdateIsSumHedging) { $("#isSumHedging").prop("checked", false); } else { $("#isSumHedging").prop("checked", true); } jqGridMgr.subGridFilter(); }; //查看交易信息 instance.tradeView = function (encryptId, tradeType) { if (tradeType.indexOf("远期") >= 0) { main.open("查看远期交易", "/forwardtrade/tradeView/?enid=" + encryptId, { area: ['90%', '90%'] }); } else if (tradeType=="收益互换") { main.open("查看交易", "/swaptrade2/tradeView/?enid=" + encryptId, { area: ['90%', '90%'] }); } else { main.open("查看交易", "/trade/tradeView/?enid=" + encryptId, { area: ['90%', '90%'] }); } }; //历史交易 instance.historytradeView = function (underlyingCode, tradeType, bookId, exchangeOptionCode) { var urlStr = `/exchangetrade/TradeListSingle?UnderlyingCodes=${underlyingCode}&TradeType=${tradeType}&AssetBookIds=${bookId || ''}&OptionCode=${exchangeOptionCode || ''}`; main.open("历史交易", urlStr, { area: ['90%', '90%'] }); }; //平仓按钮 instance.unWind = function (encryptId, tradeType, StructureType) { if (consHedgingTradeTypes.includes(tradeType)) { main.alert(`"${tradeType}"不允许平仓操作!`); return; } var srcurl = "/trade/tradeUnwind/?enid=" + encryptId; var area = ["1000px", "800px"]; if (tradeType === "收益互换") { srcurl = "/swaptrade2/SwapUnwind/?enid=" + encryptId; if (StructureType=="多空组合") { srcurl = "/swaptrade2/SwapLongShortUnwind/?enid=" + encryptId; } area = ["1300px", "720px"]; } if (tradeType.indexOf("远期") >= 0) { srcurl = "/forwardtrade/tradeUnwind/?enid=" + encryptId; } main.open("交易平仓", srcurl, { area: area, end: function () { if (!$("#realtimeRefreshCheck").prop("checked")) { //todo: } } }); }; //确认交易 instance.confirmTrade = function () { main.alert('未实现'); }; //执行期权 instance.executionTrade = function (encryptId) { main.open("执行期权", "/trade_cash/executionTradeCash/?enid=" + encryptId, { area: ["1000px", "800px"] }); }; //合约到期 instance.expireTrade = function (encryptId) { main.confirm("确定直接执行合约到期吗?", function () { main.post("/trade/tradeExpireConfirm", { enid: encryptId }, { area: ["1000px", "800px"] }).done(function () { //todo }); }); }; //执行到期 instance.exerciseOrExpireTrade = function (encryptId) { main.post("/trade_cash/checkEodPrice/", { enid: encryptId }).done(function (res) { main.open("执行期权", "/trade_cash/executionTradeCash/?enid=" + encryptId + "&isexpire=true", { area: ["1000px", "800px"] }); }); }; //子操作弹窗 instance.openOperation = function (EncryptId, StructureType, TradeType, TradeStatus, ExerciseDate, TradeId, ExerciseModeCn, TradeNumber, UnderlyingCode) { const is_hedgingTrade = consHedgingTradeTypes.includes(TradeType);//是否对冲交易 const classes = is_hedgingTrade ? ['', 'hidden'] : ['hidden', '']; const obj = { EncryptId: EncryptId, StructureType: StructureType, TradeType: TradeType, TradeStatus: TradeStatus, ExerciseDate: ExerciseDate, TradeId: TradeId, ExerciseModeCn: ExerciseModeCn, TradeNumber: TradeNumber, UnderlyingCode: UnderlyingCode, viewTradeDisabled: TradeId < 0 ? 'disabled' : '', historyTradeClass: classes[0], closeTradeTitle: '平仓', closeTradeClass: classes[1], closeTradeDisabled: '', confirmTradeTitle: '确认交易', confirmTradeClass: classes[1], confirmTradeDisabled: '', executionTradeTitle: '执行', executionTradeClass: classes[1], executionTradeDisabled: 'disabled', expireTradeTitle: '到期', expireTradeClass: 'hidden', expireTradeDisabled: 'disabled', exerciseOrExpireTradeTitle: '执行到期', exerciseOrExpireTradeClass: classes[1], exerciseOrExpireTradeDisabled: 'disabled' }; const options = { type: 1, title: TradeType + "-" + (TradeNumber || ''), shadeClose: true, shade: 0.4, area: ['420px', '150px'] }; if (!is_hedgingTrade) { var stateDisabled = consDisablePingCangStates.indexOf(TradeStatus) >= 0; var tradeTypeDisabled = consDisablePingCangTradeTypes.indexOf(TradeType) >= 0; if (stateDisabled || tradeTypeDisabled) { obj.closeTradeTitle = '交易状态为' + (stateDisabled ? TradeStatus : TradeType) + ',不能平仓'; obj.closeTradeDisabled = 'disabled'; } if (consEnableConfirmStates.indexOf(TradeStatus) < 0) { obj.confirmTradeTitle = '状态为' + TradeStatus + ',不能确认'; obj.confirmTradeDisabled = 'disabled'; } if (stateDisabled || tradeTypeDisabled || TradeType === "自定义交易") { if (tradeTypeDisabled) { obj.expireTradeClass = ''; } } else { //欧式期权,只能在行权日当天执行 var compareExe = new moment(ExerciseDate).format("YYYY-MM-DD"); if (ExerciseModeCn === "欧式" && compareExe > consDateFormat) { obj.executionTradeTitle = "欧式期权,只能在行权日当天执行"; } else { if (TradeType.indexOf("远期") < 0 && TradeType !== "收益互换") { obj.executionTradeDisabled = TradeStatus === page.TradeStatus_pcdfh ? 'disabled' : ''; } else { obj.executionTradeDisabled = 'disabled'; } //系统日期大于行权日时允许直接到期 if (compareExe < consDateFormat && TradeType !== "收益互换") { obj.expireTradeClass = ''; obj.expireTradeDisabled = ''; } } //CanExpire,执行到期OTC-6691 交易管理 - 风险对冲 - 欧式和美式期权到期交易,执行到期的操作需要在风险对冲页面作同样处理 if (["提前终止拒绝", "确认成交"].includes(TradeStatus) && main.toDate(ExerciseDate) === page.cursystemdate) { obj.exerciseOrExpireTradeDisabled = ''; } else { obj.exerciseOrExpireTradeTitle = '只有系统当天到期,并且是提前终止拒绝和确认成交的交易才可以执行到期'; } } } html = consOpenOperationRender(obj); main.open2("", html, options); }; return instance; }(jqGridMgr)); //主页面 const mainView = (function (jqGridMgr) { const instance = {}; var _selectUnderlying2Auto; //过滤信息定义 function getFilterDefineArray() { return [ { id: '#selectAssetBook', label: '簿记账户', name: 'BookIds' }, { id: '#selectAssetBookGroup', label: '簿记账户组', name: 'AssetIdGroupList' }, { id: '#selectClient', label: '客户名称', name: 'ClientIds' }, { id: '#selectAssetType', label: '结构类型', name: 'AssetTypes' }, { id: '#selectVarietyGroup', label: '品种分类', name: 'VarietyGroups' }, { id: '#selectVariety', label: '标的品种', name: 'VarietyIds' }, { id: '#selectUnderlying', label: '标的代码', name: 'UnderlyingIds' } ]; } //查询筛选中的反选控件 function _queryInvertSelects(onlyChecked) { return onlyChecked ? Array.from(document.querySelectorAll('input[name="InvertSelects"]:checked')) : document.querySelectorAll('input[name="InvertSelects"]'); } function _init() { //初始化Selectize控价 function initSelectize(selector, options) { var defaultOptions = { plugins: ['remove_button'], onItemAdd: function (value, $item) { $item.on('dblclick', function () { var selectize = $item.closest('.selectize-control').prev('select')[0].selectize; selectize.removeItem(value, true); }); } }; if (options) { _.assign(options, defaultOptions); } else { options = defaultOptions; } $(selector).selectize(options); } //实时刷新 $('#realtimeRefreshCheck').on('change', function () { localStorage.setItem('realtimeRiskRefresh', $(this).prop('checked')); realtimeRefresh(); }).prop('checked', localStorage.getItem('realtimeRiskRefresh') === 'true'); //主表下拉菜单 $jqDropdown.on('show', function (event, dropdownData) { var rowid = dropdownData.trigger.text(); $jqDropdown.data('rowid', rowid); if (page.showAutoRule) { $(this).find('.yl-autorule').toggle(!dropdownData.trigger.data('variety')); $(this).find('.yl-priceAlert').toggle(!dropdownData.trigger.data('variety')); } }); initSelectize('#selectAssetBook', { options: ylotc.assetunits, valueField: 'id', labelField: 'Name', searchField: 'Name' }); initSelectize('#selectAssetBookGroup', { options: ylotc.assetunitgroups, valueField: 'id', labelField: 'Name', searchField: 'Name' }); // "彩虹期权", "价差期权", const assetTypes = ["场内期权", "香草期权", "障碍期权", "二元期权", "亚式期权", "合成价差期权", "双鲨期权", "凤凰期权", "雪球期权", "气囊结构", "累计期权", "区间累积期权", "收益增强结构", "合成远期", "远期", "自定义交易", "收益互换", "黑箱结构", "Risky期权", "商品期货", "股票", "商品现货"]; initSelectize('#selectAssetType', { options: _.map(assetTypes, function (x) { return { id: x }; }), valueField: 'id', labelField: 'id', searchField: 'id' }); initSelectize('#selectClient', { options: ylotc.clients, valueField: 'id', labelField: 'Name', searchField: 'Name' }); initSelectize('#selectVarietyGroup', { options: ylotc.varietyGroups, valueField: 'Value', labelField: 'Text', searchField: 'Text' }); initSelectize('#selectVariety', { options: ylotc.varieties, valueField: 'id', labelField: 'Code', searchField: 'Code' }); //初始化标的代码下拉选择 var preloads = []; _.each(ylotc.underlyings, item => item.Search = (item.Code || '').toUpperCase()); initSelectize('#selectUnderlying', { options: [], valueField: 'id', labelField: 'Code', searchField: 'Search', preload: 'focus', maxOptions: 100, load: function (query, callback) { if (!query.length) { if (!preloads.length) { preloads = jqGridMgr.getUnderlyingCodes(); } return callback(preloads); } query = query.toUpperCase(); var filters = ylotc.underlyings.filter(x => x.Code.includes(query)); return callback(filters); } }); initSelectize('#AlertUnderlying', { options: [], valueField: 'Code', labelField: 'Code', searchField: 'Search', preload: 'focus', maxOptions: 100, load: function (query, callback) { if (!query.length) { if (!preloads.length) { preloads = jqGridMgr.getUnderlyingCodes(); } return callback(preloads); } query = query.toUpperCase(); var filters = ylotc.underlyings.filter(x => x.Code.includes(query)); return callback(filters); } }); initSelectize('#selectSkipTradeTypes', { maxOptions: 100, items: (page.RealtimeRisk_SkipTradeTypes || '').split(','), onDropdownClose($dropdown) { let types = $('#selectSkipTradeTypes').val().join(); main.post('/appconfig/AjaxSave', { name: 'Erp.RealtimeRisk_SkipTradeTypes', value: types }, false) .done(resp => main.message('已保存')); } }); //初始化标的名称下拉选项 if (document.getElementById('selectUnderlying2')) { _selectUnderlying2Auto = FastVue.autocomplete(document.getElementById('selectUnderlying2'), { nameField: 'text', valueField: 'code', lookup(queryLowerCase) { let suggestions = jqGridMgr.getUnderlyingLookup(); return queryLowerCase ? suggestions.filter(x => new Array(x.text, x.pinyin).some(y => y.toLowerCase().includes(queryLowerCase))) : suggestions; }, formatResult(suggestion, currentValue) { var arr = suggestion.value.split(' '); if (arr.length > 1) { return `
| ${arr[0]} | ${arr[1]} |