index.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. import { ref, computed } 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 { quoteWatch } = 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. // 当前选中的数据项
  17. const selectedItem = computed(() => {
  18. let result: { [key: string]: number | string } = {
  19. open: '--',
  20. close: '--',
  21. highest: '--',
  22. lowest: '--',
  23. ma5: '--',
  24. ma10: '--',
  25. ma15: '--',
  26. macd: '--',
  27. dif: '--',
  28. dea: '--',
  29. vol: '--',
  30. k: '--',
  31. d: '--',
  32. j: '--',
  33. cci: '--'
  34. }
  35. if (dataIndex.value > -1 && dataset.candlestick.source.length > dataIndex.value) {
  36. const { open, close, highest, lowest, ma5, ma10, ma15 } = dataset.candlestick.source[dataIndex.value];
  37. const { macd, dif, dea } = dataset.macd.source[dataIndex.value];
  38. const { vol } = dataset.vol.source[dataIndex.value];
  39. const { k, d, j } = dataset.kdj.source[dataIndex.value];
  40. const { cci } = dataset.cci.source[dataIndex.value];
  41. result = { open, close, highest, lowest, ma5, ma10, ma15, macd, dif, dea, vol, k, d, j, cci }
  42. }
  43. return result;
  44. })
  45. /**
  46. * 初始化数据
  47. * @param cycletype 周期类型
  48. */
  49. const initData = (cycletype: ChartCycleType) => {
  50. if (goodscode) {
  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. * 获取周期毫秒数
  78. * @returns
  79. */
  80. const getCycleMilliseconds = () => {
  81. const milliseconds = 60 * 1000; // 一分钟毫秒数
  82. switch (options.cycleType) {
  83. case ChartCycleType.Minutes5: {
  84. return milliseconds * 5;
  85. }
  86. case ChartCycleType.Minutes30: {
  87. return milliseconds * 30;
  88. }
  89. case ChartCycleType.Minutes60: {
  90. return milliseconds * 60;
  91. }
  92. case ChartCycleType.Hours2: {
  93. return milliseconds * 2 * 60;
  94. }
  95. case ChartCycleType.Hours4: {
  96. return milliseconds * 4 * 60;
  97. }
  98. case ChartCycleType.Day: {
  99. return milliseconds * 24 * 60;
  100. }
  101. default: {
  102. return milliseconds;
  103. }
  104. }
  105. }
  106. /**
  107. * 格式化日期
  108. * @param value
  109. * @returns
  110. */
  111. const formatDate = (value: string) => {
  112. switch (options.cycleType) {
  113. case ChartCycleType.Day: {
  114. return moment(value).format('YYYY-MM-DD')
  115. }
  116. case ChartCycleType.Hours2:
  117. case ChartCycleType.Hours4: {
  118. return moment(value).format('YYYY-MM-DD HH:00:00')
  119. }
  120. default: {
  121. return moment(value).format('YYYY-MM-DD HH:mm:00')
  122. }
  123. }
  124. }
  125. /**
  126. * 更新图表数据
  127. */
  128. const updateChart = (quote: Partial<Model.QuoteDayRsp>) => {
  129. const { last, lasttime } = quote
  130. if (last && lasttime) {
  131. const { candlestick, macd, vol, kdj, cci } = dataset
  132. const lastIndex = candlestick.source.length - 1 // 历史数据最后索引位置
  133. const cycleMilliseconds = getCycleMilliseconds()
  134. const oldTime = lastIndex === -1 ? moment(lasttime) : moment(candlestick.source[lastIndex].date) // 历史行情最后时间
  135. const diffTime = moment(lasttime).valueOf() - oldTime.valueOf() // 计算时间差
  136. // if (diffTime > cycleMilliseconds * 2) {
  137. // // 时间间隔超过两个周期,重新请求历史数据,待优化
  138. // timerInterceptor.debounce(() => {
  139. // queryHistoryDatas({
  140. // data: {
  141. // cycleType: options.cycleType,
  142. // goodsCode: goodscode,
  143. // count: 1440,
  144. // }
  145. // }).then((res) => {
  146. // // 日期升序排序
  147. // const data = res.data.sort((a, b) => moment(a.ts).valueOf() - moment(b.ts).valueOf());
  148. // if (data.length) {
  149. // dataIndex.value = data.length - 1
  150. // clearData()
  151. // handleData(data, updateOptions)
  152. // }
  153. // })
  154. // }, 1000, 'updateChart')
  155. // } else {
  156. // 判断时间差是否大于周期时间
  157. if (lastIndex === -1 || diffTime > cycleMilliseconds) {
  158. const newtime = formatDate(lasttime)
  159. // 新增K线数据
  160. candlestick.source.push({
  161. date: newtime,
  162. open: last,
  163. close: last,
  164. lowest: last,
  165. highest: last,
  166. ma5: '-',
  167. ma10: '-',
  168. ma15: '-',
  169. })
  170. // 新增MACD数据
  171. macd.source.push({
  172. date: newtime,
  173. ema12: 0,
  174. ema26: 0,
  175. dif: 0,
  176. dea: 0,
  177. macd: 0,
  178. })
  179. // 新增VOL数据
  180. vol.source.push({
  181. date: newtime,
  182. vol: 0,
  183. })
  184. // 新增KDJ数据
  185. kdj.source.push({
  186. date: newtime,
  187. k: '-',
  188. d: '-',
  189. j: '-',
  190. })
  191. // 新增CCI数据
  192. cci.source.push({
  193. date: newtime,
  194. cci: '-',
  195. })
  196. } else {
  197. // 更新列表中最后一条记录的数据
  198. const record = candlestick.source[lastIndex]
  199. if (record.lowest > last) {
  200. record.lowest = last // 更新最低价
  201. }
  202. if (record.highest < last) {
  203. record.highest = last // 更新最高价
  204. }
  205. record.close = last // 更新收盘价
  206. }
  207. // 计算各项指标
  208. calcIndicator(lastIndex === -1 ? 0 : lastIndex)
  209. updateOptions()
  210. // }
  211. }
  212. }
  213. // 监听行情推送
  214. quoteWatch(goodscode, (val) => {
  215. if (!loading.value && !isEmpty.value) {
  216. updateChart(val)
  217. }
  218. })
  219. return {
  220. loading,
  221. isEmpty,
  222. dataIndex,
  223. options,
  224. selectedItem,
  225. initData,
  226. initOptions,
  227. }
  228. }