Cached Forex Factory economic calendar data provider
Project description
forexfactory
Fetch the Forex Factory economic calendar once and reuse it everywhere — a shared local parquet cache any of your projects can read, with the data fidelity needed for expected-vs-surprise analysis.
Quick Start
pip install forexfactory
forexfactory populate
forexfactory query --currency USD --impact high
That's it. The parquet path is printed to stdout — pipe it straight into pandas.
PARQUET=$(forexfactory query --currency USD --impact high)
python -c "import pandas as pd; print(pd.read_parquet('$PARQUET').head())"
CLI Reference
forexfactory populate
Build the local parquet cache from on-disk raw JSON files (zero network calls by default):
forexfactory populate
Default scope: USD currency, high and holiday impact, all months on disk (~195 months, 2010-01 to 2026-03). Widen the scope with repeatable flags:
forexfactory populate --currency USD --currency EUR --impact high --impact medium
Force-rebuild every month unconditionally (bypasses the manifest skip-check — use after a schema migration):
forexfactory populate --force --raw-dir out
forexfactory refresh
Fetch months not yet in the cache from Forex Factory over the network:
forexfactory refresh
Gap-fills from the last cached month through the current month with a polite 1-second delay between requests. Does not overwrite already-settled months.
forexfactory query
Print the absolute path of the result parquet to stdout — nothing else — making it shell-friendly:
forexfactory query --currency USD --impact high
By default returns data-bearing events (with forecast/actual fields) and bank holidays. To include speeches and other no-data events:
forexfactory query --currency USD --impact high --include-no-data
If the requested currency/impact combination has not been populated, the command exits non-zero and prints actionable guidance to stderr.
forexfactory status
Report cache location, date range, scope, schema version, and settled/matured state:
forexfactory status
forexfactory status --json # machine-readable JSON
forexfactory --version
Print the installed package version:
forexfactory --version
Library API
forexfactory.get(...) — Path to filtered parquet
import forexfactory
from pathlib import Path
path: Path = forexfactory.get(currencies=["USD"], impacts=["high"])
import pandas as pd
df = pd.read_parquet(path)
forexfactory.get(...) returns a pathlib.Path to a filtered parquet file in the local cache. All parameters are keyword-only:
path = forexfactory.get(
currencies=["USD"], # list of currency codes (default: ["USD", "EUR", "GBP", "JPY"])
impacts=["high"], # list of impact levels (default: ["high", "medium", "holiday"])
start="2024-01", # first month to include (YYYY-MM, optional)
end="2024-12", # last month to include (YYYY-MM, optional)
include_no_data=False, # include speeches and no-data events (default: False)
cache_dir=None, # override cache directory (default: ~/.cache/forexfactory)
auto_fetch=True, # auto-refresh matured months before returning (default: True)
)
forexfactory.read(...) — DataFrame convenience loader
forexfactory.read(...) complements get() — it accepts the same keyword-only parameters but returns a pandas.DataFrame instead of a Path, so you never need to handle a file path yourself:
import forexfactory
df = forexfactory.read(currencies=["USD"], impacts=["high"])
# df is a pandas.DataFrame with a datetime_utc DatetimeIndex and datetime_utc column
The returned DataFrame has:
- A
DatetimeIndexnameddatetime_utc, sorted ascending datetime_utcretained as a column (for groupby/merge ergonomics)- All schema columns as stored — no automatic type coercion
- A
siteIdcolumn always present (null for pre-v1.1 cached months)
forexfactory.surprise(df) and forexfactory.surprise_z(df) — opt-in surprise metrics
Surprise helpers operate on the DataFrame returned by read() and return row-aligned pd.Series. They are opt-in — read() returns the plain schema; you compose surprise yourself:
import forexfactory
df = forexfactory.read(currencies=["USD"], impacts=["high"])
df["surprise"] = forexfactory.surprise(df) # raw actual − forecast (D-01)
df["surprise_z"] = forexfactory.surprise_z(df) # z-scored over each ebaseId's full history (D-02)
surprise(df):actual − forecast, verbatim. NaN when either is NaN. Sign is numeric — no polarity adjustment.surprise_z(df): z-scored over eachebaseId's full history indf. NaN for groups with fewer than 2 releases or zero standard deviation.
Output Schema
The cache stores data as parquet with the following columns (schema_version 3):
Core fields (DATA-01)
| Column | Type | Description |
|---|---|---|
datetime_utc |
datetime64[ns, UTC] | Event timestamp in UTC |
currency |
string | Currency code (e.g. USD) |
impact |
string | Impact level (high, holiday, medium, low) |
title |
string | Event name |
id |
Int64 | Forex Factory event ID (nullable) |
leaked |
boolean | Whether Forex Factory marked the event as leaked |
Raw value strings (verbatim from FF)
| Column | Type | Description |
|---|---|---|
forecast_raw |
string | Raw forecast value string (e.g. "4.3%", "202K", "") |
actual_raw |
string | Raw actual value string |
previous_raw |
string | Raw previous value string |
revision_raw |
string | Raw revision value string |
Parsed numerics
Magnitude suffixes expanded (K=×1e3, M=×1e6, B=×1e9, T=×1e12). Percent divided by 100 ("4.3%" → 0.043). Unparseable or empty strings become null (NaN).
| Column | Type | Description |
|---|---|---|
forecast |
float64 | Parsed forecast numeric (null if unparseable) |
actual |
float64 | Parsed actual numeric |
previous |
float64 | Parsed previous numeric |
revision |
float64 | Parsed revision numeric |
Surprise flags and identity
| Column | Type | Description |
|---|---|---|
actualBetterWorse |
Int64 | FF surprise flag: 1=better, 2=worse, 0=neutral/n/a (nullable) |
revisionBetterWorse |
Int64 | FF revision flag: 1=better, 2=worse, 0=neutral/n/a (nullable) |
ebaseId |
Int64 | FF metric series identifier (nullable) |
country |
string | Country code (e.g. US, UK, JN, EZ) |
hasDataValues |
boolean | True for data releases with forecast/actual/previous; False for speeches and holidays |
siteId |
object | FF site identifier (nullable — populated for new scrapes, null for pre-v1.1 cached months; prerequisite for the v2 graph API) |
Cache Layout
The cache lives at ~/.cache/forexfactory/ by default (override with --cache-dir or the
FOREXFACTORY_CACHE_DIR environment variable):
~/.cache/forexfactory/
|-- manifest.json # populated scope + per-month provenance
|-- queries/ # per-scope result parquets
| `-- USD_high_....parquet
`-- YYYY-MM.parquet # one file per calendar month
Project Structure
forexfactory/
|-- pyproject.toml
|-- requirements.txt
|-- README.md
|-- LICENSE
|-- CHANGELOG.md
|-- CONTRIBUTING.md
|-- src/forexfactory/
| |-- __init__.py
| |-- cli.py
| |-- _cache.py
| |-- _pipeline.py
| |-- _populate.py
| |-- _query.py
| |-- _refresh.py
| |-- _scrape.py
| `-- py.typed
|-- tests/
| |-- test_cache.py
| |-- test_cli.py
| |-- test_docs.py
| |-- test_pipeline.py
| |-- test_populate.py
| |-- test_query.py
| |-- test_refresh.py
| `-- test_scrape.py
`-- out/ # optional raw-staging dir (populated on re-scrape)
Data Source
Data is scraped from the Forex Factory economic calendar. For personal/research use — please respect their terms of service and rate limits.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file forexfactory-1.1.0.tar.gz.
File metadata
- Download URL: forexfactory-1.1.0.tar.gz
- Upload date:
- Size: 71.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3abe5fbbc05df8c0d1702d57da78de410dfcfc37254cc3586b212eac9274a24c
|
|
| MD5 |
d7627bffaeaf007c1632e47f097cda71
|
|
| BLAKE2b-256 |
068de4d822d5caa865739d1dbf5fcf957198e3f883a12df3b9c34a91f9400421
|
Provenance
The following attestation bundles were made for forexfactory-1.1.0.tar.gz:
Publisher:
release.yml on thomas-quant/forexfactory
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forexfactory-1.1.0.tar.gz -
Subject digest:
3abe5fbbc05df8c0d1702d57da78de410dfcfc37254cc3586b212eac9274a24c - Sigstore transparency entry: 1810949839
- Sigstore integration time:
-
Permalink:
thomas-quant/forexfactory@ee6702d401a9910c47e0d09a1547645a0b0d587e -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/thomas-quant
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ee6702d401a9910c47e0d09a1547645a0b0d587e -
Trigger Event:
push
-
Statement type:
File details
Details for the file forexfactory-1.1.0-py3-none-any.whl.
File metadata
- Download URL: forexfactory-1.1.0-py3-none-any.whl
- Upload date:
- Size: 40.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
81e85437fd2c3ebedd3c2ba51f9f76fa380184aff213cf6cfff3c9228a49704f
|
|
| MD5 |
3501d09d786e3d3a05447a57b2df8413
|
|
| BLAKE2b-256 |
bfcae1b6429921f00b8af3fd38ad133a732efa4f92593392f893aebf8af9f2d3
|
Provenance
The following attestation bundles were made for forexfactory-1.1.0-py3-none-any.whl:
Publisher:
release.yml on thomas-quant/forexfactory
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forexfactory-1.1.0-py3-none-any.whl -
Subject digest:
81e85437fd2c3ebedd3c2ba51f9f76fa380184aff213cf6cfff3c9228a49704f - Sigstore transparency entry: 1810949859
- Sigstore integration time:
-
Permalink:
thomas-quant/forexfactory@ee6702d401a9910c47e0d09a1547645a0b0d587e -
Branch / Tag:
refs/tags/v1.1.0 - Owner: https://github.com/thomas-quant
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ee6702d401a9910c47e0d09a1547645a0b0d587e -
Trigger Event:
push
-
Statement type: