Skip to content

Commit

Permalink
refactor: add cot_report function
Browse files Browse the repository at this point in the history
for easy consecutive cached calls
  • Loading branch information
philsv committed Oct 25, 2023
1 parent 3747d3d commit a396c8b
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 13 deletions.
24 changes: 21 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# pycot

[![PyPI Version](https://badge.fury.io/py/pycot-reports.svg)](https://badge.fury.io/py/pycot-reports)
[![PyPI version](https://d25lcipzij17d.cloudfront.net/badge.svg?id=py&r=r&ts=1683906897&type=6e&v=0.0.7&x2=0)](https://badge.fury.io/py/pycot-reports)
[![License: MIT](https://img.shields.io/badge/License-MIT-red.svg)](https://github.com/philsv/pycot/blob/main/LICENSE)
[![Weekly Downloads](https://static.pepy.tech/personalized-badge/pycot-reports?period=week&units=international_system&left_color=grey&right_color=blue&left_text=downloads/week)](https://pepy.tech/project/pycot-reports)
[![Monthly Downloads](https://static.pepy.tech/personalized-badge/pycot-reports?period=month&units=international_system&left_color=grey&right_color=blue&left_text=downloads/month)](https://pepy.tech/project/pycot-reports)
Expand All @@ -22,10 +22,28 @@ pip install pycot-reports
## How to use

```python
from pycot.reports import legacy_report, disaggregated_report, financial_report
from pycot import reports

df = reports.legacy_report(report_type="legacy_fut", contract_name=("FED FUNDS - CHICAGO BOARD OF TRADE", "30-DAY FEDERAL FUNDS - CHICAGO BOARD OF TRADE"))
```

## How do I get cached results?

If you want to retrieve data from the same report multiple times, you can use the `cot_report` function. This will cache the results of the previous function call.

Lets have a look at an example:

```python
from pycot.reports import cot_report, legacy_report

fed_funds_contract = ("FED FUNDS - CHICAGO BOARD OF TRADE", "30-DAY FEDERAL FUNDS - CHICAGO BOARD OF TRADE")
fed_funds_df = cot_report(legacy_report(), fed_funds_contract) # will load the full report (~ 10-15 seconds)

bbg_contract = ("BBG COMMODITY - CHICAGO BOARD OF TRADE", "BLOOMBERG COMMODITY INDEX - CHICAGO BOARD OF TRADE")
bbg_df = cot_report(legacy_report(), bbg_contract) # cached, will not load the full report again
```

Lets have a look at some examples.
## Report Types

### Legacy Report (All Contracts)

Expand Down
62 changes: 53 additions & 9 deletions pycot/reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@

@lru_cache
def legacy_report(
report_type: str,
report_type: str | None = None,
contract_name: str | tuple | None = None,
) -> pd.DataFrame:
""" "
Retrieves the legacy Commitment of Traders Reports data.
Args:
report_type (str): The type of cot report to extract.
report_type (str): The type of cot report to extract.
Defaults to "legacy_futopt".
Returns:
A pandas DataFrame with the legacy futures Commitment of Traders data.
Expand All @@ -25,6 +26,8 @@ def legacy_report(
>>> from pycot.reports import legacy_report
>>> legacy_report("legacy_fut", ("FED FUNDS - CHICAGO BOARD OF TRADE", "30-DAY FEDERAL FUNDS - CHICAGO BOARD OF TRADE"))
"""
report_type = "legacy_futopt" if report_type is None else report_type

if report_type not in ["legacy_fut", "legacy_futopt"]:
raise InvalidReportType("Please use one of the following report types: ['legacy_fut', 'legacy_futopt']")

Expand All @@ -42,11 +45,15 @@ def legacy_report(

@lru_cache
def disaggregated_report(
report_type: str,
report_type: str | None = None,
contract_name: str | tuple | None = None,
) -> pd.DataFrame:
"""
Adjusted disaggregated futures and options report data.
Args:
report_type (str): The type of cot report to extract.
Defaults to "disaggregated_futopt".
Returns:
A pandas DataFrame with the disaggregated futures and options report.
Expand All @@ -55,6 +62,8 @@ def disaggregated_report(
>>> from pycot.reports import disaggregated_report
>>> disaggregated_report("disaggregated_fut", ("BRENT LAST DAY - NEW YORK MERCANTILE EXCHANGE", "BRENT CRUDE OIL LAST DAY - NEW YORK MERCANTILE EXCHANGE"))
"""
report_type = "disaggregated_futopt" if report_type is None else report_type

if report_type not in ["disaggregated_fut", "disaggregated_futopt"]:
raise InvalidReportType("Please use one of the following report types: ['disaggregated_fut', 'disaggregated_futopt']")

Expand All @@ -79,11 +88,15 @@ def disaggregated_report(

@lru_cache
def financial_report(
report_type: str,
report_type: str | None = None,
contract_name: str | tuple | None = None,
) -> pd.DataFrame:
"""
Adjusted financial futures and options report data.
Args:
report_type (str): The type of cot report to extract.
Defaults to "traders_in_financial_futures_futopt".
Returns:
A pandas DataFrame with the financial futures and options report.
Expand All @@ -92,6 +105,8 @@ def financial_report(
>>> from pycot.reports import financial_report
>>> financial_report("financial_fut", ("UST 10Y NOTE - CHICAGO BOARD OF TRADE", "10-YEAR U.S. TREASURY NOTES - CHICAGO BOARD OF TRADE", "10 YEAR U.S. TREASURY NOTES - CHICAGO BOARD OF TRADE"))
"""
report_type = "traders_in_financial_futures_futopt" if report_type is None else report_type

if report_type not in ["traders_in_financial_futures_fut", "traders_in_financial_futures_futopt"]:
raise InvalidReportType("Please use one of the following report types: ['traders_in_financial_futures_fut', 'traders_in_financial_futures_futopt']")

Expand All @@ -113,8 +128,37 @@ def financial_report(
return get_contract(df, contract_name) if contract_name else df


if __name__ == "__main__":
contract_name = ("FED FUNDS - CHICAGO BOARD OF TRADE", "30-DAY FEDERAL FUNDS - CHICAGO BOARD OF TRADE")
df = legacy_report("legacy_fut", contract_name)
print(df)
print(df.info())
def cot_report(
report: pd.DataFrame,
contract_name: str | tuple,
) -> pd.DataFrame:
"""
Retrieves data from a selected Commitment of Traders report.
Results will be cached after the first call.
Args:
report (pd.DataFrame): The report to extract data from. Must be one of the following:
- `legacy_report()`
- `disaggregated_report()`
- `financial_report()`
contract_name (str | tuple): The name of the contract to extract data from.
Returns:
A pandas DataFrame with the Commitment of Traders data.
Example:
>>> from pycot.reports import legacy_report, cot_report
>>> report = legacy_report("legacy_fut")
>>> df_1 = cot_report(report, ("FED FUNDS - CHICAGO BOARD OF TRADE", "30-DAY FEDERAL FUNDS - CHICAGO BOARD OF TRADE"))
>>> df_2 = cot_report(report, ("BBG COMMODITY - CHICAGO BOARD OF TRADE", "BLOOMBERG COMMODITY INDEX - CHICAGO BOARD OF TRADE"))
>>> ...
"""
if not isinstance(report, pd.DataFrame):
raise TypeError("report must be a pandas DataFrame")

if not isinstance(contract_name, (str, tuple)):
raise TypeError("contract_name must be a string or a tuple")

return get_contract(report, contract_name)
2 changes: 1 addition & 1 deletion pycot/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.0.6"
__version__ = "0.0.7"
25 changes: 25 additions & 0 deletions tests/test_reports.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import time

import pandas as pd
import pytest

Expand Down Expand Up @@ -54,3 +56,26 @@ def test_disaggregated_report(report_type, contract_name):
def test_financial_report(report_type, contract_name):
df = reports.financial_report(report_type, contract_name)
assert isinstance(df, pd.DataFrame)


@pytest.mark.parametrize(
"contract_1,contract_2",
[
(
("FED FUNDS - CHICAGO BOARD OF TRADE", "30-DAY FEDERAL FUNDS - CHICAGO BOARD OF TRADE"),
("BBG COMMODITY - CHICAGO BOARD OF TRADE", "BLOOMBERG COMMODITY INDEX - CHICAGO BOARD OF TRADE"),
),
],
)
def test_cot_report(contract_1, contract_2):
start_time_1 = time.perf_counter()
df_1 = reports.cot_report(reports.legacy_report(), contract_1)
end_time_1 = time.perf_counter() - start_time_1

start_time_2 = time.perf_counter()
df_2 = reports.cot_report(reports.legacy_report(), contract_2)
end_time_2 = time.perf_counter() - start_time_2

assert end_time_1 > end_time_2
assert isinstance(df_1, pd.DataFrame)
assert isinstance(df_2, pd.DataFrame)

0 comments on commit a396c8b

Please sign in to comment.