@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.
@@ -1,6 +1,6 @@
1
1
  import { SemanticChartConfig, DataFetcher } from '@363045841yyt/klinechart-core/semantic';
2
2
  declare const KLineChartElement: import('vue').VueElementConstructor<{
3
- semanticConfig: SemanticChartConfig;
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;;;;;;;;;;;;EAErB,CAAA;AAIF,OAAO,EAAE,iBAAiB,EAAE,CAAA;AAC5B,eAAe,iBAAiB,CAAA;AAEhC,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,CAAA"}
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.1",
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: SemanticChartConfig
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.data.period)
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.data.startDate,
257
- endDate: props.semanticConfig.data.endDate,
258
- adjust: props.semanticConfig.data.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>{{ formatDate(k.timestamp) }}</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) + '万'
@@ -464,6 +464,8 @@ watch(() => props.symbol, () => {
464
464
  }
465
465
 
466
466
  .symbol-chip__spinner {
467
+ display: inline-block;
468
+ flex-shrink: 0;
467
469
  width: 12px;
468
470
  height: 12px;
469
471
  border: 2px solid var(--klc-color-axis-text);
@@ -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', description: '现货黄金', exchange: 'OANDA', source: 'tradingview' },
67
- { code: 'BTCUSDT', description: 'Bitcoin / Tether', exchange: 'BINANCE', source: 'tradingview' },
68
- { code: 'ETHUSDT', description: 'Ethereum / Tether', exchange: 'BINANCE', source: 'tradingview' },
69
- { code: 'EURUSD', description: '欧元/美元', exchange: 'OANDA', source: 'tradingview' },
70
- { code: 'SPX', description: '标普 500 指数', exchange: 'SP', source: 'tradingview' },
71
- { code: 'AAPL', description: 'Apple Inc.', exchange: 'NASDAQ', source: 'tradingview' },
72
- { code: 'TSLA', description: 'Tesla, Inc.', exchange: 'NASDAQ', source: 'tradingview' },
73
- { code: '600519', description: '贵州茅台', exchange: 'SSE', source: 'tradingview' },
74
- { code: '000001', description: '平安银行', exchange: 'SZSE', source: 'tradingview' },
75
- { code: '1810', description: '小米集团', exchange: 'HKEX', source: 'tradingview' },
76
- // ── Baostock A ──
77
- { code: 'sh.600519', description: '贵州茅台', exchange: 'SSE', source: 'baostock' },
78
- { code: 'sh.601360', description: '三六零', exchange: 'SSE', source: 'baostock' },
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', description: 'Mock 100 条', exchange: 'MOCK', source: 'mock-100' },
83
- { code: 'MOCK-10000', description: 'Mock 10000 条', exchange: 'MOCK', source: '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() ?? '')