Skip to content

feat(sl-hunting): v5j + SLH-019; CI runs the SL Hunting tests; coverage floor 73% - #181

Merged
DoRmAmMu1997 merged 5 commits into
mainfrom
feat/sl-hunting-v5j
Sep 23, 2026
Merged

DoRmAmMu1997 merged 5 commits into
mainfrom
feat/sl-hunting-v5j

Conversation

@DoRmAmMu1997

@DoRmAmMu1997 DoRmAmMu1997 commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Same read, one basket against three

Both books read 23 Sep identically: sellers seated from yesterday's fall, a FLAT open (+0.099%, 23,329.00 → 23,352.15), so BUY to hunt them.

IH bought all three indices at the open, held through a dip where NIFTY and SENSEX kept rejecting while BankNIFTY climbed, and booked his target.

The agent opened three baskets:

# open entry stop lots exit NIFTY BNF basket
1 09:32 23,371.75 23,360.00 3 discretionary −750.75 −423.00 −₹1,173.75
2 09:59 23,368.95 23,349.00 1 discretionary +149.50 +721.50 +₹871.00
3 10:17 23,368.25 23,347.00 1 discretionary +786.50 +295.50 +₹1,082.00

Day +₹779.25.

The reason trade 1 gave was false when it filled

Its exit said "booking the still-positive basket (+420)". Both legs lost at the fill: −₹1,173.75.

position_state is a point-in-time mark, read inside a turn whose median was 33–37 s across 21–23 Sep (one in ten over 45–53 s). Across the 31 exits that quoted a basket figure:

  • median gap between cited and realised: ₹496.50
  • no systematic bias (mean −₹14.63)
  • four cited a profit and realised a loss — never the reverse

The one-way flips have a mechanism: an exit is usually triggered by price turning against you, and half a minute later you fill further into that turn.

IH said the rule out loud

"Look at the trade less. Just focus on the chart… the premiums are moving up and down a lot, so the chart looks better than the premiums right now."

His own line for being wrong was a price — "if it breaks down the closing price, the trade can go wrong."

Measured before writing it

All 130 discretionary exits walked forward (one print a minute) against holding the original bracket.

Holding the bracket is refused. Exiting made +404.80 points vs +213.25 for holding; exiting won 84–46.

But the basis of the exit matters:

exit reason leans on n exit − hold
price action only 94 +241.25
cites a rupee figure 36 −49.70

Rupee-citing exits are mostly profit bookings, so that could be winners-vs-losers in disguise. Controlled for outcome it holds in both:

class price action rupee figure
winners (per exit) +3.28 +0.92
losers (per exit) +2.08 −7.38

Cutting a loser on the rupee figure did worse than letting the stop fire.

v5j

Sits directly after v4f and tells the agent how to read v4f's trigger rather than replacing it: "the move has stopped paying" is a fact about price, and the rupee figure is a late, noisy proxy for it.

  • The check: strike the rupee figure out of the exit reason; what's left must still name a price. If all you can say is a number from position_state, you don't yet have an exit reason.
  • Not a licence to exit less — stated outright, so the refused hold-the-bracket gate can't be re-derived from it.
  • Limits in the rule: one print a minute, regex classification, only ten rupee-citing losers.

A correction

While comparing I first priced trade 1 "held to trade 2's exit" at +₹5,755.50 on the same strikes. That was wrong — NIFTY fell to 23,349.55, through trade 1's 23,360 stop, so holding would have been stopped at −11.75 points, worse than its −7.25 exit. The exit was right; the reason it gave was not.

The real difference from IH is where the line sat:

level price
agent's stop 23,360.00
session low 23,349.55
IH's line — prior close 23,329.00

(Prior close from CPR AI's previous_day block; its pivot matches the agent's own 23,367.92.) Not encoded — a stop-distance floor was already priced negative at every level on 21 Sep.

Negative-tested 10 ways, all 10 caught, plus a passing control.


