{"id":356875,"name":"EpexPredictor","description":"Predicts day-ahead electricity prices for various countries in Europe.","url":"https://github.com/b3nn0/epexpredictor","last_synced_at":"2026-06-20T05:30:19.808Z","repository":{"id":284373172,"uuid":"954733513","full_name":"b3nn0/EpexPredictor","owner":"b3nn0","description":"Predicts day-ahead electricity prices for various countries in Europe","archived":false,"fork":false,"pushed_at":"2026-05-30T10:18:25.000Z","size":220,"stargazers_count":74,"open_issues_count":1,"forks_count":15,"subscribers_count":10,"default_branch":"main","last_synced_at":"2026-06-17T04:03:53.506Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/b3nn0.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2025-03-25T14:34:25.000Z","updated_at":"2026-06-11T08:17:33.000Z","dependencies_parsed_at":"2026-01-01T19:00:40.290Z","dependency_job_id":"3ba26f2c-3775-47b8-8c15-dca62ead0cc3","html_url":"https://github.com/b3nn0/EpexPredictor","commit_stats":null,"previous_names":["b3nn0/epexpredictor"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/b3nn0/EpexPredictor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b3nn0%2FEpexPredictor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b3nn0%2FEpexPredictor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b3nn0%2FEpexPredictor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b3nn0%2FEpexPredictor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/b3nn0","download_url":"https://codeload.github.com/b3nn0/EpexPredictor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b3nn0%2FEpexPredictor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34517748,"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-19T02:00:06.005Z","response_time":61,"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"}},"owner":{"login":"b3nn0","name":"Adrian Batzill","uuid":"1858945","kind":"user","description":"","email":"","website":null,"location":null,"twitter":null,"company":null,"icon_url":"https://avatars.githubusercontent.com/u/1858945?v=4","repositories_count":4,"last_synced_at":"2023-03-05T07:34:36.512Z","metadata":{"has_sponsors_listing":false},"html_url":"https://github.com/b3nn0","funding_links":[],"total_stars":null,"followers":null,"following":null,"created_at":"2022-11-15T08:24:29.238Z","updated_at":"2023-03-05T07:34:36.524Z","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/b3nn0","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/b3nn0/repositories"},"packages":[],"commits":{"id":11789576,"full_name":"b3nn0/EpexPredictor","default_branch":"master","total_commits":186,"total_committers":5,"total_bot_commits":0,"total_bot_committers":0,"mean_commits":37.2,"dds":0.11827956989247312,"past_year_total_commits":134,"past_year_total_committers":4,"past_year_total_bot_commits":0,"past_year_total_bot_committers":0,"past_year_mean_commits":33.5,"past_year_dds":0.14179104477611937,"last_synced_at":"2026-06-17T04:02:21.852Z","last_synced_commit":"dd645da5feb68c1c31ed764b94dd6606bda91958","created_at":"2026-06-04T07:53:33.788Z","updated_at":"2026-06-17T04:02:21.786Z","committers":[{"name":"Adrian Batzill","email":"dev@batzill.com","login":"b3nn0","count":164},{"name":"sokorn","email":"","login":null,"count":14},{"name":"Gernot Pansy","email":"gernot@pansy.at","login":"notz","count":4},{"name":"christian mock","email":"cm@tahina.priv.at","login":"cmock","count":2},{"name":"Nikola Ilo","email":"nikola.ilo@gmail.com","login":"thargor","count":2}],"past_year_committers":[{"name":"Adrian Batzill","email":"dev@batzill.com","login":"b3nn0","count":115},{"name":"sokorn","email":"","login":null,"count":14},{"name":"Gernot Pansy","email":"gernot@pansy.at","login":"notz","count":4},{"name":"christian mock","email":"cm@tahina.priv.at","login":"cmock","count":1}],"commits_url":"https://commits.ecosyste.ms/api/v1/hosts/GitHub/repositories/b3nn0%2FEpexPredictor/commits","host":{"name":"GitHub","url":"https://github.com","kind":"github","last_synced_at":"2026-06-19T00:00:07.604Z","repositories_count":6263501,"commits_count":875509840,"contributors_count":35076204,"owners_count":1168581,"icon_url":"https://github.com/github.png","host_url":"https://commits.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://commits.ecosyste.ms/api/v1/hosts/GitHub/repositories"}},"issues_stats":{"full_name":"b3nn0/EpexPredictor","html_url":"https://github.com/b3nn0/EpexPredictor","last_synced_at":"2026-06-15T03:01:12.701Z","status":"error","issues_count":12,"pull_requests_count":3,"avg_time_to_close_issue":347208.3,"avg_time_to_close_pull_request":21907.5,"issues_closed_count":10,"pull_requests_closed_count":2,"pull_request_authors_count":3,"issue_authors_count":9,"avg_comments_per_issue":1.75,"avg_comments_per_pull_request":2.6666666666666665,"merged_pull_requests_count":1,"bot_issues_count":0,"bot_pull_requests_count":0,"past_year_issues_count":12,"past_year_pull_requests_count":2,"past_year_avg_time_to_close_issue":347208.3,"past_year_avg_time_to_close_pull_request":605.0,"past_year_issues_closed_count":10,"past_year_pull_requests_closed_count":1,"past_year_pull_request_authors_count":2,"past_year_issue_authors_count":9,"past_year_avg_comments_per_issue":1.75,"past_year_avg_comments_per_pull_request":1.5,"past_year_bot_issues_count":0,"past_year_bot_pull_requests_count":0,"past_year_merged_pull_requests_count":0,"created_at":"2025-08-29T18:14:08.996Z","updated_at":"2026-06-15T03:01:12.701Z","repository_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories/b3nn0%2FEpexPredictor","issues_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories/b3nn0%2FEpexPredictor/issues","issue_labels_count":{},"pull_request_labels_count":{},"issue_author_associations_count":{"NONE":10,"CONTRIBUTOR":2},"pull_request_author_associations_count":{"NONE":3},"issue_authors":{"cmock":2,"MarcoPolet":2,"djfanatix":2,"avsaase":1,"Seblin01":1,"bash1073":1,"gieljnssns":1,"chk2902":1,"HolgerMiara":1},"pull_request_authors":{"cmock":1,"thargor":1,"seerdekens":1},"host":{"name":"GitHub","url":"https://github.com","kind":"github","last_synced_at":"2026-06-19T00:00:10.812Z","repositories_count":14815560,"issues_count":33058205,"pull_requests_count":109075293,"authors_count":11311234,"icon_url":"https://github.com/github.png","host_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/repositories","owners_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/owners","authors_url":"https://issues.ecosyste.ms/api/v1/hosts/GitHub/authors"},"past_year_issue_labels_count":{},"past_year_pull_request_labels_count":{},"past_year_issue_author_associations_count":{"NONE":10,"CONTRIBUTOR":2},"past_year_pull_request_author_associations_count":{"NONE":1},"past_year_issue_authors":{"cmock":2,"djfanatix":2,"MarcoPolet":2,"avsaase":1,"bash1073":1,"chk2902":1,"gieljnssns":1,"HolgerMiara":1,"Seblin01":1},"past_year_pull_request_authors":{"seerdekens":1},"maintainers":[],"active_maintainers":[]},"events":{"total":{"PullRequestEvent":4,"ForkEvent":4,"IssuesEvent":5,"WatchEvent":13,"IssueCommentEvent":27,"PushEvent":95,"PullRequestReviewEvent":4,"PullRequestReviewCommentEvent":6,"CreateEvent":7},"last_year":{"PullRequestEvent":2,"ForkEvent":3,"IssuesEvent":5,"WatchEvent":9,"IssueCommentEvent":18,"PushEvent":52,"PullRequestReviewEvent":4,"PullRequestReviewCommentEvent":6,"CreateEvent":1}},"keywords":[],"dependencies":[{"ecosystem":"docker","filepath":"Dockerfile","sha":null,"kind":"manifest","created_at":"2025-03-25T15:43:32.916Z","updated_at":"2025-03-25T15:43:32.916Z","repository_link":"https://github.com/b3nn0/EpexPredictor/blob/main/Dockerfile","dependencies":[{"id":22415604795,"package_name":"python","ecosystem":"docker","requirements":"latest","direct":true,"kind":"build","optional":false}]},{"ecosystem":"pypi","filepath":"requirements.txt","sha":null,"kind":"manifest","created_at":"2025-03-25T15:43:32.990Z","updated_at":"2025-03-25T15:43:32.990Z","repository_link":"https://github.com/b3nn0/EpexPredictor/blob/main/requirements.txt","dependencies":[{"id":22415604832,"package_name":"holidays","ecosystem":"pypi","requirements":"*","direct":true,"kind":"runtime","optional":false},{"id":22415604833,"package_name":"open_meteo_solar_forecast","ecosystem":"pypi","requirements":"*","direct":true,"kind":"runtime","optional":false},{"id":22415604924,"package_name":"scikit-learn","ecosystem":"pypi","requirements":"*","direct":true,"kind":"runtime","optional":false},{"id":22415604925,"package_name":"pandas","ecosystem":"pypi","requirements":"*","direct":true,"kind":"runtime","optional":false},{"id":22415604926,"package_name":"numpy","ecosystem":"pypi","requirements":"*","direct":true,"kind":"runtime","optional":false},{"id":22415604927,"package_name":"flask","ecosystem":"pypi","requirements":"*","direct":true,"kind":"runtime","optional":false}]},{"ecosystem":"actions","filepath":".github/workflows/docker-publish.yml","sha":null,"kind":"manifest","created_at":"2025-05-10T15:21:00.608Z","updated_at":"2025-05-10T15:21:00.608Z","repository_link":"https://github.com/b3nn0/EpexPredictor/blob/main/.github/workflows/docker-publish.yml","dependencies":[{"id":23067892982,"package_name":"actions/checkout","ecosystem":"actions","requirements":"v4","direct":true,"kind":"composite","optional":false},{"id":23067892983,"package_name":"sigstore/cosign-installer","ecosystem":"actions","requirements":"59acb6260d9c0ba8f4a2f9d9b48431a222b68e20","direct":true,"kind":"composite","optional":false},{"id":23067892984,"package_name":"docker/setup-buildx-action","ecosystem":"actions","requirements":"f95db51fddba0c2d1ec667646a06c2ce06100226","direct":true,"kind":"composite","optional":false},{"id":23067892985,"package_name":"docker/login-action","ecosystem":"actions","requirements":"343f7c4344506bcbf9b4de18042ae17996df046d","direct":true,"kind":"composite","optional":false},{"id":23067892986,"package_name":"docker/metadata-action","ecosystem":"actions","requirements":"96383f45573cb7f253c731d3b3ab81c87ef81934","direct":true,"kind":"composite","optional":false},{"id":23067892987,"package_name":"docker/build-push-action","ecosystem":"actions","requirements":"0565240e2d4ab88bba5387d719585280857ece09","direct":true,"kind":"composite","optional":false}]}],"score":5.926926025970411,"created_at":"2026-06-04T07:53:34.380Z","updated_at":"2026-06-20T05:30:19.810Z","avatar_url":"https://github.com/b3nn0.png","language":"Python","category":"Energy Systems","sub_category":"Energy Markets","monthly_downloads":0,"total_dependent_repos":0,"total_dependent_packages":0,"readme":"# EPEX day-ahead price prediction\n\nThis is a simple statistical model to predict EPEX day-ahead prices based on various parameters.\nIt works to a reasonably good degree. Better than many of the commercial solutions.\nThis repository includes\n- The self-training prediction model itself\n- A simple FastAPI app to get a REST API up\n- A Docker compose file to have it running wherever\n\nSupported Countries:\n- Germany (default)\n- Austria\n- Belgium\n- Netherlands\n- Sweden (SE1-SE4)\n- Denmark (DK1-DK2)\n- Spain\n- Portugal\n- Others can be added relatively easily, if there is interest\n\n\n## Lookout\n- Maybe package it directly as a Home Assistant Add-on\n\n## The Model\nWe sample multiple locations distributed across each region. We fetch [Weather data from Open-Meteo.com](https://open-meteo.com/) for those locations for the past n days (default n=120).\nThis serves as the main data source.\n\nPrice data is provided under CC BY 4.0 by smartd.de, retrieved via [api.energy-charts.info](https://api.energy-charts.info/) and [ENTSO-E transparency platform](https://transparency.entsoe.eu/).\n\nGrid load data is provided by [ENTSO-E transparency platform](https://transparency.entsoe.eu/).\n\n### Features\n\nWeather features (per sample location):\n- Wind speed at 80m\n- Temperature at 2m\n- Global tilted irradiance (solar)\n- Air pressure at mean sea level\n- Relative humidity\n\nTime features:\n- Azimuth of the sun as indicator of time of day\n- Elevation of the sun\n- Day of the week (Monday to Saturday)\n- Holiday/Sunday indicator (regional holidays weighted by fraction of regions, e.g. 0.5 if half the regions have the holiday)\n- Sunrise influence: how many minutes between sunrise and the current time slot\n- Sunset influence: how many minutes between sunset and the current time slot\n\nOther:\n- Entso-E load forecast (optional, but highly recommended, especially for DE and AT)\n- Natural gas day-ahead-price, forward filled (select regions only)\n\nOutput:\n- Electricity price\n\n## How it works\nThe model uses **LightGBM gradient boosting** to predict electricity prices. LightGBM automatically learns non-linear relationships and feature interactions, making it well-suited for electricity price prediction where factors like low wind+solar can cause price spikes due to merit order pricing.\n\n## Model performance\nFor performance testing, see `predictor/performance_testing.py`.\n\nRemarks:\n- Tests were run in 2026, with data from 2025-05-15 to 2026-05-15. The model is tuned for 15 minute pricing. Since data before 2025-10-01 were using hourly pricing, actual performance might be slightly better\n- The model uses a 120-day rolling training window\n- Tests were done with historical weather data. If the weather forecast is wrong, performance might be slightly worse in practice\n\nResults (1-day ahead prediction):\n| Region | MAE (ct/kWh) | RMSE (ct/kWh) |\n|--------|--------------|---------------|\n| DE     | 1.73         | 2.72          |\n| AT     | 1.98         | 3.12          |\n| BE     | 1.83         | 2.75          |\n| NL     | 1.74         | 2.79          |\n| SE1    | 1.63         | 2.79          |\n| SE2    | 1.47         | 2.6           |\n| SE3    | 1.99         | 2.81          |\n| SE4    | 2.34         | 3.22          |\n| DK1    | 1.9          | 2.83          |\n| DK2    | 2.15         | 3.26          |\n| ES     | 1.65         | 2.25          |\n| PT     | 2.07         | 2.76          |\n\n\nSome observations:\n- At night, predictions are typically within 0.5 ct/kWh\n- Morning/Evening peaks are typically within 1-1.5 ct/kWh\n- Extreme peaks due to \"Dunkelflaute\" are correctly detected, but estimation of the exact price is a challenge (e.g. the model might predict 75ct while reality is 60ct or vice versa)\n- High PV noons are usually correctly detected with good accuracy\n\n\n### Current forecast (DE)\n![image](https://epexpredictor.batzill.com/eval_plot?region=DE\u0026transparent=false\u0026width=1024\u0026height=512)\n\n\nFeel free to generate your own plot for other time ranges or regions [here](https://epexpredictor.batzill.com/docs#/default/generate_evaluation_plot_eval_plot_get).\n\n\n# Public API\nYou can find a freely accessible installment of this software [here](https://epexpredictor.batzill.com/).\nGet a glimpse of the current prediction [here](https://epexpredictor.batzill.com/prices).\n\nThere are no guarantees given whatsoever - it might work for you or not.\nI might stop or block this service at any time. Fair use is expected!\n\n# Self Hosting\nYou can easily self-host this software. For easy deployment, check out the docker compose file.\nYou will probably want to register with Entso-E and request an API key.\nWithout Entso-E API access\n- some parameters are missing and the model will perform significantly worse, especially for DE and AT\n- Some regions will not be available (e.g. SE1-4)\n\n# Home Assistant integration\nAt some point, I might create a HA addon to run everything locally.\nFor now, you have to either use my server, or run it yourself.\n\nNote: Home Assistant only supports a limited amount of data in state attributes. Therefore, we use the \"short format\" output, and limit the time to 120 hours.\nIf you need more, you will have to be more creative.\nPersonally, I provide the data as a HA \"service\" (now \"action\") using pyscript, and then call this service to work with the data.\n\n\n\n### Configuration:\n```yaml\n# Make sure you change the parameters region, surcharge and taxPercent according to your electricity plan\nsensor:\n  - platform: rest\n    resource: \"https://epexpredictor.batzill.com/prices_short?region=DE\u0026surcharge=13.70084\u0026taxPercent=19\u0026unit=EUR_PER_KWH\u0026hours=120\"\n    method: GET\n    unique_id: epex_price_prediction\n    name: \"EPEX Price Prediction\"\n    unit_of_measurement: €/kWh\n    value_template: \"{{ value_json.t[0] }}\"\n    json_attributes:\n      - s\n      - t\n\n  # If you want to evaluate performance in real time, you can add another sensor like this\n  # and plot it in the same diagram as the actual prediction sensor\n\n  #- platform: rest\n  #  resource: \"https://epexpredictor.batzill.com/prices_short?region=DE\u0026surcharge=13.70084\u0026taxPercent=19\u0026evaluation=true\u0026unit=EUR_PER_KWH\u0026hours=120\"\n  #  method: GET\n  #  unique_id: epex_price_prediction_evaluation\n  #  name: \"EPEX Price Prediction Evaluation\"\n  #  unit_of_measurement: €/kWh\n  #  value_template: \"{{ value_json.t[0] }}\"\n  #  json_attributes:\n  #    - s\n  #    - t\n```\n\n### Display, e.g. via Plotly Graph Card:\n```yaml\ntype: custom:plotly-graph\ntime_offset: 26h\nlayout:\n  yaxis9:\n    fixedrange: true\n    visible: false\n    minallowed: 0\n    maxallowed: 1\nentities:\n  - entity: sensor.epex_price_prediction\n    name: EPEX Price Prediction\n    unit_of_measurement: ct/kWh\n    texttemplate: \"%{y:.0f}\"\n    mode: lines+text\n    textposition: top right\n    filters:\n      - fn: |-\n          ({xs, ys, meta}) =\u003e {\n            return {\n              xs: xs.concat(meta.s.map(s =\u003e s*1000)),\n              ys: ys.concat(meta.t).map(t =\u003e +t*100)\n            }\n          }\n  - entity: \"\"\n    name: Now\n    yaxis: y9\n    showlegend: false\n    line:\n      width: 1\n      dash: dot\n      color: orange\n    x: $ex [Date.now(), Date.now()]\n    \"y\":\n      - 0\n      - 1\nhours_to_show: 30\nrefresh_interval: 10\n```\n\n# evcc integration\n\n[evcc](https://evcc.io/) is an open-source EV charging controller that can optimize charging based on electricity prices.\nIt now has native support for EpexPredictor, see [docs](https://docs.evcc.io/docs/tariffs#epex-predictor-predicted-epex-spot-prices)","funding_links":[],"readme_doi_urls":[],"works":{},"citation_counts":{},"total_citations":0,"keywords_from_contributors":[],"project_url":"https://ost.ecosyste.ms/api/v1/projects/356875","html_url":"https://ost.ecosyste.ms/projects/356875"}