Spaces:
Sleeping
Sleeping
| """ | |
| chan_glue.py — wires the user's notebook-style modules together at runtime. | |
| The original chan_engine.py / chan_multilevel.py were written as notebook cells: | |
| chan_multilevel references `ChanAnalyzer` / `Signal` via a commented-out import. | |
| Because both files use `from __future__ import annotations` and resolve names at | |
| call time, we can simply inject the symbols into the module namespace — the Chan | |
| analysis logic itself is left 100% untouched. | |
| Also provides a small LRU-cached analyzer factory (the original chan_common.py | |
| was A-share specific and is not used in the US version). | |
| """ | |
| from __future__ import annotations | |
| import hashlib | |
| from collections import OrderedDict | |
| import pandas as pd | |
| import chan_engine | |
| import chan_multilevel | |
| # ── inject cross-module symbols (replaces the commented `from chan_engine import …`) ── | |
| chan_multilevel.ChanAnalyzer = chan_engine.ChanAnalyzer | |
| chan_multilevel.Signal = chan_engine.Signal | |
| chan_engine.PIVOT_MAX_EXTEND_SEGS = chan_engine.PIVOT_MAX_EXTEND_SEGS # no-op, keeps linters calm | |
| # Re-exports for app code | |
| ChanAnalyzer = chan_engine.ChanAnalyzer | |
| Signal = chan_engine.Signal | |
| MultiLevelChan = chan_multilevel.MultiLevelChan | |
| MultiLevelSignal = chan_multilevel.MultiLevelSignal | |
| resample_weekly = chan_multilevel.resample_weekly | |
| resample_monthly = chan_multilevel.resample_monthly | |
| set_analyzer_factory = chan_multilevel.set_analyzer_factory | |
| # ── cached analyzer factory ────────────────────────────────────────────── | |
| _CACHE: "OrderedDict[str, chan_engine.ChanAnalyzer]" = OrderedDict() | |
| _CACHE_MAX = 64 | |
| def _df_key(level: str, df: pd.DataFrame) -> str: | |
| n = len(df) | |
| if n == 0: | |
| return f"{level}-empty" | |
| last = str(df['date'].iloc[-1]) | |
| first = str(df['date'].iloc[0]) | |
| tail_close = float(df['close'].iloc[-1]) | |
| raw = f"{level}|{n}|{first}|{last}|{tail_close:.6f}" | |
| return hashlib.md5(raw.encode()).hexdigest() | |
| def cached_analyzer(level: str, df: pd.DataFrame): | |
| key = _df_key(level, df) | |
| if key in _CACHE: | |
| _CACHE.move_to_end(key) | |
| return _CACHE[key] | |
| an = chan_engine.ChanAnalyzer(df.reset_index(drop=True)) | |
| _CACHE[key] = an | |
| while len(_CACHE) > _CACHE_MAX: | |
| _CACHE.popitem(last=False) | |
| return an | |
| def install(): | |
| """Install the cached analyzer factory into MultiLevelChan.""" | |
| set_analyzer_factory(cached_analyzer) | |
| install() | |