st-comp 0.0.13 → 0.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/auto-imports.d.ts +1 -1
  2. package/components.d.ts +2 -1
  3. package/lib/bundle.js +10145 -9151
  4. package/lib/bundle.umd.cjs +10 -12
  5. package/lib/style.css +1 -1
  6. package/lib/talib.wasm +0 -0
  7. package/package.json +4 -1
  8. package/packages/Kline/components/Contextmenu/index.vue +110 -0
  9. package/packages/Kline/components/Tips/index.vue +18 -86
  10. package/packages/Kline/formatKlineData.ts +67 -40
  11. package/packages/Kline/images/buy.svg +1 -0
  12. package/packages/Kline/images/pen.png +0 -0
  13. package/packages/Kline/images/sell.svg +1 -0
  14. package/packages/Kline/images/t.svg +1 -0
  15. package/packages/Kline/index.vue +439 -119
  16. package/packages/Kline/option.ts +316 -0
  17. package/packages/Kline/type.d.ts +192 -24
  18. package/packages/Kline/utils.ts +576 -171
  19. package/packages/Table/components/Button/index.vue +7 -0
  20. package/packages/Table/index.vue +37 -24
  21. package/packages/index.ts +0 -2
  22. package/public/talib.wasm +0 -0
  23. package/src/pages/ChartLayout/index.vue +22 -22
  24. package/src/pages/Kline/api.ts +57 -0
  25. package/src/pages/Kline/components/MultiCycleSingleVariety.vue +728 -0
  26. package/src/pages/Kline/components/SingleCycleSingleVariety.vue +663 -0
  27. package/src/pages/Kline/index.vue +85 -16
  28. package/src/router/routes.ts +0 -5
  29. package/src/style.css +75 -0
  30. package/vite.config.ts +37 -27
  31. package/vitePlugins/testRelese.ts +67 -0
  32. package/packages/Echarts/index.ts +0 -8
  33. package/packages/Echarts/index.vue +0 -113
  34. package/packages/Kline/kline_theme_dark.json +0 -30
  35. package/packages/Kline/kline_theme_light.json +0 -30
  36. package/src/components/Echarts/index.vue +0 -31
  37. package/src/pages/Echarts/index.vue +0 -12
@@ -1,54 +1,23 @@
1
- import axios from 'axios'
2
- import dayjs from 'dayjs'
3
- import type { KlineDataItem, InOption } from './type.d.ts'
1
+ import type { EChartsType, ElementEvent } from 'echarts'
2
+ import type {
3
+ KlineDataType,
4
+ WarningConfigType,
5
+ PositionConfigType,
6
+ ConditionConfigType,
7
+ GraphicEvent,
8
+ } from './type.d.ts'
4
9
 
5
- /**
6
- * @description: 获取K线数据
7
- * @param {string} code 品种代码
8
- * @param {number} bar_count 请求数据条数
9
- * @param {string} tradeDate 交易日期
10
- * @param {string} frequency 周期
11
- * @return {*}
12
- */
13
- export const getKline = async (
14
- code: string,
15
- bar_count: number,
16
- tradeDate: string,
17
- frequency: string
18
- ) => {
19
- let dt: null | string = dayjs(tradeDate).format('YYYY-MM-DD HH:mm:ss')
20
- return axios(
21
- `http://116.62.161.92:8005/history_kline?code=${code}&bar_count=${bar_count}&dt=${dt}&frequency=${frequency}`
22
- )
23
- }
24
-
25
- /**
26
- * @description: 获取指标线下拉列表类型数据以及相关样式配置
27
- * @return {*}
28
- */
29
- export const getIndicatorConfigList = () => {
30
- return axios('http://116.62.161.92:8005/get_indicator')
31
- }
10
+ // ------------------普通工具函数---------------------
32
11
 
