Over 1,040 screened symbol-days (2026-08-01 on), asking which premarket
property predicts the session running >=50% open-to-high:
premarket range n avg run ran >=50%
>= 30% 201 34.7% 15.9%
15-30% 136 28.3% 14.7%
5-15% 303 15.2% 5.9%
< 5% 400 16.8% 4.3%
A name that already travelled >=15% premarket is 3.1x more likely to run
>=50% (15.4% vs 5.0%) -- the largest single lift in this dataset, and free:
it comes off minute bars the arm pass has already fetched.
Two findings constrain the shape:
- It is a STEP at 15%, not a gradient (15-30% and >=30% are 14.7 vs 15.9;
5-15% and <5% are 5.9 vs 4.3). So the multiplier is a threshold. A linear
scale would invent precision the data does not support.
- Premarket VOLUME carries NO signal (10.0/4.2/7.9/9.0% across participation
buckets, non-monotonic) and raw premarket volume runs inversely to the
outcome. scanner_snapshots.premarket_volume being NULL costs nothing;
range is the field that mattered all along.
Do not expect 3x. Replaying armed-set selection over the same 29 sessions,
top-5 by mean/median run and >=50% runners captured out of 145 slots:
gap x rvol (baseline) 39.77% / 10.97% 27
x3.0 if PM range >= 15% 42.00% / 13.16% 32
HARD FILTER >= 15% 37.27% / 12.67% 24 <- worse
PM range alone 32.86% / 12.65% 20 <- much worse
gap x rvol already encodes much of the same information, so the marginal gain
is ~+2 points of mean run and 4-5 extra big runners per 145 slots. It is
BOOST-only for a reason: gating on this feature scored below baseline, and it
must never replace gap/rvol. Every threshold in 10-20% and gain in 1.5-5.0 beat
baseline -- a flat plateau, so not fitted. The shipped 15%/3.0x are the measured
step and the measured lift, not the sweep's peak cell.
Fail-open: an unknown range yields a neutral 1.0, never a penalty.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A2LepdJfPCfK5Q8uznjFBM
119 lines
5.1 KiB
Bash
119 lines
5.1 KiB
Bash
# Seed for /app/data/overrides.env on the LIVE stack — the admin panel
|
|
# (port 8867.. n/a on live; edit via file or add admin service) manages this.
|
|
# Every service loads it at boot; overrides BEAT compose env.
|
|
|
|
ALPACA_DATA_FEED=sip
|
|
DISCOVER_INTERVAL_SECONDS=120
|
|
DISCOVER_THREAD_ENABLED=1
|
|
LIVE_BARS_INTERVAL_SECONDS=5
|
|
LIVE_BARS_REFRESH_MINUTES=20
|
|
NEWS_CATALYST_SCORE_ENABLED=1
|
|
NEWS_DILUTION_VETO_ENABLED=1
|
|
NEWS_ENRICH_BATCH_LIMIT=50
|
|
NEWS_ENRICH_ENABLED=1
|
|
NEWS_ENRICH_INTERVAL_SECONDS=120
|
|
NEWS_ENRICH_LOOKBACK_HOURS=12
|
|
NEWS_FEEDS=prnewswire=https://www.prnewswire.com/rss/news-releases-list.rss,businesswire=https://feed.businesswire.com/rss/home/?rss=G1QFDERJXkJeGVtRWQ==,globenewswire=https://www.globenewswire.com/RssFeed/orgclass/1/feedTitle/GlobeNewswire%20-%20News%20about%20Public%20Companies
|
|
NEWS_LOOKBACK_HOURS=8
|
|
NEWS_RANK_BOOST=2.0
|
|
# Ollama lives on 11434 (the standard port). The stack pointed at 30068/4000 with
|
|
# a model that was never pulled, so catalyst enrichment produced nothing from
|
|
# 2026-08-03 to 2026-09-13 — silently, because enrich_recent_news reports failure
|
|
# in its return value rather than raising. Smoke-tested 2026-09-13: tools:latest
|
|
# parses 8/8 headlines in ~2.8s each and classifies offering_dilution / fda_approval
|
|
# correctly. Verify the model is pulled before changing either line.
|
|
OLLAMA_ENABLED=true
|
|
OLLAMA_HOST=http://192.168.1.5:11434
|
|
OLLAMA_MODEL=tools:latest
|
|
OLLAMA_TEMPERATURE=0.1
|
|
OLLAMA_TIMEOUT_SECONDS=60
|
|
TRADING_AUTO_APPROVE=1
|
|
TRADING_BACKOUT_COOLDOWN_SECONDS=180
|
|
TRADING_BLOCK_REENTRY_AFTER_EXIT=1
|
|
TRADING_ENTRY_CONFIRM_BY_MINUTE=0
|
|
TRADING_ENTRY_FILL_MODEL=marketable
|
|
TRADING_ENTRY_INVALIDATE_PCT=0.015
|
|
TRADING_ENTRY_ORDER_TYPE=limit
|
|
TRADING_ENTRY_TIMEOUT_BARS=2
|
|
TRADING_EOD_FLATTEN_ENABLED=1
|
|
TRADING_EOD_FLATTEN_TIME=15:55
|
|
TRADING_EXECUTION_ENABLED=1
|
|
# EXIT MANAGEMENT — retuned 2026-09-13. The previous config stacked FOUR
|
|
# independent ratchets (BE@+5% from the env default, step-trail every 0.25R,
|
|
# prior-low trail, and profit-lock tiers). Together they capped every winner at
|
|
# ~1R: over 62 live + 172 paper trades the bot kept only 9.3% of the move on
|
|
# trades that ran >=20%, and held winners a median 10 min vs 19 min for losers.
|
|
# Replaced with a single percentage giveback that starts only after +1R. The
|
|
# 8/12/15/20% neighbourhood all beat the old config on BOTH stacks in BOTH
|
|
# train and test splits (mean R 0.20-0.25 vs 0.125), so 12% is a plateau pick,
|
|
# not a fitted one. Re-sweep with sweep_exits.py before changing.
|
|
TRADING_EXIT_BREAKEVEN_R=1.0
|
|
TRADING_EXIT_BREAKEVEN_PCT=0.0
|
|
TRADING_EXIT_MANAGE_INTERVAL_SECONDS=4
|
|
TRADING_EXIT_PROFIT_TIERS=
|
|
TRADING_EXIT_THREAD_ENABLED=1
|
|
TRADING_EXIT_THREAD_INTERVAL_SECONDS=1.0
|
|
TRADING_EXIT_TRAIL_AFTER_R=1.0
|
|
TRADING_EXIT_TRAIL_MODE=pct
|
|
TRADING_EXIT_TRAIL_PCT=0.12
|
|
TRADING_EXIT_TRAIL_R_STEP=0.0
|
|
TRADING_LIQUIDITY_MAX_VOLUME_PCT=0.025
|
|
TRADING_MAX_BACKOUTS_PER_SYMBOL=3
|
|
TRADING_MAX_CONCURRENT_POSITIONS=10
|
|
TRADING_MAX_DAILY_LOSS_PCT=0.05
|
|
TRADING_MAX_FRESH_ENTRIES_PER_DAY=10
|
|
TRADING_MAX_GROSS_NOTIONAL_PCT=0.60
|
|
TRADING_MAX_ORDERS_PER_TICK=1
|
|
TRADING_MAX_POSITION_PCT=0.16
|
|
# Boot-time sizing fallback. calculate_position_size falls back to this ONLY when
|
|
# equity was never readable; at the old 100000 a boot inside Tradier's ~01:06
|
|
# maintenance window (equity reads 0.0 there — 16 times in 14 days) would have
|
|
# sized 5% of 100k on a ~$250 account. Keep it BELOW real account equity so the
|
|
# fallback can only ever under-size (live equity 241.75 on 2026-09-13).
|
|
TRADING_DEFAULT_EQUITY=200
|
|
TRADING_MAX_RISK_DOLLARS=50000
|
|
TRADING_MIN_DAY_VOLUME=300000
|
|
TRADING_MIN_ENTRY_GAP_PCT=0.10
|
|
TRADING_MIN_QUALITY_SCORE=0.60
|
|
# PREMARKET-RANGE RANK BOOST (2026-09-13). A name that already travelled >=15%
|
|
# premarket ran >=50% on the day 15.4% of the time vs 5.0% for the rest -- a 3.1x
|
|
# lift, the largest single predictor measured over 1,040 screened symbol-days.
|
|
# Replaying the armed-set selection, the gain is real but modest (mean run of the
|
|
# top-5 armed 39.8% -> 42.0%, 27 -> 32 big runners per 145 slots) because gap x
|
|
# rvol already encodes much of it. BOOST only: a hard filter on the same feature
|
|
# scored WORSE than baseline. Set TRADING_PM_RANGE_BOOST=0 to disable.
|
|
TRADING_PM_RANGE_BOOST=1
|
|
TRADING_PM_RANGE_MIN_PCT=15.0
|
|
TRADING_PM_RANGE_GAIN=3.0
|
|
TRADING_PRICE_MAX=20.0
|
|
TRADING_PRICE_MIN=2.0
|
|
TRADING_REENTRY_MIN_LOSS_PCT=0.01
|
|
TRADING_REGIME_GATE_ENABLED=0
|
|
TRADING_REGIME_GATE_P_MIN=0.5
|
|
TRADING_REQUIRE_ABOVE_VWAP=1
|
|
TRADING_REWARD_MULTIPLE=10.0
|
|
TRADING_RISK_PER_TRADE_PCT=0.05
|
|
TRADING_SESSION_ONLY=1
|
|
TRADING_TRIGGER_SLIP_PCT=0.004
|
|
TRADING_UNIFIED_ENTRY=1
|
|
TRIGGER_ARM_INTERVAL_SECONDS=8
|
|
TRIGGER_ENABLED=1
|
|
TRIGGER_GAP_MAX=35
|
|
TRIGGER_GAP_MIN=10.0
|
|
TRIGGER_GAP_SQUEEZE_MIN=150
|
|
TRIGGER_GAP_SQUEEZE_RVOL=5.0
|
|
TRIGGER_INTERVAL_SECONDS=2
|
|
TRIGGER_MAX_ARMED=10
|
|
TRIGGER_MIN_DOLLAR_VOL=8000
|
|
TRIGGER_PRICE_MAX_AGE=12
|
|
TRIGGER_RVOL_MIN=2.0
|
|
# Apply the shared tradeable-population gate before the watcher scores anything.
|
|
# Without it the watcher wrote 191,458 criteria receipts across 57 symbols on
|
|
# 2026-09-10, 80.6% of them for names outside the gap band. Set 0 to restore the
|
|
# old evaluate-everything behaviour.
|
|
WATCHER_POPULATION_GATE=1
|
|
WATCHER_ENABLED=1
|
|
WATCHER_INTERVAL_SECONDS=8
|
|
WATCHER_PRICE_MAX=20
|
|
WATCHER_PRICE_MIN=2
|