API Reference

pybrsa - A Python package for fetching data from BDDK.

fetch_bddk1(year, month, table_no, grup_kod=10001, currency='TL', lang='en', verbose=False)

Fetch monthly data from BDDK API.

Parameters

year : int 4-digit year (YYYY) month : int Month (1-12) table_no : int Table number (1-17) grup_kod : int or list of int, default 10001 Group code(s) (10001-10010) currency : str, default "TL" Currency code ("TL" or "USD") lang : str, default "en" Language ("en" or "tr")

Returns

pd.DataFrame DataFrame with fetched data and fetch_info in attrs

Examples

Single group code

df = fetch_bddk1(2020, 3, 1, grup_kod=10001) df.shape (82, 12)

Multiple group codes

df = fetch_bddk1(2020, 3, 1, grup_kod=[10001, 10002]) len(df['grup_kod'].unique()) 2

Turkish language output

df = fetch_bddk1(2020, 3, 1, grup_kod=10001, lang="tr") 'Yıl' in df.columns # Turkish column names True

See Also

fetch_finturk1 : For quarterly province-level data.

Source code in pybrsa/fetch_bddk.py
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
def fetch_bddk1(
    year: int, 
    month: int, 
    table_no: int, 
    grup_kod: Union[int, List[int]] = 10001,
    currency: str = "TL", 
    lang: str = "en",
    verbose: bool = False
) -> pd.DataFrame:
    """
    Fetch monthly data from BDDK API.

    Parameters
    ----------
    year : int
        4-digit year (YYYY)
    month : int
        Month (1-12)
    table_no : int
        Table number (1-17)
    grup_kod : int or list of int, default 10001
        Group code(s) (10001-10010)
    currency : str, default "TL"
        Currency code ("TL" or "USD")
    lang : str, default "en"
        Language ("en" or "tr")

    Returns
    -------
    pd.DataFrame
        DataFrame with fetched data and fetch_info in attrs

    Examples
    --------
    >>> # Single group code
    >>> df = fetch_bddk1(2020, 3, 1, grup_kod=10001)
    >>> df.shape
    (82, 12)

    >>> # Multiple group codes
    >>> df = fetch_bddk1(2020, 3, 1, grup_kod=[10001, 10002])
    >>> len(df['grup_kod'].unique())
    2

    >>> # Turkish language output
    >>> df = fetch_bddk1(2020, 3, 1, grup_kod=10001, lang="tr")
    >>> 'Yıl' in df.columns  # Turkish column names
    True

    See Also
    --------
    fetch_finturk1 : For quarterly province-level data.        
    """
    base_url = f"https://www.bddk.org.tr/BultenAylik/{lang}/Home/BasitRaporGetir"

    params = [
        ("tabloNo", str(table_no)),
        ("yil", str(year)),
        ("ay", str(month)),
        ("paraBirimi", currency)
    ]

    # Handle single or multiple grup_kod
    if isinstance(grup_kod, int):
        grup_kod = [grup_kod]

    for kod in grup_kod:
        params.append(("taraf", str(kod)))  

    try:
        response = requests.post(base_url, data=params, timeout=30)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        raise Exception(f"HTTP error: {e}")

    parsed = response.json()
    if not parsed.get("success", False):
        raise Exception("API reported unsuccessful request")

    df = parse_json(parsed.get("Json", {}))

    if df.empty:
        warnings.warn(
            f"No data for table {table_no}, {year}-{month:02d}, "
            f"grup_kod {grup_kod}"
        )
        return pd.DataFrame()

    if len(df.columns) > 0:
        df = df.rename(columns={df.columns[0]: "group_name"})

    df = df.reset_index(drop=True)
    group_rle = []
    current_name = None
    count = 0

    for name in df["group_name"]:
        if name != current_name:
            if current_name is not None:
                group_rle.append((current_name, count))
            current_name = name
            count = 1
        else:
            count += 1

    if current_name is not None:
        group_rle.append((current_name, count))

    grup_kod_series = []
    for i, (name, length) in enumerate(group_rle):
        kod = grup_kod[i % len(grup_kod)] if len(grup_kod) > i else grup_kod[-1]
        grup_kod_series.extend([kod] * length)

    df["grup_kod"] = grup_kod_series
    df["period"] = f"{year}-{month:02d}"
    df["currency"] = currency

    # Store fetch info in DataFrame attributes
    df.attrs["fetch_info"] = {
        "start_date": f"{year}-{month:02d}",
        "end_date": f"{year}-{month:02d}",
        "table_no": table_no,
        "currency": currency,
        "grup_kod": grup_kod,
        "lang": lang
    }

    return df

fetch_finturk1(year, month, table_no, grup_kod=10001, il=0, verbose=False)

Fetch quarterly data from BDDK Finturk API.

Parameters

year : int 4-digit year (YYYY) month : int Month (3, 6, 9, 12 for quarterly data) table_no : int Table number (1-7) grup_kod : int or list of int, default 10001 Group code(s) (10001-10007) il : int or list of int, default 0 Plate number(s) (0-81; 999 = Yurt Dışı)

Returns

pd.DataFrame DataFrame with fetched data and fetch_info in attrs

Examples

Single group, all provinces

df = fetch_finturk1(2020, 3, 1, grup_kod=10001) 'il_adi' in df.columns True

Multiple groups and specific provinces

df = fetch_finturk1(2020, 3, 1, grup_kod=[10006, 10007], il=[6, 34]) set(df['grup_kod'].astype(int).unique()) == {10006, 10007} True

Single group, single province

df = fetch_finturk1(2020, 3, 1, grup_kod=10001, il=34) df['il_adi'].iloc[0] 'İSTANBUL'

See Also

fetch_bddk1 : For monthly data without province granularity.

Source code in pybrsa/fetch_finturk.py
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
def fetch_finturk1(
    year: int,
    month: int,
    table_no: int,
    grup_kod: Union[int, List[int]] = 10001,
    il: Union[int, List[int]] = 0,
    verbose: bool = False  
) -> pd.DataFrame:
    """
    Fetch quarterly data from BDDK Finturk API.

    Parameters
    ----------
    year : int
        4-digit year (YYYY)
    month : int
        Month (3, 6, 9, 12 for quarterly data)
    table_no : int
        Table number (1-7)
    grup_kod : int or list of int, default 10001
        Group code(s) (10001-10007)
    il : int or list of int, default 0
        Plate number(s) (0-81; 999 = Yurt Dışı)

    Returns
    -------
    pd.DataFrame
        DataFrame with fetched data and fetch_info in attrs

     Examples
    --------
    >>> # Single group, all provinces
    >>> df = fetch_finturk1(2020, 3, 1, grup_kod=10001)
    >>> 'il_adi' in df.columns
    True

    >>> # Multiple groups and specific provinces
    >>> df = fetch_finturk1(2020, 3, 1, grup_kod=[10006, 10007], il=[6, 34])
    >>> set(df['grup_kod'].astype(int).unique()) == {10006, 10007}
    True

    >>> # Single group, single province
    >>> df = fetch_finturk1(2020, 3, 1, grup_kod=10001, il=34)
    >>> df['il_adi'].iloc[0]
    'İSTANBUL'

    See Also
    --------
    fetch_bddk1 : For monthly data without province granularity.              
    """
    if month not in [3, 6, 9, 12]:
        raise ValueError("Finturk requires quarterly months (3, 6, 9, 12)")

    if isinstance(grup_kod, int):
        grup_kod = [grup_kod]
    if isinstance(il, int):
        il = [il]

    grup_kod = [str(kod) for kod in grup_kod]
    city_names = plaka_to_city(il)

    base_url = "https://www.bddk.org.tr/BultenFinturk/tr/Home/VeriGetir"

    data = {
        "tabloNo": str(table_no),
        "donem": f"{year}-{month}"
    }

    for i, kod in enumerate(grup_kod):
        data[f"tarafList[{i}]"] = kod

    for i, city in enumerate(city_names):
        data[f"sehirList[{i}]"] = city

    headers = {
        "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
        "X-Requested-With": "XMLHttpRequest",
        "Referer": "https://www.bddk.org.tr/BultenFinturk"
    }

    try:
        response = requests.post(base_url, data=data, headers=headers, timeout=30)
        response.raise_for_status()
    except requests.exceptions.RequestException as e:
        raise Exception(f"HTTP error: {e}")

    parsed = response.json()
    if not parsed.get("success", False):
        warnings.warn("API reported unsuccessful request")
        return pd.DataFrame()

    df = parse_json(parsed.get("Json", {}))

    if df.empty:
        warnings.warn(f"No data for table {table_no}, {year}-{month:02d}")
        return pd.DataFrame()

    if "Eftodu" in df.columns:
        df = df.rename(columns={"Eftodu": "grup_kod"})


    current_cols = list(df.columns)
    for i, col in enumerate(current_cols):
        if re.fullmatch(r'Şehir', col, re.IGNORECASE):
            current_cols[i] = 'il_adi'
    df.columns = current_cols

    city_to_plaka = dict(zip(cities["il"], cities["plaka"]))
    df["plaka"] = df["il_adi"].map(city_to_plaka)

    df["grup_kod"] = df["grup_kod"].astype(str)
    df["period"] = f"{year}-{month:02d}"
    df["table_no"] = str(table_no)

    # Store fetch info
    df.attrs["fetch_info"] = {
        "start_date": f"{year}-{month:02d}",
        "end_date": f"{year}-{month:02d}",
        "table_no": table_no,
        "grup_kod": grup_kod,
        "il": il,
        "cities": city_names
    }

    return df

list_cities()

List available cities for Finturk quarterly data with plaka numbers.

Returns

pd.DataFrame DataFrame with columns 'plaka' and 'il'

Examples

import pybrsa df = pybrsa.list_cities() print(df.head())

Source code in pybrsa/info.py
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def list_cities() -> pd.DataFrame:
    """
    List available cities for Finturk quarterly data with plaka numbers.

    Returns
    -------
    pd.DataFrame
        DataFrame with columns 'plaka' and 'il'

    Examples
    --------
    >>> import pybrsa
    >>> df = pybrsa.list_cities()
    >>> print(df.head())
    """
    print("\nAvailable cities for Finturk quarterly data")
    print("Use license plate number (plaka) in fetch_finturk functions:")
    print("Valid values: 0 (HEPSI/ALL), 1-81, 999 (YURT DISI/ABROAD)\n")


    df = cities[['plaka', 'il']].copy()
    print(df.to_string(index=False))

    return df

list_groups(source='bddk', lang='en')

List available banking groups for a data source.

Parameters

source : str, default "bddk" Either "bddk" or "finturk" lang : str, default "en" Either "tr" or "en" for names

Returns

pd.DataFrame DataFrame with columns 'Group_Code' and 'Name'

Examples

import pybrsa df = pybrsa.list_groups("bddk") df = pybrsa.list_groups("finturk", "tr")

Source code in pybrsa/info.py
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def list_groups(source: str = "bddk", lang: str = "en") -> pd.DataFrame:
    """
    List available banking groups for a data source.

    Parameters
    ----------
    source : str, default "bddk"
        Either "bddk" or "finturk"
    lang : str, default "en"
        Either "tr" or "en" for names

    Returns
    -------
    pd.DataFrame
        DataFrame with columns 'Group_Code' and 'Name'

    Examples
    --------
    >>> import pybrsa
    >>> df = pybrsa.list_groups("bddk")
    >>> df = pybrsa.list_groups("finturk", "tr")
    """
    source = source.lower()
    lang = lang.lower()

    if source not in ["bddk", "finturk"]:
        raise ValueError("source must be either 'bddk' or 'finturk'")
    if lang not in ["en", "tr"]:
        raise ValueError("lang must be either 'en' or 'tr'")

    if source == "bddk":
        groups = bddk_groups
        name_col = "name_tr" if lang == "tr" else "name_en"
    else:  # finturk
        groups = finturk_groups
        name_col = "name_tr" if lang == "tr" else "name_en"

    df = groups[['grup_kod', name_col]].copy()
    df.columns = ['Group_Code', 'Name']

    print(f"\nAvailable banking groups for {source} data:\n")
    print(df.to_string(index=False))

    return df

list_tables(source='bddk', lang='en')

List available tables for a data source.

Parameters

source : str, default "bddk" Either "bddk" or "finturk" lang : str, default "en" Either "tr" or "en" for table titles

Returns

pd.DataFrame DataFrame with columns 'Table_No' and 'Title'

