{"id":51004699,"url":"https://github.com/k1lgor/fpl-momentum-tracker","last_synced_at":"2026-06-20T19:01:45.271Z","repository":{"id":338651185,"uuid":"1146322065","full_name":"k1lgor/fpl-momentum-tracker","owner":"k1lgor","description":"Identify underperforming gems and overperforming traps in Fantasy Premier League using rolling Expected Goals (xG) analysis and statistical momentum trends.","archived":false,"fork":false,"pushed_at":"2026-02-15T17:15:20.000Z","size":599,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-15T23:41:20.829Z","etag":null,"topics":["data-science","expected-goals","fantasy-premier-league","football-analytics","fpl","momentum-tracking","polars","python","regression-to-the-mean","soccer-analytics","sports-analytics","streamlit","uv","xg"],"latest_commit_sha":null,"homepage":"https://fpl-momentum-tracker.streamlit.app/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/k1lgor.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-30T23:11:53.000Z","updated_at":"2026-02-15T17:15:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/k1lgor/fpl-momentum-tracker","commit_stats":null,"previous_names":["k1lgor/fpl-momentum-tracker"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/k1lgor/fpl-momentum-tracker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k1lgor%2Ffpl-momentum-tracker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k1lgor%2Ffpl-momentum-tracker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k1lgor%2Ffpl-momentum-tracker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k1lgor%2Ffpl-momentum-tracker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/k1lgor","download_url":"https://codeload.github.com/k1lgor/fpl-momentum-tracker/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/k1lgor%2Ffpl-momentum-tracker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34581934,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-science","expected-goals","fantasy-premier-league","football-analytics","fpl","momentum-tracking","polars","python","regression-to-the-mean","soccer-analytics","sports-analytics","streamlit","uv","xg"],"created_at":"2026-06-20T19:01:42.333Z","updated_at":"2026-06-20T19:01:45.264Z","avatar_url":"https://github.com/k1lgor.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ⚽ FPL xG Momentum Tracker\n\nIdentify underperforming gems and overperforming traps in Fantasy Premier League using rolling Expected Goals (xG) analysis and statistical momentum trends.\n\n## 🚀 Overview\n\nThis tool analyzes official FPL data to find players whose actual goal output is diverging from their underlying performance. It uses **rolling windows** (4, 6, 10 games) and **linear regression** to identify:\n\n- **💎 Underperformers (BUY)**: Players with high xG but low actual goals (the \"unlucky\" ones due for regression to the mean).\n- **🚀 Rising Stars**: Players whose underlying threat (xG/90) is rapidly improving.\n- **⚠️ Sustainability Risks (SELL)**: Players outscoring their xG significantly (the \"lucky\" ones likely to dry up).\n\n## 🛠️ Tech Stack\n\n- **Python 3.12+**\n- **uv**: Ultra-fast Python package installer and resolver.\n- **Polars**: High-performance DataFrame library for data processing.\n- **Streamlit**: Interactive web UI for visualization.\n- **Altair**: Declarative statistical visualization.\n- **SciPy**: Linear regression for momentum calculation.\n- **pytest**: Testing framework for quality assurance.\n\n## 🏃 Getting Started\n\n### 1. Installation\n\nEnsure you have [uv](https://github.com/astral-sh/uv) installed.\n\n```bash\n# Install dependencies\nuv sync\n\n# Install development dependencies (includes pytest)\nuv sync --extra dev\n```\n\n### 2. Task Execution (Just)\n\nIf you have [just](https://github.com/casey/just) installed, you can use shorter commands:\n\n```bash\njust setup       # Install dependencies\njust install-dev # Install dev dependencies\njust update      # Refresh data and run analysis\njust ui          # Launch the dashboard\njust test        # Run test suite\n```\n\n### 3. Manual Execution\n\n**Fetch fresh data from the FPL API:**\n\n```bash\nuv run src/scripts/fetch_data.py\n```\n\n**Run the momentum analysis engine:**\n\n```bash\nuv run src/scripts/analyze_momentum.py\n```\n\n**Launch the Dashboard:**\n\n```bash\nuv run streamlit run src/app.py\n```\n\n## 📁 Project Structure\n\n```\nfpl-momentum-tracker/\n├── src/\n│   ├── app.py                      # Streamlit dashboard\n│   ├── data/                       # Generated data files (gitignored)\n│   └── scripts/\n│       ├── fetch_data.py           # FPL API data fetcher\n│       ├── analyze_momentum.py     # xG momentum analysis engine\n│       └── report_forwards.py      # Specific forward analysis\n├── tests/                          # Test suite\n│   ├── conftest.py                 # Pytest configuration\n│   ├── test_fetch_data.py          # Data fetcher tests\n│   └── test_analyze_momentum.py    # Analysis engine tests\n├── scripts/                        # Utility scripts for inspection\n├── Justfile                        # Task runner commands\n├── pyproject.toml                  # Project dependencies\n└── README.md                       # This file\n```\n\n## 📖 Key Metrics Explained\n\n### xG Diff (Expected Goals Difference)\n\n- **Negative (-1.5)**: Underperforming. The player is getting chances but not scoring. Regression to the mean suggests they are \"due\".\n- **Positive (+1.5)**: Overperforming. The player is scoring at an unsustainable rate compared to the quality of their chances.\n\n### Momentum Trend\n\n- **↗️ Positive (\u003e0.0)**: Underlying numbers are improving. The player is finding better chances each game.\n- **↘️ Negative (\u003c0.0)**: Underlying numbers are declining. The player's threat is fading.\n\n### DEFCON Score\n\nA composite defensive metric combining:\n\n- Tackles\n- Recoveries (weighted at 0.25x)\n- Clearances, Blocks, and Interceptions (CBI)\n\nHigher DEFCON scores indicate more defensive contribution.\n\n## 🧪 Testing\n\nRun the test suite to ensure everything works correctly:\n\n```bash\n# Run all tests\njust test\n\n# Or manually with pytest\nuv run pytest tests/ -v\n\n# Run tests in watch mode (stops on first failure)\njust test-watch\n```\n\n## 🔧 Troubleshooting\n\n### \"Analysis file not found\" error\n\nRun the data pipeline first:\n\n```bash\njust update\n```\n\n### API connection errors\n\nThe FPL API occasionally experiences downtime. Wait a few minutes and try again. The script includes automatic error handling and will inform you of connection issues.\n\n### Empty data files\n\nIf you're running this very early in the season (before gameweek 1), there may be no historical data available. The scripts will handle this gracefully.\n\n## 🤝 Contributing\n\nContributions are welcome! Here's how you can help:\n\n1. **Report bugs**: Open an issue with details about the problem\n2. **Suggest features**: Share ideas for new analysis metrics or visualizations\n3. **Submit PRs**: Fork the repo, make your changes, and submit a pull request\n\n### Development Workflow\n\n1. Install dev dependencies: `just install-dev`\n2. Make your changes\n3. Run tests: `just test`\n4. Ensure code quality (no lint errors)\n5. Submit a PR with a clear description\n\n## 📊 Data Sources\n\nAll data is fetched from the official [Fantasy Premier League API](https://fantasy.premierleague.com/api/):\n\n- Bootstrap static data (players, teams, gameweeks)\n- Player gameweek history (performance metrics)\n\n## 📝 License\n\nThis project is for educational and personal use. All FPL data belongs to the Premier League.\n\n---\n\nBuilt with ⚽ for FPL Managers by data-driven enthusiasts.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk1lgor%2Ffpl-momentum-tracker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fk1lgor%2Ffpl-momentum-tracker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fk1lgor%2Ffpl-momentum-tracker/lists"}