Перейти к содержимому
Все документы библиотеки

Загрузка данных о позициях CFTC для анализа фьючерсов

Код Machine Learning for Trading

Сводка

В документе объясняется, как получать еженедельные данные CFTC Commitment of Traders по выбранным фьючерсным инструментам и сохранять историю каждого инструмента в файл Parquet. Отчёты COT фиксируют позиции на вторник и публикуются в пятницу; категории трейдеров различаются для финансовых фьючерсов и сырьевых товаров. Полученные данные включают даты отчётов, открытый интерес, а также длинные, короткие и чистые позиции; их можно использовать для формирования признаков позиционирования или настроений в исследовательском процессе по фьючерсам.

Загрузчик позволяет выбрать инструменты и диапазон лет либо использовать заданный список инструментов и диапазон дат по умолчанию. Он проверяет запрошенные коды инструментов, отмечает инструменты, по которым данные не получены, и сообщает об ошибках загрузки. Это практическое руководство, а не анализ эффективности сигналов COT: в нём нет бэктеста, свидетельств предсказательной силы или правил интерпретации изменений позиций. Наблюдения COT еженедельные и отражают срез данных, поэтому документ не устанавливает их своевременность или полезность для какой-либо конкретной торговой стратегии.

Ключевые идеи

  • Отчёты CFTC дают еженедельные срезы позиций по фьючерсам; категории трейдеров зависят от рынка и типа отчёта.
  • По дате отчёта сохраняются открытый интерес и длинные, короткие и чистые позиции по категориям трейдеров.
  • Пользователи могут выбирать инструменты и годы; ошибки загрузки и пустые результаты отмечаются отдельно.
  • В документе описаны получение и хранение данных, но не проверяется, предсказывают ли признаки COT доходность.

Теги

Полный текст
# cot_download.py


```py
#!/usr/bin/env python3
"""Download CFTC Commitment of Traders (COT) data.

CFTC publishes weekly COT reports (Tuesday snapshot, released Friday) showing
futures positioning broken down by trader type (dealers, asset managers,
leveraged money for financial futures; commercials, managed money for
commodities). The data is free and useful for sentiment/positioning features.

This downloader uses ``ml4t.data.cot.COTFetcher`` — which wraps the
``cot_reports`` library — to fetch per-product panels and writes one parquet
per product to ``$ML4T_DATA_PATH/futures/positioning/cot/{product}.parquet``. The
``load_cot()`` loader in ``data/futures/loader.py`` consumes these files.

Output layout under ``$ML4T_DATA_PATH/futures/positioning/cot/``::

    {PRODUCT}.parquet    one parquet per product code (e.g., ES.parquet)

Schema (columns vary by report type but include):

    product              exchange product code (ES, CL, GC, …)
    report_type          CFTC report that produced the row
    report_date          Tuesday snapshot date
    open_interest        total open interest
    <trader>_long        long positions per trader category
    <trader>_short       short positions per trader category
    <trader>_net         computed long − short per category

Usage::

    # Default: all products in PRODUCT_MAPPINGS, 2020–current year
    python data/futures/positioning/cot_download.py

    # Restrict to a subset
    python data/futures/positioning/cot_download.py --products ES,NQ,CL,GC

    # Wider year range
    python data/futures/positioning/cot_download.py --start-year 2010 --end-year 2024

    # Override output root
    python data/futures/positioning/cot_download.py --data-path /tmp/ml4t-data
"""

from __future__ import annotations

import argparse
from pathlib import Path

from ml4t.data.cot import PRODUCT_MAPPINGS, COTConfig, COTFetcher

from utils.downloading import resolve_data_dir


def main() -> int:
    parser = argparse.ArgumentParser(
        description="Download CFTC Commitment of Traders data",
        formatter_class=argparse.RawDescriptionHelpFormatter,
    )
    parser.add_argument(
        "--products",
        type=str,
        default=None,
        help=(
            "Comma-separated product codes (default: all in PRODUCT_MAPPINGS). "
            f"Available: {', '.join(sorted(PRODUCT_MAPPINGS.keys()))}"
        ),
    )
    parser.add_argument(
        "--start-year",
        type=int,
        default=2020,
        help="First calendar year to fetch (default: 2020)",
    )
    parser.add_argument(
        "--end-year",
        type=int,
        default=None,
        help="Last calendar year to fetch (default: current year)",
    )
    parser.add_argument(
        "--data-path",
        type=Path,
        default=None,
        help="Override output root (default: $ML4T_DATA_PATH)",
    )
    args = parser.parse_args()

    if args.products:
        products = [p.strip().upper() for p in args.products.split(",") if p.strip()]
        unknown = [p for p in products if p not in PRODUCT_MAPPINGS]
        if unknown:
            print(f"ERROR: unknown product code(s): {', '.join(unknown)}")
            print(f"Available: {', '.join(sorted(PRODUCT_MAPPINGS.keys()))}")
            return 1
    else:
        products = sorted(PRODUCT_MAPPINGS.keys())

    data_path = resolve_data_dir(args.data_path)
    output_dir = data_path / "futures" / "positioning" / "cot"
    output_dir.mkdir(parents=True, exist_ok=True)

    config = COTConfig(
        products=products,
        start_year=args.start_year,
        end_year=args.end_year,
        storage_path=output_dir,
    )
    fetcher = COTFetcher(config)

    print()
    print(f"Output:       {output_dir}")
    print(f"Years:        {config.start_year}–{config.end_year}")
    print(f"Products:     {len(products)} ({', '.join(products)})")
    print()

    written = 0
    empty = 0
    failed: list[str] = []
    for i, product in enumerate(products, 1):
        print(f"  [{i}/{len(products)}] {product}…", end="", flush=True)
        try:
            df = fetcher.fetch_product(product)
        except Exception as e:
            failed.append(product)
            print(f" FAILED ({e})")
            continue

        if df.is_empty():
            empty += 1
            print(" no rows returned")
            continue

        out_path = output_dir / f"{product}.parquet"
        df.write_parquet(out_path)
        written += 1
        print(f" {len(df):,} rows → {out_path.name}")

    print()
    print(f"Wrote:        {written} parquet(s)")
    if empty:
        print(f"Empty:        {empty} product(s) returned no rows")
    if failed:
        print(f"Failed:       {len(failed)} — {', '.join(failed)}")
        return 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

```

Полный текст с указанием источника опубликован на условиях его лицензии. Лицензия: MIT

Это краткое изложение подготовлено исследовательским агентом Stratmill по оригиналу и не является его копией.