Addendum: SLH-019 — the mark is dated, and an EXIT reports what it booked

You approved both code follow-ups, so they ship here.

position_state is dated. With a position open it carries as_of — the moment its P&L was marked. The tool description now says what that means: a point-in-time mark, and one turn takes about half a minute, so any order fills later and at a different price.

An accepted EXIT reports what it actually booked:

field what it is
realised_pnl change in the worker's realized_pnl across the exit — both legs book there, so it's right for NIFTY, BNF and BOTH, and excludes the day's earlier trades
open_legs_after any leg still open afterwards
exited_at when the exit returned
mark_you_read the position_state figure read earlier this turn, and how many seconds before the exit

23 Sep replayed through the order tool: +420 read at 09:50:06 → filled 09:50:34, seconds_before_exit 28.0, realised_pnl −1,173.75.

Honest in the two cases that matter: an unconfirmed live exit books nothing and keeps its leg open, so it reports 0.0 and names the leg; a worker with no numeric realized_pnl gets no figure at all rather than an invented zero. The order tool calls this under the same lock the worker's stop/target/square-off paths hold, so nothing books between the two readings.

What it can't do: the EXIT's reason is written before the fill and is the permanent journal record, so it can't be corrected. SLH-019 corrects the final decision reasoning (the decisions log). v5j now names the new fields and says the realised figure is the one to state.

Tests: 10 on fakes in the agent suite, plus 2 on the real SLHuntingAIWorker — a BOTH exit with NIFTY down and BankNIFTY up reports what both legs booked; NIFTY-only then BNF-only report each leg alone. Negative-tested 14 ways, all 14 caught; two of them (a one-leg exit reporting nothing booked) are caught only by the real-worker tests.

Found on the way: CI never ran the SL Hunting worker tests — now fixed here (third commit)

The master imports the SL Hunting modules only behind SL_HUNTING_ENABLED, which CI never set, so CI reported OK (skipped=62) while skipping every SL Hunting worker test — mirror, basket P&L, one-leg exits, cooldown, exit routing, and SLH-019's two real-worker tests. They only ran on your box, because its .env switches the agent on.

Gates: master 613 OK (skipped=60) as CI runs it, and 613 OK with SL_HUNTING_ENABLED=true · 28 market-data-health · 1594 pytest · ruff · mypy (80 files) · compileall · bandit.


Third commit: CI now runs the SL Hunting worker tests

before (1ca9b80) after (e3bfd9b)
master tests run 613 617
skipped 62 2
CI coverage 72.1% 73.8%

Both Python 3.12 and 3.13, on Linux — where these ~60 tests had never run before. All passed first time. The 2 remaining skips are the Shoonya/Kotak execution-layer tests, whose SDKs the quality job doesn't install by design.

The fix is in the test loader only. The suite already loads the master inside patch.dict(os.environ, {...}); SL_HUNTING_ENABLED=true is added there. The master reads the flag once at import, patch.dict restores the environment the moment the load ends, and the production default stays off. Because the master loads .env with override=False, CI, worktrees and your box now behave identically.

What the import needs — verified, not assumed. With claude_agent_sdk blocked, all five SL Hunting modules still import; with pydantic blocked, they fail. pydantic is pinned in requirements-ai.txt, which CI already installs, so the workflow is unchanged.

Truthful skip messages. Five skip sites — three of which blamed "missing" packages that were installed — now share one helper naming the real cause: master failed to load, flag off, or import failed.

Guards, because a silent skip is how this went unnoticed:

  • the worker must load whenever pydantic is installed — so the original bug now fails the suite instead of reporting OK;
  • the flag must not outlive the load;
  • the skip reason must tell "flag off" from "import failed";
  • the master's production default must stay False — pinning the tempting wrong fix.

Negative-tested 5 ways, all 5 caught, each by the test meant for it. Dropping the flag reproduces the original bug exactly (skipped=60) and now fails.

Coverage floor — raised to 73% in the fourth commit, below.