Examples

import pybrsa df = pybrsa.list_tables("bddk") df = pybrsa.list_tables("finturk", "tr")

Source code in pybrsa/info.py
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
def list_tables(source: str = "bddk", lang: str = "en") -> pd.DataFrame:
    """
    List available tables for a data source.

    Parameters
    ----------
    source : str, default "bddk"
        Either "bddk" or "finturk"
    lang : str, default "en"
        Either "tr" or "en" for table titles

    Returns
    -------
    pd.DataFrame
        DataFrame with columns 'Table_No' and 'Title'

    Examples
    --------
    >>> import pybrsa
    >>> df = pybrsa.list_tables("bddk")
    >>> df = pybrsa.list_tables("finturk", "tr")
    """
    source = source.lower()
    lang = lang.lower()

    if source not in ["bddk", "finturk"]:
        raise ValueError("source must be either 'bddk' or 'finturk'")
    if lang not in ["en", "tr"]:
        raise ValueError("lang must be either 'en' or 'tr'")

    if source == "bddk":
        tables = bddk_tables
        title_col = "title_tr" if lang == "tr" else "title_en"
    else:  # finturk
        tables = finturk_tables
        title_col = "title_tr" if lang == "tr" else "title_en"

    df = tables[['table_no', title_col]].copy()
    df.columns = ['Table_No', 'Title']

    print(f"\nAvailable tables for {source} data:\n")
    print(df.to_string(index=False))

    return df

save_data(df, filename=None, format='pkl')

Save fetched data to multiple formats.

Parameters

df : pd.DataFrame DataFrame to save filename : str Required. A non-empty string (without extension) must be provided. format : str, default "pkl" Output format: "pkl", "csv", or "xlsx"

Returns

str Full file path with extension

Examples

import pybrsa import tempfile

df = pybrsa.fetch_bddk1(2024, 1, table_no=1) temp_path = tempfile_base() saved_path = pybrsa.save_data(df, temp_path, format="csv")

Source code in pybrsa/io.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def save_data(
    df: pd.DataFrame,
    filename: str = None,
    format: str = "pkl"
) -> str:
    """
    Save fetched data to multiple formats.

    Parameters
    ----------
    df : pd.DataFrame
        DataFrame to save
    filename : str
         **Required**. A non-empty string (without extension) must be provided.
    format : str, default "pkl"
        Output format: "pkl", "csv", or "xlsx"

    Returns
    -------
    str
        Full file path with extension

    Examples
    --------
    >>> import pybrsa
    >>> import tempfile

    >>> df = pybrsa.fetch_bddk1(2024, 1, table_no=1)
    >>> temp_path = tempfile_base()
    >>> saved_path = pybrsa.save_data(df, temp_path, format="csv")
    """
    valid_formats = ["pkl", "csv", "xlsx"]
    if format not in valid_formats:
        raise ValueError(
            f"Invalid format. Must be one of: {', '.join(valid_formats)}")
    if filename is None or filename == "":
        raise ValueError("Argument 'filename' is required and cannot be empty")

    # Add extension
    filename = f"{filename}.{format}"

    if format == "csv":
        df.to_csv(filename, index=False)
    elif format == "xlsx":
        df.to_excel(filename, index=False)
    elif format == "pkl":
        df.to_pickle(filename)

    print(f"Data saved to {filename}")
    return filename

tempfile_base()

Create a temporary file base name without extension.

Equivalent to R's tempfile() function.

Returns

str Temporary file path without extension

Examples

temp_path = tempfile_base()

Use with save_data

pybrsa.save_data(df, temp_path, format="csv")

Source code in pybrsa/io.py
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def tempfile_base() -> str:
    """
    Create a temporary file base name without extension.

    Equivalent to R's tempfile() function.

    Returns
    -------
    str
        Temporary file path without extension

    Examples
    --------
    >>> temp_path = tempfile_base()
    >>> # Use with save_data
    >>> pybrsa.save_data(df, temp_path, format="csv")
    """
    with tempfile.NamedTemporaryFile() as tmp:
        # Get path and remove any potential extension
        base = tmp.name.rsplit('.', 1)[0] if '.' in tmp.name else tmp.name
        return base

:::