import { reactive, computed, toRefs } from 'vue' import { handlePriceColor, round } from '@/filters' import { BuyOrSell } from '@/constants/order' import { queryTradePosition, querySBYJMyOrders } from '@/services/api/order' import { useGlobalStore } from './global' import { useFuturesStore } from './futures' import { defineStore } from '../store' import eventBus from '@/services/bus' import quoteSocket from '@/services/websocket/quote' /** * 持仓存储对象 */ export const usePositionStore = defineStore(() => { const globalStore = useGlobalStore() const futuresStore = useFuturesStore() const subscribe = quoteSocket.createSubscribe() const state = reactive({ loading: false, positionList: [], // 持仓汇总列表 }) // 获取持仓汇总列表 const getTradePosition = async () => { if (!state.loading) { subscribe.stop() try { state.loading = true const res = await queryTradePosition() state.positionList = res.data subscribe.start(...res.data.map((e) => e.goodscode)) } finally { state.loading = false } } } // 持仓汇总计算列表 const positionComputedList = computed(() => { const result: (Model.TradePositionRsp & { lastColor: string; // 最新价颜色 closepl: number; // 浮动盈亏 closeplColor: string; // 浮动盈亏颜色 marketValue: number; // 市值 })[] = [] state.positionList.forEach((item) => { const quote = futuresStore.getGoodsQuote(item.goodscode) const refQuote = futuresStore.getGoodsQuote(item.refgoodscode) const last = refQuote.value?.last || quote.value?.last || 0 // 有 refgoodscode 的优先取 refgoodscode 行情 const presettle = quote.value?.presettle || 0 const price = last || presettle // 没有最新价取昨结价 // 计算市值 = 现价 * 数量 * 合约单位 const marketValue = price ? price * item.curpositionqty * item.agreeunit : 0 const roundedMarketValue = round(marketValue, quote.value?.decimalplace) // 计算浮动盈亏 任务 #5600 #6013 const closepl = (price && globalStore.getSystemInfo('riskType') !== 1) ? (roundedMarketValue - item.curholderamount) * (item.buyorsell === BuyOrSell.Buy ? 1 : -1) : 0 const roundedClosepl = round(closepl, quote.value?.decimalplace) result.push({ ...item, lastprice: price, lastColor: handlePriceColor(price, presettle), closepl: roundedClosepl, closeplColor: handlePriceColor(roundedClosepl, 0), marketValue: roundedMarketValue, }) }) return result }) const getPositionListByTradeMode = (...tradeMode: number[]) => { return positionComputedList.value.filter((e) => tradeMode.includes(e.trademode)) } // 获取持仓数量 const getOrderQty = (buyOrSell: BuyOrSell, code?: string | number) => { const item = state.positionList.find((e) => (e.goodscode === code || e.goodsid === code) && e.buyorsell === buyOrSell) return item?.enableqty ?? 0 } // 接收头寸变化通知 const posChangedNtf = eventBus.$on('PosChangedNtf', () => getTradePosition()) // 接收登入请求数据 eventBus.$on('LoginNotify', () => { getTradePosition() }) // 接收登出通知清空数据 eventBus.$on('LogoutNotify', () => { state.positionList = [] }) return { ...toRefs(state), getTradePosition, getPositionListByTradeMode, getOrderQty, positionComputedList, posChangedNtf, subscribe } }) /** * 订单存储对象 */ export const useSBYJOrderStore = defineStore(() => { const futuresStore = useFuturesStore() const subscribe = quoteSocket.createSubscribe() const state = reactive({ loading: false, error: false, orderList: [], // 订单列表 }) const orderComputedList = computed(() => { state.orderList.forEach((e) => { e.tHDetailEx.depositRate = calcDepositRate(e) e.tHDetailEx.floatPL = calcFloatpl(e) }) // 任务 #5753 return state.orderList.filter((e) => e.tHDetailEx.holderQty > 0) }) // 计算浮动盈亏 const calcFloatpl = ({ tHDetailEx }: Model.SBYJMyOrderRsp) => { const quote = futuresStore.getGoodsQuote(tHDetailEx.goodsID) const { ask = 0, bid = 0, agreeunit = 0 } = quote.value ?? {} const price = tHDetailEx.buyOrSell === BuyOrSell.Buy ? bid : ask // 根据方向取买卖价 // 计算浮动盈亏 (价格 * 手数 * 合约乘数 - 持仓金额) * 方向标识 const float = price ? price * tHDetailEx.holderQty * agreeunit - tHDetailEx.holderAmount : 0 const result = float * (tHDetailEx.buyOrSell === BuyOrSell.Buy ? 1 : -1) return round(result, quote.value?.decimalplace) } // 计算定金率 const calcDepositRate = ({ tHDetailEx }: Model.SBYJMyOrderRsp) => { const quote = futuresStore.getGoodsQuote(tHDetailEx.goodsID) const { ask = 0, bid = 0, agreeunit = 0 } = quote.value ?? {} const price = tHDetailEx.buyOrSell === BuyOrSell.Buy ? bid : ask // 根据方向取买卖价 // 计算浮动盈亏 (价格 * 手数 * 合约乘数 - 持仓金额) * 方向标识 const float = price ? price * tHDetailEx.holderQty * agreeunit - tHDetailEx.holderAmount : 0 const floatpl = float * (tHDetailEx.buyOrSell === BuyOrSell.Buy ? 1 : -1) // 计算定金率 (已付定金 + 补充定金 +盈亏 - 已计滞纳金) / 已付定金 const depositRate = (tHDetailEx.payedDeposit + tHDetailEx.restockDeposit + floatpl - tHDetailEx.callAteFee) / tHDetailEx.payedDeposit return depositRate } // 获取订单列表 const getSBYJMyOrders = async () => { if (!state.loading) { subscribe.stop() try { state.error = false state.loading = true const res = await querySBYJMyOrders() state.orderList = res.data subscribe.start(...res.data.map((e) => e.goodsCode)) } catch { state.error = true } finally { state.loading = false } } } const getOrderListByGoodsId = (goodsId = 0) => { return orderComputedList.value.filter((e) => e.tHDetailEx.goodsID === goodsId) } // 接收委托单成交通知 const orderDealedNtf = eventBus.$on('OrderDealedNtf', () => getSBYJMyOrders()) // 接收登入请求数据 eventBus.$on('LoginNotify', () => { getSBYJMyOrders() }) // 接收登出通知清空数据 eventBus.$on('LogoutNotify', () => { state.orderList = [] }) return { ...toRefs(state), orderComputedList, getSBYJMyOrders, getOrderListByGoodsId, orderDealedNtf, subscribe } })