Gates (this commit): master 617 OK, 0 skipped under CI conditions · 28 market-data-health · 1594 pytest · coverage policy passed · ruff · mypy (80 files) · compileall · bandit.


Fourth commit: coverage floor 70% → 73%, docs level

At your direction, into the headroom the third commit created (CI 73.8%, identical on 3.12 and 3.13). The old 70.0 sat under a CI figure of 70.2% that was measured without the SL Hunting tests. New margin ~0.8pp — on the order of 230 statements and branches — so a PR adding materially untested code still goes red.

The floor is stated in several places, so they moved together:

file change
pyproject.toml fail_under 70.0 → 73.0; comment block rewritten (the 73.8% basis, why 70.2% was measured without the SL Hunting tests)
test_repository_policy.py floor pin 70.0 → 73.0, with a ledger entry
scripts/check_coverage_thresholds.py docstring "70% floor" → "73% floor"
CLAUDE.md / AGENTS.md identical edits: 73% floor, CI measures 73.8%, and the master-suite note about the load-time flag
README.md, docs/lld/testing-and-ci.md same floor and CI figure — nothing in the repo still says 70%

The local-vs-CI gap is now ~0.5 points, not ~2. CI skips 9 tests a fully-equipped machine runs (2 master, 7 pytest); local reads 74.3% vs CI's 73.8%. Most of the old 2-point gap was the SL Hunting tests CI wasn't running. The docs also no longer blame the broker SDKs alone — scikit-learn isn't in CI's install either.

Parity. AGENTS.md and CLAUDE.md were already identical below ## What this project is — enforced by test_agent_architecture_docs_stay_in_sync_…. The title and short intro above that marker differ on purpose (CLAUDE.md tells Claude which skills to load). Every edit went to both, and the parity test still passes.

Negative-checked 4 ways, all caught: reverting the floor to 70.0, quietly lowering it to 72.0, and editing either doc alone.

Gates (this commit): master 617 OK, 0 skipped · 28 market-data-health · 1594 pytest · coverage report exits 0 under fail_under = 73.0 · coverage policy passed · ruff · mypy · compileall · bandit.


Final addendum: the pre-open note for 24 SEP 2026

Source: Prediction For 24 SEP 2026 (4BKhLKn4zHY, uploaded 2026-09-23 21:25 IST).

The seated side flipped, and the flat branch with it. Tonight: positive momentum with only a small retracement, no big one (BankNIFTY held above 56500) — so buyers may be seated, and a flat open means SELL.

open 23 Sep 24 Sep
flat BUY (hunt sellers) SELL (hunt buyers)
gap down small: BUY SELL
gap up BUY BUY only if it opens above the prior high (NIFTY: especially above 23500)

The buy branch is a level, not a gap size. Above the "higher point", buyers stay confident and leave no SLs to hunt. That can disagree with the agent's own open classification (SLH-017's 0.5% threshold), so the note says outright that a computed GAP_UP verdict alone doesn't select the buy branch — and a gap up opening below the prior high is in neither branch. The test asserts that absence.

SENSEX has its expiry on 24 Sep.

One garble, resolved from the chart again. NIFTY's supports came through as "2360 2370" — neither obvious reading. The 1080p frame at 1:44 tags 23,369.60 and 23,271.75 (the second is the same drawn line as last night's), so 23370 / 23270. The resistances are last night's lines too (23,500.15 / 23,567.20), spoken as 23500 and 23570.

resistance support
NIFTY 23500 / 23570 23370 / 23270
BANKNIFTY 56800 / 57000 56370 / 56100
SENSEX 75100 / 75300 74650 / 74430

Negative-tested 12 ways, all 12 caught — including carrying 23 Sep's flat → BUY forward, turning the buy branch back into a gap-size rule, letting a GAP_UP verdict select it, and both natural misreadings of the garbled supports.

Gates (this commit): master 617 OK, 0 skipped · 28 market-data-health · 1594 pytest · ruff · mypy · compileall.

🤖 Generated with Claude Code

