Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 17 additions & 18 deletions Signal Generators/SL Hunting AI Agent/premarket_note.json
Original file line number Diff line number Diff line change
@@ -1,46 +1,45 @@
{
"for_date": "2026-09-16",
"source": "Intraday Hunter, 'Prediction For 16 SEP 2026' (2siXRlm4_jo, uploaded 2026-09-15)",
"context": "15 Sep gave back the prior day's whole positive move -- 'as much positive momentum as came a day before, that much selling has already happened'. The market is ALREADY negative, so POSITIONAL SELLERS are now seated and in profit.",
"for_date": "2026-09-17",
"source": "Intraday Hunter, 'Prediction For 17 SEP 2026' (SQIo4PisLw0, uploaded 2026-09-16)",
"context": "Today's selling broke down and then RECOVERED, without crossing the higher point or the round number. The session therefore leaves one question open -- which side it trapped -- and SENSEX has its expiry tomorrow.",
"plan": [
"THE PLAN IS CONDITIONAL ON THE OPEN, inverting yesterday's all-buy note: a good GAP UP means BUY, FLAT or GAP DOWN means SELL. He repeats it for all three indices, so the open picks the side before any setup is read.",
"GAP UP -> BUY, because the gap traps the seated sellers: 'the market is already negative and made good momentum today too, so there can be POSITIONAL sellers here -- if we get a good gap up we CAN target these sellers'.",
"FLAT OR GAP DOWN -> SELL, and the reason is the ABSENCE of a target rather than weakness: 'they will already be sitting in confidence so we cannot target them -- there we must go WITH the market'.",
"A GAP DOWN IS THE EASY CASE, NOT A WARNING: 'if a gap down opens that is a very good thing, because momentum is already good, so walking with the market will be easy'. Flat is fine too -- 'in flat there is no problem either'.",
"TARGET THE LATE SELLERS, NOT THE EARLY ONES: 'the upper-side seller we cannot make our target, but those sitting having SOLD HERE can be targeted'. The cohort that sold into today's lows is the marginal one.",
"SELLERS IN PROFIT CANNOT BE HUNTED QUICKLY: 'the sellers will come into some profit, and second, confidence will stay inside them, so we cannot make a target quickly'. Profit plus confidence is what removes them as prey."
"SAME CONDITIONAL SHAPE AS YESTERDAY, DIFFERENT REASON: gap up -> BUY, flat or gap down -> SELL, stated for all three indices. The question underneath is WHICH crowd today trapped, and the open is what answers it.",
"FLAT OR GAP DOWN -> SELL, because the sellers were only TRAPPED and never seated: 'seeing the retracement, who comes here? SELLERS come. But because the market stays SIDEWAYS they leave again' -- so no seller crowd is left to squeeze.",
"GAP UP -> BUY, the tell is what price did NOT do: 'it did not cross the round number, it did not cross its high point', so 'maybe some good trader slowly bought here and other people could not buy'. That thin long inventory is the target.",
"THE UNCROSSED HIGH IS WHY RETAIL IS ABSENT: 'because the higher point was not crossed, retail did not do much work'. Only a deliberate buyer may be seated, never a crowd, which is why the buy branch needs the gap up to confirm one exists.",
"SENSEX EXPIRES TOMORROW, flagged twice -- in his opening line and again at its levels. That is context for the triple-index read, not a premise of its own."
],
"levels": [
{
"index": "NIFTY",
"resistance": [
23280,
23340
23420,
23280
],
"support": [
23080,
23110,
23000
]
},
{
"index": "BANKNIFTY",
"resistance": [
56650,
56300
56300,
56650
],
"support": [
55500,
55200
55810,
55500
]
},
{
"index": "SENSEX",
"resistance": [
74800,
75000,
74500
],
"support": [
73800,
74000,
73650
]
}
Expand Down
176 changes: 176 additions & 0 deletions Signal Generators/SL Hunting AI Agent/sl_hunting_doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -7188,3 +7188,179 @@ it. A ninth mutation was written and discarded as invalid -- setting the
exception branch to `float("inf")` is filtered by the `isfinite` guard and
changes no behaviour, so it proved nothing; it was replaced by mutations that
make the exception branch refuse and re-raise, both caught.
## v5f - a one-way day seats nobody, and the next open is the receipt (16 Sep)

Source: `TXiU5Odet04`, "Live Bank Nifty Option Trading", uploaded 2026-09-16
10:09 IST. Compared against the agent's own session the same morning: four
entries, all LONG, inside 53 minutes, basket **-Rs.863.75**.

**Same note, same morning, opposite branch.** The pre-open note shipped for
16 Sep (PR #171) was conditional: gap up -> BUY the trapped sellers, flat or
gap down -> SELL with the market. NIFTY opened +82 points, +0.36%; BankNIFTY
+0.38%.

- IH: "today we saw a FLAT opening, and with this kind of opening we are going
to follow the CONTINUED SELLING... if a VERY BIG gap up had opened we could
not have worked like this." He bought puts across all three indices, booked
around his 3-lakh target on a sharp simultaneous breakdown, and closed the
session a clear winner.
- The agent: "NIFTY gapped +82pts (0.36%) and BankNIFTY +213pts (0.38%) above
prior close after a 457pt breakdown day that seated positional sellers,
satisfying the pre-open note's GAP-UP->BUY branch." All four entries LONG.

**The proximate cause is a v4t violation, not a knowledge gap.** v4t already
says the classification is a JUDGEMENT you make and state, already calibrates
it ("a quarter of a percent is not a gap... something in the region of half a
percent is where the gap reading starts to earn itself"), and already says
that hesitation resolves to flat. 0.36% sits below that line. The number was
computed and written into every one of the four entry rationales and never
once tested against the rule. This is the THIRD session in the series decided
by that one word: 31 Aug produced v4t, 01 Sep produced its v4u 3:15 sub-rule
at a cost of Rs.1,488.25, and this one cost Rs.863.75.

**What IS net-new is the premise UNDERNEATH the branch**, and it is the reason
the agent wanted the gap-up branch at all. All four rationales asserted that
the prior 457-point breakdown had "seated positional sellers". IH argues the
exact opposite, with a mechanism: "when do sellers REMAIN seated? When a
retracement happens. When there is no retracement, every trader keeps fearing
that a retracement might come, that his trade might go wrong" -- so on
continuous momentum "traders do come, but they also book their target and
leave", and "the chances of HOLDING are low here". A violent one-way session
ends with almost nobody carrying inventory, however large its range.

He then supplies the falsification test, which is the part that can run before
the trade: "but if sellers had been seated in good quantity, what would the
market have opened as? We would have seen a straight gap up." The open is the
RECEIPT for the premise. A small gap is not a weak version of that open; it is
the evidence against it.

Encoded as **A ONE-WAY DAY LEAVES NOBODY SEATED, AND THE NEXT OPEN IS THE
RECEIPT (v5f)**, placed directly after the whole v4t block (including its v4u
sub-bullet, which it must not split) so the model reads "decide which word
describes the open" and then "here is what the open's size is measuring". It
is v5c one scale up: there a retracement recruits a crowd inside the move,
here a retracement is what lets a crowd survive into the NEXT session.

Negative-tested 14 ways, all 14 caught, plus a control mutation of unasserted
prose that correctly did not trip the test. One anchor initially matched zero
times because it began mid-line ("That is v5c...") rather than at a line
start; it was re-run line-contiguously and caught. That is the same
wrap-spanning mistake the mutation harnesses keep inviting -- print the raw
line boundaries first.

**Considered and not encoded.** IH's "a retracement is what seats a crowd" is
partly v5c already; only the cross-session half is new and that is what v5f
carries. His loss-discipline material repeats v3y. His round-number caution
("there is a round number here, a small problem will show, control your heart,
do not run") is already covered by the round-number rules in BNF_SPECIFIC.

Two runtime items were raised from this session. The first became SLH-017
below. The second is recorded there too, and is NOT being built.

## SLH-017 - the open is classified in code, not derived by the model

Three sessions in this book were decided by one word, with two knowledge rules
already in place specifically to get it right: 31 Aug produced v4t, 01 Sep
produced its v4u sub-rule at a cost of Rs.1,488.25, and 16 Sep cost Rs.863.75.
On 16 Sep the model computed the deciding number correctly -- "+82pts (0.36%)"
-- wrote it into all four entry rationales, and never compared it with v4t's
own calibration. That is the exact shape the corpus already has a law for:
PROSE RULES DON'T BIND, and JUDGEMENT RULES GET TALKED PAST.

`pivot_and_levels` now returns an `open_classification` block:

previous_close / today_open / gap_points / gap_pct
threshold_pct (GAP_CLASSIFICATION_THRESHOLD_PCT = 0.5)
verdict FLAT | GAP_UP | GAP_DOWN
reference "previous session's last candle close, not the official
15:30 close"

The threshold is not invented: it is v4t's own calibration ("a quarter of a
percent is not a gap... something in the region of half a percent is where the
gap reading starts to earn itself"), and sub-threshold opens read FLAT in both
directions because v4t also says hesitation resolves to flat. The reference is
v4u's, for the reason v4u gives -- the closing auction carries settlement
prints no crowd traded around.

It flows to the model through the `levels` tool and, for BankNIFTY, through
`bank_nifty`. Run against 16 Sep's real numbers both come back **FLAT**
(NIFTY 0.355%, BankNIFTY 0.381%) -- which is IH's reading of that morning and
the opposite of the one the agent acted on.

**Wired, not just added.** v4t now carries an SLH-017 paragraph telling the
model to READ the verdict and state it, and not to recompute or argue past it,
because an unwired fact is one the model will simply re-derive its own way.
The existing v4t marker test was extended rather than rewritten, so its old
assertions still pin the original prose.

**Scope.** This supplies the arithmetic and the threshold; it does not reject
orders and does not judge what the classification MEANS. That part stays with
the model, which is where the real reasoning is.

Negative-tested 9 ways, all 9 caught, plus a control mutation of unasserted
prose that correctly did not trip the tests. One mutation -- measuring from
today's LAST price instead of its OPEN -- initially PASSED, because every
fixture opened and closed at the same price. That is a real defect the tests
could not see: a flat open would silently become a "gap up" by mid-morning and
re-select the branch hours after the fact. A dedicated drift test was added
and the mutation then caught.

## SLH-018 - one round of friction on a reasonless EXIT (operator decision)

The session's other item was that at 09:16:38 an EXIT with no reason executed
and closed the day's only winner (+Rs.1,182 basket), about 100 seconds before
that trade's 23276 target printed. The order tool logged it as "a probable
UNINTENDED order" and honoured it anyway; the model's own next decision called
the call erroneous.

This was first raised and **declined**, because refusing such an exit reverses a
standing decision: SLH-007 says an EXIT is never refused over its wording, since
bouncing it would strand an open position; SLH-010 explicitly declined to reverse
that and added the warning instead; and
`test_exit_with_no_reason_still_executes_but_warns_loudly` existed so that "a
later tightening cannot quietly turn the warning into a refusal".

**The operator then took the decision explicitly (2026-09-16), choosing the
one-round form**, on the reasoning that it "would filter out the anomalies and
let SLH-007 work on genuine wordless exit cases". SLH-007's guarantee is
NARROWED, not reversed, and the tightening is neither quiet nor unilateral.

**The contract.** The first EXIT that resolves to the no-reason sentinel is sent
back once, with a rejection naming both ways forward -- state the reason, or send
the EXIT again. Any repeat is honoured unconditionally, whatever it carries. So
the worst case is ONE decision cycle, never a stranded position, and the
mechanical stop, target, max-loss and 15:15 square-off are host-owned throughout
and are never gated by any of this.

**Where the state lives matters.** The armed flag sits on the EXECUTOR, not on
the tool context. A context is rebuilt every bar, so context-local state would
bounce the first attempt of every bar forever and could genuinely strand a
position -- the exact outcome SLH-007 forbids. The executor is created once per
worker (`self._executor = MasterWorkerExecutor(self)`) and outlives the pass. It
is set and cleared duck-typed through `getattr`/`setattr` under
`contextlib.suppress`, because `TradeExecutor` is a Protocol and a third-party
executor need not tolerate the attribute.

**Scoped per episode.** Any ACCEPTED order clears the arm -- the repeat exit, a
restated reason, or a new entry. A bounce spent on this morning's slip cannot buy
a later position a free pass.

**Placeholder reasons bounce too.** `_safe_exit_reason` maps "placeholder",
"n/a" and friends to the same sentinel as an empty string, so they are the same
class of anomaly and get the same single bounce.
`test_do_order_never_rejects_an_exit_for_a_bad_reason` was rewritten as
`test_a_junk_exit_reason_bounces_once_then_exits_and_records_the_sentinel`,
keeping its real assertions: the position still comes out, and the junk still
never becomes the permanent record.

**The tool description had to change, or the model keeps a false contract.** It
said an EXIT "is NEVER rejected". It now states the single exception and the way
out of it, and a test asserts the stale absolute is GONE rather than merely that
the new wording is present -- a model told exits can never be refused, that then
receives a refusal, has been handed a contract its tool does not keep. That is
the SLH-017 unwired-fact failure arriving from the other side.

Negative-tested 7 ways, all 7 caught, plus a control mutation of an unasserted
comment that correctly did not trip the tests. The two mutations that matter
most are both caught: removing the bounce entirely, and never disarming (which
would strand a position by refusing the second attempt as well).
54 changes: 54 additions & 0 deletions Signal Generators/SL Hunting AI Agent/sl_hunting_indicators.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@
_RETRACEMENTS = (0.5, 0.618, 0.786)
_EXTENSIONS = (1.272, 1.618, 2.618)

# SLH-017: where "flat" stops and "gap" starts, as a PERCENTAGE of the prior
# session's close. The number is not arbitrary -- it is the calibration v4t
# already carries in the knowledge: a quarter of a percent is not a gap, and
# "something in the region of half a percent" is where the gap reading starts
# to earn itself. Anything below reads FLAT, because v4t also says that
# hesitation between the two words resolves to flat.
GAP_CLASSIFICATION_THRESHOLD_PCT = 0.5


@dataclass(frozen=True)
class SLHuntingIndicatorConfig:
Expand Down Expand Up @@ -277,12 +285,58 @@ def _dist(level: float | None) -> dict[str, Any] | None:
pts = round(last_price - level, 2)
return {"level": round(level, 2), "points_away": pts, "pct_away": round(100.0 * pts / max(level, 1e-9), 3)}

# SLH-017: classify the open HERE rather than leaving the model to derive
# it. This one word selects the branch of a conditional pre-open plan, and
# three sessions in this book were decided by getting it wrong (31 Aug,
# 01 Sep, 16 Sep) -- on 16 Sep the model computed "+82pts (0.36%)"
# correctly, called it a gap-up anyway, and took four losing longs. The
# arithmetic and the threshold are mechanical, so they belong in code; what
# the classification MEANS is still the model's to reason about.
if prev_day is None:
open_classification: dict[str, Any] = {
"available": False,
"verdict": None,
"reason": "no previous session in the candle window to measure against",
}
else:
prev_close = float(prev_day["close"])
today_open = float(cast(float, today_levels["open"]))
gap_points = round(today_open - prev_close, 2)
gap_pct = round(100.0 * gap_points / max(abs(prev_close), 1e-9), 3)
if abs(gap_pct) >= GAP_CLASSIFICATION_THRESHOLD_PCT:
verdict = "GAP_UP" if gap_points > 0 else "GAP_DOWN"
else:
verdict = "FLAT"
open_classification = {
"available": True,
"previous_close": round(prev_close, 2),
"today_open": round(today_open, 2),
"gap_points": gap_points,
"gap_pct": gap_pct,
"threshold_pct": GAP_CLASSIFICATION_THRESHOLD_PCT,
"verdict": verdict,
# v4u: the prior session's LAST CANDLE, deliberately not the
# official 15:30 close -- the closing auction carries settlement
# prints no crowd traded around, and positioning is the only thing
# this classification is trying to read.
"reference": (
"previous session's last candle close, not the official 15:30 close"
),
"note": (
"This verdict selects the branch of a conditional pre-open plan. "
"It is measured, not estimated -- do not re-derive it. Below the "
"threshold the open is FLAT whatever the sign, because a move too "
"small to act before the crowd can decide has recruited nobody."
),
}

return {
"available": True,
"last_price": round(last_price, 2),
"pivot": pivot,
"previous_day_ohlc": prev_day,
"previous_close": prev_day["close"] if prev_day else None,
"open_classification": open_classification,
"today": today_levels,
"psych_levels": psych,
"psych_step": step,
Expand Down
Loading
Loading