index.ts 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. import { ref, computed, watch } from 'vue'
  2. //import { timerInterceptor } from '@/utils/timer'
  3. import { ChartCycleType } from '@/constants/chart'
  4. import { queryHistoryDatas } from '@/services/api/quote'
  5. import { useFuturesStore } from '@/stores'
  6. import { useDataset } from './dataset'
  7. import { useOptions } from './options'
  8. import moment from 'moment'
  9. export function useCandlestickChart(goodscode: string) {
  10. const futuresStore = useFuturesStore()
  11. const { dataset, handleData, clearData, calcIndicator } = useDataset();
  12. const { options, initOptions, updateOptions } = useOptions(dataset);
  13. const loading = ref(false);
  14. const isEmpty = ref(true);
  15. const dataIndex = ref(-1); // 当前数据索引值
  16. const quote = futuresStore.getQuoteInfo(goodscode); // 实时行情
  17. // 当前选中的数据项
  18. const selectedItem = computed(() => {
  19. let result: { [key: string]: number | string } = {
  20. open: '--',
  21. close: '--',
  22. highest: '--',
  23. lowest: '--',
  24. ma5: '--',
  25. ma10: '--',
  26. ma15: '--',
  27. macd: '--',
  28. dif: '--',
  29. dea: '--',
  30. vol: '--',
  31. k: '--',
  32. d: '--',
  33. j: '--',
  34. cci: '--'
  35. }
  36. if (dataIndex.value > -1) {
  37. const { open, close, highest, lowest, ma5, ma10, ma15 } = dataset.candlestick.source[dataIndex.value];
  38. const { macd, dif, dea } = dataset.macd.source[dataIndex.value];
  39. const { vol } = dataset.vol.source[dataIndex.value];
  40. const { k, d, j } = dataset.kdj.source[dataIndex.value];
  41. const { cci } = dataset.cci.source[dataIndex.value];
  42. result = { open, close, highest, lowest, ma5, ma10, ma15, macd, dif, dea, vol, k, d, j, cci }
  43. }
  44. return result;
  45. })
  46. /**
  47. * 初始化数据
  48. * @param cycletype 周期类型
  49. */
  50. const initData = (cycletype: ChartCycleType) => {
  51. clearData();
  52. dataIndex.value = -1;
  53. options.cycleType = cycletype;
  54. loading.value = true;
  55. isEmpty.value = true;
  56. // 获取历史行情
  57. queryHistoryDatas({
  58. data: {
  59. cycleType: cycletype,
  60. goodsCode: goodscode,
  61. count: 1440,
  62. }
  63. }).then((res) => {
  64. // 日期升序排序
  65. const data = res.data.sort((a, b) => moment(a.ts).valueOf() - moment(b.ts).valueOf());
  66. if (data.length) {
  67. dataIndex.value = data.length - 1;
  68. isEmpty.value = false;
  69. handleData(data);
  70. }
  71. }).finally(() => {
  72. loading.value = false;
  73. })
  74. }
  75. /**
  76. * 获取周期毫秒数
  77. * @returns
  78. */
  79. const getCycleMilliseconds = () => {
  80. const milliseconds = 60 * 1000; // 一分钟毫秒数
  81. switch (options.cycleType) {
  82. case ChartCycleType.Minutes5: {
  83. return milliseconds * 5;
  84. }
  85. case ChartCycleType.Minutes30: {
  86. return milliseconds * 30;
  87. }
  88. case ChartCycleType.Minutes60: {
  89. return milliseconds * 60;
  90. }
  91. case ChartCycleType.Hours2: {
  92. return milliseconds * 2 * 60;
  93. }
  94. case ChartCycleType.Hours4: {
  95. return milliseconds * 4 * 60;
  96. }
  97. case ChartCycleType.Day: {
  98. return milliseconds * 24 * 60;
  99. }
  100. default: {
  101. return milliseconds;
  102. }
  103. }
  104. }
  105. /**
  106. * 更新图表数据
  107. */
  108. const updateChart = () => {
  109. if (quote.value) {
  110. const { last, lasttime } = quote.value;
  111. const { candlestick, macd, vol, kdj, cci } = dataset;
  112. const lastIndex = candlestick.source.length - 1; // 历史数据最后索引位置
  113. const cycleMilliseconds = getCycleMilliseconds();
  114. const oldTime = lastIndex === -1 ? moment(lasttime) : moment(candlestick.source[lastIndex].date); // 历史行情最后时间
  115. const diffTime = moment(lasttime).valueOf() - oldTime.valueOf(); // 计算时间差
  116. if (diffTime > cycleMilliseconds * 2) {
  117. // 时间间隔超过两个周期,重新请求历史数据
  118. //timerInterceptor.debounce(() => initData(cycleType.value), 1000, 'updateChart');
  119. } else {
  120. // 判断时间差是否大于周期时间
  121. if (lastIndex === -1 || diffTime > cycleMilliseconds) {
  122. oldTime.add(cycleMilliseconds, 'ms');
  123. const lastDate = oldTime.format('YYYY-MM-DD HH:mm:ss');
  124. // 新增K线数据
  125. candlestick.source.push({
  126. date: lastDate,
  127. open: last,
  128. close: last,
  129. lowest: last,
  130. highest: last,
  131. ma5: '-',
  132. ma10: '-',
  133. ma15: '-',
  134. })
  135. // 新增MACD数据
  136. macd.source.push({
  137. date: lastDate,
  138. ema12: 0,
  139. ema26: 0,
  140. dif: 0,
  141. dea: 0,
  142. macd: 0,
  143. })
  144. // 新增VOL数据
  145. vol.source.push({
  146. date: lastDate,
  147. vol: 0,
  148. })
  149. // 新增KDJ数据
  150. kdj.source.push({
  151. date: lastDate,
  152. k: '-',
  153. d: '-',
  154. j: '-',
  155. })
  156. // 新增CCI数据
  157. cci.source.push({
  158. date: lastDate,
  159. cci: '-',
  160. })
  161. } else {
  162. // 更新列表中最后一条记录的数据
  163. const record = candlestick.source[lastIndex];
  164. if (record.lowest > last) {
  165. record.lowest = last; // 更新最低价
  166. }
  167. if (record.highest < last) {
  168. record.highest = last; // 更新最高价
  169. }
  170. record.close = last; // 更新收盘价
  171. }
  172. // 计算各项指标
  173. calcIndicator(lastIndex === -1 ? 0 : lastIndex);
  174. updateOptions();
  175. }
  176. }
  177. }
  178. // 监听行情推送
  179. watch(() => quote.value?.last, () => {
  180. if (!loading.value && !isEmpty.value) {
  181. updateChart();
  182. }
  183. })
  184. return {
  185. loading,
  186. isEmpty,
  187. dataIndex,
  188. options,
  189. selectedItem,
  190. initData,
  191. initOptions,
  192. }
  193. }