const datePickerOpt = { changeMonth: true, changeYear: true, showButtonPanel: true, showOtherMonths: true, selectOtherMonths: true, maxDate: pageObj.valueDate }; //全局SkewMap const globalHandler = (new function () { this.init = function () { $('#uploadSkewMapCtrl').on('change', function () { $(this).next().text($(this).val()); }).next().on('click', function () { $(this).prev().click(); }); }; this.upload = function () { var formData = new FormData(); formData.append("skewMapType", $("#skewMapType").val()); //上传的文件file let files = document.getElementById('uploadSkewMapCtrl').files; if (!files.length) { return main.alert('请选择上传文件'); } formData.append("file", files[0]); main.waitMe("show"); $.ajax({ url: '/skewMap/UploadSkewMap', type: 'POST', processData: false, contentType: false, data: formData, cache: false, success(resp) { if (resp.success) { parent.main.message("导入成功!"); $('#uploadSkewMapCtrl').val('').next().text('请选择...'); } else { main.message("导入失败:" + resp.msg); } }, error() { main.message("导入失败"); }, complete() { main.waitMe("hide"); } }); }; this.download = function () { $('#hide_skewMapType').val($("#skewMapType").val()); $('#formGlobal').submit(); }; }); //光证波动率 const gzVolHandler = (new function () { var volInputCtrl; function getVol() { $("#varietyVol_gz").val(""); let data = { varietyId: $('#varietyId_gz').val(), valueDate: $('#maintainDate_gz').val(), }; if (!data.valueDate || !data.varietyId) return; main.post("/skewMap/GetVarietyVol", data).done(function (res) { if (res.obj) { volInputCtrl.setValue(res.obj.Vol); } else { main.message("光证波动率不存在"); } }); } this.init = function () { $("#maintainDate_gz").datepicker(datePickerOpt).val(pageObj.valueDate).change(); let autoVariety = FastVue.autocomplete(document.getElementById('varietyId_gz'), { lookup: pageObj.varieties, nameField: 'Name', valueField: 'id', searchField: ['Name', 'Code', 'PinYin'], onSelect: getVol }); volInputCtrl = FastVue.numberInput('varietyVol_gz', { append: '%' }); $('#maintainDate_gz').on('change', function () { let enable = pageObj.valueDate === $("#maintainDate_gz").val(); $('#btnSaveGzVol').prop('disabled', !enable); getVol(); }); } this.saveVol = function () { let data = { varietyId: $('#varietyId_gz').val(), valueDate: $('#maintainDate_gz').val(), vol: volInputCtrl.getValue() }; if (!data.varietyId) { return main.alert('标的品种 必须填写'); } if (!data.valueDate) { return main.alert('维护日期 必须填写'); } if (!data.vol) { return main.alert(' 光证波动率 必须填写'); } main.post("/skewMap/SetVarietyVol", data).done(function () { main.message("保存成功"); }); }; }); //标的BaseVol const baseVolVue = new Vue({ el: "#baseVolWrap", data: { Vollist: {}, expireList: [], BidVar: 1, AskVar: 1, Model: { canSaveVol: true, VolSurfaceMode: "MoneynessVol", InterpolationMethod: "", VolTable: [], VolType: "交易", DefaultVol: "0.3", CacheVollist: {}, StrikeDesc: "行权价", CheckAddExpire: true, CheckVols: true }, }, methods: { setVolTableProxy: function (volTable) { var thisObj = this; var list = volTable; const proxyProps = ["Strike"]; if (list && list.length) { list.forEach(function (obj) { var propDefines = {}; proxyProps.map(function (pname) { propDefines[pname + 'Proxy'] = { get: function () { return numeral(obj[pname] * 100).format("0.00"); }, set: function (newValue) { obj[pname] = newValue / 100; thisObj.Model.InputVolChange = true; } }; }); Object.defineProperties(obj, propDefines); }); } else { var propDefines = {}; proxyProps.map(function (pname) { propDefines[pname + 'Proxy'] = { get: function () { return numeral(volTable[pname] * 100).format("0.00"); }, set: function (newValue) { volTable[pname] = newValue / 100; thisObj.Model.InputVolChange = true; } }; }); Object.defineProperties(volTable, propDefines); } return volTable; }, watchVol: function (VolProxy) { var valueArray = String(VolProxy).split("."); if (valueArray.length > 1 && valueArray[1].length > 2) { if (pageObj.volMoreAccurate) { VolProxy = Math.floor(VolProxy * 10000) / 10000; } else { VolProxy = Math.floor(VolProxy * 100) / 100; } } return VolProxy; }, checkvols: function (event) { //检查vol的数字必需为正数. //2. 同一个vol grid, 检查所有数字,发现max > 10 * min,就报错,提示交易员有问题。纠正后再保存。 //如果用户选择忽略,则允许保存。 if (event) { let vol = this.watchVol($(event.target).val()); let strike = $(event.target).attr("Strike"); let expire = $(event.target).attr("Expire"); $.each(baseVolVue.expireList, function (i, obj) { if (obj.Expire === expire) { $.each(obj.Vols, function (j, item) { if (item.Strike === strike) { item.VolProxy = vol; item.Vol = vol / 100; } return false; }); return false; } }); if (vol <= 0) { $(event.target).focus(); main.message("波动率请输入正数"); this.Model.CheckVols = false; return; } } var maxVol = { Vol: 0 }; var minVol = { Vol: 99999 }; $.grep(baseVolVue.expireList, function (obj, index) { $.grep(obj.Vols, function (data, i) { if (data.Vol && obj.Expire !== "BidVar" && obj.Expire !== "AskVar") { if (data.Vol > maxVol.Vol) { maxVol = data; } if (data.Vol < minVol.Vol) { minVol = data; } } }); }); if (maxVol.Vol > 10 * minVol.Vol) { main.message("警告,最大Vol超过10倍最小Vol"); } this.Model.CheckVols = true; }, checkVar: function (ex) { if (!(/^\d+$/.test(ex.currentTarget.value))) { main.message("正确的Var值应为正整数"); ex.currentTarget.focus(); } }, checkAddExpire: function (obj) { var thisObj = this; $("#newAddExpire").val($("#newAddExpire").val().toUpperCase()); var newExpire = $("#newAddExpire").val(); if (!newExpire || !thisObj.checkExpire(newExpire)) { main.message("请输入正确的期限"); thisObj.Model.CheckAddExpire = false; $("#newAddExpire").focus(); return; } var eList = []; $.each(this.expireList, function (i, obj) { if (!obj.IsNewExpire) { eList.push(obj); } }); if (eList.some(x => x.Expire === newExpire)) { main.message("请输入不同的期限"); thisObj.Model.CheckAddExpire = false; $("#newAddExpire").focus(); } else { thisObj.Model.CheckAddExpire = true; } this.checkvols(); }, deleteExpire: function (expire) { var thisObj = this; var flag = false; var grepExpire = []; if (!expire.IsNewExpire) { //删除行为新增到期日时 $.grep(thisObj.Vollist.VolTable, function (value) { if (value.Expire != expire.Expire) { grepExpire.push(value); } }); } else { $.grep(thisObj.Vollist.VolTable, function (value) { if (value.Expire != "") { grepExpire.push(value); } }); } if (!grepExpire.length) { flag = true; } if (!flag) { if (expire.IsNewExpire) { thisObj.Model.CheckAddExpire = true; } thisObj.Vollist.VolTable = grepExpire; thisObj.Vollist.Data = JSON.stringify(thisObj.Vollist.VolTable); } if (flag) { main.message("不能删光到期日"); return; } thisObj.loadVollist(); if (expire.IsNewExpire) { thisObj.Model.CheckAddExpire = true; } }, loadVollist: function () { //为展示分析波动率数据 var thisObj = this; //移除空 thisObj.expireList = []; if (thisObj.Vollist.VolTable && thisObj.Vollist.VolTable.length) { thisObj.Vollist.VolTable.sort(function sortStrike(a, b) { return a.Strike - b.Strike }); $.each(thisObj.Vollist.VolTable, function (i, d) { //补丁,有时候会出现Strike为1.0和1.00不是同一个strike情况 d.Strike = main.toNumber(d.Strike, 4); if (typeof (d) !== "function") { if (d.IsNewExpire || (d.Expire !== "" && d.Vol !== 0)) { if (d.Expire === "AskVar") { thisObj.AskVar = d.Vol; } else if (d.Expire === "BidVar") { thisObj.BidVar = d.Vol; } else if (!thisObj.expireList.some(x => x.Expire === d.Expire)) { thisObj.expireList.push({ ValidState: d.ExpireValidState, Expire: d.Expire, IsNewExpire: d.IsNewExpire, Vols: [{ Vol: d.Vol, Strike: d.Strike }] }); } else { $.each(thisObj.expireList, function (j, obj) { if (obj.Expire === d.Expire) { obj.Vols.push({ Vol: d.Vol, Strike: d.Strike }); } }); } } } }); }; var orderExpire = ["D", "W", "M", "Y"]; $.each(thisObj.expireList, function (i, obj) { thisObj.setVolTableProxy(obj.Vols); $.each(obj.Vols, function (j, item) { item.VolProxy = numeral(item.Vol * 100).format("0.00") }); }) thisObj.expireList.sort(function sortExpire(a, b) { //比较到期日字母,比较数字 var adata = thisObj.getExpireDay(a.Expire); var bdata = thisObj.getExpireDay(b.Expire); return adata - bdata; }); }, getExpireDay: function (expire) { var mu = expire.substr(expire.length - 1, 1); var data = expire.substr(0, expire.length - 1); var drate = 1; switch (mu) { case "W": drate = 7; break; case "M": drate = 30; break; case "Y": drate = 365; break; } return data * drate; }, checkExpire: function (ex) { return /^\d+(W|Y|M|D)$/.test(ex); } } }); //标的BaseVol const baseVolHandler = (new function () { var _autoUnderlying; function initVoTable() { baseVolVue.BidVar = 1; baseVolVue.AskVar = 1; baseVolVue.expireList = []; baseVolVue.Vollist = { canSaveVol: true, VolTable: [{ Strike: 1, Expire: "", Vol: "" }], DefaultVol: "0.3", CacheVollist: {}, StrikeDesc: "行权价", CheckAddExpire: true, CheckVols: true }; baseVolVue.loadVollist(); } function getBaseVolInfo() { initVoTable(); let data = { valueDate: _.trim($("#maintainDate").val()), underlyingCode: _.trim($('#selUnderlying').val()) }; if (!data.valueDate || !data.underlyingCode) { return; } main.post("/skewMap/GetBaseVol", data).done(function (res) { let baseVol = res.obj; if (baseVol) { baseVolVue.Vollist = baseVol; baseVolVue.loadVollist(); } else { main.message("BaseVol不存在"); } }); } this.init = function () { $("#maintainDate").datepicker(datePickerOpt).val(pageObj.valueDate).change(); $('#uploadBaseVolCtrl').on('change', function () { $(this).next().text($(this).val()); }).next().on('click', function () { $(this).prev().click(); }); let unflag = tradeHelper.UnderlyingSelectFlag; let options = { SelectFlag: unflag.UsePinYinFilter | unflag.IncludeMatured, onSelect: getBaseVolInfo }; _autoUnderlying = tradeHelper.UnderlyingAutoComplete('selUnderlying', options); _autoUnderlying.selectFirst(); $('#maintainDate').on('change', function () { let enable = pageObj.valueDate === $("#maintainDate").val(); $('#btnSaveBaseVol').prop('disabled', !enable); getBaseVolInfo(); }); }; this.upload = function () { let files = document.getElementById('uploadBaseVolCtrl').files; if (!files.length) { return main.alert('请选择上传文件'); } var formData = new FormData(); formData.append("file", files[0]); main.waitMe("show"); $.ajax({ url: '/skewMap/UploadBaseVol', type: 'POST', processData: false, contentType: false, data: formData, cache: false, success: function (resp) { if (resp.success) { main.message("导入成功!"); $('#uploadBaseVolCtrl').val('').next().text('请选择...'); } else { main.message("导入失败:" + resp.msg); } }, error(data) { main.message("导入失败"); }, complete() { main.waitMe("hide"); } }); }; this.download = function (isAll) { let data = { valueDate: _.trim($("#maintainDate").val()), underlyingCode: isAll ? "" : _.trim($('#selUnderlying').val()) }; if (!data.valueDate) { return main.alert('维护日期 必须填写'); } if (!isAll && !data.underlyingCode) { return main.alert('标的代码 必须填写'); } $('#hide_base_valueDate').val(data.valueDate); $('#hide_base_underlyingCode').val(data.underlyingCode); $('#formBaseVol').submit(); }; this.addExpire = function () { if (baseVolVue.Vollist.VolTable.some(x => x.IsNewExpire)) { return main.message("已经有新增到期日"); } var newVol = []; if (baseVolVue.expireList.length > 0) { $.each(baseVolVue.expireList[0].Vols, function (i, d) { newVol.push({ Strike: d.Strike, Vol: d.Vol }); }) } else { newVol.push({ Strike: 1, Vol: 0.3 }); } $.each(newVol, function (i, d) { baseVolVue.Vollist.VolTable.push({ Expire: "", IsNewExpire: true, Strike: d.Strike, Vol: d.Vol }); }) baseVolVue.loadVollist(); }; this.clearChange = getBaseVolInfo; this.saveBaseVol = function () { let data = { QuotationDate: _.trim($("#maintainDate").val()), ContractCode: _.trim($('#selUnderlying').val()) }; if (!data.QuotationDate) { return main.alert('维护日期 必须填写'); } if (!data.ContractCode) { return main.alert('标的代码 必须填写'); } if (!baseVolVue.Model.CheckAddExpire) { return main.message("请检查新增到期日是否正确"); } if (!baseVolVue.Model.CheckVols) { return main.message("请检查波动率是否正确"); } if (!(/^\d+$/.test(baseVolVue.BidVar))) { return main.message("请检查BidVar是否正确"); } if (!(/^\d+$/.test(baseVolVue.AskVar))) { return main.message("请检查AskVar是否正确"); } let VolTable = []; $.each(baseVolVue.expireList, function (i, obj) { $.each(obj.Vols, function (j, d) { VolTable.push({ Strike: d.Strike, Expire: obj.Expire.toUpperCase(), Vol: main.toNumber(d.Vol, 4) }); }); }); VolTable.push({ Strike: 1, Expire: "BidVar", Vol: baseVolVue.BidVar }); VolTable.push({ Strike: 1, Expire: "AskVar", Vol: baseVolVue.AskVar }); data.Data = JSON.stringify(VolTable); main.post('/skewMap/SetBaseVol', data).done(function (res) { main.alert("保存成功"); baseVolVue.Vollist = res.obj; baseVolVue.loadVollist(); }); }; }); $(function () { globalHandler.init(); gzVolHandler.init(); baseVolHandler.init(); });