Skip to main content

cotmetrics

PyPI Python License: MIT

Turn raw COT (Commitments of Traders) data into positioning metrics and trading signals — the positioning index, concentration / clustering / position-size, reversal signals, and the CotIndexer that assembles per-instrument weekly panels.

Split out of the cot-analyzer dashboard so the metrics layer installs without the Dash/Plotly UI stack. Reads prices and COT from the shared cotdata store.

Install

pip install cotmetrics

This pulls in cotdata, the data layer beneath it. cotmetrics computes metrics over a populated cotdata store — point COTDATA_STORE at one before you can read real prices/COT (see cotdata for how to build the store). Optional extras: pip install "cotmetrics[options]" (max-pain options snapshots via yfinance).

Use

import cotmetrics                                    # flat metric fns, side-effect-free import
from cotmetrics.indexer import get_indexer, boot_options_update
from cotmetrics.signals import append_trading_signals

cotmetrics.calculate_cot_index(...)

import cotmetrics is side-effect-free. get_indexer() constructs (and caches) the CotIndexer, which loads the store on first use; the daily options fetch runs only when you call boot_options_update() explicitly.

Config / paths

env meaning default
COTDATA_STORE shared price/COT store (from cotdata) required
COTMETRICS_CACHE derived per-instrument parquet cache ~/.cache/cotmetrics
COTMETRICS_CITPY CIT PY research notes (dated .md/.txt), persistent data not a cache. Point it at the generating tool's output dir, never inside COTDATA_STORE ~/.local/share/cotmetrics/citpy
COTMETRICS_PARAMS instrument/params config packaged sample params.yaml
COTMETRICS_DATA working dir for real_test_data (fixture) exports <cache>/../cotmetrics_data

The packaged params.yaml is a small generic sample (a handful of well-known symbols, untuned 52-week lookbacks) so cotmetrics runs out of the box. For a real instrument universe and any tuned parameters, set COTMETRICS_PARAMS to your own config file.

Scheduling (weekly COT refresh + email)

COT data is produced by cotdata, not here. cotmetrics only reads the shared store, so refresh COT on the schedule cotdata documents (see the "Scheduling on Linux (cron)" section of the cotdata README: cotdata-update --cot-all, run through the CFTC's Friday ~3:30pm ET release window).

scripts/cron_update.sh wraps that refresh and emails the weekly report only when the COT report date actually advances. It takes its config from the environment (no paths baked in), so point the crontab at it:

# Friday afternoon (times in ET): refresh COT, email the report only if new data landed.
*/2 15-16 * * 5  COTDATA_STORE=/path/to/store /path/to/cotmetrics/scripts/cron_update.sh >> /path/to/cot.log 2>&1
env meaning default
COTDATA_STORE shared cotdata store required
COTDATA_UPDATE the cotdata-update binary cotdata-update on PATH

The script reads status.json's newest_data.cot_legacy before and after the update and runs scripts/generate-weekly-report-email.sh only on a change, so re-running across the release window is a harmless no-op until the CFTC zip lands.

This route suits a box that produces COT. It runs cotdata-update itself, so on a box whose store is a replica fed by a producer push, it would make a second producer racing that push. Such a box has no download to trigger on, and should instead let the consuming app send: cot-analyzer's store poller notices status.json advancing and calls cotmetrics.weekly_email in-process, guarded by an opt-in flag and a ledger so it sends once per COT week. Sending in-process also means the email inherits the app's own COTMETRICS_PARAMS, which is worth more than it sounds: unset, that silently resolves to the 6-symbol SAMPLE universe, and an email covering six markets looks exactly like an email covering forty-seven.

Sending it directly

scripts/generate-weekly-report-email.py sends one now, and is a thin CLI over cotmetrics.weekly_email.send_weekly_matrix_email. It reads three variables from the environment of the process invoking it and loads no .env of its own:

env meaning
EMAIL_USER the sending account
RECEIVER_EMAIL_USER where the report goes
EMAIL_PASSWORD an app password, not the account password

The subject line names the COT week the matrix carries, not the day the send ran.

Development (from source)

Developed alongside its sibling repos in a shared workspace, with cotdata installed editable rather than from PyPI:

git clone https://github.com/mspinola/cotmetrics
pip install -e ../cotdata -e ".[options,dev]"
export COTDATA_STORE=~/code/cotdata_store     # shared data store
pytest

Docs

License

MIT — see LICENSE.

Metadata

Release files for cotmetrics 0.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cotmetrics 0.9.0
File Size Uploaded
cotmetrics-0.9.0.tar.gz 189.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cotmetrics 0.9.0
File Interpreter ABI Platform
cotmetrics-0.9.0-py3-none-any.whl Python 3 none any Details

Total release size: 330.0 kB

Release files / cotmetrics-0.9.0.tar.gz

Download URL cotmetrics-0.9.0.tar.gz
Size 189.0 kB
Tags Source
SHA-256 checksum
How to use checksums
5772c658ae714a107b0d8efcc3dc2f06a3e26fa256cae7666bfa8d9b2535e0d4
BLAKE2b-256 checksum
How to use checksums
7e50876d48339764c4310e6885d85ad970ca3026a69444550787b949b80cf4d7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release files / cotmetrics-0.9.0-py3-none-any.whl

Download URL cotmetrics-0.9.0-py3-none-any.whl
Size 141.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
716a897d3cf70594c5d4a5533e1f62d4d37e75c7de931bc83abee7d3a56f29ac
BLAKE2b-256 checksum
How to use checksums
eb1a1b1b6a7dcd18edf8b87d4944087c7ad50eaa02bea4f8db212e6c52fcf781
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.

Transparency log

Release history Release notifications | RSS feed

0.15.1

2 release files

0.12.0

2 release files

This release

0.9.0 This release

2 release files

0.4.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page