chanlun/indicators/ta.py 接口兼容 talib.abstract,实现代码实际用到的 SMA/MA/EMA/RSI/ATR/MACD/BBANDS;chanlun/pipeline/resample.py 替代 technical.util.resample_to_interval。调用点只改 import,逻辑未动。 暖机长度与平滑种子按 TA-Lib 的约定实现,差一根 K 线就会让下游所有 笔/线段/中枢整体位移。其中 MACD 需特别处理:TA-Lib 让快慢两条 EMA 在同一根 K 线出首值,因而快线的种子取 x[slow-fast:slow] 的均值,而非 从 fastperiod-1 一路递推——两者在百元价位上相差约 0.17。 BBANDS 是有意的分歧:TA-Lib 用 sumsq/n - mean² 求方差,短窗口远离零 时灾难性抵消(timeperiod=2 误差 8.7e-7),本实现用 rolling std,对 50 位精度基准误差为 0。项目实际使用的周期两者一致到 1e-10。 顺带清理 12 个文件中 16 处从未调用的 talib/technical 导入。 验证:9440 组随机对拨;真实 K 线端到端比对 add_indicators 全部 33 个 指标列,NaN 模式一致、MACD 柱符号 100% 相同;屏蔽两个包后 60 个模块 均可导入。新增 test_ta_compat.py 将输出逐 bar 钉在 TA-Lib 上,但该文件 在 TA-Lib 缺失时静默跳过,改动 ta.py 需在装有 TA-Lib 的环境复跑。 Co-authored-by: Cursor <cursoragent@cursor.com>
53 lines
1.4 KiB
Python
53 lines
1.4 KiB
Python
"""OHLCV resampling — replaces `technical.util.resample_to_interval`.
|
|
|
|
That was the only symbol this project imported from `technical`, which in turn
|
|
pulled in the freqtrade dependency chain. Behaviour is preserved exactly,
|
|
including the left-labelled bins (rows are candle *open* times) and the
|
|
`dropna()` that drops empty intervals.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pandas as pd
|
|
|
|
__all__ = ["TICKER_INTERVAL_MINUTES", "resample_to_interval"]
|
|
|
|
TICKER_INTERVAL_MINUTES: dict[str, int] = {
|
|
"1m": 1,
|
|
"5m": 5,
|
|
"15m": 15,
|
|
"30m": 30,
|
|
"1h": 60,
|
|
"60m": 60,
|
|
"2h": 120,
|
|
"4h": 240,
|
|
"6h": 360,
|
|
"12h": 720,
|
|
"1d": 1440,
|
|
"1w": 10080,
|
|
}
|
|
|
|
_OHLC_AGG = {
|
|
"open": "first",
|
|
"high": "max",
|
|
"low": "min",
|
|
"close": "last",
|
|
"volume": "sum",
|
|
}
|
|
|
|
|
|
def resample_to_interval(dataframe: pd.DataFrame, interval: int | str) -> pd.DataFrame:
|
|
"""Resample OHLCV rows to `interval` minutes (or a timeframe string).
|
|
|
|
Merging the result back onto a finer frame requires care to avoid lookahead
|
|
bias; this function only resamples.
|
|
"""
|
|
if isinstance(interval, str):
|
|
interval = TICKER_INTERVAL_MINUTES[interval]
|
|
|
|
df = dataframe.copy()
|
|
df = df.set_index(pd.DatetimeIndex(df["date"]))
|
|
df = df.resample(f"{interval}min", label="left").agg(_OHLC_AGG).dropna()
|
|
df.reset_index(inplace=True)
|
|
return df
|