Skip to content

manishklach/stock-picker

Repository files navigation

Stock Picker

Quant-style S&P 500 stock selection and portfolio allocation engine with risk profiles (conservative, moderate, aggressive), beta-aware scoring, and a companion backtest tool.

What This Project Does

  • Builds a ranked S&P 500 universe from fundamentals.
  • Scores stocks using valuation, growth, profitability, and beta-aware style logic.
  • Produces style-specific top picks and a dollar/share allocation plan.
  • Caches ranked universe data and refreshes weekly (configurable).
  • Computes portfolio beta (selected style + style summary).
  • Backtests style portfolios vs benchmark (SPY by default) with risk metrics.

Project Files

  • stock_picker.py: Main ranking + allocation engine.
  • backtest_styles.py: Backtest script for style portfolios.
  • sp500_ranked.csv: Cached ranked universe.
  • allocation_plan.csv: Latest allocation output.
  • style_backtest_metrics.csv: Backtest performance metrics.
  • style_equity_curves.csv: Equity curves for styles + benchmark.
  • style_holdings_snapshot.csv: Holdings/weights snapshot used in backtest.

Installation

1) Prerequisites

  • Python 3.10+
  • Internet access for market/fundamental data

2) Clone repository

git clone https://github.com/manishklach/stock-picker.git
cd stock-picker

3) Install dependencies

python -m pip install --upgrade pip
python -m pip install yfinance pandas numpy lxml html5lib

Quick Start

Refresh ranked universe + generate allocation

python -u stock_picker.py --refresh-ranking-now --budget 100000 --top-n 10 --allocation-style moderate

Run with verbose logs

python -u stock_picker.py --budget 100000 --top-n 10 --allocation-style aggressive --verbose

Backtest all styles

python -u backtest_styles.py --start-date 2022-01-01 --rebalance monthly --benchmark SPY --top-n 10

stock_picker.py Usage

python -u stock_picker.py [options]

Core options

  • --budget: Portfolio budget (default 100000).
  • --top-n: Number of stocks to pick (default 10).
  • --allocation-style: conservative | moderate | aggressive.
  • --verbose: Detailed fetch/allocation logs.

Ranking/cache options

  • --rank-refresh-days: Reuse sp500_ranked.csv if newer than this many days (default 7).
  • --refresh-ranking-now / --force-refresh: Force fresh ranking now.
  • --universe-csv: Ranked universe file path (default sp500_ranked.csv).
  • --tickers-csv: Optional local symbol list (CSV with Symbol column).

Fetch robustness options

  • --workers: Parallel workers for fundamentals fetch (default 8).
  • --overall-timeout: Max seconds for fundamentals phase (default 240).
  • --progress-every: Progress print interval (default 25).
  • --max-tickers: Optional cap for quicker runs.

Allocation/beta options

  • --allocation-csv: Allocation output CSV path (default allocation_plan.csv).
  • --beta-coverage-threshold: Warn when selected picks with beta are below threshold fraction (default 0.70).

Style Logic (Quant Summary)

  • conservative

  • Selection: quality + valuation with lower-beta tilt.

  • Sizing: smoother weights and tighter concentration cap.

  • moderate

  • Selection: balanced core score with light low-beta preference.

  • Sizing: balanced concentration.

  • aggressive

  • Selection: growth-heavy with high-beta tilt.

  • Sizing: more concentrated on top-ranked names.

Output from stock_picker.py

The script prints and/or saves:

  • Top picks table (Style_Score, Total_Score, Beta, core metrics)
  • Allocation plan (Ticker, Weight, Target_Dollars, Shares, Invested_Dollars, Beta)
  • Style beta summary table (all three styles)
  • Selected-style realized portfolio beta
  • Beta coverage warning (if below threshold)

backtest_styles.py Usage

python -u backtest_styles.py [options]

Main options

  • --start-date: Backtest start (YYYY-MM-DD, default 2022-01-01).
  • --end-date: Optional end date.
  • --top-n: Number of names per style (default 10).
  • --rebalance: none | weekly | monthly | quarterly (default monthly).
  • --benchmark: Benchmark ticker (default SPY).
  • --risk-free-rate: Annual risk-free rate for Sharpe/alpha (default 0.04).
  • --ranked-csv: Input ranked universe CSV (default sp500_ranked.csv).

Backtest outputs

  • style_backtest_metrics.csv
  • style_equity_curves.csv
  • style_holdings_snapshot.csv

Metrics included

  • Total_Return, CAGR, Volatility, Sharpe
  • Max_Drawdown, Calmar
  • Beta_vs_Benchmark, Alpha_CAPM
  • Hit_Rate, Avg_Turnover_per_Rebalance, Observations

Example Workflows

A) Weekly production allocation

python -u stock_picker.py --budget 100000 --top-n 10 --allocation-style moderate

B) Forced refresh + aggressive profile

python -u stock_picker.py --refresh-ranking-now --allocation-style aggressive --budget 100000

C) Conservative profile + stricter beta coverage

python -u stock_picker.py --allocation-style conservative --beta-coverage-threshold 0.85

D) Backtest with quarterly rebalancing

