408 lines
17 KiB
JavaScript
408 lines
17 KiB
JavaScript
var abType = ["报价Ask", "报价Bid"];
|
|
|
|
const consVarieties = ylotc.varieties;
|
|
var skey = $("#mainlayoutuser").html().trim() + "t_table";
|
|
var storedata = JSON.parse(localStorage.getItem(skey));
|
|
var default_Model = {
|
|
OtherInfo: "",
|
|
OtherInfoObj: {},
|
|
WorkDayHTML: "",
|
|
SelectModel: "波动率",
|
|
Count: 1,
|
|
InputVolChange: true, InputChange: false,
|
|
QuotationModes: [{ Mode: "波动率", value: 0 }, { Mode: "百分比", value: 1 }, { Mode: "绝对价格", value: 2 }],
|
|
TQuoteRecords: { LatestPrice: 0, quotaList: [{ Strike: 0 }] }, ExerciseDate: "", PricingModel: "BSM", ExerciseMode: "European", QuotationMode: "波动率", DefaultVol: "0.3", ZhiXingJianGe: "", ZhiXingShuLiang: 11, CanSaveLocalCache: false
|
|
|
|
};
|
|
if (storedata) {
|
|
Underlying = storedata["Underlying"];
|
|
expireList = storedata["expireList"];
|
|
orderStrikes = storedata["orderStrikes"];
|
|
default_Model = storedata["Model"];
|
|
}
|
|
const consUnderlyingFlag = (function () {
|
|
let unSelFlag = tradeHelper.UnderlyingSelectFlag;
|
|
return unSelFlag.UseForTrading | unSelFlag.IncludeMatured | unSelFlag.UsePinYinFilter;
|
|
}());
|
|
var autoVariety, autoUnderlying, salesCommissionCtrl;
|
|
function __init(vue) {
|
|
|
|
//标的品种
|
|
autoVariety = FastVue.autocomplete(document.getElementById('VarietyId'), {
|
|
lookup: consVarieties, nameField: 'Name', valueField: 'id', searchField: ['Name', 'Code', 'PinYin'],
|
|
onSelect: function (data) { vue.changeVariety(data, 'select'); }
|
|
});
|
|
|
|
//标的资产
|
|
autoUnderlying = tradeHelper.UnderlyingAutoComplete('UnderlyingCode').setFlag(consUnderlyingFlag);
|
|
autoUnderlying.onSelect(vue.changeunderlying);
|
|
|
|
//标的控件初始化
|
|
if (vue.Underlying.UnderlyingName) {
|
|
autoUnderlying.selectByCode(vue.Underlying.UnderlyingName);
|
|
}
|
|
else {
|
|
autoUnderlying.selectFirst();
|
|
}
|
|
|
|
}
|
|
|
|
var vue = new Vue({
|
|
el: "#listdiv",
|
|
data: {
|
|
Variety: tradeHelper.getEmptyVariety(),
|
|
Underlying: { ...tradeHelper.getEmptyUnderlying(), Price: 0 },
|
|
expireList: [{ Expire: "", IsNew: false, Vol: [{ Strike: "", VolValue: "" }] }],
|
|
orderStrikes: [{ Vol: "", Strike: "", IsNew: false }],
|
|
Model: default_Model,
|
|
on_underlyingGetById: false
|
|
},
|
|
mounted: function () {
|
|
//设置默认到期日
|
|
var thisObj = this;
|
|
$(window).on('beforeunload', function () {
|
|
//设置local
|
|
if (thisObj.CanSaveLocalCache) {
|
|
var pagedata = JSON.stringify(vue.$data);
|
|
localStorage.setItem(skey, pagedata);
|
|
}
|
|
});
|
|
__init(thisObj);
|
|
main.setTradeDatePicker();
|
|
thisObj.setUnderlyingInstrumentType();
|
|
},
|
|
computed: {
|
|
attachesFilter: function (d) {
|
|
var data = $.map(value, function (a, t) { if (a.masterId == oid) return true; });
|
|
return data;
|
|
}
|
|
},
|
|
updated: function () {
|
|
$(".chosen-select").trigger("chosen:updated");
|
|
this.handlechange();
|
|
if (this.Model.InputChange) {
|
|
this.calcTTable();
|
|
this.Model.InputChange = false;
|
|
}
|
|
},
|
|
filters: {
|
|
SetVolTypeName: function (rawName) {
|
|
switch (rawName) {
|
|
case "交易": return "交易Mid";
|
|
case "报价Bid": return "交易Bid";
|
|
case "报价Ask": return "交易Ask";
|
|
default: return rawName;
|
|
}
|
|
},
|
|
toInt: function (d) {
|
|
return d.toFixed(0);
|
|
},
|
|
toPercent: function (d) {
|
|
return (d * 100).toFixed(1) + "%";
|
|
},
|
|
CallPv: function (tt, iindex, index) {
|
|
try {
|
|
return tt[iindex].OVR[index].看涨.Pv.toFixed(2);
|
|
} catch (e) {
|
|
//
|
|
}
|
|
},
|
|
percentVol: function (data) {
|
|
return numeral(data * 100).format("0.00");
|
|
}
|
|
},
|
|
methods: {
|
|
setTQuoteRecordsProxy: function (TQuoteRecords) {
|
|
var thisObj = this;
|
|
var list = TQuoteRecords.quotaList;
|
|
if (list && list.length) {
|
|
const proxyProps = ["CallBidVol", "CallAskVol", "PutBidVol", "PutAskVol"];
|
|
list.forEach(function (obj) {
|
|
var propDefines = {};
|
|
proxyProps.map(function (pname) {
|
|
obj[pname + 'Proxy'] = numeral(obj[pname] * 100).format("0.00");
|
|
});
|
|
});
|
|
}
|
|
return TQuoteRecords;
|
|
},
|
|
FormatProxyValue: function (event) {
|
|
var vol = $(event.target).val();
|
|
$(event.target).val(numeral(vol).format("0.00"));
|
|
},
|
|
handlechange() {
|
|
var thisObj = this;
|
|
if (this.Model.SelectModel == "波动率") {
|
|
$(".datatwo").css('display', 'none');
|
|
$(".datathree").css('display', 'none');
|
|
$(".dataone").css('display', 'block');
|
|
} else if (this.Model.SelectModel == "百分比") {
|
|
|
|
$(".datatwo").css('display', 'block')
|
|
$(".dataone").css('display', 'none');
|
|
$(".datathree").css('display', 'none');
|
|
} else if (this.Model.SelectModel == "绝对价格") {
|
|
|
|
$(".datatwo").css('display', 'none');
|
|
$(".dataone").css('display', 'none');
|
|
$(".datathree").css('display', 'block');
|
|
}
|
|
},
|
|
percentVol: function (data) {
|
|
return numeral(data * 100).format("0.00");
|
|
},
|
|
setUnderlyingInstrumentType: function () {
|
|
var Underlying = $("#selUnderlyingInstrumentType").val();
|
|
autoUnderlying.selectFirst({ InstrumentTypes: Underlying });
|
|
},
|
|
changeVariety: function (variety, flag) {
|
|
if (flag === 'select') {
|
|
if (this.Model.VarietyId === variety.id) return;
|
|
//this.Model.UnderlyingInstrumentType = variety.InstrumentType;
|
|
autoUnderlying.setVarietyId(variety.id);
|
|
//Object.assign(this.Variety.underlying, tradeHelper.getEmptyUnderlying(variety.id));
|
|
autoUnderlying.selectFirst(variety.id);
|
|
} else {
|
|
autoVariety.setData(variety);
|
|
}
|
|
Object.assign(this.Variety, variety || tradeHelper.getEmptyVariety());
|
|
},
|
|
changeunderlying: function (data) {
|
|
var thisObj = this;
|
|
if (thisObj.on_underlyingGetById) return;
|
|
thisObj.Underlying.id = data.id;
|
|
|
|
if (thisObj.Underlying.id) {
|
|
thisObj.on_underlyingGetById = true;
|
|
thisObj.Underlying.UnderlyingCode = data.Code;
|
|
thisObj.Underlying.UnderlyingInstrumentType = data.InstrumentType;
|
|
thisObj.Underlying.UnderlyingTypeId = data.VarietyId;
|
|
thisObj.Underlying.ContractSize = data.ContractSize;
|
|
thisObj.Underlying.CountRatio = data.CountRatio;
|
|
thisObj.Underlying.Price = main.toNumber(data.Price);
|
|
thisObj.Model.ExerciseDate = main.toDate(data.ExerciseDate);
|
|
thisObj.Model.ZhiXingJianGe = main.toInt(thisObj.Underlying.Price * 0.05);
|
|
if (thisObj.Model.ZhiXingJianGe <= 0) thisObj.Model.ZhiXingJianGe = 1;
|
|
thisObj.changeVariety(data.VarietyId ? ylotc.varieties.find(x => x.id === data.VarietyId) : null);
|
|
thisObj.Model.InputChange = true;
|
|
main.setTradeDatePicker();
|
|
thisObj.on_underlyingGetById = false;
|
|
main.post("/Pricing/AjaxGetExerciseDate", { underlyingMaturityDate: data.MaturityDate, tradeDate: thisObj.Model.TradeDate }, { async: false }).done(function (res) {
|
|
thisObj.Model.ExerciseDate = new moment(res.obj.ExerciseDate).format("YYYY-MM-DD");
|
|
});
|
|
}
|
|
|
|
},
|
|
changeVolMode: function () {
|
|
var thisObj = this;
|
|
},
|
|
loadVols: function () { //读取波动率
|
|
this.Model.InputChange = true;
|
|
},
|
|
changeJianGe: function () { //波动率模式改变
|
|
this.Model.InputChange = true;
|
|
this.Model.ZhiXingJianGe = main.toInt(Math.abs(this.Model.ZhiXingJianGe));
|
|
},
|
|
checkPayOffType: function () { //行权方式改变
|
|
this.Model.InputChange = true;
|
|
},
|
|
changeZhiXingShuLiang: function () { //执行数量改变
|
|
this.Model.InputChange = true;
|
|
},
|
|
changeUnderlyingPrice: function () { //执行数量改变
|
|
if (main.toNumberExcludingNaN(this.Underlying.Price) == "0.00") {
|
|
$("#UnderlyingPrice").focus();
|
|
main.message("请输入正确的标的价格");
|
|
return;
|
|
}
|
|
var thisObj = this;
|
|
setTimeout(function () {
|
|
thisObj.Model.InputChange = true;
|
|
}, 10);
|
|
|
|
},
|
|
exerciseDateChange: function () { //到期日改变
|
|
this.Model.ExerciseDate = $("#Trade_ExerciseDate").val();
|
|
if (!this.Model.ExerciseDate) return;
|
|
var systsemdate = $("#mainsystemvaluedate").html();
|
|
var checkMaturityDate = this.Underlying.MaturityDate;
|
|
if (this.Model.ExerciseDate > checkMaturityDate) {
|
|
main.message("期权到期日不能大于标的到期日:{0}".template(this.Underlying.MaturityDate));
|
|
this.Model.ExerciseDate = null;
|
|
}
|
|
if (this.Model.ExerciseDate < systsemdate) {
|
|
main.message("期权到期日不能小于系统日期");
|
|
this.Model.ExerciseDate = null;
|
|
}
|
|
this.Model.InputChange = true;
|
|
},
|
|
calcVolTTable: function () { //计算价格
|
|
var thisObj = this;
|
|
if (!thisObj.Model.ExerciseDate) {
|
|
main.message("请输入期权到期日"); return;
|
|
}
|
|
if (!thisObj.Underlying.id) {
|
|
main.message("请输入标的代码"); return;
|
|
}
|
|
//有改动
|
|
if (thisObj.Underlying.Price <= 0) {
|
|
main.message("请输入正数标的价格"); return;
|
|
}
|
|
//console.log(thisObj.Underlying.Price);
|
|
thisObj.FormatVols();//同步Poxy字段和实际字段的值
|
|
var reqObj = { Records: thisObj.Model.TQuoteRecords.quotaList, SpotPrice: thisObj.Underlying.Price, UnderlyingCode: thisObj.Underlying.UnderlyingCode, MaturityDate: thisObj.Model.ExerciseDate };
|
|
main.post("/volatility/TQuoteWithCustomizedVol", reqObj).done(function (res) {
|
|
thisObj.Model.TQuoteRecords = thisObj.setTQuoteRecordsProxy(res.obj);
|
|
thisObj.Model.InputVolChange = false;
|
|
});
|
|
},
|
|
FormatVols: function () {
|
|
var thisObj = this;
|
|
$.each(thisObj.Model.TQuoteRecords.quotaList, function (i, obj) {
|
|
obj.CallBidVol = obj.CallBidVolProxy / 100;
|
|
obj.CallAskVol = obj.CallAskVolProxy / 100;
|
|
obj.PutBidVol = obj.PutBidVolProxy / 100;
|
|
obj.PutAskVol = obj.PutAskVolProxy / 100;
|
|
});
|
|
},
|
|
FixCenterNumber: function (strike) {
|
|
var thisObj = this;
|
|
if (strike == thisObj.Model.TQuoteRecords.LatestPrice) {
|
|
return "<span style='background:green'>{0}</span>".template(strike);
|
|
}
|
|
return strike;
|
|
},
|
|
calcTTable: function () { //读取波动率 其实时间在服务端,永远为当前日期
|
|
//检查输入
|
|
var thisObj = this;
|
|
thisObj.CanSaveLocalCache = false;
|
|
if (!thisObj.Model.ExerciseDate) {
|
|
main.message("请输入期权到期日"); return;
|
|
}
|
|
if (!thisObj.Underlying.id) {
|
|
main.message("请输入标的代码"); return;
|
|
}
|
|
if (thisObj.Underlying.Price <= 0) {
|
|
main.message("请输入正数标的价格"); return;
|
|
}
|
|
|
|
thisObj.Model.InputChange = false;
|
|
var reqObj = { strikeCount: thisObj.Model.ZhiXingShuLiang, strikeInterval: thisObj.Model.ZhiXingJianGe, spotPrice: thisObj.Underlying.Price, underlyingCode: thisObj.Underlying.UnderlyingCode, maturityDate: thisObj.Model.ExerciseDate };
|
|
main.post("/volatility/TQuote", reqObj).done(function (res) {
|
|
if (res.obj.StatusCode != 0) {
|
|
main.message(res.obj.Info);
|
|
}
|
|
else {
|
|
//TQuote
|
|
thisObj.Model.TQuoteRecords = thisObj.setTQuoteRecordsProxy(res.obj);
|
|
thisObj.Model.Count = res.obj.quotaList == undefined ? 0 : res.obj.quotaList.length;
|
|
|
|
thisObj.Model.OtherInfo = res.obj.OtherInfo;
|
|
thisObj.getWorkDayDesc();
|
|
thisObj.CanSaveLocalCache = true;
|
|
}
|
|
});
|
|
},
|
|
getWorkDayDesc: function () {
|
|
var thisObj = this;
|
|
var from = moment().format("YYYY-MM-DD");
|
|
var to = main.toDate(thisObj.Model.ExerciseDate);
|
|
var underlying = thisObj.Underlying;
|
|
main.post("/calendar/DaysInPeriod", { from: from, to: to, varietyid: underlying.UnderlyingTypeId }).done(function (res) {
|
|
var bidtunning = 0, asktunning = 0;
|
|
bidtunning += res.obj; asktunning += res.obj;
|
|
thisObj.Model.WorkDayHTML = "期权交易日天数: {0}".template(res.obj, bidtunning, asktunning);
|
|
if (bidtunning != res.obj || asktunning != res.obj) {
|
|
thisObj.Model.WorkDayHTML += "</br>买入期权交易调整后交易日天数:{1}</br>卖出期权交易调整后交易日天数:{2}</br>".template(res.obj, bidtunning, asktunning);
|
|
}
|
|
});
|
|
},
|
|
sortVolTypes: function () {
|
|
var thisObj = this;
|
|
//VolTypes 显示排序补丁
|
|
var typeSort = ["报价Bid", "交易", "报价Ask"];
|
|
thisObj.VolTypes.sort(function (a, b) {
|
|
var aindex = typeSort.indexOf(a.VolModelName);
|
|
var bindex = typeSort.indexOf(b.VolModelName);
|
|
return aindex - bindex;
|
|
});
|
|
|
|
},
|
|
getCTPdata: function (unid, vueObj) {
|
|
var thisObj = this;
|
|
main.post("/pricing/AjaxGetUnderlyingPrice", { underlyingCode: thisObj.Underlying.UnderlyingCode }).done(function (res) {
|
|
if (typeof res.obj.price !== "undefined") {
|
|
thisObj.Underlying.Price = main.toNumber(res.obj.price);
|
|
thisObj.Model.InputChange = true;
|
|
}
|
|
else {
|
|
thisObj.Underlying.Price = 0;
|
|
}
|
|
});
|
|
},
|
|
changeVolInput: function () {
|
|
var thisObj = this;
|
|
thisObj.FormatVols();//同步Poxy字段和实际字段的值
|
|
var $obj = $(event.srcElement);
|
|
var thisData = $obj.val() / 100;
|
|
var type = $obj.attr("recordtype");
|
|
var rindex = $obj.attr("recordindex");
|
|
thisObj.Model.TQuoteRecords.quotaList[rindex][type] = thisData;
|
|
thisObj.Model.InputVolChange = true;
|
|
},
|
|
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);
|
|
},
|
|
up: function (type) {
|
|
var thisObj = this;
|
|
thisObj.FormatVols();//同步Poxy字段和实际字段的值
|
|
thisObj.Model.InputVolChange = true;
|
|
$.each(thisObj.Model.TQuoteRecords.quotaList, function (i, d) {
|
|
d[type] = d[type] + 0.001;
|
|
});
|
|
thisObj.setTQuoteRecordsProxy(thisObj.Model.TQuoteRecords);
|
|
},
|
|
down: function (type) {
|
|
var thisObj = this;
|
|
thisObj.FormatVols();//同步Poxy字段和实际字段的值
|
|
thisObj.Model.InputVolChange = true;
|
|
$.each(thisObj.Model.TQuoteRecords.quotaList, function (i, d) {
|
|
d[type] = d[type] - 0.001;
|
|
//d[type + 'Proxy'] = numeral(d[type] * 100).format("0.00");
|
|
|
|
});
|
|
thisObj.setTQuoteRecordsProxy(thisObj.Model.TQuoteRecords);
|
|
},
|
|
PercentNumber: function (data) {
|
|
return numeral(data).format("0,0.00%");
|
|
},
|
|
clearChange: function () {
|
|
// window.location.href = window.location.href;
|
|
var thisObj = this;
|
|
thisObj.changeunderlying();
|
|
},
|
|
closePage: function (cid) {
|
|
parent.layer.closeAll();
|
|
},
|
|
showAlink: function (obj) {
|
|
var thisObj = this;
|
|
if (this.Model.SelectModel == "波动率") {
|
|
$(obj).find("a").css("display", "inline");
|
|
}
|
|
},
|
|
hideAlink: function (obj) {
|
|
$(obj).find("a").css("display", "none");
|
|
}
|
|
}
|
|
}); |