@363045841yyt/klinechart 0.6.9 → 0.6.10

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 (48) hide show
  1. package/README.md +1 -0
  2. package/dist/index.cjs +5 -5
  3. package/dist/index.js +3824 -2564
  4. package/dist/klinechart.css +1 -1
  5. package/dist/src/api/data/baostock.d.ts +4 -0
  6. package/dist/src/components/IndicatorSelector.vue.d.ts +0 -9
  7. package/dist/src/core/chart.d.ts +38 -5
  8. package/dist/src/core/controller/interaction.d.ts +2 -30
  9. package/dist/src/core/controller/markerInteraction.d.ts +28 -0
  10. package/dist/src/core/controller/pinchTracker.d.ts +18 -0
  11. package/dist/src/core/controller/tooltipPosition.d.ts +21 -0
  12. package/dist/src/core/indicators/atrState.d.ts +16 -0
  13. package/dist/src/core/indicators/calculators.d.ts +67 -0
  14. package/dist/src/core/indicators/demaState.d.ts +16 -0
  15. package/dist/src/core/indicators/donchianState.d.ts +23 -0
  16. package/dist/src/core/indicators/hmaState.d.ts +16 -0
  17. package/dist/src/core/indicators/indicatorRuntime.d.ts +20 -0
  18. package/dist/src/core/indicators/kamaState.d.ts +20 -0
  19. package/dist/src/core/indicators/keltnerState.d.ts +27 -0
  20. package/dist/src/core/indicators/sarState.d.ts +26 -0
  21. package/dist/src/core/indicators/scheduler.d.ts +46 -2
  22. package/dist/src/core/indicators/stateComposer.d.ts +30 -0
  23. package/dist/src/core/indicators/supertrendState.d.ts +22 -0
  24. package/dist/src/core/indicators/temaState.d.ts +16 -0
  25. package/dist/src/core/indicators/wmaState.d.ts +16 -0
  26. package/dist/src/core/indicators/workerProtocol.d.ts +111 -1
  27. package/dist/src/core/paneRenderer.d.ts +3 -1
  28. package/dist/src/core/renderers/Indicator/atr.d.ts +17 -0
  29. package/dist/src/core/renderers/Indicator/dema.d.ts +5 -0
  30. package/dist/src/core/renderers/Indicator/donchian.d.ts +5 -0
  31. package/dist/src/core/renderers/Indicator/hma.d.ts +5 -0
  32. package/dist/src/core/renderers/Indicator/index.d.ts +2 -1
  33. package/dist/src/core/renderers/Indicator/indicatorData.d.ts +13 -0
  34. package/dist/src/core/renderers/Indicator/kama.d.ts +5 -0
  35. package/dist/src/core/renderers/Indicator/keltner.d.ts +5 -0
  36. package/dist/src/core/renderers/Indicator/sar.d.ts +5 -0
  37. package/dist/src/core/renderers/Indicator/scale/atr_scale.d.ts +11 -0
  38. package/dist/src/core/renderers/Indicator/subPaneConfig.d.ts +9 -0
  39. package/dist/src/core/renderers/Indicator/supertrend.d.ts +5 -0
  40. package/dist/src/core/renderers/Indicator/tema.d.ts +5 -0
  41. package/dist/src/core/renderers/Indicator/wma.d.ts +5 -0
  42. package/dist/src/core/renderers/webgl/candleSurface.d.ts +16 -5
  43. package/dist/src/core/renderers/webgl/sharedWebGLSurface.d.ts +33 -0
  44. package/dist/src/core/subPaneManager.d.ts +22 -0
  45. package/dist/src/semantic/types.d.ts +36 -0
  46. package/dist/src/test-setup.d.ts +6 -0
  47. package/package.json +1 -1
  48. /package/dist/src/api/data/{baostock.test.d.ts → baostock.integration.test.d.ts} +0 -0
