2702 lines
117 KiB
JavaScript
2702 lines
117 KiB
JavaScript
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 = '<option value="">全部</option>';
|
|
if (arr.length) {
|
|
if (setting.key === 'ClientId') {
|
|
html += arr.map(x => `<option value="${x}" ${x === selVal ? "selected" : ""}>${_clientMap[x]}</option>`).reduce(reducer);
|
|
} else {
|
|
html += arr.map(x => `<option value="${x}" ${x === selVal ? "selected" : ""}>${x}</option>`).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 '<input type="button" class="wentiEdit" title="历史交易" value="历史交易" onclick="' + onclick + '" />';
|
|
}
|
|
|
|
var minMaturityDay = rowObject.MaturityWorkDay;
|
|
var minRealDay = rowObject.MaturityDay;
|
|
var pictures = ['red', 'red', 'yellow', 'green'];
|
|
var picture = pictures[minMaturityDay] || '';
|
|
if (picture) {
|
|
picture = `<label class="yl-light yl-light-${picture}" title="存在${minRealDay ? minRealDay : "当"}天内到期交易,工作日间隔:${minMaturityDay}天"></label>`;
|
|
}
|
|
|
|
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 + '<input type="button" class="wentiEdit" title="弹出按钮" value="操作" onclick="' + onclick + '" />';
|
|
}
|
|
//结构类型
|
|
function showTradeType(cellValue, options, rowObject) {
|
|
if (rowObject.TradeType === "结构化交易") {
|
|
var showTable = tradelistBase.setStructTable(rowObject);
|
|
return `<a href="#" class="selftooltip" style="z-index:10000000" data-toggle="tooltip" title="${rowObject.StructureType || ''}">${showTable}</a>`;
|
|
}
|
|
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 '<span ondblclick="jqGridEventHandler.showUpdateHedgingVol(\''
|
|
+ options.rowId + '\')" style="display:block;">' + hedgeVolFormat(cellValue) + '</span>';
|
|
}
|
|
//当前波动率%
|
|
function cvolfloatFormat(cellValue, options, rowObject) {
|
|
if (consHedgingTradeTypes2.includes(rowObject.TradeType)) return '';
|
|
if (rowObject.TradeType !== '场内期权' || page.VolType === '交易曲面') return hedgeVolFormat(cellValue);
|
|
return '<span ondblclick="jqGridEventHandler.showUpdateCurVol(\''
|
|
+ options.rowId + '\')" style="display:block;">' + hedgeVolFormat(cellValue) + '</span>';
|
|
}
|
|
//日期
|
|
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 '<span ondblclick="jqGridEventHandler.showUpdateDividendRate(\''
|
|
+ options.rowId + '\')" style="display:block;">' + hedgeVolFormat(cellValue) + '</span>';
|
|
}
|
|
|
|
//无风险利率
|
|
function noRiskRateFormat(cellValue, options, rowObject) {
|
|
if (consHedgingTradeTypes.includes(rowObject.TradeType)) return '';
|
|
return '<span ondblclick="jqGridEventHandler.showUpdateNoRiskRate(\''
|
|
+ options.rowId + '\')" style="display:block;">' + hedgeVolFormat(cellValue) + '</span>';
|
|
}
|
|
|
|
//交易方向
|
|
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 `<a href="#" data-jq-dropdown="#jq-dropdown-1" class="yl-tooltip" data-variety="${varietyFlag}" data-tooltip-text="${tipText}" data-tooltip-side="top" data-tooltip-arrow="no">${cellValue}</a>`;
|
|
}
|
|
//DailyPnl
|
|
function dailyPnlFormat(cellValue, options, rowObject) {
|
|
var formatVal = consNumberFormat.tradePrice(cellValue);
|
|
var style = cellValue < 0 ? 'color:green' : cellValue > 1e-5 ? "color:red" : '';
|
|
return `<span style="${style}">${formatVal}</span>`;
|
|
}
|
|
//标的价格
|
|
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 ? ' ' : `<strong style="${style}">${formatVal}</strong>`
|
|
: 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 `<strong style="${style}">${formatVal}</strong>`;
|
|
}
|
|
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 `<strong style="${style}">${formatVal}</strong>`;
|
|
}
|
|
//Delta风险敞口
|
|
function deltaRiskFormat(cellValue, options, rowObject) {
|
|
return rowObject.rowFlag & ConsVariety ? consNumberFormat.fixed2P(cellValue) : '';
|
|
}
|
|
//行勾选
|
|
function checkboxFormat(cellValue, options, rowObject) {
|
|
return rowObject.rowFlag & ConsVariety ? '' : '<input type="checkbox">';
|
|
}
|
|
//展开折叠
|
|
function expandFormat(cellValue, options, rowObject) {
|
|
var fa = rowObject.rowFlag & ConsExpand ? ' fa-minus' : '';
|
|
if (rowObject.VarietyCode === '$$foot') {
|
|
return `<a class="yl-grid-plus" title="全部展开" href="#" onclick="jqGridEventHandler.toggleExpandAll()"><i class="fa fa-plus${fa}"></i></a>`;
|
|
}
|
|
return rowObject.rowFlag & ConsVariety
|
|
? `<a class="yl-grid-plus" href="#" onclick="jqGridEventHandler.toggleExpandVariety('${rowObject.UnderlyingCode}')"><i class="fa fa-plus${fa}"></i></a>`
|
|
: '';
|
|
}
|
|
//场外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 && $(`<input type="hidden" name="${key}" value="${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 `<table class="suggestion-table"><tr><td>${arr[0]}</td><td>${arr[1]}</td></tr></table>`;
|
|
}
|
|
return suggestion.value;
|
|
},
|
|
onSelect: jqGridMgr.frontUpdateData
|
|
});
|
|
}
|
|
|
|
//还原筛选条件
|
|
var postData = localStorage.getItem(consStorageKey);
|
|
if (postData) {
|
|
postData = JSON.parse(postData) || {};
|
|
getFilterDefineArray().forEach(x => {
|
|
var val = postData[x.name];
|
|
if (!val || !val.length) return;
|
|
var selectize = $(x.id)[0].selectize;
|
|
if (x.name === 'UnderlyingIds') {
|
|
var arr = ylotc.underlyings.filter(x => val.includes(x.id.toString()));
|
|
selectize.addOption(arr);
|
|
}
|
|
selectize.setValue(val);
|
|
});
|
|
postData.OnlyPosition && $('#checkShowPositions').prop('checked', true);
|
|
postData.InvertSelects && _queryInvertSelects().forEach(x => {
|
|
x.checked = postData.InvertSelects.includes(x.value);
|
|
});
|
|
}
|
|
instance.clickFilterData(true);
|
|
|
|
$('#searchFilterDesc').on('click', function () {
|
|
$(this).toggleClass('auto-height');
|
|
});
|
|
|
|
//板块性质
|
|
if (page.isStock) {
|
|
$('#menuBlock').on('click', 'a', _changeBlock);
|
|
page.blockType = parseInt(localStorage.getItem("realtimeRiskBlock")) || 0;
|
|
var blockText = $('#menuBlock').find('[data-type="' + page.blockType + '"]').addClass("active").text();
|
|
blockText && $('#selectBlockText').text(blockText);
|
|
}
|
|
var volType = $("#selectVolTypeMenuText").text();
|
|
jqGridMgr.getPreSettleDate(volType.trim());
|
|
}
|
|
|
|
//初始化标的品种排序
|
|
function _initSortable() {
|
|
|
|
var sortable2;
|
|
|
|
function saveConfig() {
|
|
var arr = sortable2.toArray();
|
|
$.post("/configcolumn/saveconfig", { targetname: 'RiskHedgingIndexV2Sort', data: arr.join() }).done(function () {
|
|
page.mainSortable = arr;
|
|
}).fail(function (res) {
|
|
main.alert('配置保存失败');
|
|
});
|
|
}
|
|
|
|
var sortList1 = $('#sortList1').children().map(function () { return $(this).data('id'); }).get();
|
|
|
|
var sortable1 = new Sortable(document.getElementById('sortList1'), {
|
|
group: 'shared',
|
|
animation: 150,
|
|
sort: false,
|
|
onAdd: function (evt) {
|
|
var id = $(evt.item).data('id');
|
|
var index = _.sortedIndex(sortList1, id);
|
|
if (index < 0) index = 0;
|
|
sortList1.splice(index, 0, id);
|
|
sortable1.sort(sortList1);
|
|
},
|
|
onRemove: function (evt) {
|
|
var itemEl = evt.item;
|
|
var code = $(itemEl).data('id');
|
|
_.remove(sortList1, x => x === code);
|
|
}
|
|
});
|
|
|
|
sortable2 = new Sortable(document.getElementById('sortList2'), {
|
|
group: 'shared',
|
|
animation: 150,
|
|
dragClass: 'sortable-drag',
|
|
ghostClass: 'sortable-ghost',
|
|
onAdd: saveConfig,
|
|
onUpdate: saveConfig,
|
|
onRemove: saveConfig
|
|
});
|
|
|
|
$('#sortModal').on('hidden.bs.modal', jqGridMgr.mainGridSort);
|
|
}
|
|
|
|
//初始化右边栏
|
|
function _initSidebar() {
|
|
|
|
if (!page.showSidebar) return;
|
|
|
|
//边栏按钮点击显示或隐藏弹窗
|
|
$('.yl-tabs-toggle', '.yl-sidebar').on('click', function () {
|
|
event.preventDefault();
|
|
var $tab = $(this).toggleClass('active');
|
|
$tab.siblings().removeClass('active');
|
|
var $tabPane = $($tab.attr('href'));
|
|
if ($tab.hasClass('active')) {
|
|
$tabPane.siblings().removeClass('active');
|
|
$tabPane.parent().addClass('in').parent().addClass('expand');
|
|
} else {
|
|
$tabPane.parent().removeClass('in').parent().removeClass('expand');
|
|
}
|
|
$tabPane.toggleClass('active');
|
|
});
|
|
|
|
//页面点击时隐藏边栏弹窗
|
|
$('body').on('click', function (event) {
|
|
if ($(event.target).closest('.yl-sidebar').length < 1) {
|
|
var $tab = $(".yl-sidebar-tabs").find('.active');
|
|
if ($tab.length > 0) {
|
|
$tab.removeClass('active');
|
|
$($tab.attr('href')).removeClass('active')
|
|
.parent().removeClass('in')
|
|
.parent().removeClass('expand');
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
//更改板块性质
|
|
function _changeBlock() {
|
|
event.preventDefault();
|
|
var $li = $(event.target);
|
|
if ($li.hasClass('active')) return;
|
|
$li.addClass('active').siblings().removeClass('active');
|
|
$('#selectBlockText').text($li.text());
|
|
page.blockType = parseInt($li.data("type")) || 0;
|
|
localStorage.setItem("realtimeRiskBlock", page.blockType);
|
|
jqGridMgr.updateData('block');
|
|
}
|
|
|
|
instance.init = function () {
|
|
jqGridMgr.updateData();
|
|
};
|
|
|
|
if (page.isMainView) {
|
|
instance.init = function () {
|
|
_init();
|
|
_initSortable();
|
|
_initSidebar();
|
|
};
|
|
}
|
|
|
|
//点击过滤数据
|
|
instance.clickFilterData = function (innerCall) {
|
|
let defArr = getFilterDefineArray(), postData = {}, descArr = [];
|
|
postData.InvertSelects = _queryInvertSelects(true).map(x => x.value);
|
|
defArr.forEach(function (x) {
|
|
postData[x.name] = $(x.id).val();
|
|
var texts = $(x.id).find('option:selected').map(function () { return this.text; }).get().join();
|
|
if (texts) {
|
|
let label = x.label;
|
|
postData.InvertSelects.includes(x.label) && (label += "(反选)");
|
|
descArr.push(`<span class="yl-filterdesc"><strong>${label}: </strong>${texts}</span> `);
|
|
}
|
|
});
|
|
postData.OnlyPosition = $('#checkShowPositions').prop('checked');
|
|
innerCall || $('#btnFilterPopup').dropdown('toggle');
|
|
jqGridMgr.mainFilter(postData);
|
|
if (postData.OnlyPosition) {
|
|
descArr.push('<strong class="yl-filterdesc">只显示有持仓的合约</strong> ');
|
|
}
|
|
$('#searchFilterDesc').html(descArr.join('') || '<strong>筛选条件: </strong>全部');
|
|
if (descArr.length) {
|
|
$('#btnFilterPopup').addClass('hasFilter');
|
|
} else {
|
|
$('#btnFilterPopup').removeClass('hasFilter');
|
|
}
|
|
};
|
|
|
|
//清除过滤条件
|
|
instance.clickClearFilters = function () {
|
|
var defArr = getFilterDefineArray(), postData = {};
|
|
defArr.forEach(function (x) {
|
|
postData[x.name] = '';
|
|
var par = $(x.id).val('')[0];
|
|
if (par) {
|
|
par.selectize.clear();
|
|
}
|
|
});
|
|
$('#checkShowPositions').prop('checked', false);
|
|
postData.OnlyPosition = false;
|
|
postData.InvertSelects = null;
|
|
_queryInvertSelects().forEach(x => {
|
|
x.checked = false;
|
|
});
|
|
jqGridMgr.mainFilter(postData);
|
|
$('#searchFilterDesc').html('<strong>筛选条件: </strong>全部');
|
|
$('#btnFilterPopup').removeClass('hasFilter');
|
|
};
|
|
|
|
//持仓比对
|
|
instance.checkHedgePosition = function (isStock) {
|
|
var url = "/RiskHedging/DiffHedgePositions?isStock=" + (isStock === "1");
|
|
main.open("持仓比对", url, { area: ['1260px', '800px'] });
|
|
};
|
|
|
|
//更改波动率计算类型
|
|
instance.changeVolType = function () {
|
|
var $li = $(event.target);
|
|
if ($li.hasClass('current')) return;
|
|
$li.addClass('current').siblings().removeClass('current');
|
|
page.VolType = $li.text();
|
|
$('#selectVolTypeMenuText').text(page.VolType);
|
|
jqGridMgr.mainFilter({ VolType: page.VolType });
|
|
jqGridMgr.getPreSettleDate(page.VolType);
|
|
};
|
|
//更改波动率计算类型
|
|
instance.changeDividendRateType = function () {
|
|
var $li = $(event.target);
|
|
if ($li.hasClass('current')) return;
|
|
$li.addClass('current').siblings().removeClass('current');
|
|
page.DividendRateType = $li.text();
|
|
$('#selectDividendRateTypeMenuText').text(page.DividendRateType);
|
|
jqGridMgr.mainFilter({ DividendRateType: page.DividendRateType });
|
|
};
|
|
//标的代码下拉菜单--查看详细
|
|
instance.showSubList = function () {
|
|
event.preventDefault();
|
|
var rowid = $jqDropdown.data('rowid');
|
|
var postData = jqGridMgr.getPostData(rowid);
|
|
var $form = $('#formNew').html('');
|
|
_.forIn(postData, function (val, key) {
|
|
if (key === 'VarietyIds' || key === 'UnderlyingIds') return;
|
|
if (!_.isArray(val)) val = [val];
|
|
_.each(val, function (x) {
|
|
x && $(`<input type="hidden" name="${key}" value="${x}" />`).appendTo($form);
|
|
});
|
|
});
|
|
$form.submit();
|
|
};
|
|
|
|
//标的代码下拉菜单--对冲规则
|
|
instance.showAutoRule = function () {
|
|
event.preventDefault();
|
|
var code = $jqDropdown.data('rowid') || '';
|
|
code = code.replace(/^\$*/, '');
|
|
code = encodeURIComponent(code);
|
|
var index = layer.open({
|
|
type: 2, title: '对冲规则', shadeClose: true,
|
|
area: ['600px', '450px'], content: "/trade_autorule/edit2?code=" + code
|
|
});
|
|
};
|
|
|
|
//标的代码下拉菜单--价格阈值
|
|
instance.setPriceAlert = function () {
|
|
event.preventDefault();
|
|
var code = $jqDropdown.data('rowid') || '';
|
|
code = code.replace(/^\$*/, '');
|
|
code = encodeURIComponent(code);
|
|
var index = layer.open({
|
|
type: 2, title: '价格预警', shadeClose: true,
|
|
area: ['600px', '450px'], content: "/RiskHedging/setPriceAlert?code=" + code
|
|
});
|
|
};
|
|
|
|
//调整波动率配置
|
|
instance.showVolAdjust = function () {
|
|
var index = layer.open({
|
|
type: 2, min: false, title: '调整波动率配置',
|
|
shadeClose: true, maxmin: true, area: ['660px', '85%'],
|
|
content: "/VarietyVol/AdjustList",
|
|
end: function () {
|
|
window.location.reload();
|
|
}
|
|
});
|
|
};
|
|
|
|
//通用配置
|
|
instance.showSetting = function () {
|
|
$('#settingModal').modal('show');
|
|
};
|
|
|
|
//帮助
|
|
instance.showHelper = function () {
|
|
$('#helperModal').modal('show');
|
|
};
|
|
|
|
//通用配置--保存
|
|
instance.saveSetting = function () {
|
|
page.showTimestamp = $('#showTimestampSetting').prop('checked');
|
|
var data = {
|
|
UseMarketForExOptions: $('#exOptionPriceSetting').prop('checked'),
|
|
ShowTimestamp: page.showTimestamp
|
|
};
|
|
main.post('/RiskHedging/AjaxSaveConfig', data, false);
|
|
};
|
|
|
|
//通用配置--保存appconfig
|
|
instance.saveAppConfig = function (name) {
|
|
main.post('/appconfig/AjaxSave', { name: name, value: $(event.target).prop('checked') }, false);
|
|
};
|
|
|
|
//标的名称前端筛选
|
|
instance.clearFrontFilter = function () {
|
|
if (_selectUnderlying2Auto) {
|
|
_selectUnderlying2Auto.setData(null);
|
|
jqGridMgr.frontUpdateData();
|
|
}
|
|
}
|
|
return instance;
|
|
}(jqGridMgr));
|
|
|
|
//jQuery.Ready
|
|
$(function () {
|
|
const fp = flatpickr(".form_datetime", {
|
|
enableTime: true, dateFormat: "Y-m-d H:i",
|
|
allowInput: true, time_24hr: true
|
|
});
|
|
|
|
//初始化jqgrid
|
|
jqGridMgr.init(subView);
|
|
|
|
//对tooltips进行设置
|
|
$('body').on('mouseenter', '.yl-tooltip:not(.tooltipstered)', function () {
|
|
var content = $(this).data('tooltip-text');
|
|
if (content) {
|
|
$(this).tooltipster({
|
|
theme: 'tooltipster-borderless', delay: 0, content: $(this).data('tooltip-text'),
|
|
side: $(this).data('tooltip-side') || 'top', arrow: $(this).data('tooltip-arrow') !== 'no'
|
|
}).tooltipster('open');
|
|
} else {
|
|
$(this).addClass("tooltipstered");
|
|
}
|
|
});
|
|
|
|
mainView.init();
|
|
|
|
realtimeRefresh();
|
|
|
|
priceAlertInit();
|
|
});
|
|
|
|
//实时刷新
|
|
function realtimeRefresh() {
|
|
if ($('#realtimeRefreshCheck').prop('checked')) {
|
|
jqGridMgr.updateData();
|
|
setTimeout(realtimeRefresh, 2000);
|
|
}
|
|
}
|
|
|
|
function refreshOnce() {
|
|
$('#realtimeRefreshCheck').prop('checked', false);
|
|
jqGridMgr.updateData();
|
|
}
|
|
|
|
function showAlertUnderlying() {
|
|
if ($("#priceAlertUnderlying").is(":hidden")) {
|
|
$("#priceAlertUnderlying").show();
|
|
} else {
|
|
$("#priceAlertUnderlying").hide();
|
|
}
|
|
}
|
|
|
|
function setUnderlyingPriceAlert(code) {
|
|
if (code) {
|
|
let index = layer.open({
|
|
type: 2, title: '价格预警', shadeClose: true,
|
|
area: ['600px', '450px'], content: "/RiskHedging/setPriceAlert?code=" + encodeURIComponent(code)
|
|
});
|
|
} else {
|
|
let index = layer.open({
|
|
type: 2, title: '价格预警', shadeClose: true,
|
|
area: ['600px', '450px'], content: "/RiskHedging/setPriceAlert"
|
|
});
|
|
}
|
|
|
|
}
|
|
|
|
function priceAlertInit() {
|
|
let $alertSum = $("#alertSum");
|
|
|
|
$alertSum.prev('.fa').addClass("fa-bell-o");
|
|
|
|
if (page.UnderlyingAlerts && page.UnderlyingAlerts.length) {
|
|
let count = 0;
|
|
for (var i = 0; i < page.UnderlyingAlerts.length; i++) {
|
|
var um = page.UnderlyingAlerts[i];
|
|
var tdId = "#" + jqSelector(um.UnderlyingCode.replace(".", "_"));
|
|
var rate = (um.nowPrice - um.basePrice) / um.basePrice;
|
|
if (rate > um.priceIncreaseRate || rate < (um.priceDecreaseRate * -1)) {
|
|
count++;
|
|
$(tdId).css("background-color", 'lightsalmon');
|
|
} else {
|
|
$(tdId).css("background-color", 'white');
|
|
}
|
|
}
|
|
|
|
if (count > 0) {
|
|
$alertSum.html(count > 99 ? "99+" : count).prev('.fa').removeClass("fa-bell-o");
|
|
}
|
|
}
|
|
}
|
|
|
|
function jqSelector(str) {
|
|
return str.replace(/([;&,.+*~':"!^#$%@[\]()=>|])/g, '\\$1');
|
|
}
|
|
//缺陷:
|
|
//1.品种价格试算时,如果有新的标的交易出现,此交易将被排除在品种价格试算外,除非重新试算
|