- 估值日严格取互换起始日 StartDate,去掉"悄悄回退交易日(TradeDate)":
真的为空时返回错误提示("请先填写开始日…或手动填写三项数值")并 return,
不调用计算器、不覆盖手工输入,与需求(按开始日估值)完全一致。
- 抽纯函数 getBondStartDateMissingMsg(StartDate 空→文案/null) + 导出;
复用 D3 的 shouldShowBondErr 去重,避免空开始日时价格格逐键连刷。
- BondCalcHepler.cs 仅补 XML 注释说明前端已强制 StartDate 必填;
targetDate 空→代理默认 T+1 行为不变(兜底 RealtimePnlCalc 旧链路)。
- 补提此前漏提交的回归用例:bondCalc.test.js(×100/÷100 端到端 + 逐字段手动锁定)、
swapCalc.test.js(D1/D2/D3 + 本次估值日缺失守卫)。
- jest bondCalc+swapCalc 全绿(68 passed)。
364 lines
20 KiB
JavaScript
364 lines
20 KiB
JavaScript
/**
|
||
* swapCalc.js — 互换结算/平仓纯计算函数(与 C# FrontendCalcReference 对齐)
|
||
* ============================================================================
|
||
* 设计要点:
|
||
* - 无 Vue / otcformat / jQuery / lodash 依赖,全部为纯函数,便于 jest 直接 import。
|
||
* - 浏览器:挂到 window.SwapCalc(需在 incomeSwapTrade.js / swapTradeEdit.js 之前加载)。
|
||
* - Node: module.exports(UMD 包装),供 fe-tests/*.test.js 使用。
|
||
* - 公式与 YLErpDAL/Helpers/FrontendCalcReference.cs 保持一致,是前后端同一份金标准。
|
||
*
|
||
* 生产接线状态(tested == used):incomeSwapTrade.js / swapTradeEdit.js 已调用
|
||
* getPriceScale / deriveTradingAmountAvg / calcFloatPnlSum / calcStockEqvNotional
|
||
* 这 4 个叶子函数(对应真实出过的 4 个 bug:20ea93d8 / dcf649f2 / 3c5f25a5 / f873239a)。
|
||
* calcUnwind / calcIncome 仅用于 swapCalc.test.js 的前后端金标准交叉校验,未接入生产代码。
|
||
*
|
||
* 守卫的 bug(见 git 历史):
|
||
* - 20ea93d8 / dcf649f2:deriveTradingAmountAvg 必须用 PosiGrossPrice(全价) 且债券 ×100
|
||
* - 3c5f25a5:calcFloatPnlSum 必须 .toFixed(2)(保留 2 位小数)
|
||
* - f873239a:calcStockEqvNotional 必须 round 到 2 位
|
||
* ============================================================================
|
||
*/
|
||
(function (root, factory) {
|
||
if (typeof module === 'object' && module.exports) {
|
||
module.exports = factory();
|
||
} else {
|
||
root.SwapCalc = factory();
|
||
}
|
||
})(typeof self !== 'undefined' ? self : this, function () {
|
||
'use strict';
|
||
|
||
// 四舍五入(远离零),对齐 C# MidpointRounding.AwayFromZero
|
||
function roundHalfAwayFromZero(value, digits) {
|
||
var f = Math.pow(10, digits);
|
||
var n = Number(value) * f;
|
||
var sign = n < 0 ? -1 : 1;
|
||
var r = Math.round(Math.abs(n)) * sign;
|
||
var result = r / f;
|
||
return result === 0 ? 0 : result; // 消除 -0
|
||
}
|
||
|
||
// 价格缩放因子:债券(multiplier=100)界面为百分比态,计算用相对价需 ÷100
|
||
function getPriceScale(multiplier) {
|
||
return multiplier === 100 ? 0.01 : 1;
|
||
}
|
||
|
||
// 期末全价(界面态) = 期初全价(相对价) × multiplier
|
||
// 必须用 PosiGrossPrice(全价),非 PosiNetPrice(净价);债券 ×100 转界面百分比态
|
||
function deriveTradingAmountAvg(posiGrossPrice, multiplier) {
|
||
return posiGrossPrice * multiplier;
|
||
}
|
||
|
||
// 普通打开时以期初全价作为期末价默认值;审批打开时回显已提交的期末相对价。
|
||
function resolveIncomeTradingAmountAvg(posiGrossPrice, submittedTradingAmountAvg, multiplier, isUseApproval) {
|
||
var relativePrice = isUseApproval && submittedTradingAmountAvg !== undefined && submittedTradingAmountAvg !== null
|
||
? submittedTradingAmountAvg
|
||
: posiGrossPrice;
|
||
return relativePrice * multiplier;
|
||
}
|
||
|
||
// 金额四舍五入到指定小数位(避免 0.1+0.2 类浮点误差)
|
||
function roundMoney(value, digits) {
|
||
return roundHalfAwayFromZero(value, digits);
|
||
}
|
||
|
||
// 浮动盈亏合计 = (平仓盈亏 + 交易费用 + 待结算费用 + 分红).toFixed(2)
|
||
function calcFloatPnlSum(markClosePnl, tradingFee, tradingFeePending, dividendIn) {
|
||
var sum = (+markClosePnl) + (+tradingFee) + (+tradingFeePending) + (+dividendIn);
|
||
return roundHalfAwayFromZero(sum, 2);
|
||
}
|
||
|
||
// 名义本金 = 期初全价 × 因子,保留 2 位(EQD-6090)
|
||
// factor 在前端 = 数量 × 乘数(national)
|
||
function calcStockEqvNotional(posiGrossPrice, factor) {
|
||
return roundHalfAwayFromZero(posiGrossPrice * factor, 2);
|
||
}
|
||
|
||
// 平仓名义本金 = 平仓比例 × 剩余持仓名义本金(PosiNotionalValue)
|
||
// 多次部分平仓后必须用剩余本金 PosiNotionalValue,不能用原始 NotionalValue,否则偏大
|
||
function calcCloseNotionalByRemaining(closePercent, posiNotionalValue) {
|
||
return roundHalfAwayFromZero(Number(closePercent) * Number(posiNotionalValue), 2);
|
||
}
|
||
|
||
// 平仓比例 = 平仓名义本金 / 剩余持仓名义本金(PosiNotionalValue)
|
||
// 多次部分平仓后必须以剩余本金为分母,否则比例偏小,导致后端预付金返还本金计算错误
|
||
function calcClosePercentByRemaining(closeNotionalValue, posiNotionalValue) {
|
||
if (Number(posiNotionalValue) === 0) return 0;
|
||
return roundHalfAwayFromZero(Number(closeNotionalValue) / Number(posiNotionalValue), 6);
|
||
}
|
||
|
||
// 平仓数量(占期初口径 A):CloseQty = PositionQty × (closePercent / oriClosePercent)
|
||
// closePercent 是"占期初名义本金比例"(A),需先除以 oriClosePercent(=剩余/期初) 转成"占剩余比例"(B),
|
||
// 再乘以剩余持仓数量 PositionQty。
|
||
// 多次部分平仓后必须这样转换,否则全部↔部分切换时 ClosePercent 没变但 CloseQty 会变(不自洽)。
|
||
// 除零保护:oriClosePercent=0(剩余为0,已全部平完)时返回 0。
|
||
function calcCloseQtyByOriginalPercent(closePercent, oriClosePercent, positionQty) {
|
||
var ori = Number(oriClosePercent);
|
||
if (ori === 0) return 0;
|
||
return roundHalfAwayFromZero(Number(positionQty) * (Number(closePercent) / ori), 2);
|
||
}
|
||
|
||
// 平仓比例(占期初口径 A)= (CloseQty / PositionQty) × oriClosePercent
|
||
// CloseQty/PositionQty 得到"占剩余比例"(B),乘以 oriClosePercent(=剩余/期初) 转成"占期初比例"(A)。
|
||
// 除零保护:PositionQty=0 时返回 0。
|
||
function calcOriginalClosePercentByQty(closeQty, positionQty, oriClosePercent) {
|
||
var qty = Number(positionQty);
|
||
if (qty === 0) return 0;
|
||
return roundHalfAwayFromZero((Number(closeQty) / qty) * Number(oriClosePercent), 6);
|
||
}
|
||
|
||
// 盯市平仓盈亏(unwind):CloseQty × (期末全价×scale − 期初全价) × floatRatio × longRatio
|
||
// 对齐 FrontendCalcReference.CalcUnwind:先 ×10000 取整再 ÷10000,最后 toFixed(2)
|
||
// 干净输入下等价于直接 round(.., 2)
|
||
function calcMarkClosePnl(closeQty, tradingAmountAvg, scale, entryPrice, floatRatio, longRatio) {
|
||
var product = closeQty * (tradingAmountAvg * scale - entryPrice) * floatRatio * longRatio;
|
||
var step = Math.round(product * 10000) / 10000; // 对齐 C# Math.Round(.. * 10000) / 10000
|
||
return roundHalfAwayFromZero(step, 2);
|
||
}
|
||
|
||
// ---- 组合函数:对齐 C# FrontendCalcReference.CalcUnwind / CalcIncome ----
|
||
// 用途:作为「前端 JS 完整盈亏聚合公式」与「后端 C# 金标准」的交叉校验
|
||
// (见 swapCalc.test.js 的 FC_001~FC_008 八个冻结场景)。
|
||
// 注意:以下 calcUnwind / calcIncome **未接入生产代码**——生产 Vue 组件只调用上方
|
||
// 4 个叶子函数。它们是冻结完整聚合逻辑的参考规格;若要让生产聚合逻辑也被自动守卫,
|
||
// 需把 incomeSwapTrade.js / swapTradeEdit.js / unwindSwapTrade.js 的聚合计算也改调它们。
|
||
|
||
function parseOrZero(s) {
|
||
return (s === undefined || s === null || s === '') ? 0 : Number(s);
|
||
}
|
||
|
||
function sumLegs(legs) {
|
||
return (legs || []).reduce(function (acc, l) { return acc + parseOrZero(l.interestClosePnL); }, 0);
|
||
}
|
||
|
||
// 平仓页(unwind)盈亏汇总 — 对齐 FrontendCalcReference.CalcUnwind
|
||
function calcUnwind(input) {
|
||
var entryPrice = input.posiGrossPrice;
|
||
var scale = input.multiplier === 100 ? 0.01 : 1;
|
||
var floatRatio = input.payDirection === 1 ? 1 : -1;
|
||
var longRatio = input.positionType === 1 ? 1 : -1;
|
||
|
||
var tradingFee = parseOrZero(input.tradingFee);
|
||
var tradingFeePending = parseOrZero(input.tradingFeePending);
|
||
var dividendIn = parseOrZero(input.dividendIn);
|
||
|
||
var markClosePnl = calcMarkClosePnl(
|
||
input.closeQty, input.tradingAmountAvg, scale, entryPrice, floatRatio, longRatio);
|
||
markClosePnl = roundHalfAwayFromZero(markClosePnl, 2);
|
||
|
||
var floatPnlSum = roundHalfAwayFromZero(markClosePnl + tradingFee + tradingFeePending + dividendIn, 2);
|
||
|
||
var swapRealizedPnL = floatPnlSum + sumLegs(input.interestLegs) + sumLegs(input.marginLegs);
|
||
var swapCloseAmount = floatPnlSum + sumLegs(input.interestLegs) + sumLegs(input.marginLegs);
|
||
var swapMarginRebatePnl = sumLegs(input.marginLegs);
|
||
|
||
var ratio = input.positionType === 1 ? 1 : -1;
|
||
var tradingAmountFeeAvg = input.closeQty === 0 ? 0
|
||
: input.tradingAmountAvg * scale + (tradingFee / input.closeQty) * ratio;
|
||
|
||
return {
|
||
MarkClosePnl: roundHalfAwayFromZero(markClosePnl, 2),
|
||
FloatPnlSum: floatPnlSum,
|
||
SwapRealizedPnL: roundHalfAwayFromZero(swapRealizedPnL, 2),
|
||
SwapCloseAmount: roundHalfAwayFromZero(swapCloseAmount, 2),
|
||
SwapMarginRebatePnl: roundHalfAwayFromZero(swapMarginRebatePnl, 2),
|
||
TradingAmountFeeAvg: tradingAmountFeeAvg
|
||
};
|
||
}
|
||
|
||
// 结息页(income)盈亏汇总 — 对齐 FrontendCalcReference.CalcIncome
|
||
function calcIncome(input) {
|
||
var entryPrice = input.posiGrossPrice;
|
||
var scale = input.multiplier === 100 ? 0.01 : 1;
|
||
var floatRatio = input.payDirection === 1 ? 1 : -1;
|
||
|
||
var tradingFee = parseOrZero(input.tradingFee);
|
||
var tradingFeePending = parseOrZero(input.tradingFeePending);
|
||
var dividendIn = parseOrZero(input.dividendIn);
|
||
|
||
var contractSize = input.contractSize === undefined || input.contractSize === null
|
||
? 1 : Number(input.contractSize);
|
||
var markClosePnl = roundHalfAwayFromZero(
|
||
input.positionQty * contractSize * (input.tradingAmountAvg * scale - entryPrice) * floatRatio, 2);
|
||
|
||
var floatPnlSum = roundHalfAwayFromZero(markClosePnl + tradingFee + tradingFeePending + dividendIn, 2);
|
||
|
||
var swapRealizedPnL = floatPnlSum + sumLegs(input.interestLegs) + sumLegs(input.marginLegs);
|
||
var swapCloseAmount = floatPnlSum + sumLegs(input.interestLegs) + sumLegs(input.marginLegs);
|
||
var swapMarginRebatePnl = sumLegs(input.marginLegs);
|
||
|
||
var tradingAmountFeeAvg = input.closeQty > 0
|
||
? input.tradingAmountAvg * scale + (tradingFee / input.closeQty) * floatRatio
|
||
: input.tradingAmountAvg * scale;
|
||
|
||
return {
|
||
MarkClosePnl: markClosePnl,
|
||
FloatPnlSum: floatPnlSum,
|
||
SwapRealizedPnL: roundHalfAwayFromZero(swapRealizedPnL, 2),
|
||
SwapCloseAmount: roundHalfAwayFromZero(swapCloseAmount, 2),
|
||
SwapMarginRebatePnl: roundHalfAwayFromZero(swapMarginRebatePnl, 2),
|
||
TradingAmountFeeAvg: tradingAmountFeeAvg
|
||
};
|
||
}
|
||
|
||
/**
|
||
* 债券净价/全价/收益率三字段互算:回写时跳过"用户手填过的字段"(逐字段手动锁定,永不覆盖)。
|
||
* - manualSet: { CP:bool, DP:bool, YD:bool },标记哪些字段是用户本次会话中手动输入/修改过的
|
||
* - calc: { cleanPrice, dirtyPrice, ytm } 来自 /Bond/CalcBond 的 resp.obj
|
||
* - state: 持有三个字段的对象(直接原地写回)
|
||
* 设计(回应"计算结果不认可时如何优雅手动覆盖"):
|
||
* 用户每手填一个字段,该字段即被锁定;反算只填充"未手填"的字段,已手填的(含刚编辑的)一律不回写。
|
||
* 因此用户可逐个手填全部三个,互算绝不会冲掉其中任何一个。
|
||
* 纯函数,jest 可直接测(见 fe-tests/bondCalc.test.js)。
|
||
*/
|
||
function applyBondCalcResult(state, calc, manualSet) {
|
||
var EPS = 1e-4;
|
||
function write(field, type, value) {
|
||
if (manualSet && manualSet[type]) return; // 用户手填过的字段:绝不回写
|
||
if (value === undefined || value === null) return; // 计算器未返回该值则不覆盖
|
||
var cur = state[field];
|
||
if (typeof cur === 'number' && Math.abs(cur - value) < EPS) return; // 无变化不写,避免光标跳动
|
||
state[field] = value;
|
||
}
|
||
write('cleanPrice', 'CP', calc && calc.cleanPrice);
|
||
write('dirtyPrice', 'DP', calc && calc.dirtyPrice);
|
||
write('ytm', 'YD', calc && calc.ytm);
|
||
}
|
||
|
||
/**
|
||
* 债券价格【存储态小数 ↔ 展示态每百元百分比】边界换算。
|
||
* 约定(见 ConsGlobal.bondPriceMultiple=0.01 / bondShowPriceMultiple=100、BondPriceConverter):
|
||
* - 模型/DB 存【存储态小数】(如 0.995 = 99.5 元/百元面值);
|
||
* - 债券计算器(bond-calc,经 zszq-bond-oms 代理)要【展示态百分比】(如 99.5)。
|
||
* 历史坑:calcBondForItem 曾漏掉这正反两步,把存储态 0.995 当 99.5 发给计算器、
|
||
* 又把返回 97.82 原样落库;配合 vue-number-input 的 percent:true(显示再×100)
|
||
* 造成 -117.93 / 378543 离谱值。故发计算器前 bondPriceToCalc(×100)、回写前 bondCalcPriceToStorage(÷100)。
|
||
* 纯函数,jest 可直接测。
|
||
*/
|
||
function bondPriceToCalc(storagePrice) {
|
||
return Number(storagePrice) * 100; // 存储态小数 → 展示态每百元百分比
|
||
}
|
||
function bondCalcPriceToStorage(displayPrice) {
|
||
return Number(displayPrice) / 100; // 展示态百分比 → 存储态小数
|
||
}
|
||
/**
|
||
* 清空债券三字段互算的【手动/源】标志(纯函数,jest 可测)。
|
||
* 用途:切换标的(setUnderlyingCode)时调用,避免旧债券的手填状态(bondManual/bondDriverType)
|
||
* 污染新债券——否则旧债券标记过的字段在新债券上会被错误跳过 / 沿用旧态(D1 修复)。
|
||
* 直接对传入对象赋值;在 Vue 组件里该 item 已是响应式对象(首次交互已 $set 过 bondManual),
|
||
* 故重赋值能正常触发响应式更新;全新未交互过的标的清不清都无副作用。
|
||
*/
|
||
function clearBondCalcFlags(state) {
|
||
state.bondManual = { CP: false, DP: false, YD: false };
|
||
state.bondDriverType = null;
|
||
return state;
|
||
}
|
||
|
||
/**
|
||
* 从 /Bond/CalcBond 响应(resp.obj,即 CalBondResult)中提取应展示给用户的错误文案;
|
||
* 无错误返回 null(调用方据此决定是否回写、是否提示)。
|
||
* 覆盖:
|
||
* - 空响应(计算器无响应)
|
||
* - 业务错误码 errCode!=0(债券不存在 / 债券信息不全 / 参数非法)
|
||
* - 防御性值域校验(errCode=0 但数值离谱):即便计算器返回 success,
|
||
* 仍可能因【前端↔计算器的单位换算不匹配】或
|
||
* 行权收益率哨兵(-999999) 而给出负净价 / 收益率量级爆炸(如 378543) 之类的垃圾值。
|
||
* 现有 errCode 守卫拦不住这类"成功但离谱"的响应,故在此加值域闸门,
|
||
* 宁可不回写并提示用户,也绝不用垃圾值覆盖手工输入。
|
||
* 与 C# BondCalcHepler 的 errCode 守卫一一对应,确保"坏结果"不会静默回写覆盖手工输入。
|
||
* 纯函数,jest 可直接测(见 fe-tests/bondCalc.test.js)。
|
||
*/
|
||
function getBondCalcErrorMessage(resp) {
|
||
if (!resp) return "债券计算器无响应,已保留手工输入";
|
||
if (resp.errCode && resp.errCode !== 0) {
|
||
return resp.errMsg || "债券计算失败,请检查标的或参数";
|
||
}
|
||
// 防御性值域校验:拦截 errCode=0 但数值离谱的响应(部署环境主数据量纲错误 / 哨兵值)
|
||
var SENTINEL = -999999; // bond-calc 行权收益率不可用哨兵
|
||
var cp = resp.cleanPrice, dp = resp.dirtyPrice, yd = resp.ytm;
|
||
var absurd = function (v) {
|
||
return typeof v === 'number' && (v === SENTINEL || v === SENTINEL * 100);
|
||
};
|
||
if (absurd(cp) || absurd(dp) || absurd(yd)) {
|
||
return "债券计算返回哨兵值(部分指标不可用),已保留手工输入,请检查估值日/价格输入或联系管理员核对债券计算服务";
|
||
}
|
||
// 净价/全价:占面值百分比,正常约 20~300,绝不为负、也不会破千
|
||
if ((typeof cp === 'number' && (cp <= 0 || cp > 1000)) ||
|
||
(typeof dp === 'number' && (dp <= 0 || dp > 1000))) {
|
||
return "债券计算净价/全价超出合理范围(应为面值百分比且为正),已保留手工输入;" +
|
||
"请检查估值日/价格输入或联系管理员核对债券计算服务";
|
||
}
|
||
// 到期收益率:百分数口径(如 6.37 表示 6.37%),正常约 -5~30,|收益率|>100 视为爆炸
|
||
if (typeof yd === 'number' && Math.abs(yd) > 100) {
|
||
return "债券计算收益率量级异常(" + yd + "),已保留手工输入;" +
|
||
"请检查估值日/价格输入或联系管理员核对债券计算服务";
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* D2 修复(纯函数,jest 可测):重开(审批重开/刷新)一只【已保存且三字段齐全】的债券成交单时,
|
||
* 把三字段互算的手动标志一次性全置 true,使计算器在重开期间不再自动反算、覆盖当初保存的其他两个值。
|
||
* - 不设置 bondDriverType:重开时没有任何字段作为"计算源",calcBondForItem 会早返回(要求 driver 非空),
|
||
* 故纯展示保存值、零自动推导;用户点"重算"才清除标志并重新推导。
|
||
* - 用户若编辑其中某格:onBondPriceInput 会把它设为 driver 并重算,但因另两格仍是 manual=true,
|
||
* 不会被覆盖 → 满足"重开后手填覆盖跨会话 sticky、编辑不联动另两格"。
|
||
* 仅在加载路径对"债券且三值齐全"的标的调用,全新未填的债券不会被误锁。
|
||
*/
|
||
function markExistingBondManual(state) {
|
||
state.bondManual = { CP: true, DP: true, YD: true };
|
||
return state;
|
||
}
|
||
|
||
/**
|
||
* D3 修复(纯函数,jest 可测):债券计算器失败提示去重。
|
||
* 不可算的债券上用户逐键手填时,v-on:input 每次按键都触发一次失败计算并弹 toast,会连刷数条相同提示。
|
||
* 这里按"同一错误文案连续出现只提示一次"抑制噪声;错误文案变化(如 债券不存在→信息不全)则照常提示,
|
||
* 成功(传入 null/空)时清掉标记,便于下次真出不同错误时仍能提示。
|
||
* 纯做"是否该弹"的决策并维护 state._lastBondErr,不触碰任何计算逻辑,零风险。
|
||
*/
|
||
function shouldShowBondErr(state, err) {
|
||
if (!err) { state._lastBondErr = null; return false; } // 成功/无错误:清标记、不提示
|
||
if (state._lastBondErr === err) return false; // 连续相同错误 → 抑制重复 toast
|
||
state._lastBondErr = err;
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* 估值日(开始日)缺失校验(纯函数,jest 可测)。
|
||
* 需求:债券净价/全价/收益率以【互换起始日 StartDate】估值;开始日现已默认即有,
|
||
* 故不再"悄悄回退到交易日",而是真的为空时返回错误文案,由上层提示用户
|
||
* (并允许其手动填写三项数值,见需求2)。
|
||
* 返回 非空字符串=缺失需提示;返回 null=已具备估值日。
|
||
*/
|
||
function getBondStartDateMissingMsg(startDate) {
|
||
if (startDate) return null;
|
||
return "请先填写开始日(互换起始日,作为估值日)后再计算债券净价/全价/收益率;" +
|
||
"若暂不需要计算,可手动填写净价/全价/收益率三项数值";
|
||
}
|
||
|
||
return {
|
||
applyBondCalcResult: applyBondCalcResult,
|
||
getBondCalcErrorMessage: getBondCalcErrorMessage,
|
||
bondPriceToCalc: bondPriceToCalc,
|
||
bondCalcPriceToStorage: bondCalcPriceToStorage,
|
||
clearBondCalcFlags: clearBondCalcFlags,
|
||
markExistingBondManual: markExistingBondManual,
|
||
shouldShowBondErr: shouldShowBondErr,
|
||
getBondStartDateMissingMsg: getBondStartDateMissingMsg,
|
||
roundHalfAwayFromZero: roundHalfAwayFromZero,
|
||
getPriceScale: getPriceScale,
|
||
deriveTradingAmountAvg: deriveTradingAmountAvg,
|
||
resolveIncomeTradingAmountAvg: resolveIncomeTradingAmountAvg,
|
||
roundMoney: roundMoney,
|
||
calcFloatPnlSum: calcFloatPnlSum,
|
||
calcStockEqvNotional: calcStockEqvNotional,
|
||
calcCloseNotionalByRemaining: calcCloseNotionalByRemaining,
|
||
calcClosePercentByRemaining: calcClosePercentByRemaining,
|
||
calcCloseQtyByOriginalPercent: calcCloseQtyByOriginalPercent,
|
||
calcOriginalClosePercentByQty: calcOriginalClosePercentByQty,
|
||
calcMarkClosePnl: calcMarkClosePnl,
|
||
calcUnwind: calcUnwind,
|
||
calcIncome: calcIncome
|
||
};
|
||
});
|