jhennemann/SwingTrade
Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
# SwingTrade
SwingTrade is a research project for finding and studying pullback setups in liquid large-cap stocks. It scans a combined S&P 500 and Nasdaq 100 universe, applies a rules-based trend/pullback setup, generates charts for manual review, and provides backtesting tools for testing changes to the strategy.
This project is for education and strategy research. It does not place trades and should not be treated as financial advice.
## What It Does
- Scans the S&P 500 and Nasdaq 100 for pullback-uptrend setups.
- Uses SPY above its 200-day moving average as a market filter.
- Ranks daily signals by relative strength.
- Generates candidate charts and daily PDF galleries.
- Saves daily scan results to `data/charts/`.
- Optionally sends daily signal summaries to Discord.
- Optionally syncs open and closed signals to Supabase.
- Runs historical backtests across cached price data.
- Compares strategy rule variants against the same backtest assumptions.
## Strategy Summary
The core setup lives in `src/setup_rules.py` as `PullbackUptrendSetup`.
Default rule logic:
1. Stock is in an uptrend:
- Close is above SMA50.
- SMA20 is above SMA50.
2. Previous day pulled back to the SMA20 area:
- Previous close is within 2% of SMA20.
- Previous close is at or below SMA20.
3. Current day reclaims SMA20:
- Close is above SMA20.
4. Optional quiet-volume filter:
- Previous day volume is below its 20-day volume average.
The setup class also supports research knobs:
- `pullback_pct`: how close the pullback must be to SMA20.
- `use_volume`: whether quiet pullback volume is required.
- `reclaim_pct`: how far above SMA20 the reclaim close must be.
- `require_sma200`: whether the stock must also close above SMA200.
Daily scans are candidates for manual review, not automatic buy recommendations.
## Project Structure
```text
SwingTrade/
main.py Daily scanner, chart generation, alerts, Supabase sync
run.bat Convenience script for running the scanner
download_cache.py Downloads historical price cache
backtest_2025.py Main historical backtest
compare_setup_variants.py Compares setup rule variants
backfill_entry.py Backfills entry prices for stored signals
backfill_exits.py Backfills exits for stored signals
price_updater.py Updates current/open signal prices
review_winners.py Review helper for prior winners
requirements.txt Python dependencies
package.json Root JavaScript dependencies
cache/ Cached OHLCV price CSVs
data/
charts/ Daily scan images, PDF galleries, scan CSVs
progress/ Per-ticker progress reports
run_logs/ Historical scanner logs
src/
setup_rules.py Pullback setup definition
scanner.py Scanner and SPY market filter
universe.py S&P 500 and Nasdaq 100 universe loaders
ranking.py Relative-strength ranking
charting.py Candidate chart generation
reporting.py PDF gallery export
progress_viewer.py Single-ticker progress reports
market_calendar.py Market-open checks
exit_rules.py Exit helpers
frontend/ React/Vite dashboard
```
## Setup
Create and activate a Python environment, then install dependencies:
```powershell
pip install -r requirements.txt
```
The scanner downloads live data and universe lists, so it needs internet access.
Optional environment variables:
```powershell
$env:DISCORD_WEBHOOK_URL="..."
$env:SUPABASE_URL="..."
$env:SUPABASE_SERVICE_KEY="..."
```
If these are not set, the scanner still runs locally. It will skip Discord alerts and Supabase sync.
## Daily Scan
Run:
```powershell
python main.py
```
The scan:
1. Checks whether the market is open.
2. Loads S&P 500 and Nasdaq 100 tickers.
3. Applies the SPY SMA200 market filter.
4. Scans each ticker for the pullback setup.
5. Ranks today's signals by relative strength.
6. Saves charts and a PDF gallery.
7. Saves the daily scan CSV.
8. Optionally checks exits and syncs signals to Supabase.
9. Optionally sends a Discord summary.
Typical outputs:
```text
data/charts/YYYY/MM/YYYY-MM-DD/scan_results_YYYY-MM-DD.csv
data/charts/YYYY/MM/YYYY-MM-DD/gallery_YYYY-MM-DD.pdf
data/charts/YYYY/MM/YYYY-MM-DD/TICKER/pullback_setup.png
```
## Historical Price Cache
Backtests use cached CSV files in `cache/`.
Refresh or populate the cache with:
```powershell
python download_cache.py
```
The current cache contains hundreds of large-cap ticker files plus `SPY.csv`.
## Backtesting
Run the main backtest:
```powershell
python backtest_2025.py
```
Current default assumptions:
- Years: 2023, 2024, 2025
- Entry: next trading day open
- Stop loss: 2%
- Profit target: 7%
- Max hold: 10 trading days
- Market filter: SPY close above SMA200
- ATR filter: skips high-volatility stocks where ATR / close is above 3%
Backtest outputs:
```text
backtest_summary.csv
stop_losses.csv
```
## Strategy Variant Comparison
Run:
```powershell
python compare_setup_variants.py
```
This compares the baseline setup against several one-variable changes:
- Remove quiet-volume requirement.
- Tighten pullback depth from 2% to 1%.
- Require reclaim close at least 0.5% above SMA20.
- Require stock close above SMA200.
The comparison runner is offline by design. It uses tickers already present in `cache/` instead of downloading a fresh universe.
Variant outputs:
```text
strategy_variant_summary.csv
strategy_variant_headline.csv
strategy_variant_trades.csv
```
Most recent comparison takeaway: removing the quiet-volume requirement improved trade count, win rate, and average P&L in the cached 2023-2025 test set.
## Progress Reports
Generate a ticker progress report:
```powershell
python -m src.progress_viewer TICKER YYYY-MM-DD
```
Short dates like `1/20` are also accepted and interpreted as the most recent past matching date.
Outputs are saved under:
```text
data/progress/YYYY/MM/DD/TICKER/
```
## Frontend
The React/Vite app is in `frontend/`.
Install and run it:
```powershell
cd frontend
npm install
npm run dev
```
Build:
```powershell
npm run build
```
The frontend uses Supabase through `frontend/src/supabase.js`, so it is most useful when the Supabase signal table is configured.
## Notes On Data And Bias
This project is useful for learning and research, but results should be interpreted carefully:
- Cached universe membership may not match true point-in-time index membership.
- Historical scans can be affected by survivorship bias.
- Backtests use daily candles and simplified execution assumptions.
- Strategy changes should be judged across enough trades and multiple market regimes.
- Manual chart review remains part of the workflow.
## Current Status
Working:
- Daily universe scan
- Pullback setup filtering
- SPY market filter
- Relative strength ranking
- Chart generation
- PDF gallery export
- Historical cache-based backtesting
- Strategy variant comparison
- Optional Discord alerts
- Optional Supabase signal tracking
- React/Vite frontend
Planned or possible improvements:
- Cleaner configuration file for strategy parameters
- More robust point-in-time universe handling
- Better reporting around expectancy, drawdowns, and trade distribution
- Frontend views for backtest and variant results
- More systematic review journal
- Additional setup families beyond SMA20 pullbacks
## Disclaimer
This project is for educational and research purposes only. It is not financial advice, does not recommend securities, and does not automate trade execution. Any trading decision made after using this project is the user's sole responsibility.