Market context & regimeIntermediate#breadth#end-of-day#python

Build a market-regime dashboard from your own exposure rules

Each end of day, a script computes index trend, breadth and new highs versus new lows, then an agent applies your written rules and shows the matching exposure band next to every input. Missing or contradictory inputs mean no band.

How it works

  1. Write {{regime_rules_file}} as a Python file containing determine_regime(trend: str, breadth_pct: float, nh_nl_ratio: float) -> str. trend is the string "above" or "below", not a number. Write each band as a condition that cannot be true at the same time as another band, and raise ValueError if an input is missing or if zero or more than one condition is true. Do not add prose to the file.
  2. Run a Python script that writes {{inputs_csv}} with index trend versus moving averages, the share of your universe above the 50-day average, and new highs versus new lows.
  3. Paste the prompt into Grok with both files.
  4. Run determine_regime on the same row yourself as a cross-check. If its band differs from the one the agent quoted, discard the page and fix the rules file first.
  5. Read the inputs table first; copy the page into your journal only if the inputs look right and a band was allowed.

Copy-paste prompt

Build my daily regime page from {{inputs_csv}} and the rules in {{regime_rules_file}}.
1. Show every input value in a table first.
2. Match the input table to the if/then rules in {{regime_rules_file}}. Quote the one matching rule and state its exposure band. If none match, or more than one matches, say the rules are ambiguous and do not pick a band. This is a reading of my written rules, not a code-execution result.
Compare the band to {{prior_band}}. If it changed, name the input that crossed a threshold in the quoted rule. If {{prior_band}} is empty, say the change cannot be determined. Never invent a prior band or a missing input.
3. If inputs are missing or contradictory, say so and do not pick a band.
4. No forecasts and no commentary on specific instruments.
5. Show the journal entry you would write as a diff. Do not save anything; I will copy it into my journal only if I accept it.

Guardrails

  • Show inputs alongside the conclusion.
  • Bands come from your written rules.
  • Missing data means no conclusion.
  • Rules must be simple deterministic if/then conditions on the three inputs; complex or ambiguous rules are rejected with explanation.

What can go wrong

The new-highs feed used a broader universe than the 50-day breadth file, so one mismatched print flipped the band. The input table made the bad row obvious; a single headline number would have hidden it. Align both series to the same universe before treating a band change as real. Inaccurate public-data inputs or poorly written rules produce wrong bands that can lead to over-exposure in adverse regimes. Before using any new band, recompute all three inputs from a second export of the same universe (index level and a moving average are on most chart sites; breadth and new highs versus new lows are not a standard Yahoo quote, and another vendor's default list is a different universe), and confirm the Python function returns the identical band. Do this for the first 30 daily runs.

Why it helps

A written regime rule stops you from being fully exposed in a weak market just because one chart looks good.

A concrete example

Keep your rules in regime_rules_file.py as plain if/then conditions on the three numeric inputs. Write each band so that exactly one condition is true for any valid row:

def determine_regime(trend: str, breadth_pct: float, nh_nl_ratio: float) -> str:
    conditions = {
        "full": trend == "above" and breadth_pct >= 60 and nh_nl_ratio >= 2,
        "partial_a": trend == "above" and breadth_pct >= 40 and nh_nl_ratio < 2,
        "partial_b": trend == "above" and 40 <= breadth_pct < 60 and nh_nl_ratio >= 2,
        "reduced": trend == "below" or breadth_pct < 40,
    }
    matched = [name for name, is_true in conditions.items() if is_true]
    if len(matched) != 1:
        raise ValueError("inputs match zero or more than one rule, or an input is missing")
    band = matched[0]
    return "partial" if band.startswith("partial") else band

Your script writes inputs_csv with these column names and one row per day, for example:

date,trend,breadth_pct,nh_nl_ratio
2026-10-17,above,58.0,1.4

Expected output when a rule matches:

| input         | value |
|---------------|-------|
| trend         | above |
| breadth_pct   | 58.0  |
| nh_nl_ratio   | 1.4   |

Matching rule: trend == "above" and breadth_pct >= 40 and nh_nl_ratio < 2  ->  band: partial
Band: partial
Change vs prior (full): breadth_pct crossed below 60 and nh_nl_ratio crossed below 2.

Source and references

Original write-up by Agents for Traders. Background reading is linked below.

Spotted an error, or want your post removed? Email hello@agentsfortraders.com.

Educational content only. Not investment advice or a personal recommendation. No tickers, signals or trade alerts. Trading involves risk of loss.

Conteúdo exclusivamente educativo. Não constitui aconselhamento nem recomendação de investimento. Sem tickers, sinais ou alertas de negociação. Negociar envolve risco de perda.

Related use cases