position.ts 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. import { reactive, computed, toRefs } from 'vue'
  2. import { handlePriceColor, round } from '@/filters'
  3. import { BuyOrSell } from '@/constants/order'
  4. import { queryTradePosition, querySBYJMyOrders } from '@/services/api/order'
  5. import { useGlobalStore } from './global'
  6. import { useFuturesStore } from './futures'
  7. import { defineStore } from '../store'
  8. import eventBus from '@/services/bus'
  9. import quoteSocket from '@/services/websocket/quote'
  10. /**
  11. * 持仓存储对象
  12. */
  13. export const usePositionStore = defineStore(() => {
  14. const globalStore = useGlobalStore()
  15. const futuresStore = useFuturesStore()
  16. const subscribe = quoteSocket.createSubscribe()
  17. const state = reactive({
  18. loading: false,
  19. positionList: <Model.TradePositionRsp[]>[], // 持仓汇总列表
  20. })
  21. // 获取持仓汇总列表
  22. const getTradePosition = async () => {
  23. if (!state.loading) {
  24. subscribe.stop()
  25. try {
  26. state.loading = true
  27. const res = await queryTradePosition()
  28. state.positionList = res.data
  29. subscribe.start(...res.data.map((e) => e.goodscode))
  30. } finally {
  31. state.loading = false
  32. }
  33. }
  34. }
  35. // 持仓汇总计算列表
  36. const positionComputedList = computed(() => {
  37. const result: (Model.TradePositionRsp & {
  38. lastColor: string; // 最新价颜色
  39. closepl: number; // 浮动盈亏
  40. closeplColor: string; // 浮动盈亏颜色
  41. marketValue: number; // 市值
  42. })[] = []
  43. state.positionList.forEach((item) => {
  44. const quote = futuresStore.getGoodsQuote(item.goodscode)
  45. const refQuote = futuresStore.getGoodsQuote(item.refgoodscode)
  46. const last = refQuote.value?.last || quote.value?.last || 0 // 有 refgoodscode 的优先取 refgoodscode 行情
  47. const presettle = quote.value?.presettle || 0
  48. const price = last || presettle // 没有最新价取昨结价
  49. // 计算市值 = 现价 * 数量 * 合约单位
  50. const marketValue = price ? price * item.curpositionqty * item.agreeunit : 0
  51. const roundedMarketValue = round(marketValue, quote.value?.decimalplace)
  52. // 计算浮动盈亏 任务 #5600 #6013
  53. const closepl = (price && globalStore.getSystemInfo('riskType') !== 1) ? (roundedMarketValue - item.curholderamount) * (item.buyorsell === BuyOrSell.Buy ? 1 : -1) : 0
  54. const roundedClosepl = round(closepl, quote.value?.decimalplace)
  55. result.push({
  56. ...item,
  57. lastprice: price,
  58. lastColor: handlePriceColor(price, presettle),
  59. closepl: roundedClosepl,
  60. closeplColor: handlePriceColor(roundedClosepl, 0),
  61. marketValue: roundedMarketValue,
  62. })
  63. })
  64. return result
  65. })
  66. const getPositionListByTradeMode = (...tradeMode: number[]) => {
  67. return positionComputedList.value.filter((e) => tradeMode.includes(e.trademode))
  68. }
  69. // 获取持仓数量
  70. const getOrderQty = (buyOrSell: BuyOrSell, code?: string | number) => {
  71. const item = state.positionList.find((e) => (e.goodscode === code || e.goodsid === code) && e.buyorsell === buyOrSell)
  72. return item?.enableqty ?? 0
  73. }
  74. // 接收头寸变化通知
  75. const posChangedNtf = eventBus.$on('PosChangedNtf', () => getTradePosition())
  76. // 接收登入请求数据
  77. eventBus.$on('LoginNotify', () => {
  78. getTradePosition()
  79. })
  80. // 接收登出通知清空数据
  81. eventBus.$on('LogoutNotify', () => {
  82. state.positionList = []
  83. })
  84. return {
  85. ...toRefs(state),
  86. getTradePosition,
  87. getPositionListByTradeMode,
  88. getOrderQty,
  89. positionComputedList,
  90. posChangedNtf,
  91. subscribe
  92. }
  93. })
  94. /**
  95. * 订单存储对象
  96. */
  97. export const useSBYJOrderStore = defineStore(() => {
  98. const futuresStore = useFuturesStore()
  99. const subscribe = quoteSocket.createSubscribe()
  100. const state = reactive({
  101. loading: false,
  102. error: false,
  103. orderList: <Model.SBYJMyOrderRsp[]>[], // 订单列表
  104. })
  105. const orderComputedList = computed(() => {
  106. state.orderList.forEach((e) => {
  107. e.tHDetailEx.depositRate = calcDepositRate(e)
  108. e.tHDetailEx.floatPL = calcFloatpl(e)
  109. })
  110. // 任务 #5753
  111. return state.orderList.filter((e) => e.tHDetailEx.holderQty > 0)
  112. })
  113. // 计算浮动盈亏
  114. const calcFloatpl = ({ tHDetailEx }: Model.SBYJMyOrderRsp) => {
  115. const quote = futuresStore.getGoodsQuote(tHDetailEx.goodsID)
  116. const { ask = 0, bid = 0, agreeunit = 0 } = quote.value ?? {}
  117. const price = tHDetailEx.buyOrSell === BuyOrSell.Buy ? bid : ask // 根据方向取买卖价
  118. // 计算浮动盈亏 (价格 * 手数 * 合约乘数 - 持仓金额) * 方向标识
  119. const float = price ? price * tHDetailEx.holderQty * agreeunit - tHDetailEx.holderAmount : 0
  120. const result = float * (tHDetailEx.buyOrSell === BuyOrSell.Buy ? 1 : -1)
  121. return round(result, quote.value?.decimalplace)
  122. }
  123. // 计算定金率
  124. const calcDepositRate = ({ tHDetailEx }: Model.SBYJMyOrderRsp) => {
  125. const quote = futuresStore.getGoodsQuote(tHDetailEx.goodsID)
  126. const { ask = 0, bid = 0, agreeunit = 0 } = quote.value ?? {}
  127. const price = tHDetailEx.buyOrSell === BuyOrSell.Buy ? bid : ask // 根据方向取买卖价
  128. // 计算浮动盈亏 (价格 * 手数 * 合约乘数 - 持仓金额) * 方向标识
  129. const float = price ? price * tHDetailEx.holderQty * agreeunit - tHDetailEx.holderAmount : 0
  130. const floatpl = float * (tHDetailEx.buyOrSell === BuyOrSell.Buy ? 1 : -1)
  131. // 计算定金率 (已付定金 + 补充定金 +盈亏 - 已计滞纳金) / 已付定金
  132. const depositRate = (tHDetailEx.payedDeposit + tHDetailEx.restockDeposit + floatpl - tHDetailEx.callAteFee) / tHDetailEx.payedDeposit
  133. return depositRate
  134. }
  135. // 获取订单列表
  136. const getSBYJMyOrders = async () => {
  137. if (!state.loading) {
  138. subscribe.stop()
  139. try {
  140. state.error = false
  141. state.loading = true
  142. const res = await querySBYJMyOrders()
  143. state.orderList = res.data
  144. subscribe.start(...res.data.map((e) => e.goodsCode))
  145. } catch {
  146. state.error = true
  147. } finally {
  148. state.loading = false
  149. }
  150. }
  151. }
  152. const getOrderListByGoodsId = (goodsId = 0) => {
  153. return orderComputedList.value.filter((e) => e.tHDetailEx.goodsID === goodsId)
  154. }
  155. // 接收委托单成交通知
  156. const orderDealedNtf = eventBus.$on('OrderDealedNtf', () => getSBYJMyOrders())
  157. // 接收登入请求数据
  158. eventBus.$on('LoginNotify', () => {
  159. getSBYJMyOrders()
  160. })
  161. // 接收登出通知清空数据
  162. eventBus.$on('LogoutNotify', () => {
  163. state.orderList = []
  164. })
  165. return {
  166. ...toRefs(state),
  167. orderComputedList,
  168. getSBYJMyOrders,
  169. getOrderListByGoodsId,
  170. orderDealedNtf,
  171. subscribe
  172. }
  173. })