33
12
  /**
34
- * @description: 获取指标线具体数据
35
- * @param {string} code 品种代码
36
- * @param {string} start_date 开始日期
37
- * @param {string} end_date 结束日期
38
- * @param {string} frequency 周期
39
- * @param {string} indicator 指标类型
40
- * @return {*}
13
+ * @description: console方法封装
14
+ * @param {String} message 消息文本
15
+ * @param {Object} option 配置选项
41
16
  */
42
- export const getIndicator = (
43
- code: string,
44
- start_date: string,
45
- end_date: string,
46
- frequency: string,
47
- indicator: string
48
- ) => {
49
- return axios(
50
- `http://116.62.161.92:8005/realtime_indicator?code=${code}&start_date=${start_date}&end_date=${end_date}&indicator=${indicator}&frequency=${frequency}`
51
- )
17
+ export const printConsole = (message: string, option?: { type?: string; color?: string }) => {
18
+ const { type = 'log', color = 'black' } = option ?? {}
19
+ let isShow = localStorage.getItem('st-kline-console-show') === 'true' ? true : false
20
+ isShow && console[type](`%c${message}`, `color:${color}`)
52
21
  }
53
22
 
54
23
  /**
@@ -77,153 +46,589 @@ export const formatPrice = (value: number) => {
77
46
  }
78
47
  }
79
48
 
80
- /**
81
- * @description: 格式化K线图配置项
82
- * @param {InOption} data
83
- * @return {*}
84
- */
85
- export const getOption = async (data: InOption) => {
86
- const { kLineData, indicatorData, indicator, indicatorConfigList, defaultShowBarCount } = data
87
- // 处理k线数据,x轴数据
88
- const candlestickData: any[] = [] // k线数据
89
- const xAxisData: number[] = [] // x轴数据
90
- const kLineLength = kLineData.length // k线条数
91
-
92
- kLineData.forEach((item: KlineDataItem) => {
93
- candlestickData.push([
94
- formatValue(item[1]),
95
- formatValue(item[4]),
96
- formatValue(item[3]),
97
- formatValue(item[2]),
98
- ])
99
- xAxisData.push(item[0])
100
- })
101
-
102
- // 处理指标线数据
103
- const indicatorInfo = indicatorConfigList[indicator]
104
- const lineSeries = indicatorData
105
- ? Object.keys(indicatorData[0])
106
- .filter(i => i !== 'datetime')
107
- .map((key: string) => {
108
- let color = 'rgba(238, 238, 238, 0.5)'
109
- if (indicatorInfo && indicatorInfo[key]) {
110
- color = `#${indicatorInfo[key].split('#')[1]}`
111
- }
112
- return {
113
- name: key,
114
- type: 'line',
115
- symbol: 'none',
116
- data: indicatorData.map(i => i[key]),
117
- lineStyle: {
118
- width: 1,
119
- },
120
- itemStyle: {
121
- color,
122
- },
123
- }
124
- })
125
- : []
49
+ // -----------------额外画线工具函数-------------------
50
+ interface InfoType {
51
+ info: any
52
+ config: WarningConfigType | PositionConfigType | ConditionConfigType
53
+ event: GraphicEvent
54
+ }
55
+
56
+ // 单条线的配置-预警线
57
+ interface warningParamsType {
58
+ y: number
59
+ text: string
60
+ info: InfoType
61
+ gridLeft: number
62
+ gridRight: number
63
+ echartsWidth: number
64
+ echartsInstance: EChartsType
65
+ }
66
+ export const getWarningItem = (params: warningParamsType) => {
67
+ // 1.解构入参
68
+ const { y, text, info, gridLeft, gridRight, echartsWidth, echartsInstance } = params
69
+ const { config, event } = info
126
70
 
71
+ let dragStart = 0 // 拖拽开始坐标
72
+
73
+ // -----------------------------------return-------------------------------------------
127
74
  return {
128
- dataset: {
129
- id: 'data',
130
- source: {
131
- kLineData,
75
+ type: 'group',
76
+ draggable: config.draggable ? 'vertical' : false,
77
+ children: [
78
+ {
79
+ type: 'line',
80
+ info,
81
+ shape: {
82
+ x1: gridLeft,
83
+ y1: y,
84
+ x2: echartsWidth - gridRight,
85
+ y2: y,
86
+ },
87
+ style: {
88
+ stroke: config.lineColor,
89
+ lineWidth: 1,
90
+ lineDash: [8, 4],
91
+ },
92
+ z: 10,
132
93
  },
133
- },
134
- grid: {
135
- left: '50px',
136
- top: '50px',
137
- right: '30px',
138
- bottom: '30px',
139
- },
140
- tooltip: {
141
- trigger: 'axis',
142
- showContent: false,
143
- axisPointer: {
144
- type: 'cross',
145
- label: {
146
- formatter: (data: any) => {
147
- const { axisDimension, value } = data
148
- if (axisDimension === 'x') {
149
- return dayjs(new Date(value * 1000)).format('YYYY-MM-DD HH:mm')
150
- } else {
151
- return String(formatValue(value))
152
- }
94
+ {
95
+ type: 'group',
96
+ x: echartsWidth,
97
+ y: y - 5,
98
+ children: [
99
+ {
100
+ type: 'text',
101
+ left: -1 * gridRight,
102
+ info,
103
+ style: {
104
+ fill: config.textColor,
105
+ text,
106
+ stroke: '#000',
107
+ lineWidth: 1,
108
+ opacity: 1,
109
+ },
110
+ z: 10,
153
111
  },
154
- },
112
+ ],
155
113
  },
114
+ ],
115
+ // 事件:鼠标滑入
116
+ onmouseover: (params: ElementEvent) => {
117
+ if (event.onmouseover instanceof Function) {
118
+ event.onmouseover(params, info)
119
+ }
120
+ },
121
+ // 事件:鼠标滑出
122
+ onmouseout: (params: ElementEvent) => {
123
+ if (event.onmouseout instanceof Function) {
124
+ event.onmouseout(params, info)
125
+ }
156
126
  },
157
- xAxis: {
158
- type: 'category',
159
- data: xAxisData,
160
- axisLine: {
161
- lineStyle: {
162
- color: 'red',
127
+ // 事件:开始拖拽
128
+ ondragstart: (params: ElementEvent) => {
129
+ if (event.ondragstart instanceof Function && config.draggable) {
130
+ dragStart = params.offsetY // 记录拖拽开始坐标
131
+ event.ondragstart(params, info)
132
+ }
133
+ },
134
+ // 事件:结束拖拽
135
+ ondragend: (params: ElementEvent) => {
136
+ if (event.ondragend instanceof Function && config.draggable) {
137
+ const dragEnd = params.offsetY // 记录结束拖拽坐标
138
+ const dragInterval = dragEnd - dragStart // 拖拽偏移量
139
+ if (dragInterval === 0) {
140
+ return
141
+ }
142
+ const yAxisValue = echartsInstance.convertFromPixel({ yAxisIndex: 0 }, y + dragInterval)
143
+ event.ondragend(params, info, yAxisValue)
144
+ }
145
+ },
146
+ }
147
+ }
148
+
149
+ // 单条线的配置-持仓线
150
+ interface positionParamsType {
151
+ y: number
152
+ text: string
153
+ info: InfoType
154
+ gridLeft: number
155
+ gridRight: number
156
+ echartsWidth: number
157
+ echartsInstance: EChartsType
158
+ }
159
+ export const getPositionItem = (params: positionParamsType) => {
160
+ // 1.解构入参
161
+ const { y, text, info, gridLeft, gridRight, echartsWidth, echartsInstance } = params
162
+ const { config, event } = info
163
+
164
+ let dragStart = 0 // 拖拽开始坐标
165
+
166
+ // --------------------默认鼠标滑入/滑出展示事件: 展示持仓线文本--------------------------
167
+ const defaultOnMouseOver = (params: ElementEvent) => {
168
+ let groupItem: any = null
169
+ if (params.target.type === 'line') {
170
+ groupItem = params.target.parent
171
+ } else if (params.target.type === 'tspan') {
172
+ groupItem = params.target.parent.parent.parent
173
+ }
174
+ // 处理持仓线鼠标滑入时展示
175
+ groupItem.children()[1].children()[0].animate('style', false).when(200, { opacity: 1 }).start()
176
+ }
177
+ const defaultOnMouseOut = (params: ElementEvent) => {
178
+ let groupItem: any = null
179
+ if (params.target.type === 'line') {
180
+ groupItem = params.target.parent
181
+ } else if (params.target.type === 'tspan') {
182
+ groupItem = params.target.parent.parent.parent
183
+ }
184
+ // 处理持仓线鼠标滑出时展示
185
+ groupItem.children()[1].children()[0].animate('style', false).when(200, { opacity: 0 }).start()
186
+ }
187
+
188
+ // -----------------------------------return-------------------------------------------
189
+ return {
190
+ type: 'group',
191
+ draggable: config.draggable ? 'vertical' : false, // 是否支持拖拽
192
+ children: [
193
+ {
194
+ type: 'line',
195
+ info,
196
+ shape: {
197
+ x1: gridLeft,
198
+ y1: y,
199
+ x2: echartsWidth - gridRight,
200
+ y2: y,
163
201
  },
164
- },
165
- splitLine: {
166
- show: true,
167
- lineStyle: {
168
- type: 'dotted',
202
+ style: {
203
+ stroke: config.lineColor,
204
+ lineWidth: 1,
169
205
  },
206
+ z: 10,
170
207
  },
171
- axisLabel: {
172
- show: true,
173
- formatter: data => dayjs(new Date(data * 1000)).format('YYYY-MM-DD HH:mm'),
208
+ {
209
+ type: 'group',
210
+ x: echartsWidth / 2,
211
+ y: y - 5,
212
+ children: [
213
+ {
214
+ type: 'text',
215
+ left: 'center',
216
+ info,
217
+ style: {
218
+ fill: config.textColor,
219
+ text,
220
+ stroke: '#000',
221
+ lineWidth: 1,
222
+ opacity: 0, //隐藏文本
223
+ },
224
+ z: 10,
225
+ },
226
+ ],
174
227
  },
228
+ ],
229
+ // 事件:鼠标滑入
230
+ onmouseover: (params: ElementEvent) => {
231
+ if (event.onmouseover instanceof Function) {
232
+ event.onmouseover(params, info)
233
+ } else {
234
+ defaultOnMouseOver(params)
235
+ }
236
+ },
237
+ // 事件:鼠标滑出
238
+ onmouseout: (params: ElementEvent) => {
239
+ if (event.onmouseout instanceof Function) {
240
+ event.onmouseout(params, info)
241
+ } else {
242
+ defaultOnMouseOut(params)
243
+ }
244
+ },
245
+ // 事件:开始拖拽
246
+ ondragstart: (params: ElementEvent) => {
247
+ if (event.ondragstart instanceof Function && config.draggable) {
248
+ dragStart = params.offsetY // 记录拖拽开始坐标
249
+ event.ondragstart(params, info)
250
+ }
175
251
  },
176
- yAxis: [
252
+ // 事件:结束拖拽
253
+ ondragend: (params: ElementEvent) => {
254
+ if (event.ondragend instanceof Function && config.draggable) {
255
+ const dragEnd = params.offsetY // 记录结束拖拽坐标
256
+ const dragInterval = dragEnd - dragStart // 拖拽偏移量
257
+ if (dragInterval === 0) {
258
+ return
259
+ }
260
+ const yAxisValue = echartsInstance.convertFromPixel({ yAxisIndex: 0 }, y + dragInterval)
261
+ event.ondragend(params, info, yAxisValue)
262
+ }
263
+ },
264
+ }
265
+ }
266
+
267
+ // 单条线的配置-条件单
268
+ interface conditionParamsType {
269
+ y: number
270
+ text: string
271
+ profitY: number
272
+ profitText: string
273
+ lossY: number
274
+ lossText: string
275
+ info: InfoType
276
+ gridLeft: number
277
+ gridRight: number
278
+ echartsWidth: number
279
+ echartsInstance: EChartsType
280
+ }
281
+ export const getConditionItem = (params: conditionParamsType) => {
282
+ // 1.解构入参
283
+ const { y, text, profitY, profitText, lossY, lossText, info, gridLeft, gridRight, echartsWidth, echartsInstance } =
284
+ params
285
+ const { config, event } = info
286
+
287
+ let dragStart = 0 // 拖拽开始坐标
288
+
289
+ // --------------------默认鼠标滑入/滑出展示事件: alt展示盈亏线---------------------------
290
+ // 键盘按下事件函数
291
+ let handleKeyDown: any = null
292
+ // 键盘弹起函数
293
+ let handleKeyUp: any = null
294
+ // [展示/隐藏]盈亏线
295
+ const handleProfitLossShow = (groupItem: any, show: boolean) => {
296
+ groupItem.children()[2].animate('style', false).when(200, { opacity: ~~show }).start()
297
+ groupItem.children()[3].children()[0].animate('style', false).when(200, { opacity: ~~show }).start()
298
+ groupItem.children()[4].animate('style', false).when(200, { opacity: ~~show }).start()
299
+ groupItem.children()[5].children()[0].animate('style', false).when(200, { opacity: ~~show }).start()
300
+ }
301
+ // 默认的鼠标滑入事件
302
+ const defaultOnMouseOver = (params: ElementEvent) => {
303
+ let groupItem: any = null
304
+ if (params.target.type === 'line') {
305
+ groupItem = params.target.parent
306
+ } else if (params.target.type === 'tspan') {
307
+ groupItem = params.target.parent.parent.parent
308
+ }
309
+ // 处理持仓线鼠标滑入+按下alt时展示
310
+ handleKeyDown = e => {
311
+ e.preventDefault()
312
+ if (e.code === 'AltLeft' || e.code === 'AltRight') {
313
+ handleProfitLossShow(groupItem, true)
314
+ }
315
+ }
316
+ handleKeyUp = e => {
317
+ if (e.code === 'AltLeft' || e.code === 'AltRight') {
318
+ handleProfitLossShow(groupItem, false)
319
+ }
320
+ }
321
+ window.addEventListener('keydown', handleKeyDown)
322
+ window.addEventListener('keyup', handleKeyUp)
323
+ }
324
+ // 默认的鼠标滑出事件
325
+ const defaultOnMouseOut = (params: ElementEvent) => {
326
+ let groupItem: any = null
327
+ if (params.target.type === 'line') {
328
+ groupItem = params.target.parent
329
+ } else if (params.target.type === 'tspan') {
330
+ groupItem = params.target.parent.parent.parent
331
+ }
332
+ // 处理持仓线鼠标滑出时展示
333
+ handleProfitLossShow(groupItem, false)
334
+ window.removeEventListener('keydown', handleKeyDown)
335
+ window.removeEventListener('keyup', handleKeyUp)
336
+ }
337
+
338
+ // -----------------------------------return-------------------------------------------
339
+ return {
340
+ type: 'group',
341
+ draggable: config.draggable ? 'vertical' : false, // 是否支持拖拽
342
+ children: [
343
+ // 条件单-主线
177
344
  {
178
- index: 0,
179
- min: 'dataMin',
180
- axisLine: {
181
- show: true,
182
- lineStyle: {
183
- color: 'red',
184
- },
345
+ type: 'line',
346
+ info,
347
+ shape: {
348
+ x1: gridLeft,
349
+ y1: y,
350
+ x2: echartsWidth - gridRight,
351
+ y2: y,
352
+ },
353
+ style: {
354
+ stroke: config.lineColor,
355
+ lineWidth: 1,
185
356
  },
186
- splitLine: {
187
- show: true,
188
- lineStyle: {
189
- type: 'dotted',
357
+ z: 10,
358
+ },
359
+ // 条件单-文本内容
360
+ {
361
+ type: 'group',
362
+ x: echartsWidth / 2,
363
+ y: y - 5,
364
+ children: [
365
+ {
366
+ type: 'text',
367
+ left: 'center',
368
+ info,
369
+ style: {
370
+ fill: config.textColor, // 填充色
371
+ text: text,
372
+ stroke: '#000', // 线条颜色
373
+ lineWidth: 1,
374
+ opacity: 1, //直接展示文本
375
+ },
376
+ z: 10,
190
377
  },
378
+ ],
379
+ },
380
+ // 条件单-止盈线
381
+ {
382
+ type: 'line',
383
+ info,
384
+ shape: {
385
+ x1: gridLeft,
386
+ y1: profitY,
387
+ x2: echartsWidth - gridRight,
388
+ y2: profitY,
191
389
  },
192
- axisLabel: {
193
- formatter: (value: number) => formatValue(value),
390
+ style: {
391
+ stroke: (config as ConditionConfigType).profitLineColor,
392
+ lineWidth: 1,
393
+ lineDash: [8, 4],
394
+ opacity: 0,
194
395
  },
396
+ z: 10,
195
397
  },
196
- ],
197
- dataZoom: [
398
+ // 条件单-止盈线文本内容
198
399
  {
199
- type: 'inside',
200
- xAxisIndex: [0, 0],
201
- startValue: kLineLength >= defaultShowBarCount ? kLineLength - defaultShowBarCount : 0,
202
- endValue: kLineLength - 1,
400
+ type: 'group',
401
+ x: echartsWidth / 2,
402
+ y: profitY - 5,
403
+ children: [
404
+ {
405
+ type: 'text',
406
+ left: 'center',
407
+ info,
408
+ style: {
409
+ fill: (config as ConditionConfigType).profitTextColor,
410
+ text: profitText,
411
+ stroke: '#000',
412
+ lineWidth: 1,
413
+ opacity: 0,
414
+ },
415
+ z: 10,
416
+ },
417
+ ],
203
418
  },
204
- ],
205
- series: [
419
+ // 条件单-止损线
206
420
  {
207
- name: 'k线',
208
- type: 'candlestick',
209
- data: candlestickData,
421
+ type: 'line',
422
+ info,
423
+ shape: {
424
+ x1: gridLeft,
425
+ y1: lossY,
426
+ x2: echartsWidth - gridRight,
427
+ y2: lossY,
428
+ },
429
+ style: {
430
+ stroke: (config as ConditionConfigType).lossLineColor,
431
+ lineWidth: 1,
432
+ lineDash: [8, 4],
433
+ opacity: 0,
434
+ },
435
+ z: 10,
436
+ },
437
+ // 条件单-止损线文本内容
438
+ {
439
+ type: 'group',
440
+ x: echartsWidth / 2,
441
+ y: lossY - 5,
442
+ children: [
443
+ {
444
+ type: 'text',
445
+ left: 'center',
446
+ info,
447
+ style: {
448
+ fill: (config as ConditionConfigType).lossTextColor,
449
+ text: lossText,
450
+ stroke: '#000',
451
+ lineWidth: 1,
452
+ opacity: 0,
453
+ },
454
+ z: 10,
455
+ },
456
+ ],
210
457
  },
211
- ...lineSeries,
212
458
  ],
213
- toolbox: {
214
- show: false,
459
+ // 事件:鼠标滑入
460
+ onmouseover: (params: ElementEvent) => {
461
+ if (event.onmouseover instanceof Function) {
462
+ event.onmouseover(params, info)
463
+ } else {
464
+ defaultOnMouseOver(params)
465
+ }
215
466
  },
216
- brush: {
217
- xAxisIndex: 'all',
218
- brushLink: 'all',
219
- transformable: false,
220
- outOfBrush: {
221
- colorAlpha: 1,
222
- },
223
- brushStyle: {
224
- color: 'rgba(120,140,180,0)',
225
- borderColor: 'rgba(255,255,255,0.4)',
226
- },
467
+ // 事件:鼠标滑出
468
+ onmouseout: (params: ElementEvent) => {
469
+ if (event.onmouseout instanceof Function) {
470
+ event.onmouseout(params, info)
471
+ } else {
472
+ defaultOnMouseOut(params)
473
+ }
474
+ },
475
+ // 事件:开始拖拽
476
+ ondragstart: (params: ElementEvent) => {
477
+ if (event.ondragstart instanceof Function && config.draggable) {
478
+ dragStart = params.offsetY // 记录拖拽开始坐标
479
+ event.ondragstart(params, info)
480
+ }
227
481
  },
482
+ // 事件:结束拖拽
483
+ ondragend: (params: ElementEvent) => {
484
+ if (event.ondragend instanceof Function && config.draggable) {
485
+ const dragEnd = params.offsetY // 记录结束拖拽坐标
486
+ const dragInterval = dragEnd - dragStart // 拖拽偏移量
487
+ if (dragInterval === 0) {
488
+ return
489
+ }
490
+ const yAxisValue = echartsInstance.convertFromPixel({ yAxisIndex: 0 }, y + dragInterval)
491
+ event.ondragend(params, info, yAxisValue)
492
+ }
493
+ },
494
+ }
495
+ }
496
+
497
+ // -----------------点位处理工具函数--------------------
498
+
499
+ /**
500
+ * @description: 返回交易类型
501
+ * @param {Object} data 单个点位数据
502
+ * @param {String} type 买卖点[sellbuy], 开平点[openClose]
503
+ * @returns {String} tradeType
504
+ */
505
+ const handleTradeType = (
506
+ data: {
507
+ direction?: string
508
+ tradeAction?: string
509
+ tradeType?: string
510
+ },
511
+ type: string
512
+ ) => {
513
+ const { direction = '', tradeAction = '', tradeType = '' } = data
514
+ if (type === 'sellBuy') {
515
+ const key = tradeType ?? direction + tradeAction
516
+ const keyMap = new Map([
517
+ ['开多', '买'],
518
+ ['平多', '卖'],
519
+ ['开空', '卖'],
520
+ ['平空', '买'],
521
+ ])
522
+ return keyMap.get(key)
523
+ } else if (type === 'openClose') {
524
+ return tradeType ?? direction + tradeAction
228
525
  }
229
526
  }
527
+
528
+ /**
529
+ * @description: 返回买卖点配置
530
+ * @todo: 均标注在K线最上方
531
+ */
532
+ const handleSellBuyConfig = (data: any[], originData: KlineDataType) => {
533
+ return data.reduce((result, next) => {
534
+ // 1.获取交易类型
535
+ const tradeType = handleTradeType(next, 'sellBuy')
536
+ /**
537
+ * 2.获取标注图标
538
+ * 因为传入参数数据时,已经对数据进行了合并处理,不会出现例如: 两个平空数据于一条K线上,这种情况,所以
539
+ * 简单判断该条K线上是否有多个数据即可判断出是否是买卖同时存在,如果同时存在图标变成T
540
+ */
541
+ let symbol = 'image://' + new URL(`./images/${tradeType === '买' ? 'buy' : 'sell'}.svg`, import.meta.url).href
542
+ if (data.filter((item: any) => item.time === next.time).length > 1) {
543
+ symbol = 'image://' + new URL('./images/t.svg', import.meta.url).href
544
+ }
545
+ // 3.获取对应Y轴值
546
+ const originDataItem = originData.find((item: any) => item[0] === next.time) ?? []
547
+ const yAxisValue = originDataItem[2]
548
+ result.push({
549
+ symbol, // 图标
550
+ symbolSize: 25, // 图标大小
551
+ animation: false, // 是否展示动画
552
+ coord: [next.time + '', yAxisValue], // X轴[时间],Y轴[最高价]
553
+ symbolRotate: 0, // 旋转角度
554
+ symbolOffset: [0, '-7'], // 偏移距离
555
+ })
556
+ return result
557
+ }, [])
558
+ }
559
+
560
+ /**
561
+ * @description: 返回开平点配置
562
+ * @todo: 开标注在K线最上方,平标注在K线最下方
563
+ */
564
+ const handleOpenCloseConfig = (data: any[], originData: KlineDataType) => {
565
+ return data.reduce((result, next, index) => {
566
+ // 1.获取交易类型
567
+ const tradeType = handleTradeType(next, 'openClose')
568
+ // 2.确定位置
569
+ const position = tradeType === '开多' || tradeType === '开空' ? 'top' : 'bottom'
570
+ // 3.获取对应Y轴值
571
+ const originDataItem = originData.find((item: any) => item[0] === next.time) ?? []
572
+ const yAxisValue = position === 'top' ? originDataItem[2] : originDataItem[3]
573
+ // 4.计算偏移量,避免点位重叠
574
+ let offset = 7
575
+ offset +=
576
+ data.slice(0, index).filter((item: any) => {
577
+ const itemTradeType = handleTradeType(item, 'openClose')
578
+ const itemPosition = itemTradeType === '开多' || itemTradeType === '开空' ? 'top' : 'bottom'
579
+ return itemPosition === position && item.time === next.time
580
+ }).length * 7
581
+ result.push({
582
+ symbol: 'triangle', // 图标
583
+ symbolSize: [10, 12], // 图标大小
584
+ animation: false, // 是否展示动画
585
+ coord: [next.time + '', yAxisValue], // X轴[时间],Y轴[最高价||最低价]
586
+ symbolRotate: position === 'top' ? 180 : 0, //标注旋转角度
587
+ symbolOffset: [0, `${position === 'top' ? offset * -1 : offset}`], //标注偏移距离
588
+ itemStyle: { color: position === 'top' ? '#FF0000' : '#389e0d' }, // 图标颜色
589
+ // 文本
590
+ label: {
591
+ show: true, // 是否展示
592
+ position,
593
+ color: '#fff',
594
+ formatter: `${tradeType} ${position === 'top' ? '+' : '-'} ${next.amount}手 (${next.part}份)`,
595
+ },
596
+ })
597
+ return result
598
+ }, [])
599
+ }
600
+
601
+ /**
602
+ * @description: 返回点位配置
603
+ * @param {Array} markData 点位数据
604
+ * @param {Array} originData K线源数据
605
+ */
606
+ export const handlePoint = (markData, originData: KlineDataType) => {
607
+ return markData.reduce((result, next) => {
608
+ const { key, data } = next
609
+ // 无数据直接循环下一组数据
610
+ if (data === null || data.length === 0) return result
611
+ // 点位数据转换配置项结构
612
+ const configMap = new Map([
613
+ // 买卖点
614
+ [
615
+ 'sellBuy',
616
+ () => {
617
+ return handleSellBuyConfig(data, originData)
618
+ },
619
+ ],
620
+ // 开平点
621
+ [
622
+ 'openClose',
623
+ () => {
624
+ return handleOpenCloseConfig(data, originData)
625
+ },
626
+ ],
627
+ // 信号点
628
+ ['signal', () => {}],
629
+ ])
630
+ const callBack = configMap.get(key)
631
+ if (callBack instanceof Function) result.push(...callBack())
632
+ return result
633
+ }, [])
634
+ }