@363045841yyt/klinechart 0.8.1 → 0.8.3
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.
- package/README.md +6 -2
- package/dist/components/KLineAdjustmentDropdown.vue.d.ts +13 -0
- package/dist/components/KLineAdjustmentDropdown.vue.d.ts.map +1 -0
- package/dist/components/KLineChart.vue.d.ts +26 -3
- package/dist/components/KLineChart.vue.d.ts.map +1 -1
- package/dist/components/KLineLevelDropdown.vue.d.ts +1 -1
- package/dist/components/KLineLevelDropdown.vue.d.ts.map +1 -1
- package/dist/components/KLineTooltip.vue.d.ts +6 -0
- package/dist/components/KLineTooltip.vue.d.ts.map +1 -1
- package/dist/components/SymbolSelector.vue.d.ts.map +1 -1
- package/dist/components/TopToolbar.vue.d.ts +3 -0
- package/dist/components/TopToolbar.vue.d.ts.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.css +1 -1
- package/dist/index.js +704 -654
- package/dist/web-component.d.ts +18 -1
- package/dist/web-component.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/components/KLineAdjustmentDropdown.vue +32 -0
- package/src/components/KLineChart.vue +37 -7
- package/src/components/KLineLevelDropdown.vue +2 -0
- package/src/components/KLineTooltip.vue +16 -9
- package/src/components/SymbolSelector.vue +2 -0
- package/src/components/TopToolbar.vue +22 -17
package/dist/web-component.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SemanticChartConfig, DataFetcher } from '@363045841yyt/klinechart-core/semantic';
|
|
2
2
|
declare const KLineChartElement: import('vue').VueElementConstructor<{
|
|
3
|
-
semanticConfig
|
|
3
|
+
semanticConfig?: SemanticChartConfig;
|
|
4
4
|
dataFetcher: DataFetcher;
|
|
5
5
|
yPaddingPx?: number;
|
|
6
6
|
minKWidth?: number;
|
|
@@ -11,6 +11,23 @@ declare const KLineChartElement: import('vue').VueElementConstructor<{
|
|
|
11
11
|
zoomLevels?: number;
|
|
12
12
|
initialZoomLevel?: number;
|
|
13
13
|
isFullscreen?: boolean;
|
|
14
|
+
timezone?: string;
|
|
15
|
+
mcp?: {
|
|
16
|
+
wsUrl?: string;
|
|
17
|
+
onToolCall?: (call: {
|
|
18
|
+
name: string;
|
|
19
|
+
input: Record<string, unknown>;
|
|
20
|
+
}) => {
|
|
21
|
+
success: boolean;
|
|
22
|
+
error?: string;
|
|
23
|
+
data?: unknown;
|
|
24
|
+
} | Promise<{
|
|
25
|
+
success: boolean;
|
|
26
|
+
error?: string;
|
|
27
|
+
data?: unknown;
|
|
28
|
+
}>;
|
|
29
|
+
autoReconnect?: boolean;
|
|
30
|
+
};
|
|
14
31
|
}>;
|
|
15
32
|
export { KLineChartElement };
|
|
16
33
|
export default KLineChartElement;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web-component.d.ts","sourceRoot":"","sources":["../src/web-component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAE9F,QAAA,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"web-component.d.ts","sourceRoot":"","sources":["../src/web-component.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,wCAAwC,CAAA;AAE9F,QAAA,MAAM,iBAAiB;;;;;;;;;;;;;;aAU6uzC,CAAC;kBAAyB,CAAC;;;;;iBAAsH,CAAC;gBAAc,CAAC;;;iBAAuD,CAAC;gBAAc,CAAC;;qBAAgC,CAAC;;EAR3g0C,CAAA;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA;AAEhC,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@363045841yyt/klinechart",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Vue 3 bindings for @363045841yyt/klinechart-core. Idiomatic composables, SFC components.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -71,6 +71,7 @@
|
|
|
71
71
|
"vue": "^3.4.0"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
+
"@363045841yyt/klinechart-ai-runtime": "workspace:*",
|
|
74
75
|
"@arethetypeswrong/cli": "^0.18.3",
|
|
75
76
|
"@size-limit/preset-small-lib": "^12.1.0",
|
|
76
77
|
"@vitejs/plugin-vue": "^6.0.7",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Dropdown
|
|
3
|
+
:model-value="modelValue"
|
|
4
|
+
:options="adjustmentOptions"
|
|
5
|
+
label="复权"
|
|
6
|
+
title="复权方式"
|
|
7
|
+
size="md"
|
|
8
|
+
@update:model-value="emit('update:modelValue', $event as KLineAdjustment)"
|
|
9
|
+
/>
|
|
10
|
+
</template>
|
|
11
|
+
|
|
12
|
+
<script setup lang="ts">
|
|
13
|
+
import Dropdown from './Dropdown.vue'
|
|
14
|
+
import type { AdjustType } from '@363045841yyt/klinechart-core/semantic'
|
|
15
|
+
|
|
16
|
+
export type KLineAdjustment = AdjustType
|
|
17
|
+
|
|
18
|
+
const adjustmentOptions: Array<{ label: string; value: KLineAdjustment }> = [
|
|
19
|
+
{ label: '前复权', value: 'qfq' },
|
|
20
|
+
{ label: '后复权', value: 'hfq' },
|
|
21
|
+
{ label: '仅拆股', value: 'splits' },
|
|
22
|
+
{ label: '不复权', value: 'none' },
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
defineProps<{
|
|
26
|
+
modelValue?: string
|
|
27
|
+
}>()
|
|
28
|
+
|
|
29
|
+
const emit = defineEmits<{
|
|
30
|
+
(e: 'update:modelValue', adjust: KLineAdjustment): void
|
|
31
|
+
}>()
|
|
32
|
+
</script>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<TopToolbar
|
|
4
4
|
:symbol="currentSymbol"
|
|
5
5
|
:k-line-level="kLineLevel"
|
|
6
|
+
:k-line-adjust="kLineAdjust"
|
|
6
7
|
:symbol-loading="symbolLoading"
|
|
7
8
|
:symbol-error="symbolError"
|
|
8
9
|
:overlay-symbols="overlaySymbols"
|
|
@@ -11,6 +12,7 @@
|
|
|
11
12
|
@add-overlay-symbol="onAddOverlaySymbol"
|
|
12
13
|
@remove-overlay-symbol="onRemoveOverlaySymbol"
|
|
13
14
|
@k-line-level-change="onKLineLevelChange"
|
|
15
|
+
@k-line-adjust-change="onKLineAdjustChange"
|
|
14
16
|
@toggle-indicator="onToggleIndicator"
|
|
15
17
|
@symbol-change="onSymbolChange"
|
|
16
18
|
/>
|
|
@@ -91,6 +93,8 @@
|
|
|
91
93
|
:anchor-placement="tooltipAnchorPlacement"
|
|
92
94
|
:up-color="tooltipColors.upColor"
|
|
93
95
|
:down-color="tooltipColors.downColor"
|
|
96
|
+
:timezone="props.timezone"
|
|
97
|
+
:show-time="isIntraday"
|
|
94
98
|
/>
|
|
95
99
|
<MarkerTooltip
|
|
96
100
|
v-if="hoveredMarker || hoveredCustomMarker"
|
|
@@ -168,8 +172,8 @@ import TopToolbar, { type SymbolItem } from './TopToolbar.vue'
|
|
|
168
172
|
|
|
169
173
|
const props = withDefaults(
|
|
170
174
|
defineProps<{
|
|
171
|
-
/**
|
|
172
|
-
semanticConfig
|
|
175
|
+
/** 语义化配置(可选,唯一控制源) */
|
|
176
|
+
semanticConfig?: SemanticChartConfig
|
|
173
177
|
|
|
174
178
|
/** 数据获取函数(必需)。框架不绑定数据源,由使用者注入。 */
|
|
175
179
|
dataFetcher: DataFetcher
|
|
@@ -190,6 +194,20 @@ const props = withDefaults(
|
|
|
190
194
|
initialZoomLevel?: number
|
|
191
195
|
/** 是否全屏 */
|
|
192
196
|
isFullscreen?: boolean
|
|
197
|
+
/** 时区,默认 Asia/Shanghai */
|
|
198
|
+
timezone?: string
|
|
199
|
+
|
|
200
|
+
/** MCP / AI runtime bridge 配置。传入后自动连接 MCP WebSocket server */
|
|
201
|
+
mcp?: {
|
|
202
|
+
wsUrl?: string
|
|
203
|
+
onToolCall?: (call: {
|
|
204
|
+
name: string
|
|
205
|
+
input: Record<string, unknown>
|
|
206
|
+
}) =>
|
|
207
|
+
| { success: boolean; error?: string; data?: unknown }
|
|
208
|
+
| Promise<{ success: boolean; error?: string; data?: unknown }>
|
|
209
|
+
autoReconnect?: boolean
|
|
210
|
+
}
|
|
193
211
|
}>(),
|
|
194
212
|
{
|
|
195
213
|
yPaddingPx: 20,
|
|
@@ -201,6 +219,7 @@ const props = withDefaults(
|
|
|
201
219
|
zoomLevels: 20,
|
|
202
220
|
initialZoomLevel: 3,
|
|
203
221
|
isFullscreen: false,
|
|
222
|
+
timezone: 'Asia/Shanghai',
|
|
204
223
|
},
|
|
205
224
|
)
|
|
206
225
|
|
|
@@ -209,9 +228,12 @@ const emit = defineEmits<{
|
|
|
209
228
|
(e: 'toggleFullscreen'): void
|
|
210
229
|
(e: 'themeChange', theme: 'light' | 'dark'): void
|
|
211
230
|
(e: 'kLineLevelChange', level: string): void
|
|
231
|
+
(e: 'kLineAdjustChange', adjust: 'qfq' | 'hfq' | 'splits' | 'none'): void
|
|
212
232
|
}>()
|
|
213
233
|
|
|
214
|
-
const kLineLevel = ref(props.semanticConfig
|
|
234
|
+
const kLineLevel = ref(props.semanticConfig?.data?.period ?? 'daily')
|
|
235
|
+
const kLineAdjust = ref(props.semanticConfig?.data?.adjust ?? 'none')
|
|
236
|
+
const isIntraday = computed(() => kLineLevel.value.includes('min'))
|
|
215
237
|
const currentSymbol = ref('选择商品')
|
|
216
238
|
const currentSymbolItem = ref<SymbolItem | null>(null)
|
|
217
239
|
const symbolLoading = ref(false)
|
|
@@ -225,6 +247,12 @@ function onKLineLevelChange(level: string) {
|
|
|
225
247
|
syncSymbolsToController()
|
|
226
248
|
}
|
|
227
249
|
|
|
250
|
+
function onKLineAdjustChange(adjust: 'qfq' | 'hfq' | 'splits' | 'none') {
|
|
251
|
+
kLineAdjust.value = adjust
|
|
252
|
+
emit('kLineAdjustChange', adjust)
|
|
253
|
+
syncSymbolsToController()
|
|
254
|
+
}
|
|
255
|
+
|
|
228
256
|
function onSymbolChange(item: SymbolItem) {
|
|
229
257
|
symbolError.value = false
|
|
230
258
|
currentSymbol.value = item.code
|
|
@@ -253,9 +281,9 @@ function toSymbolSpec(item: SymbolItem): SymbolSpec {
|
|
|
253
281
|
exchange: item.exchange,
|
|
254
282
|
period: kLineLevel.value,
|
|
255
283
|
source: item.source,
|
|
256
|
-
startDate: props.semanticConfig
|
|
257
|
-
endDate: props.semanticConfig
|
|
258
|
-
adjust:
|
|
284
|
+
startDate: props.semanticConfig?.data?.startDate ?? '',
|
|
285
|
+
endDate: props.semanticConfig?.data?.endDate ?? '',
|
|
286
|
+
adjust: kLineAdjust.value,
|
|
259
287
|
}
|
|
260
288
|
}
|
|
261
289
|
|
|
@@ -706,7 +734,7 @@ function clearAllSubPanes(): void {
|
|
|
706
734
|
function initIndicatorsFromConfig(): void {
|
|
707
735
|
const config = props.semanticConfig
|
|
708
736
|
const c = controller.value
|
|
709
|
-
if (!c) return
|
|
737
|
+
if (!config || !c) return
|
|
710
738
|
|
|
711
739
|
const mainIndicators = config.indicators?.main
|
|
712
740
|
if (mainIndicators) {
|
|
@@ -848,6 +876,7 @@ defineExpose({
|
|
|
848
876
|
zoomOut: (anchorX?: number) => applyZoomToLevel(zoomLevel.value - 1, anchorX),
|
|
849
877
|
getZoomLevel: () => zoomLevel.value,
|
|
850
878
|
getZoomLevelCount: () => controller.value?.getZoomLevelCount() ?? 10,
|
|
879
|
+
getController: () => controller.value,
|
|
851
880
|
})
|
|
852
881
|
|
|
853
882
|
// ==================== onMounted 拆分函数 ====================
|
|
@@ -880,6 +909,7 @@ function initChart(
|
|
|
880
909
|
priceLabelWidth: props.priceLabelWidth,
|
|
881
910
|
minKWidth: props.minKWidth,
|
|
882
911
|
maxKWidth: props.maxKWidth,
|
|
912
|
+
mcp: props.mcp,
|
|
883
913
|
})
|
|
884
914
|
return ctrl
|
|
885
915
|
}
|
|
@@ -18,12 +18,14 @@ export type KLineLevel =
|
|
|
18
18
|
| '15min'
|
|
19
19
|
| '30min'
|
|
20
20
|
| '60min'
|
|
21
|
+
| 'daily'
|
|
21
22
|
| 'weekly'
|
|
22
23
|
| 'monthly'
|
|
23
24
|
| 'quarterly'
|
|
24
25
|
| 'yearly'
|
|
25
26
|
|
|
26
27
|
const kLineLevelOptions: Array<{ label: string; value: KLineLevel }> = [
|
|
28
|
+
{ label: '1day', value: 'daily' },
|
|
27
29
|
{ label: '1min', value: '1min' },
|
|
28
30
|
{ label: '5min', value: '5min' },
|
|
29
31
|
{ label: '15min', value: '15min' },
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
>
|
|
9
9
|
<div class="kline-tooltip__title">
|
|
10
10
|
<span v-if="k.stockCode">{{ k.stockCode }}</span>
|
|
11
|
-
<span>{{
|
|
11
|
+
<span>{{ formattedDate }}</span>
|
|
12
12
|
</div>
|
|
13
13
|
<div class="kline-tooltip__grid">
|
|
14
14
|
<div class="row">
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
<script setup lang="ts">
|
|
52
52
|
import { computed } from 'vue'
|
|
53
53
|
import type { ComponentPublicInstance } from 'vue'
|
|
54
|
+
import { formatTimestamp } from '@363045841yyt/klinechart-core'
|
|
54
55
|
|
|
55
56
|
export interface KLineData {
|
|
56
57
|
timestamp: number
|
|
@@ -79,9 +80,23 @@ const props = withDefaults(defineProps<{
|
|
|
79
80
|
upColor?: string
|
|
80
81
|
/** 跌的颜色(默认绿跌) */
|
|
81
82
|
downColor?: string
|
|
83
|
+
/** 时区,默认 Asia/Shanghai */
|
|
84
|
+
timezone?: string
|
|
85
|
+
/** 是否显示时分,默认 false */
|
|
86
|
+
showTime?: boolean
|
|
82
87
|
}>(), {
|
|
83
88
|
upColor: '#ef4444',
|
|
84
89
|
downColor: '#22c55e',
|
|
90
|
+
timezone: 'Asia/Shanghai',
|
|
91
|
+
showTime: false,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const formattedDate = computed(() => {
|
|
95
|
+
if (!props.k) return ''
|
|
96
|
+
return formatTimestamp(props.k.timestamp, {
|
|
97
|
+
timeZone: props.timezone,
|
|
98
|
+
showTime: props.showTime,
|
|
99
|
+
})
|
|
85
100
|
})
|
|
86
101
|
|
|
87
102
|
const useAnchor = computed(() => props.useAnchor === true)
|
|
@@ -93,14 +108,6 @@ function onRef(el: Element | ComponentPublicInstance | null) {
|
|
|
93
108
|
props.setEl?.(el as HTMLDivElement | null)
|
|
94
109
|
}
|
|
95
110
|
|
|
96
|
-
function formatDate(ts: number): string {
|
|
97
|
-
const d = new Date(ts)
|
|
98
|
-
const y = d.getFullYear()
|
|
99
|
-
const m = String(d.getMonth() + 1).padStart(2, '0')
|
|
100
|
-
const day = String(d.getDate()).padStart(2, '0')
|
|
101
|
-
return `${y}-${m}-${day}`
|
|
102
|
-
}
|
|
103
|
-
|
|
104
111
|
function formatVolume(v: number): string {
|
|
105
112
|
if (v >= 1e8) return (v / 1e8).toFixed(2) + '亿'
|
|
106
113
|
if (v >= 1e4) return (v / 1e4).toFixed(2) + '万'
|
|
@@ -20,6 +20,10 @@
|
|
|
20
20
|
:model-value="kLineLevel"
|
|
21
21
|
@update:model-value="emit('kLineLevelChange', $event)"
|
|
22
22
|
/>
|
|
23
|
+
<KLineAdjustmentDropdown
|
|
24
|
+
:model-value="kLineAdjust"
|
|
25
|
+
@update:model-value="emit('kLineAdjustChange', $event)"
|
|
26
|
+
/>
|
|
23
27
|
<button
|
|
24
28
|
type="button"
|
|
25
29
|
class="indicator-button"
|
|
@@ -36,6 +40,7 @@
|
|
|
36
40
|
<script setup lang="ts">
|
|
37
41
|
import { computed } from 'vue'
|
|
38
42
|
import KLineLevelDropdown, { type KLineLevel } from './KLineLevelDropdown.vue'
|
|
43
|
+
import KLineAdjustmentDropdown, { type KLineAdjustment } from './KLineAdjustmentDropdown.vue'
|
|
39
44
|
import SymbolSelector from './SymbolSelector.vue'
|
|
40
45
|
import CompareSymbolSelector from './CompareSymbolSelector.vue'
|
|
41
46
|
import type { SymbolItem } from './SymbolSelector.vue'
|
|
@@ -45,6 +50,7 @@ export type { SymbolItem }
|
|
|
45
50
|
const props = defineProps<{
|
|
46
51
|
symbol?: string
|
|
47
52
|
kLineLevel?: string
|
|
53
|
+
kLineAdjust?: string
|
|
48
54
|
symbols?: SymbolItem[]
|
|
49
55
|
symbolLoading?: boolean
|
|
50
56
|
symbolError?: boolean
|
|
@@ -57,30 +63,29 @@ const emit = defineEmits<{
|
|
|
57
63
|
(e: 'addOverlaySymbol', item: SymbolItem): void
|
|
58
64
|
(e: 'removeOverlaySymbol', code: string): void
|
|
59
65
|
(e: 'kLineLevelChange', level: KLineLevel): void
|
|
66
|
+
(e: 'kLineAdjustChange', adjust: KLineAdjustment): void
|
|
60
67
|
(e: 'toggleIndicator'): void
|
|
61
68
|
(e: 'symbolChange', symbol: SymbolItem): void
|
|
62
69
|
}>()
|
|
63
70
|
|
|
64
71
|
const MOCK_SYMBOLS: SymbolItem[] = [
|
|
65
72
|
// ── TradingView 全球品种 ──
|
|
66
|
-
{ code: 'XAUUSD',
|
|
67
|
-
{ code: 'BTCUSDT', description: 'Bitcoin / Tether',
|
|
68
|
-
{ code: 'ETHUSDT', description: 'Ethereum / Tether',
|
|
69
|
-
{ code: 'EURUSD',
|
|
70
|
-
{ code: 'SPX',
|
|
71
|
-
{ code: 'AAPL',
|
|
72
|
-
{ code: 'TSLA',
|
|
73
|
-
{ code: '
|
|
74
|
-
|
|
75
|
-
{ code: '
|
|
76
|
-
|
|
77
|
-
{ code: '
|
|
78
|
-
{ code: '
|
|
79
|
-
{ code: '000858', description: '五 粮 液', exchange: 'SZSE', source: 'baostock' },
|
|
80
|
-
{ code: '000001', description: '平安银行', exchange: 'SZSE', source: 'baostock' },
|
|
73
|
+
{ code: 'XAUUSD', description: '现货黄金', exchange: 'OANDA', source: 'tradingview' },
|
|
74
|
+
{ code: 'BTCUSDT', description: 'Bitcoin / Tether', exchange: 'BINANCE', source: 'tradingview' },
|
|
75
|
+
{ code: 'ETHUSDT', description: 'Ethereum / Tether', exchange: 'BINANCE', source: 'tradingview' },
|
|
76
|
+
{ code: 'EURUSD', description: '欧元/美元', exchange: 'OANDA', source: 'tradingview' },
|
|
77
|
+
{ code: 'SPX', description: '标普 500 指数', exchange: 'SP', source: 'tradingview' },
|
|
78
|
+
{ code: 'AAPL', description: 'Apple Inc.', exchange: 'NASDAQ', source: 'tradingview' },
|
|
79
|
+
{ code: 'TSLA', description: 'Tesla, Inc.', exchange: 'NASDAQ', source: 'tradingview' },
|
|
80
|
+
{ code: '1810', description: '小米集团', exchange: 'HKEX', source: 'tradingview' },
|
|
81
|
+
// ── gotdx A 股 ──
|
|
82
|
+
{ code: '600519', description: '贵州茅台', exchange: 'SSE', source: 'gotdx' },
|
|
83
|
+
{ code: '601360', description: '三六零', exchange: 'SSE', source: 'gotdx' },
|
|
84
|
+
{ code: '000858', description: '五 粮 液', exchange: 'SZSE', source: 'gotdx' },
|
|
85
|
+
{ code: '000001', description: '平安银行', exchange: 'SZSE', source: 'gotdx' },
|
|
81
86
|
// ── Mock ──
|
|
82
|
-
{ code: 'MOCK-100',
|
|
83
|
-
{ code: 'MOCK-10000', description: 'Mock 10000 条',
|
|
87
|
+
{ code: 'MOCK-100', description: 'Mock 100 条', exchange: 'MOCK', source: 'mock-100' },
|
|
88
|
+
{ code: 'MOCK-10000', description: 'Mock 10000 条', exchange: 'MOCK', source: 'mock-10000' },
|
|
84
89
|
]
|
|
85
90
|
|
|
86
91
|
const displaySymbol = computed(() => props.symbol?.trim() ?? '')
|