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

538 lines
19 KiB
JavaScript

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();
});