DoRmAmMu1997 and others added 2 commits September 23, 2026 13:08
Source: IH's live session (-dvbW6vgjPc, 2026-09-23 11:40 IST), traded on the
same pre-open plan this book was given, plus this book's own three trades.

THE DAY. Both books read it identically - sellers seated from 22 Sep's fall, a
FLAT open (+0.099%, 23,329.00 -> 23,352.15), so BUY to hunt them. IH bought all
three indices at the open, held through a dip in which NIFTY and Sensex kept
rejecting while BankNIFTY climbed, and booked his target. The agent opened
three baskets: -1,173.75, +871.00, +1,082.00. Day +779.25.

WHAT IH SAID, MID-TRADE: "look at the trade LESS. Just focus on the chart...
the premiums are moving up and down a lot, so the chart looks better than the
premiums right now." His own line for being wrong was a PRICE - "if it breaks
down the closing price, the trade can go wrong".

WHY THE FIGURE IS WORSE FOR THIS AGENT - IT IS LATE. Trade 1's exit said
"booking the still-positive basket (+420)"; both legs lost at the fill,
-1,173.75. position_state is a point-in-time mark read inside a turn whose
median was 33.2s / 34.4s / 37.0s across 21-23 Sep, one in ten over 45-53s.
Across 31 exits that quoted a basket figure: median gap 496.50, no systematic
bias (mean -14.63), and FOUR cited a profit and realised a loss - never the
reverse. Mechanism: an exit is usually triggered BY price turning against you,
and half a minute later you fill further into that turn.

MEASURED FIRST, AS ALWAYS. All 130 discretionary exits were walked forward,
one print a minute from the decisions log, against holding the original bracket.

  * Holding is REFUSED: exiting made +404.80 points against +213.25; exiting
    won 84-46; holding would have hit the stop 59 times, the target 17.
  * But the basis matters. Exits resting on price action beat holding by
    +241.25; exits citing a rupee figure did WORSE than holding, -49.70.
  * Controlled for outcome class it survives in both: winners +3.28 vs +0.92
    per exit, losers +2.08 vs -7.38. Cutting a loser on the rupee figure did
    worse than letting the stop fire.

v5j sits directly after v4f and tells the agent how to READ v4f's trigger
rather than replacing it: "the move has stopped paying" is a fact about price.
It carries a concrete check - strike the rupee figure from the exit reason;
what remains must still name a price - and says outright that it is NOT a
licence to exit less, so the refused hold-the-bracket gate cannot be
re-derived from it. Its limits are in the rule: one print a minute, regex
classification of reasons, only ten rupee-citing losers.