@@ -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-f3fbebbd]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-f3fbebbd]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-f3fbebbd]::-webkit-scrollbar{display:none}.indicator-list[data-v-f3fbebbd]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-f3fbebbd]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-f3fbebbd]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-f3fbebbd],.indicator-item.draggable .indicator-btn[data-v-f3fbebbd],.indicator-item.draggable[data-v-f3fbebbd]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-f3fbebbd]{cursor:move}.indicator-item.is-dragging[data-v-f3fbebbd]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-f3fbebbd]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-f3fbebbd]{position:relative}.indicator-btn[data-v-f3fbebbd]{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-f3fbebbd]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-f3fbebbd]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-f3fbebbd]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-f3fbebbd]{z-index:1;position:relative}.param-hint[data-v-f3fbebbd]{opacity:.85;font-size:11px}.hover-overlay[data-v-f3fbebbd]{-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-f3fbebbd]{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-f3fbebbd]:hover{color:#333;background:#0000000f}.settings-btn[data-v-f3fbebbd]:hover{color:#1a1a1a}.remove-btn[data-v-f3fbebbd]:hover{color:#ff4d4f}.divider[data-v-f3fbebbd]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-f3fbebbd]{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-f3fbebbd]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.add-menu[data-v-f3fbebbd]{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-f3fbebbd]{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-f3fbebbd]{padding:4px 0}.menu-section[data-v-f3fbebbd]:not(:last-child){border-bottom:1px solid #f0f0f0}.menu-title[data-v-f3fbebbd]{color:#999;padding:4px 16px;font-size:12px;font-weight:500}.menu-items[data-v-f3fbebbd]{flex-direction:column;gap:2px;display:flex}.menu-item[data-v-f3fbebbd]{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-f3fbebbd]:hover:not(.disabled){background:#f5f5f5}.menu-item.disabled[data-v-f3fbebbd]{color:#999;cursor:not-allowed}.menu-item .param-hint[data-v-f3fbebbd]{color:#999;font-size:11px}.active-tag[data-v-f3fbebbd]{color:#1a1a1a;align-items:center;margin-left:auto;display:flex}.fade-enter-active[data-v-f3fbebbd],.fade-leave-active[data-v-f3fbebbd]{transition:opacity .2s}.fade-enter-from[data-v-f3fbebbd],.fade-leave-to[data-v-f3fbebbd]{opacity:0}.slide-enter-active[data-v-f3fbebbd],.slide-leave-active[data-v-f3fbebbd]{transition:all .2s}.slide-enter-from[data-v-f3fbebbd],.slide-leave-to[data-v-f3fbebbd]{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-20a39cb3]{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-20a39cb3]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-20a39cb3]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-20a39cb3]{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-20a39cb3]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-20a39cb3]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-20a39cb3]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-20a39cb3]{width:16px;height:16px}.corner-indicator[data-v-20a39cb3]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-20a39cb3]: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-20a39cb3]:after,.left-toolbar__button.active .corner-indicator[data-v-20a39cb3]:after{opacity:.7}.corner-indicator.open[data-v-20a39cb3]:after{opacity:.8}.tool-dropdown[data-v-20a39cb3]{-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-20a39cb3]{position:relative}.dropdown-enter-active[data-v-20a39cb3],.dropdown-leave-active[data-v-20a39cb3]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-20a39cb3],.dropdown-leave-to[data-v-20a39cb3]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-20a39cb3]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-20a39cb3]{gap:3px}.left-toolbar__button[data-v-20a39cb3]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-20a39cb3]{width:16px}.corner-indicator[data-v-20a39cb3]{width:7px;height:7px}.corner-indicator[data-v-20a39cb3]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-20a39cb3]{height:36px}}.settings-overlay[data-v-20a39cb3]{-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-20a39cb3]{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-20a39cb3]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-20a39cb3]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-20a39cb3]{align-items:center;gap:8px;display:flex}.settings-title[data-v-20a39cb3]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.settings-subtitle[data-v-20a39cb3]{color:#999;font-size:11px}.settings-close[data-v-20a39cb3]{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-20a39cb3]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.settings-close svg[data-v-20a39cb3]{width:14px;height:14px}.settings-body[data-v-20a39cb3]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.settings-item[data-v-20a39cb3]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:8px 12px}.settings-label[data-v-20a39cb3]{color:#333;cursor:pointer;justify-content:space-between;align-items:center;font-size:13px;display:flex}.settings-checkbox[data-v-20a39cb3]{cursor:pointer;accent-color:#1a1a1a;width:16px;height:16px}.settings-select[data-v-20a39cb3]{color:#333;cursor:pointer;background:#fff;border:1px solid #d0d0d0;border-radius:6px;outline:none;min-width:140px;padding:4px 8px;font-size:12px}.settings-select[data-v-20a39cb3]:hover{border-color:#9ca3af}.settings-select[data-v-20a39cb3]:focus{border-color:#6b7280;box-shadow:0 0 0 2px #6b728026}.settings-section-divider[data-v-20a39cb3]{align-items:center;gap:8px;margin-top:4px;display:flex}.settings-section-divider[data-v-20a39cb3]:before,.settings-section-divider[data-v-20a39cb3]:after{content:"";border-top:1px solid #e0e0e0;flex:1}.settings-section-label[data-v-20a39cb3]{color:#999;white-space:nowrap;font-size:11px}.settings-item.experimental[data-v-20a39cb3]{background:#fdf8f3;border-color:#f0e0d0}.settings-footer[data-v-20a39cb3]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-20a39cb3]{gap:8px;display:flex}.settings-btn[data-v-20a39cb3]{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-20a39cb3]{flex-shrink:0;width:12px;height:12px}.settings-btn.reset[data-v-20a39cb3]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.reset[data-v-20a39cb3]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.settings-btn.cancel[data-v-20a39cb3]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.cancel[data-v-20a39cb3]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.settings-btn.confirm[data-v-20a39cb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.settings-btn.confirm[data-v-20a39cb3]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.settings-btn.confirm[data-v-20a39cb3]:active{box-shadow:none;transform:translateY(0)}.chart-wrapper[data-v-6dd10e17]{--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-6dd10e17]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-6dd10e17]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-6dd10e17]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-6dd10e17]{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-6dd10e17]{border-top-width:2px;border-top-color:#3b82f6;margin-top:-1px}.chart-stage.is-resizing-pane[data-v-6dd10e17],.chart-stage.is-hovering-pane-separator[data-v-6dd10e17]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-6dd10e17]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-6dd10e17]{cursor:ns-resize}.chart-stage.is-dragging[data-v-6dd10e17]{cursor:grabbing}.chart-container[data-v-6dd10e17]{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-6dd10e17]::-webkit-scrollbar{display:none}.right-axis-host[data-v-6dd10e17]{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-6dd10e17]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-6dd10e17]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-layer[data-v-6dd10e17]{pointer-events:none;z-index:30;position:absolute;inset:0}.tooltip-anchor[data-v-6dd10e17]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-6dd10e17]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-6dd10e17]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-6dd10e17]{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-b8333f39]{width:80%;margin:20px;position:relative}.indicator-scroll-container[data-v-b8333f39]{scrollbar-width:none;-webkit-overflow-scrolling:touch;text-align:center;width:100%;overflow:auto hidden}.indicator-scroll-container[data-v-b8333f39]::-webkit-scrollbar{display:none}.indicator-list[data-v-b8333f39]{gap:8px;margin:0 auto;padding:2px;display:inline-flex}.indicator-divider[data-v-b8333f39]{background:#d9d9d9;align-self:center;width:1px;height:20px}.indicator-item[data-v-b8333f39]{align-items:center;gap:4px;display:flex}.indicator-item.draggable[data-v-b8333f39],.indicator-item.draggable .indicator-btn[data-v-b8333f39],.indicator-item.draggable[data-v-b8333f39]:hover,.indicator-item.draggable:hover .indicator-btn[data-v-b8333f39]{cursor:move}.indicator-item.is-dragging[data-v-b8333f39]{opacity:.6}.indicator-item.drag-over .indicator-btn[data-v-b8333f39]{border-color:#1a1a1a;box-shadow:0 0 0 2px #1a1a1a1f}.indicator-btn-wrapper[data-v-b8333f39]{position:relative}.indicator-btn[data-v-b8333f39]{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-b8333f39]:hover:not(.hovering){color:#333;background:#f8f8f8;border-color:#ccc}.indicator-btn.active[data-v-b8333f39]{color:#1a1a1a;background:#f8f8f8;border-color:#1a1a1a}.indicator-btn.active[data-v-b8333f39]:hover:not(.hovering){background:#f0f0f0;border-color:#333}.btn-content[data-v-b8333f39]{z-index:1;position:relative}.param-hint[data-v-b8333f39]{opacity:.85;font-size:11px}.hover-overlay[data-v-b8333f39]{-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-b8333f39]{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-b8333f39]:hover{color:#333;background:#0000000f}.settings-btn[data-v-b8333f39]:hover{color:#1a1a1a}.remove-btn[data-v-b8333f39]:hover{color:#ff4d4f}.divider[data-v-b8333f39]{background:#e0e0e0;width:1px;height:14px}.add-btn[data-v-b8333f39]{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-b8333f39]:hover{color:#1a1a1a;background:#1a1a1a0a;border-color:#1a1a1a}.add-menu[data-v-b8333f39]{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-b8333f39]{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-b8333f39]{padding:4px 0}.menu-section[data-v-b8333f39]:not(:last-child){border-bottom:1px solid #f0f0f0}.menu-title[data-v-b8333f39]{color:#999;padding:4px 16px;font-size:12px;font-weight:500}.menu-items[data-v-b8333f39]{flex-direction:column;gap:2px;display:flex}.menu-item[data-v-b8333f39]{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-b8333f39]:hover:not(.disabled){background:#f5f5f5}.menu-item.disabled[data-v-b8333f39]{color:#999;cursor:not-allowed}.menu-item .param-hint[data-v-b8333f39]{color:#999;font-size:11px}.active-tag[data-v-b8333f39]{color:#1a1a1a;align-items:center;margin-left:auto;display:flex}.fade-enter-active[data-v-b8333f39],.fade-leave-active[data-v-b8333f39]{transition:opacity .2s}.fade-enter-from[data-v-b8333f39],.fade-leave-to[data-v-b8333f39]{opacity:0}.slide-enter-active[data-v-b8333f39],.slide-leave-active[data-v-b8333f39]{transition:all .2s}.slide-enter-from[data-v-b8333f39],.slide-leave-to[data-v-b8333f39]{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-20a39cb3]{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-20a39cb3]{flex-direction:column;gap:4px;display:flex}.left-toolbar__divider[data-v-20a39cb3]{background:#e5e7eb;width:18px;height:1px}.left-toolbar__button[data-v-20a39cb3]{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-20a39cb3]:hover{color:#374151;background:#f3f4f6;border-color:#d1d5db}.left-toolbar__button.active[data-v-20a39cb3]{color:#1f2937;background:#e5e7eb;border-color:#9ca3af}.left-toolbar__button[data-v-20a39cb3]:focus-visible{border-color:#6b7280;outline:none}.tool-icon[data-v-20a39cb3]{width:16px;height:16px}.corner-indicator[data-v-20a39cb3]{cursor:pointer;width:8px;height:8px;position:absolute;bottom:0;right:0;overflow:hidden}.corner-indicator[data-v-20a39cb3]: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-20a39cb3]:after,.left-toolbar__button.active .corner-indicator[data-v-20a39cb3]:after{opacity:.7}.corner-indicator.open[data-v-20a39cb3]:after{opacity:.8}.tool-dropdown[data-v-20a39cb3]{-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-20a39cb3]{position:relative}.dropdown-enter-active[data-v-20a39cb3],.dropdown-leave-active[data-v-20a39cb3]{transition:opacity .15s,transform .15s}.dropdown-enter-from[data-v-20a39cb3],.dropdown-leave-to[data-v-20a39cb3]{opacity:0;transform:translateY(-50%)translate(-6px)}@media (width<=768px),(height<=640px){.left-toolbar[data-v-20a39cb3]{border-radius:5px;flex-basis:36px;gap:5px;padding:6px 4px}.left-toolbar__group[data-v-20a39cb3]{gap:3px}.left-toolbar__button[data-v-20a39cb3]{border-radius:3px;width:26px;height:26px}.left-toolbar__divider[data-v-20a39cb3]{width:16px}.corner-indicator[data-v-20a39cb3]{width:7px;height:7px}.corner-indicator[data-v-20a39cb3]:after{border-bottom-width:4px;border-left-width:4px}.tool-dropdown[data-v-20a39cb3]{height:36px}}.settings-overlay[data-v-20a39cb3]{-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-20a39cb3]{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-20a39cb3]{background:#f8f8f8;border-bottom:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:16px 20px;display:flex}.header-left[data-v-20a39cb3]{align-items:baseline;gap:8px;display:flex}.header-right[data-v-20a39cb3]{align-items:center;gap:8px;display:flex}.settings-title[data-v-20a39cb3]{color:#1a1a1a;letter-spacing:.2px;font-size:14px;font-weight:600}.settings-subtitle[data-v-20a39cb3]{color:#999;font-size:11px}.settings-close[data-v-20a39cb3]{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-20a39cb3]:hover{color:#333;background:#f0f0f0;border-color:#ccc}.settings-close svg[data-v-20a39cb3]{width:14px;height:14px}.settings-body[data-v-20a39cb3]{flex-direction:column;gap:10px;padding:16px 20px;display:flex}.settings-item[data-v-20a39cb3]{background:#f8f8f8;border:1px solid #e8e8e8;border-radius:8px;padding:8px 12px}.settings-label[data-v-20a39cb3]{color:#333;cursor:pointer;justify-content:space-between;align-items:center;font-size:13px;display:flex}.settings-checkbox[data-v-20a39cb3]{cursor:pointer;accent-color:#1a1a1a;width:16px;height:16px}.settings-select[data-v-20a39cb3]{color:#333;cursor:pointer;background:#fff;border:1px solid #d0d0d0;border-radius:6px;outline:none;min-width:140px;padding:4px 8px;font-size:12px}.settings-select[data-v-20a39cb3]:hover{border-color:#9ca3af}.settings-select[data-v-20a39cb3]:focus{border-color:#6b7280;box-shadow:0 0 0 2px #6b728026}.settings-section-divider[data-v-20a39cb3]{align-items:center;gap:8px;margin-top:4px;display:flex}.settings-section-divider[data-v-20a39cb3]:before,.settings-section-divider[data-v-20a39cb3]:after{content:"";border-top:1px solid #e0e0e0;flex:1}.settings-section-label[data-v-20a39cb3]{color:#999;white-space:nowrap;font-size:11px}.settings-item.experimental[data-v-20a39cb3]{background:#fdf8f3;border-color:#f0e0d0}.settings-footer[data-v-20a39cb3]{background:#f8f8f8;border-top:1px solid #e8e8e8;justify-content:space-between;align-items:center;padding:12px 20px;display:flex}.footer-right[data-v-20a39cb3]{gap:8px;display:flex}.settings-btn[data-v-20a39cb3]{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-20a39cb3]{flex-shrink:0;width:12px;height:12px}.settings-btn.reset[data-v-20a39cb3]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.reset[data-v-20a39cb3]:hover{color:#e74c3c;background:#e74c3c14;border-color:#c0392b}.settings-btn.cancel[data-v-20a39cb3]{color:#666;background:0 0;border-color:#d0d0d0}.settings-btn.cancel[data-v-20a39cb3]:hover{color:#333;background:#f0f0f0;border-color:#bbb}.settings-btn.confirm[data-v-20a39cb3]{color:#fff;background:#1a1a1a;border-color:#1a1a1a}.settings-btn.confirm[data-v-20a39cb3]:hover{background:#333;border-color:#333;transform:translateY(-1px);box-shadow:0 2px 10px #00000026}.settings-btn.confirm[data-v-20a39cb3]:active{box-shadow:none;transform:translateY(0)}.chart-wrapper[data-v-2385e6a5]{--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-2385e6a5]{align-items:stretch;gap:8px;width:95%;height:85%;min-height:255px;display:flex}.chart-main[data-v-2385e6a5]{flex:auto;align-items:stretch;gap:0;min-width:0;height:100%;display:flex;position:relative}.pane-separator-layer[data-v-2385e6a5]{pointer-events:none;z-index:20;position:absolute;inset:0}.pane-separator-line[data-v-2385e6a5]{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-2385e6a5]{border-top-width:2px;border-top-color:#3b82f6;margin-top:-1px}.chart-stage.is-resizing-pane[data-v-2385e6a5],.chart-stage.is-hovering-pane-separator[data-v-2385e6a5]{cursor:ns-resize}.chart-stage.is-hovering-kline[data-v-2385e6a5]{cursor:pointer}.chart-stage.is-hovering-right-axis[data-v-2385e6a5]{cursor:ns-resize}.chart-stage.is-dragging[data-v-2385e6a5]{cursor:grabbing}.chart-container[data-v-2385e6a5]{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-2385e6a5]::-webkit-scrollbar{display:none}.right-axis-host[data-v-2385e6a5]{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-2385e6a5]{height:100%;min-height:inherit;position:relative}.canvas-layer[data-v-2385e6a5]{pointer-events:none;position:sticky;top:0;left:0}.tooltip-layer[data-v-2385e6a5]{pointer-events:none;z-index:30;position:absolute;inset:0}.tooltip-anchor[data-v-2385e6a5]{pointer-events:none;width:1px;height:1px;position:absolute}.tooltip-anchor.kline-tooltip-anchor.use-anchor[data-v-2385e6a5]{anchor-name:--kline-tooltip-anchor}.tooltip-anchor.marker-tooltip-anchor.use-anchor[data-v-2385e6a5]{anchor-name:--marker-tooltip-anchor}@media (width<=768px),(height<=640px){.chart-stage[data-v-2385e6a5]{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*/
@@ -65,6 +65,10 @@ interface BaoStockKDataResponse {
65
65
  * @param param 请求参数
66
66
  * @returns Promise<KLineData[]>
67
67
  */
68
+ /**
69
+ * 从静态 JSON 加载 mock K 线数据(用于 GitHub Pages 等静态部署)
70
+ */
71
+ export declare function loadMockKLineData(): Promise<KLineData[]>;
68
72
  export declare function getKlineDataBaoStock(param: {
69
73
  symbol: string;
70
74
  start_date: string;
@@ -1,12 +1,3 @@
1
- import { ParamConfig } from './IndicatorParams.vue';
2
- export interface Indicator {
3
- id: string;
4
- label: string;
5
- name: string;
6
- pane: 'main' | 'sub';
7
- description?: string;
8
- params?: ParamConfig[];
9
- }
10
1
  type __VLS_Props = {
11
2
  activeIndicators?: string[];
12
3
  indicatorParams?: Record<string, Record<string, unknown>>;
@@ -6,6 +6,7 @@ import { PaneRenderer } from './paneRenderer';
6
6
  import { MarkerManager, CustomMarkerEntity } from './marker/registry';
7
7
  import { getPhysicalKLineConfig, calcKWidthPx } from './utils/klineConfig';
8
8
  import { IndicatorScheduler } from './indicators/scheduler';
9
+ import { SubPaneEntry } from './subPaneManager';
9
10
  import { PluginHostImpl, RendererPlugin, RendererPluginWithHost, PaneRole, PaneCapabilities } from '../plugin';
10
11
  import { SubIndicatorType } from './renderers/Indicator';
11
12
  export { getPhysicalKLineConfig, calcKWidthPx };
@@ -123,6 +124,8 @@ export declare class Chart {
123
124
  private onViewportChange?;
124
125
  /** 共享 X 轴上下文缓存 */
125
126
  private xAxisCtx;
127
+ /** Chart 级共享 WebGL canvas/context */
128
+ private sharedWebGLSurface;
126
129
  /** pane 布局回流回调(Chart -> UI 单向) */
127
130
  private onPaneLayoutChange?;
128
131
  /** 数据变化回调(供外部同步 dataLength) */
@@ -139,6 +142,8 @@ export declare class Chart {
139
142
  private lastVisibleRange;
140
143
  /** Overlay 帧复用的最近主渲染结果 */
141
144
  private cachedDrawFrame;
145
+ /** 副图管理器 */
146
+ private subPaneManager;
142
147
  /** 当前激活的主图指标列表(如 ['boll', 'ma']) */
143
148
  private activeMainIndicators;
144
149
  /** 主图指标参数配置 */
@@ -237,6 +242,9 @@ export declare class Chart {
237
242
  * @param level 更新级别,决定渲染哪些层
238
243
  */
239
244
  draw(level?: UpdateLevel): void;
245
+ private prepareFrameData;
246
+ private renderPanes;
247
+ private renderXAxis;
240
248
  /**
241
249
  * 应用渲染状态(由 Vue/Store 层在状态更新后调用)
242
250
  * Chart 不拥有业务 SSOT,只负责接收参数并渲染
@@ -308,28 +316,53 @@ export declare class Chart {
308
316
  * @param paneId pane 标识符
309
317
  */
310
318
  hasPane(paneId: string): boolean;
311
- /** 副图渲染器名称前缀 */
312
- private static readonly SUB_PANE_PREFIX;
313
319
  /**
314
320
  * 创建副图面板并注册指标渲染器
321
+ * @param paneId 副图实例标识符(如 'RSI_0', 'MACD_0')
315
322
  * @param indicatorId 指标类型
316
323
  * @param params 指标参数
317
324
  * @returns 是否创建成功
318
325
  */
319
- createSubPane(indicatorId: SubIndicatorType, params?: Record<string, number | boolean>): boolean;
326
+ createSubPane(paneId: string, indicatorId: SubIndicatorType, params?: Record<string, number | boolean>): boolean;
320
327
  /**
321
328
  * 移除副图面板及其渲染器
322
- * @param indicatorId 指标类型
329
+ * @param paneId 副图实例标识符
330
+ */
331
+ removeSubPane(paneId: string): void;
332
+ /**
333
+ * 替换副图的指标类型
334
+ * @param paneId 副图实例标识符
335
+ * @param newIndicatorId 新的指标类型
336
+ * @param params 新指标参数
337
+ */
338
+ replaceSubPaneIndicator(paneId: string, newIndicatorId: SubIndicatorType, params?: Record<string, number | boolean>): void;
339
+ /**
340
+ * 更新副图指标参数
341
+ * @param paneId 副图实例标识符
342
+ * @param params 新参数
323
343
  */
324
- removeSubPane(indicatorId: SubIndicatorType): void;
344
+ updateSubPaneParams(paneId: string, params: Record<string, unknown>): void;
325
345
  /**
326
346
  * 清除所有副图面板
327
347
  */
328
348
  clearSubPanes(): void;
329
349
  /**
330
350
  * 获取当前所有副图指标类型
351
+ * @deprecated 使用 getSubPaneEntries 获取完整信息
331
352
  */
332
353
  getSubPaneIndicators(): SubIndicatorType[];
354
+ /**
355
+ * 获取所有副图条目
356
+ */
357
+ getSubPaneEntries(): SubPaneEntry[];
358
+ /**
359
+ * 根据 paneId 获取副图条目
360
+ * @param paneId 副图实例标识符
361
+ */
362
+ getSubPaneEntry(paneId: string): SubPaneEntry | undefined;
363
+ private getDefaultSubPaneParams;
364
+ /** 副图渲染器名称前缀(保留向后兼容) */
365
+ private static readonly SUB_PANE_PREFIX;
333
366
  /**
334
367
  * 平移价格轴(用于主图区域上下拖动)
335
368
  * @param paneId 目标 pane ID
@@ -43,13 +43,7 @@ export declare class InteractionController {
43
43
  private hoveredRightAxisPaneId;
44
44
  /** [触屏]:触摸会话标记,避免触摸触发的模拟 mouse 事件干扰 */
45
45
  private isTouchSession;
46
- /** [触屏]:多点触摸跟踪,用于双指捏合缩放 */
47
- private activePointers;
48
- private lastPinchDistance;
49
- private pinchCenter;
50
- private isPinching;
51
- /** 捏合缩放回调 */
52
- private onPinchZoomCallback?;
46
+ private pinchTracker;
53
47
  /** 十字线位置 */
54
48
  crosshairPos: {
55
49
  x: number;
@@ -81,24 +75,7 @@ export declare class InteractionController {
81
75
  private onInteractionChangeCallback?;
82
76
  /** 用户设置 */
83
77
  private settings;
84
- /** 当前 hover 的 marker ID */
85
- hoveredMarkerId: string | null;
86
- /** 当前点击的 marker ID */
87
- clickedMarkerId: string | null;
88
- /** 当前 hover 的 marker 数据(供外部显示 tooltip 使用) */
89
- hoveredMarkerData: MarkerEntity | null;
90
- /** 当前点击的 marker 数据(供外部显示 tooltip 使用) */
91
- clickedMarkerData: MarkerEntity | null;
92
- /** marker hover 回调函数 */
93
- private onMarkerHoverCallback?;
94
- /** marker click 回调函数 */
95
- private onMarkerClickCallback?;
96
- /** 当前 hover 的自定义标记 */
97
- hoveredCustomMarker: CustomMarkerEntity | null;
98
- /** 自定义标记 hover 回调 */
99
- private onCustomMarkerHoverCallback?;
100
- /** 自定义标记 click 回调 */
101
- private onCustomMarkerClickCallback?;
78
+ private markerState;
102
79
  /** 当前帧的 K 线起始 x 坐标数组 */
103
80
  private kLinePositions;
104
81
  /** 当前帧的可见 K 线索引范围 */
@@ -108,7 +85,6 @@ export declare class InteractionController {
108
85
  /** K 线宽度(物理像素),用于计算 K 线中心偏移 */
109
86
  private kWidthPx;
110
87
  constructor(chart: Chart);
111
- /** 设置捏合缩放回调 */
112
88
  setOnPinchZoom(callback: (delta: number, centerX: number) => void): void;
113
89
  /** 更新用户设置 */
114
90
  updateSettings(settings: ChartSettings): void;
@@ -163,13 +139,9 @@ export declare class InteractionController {
163
139
  onRightAxisPointerLeave(e: PointerEvent): void;
164
140
  /** 检查是否正在拖拽 */
165
141
  isDraggingState(): boolean;
166
- /** 设置 marker hover 回调 */
167
142
  setOnMarkerHover(callback: (marker: MarkerEntity | null) => void): void;
168
- /** 设置 marker click 回调 */
169
143
  setOnMarkerClick(callback: (marker: MarkerEntity) => void): void;
170
- /** 设置自定义标记 hover 回调 */
171
144
  setOnCustomMarkerHover(callback: (marker: CustomMarkerEntity | null) => void): void;
172
- /** 设置自定义标记 click 回调 */
173
145
  setOnCustomMarkerClick(callback: (marker: CustomMarkerEntity) => void): void;
174
146
  /** 命中可拖拽分隔线(返回上方 paneId) */
175
147
  private hitTestPaneSeparator;
@@ -0,0 +1,28 @@
1
+ import { MarkerEntity, CustomMarkerEntity, MarkerManager } from '../marker/registry';
2
+ /** Marker交互状态,管理标记 hover/click 状态和回调,与 InteractionController 正交。 */
3
+ export declare class MarkerInteractionState {
4
+ hoveredMarkerId: string | null;
5
+ clickedMarkerId: string | null;
6
+ hoveredMarkerData: MarkerEntity | null;
7
+ clickedMarkerData: MarkerEntity | null;
8
+ hoveredCustomMarker: CustomMarkerEntity | null;
9
+ private onMarkerHoverCallback?;
10
+ private onMarkerClickCallback?;
11
+ private onCustomMarkerHoverCallback?;
12
+ private onCustomMarkerClickCallback?;
13
+ setOnMarkerHover(callback: (marker: MarkerEntity | null) => void): void;
14
+ setOnMarkerClick(callback: (marker: MarkerEntity) => void): void;
15
+ setOnCustomMarkerHover(callback: (marker: CustomMarkerEntity | null) => void): void;
16
+ setOnCustomMarkerClick(callback: (marker: CustomMarkerEntity) => void): void;
17
+ handleClick(hitMarker: MarkerEntity): void;
18
+ /** 从坐标更新 hover 状态。返回 true 表示命中 marker/custom-marker,调用方应跳过后续 hover 逻辑。 */
19
+ updateHoverFromPoint(worldX: number, mouseX: number, mouseY: number, markerManager: MarkerManager): boolean;
20
+ private enterMarkerHover;
21
+ private leaveMarkerHover;
22
+ private enterCustomMarkerHover;
23
+ private leaveCustomMarkerHover;
24
+ /** 清空 hover 状态并触发回调(拖拽/离开时调用)。需要 markerManager 以便同步清除 Native hover。 */
25
+ clearAll(markerManager: MarkerManager): void;
26
+ /** 全量重置(数据更新时调用,不触发热点回调) */
27
+ reset(): void;
28
+ }
@@ -0,0 +1,18 @@
1
+ /** 触屏双指捏合跟踪,与 InteractionController 正交。 */
2
+ export declare class PinchTracker {
3
+ private activePointers;
4
+ private lastPinchDistance;
5
+ private pinchCenter;
6
+ private isPinching;
7
+ private onPinchZoomCallback?;
8
+ setOnPinchZoom(callback: (delta: number, centerX: number) => void): void;
9
+ getIsPinching(): boolean;
10
+ getPointerCount(): number;
11
+ /** Returns true if pinch started (caller should early-return, not process drag). */
12
+ handlePointerDown(e: PointerEvent, isTouchSession: boolean): boolean;
13
+ handlePointerUp(e: PointerEvent): void;
14
+ handlePointerLeave(e: PointerEvent): void;
15
+ /** Returns true if pinch zoom was processed (caller should skip further pointer-move handling). */
16
+ handlePointerMove(e: PointerEvent): boolean;
17
+ reset(): void;
18
+ }
@@ -0,0 +1,21 @@
1
+ export interface TooltipPositionInput {
2
+ mouseX: number;
3
+ mouseY: number;
4
+ viewWidth: number;
5
+ viewHeight: number;
6
+ plotWidth: number;
7
+ plotHeight: number;
8
+ tooltipSize: {
9
+ width: number;
10
+ height: number;
11
+ };
12
+ useAnchorPositioning: boolean;
13
+ }
14
+ export interface TooltipPositionOutput {
15
+ pos: {
16
+ x: number;
17
+ y: number;
18
+ };
19
+ anchorPlacement?: 'right-bottom' | 'left-bottom';
20
+ }
21
+ export declare function computeTooltipPosition(input: TooltipPositionInput): TooltipPositionOutput;
@@ -0,0 +1,16 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface ATRRenderState extends BaseIndicatorState {
3
+ timestamp: number;
4
+ series: (number | undefined)[];
5
+ params: {
6
+ period: number;
7
+ showATR: boolean;
8
+ };
9
+ valueMin: number;
10
+ valueMax: number;
11
+ visibleMin: number;
12
+ visibleMax: number;
13
+ }
14
+ export declare const createATRStateKey: (paneId: string) => `indicator:${string}:${string}`;
15
+ export declare const DEFAULT_ATR_PERIOD = 14;
16
+ export declare const EMPTY_ATR_STATE: ATRRenderState;
@@ -267,3 +267,70 @@ export declare function calcFASTKDataSoA(layout: KLineSoALayout, period: number)
267
267
  * @returns MACD 数据点数组
268
268
  */
269
269
  export declare function calcMACDDataSoA(layout: KLineSoALayout, fastPeriod: number, slowPeriod: number, signalPeriod: number): MACDPoint[];
270
+ export declare const DEFAULT_ATR_PERIOD = 14;
271
+ /**
272
+ * 计算 Wilder ATR。
273
+ * TR(0) = H(0) - L(0)
274
+ * TR(t) = max(H(t) - L(t), |H(t) - C(t-1)|, |L(t) - C(t-1)|)
275
+ * ATR(period-1) = mean(TR[0..period-1])
276
+ * ATR(t) = ((period-1) * ATR(t-1) + TR(t)) / period for t >= period
277
+ *
278
+ * @param data K 线数组
279
+ * @param period 周期,需 >= 1;若 <= 0 或 data.length < period,返回全 undefined
280
+ */
281
+ export declare function calcATRData(data: KLineData[], period: number): (number | undefined)[];
282
+ /**
283
+ * 从 SoA 布局计算 ATR(包装函数,对齐其他指标的 SoA 入口)
284
+ */
285
+ export declare function calcATRDataSoA(layout: KLineSoALayout, period: number): (number | undefined)[];
286
+ export declare const DEFAULT_WMA_PERIOD = 9;
287
+ export declare function calcWMAData(data: KLineData[], period: number): (number | undefined)[];
288
+ export declare function calcWMADataSoA(layout: KLineSoALayout, period: number): (number | undefined)[];
289
+ export declare const DEFAULT_DEMA_PERIOD = 20;
290
+ export declare function calcDEMAData(data: KLineData[], period: number): (number | undefined)[];
291
+ export declare function calcDEMADataSoA(layout: KLineSoALayout, period: number): (number | undefined)[];
292
+ export declare const DEFAULT_TEMA_PERIOD = 20;
293
+ export declare function calcTEMAData(data: KLineData[], period: number): (number | undefined)[];
294
+ export declare function calcTEMADataSoA(layout: KLineSoALayout, period: number): (number | undefined)[];
295
+ export declare const DEFAULT_HMA_PERIOD = 9;
296
+ export declare function calcHMAData(data: KLineData[], period: number): (number | undefined)[];
297
+ export declare function calcHMADataSoA(layout: KLineSoALayout, period: number): (number | undefined)[];
298
+ export declare const DEFAULT_KAMA_PERIOD = 10;
299
+ export declare const DEFAULT_KAMA_FAST_PERIOD = 2;
300
+ export declare const DEFAULT_KAMA_SLOW_PERIOD = 30;
301
+ export declare function calcKAMAData(data: KLineData[], period: number, fastPeriod: number, slowPeriod: number): (number | undefined)[];
302
+ export declare function calcKAMADataSoA(layout: KLineSoALayout, period: number, fastPeriod: number, slowPeriod: number): (number | undefined)[];
303
+ export interface SARPoint {
304
+ value: number;
305
+ trend: 'up' | 'down';
306
+ }
307
+ export declare const DEFAULT_SAR_STEP = 0.02;
308
+ export declare const DEFAULT_SAR_MAX_STEP = 0.2;
309
+ export declare function calcSARData(data: KLineData[], step: number, maxStep: number): (SARPoint | undefined)[];
310
+ export declare function calcSARDataSoA(layout: KLineSoALayout, step: number, maxStep: number): (SARPoint | undefined)[];
311
+ export interface SuperTrendPoint {
312
+ value: number;
313
+ trend: 'up' | 'down';
314
+ }
315
+ export declare const DEFAULT_SUPERTREND_ATR_PERIOD = 10;
316
+ export declare const DEFAULT_SUPERTREND_MULTIPLIER = 3;
317
+ export declare function calcSuperTrendData(data: KLineData[], atrPeriod: number, multiplier: number): (SuperTrendPoint | undefined)[];
318
+ export declare function calcSuperTrendDataSoA(layout: KLineSoALayout, atrPeriod: number, multiplier: number): (SuperTrendPoint | undefined)[];
319
+ export interface KeltnerPoint {
320
+ upper: number;
321
+ middle: number;
322
+ lower: number;
323
+ }
324
+ export declare const DEFAULT_KELTNER_EMA_PERIOD = 20;
325
+ export declare const DEFAULT_KELTNER_ATR_PERIOD = 10;
326
+ export declare const DEFAULT_KELTNER_MULTIPLIER = 2;
327
+ export declare function calcKeltnerData(data: KLineData[], emaPeriod: number, atrPeriod: number, multiplier: number): (KeltnerPoint | undefined)[];
328
+ export declare function calcKeltnerDataSoA(layout: KLineSoALayout, emaPeriod: number, atrPeriod: number, multiplier: number): (KeltnerPoint | undefined)[];
329
+ export interface DonchianPoint {
330
+ upper: number;
331
+ middle: number;
332
+ lower: number;
333
+ }
334
+ export declare const DEFAULT_DONCHIAN_PERIOD = 20;
335
+ export declare function calcDonchianData(data: KLineData[], period: number): (DonchianPoint | undefined)[];
336
+ export declare function calcDonchianDataSoA(layout: KLineSoALayout, period: number): (DonchianPoint | undefined)[];
@@ -0,0 +1,16 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface DEMARenderState extends BaseIndicatorState {
3
+ timestamp: number;
4
+ series: (number | undefined)[];
5
+ params: {
6
+ period: number;
7
+ showDEMA: boolean;
8
+ };
9
+ valueMin: number;
10
+ valueMax: number;
11
+ visibleMin: number;
12
+ visibleMax: number;
13
+ }
14
+ export declare const createDEMAStateKey: (paneId: string) => `indicator:${string}:${string}`;
15
+ export declare const DEFAULT_DEMA_PERIOD = 20;
16
+ export declare const EMPTY_DEMA_STATE: DEMARenderState;
@@ -0,0 +1,23 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface DonchianPoint {
3
+ upper: number;
4
+ middle: number;
5
+ lower: number;
6
+ }
7
+ export interface DonchianRenderState extends BaseIndicatorState {
8
+ timestamp: number;
9
+ series: (DonchianPoint | undefined)[];
10
+ params: {
11
+ period: number;
12
+ showUpper: boolean;
13
+ showMiddle: boolean;
14
+ showLower: boolean;
15
+ };
16
+ valueMin: number;
17
+ valueMax: number;
18
+ visibleMin: number;
19
+ visibleMax: number;
20
+ }
21
+ export declare const createDonchianStateKey: (paneId: string) => `indicator:${string}:${string}`;
22
+ export declare const DEFAULT_DONCHIAN_PERIOD = 20;
23
+ export declare const EMPTY_DONCHIAN_STATE: DonchianRenderState;
@@ -0,0 +1,16 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface HMARenderState extends BaseIndicatorState {
3
+ timestamp: number;
4
+ series: (number | undefined)[];
5
+ params: {
6
+ period: number;
7
+ showHMA: boolean;
8
+ };
9
+ valueMin: number;
10
+ valueMax: number;
11
+ visibleMin: number;
12
+ visibleMax: number;
13
+ }
14
+ export declare const createHMAStateKey: (paneId: string) => `indicator:${string}:${string}`;
15
+ export declare const DEFAULT_HMA_PERIOD = 9;
16
+ export declare const EMPTY_HMA_STATE: HMARenderState;
@@ -21,6 +21,16 @@ export declare class IndicatorRuntime {
21
21
  private cachedKstSeries;
22
22
  private cachedFastkSeries;
23
23
  private cachedMacdSeries;
24
+ private cachedAtrSeries;
25
+ private cachedWmaSeries;
26
+ private cachedDemaSeries;
27
+ private cachedTemaSeries;
28
+ private cachedHmaSeries;
29
+ private cachedKamaSeries;
30
+ private cachedSarSeries;
31
+ private cachedSupertrendSeries;
32
+ private cachedKeltnerSeries;
33
+ private cachedDonchianSeries;
24
34
  private dirtyData;
25
35
  private dirtyMAConfig;
26
36
  private dirtyBollConfig;
@@ -34,6 +44,16 @@ export declare class IndicatorRuntime {
34
44
  private dirtyKstConfig;
35
45
  private dirtyFastkConfig;
36
46
  private dirtyMacdConfig;
47
+ private dirtyAtrConfig;
48
+ private dirtyWmaConfig;
49
+ private dirtyDemaConfig;
50
+ private dirtyTemaConfig;
51
+ private dirtyHmaConfig;
52
+ private dirtyKamaConfig;
53
+ private dirtySarConfig;
54
+ private dirtySupertrendConfig;
55
+ private dirtyKeltnerConfig;
56
+ private dirtyDonchianConfig;
37
57
  private getDefaultConfig;
38
58
  /**
39
59
  * 更新数据
@@ -0,0 +1,20 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface KAMARenderState extends BaseIndicatorState {
3
+ timestamp: number;
4
+ series: (number | undefined)[];
5
+ params: {
6
+ period: number;
7
+ fastPeriod: number;
8
+ slowPeriod: number;
9
+ showKAMA: boolean;
10
+ };
11
+ valueMin: number;
12
+ valueMax: number;
13
+ visibleMin: number;
14
+ visibleMax: number;
15
+ }
16
+ export declare const createKAMAStateKey: (paneId: string) => `indicator:${string}:${string}`;
17
+ export declare const DEFAULT_KAMA_PERIOD = 10;
18
+ export declare const DEFAULT_KAMA_FAST_PERIOD = 2;
19
+ export declare const DEFAULT_KAMA_SLOW_PERIOD = 30;
20
+ export declare const EMPTY_KAMA_STATE: KAMARenderState;
@@ -0,0 +1,27 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ export interface KeltnerPoint {
3
+ upper: number;
4
+ middle: number;
5
+ lower: number;
6
+ }
7
+ export interface KeltnerRenderState extends BaseIndicatorState {
8
+ timestamp: number;
9
+ series: (KeltnerPoint | undefined)[];
10
+ params: {
11
+ emaPeriod: number;
12
+ atrPeriod: number;
13
+ multiplier: number;
14
+ showUpper: boolean;
15
+ showMiddle: boolean;
16
+ showLower: boolean;
17
+ };
18
+ valueMin: number;
19
+ valueMax: number;
20
+ visibleMin: number;
21
+ visibleMax: number;
22
+ }
23
+ export declare const createKeltnerStateKey: (paneId: string) => `indicator:${string}:${string}`;
24
+ export declare const DEFAULT_KELTNER_EMA_PERIOD = 20;
25
+ export declare const DEFAULT_KELTNER_ATR_PERIOD = 10;
26
+ export declare const DEFAULT_KELTNER_MULTIPLIER = 2;
27
+ export declare const EMPTY_KELTNER_STATE: KeltnerRenderState;
@@ -0,0 +1,26 @@
1
+ import { BaseIndicatorState } from '../../plugin';
2
+ /**
3
+ * SAR 点:value 是 SAR 价格,trend = 'up' 表示 SAR 在 K 线下方(多头止损)
4
+ * 'down' 表示 SAR 在 K 线上方(空头止损)。
5
+ */
6
+ export interface SARPoint {
7
+ value: number;
8
+ trend: 'up' | 'down';
9
+ }
10
+ export interface SARRenderState extends BaseIndicatorState {
11
+ timestamp: number;
12
+ series: (SARPoint | undefined)[];
13
+ params: {
14
+ step: number;
15
+ maxStep: number;
16
+ showSAR: boolean;
17
+ };
18
+ valueMin: number;
19
+ valueMax: number;
20
+ visibleMin: number;
21
+ visibleMax: number;
22
+ }
23
+ export declare const createSARStateKey: (paneId: string) => `indicator:${string}:${string}`;
24
+ export declare const DEFAULT_SAR_STEP = 0.02;
25
+ export declare const DEFAULT_SAR_MAX_STEP = 0.2;
26
+ export declare const EMPTY_SAR_STATE: SARRenderState;