Source code for macrosynergy.download.transaction_costs

import datetime
import pandas as pd
import warnings
import requests
from typing import List
from macrosynergy.management.types import QuantamentalDataFrame
from macrosynergy.management.utils import get_cid, get_xcat
from io import StringIO

MAX_RETRIES = 3
TRANSACTION_COSTS_FILE_URL = "https://macrosynergy-trading-costs.s3.eu-west-2.amazonaws.com/transaction-costs.parquet"


def _request_wrapper(url: str, verbose: bool = True, **kwargs) -> str:
    """
    Wrapper around `requests.get` to handle errors and retries.
    Any additional keyword arguments are passed to `requests.get`. Purpose is to allow
    users to pass additional headers, proxy settings, cert verification, etc.
    """

    if verbose:
        print(f"Requesting data from {url}")

    for _ in range(MAX_RETRIES):
        try:
            r = requests.get(url, **kwargs)
            r.raise_for_status()
            return r.text
        except requests.exceptions.RequestException as e:
            if verbose:
                print(f"Error downloading {url}: {e}")
            continue
    raise requests.exceptions.RequestException(f"Failed to download {url}")


AVAILABLE_CTYPES: List[str] = ["FX", "IRS", "CDS"]
AVAIALBLE_COSTS: List[str] = ["BIDOFFER", "ROLLCOST", "SIZE"]
AVAILABLE_STATS: List[str] = ["MEDIAN", "90PCTL"]
AVAILABLE_CATS: List[str] = [
    f"{c}{t}_{s}"
    for c in AVAILABLE_CTYPES
    for t in AVAIALBLE_COSTS
    for s in AVAILABLE_STATS
]

VALID_FILE_FORMATS: List[str] = ["auto", "csv", "parquet"]

[docs]def download_transaction_costs( file_url: str = TRANSACTION_COSTS_FILE_URL, verbose: bool = False, categorical: bool = False, file_format: str = "auto", **kwargs, ) -> QuantamentalDataFrame: """ Download trading costs data from the S3 bucket. Parameters ---------- file_url : str URL of the file to download. If the file format is "auto", the function will try to infer the file format from the URL extension. verbose : bool Print progress information. file_format : str Format of the file to download. Default is "auto", where the function will try to infer the format from the URL extension. Supported formats are "csv" and "parquet". **kwargs : args Additional keyword arguments to pass to `requests.get`. This can be used to pass additional headers, proxy settings, cert verification, etc. """ if file_url is None or not isinstance(file_url, str): raise ValueError(f"Invalid file URL provided: {file_url}") if verbose: print(f"Timestamp (UTC): {datetime.datetime.now(datetime.timezone.utc)}") print(f"Downloading trading costs data from {file_url}") file_format = file_format.lower() if file_format == "csv" or (file_format == "auto" and file_url.endswith(".csv")): dfd: pd.DataFrame = pd.read_csv( StringIO(_request_wrapper(file_url, **kwargs)), parse_dates=["real_date"], ) elif file_format == "parquet" or ( file_format == "auto" and file_url.endswith(".parquet") ): dfd: pd.DataFrame = pd.read_parquet(file_url) else: raise ValueError( f"Invalid file format provided: {file_format}. " f"Supported formats are: {VALID_FILE_FORMATS}" ) dfd["cid"], dfd["xcat"] = get_cid(dfd["ticker"]), get_xcat(dfd["ticker"]) dfd = dfd[QuantamentalDataFrame.IndexCols + ["value"]] if not isinstance(dfd, pd.DataFrame) or dfd.empty: raise ValueError("Failed to download trading costs data") if not isinstance(dfd, QuantamentalDataFrame): if verbose: warnings.warn( "Downloaded data could not be converted to QuantamentalDataFrame", UserWarning, ) else: if verbose: print("Downloaded data and transformed data successfully") dfd = QuantamentalDataFrame(dfd, categorical=categorical) return dfd
if __name__ == "__main__": print(download_transaction_costs(verbose=True).head())