- 现象(客户反馈):输入关键词接口返回20条但下拉只显示2条,继续输入又正常
- 根因:FastVue.autocomplete 对函数型 lookup 只同步取返回值渲染,服务端响应
回来后仅写缓存、未触发重渲染,下拉永远显示"上一次请求结果+当前词再过滤",
慢一拍且被前端二次过滤(品种/IsCombined/contains)进一步砍少
- 修复:响应到达且输入未变、下拉可见时重触发插件 onValueChange 重渲染;
_fresh 命中当前关键词直接展示服务端结果(不再前端二次过滤,跨品种结果不误滤),
_seq 单调递增丢弃乱序响应,_inflight 防同关键词重复请求
- 移除 mounted 中无效的 autocomplete('search') 调用(插件无此方法,一直为空操作)
- 同步修改东莞定制版 structure_dz.js
- 已用 Playwright 对照验证:旧代码复现"输入20只显2项/接口返回20条",修复后
两文件 20 项断言全过(显示数=服务端返回、无请求风暴、乱序不污染、可选中)
3108 lines
126 KiB
JavaScript
3108 lines
126 KiB
JavaScript
|
||
//客户选择组件
|
||
const vueClient = function () {
|
||
return {
|
||
props: ['value'],
|
||
data() {
|
||
return { current: { id: 0, Name: '' } };
|
||
},
|
||
mounted() {
|
||
var self = this;
|
||
var id = parseInt(this.value);
|
||
if (id) {
|
||
this.current = _.clone(ylotc.clients.find(x => x.id === id));
|
||
}
|
||
var width = 152;
|
||
for (var i = 0; i < ylotc.clients.length; i++) {
|
||
let ele = document.createElement('span')
|
||
ele.innerText = ylotc.clients[i].Name;
|
||
ele.style.fontSize = '14px';
|
||
document.documentElement.append(ele);
|
||
var charLength = ele.offsetWidth + 28;//滚动条
|
||
document.documentElement.removeChild(ele);
|
||
if (charLength > width) {
|
||
width = charLength
|
||
}
|
||
}
|
||
FastVue.autocomplete(this.$el, {
|
||
valueField: 'Name', searchField: ['Name', 'PinYin'], lookup: ylotc.clients, width: width,
|
||
onSelect(data) {
|
||
self.current = _.clone(data);
|
||
if (self.value !== data.id) {
|
||
self.value = data.id;
|
||
self.$emit('input', self.value);
|
||
}
|
||
$(self.$el).blur();
|
||
}
|
||
});
|
||
},
|
||
watch: {
|
||
value(val, old) {
|
||
if (val !== old) {
|
||
var id = parseInt(val);
|
||
if (id !== this.current.id) {
|
||
this.current = _.clone(ylotc.clients.find(x => x.id === id) || { id: 0, Name: '' });
|
||
}
|
||
$(this.$el).data('select', '').attr("placeholder", '');
|
||
}
|
||
}
|
||
},
|
||
destroyed() {
|
||
FastVue.autocomplete.dispose(this.$el);
|
||
},
|
||
template: '<input id="txtCurrentClient" type="text" v-model="current.Name" :title="current.Name" :data-IsCentralClearing="current.IsCentralClearing" :data-CentralClearingPaltform="current.CentralClearingPaltform" :data-TradingPaltform="current.TradingPaltform"/>'
|
||
};
|
||
};
|
||
|
||
//品种选择组件
|
||
const vueVariety = function () {
|
||
return {
|
||
props: ['variety'],
|
||
mounted() {
|
||
var self = this;
|
||
FastVue.autocomplete(this.$el, {
|
||
valueField: 'Name', searchField: ['Name', 'Code', 'PinYin'],
|
||
lookup: ylotc.varieties,
|
||
onSelect(data) {
|
||
if (self.variety !== data) {
|
||
self.$emit('change-variety', data);
|
||
}
|
||
}
|
||
});
|
||
},
|
||
destroyed() {
|
||
FastVue.autocomplete.dispose(this.$el);
|
||
},
|
||
template: '<input type="text" v-model="variety.Name" />'
|
||
};
|
||
};
|
||
|
||
//期权类型选择组件
|
||
const vueTradeType = function () {
|
||
return {
|
||
props: ['value'],
|
||
mounted() {
|
||
var self = this;
|
||
FastVue.autocomplete(this.$el, {
|
||
valueField: 'value', searchField: ['value', 'pinyin'],
|
||
lookup: tradeHelper.OptionTradeTypes,
|
||
onSelect(data) {
|
||
if (self.value !== data.value) {
|
||
self.value = data.value;
|
||
self.$emit('input', self.value);
|
||
}
|
||
}
|
||
});
|
||
this.$el.value = this.value || '';
|
||
},
|
||
watch: {
|
||
value(val, old) {
|
||
if (val !== old) {
|
||
$(this.$el).val(this.value).data('select', '').attr("placeholder", '');
|
||
}
|
||
}
|
||
},
|
||
destroyed() {
|
||
FastVue.autocomplete.dispose(this.$el);
|
||
},
|
||
template: '<input type="text" maxlength="20" />'
|
||
};
|
||
};
|
||
|
||
//标的选择组件(EQD-7049:改为服务端搜索,不再依赖全量 ylotc.underlyings,避免十几万标的整段下载卡死)
|
||
const vueUnderlying = function () {
|
||
const _suggestionTpl = _.template($('#underlyingSuggestionTpl').html());
|
||
// 标的缓存(同品种各实例共享):_cache 为最近一次服务端结果,_fresh 记录其对应的 品种|关键词,
|
||
// _seq 单调递增丢弃乱序/过期响应,_inflight 防同关键词重复请求(helper 收在函数内,避免全局绑定冲突)
|
||
const _cache = {};
|
||
const _fresh = {};
|
||
const _seq = {};
|
||
const _inflight = {};
|
||
function _fetch(varietyId, query, cb) {
|
||
var vid = varietyId || 0;
|
||
var q = query || '';
|
||
var key = vid + '|' + q;
|
||
if (_inflight[key]) return;
|
||
var seq = (_seq[vid] = (_seq[vid] || 0) + 1);
|
||
_inflight[key] = true;
|
||
var postData = {
|
||
FilterCode: q.toUpperCase(),
|
||
VarietyId: vid,
|
||
MaxShowLength: 20,
|
||
BlackLimit: 1,
|
||
UseForTrading: true,
|
||
IncludeMatured: true,
|
||
CheckLaunch: true
|
||
};
|
||
main.post('/frontdata/AjaxGetUnderlyingSelect', postData).done(function (res) {
|
||
delete _inflight[key];
|
||
if (_seq[vid] !== seq) return; // 已有更新的关键词发起请求,丢弃本响应
|
||
var arr = (res && (res.obj || res.data)) || [];
|
||
var norm = arr.map(function (x) {
|
||
return {
|
||
Code: x.Code,
|
||
Name: x.Name,
|
||
InstrumentType: x.InstrumentType,
|
||
VarietyId: x.VarietyId,
|
||
Disallow: !!x.Disallow,
|
||
IsCombined: !!x.IsSynthetic || !!x.IsBasket,
|
||
BlackWhiteState: x.BlackWhiteState || 0,
|
||
PinYin: x.PinYin || ''
|
||
};
|
||
});
|
||
_cache[vid] = norm;
|
||
_fresh[vid] = key;
|
||
cb && cb(norm, q);
|
||
}).fail(function () {
|
||
delete _inflight[key];
|
||
});
|
||
}
|
||
function _filter(list, query, varietyId) {
|
||
if (!query) return (list || []).slice(0, 20);
|
||
query = query.toUpperCase();
|
||
return (list || []).filter(function (x) {
|
||
if (varietyId && x.VarietyId !== varietyId) return false;
|
||
if (x.IsCombined) return false; // 与原逻辑一致:搜索时排除组合标的
|
||
return (x.Code && x.Code.toUpperCase().indexOf(query) !== -1)
|
||
|| (x.PinYin && x.PinYin.toUpperCase().indexOf(query) !== -1);
|
||
}).slice(0, 20);
|
||
}
|
||
return {
|
||
props: ['underlying'],
|
||
data() {
|
||
return { jqInput: null, autoctrl: null };
|
||
},
|
||
mounted() {
|
||
var self = this;
|
||
this.jqInput = $(this.$el).children(0);
|
||
// EQD-7049:预拉默认20条(当前品种),获得焦点时由插件自身的 onValueChange 呈现
|
||
_fetch(self.underlying.VarietyId, '');
|
||
this.autoctrl = FastVue.autocomplete(this.jqInput, {
|
||
valueField: 'Code',
|
||
lookup(query) {
|
||
var varietyId = self.underlying.VarietyId;
|
||
var vid = varietyId || 0;
|
||
var key = vid + '|' + (query || '');
|
||
if (_fresh[vid] === key) {
|
||
// 命中当前关键词的服务端结果:直接展示(服务端已按 StartsWith+品种/黑名单过滤,不再前端二次过滤)
|
||
return (_cache[vid] || []).slice(0, 20);
|
||
}
|
||
// 异步搜索。FastVue 包装的 lookup 只同步取返回值渲染,服务端结果到达后必须重新触发
|
||
// onValueChange 才会显示;重走 lookup 时命中上面的 _fresh 分支直接返回,不会循环请求
|
||
_fetch(varietyId, query, function (list, q) {
|
||
var inst = self.jqInput.autocomplete();
|
||
if (!inst || !inst.visible) return; // 下拉已关闭:留待下次获得焦点时呈现
|
||
if ((self.jqInput.val() || '').toLowerCase() !== q.toLowerCase()) return; // 输入已变化:等新关键词的响应
|
||
inst.onValueChange();
|
||
});
|
||
// 过渡兜底:服务端响应到达前用旧缓存按关键词过滤,避免搜索期间下拉空白
|
||
return _filter(_cache[vid] || [], query, varietyId);
|
||
},
|
||
onSelect(data) {
|
||
if (self.underlying !== data) {
|
||
self.$emit('change-underlying', data);
|
||
}
|
||
self.jqInput.blur();
|
||
},
|
||
formatResult(suggestion, currentValue) {
|
||
return _suggestionTpl(suggestion.data);
|
||
}
|
||
});
|
||
this.jqInput.val(this.underlying.Code);
|
||
},
|
||
methods: {
|
||
showInput() {
|
||
this.jqInput.show().focus().next().hide();
|
||
},
|
||
hideInput() {
|
||
this.jqInput.hide().next().show();
|
||
}
|
||
},
|
||
computed: {
|
||
showName() {
|
||
return (this.underlying.InstrumentType === 'Stock' || this.underlying.InstrumentType === 'StockIndex') ? this.underlying.Name : ' ';
|
||
}
|
||
},
|
||
destroyed() {
|
||
FastVue.autocomplete.dispose(this.jqInput);
|
||
},
|
||
template: '<div v-on:click="showInput"><input v-on:blur="hideInput" type="text" style="display:none" />' +
|
||
'<span>{{underlying.Code}}</span><span style="font-size:80%">{{showName}}</span></div>'
|
||
};
|
||
};
|
||
|
||
//预付金模板
|
||
const vueMarginTemplateName = function () {
|
||
return {
|
||
props: ['value'],
|
||
data() {
|
||
return { autoCtrl: null };
|
||
},
|
||
mounted() {
|
||
var self = this;
|
||
this.autoctrl = FastVue.autocomplete(this.$el, {
|
||
valueField: 'Value',
|
||
searchField: ['Value'],
|
||
lookup: ylotc.tradeMarginTemplateItems,
|
||
onSelect(data) {
|
||
if (self.value !== data.Value) {
|
||
self.value = data.Value;
|
||
self.$emit('input', self.value);
|
||
}
|
||
}
|
||
});
|
||
value = self.value || "系统默认";
|
||
this.autoctrl.setData({ Text: value, Value: value })
|
||
},
|
||
watch: {
|
||
value(newVal, oldVal) {
|
||
if (newVal !== oldVal) {
|
||
let data = ylotc.tradeMarginTemplateItems.find(x => x.Value === newVal);
|
||
this.autoctrl.setData(data || { Text: "系统默认", Value: "系统默认" })
|
||
}
|
||
}
|
||
},
|
||
destroyed() {
|
||
FastVue.autocomplete.dispose(this.$el);
|
||
},
|
||
template: '<input type="text" />'
|
||
};
|
||
}
|
||
|
||
//计算结果字段
|
||
const consCalcFields = Object.freeze(['TotalMargin', 'Pv', 'Delta', 'Gamma', 'Vega', 'Theta', 'Rho', 'PvContainsKnockOut', 'DeltaContainsKnockOut', 'DeltaInLots', 'GammaInLots', 'DeltaCash', 'GammaCash', 'VegaCash', 'GammaContainsKnockOut', 'Delta_r', 'Delta_r_1bp', 'Dv01', 'Gamma_r', 'Gamma_r_1bp', 'Vega_r', 'Vega_r_1bp', 'Vega_1bp']);
|
||
|
||
var _trades, _tradeVues, _salesCommissionCtrl;
|
||
//交易保存
|
||
const tradeSaver = (function () {
|
||
const needClient = !pageVue.ClientUsedForCalc;
|
||
|
||
function showTradeView(items) {
|
||
let item = items.shift();
|
||
if (!item) return;
|
||
let url = "/trade/tradeview?abstract=1&enid=" + item.EncryptId;
|
||
main.open("查看交易", url, {
|
||
end: function () {
|
||
showTradeView(items);
|
||
}
|
||
});
|
||
}
|
||
|
||
function _saveAccumulator() {
|
||
if (!_trades) return;
|
||
let AssetId = parseInt($('#accumulatorAssetId').data('id'));
|
||
let TraderId = parseInt($('#accumulatorTradeID').data('id'));
|
||
let ClientId = parseInt($('#accumulatorClientId').data('id'));
|
||
if (!AssetId) {
|
||
return main.alert("未设置簿记账户");
|
||
}
|
||
if (!TraderId) {
|
||
return main.alert("未设置交易员");
|
||
}
|
||
if (needClient && !ClientId) {
|
||
return main.alert("未设置客户");
|
||
}
|
||
|
||
let TradeNumber = $('#accumulatorTradeNumber').val();
|
||
let AssetBookName = $('#accumulatorAssetId').val();
|
||
let TraderName = $('#accumulatorTradeID').val();
|
||
let ClientName = $('#accumulatorClientId').val();
|
||
let TradingPlace = $("#accumulatorTradingPlace").val();
|
||
let ClearingAgency = $("#accumulatorClearingAgency").val();
|
||
let MainProtocolCode = $("#accumulatorMainProtocolCode").val();
|
||
let SupProtocolCode = $("#accumulatorSupProtocolCode").val();
|
||
let OpponentRole = $("#accumulatorOpponentRole").val();
|
||
let InitialAdvance = parseFloat($("#accumulatorInitialAdvance").val()) || 0;
|
||
let PeriodAdvance = parseFloat($("#accumulatorPeriodAdvance").val()) || 0;
|
||
let FontEarning = parseFloat($("#accumulatorFontEarning").val()) || 0;
|
||
let ConfirmedLine = parseFloat($("#accumulatorConfirmedLine").val()) || 0;
|
||
let ConfirmedFloor = parseFloat($("#accumulatorConfirmedFloor").val()) || 0;
|
||
let salesCommission = _salesCommissionCtrl.getValue();
|
||
|
||
let IsCentralClearing = $("#accumulatorIsCentralClearing").val();
|
||
let CentralClearingPaltform = $("#accumulatorCentralClearingPaltform").val();
|
||
let TradingPaltform = $("#accumulatorTradingPaltform").val();
|
||
let ExchangeRate = $("#accumulatorExchangeRate").val();
|
||
let QuoteCurrency = $("#accumulatorQuoteCurrency").val();
|
||
|
||
|
||
let SettlementMode = $("#SettlementMode").val();
|
||
let ForwardPriceType = $("#ForwardPriceType").val();
|
||
let ForwardDateType = $("#ForwardDateType").val();
|
||
let SettlementMode1 = $("#SettlementMode1").val();
|
||
let ForwardPriceType1 = $("#ForwardPriceType1").val();
|
||
let ForwardDateType1 = $("#ForwardDateType1").val();
|
||
let SettlementMode2 = $("#SettlementMode2").val();
|
||
let ForwardPriceType2 = $("#ForwardPriceType2").val();
|
||
let ForwardDateType2 = $("#ForwardDateType2").val();
|
||
let SettlementMode3 = $("#SettlementMode3").val();
|
||
let ForwardPriceType3 = $("#ForwardPriceType3").val();
|
||
let ForwardDateType3 = $("#ForwardDateType3").val();
|
||
let AccumuType = $("#AccumuType").val();
|
||
var tags = getSelectTags();
|
||
|
||
if (SettlementMode === '现金期末'&& _trades.some(x => x.EarlyTerminate && (x.AccumulatorStructureType + '') !== '1')) {
|
||
return main.alert("结算方式为'现金结算(期末)'时,需要将'敲出是否终止'设为'否'");
|
||
}
|
||
|
||
_trades.forEach(x => {
|
||
x.AssetId = AssetId;
|
||
x.AssetBookName = AssetBookName;
|
||
x.TraderId = TraderId;
|
||
x.TraderName = TraderName;
|
||
x.TradeNumber = TradeNumber;
|
||
x.SalesCommission = salesCommission;
|
||
if (needClient) {
|
||
x.ClientId = ClientId;
|
||
x.ClientName = ClientName;
|
||
}
|
||
if (x.TradePremium) {
|
||
x.MetaDic["交易溢价"] = x.TradePremium;
|
||
}
|
||
x.MetaDic["交易场所"] = TradingPlace;
|
||
x.MetaDic["清算机构"] = ClearingAgency;
|
||
x.MetaDic["主协议编号"] = MainProtocolCode;
|
||
x.MetaDic["补充协议编号"] = SupProtocolCode;
|
||
|
||
x.MetaDic["中央对手方清算"] = IsCentralClearing;
|
||
x.MetaDic["中央清算平台"] = CentralClearingPaltform;
|
||
x.MetaDic["ExchangeRate"] = ExchangeRate;
|
||
x.MetaDic["交易平台"] = TradingPaltform;
|
||
|
||
if (pageData.showCCR) {
|
||
//if (x.MarginType == 0) {
|
||
x.MetaDic["ccr_k"] = x.ccr_k || "0";
|
||
//}
|
||
x.MetaDic["ignoreRiskExposure"] = x.ignoreRiskExposure || "0";
|
||
}
|
||
x.TradeType === '现金流交易' && tradeUtils.resetCashFlow(x);
|
||
if (x.TradeType == '累计期权') {
|
||
if (x.AccumulatorStructureType.toString() === '1') {
|
||
x.SettlementMode = SettlementMode1;
|
||
x.ForwardPriceType = ForwardPriceType1;
|
||
x.ForwardDateType = ForwardDateType1;
|
||
x.SettlementMode2 = SettlementMode2;
|
||
x.ForwardPriceType2 = ForwardPriceType2;
|
||
x.ForwardDateType2 = ForwardDateType2;
|
||
x.SettlementMode3 = SettlementMode3;
|
||
x.ForwardPriceType3 = ForwardPriceType3;
|
||
x.ForwardDateType3 = ForwardDateType3;
|
||
} else {
|
||
x.AccumuType = AccumuType;
|
||
x.SettlementMode = SettlementMode;
|
||
x.ForwardPriceType = ForwardPriceType;
|
||
x.ForwardDateType = ForwardDateType;
|
||
}
|
||
}
|
||
x.OpponentRole = OpponentRole;
|
||
x.QuoteCurrency = QuoteCurrency;
|
||
x.InitialAdvance = InitialAdvance;
|
||
x.PeriodAdvance = PeriodAdvance;
|
||
x.FontEarning = FontEarning;
|
||
x.ConfirmedLine = ConfirmedLine;
|
||
x.ConfirmedFloor = ConfirmedFloor;
|
||
x.IsUsePremiumRate = (x.IsUsePremiumRate == "" || x.IsUsePremiumRate == null) ? false : x.IsUsePremiumRate;
|
||
x.Tags = tags;
|
||
x.IsUsePremiumRate = false;
|
||
extendVue2.setExtendInfo(x);
|
||
});
|
||
main.post("/pricing/AjaxSaveTrades", { trades: _trades }).done(function (resp) {
|
||
if (pageVue.IsImport) {
|
||
let url = "#/trade/tradeview?abstract=1&enid=" + resp.obj[0].EncryptId;
|
||
layer.closeMe(url);//必须以#开头
|
||
} else {
|
||
floatVue.hide();
|
||
$('#accumulatormodalTradeSave').modal('hide');
|
||
showTradeView(resp.obj);
|
||
_.each(_tradeVues, x => x.remove(true));
|
||
}
|
||
$(".tag-context .tag-item").remove();
|
||
});
|
||
}
|
||
//保存 录入增加字段时 ,累计也需要 增加html、js都要在对应字段保存,因时间仓促目前实现方式不好
|
||
function _save() {
|
||
if (!_trades) return;
|
||
let AssetId = parseInt($('#AssetId').data('id'));
|
||
let TraderId = parseInt($('#TraderId').data('id'));
|
||
let ClientId = parseInt($('#ClientId').data('id'));
|
||
if (!AssetId) {
|
||
return main.alert("未设置簿记账户");
|
||
}
|
||
if (!TraderId) {
|
||
return main.alert("未设置交易员");
|
||
}
|
||
if (needClient && !ClientId) {
|
||
return main.alert("未设置客户");
|
||
}
|
||
let TradeNumber = $('#TradeNumber').val();
|
||
let AssetBookName = $('#AssetId').val();
|
||
let TraderName = $('#TraderId').val();
|
||
let ClientName = $('#ClientId').val();
|
||
let TradingPlace = $("#TradingPlace").val();
|
||
let ClearingAgency = $("#ClearingAgency").val();
|
||
let MainProtocolCode = $("#MainProtocolCode").val();
|
||
let SupProtocolCode = $("#SupProtocolCode").val();
|
||
let OpponentRole = $("#OpponentRole").val();
|
||
let InitialAdvance = parseFloat($("#InitialAdvance").val()) || 0;
|
||
let PeriodAdvance = parseFloat($("#PeriodAdvance").val()) || 0;
|
||
let FontEarning = parseFloat($("#FontEarning").val()) || 0;
|
||
let ConfirmedLine = parseFloat($("#ConfirmedLine").val()) || 0;
|
||
let ConfirmedFloor = parseFloat($("#ConfirmedFloor").val()) || 0;
|
||
let salesCommission = _salesCommissionCtrl.getValue();
|
||
|
||
let IsCentralClearing = $("#IsCentralClearing").val();
|
||
let CentralClearingPaltform = $("#CentralClearingPaltform").val();
|
||
let TradingPaltform = $("#TradingPaltform").val();
|
||
let ExchangeRate = $("#ExchangeRate").val();
|
||
let QuoteCurrency = $("#QuoteCurrency").val();
|
||
var tags = getSelectTags();
|
||
|
||
|
||
_trades.forEach(x => {
|
||
x.AssetId = AssetId;
|
||
x.AssetBookName = AssetBookName;
|
||
x.TraderId = TraderId;
|
||
x.TraderName = TraderName;
|
||
x.TradeNumber = TradeNumber;
|
||
x.SalesCommission = salesCommission;
|
||
if (needClient) {
|
||
x.ClientId = ClientId;
|
||
x.ClientName = ClientName;
|
||
}
|
||
if (x.TradePremium) {
|
||
x.MetaDic["交易溢价"] = x.TradePremium;
|
||
}
|
||
x.MetaDic["交易场所"] = TradingPlace;
|
||
x.MetaDic["清算机构"] = ClearingAgency;
|
||
x.MetaDic["主协议编号"] = MainProtocolCode;
|
||
x.MetaDic["补充协议编号"] = SupProtocolCode;
|
||
|
||
x.MetaDic["中央对手方清算"] = IsCentralClearing;
|
||
x.MetaDic["中央清算平台"] = CentralClearingPaltform;
|
||
x.MetaDic["ExchangeRate"] = ExchangeRate;
|
||
x.MetaDic["交易平台"] = TradingPaltform;
|
||
|
||
if (pageData.showCCR) {
|
||
//if (x.MarginType == 0) {
|
||
x.MetaDic["ccr_k"] = x.ccr_k || "0";
|
||
//}
|
||
x.MetaDic["ignoreRiskExposure"] = x.ignoreRiskExposure || "0";
|
||
}
|
||
x.TradeType === '现金流交易' && tradeUtils.resetCashFlow(x);
|
||
x.OpponentRole = OpponentRole;
|
||
x.QuoteCurrency = QuoteCurrency;
|
||
x.InitialAdvance = InitialAdvance;
|
||
x.PeriodAdvance = PeriodAdvance;
|
||
x.FontEarning = FontEarning;
|
||
x.ConfirmedLine = ConfirmedLine;
|
||
x.ConfirmedFloor = ConfirmedFloor;
|
||
x.IsUsePremiumRate = (x.IsUsePremiumRate == "" || x.IsUsePremiumRate == null) ? false : x.IsUsePremiumRate;
|
||
x.Tags = tags;
|
||
extendVue.setExtendInfo(x);
|
||
});
|
||
main.post("/pricing/AjaxSaveTrades", { trades: _trades }).done(function (resp) {
|
||
if (pageVue.IsImport) {
|
||
let url = "#/trade/tradeview?abstract=1&enid=" + resp.obj[0].EncryptId;
|
||
layer.closeMe(url);//必须以#开头
|
||
} else {
|
||
floatVue.hide();
|
||
$('#modalTradeSave').modal('hide');
|
||
showTradeView(resp.obj);
|
||
_.each(_tradeVues, x => x.remove(true));
|
||
}
|
||
$(".tag-context .tag-item").remove();
|
||
});
|
||
}
|
||
//保存
|
||
function _saveTrades(tradeVues) {
|
||
|
||
_tradeVues = tradeVues;
|
||
if (!Array.isArray(_tradeVues)) {
|
||
throw "参数错误:tradeVues";
|
||
}
|
||
if (!_tradeVues.length) {
|
||
return main.alert("请至少勾选一条交易");
|
||
}
|
||
|
||
_trades = _.flatMap(_tradeVues, x => x.datas).map(x => {
|
||
x.viewState.synthetic && (x.trade.MetaDic["组合标的"] = JSON.stringify(x.viewState.synthetic));
|
||
return x.trade;
|
||
});
|
||
|
||
var viewStates = _.flatMap(_tradeVues, x => x.datas).map(x => x.viewState).filter(x => x.variety && x.variety.Code);
|
||
$("#QuoteCurrency").val(viewStates[0]?.variety.QuoteCurrency);
|
||
if ($("#QuoteCurrency").val() && $("#QuoteCurrency").val() != "CNY") {
|
||
$("#ExchangeRateDiv").show();
|
||
} else {
|
||
$("#ExchangeRateDiv").hide();
|
||
}
|
||
_trades = tradeUtils.prepareTrades(_trades, pageVue.getVolType(), true);
|
||
if (_trades) {
|
||
$('#TradeNumber').val('').parent().toggle(_tradeVues.length === 1);
|
||
var accumulatorStandard = _trades.filter(x => x.TradeType == "累计期权" && x.AccumulatorStructureType == "0");
|
||
var accumulatorSegmented = _trades.filter(x => x.TradeType == "累计期权" && x.AccumulatorStructureType == "1");
|
||
if (accumulatorSegmented.length > 0 && accumulatorStandard.length > 0) {
|
||
return main.alert("因累计结构类型不一致,不支持快速录入");
|
||
}
|
||
else if (accumulatorStandard.length > 0) {
|
||
var accumulatorPayoffType = accumulatorStandard.filter(x => x.PayoffType == "浮动");
|
||
if (accumulatorPayoffType.length != 0 && accumulatorPayoffType.length != accumulatorStandard.length) {
|
||
return main.alert("因上端收益类型不一致,不支持快速录入");
|
||
}
|
||
}
|
||
if (accumulatorSegmented.length > 0 || accumulatorStandard.length > 0) {
|
||
$('#accumulatormodalTradeSave').modal('show');
|
||
if (accumulatorSegmented.length > 0) {
|
||
$("#leiji").hide();
|
||
$("#leijisanduanshi").show();
|
||
} else {
|
||
$("#leijisanduanshi").hide();
|
||
$("#leiji").show();
|
||
var accumulatorPayoffTypeF = accumulatorStandard.filter(x => x.PayoffType == "固定");
|
||
$("#SettlementMode option").each(function (i, el) {
|
||
if ($(el).text() == "现金结算(期末)" && accumulatorPayoffTypeF.length > 0) {
|
||
$(this).attr("disabled", true);
|
||
} else {
|
||
$(this).attr("disabled", false);
|
||
|
||
}
|
||
})
|
||
}
|
||
} else {
|
||
$('#modalTradeSave').modal('show');
|
||
}
|
||
|
||
_setSalesman();
|
||
if (pageVue.SecuritiesEnvironment && !pageVue.ClientUsedForCalc) {
|
||
var clientId = parseInt($('#ClientId').data('id')) || _trades[0].ClientId;
|
||
_getMainProtocolCode(clientId);
|
||
}
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
function _setAutocomplete(elId, datas, initData, onSelectFn, width) {
|
||
initData = initData || datas[0] || {};
|
||
FastVue.autocomplete(document.getElementById(elId), {
|
||
valueField: 'Name', searchField: ['Name', 'PinYin'], lookup: datas, width: width,
|
||
onSelect(data) {
|
||
$('#' + elId).data('id', data.id);
|
||
if (elId === "ClientId") {
|
||
if (!pageVue.ClientUsedForCalc) {
|
||
$("#IsCentralClearing").val(data.IsCentralClearing);
|
||
$("#CentralClearingPaltform").val(data.CentralClearingPaltform);
|
||
$("#TradingPaltform").val(data.TradingPaltform);
|
||
}
|
||
_setSalesman();
|
||
}
|
||
onSelectFn && onSelectFn(data);
|
||
},
|
||
zIndex: 300000
|
||
}).setData(initData);
|
||
$('#' + elId).data('id', initData.id);
|
||
}
|
||
//保存组合交易
|
||
function _saveGroupTrades(tradeVues) {
|
||
_tradeVues = tradeVues;
|
||
if (!Array.isArray(_tradeVues)) {
|
||
throw "参数错误:tradeVues";
|
||
}
|
||
if (!_tradeVues.length) {
|
||
return main.alert("请至少勾选一条交易");
|
||
}
|
||
|
||
_trades = _.flatMap(_tradeVues, x => x.datas).map(x => {
|
||
x.viewState.synthetic && (x.trade.MetaDic["组合标的"] = JSON.stringify(x.viewState.synthetic));
|
||
return x.trade;
|
||
});
|
||
|
||
var viewStates = _.flatMap(_tradeVues, x => x.datas).map(x => x.viewState).filter(x => x.variety && x.variety.Code);
|
||
|
||
//验证分组交易是否是同标的同期初价格
|
||
$("#selQuoteCurrency").val(viewStates[0].variety.QuoteCurrency);
|
||
if ($("#selQuoteCurrency").val() && $("#selQuoteCurrency").val() != "CNY") {
|
||
$("#selExchangeRateDiv").show();
|
||
} else {
|
||
$("#selExchangeRateDiv").hide();
|
||
}
|
||
var underlyingId = 0;
|
||
var hasDiffUnderlying = false;
|
||
var spotPrice = 0;
|
||
var hasDiffPrice = false;
|
||
var tradeDate = null;
|
||
var exerciseDate = null;
|
||
var hasDiffTradeDate = false;
|
||
var buySell = groupVue.trade.BuySell;
|
||
var tradePrice = 0;
|
||
var clientIdArr = [];
|
||
_trades.forEach(x => {
|
||
if (x.TradeType != "现金流交易") {
|
||
if (underlyingId && underlyingId != x.UnderlyingId) {
|
||
hasDiffUnderlying = true;
|
||
}
|
||
else {
|
||
underlyingId = x.UnderlyingId;
|
||
}
|
||
|
||
if (spotPrice && parseFloat(spotPrice) != parseFloat(x.SpotPrice)) {
|
||
hasDiffPrice = true;
|
||
}
|
||
else {
|
||
spotPrice = x.SpotPrice;
|
||
}
|
||
|
||
if (!buySell) {
|
||
buySell = x.BuySell;
|
||
}
|
||
}
|
||
|
||
tradePrice += x.TradePrice * (x.BuySell == "卖出" ? 1 : -1);
|
||
|
||
if (tradeDate != null && tradeDate != x.TradeDate) {
|
||
hasDiffTradeDate = true;
|
||
}
|
||
else {
|
||
tradeDate = x.TradeDate;
|
||
}
|
||
|
||
if (exerciseDate == null || exerciseDate < x.ExerciseDate) {
|
||
exerciseDate = x.ExerciseDate;
|
||
}
|
||
|
||
if (clientIdArr.indexOf(x.ClientId) == -1 && x.ClientId > 0) {
|
||
clientIdArr.push(x.ClientId);
|
||
}
|
||
});
|
||
if (hasDiffUnderlying) {
|
||
main.alert("分组交易必须要保持相同的标的");
|
||
return false;
|
||
}
|
||
if (hasDiffPrice) {
|
||
main.alert("分组交易必须要保持相同的期初价格");
|
||
return false;
|
||
}
|
||
if (hasDiffTradeDate) {
|
||
main.alert("分组交易必须要保持相同的交易日期");
|
||
return false;
|
||
}
|
||
if (clientIdArr.length > 1) {
|
||
main.alert("分组交易必须要保持相同的客户");
|
||
return false;
|
||
}
|
||
|
||
_trades = tradeUtils.prepareTrades(_trades, pageVue.getVolType(), true);
|
||
if (_trades) {
|
||
$('#TradeNumber').val('').parent().toggle(_tradeVues.length === 1);
|
||
groupVue.viewState = viewStates[0];
|
||
groupVue.trade.TradeDate = tradeDate;
|
||
groupVue.trade.ExerciseDate = exerciseDate;
|
||
groupVue.trade.BuySell = buySell;
|
||
if (groupVue.trade.IsUsePremiumRate == null) {
|
||
groupVue.trade.IsUsePremiumRate = true
|
||
}
|
||
if (groupVue.trade.IsMoneynessOption == null) {
|
||
groupVue.trade.IsMoneynessOption = "是";
|
||
}
|
||
groupVue.trade.IsTradePricePayType = true;
|
||
groupVue.trade.TradePrice = tradePrice * (buySell == "卖出" ? 1 : -1);
|
||
groupVue.changeIsUsePremiumRate();
|
||
groupVue.trade.SpotPrice = spotPrice;
|
||
if (!groupVue.trade.StructureType) {
|
||
groupVue.trade.StructureType = "气囊结构";
|
||
groupVue.trade.OptionType = "看涨";
|
||
groupVue.trade.trade_airbag.Barrier = 0.8;
|
||
groupVue.trade.Strike = 1;
|
||
groupVue.trade.trade_airbag.NotKIParticipationRate = 1;
|
||
groupVue.trade.trade_airbag.KIParticipationRate = 1;
|
||
}
|
||
|
||
|
||
let stockEqvNotionalArrs = _trades.map((value, index, array) => {
|
||
return value.StockEqvNotional
|
||
});
|
||
groupVue.trade.StockEqvNotional = Math.max(...stockEqvNotionalArrs);
|
||
groupVue.changeStockEqvNotional();
|
||
if (clientIdArr.length > 0) {
|
||
groupVue.trade.ClientId = clientIdArr[0];
|
||
}
|
||
$('#modalGroupTradeSave').modal('show');
|
||
groupVue.init();
|
||
_setSalesman();
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
return {
|
||
saveTrades: _saveTrades,
|
||
saveGroupTrades: _saveGroupTrades,
|
||
init() {
|
||
_setAutocomplete('AssetId', ylotc.assetunits);
|
||
if (pageVue.CanSelectTrader) {
|
||
let trader = pageVue.Trade.TraderId > 0 ? ylotc.traders.find(x => x.id === pageVue.Trade.TraderId) : null;
|
||
if (!trader) {
|
||
trader = { Name: "", id: 0 }
|
||
}
|
||
_setAutocomplete('TraderId', ylotc.traders, { Name: trader.Name });
|
||
}
|
||
if (!pageVue.ClientUsedForCalc) {
|
||
var width = 300;
|
||
for (var i = 0; i < ylotc.clients.length; i++) {
|
||
let ele = document.createElement('span')
|
||
ele.innerText = ylotc.clients[i].Name;
|
||
ele.style.fontSize = '14px';
|
||
document.documentElement.append(ele);
|
||
var charLength = ele.offsetWidth + 28;//滚动条
|
||
document.documentElement.removeChild(ele);
|
||
if (charLength > width) {
|
||
width = charLength
|
||
}
|
||
}
|
||
_setAutocomplete('ClientId', ylotc.clients, null, (pageVue.SecuritiesEnvironment ? _getMainProtocolCode : null), width);
|
||
}
|
||
//组合标的控件
|
||
synthenticPriceCtrl.init({
|
||
getSynthetic(input) {
|
||
return consSyntheticMap[input.dataset.calcid];
|
||
},
|
||
setSynthetic(input, synthetic) {
|
||
var calcid = input.dataset.calcid;
|
||
_.each(pricingVue.getTradeVues(), x => !x.updateSynthetic(calcid, synthetic));
|
||
}
|
||
});
|
||
//销售提成控件
|
||
_salesCommissionCtrl = new SalesCommissionCtrl(document.getElementById('salesCommissionCtrl'), pageVue.SalesCommission);
|
||
//累计
|
||
_setAutocomplete('accumulatorAssetId', ylotc.assetunits);
|
||
if (pageVue.CanSelectTrader) {
|
||
let trader = pageVue.Trade.TraderId > 0 ? ylotc.traders.find(x => x.id === pageVue.Trade.TraderId) : null;
|
||
if (!trader) {
|
||
trader = { Name: "", id: 0 }
|
||
}
|
||
_setAutocomplete('accumulatorTradeID', ylotc.traders, { Name: trader.Name });
|
||
}
|
||
if (!pageVue.ClientUsedForCalc) {
|
||
var width = 300;
|
||
for (var i = 0; i < ylotc.clients.length; i++) {
|
||
let ele = document.createElement('span')
|
||
ele.innerText = ylotc.clients[i].Name;
|
||
ele.style.fontSize = '14px';
|
||
document.documentElement.append(ele);
|
||
var charLength = ele.offsetWidth + 28;//滚动条
|
||
document.documentElement.removeChild(ele);
|
||
if (charLength > width) {
|
||
width = charLength
|
||
}
|
||
}
|
||
_setAutocomplete('accumulatorClientId', ylotc.clients, null, (pageVue.SecuritiesEnvironment ? _getMainProtocolCode : null), width);
|
||
}
|
||
//销售提成控件
|
||
_salesCommissionCtrl = new SalesCommissionCtrl(document.getElementById('salesaccumulatorCommissionCtrl'), pageVue.SalesCommission);
|
||
|
||
_setSalesman();
|
||
|
||
|
||
$('#btnSave').on('click', _save);
|
||
$('#btnAccumulatorSave').on('click', _saveAccumulator);
|
||
if (pageData.is厦门象屿) {
|
||
$("#SettlementMode").val("现金实物合并结算");
|
||
$("#SettlementMode1").val("现金实物合并结算");
|
||
$("#SettlementMode2").val("现金实物合并结算");
|
||
$("#SettlementMode3").val("现金实物合并结算");
|
||
$("#ForwardPriceType").val("远期开仓现价");
|
||
$("#ForwardPriceType1").val("远期开仓现价");
|
||
$("#ForwardPriceType2").val("远期开仓现价");
|
||
$("#ForwardPriceType3").val("远期开仓现价");
|
||
$("#ForwardDateType option").each(function (i, el) {
|
||
if ($(el).text() == "标的交割月前一交易日") {
|
||
$("#ForwardDateType").val("标的交割月前一交易日");
|
||
}
|
||
})
|
||
$("#ForwardDateType1 option").each(function (i, el) {
|
||
if ($(el).text() == "标的交割月前一交易日") {
|
||
$("#ForwardDateType1").val("标的交割月前一交易日");
|
||
}
|
||
})
|
||
$("#ForwardDateType2 option").each(function (i, el) {
|
||
if ($(el).text() == "标的交割月前一交易日") {
|
||
$("#ForwardDateType2").val("标的交割月前一交易日");
|
||
}
|
||
})
|
||
$("#ForwardDateType3 option").each(function (i, el) {
|
||
if ($(el).text() == "标的交割月前一交易日") {
|
||
$("#ForwardDateType3").val("标的交割月前一交易日");
|
||
}
|
||
})
|
||
$("#AccumuType").attr("disabled", false);
|
||
$("#AccumuType option").each(function (i, el) {
|
||
if ($(el).text() == "子弹") {
|
||
$(this).attr("disabled", true);
|
||
} else {
|
||
$(this).attr("disabled", false);
|
||
|
||
}
|
||
})
|
||
}
|
||
else {
|
||
$("#ForwardPriceType").attr("disabled", true);
|
||
$("#ForwardDateType").attr("disabled", true);
|
||
$("#ForwardPriceType1").attr("disabled", true);
|
||
$("#ForwardDateType1").attr("disabled", true);
|
||
$("#ForwardPriceType2").attr("disabled", true);
|
||
$("#ForwardDateType2").attr("disabled", true);
|
||
$("#ForwardPriceType3").attr("disabled", true);
|
||
$("#ForwardDateType3").attr("disabled", true);
|
||
$("#AccumuType").attr("disabled", true);
|
||
}
|
||
|
||
|
||
$("#SettlementMode").change(function () {
|
||
$("#AccumuType").val('');
|
||
$("#AccumuType").attr("selected", true);
|
||
if ($("#SettlementMode").val() == "实物交割" || $("#SettlementMode").val() == "现金实物合并结算") {
|
||
$("#AccumuType").attr("disabled", false);
|
||
$("#ForwardPriceType").attr("disabled", false);
|
||
$("#ForwardDateType").attr("disabled", false);
|
||
$("#AccumuType option").each(function (i, el) {
|
||
if ($(el).text() == "子弹") {
|
||
$(this).attr("disabled", true);
|
||
} else {
|
||
$(this).attr("disabled", false);
|
||
|
||
}
|
||
})
|
||
} else {
|
||
$("#AccumuType").attr("disabled", true);
|
||
$("#ForwardPriceType").attr("disabled", true);
|
||
$("#ForwardDateType").attr("disabled", true);
|
||
}
|
||
if ($("#SettlementMode").val() == "现金期末") {
|
||
$("#AccumuType").attr("disabled", false);
|
||
$("#AccumuType option").each(function (i, el) {
|
||
if ($(el).text() == "区间现金结算") {
|
||
$(this).attr("disabled", true);
|
||
} else {
|
||
$(this).attr("disabled", false);
|
||
}
|
||
})
|
||
}
|
||
|
||
})
|
||
$("#SettlementMode1").change(function () {
|
||
if ($("#SettlementMode1").val() == "实物交割" || $("#SettlementMode1").val() == "现金实物合并结算") {
|
||
$("#ForwardPriceType1").attr("disabled", false);
|
||
$("#ForwardDateType1").attr("disabled", false);
|
||
} else {
|
||
$("#ForwardPriceType1").attr("disabled", true);
|
||
$("#ForwardDateType1").attr("disabled", true);
|
||
}
|
||
})
|
||
$("#SettlementMode2").change(function () {
|
||
if ($("#SettlementMode2").val() == "实物交割" || $("#SettlementMode2").val() == "现金实物合并结算") {
|
||
$("#ForwardPriceType2").attr("disabled", false);
|
||
$("#ForwardDateType2").attr("disabled", false);
|
||
} else {
|
||
$("#ForwardPriceType2").attr("disabled", true);
|
||
$("#ForwardDateType2").attr("disabled", true);
|
||
}
|
||
})
|
||
$("#SettlementMode3").change(function () {
|
||
if ($("#SettlementMode3").val() == "实物交割" || $("#SettlementMode3").val() == "现金实物合并结算") {
|
||
$("#ForwardPriceType3").attr("disabled", false);
|
||
$("#ForwardDateType3").attr("disabled", false);
|
||
} else {
|
||
$("#ForwardPriceType3").attr("disabled", true);
|
||
$("#ForwardDateType3").attr("disabled", true);
|
||
}
|
||
})
|
||
|
||
$("#btnCloseInputTrade").click(function () {
|
||
$('#modalTradeSave').modal('hide');
|
||
$(".tag-context .tag-item").remove();
|
||
});
|
||
$("#btnAccumulatorCloseInputTrade").click(function () {
|
||
$('#accumulatormodalTradeSave').modal('hide');
|
||
$(".tag-context .tag-item").remove();
|
||
})
|
||
$('#MainProtocolCode').on('change', _changeMainProtocolCode);
|
||
|
||
$('#modalTradeSave').on('show.bs.modal', function () {
|
||
$('#TradeNumber').val('');
|
||
_salesCommissionCtrl.reset();
|
||
});
|
||
|
||
$('#accumulatormodalTradeSave').on('show.bs.modal', function () {
|
||
$('#TradeNumber').val('');
|
||
_salesCommissionCtrl.reset();
|
||
});
|
||
}
|
||
};
|
||
}());
|
||
|
||
//截图
|
||
const screenshoter = (function () {
|
||
|
||
var _layerIndex;
|
||
|
||
function execute(tradeVue) {
|
||
if (!tradeVue.floating) {
|
||
floatVue.show(tradeVue, true);
|
||
}
|
||
|
||
pageVue.viewState.SS_SinglePrincipalWrite = tradeVue.datas.reduce((p, x) => p + (parseFloat(x.trade.SinglePrincipalWrite) || 0), 0);
|
||
pageVue.viewState.SS_PrincipalSum = tradeVue.datas.reduce((p, x) => p + (parseFloat(x.trade.OriginalPrincipalSum) || 0), 0);
|
||
|
||
var $fs = $('#for-screenshot');
|
||
$fs.parent().children().addClass('for-screenshot');
|
||
$fs.closest('.modal').css('margin-top', -999999);
|
||
setTimeout(function () {//OTC-8517 在结构跟香草之间来回切换生成截图时,香草的高度会变成结构的高度,页面需要过段时间才会更新
|
||
var opts = { bgcolor: '#fff', width: tradeVue.datas.length * 200 + 140, height: $fs.height() };
|
||
domtoimage.toPng($fs[0], opts).then(function (dataUrl) {
|
||
$('#screenshot-img').attr('src', dataUrl);
|
||
_layerIndex = layer.open({
|
||
type: 1, closeBtn: 0, title: false, scrollbar: false, shadeClose: true,
|
||
area: ['auto', '50%'], content: $('#screenshot'), offset: '100px',
|
||
success: function (layero, index) {
|
||
setTimeout(function () {
|
||
let height = $('#screenshot-img').height();
|
||
height > 100 && layero.children('.layui-layer-content').css('height', height + 100);
|
||
}, 100);
|
||
}
|
||
});
|
||
}).catch(function (error) {
|
||
main.alert('截图发生错误:' + error);
|
||
}).finally(function () {
|
||
$fs.closest('.modal').css('margin-top', 0);
|
||
$fs.parent().children().removeClass('for-screenshot');
|
||
if (!tradeVue.floating) {
|
||
$('#floatModal').modal('hide');
|
||
}
|
||
});
|
||
}, 10)
|
||
|
||
}
|
||
|
||
function closeShow() {
|
||
layer.close(_layerIndex);
|
||
}
|
||
|
||
//保存截图
|
||
function download() {
|
||
domtoimage.toBlob(document.getElementById('screenshot-img'))
|
||
.then(function (blob) {
|
||
moment().format();
|
||
window.saveAs(blob, '报价' + moment().format('YYYYMMDDHHmmss') + '.png');
|
||
});
|
||
}
|
||
|
||
return {
|
||
execute: execute,
|
||
download: download,
|
||
closeShow: closeShow
|
||
};
|
||
}());
|
||
|
||
//#singleprice
|
||
const singlePricer = (function () {
|
||
|
||
const _sumDatas = [];
|
||
|
||
//datas:[{Pv,Notional}]
|
||
function _calcSinglePrice(datas) {
|
||
let tradeSinglePrice = 0;
|
||
var result = _.reduce(datas, (acc, data) => {
|
||
if (Array.isArray(data)) {
|
||
_.each(data, item => {
|
||
acc.totalPv += parseFloat(item.Pv) || 0;
|
||
var notional = parseFloat(item.Notional) || 0;
|
||
tradeSinglePrice += parseFloat(pricingFormat.tradeSinglePrice((parseFloat(item.Pv) || 0) / notional));
|
||
if (acc.minNotional > notional) {
|
||
acc.minNotional = notional;
|
||
}
|
||
});
|
||
} else if (data) {
|
||
acc.totalPv += parseFloat(data.Pv) || 0;
|
||
var notional = parseFloat(data.Notional) || 0;
|
||
tradeSinglePrice += parseFloat(pricingFormat.tradeSinglePrice((parseFloat(data.Pv) || 0) / notional));
|
||
if (acc.minNotional > notional) {
|
||
acc.minNotional = notional;
|
||
}
|
||
}
|
||
return acc;
|
||
}, { totalPv: 0, minNotional: Number.MAX_SAFE_INTEGER });
|
||
var singlePrice = Math.abs(result.minNotional) < 1e-5 ? "0.00"
|
||
: pricingFormat.tradeSinglePrice(Math.abs(result.totalPv) / result.minNotional);
|
||
if (pageObj.IsTradeSinglePriceCalcu) {
|
||
return pageVue.CompanyName + (tradeSinglePrice >= 0 ? "付" : "收") + pricingFormat.tradeSinglePrice(Math.abs(tradeSinglePrice));
|
||
} else {
|
||
return pageVue.CompanyName + (result.totalPv >= 0 ? "付" : "收") + singlePrice;
|
||
}
|
||
}
|
||
|
||
//重设统计单价
|
||
function _reset() {
|
||
var singlePrice = _calcSinglePrice(_sumDatas);
|
||
$('#singleprice').text(singlePrice);
|
||
}
|
||
|
||
const _debounceReset = _.debounce(_reset, 300);
|
||
|
||
return {
|
||
//data:[{Pv,Notional}]
|
||
reset(index, data) {
|
||
_sumDatas[index] = !data || Array.isArray(data) ? data : [data];
|
||
_debounceReset();
|
||
},
|
||
//datas:[{Pv,Notional}]
|
||
calcSinglePrice: _calcSinglePrice
|
||
};
|
||
}());
|
||
|
||
//pageVue状态
|
||
(function () {
|
||
|
||
const viewState = { VolType: '交易', structureType: '', SS_PrincipalSum: 0, SS_SinglePrincipalWrite: 0 };
|
||
|
||
_.extend(pageVue, {
|
||
viewState: viewState,
|
||
getVolType() { return viewState.VolType; },
|
||
setVolType(value) { viewState.VolType = value; },
|
||
getStructureType() { return viewState.structureType; },
|
||
setStructureType(value) { viewState.structureType = value; }
|
||
});
|
||
|
||
//冻结修改
|
||
_.each([pageVue], x => Object.freeze(x));
|
||
}());
|
||
|
||
//一个简单的事件总线
|
||
const EventBus = (new function () {
|
||
|
||
var _bus;
|
||
|
||
function getBus() {
|
||
return _bus || (_bus = document.createElement('div'));
|
||
}
|
||
|
||
//增加事件监听
|
||
this.addEventListener = function (event, callback) {
|
||
getBus().addEventListener(event, callback);
|
||
};
|
||
|
||
//移除事件监听
|
||
this.removeEventListener = function (event, callback) {
|
||
getBus().removeEventListener(event, callback);
|
||
};
|
||
|
||
//激发事件
|
||
this.triggerEvent = function (event, detail = {}) {
|
||
getBus().dispatchEvent(new CustomEvent(event, { detail }));
|
||
};
|
||
|
||
//仅供调试用
|
||
this.getEventListeners = function () {
|
||
return getEventListeners(getBus());
|
||
};
|
||
}())
|
||
|
||
//顶部组件
|
||
const topVue = (function () {
|
||
return new Vue({
|
||
el: '#pricing-top',
|
||
data: {
|
||
viewState: pageVue.viewState,
|
||
simpleMode: pageVue.SimpleMode,
|
||
calcMargin: pageVue.CalcMargin && pageVue.ShowInitialMargin,
|
||
calcAutocallGreeks: pageVue.CalcAutocallGreeks,
|
||
},
|
||
mounted() {
|
||
|
||
},
|
||
methods: {
|
||
changeVolType() {
|
||
pricingVue.changeVolType();
|
||
},
|
||
addStructure(type, typeCn) {
|
||
pageVue.setStructureType(typeCn);
|
||
var url = "/trade/structureoptionV2?name=" + type;
|
||
main.open("添加策略", url, { area: ['500px', '800px'] });
|
||
},
|
||
normOtcTrade(td) {
|
||
if (!pageData.is厦门象屿 && td.TradeType !== "Risky期权") {
|
||
td.PremiumPayDate = '';
|
||
}
|
||
td.Notional = pricingFormat.notional(td.Notional);
|
||
td.TradeAmount = pricingFormat.notional(td.TradeAmount);
|
||
td.TradePrice = pricingFormat.tradePrice(td.TradePrice);
|
||
td.StockEqvNotional = pricingFormat.StockEqvNotional(td.StockEqvNotional);
|
||
td.StockEqvNotionalReal = pricingFormat.StockEqvNotional(td.StockEqvNotionalReal);
|
||
tradeUtils.normalizeTrade(td);
|
||
return td;
|
||
},
|
||
importTrade() {
|
||
let tradeNumber = $('#importTradeNumber').val().trim();
|
||
if (!tradeNumber) return;
|
||
var self = this;
|
||
main.post('/pricing/AjaxGetOtcTradeFull?tradeNumber=' + encodeURIComponent(tradeNumber)).done(function (resp) {
|
||
if (resp.obj) {
|
||
pricingVue.addTrade(self.normOtcTrade(resp.obj));
|
||
} else {
|
||
main.alert('没有找到交易数据');
|
||
}
|
||
}).always(function () {
|
||
|
||
});
|
||
},
|
||
toggleSimpleMode() {
|
||
this.simpleMode = !this.simpleMode;
|
||
EventBus.triggerEvent('simpleMode.changed');
|
||
main.post("/sysuserConfig/AjaxSaveOtcWebConfig", { name: 'Pricing_SimpleMode', value: this.simpleMode }, false);
|
||
},
|
||
toggleCalcMargin() {
|
||
this.calcMargin = !this.calcMargin;
|
||
main.post("/sysuserConfig/AjaxSaveOtcWebConfig", { name: 'Pricing_CalcMargin', value: this.calcMargin }, false);
|
||
},
|
||
toggleCalcAutocallGreeks() {
|
||
this.calcAutocallGreeks = !this.calcAutocallGreeks;
|
||
main.post("/sysuserConfig/AjaxSaveOtcWebConfig", { name: 'Pricing_CalcAutocallGreeks', value: this.calcAutocallGreeks }, false);
|
||
}
|
||
}
|
||
})
|
||
}());
|
||
|
||
//统计组件
|
||
const summaryVue = (function () {
|
||
|
||
const _summaryDatas = [];
|
||
|
||
const summary = _.reduce(consCalcFields, (acc, cur) => {
|
||
acc[cur] = 0;
|
||
return acc;
|
||
}, {});
|
||
|
||
//重设统计合计
|
||
function _resetSummary() {
|
||
var datas = _.flatMap(_summaryDatas, x => x && x.length > 0 ? x : []);
|
||
var UnderlyingCode = '';
|
||
var isSameCode = _.every(datas, x => {
|
||
return !x.UnderlyingCode ? true : (UnderlyingCode ? x.UnderlyingCode === UnderlyingCode : UnderlyingCode = x.UnderlyingCode);
|
||
});
|
||
if (isSameCode) {
|
||
_.each(summary, (val, key) => {
|
||
summary[key] = 0;
|
||
});
|
||
_.each(datas, data =>
|
||
_.each(consCalcFields, field => summary[field] += parseFloat(data[field]) || 0)
|
||
);
|
||
} else {
|
||
_.each(summary, (val, key) => {
|
||
summary[key] = 'NaN';
|
||
});
|
||
summary.Pv = summary.TotalMargin = summary.Rho = 0;
|
||
_.each(datas, data => {
|
||
summary.Pv += parseFloat(data.Pv) || 0;
|
||
summary.TotalTradePrice += parseFloat(data.TradePrice) || 0;
|
||
summary.Rho += parseFloat(data.Rho) || 0;
|
||
summary.TotalMargin += parseFloat(data.TotalMargin) || 0;
|
||
});
|
||
}
|
||
if (!pageVue.TwoSideMargin) {
|
||
//如果为负数,则显示0
|
||
summary.TotalMargin < 0 && (summary.TotalMargin = 0);
|
||
}
|
||
}
|
||
|
||
const _debounceReset = _.debounce(_resetSummary, 300);
|
||
|
||
const _vue = new Vue({
|
||
el: '#pricing-summary',
|
||
data: {
|
||
summary: summary
|
||
},
|
||
computed: {
|
||
DeltaHands() {
|
||
var delta = this.summary.DeltaInLots;
|
||
return typeof delta !== 'number' ? delta
|
||
: (delta > 0 ? "卖" : "买") + pricingFormat.greek(Math.abs(delta)) + '手';
|
||
}
|
||
},
|
||
filter: {
|
||
greekFmt(val) {
|
||
return typeof val !== 'number' ? val : pricingFormat.greek(val);
|
||
}
|
||
}
|
||
});
|
||
|
||
return {
|
||
getVue() {
|
||
return _vue;
|
||
},
|
||
//data:consCalcFields
|
||
reset(index, data) {
|
||
_summaryDatas[index] = !data || Array.isArray(data) ? data : [data];
|
||
_debounceReset();
|
||
}
|
||
};
|
||
}());
|
||
|
||
//视图呈现器
|
||
const renders = (function () {
|
||
|
||
function _getHtml($tpl, removeClass) {
|
||
var html = $tpl.html();
|
||
var $temp = $('<div>').append(html);
|
||
$temp.find(removeClass).remove();
|
||
$temp.find('template').each(function () {
|
||
html = _getHtml($(this), removeClass);
|
||
$(this).html(html);
|
||
});
|
||
return $temp.html();
|
||
}
|
||
|
||
//定价视图呈现器
|
||
const title = Vue.compile(_getHtml($('#pricingItem_tpl'), '.pitem,.pitem-cash'));
|
||
const item = Vue.compile(_getHtml($('#pricingItem_tpl'), '.ptitle,.pitem-cash:not(.pitem)'));
|
||
const itemCash = Vue.compile(_getHtml($('#pricingItem_tpl'), '.ptitle,.pitem:not(.pitem-cash)'));
|
||
const items = Vue.compile($('#pricingItems_tpl').html() || '');
|
||
|
||
return {
|
||
title(forStatic) {
|
||
return forStatic ? title.staticRenderFns : title.render;
|
||
},
|
||
item(forStatic) {
|
||
return forStatic ? item.staticRenderFns : item.render;
|
||
},
|
||
itemCash(forStatic) {
|
||
return forStatic ? itemCash.staticRenderFns : itemCash.render;
|
||
},
|
||
items(forStatic) {
|
||
return forStatic ? items.staticRenderFns : items.render;
|
||
}
|
||
};
|
||
}());
|
||
|
||
//单个定价组件
|
||
const vueTrade = function () {
|
||
return {
|
||
props: ['trade', 'viewState', 'calcResult', 'floating'],
|
||
data() {
|
||
return {
|
||
isTitle: false,
|
||
canEditEngineName: true,
|
||
...consVueTrade.data(),
|
||
fieldState: tradeFieldMgr.getFieldState(this.floating),
|
||
tradeMarginTemplates: ylotc.tradeMarginTemplates,
|
||
binaryPayoffTypes: this.trade.ExerciseMode === 'European' ?
|
||
consBinaryPayoffTypes.European : consBinaryPayoffTypes.American,
|
||
engineNames: tradeUtils.getEngineNames(this.trade),
|
||
ExerciseModes: this.trade.TradeType === '障碍期权' ? [{ value: 'European', text: '欧式' }] : tradeHelper.ExerciseModes
|
||
};
|
||
},
|
||
watch: {
|
||
'trade.Notional': {
|
||
handler(newVal, oldVal) {
|
||
this.resetSummary(resetSummaryFlags.notional);
|
||
},
|
||
immediate: false
|
||
},
|
||
'trade.TradeType': {
|
||
handler(newVal, oldVal) {
|
||
this.updateKey.KIPayoffType = new Date().getTime();
|
||
this.fieldState.onTradeTypeChanged(this.trade, oldVal, this);
|
||
this.fieldState.setFieldState('TradeAmount', (newVal === '累计期权'));
|
||
if (this.trade.TradeType === '累计期权') {
|
||
this.trade.IsUsePremiumRate = false;
|
||
if (this.trade.AccumulatorStructureType == '1') {
|
||
this.trade.EarlyTerminate = false;
|
||
if (this.trade.PayoffType === '固定' && this.trade.OptionType === '看涨') {
|
||
this.trade.Multiplier2 = 1;
|
||
this.trade.Multiplier3 = 1;
|
||
}
|
||
if (this.trade.PayoffType === '固定' && this.trade.OptionType === '看跌') {
|
||
this.trade.Multiplier1 = 1;
|
||
this.trade.Multiplier2 = 1;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (this.trade.TradeType === '障碍期权') {
|
||
this.ExerciseModes = [{ value: 'European', text: '欧式' }];
|
||
} else {
|
||
this.ExerciseModes = tradeHelper.ExerciseModes;
|
||
}
|
||
|
||
this.changeEngineName();
|
||
},
|
||
immediate: true
|
||
},
|
||
'trade.ExerciseDate': {
|
||
handler(newVal, oldVal) {
|
||
this.trade.SettlementDate = newVal;
|
||
this.changeIsAnnualized();
|
||
},
|
||
immediate: false
|
||
},
|
||
'trade.AccumulatorStructureType': {
|
||
handler(newVal, oldVal) {
|
||
if (this.trade.AccumulatorStructureType == '1') {
|
||
this.trade.EarlyTerminate = false;
|
||
}
|
||
},
|
||
immediate: false
|
||
},
|
||
'trade.PayoffType': {
|
||
handler(newVal, oldVal) {
|
||
if (this.trade.TradeType == "累计期权" && this.trade.AccumulatorStructureType == '1' && this.trade.PayoffType === '固定') {
|
||
if (this.trade.OptionType === '看涨') {
|
||
this.trade.Multiplier = 1;
|
||
this.trade.Multiplier2 = 1;
|
||
this.trade.Multiplier3 = 1;
|
||
}
|
||
if (this.trade.OptionType === '看跌') {
|
||
this.trade.Multiplier = 1;
|
||
this.trade.Multiplier2 = 1;
|
||
this.trade.Multiplier3 = 1;
|
||
}
|
||
}
|
||
this.changeEngineName();
|
||
},
|
||
immediate: false
|
||
},
|
||
'trade.OptionType': {
|
||
handler(newVal, oldVal) {
|
||
if (this.trade.TradeType == "累计期权" && this.trade.AccumulatorStructureType == '1' && this.trade.PayoffType === '固定') {
|
||
if (this.trade.OptionType === '看涨') {
|
||
this.trade.Multiplier = 1;
|
||
this.trade.Multiplier2 = 1;
|
||
this.trade.Multiplier3 = 1;
|
||
}
|
||
if (this.trade.OptionType === '看跌') {
|
||
this.trade.Multiplier = 1;
|
||
this.trade.Multiplier2 = 1;
|
||
this.trade.Multiplier3 = 1;
|
||
}
|
||
}
|
||
},
|
||
immediate: false
|
||
},
|
||
'trade.EnhancedPrice': {
|
||
handler(newVal, oldVal) {
|
||
this.changeEngineName();
|
||
},
|
||
immediate: true
|
||
},
|
||
'trade.StrikeType': {
|
||
handler(newVal, oldVal) {
|
||
this.changeEngineName();
|
||
},
|
||
immediate: false
|
||
}
|
||
},
|
||
created: consVueTrade.created,
|
||
mounted() {
|
||
consSyntheticMap[this.trade.CalcId] = this.viewState.synthetic;
|
||
if (pageVue.ClientUsedForCalc) {
|
||
if (!this.trade.ClientId) {
|
||
ylotc.clients.length && (this.trade.ClientId = ylotc.clients[0].id);
|
||
if (this.trade.ClientId) {
|
||
this.changeClient();
|
||
}
|
||
} else {
|
||
this.updateKey.client = new Date().getTime();
|
||
}
|
||
}
|
||
this.$nextTick(function () {
|
||
switch (this.viewState.initFlag) {
|
||
case 'first':
|
||
this.viewState.initFlag = '';
|
||
this.changeInstrumentType();
|
||
break;
|
||
case 'import1':
|
||
case 'import2':
|
||
case 'template':
|
||
!this.floating && this.updateUnderlying({ UnderlyingCode: this.trade.UnderlyingCode });
|
||
break;
|
||
}
|
||
});
|
||
topVue.simpleMode && (this.trade.UnderlyingPrice = '');
|
||
!this.floating && EventBus.addEventListener('simpleMode.changed', this.onSimpleModeChanged);
|
||
},
|
||
methods: {
|
||
...consVueTrade.methods,
|
||
//变更客户
|
||
changeClient() {
|
||
this.$emit('change-client', this.trade.ClientId);
|
||
},
|
||
//变更期权类型
|
||
changeTradeType() {
|
||
this.viewState.Observation.hasValue = false;
|
||
this.viewState.KOObservation.hasValue = false;
|
||
this.changeExerciseMode('TradeType');
|
||
this.refreshEngineNames();
|
||
if (this.trade.TradeType === "现金流交易") {
|
||
tradeUtils.resetCashFlow(this.trade);
|
||
} else if (this.trade.TradeType === "Risky期权") {
|
||
tradeUtils.resetRisky(this.trade);
|
||
}
|
||
},
|
||
//变更标的类型
|
||
changeInstrumentType() {
|
||
if (new Date().getTime() < this.updateKey.underlying + 300) return;
|
||
let instType = this.trade.UnderlyingInstrumentType;
|
||
this.viewState.variety = tradeHelper.getEmptyVariety(instType);
|
||
this.updateUnderlying({ InstrumentType: instType });
|
||
},
|
||
//变更标的品种
|
||
changeVariety(variety) {
|
||
this.viewState.variety = variety;
|
||
$("#QuoteCurrency").val(this.viewState.variety.QuoteCurrency);
|
||
this.updateUnderlying({ VarietyId: variety.id });
|
||
},
|
||
//变更标的
|
||
changeUnderlying(underlying) {
|
||
if (underlying.Disallow) {
|
||
if (underlying.IsCombined) {
|
||
main.alert(underlying.BlackWhiteState === 1 ? "该组合中包含存在于黑名单的标的" : "该组合中包含不在白名单中的标的");
|
||
}
|
||
else {
|
||
main.alert(underlying.BlackWhiteState === 1 ? "该标的存在于黑名单中" : "该标的不在白名单中");
|
||
return;
|
||
}
|
||
}
|
||
this.viewState.underlying = underlying;
|
||
this.updateUnderlying({ UnderlyingCode: underlying.Code }, true);
|
||
this.changeEffectRatio();
|
||
},
|
||
//变更定价模型
|
||
changeEngineName() {
|
||
// 增强亚式期权,在执行价格和增强价格不一致的情况下,默认只支持使用蒙特卡洛计算引擎
|
||
if (tradeUtils.changeEngineName(this.trade)) {
|
||
this.canEditEngineName = false;
|
||
} else {
|
||
this.canEditEngineName = true;
|
||
}
|
||
},
|
||
//更新标的
|
||
updateUnderlying(reqData, fromSelect) {
|
||
let self = this;
|
||
// EQD-7049:新建空白页未选标的/品种/类型时,跳过必然失败的后端默认标的查询,避免报“标的信息缺失”
|
||
var hasQueryKey = !!(reqData.UnderlyingCode || reqData.InstrumentType || reqData.VarietyId > 0);
|
||
if (!hasQueryKey) {
|
||
!fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying());
|
||
return;
|
||
}
|
||
var instTypeChanged = !!reqData.InstrumentType;
|
||
!fromSelect && (self.viewState.underlying = tradeHelper.getEmptyUnderlying());
|
||
main.post("/pricing/AjaxGetUnderlying", reqData).done(function (resp) {
|
||
let trade = self.trade;
|
||
let um = resp.obj.underlying;
|
||
if (!fromSelect) {
|
||
self.viewState.underlying = {
|
||
id: um.id, Code: um.UnderlyingCode, Name: um.UnderlyingName,
|
||
InstrumentType: um.UnderlyingInstrumentType, VarietyId: um.UnderlyingTypeId,
|
||
QuoteUnitString: um.QuoteUnitString
|
||
};
|
||
}
|
||
self.updateKey.underlying = new Date().getTime();
|
||
instTypeChanged || (instTypeChanged = trade.UnderlyingInstrumentType !== um.UnderlyingInstrumentType);
|
||
|
||
trade.UnderlyingId = um.id;
|
||
trade.UnderlyingCode = um.UnderlyingCode;
|
||
trade.UnderlyingName = um.UnderlyingName;
|
||
trade.UnderlyingInstrumentType = um.UnderlyingInstrumentType;
|
||
trade.VarietyId = um.UnderlyingTypeId;
|
||
trade.CountRatio = um.CountRatio;
|
||
|
||
self.viewState.variety = _.clone(ylotc.varieties.find(x => x.id === um.UnderlyingTypeId))
|
||
|| tradeHelper.getEmptyVariety(trade.UnderlyingInstrumentType);
|
||
self.updateKey.variety = new Date().getTime();
|
||
|
||
if (self.viewState.initFlag === 'import1') {
|
||
self.getTTM(false, false);
|
||
return self.viewState.initFlag = '';
|
||
}
|
||
|
||
if (self.viewState.initFlag === 'template') {
|
||
return self.viewState.initFlag = '';
|
||
}
|
||
|
||
trade.DividendRate = um.DividendRate;
|
||
self.viewState.synthetic = consSyntheticMap[trade.CalcId] = resp.obj.synthetic;
|
||
|
||
//初始预付金
|
||
trade.InitialMargin = 0;
|
||
|
||
//加载结构化交易
|
||
if (self.viewState.initFlag === 'import2') {
|
||
trade.SettlementDate = trade.ExerciseDate;
|
||
(trade.TradeOpenVolatility !== '') && (self.viewState.VolState = 'user');
|
||
(trade.TradeCloseVolatility !== '') && (self.viewState.CloseVolState = 'user');
|
||
self.changeTradeDate('import2');
|
||
if (trade.PremiumRate !== '' || trade.TradeSinglePrice !== '') {
|
||
trade.PremiumRate !== '' ? self.changePremiumRate() : self.changeTradeSinglePrice();
|
||
} else {
|
||
trade.PremiumRate = trade.TradeSinglePrice = trade.TradePrice = 0;
|
||
}
|
||
return self.viewState.initFlag = '';
|
||
}
|
||
|
||
//重置权利金
|
||
trade.PremiumRate = trade.TradeSinglePrice = trade.TradePrice = 0;
|
||
|
||
trade.SpotPrice = pricingFormat.umprice(um.Price);
|
||
|
||
//重置视图状态
|
||
_.each(tradeFieldMgr.defaultData.viewState, (val, key) => {
|
||
if (key === 'VolState' && self.viewState['VolLockState'] !== 'system') {
|
||
val = 'user';
|
||
}
|
||
else if (key !== 'VolLockState') {
|
||
val === 'system' && (self.viewState[key] = "system");
|
||
}
|
||
});
|
||
|
||
//根据标的类型切换,权益类默认名义本金成交方式
|
||
if (um.UnderlyingInstrumentType === "Stock" || um.UnderlyingInstrumentType === "StockIndex") {
|
||
if (!trade.DividendRate) {
|
||
trade.DividendRate = 0;
|
||
}
|
||
trade.IsUsePremiumRate = trade.TradeType!=='累计期权';
|
||
//名义本金影响交易数量
|
||
self.changeStockEqvNotional(1e6);
|
||
if (trade.IsMoneynessOption !== "是" || !trade.Strike) {
|
||
trade.Strike = pricingFormat.umprice(um.Price);
|
||
self.showPercentStrike();
|
||
instTypeChanged = true;
|
||
}
|
||
} else {
|
||
trade.IsUsePremiumRate = false;
|
||
self.changeTradeAmount(instTypeChanged ? 1 : null);
|
||
if (trade.IsMoneynessOption === "是" || !trade.Strike) {
|
||
trade.Strike = "1";
|
||
self.showAbsStrike();
|
||
instTypeChanged = true;
|
||
}
|
||
}
|
||
|
||
//如果资产大类变更则清除掉IsMoneynessOption和IsUsePremiumRate关联的字段值
|
||
instTypeChanged && tradeUtils.onChangeInstrumentType(trade);
|
||
|
||
//到期日ExerciseDate默认为1个月之后,股票到期日不显示
|
||
trade.TradeDate = pageVue.SysDate;
|
||
trade.ExerciseDate = new moment(um.ExerciseDate).format("YYYY-MM-DD");
|
||
trade.MaturityDate = new moment(um.MaturityDate || "2029-01-01").format("YYYY-MM-DD");
|
||
trade.TradeDate > trade.ExerciseDate && (trade.TradeDate = trade.ExerciseDate);
|
||
|
||
if (trade.TradeType === "Risky期权") {
|
||
if (trade.IsMoneynessOption === "是") {
|
||
trade.Strike1 = "";
|
||
trade.Strike2 = "";
|
||
trade.Strike3 = 1;
|
||
} else {
|
||
trade.Strike1 = "";
|
||
trade.Strike2 = "";
|
||
trade.Strike3 = um.Price;
|
||
}
|
||
}
|
||
self.changeTradeDate(true, true);
|
||
|
||
if (pageData.is厦门象屿 || trade.TradeType === "Risky期权") {
|
||
trade.PremiumPayDate = trade.ExerciseDate;
|
||
}
|
||
|
||
//重置计算结果
|
||
self.calcResult.reset();
|
||
if (fromSelect) {
|
||
self.resetSummary(resetSummaryFlags.all);
|
||
}
|
||
});
|
||
},
|
||
//刷新波动率,影响波动率的属性:SpotPrice,Strike,TradeDate,ExerciseDate,UnderlyingId
|
||
getVol(debounce) {
|
||
if (this.trade.TradeType === "现金流交易") return;
|
||
if (pageVue.IsTradeVol) {
|
||
let flag = 0;
|
||
if (!pageVue.SkewMapVol) {
|
||
this.viewState.VolState !== 'user' && (flag |= 1);
|
||
this.viewState.CloseVolState !== 'user' && (flag |= 2);
|
||
if (flag === 0) return;
|
||
} else {
|
||
flag = 1 | 2;
|
||
}
|
||
if (debounce === true) {
|
||
if (!this.debounceGetVol) {
|
||
this.debounceGetVol = _.debounce(function (t) {
|
||
(t.flag & 1) > 0 && t.vue.getTradeOpenVolatility();
|
||
(t.flag & 2) > 0 && t.vue.getTradeCloseVolatility();
|
||
}, 1000, { trailing: true });
|
||
}
|
||
this.debounceGetVol({ vue: this, flag: flag });
|
||
} else {
|
||
(flag & 1) > 0 && this.getTradeOpenVolatility();
|
||
(flag & 2) > 0 && this.getTradeCloseVolatility();
|
||
}
|
||
} else if (this.viewState.VolState !== 'user') {
|
||
this.getTradeOpenVolatility();
|
||
}
|
||
},
|
||
//重置统计数据
|
||
resetSummary(flag) {
|
||
this.$emit('reset-summary', flag);
|
||
},
|
||
//获取标的价格(计算用)
|
||
getUnderlyingPrice() {
|
||
var self = this;
|
||
return main.post("/pricing/AjaxGetUnderlyingPrice", { underlyingCode: this.trade.UnderlyingCode, tradeDate: this.trade.ValueDate })
|
||
.done(function (resp) {
|
||
self.trade.UnderlyingPrice = pricingFormat.umprice(resp.obj.price);
|
||
});
|
||
},
|
||
//精简模式切换时的处理
|
||
onSimpleModeChanged() {
|
||
this.trade.UnderlyingPrice = '';
|
||
}
|
||
},
|
||
computed: { ...consVueTrade.computed },
|
||
components: {
|
||
'vue-margintemplatename': vueMarginTemplateName(),
|
||
'vue-niceselect': FastVue.vueNiceSelect(),
|
||
'vue-variety': vueVariety(),
|
||
'vue-tradetype': vueTradeType(),
|
||
'vue-underlying': vueUnderlying(),
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput(),
|
||
'vue-daycount': vueDayCount(),
|
||
'vue-client': vueClient(),
|
||
},
|
||
render: renders.item(),
|
||
staticRenderFns: renders.item(true),
|
||
destroyed() {
|
||
delete consSyntheticMap[this.trade.calcId];
|
||
topVue.simpleMode && (this.trade.UnderlyingPrice = '');
|
||
EventBus.removeEventListener('simpleMode.changed', this.onSimpleModeChanged);
|
||
}
|
||
};
|
||
};
|
||
|
||
//单个定价组件(现金流)
|
||
const vueTrade2 = function () {
|
||
return {
|
||
props: ['trade', 'viewState', 'calcResult', 'floating'],
|
||
data() {
|
||
return {
|
||
isTitle: false,
|
||
...consVueTrade.data(),
|
||
fieldState: tradeFieldMgr.getFieldState(this.floating),
|
||
};
|
||
},
|
||
watch: {
|
||
'trade.ExerciseDate': {
|
||
handler(newVal, oldVal) {
|
||
this.trade.SettlementDate = newVal;
|
||
},
|
||
immediate: false
|
||
}
|
||
},
|
||
mounted() {
|
||
if (pageVue.ClientUsedForCalc) {
|
||
if (!this.trade.ClientId) {
|
||
ylotc.clients.length && (this.trade.ClientId = ylotc.clients[0].id);
|
||
if (this.trade.ClientId) {
|
||
this.changeClient();
|
||
}
|
||
} else {
|
||
this.updateKey.client = new Date().getTime();
|
||
}
|
||
}
|
||
this.fieldState.onTradeTypeChanged(this.trade, null, this);
|
||
this.trade.IsUsePremiumRate = true;
|
||
},
|
||
methods: {
|
||
...consVueTrade.methods,
|
||
//变更客户
|
||
changeClient() {
|
||
this.$emit('change-client', this.trade.ClientId);
|
||
},
|
||
//重置统计数据
|
||
resetSummary(flag) {
|
||
this.$emit('reset-summary', flag);
|
||
}
|
||
},
|
||
computed: { ...consVueTrade.computed },
|
||
components: {
|
||
'vue-niceselect': FastVue.vueNiceSelect(),
|
||
'vue-client': vueClient(),
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput(),
|
||
'vue-daycount': vueDayCount(),
|
||
},
|
||
render: renders.itemCash(),
|
||
staticRenderFns: renders.itemCash(true),
|
||
destroyed() {
|
||
|
||
}
|
||
};
|
||
};
|
||
|
||
//主视图定价头部拖动处理
|
||
const mainDragScroll = dragScroll.create({ container: '.pricing-main', yscroll: false, throttle: _.throttle });
|
||
|
||
//定价组件组合
|
||
function createVue(index, baseVue, floating) {
|
||
|
||
var datas = baseVue.datas;
|
||
var fromLocal = baseVue.fromLocal === true;
|
||
|
||
if (datas.length < 1) {
|
||
return main.alert('缺少数据');
|
||
}
|
||
|
||
var structureType = baseVue.combining && datas.length > 1 ? '结构化交易' : baseVue.structureType || '';
|
||
|
||
_.each(datas, (data, index2) => {
|
||
|
||
data.trade.CalcId = index + '-' + (index2 + 1);
|
||
|
||
if (!data.calcResult) {
|
||
data.calcResult = {
|
||
sourceData: null,
|
||
reset(data) {
|
||
this.sourceData = data;
|
||
if (!data) {
|
||
_.each(consCalcFields, x => this[x] = '');
|
||
}
|
||
}
|
||
};
|
||
_.each(consCalcFields, x => data.calcResult[x] = '');
|
||
} else if (baseVue.combining) {
|
||
data.calcResult = _.cloneDeep(data.calcResult);
|
||
}
|
||
|
||
if (!data.trade.UnderlyingInstrumentType) {
|
||
data.trade.UnderlyingInstrumentType = pageVue.StockFirst ? 'Stock' : 'CommodityFutures';
|
||
}
|
||
|
||
data.trade.StructureType = structureType;
|
||
});
|
||
|
||
if (datas.length === 1) {
|
||
datas[0].trade.CalcId = index.toString();
|
||
}
|
||
|
||
var debounceFloatSinglePrice = _.debounce(singlePricer.calcSinglePrice, 300);
|
||
|
||
var vue = new Vue({
|
||
data: {
|
||
index: index,
|
||
datas: datas,
|
||
floating: floating,
|
||
isSelected: !!baseVue.isSelected,
|
||
structureType: structureType,
|
||
showFloatingIcon: !structureType || datas.every(x => x.trade.TradeType === '香草期权')
|
||
},
|
||
computed: {
|
||
|
||
},
|
||
mounted() {
|
||
if (this.floating) {
|
||
var singlePrice = singlePricer.calcSinglePrice(this.convertForSinglePrice());
|
||
singlePrice && $('#singleprice2').text(singlePrice);
|
||
} else {
|
||
pricingVue.onMountd(this);
|
||
}
|
||
},
|
||
methods: {
|
||
getData(index) {
|
||
return this.datas[index || 0];
|
||
},
|
||
getVol() {
|
||
_.each(this.$children, x => x.getVol());
|
||
},
|
||
remove(blRemoveChain) {
|
||
this.$destroy();
|
||
this.$el.remove();
|
||
pricingVue.remove(this, blRemoveChain);
|
||
},
|
||
saveTrade() {
|
||
tradeSaver.saveTrades([this]);
|
||
},
|
||
showFloatVue() {
|
||
floatVue.show(this);
|
||
let td = this.getData(0);
|
||
setTimeout(function () {//交易详情页-定价增强价格不显示问题
|
||
if (td && td.trade.TradeType == "亚式期权" && td.trade.StrikeType != "Floating" && td.trade.PayoffType == 'EnhancedArithmeticAverage') {
|
||
$("#EnhancedPriceTitle").show();
|
||
}
|
||
}, 500);
|
||
|
||
},
|
||
screenshot() {
|
||
screenshoter.execute(this);
|
||
},
|
||
uncouple() {
|
||
pricingVue.uncouple(this);
|
||
},
|
||
convertForSinglePrice() {
|
||
return _.reduce(this.datas, (result, data) => {
|
||
var sdata = data.calcResult.sourceData;
|
||
sdata && (result || (result = [])).push({ Pv: sdata.Pv, Notional: data.trade.Notional });
|
||
return result;
|
||
}, null);
|
||
},
|
||
//重置统计数据
|
||
resetSummary(flag) {
|
||
//浮窗页面
|
||
if (this.floating && flag < resetSummaryFlags.ten) {
|
||
var singlePrice = singlePricer.calcSinglePrice(this.convertForSinglePrice());
|
||
singlePrice && $('#singleprice2').text(singlePrice);
|
||
}
|
||
//主页面
|
||
if (this.isSelected) {
|
||
if (flag === resetSummaryFlags.initialMargin) {
|
||
var data = this.datas[this.datas.length - 1];
|
||
data.calcResult.TotalMargin = pageVue.GetTotalMargin(_.map(this.datas, x => x.trade), this.structureType);
|
||
return summaryVue.reset(this.index, this.datas.map(x => x.calcResult));
|
||
}
|
||
singlePricer.reset(this.index, this.convertForSinglePrice());
|
||
if (flag !== resetSummaryFlags.notional) {
|
||
summaryVue.reset(this.index, this.datas.map(x => x.calcResult));
|
||
}
|
||
}
|
||
else if (flag === true) {
|
||
summaryVue.reset(this.index, null);
|
||
singlePricer.reset(this.index, null);
|
||
}
|
||
},
|
||
setCalcResult(result) {
|
||
var data = _.find(this.datas, x => x.trade.CalcId === result.CalcId);
|
||
if (!data) {
|
||
return main.alert('系统错误');
|
||
}
|
||
|
||
var trade = data.trade;
|
||
|
||
if (topVue.calcMargin) {
|
||
if (data.viewState.InitialMargin !== 'user' || (data.viewState.InitialMargin === 'user' && trade.InitialMargin === '')) {
|
||
if (pageVue.ClientUsedForCalc && pageVue.TwoSideMargin &&
|
||
!data.viewState.TwoSideMargin && result.initialMargin < 0
|
||
&& !trade.StructureType) {
|
||
trade.InitialMargin = 0;
|
||
}
|
||
else {
|
||
trade.InitialMargin = pricingFormat.tradePrice(result.initialMargin);
|
||
}
|
||
data.viewState.InitialMargin = "system";
|
||
}
|
||
} else {
|
||
trade.InitialMargin = '';
|
||
}
|
||
|
||
var calcResult = data.calcResult;
|
||
var contractSize = result.contractSize;
|
||
|
||
//对象缩小为具体计算结果
|
||
result = result.calcResult;
|
||
calcResult.reset(result);
|
||
|
||
//用于统计
|
||
calcResult.UnderlyingCode = trade.UnderlyingCode;
|
||
|
||
if (trade.IsUsePremiumRate) {
|
||
trade.TradePrice = result.Pv * (trade.BuySell == "买入" ? 1 : -1);
|
||
if (trade.TradeType !== "现金流交易") {
|
||
//根据总额算出期权费率
|
||
tradePricing.tradeCalc(trade, tradePricing.calcReason.Pv);
|
||
//由于期权费率会有精度损失,进行了四舍五入处理,需要再根据期权费率反算出期权费总额
|
||
//因为录入交易时是根据期权费率作为标准的
|
||
tradePricing.tradeCalc(trade, tradePricing.calcReason.PremiumRate);
|
||
}
|
||
else {
|
||
trade.TradePrice = pricingFormat.tradePrice(trade.TradePrice);
|
||
}
|
||
}
|
||
else {
|
||
let notional = trade.Notional;
|
||
if (trade.TradeType == "累计期权") {
|
||
var datas = {
|
||
kOObservationDates: trade.KOObservationDates,
|
||
valueDate: trade.ValueDate || trade.TradeDate,
|
||
tradeDate: trade.TradeDate,
|
||
exerciseDate: trade.ExerciseDate,
|
||
}
|
||
var dayCount = 0;
|
||
main.post("/trade_cash/GetAccTradeUnwindDayCount", datas, { async: false }).done(
|
||
function (res) {
|
||
dayCount = res.obj;
|
||
}
|
||
);
|
||
notional = dayCount * trade.AccumuTradeAmount;
|
||
trade.Notional = notional;
|
||
}
|
||
var pv = result.Pv * (trade.BuySell == "买入" ? 1 : -1);
|
||
trade.TradeSinglePrice = notional ? pv / notional : 0;
|
||
tradePricing.tradeCalc(trade, tradePricing.calcReason.TradeSinglePrice);
|
||
}
|
||
|
||
if (pageObj.IsPVIncludePrincipal && trade.OriginalPrincipalSum > 0) {
|
||
result.Pv += trade.OriginalPrincipalSum * (trade.BuySell === '卖出' ? -1 : 1);
|
||
result.PvContainsKnockOut += trade.OriginalPrincipalSum * (trade.BuySell === '卖出' ? -1 : 1);
|
||
|
||
}
|
||
|
||
//todo:光子模式下是否要重设TradeOpenVolatility的值
|
||
// delta gamma 用手数,其它份额 Vega,pho份额*100 qdp用的是份额计算
|
||
//现在计算的是数量 份额数量比
|
||
//手数 = 交易数量 / 交易单位 (5吨 / 手)
|
||
//交易数量 = 份额 / 比率
|
||
//手数 = 份额 / (比率 * 交易单位)
|
||
//TradeUnitValue 是手数对份额的比率 鸡蛋时为 10
|
||
var variety = data.viewState.variety;
|
||
var fe_ration = 1;
|
||
!contractSize && (contractSize = variety && variety.ContractSize ? variety.ContractSize : 1);
|
||
calcResult.Pv = pricingFormat.tradePrice(result.Pv);
|
||
calcResult.Delta = pricingFormat.greek(result.Delta);
|
||
calcResult.Gamma = pricingFormat.greek(result.Gamma);
|
||
calcResult.DeltaInLots = pricingFormat.greek(result.Delta / contractSize);
|
||
calcResult.GammaInLots = pricingFormat.greek(result.Gamma / contractSize);
|
||
calcResult.Theta = pricingFormat.greek(fe_ration * result.Theta);
|
||
calcResult.Vega = pricingFormat.greek(fe_ration * result.Vega);
|
||
calcResult.Rho = pricingFormat.greek(fe_ration * result.Rho * 100);
|
||
calcResult.DeltaCash = pricingFormat.greek(result.DeltaCash);
|
||
calcResult.GammaCash = pricingFormat.greek(result.GammaCash);
|
||
calcResult.VegaCash = pricingFormat.greek(result.VegaCash);
|
||
calcResult.PvContainsKnockOut = pricingFormat.tradePrice(result.PvContainsKnockOut);
|
||
calcResult.DeltaContainsKnockOut = pricingFormat.greek(result.DeltaContainsKnockOut);
|
||
calcResult.GammaContainsKnockOut = pricingFormat.greek(result.GammaContainsKnockOut);
|
||
calcResult.Delta_r = result.Delta_r != null ? pricingFormat.greek(result.Delta_r) : "";
|
||
calcResult.Delta_r_1bp = result.Delta_r_1bp != null ? pricingFormat.greek(result.Delta_r_1bp) : "";
|
||
calcResult.Dv01 = result.Dv01 != null ? pricingFormat.greek(result.Dv01) : "";
|
||
calcResult.Gamma_r = result.Gamma_r != null ? pricingFormat.greek(result.Gamma_r) : "";
|
||
calcResult.Gamma_r_1bp = result.Gamma_r_1bp != null ? pricingFormat.greek(result.Gamma_r_1bp) : "";
|
||
calcResult.Vega_r = result.Vega_r != null ? pricingFormat.greek(result.Vega_r) : "";
|
||
calcResult.Vega_r_1bp = result.Vega_r_1bp != null ? pricingFormat.greek(result.Vega_r_1bp) : "";
|
||
calcResult.Vega_1bp = result.Vega_1bp != null ? pricingFormat.greek(result.Vega_1bp) : "";
|
||
calcResult.TotalMargin = 0;
|
||
if (data === this.datas[this.datas.length - 1]) {
|
||
calcResult.TotalMargin = pageVue.GetTotalMargin(_.map(this.datas, x => x.trade), this.structureType);
|
||
}
|
||
this.resetSummary(resetSummaryFlags.all);
|
||
},
|
||
changeClient(clientId) {
|
||
let client = null;
|
||
if (pageVue.ClientUsedForCalc && pageVue.TwoSideMargin) {
|
||
client = ylotc.clients.find(y => y.id === clientId);
|
||
}
|
||
_.each(this.datas, x => {
|
||
x.trade.ClientId = clientId;
|
||
x.trade.MarginOptionType = client.MarginOptionType;
|
||
x.viewState.TwoSideMargin = client && client.MarginOptionType === 1;
|
||
x.trade.MarginTemplateName = client.MarginOptionType === 3 ? "无预付金" : "系统默认";
|
||
tradeUtils.changeMarginTemplate(x.trade, []);
|
||
});
|
||
},
|
||
updateSynthetic(calcId, synthetic) {
|
||
var index = this.datas.findIndex(x => x.trade.CalcId === calcId);
|
||
if (index < 0) return false;
|
||
this.datas[index].trade.SpotPrice = synthetic.Price;
|
||
this.$children[index].changeSpotPrice(true);
|
||
return true;
|
||
},
|
||
copyThis() {
|
||
pricingVue.copyItem(this);
|
||
}
|
||
},
|
||
components: {
|
||
'vue-trade': vueTrade(),
|
||
'vue-trade2': vueTrade2(),
|
||
},
|
||
destroyed() {
|
||
if (!this.floating && this.isSelected) {
|
||
summaryVue.reset(this.index, null);
|
||
singlePricer.reset(this.index, null);
|
||
}
|
||
},
|
||
render: renders.items(),
|
||
staticRenderFns: renders.items(true)
|
||
});
|
||
|
||
if (!baseVue.combining && !baseVue.selfMount) {
|
||
if (vue.floating) {
|
||
vue.$mount($('<div>').appendTo('#pricing-items2').get(0));
|
||
} else if (fromLocal) {
|
||
vue.$mount($('<div>').appendTo('#pricing-items').get(0));
|
||
} else {
|
||
vue.$mount($('<div>').prependTo('#pricing-items').get(0));
|
||
}
|
||
}
|
||
|
||
!floating && mainDragScroll.reset();
|
||
|
||
return vue;
|
||
}
|
||
|
||
function _setAutocomplete(elId, datas, initData, onSelectFn) {
|
||
initData = initData || {};
|
||
if (elId === "GroupClientId") {
|
||
groupVue.trade.ClientId = initData.id;
|
||
groupVue.trade.ClientName = initData.Name;
|
||
}
|
||
else if (elId === "GroupAssetId") {
|
||
groupVue.trade.AssetId = initData.id;
|
||
groupVue.trade.AssetBookName = initData.Name;
|
||
}
|
||
else if (elId === "GroupTraderId") {
|
||
groupVue.trade.TraderId = initData.id;
|
||
groupVue.trade.TraderName = initData.Name;
|
||
}
|
||
|
||
FastVue.autocomplete(document.getElementById(elId), {
|
||
valueField: 'Name', searchField: ['Name', 'PinYin'], lookup: datas,
|
||
onSelect(data) {
|
||
$('#' + elId).data('id', data.id);
|
||
if (elId === "ClientId" || elId === "GroupClientId") {
|
||
if (!pageVue.ClientUsedForCalc || elId === "GroupClientId") {
|
||
$("#selIsCentralClearing").val(data.IsCentralClearing);
|
||
$("#selCentralClearingPaltform").val(data.CentralClearingPaltform);
|
||
$("#selTradingPaltform").val(data.TradingPaltform);
|
||
}
|
||
_setSalesman();
|
||
}
|
||
onSelectFn && onSelectFn(data);
|
||
},
|
||
zIndex: 300000
|
||
}).setData(initData);
|
||
$('#' + elId).data('id', initData.id);
|
||
}
|
||
|
||
function _setSalesman() {
|
||
if (pageVue.ClientUsedForCalc) {
|
||
var IsCentralClearing = $("#txtCurrentClient").attr("data-IsCentralClearing");
|
||
var CentralClearingPaltform = $("#txtCurrentClient").attr("data-CentralClearingPaltform");
|
||
var TradingPaltform = $("#txtCurrentClient").attr("data-TradingPaltform");
|
||
$("#IsCentralClearing").val(IsCentralClearing);
|
||
$("#CentralClearingPaltform").val(CentralClearingPaltform);
|
||
$("#TradingPaltform").val(TradingPaltform);
|
||
}
|
||
|
||
if ($("#ClientId").data('id') && _salesCommissionCtrl) {
|
||
_salesCommissionCtrl.changeSalesmen($("#ClientId").data('id'));
|
||
_getMainProtocolCode($("#ClientId").data('id'));
|
||
}
|
||
|
||
}
|
||
|
||
function _changeMainProtocolCode() {
|
||
_getSupProtocolCode();
|
||
}
|
||
|
||
function _getMainProtocolCode(client) {
|
||
$("#MainProtocolCode option").remove();
|
||
if (client) {
|
||
let clientId = typeof client === 'object' ? client.id : client;
|
||
main.post("/Client/getMainProtocolCodes", { clientId: clientId }, { async: false }).done(function (resp) {
|
||
var obj = $("#MainProtocolCode");
|
||
_.forEach(resp, (v) => {
|
||
obj.append("<option >" + v.Text + "</option>");
|
||
})
|
||
});
|
||
}
|
||
_getSupProtocolCode()
|
||
}
|
||
|
||
function getSelectTags() {
|
||
var tags = new Array();
|
||
$(".tag-context .tag-item").each(function (i, v) {
|
||
var exist = false;
|
||
var name = $(v).data("name");
|
||
tags.forEach(function (o) {
|
||
if (o.Name == name) {
|
||
exist = true;
|
||
}
|
||
});
|
||
if (!exist) {
|
||
tags.push({ Id: $(v).data("id"), Name: name });
|
||
}
|
||
});
|
||
return tags;
|
||
}
|
||
|
||
function _getSupProtocolCode() {
|
||
$("#SupProtocolCode option").remove();
|
||
if ($("#MainProtocolCode").val()) {
|
||
main.post("/Client/getSideProtocols", { mainProtocol: $("#MainProtocolCode").val() }, { async: false }).done(function (resp) {
|
||
var obj = $("#SupProtocolCode");
|
||
_.forEach(resp, (v) => {
|
||
obj.append("<option >" + v + "</option>");
|
||
})
|
||
});
|
||
}
|
||
}
|
||
|
||
|
||
function CalcResultShowCfg() {
|
||
var srcurl = "/CalcPriceShowCfg/Index";
|
||
main.open("计算指标显示设置", srcurl, { area: ["800px", "700px"] });
|
||
}
|
||
|
||
|
||
//定价组件
|
||
const pricingVue = (function () {
|
||
|
||
//创建定价标题组件
|
||
function createTitleVue(el, floating) {
|
||
var vue = new Vue({
|
||
el: el,
|
||
data: {
|
||
trade: {},
|
||
isTitle: true,
|
||
floating: floating,
|
||
fieldState: tradeFieldMgr.getTitleState(floating)
|
||
},
|
||
render: renders.title(),
|
||
staticRenderFns: renders.title(true)
|
||
});
|
||
return vue;
|
||
}
|
||
|
||
createTitleVue('#pricing-titles', false);
|
||
createTitleVue('#pricing-titles2', true);
|
||
|
||
var _index = 1;
|
||
|
||
//定价组件集合
|
||
const _tradeVues = [];
|
||
|
||
function __clear() {
|
||
if (!_tradeVues.length) return;
|
||
_index = 0;
|
||
_tradeVues.splice(0, _tradeVues.length).forEach(x => x.remove());
|
||
$('#pricing-items').parent().floatingScroll('update');
|
||
}
|
||
|
||
//清空
|
||
function clear(force) {
|
||
if (!_tradeVues.length) return;
|
||
if (force) {
|
||
__clear();
|
||
} else {
|
||
main.confirmV2("确认清空吗?").done(__clear);
|
||
}
|
||
}
|
||
|
||
//移除
|
||
function remove(tradeVue, blRemoveChain) {
|
||
if (blRemoveChain && tradeVue.floating) {
|
||
var baseVue = _tradeVues.find(x => x.index === tradeVue.index);
|
||
baseVue && baseVue.remove();
|
||
}
|
||
_.pull(_tradeVues, tradeVue);
|
||
$('#pricing-items').parent().floatingScroll('update');
|
||
}
|
||
|
||
//新增单腿
|
||
function addTrade(trade, tradeType) {
|
||
_index += 1;
|
||
let baseVue = _tradeVues[0] || { datas: [tradeFieldMgr.defaultData] };
|
||
if (trade && typeof trade === 'object') {
|
||
let viewState = _.cloneDeep(tradeFieldMgr.defaultData.viewState);
|
||
viewState.initFlag = 'import1';
|
||
baseVue = { datas: [{ trade: trade, viewState: viewState }] };
|
||
} else if (tradeType === "现金流交易") {
|
||
let data = tradeFieldMgr.defaultData;
|
||
data = {
|
||
trade: _.cloneDeep(data.trade),
|
||
viewState: _.cloneDeep(data.viewState)
|
||
};
|
||
_tradeVues.length < 1 && (data.viewState.initFlag = 'first');
|
||
data.trade.IsUsePremiumRate = true;
|
||
baseVue = { datas: [data] };
|
||
trade = data.trade;
|
||
}
|
||
else {
|
||
let data = baseVue.datas[0];
|
||
data = {
|
||
trade: _.cloneDeep(data.trade),
|
||
viewState: _.cloneDeep(data.viewState)
|
||
};
|
||
_tradeVues.length < 1 && (data.viewState.initFlag = 'first');
|
||
baseVue = { datas: [data] };
|
||
trade = data.trade;
|
||
}
|
||
if (typeof tradeType === 'string' && trade.TradeType !== tradeType) {
|
||
trade.TradeType = tradeType;
|
||
tradeFieldMgr.initFieldValue(trade);
|
||
}
|
||
if (trade.TradeAmount && !trade.TradeAmountV) {
|
||
trade.TradeAmountV = tradeHelper.getTradeAmountV(trade);
|
||
}
|
||
let vue = createVue(_index, baseVue);
|
||
_tradeVues.unshift(vue);
|
||
if (pageVue.IsImport || !new Array('香草期权', '合成价差期权').includes(trade.TradeType)) {
|
||
floatVue.show(vue);
|
||
}
|
||
}
|
||
|
||
//复制项目
|
||
function copyItem(tradeVue) {
|
||
var arrIndex = _.indexOf(_tradeVues, tradeVue);
|
||
if (arrIndex < 0) {
|
||
throw '系统错误';
|
||
}
|
||
_index += 1;
|
||
let baseVue = tradeVue;
|
||
baseVue = { datas: _.cloneDeep(baseVue.datas), structureType: baseVue.structureType, selfMount: true };
|
||
var vue = createVue(_index, baseVue);
|
||
vue.$mount($('<div>').insertBefore(tradeVue.$el).get(0));
|
||
_tradeVues.splice(arrIndex, 0, vue);
|
||
}
|
||
|
||
//新增策略
|
||
function addTrades(trades) {
|
||
var datas = _.map(trades, trade => {
|
||
trade = _.transform(trade, (result, val, key) => {
|
||
key in result && (result[key] = val);
|
||
}, _.cloneDeep(pageVue.Trade));
|
||
if (trade.UnderlyingInstrumentType !== 'Stock' && trade.UnderlyingInstrumentType !== 'StockIndex') {
|
||
trade.StockEqvNotionalReal = pricingFormat.StockEqvNotional(trade.Notional * trade.SpotPrice);
|
||
trade.StockEqvNotional = trade.StockEqvNotionalReal;
|
||
}
|
||
else {
|
||
trade.StockEqvNotionalReal = trade.StockEqvNotional;
|
||
}
|
||
trade.SpotPrice = trade.UnderlyingPrice;
|
||
trade.NoRiskRate = null;
|
||
trade.DividendRate = 0;
|
||
trade.ParticipationRate = 1;
|
||
trade.AnnualizeFactor = 1;
|
||
if (pageVue.NumOfSmoothingDaysCfg === 'ONE' && pageVue.IsTradeVol) {
|
||
trade.NumOfSmoothingDays = 1;
|
||
}
|
||
tradeUtils.normalizeTrade(trade);
|
||
let viewState = _.cloneDeep(tradeFieldMgr.defaultData.viewState);
|
||
viewState.initFlag = 'import2';
|
||
return { trade: trade, viewState: viewState };
|
||
});
|
||
|
||
_index += 1;
|
||
var vue = createVue(_index, { datas: datas, structureType: pageVue.getStructureType() });
|
||
_tradeVues.unshift(vue);
|
||
}
|
||
|
||
//自由组合
|
||
function combine() {
|
||
var comVues = _.filter(_tradeVues, x => x.isSelected);
|
||
if (comVues.length < 2) {
|
||
return main.alert('请选择至少两项进行组合!');
|
||
}
|
||
var firstVue = comVues[0];
|
||
var datas = _.flatMap(comVues.map(x => x.datas));
|
||
if (pageVue.ClientUsedForCalc) {
|
||
var clientId = parseInt(datas[0].trade.ClientId);
|
||
if (!_.every(datas, x => parseInt(x.trade.ClientId) === clientId)) {
|
||
return main.alert('所选项客户必须一致!');
|
||
}
|
||
}
|
||
var vue = createVue(firstVue.index, { combining: true, datas: datas, fromLocal: true });
|
||
vue.$mount($('<div>').insertBefore(firstVue.$el).get(0));
|
||
var index = _.indexOf(_tradeVues, firstVue);
|
||
_tradeVues[index] = vue;
|
||
_.pullAll(_tradeVues, comVues);
|
||
comVues.forEach(x => x.remove());
|
||
}
|
||
|
||
//取消组合
|
||
function uncouple(tradeVue) {
|
||
if (!tradeVue || tradeVue.floating) {
|
||
throw '系统错误';
|
||
}
|
||
var arrIndex = _.indexOf(_tradeVues, tradeVue);
|
||
if (arrIndex < 0) {
|
||
throw '系统错误';
|
||
}
|
||
var index = _index += tradeVue.datas.length;
|
||
var map = _.map(tradeVue.datas, data => {
|
||
var vue = createVue(index--, { combining: true, datas: [data], fromLocal: true });
|
||
vue.$mount($('<div>').insertBefore(tradeVue.$el).get(0));
|
||
return vue;
|
||
});
|
||
var args = [arrIndex, 1].concat(map);
|
||
Array.prototype.splice.apply(_tradeVues, args);
|
||
tradeVue.remove();
|
||
}
|
||
|
||
//波动率类型变更
|
||
function changeVolType() {
|
||
_tradeVues.forEach(x => x.getVol());
|
||
}
|
||
|
||
//获取所有交易数据
|
||
function getTrades() {
|
||
return _.flatMap(_tradeVues.map(x => x.datas)).map(x => x.trade);
|
||
}
|
||
|
||
//录入交易
|
||
function saveTrades() {
|
||
tradeSaver.saveTrades(_tradeVues.filter(x => x.isSelected));
|
||
}
|
||
|
||
//录入组合交易
|
||
function saveGroupTrades() {
|
||
tradeSaver.saveGroupTrades(_tradeVues.filter(x => x.isSelected));
|
||
}
|
||
|
||
//定价计算
|
||
function calcPrice(tradeVues) {
|
||
|
||
!tradeVues && (tradeVues = _tradeVues);
|
||
|
||
if (!tradeVues.length) {
|
||
return main.alert("请至少录入一个交易");
|
||
}
|
||
|
||
var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade);
|
||
|
||
//检查并转换数据
|
||
trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false);
|
||
|
||
if (trades) {
|
||
let data = {
|
||
version: pageVue.CalcVersion,
|
||
trades: trades, calcMargin: topVue.calcMargin,
|
||
calcAutocallGreeks: topVue.calcAutocallGreeks
|
||
};
|
||
main.post("/pricing/ajaxCalcPrices", data).done(function (resp) {
|
||
//tradeVues转换为calcId为key的字典
|
||
var map = tradeVues.reduce((result, cur) => {
|
||
_.each(cur.datas, x => {
|
||
result[x.trade.CalcId] = cur;
|
||
});
|
||
return result;
|
||
}, {});
|
||
//设置计算结果
|
||
_.each(resp.obj, item => {
|
||
map[item.CalcId].setCalcResult(item);
|
||
});
|
||
});
|
||
}
|
||
}
|
||
|
||
//显示组合到期收益曲线图形
|
||
function showPayoffLineChart(tradeVues) {
|
||
var selectVues = _.filter(_tradeVues, x => x.isSelected);
|
||
!tradeVues && (tradeVues = selectVues);
|
||
|
||
if (!tradeVues.length) {
|
||
return main.alert("请至少录入一个交易");
|
||
}
|
||
|
||
var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade);
|
||
|
||
//检查并转换数据
|
||
trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false);
|
||
|
||
window.sessionStorage.removeItem("pricing_payoff_line");
|
||
if (trades) {
|
||
main.post("/pricing/GetTradesPayoffLine", { trades: trades }).done(function (resp) {
|
||
//resp.obj
|
||
window.sessionStorage.setItem("pricing_payoff_line", JSON.stringify(resp));
|
||
window.open("/Statics/html/PayoffChart.html");
|
||
});
|
||
}
|
||
}
|
||
|
||
//显示组合Pv曲线
|
||
function showPvChart(tradeVues) {
|
||
var selectVues = _.filter(_tradeVues, x => x.isSelected);
|
||
!tradeVues && (tradeVues = selectVues);
|
||
|
||
if (!tradeVues.length) {
|
||
return main.alert("请至少录入一个交易");
|
||
}
|
||
|
||
var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade);
|
||
|
||
//检查并转换数据
|
||
trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false);
|
||
|
||
window.sessionStorage.removeItem("pricing_pv_line");
|
||
if (trades) {
|
||
main.post("/pricing/GetTradesPvLine", { trades: trades }).done(function (resp) {
|
||
//resp.obj
|
||
window.sessionStorage.setItem("pricing_pv_line", JSON.stringify(resp));
|
||
window.open("/Statics/html/PvChart.html");
|
||
});
|
||
}
|
||
}
|
||
|
||
function showLifeLineChart(tradeVues) {
|
||
var selectVues = _.filter(_tradeVues, x => x.isSelected);
|
||
!tradeVues && (tradeVues = selectVues);
|
||
|
||
if (!tradeVues.length) {
|
||
return main.alert("请至少选择一笔交易");
|
||
}
|
||
|
||
var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade);
|
||
|
||
//检查并转换数据
|
||
trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false);
|
||
|
||
window.sessionStorage.removeItem("pricing_life_lines");
|
||
if (trades) {
|
||
main.post("/pricing/GetTradesLifePvLine", { trades: trades }).done(function (resp) {
|
||
//resp.obj
|
||
window.sessionStorage.setItem("pricing_life_lines", JSON.stringify(resp));
|
||
window.open("/Statics/html/PvLifeChart.html");
|
||
});
|
||
}
|
||
}
|
||
|
||
//显示Greeks变化曲线
|
||
function showGreeksChart(tradeVues) {
|
||
var selectVues = _.filter(_tradeVues, x => x.isSelected);
|
||
!tradeVues && (tradeVues = selectVues);
|
||
|
||
if (!tradeVues.length) {
|
||
return main.alert("请至少选择一笔交易");
|
||
}
|
||
|
||
var trades = _.flatMap(tradeVues, x => x.datas).map(x => x.trade);
|
||
|
||
//检查并转换数据
|
||
trades = tradeUtils.prepareTrades(trades, pageVue.getVolType(), false);
|
||
|
||
window.sessionStorage.removeItem("pricing_greeks_line");
|
||
if (trades) {
|
||
main.post("/pricing/GetTradesGreeksForLifetime", { trades: trades }).done(function (resp) {
|
||
//resp.obj
|
||
window.sessionStorage.setItem("pricing_greeks_line", JSON.stringify(resp));
|
||
window.open("/Statics/html/GreeksChart.html");
|
||
});
|
||
}
|
||
}
|
||
|
||
//打开历史回测页面
|
||
function openHistoricalBacktest(tradeVues) {
|
||
layer.open({
|
||
type: 2, title: "报价管理-历史回测工具", shadeClose: false, shade: 0.4,
|
||
area: ['1200px', '560px'], content: "/pricing/HistoricalBacktest?isLayer=true"
|
||
});
|
||
}
|
||
|
||
//设置观察数据
|
||
function setObservation(observationNum, observationUnit, observationHolidayType, observationDates, alignEnd, calcId, couponDayInterval) {
|
||
if (!calcId) return;
|
||
|
||
let _data = null, calcId2 = calcId.replace(/#.*$/, "");
|
||
|
||
_.each(_tradeVues, vue => {
|
||
return !(_data = _.find(vue.datas, data => data.trade.CalcId === calcId2));
|
||
});
|
||
|
||
_data && consVueTrade.methods.setObservation.apply(_data, arguments);
|
||
}
|
||
|
||
//对冲下单
|
||
function hedgingOrder() {
|
||
var comVues = _.filter(_tradeVues, x => x.isSelected);
|
||
if (comVues.length < 1) {
|
||
return main.alert('请至少选择一项!');
|
||
}
|
||
var datas = _.flatMap(comVues.map(x => x.datas));
|
||
var instType = datas[0].trade.UnderlyingInstrumentType;
|
||
if (!_.every(datas, x => x.trade.UnderlyingInstrumentType === instType)) {
|
||
return main.alert('所选项标的类型必须一致!');
|
||
}
|
||
var rd = _.reduce(datas, (acc, cur) => {
|
||
var code = cur.trade.UnderlyingCode;
|
||
var delta = acc[code];
|
||
acc[code] = (delta || 0) + (parseFloat(cur.calcResult.Delta) || 0);
|
||
return acc;
|
||
}, {});
|
||
var items = _.reduce(rd, (acc, value, key) => {
|
||
var index = acc.length / 2;
|
||
acc.push('<input type="hidden" name="Items[' + index + '].UnderlyingCode" value="' + key + '" />');
|
||
acc.push('<input type="hidden" name="Items[' + index + '].DeltaInLots" value="' + value + '" />');
|
||
return acc;
|
||
}, []);
|
||
items.push('<input type="hidden" name="InstType" value="' + instType + '" />');
|
||
$('#orderForm').html(items.join("")).submit();
|
||
}
|
||
|
||
//浏览器本地数据缓存
|
||
const localData = (new function () {
|
||
if (pageVue.IsImport) {
|
||
this.save = $.noop;
|
||
this.load = $.noop;
|
||
return;
|
||
}
|
||
this.save = function () {
|
||
var vueDatas = _tradeVues.map(x => new Object({
|
||
index: x.index,
|
||
structureType: x.structureType,
|
||
datas: x.datas.map(data => new Object({ trade: data.trade, viewState: data.viewState }))
|
||
}));
|
||
var data = {
|
||
index: _index,
|
||
VolType: pageVue.getVolType(),
|
||
SysDate: pageVue.SysDate,
|
||
vueDatas: vueDatas,
|
||
time: new Date().getTime()
|
||
};
|
||
var json = JSON.stringify(data);
|
||
localStorage.setItem("pricing-structure-" + pageVue.UserId, json);
|
||
};
|
||
this.load = function () {
|
||
//设置默认值
|
||
var saveKey = "pricing-structure-" + pageVue.UserId;
|
||
var storage = localStorage.getItem(saveKey);
|
||
if (!storage) return;
|
||
var data = JSON.parse(storage);
|
||
if (pageVue.SysDate !== data.SysDate ||
|
||
new Date().getHours > 18 && new Date(data.time).getHours() < 18) {
|
||
//需要清空缓存
|
||
localStorage.removeItem(saveKey);
|
||
}
|
||
else {
|
||
_index = data.index;
|
||
pageVue.setVolType(data.VolType);
|
||
_.each(data.vueDatas, function (x) {
|
||
x.fromLocal = true;
|
||
var vue = createVue(x.index, x);
|
||
_tradeVues.push(vue);
|
||
});
|
||
}
|
||
};
|
||
}());
|
||
|
||
//持久化定价数据
|
||
$(window).on('beforeunload', localData.save);
|
||
$(localData.load);
|
||
|
||
return {
|
||
clear: clear,
|
||
remove: remove,
|
||
addTrade: addTrade,
|
||
copyItem: copyItem,
|
||
combine: combine,
|
||
changeVolType: changeVolType,
|
||
saveTrades: saveTrades,
|
||
saveGroupTrades: saveGroupTrades,
|
||
calcPrice: calcPrice,
|
||
showPayoffLineChart: showPayoffLineChart,
|
||
showPvChart: showPvChart,
|
||
showGreeksChart: showGreeksChart,
|
||
showLifeLineChart: showLifeLineChart,
|
||
openHistoricalBacktest: openHistoricalBacktest,
|
||
getTradeVues(onlySelected) {
|
||
return onlySelected ? _tradeVues.filter(x => x.isSelected) : _tradeVues;
|
||
},
|
||
getTradeVue(index) { return _tradeVues[index || 0]; },
|
||
saveLocalData: localData.save,
|
||
setOption: addTrades, //用于和老版兼容
|
||
setObservation: setObservation,
|
||
uncouple: uncouple,
|
||
hedgingOrder: hedgingOrder,
|
||
onMountd(vue) {
|
||
_tradeVues.length && $('#pricing-items').parent().floatingScroll();
|
||
},
|
||
swap(oldIndex, newIndex) {
|
||
if (oldIndex === newIndex) return;
|
||
let vue = _tradeVues[oldIndex];
|
||
_tradeVues.splice(oldIndex, 1);
|
||
_tradeVues.splice(newIndex, 0, vue);
|
||
},
|
||
//新增模板
|
||
addTemplate(tplItems) {
|
||
tplItems.forEach(x => {
|
||
x.datas.forEach(d => {
|
||
d.viewState = _.cloneDeep(tradeFieldMgr.defaultData.viewState);
|
||
d.viewState.initFlag = 'template';
|
||
});
|
||
_index += 1;
|
||
var vue = createVue(_index, x);
|
||
_tradeVues.unshift(vue);
|
||
});
|
||
}
|
||
};
|
||
}());
|
||
|
||
//浮窗定价组件
|
||
const floatVue = (function () {
|
||
var _tradeVue;
|
||
|
||
//关闭浮窗
|
||
function hide() {
|
||
if (_tradeVue) {
|
||
_tradeVue.remove();
|
||
_tradeVue = null;
|
||
}
|
||
$('#floatModal').modal('hide');
|
||
$(document.body).removeClass('has-float');
|
||
if (pageVue.IsImport) {
|
||
layer.closeMe();
|
||
}
|
||
}
|
||
|
||
//显示浮窗index, trade, viewState
|
||
function show(baseVue, forScreenshot) {
|
||
_tradeVue && _tradeVue.remove();
|
||
_tradeVue = createVue(baseVue.index, baseVue, true);
|
||
$(document.body).toggleClass('has-float', !forScreenshot);
|
||
$('#floatModal').modal('show');
|
||
}
|
||
|
||
function screenshot() {
|
||
screenshoter.execute(_tradeVue);
|
||
}
|
||
|
||
return {
|
||
show: show,
|
||
hide: hide,
|
||
calcPrice() {
|
||
_tradeVue && pricingVue.calcPrice([_tradeVue]);
|
||
},
|
||
saveTrade() {
|
||
_tradeVue && _tradeVue.saveTrade();
|
||
},
|
||
screenshot: screenshot,
|
||
getVue() { return _tradeVue; }
|
||
};
|
||
}());
|
||
|
||
//dom ready function
|
||
$(function () {
|
||
tradeSaver.init();
|
||
groupVue.init();
|
||
//解决上层popover不能编辑的问题
|
||
$('#floatModal').on('shown.bs.modal', function () {
|
||
$(document).off('focusin.modal');
|
||
});
|
||
$(".search-label").addClass("formlabel");
|
||
$(".formlabel").addClass("search-label");
|
||
var sortable = Sortable.create(document.getElementById('pricing-items'), {
|
||
handle: '.pricing-index-drag',
|
||
onEnd: function (evt) {
|
||
pricingVue.swap(evt.oldIndex, evt.newIndex);
|
||
},
|
||
});
|
||
if (pageVue.IsImport) {
|
||
let trade = _.cloneDeep(pageVue.Trade);
|
||
pricingVue.addTrade(trade);
|
||
setTimeout(function () {//交易详情页-定价增强价格不显示问题
|
||
if (trade.TradeType == "亚式期权" && trade.StrikeType != "Floating" && trade.PayoffType == 'EnhancedArithmeticAverage') {
|
||
$("#EnhancedPriceTitle").show();
|
||
}
|
||
}, 500);
|
||
}
|
||
//#OTC-2651
|
||
$('#floatModal>.modal-dialog>.modal-content>.modal-body').on('scroll',
|
||
_.debounce(function () { $(this).find('input.hasDatepicker').blur().datepicker('hide'); }, 500, { 'leading': true, 'trailing': false }));
|
||
});
|
||
|
||
//用于和老版兼容
|
||
window.vue = pricingVue;
|
||
|
||
//兼容定价计算页面观察日设置
|
||
var getObservationDatesSetting = pricingVue.setObservation;
|
||
|
||
//连离类型:障碍(Discrete),二元(MonitorType,美式)
|
||
//补偿类型:障碍(RebateType),二元(RebateType,美式)
|
||
|
||
//定价模板
|
||
var templateVue = (function () {
|
||
|
||
if (pageVue.IsImport) return;
|
||
|
||
var debounceSearch;
|
||
|
||
return new Vue({
|
||
el: '#modalTemplate',
|
||
data: {
|
||
saveMode: true,
|
||
saveData: {
|
||
name: '',
|
||
id: 0,
|
||
_override: true,
|
||
_CommonTemplate: false
|
||
},
|
||
listData: [],
|
||
searchText: ''
|
||
},
|
||
mounted() {
|
||
this.refreshList();
|
||
debounceSearch = _.debounce(this.searchInner, 500);
|
||
},
|
||
methods: {
|
||
showSave() {
|
||
let selVues = pricingVue.getTradeVues(true);
|
||
if (!selVues.length) {
|
||
return main.alert('请勾选要保存的定价数据');
|
||
}
|
||
this.saveMode = true;
|
||
this.saveData.name = '';
|
||
this.saveData.json = '';
|
||
$('#modalTemplate').modal('show');
|
||
},
|
||
showList() {
|
||
this.saveMode = false;
|
||
$('#modalTemplate').modal('show');
|
||
},
|
||
saveTemplate() {
|
||
let selVues = pricingVue.getTradeVues(true);
|
||
if (!selVues.length) {
|
||
return main.alert('没有可保存的定价数据');
|
||
}
|
||
let name = (this.saveData.name).trim();
|
||
if (!name) {
|
||
return main.alert('请填写模板名称');
|
||
}
|
||
let self = this;
|
||
let vueDatas = selVues.map(x => new Object({
|
||
structureType: x.structureType,
|
||
datas: x.datas.map(data => new Object({ trade: data.trade }))
|
||
}));
|
||
let dataJson = JSON.stringify(vueDatas);
|
||
main.post('/pricing/AjaxSaveTemplate/v2', { name, dataJson, _override: this.saveData._override, _CommonTemplate: this.saveData._CommonTemplate }).done(function () {
|
||
$('#modalTemplate').modal('hide');
|
||
self.refreshList();
|
||
self.searchInner();
|
||
});
|
||
},
|
||
removeTemplate(sysUserConfigId) {
|
||
let $item = $(event.target).closest('.yt-template-item');
|
||
if (!$item) {
|
||
return main.alert('系统错误,没有找到所选项');
|
||
}
|
||
let self = this;
|
||
let index = $item.prevAll().length;
|
||
let names = [$item.children('a').text()];
|
||
main.confirmPost('确认要删除所选项"' + names[0] + '"吗?', '/pricing/AjaxRemoveTemplate', { sysUserConfigId }).done(function () {
|
||
self.listData.splice(index, 1);
|
||
});
|
||
},
|
||
loadTemplate() {
|
||
let name = $(event.target).text();
|
||
let TemplateType = $(event.target).next().text();
|
||
function __do() {
|
||
pricingVue.clear(true);
|
||
main.post('/pricing/ajaxGetTemplate/v2', { name, TemplateType }).done(function (resp) {
|
||
let items = JSON.parse(resp.obj);
|
||
pricingVue.addTemplate(items);
|
||
$('#modalTemplate').modal('hide');
|
||
});
|
||
}
|
||
if (pricingVue.getTradeVues().length) {
|
||
main.confirm("加载自定义模板将清空页面现有交易,是否继续?", __do);
|
||
} else {
|
||
__do();
|
||
}
|
||
},
|
||
refreshList() {
|
||
let self = this;
|
||
this.searchText = '';
|
||
main.post('/pricing/AjaxGetTemplateList').done(function (resp) {
|
||
self.listData = resp.obj.map(x => new Object({ id: x.id, name: x.ConfigName, show: true, UserId: x.UserId, ConfigType: x.ConfigType }));
|
||
});
|
||
},
|
||
searchInner() {
|
||
console.log('searchInner');
|
||
let text = this.searchText ? this.searchText.toLowerCase() : '';
|
||
this.listData.forEach(x => {
|
||
x.show = !text || x.name.toLowerCase().indexOf(text) >= 0;
|
||
});
|
||
},
|
||
searchList(action) {
|
||
if (action === 'reset') {
|
||
debounceSearch.cancel();
|
||
this.searchText = '';
|
||
this.searchInner();
|
||
} else {
|
||
debounceSearch();
|
||
}
|
||
}
|
||
}
|
||
});
|
||
}());
|
||
|
||
const customNumberFormat = { precision: 6, negative: true, };
|
||
const customNumberPercentFormat = { precision: 6, negative: true, append: '%' };
|
||
|
||
var groupVue = new Vue({
|
||
el: '#modalGroupTradeSave',
|
||
data: {
|
||
viewState: pageVue.viewState,
|
||
...consVueTrade.data(),
|
||
trade: ylotc.trade,
|
||
options: ylotc.options,
|
||
structureTypes: pageObj.structureTypes,
|
||
PropertyMap: pageObj.PropertyMap,
|
||
},
|
||
computed: { ...consVueTrade.computed },
|
||
methods: {
|
||
...consVueTrade.methods,
|
||
closeModal: function () {
|
||
$('#modalGroupTradeSave').modal('hide');
|
||
$(".tag-context .tag-item").remove();
|
||
},
|
||
saveGroupTrade: function () {
|
||
if (!_trades) return;
|
||
_trades.forEach(x => {
|
||
x.AssetId = this.trade.AssetId;
|
||
x.AssetBookName = this.trade.AssetBookName;
|
||
x.TraderId = this.trade.TraderId;
|
||
x.TraderName = this.trade.TraderName;
|
||
x.TradeNumber = this.trade.TradeNumber;
|
||
x.SalesCommission = this.trade.salesCommission;
|
||
x.ClientId = this.trade.ClientId;
|
||
x.ClientName = this.trade.ClientName;
|
||
|
||
if (x.TradePremium) {
|
||
x.MetaDic["交易溢价"] = x.TradePremium;
|
||
}
|
||
x.MetaDic["交易场所"] = this.trade.TradingPlace;
|
||
x.MetaDic["清算机构"] = this.trade.ClearingAgency;
|
||
x.MetaDic["主协议编号"] = this.trade.MainProtocolCode;
|
||
x.MetaDic["补充协议编号"] = this.trade.SupProtocolCode;
|
||
|
||
x.MetaDic["中央对手方清算"] = $("#selIsCentralClearing").val();
|
||
x.MetaDic["中央清算平台"] = $("#selCentralClearingPaltform").val();
|
||
x.MetaDic["ExchangeRate"] = $("#selExchangeRate").val();
|
||
x.MetaDic["交易平台"] = $("#selTradingPaltform").val();
|
||
|
||
x.TradeType === '现金流交易' && tradeUtils.resetCashFlow(x);
|
||
});
|
||
this.trade.Tags = getSelectTags();
|
||
if (this.trade.StructureType == "气囊结构") {
|
||
this.trade.trade_airbag.KIParticipationRate = 1;
|
||
}
|
||
this.setExtendInfo();
|
||
main.post("/pricing/AjaxSaveGroupTrade", { trade: this.trade, subTrades: _trades }).done(function (resp) {
|
||
if (pageVue.IsImport) {
|
||
let url = "#/trade/tradeview?abstract=1&enid=" + resp.obj[0].EncryptId;
|
||
layer.closeMe(url);//必须以#开头
|
||
} else {
|
||
floatVue.hide();
|
||
$('#modalTradeSave').modal('hide');
|
||
_.each(_tradeVues, x => x.remove(true));
|
||
}
|
||
$(".tag-context .tag-item").remove();
|
||
});
|
||
},
|
||
addNewProperty: function () {
|
||
this.PropertyMap[this.trade.StructureType].push({ isNew: true, ColumnName: "", ColumnDefaultValue: "", ColumnType: 0 });//0:文本
|
||
},
|
||
deleteProperty: function (index) {
|
||
this.PropertyMap[this.trade.StructureType].splice(index, 1);
|
||
},
|
||
setExtendInfo: function () {
|
||
var propertyList = [];
|
||
this.PropertyMap[this.trade.StructureType].forEach((item, index) => {
|
||
var note = { name: item.name || item.ColumnName, value: PercentColumnText.displayText(item) };
|
||
if (note.name) {
|
||
propertyList.push(note);
|
||
}
|
||
});
|
||
this.trade.ExtendInfo = this.trade.StructureType == "气囊结构" ? null : JSON.stringify(propertyList);
|
||
return this.trade.ExtendInfo;
|
||
},
|
||
changeStrucTureType: function () {
|
||
if (groupVue.trade.TradeType == "气囊结构") {
|
||
groupVue.trade.trade_airbag.KIParticipationRate = 1;
|
||
}
|
||
else {
|
||
groupVue.trade.OptionType = null;
|
||
groupVue.trade.Strike = null;
|
||
}
|
||
},
|
||
changeBuySell: function () {
|
||
groupVue.trade.TradePrice *= -1;
|
||
groupVue.trade.TradeSinglePrice *= -1;
|
||
groupVue.trade.PremiumRate *= -1;
|
||
},
|
||
changeIsUsePremiumRate: function () {
|
||
if (groupVue.trade.IsUsePremiumRate) {
|
||
groupVue.changeStockEqvNotional();
|
||
}
|
||
else {
|
||
groupVue.changeTradeAmount();
|
||
}
|
||
},
|
||
changeStockEqvNotional: function () {
|
||
var notional = Math.abs(groupVue.trade.StockEqvNotional / groupVue.trade.SpotPrice);
|
||
groupVue.trade.Notional = pricingFormat.notional(notional);
|
||
groupVue.trade.TradeAmount = pricingFormat.notional(notional / groupVue.viewState.variety.CountRatio);
|
||
groupVue.trade.TradeSinglePrice = pricingFormat.tradeSinglePrice(groupVue.trade.TradePrice / groupVue.trade.Notional);
|
||
groupVue.trade.PremiumRate = pricingFormat.premiumRate(groupVue.trade.TradePrice / groupVue.trade.StockEqvNotional);
|
||
},
|
||
changeTradeAmount: function () {
|
||
var notional = groupVue.trade.TradeAmount * groupVue.viewState.variety.CountRatio;
|
||
groupVue.trade.Notional = pricingFormat.notional(notional);
|
||
groupVue.trade.StockEqvNotional = pricingFormat.stockEqvNotional(Math.abs(notional * groupVue.trade.SpotPrice));
|
||
groupVue.trade.TradeSinglePrice = pricingFormat.tradeSinglePrice(groupVue.trade.TradePrice / groupVue.trade.Notional);
|
||
groupVue.trade.PremiumRate = pricingFormat.premiumRate(groupVue.trade.TradePrice / groupVue.trade.StockEqvNotional);
|
||
},
|
||
init: function () {
|
||
_setAutocomplete('GroupAssetId', ylotc.assetunits, null, function (data) {
|
||
groupVue.trade.AssetId = data.id;
|
||
groupVue.trade.AssetBookName = data.Name;
|
||
});
|
||
var traders = $.grep(ylotc.traders, function (e) { return e.Name == pageVue.Trade.TraderName; });
|
||
let trader = pageVue.Trade.TraderId > 0 ? ylotc.traders.find(x => x.id === pageVue.Trade.TraderId) : null;
|
||
if (!trader) {
|
||
trader = { Name: "", id: 0 }
|
||
}
|
||
_setAutocomplete('GroupTraderId', ylotc.traders, { Name: trader.Name, id: trader.id }, function (data) {
|
||
groupVue.trade.TraderId = data.id;
|
||
groupVue.trade.TraderName = data.Name;
|
||
});
|
||
|
||
var groupClientInitData = null;
|
||
if (this.trade.ClientId > 0) {
|
||
groupClientInitData = { id: this.trade.ClientId, Name: "" };
|
||
var client = ylotc.clients.find(y => y.id === this.trade.ClientId);
|
||
groupClientInitData.Name = client.Name;
|
||
$("#selIsCentralClearing").val(client.IsCentralClearing);
|
||
$("#selCentralClearingPaltform").val(client.CentralClearingPaltform);
|
||
$("#selTradingPaltform").val(client.TradingPaltform);
|
||
}
|
||
_setAutocomplete('GroupClientId', ylotc.clients, groupClientInitData, function (data) {
|
||
pageVue.SecuritiesEnvironment ? _getMainProtocolCode : null;
|
||
groupVue.trade.ClientId = data.id;
|
||
groupVue.trade.ClientName = data.Name;
|
||
});
|
||
},
|
||
changeOption: function () {
|
||
this.PropertyMap[this.trade.StructureType].forEach(d => {
|
||
if (d.ColumnName != undefined) {
|
||
d.name = d.ColumnName;
|
||
}
|
||
if (d.ColumnDefaultValue != undefined) {
|
||
d.value = d.ColumnDefaultValue;
|
||
}
|
||
});
|
||
}
|
||
},
|
||
components: {
|
||
'vue-niceselect': FastVue.vueNiceSelect(),
|
||
'vue-client': vueClient(),
|
||
'vue-variety': vueVariety(),
|
||
'vue-margintemplatename': vueMarginTemplateName(),
|
||
'vue-tradetype': vueTradeType(),
|
||
'vue-underlying': vueUnderlying(),
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput(),
|
||
'vue-daycount': vueDayCount(),
|
||
},
|
||
});
|
||
|
||
var extendVue = new Vue({
|
||
el: "#tradeSave_ExtendInfo",
|
||
data: {
|
||
ExtendMap: pageObj.ExtendMap,
|
||
ExtendInfos: "",
|
||
},
|
||
methods: {
|
||
addNewProperty: function () {
|
||
var map = this.ExtendMap[this.ExtendInfos];
|
||
map.push({ isNew: true, ColumnName: "", ColumnDefaultValue: "", ColumnType: 0 });//0:文本
|
||
},
|
||
deleteProperty: function (index) {
|
||
var map = this.ExtendMap[this.ExtendInfos];
|
||
map.splice(index, 1);
|
||
},
|
||
changeOption: function (index) {
|
||
var map = this.ExtendMap[this.ExtendInfos];
|
||
map.forEach(d => {
|
||
if (d.ColumnName != undefined) {
|
||
d.name = d.ColumnName;
|
||
}
|
||
if (d.ColumnDefaultValue != undefined) {
|
||
d.value = d.ColumnDefaultValue;
|
||
}
|
||
});
|
||
},
|
||
setExtendInfo: function (trade) {
|
||
var propertyList = [];
|
||
var key = this.ExtendInfos;
|
||
if (key) {
|
||
var map = this.ExtendMap;
|
||
if (map[key]) {
|
||
map[key].forEach((item, index) => {
|
||
var note = { name: item.name || item.ColumnName, value: PercentColumnText.displayText(item) };
|
||
if (note.name) {
|
||
propertyList.push(note);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
trade.ExtendInfo = propertyList.length === 0 ? null : JSON.stringify(propertyList);
|
||
if (trade.ExtendInfo) {
|
||
trade.MetaDic["自定义要素模板"] = key;
|
||
} else {
|
||
trade.MetaDic["自定义要素模板"] = "";
|
||
}
|
||
return trade.ExtendInfo;
|
||
},
|
||
},
|
||
components: {
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput(),
|
||
}
|
||
});
|
||
|
||
var extendVue2 = new Vue({
|
||
el: "#tradeSave_ExtendInfo2",
|
||
data: {
|
||
ExtendMap: pageObj.ExtendMap,
|
||
ExtendInfos: "",
|
||
},
|
||
methods: {
|
||
addNewProperty: function () {
|
||
var map = this.ExtendMap[this.ExtendInfos];
|
||
map.push({ isNew: true, ColumnName: "", ColumnDefaultValue: "", ColumnType: 0 });//0:文本
|
||
},
|
||
deleteProperty: function (index) {
|
||
var map = this.ExtendMap[this.ExtendInfos];
|
||
map.splice(index, 1);
|
||
},
|
||
changeOption: function (index) {
|
||
var map = this.ExtendMap[this.ExtendInfos];
|
||
map.forEach(d => {
|
||
if (d.ColumnName != undefined) {
|
||
d.name = d.ColumnName;
|
||
}
|
||
if (d.ColumnDefaultValue != undefined) {
|
||
d.value = d.ColumnDefaultValue;
|
||
}
|
||
});
|
||
},
|
||
setExtendInfo: function (trade) {
|
||
var propertyList = [];
|
||
var key = this.ExtendInfos;
|
||
if (key) {
|
||
var map = this.ExtendMap;
|
||
if (map[key]) {
|
||
map[key].forEach((item, index) => {
|
||
var note = { name: item.name || item.ColumnName, value: PercentColumnText.displayText(item) };
|
||
if (note.name) {
|
||
propertyList.push(note);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
trade.ExtendInfo = propertyList.length === 0 ? null : JSON.stringify(propertyList);
|
||
if (trade.ExtendInfo) {
|
||
trade.MetaDic["自定义要素模板"] = key;
|
||
} else {
|
||
trade.MetaDic["自定义要素模板"] = "";
|
||
}
|
||
return trade.ExtendInfo;
|
||
},
|
||
},
|
||
components: {
|
||
'vue-datepicker': FastVue.vueDatePicker(),
|
||
'vue-number-input': FastVue.vueNumberInput(),
|
||
}
|
||
}); |