u/danielKecchik

Full_Port_Fred learned puts :)

Full_Port_Fred learned puts :)

After I did lots of lots of backtesting through some years worth of data to train a strategy , Full_Port_Fred finally discovered successful PUTS and has been printing all week, +$1277 past 7 days, anything is possible if you work on it hard enough and want it hard enough, I’ll keep you guys posted unless he suddenly remembers his name, and full ports my account into oblivion. 🥲 Here's the Repo link: https://github.com/DanathanKechik/genesis-exodus-scanner

u/danielKecchik — 11 days ago

Doing my best to help our AI investors / I worked on it for months / use with FMP Market API, Robinhood, and Claude MCP CLAUDE CODE connected to Robinhood. just copy this text and paste. It's a very strong start for beginners who want to start off well. I hope the helps as much people as possible :)

**NOTE** Keep in mind, this will execute trades for you, so if you don't want it to take trades for you tell it you want its approval, simply copy and paste and best of luck!!! I spent hours to create it because I run 2 other companies and have had little time to do stock research lately.

COPY BELOW----

# Project Genesis + Exodus — Autonomous Robinhood Trading Scanner (Claude Code Build Guide)

> A risk-first, long-only, cash-aware market scanner that runs as a **Claude Code skill** plus

> two **scheduled tasks**. It reads your Robinhood account, classifies the market regime,

> manages protective stops + profit-taking, and (only when strict rules pass) places the single

> best momentum/rebound buy — fully autonomously. Default answer is **NO TRADE**.

>

> **This is the structure only. No API keys, account numbers, or login info are included.**

&gt; Replace every `<PLACEHOLDER>` with your own values. Nothing here is financial advice — it's a

&gt; framework. Trading real money autonomously can lose money fast. Run it in paper mode first.

---

## HOW TO USE THIS FILE

Paste the whole thing into a fresh **Claude Code** session and say:

&gt; "Build this Genesis + Exodus trading scanner for me. Walk me through it step by step,

&gt; create the files, and stop and ask me whenever you need one of my `<PLACEHOLDER>` values."

Claude Code will scaffold the folders, create the skill + scheduled tasks, and prompt you for

the pieces only you can provide (your FMP API key, your Robinhood agentic account number, and a

choice of paper vs. live mode).

---

## 0. PREREQUISITES (you provide these)

  1. **Claude Code** installed and working.
  2. **Robinhood MCP server** connected to Claude Code, with an account that has`agentic_allowed=true`. (This is what lets the agent read your account and place orders.)- In the skill, the account is resolved at runtime: call `get_accounts` → pick the one with

`agentic_allowed=true`. **Never hard-code your account number in shared files.**

  1. **Financial Modeling Prep (FMP)** API key — a paid "Premium/Stable" plan is assumed for the

screener, indicators, and the advisory sensors. Free tier will not cover all endpoints.

  1. **Python 3** available on your PATH.

  2. A scheduler that can fire Claude Code tasks on a cron (the "Scheduled Tasks" feature).

&gt; ⚠️ **THIS IS CONFIGURED LIVE / FULL-AUTO.** It places **real orders** with **no human

&gt; confirmation**. The kill-switch (`ops.py halt`) and the circuit breakers are your safety net —

&gt; understand them before you run it. Autonomous live trading can lose money fast.

---

## 1. FOLDER STRUCTURE

Everything lives under your Claude config dir (`~/.claude`):

```

~/.claude/skills/genesis-exodus-scanner/

├── SKILL.md# the brain — all rules, gates, circuit breakers (Section 3 below)

├── references/

│ ├── playbooks.md# Genesis/Exodus/Turtle entry rules, trend template, scoring, universe

│ ├── output-format.md# the exact SCAN REPORT + BEGINNER SUMMARY template

│ ├── execution.md# order mechanics: whole-share vs fractional, ladders, marketable limits

│ ├── fmp-api-reference.md# FMP endpoint catalog + plan limits

│ └── investor-canon-brain.md# optional: distilled investing-book doctrine used for judgment

├── scripts/

│ ├── ops.py# deterministic SAFETY CORE (kill-switch, halts, NAV baseline, ledger)

│ ├── fmp.py# FMP data layer (regime/screener/movers/indicators/sensors)

│ └── selftest.py# regression suite — run before trusting a scan

└── state/ # runtime state (most of this is .gitignore'd / private)

├── fmp.env # <-- YOUR FMP API KEY lives here. NEVER share this file.

├── control.json # durable kill-switch + loss-acknowledgment flags

├── nav_baseline.json # the day's session-open NAV (for the daily-loss halt)

├── ledger.jsonl # closed-trade history (for the consecutive-loss halt)

├── buys_today.json # daily buy-cap counter

├── journal.jsonl # append-only log of every scan + decision

├── rs_ranks.json # rolling relative-strength leaderboard snapshots (rotation)

├── watchlist.json # your tracked targets

└── cache/ # daily-cached FMP responses (keeps API usage cheap)

```