python -u backtest_styles.py --start-date 2021-01-01 --rebalance quarterly --benchmark SPY --top-n 15

Assumptions and Notes

  • Ranked universe uses currently fetched fundamentals and is cached.
  • Backtest uses style baskets derived from ranked universe and price-based portfolio simulation.
  • Backtest does not reconstruct historical fundamentals point-in-time by rebalance date.
  • Missing beta values are excluded from weighted-beta calculations.
  • Market data source behavior depends on Yahoo Finance API availability.

Troubleshooting

  • If fetch hangs/slow:

  • Reduce --workers and/or --max-tickers.

  • Use --overall-timeout to cap fundamentals fetch time.

  • If beta coverage is low:

  • Run with --refresh-ranking-now.

  • Increase --top-n for broader basket.

  • If ranked CSV schema is old:

  • Rebuild with --refresh-ranking-now.

License

Add your preferred license (MIT/Apache-2.0/etc.) in a LICENSE file.

Disclaimer

This project is for research/education. It is not investment advice.

One-Command Quickstart

PowerShell (Windows)

python -m pip install -r requirements.txt; python -u stock_picker.py --refresh-ranking-now --budget 100000 --top-n 10 --allocation-style moderate

This installs dependencies and generates a fresh ranked universe plus allocation in one command.

Quick Start

Refresh ranked universe + generate allocation

Task Shortcuts (Windows + Cross-Tool)

You now have three shortcut options:

  • tasks.ps1 (best on Windows PowerShell)
  • justfile (if you use just)
  • Makefile (if you use make)

PowerShell task runner examples

# install deps
.\tasks.ps1 -Task install

# refresh ranked universe and build moderate allocation
.\tasks.ps1 -Task refresh

# run style portfolios
.\tasks.ps1 -Task run-conservative
.\tasks.ps1 -Task run-moderate
.\tasks.ps1 -Task run-aggressive

# run aggressive with extra flags
.\tasks.ps1 -Task run-aggressive -Extra '--verbose --beta-coverage-threshold 0.8'

# backtest
.\tasks.ps1 -Task backtest
.\tasks.ps1 -Task backtest -Extra '--start-date 2021-01-01 --rebalance quarterly --top-n 15'

just examples

just install
just refresh
just run-conservative
just run-moderate
just run-aggressive
just backtest

make examples

make install
make refresh
make run-conservative
make run-moderate
make run-aggressive
make backtest

Example Output

Below are real example runs from this project (PowerShell, Python venv).

Aggressive style (--refresh-ranking-now --allocation-style aggressive)

Refreshing ranked universe from live data (--refresh-ranking-now set)...
Started fundamentals fetch for 503 tickers with 8 workers...
Fetched metrics for 25/503 tickers
...
Fetched metrics for 503/503 tickers
Saved refreshed ranked universe -> sp500_ranked.csv

Top picks:
Ticker  Style_Score  Total_Score  Beta  Forward_PE    PEG  Earnings_Growth  Revenue_Growth
   PSX     7.500726     6.194144 0.871   13.058196 0.5211         2427.284           0.013
   KEY     1.935328     1.502370 1.086    9.350459 1.8911              NaN           1.315
   ...

Style beta summary (Top-N picks by style):
       Style  Portfolio_Beta  Beta_Coverage  TopN
conservative        0.877956            1.0    10
    moderate        1.041412            1.0    10
  aggressive        1.230383            1.0    10

Allocation style: aggressive
Selected-style realized portfolio beta: 1.228
Beta coverage (selected picks): 100.0%
Budget: $100,000.00
Invested: $99,531.12
Cash left: $468.88
Saved allocation plan -> allocation_plan.csv

Moderate style (--allocation-style moderate)

Using cached ranked universe (sp500_ranked.csv, age=0.0 days, refresh in ~7.0 days)
...
Style beta summary (Top-N picks by style):
       Style  Portfolio_Beta  Beta_Coverage  TopN
conservative        0.877956            1.0    10
    moderate        1.041412            1.0    10
  aggressive        1.230383            1.0    10

Allocation style: moderate
Selected-style realized portfolio beta: 1.040
Beta coverage (selected picks): 100.0%
Budget: $100,000.00
Invested: $99,381.30
Cash left: $618.70
Saved allocation plan -> allocation_plan.csv

Conservative style (--allocation-style conservative)

Using cached ranked universe (sp500_ranked.csv, age=0.0 days, refresh in ~7.0 days)
...
Style beta summary (Top-N picks by style):
       Style  Portfolio_Beta  Beta_Coverage  TopN
conservative        0.877956            1.0    10
    moderate        1.041412            1.0    10
  aggressive        1.230383            1.0    10

Allocation style: conservative
Selected-style realized portfolio beta: 0.879
Beta coverage (selected picks): 100.0%
Budget: $100,000.00
Invested: $99,144.41
Cash left: $855.59
Saved allocation plan -> allocation_plan.csv

About

Python toolkit for S&P 500 stock ranking and allocation across conservative/moderate/aggressive styles, with weekly universe caching, portfolio beta analytics, and benchmarked backtests (CAGR, Sharpe, drawdown, alpha/beta, turnover).

Topics

Resources

Stars

Watchers

Forks

Contributors