Fred v1.0
Buy US stocks under $5 the moment they break their pre-market high on heavy pre-market volume, if the break is calm.
Why it should work
Small caps that trade a full day's volume before the open are in play. When the regular session takes out the pre-market high without a burst of volume right before it, the move tends to carry. Fred buys that break once, takes +25% if it comes, cuts at -10%, and is flat at the close every day.
How it trades
Universebefore 04:00 ET
Nasdaq, NYSE and NYSE American common stocks whose previous close was under $5, with at least 20 sessions of history.
Volume filter04:00 to 09:30 ET
Pre-market volume reaches at least 90% of the stock's average daily volume over the previous 90 sessions. The names that pass at 09:30 are the day's roster.
Triggerfrom 09:30 ET
The first regular-session trade above the pre-market high. If the stock opens above it, Fred waits for a trade back below and then a new cross.
Calm-before-break gateat the cross
Volume over the 5 minutes before the cross, per minute, must be under 2x the average pre-market volume per minute. A spike into the level is skipped.
Entryat the cross
Marketable limit order, immediate-or-cancel, at the pre-market high +1%. If the ask is already higher, there is no trade. One entry per stock per day, none after 15:59.
Exituntil 16:00 ET
Limit sell at +25% from the fill, stop at -10% from the fill, otherwise sold in the closing auction.
Sizeper trade
10% of the day's starting equity per trade (5% roughly halves the drawdown). The backtest also caps size at 10% of the entry minute's volume.
Parameters, read from the locked config
| Universe | Previous close under | $5.00 |
| Universe | Exchanges | NASDAQ, NYSE, AMEX |
| Universe | Minimum history | 20 sessions |
| Roster | Pre-market volume | ≥ 90% of the 90-session average daily volume |
| Roster | Roster fixed at | 09:30 ET |
| Entry | Limit (IOC) | pre-market high +1% |
| Entry | Calm before break | last 5 min volume/min < 2x pre-market volume/min |
| Entry | No entry after | 15:59 ET |
| Entry | Entries per stock per day | 1 |
| Exit | Take profit | +25% from the fill |
| Exit | Stop loss | -10% from the fill |
| Exit | End of day | closing auction (MOC) |
| Size | Per trade | 10% of the day's starting equity |
Full config (configs/versions/v1.0.yaml)
# Fred v1 (locked 2026-11-09), paper trading. The rules in words: docs/fred_v1.md.
# The spec values (configs/fred_v1.yaml) mapped onto the live building blocks.
# fred scan configs/fred_v1_live.yaml morning scanner (watchlist 09:00, roster 09:30 ET)
# fred paper configs/fred_v1_live.yaml trades the roster on Alpaca paper
name: fred_v1
plan: paid # SIP real time (Algo Trader Plus). IEX misses ~99.8% of pre-market volume.
scanner:
prep_at: "03:50"
start: "04:00"
poll_seconds: 60
watchlist_at: "09:00"
roster_at: "09:30"
watchlist_min_progress: 0.5 # "on track" = at least 50% of the volume threshold by 09:00
max_lines: 15
baselines:
max_price: 5.0 # previous raw close under $5
exchanges: [NASDAQ, NYSE, AMEX]
avg_sessions: 90
min_history: 20
filters:
- {cls: fred.scanner.filters:PriceBand, params: {max_price: 5.0, field: prev_close}}
- {cls: fred.scanner.filters:PremarketVolumeVsAverage, params: {ratio: 0.9}}
trader:
broker: alpaca_paper # alpaca_paper | sim (dry run, no orders sent)
poll_seconds: 1 # how often the last trade is checked for the cross
last_entry: "15:59"
max_entries_per_symbol: 1
# first trade above the PM high from 09:30 (after a dip below if it opened above) -> limit IOC at PM high x 1.01
entry: {cls: fred.signals.pm_high_breakout:PmHighCross, params: {max_chase: 0.01}}
gates: # checked at the moment of the cross
- {cls: fred.live.gates:CalmBeforeBreak, params: {lookback: 5, max_ratio: 2.0}}
exit: {cls: fred.exits.target_stop:TargetStop, params: {take_profit: 0.25, stop_loss: 0.10}}
close_order: moc # anything still open sells in the closing auction
close_buffer_minutes: 15 # MOC sent at 15:45 (Alpaca cutoff 15:50); 12:45 on half days
sizer: {cls: fred.sizing.percent:PercentOfEquity, params: {pct: 0.10, skip_if_insufficient_cash: true}}
# The spec also caps size at 10% of the entry minute's volume. That volume is only known after the
# minute ends (the backtest used the full bar), so live runs without the cap; the trade log
# records the entry minute's volume to check afterwards whether it would have bound.
# To turn a live estimate on: add max_participation: 0.10 to the params above.
risk:
- {cls: fred.risk.guards:KillSwitch}
Results the version was chosen on
Replayed tick by tick. Buys at the ask and sells at the bid 1 second after each trigger, targets fill at the limit, Alpaca fees (no commission, SEC and FINRA fees on sells). $25,000 start.
By year: 2025: +31.6% · 2026: +4.5%. Exits: 18% target · 38% stop · 44% close. 15 of 23 months positive.
How it is doing since the lock
Every weekday after the close, the day is replayed tick by tick from the delayed SIP tape exactly as this config would have traded it.
Backtest vs forward test
| Backtest | Forward test | |
|---|---|---|
| Trades per day | 0.80 | 2.00 |
| Win rate | 40% | 100% |
| Average trade | +0.9% | +16.5% |
| Average win | +14.3% | +16.5% |
| Average loss | −8.0% | – |
| Exits | 18% target · 38% stop · 44% close | 50% target · 0% stop · 50% close |
Every trigger
| Date | Symbol | Outcome | Detail | Return |
|---|---|---|---|---|
| 2026-11-06 | BTDL | close | in 3.2900 at 11:57:35, out 3.5500 at 16:00:00 | +7.9% |
| 2026-11-06 | SNT | target | in 1.7000 at 11:34:44, out 2.1250 at 14:30:01 | +25.0% |
| 2026-11-06 | RAYA | not calm | crossed 09:37:21, not calm: last 5 bars 4.2x the PM average per minute | – |
| 2026-11-06 | VIVK | not calm | crossed 09:44:27, not calm: last 5 bars 4.0x the PM average per minute | – |
Roster names that never crossed their pre-market high are left out (21 so far).
Caveats
- The calm filter and the exit were chosen while looking at the same 22 months as the backtest. The forward test below is the only clean evidence.
- Volume baselines use full-day volume, extended hours included.
- Some delisted stocks are missing from the backtest universe (ticker lists are 6-monthly snapshots).
- Live trading needs SIP real-time data (Alpaca Algo Trader Plus). The forward test replays the delayed SIP tape for free after the close.