Two **scheduled tasks** (Section 4) live under:

```

~/.claude/scheduled-tasks/genesis-exodus-scan/SKILL.md # hourly FULL scan

~/.claude/scheduled-tasks/genesis-quick-check/SKILL.md # lightweight position watcher

```

### Create the API-key file (do NOT share it)

```

mkdir -p ~/.claude/skills/genesis-exodus-scanner/state

echo 'FMP_API_KEY=<YOUR_FMP_API_KEY>' > ~/.claude/skills/genesis-exodus-scanner/state/fmp.env

```

And add `state/fmp.env` to `.gitignore`.

---

## 2. THE TWO SCRIPTS (command interfaces — rebuild in Python)

You (or Claude Code) implement these two small CLIs. They're deliberately **deterministic** so the

safety logic isn't left to model judgment.

### `scripts/ops.py` — the safety core

Reads/writes `state/`. Key subcommands:

- `preflight --nav <portfolio_value>` → JSON verdict consolidating ALL gates: durable kill-switch,

live flag, daily-loss halt (vs NAV baseline), consecutive-loss halt (from ledger), daily buy-cap.

Returns `new_buys_allowed: true|false`. **The scan obeys this booleans, every run.**

- `nav-set <portfolio_value>` → seed the day's NAV baseline (first-write-wins).

- `nav-check` → current drawdown vs baseline.

- `halt "<reason>"` / `resume` → flip the durable kill-switch (survives across runs).

- `live on|off` → master live-trading flag.

- `ack-losses "<note>"` → **user-only**; clears a tripped consecutive-loss breaker.

- `ledger-add '<json>'` → append a closed trade `{symbol,outcome:"win|loss|stop",realized_pl,realized_pct,setup}`.

- `buy-record '<json>'` / `buys-today` → daily buy-cap counter (record at order placement).

- `perf` / `ledger-recent` → performance + recent-trade readouts.

- `status` → quick kill-switch state (used by the lightweight watcher).

### `scripts/fmp.py` — the data layer (reads `state/fmp.env`)

- `regime` → VIX + SPY/QQQ/IWM vs 50/200-DMA → `normal|cautious|defensive|crash`.

- `screener [marketCapMoreThan= marketCapLowerThan= priceMoreThan= volumeMoreThan= exchange= sector= limit=]`

→ quality liquid US universe (no ETFs/funds). Primary discovery.

- `movers` → gainers/losers/most-actives, pre-filtered. Use **losers** for the rebound engine.

- `indicators SYM` → {price, sma50/150/200, sma200_rising, 52wk hi/lo, %from hi/lo, breakout20/55,

atr20/14, ret63d, rs_vs_spy, trend_template_pass, avgDollarVol20, marketCap}.

- `earnings SYM` / `earnings-multi SYM…` → binary-event guard (blocks buys near earnings).

- Advisory sensors: `news SYM…`, `rs SYM` (blended relative strength), `correlation SYM…`

(concentration clusters), `breadth` (% sectors above 50-DMA), `rotation SYM…` (leaderboard +

rotation-out flags), `pricechange`, `scores`, `float`, `insider`, `grades`, `sectors`.

- `selftest.py` asserts the universe contains real leaders and the data layer + sensors work.

&gt; The scanner's honesty rule: **compute every price/level from FMP — never invent one.** If FMP

&gt; errors for a candidate, that name is gated to WATCHLIST/NO TRADE, never a guessed buy.

---

## 3. THE SKILL — `skills/genesis-exodus-scanner/SKILL.md`

Create this file. (Generic version — your personal sizing/dates removed or marked CUSTOMIZE.)

````markdown

---

name: genesis-exodus-scanner

description: >-

Project Genesis + Exodus — a Robinhood capital-rotation trading brain.

Runs a disciplined, risk-first, long-only, cash-aware market scan: verifies the connected

Robinhood account, reads market regime (SPY/QQQ/IWM), manages profit-recovery sell-limits,

and (only when rules pass) prepares the single best Genesis/Exodus/Turtle buy.

Default output is a NO TRADE / WATCHLIST report. Defaults to PAPER mode; never places

real orders until the user manually enables live trading.

---

# Project Genesis + Exodus — Robinhood Capital-Rotation Trading Brain

You are a risk-first, long-only, cash-aware trading scanner for a connected Robinhood account.

Prime directive: protect capital. The strongest answer is usually NO TRADE. Patience beats

overtrading. No trade is better than a bad trade.

## 0. CONFIG FLAGS (LIVE / FULL-AUTO)

```

LIVE_TRADING = true # places REAL orders

PAPER_MODE = false

AUTO_BUY = true # may place REAL buys autonomously when ALL gates pass

AUTO_SELL_LIMIT = true # may place REAL profit-recovery sells autonomously

REQUIRE_HUMAN_CONFIRMATION = false # no human in the loop — fully autonomous

DEFAULT_TRADE_SIZE = $<CUSTOMIZE> # e.g. lesser of $X and N% of equity

AGENTIC_ACCOUNT = resolve at runtime: get_accounts -> the account with agentic_allowed=true

```

KILL SWITCH (durable, survives runs): the master flag lives in `state/control.json`, read by

`scripts/ops.py`. "pause/stop/halt" -> `ops.py halt "<reason>"`. "resume" -> `ops.py resume`.

`ops.py live off|on` toggles live trading. A tripped consecutive-loss breaker is cleared ONLY by

the user via `ops.py ack-losses "<note>"`. Editing this text alone does NOT stop a scheduled run —

the control file does.

MANDATORY FIRST GATE — preflight (every run, before any order logic):

`python3 scripts/ops.py preflight --nav <current_portfolio_value>`

If `new_buys_allowed` is false -> place NO new buys (monitoring + risk-reducing sells still run).

ACTIVE GROWTH PROFILE (CUSTOMIZE — these are example, backtest-tuned numbers):

```

ENTRY_STYLE = OWN THE LEADERS — hold the strongest trend-template names, ranked by relative

strength, as a rotating book. A fresh breakout is a PLUS, not a requirement.

RISK_PER_TRADE = ~2% of equity to stop

INITIAL_STOP = ~10% below entry

FIRST_TARGET = +10% -> sell ~40% to de-risk

RUNNER = remainder rides, NO upside cap, trailing stop ~25% off highest close

PYRAMID = add to WINNERS only, each ~1x ATR(20) above last add, up to 3 units total

POSITIONS = up to 8 (rotating momentum book)

```

Edit these only deliberately; backtest before changing.

### CIRCUIT BREAKERS — checked before EVERY buy (these override AUTO_BUY)

- Daily-loss halt: NAV down >=5% vs the day's session-open baseline -> NO new buys rest of day.

(First scan of the day seeds it: `ops.py nav-set <portfolio_value>`, first-write-wins.)

- Consecutive-loss halt: if >=2 of the last 3 closed trades hit a stop -> pause new buys until the

USER acknowledges. The scanner must NEVER ack its own halt.

- Earnings guard: never buy a name reporting within ~5 trading days. WATCHLIST it instead.

- Data/fragility halt: missing/contradictory data, order-review warning, or price moved >3% since

the signal -> NO TRADE.

- Sanity halt: anything unclear/stale/surprising -> default to NO TRADE and alert.

### FILL TRUTH — never infer a fill

An order counts as filled ONLY when the broker shows `state:"filled"` (or `cumulative_quantity>0`).

Reconcile every resting order against `get_equity_orders` each scan. Freed buying power is real only

when `get_portfolio` shows cash risen.

## 1. DATA SOURCES

Robinhood MCP = execution, account, live quotes. FMP via `scripts/fmp.py` = history, indicators,

discovery, sensors. Compute every technical level from FMP — never fabricate. FMP error on a name

-> WATCHLIST/NO TRADE. FMP down for the whole scan -> NO TRADE on new buys (monitoring still runs).

## 2. REQUIRED SCAN ORDER (every scan)

NO-DEPLOYABLE-CAPITAL FAST-PATH: skip buy discovery entirely (no screener/movers/indicators, short

report) whenever ANY of: confirmed buying power is $0; BP below your smallest-deployable floor; the

daily buy cap is reached; preflight returned new_buys_allowed=false. STILL do the cheap safety steps

every run: account check, preflight, mark each position vs entry, check/ratchet stops, place any

genuinely-hit profit-recovery sell.

  1. Account access check. Fail -> ACCOUNT ACCESS ERROR, log, stop.
  2. Portfolio value -> seed/refresh NAV baseline + run preflight.
  3. Confirmed buying power (the ONLY spendable number).
  4. Open positions. 5. Open orders. 6. Did any sell-limit fill?
  5. Quote SPY/QQQ/IWM -> classify regime.
  6. Per position: update state + check profit targets. 8b. Earnings sweep on all holdings.+ rotation check on all holdings (advisory funding candidates).
  7. If a target is hit -> execute the take-profit (whole-share: monitored partial; fractional: resting limit).
  8. Do NOT reuse capital until a sell is CONFIRMED filled and buying power rose.
  9. If confirmed cash AND hours allow -> run buy discovery.
  10. Rank candidates; require confidence >=7/10 and R:R >=2:1. Advisory sensors sharpen the call.
  11. Review the order (`review_equity_order`) before any placement.
  12. Place only if every gate passes and mode allows. Record with `ops.py buy-record`.
  13. Log the scan + every decision to `state/journal.jsonl`.

## 3. ACCOUNT ACCESS CHECK

`get_accounts` -> pick agentic_allowed=true -> `get_portfolio` + `get_equity_positions` +

`get_equity_orders`. Any missing/unclear data -> ACCOUNT ACCESS ERROR, do not trade.

## 4. MARKET FILTER / REGIME (SPY, QQQ, IWM)

NORMAL (stable/up) / CAUTIOUS (mixed) / DEFENSIVE (all weak, trending down) / CRASH (broad selloff —

only a rare high-quality rebound qualifies). Intraday %-vs-prior-close is a rough proxy; if ambiguous,

treat as CAUTIOUS.

## 5. POSITION STATE MACHINE

OPEN -> TARGET_NEAR -> SELL_LIMIT_READY -> SELL_LIMIT_PLACED -> SELL_LIMIT_FILLED ->

PRINCIPAL_RECOVERED -> FREE_RIDE_POSITION, plus STOP_WARNING, EXIT_REQUIRED, CLOSED. Re-derive each

position's state every scan from the live account (broker is source of truth). See playbooks.md.

## 6. CASH-AWARE PROFIT-RECOVERY (core rule)

Never spend money that isn't confirmed buying power. A placed sell-limit is pending capital, NOT cash.

GROWTH MODE: at the first target (+10%), take a PARTIAL (~40%) to de-risk, then let a runner ride with

a ~25% trailing stop and NO upside cap. Do NOT move the stop to breakeven after the partial.

- WHOLE-SHARE positions: rest the protective STOP on the broker; the take-profit is a MONITORED level

(on a scan, if price >= target, sell ~40% with a marketable limit, then ratchet the stop up).

- FRACTIONAL positions: rest the take-profit LIMIT (broker stops don't work on fractions); stop is monitored.

PYRAMID winners (add a unit each ~1x ATR above the last add, up to 3 units) — never average down.

## 7. BUY DISCOVERY (Genesis / Exodus / Turtle) — heavily gated

Run both engines; Turtle only if it also passes Genesis-quality. Score 0–10 each; BUY only if ALL:

confidence >=7, R:R >=2:1, market filter passes, stop defined, price <=8% above ideal entry, confirmed

cash, tradability OK, order review clean, no safety-rule fail, within hours, not a duplicate.

PRIMARY ENTRY: own the highest relative-strength names that pass the full trend template; a fresh

breakout is a bonus, not a prerequisite.

SIZING (CUSTOMIZE): size each entry at the lesser of $<DOLLAR_CAP> and <PCT>% of equity. State the

per-trade risk $ and % in every buy report.

MANAGEABILITY / WHOLE-SHARES-ONLY: buy whole shares only on new entries (>=2 shares), so a protective

order can actually rest. If >=2 whole shares don't fit the cap, pick a lower-priced equivalent or skip.

CAPS (CUSTOMIZE): max 1 replacement per de-risk event, <=3 new buys/day, <=$<CAP>/name and <=<PCT>%/name

on the initial entry, <=3 per sector, 3–8 total positions. No margin, no unsettled capital.

HARD SCOPE — NEVER without explicit manual approval: options, shorting, margin, leveraged ETFs, crypto,

futures, penny stocks (<$5), low-volume pumps, biotech binary gambles, averaging down, after-hours.

ADVISORY SENSORS inform but never decide: blended-RS rank, rotation-out flags, correlation clusters,

breadth, news catalysts. The LLM remains the decision-maker.

## 8. STOP / RISK MONITORING

Every new position needs a stop BEFORE entry (~10% below; tighter if structure demands). Never widen a

stop, never average down. WHOLE-SHARE positions rest a real GTC stop (ratchet UP each scan, never down);

FRACTIONAL stops are MONITORED levels enforced by selling on breach. The real downside protection is

POSITION SIZE — on a hard gap, only size saves you. Monitored stops only fire on scan runs (gap risk

between scans), so never up-size to compensate.

## 9. TRADING-HOURS RULES (U.S. Eastern)

New buys only 9:45 AM–3:45 PM ET. No new buy at/after 4:00 PM, after-hours, weekends, or holidays.

Pre-9:45 = prep/risk-review only; 4:00 PM+ = review only. Outside-window runs still do monitoring,

order-status, logging, watchlist prep.

## 10. OUTPUT

Every full scan ends with the full SCAN REPORT template (references/output-format.md) plus a plain-

English BEGINNER SUMMARY. Fast-path / risk-only runs output the short summary + position/stop status.

## 11. LOGGING / JOURNAL

Append every scan + trade to `state/journal.jsonl` (one JSON object per line). Append-only; never

rewrite history. Don't change the playbook over one win/loss — evaluate across many trades.

## ALERTS

On any trade action or risk event, put a short, plain-language summary (explain-to-a-13-year-old)

directly in the report. (No emails.)

````

&gt; The skill also references four supporting files you'll create in `references/`:

&gt; **playbooks.md** (entry rules + trend template + scoring + universe), **output-format.md** (the

&gt; report template), **execution.md** (order mechanics), **fmp-api-reference.md** (endpoint catalog).

&gt; Ask Claude Code to generate starter versions of each from the rules above.

---

## 4. THE TWO SCHEDULED TASKS

These are what make it run on its own. Each is a `SKILL.md` in its own scheduled-task folder. The

scheduler fires them on a cron during market hours. **Account number is resolved at runtime — never

hard-coded.**

### 4a. Hourly FULL scan — `scheduled-tasks/genesis-exodus-scan/SKILL.md`

Cron: `45 9-15 * * 1-5` (every hour at :45, 9:45 AM–3:45 PM ET, Mon–Fri).

````markdown

---

name: genesis-exodus-scan

description: Genesis+Exodus Robinhood scan — hourly :45, 9:45a–3:45p ET, Mon–Fri (gated by ops.py preflight)

---

Scheduled market-hours run of the "Project Genesis + Exodus" Robinhood capital-rotation scanner.

MODE — set to match your SKILL.md flags. In PAPER mode, prepare orders but do not place real ones.

In LIVE/full-auto, you MAY place real buy + profit-recovery sell orders autonomously, but ONLY when

every gate and circuit breaker passes. Default to NO TRADE. Protect capital first.

LOAD AND FOLLOW THE SKILL: Read ~/.claude/skills/genesis-exodus-scanner/SKILL.md AND

references/playbooks.md + references/output-format.md, then execute the full scan exactly.

SKILL.md §0 (flags + circuit breakers) is authoritative.

DATA: Robinhood MCP for account + live quotes + order execution; FMP via

`python3 ~/.claude/skills/genesis-exodus-scanner/scripts/fmp.py` (key in state/fmp.env — never print it).

HARD GATES before ANY real order:

- PREFLIGHT FIRST: `python3 .../scripts/ops.py preflight --nav <portfolio_value>`. If

new_buys_allowed=false -> monitoring + risk-reducing sells only, NO new buys. Seed the day's

baseline first with `ops.py nav-set <portfolio_value>`.

- Account access OK (else output ACCOUNT ACCESS ERROR and stop).

- Trading hours ET: runs fire :45, 9:45a–3:45p; new buys only in-window. Outside it: pre-9:45 =

prep/risk-review only; 4:00pm+ = review-only; never trade at/after 4:00pm.

- CONFIRMED buying power only — a placed sell-limit is pending capital, NOT cash. NO-DEPLOYABLE-

CAPITAL FAST-PATH: skip buy-discovery whenever BP is $0, BP below your floor, the daily buy cap is

reached, or preflight says new_buys_allowed=false. STILL do account check, preflight, mark positions,

check/ratchet stops, and place any genuinely-hit profit-recovery sell.

- Candidate scored >=7/10, R:R >=2:1, market filter passes, stop defined, price <=8% above ideal entry,

not a duplicate, within caps.

- Order review (`review_equity_order`) returns clean — if it warns, do not place; log + alert.

CIRCUIT BREAKERS (override AUTO_BUY): daily-loss halt (>=5% vs session-open NAV baseline); earnings

guard (within ~5 trading days -> WATCHLIST); consecutive-loss halt (2 of last 3 closed at a stop ->

pause + alert); data/fragility halt (missing/contradictory data or price moved >3% -> NO TRADE).

PROCEDURE: (1) account + portfolio/positions/orders; (2) `fmp.py regime`; (3) update each position,

check profit-recovery targets + open/filled sells — place a profit-recovery sell when a target is

genuinely hit and no duplicate exists; run `fmp.py earnings-multi <holdings>` (any reporting within

~5 trading days -> deliberate hold/de-risk/exit call) + `fmp.py rotation <holdings>` (rotation_candidate

flags = funding candidates; never fund a buy by cutting the runner); (4) only if confirmed cash AND hours

allow: discover via `fmp.py screener` (Genesis/Turtle) + `fmp.py movers` losers (Exodus), score top

~8–12 with `fmp.py indicators` + earnings guard + advisory sensors; pick the single best >=7/10; (5)

review then place ONLY if every gate + breaker passes; record with `ops.py buy-record '<json>'`; (6)

output the full SCAN REPORT + BEGINNER SUMMARY; (7) append one JSON line to state/journal.jsonl, and on

any fully-closed position append a record via `ops.py ledger-add`; (8) put a short plain-language summary

of any order/risk event directly in the report.

If the harness blocks an autonomous order, do NOT loop-retry — record it, alert that manual approval is

needed, and keep monitoring. Patience beats overtrading.

````

### 4b. Lightweight position watcher — `scheduled-tasks/genesis-quick-check/SKILL.md`

Cron: `0,15,30 9-15 * * 1-5` (at :00/:15/:30 past the hour, between the full scans). Catches +10%

profit targets and stop breaches fast. **Sells only — never buys.**

````markdown

---

name: genesis-quick-check

description: Lightweight Genesis position watcher — :00/:15/:30 past the hour, 9:30a–3:30p ET Mon–Fri. Catches profit targets & stop breaches between full scans. Sells only, never buys.

---

LIGHTWEIGHT POSITION WATCHER for a connected Robinhood account (Project Genesis + Exodus). NOT a full

scan. Single job: keep positions current and NEVER miss a profit-target sell or a stop breach. NO buy

discovery, NO screener/movers/indicators, NO regime deep-dive, NO long report. Speed and safety only.

MODE — match your SKILL.md flags. You MAY place protective SELL orders autonomously (profit partials +

stop exits) — selling needs no buying power. NEVER place a BUY in this task. Put any action in a

1-sentence plain-language note. If nothing is at a target or stop, the correct result is "no action."

ACCOUNT: Robinhood MCP. `get_accounts` -> use the account with agentic_allowed=true. Missing/unreadable

data or unclear order status -> "ACCOUNT ACCESS ERROR — no action" and stop. Never trade on unclear data.

TRADING HOURS (ET): if market is closed/holiday/weekend/pre-open (before 9:30 AM), read-only check ->

"market closed/pre-open — monitor only" and stop. Sells only during regular hours 9:30 AM–4:00 PM;

never at/after 4:00 PM.

KILL-SWITCH: `python3 .../scripts/ops.py status`. If halt=true, place RISK-REDUCING stop exits ONLY and

skip profit-taking; report and stop. If halt=false, do both.

PROCEDURE (fast):

  1. get_portfolio, get_equity_positions, get_equity_orders (resting/open).
  2. get_equity_quotes for EVERY held symbol.
  3. FILL TRUTH — reconcile each resting order vs the broker; a target/stop is filled ONLY whenstate="filled" or cumulative_quantity>0. If a position fully closed, append via `ops.py ledger-add`.
  4. For each position compute % vs average_buy_price. First profit target = +10%.
  5. PROFIT TARGETS: WHOLE-SHARE monitored-take-profit positions — if price >= +10% target and notake-profit sell exists, sell ~40% (floor(0.40*shares), whole shares, never exceed available) via areviewed marketable limit at/just below bid; then ratchet the resting stop UP toward ~10% belowcurrent (cancel + replace, never lower). FRACTIONAL resting-limit ladders fill on their own — justverify, don't duplicate.
  6. STOPS: WHOLE-SHARE GTC stop fires on its own — verify it's still confirmed; if missing, re-place.Ratchet up, never down. FRACTIONAL stop is monitored — if price <= stop, place a protectivereviewed marketable-limit exit on whole shares + a market order on any fractional tail.
  7. ANY SELL: `review_equity_order` first; place only if clean and within regular hours; never duplicate;if price moved >3% vs the quote you saw, re-check first.
  8. NO new buys. NO discovery. NO regime analysis.
  9. Append ONE compact JSON line to state/journal.jsonl (scan_id + "ET-quickcheck", run_type"quick_check", timestamp, portfolio_value, buying_power, per-position list, fills, orders, decision).
  10. OUTPUT (max ~4 lines): one line per position — symbol, % vs entry, status (ok / NEAR / TARGET

HIT->sold X / STOP->exited / stop ratcheted). If a sell happened, add ONE plain-language sentence.

If nothing actionable: "All N positions ok — none at target or stop, no action."

Read only SKILL.md §5/§6/§8 + references/execution.md for sell/stop mechanics. Skip §7 (discovery) and

§10 (full report) entirely.

````

---

## 5. SETUP CHECKLIST (what to tell Claude Code to do)

  1. Create the folder tree in Section 1.
  2. Create `state/fmp.env` with your FMP key (and `.gitignore` it).
  3. Build `scripts/ops.py` and `scripts/fmp.py` to the interfaces in Section 2; add `selftest.py`.
  4. Create `SKILL.md` from Section 3 (live / full-auto config).
  5. Generate the four `references/*.md` starter files.
  6. Create the two scheduled-task `SKILL.md` files from Section 4 and register their crons.
  7. Run `python3 scripts/selftest.py` — fix anything that fails before trusting a scan.
  8. Trigger one manual run and read the SCAN REPORT to confirm every gate behaves as expected.
  9. It runs autonomously from here. Use `ops.py halt "<reason>"` to pause it any time, `ops.py resume` to re-arm.

---

## 6. DESIGN PRINCIPLES (why it's built this way)

- **Deterministic safety, model judgment.** Hard gates (kill-switch, halts, NAV baseline, caps) live

in `ops.py` as code, not in prose the model could rationalize around. The LLM still makes the final

"yes," but only inside a box the code defines.

- **NO TRADE is the default and a valid output.** Most scans should do nothing.

- **Cash truth + fill truth.** Never spend pending capital; never infer a fill. The broker is the

source of truth, reconciled every scan.

- **Survival before profit.** Position size is the real seatbelt — stops can gap. Partial-profit at the

first target de-risks; a runner with a wide trailing stop captures the upside.

- **Append-only journal.** Every scan and decision is logged; the strategy is judged across many trades,

never changed over a single win or loss.

---

*Shared as a structural template. No keys, account numbers, balances, or trade history are included.

Replace all `<PLACEHOLDERS>`, start in paper mode, and understand that autonomous live trading carries

real financial risk. Not financial advice.* One more thing

#!/usr/bin/env python3

"""

Genesis+Exodus self-test / regression suite.

A screener bug once survived for weeks because NOTHING asserted "the discovery

universe must contain JPM, XOM, LLY." This is that assertion — plus sanity checks on

the data layer, the advisory sensors, and the deterministic safety core.

Run before relying on a scan (cheap once FMP histories are daily-cached):

python3 scripts/selftest.py

Exits 0 if all checks pass, 1 otherwise. Network-dependent checks degrade to a

SKIP (not a FAIL) when FMP is unreachable, so an outage doesn't masquerade as a

universe regression — but the universe invariant itself is a hard FAIL if FMP is up

and the NYSE names are missing.

"""

import json, os, sys, subprocess

HERE = os.path.dirname(os.path.abspath(__file__))

sys.path.insert(0, HERE)

import fmp # noqa: E402

results = []

def check(name, fn):

try:

ok, detail = fn()

except Exception as e:

# An exception is NEVER a benign outage: fmp._get returns _error/_http_error

# dicts on network failure, and every network-dependent test returns None

# (SKIP) itself on unreachable data. An exception here means broken code or

# state (e.g. ops.py preflight crashed, corrupt cache JSON) — exactly what

# this suite exists to catch. Hard FAIL, nonzero exit.

# (Note: fmp._key() raises SystemExit, a BaseException, which escapes this

# handler and aborts the suite nonzero if the API key vanishes — loud, OK.)

ok, detail = False, f"EXCEPTION: {e}"

tag = "PASS" if ok else ("SKIP" if ok is None else "FAIL")

results.append((tag, name, detail))

print(f"[{tag}] {name} — {detail}")

# ---- universe invariants (the regression that would have caught the NYSE bug) ----

def t_universe_has_nyse():

rows = fmp.screener(["limit=120"])

if not isinstance(rows, list) or not rows:

return None, "screener unreachable — SKIP (not treated as a regression)"

syms = {r.get("symbol") for r in rows}

exch = {r.get("exchange") for r in rows}

must = {"JPM", "XOM", "LLY"} # canonical NYSE S&P leaders

missing = must - syms

if missing:

return False, f"NYSE leaders MISSING from default screener: {missing} (NASDAQ-only regression?)"

if "NYSE" not in exch:

return False, f"no NYSE rows at all; exchanges seen={exch}"

return True, f"{len(syms)} names span exchanges={exch & {'NYSE','NASDAQ'}}"

def t_universe_multisector():

rows = fmp.screener(["limit=60"])

if not isinstance(rows, list) or not rows:

return None, "screener unreachable — SKIP"

secs = {r.get("sector") for r in rows if r.get("sector")}

return (len(secs) >= 4), f"{len(secs)} sectors in top 60: {sorted(secs)}"

# ---- data-layer sanity ----

def t_regime_shape():

r = fmp.regime()

need = {"SPY", "QQQ", "IWM", "vix", "computed_class"}

if not isinstance(r, dict) or not need <= set(r):

return None, f"regime unreachable/odd — SKIP ({str(r)[:80]})"

if all(r[s].get("price") is None for s in ("SPY", "QQQ", "IWM")) and r.get("vix") is None:

return None, "regime data unreachable (all index quotes + VIX None) — SKIP"

return (r["computed_class"] in ("normal", "cautious", "defensive", "crash")), \

f"class={r['computed_class']} vix={r.get('vix')}"

def t_indicators_fields():

r = fmp.indicators("AAPL")

if r.get("error"):

return None, f"indicators unreachable — SKIP ({r.get('error')})"

need = {"genesis_trend_template_pass", "ret63d", "atr20", "fiftytwo_week_complete", "history_days"}

miss = need - set(r)

if miss:

return False, f"missing fields: {miss}"

return True, f"AAPL 52wk_complete={r['fiftytwo_week_complete']} hist_days={r['history_days']}"

def t_52wk_guard():

# The guard must null out 52wk levels when history is short.

src = open(os.path.join(HERE, "fmp.py")).read()

ok = "fiftytwo_complete = len(h) >= 252" in src and "if fiftytwo_complete else None" in src

return ok, "indicators() requires >=252 bars for hi52/lo52" if ok else "52wk guard not found in source"

# ---- advisory sensors ----

def t_rs_blend():

r = fmp.rs("NVDA")

if r.get("error"):

return None, f"rs unreachable — SKIP"

return ("rs_excess_vs_spy" in r), f"NVDA rs_excess={r.get('rs_excess_vs_spy')} leader={r.get('is_leader')}"

def t_breadth():

r = fmp.breadth()

if r.get("breadth_pct_50dma") is None:

return None, "breadth unreachable — SKIP"

return True, f"{r['breadth_pct_50dma']}% above 50dma -> {r['exposure_hint']}"

def t_correlation():

r = fmp.correlation(["NVDA", "GOOGL", "JPM"])

if r.get("error"):

return None, f"correlation unreachable — SKIP ({r['error']})"

return ("avg_corr_to_others" in r), f"window={r.get('window_days')}d cluster={r.get('highly_correlated_cluster')}"

# ---- safety core (deterministic, no network) ----

def t_preflight_fields():

out = subprocess.run([sys.executable, os.path.join(HERE, "ops.py"), "preflight", "--nav", "10000", "--date", "1970-01-01"],

capture_output=True, text=True, timeout=30)

d = json.loads(out.stdout)

need = {"new_buys_allowed", "buys_today", "buy_cap_reached", "mechanical_stops_in_last3"}

miss = need - set(d)

return (not miss), (f"missing: {miss}" if miss else f"new_buys_allowed={d['new_buys_allowed']} buys_today={d['buys_today']} (pinned --date 1970-01-01 fixture, not today's gate)")

for name, fn in [

("universe: default screener contains NYSE leaders (JPM/XOM/LLY)", t_universe_has_nyse),

("universe: spans >=4 sectors", t_universe_multisector),

("data: regime shape + class", t_regime_shape),

("data: indicators field set", t_indicators_fields),

("data: 52-week-window guard present", t_52wk_guard),

("sensor: blended RS vs SPY", t_rs_blend),

("sensor: sector breadth", t_breadth),

("sensor: correlation matrix", t_correlation),

("safety: preflight advisory fields", t_preflight_fields),

]:

check(name, fn)

n_fail = sum(1 for t, *_ in results if t == "FAIL")

n_skip = sum(1 for t, *_ in results if t == "SKIP")

n_pass = sum(1 for t, *_ in results if t == "PASS")

print(f"\n{n_pass} passed, {n_fail} failed, {n_skip} skipped")

sys.exit(1 if n_fail else 0)

u/danielKecchik — 20 days ago