Skip to main content

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.

PyPI version Python versions CI License: MIT

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 DatetimeIndex named datetime_utc, sorted ascending
  • datetime_utc retained as a column (for groupby/merge ergonomics)
  • All schema columns as stored — no automatic type coercion
  • A siteId column 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 each ebaseId's full history in df. 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

forexfactory-1.1.0.tar.gz (71.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

forexfactory-1.1.0-py3-none-any.whl (40.3 kB view details)

Uploaded Python 3

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

Hashes for forexfactory-1.1.0.tar.gz
Algorithm Hash digest
SHA256 3abe5fbbc05df8c0d1702d57da78de410dfcfc37254cc3586b212eac9274a24c
MD5 d7627bffaeaf007c1632e47f097cda71
BLAKE2b-256 068de4d822d5caa865739d1dbf5fcf957198e3f883a12df3b9c34a91f9400421

See more details on using hashes here.

Provenance

The following attestation bundles were made for forexfactory-1.1.0.tar.gz:

Publisher: release.yml on thomas-quant/forexfactory

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for forexfactory-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 81e85437fd2c3ebedd3c2ba51f9f76fa380184aff213cf6cfff3c9228a49704f
MD5 3501d09d786e3d3a05447a57b2df8413
BLAKE2b-256 bfcae1b6429921f00b8af3fd38ad133a732efa4f92593392f893aebf8af9f2d3

See more details on using hashes here.

Provenance

The following attestation bundles were made for forexfactory-1.1.0-py3-none-any.whl:

Publisher: release.yml on thomas-quant/forexfactory

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page