feat(er): Kaufman Efficiency Ratio, KAMA's inner ratio standalone (#350) - #378
Conversation
…-Lib#350) ER[t] = |c[t] - c[t-P]| / SUM |one-bar changes| over the same P bars -- Perry J. Kaufman, Smarter Trading (1995). Default 10 (the author's own; TA_KAMA's same window defaults to 30 -- documented divergence), group Momentum Indicators, single real in/out, lookback P, no unstable period. The body is a verbatim lift of CURRENT kama.c, which is not the issue's snippet: that predates TA-Lib#253. The absolute TA_IS_ZERO band it carried fails the QUOTE-UNIT/SCALE gate (ER is homogeneous of degree 0; a fixed 1e-14 met a price-carrying sum). Current kama.c counts exactly-zero one-bar changes instead -- nullRun >= P purges the running sum to 0.0, after which the signed `sumROC1 <= periodROC` clamp (both sides carry the quote unit) answers the flat window's 0/0 with 1.0 through 0 <= 0. The clamp fires only on advances; on sustained declines the raw fabs ratio may exceed 1.0 by a few ULP, documented as such. Tests (test_composite2.c, tag now SMI,COPPOCK,ER): - a bit-exact composite differential against shipped TA_MOM(P) + |TA_MOM(1)| -> TA_SUM(P) with the two decisions re-applied, over a 4-period x 6-start grid (3000-value floor), TA_SUM anchored at the clamped start; - a KAMA-reconstruction differential: rebuild TA_KAMA from TA_ER via sc = fma(er, constDiff, constMax)^2 and prev = fma(c-prev, sc, prev), memcmp'd -- the generated ta_KAMA.c lowers both steps through explicit fma() (TA-Lib#183), so the reconstruction must too or it diverges in the last bit (measured at bar 23). A regression guard against the two bodies drifting, not independent evidence; - the issue's frozen pandas goldens at rel 1e-12; - edges: dead-flat == exact 1.0, round-trip zigzag == exact 0.0, monotone-up == exact 1.0 (the clamp), monotone-down inside 1 +- 1e-12 (the clamp's asymmetry: never exact equality), and outReal == inReal aliasing (the trailingValue cache). The pandas/ta4j oracle arms named by the issue live in the oracle infrastructure outside this repository; the goldens above carry the formula proof here. CHANGELOG entry added.
|
Reviewed. One blocker, two vacuous legs, and some doc items. Blocker — the asymmetric clamp cannot serve as the zero guard
Keeping the clamp asymmetric is right — it is what buys KAMA parity, and An exact Two legs that cannot fail
Documentation
|
…ble to fail Review of TA-Lib#378. The asymmetric clamp cannot double as the zero guard. It compares against the SIGNED numerator, so it is false for every down move, and a subtract-then-add sum can reach exactly 0.0 -- or below it -- on a window that is not flat, when a term absorbed on the way in is subtracted later at full precision. Those bars divided by zero and returned +Inf. The division now runs only where sumROC1 is exactly positive; the clamp is untouched, so KAMA parity is untouched. The nullRun purge does not cover this case: the window is not flat. Three legs, each with the control that reddens it: - zero denominator, new. A 1e16 step then a decline, at P=5. Drop the guard and bar 6 is +Inf. - dead-flat, new second leg. The old one is flat from bar 0, where the priming sum is already an exact 0.0 and the purge can change nothing; this one goes flat after live bars, so the sum carries residue. Delete the purge and every asserted bar reports 0.0 -- a flat market read as maximally inefficient -- while the old leg stays green. - monotone-down. On a uniform decrement all 54 outputs are exactly 1.0 under either clamp, so the 1 +- 1e-12 band was satisfied by the fabs edit er.c forbids. Two alternating decrements put 24 outputs strictly above 1.0, and the leg now counts them: with fabs the count is 0. Docs: er.md restated the two YAML defaults in prose, was missing Implementation, Aliases, See Also and References, and opened the Summary with an initial that truncate_description cuts the page description at.
Every conflict was a generated file, rebuilt by `generate` rather than merged by hand. Both sides had allocated internal error id 424 -- VORTEX's is the one upstream ships, so ER's entry was dropped and `generate` reassigned it to 425. The id suite catches the collision; a merge that only took both YAML lines leaves it.
|
All four findings verified fixed — thanks, that was fast.
Stop rebasing for now — the id will collide no matter what you do. #379 ERI and this branch both rebased onto ERI is gating now and will land first. I will do this branch's regenerate myself when I land it, exactly as with COPPOCK — drop the unshipped Worth knowing for future PRs, since this has now bitten four times: |
Implements #350:
TA_ER, Kaufman's Efficiency Ratio —|c[t] − c[t−P]| / Σ|one-bar changes|over the samePbars, the exact ratioTA_KAMAcomputes internally, exposed standalone and kept bit-identical to it. Default 10 (the author's own;TA_KAMA's same window defaults to 30 — divergence documented iner.md), lookbackP,flags: [stream](T3 trailing ring, folded first try), no unstable period.The issue's "verbatim kama.c" predates #253 — the current source wins
The snippet in the issue carries
TA_IS_ZERO(sumROC1); current kama.c does not — #253 replaced it with the flat-run count, and the QUOTE-UNIT/SCALE gate is why (measured here: the old band fails it at 2^-120; ER is homogeneous of degree 0, and a fixed 1e-14 met a price-carrying sum). So the true verbatim lift is:nullRun >= Ppurges the running sum to an exact 0.0, and the signedsumROC1 <= periodROCclamp — both sides carrying the quote unit — answers the flat window's 0/0 with 1.0 through0 <= 0. Decision 3's ruled value (flat ⇒ exactly 1.0) is unchanged; only the mechanism follows current kama.c.The clamp's asymmetry is preserved and documented per decision 4: it compares against the signed numerator, fires only on advances, and on sustained declines the raw
fabsratio may exceed 1.0 by a few ULP. Not "fixed" — that would changeTA_KAMA.Tests (
test_composite2.c, tag nowSMI,COPPOCK,ER— same placement rationale as SMI: the reference re-applies hand-written guards, so it is not a pure composition)memcmp): shippedTA_MOM(P)+|TA_MOM(1)|→TA_SUM(P)with the two decisions re-applied, 4 periods × 6 startIdx (≥3000-value floor),TA_SUManchored at the fused loop's clamped start.TA_KAMAfromTA_ERviasc = fma(er, constDiff, constMax)²,prev = fma(c − prev, sc, prev),memcmp'd againstTA_KAMAat unstable 0. The generatedta_KAMA.clowers both steps through explicitfma()(Evaluate retiring TA_EMA_Private: a vestige, but it silently suppresses FMA on EMA #183), so the reconstruction must too — the plain-multiply form diverges in the last bit (measured, bar 23). A regression guard against the two bodies drifting, per the issue: not independent evidence.outReal == inRealaliasing (thetrailingValuecache).Verification
Full
--codegen(four languages) rc 0 including QUOTE-UNIT/SCALE,stream_verifygreen,--xlang-hashzero non-baseline mismatches, full generator suite + clippy +regen-check+check-source-listsclean. The pandas/ta4j arms named by the issue live in the oracle infrastructure outside this repo (the ta4j arm is the KAMA-inversion construction the issue conditions-tested); the goldens above carry the formula proof here. CHANGELOG entry added.