Skip to content

feat(shadow-account): add as-of price-context features (entry RSI, prior return)#302

Merged
warren618 merged 1 commit into
HKUDS:mainfrom
Robin1987China:shadow-account-price-features
Jun 25, 2026
Merged

feat(shadow-account): add as-of price-context features (entry RSI, prior return)#302
warren618 merged 1 commit into
HKUDS:mainfrom
Robin1987China:shadow-account-price-features

Conversation

@Robin1987China

@Robin1987China Robin1987China commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Shadow Account's _compute_features() only learned from journal columns
(holding_days, pnl_pct, entry_hour, entry_weekday, market), so the
extracted rules were purely behavioral with no market context. This adds two
price-context features per profitable roundtrip, read as-of the buy date:

  • entry_rsi14 — 14-period Wilder RSI at entry
  • prior_5d_return — trailing 5-bar close-to-close return ending at buy_dt

This is the first step you green-lit in #295. I followed the three scoping notes
from that thread:

  1. Reused existing pieces. RSI mirrors the causal compute_rsi shape in
    agent/src/skills/technical-basic/example_signal_engine.py:13 (re-implemented
    inline because that hyphenated skills dir isn't importable). Prices go through
    the loader registry (resolve_loader + fetch), the same path
    backtest/runner.py uses.
  2. As-of buy_dt, no look-ahead. Both features read only bars dated
    <= buy_dt. The fetch window ends at buy_dt, so the (buy_dt, sell_dt] exit
    window is never touched — look-ahead is structurally impossible, not just
    guarded after the fact.
  3. Kept v1 degradation + offline determinism. Any failure (unmapped market,
    no source, empty result, insufficient history) drops the feature to NaN and the
    pipeline still runs. All tests use mocked loaders — no network.

A price feature only joins the KMeans feature set when it's present for
>= min_support roundtrips; otherwise clustering stays journal-only, exactly as
before. Partial NaNs are median-imputed (that affects grouping only — rule bounds
never read price features).

Why

Shadow Account extracts rules from journal columns alone, so extracted rules
are purely behavioral with no market context. Adding price-context features
lets clustering see whether profitable roundtrips share common entry conditions
(overbought RSI, recent momentum), making extracted rules actionable rather
than just descriptive.

Changes

  • agent/src/shadow_account/extractor.py: _compute_rsi, _fetch_price_history,
    _as_of_index, _price_features_as_of, _attach_price_features (batches one
    fetch per symbol); _auto_cluster takes a numeric_features arg instead of the
    module constant; _promoted_numeric_features gates promotion.
  • agent/tests/test_shadow_account.py: 15 new tests + an autouse offline fixture
    so the suite stays network-free.

Test Plan

  • ruff check — clean
  • pytest agent/tests/test_shadow_account.py — 43 passed
  • full suite (excl e2e) — 4385 passed, 1 skipped
  • RSI causality, look-ahead guard (bars after buy_dt don't change values),
    tz-aware buy_dt, all three degradation branches, batch-once-per-symbol,
    median-impute / all-NaN-drop in clustering

Checklist

Refs #295

Extend Shadow Account feature engineering with two point-in-time-safe
price-context features per profitable roundtrip, read as-of the buy date:

- entry_rsi14: 14-period Wilder RSI at entry (causal; mirrors the shape of
  compute_rsi in skills/technical-basic, re-implemented since that hyphenated
  skills dir is not importable).
- prior_5d_return: trailing 5-bar close-to-close return ending at buy_dt.

Both read only bars dated <= buy_dt (never the (buy_dt, sell_dt] exit window),
so look-ahead is structurally impossible — the fetch window ends at buy_dt.
Prices come through the backtest loader registry (resolve_loader + fetch),
the same path the runner uses. Any failure (unmapped market, no source, empty
result, insufficient history) degrades to NaN and the pipeline still runs,
honoring the v1 'price features optional' contract.

A price feature joins the clustering numeric set only when present for
>= min_support roundtrips; partial NaNs are median-imputed (imputation affects
grouping only, never rule bounds). Tests are deterministic and network-free.

Refs HKUDS#295

Signed-off-by: Robin1987China <41602358+Robin1987China@users.noreply.github.com>
@warren618 warren618 merged commit b175c25 into HKUDS:main Jun 25, 2026
1 check passed
@warren618

Copy link
Copy Markdown
Collaborator

Thanks @Robin1987China! Merged as b175c25. Nicely PIT-safe — entry_rsi14 / prior_5d_return are read as-of buy_dt through the loader registry, the per-symbol batch fetch still re-slices to each roundtrip's own buy date, and sparse price data cleanly degrades to the journal-only baseline. 🙏

warren618 pushed a commit that referenced this pull request Jun 26, 2026
…es (#314)

Promoted entry_rsi14 / prior_5d_return bounds now flow into extracted ShadowRules and the generated SignalEngine for real conditional entry. Follows #302. Thanks @Robin1987China.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants