Files
momentum-system/deploy
momentum devandClaude Opus 5 45b0386347 feat: rank gappers by premarket range, the one measured predictor
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
2026-09-13 19:16:17 -05:00
..

Deploying Momentum

Three supported shapes, one image/codebase. Pick by where it runs:

Mode Status Use when Docs
Docker Compose ✅ canonical (production since 2026-07-09) Any always-on Linux host; TrueNAS SCALE docker/README.md, docker-compose.yml (root), docker/truenas-compose.yml
Local (systemd) ✅ maintained Development machine, WSL, bare metal without Docker systemd/README.md + unit templates in deploy/systemd/
Helm / Kubernetes 🚧 planned refresh Future k8s hosting helm/ — the chart predates the 2026-07 architecture; starting point, not deployable

Docker Compose (canonical)

The root docker-compose.yml runs the full stack self-contained: postgres 18, trading loop, dashboard (:8765), admin panel (:8767), telegram bot, transcripts pipeline, nightly scheduler, on-demand jobs, optional Grafana. The image is published to docker.io/fez5587/momentum-app and ghcr.io/fez5587/momentum-app by CI on every master push.

For TrueNAS SCALE use docker/truenas-compose.yml (pull-only, dataset host paths, inline env). Read the gotchas in docker/README.md before editing the YAML — anchor expansion, per-service env, and path case-sensitivity have each caused an outage.

Local (systemd user services)

The original deployment: unit templates in deploy/systemd/ running a git checkout + venv, config from .env. Still the best loop for development — tests, backtests, and research scripts run here. Keep the units disabled while the compose stack owns production: two loops against one Alpaca account create duplicate orders.

Helm (future)

deploy/helm/ holds the original chart (single app deployment + CronJobs). It predates the service split, the session gate, and the env-flag inventory; the refresh is tracked in GitHub issues. Until then, compose is the way.

Config in all modes

  • .env.example (committed, sanitized) is the full variable inventory and says which layer each belongs in.
  • Behavior flags that MUST be set explicitly in any deployment — silent defaults bite: TRADING_AUTO_APPROVE=1 (else entries queue for manual approval), ALPACA_DATA_FEED=sip, OLLAMA_ENABLED=true (catalyst engine), FMP_API_KEY (float cache). TRADING_SESSION_ONLY defaults ON in deployed configs (bars after-hours entries).
  • Runtime overrides: the admin panel writes data/overrides.env, which every service loads over its baked env at boot (runtime/env_overrides.py).