A CORRECTION, recorded in the doc. While comparing, I first priced trade 1
"held to trade 2's exit" at +5,755.50 on the same strikes. Wrong: NIFTY fell to
23,349.55 through its 23,360 stop, so holding would have been stopped at
-11.75, worse than its -7.25 exit. The exit was right; the reason was not. The
real difference from IH is the line: his was the prior close (23,329.00, from
CPR AI's previous_day block, pivot cross-checked), which the low held by 20.55.
Not encoded - a stop-distance floor was priced negative at every level on 21
Sep.

Not built, named for the operator: an as_of timestamp on position_state, and
the EXIT tool reporting the realised basket figure back into the turn.

Negative-tested 10 ways, all 10 caught, plus a passing control.

Gates: 611 master, 28 market-data-health, 1584 pytest, ruff (0.16.7 locally;
CI enforces the 0.16.8 pin), mypy (80 files), compileall.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n EXIT booked

Addendum to the v5j PR, at the operator's direction. v5j tells the model to
judge an exit on price rather than on the rupee figure; this gives it the two
facts that make that checkable at the moment it acts.

On 2026-09-23 an exit reasoned "booking the still-positive basket (+420)" and
filled at -1,173.75. position_state is a point-in-time mark, read inside a turn
whose median is 33-37s. Nothing told the model when the mark was taken, and
nothing told it what the exit actually booked.

POSITION_STATE IS DATED. With a position open the payload carries `as_of`, the
moment its figures were marked, from a clock injected on the tool context
(naive local time, as every other timestamp this agent writes). A flat snapshot
is unchanged. The description, now a module constant so tests can assert it
like order_tool_description, says what the stamp means.

AN ACCEPTED EXIT REPORTS WHAT IT BOOKED:
  realised_pnl     change in the worker's realized_pnl across the exit call.
                   Both legs book there, so one figure is right for NIFTY, BNF
                   and BOTH, and it excludes whatever the day booked before.
  open_legs_after  any leg still open afterwards.
  exited_at        when the exit returned.
  mark_you_read    the position_state mark read earlier this pass, and how many
                   seconds before the exit (omitted if none was read).

The before/after delta is the codebase's own method - the worker already
snapshots realized_pnl at entry for the journal's basket figure. It is honest
in the two cases that matter: an unconfirmed live exit books nothing and keeps
its leg open, so the result says 0.0 and names the leg; and a worker with no
numeric realized_pnl gets no figure at all rather than an invented zero. The
order tool calls this under the lock the worker's stop/target/square-off paths
also hold, so no mechanical exit can book between the two readings.

What it cannot do: the EXIT's `reason` is written before the fill and is the
permanent journal record, so it cannot be corrected. What SLH-019 corrects is
the final decision reasoning, written after the tool returns. v5j now names the
new fields and says the realised figure is the one to state.

TESTS. Ten in the agent suite on fakes, including 23 Sep replayed end to end
through the order tool (+420 read at 09:50:06, filled 09:50:34,
seconds_before_exit 28.0, realised -1,173.75). Two in the master suite on the
REAL SLHuntingAIWorker with option prices moved in the shared store: a BOTH exit
with NIFTY down and BankNIFTY up reports what both legs booked, and NIFTY-only
then BNF-only exits report each leg alone.

Negative-tested 14 ways, all 14 caught, plus a passing control. Two of them -
a one-leg exit that reports nothing booked - are caught ONLY by the real-worker
tests.

A GAP FOUND ON THE WAY, not fixed here: the master imports the SL Hunting
modules only behind SL_HUNTING_ENABLED, which CI never sets, so CI's master
suite reports OK (skipped=60) - the SL Hunting worker tests have never run in
CI, including the two above. They run on the operator's box, whose .env sets
the flag. Flagged as its own task.

Gates: master 613 OK (skipped=60) as CI runs it, and 613 OK with
SL_HUNTING_ENABLED=true (0 skipped); 28 market-data-health; 1594 pytest; ruff
(0.16.7 locally; CI enforces 0.16.8); mypy (80 files); compileall; bandit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DoRmAmMu1997 DoRmAmMu1997 changed the title feat(sl-hunting): v5j — judge the exit on the chart, not on the premium feat(sl-hunting): v5j — judge the exit on the chart, not on the premium (+ SLH-019) Sep 23, 2026
…ng them

CI's master suite has reported OK while skipping every SL Hunting worker test:
the run on this PR's previous commit shows 613 tests, OK (skipped=62). Sixty of
those are the BankNIFTY mirror, basket P&L, one-leg exits, post-exit cooldown
(SLH-005), executor exit routing and SLH-019's two real-worker tests. They ran
only on a machine whose private Dependencies/.env switched the agent on.

ROOT CAUSE. The master imports the SL Hunting modules only
`if SL_HUNTING_ENABLED:` (default False). CI has no .env and never sets it, and
the test module did not either, so SLHuntingAIWorker stayed undefined and every
test skipped - under a message blaming claude-agent-sdk / pydantic, which were
installed.

THE FIX IS IN THE TEST LOADER ONLY. The suite already loads the master inside
patch.dict(os.environ, {...}); SL_HUNTING_ENABLED=true is added there. The
master reads the flag once, into a module constant at import, and patch.dict
restores the environment the moment the load ends, so nothing leaks into the
tests that follow and the production default stays off. The master loads .env
with override=False, so the value wins on every machine alike - CI, a worktree,
and the operator's box now behave identically.

WHAT THE IMPORT NEEDS, VERIFIED RATHER THAN ASSUMED. With claude_agent_sdk
blocked in sys.modules all five SL Hunting modules still import; with pydantic
blocked they fail. pydantic is the one hard dependency, it is pinned in
requirements-ai.txt, and CI already installs that file - so the workflow's
install step is unchanged.

TRUTHFUL SKIP MESSAGES. Five SL Hunting skip sites (three blaming missing
packages) now share one helper that names the real cause: the master failed to
load, SL_HUNTING_ENABLED is off, or the flag is on and the import failed (whose
cause the master already logs at load).

GUARDS, because a SILENT skip is how this went unnoticed:
  * the worker must load whenever pydantic is installed - so the original bug
    now FAILS the suite instead of reporting OK (it still skips, honestly,
    where pydantic genuinely is not installed);
  * the flag must not outlive the load;
  * the skip reason must tell "flag off" from "import failed";
  * the master's production default must stay False - pinning the tempting
    wrong fix, which would make an opt-in, LLM-driven, live-capable strategy
    opt-out everywhere.

Negative-tested 5 ways, all 5 caught, each by the test meant for it, plus a
passing control. Dropping the flag reproduces the original bug exactly
(skipped=60) and now fails.

Every newly-running test passed at first run under CI conditions (no .env, no
SL_HUNTING_* variable): 617 run, 0 skipped locally. No floor was changed;
coverage reads 74.3% locally, which CLAUDE.md warns runs about 2 points high,
so the figure to judge is CI's.

Gates: master 617 OK (0 skipped) under CI conditions; 28 market-data-health;
1594 pytest; branch coverage + check_coverage_thresholds.py passed; ruff; mypy
(80 files); compileall; bandit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DoRmAmMu1997 DoRmAmMu1997 changed the title feat(sl-hunting): v5j — judge the exit on the chart, not on the premium (+ SLH-019) feat(sl-hunting): v5j + SLH-019, and CI now runs the SL Hunting worker tests Sep 23, 2026
…cs level

At the operator's direction, into the headroom the previous commit created.

That commit made CI run the ~60 SL Hunting worker tests it had always skipped,
and CI's measured overall coverage rose from 72.1% to 73.8% on the same code,
identically on Python 3.12 and 3.13. The old 70.0 floor sat under a CI figure
(70.2%) that was taken WITHOUT those tests. The figure is deterministic, so the
new margin of ~0.8pp (on the order of 230 statements and branches) is a
choice, not luck - a PR that adds materially untested code should go red.

Changed together, because the floor is stated in several places and they must
not disagree:

  pyproject.toml          fail_under 70.0 -> 73.0, and its comment block
                          rewritten: the 73.8% basis, why the old 70.2% was
                          measured without the SL Hunting tests, and the new
                          local-vs-CI gap.
  test_repository_policy  the floor pin 70.0 -> 73.0, with a ledger entry.
  check_coverage_...py    docstring: "70% floor" -> "73% floor".
  CLAUDE.md / AGENTS.md   identical edits: the 73% floor, CI measures 73.8%,
                          and the master-suite note that the loader switches
                          SL_HUNTING_ENABLED on for the load only.
  README.md, docs/lld/testing-and-ci.md
                          the same floor and CI figure, so no document still
                          says 70%.

THE LOCAL-VS-CI GAP IS NOW ~0.5 POINTS, NOT ~2. The docs said a machine with the
broker SDKs "runs 7 tests CI skips and reads ~2 points high". Measured now: CI
skips 9 tests (2 in the master suite, 7 in pytest) that a fully equipped
machine runs, and the local figure is 74.3% against CI's 73.8%. Most of the old
2-point gap was the SL Hunting tests CI was not running. The docs also no
longer blame the broker SDKs alone: scikit-learn is not in CI's install either,
so the wording names the optional extras CI lacks without attributing each
skip to one of them.

PARITY. AGENTS.md and CLAUDE.md were already identical below "## What this
project is", which test_agent_architecture_docs_stay_in_sync_... enforces; the
title and the short intro above that marker differ on purpose (CLAUDE.md tells
Claude which skills to load). Every edit here was made identically to both, and
the parity test still passes.

Negative-checked 4 ways, all caught: reverting the floor to 70.0, quietly
lowering it to 72.0, and editing either CLAUDE.md or AGENTS.md alone.

Gates: master 617 OK (0 skipped, CI conditions); 28 market-data-health; 1594
pytest; coverage report exits 0 under fail_under = 73.0 (74.3% locally - CI's
73.8% is the figure that counts); check_coverage_thresholds.py passed; ruff;
mypy (80 files); compileall; bandit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DoRmAmMu1997 DoRmAmMu1997 changed the title feat(sl-hunting): v5j + SLH-019, and CI now runs the SL Hunting worker tests feat(sl-hunting): v5j + SLH-019; CI runs the SL Hunting tests; coverage floor 73% Sep 23, 2026
Source: 'Prediction For 24 SEP 2026' (4BKhLKn4zHY, uploaded 2026-09-23 21:25
IST). Final addendum to this PR.

THE SEATED SIDE FLIPPED, AND THE FLAT BRANCH WITH IT. 23 Sep's note hunted
seated SELLERS with a BUY on any flat open. Tonight: positive momentum on all
three indices with only a small retracement, no big one (BankNIFTY held itself
above 56500), so BUYERS may be seated, and a flat open means SELL.

                   23 Sep                       24 Sep
  flat             BUY  (hunt sellers)          SELL (hunt buyers)
  gap down         small: BUY                   SELL
  gap up           BUY                          BUY only if it opens ABOVE the
                                                prior high (NIFTY: esp. > 23500)

THE BUY BRANCH IS A LEVEL, NOT A GAP SIZE. On all three indices he conditions
it on the open landing above the "higher point": there buyers stay confident,
will not cut, and leave no SLs to hunt. That can disagree with the agent's own
open classification, which is a percentage (SLH-017's 0.5% threshold), so the
note says outright that a computed GAP_UP verdict alone does not select the buy
branch - and that a gap up opening BELOW the prior high is in neither branch.
The test asserts that absence, because an absent case is what gets filled in.

SENSEX has its expiry on 24 Sep; he names it before any level.

NIFTY'S SUPPORTS came through as "2360 2370", which matches neither obvious
reading. Read from the 1080p chart frame at 1:44: the support lines are tagged
23,369.60 and 23,271.75, so the levels are 23370 / 23270 - and 23,271.75 is the
same drawn line as the previous night's. The resistances are the previous
night's lines too (23,500.15 / 23,567.20); he called 23500 the important
psychological number and spoke the upper line as 23570 tonight where 23 Sep
said 23560. Recorded as spoken.

  NIFTY      R 23500 / 23570   S 23370 / 23270
  BANKNIFTY  R 56800 / 57000   S 56370 / 56100
  SENSEX     R 75100 / 75300   S 74650 / 74430

Negative-tested 12 ways, all 12 caught, plus a passing control - including
carrying 23 Sep's flat -> BUY forward, seating the wrong side, turning the buy
branch back into a gap-size rule, letting a GAP_UP verdict select it, inventing
coverage for a gap up below the prior high, and both natural misreadings of the
garbled supports.

Gates: master 617 OK (0 skipped, CI conditions); 28 market-data-health; 1594
pytest; ruff; mypy (80 files); compileall.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DoRmAmMu1997
DoRmAmMu1997 merged commit 06dcdac into main Sep 23, 2026
7 of 8 checks passed
@DoRmAmMu1997
DoRmAmMu1997 deleted the feat/sl-hunting-v5j branch September 23, 2026 17:34
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.

1 participant