279 lines
14 KiB
JavaScript
279 lines
14 KiB
JavaScript
//定价格式化(来自配置)
|
||
const inputFormatPercent = Object.freeze({ precision: 2, append: '%' });
|
||
const inputFormatPercentNegative = Object.freeze({ precision: 2, append: '%', negative: true });
|
||
const inputFormatNegative = Object.freeze({ precision: 2, negative: true });
|
||
|
||
const MarginRuleTypeEnum = {
|
||
无预付金: "0",
|
||
按固定利率: "1",
|
||
按浮动盈亏: "2",
|
||
类香草预付金规则: "3",
|
||
自动赎回买入预付金规则: "4",
|
||
触发条件预付金规则1: "5",
|
||
触发条件预付金规则2: "6",
|
||
保底预付金规则: "7",
|
||
含赔付预付金计算规则: "8",
|
||
触发条件预付金规则3: "9",
|
||
交易所基本规则: "10",
|
||
标准SPAN: "11",
|
||
买入自动赎回规则1: "12",
|
||
卖出自动赎回规则1: "13",
|
||
区间追保结构: "15",
|
||
默认预付金规则: "99"
|
||
};
|
||
|
||
const UnderlyingSeperateTypeEnum = {
|
||
None: "0",//不区分
|
||
CustomStock: "1",//按自定义权益分类
|
||
CustomInstrumentType: "2"//按资产类型分类
|
||
};
|
||
|
||
const vue = new Vue({
|
||
el: '#marginTemplateV2Form',
|
||
data: {
|
||
isAdd: page.isAdd,
|
||
marginTemplate: page.marginTemplate,
|
||
latestValueDate: page.marginTemplate.LatestValueDate
|
||
},
|
||
created: function () {
|
||
this.changeRuleType(true);
|
||
},
|
||
methods: {
|
||
changeRuleType(isInitial) {
|
||
switch (this.marginTemplate.RuleType.toString()) {
|
||
case MarginRuleTypeEnum.无预付金:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为零。";
|
||
break;
|
||
case MarginRuleTypeEnum.按固定利率:
|
||
this.marginTemplate.Comments = "预付金占用为成交/实时名义本金的固定比例。";
|
||
break;
|
||
case MarginRuleTypeEnum.按浮动盈亏:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为成交/实时名义本金的固定比例,加上对手方交易浮动亏损,扣除对手方交易浮动盈利。";
|
||
break;
|
||
case MarginRuleTypeEnum.类香草预付金规则:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为为成交/实时名义本金的浮动比例,加上对手方交易浮动亏损。浮动比例依据标的涨跌停情况判断。";
|
||
break;
|
||
case MarginRuleTypeEnum.自动赎回买入预付金规则:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为n+2(≤N)个票息之和,N为合约期内敲出观察日总数,n为当前经过的敲出观察日个数(当n+2>N时,n = N - 2)。";
|
||
break;
|
||
case MarginRuleTypeEnum.触发条件预付金规则1:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为成交名义本金的固定比例,加标的跌幅的市值(跌幅达到一定条件触发)";
|
||
break;
|
||
case MarginRuleTypeEnum.触发条件预付金规则2:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为成交/实时名义本金的固定比例,加标的跌幅的市值(跌幅达到一定条件触发)";
|
||
break;
|
||
case MarginRuleTypeEnum.触发条件预付金规则3:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为成交/实时名义本金的固定比例,加上对手方分段式交易浮动亏损(涨跌幅达到一定条件触发)";
|
||
break;
|
||
case MarginRuleTypeEnum.保底预付金规则:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为对手方最大亏损金额。";
|
||
break;
|
||
case MarginRuleTypeEnum.含赔付预付金计算规则:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "预付金占用为对手方最大赔付金额。";
|
||
break;
|
||
case MarginRuleTypeEnum.交易所基本规则:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "交易所基本规则";
|
||
break;
|
||
case MarginRuleTypeEnum.标准SPAN:
|
||
this.marginTemplate.Comments = "计算标的价格和波动率上涨下跌4个场景下的对手方最大亏损";
|
||
break;
|
||
case MarginRuleTypeEnum.买入自动赎回规则1:
|
||
this.marginTemplate.UnderlyingSeperateType = UnderlyingSeperateTypeEnum.None;
|
||
this.marginTemplate.Comments = "Min(x*首次票息金额+y*Max(0,Pv),合约期间全部票息金额);\n若勾选了“取与保底金额孰小”,则还要与取较小的一个;\n保底金额 =ABS(执行价格 - 保底价格)* ABS(交易数量)。";
|
||
break;
|
||
case MarginRuleTypeEnum.卖出自动赎回规则1:
|
||
this.marginTemplate.Comments = "名义本金*Max(x,y-0.5*虚值比例)+ Flag*Max(0,PV);\n其中虚值比例 = max(0, P - 执行价)/期初价格,当计算日为成交日时,Flag = 0,P = 期初价格,当计算日不为成交日时,Flag = 1,P = 标的现价;\n若勾选了“取与保底金额孰小”,则取较小的一个;\n保底金额 =ABS(执行价格 - 保底价格)* ABS(交易数量)。";
|
||
break;
|
||
case MarginRuleTypeEnum.区间追保结构:
|
||
this.marginTemplate.Comments = "预付金占用为名义本金的固定比例。按利率债期限(<5y/5y-10y/10y-30y/>30y)分别设置初始预付金率x、维持预付金率y,支持再按标的资产类型(利率债/信用债/其它债券/股票/股指等全部资产类型)分组;以期初净价为基准,按(x-y)逐档推算预警线/平仓线,标的价格触及档位线时触发追保或平仓。";
|
||
break;
|
||
case MarginRuleTypeEnum.默认预付金规则:
|
||
this.marginTemplate.Comments = "考虑了14种场景下的Span算法与Delta算法比较的通用预付金规则,该规则可以调整Span涨跌幅度";
|
||
break;
|
||
default:
|
||
this.marginTemplate.Comments = "";
|
||
break;
|
||
}
|
||
this.changeUnderlyingSeperateType(isInitial);
|
||
},
|
||
changeUnderlyingSeperateType(isInitial) {
|
||
if (isInitial && this.marginTemplate.Details.length >= 1) {
|
||
return;
|
||
}
|
||
|
||
if (this.marginTemplate.UnderlyingSeperateType == UnderlyingSeperateTypeEnum.None) {
|
||
this.marginTemplate.UnderlyingSeperateComments = "无论挂钩标的代码为何,都采用同一套参数";
|
||
} else if (this.marginTemplate.UnderlyingSeperateType == UnderlyingSeperateTypeEnum.CustomInstrumentType) {
|
||
this.marginTemplate.UnderlyingSeperateComments = "按标的的资产类型分类:在每组参数中选择适用的资产类型(利率债/信用债/其它债券/股票/股指/商品期货等全部资产类型),按标的资产类型匹配对应参数组的初始预付金率x、维持预付金率y。";
|
||
} else {
|
||
this.marginTemplate.UnderlyingSeperateComments = "把所有标的根据代码所属区间段自动分为4类:\n【1-指数】沪深指数;\n【2-个股/ETF-核准制发行】主板股票、非科创版ETF;\n【3-个股/ETF-非核准制发行】科创版股票、科创版ETF、创业板股票;\n【4-其他】所有不满足以上分类的。";
|
||
}
|
||
|
||
let that = this
|
||
new Promise((reslove) => {
|
||
that.marginTemplate.Details = [];
|
||
reslove();
|
||
}).then(() => {
|
||
var needDetailRules = [];
|
||
needDetailRules.push(MarginRuleTypeEnum.按固定利率);
|
||
needDetailRules.push(MarginRuleTypeEnum.按浮动盈亏);
|
||
needDetailRules.push(MarginRuleTypeEnum.类香草预付金规则);
|
||
needDetailRules.push(MarginRuleTypeEnum.触发条件预付金规则1);
|
||
needDetailRules.push(MarginRuleTypeEnum.触发条件预付金规则2);
|
||
needDetailRules.push(MarginRuleTypeEnum.触发条件预付金规则3);
|
||
needDetailRules.push(MarginRuleTypeEnum.标准SPAN);
|
||
needDetailRules.push(MarginRuleTypeEnum.买入自动赎回规则1);
|
||
needDetailRules.push(MarginRuleTypeEnum.卖出自动赎回规则1);
|
||
needDetailRules.push(MarginRuleTypeEnum.区间追保结构);
|
||
needDetailRules.push(MarginRuleTypeEnum.默认预付金规则);
|
||
if (needDetailRules.indexOf(that.marginTemplate.RuleType.toString()) >= 0) {
|
||
new Promise((reslove) => {
|
||
that.marginTemplate.Details.push(_.cloneDeep(page.detail));
|
||
reslove();
|
||
}).then(() => {
|
||
SetAceDropDown();
|
||
})
|
||
}
|
||
})
|
||
},
|
||
saveMarginTemplateV2(isForClient) {
|
||
if (!this.marginTemplate.Name) {
|
||
main.message("模板名称不能为空");
|
||
return;
|
||
}
|
||
this.marginTemplate.TradeTypes = $("#tradeTypes").val().join(",");
|
||
this.marginTemplate.IsDefault = true;
|
||
this.marginTemplate.IsForClient = isForClient;
|
||
this.marginTemplate.BuySellType = this.sum($("#BuySellType").val());
|
||
this.marginTemplate.MarginScenarios = this.sum($("#MarginScenarios").val());
|
||
var that = this;
|
||
this.marginTemplate.Details.forEach((detail, index) => {
|
||
if (that.marginTemplate.UnderlyingSeperateType == 0) {
|
||
detail.UnderlyingType = 15;
|
||
}
|
||
else {
|
||
detail.UnderlyingType = that.sum($("#UnderlyingType" + index).val());
|
||
}
|
||
detail.SpanConfigJson = JSON.stringify(detail.SpanConfig);
|
||
});
|
||
main.post("/margin_template_v2/saveMarginTemplateV2", { marginTemplate: this.marginTemplate }).done(function (resp) {
|
||
try {
|
||
window.parent.reloadmargin_template();
|
||
(parent || window).layer.closeAll();
|
||
} catch (e) { }
|
||
});
|
||
},
|
||
setTemplateDetail(detail) {
|
||
vueDetail.backupDetail = _.cloneDeep(detail);
|
||
detail.ValueDate = new moment(detail.ValueDate).format("YYYY-MM-DD");
|
||
detail.UsePositionStockEqvNotional = false;
|
||
vueDetail.detail = detail;
|
||
vueDetail.isAdd = false;
|
||
vueDetail.ruleType = vue.marginTemplate.RuleType;
|
||
$("#myModal").modal("show");
|
||
},
|
||
addDetail() {
|
||
let that = this
|
||
new Promise((reslove) => {
|
||
that.marginTemplate.Details.push(_.cloneDeep(page.detail));
|
||
reslove();
|
||
}).then(() => {
|
||
SetAceDropDown();
|
||
})
|
||
},
|
||
deleteDetail(index) {
|
||
this.marginTemplate.Details.splice(index, 1);
|
||
},
|
||
sum(items) {
|
||
var total = 0;
|
||
if (items) {
|
||
for (var index = 0; index < items.length; index++) {
|
||
total = total + parseFloat(items[index]);
|
||
}
|
||
}
|
||
return total;
|
||
}
|
||
|
||
},
|
||
mounted: function () {
|
||
/*console.log(this.marginTemplate.Details);*/
|
||
|
||
},
|
||
components: {
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput()
|
||
}
|
||
});
|
||
|
||
$(function () {
|
||
$(".datepicker").change(function () {
|
||
var dateVal = $(this).val();
|
||
if (!dateVal) return;
|
||
dateVal = dateVal.replace(/\D/g, '').padStart(4, '0');
|
||
switch (dateVal.length) {
|
||
case 4:
|
||
dateVal = new Date().getFullYear() + dateVal; break;
|
||
case 6:
|
||
dateVal = '20' + dateVal; break;
|
||
case 8: break;
|
||
default:
|
||
dateVal = dateVal.length > 8 ? dateVal.substring(0, 8) : ''; break;
|
||
}
|
||
|
||
if (dateVal) {
|
||
dateVal = moment(dateVal).format('YYYY-MM-DD');
|
||
!/^\d+/.test(dateVal) && (dateVal = '');
|
||
}
|
||
|
||
$(this).datepicker("setDate", dateVal);
|
||
});
|
||
|
||
SetAceDropDown();
|
||
});
|
||
|
||
var vueDetail = new Vue({
|
||
el: "#myModal",
|
||
data: {
|
||
detail: {},
|
||
backupDetail: {},
|
||
isAdd: true,
|
||
ruleType: 0,
|
||
},
|
||
created: function () {
|
||
},
|
||
methods: {
|
||
closeModal: function () {
|
||
if (!this.isAdd) {
|
||
Vue.set(vue.marginTemplate.Details, vue.marginTemplate.Details.indexOf(this.detail), this.backupDetail);
|
||
}
|
||
$('#myModal').modal('hide');
|
||
},
|
||
saveModal: function () {
|
||
if (this.isAdd) {
|
||
if (vue.latestValueDate && vue.latestValueDate >= this.detail.ValueDate) {
|
||
main.message("生效日期需要大于已设置生效日");
|
||
return;
|
||
}
|
||
|
||
vue.marginTemplate.Details.push(this.detail);
|
||
vue.latestValueDate = this.detail.ValueDate;
|
||
}
|
||
Vue.set(vue.marginTemplate.Details, vue.marginTemplate.Details.indexOf(this.detail), this.detail);
|
||
$('#myModal').modal('hide');
|
||
}
|
||
},
|
||
components: {
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput()
|
||
}
|
||
}); |