diff --git a/deploy/profile-scripts/indicators.py b/deploy/profile-scripts/indicators.py index 6a012628..c6a33ffb 100644 --- a/deploy/profile-scripts/indicators.py +++ b/deploy/profile-scripts/indicators.py @@ -47,17 +47,27 @@ def calc_rsi(series, n=14): def calc_atr(klines, n=14): - """ATR(Average True Range),与回测 calc_factors 的 atr_pct 同口径。 - klines: [{high, low, close, ...}]""" + """ATR(Average True Range),EMA 平滑——与 backtest_framework.calc_atr 完全一致 + (2026-08-12 统一口径:原 SMA 与回测 EMA 差 3.59%,回测实盘口径分裂)。 + klines: [{high, low, close, ...}]。返回最新 ATR 值(单值)。""" if len(klines) < n + 1: return None - trs = [] - for i in range(1, len(klines)): - h, l, pc = klines[i]["high"], klines[i]["low"], klines[i - 1]["close"] - tr = max(h - l, abs(h - pc), abs(l - pc)) - trs.append(tr) - atr = sum(trs[-n:]) / n - return atr + highs = [k["high"] for k in klines] + lows = [k["low"] for k in klines] + closes = [k["close"] for k in klines] + # True Range(与 backtest_framework.calc_tr 一致) + tr = [highs[0] - lows[0]] + for i in range(1, len(highs)): + hl = highs[i] - lows[i] + hc = abs(highs[i] - closes[i - 1]) + lc = abs(lows[i] - closes[i - 1]) + tr.append(max(hl, hc, lc)) + # EMA 平滑(与 backtest_framework.calc_atr 一致:calc_ema(tr, n)) + k = 2 / (n + 1) + ema = tr[0] + for t in tr[1:]: + ema = t * k + ema * (1 - k) + return ema def calc_obv(klines):