@363045841yyt/klinechart 0.5.6 → 0.6.1

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 (43) hide show
  1. package/README.md +7 -4
  2. package/dist/index.cjs +4 -4
  3. package/dist/index.js +3488 -3146
  4. package/dist/klinechart.css +1 -1
  5. package/dist/src/components/KLineChart.vue.d.ts +1 -1
  6. package/dist/src/config/chartSettings.d.ts +1 -0
  7. package/dist/src/core/chart.d.ts +25 -8
  8. package/dist/src/core/controller/interaction.d.ts +4 -0
  9. package/dist/src/core/indicators/bollState.d.ts +34 -0
  10. package/dist/src/core/indicators/calculators.d.ts +129 -0
  11. package/dist/src/core/indicators/cciState.d.ts +15 -0
  12. package/dist/src/core/indicators/eneState.d.ts +30 -0
  13. package/dist/src/core/indicators/expmaState.d.ts +30 -0
  14. package/dist/src/core/indicators/fastkState.d.ts +15 -0
  15. package/dist/src/core/indicators/kstState.d.ts +21 -0
  16. package/dist/src/core/indicators/maState.d.ts +26 -0
  17. package/dist/src/core/indicators/momState.d.ts +15 -0
  18. package/dist/src/core/indicators/rsiState.d.ts +39 -0
  19. package/dist/src/core/indicators/scheduler.d.ts +251 -0
  20. package/dist/src/core/indicators/stochState.d.ts +18 -0
  21. package/dist/src/core/indicators/wmsrState.d.ts +15 -0
  22. package/dist/src/core/layout/pane.d.ts +11 -0
  23. package/dist/src/core/paneRenderer.d.ts +2 -1
  24. package/dist/src/core/renderers/Indicator/boll.d.ts +9 -26
  25. package/dist/src/core/renderers/Indicator/cci.d.ts +2 -19
  26. package/dist/src/core/renderers/Indicator/ene.d.ts +9 -18
  27. package/dist/src/core/renderers/Indicator/expma.d.ts +9 -17
  28. package/dist/src/core/renderers/Indicator/fastk.d.ts +2 -19
  29. package/dist/src/core/renderers/Indicator/index.d.ts +10 -10
  30. package/dist/src/core/renderers/Indicator/kst.d.ts +2 -34
  31. package/dist/src/core/renderers/Indicator/ma.d.ts +10 -10
  32. package/dist/src/core/renderers/Indicator/mainIndicatorLegend.d.ts +3 -3
  33. package/dist/src/core/renderers/Indicator/mom.d.ts +2 -19
  34. package/dist/src/core/renderers/Indicator/rsi.d.ts +3 -27
  35. package/dist/src/core/renderers/Indicator/stoch.d.ts +2 -28
  36. package/dist/src/core/renderers/Indicator/wmsr.d.ts +2 -19
  37. package/dist/src/core/theme/fonts.d.ts +1 -0
  38. package/dist/src/debug/canvasProfiler.d.ts +21 -0
  39. package/dist/src/plugin/rendererPluginManager.d.ts +3 -2
  40. package/dist/src/plugin/types.d.ts +9 -0
  41. package/dist/src/utils/kLineDraw/axis.d.ts +0 -16
  42. package/package.json +2 -1
  43. package/dist/src/utils/kline/ma.d.ts +0 -2
