Argus is a lightweight Streamlit research application designed to monitor stocks in sectors linked to AI infrastructure and data centers (power/grid, cooling, optical networking, semiconductor equipment, data center REITs) plus separate Emerging Compute themes such as quantum computing. It supports a local SQLite database for development and a hosted PostgreSQL database (such as Supabase) for production deployment. It helps identify high-quality stock pullbacks, tracks recent SEC filings and news catalysts, constructs a custom AI Infra Core index, and sends email alerts.
Argus is designed for a simple, two-user family workflow (research and decision support). It is not a trading execution platform.
Follow these steps to set up Argus on your local machine.
Argus requires Python 3.12 or higher. Create a virtual environment and activate it:
# Create virtual environment
python3 -m venv .venv
# Activate virtual environment
source .venv/bin/activateInstall dependencies from requirements.txt and install the package in editable mode.
Tip
Installing in editable mode (-e .) registers the argus package with your virtual environment, ensuring all import paths resolve correctly and preventing common path errors.
# Install core requirements
pip install -r requirements.txt
# Install package in editable mode
pip install -e .Copy the template configuration file to create your local .env file:
cp .env.example .envOpen .env in a text editor to configure settings. Key configurations include:
APP_PASSWORD: Set a shared password to protect the dashboard (leave blank to disable login).APP_AUTH_SECRET: Optional signing secret for auth tokens and legacy auth cookies. If blank, Argus usesAPP_PASSWORD.SEC_USER_AGENT: Required format for SEC filings (e.g.,Argus/1.0 (contact@example.com)).MARKET_DATA_PROVIDER: Set toyfinance(default, free, no key required) or configure optional API keys forfinnhub,twelvedata, oralphavantage.- SMTP details (
EMAIL_HOST,EMAIL_USERNAME,EMAIL_PASSWORD,EMAIL_TO) for email alerts.EMAIL_TOsupports comma-separated recipients. - For Supabase/Postgres, either:
- put full credentials in
DATABASE_URL, or - keep a placeholder in
DATABASE_URL([YOUR-PASSWORD],<PASSWORD>, or__DB_PASSWORD__) and setDATABASE_PASSWORD.
- put full credentials in
Argus uses a local SQLite database at data/app.db by default, or PostgreSQL if DATABASE_URL is configured. Run these commands sequentially to prepare the database and backfill market data:
Initialize the database file and seed it with the default universe of companies and themes:
# Create tables
python scripts/init_db.py
# Seed initial stock list and watchlists
python scripts/seed_companies.pyIngest historical pricing data, compute relative metrics (vs. QQQ and NVDA), and generate Pullback Finder scores:
# Ingest 2 years of daily price history
python scripts/backfill_prices.py --period 2y
# Refresh recent 15-minute bars during market hours
python scripts/backfill_prices.py --period 5d --interval 15m
# Compute technical/moving average indicators
python scripts/compute_metrics.py
# Calculate opportunity and pullback scores
python scripts/compute_scores.py
# Pre-calculate AI Infra Core Index values
python scripts/refresh_index.py
# Compute rich signals (NVDA/hyperscaler correlation, capex growth, power demand, etc.)
python scripts/compute_signals.pyFetch news headlines and company filings from RSS/GDELT and SEC EDGAR:
# Refresh broad market news articles (uses provider cooldown protection)
python scripts/refresh_news.py
# Refresh selected company investor-relations feeds
python scripts/refresh_ir_feeds.py
# Refresh SEC filings (requires valid SEC_USER_AGENT in .env)
python scripts/refresh_ciks.py
python scripts/refresh_filings.pyRefresh FRED macro indicators, automated or manual hyperscaler capex data, and macro release schedules:
# Refresh Treasury yields and inflation indicators from FRED
python scripts/refresh_macro.py
# Ingest upcoming FRED release schedules (requires FRED_API_KEY)
python scripts/refresh_release_calendar.py
# Ingest automated capex from SEC CompanyFacts (MSFT, AMZN, GOOGL, META)
python scripts/refresh_capex.py
# Add a manual quarterly capex observation (fallback / overrides)
python scripts/add_capex_observation.py --ticker MSFT --period-end 2026-03-31 --capex 10000000000 --source-label "Q1 earnings"Evaluate watchlist metrics against your enabled alert parameters (sends emails for triggers):
python scripts/run_alerts.pyInstead of running individual scripts, use the daily orchestrator to sync prices, compute metrics/scores, retrieve filings, and evaluate alerts in one command. Scheduled production news refreshes run separately at market open and market close to avoid rate limits:
# Run the complete refresh workflow
python scripts/run_daily_refresh.py --period 2yUseful daily workflow flags:
--skip-news: Skip fetching news headlines.--skip-filings: Skip checking SEC filings.--skip-alerts: Skip checking alert triggers.--skip-macro: Skip FRED macro refresh.
Start the Streamlit dashboard on your local machine:
streamlit run app/main.pyThe application will be accessible at http://localhost:8501. If APP_PASSWORD is defined in your .env, you will be greeted by a secure login page.
To execute the unit and integration test suite, run:
pytestNote: The test suite runs in ~30 seconds, uses SQLite in-memory fixtures, and mocks all external API/network requests.
To check for syntax, format, or type issues, run:
ruff check .This occurs if python cannot find the internal packages when executing scripts or running tests.
- Fix: Ensure you have installed the package in editable mode (
pip install -e .) inside your active virtual environment. Alternatively, manually prefix commands withPYTHONPATH=.(e.g.PYTHONPATH=. python scripts/init_db.py).
SQLite supports multiple concurrent readers but only one concurrent writer. If a script freezes or throws this error, another ingestion script or the Streamlit app might be in the middle of a write transaction.
- Fix: Check for and terminate dangling python ingestion processes. If the database remains locked, delete
data/app.db-journalif it exists, or restart the Streamlit server.
The SEC strictly requires a descriptive User-Agent header containing contact details. Without it, requests are rejected with a 403 error.
- Fix: Open
.envand ensureSEC_USER_AGENTis configured with a format likeCompany/Version (contact@email.com). Do not use generic user agents.
Alternative API providers on free tiers have strict limits (e.g., 5 calls per minute or 500 calls per day). Ingesting historical prices for 30+ tickers will exhaust these immediately.
- Fix: Use the default
yfinanceprovider (MARKET_DATA_PROVIDER=yfinance), which has no API key requirement and high rate limits. Use alternative providers only for testing.
Argus supports both local SQLite (default) and Supabase Postgres for production deployment. When DATABASE_URL is set, all pipelines and the Streamlit app will use that connection instead of the local SQLite file.
-
Create a free project at supabase.com.
-
In Settings β Database, copy the Connection string (URI) β it looks like:
postgresql://postgres.[project-ref]:[password]@aws-0-[region].pooler.supabase.com:6543/postgresYou can also store this as:
DATABASE_URL=postgresql://postgres.[project-ref]:[YOUR-PASSWORD]@...DATABASE_PASSWORD=your-actual-password
-
Initialize the schema and seed data by running the standard scripts with
DATABASE_URLset.init_db.pycreates the current schema and records the schema version used for future hosted upgrades:DATABASE_URL="postgresql://..." python scripts/init_db.py DATABASE_URL="postgresql://..." python scripts/enable_rls.py DATABASE_URL="postgresql://..." python scripts/seed_companies.py
-
Backfill prices and compute metrics:
DATABASE_URL="postgresql://..." python scripts/backfill_prices.py --period 2y DATABASE_URL="postgresql://..." python scripts/backfill_prices.py --period 5d --interval 15m DATABASE_URL="postgresql://..." python scripts/compute_metrics.py DATABASE_URL="postgresql://..." python scripts/compute_scores.py DATABASE_URL="postgresql://..." python scripts/refresh_index.py
Note
Argus automatically normalizes postgresql:// prefixes to postgresql+psycopg:// for SQLAlchemy 2.0 compatibility. You do not need to modify the Supabase URI.
To deploy the Streamlit app on Streamlit Community Cloud:
- Push your repo to GitHub.
- Create a new app on Streamlit Cloud pointing to
app/main.py. - In the app's Settings β Secrets, add a TOML block:
DATABASE_URL = "postgresql://postgres.[ref]:[YOUR-PASSWORD]@aws-0-[region].pooler.supabase.com:6543/postgres" DATABASE_PASSWORD = "your-actual-password" APP_PASSWORD = "your-shared-password" APP_AUTH_SECRET = "a-long-random-cookie-signing-secret" SEC_USER_AGENT = "Argus/1.0 (your-email@example.com)"
Important
Never commit secrets to your repository. The Streamlit secrets panel and GitHub Actions secrets are the only places credentials should live.
Important
Run scripts/enable_rls.py after schema creation for Supabase deployments. It enables Row Level Security on Argus tables and grants access to the database role used by your DATABASE_URL.
Argus includes five workflow files for production scheduling:
.github/workflows/intraday-prices.yml- Every 30 minutes on weekdays
- Executes only during the ET market window (9:30 AMβ4:00 PM)
- Runs: yfinance 15-minute prices (
--period 5d --interval 15m) β metrics β daily index refresh β alerts
.github/workflows/news-refresh.yml- Every 2 hours, every day
- Runs: broad RSS/GDELT news refresh with 24-hour provider cooldown after HTTP 429
.github/workflows/filings-refresh.yml- Every 3 hours, every day
- Runs: official SEC ticker-to-CIK synchronization followed by SEC filings refresh
.github/workflows/ir-feeds-refresh.yml- Once daily between 5:00β6:00 PM ET, targeting 5:22 PM ET
- Runs: selected investor-relations feed refresh for cybersecurity and optical/networking names
.github/workflows/daily-refresh.yml- Once after US market close on weekdays between 4:30β5:30 PM ET, targeting 4:41 PM ET
- Runs: daily bars, macro indicators, metrics, scores, index, and alerts (
run_daily_refresh.py --period 2y --skip-news --skip-filings)
Required GitHub repository secrets (Settings β Secrets and variables β Actions):
| Secret | Description | Required |
|---|---|---|
DATABASE_URL |
Supabase Postgres connection string | β |
DATABASE_PASSWORD |
Optional password if URL has placeholder | Optional |
SEC_USER_AGENT |
SEC EDGAR user-agent header | β |
FRED_API_KEY |
St. Louis Fed API key for macro calendars | Optional |
EIA_API_KEY |
U.S. EIA API key for power signal metrics | Optional |
EMAIL_HOST |
SMTP host for alert emails | Optional |
EMAIL_USERNAME |
SMTP username | Optional |
EMAIL_PASSWORD |
SMTP password | Optional |
EMAIL_TO |
Alert recipient email address(es), comma-separated if multiple | Optional |
For a persistent SQLite deployment (no Postgres), deploy to a VPS or PaaS with volume support:
- Use Render, Railway, Fly.io, or DigitalOcean with a persistent volume.
- Mount a persistent disk to the
data/folder. SetDATABASE_URL=sqlite:////mnt/persistent/app.db. - Configure a cron job for daily ingestion:
0 18 * * 1-5 /path/to/project/.venv/bin/python /path/to/project/scripts/run_daily_refresh.py --skip-news
- No Docker required β install Python 3.12, clone, install requirements, and run with systemd or PM2.
The custom AI Infra Core Index is built to monitor the collective performance of AI infrastructure and data-center supplier stocks.
- Equal Weighted: The index is an equal-weighted average of all active constituent stocks.
- Base Level: Set to a base of 100.0. The chart on the Dashboard dynamically rebases the index level to 100 on the starting date of the selected timeframe for easy comparison.
- Dynamic Rebalancing / Missing History: IPOs (e.g.,
GEVorALAB) and companies with missing historical price bars are handled gracefully. The daily index return is the average of daily returns of only those constituents that have valid price data on both the current and the previous trading day. This average return is compounded daily. - Exclusions: Benchmark-only and large hyperscaler names (
QQQ,NVDA,MSFT,AMZN,GOOGL,META), optional highly aggressive stocks (ALAB,CRDO), and Emerging Compute names such as Quantum Computing stocks are excluded from the AI Infra Core index calculation by default.
Argus includes an interactive Index Lab page (app/pages/8_Index_Lab.py) that allows users to define, backtest, and analyze custom index definitions:
- Weighting Modes:
- Equal weight: Distributes weights equally across all selected constituent tickers.
- Theme exposure weight: Normalizes and scales constituent weights based on their manually assigned theme exposure scores.
- Manual weight: Allows custom percentage weights for each constituent, validated to ensure they sum to exactly 100%.
- Historical Analysis: Backtests custom definitions and renders interactive Plotly charts comparing their performance against QQQ and NVDA benchmarks across 1M, 3M, 6M, 1Y, and historical timeframes.
- Deep Dives: Displays the constituent weights table, historical theme concentration breakdown, and top performance contributors over the past 90 days.