@next.ts 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import { reactive, toRefs, computed } from 'vue'
  2. import { queryHistoryDatas } from '@/services/api/quote'
  3. import { ChartCycleType } from '@/constants/chart'
  4. import { echarts, ECOption } from '@/components/base/echarts/core'
  5. import { useFuturesStore } from '@/stores'
  6. import { useDataset } from '@/hooks/echarts/candlestick/dataset'
  7. import moment from 'moment'
  8. export function useCandlestick(goodsCode: string) {
  9. const { dataset, handleData, clearData } = useDataset()
  10. const { quoteWatch } = useFuturesStore()
  11. const state = reactive({
  12. loading: false,
  13. dataIndex: -1,
  14. cycleType: ChartCycleType.Minutes
  15. })
  16. // 当前选中的数据项
  17. const selectedItem = computed(() => {
  18. if (state.dataIndex > -1 && dataset.candlestick.source.length > state.dataIndex) {
  19. const { open, close, highest, lowest, ma5, ma10, ma15 } = dataset.candlestick.source[state.dataIndex]
  20. const { macd, dif, dea } = dataset.macd.source[state.dataIndex]
  21. const { vol } = dataset.vol.source[state.dataIndex]
  22. const { k, d, j } = dataset.kdj.source[state.dataIndex]
  23. const { cci } = dataset.cci.source[state.dataIndex]
  24. return { open, close, highest, lowest, ma5, ma10, ma15, macd, dif, dea, vol, k, d, j, cci }
  25. } else {
  26. return { open: '--', close: '--', highest: '--', lowest: '--', ma5: '--', ma10: '--', ma15: '--', macd: '--', dif: '--', dea: '--', vol: '--', k: '--', d: '--', j: '--', cci: '--' }
  27. }
  28. })
  29. // 获取历史行情
  30. const getHistoryData = async () => {
  31. try {
  32. clearData()
  33. state.dataIndex = -1
  34. state.loading = true
  35. const res = await queryHistoryDatas({
  36. data: {
  37. goodsCode,
  38. cycleType: state.cycleType,
  39. count: 1440,
  40. }
  41. })
  42. // 日期升序排序
  43. const data = res.data.sort((a, b) => moment(a.ts).valueOf() - moment(b.ts).valueOf())
  44. state.dataIndex = data.length - 1
  45. handleData(data)
  46. } finally {
  47. state.loading = false
  48. }
  49. }
  50. let chartInstance: echarts.ECharts
  51. let asyncHistoryData = getHistoryData()
  52. const createCandlestick = (chart: echarts.ECharts) => {
  53. chartInstance = chart
  54. asyncHistoryData.then(() => {
  55. const { source, dimensions } = dataset.candlestick
  56. const opt: ECOption = {
  57. grid: [
  58. {
  59. top: '0',
  60. height: "70%"
  61. },
  62. {
  63. top: '70%',
  64. height: "18%"
  65. }
  66. ],
  67. xAxis: [
  68. {
  69. type: 'category',
  70. axisLabel: {
  71. formatter: (val: string) => {
  72. if (val) {
  73. switch (state.cycleType) {
  74. case ChartCycleType.Day: {
  75. return moment(val).format('YYYY-MM-DD')
  76. }
  77. default: {
  78. return moment(val).format('HH:mm')
  79. }
  80. }
  81. }
  82. return ''
  83. }
  84. }
  85. },
  86. {
  87. type: 'category',
  88. gridIndex: 1
  89. }
  90. ],
  91. yAxis: [
  92. {
  93. type: 'value',
  94. scale: true,
  95. },
  96. {
  97. type: 'value',
  98. scale: true,
  99. gridIndex: 1
  100. }
  101. ],
  102. dataZoom: {
  103. type: 'inside',
  104. startValue: source.length - 60, // 起始显示K线条数(最新60条)
  105. end: 100,
  106. minValueSpan: 30, // 限制窗口缩放显示最少数据条数
  107. maxValueSpan: 200, // 限制窗口缩放显示最大数据条数
  108. xAxisIndex: [0, 1]
  109. },
  110. dataset: {
  111. dimensions,
  112. source,
  113. },
  114. series: [
  115. {
  116. name: 'KLine',
  117. type: 'candlestick'
  118. },
  119. {
  120. name: 'MACD',
  121. type: 'bar',
  122. xAxisIndex: 1,
  123. yAxisIndex: 1,
  124. }
  125. ]
  126. }
  127. chart.setOption(opt)
  128. })
  129. }
  130. const initChart = (cycleType: ChartCycleType) => {
  131. state.cycleType = cycleType
  132. asyncHistoryData = getHistoryData()
  133. }
  134. /**
  135. * 格式化日期
  136. * @param value
  137. * @returns
  138. */
  139. const formatDate = (value: string) => {
  140. switch (state.cycleType) {
  141. case ChartCycleType.Day: {
  142. return moment(value).format('YYYY-MM-DD')
  143. }
  144. case ChartCycleType.Hours2:
  145. case ChartCycleType.Hours4: {
  146. return moment(value).format('YYYY-MM-DD HH:00:00')
  147. }
  148. default: {
  149. return moment(value).format('YYYY-MM-DD HH:mm:00')
  150. }
  151. }
  152. }
  153. quoteWatch(goodsCode, (q) => {
  154. if (chartInstance) {
  155. asyncHistoryData.then(() => {
  156. const { last, lasttime } = q
  157. if (last && lasttime) {
  158. const { candlestick, macd, vol, kdj, cci } = dataset
  159. const lastIndex = candlestick.source.length - 1 // 历史数据最后索引位置
  160. const oldTime = lastIndex === -1 ? moment(lasttime) : moment(candlestick.source[lastIndex].date) // 历史行情最后时间
  161. const diffTime = moment(lasttime).valueOf() - oldTime.valueOf() // 计算时间差
  162. // 判断时间差是否大于周期时间
  163. if (lastIndex === -1 || diffTime > 60 * 1000) {
  164. const newtime = formatDate(lasttime)
  165. // 新增K线数据
  166. candlestick.source.push({
  167. date: newtime,
  168. open: last,
  169. close: last,
  170. lowest: last,
  171. highest: last,
  172. ma5: '-',
  173. ma10: '-',
  174. ma15: '-',
  175. })
  176. // 新增MACD数据
  177. macd.source.push({
  178. date: newtime,
  179. ema12: 0,
  180. ema26: 0,
  181. dif: 0,
  182. dea: 0,
  183. macd: 0,
  184. })
  185. // 新增VOL数据
  186. vol.source.push({
  187. date: newtime,
  188. vol: 0,
  189. })
  190. // 新增KDJ数据
  191. kdj.source.push({
  192. date: newtime,
  193. k: '-',
  194. d: '-',
  195. j: '-',
  196. })
  197. // 新增CCI数据
  198. cci.source.push({
  199. date: newtime,
  200. cci: '-',
  201. })
  202. } else {
  203. // 更新列表中最后一条记录的数据
  204. const record = candlestick.source[lastIndex]
  205. if (record.lowest > last) {
  206. record.lowest = last // 更新最低价
  207. }
  208. if (record.highest < last) {
  209. record.highest = last // 更新最高价
  210. }
  211. record.close = last // 更新收盘价
  212. }
  213. // chartInstance.setOption({
  214. // dataset: {
  215. // source: candlestick.source
  216. // }
  217. // })
  218. }
  219. })
  220. }
  221. })
  222. return {
  223. ...toRefs(state),
  224. selectedItem,
  225. createCandlestick,
  226. initChart
  227. }
  228. }