@@ -1,2 +1,2 @@
1
- .kline-tooltip[data-v-d0fe85e6]{z-index:10;color:#000000c7;pointer-events:none;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#ffffffeb;border:1px solid #0000001f;border-radius:8px;min-width:200px;max-width:260px;padding:10px 12px;font-size:12px;line-height:1.4;position:absolute;box-shadow:0 6px 18px #0000001f}.kline-tooltip__title[data-v-d0fe85e6]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.kline-tooltip__grid[data-v-d0fe85e6]{grid-template-columns:1fr;gap:2px;display:grid}.kline-tooltip__grid .row[data-v-d0fe85e6]{justify-content:space-between;gap:10px;display:flex}.kline-tooltip__grid .row span[data-v-d0fe85e6]:first-child{color:#0000008f}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.kline-tooltip.use-anchor[data-v-d0fe85e6]{position-anchor:--kline-tooltip-anchor;left:anchor(left);top:anchor(top);position:absolute}.kline-tooltip.use-anchor.anchor-right-bottom[data-v-d0fe85e6]{transform:translate(14px,14px)}.kline-tooltip.use-anchor.anchor-left-bottom[data-v-d0fe85e6]{transform:translate(calc(-100% - 14px),14px)}}.marker-tooltip[data-v-5574cc25]{z-index:10;color:#000000c7;pointer-events:none;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#ffffffeb;border:1px solid #0000001f;border-radius:8px;min-width:180px;max-width:260px;padding:10px 12px;font-size:12px;line-height:1.4;position:absolute;box-shadow:0 6px 18px #0000001f}.marker-tooltip__title[data-v-5574cc25]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.marker-tooltip__content[data-v-5574cc25]{grid-template-columns:1fr;gap:2px;display:grid}.marker-tooltip__content .row[data-v-5574cc25]{justify-content:space-between;gap:10px;display:flex}.marker-tooltip__content .row span[data-v-5574cc25]:first-child{color:#0000008f}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.marker-tooltip.use-anchor[data-v-5574cc25]{position-anchor:--marker-tooltip-anchor;left:anchor(left);top:anchor(top);position:absolute}.marker-tooltip.use-anchor.anchor-right-bottom[data-v-5574cc25]{transform:translate(12px,12px)}.marker-tooltip.use-anchor.anchor-left-bottom[data-v-5574cc25]{transform:translate(calc(-100% - 12px),12px)}}.params-overlay[data-v-bb1d1eb3]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1000;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.indicator-params[data-v-bb1d1eb3]{background:#fff;border:1px solid #e0e0e0;border-radius:12px;width:90vw;min-width:340px;max-width:420px;overflow:hidden;box-shadow:0 8px 40px #00000026}.params-header[data-v-bb1d1eb3]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-bb1d1eb3]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-bb1d1eb3]{align-items:center;gap:8px;display:flex}.params-title[data-v-bb1d1eb3]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.params-subtitle[data-v-bb1d1eb3]{color:#999;font-size:11px}.toggle-desc-btn[data-v-bb1d1eb3]{cursor:pointer;color:#888;background:#fff;border:1px solid #e0e0e0;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:all .2s;display:flex}.toggle-desc-btn[data-v-bb1d1eb3]:hover{color:#555;background:#f0f0f0;border-color:#ccc}.toggle-desc-btn.active[data-v-bb1d1eb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.toggle-desc-btn svg[data-v-bb1d1eb3]{width:14px;height:14px}.params-close[data-v-bb1d1eb3]{cursor:pointer;color:#888;background:#fff;border:1px solid #e0e0e0;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:background .15s,color .15s,border-color .15s;display:flex}.params-close[data-v-bb1d1eb3]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.params-close svg[data-v-bb1d1eb3]{width:14px;height:14px}.indicator-description[data-v-bb1d1eb3]{background:#f0f7ff;border-bottom:1px solid #d6e8f5;padding:12px 20px}.indicator-description p[data-v-bb1d1eb3]{color:#2c5282;margin:0;font-size:12px;line-height:1.6}.params-body[data-v-bb1d1eb3]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.param-item[data-v-bb1d1eb3]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:10px 14px;transition:border-color .2s}.param-item[data-v-bb1d1eb3]:has(.param-input:focus){border-color:#bbb}.param-item.has-desc[data-v-bb1d1eb3]{padding:10px 14px 8px}.param-header[data-v-bb1d1eb3]{justify-content:space-between;align-items:center;gap:16px;display:flex}.param-label[data-v-bb1d1eb3]{flex-direction:column;gap:3px;display:flex}.param-label-text[data-v-bb1d1eb3]{color:#333;font-size:13px;font-weight:500}.param-range[data-v-bb1d1eb3]{color:#999;font-size:11px}.param-description[data-v-bb1d1eb3]{color:#666;border-top:1px dashed #e0e0e0;margin-top:8px;padding-top:8px;font-size:11px;line-height:1.5}.input-wrapper[data-v-bb1d1eb3]{background:#fff;border:1px solid #d0d0d0;border-radius:7px;align-items:stretch;height:32px;transition:border-color .2s;display:flex;overflow:hidden}.input-wrapper[data-v-bb1d1eb3]:focus-within{border-color:#999}.stepper-btn[data-v-bb1d1eb3]{cursor:pointer;color:#666;background:#f0f0f0;border:none;flex-shrink:0;justify-content:center;align-items:center;width:28px;font-size:15px;font-weight:400;line-height:1;transition:background .15s,color .15s;display:flex}.stepper-btn[data-v-bb1d1eb3]:hover:not(:disabled){color:#333;background:#e0e0e0}.stepper-btn[data-v-bb1d1eb3]:disabled{color:#ccc;cursor:not-allowed}.param-input[data-v-bb1d1eb3]{text-align:center;color:#1a1a1a;appearance:textfield;background:0 0;border:none;border-left:1px solid #e8e8e8;border-right:1px solid #e8e8e8;width:60px;font-size:13px;font-weight:600}.param-input[data-v-bb1d1eb3]::-webkit-inner-spin-button{-webkit-appearance:none}.param-input[data-v-bb1d1eb3]::-webkit-outer-spin-button{-webkit-appearance:none}.param-input[data-v-bb1d1eb3]:focus{outline:none}.params-footer[data-v-bb1d1eb3]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-bb1d1eb3]{gap:8px;display:flex}.params-btn[data-v-bb1d1eb3]{cursor:pointer;border:1px solid #0000;border-radius:7px;align-items:center;gap:5px;padding:6px 14px;font-size:13px;font-weight:500;line-height:1.4;transition:all .15s;display:flex}.params-btn svg[data-v-bb1d1eb3]{flex-shrink:0;width:12px;height:12px}.params-btn.reset[data-v-bb1d1eb3]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.reset[data-v-bb1d1eb3]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.params-btn.cancel[data-v-bb1d1eb3]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.cancel[data-v-bb1d1eb3]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.params-btn.confirm[data-v-bb1d1eb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.params-btn.confirm[data-v-bb1d1eb3]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.params-btn.confirm[data-v-bb1d1eb3]:active{box-shadow:none;transform:translateY(0)}.overlay-enter-active[data-v-bb1d1eb3],.overlay-leave-active[data-v-bb1d1eb3]{transition:opacity .2s}.overlay-enter-from[data-v-bb1d1eb3],.overlay-leave-to[data-v-bb1d1eb3]{opacity:0}.modal-enter-active[data-v-bb1d1eb3]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-bb1d1eb3]{transition:all .16s ease-in}.modal-enter-from[data-v-bb1d1eb3]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-bb1d1eb3]{opacity:0;transform:scale(.94)translateY(8px)}.slide-enter-active[data-v-bb1d1eb3],.slide-leave-active[data-v-bb1d1eb3]{transition:all .2s;overflow:hidden}.slide-enter-from[data-v-bb1d1eb3],.slide-leave-to[data-v-bb1d1eb3]{opacity:0;max-height:0;margin-top:0;padding-top:0;padding-bottom:0}.indicator-selector[data-v-0f3a76b5]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-0f3a76b5]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-0f3a76b5]::-webkit-scrollbar{display:none}.indicator-list[data-v-0f3a76b5]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-0f3a76b5]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-0f3a76b5]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-0f3a76b5],.indicator-item.draggable .indicator-btn[data-v-0f3a76b5],.indicator-item.draggable[data-v-0f3a76b5]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-0f3a76b5]{cursor:move}.indicator-item.is-dragging[data-v-0f3a76b5]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-0f3a76b5]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-0f3a76b5]{position:relative}.indicator-btn[data-v-0f3a76b5]{color:#666;cursor:pointer;white-space:nowrap;background:#fff;border:1px solid #e0e0e0;border-radius:16px;flex-shrink:0;justify-content:center;align-items:center;gap:4px;padding:6px 16px;font-size:13px;font-weight:500;transition:all .3s;display:flex;position:relative;overflow:hidden}.indicator-btn[data-v-0f3a76b5]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-0f3a76b5]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-0f3a76b5]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-0f3a76b5]{z-index:1;position:relative}.param-hint[data-v-0f3a76b5]{opacity:.85;font-size:11px}.hover-overlay[data-v-0f3a76b5]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:2;background:#ffffffd9;border-radius:16px;justify-content:center;align-items:center;gap:4px;display:flex;position:absolute;inset:0}.action-btn[data-v-0f3a76b5]{color:#666;cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;transition:all .2s;display:flex}.action-btn[data-v-0f3a76b5]:hover{color:#333;background:#0000000f}.settings-btn[data-v-0f3a76b5]:hover{color:#1a1a1a}.remove-btn[data-v-0f3a76b5]:hover{color:#ff4d4f}.divider[data-v-0f3a76b5]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-0f3a76b5]{anchor-name:--indicator-add-btn;color:#999;cursor:pointer;background:0 0;border:1px dashed #d9d9d9;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:32px;height:32px;padding:0;transition:all .3s;display:flex}.add-btn[data-v-0f3a76b5]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.add-menu[data-v-0f3a76b5]{white-space:nowrap;z-index:9999;background:#fff;border-radius:8px;padding:8px 0;position:fixed;transform:translate(-50%);box-shadow:0 6px 16px #00000014,0 3px 6px -4px #0000001f,0 9px 28px 8px #0000000d}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.add-menu.use-anchor[data-v-0f3a76b5]{position-anchor:--indicator-add-btn;left:anchor(center);top:anchor(top);max-width:calc(100vw - 16px);position:fixed;transform:translate(-50%,calc(-100% - 8px))}}.menu-section[data-v-0f3a76b5]{padding:4px 0}.menu-section[data-v-0f3a76b5]:not(:last-child){border-bottom:1px solid #f0f0f0}.menu-title[data-v-0f3a76b5]{color:#999;padding:4px 16px;font-size:12px;font-weight:500}.menu-items[data-v-0f3a76b5]{flex-direction:column;gap:2px;display:flex}.menu-item[data-v-0f3a76b5]{text-align:left;color:#333;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;width:100%;padding:8px 16px;font-size:13px;transition:background .2s;display:flex}.menu-item[data-v-0f3a76b5]:hover:not(.disabled){background:#f5f5f5}.menu-item.disabled[data-v-0f3a76b5]{color:#999;cursor:not-allowed}.menu-item .param-hint[data-v-0f3a76b5]{color:#999;font-size:11px}.active-tag[data-v-0f3a76b5]{color:#1a1a1a;align-items:center;margin-left:auto;display:flex}.fade-enter-active[data-v-0f3a76b5],.fade-leave-active[data-v-0f3a76b5]{transition:opacity .2s}.fade-enter-from[data-v-0f3a76b5],.fade-leave-to[data-v-0f3a76b5]{opacity:0}.slide-enter-active[data-v-0f3a76b5],.slide-leave-active[data-v-0f3a76b5]{transition:all .2s}.slide-enter-from[data-v-0f3a76b5],.slide-leave-to[data-v-0f3a76b5]{opacity:0;transform:translate(-50%)translateY(8px)}.drawing-style-toolbar[data-v-088ccef5]{-webkit-backdrop-filter:blur(8px);z-index:100;-webkit-user-select:none;user-select:none;pointer-events:auto;background:#fafbfce0;border:1px solid #e5e7eb;border-radius:6px;align-items:center;gap:6px;height:32px;padding:4px 8px;display:flex;position:absolute;top:8px;left:50%;transform:translate(-50%);box-shadow:0 1px 3px #0000000f}.toolbar-item[data-v-088ccef5]{justify-content:center;align-items:center;display:inline-flex}.color-item[data-v-088ccef5]{width:24px;height:24px;position:relative}.color-swatch[data-v-088ccef5]{cursor:pointer;border:1px solid #d1d5db;border-radius:4px;width:100%;height:100%;display:block}.color-input[data-v-088ccef5]{opacity:0;cursor:pointer;width:100%;height:100%;position:absolute;inset:0}.toolbar-select[data-v-088ccef5]{color:#374151;cursor:pointer;background:#fff;border:1px solid #d1d5db;border-radius:4px;outline:none;height:24px;padding:0 4px;font-size:12px}.toolbar-select[data-v-088ccef5]:hover{border-color:#9ca3af}.toolbar-btn[data-v-088ccef5]{color:#6b7280;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;width:24px;height:24px;padding:0;transition:border-color .15s,background .15s,color .15s;display:inline-flex}.toolbar-btn[data-v-088ccef5]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.delete-btn[data-v-088ccef5]:hover{color:#dc2626;background:#fef2f2;border-color:#fca5a5}.delete-icon[data-v-088ccef5]{width:14px;height:14px}.left-toolbar[data-v-1f5465f7]{box-sizing:border-box;-webkit-user-select:none;user-select:none;background:#fafbfc;border:1px solid #e5e7eb;border-radius:6px;flex-direction:column;flex:0 0 40px;align-items:center;gap:6px;padding:8px 5px;display:flex;box-shadow:0 1px 3px #0000000f}.left-toolbar__group[data-v-1f5465f7]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-1f5465f7]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-1f5465f7]{color:#6b7280;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:border-color .15s,background .15s,color .15s;display:inline-flex;position:relative}.left-toolbar__button[data-v-1f5465f7]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-1f5465f7]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-1f5465f7]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-1f5465f7]{width:16px;height:16px}.corner-indicator[data-v-1f5465f7]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-1f5465f7]:after{content:"";opacity:.45;border-bottom:5px solid;border-left:5px solid #0000;width:0;height:0;transition:opacity .15s;position:absolute;bottom:0;right:0}.left-toolbar__button:hover .corner-indicator[data-v-1f5465f7]:after,.left-toolbar__button.active .corner-indicator[data-v-1f5465f7]:after{opacity:.7}.corner-indicator.open[data-v-1f5465f7]:after{opacity:.8}.tool-dropdown[data-v-1f5465f7]{-webkit-backdrop-filter:blur(8px);box-sizing:border-box;z-index:100;background:#fafbfcd1;border:1px solid #e5e7eb;border-radius:6px;flex-direction:row;align-items:center;gap:4px;height:40px;padding:0 5px;display:flex;position:absolute;top:50%;left:calc(100% + 13px);transform:translateY(-50%);box-shadow:0 1px 3px #0000000f}.tool-item[data-v-1f5465f7]{position:relative}.dropdown-enter-active[data-v-1f5465f7],.dropdown-leave-active[data-v-1f5465f7]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-1f5465f7],.dropdown-leave-to[data-v-1f5465f7]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-1f5465f7]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-1f5465f7]{gap:3px}.left-toolbar__button[data-v-1f5465f7]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-1f5465f7]{width:16px}.corner-indicator[data-v-1f5465f7]{width:7px;height:7px}.corner-indicator[data-v-1f5465f7]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-1f5465f7]{height:36px}}.settings-overlay[data-v-1f5465f7]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1000;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.settings-modal[data-v-1f5465f7]{background:#fff;border:1px solid #e0e0e0;border-radius:12px;width:90vw;min-width:340px;max-width:420px;overflow:hidden;box-shadow:0 8px 40px #00000026}.settings-header[data-v-1f5465f7]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-1f5465f7]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-1f5465f7]{align-items:center;gap:8px;display:flex}.settings-title[data-v-1f5465f7]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.settings-subtitle[data-v-1f5465f7]{color:#999;font-size:11px}.settings-close[data-v-1f5465f7]{cursor:pointer;color:#888;background:#fff;border:1px solid #e0e0e0;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:background .15s,color .15s,border-color .15s;display:flex}.settings-close[data-v-1f5465f7]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.settings-close svg[data-v-1f5465f7]{width:14px;height:14px}.settings-body[data-v-1f5465f7]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.settings-item[data-v-1f5465f7]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:8px 12px}.settings-label[data-v-1f5465f7]{color:#333;cursor:pointer;justify-content:space-between;align-items:center;font-size:13px;display:flex}.settings-checkbox[data-v-1f5465f7]{cursor:pointer;accent-color:#1a1a1a;width:16px;height:16px}.settings-footer[data-v-1f5465f7]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-1f5465f7]{gap:8px;display:flex}.settings-btn[data-v-1f5465f7]{cursor:pointer;border:1px solid #0000;border-radius:7px;align-items:center;gap:5px;padding:6px 14px;font-size:13px;font-weight:500;line-height:1.4;transition:all .15s;display:flex}.settings-btn svg[data-v-1f5465f7]{flex-shrink:0;width:12px;height:12px}.settings-btn.reset[data-v-1f5465f7]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.reset[data-v-1f5465f7]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.settings-btn.cancel[data-v-1f5465f7]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.cancel[data-v-1f5465f7]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.settings-btn.confirm[data-v-1f5465f7]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.settings-btn.confirm[data-v-1f5465f7]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.settings-btn.confirm[data-v-1f5465f7]:active{box-shadow:none;transform:translateY(0)}.chart-wrapper[data-v-fff9d345]{--kmap-height:var(--kmap-chart-height,100%);--kmap-width:var(--kmap-chart-width,100%);width:var(--kmap-width);height:var(--kmap-height);flex-direction:column;justify-content:center;align-items:center;min-height:300px;display:flex}.chart-stage[data-v-fff9d345]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-fff9d345]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-fff9d345]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-fff9d345]{opacity:1;box-sizing:border-box;border-top:1px solid #e5e7eb;height:0;transition:border-top-color .12s,border-top-width .12s,margin-top .12s,opacity .12s;position:absolute;left:0;right:0}.pane-separator-line.is-active[data-v-fff9d345]{border-top-width:2px;border-top-color:#3b82f6;margin-top:-1px}.chart-stage.is-resizing-pane[data-v-fff9d345],.chart-stage.is-hovering-pane-separator[data-v-fff9d345]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-fff9d345]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-fff9d345]{cursor:ns-resize}.chart-stage.is-dragging[data-v-fff9d345]{cursor:grabbing}.chart-container[data-v-fff9d345]{height:100%;min-height:inherit;scrollbar-width:none;-ms-overflow-style:none;box-sizing:border-box;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:none;background:#fff;border:1px solid #e5e7eb;border-right:0;border-radius:6px 0 0 6px;flex:auto;position:relative;overflow:auto hidden}.chart-container[data-v-fff9d345]::-webkit-scrollbar{display:none}.chart-container[data-v-fff9d345]:hover{cursor:crosshair}.chart-stage.is-resizing-pane .chart-container[data-v-fff9d345],.chart-stage.is-hovering-pane-separator .chart-container[data-v-fff9d345]{cursor:ns-resize}.chart-stage.is-hovering-kline .chart-container[data-v-fff9d345]{cursor:pointer}.chart-stage.is-dragging .chart-container[data-v-fff9d345]{cursor:grabbing}.right-axis-host[data-v-fff9d345]{height:100%;min-height:inherit;box-sizing:border-box;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:none;background:#fff;border:1px solid #e5e7eb;border-top-right-radius:6px;border-bottom-right-radius:6px;flex:none;position:relative;overflow:visible}.scroll-content[data-v-fff9d345]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-fff9d345]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-layer[data-v-fff9d345]{pointer-events:none;z-index:30;position:absolute;inset:0}.tooltip-anchor[data-v-fff9d345]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-fff9d345]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-fff9d345]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-fff9d345]{gap:6px}}.plot-canvas{display:block;position:absolute;top:0;left:0}.right-axis{display:block;position:absolute;left:0}.x-axis-canvas{z-index:10;display:block;position:absolute;bottom:0;left:0}.right-axis{z-index:15}
1
+ .kline-tooltip[data-v-d0fe85e6]{z-index:10;color:#000000c7;pointer-events:none;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#ffffffeb;border:1px solid #0000001f;border-radius:8px;min-width:200px;max-width:260px;padding:10px 12px;font-size:12px;line-height:1.4;position:absolute;box-shadow:0 6px 18px #0000001f}.kline-tooltip__title[data-v-d0fe85e6]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.kline-tooltip__grid[data-v-d0fe85e6]{grid-template-columns:1fr;gap:2px;display:grid}.kline-tooltip__grid .row[data-v-d0fe85e6]{justify-content:space-between;gap:10px;display:flex}.kline-tooltip__grid .row span[data-v-d0fe85e6]:first-child{color:#0000008f}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.kline-tooltip.use-anchor[data-v-d0fe85e6]{position-anchor:--kline-tooltip-anchor;left:anchor(left);top:anchor(top);position:absolute}.kline-tooltip.use-anchor.anchor-right-bottom[data-v-d0fe85e6]{transform:translate(14px,14px)}.kline-tooltip.use-anchor.anchor-left-bottom[data-v-d0fe85e6]{transform:translate(calc(-100% - 14px),14px)}}.marker-tooltip[data-v-5574cc25]{z-index:10;color:#000000c7;pointer-events:none;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#ffffffeb;border:1px solid #0000001f;border-radius:8px;min-width:180px;max-width:260px;padding:10px 12px;font-size:12px;line-height:1.4;position:absolute;box-shadow:0 6px 18px #0000001f}.marker-tooltip__title[data-v-5574cc25]{justify-content:space-between;gap:10px;margin-bottom:6px;font-weight:600;display:flex}.marker-tooltip__content[data-v-5574cc25]{grid-template-columns:1fr;gap:2px;display:grid}.marker-tooltip__content .row[data-v-5574cc25]{justify-content:space-between;gap:10px;display:flex}.marker-tooltip__content .row span[data-v-5574cc25]:first-child{color:#0000008f}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.marker-tooltip.use-anchor[data-v-5574cc25]{position-anchor:--marker-tooltip-anchor;left:anchor(left);top:anchor(top);position:absolute}.marker-tooltip.use-anchor.anchor-right-bottom[data-v-5574cc25]{transform:translate(12px,12px)}.marker-tooltip.use-anchor.anchor-left-bottom[data-v-5574cc25]{transform:translate(calc(-100% - 12px),12px)}}.params-overlay[data-v-bb1d1eb3]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1000;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.indicator-params[data-v-bb1d1eb3]{background:#fff;border:1px solid #e0e0e0;border-radius:12px;width:90vw;min-width:340px;max-width:420px;overflow:hidden;box-shadow:0 8px 40px #00000026}.params-header[data-v-bb1d1eb3]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-bb1d1eb3]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-bb1d1eb3]{align-items:center;gap:8px;display:flex}.params-title[data-v-bb1d1eb3]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.params-subtitle[data-v-bb1d1eb3]{color:#999;font-size:11px}.toggle-desc-btn[data-v-bb1d1eb3]{cursor:pointer;color:#888;background:#fff;border:1px solid #e0e0e0;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:all .2s;display:flex}.toggle-desc-btn[data-v-bb1d1eb3]:hover{color:#555;background:#f0f0f0;border-color:#ccc}.toggle-desc-btn.active[data-v-bb1d1eb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.toggle-desc-btn svg[data-v-bb1d1eb3]{width:14px;height:14px}.params-close[data-v-bb1d1eb3]{cursor:pointer;color:#888;background:#fff;border:1px solid #e0e0e0;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:background .15s,color .15s,border-color .15s;display:flex}.params-close[data-v-bb1d1eb3]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.params-close svg[data-v-bb1d1eb3]{width:14px;height:14px}.indicator-description[data-v-bb1d1eb3]{background:#f0f7ff;border-bottom:1px solid #d6e8f5;padding:12px 20px}.indicator-description p[data-v-bb1d1eb3]{color:#2c5282;margin:0;font-size:12px;line-height:1.6}.params-body[data-v-bb1d1eb3]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.param-item[data-v-bb1d1eb3]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:10px 14px;transition:border-color .2s}.param-item[data-v-bb1d1eb3]:has(.param-input:focus){border-color:#bbb}.param-item.has-desc[data-v-bb1d1eb3]{padding:10px 14px 8px}.param-header[data-v-bb1d1eb3]{justify-content:space-between;align-items:center;gap:16px;display:flex}.param-label[data-v-bb1d1eb3]{flex-direction:column;gap:3px;display:flex}.param-label-text[data-v-bb1d1eb3]{color:#333;font-size:13px;font-weight:500}.param-range[data-v-bb1d1eb3]{color:#999;font-size:11px}.param-description[data-v-bb1d1eb3]{color:#666;border-top:1px dashed #e0e0e0;margin-top:8px;padding-top:8px;font-size:11px;line-height:1.5}.input-wrapper[data-v-bb1d1eb3]{background:#fff;border:1px solid #d0d0d0;border-radius:7px;align-items:stretch;height:32px;transition:border-color .2s;display:flex;overflow:hidden}.input-wrapper[data-v-bb1d1eb3]:focus-within{border-color:#999}.stepper-btn[data-v-bb1d1eb3]{cursor:pointer;color:#666;background:#f0f0f0;border:none;flex-shrink:0;justify-content:center;align-items:center;width:28px;font-size:15px;font-weight:400;line-height:1;transition:background .15s,color .15s;display:flex}.stepper-btn[data-v-bb1d1eb3]:hover:not(:disabled){color:#333;background:#e0e0e0}.stepper-btn[data-v-bb1d1eb3]:disabled{color:#ccc;cursor:not-allowed}.param-input[data-v-bb1d1eb3]{text-align:center;color:#1a1a1a;appearance:textfield;background:0 0;border:none;border-left:1px solid #e8e8e8;border-right:1px solid #e8e8e8;width:60px;font-size:13px;font-weight:600}.param-input[data-v-bb1d1eb3]::-webkit-inner-spin-button{-webkit-appearance:none}.param-input[data-v-bb1d1eb3]::-webkit-outer-spin-button{-webkit-appearance:none}.param-input[data-v-bb1d1eb3]:focus{outline:none}.params-footer[data-v-bb1d1eb3]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-bb1d1eb3]{gap:8px;display:flex}.params-btn[data-v-bb1d1eb3]{cursor:pointer;border:1px solid #0000;border-radius:7px;align-items:center;gap:5px;padding:6px 14px;font-size:13px;font-weight:500;line-height:1.4;transition:all .15s;display:flex}.params-btn svg[data-v-bb1d1eb3]{flex-shrink:0;width:12px;height:12px}.params-btn.reset[data-v-bb1d1eb3]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.reset[data-v-bb1d1eb3]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.params-btn.cancel[data-v-bb1d1eb3]{color:#666;background:0 0;border-color:#d0d0d0}.params-btn.cancel[data-v-bb1d1eb3]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.params-btn.confirm[data-v-bb1d1eb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.params-btn.confirm[data-v-bb1d1eb3]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.params-btn.confirm[data-v-bb1d1eb3]:active{box-shadow:none;transform:translateY(0)}.overlay-enter-active[data-v-bb1d1eb3],.overlay-leave-active[data-v-bb1d1eb3]{transition:opacity .2s}.overlay-enter-from[data-v-bb1d1eb3],.overlay-leave-to[data-v-bb1d1eb3]{opacity:0}.modal-enter-active[data-v-bb1d1eb3]{transition:all .22s cubic-bezier(.34,1.56,.64,1)}.modal-leave-active[data-v-bb1d1eb3]{transition:all .16s ease-in}.modal-enter-from[data-v-bb1d1eb3]{opacity:0;transform:scale(.88)translateY(-16px)}.modal-leave-to[data-v-bb1d1eb3]{opacity:0;transform:scale(.94)translateY(8px)}.slide-enter-active[data-v-bb1d1eb3],.slide-leave-active[data-v-bb1d1eb3]{transition:all .2s;overflow:hidden}.slide-enter-from[data-v-bb1d1eb3],.slide-leave-to[data-v-bb1d1eb3]{opacity:0;max-height:0;margin-top:0;padding-top:0;padding-bottom:0}.indicator-selector[data-v-0f3a76b5]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-0f3a76b5]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-0f3a76b5]::-webkit-scrollbar{display:none}.indicator-list[data-v-0f3a76b5]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-0f3a76b5]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-0f3a76b5]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-0f3a76b5],.indicator-item.draggable .indicator-btn[data-v-0f3a76b5],.indicator-item.draggable[data-v-0f3a76b5]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-0f3a76b5]{cursor:move}.indicator-item.is-dragging[data-v-0f3a76b5]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-0f3a76b5]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-0f3a76b5]{position:relative}.indicator-btn[data-v-0f3a76b5]{color:#666;cursor:pointer;white-space:nowrap;background:#fff;border:1px solid #e0e0e0;border-radius:16px;flex-shrink:0;justify-content:center;align-items:center;gap:4px;padding:6px 16px;font-size:13px;font-weight:500;transition:all .3s;display:flex;position:relative;overflow:hidden}.indicator-btn[data-v-0f3a76b5]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-0f3a76b5]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-0f3a76b5]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-0f3a76b5]{z-index:1;position:relative}.param-hint[data-v-0f3a76b5]{opacity:.85;font-size:11px}.hover-overlay[data-v-0f3a76b5]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:2;background:#ffffffd9;border-radius:16px;justify-content:center;align-items:center;gap:4px;display:flex;position:absolute;inset:0}.action-btn[data-v-0f3a76b5]{color:#666;cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;width:24px;height:24px;padding:0;transition:all .2s;display:flex}.action-btn[data-v-0f3a76b5]:hover{color:#333;background:#0000000f}.settings-btn[data-v-0f3a76b5]:hover{color:#1a1a1a}.remove-btn[data-v-0f3a76b5]:hover{color:#ff4d4f}.divider[data-v-0f3a76b5]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-0f3a76b5]{anchor-name:--indicator-add-btn;color:#999;cursor:pointer;background:0 0;border:1px dashed #d9d9d9;border-radius:50%;flex-shrink:0;justify-content:center;align-items:center;width:32px;height:32px;padding:0;transition:all .3s;display:flex}.add-btn[data-v-0f3a76b5]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.add-menu[data-v-0f3a76b5]{white-space:nowrap;z-index:9999;background:#fff;border-radius:8px;padding:8px 0;position:fixed;transform:translate(-50%);box-shadow:0 6px 16px #00000014,0 3px 6px -4px #0000001f,0 9px 28px 8px #0000000d}@supports (anchor-name:--kmap-anchor) and (position-anchor:--kmap-anchor){.add-menu.use-anchor[data-v-0f3a76b5]{position-anchor:--indicator-add-btn;left:anchor(center);top:anchor(top);max-width:calc(100vw - 16px);position:fixed;transform:translate(-50%,calc(-100% - 8px))}}.menu-section[data-v-0f3a76b5]{padding:4px 0}.menu-section[data-v-0f3a76b5]:not(:last-child){border-bottom:1px solid #f0f0f0}.menu-title[data-v-0f3a76b5]{color:#999;padding:4px 16px;font-size:12px;font-weight:500}.menu-items[data-v-0f3a76b5]{flex-direction:column;gap:2px;display:flex}.menu-item[data-v-0f3a76b5]{text-align:left;color:#333;cursor:pointer;background:0 0;border:none;align-items:center;gap:8px;width:100%;padding:8px 16px;font-size:13px;transition:background .2s;display:flex}.menu-item[data-v-0f3a76b5]:hover:not(.disabled){background:#f5f5f5}.menu-item.disabled[data-v-0f3a76b5]{color:#999;cursor:not-allowed}.menu-item .param-hint[data-v-0f3a76b5]{color:#999;font-size:11px}.active-tag[data-v-0f3a76b5]{color:#1a1a1a;align-items:center;margin-left:auto;display:flex}.fade-enter-active[data-v-0f3a76b5],.fade-leave-active[data-v-0f3a76b5]{transition:opacity .2s}.fade-enter-from[data-v-0f3a76b5],.fade-leave-to[data-v-0f3a76b5]{opacity:0}.slide-enter-active[data-v-0f3a76b5],.slide-leave-active[data-v-0f3a76b5]{transition:all .2s}.slide-enter-from[data-v-0f3a76b5],.slide-leave-to[data-v-0f3a76b5]{opacity:0;transform:translate(-50%)translateY(8px)}.drawing-style-toolbar[data-v-92699cb2]{-webkit-backdrop-filter:blur(8px);z-index:100;-webkit-user-select:none;user-select:none;pointer-events:auto;background:#fafbfce0;border:1px solid #e5e7eb;border-radius:6px;align-items:center;gap:6px;height:32px;padding:4px 8px;display:flex;position:absolute;top:8px;left:50%;transform:translate(-50%);box-shadow:0 1px 3px #0000000f}.toolbar-item[data-v-92699cb2]{justify-content:center;align-items:center;display:inline-flex}.color-item[data-v-92699cb2]{width:24px;height:24px;position:relative}.color-swatch[data-v-92699cb2]{cursor:pointer;border:1px solid #d1d5db;border-radius:4px;width:100%;height:100%;display:block}.color-input[data-v-92699cb2]{opacity:0;cursor:pointer;width:100%;height:100%;position:absolute;inset:0}.toolbar-select[data-v-92699cb2]{color:#374151;cursor:pointer;background:#fff;border:1px solid #d1d5db;border-radius:4px;outline:none;height:24px;padding:0 4px;font-size:12px}.toolbar-select[data-v-92699cb2]:hover{border-color:#9ca3af}.toolbar-btn[data-v-92699cb2]{color:#6b7280;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;width:24px;height:24px;padding:0;transition:border-color .15s,background .15s,color .15s;display:inline-flex}.toolbar-btn[data-v-92699cb2]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.delete-btn[data-v-92699cb2]:hover{color:#dc2626;background:#fef2f2;border-color:#fca5a5}.delete-icon[data-v-92699cb2]{width:14px;height:14px}.left-toolbar[data-v-43b6f5f6]{box-sizing:border-box;-webkit-user-select:none;user-select:none;background:#fafbfc;border:1px solid #e5e7eb;border-radius:6px;flex-direction:column;flex:0 0 40px;align-items:center;gap:6px;padding:8px 5px;display:flex;box-shadow:0 1px 3px #0000000f}.left-toolbar__group[data-v-43b6f5f6]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-43b6f5f6]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-43b6f5f6]{color:#6b7280;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:4px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:border-color .15s,background .15s,color .15s;display:inline-flex;position:relative}.left-toolbar__button[data-v-43b6f5f6]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-43b6f5f6]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-43b6f5f6]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-43b6f5f6]{width:16px;height:16px}.corner-indicator[data-v-43b6f5f6]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-43b6f5f6]:after{content:"";opacity:.45;border-bottom:5px solid;border-left:5px solid #0000;width:0;height:0;transition:opacity .15s;position:absolute;bottom:0;right:0}.left-toolbar__button:hover .corner-indicator[data-v-43b6f5f6]:after,.left-toolbar__button.active .corner-indicator[data-v-43b6f5f6]:after{opacity:.7}.corner-indicator.open[data-v-43b6f5f6]:after{opacity:.8}.tool-dropdown[data-v-43b6f5f6]{-webkit-backdrop-filter:blur(8px);box-sizing:border-box;z-index:100;background:#fafbfcd1;border:1px solid #e5e7eb;border-radius:6px;flex-direction:row;align-items:center;gap:4px;height:40px;padding:0 5px;display:flex;position:absolute;top:50%;left:calc(100% + 13px);transform:translateY(-50%);box-shadow:0 1px 3px #0000000f}.tool-item[data-v-43b6f5f6]{position:relative}.dropdown-enter-active[data-v-43b6f5f6],.dropdown-leave-active[data-v-43b6f5f6]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-43b6f5f6],.dropdown-leave-to[data-v-43b6f5f6]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-43b6f5f6]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-43b6f5f6]{gap:3px}.left-toolbar__button[data-v-43b6f5f6]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-43b6f5f6]{width:16px}.corner-indicator[data-v-43b6f5f6]{width:7px;height:7px}.corner-indicator[data-v-43b6f5f6]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-43b6f5f6]{height:36px}}.settings-overlay[data-v-43b6f5f6]{-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);z-index:1000;background:#0000004d;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.settings-modal[data-v-43b6f5f6]{background:#fff;border:1px solid #e0e0e0;border-radius:12px;width:90vw;min-width:340px;max-width:420px;overflow:hidden;box-shadow:0 8px 40px #00000026}.settings-header[data-v-43b6f5f6]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-43b6f5f6]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-43b6f5f6]{align-items:center;gap:8px;display:flex}.settings-title[data-v-43b6f5f6]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.settings-subtitle[data-v-43b6f5f6]{color:#999;font-size:11px}.settings-close[data-v-43b6f5f6]{cursor:pointer;color:#888;background:#fff;border:1px solid #e0e0e0;border-radius:6px;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:background .15s,color .15s,border-color .15s;display:flex}.settings-close[data-v-43b6f5f6]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.settings-close svg[data-v-43b6f5f6]{width:14px;height:14px}.settings-body[data-v-43b6f5f6]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.settings-item[data-v-43b6f5f6]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:8px 12px}.settings-label[data-v-43b6f5f6]{color:#333;cursor:pointer;justify-content:space-between;align-items:center;font-size:13px;display:flex}.settings-checkbox[data-v-43b6f5f6]{cursor:pointer;accent-color:#1a1a1a;width:16px;height:16px}.settings-section-divider[data-v-43b6f5f6]{align-items:center;gap:8px;margin-top:4px;display:flex}.settings-section-divider[data-v-43b6f5f6]:before,.settings-section-divider[data-v-43b6f5f6]:after{content:"";border-top:1px solid #e0e0e0;flex:1}.settings-section-label[data-v-43b6f5f6]{color:#999;white-space:nowrap;font-size:11px}.settings-item.experimental[data-v-43b6f5f6]{background:#fdf8f3;border-color:#f0e0d0}.settings-footer[data-v-43b6f5f6]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-43b6f5f6]{gap:8px;display:flex}.settings-btn[data-v-43b6f5f6]{cursor:pointer;border:1px solid #0000;border-radius:7px;align-items:center;gap:5px;padding:6px 14px;font-size:13px;font-weight:500;line-height:1.4;transition:all .15s;display:flex}.settings-btn svg[data-v-43b6f5f6]{flex-shrink:0;width:12px;height:12px}.settings-btn.reset[data-v-43b6f5f6]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.reset[data-v-43b6f5f6]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.settings-btn.cancel[data-v-43b6f5f6]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.cancel[data-v-43b6f5f6]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.settings-btn.confirm[data-v-43b6f5f6]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.settings-btn.confirm[data-v-43b6f5f6]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.settings-btn.confirm[data-v-43b6f5f6]:active{box-shadow:none;transform:translateY(0)}.chart-wrapper[data-v-59c0bc54]{--kmap-height:var(--kmap-chart-height,100%);--kmap-width:var(--kmap-chart-width,100%);width:var(--kmap-width);height:var(--kmap-height);flex-direction:column;justify-content:center;align-items:center;min-height:300px;display:flex}.chart-stage[data-v-59c0bc54]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-59c0bc54]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-59c0bc54]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-59c0bc54]{opacity:1;box-sizing:border-box;border-top:1px solid #e5e7eb;height:0;transition:border-top-color .12s,border-top-width .12s,margin-top .12s,opacity .12s;position:absolute;left:0;right:0}.pane-separator-line.is-active[data-v-59c0bc54]{border-top-width:2px;border-top-color:#3b82f6;margin-top:-1px}.chart-stage.is-resizing-pane[data-v-59c0bc54],.chart-stage.is-hovering-pane-separator[data-v-59c0bc54]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-59c0bc54]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-59c0bc54]{cursor:ns-resize}.chart-stage.is-dragging[data-v-59c0bc54]{cursor:grabbing}.chart-container[data-v-59c0bc54]{height:100%;min-height:inherit;scrollbar-width:none;-ms-overflow-style:none;box-sizing:border-box;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:none;background:#fff;border:1px solid #e5e7eb;border-right:0;border-radius:6px 0 0 6px;flex:auto;position:relative;overflow:auto hidden}.chart-container[data-v-59c0bc54]::-webkit-scrollbar{display:none}.chart-container[data-v-59c0bc54]:hover{cursor:crosshair}.chart-stage.is-resizing-pane .chart-container[data-v-59c0bc54],.chart-stage.is-hovering-pane-separator .chart-container[data-v-59c0bc54]{cursor:ns-resize}.chart-stage.is-hovering-kline .chart-container[data-v-59c0bc54]{cursor:pointer}.chart-stage.is-dragging .chart-container[data-v-59c0bc54]{cursor:grabbing}.right-axis-host[data-v-59c0bc54]{height:100%;min-height:inherit;box-sizing:border-box;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;touch-action:none;background:#fff;border:1px solid #e5e7eb;border-top-right-radius:6px;border-bottom-right-radius:6px;flex:none;position:relative;overflow:visible}.scroll-content[data-v-59c0bc54]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-59c0bc54]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-layer[data-v-59c0bc54]{pointer-events:none;z-index:30;position:absolute;inset:0}.tooltip-anchor[data-v-59c0bc54]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-59c0bc54]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-59c0bc54]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-59c0bc54]{gap:6px}}.plot-canvas{display:block;position:absolute;top:0;left:0}.right-axis{display:block;position:absolute;left:0}.x-axis-canvas{z-index:10;display:block;position:absolute;bottom:0;left:0}.right-axis{z-index:15}
2
2
  /*$vite$:1*/
@@ -20,7 +20,7 @@ type __VLS_Props = {
20
20
  isFullscreen?: boolean;
21
21
  };
22
22
  declare function scheduleRender(): void;
23
- declare function addSubPane(indicatorId?: SubIndicatorType, params?: Record<string, number>): boolean;
23
+ declare function addSubPane(indicatorId?: SubIndicatorType, params?: Record<string, number | boolean>): boolean;
24
24
  declare function removeSubPane(paneId: string): void;
25
25
  declare function clearAllSubPanes(): void;
26
26
  declare function switchSubIndicator(paneId: string, newIndicatorId: SubIndicatorType): void;
@@ -6,6 +6,7 @@ export interface SettingItem {
6
6
  label: string;
7
7
  type: 'boolean';
8
8
  default: boolean;
9
+ group?: string;
9
10
  }
10
11
  /** 默认设置配置 */
11
12
  export declare const DEFAULT_SETTINGS: SettingItem[];
@@ -1,9 +1,10 @@
1
1
  import { KLineData } from '../types/price';
2
- import { VisibleRange } from './layout/pane';
2
+ import { VisibleRange, UpdateLevel } from './layout/pane';
3
3
  import { InteractionController } from './controller/interaction';
4
4
  import { PaneRenderer } from './paneRenderer';
5
5
  import { MarkerManager, CustomMarkerEntity } from './marker/registry';
6
6
  import { getPhysicalKLineConfig, calcKWidthPx } from './utils/klineConfig';
7
+ import { IndicatorScheduler } from './indicators/scheduler';
7
8
  import { PluginHostImpl, RendererPlugin, RendererPluginWithHost, PaneRole, PaneCapabilities } from '../plugin';
8
9
  import { SubIndicatorType } from './renderers/Indicator';
9
10
  export { getPhysicalKLineConfig, calcKWidthPx };
@@ -39,7 +40,8 @@ export type PaneSpec = {
39
40
  capabilities?: Partial<PaneCapabilities>;
40
41
  };
41
42
  export type PaneRendererDom = {
42
- plotCanvas: HTMLCanvasElement;
43
+ mainCanvas: HTMLCanvasElement;
44
+ overlayCanvas: HTMLCanvasElement;
43
45
  yAxisCanvas: HTMLCanvasElement;
44
46
  };
45
47
  export type ChartOptions = {
@@ -90,6 +92,7 @@ export declare class Chart {
90
92
  private opt;
91
93
  private data;
92
94
  private raf;
95
+ private pendingUpdateLevel;
93
96
  private viewport;
94
97
  private paneRenderers;
95
98
  private markerManager;
@@ -119,6 +122,12 @@ export declare class Chart {
119
122
  private currentZoomLevel;
120
123
  /** 缩放级别总数 */
121
124
  private readonly zoomLevelCount;
125
+ /** 指标调度器(负责计算 MA 等指标并写入 StateStore)
126
+ * TODO: 阶段5迁移为插件注册,Scheduler 通过事件监听 data/viewport 变更,Chart 不直接持有
127
+ */
128
+ private indicatorScheduler;
129
+ /** 上次可见范围(用于检测视口变化) */
130
+ private lastVisibleRange;
122
131
  /**
123
132
  * 创建图表实例
124
133
  * @param dom 由 Vue 组件传入的 DOM 句柄
@@ -146,8 +155,11 @@ export declare class Chart {
146
155
  getAllRenderers(): RendererPlugin[];
147
156
  /** 更新用户设置(触发重绘) */
148
157
  updateSettings(settings: Record<string, boolean>): void;
149
- /** 绘制一帧 */
150
- draw(): void;
158
+ /**
159
+ * 绘制一帧
160
+ * @param level 更新级别,决定渲染哪些层
161
+ */
162
+ draw(level?: UpdateLevel): void;
151
163
  /**
152
164
  * 应用渲染状态(由 Vue/Store 层在状态更新后调用)
153
165
  * Chart 不拥有业务 SSOT,只负责接收参数并渲染
@@ -192,7 +204,7 @@ export declare class Chart {
192
204
  setPaneDefinitions(defs: PaneSpec[]): void;
193
205
  upsertPane(def: PaneSpec): void;
194
206
  removePaneDefinition(paneId: string): void;
195
- bindIndicatorToPane(paneId: string, indicatorId: SubIndicatorType, params?: Record<string, number>): void;
207
+ bindIndicatorToPane(paneId: string, indicatorId: SubIndicatorType, params?: Record<string, number | boolean>): void;
196
208
  /** 更新绘图对象 */
197
209
  setDrawings(drawings: import('../plugin').DrawingObject[]): void;
198
210
  /** 更新选中的绘图 ID */
@@ -227,7 +239,7 @@ export declare class Chart {
227
239
  * @param params 指标参数
228
240
  * @returns 是否创建成功
229
241
  */
230
- createSubPane(indicatorId: SubIndicatorType, params?: Record<string, number>): boolean;
242
+ createSubPane(indicatorId: SubIndicatorType, params?: Record<string, number | boolean>): boolean;
231
243
  /**
232
244
  * 移除副图面板及其渲染器
233
245
  * @param indicatorId 指标类型
@@ -260,6 +272,8 @@ export declare class Chart {
260
272
  updateData(data: KLineData[]): void;
261
273
  /** 获取当前数据源(供 renderers 和 interaction 使用) */
262
274
  getData(): KLineData[];
275
+ /** 获取指标调度器(供外部控制器更新指标配置) */
276
+ getIndicatorScheduler(): IndicatorScheduler;
263
277
  private getTrailingSlotCount;
264
278
  getLogicalSlotCount(): number;
265
279
  getTimestampAtLogicalIndex(index: number): number | null;
@@ -271,8 +285,11 @@ export declare class Chart {
271
285
  getContentWidth(): number;
272
286
  /** 容器尺寸变化时调用 */
273
287
  resize(): void;
274
- /** 请求下一帧重绘(RAF 合并) */
275
- scheduleDraw(): void;
288
+ /**
289
+ * 请求下一帧重绘(RAF 合并,支持分层更新)
290
+ * @param level 更新级别,默认为 All
291
+ */
292
+ scheduleDraw(level?: UpdateLevel): void;
276
293
  /** 销毁图表实例 */
277
294
  destroy(): Promise<void>;
278
295
  /** 初始化所有 pane */
@@ -78,6 +78,8 @@ export declare class InteractionController {
78
78
  private useTooltipAnchorPositioning;
79
79
  /** 统一交互状态变更回调 */
80
80
  private onInteractionChangeCallback?;
81
+ /** 用户设置 */
82
+ private settings;
81
83
  /** 当前 hover 的 marker ID */
82
84
  hoveredMarkerId: string | null;
83
85
  /** 当前点击的 marker ID */
@@ -105,6 +107,8 @@ export declare class InteractionController {
105
107
  constructor(chart: Chart);
106
108
  /** 设置捏合缩放回调 */
107
109
  setOnPinchZoom(callback: (delta: number, centerX: number) => void): void;
110
+ /** 更新用户设置 */
111
+ updateSettings(settings: Record<string, boolean>): void;
108
112
  getInteractionSnapshot(): InteractionSnapshot;
109
113
  setOnInteractionChange(callback: (snapshot: InteractionSnapshot) => void): void;
110
114
  private notifyInteractionChange;
@@ -0,0 +1,34 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ import { BOLLPoint } from './calculators';
3
+ /**
4
+ * BOLL 渲染器状态(共享给渲染器和图例)
5
+ * 包含全量 BOLL 数组、计算参数、以及视口极值
6
+ */
7
+ export interface BOLLRenderState extends BaseIndicatorState {
8
+ timestamp: number;
9
+ /** 全量 BOLL 数组(稀疏:前 period-1 个为 undefined) */
10
+ series: BOLLPoint[];
11
+ /** 计算和渲染参数(渲染器从此读取 showUpper/showMiddle/showLower/showBand) */
12
+ params: {
13
+ period: number;
14
+ multiplier: number;
15
+ showUpper: boolean;
16
+ showMiddle: boolean;
17
+ showLower: boolean;
18
+ showBand: boolean;
19
+ };
20
+ /** 视口内所有 BOLL 线的最低价 */
21
+ visibleMin: number;
22
+ /** 视口内所有 BOLL 线的最高价 */
23
+ visibleMax: number;
24
+ }
25
+ /**
26
+ * BOLL 状态的 StateStore 键名
27
+ * 格式:indicator:boll:main
28
+ */
29
+ export declare const BOLL_STATE_KEY: `indicator:${string}:${string}`;
30
+ /**
31
+ * 空数据占位状态
32
+ * 消费者应检查 visibleMin > visibleMax 判断"无有效数据"
33
+ */
34
+ export declare const EMPTY_BOLL_STATE: BOLLRenderState;
@@ -0,0 +1,129 @@
1
+ import { KLineData } from '../../types/price';
2
+ /**
3
+ * MA 周期配置标志
4
+ */
5
+ export type MAFlags = {
6
+ ma5?: boolean;
7
+ ma10?: boolean;
8
+ ma20?: boolean;
9
+ ma30?: boolean;
10
+ ma60?: boolean;
11
+ };
12
+ /**
13
+ * 默认 MA 周期列表
14
+ */
15
+ export declare const DEFAULT_MA_PERIODS: readonly [5, 10, 20, 30, 60];
16
+ /**
17
+ * BOLL 数据点
18
+ */
19
+ export interface BOLLPoint {
20
+ upper: number;
21
+ middle: number;
22
+ lower: number;
23
+ }
24
+ /**
25
+ * 默认 BOLL 参数
26
+ */
27
+ export declare const DEFAULT_BOLL_PERIOD = 20;
28
+ export declare const DEFAULT_BOLL_MULTIPLIER = 2;
29
+ /**
30
+ * 计算 BOLL 数据(使用滑动窗口优化)
31
+ * @param data K线数据数组
32
+ * @param period 周期(默认20)
33
+ * @param multiplier 标准差倍数(默认2)
34
+ * @returns 每个索引对应的BOLL值,前 period-1 个为 undefined
35
+ */
36
+ export declare function calcBOLLData(data: KLineData[], period: number, multiplier: number): BOLLPoint[];
37
+ /**
38
+ * EXPMA 数据点
39
+ */
40
+ export interface EXPMAPoint {
41
+ fast: number;
42
+ slow: number;
43
+ }
44
+ /**
45
+ * 默认 EXPMA 参数
46
+ */
47
+ export declare const DEFAULT_EXPMA_FAST_PERIOD = 12;
48
+ export declare const DEFAULT_EXPMA_SLOW_PERIOD = 50;
49
+ /**
50
+ * 计算 EXPMA 数据
51
+ * 公式:EXPMA(i) = C(i) × K + EXPMA(i-1) × (1-K),K = 2/(N+1)
52
+ * @param data K线数据数组
53
+ * @param fastPeriod 快线周期(默认12)
54
+ * @param slowPeriod 慢线周期(默认50)
55
+ * @returns 每个索引对应的EXPMA值(从 index 0 开始有值)
56
+ */
57
+ export declare function calcEXPMAData(data: KLineData[], fastPeriod: number, slowPeriod: number): EXPMAPoint[];
58
+ /**
59
+ * ENE 数据点
60
+ */
61
+ export interface ENEPoint {
62
+ upper: number;
63
+ middle: number;
64
+ lower: number;
65
+ }
66
+ /**
67
+ * 默认 ENE 参数
68
+ */
69
+ export declare const DEFAULT_ENE_PERIOD = 10;
70
+ export declare const DEFAULT_ENE_DEVIATION = 11;
71
+ /**
72
+ * 计算 ENE 数据
73
+ * 中轨 = MA(close, N)
74
+ * 上轨 = 中轨 × (1 + M/100)
75
+ * 下轨 = 中轨 × (1 - M/100)
76
+ * @param data K线数据数组
77
+ * @param period 周期(默认10)
78
+ * @param deviation 偏离率百分比(默认11)
79
+ * @returns 每个索引对应的ENE值,前 period-1 个为 undefined
80
+ */
81
+ export declare function calcENEData(data: KLineData[], period: number, deviation: number): ENEPoint[];
82
+ /**
83
+ * 计算指定周期的 MA 数据(使用滑动窗口优化,O(n) 复杂度)
84
+ * @param data K线数据数组
85
+ * @param period MA周期
86
+ * @returns 每个索引对应的MA值,前 period-1 个为 undefined
87
+ */
88
+ export declare function calcMAData(data: KLineData[], period: number): (number | undefined)[];
89
+ /**
90
+ * 默认 RSI 参数
91
+ */
92
+ export declare const DEFAULT_RSI_PERIOD1 = 6;
93
+ export declare const DEFAULT_RSI_PERIOD2 = 12;
94
+ export declare const DEFAULT_RSI_PERIOD3 = 24;
95
+ export declare const DEFAULT_RSI_PERIODS: readonly [6, 12, 24];
96
+ /**
97
+ * 计算 RSI 数据
98
+ * RSI = 100 - 100 / (1 + RS)
99
+ * RS = 平均上涨幅度 / 平均下跌幅度
100
+ * @param data K线数据数组
101
+ * @param period RSI周期
102
+ * @returns 每个索引对应的RSI值,前 period+1 个为 undefined(需要 period+1 个数据点计算初始平均)
103
+ */
104
+ export declare function calcRSIData(data: KLineData[], period: number): (number | undefined)[];
105
+ export declare const DEFAULT_CCI_PERIOD = 14;
106
+ export declare function calcCCIData(data: KLineData[], period: number): (number | undefined)[];
107
+ export declare const DEFAULT_STOCH_N = 9;
108
+ export declare const DEFAULT_STOCH_M = 3;
109
+ export interface STOCHPoint {
110
+ k: number;
111
+ d: number;
112
+ }
113
+ export declare function calcSTOCHData(data: KLineData[], n: number, m: number): STOCHPoint[];
114
+ export declare const DEFAULT_MOM_PERIOD = 10;
115
+ export declare function calcMOMData(data: KLineData[], period: number): (number | undefined)[];
116
+ export declare const DEFAULT_WMSR_PERIOD = 14;
117
+ export declare function calcWMSRData(data: KLineData[], period: number): (number | undefined)[];
118
+ export declare const DEFAULT_KST_ROC1 = 10;
119
+ export declare const DEFAULT_KST_ROC2 = 15;
120
+ export declare const DEFAULT_KST_ROC3 = 20;
121
+ export declare const DEFAULT_KST_ROC4 = 30;
122
+ export declare const DEFAULT_KST_SIGNAL = 9;
123
+ export interface KSTPoint {
124
+ kst: number;
125
+ signal: number;
126
+ }
127
+ export declare function calcKSTData(data: KLineData[], roc1: number, roc2: number, roc3: number, roc4: number, signalPeriod: number): KSTPoint[];
128
+ export declare const DEFAULT_FASTK_PERIOD = 9;
129
+ export declare function calcFASTKData(data: KLineData[], period: number): (number | undefined)[];
@@ -0,0 +1,15 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface CCIRenderState extends BaseIndicatorState {
3
+ timestamp: number;
4
+ series: (number | undefined)[];
5
+ params: {
6
+ period: number;
7
+ showCCI: boolean;
8
+ };
9
+ valueMin: number;
10
+ valueMax: number;
11
+ visibleMin: number;
12
+ visibleMax: number;
13
+ }
14
+ export declare const createCCIStateKey: (paneId: string) => `indicator:${string}:${string}`;
15
+ export declare const EMPTY_CCI_STATE: CCIRenderState;
@@ -0,0 +1,30 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ import { ENEPoint } from './calculators';
3
+ /**
4
+ * ENE 渲染器状态(共享给渲染器和图例)
5
+ * 包含全量 ENE 数组、计算参数、以及视口极值
6
+ */
7
+ export interface ENERenderState extends BaseIndicatorState {
8
+ timestamp: number;
9
+ /** 全量 ENE 数组(稀疏:前 period-1 个为 undefined) */
10
+ series: ENEPoint[];
11
+ /** 计算参数 */
12
+ params: {
13
+ period: number;
14
+ deviation: number;
15
+ };
16
+ /** 视口内所有 ENE 线的最低价 */
17
+ visibleMin: number;
18
+ /** 视口内所有 ENE 线的最高价 */
19
+ visibleMax: number;
20
+ }
21
+ /**
22
+ * ENE 状态的 StateStore 键名
23
+ * 格式:indicator:ene:main
24
+ */
25
+ export declare const ENE_STATE_KEY: `indicator:${string}:${string}`;
26
+ /**
27
+ * 空数据占位状态
28
+ * 消费者应检查 visibleMin > visibleMax 判断"无有效数据"
29
+ */
30
+ export declare const EMPTY_ENE_STATE: ENERenderState;
@@ -0,0 +1,30 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ import { EXPMAPoint } from './calculators';
3
+ /**
4
+ * EXPMA 渲染器状态(共享给渲染器和图例)
5
+ * 包含全量 EXPMA 数组、计算参数、以及视口极值
6
+ */
7
+ export interface EXPMARenderState extends BaseIndicatorState {
8
+ timestamp: number;
9
+ /** 全量 EXPMA 数组(密集:从 index 0 开始) */
10
+ series: EXPMAPoint[];
11
+ /** 计算参数 */
12
+ params: {
13
+ fastPeriod: number;
14
+ slowPeriod: number;
15
+ };
16
+ /** 视口内所有 EXPMA 线的最低价 */
17
+ visibleMin: number;
18
+ /** 视口内所有 EXPMA 线的最高价 */
19
+ visibleMax: number;
20
+ }
21
+ /**
22
+ * EXPMA 状态的 StateStore 键名
23
+ * 格式:indicator:expma:main
24
+ */
25
+ export declare const EXPMA_STATE_KEY: `indicator:${string}:${string}`;
26
+ /**
27
+ * 空数据占位状态
28
+ * 消费者应检查 visibleMin > visibleMax 判断"无有效数据"
29
+ */
30
+ export declare const EMPTY_EXPMA_STATE: EXPMARenderState;
@@ -0,0 +1,15 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface FASTKRenderState extends BaseIndicatorState {
3
+ timestamp: number;
4
+ series: (number | undefined)[];
5
+ params: {
6
+ period: number;
7
+ showFASTK: boolean;
8
+ };
9
+ valueMin: number;
10
+ valueMax: number;
11
+ visibleMin: number;
12
+ visibleMax: number;
13
+ }
14
+ export declare const createFASTKStateKey: (paneId: string) => `indicator:${string}:${string}`;
15
+ export declare const EMPTY_FASTK_STATE: FASTKRenderState;
@@ -0,0 +1,21 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ import { KSTPoint } from './calculators';
3
+ export interface KSTRenderState extends BaseIndicatorState {
4
+ timestamp: number;
5
+ series: KSTPoint[];
6
+ params: {
7
+ roc1: number;
8
+ roc2: number;
9
+ roc3: number;
10
+ roc4: number;
11
+ signalPeriod: number;
12
+ showKST: boolean;
13
+ showSignal: boolean;
14
+ };
15
+ valueMin: number;
16
+ valueMax: number;
17
+ visibleMin: number;
18
+ visibleMax: number;
19
+ }
20
+ export declare const createKSTStateKey: (paneId: string) => `indicator:${string}:${string}`;
21
+ export declare const EMPTY_KST_STATE: KSTRenderState;
@@ -0,0 +1,26 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ /**
3
+ * MA 渲染器状态(共享给渲染器和图例)
4
+ * 包含全量 MA 数组、启用的周期列表、以及视口极值
5
+ */
6
+ export interface MARenderState extends BaseIndicatorState {
7
+ timestamp: number;
8
+ /** period → 全量 MA 数组(用 Record 而非 Map,兼容 JSON 序列化和 postMessage) */
9
+ series: Record<number, (number | undefined)[]>;
10
+ /** 当前启用的周期列表(渲染器直接从此字段决定绘制哪些线) */
11
+ enabledPeriods: number[];
12
+ /** 视口内所有 MA 线的最低价(供 Y 轴刻度渲染器使用) */
13
+ visibleMin: number;
14
+ /** 视口内所有 MA 线的最高价 */
15
+ visibleMax: number;
16
+ }
17
+ /**
18
+ * MA 状态的 StateStore 键名
19
+ * 格式:indicator:ma:main
20
+ */
21
+ export declare const MA_STATE_KEY: `indicator:${string}:${string}`;
22
+ /**
23
+ * 空数据占位状态
24
+ * 消费者应检查 visibleMin > visibleMax 判断"无有效数据"
25
+ */
26
+ export declare const EMPTY_MA_STATE: MARenderState;
@@ -0,0 +1,15 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface MOMRenderState extends BaseIndicatorState {
3
+ timestamp: number;
4
+ series: (number | undefined)[];
5
+ params: {
6
+ period: number;
7
+ showMOM: boolean;
8
+ };
9
+ valueMin: number;
10
+ valueMax: number;
11
+ visibleMin: number;
12
+ visibleMax: number;
13
+ }
14
+ export declare const createMOMStateKey: (paneId: string) => `indicator:${string}:${string}`;
15
+ export declare const EMPTY_MOM_STATE: MOMRenderState;
@@ -0,0 +1,39 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ /**
3
+ * RSI 渲染器状态(共享给渲染器、图例和 scale 渲染器)
4
+ * 包含全量 RSI 数组、计算参数、固定 Y 轴范围以及视口极值
5
+ */
6
+ export interface RSIRenderState extends BaseIndicatorState {
7
+ timestamp: number;
8
+ /** 各周期 RSI 数组(稀疏:前 period+1 个为 undefined) */
9
+ series: Record<number, (number | undefined)[]>;
10
+ /** 当前启用的周期列表 */
11
+ enabledPeriods: number[];
12
+ /** 计算和渲染参数 */
13
+ params: {
14
+ period1: number;
15
+ period2: number;
16
+ period3: number;
17
+ showRSI1: boolean;
18
+ showRSI2: boolean;
19
+ showRSI3: boolean;
20
+ };
21
+ /** 固定 Y 轴最小值(始终为 0) */
22
+ valueMin: number;
23
+ /** 固定 Y 轴最大值(始终为 100) */
24
+ valueMax: number;
25
+ /** 视口内所有 RSI 线的最小值 */
26
+ visibleMin: number;
27
+ /** 视口内所有 RSI 线的最大值 */
28
+ visibleMax: number;
29
+ }
30
+ /**
31
+ * 创建 RSI 状态的 StateStore 键名
32
+ * 格式:indicator:rsi:{paneId}
33
+ */
34
+ export declare const createRSIStateKey: (paneId: string) => `indicator:${string}:${string}`;
35
+ /**
36
+ * 空数据占位状态
37
+ * 消费者应检查 visibleMin > visibleMax 判断"无有效数据"
38
+ */
39
+ export declare const EMPTY_RSI_STATE: RSIRenderState;