Files
zszq-trs/YLErpWeb/wwwroot/Scripts/app/riskHedging/riskIndex2.js
T
2024-05-09 14:06:26 +08:00

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 ? '&nbsp;' : `<strong style="${style}">${formatVal}</strong>`
: rowObject.rowFlag & ConsFixPriceV
? consPriceRenderV2({ price: formatVal, UnderlyingCode: rowObject.UnderlyingCode })
: consPriceRenderV1({
style: style, UnderlyingCode: rowObject.UnderlyingCode,
formatVal: rowObject.rowFlag & ConsExpand ? '&nbsp;' : 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 = '交易编号:&nbsp;&nbsp;' + (rowData.TradeNumber || '') + ',&nbsp;&nbsp;标的代码:&nbsp;&nbsp;' + 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}:&nbsp;&nbsp;</strong>${texts}</span>&nbsp;&nbsp;`);
}
});
postData.OnlyPosition = $('#checkShowPositions').prop('checked');
innerCall || $('#btnFilterPopup').dropdown('toggle');
jqGridMgr.mainFilter(postData);
if (postData.OnlyPosition) {
descArr.push('<strong class="yl-filterdesc">只显示有持仓的合约</strong>&nbsp;&nbsp;');
}
$('#searchFilterDesc').html(descArr.join('') || '<strong>筛选条件:&nbsp;</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>筛选条件:&nbsp;</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.品种价格试算时,如果有新的标的交易出现,此交易将被排除在品种价格试算外,除非重新试算