import { reactive, ref, computed } from 'vue'; import { queryErmcpTradePosition } from '@/services/go/ermcp/futures'; import { QueryErmcpTradePositionRsp } from '@/services/go/ermcp/futures/interface'; import { getQuoteDayInfoByCode } from "@/services/bus/goods"; import { BuyOrSell } from '@/common/constants/enumCommon'; import { getTaAccounts } from '@/services/go/TaAccount'; import { Taaccount } from "@/services/go/TaAccount/interface"; import { geLoginID_number } from '@/services/bus/login'; import { Systemparam } from '@/services/go/useInfo/interface'; import { getSelectedAccountId, setSelectedAccount } from '@/services/bus/account'; // 为了兼容以前代码,待优化后期废除 import { subcriteGoodsQuote } from '@/common/setup/table/tableQuote'; import { TradeAccount, TradePosition } from './interface' import APP from '@/services'; let stopSubcribe: () => void; // 加载状态 const loading = ref(false); // 资金账户列表 const tradeAccountList: TradeAccount[] = reactive([]); // 当前账户期货持仓列表 const tradePositionList: TradePosition[] = reactive([]); // 当前资金账户信息 const tradeAccount = ref(); /** * 资金账户 */ export function useTradeAccount() { // 获取资金账户列表 const getTradeAccountList = () => { if (!loading.value) { tradeAccountList.length = 0; loading.value = true; // 登录ID const loginID = Number(geLoginID_number()); getTaAccounts({ loginID }).then(async (res) => { for (let i = 0; i < res.length; i++) { const account = res[i]; const positionList: TradePosition[] = []; // 获取账户下的期货持仓列表 await queryErmcpTradePosition({ accountID: account.accountid }).then((res) => { res.forEach((item) => { positionList.push({ ...item, ...calcPositionValue(item), }) }) }) tradeAccountList.push({ positionList, ...account, ...calcCapitalValue(account, positionList), }) } tradeAccountChange(getSelectedAccountId()); loading.value = false; }) } } // 切换资金账户 const tradeAccountChange = (accountId: number) => { tradePositionList.length = 0; // 停止上次订阅 stopSubcribe && stopSubcribe(); const account = tradeAccountList.find((account) => account.accountid === accountId); if (account) { tradeAccount.value = account; tradePositionList.push(...account.positionList); setSelectedAccount(account); // 为了兼容以前代码,待优化后期废除 // 开始行情订阅 stopSubcribe = subcriteGoodsQuote(account.positionList.map((e) => e.goodscode)); } else { tradeAccount.value = undefined; } } // 期货账户列表 const futuresAccountList = computed(() => tradeAccountList.filter((account) => account.taaccounttype === 1)); return { loading, tradeAccountList, tradePositionList, tradeAccount, futuresAccountList, getTradeAccountList, tradeAccountChange, } } /** * 计算持仓数据 * @param position * @returns */ function calcPositionValue(position: QueryErmcpTradePositionRsp) { // 获取对应的商品行情 const quote = getQuoteDayInfoByCode(position.goodscode); // 计算开仓均价 const openAveragePrice = computed(() => { const { opencost, curpositionqty, agreeunit } = position // 开仓成本 ÷ 期末头寸 ÷ 合约单位 return opencost / curpositionqty / agreeunit; }) // 计算持仓均价 const positionAveragePrice = computed(() => { const { positioncost, curpositionqty, agreeunit } = position // 持仓成本 ÷ 期末头寸 ÷ 合约单位 return positioncost / curpositionqty / agreeunit; }) // 计算浮动盈亏 - 对应市场收益权 const positionProfitAndLoss = computed(() => { const { curpositionqty, agreeunit } = position if (quote?.last) { if (position.buyorsell === BuyOrSell.buy) { // 买方向 = (最新价 - 持仓均价) * 买期末头寸 * 合约单位 return (quote.last - openAveragePrice.value) * curpositionqty * agreeunit } else { // 卖方向 = (持仓均价 - 最新价) * 卖期末头寸 * 合约单位 return (positionAveragePrice.value - quote.last) * curpositionqty * agreeunit } } return position.positionpl }) // 计算市值 - 对应市场所有权 const capitalization = computed(() => { if (quote?.last) { // 市值 = 最新价 * 持仓数量 * 合约单位 return quote.last * position.curpositionqty * position.agreeunit } return 0 }) // 计算盈亏比例 const positionProfitAndLossRate = computed(() => { const { opencost } = position // 持仓盈亏 ÷ 开仓成本 const result = positionProfitAndLoss.value / opencost * 100 if (isNaN(result)) { return 0 } return result }) return { openAveragePrice, capitalization, positionAveragePrice, positionProfitAndLoss, positionProfitAndLossRate, } } /** * 计算资金数据 * @param account * @param positionList * @returns */ function calcCapitalValue(account: Taaccount, positionList: TradePosition[]) { // 系统参数 const systemParams = APP.get('systemParams'); // 计算总浮动盈亏 const positionProfitAndLoss = computed(() => positionList.reduce((res, item) => res + item.positionProfitAndLoss.value, 0)); // 计算总市值 const marketCap = computed(() => { // 根据系统参数“087 风险净值是否加上市值 - 0:不加 1:加“ const flag = systemParams.find((e) => e.paramcode === '087')?.paramvalue === '1'; if (flag) { return positionList.reduce((res, item) => res + item.capitalization.value, 0); } return 0; }); // 计算可用资金 const availableBalance = computed(() => { // *系统参数"113"(当日浮动盈利是否可用) 0:不可用 1:可用 const flag = systemParams.find((e) => e.paramcode === '113')?.paramvalue === '1'; const { currentbalance, usedmargin, freezemargin, freezecharge, otherfreezemargin, outamountfreeze } = account; const freeze = currentbalance - usedmargin - freezemargin - otherfreezemargin - freezecharge - outamountfreeze; if (positionProfitAndLoss.value < 0 || (positionProfitAndLoss.value >= 0 && flag)) { // 账户(总浮动盈亏为负) 或(总浮动盈亏为正 且 113 = 1) // 可用资金 = 总浮动盈亏 + 期末余额 - 占用 - 冻结 - 其它冻结 - 手续费冻结 - 出金冻结 return positionProfitAndLoss.value + freeze; } else { // 可用资金 = 期末余额 - 占用 - 冻结 - 其它冻结 - 手续费冻结 - 出金冻结 return freeze; } }); // 计算权益/净值 const equity = computed(() => { // 根据系统参数“307 账户净值是否减冻结资金 - 0:不减 1:减“ const flag = systemParams.find((e) => e.paramcode === '307')?.paramvalue === '1'; const result = account.currentbalance + marketCap.value + positionProfitAndLoss.value; if (flag) { const { otherfreezemargin, outamountfreeze } = account; // 净值 = 期末余额 + 市值(所有权) + 浮动盈亏(收益权) - 其它冻结 - 出金冻结 return result - otherfreezemargin - outamountfreeze; } else { // 净值 = 期末余额 + 市值(所有权) + 浮动盈亏(收益权) return result; } }) // 计算冻结资金 const freezeAmount = computed(() => { const { freezemargin, otherfreezemargin, outamountfreeze, freezecharge } = account; // 冻结资金 = 冻结保证金 + 手续费冻结 + 出金冻结 + 其他冻结保证金 return freezemargin + freezecharge + outamountfreeze + otherfreezemargin; }) // 计算风险净值 const valueAtRisk = computed(() => { // 根据系统参数“307 账户净值是否减冻结资金 - 0:不减 1:减“ const flag = systemParams.find((e) => e.paramcode === '087')?.paramvalue === '1'; const { otherfreezemargin, outamountfreeze } = account; const result = account.currentbalance + positionProfitAndLoss.value - otherfreezemargin - outamountfreeze; if (flag) { // 风险净值 = 期末余额 + 市值(所有权) + 浮动盈亏(收益权) - 其他冻结-出金冻结 return result + marketCap.value; } else { // 风险净值 = 期末余额 + 浮动盈亏(收益权) - 其他冻结 - 出金冻结 return result; } }) // 计算风险率 const hazardRatio = computed(() => { // 根据系统参数“132 风险率计算公式”: const flag = systemParams.find((e) => e.paramcode === '132')?.paramvalue === '1'; const { usedmargin, mortgagecredit } = account; let result = 0 if (flag) { // 风险率 = 占用 / 风险净值 result = usedmargin / valueAtRisk.value; } else { // 风险率 = (占用 - 授信金额) / (风险净值 - 授信金额) result = (usedmargin - mortgagecredit) / (valueAtRisk.value - mortgagecredit); } return isNaN(result) ? 0 : result; }) return { equity, positionProfitAndLoss, availableBalance, freezeAmount, hazardRatio, } }