Estimating EM sovereign risk premia #

Get packages and JPMaQS data #

Setup and imports #

# !pip install macrosynergy --upgrade
DQ_CLIENT_ID: str = "your_client_id"
DQ_CLIENT_SECRET: str = "your_client_secret"
# Constants and credentials
import os

REQUIRED_VERSION: str = "1.2.2"
DQ_CLIENT_ID: str = os.getenv("DQ_CLIENT_ID")
DQ_CLIENT_SECRET: str = os.getenv("DQ_CLIENT_SECRET")
PROXY = {}  # Configure if behind corporate firewall
START_DATE: str = "1998-01-01"
import macrosynergy as msy

msy.check_package_version(required_version=REQUIRED_VERSION)
# If version check fails: pip install macrosynergy --upgrade
if not DQ_CLIENT_ID or not DQ_CLIENT_SECRET:
    raise ValueError(
        "Missing DataQuery credentials." \
        "Please set DQ_CLIENT_ID and DQ_CLIENT_SECRET as environment variables or insert them directly in the notebook."
    )
import numpy as np
import pandas as pd
from pandas import Timestamp
import matplotlib.pyplot as plt
import os
import io

from datetime import datetime

import macrosynergy.management as msm
import macrosynergy.panel as msp
import macrosynergy.signal as mss
import macrosynergy.pnl as msn
import macrosynergy.visuals as msv

from macrosynergy.download import JPMaQSDownload
from macrosynergy.panel.adjust_weights import adjust_weights
import warnings

pd.set_option('display.width', 400)

warnings.simplefilter("ignore")

Data selection and download #

cids_fc_latam = [  # Latam foreign currency debt countries
    "BRL",
    "CLP",
    "COP",
    "DOP",
    "MXN",
    "PEN",
    "UYU",
]
cids_fc_emeu = [  # EM Europe foreign currency debt countries
    "HUF",
    "PLN",
    "RON",
    "RUB",
    "RSD",
    "TRY",
]
cids_fc_meaf = [  # Middle-East and Africa foreign currency debt countries
    "AED",
    "EGP",
    "NGN",
    "OMR",
    "QAR",
    "ZAR",
    "SAR",
]
cids_fc_asia = [  # Asia foreign currency debt countries
    "CNY",
    "IDR",
    "INR",
    "PHP",
]

cids_fc = sorted(
    list(
        set(cids_fc_latam + cids_fc_emeu + cids_fc_meaf + cids_fc_asia)
    )
)
cids_emxfc = ["CZK", "ILS", "KRW", "MYR", "SGD", "THB", "TWD"]

cids_em = sorted(cids_fc + cids_emxfc)
# Category tickers

# Features
govfin = [
    "GGOBGDPRATIO_NSA",
    "GGOBGDPRATIONY_NSA",
    "GGDGDPRATIO_NSA",
]

xbal = [
    "CABGDPRATIO_NSA_12MMA",
    "MTBGDPRATIO_NSA_12MMA",
]

xliab = [
    "NIIPGDP_NSA_D1Mv2YMA",
    "NIIPGDP_NSA_D1Mv5YMA",
    "IIPLIABGDP_NSA_D1Mv2YMA",
    "IIPLIABGDP_NSA_D1Mv5YMA",
]

xdebt = [
    "ALLIFCDSGDP_NSA",
    "GGIFCDSGDP_NSA",
]

GOVRISK = [
    "ACCOUNTABILITY_NSA",
    "POLSTAB_NSA",
    "CORRCONTROL_NSA",
]
growth = [
    'RGDP_SA_P1Q1QL4_20QMA',
    "RGDP_SA_P1Q1QL4"
] 

infl = [
    "CPIC_SA_P1M1ML12",
    "CPIH_SA_P1M1ML12",
]
 

risk_metrics = [
    "LTFCRATING_NSA",
    "LTLCRATING_NSA",
    "FCBICRY_NSA",
    "FCBICRY_VT10",
    "CDS05YSPRD_NSA",
    "CDS05YXRxEASD_NSA",
]

# Targets

rets = ["FCBIR_NSA", "FCBIXR_NSA", "FCBIXR_VT10"]

# Benchmark returns

bms = ["USD_EQXR_NSA", "UHY_CRXR_NSA", "UIG_CRXR_NSA"]

# Create ticker list

xcats = govfin + xbal + xliab + xdebt + GOVRISK + growth + infl + risk_metrics + rets
tickers = [cid + "_" + xcat for cid in cids_em for xcat in xcats] + bms

print(f"Maximum number of tickers is {len(tickers)}")
Maximum number of tickers is 840
# Download macro-quantamental indicators from JPMaQS via the DataQuery API

with JPMaQSDownload(
    client_id=DQ_CLIENT_ID, 
    client_secret=DQ_CLIENT_SECRET,
    proxy=PROXY
) as downloader:
    df: pd.DataFrame = downloader.download(
        tickers=tickers,
        start_date=START_DATE,
        metrics=["value",],
        suppress_warning=True,
        show_progress=True,
        report_time_taken=True,
        get_catalogue=True,
    )
Downloading the JPMAQS catalogue from DataQuery...
Downloaded JPMAQS catalogue with 23224 tickers.
Removed 82/840 expressions that are not in the JPMaQS catalogue.
Downloading data from JPMaQS.
Timestamp UTC:  2025-07-11 11:05:55
Connection successful!
Requesting data: 100%|██████████| 38/38 [00:07<00:00,  4.92it/s]
Downloading data: 100%|██████████| 38/38 [00:32<00:00,  1.15it/s]
Time taken to download data: 	42.53 seconds.
Some expressions are missing from the downloaded data. Check logger output for complete list.
1 out of 758 expressions are missing. To download the catalogue of all available expressions and filter the unavailable expressions, set `get_catalogue=True` in the call to `JPMaQSDownload.download()`.
# Preserve original downloaded data for debugging and comparison
dfx = df.copy()
dfx.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4680163 entries, 0 to 4680162
Data columns (total 4 columns):
 #   Column     Dtype         
---  ------     -----         
 0   real_date  datetime64[ns]
 1   cid        object        
 2   xcat       object        
 3   value      float64       
dtypes: datetime64[ns](1), float64(1), object(2)
memory usage: 142.8+ MB

Availability checks and blacklisting #

Availability #

xcatx = govfin
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/b56fbf28e87509714e868e7cfcbf62439331d3ff407151041bc701d2592b70d1.png
xcatx = xbal
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/ab05e39441e1ba458ba42f57e448b959455066b586120df9bad98a66520fd5ac.png
xcatx = xliab
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/43bc953c36506ae40ff3dd9fae94b3518ca46229d580a44e767a84943868a911.png
xcatx = xdebt
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/d54483f26d7a1492053dfdddd3bca6ef0497b288af70576b098c5d70bd695177.png
xcatx = risk_metrics
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/610b53b4badeed799c33a4e023a5cfcb46c708a126869c9615888451ef6a8e63.png
xcatx = rets
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/3aeaea5523904061541e73b150585beee99e694f1afb8385d15a60a90282e909.png
xcatx = growth
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/7b172150c0a595c1bee80f07c026569b46acb6703c532e3e18acac622ad20eb6.png
xcatx = infl
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/cf420a58677ebb28a3c9643060b10005fb7c51d202f872016d136dd6add22d28.png

Blacklist #

black_fc = {'RUB': [Timestamp('2022-02-01 00:00:00'), Timestamp('2035-02-26 00:00:00')]}

Macro risk score construction and checks #

Preparatory transformations #

# Non-linear inflation effect theory

x = np.linspace(-5, 100, 100)
y = np.power(abs(x - 2), 1/2)

plt.figure(figsize=(12, 4))
plt.plot(x, y)
plt.title("Inflation and presumed effect on sovereign default risk")
plt.xlabel("Inflation")
plt.ylabel("Presumed impact on default risk")
plt.grid(True)
plt.show()
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/e25663e2f40de7dcd8355d083b494472d24c51f62849192d317f4581398dc925.png
# Inflation effects

cidx = cids_fc
xcx = ["CPIH", "CPIC"]

calcs = [
    f"{xc}_IE = {xc}_SA_P1M1ML12.applymap(lambda x: np.power(abs(x - 2), 1/2))"
    for xc in xcx
]
dfa = msp.panel_calculator(dfx, calcs=calcs, cids=cidx)
dfx = msm.update_df(dfx, dfa)


xcatx = ["CPIH_IE", "CPIH_SA_P1M1ML12"]


msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start="2000-01-01",
    title='CPI comparison - square function vs standard inflation change',
    aspect=2,
    same_y=False,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/02fd9d20810d85314352191e473764d718e478873851784b6c30690eb899d5cb.png

Macro risk scores #

Conceptual factor scores #

# Placeholder dictionaries

dict_factz = {}
dict_labels = {}
# Governing dictionary of quantamental indicators, neutral levels, and weightings

dict_macros = {
    "GFINRISK":{
        "GGOBGDPRATIO_NSA": ["median", "NEG", 1/3],
        "GGOBGDPRATIONY_NSA": ["median", "NEG", 1/3],
        "GGDGDPRATIO_NSA": ["median", "", 1/3],
    },
    "XBALRISK":{
        "CABGDPRATIO_NSA_12MMA": ["median", "NEG", 0.5],
        "MTBGDPRATIO_NSA_12MMA": ["median", "NEG", 0.5],
    },
    "XLIABRISK":{
        "NIIPGDP_NSA_D1Mv2YMA": ["median", "NEG", 0.25],
        "NIIPGDP_NSA_D1Mv5YMA": ["median", "NEG", 0.25],
        "IIPLIABGDP_NSA_D1Mv2YMA": ["median", "", 0.25],
        "IIPLIABGDP_NSA_D1Mv5YMA": ["median", "", 0.25],
    },
    "XDEBTRISK":{
        "ALLIFCDSGDP_NSA": ["median", "", 0.5],
        "GGIFCDSGDP_NSA": ["median", "", 0.5],
    },
    "GOVRISK":{
        "ACCOUNTABILITY_NSA": ["median", "NEG", 1/3],
        "POLSTAB_NSA": ["median", "NEG", 1/3],
        "CORRCONTROL_NSA": ["median", "NEG", 1/3],
    },
    "GROWTHRISK":{
        "RGDP_SA_P1Q1QL4_20QMA": ["median", "NEG", 0.5],
        "RGDP_SA_P1Q1QL4": ["median", "NEG", 0.5],
    },
    "INFLRISK":{
        "CPIH_IE": ["median", "", 0.5],
        "CPIC_IE": ["median", "", 0.5],
    }
}
# Normalize all macro-quantamental categories based on the broad EM set

cidx = cids_em

for fact in dict_macros.keys():
    
    dict_fact = dict_macros[fact]
    xcatx = list(dict_fact.keys())

    dfa = pd.DataFrame(columns=list(dfx.columns))

    for xc in xcatx:

        postfix = dict_fact[xc][1]
        neutral = dict_fact[xc][0]

        dfaa = msp.make_zn_scores(
            dfx,
            xcat=xc,
            cids=cidx,
            sequential=True,
            min_obs=261 * 3,
            neutral=neutral,
            pan_weight=1,
            thresh=3,
            postfix="_" + postfix + "ZN",
            est_freq="m",
        )
        dfaa["value"] = dfaa["value"] * (1 if postfix == "" else -1)
        dfa = msm.update_df(dfa, dfaa)

    dict_factz[fact] = dfa["xcat"].unique()
    dfx = msm.update_df(dfx, dfa)
# Combine quantamental scores to conceptual scores

cidx = cids_em

for key, value in dict_factz.items():

    weights = [w[2] for w in list(dict_macros[key].values())]
    dfa = msp.linear_composite(
        dfx,
        xcats=value,
        cids=cidx,
        weights=weights,
        normalize_weights= True,
        complete_xcats=False,
        new_xcat=key,
    )

    dfx = msm.update_df(dfx, dfa)

for key in dict_factz.keys():

    dfa = msp.make_zn_scores(
        dfx,
        xcat=key,
        cids=cidx,
        sequential=True,
        min_obs=261 * 3,
        neutral="zero",
        pan_weight=1,
        thresh=3,
        postfix="_ZN",
        est_freq="m",
    )
    
    dfx = msm.update_df(dfx, dfa)

macroz = [fact + "_ZN" for fact in dict_factz.keys()]
dict_labels["GGOBGDPRATIO_NSA_NEGZN"] = "Excess government balance, % of GDP, current year, negative"
dict_labels["GGOBGDPRATIONY_NSA_NEGZN"] = "Excess government balance, % of GDP, next year, negative"
dict_labels["GGDGDPRATIO_NSA_ZN"] = "Excess general government debt ratio, % of GDP"

dict_labels["GFINRISK_ZN"] = "Government finances risk score"

dict_labels["CABGDPRATIO_NSA_12MMA_NEGZN"] = "Current account balance, 12mma, % of GDP, negative"
dict_labels["MTBGDPRATIO_NSA_12MMA_NEGZN"] = "Merchandise trade balance, 12mma, % of GDP, negative"

dict_labels["XBALRISK_ZN"] = "External balances risk score"

dict_labels["IIPLIABGDP_NSA_D1Mv2YMA_ZN"] = "International liabilities, vs. 2yma, % of GDP"
dict_labels["IIPLIABGDP_NSA_D1Mv5YMA_ZN"] = "International liabilities, vs. 5yma, % of GDP"
dict_labels["NIIPGDP_NSA_D1Mv2YMA_NEGZN"] = "Net international investment position, vs. 2yma, % of GDP, negative"
dict_labels["NIIPGDP_NSA_D1Mv5YMA_NEGZN"] = "Net international investment position, vs. 5yma, % of GDP, negative"

dict_labels["XLIABRISK_ZN"] = "International position risk score"

dict_labels["ALLIFCDSGDP_NSA_NEGZN"] = "Excess foreign-currency debt securities, all, % of GDP, negative"
dict_labels["GGIFCDSGDP_NSA_NEGZN"] = "Excess foreign-currency debt securities, government, % of GDP, negative"

dict_labels["XDEBTRISK_ZN"] = "Foreign-currency debt risk score"

dict_labels["ACCOUNTABILITY_NSA_NEGZN"] = "Voice and accountability index, z-score"
dict_labels["POLSTAB_NSA_NEGZN"] = "Political stability and absence of violence/terrorism index, z-score"
dict_labels["CORRCONTROL_NSA_NEGZN"] = "Corruption control index, z-score"

dict_labels['GOVRISK_ZN'] = 'Governance risk score'

dict_labels["RGDP_SA_P1Q1QL4_20QMA_NEGZN"] = "Real GDP growth, percentage over a year ago, z-score, negative"
dict_labels["RGDP_SA_P1Q1QL4_NEGZN"] = "Real GDP growth, percentage over a year ago, z-score"

dict_labels['GROWTHRISK_ZN'] = "Growth risk score"

dict_labels["CPIH_IE_NEGZN"] = "Headline CPI inflation effect, z-score"
dict_labels["CPIC_IE_NEGZN"] = "Core CPI inflation effect, z-score"

dict_labels["INFLRISK_ZN"] = "Inflation risk score"
dict_countries = {
    'AED': 'United Arab Emirates',
    'BRL': 'Brazil',
    'CLP': 'Chile',
    'CNY': 'China',
    'COP': 'Colombia',
    'DOP': 'Dominican Republic',
    'EGP': 'Egypt',
    'HUF': 'Hungary',
    'IDR': 'Indonesia',
    'INR': 'India',
    'MXN': 'Mexico',
    'NGN': 'Nigeria',
    'OMR': 'Oman',
    'PEN': 'Peru',
    'PHP': 'Philippines',
    'PLN': 'Poland',
    'QAR': 'Qatar',
    'RON': 'Romania',
    'RSD': 'Serbia',
    'RUB': 'Russia',
    'SAR': 'Saudi Arabia',
    'TRY': 'Turkey',
    'UYU': 'Uruguay',
    'ZAR': 'South Africa'
}
# Box for quantamental score review

factor = "XBALRISK"   # "GFINRISK" "XBALRISK" "XLIABRISK" "XDEBTRISK" "GOVRISK" "GROWTHRISK" "INFLRISK"
xcatx = list(dict_factz[factor])
cidx = cids_fc
sdate = "2000-01-01"

msp.view_ranges(
    dfx,
    xcats=xcatx,
    kind="bar",
    sort_cids_by="mean",  # countries sorted by mean of the first category
    start=sdate,
    xcat_labels=dict_labels,
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=True,
    aspect=2,
    xcat_labels=dict_labels,
    cid_labels=dict_countries,
    title=None,
    title_fontsize=22,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/4f82ed3ae2d223ac6628a7217711e65e1bd7adf4ba88ad0fdc8fe7ead6563c13.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/e195aa9fb05e91f3266cf06f4c27de59e1bb0ee4334aab905aea6ffd2fd48f74.png
xcatx = macroz
cidx = cids_fc
sdate = "2000-01-01"

msp.view_ranges(
    dfx,
    xcats=xcatx,
    kind="bar",
    sort_cids_by=None,
    start=sdate,
    xcat_labels=dict_labels,
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=True,
    aspect=2,
    xcat_labels=dict_labels,
    cid_labels=dict_countries,
    title="Macro scores related to sovereign debt default risk (higher score means higher risk)",
    title_fontsize=25,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/a147db721f270a6c772a600282057d0a63124b914292b9f309276ad0249c66d8.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/f39ff69f104668431c7a86e1e44b233f1118aaa7c3958b677131f0eb614e38b4.png

Composite macro risk scores #

# Custom weights

dict_custom_weights = {
    'GFINRISK_ZN': 1,
    'XBALRISK_ZN': 1,
    'XLIABRISK_ZN': 1,
    'XDEBTRISK_ZN': 0.001,
    'GOVRISK_ZN': 1,
    'GROWTHRISK_ZN': 0.001,
    'INFLRISK_ZN': 0.001,
}

reduced_dict_custom_weights = {
    'GFINRISK_ZN': 1,
    'XBALRISK_ZN': 1,
    'XLIABRISK_ZN': 1,
    'GOVRISK_ZN': 1
}
# Weighted composite macro risk scores

cidx = cids_fc
xcatx = macroz

reduced_macroz = ['GFINRISK_ZN', 'XBALRISK_ZN', 'XLIABRISK_ZN', 'GOVRISK_ZN']

equal_weights = [1/len(macroz)] * len(macroz)
reduced_custom_weights = [reduced_dict_custom_weights[m] for m in reduced_macroz]

weights = {
    "EWS": (macroz, equal_weights),
    "CWS": (reduced_macroz, reduced_custom_weights),
}

# Step 4: Loop through
for k, (xcat_list, weight_list) in weights.items():
    dfa = msp.linear_composite(
        dfx,
        xcats=xcat_list,
        cids=cids_fc,
        weights=weight_list,
        normalize_weights=True,
        complete_xcats=False,
        new_xcat="MACRORISK_" + k,
    )
    dfx = msm.update_df(dfx, dfa)

# Re-scoring the composites

for m in ['MACRORISK_EWS', 'MACRORISK_CWS']:
    dfa = msp.make_zn_scores(
        dfx,
        xcat=m,
        cids=cidx,
        sequential=True,
        min_obs=261 * 3,
        neutral="zero",
        pan_weight=1,
        thresh=3,
        postfix="_ZN",
        est_freq="m",
    )
    
    dfx = msm.update_df(dfx, dfa)

dict_labels['MACRORISK_EWS_ZN'] = 'Composite macro risk score'
dict_labels['MACRORISK_CWS_ZN'] = 'Custom weighted macro risk score'
xcatx = ['MACRORISK_EWS_ZN'] # ['MACRORISK_EWS_ZN', 'MACRORISK_CWS_ZN']
cidx = cids_fc
sdate = "2000-01-01"

msp.view_ranges(
    dfx,
    xcats=xcatx,
    kind="bar",
    sort_cids_by=None,
    start=sdate,
    xcat_labels=dict_labels,
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=True,
    aspect=2,
    xcat_labels=dict_labels,
    cid_labels=dict_countries,
    title="Composite macro risk related to sovereign risk, equally-weighted score of 7 constituents",
    title_fontsize=25,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/a7ba9fa83c7469412ef7b5f6f5bd834dae470ff03e2b5e730b10d16b4dc66f6e.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/3bc70c3a23f9192bd49f8985ef6b6978973ccb9fbf26319cd46054dd6965dd71.png

Market-implied risk scores #

# Use index carry where CDS spreads not available ("priced risk" score)

msm.missing_in_df(df, xcats=["CDS05YSPRD_NSA"], cids=cids_fc)  # countries without CDS
cidx = ['AED', 'DOP', 'EGP', 'INR', 'NGN', 'OMR', 'QAR', 'RSD', 'SAR', 'UYU']

calcs = ["CDS05YSPRD_NSA = FCBICRY_NSA"]
dfa = msp.panel_calculator(dfx, calcs=calcs, cids=cidx)
dfx = msm.update_df(dfx, dfa)

# Use inverse rating score ("rated risk" score)

calcs = [
    "LTFCRATING_ADJ = LTFCRATING_NSA + 1",  # temporary fix for VEF/RUB problem
    "LTFCRATING_INV = 1 / LTFCRATING_ADJ",
    "CDS05YSPRD_LOG = np.log( CDS05YSPRD_NSA )"  # accoount for non-linearity of spread changes
    
]
cidx = cids_fc
dfa = msp.panel_calculator(dfx, calcs=calcs, cids=cidx)
dfx = msm.update_df(dfx, dfa)
No missing XCATs across DataFrame.
Missing cids for CDS05YSPRD_NSA:  ['AED', 'DOP', 'EGP', 'INR', 'NGN', 'OMR', 'QAR', 'RSD', 'SAR', 'UYU']
xcatx = ["LTFCRATING_INV", "MACRORISK_EWS_ZN"]
cidx = cids_fc

catregs = {}

for xc in xcatx:
    catregs[xc] = msp.CategoryRelations(
        dfx,
        xcats=[xc, "CDS05YSPRD_NSA"],
        cids=cidx,
        years=1,
        lag=0,
        xcat_aggs=["mean", "mean"],
        blacklist=black_fc,
        start="2000-01-01",
    )

msv.multiple_reg_scatter(
    cat_rels=[v for k, v in catregs.items()],
    reg_order=2,
    share_axes=False,
    ncol=2,
    nrow=1,
    figsize=(14, 7),
    title="Risk indices and sovereign credit spreads, annual averages, 24 countries, since 2000",
    title_fontsize=18,
    xlab="Risk index",
    ylab="Sovereign credit spread, %",
    subplot_titles=["Ratings-related risk index", "Macro risk score"],
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/5ca58cd7589ca559c5d40a14bd1cf294f8137879c99b55e4c3921f8be1faa741.png
# Re-score the composite

for xc in ["CDS05YSPRD_LOG", "LTFCRATING_INV"]:
    dfa = msp.make_zn_scores(
        dfx,
        xcat=xc,
        cids=cidx,
        sequential=True,
        min_obs=261 * 3,
        neutral="median",
        pan_weight=1,
        thresh=3,
        postfix="_ZN",
        est_freq="m",
    )
    
    dfx = msm.update_df(dfx, dfa)

dict_labels["CDS05YSPRD_LOG_ZN"] = "Log spread-based market risk score"
dict_labels["LTFCRATING_INV_ZN"] = "Ratings-based market risk score"
# Composite market risk scores

cidx = cids_fc
xcatx = ["CDS05YSPRD_LOG_ZN", "LTFCRATING_INV_ZN"]

dfa = msp.linear_composite(
    dfx,
    xcats=xcatx,
    cids=cidx,
    complete_xcats=False,
    new_xcat="MARKETRISK",
)

dfx = msm.update_df(dfx, dfa)

# Re-score the composite

dfa = msp.make_zn_scores(
    dfx,
    xcat="MARKETRISK",
    cids=cidx,
    sequential=True,
    min_obs=261 * 3,
    neutral="zero",
    pan_weight=1,
    thresh=3,
    postfix="_ZN",
    est_freq="m",
)

dfx = msm.update_df(dfx, dfa)

dict_labels["MARKETRISK_ZN"] = "Composite market risk score"
xcatx = ["MARKETRISK_ZN", "CDS05YSPRD_LOG_ZN", "LTFCRATING_INV_ZN"]
cidx = cids_fc
sdate = "2000-01-01"


msp.view_ranges(
    dfx,
    xcats=xcatx,
    kind="bar",
    sort_cids_by="mean",
    start=sdate,
    xcat_labels=dict_labels,
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=True,
    xcat_labels=dict_labels,
    title='Market risk scores for foreign-currency sovereign debt of major EMBI countries',
    title_fontsize=25,
    legend_fontsize=16,
    cid_labels=dict_countries,
    aspect=2,
    height=2,
    blacklist=black_fc
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/6f0f2a588154305d96b8b892ba7e81c9bdc18fb557b46200aef230e461eaddfc.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/1fa4987767965f5596c24c88666c80b856af3b5e18edace64dde5b7a1e0cdbb8.png

Basic relationship visualizations #

Long-term relations #

# Long-term ratings - spread relations

xcatx = ["LTFCRATING_INV_ZN", "CDS05YSPRD_LOG_ZN"]
cidx = cids_fc

cr = msp.CategoryRelations(
    dfx,
    xcats=xcatx,
    cids=cidx,
    years=5,
    lag=0,
    xcat_aggs=["mean", "mean"],
    blacklist=black_fc,
    start="2000-01-01",
)

cr.reg_scatter(
    labels=True,
    label_fontsize=12,
    title="Long-term relations between credit spread and rated risk scores, by half-decades, since 2000",
    title_fontsize=16,
    xlab="Rated risk score, half-decade average",
    ylab="Credit spread score, half-decade average",
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/b48fbc38f4856822f14111bb54ff6e635ae03ece0c5f5b281cf76ff1eb6d7cef.png
# Long-term macro risk - spread relations

xcatx = ["MACRORISK_EWS_ZN", "CDS05YSPRD_LOG_ZN"]
cidx = cids_fc

cr = msp.CategoryRelations(
    dfx,
    xcats=xcatx,
    cids=cidx,
    years=5,
    lag=0,
    xcat_aggs=["mean", "mean"],
    blacklist=black_fc,
    start="2000-01-01",
)

cr.reg_scatter(
    labels=True,
    label_fontsize=12,
    title="Long-term relations between composite sovereign risk and credit spread scores, by half-decades, since 2000",
    title_fontsize=16,
    xlab="Sovereign credit-related macro risk score, half-decade average (as far as available)",
    ylab=dict_labels['CDS05YSPRD_LOG_ZN'],
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/2ffee19ee4d7600a921b50f70deb8643b43d729d3e10a3df956bf05d73b4084d.png
# Long-term macro risk - ratings relations

xcatx = ["MACRORISK_EWS_ZN", "LTFCRATING_INV_ZN"]
cidx = cids_fc

cr = msp.CategoryRelations(
    dfx,
    xcats=xcatx,
    cids=cidx,
    years=5,
    lag=0,
    xcat_aggs=["mean", "mean"],
    blacklist=black_fc,
    start="2000-01-01",
)

cr.reg_scatter(
    labels=True,
    label_fontsize=12,
    title="Long-term relations between composite sovereign risk and rated risk scores, by half-decades, since 2000",
    title_fontsize=16,
    xlab="Sovereign credit-related macro risk score, half-decade average (as far as available)",
    ylab=dict_labels['LTFCRATING_INV_ZN'],
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/04f1694e4344ec6af2d9595d5b005ac39112a60c4388d1087b0677517e2afd65.png
# Long-term macro risk - ratings relations

xcatx = ["MACRORISK_EWS_ZN", "MARKETRISK_ZN"]
cidx = cids_fc

cr = msp.CategoryRelations(
    dfx,
    xcats=xcatx,
    cids=cidx,
    years=5,
    lag=0,
    xcat_aggs=["mean", "mean"],
    blacklist=black_fc,
    start="2000-01-01",
)

cr.reg_scatter(
    labels=True,
    label_fontsize=12,
    title="EM credit risk: macro risk scores and market risk scores, by half-decades, 24 sovereigns, since 2000",
    title_fontsize=16,
    xlab="Sovereign credit-related macro risk score, half-decade average (as far as available)",
    ylab="Market risk score, half-decade average (as far as available)",
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/02d3afccfd858e3f6402fe5150080ef9091ddd3c4aea19c09305bbf936c0ffad.png
cidx = cids_fc

risks = ["MARKETRISK_ZN", "MACRORISK_EWS_ZN"]
returns = ["FCBIXR_NSA", "FCBIXR_VT10"]

dict_labels["FCBIXR_NSA"] = "Foreign-currency sovereign bond index return, %"
dict_labels["FCBIXR_VT10"] = "Vol-targeted foreign-currency sovereign bond index return, %"

all_relations = []
all_titles = []

for risk in risks:
    for ret in returns:
        cr = msp.CategoryRelations(
            dfx,
            xcats=[risk, ret],
            cids=cidx,
            freq="A",
            # years=10,
            lag=1,
            xcat_aggs=["mean", "sum"],
            blacklist=black_fc,
            start="2000-01-01",
        )
        all_relations.append(cr)
        risk_label = dict_labels[risk]
        ret_label = dict_labels[ret].lower()
        all_titles.append(risk_label + " vs. " + ret_label)

msv.multiple_reg_scatter(
    cat_rels=all_relations,
    title="Annual risk scores and subsequent returns for foreign-currency sovereign debt, 24 countries, since 2000",
    xlab="Risk score (annual average)",
    ylab="Returns, %, next year",
    ncol=2,
    nrow=2,
    figsize=(14, 12),
    prob_est="map",
    coef_box="lower left",
    subplot_titles=all_titles
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/5b94e69c8e70d91d1b280f0d754c5a7d2f09b3436110d20c2c6d20727ead0273.png
cidx = cids_fc

risks = ["CDS05YSPRD_LOG_ZN", "LTFCRATING_INV_ZN"]
returns = ["FCBIXR_NSA", "FCBIXR_VT10"]

all_relations = []
all_titles = []

for risk in risks:
    for ret in returns:
        cr = msp.CategoryRelations(
            dfx,
            xcats=[risk, ret],
            cids=cidx,
            freq="A",
            # years=10,
            lag=1,
            xcat_aggs=["mean", "sum"],
            blacklist=black_fc,
            start="2000-01-01",
        )
        all_relations.append(cr)
        risk_label = dict_labels[risk]
        ret_label = dict_labels[ret].lower()
        all_titles.append(risk_label + " vs. " + ret_label)

msv.multiple_reg_scatter(
    cat_rels=all_relations,
    title=None,
    xlab=None,
    ylab=None,
    ncol=2,
    nrow=2,
    figsize=(16, 10),
    prob_est="map",
    coef_box="lower left",
    subplot_titles=all_titles
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/b0508ef63c34bd0d1d9571a0850a812506e62d339437a9d6f4ca90707b6b3a96.png

Macro risk premium scores #

Aggregate macro risk premium scores #

# Score differences

cidx = cids_fc

calcs = [
    "MACROSPREAD_RPS = CDS05YSPRD_LOG_ZN - MACRORISK_EWS_ZN",
    "MACRORATING_RPS = LTFCRATING_INV_ZN - MACRORISK_EWS_ZN",
    "MACROALL_RPS = MARKETRISK_ZN - MACRORISK_EWS_ZN",
    "MACROSPREAD_RPS_CWS = CDS05YSPRD_LOG_ZN - MACRORISK_CWS_ZN",
    "MACRORATING_RPS_CWS = LTFCRATING_INV_ZN - MACRORISK_CWS_ZN",
    "MACROALL_RPS_CWS = MARKETRISK_ZN - MACRORISK_CWS_ZN",
]
dfa = msp.panel_calculator(dfx, calcs=calcs, cids=cidx)
dfx = msm.update_df(dfx, dfa)

rps = list(dfa['xcat'].unique())

# Re-z-scoring the risk premium scores

for rp in rps:
    dfa = msp.make_zn_scores(
        dfx,
        xcat=rp,
        cids=cidx,
        sequential=True,
        min_obs=261 * 3,
        neutral="zero",
        pan_weight=1,
        thresh=3,
        postfix="_ZN",
        est_freq="m",
    )
    dfx = msm.update_df(dfx, dfa)

dict_labels["MACROSPREAD_RPS_ZN"] = "Spread-based macro risk premium score"
dict_labels["MACRORATING_RPS_ZN"] = "Ratings-based macro risk premium score"
dict_labels["MACROALL_RPS_ZN"] = "Macro risk premium score"

dict_labels["MACROSPREAD_RPS_CWS_ZN"] = "Spread-based macro risk premium score, custom weights"
dict_labels["MACRORATING_RPS_CWS_ZN"] = "Ratings-based macro risk premium score, custom weights"
dict_labels["MACROALL_RPS_CWS_ZN"] = "Macro risk premium score, custom weights"

rpz = ["MACROSPREAD_RPS_ZN", "MACRORATING_RPS_ZN", "MACROALL_RPS_ZN",]
xrpz = rpz + [rp[:-3] + "_CWS_ZN" for rp in rpz]
xcatx = rpz
cidx = cids_fc
sdate = "2000-01-01"

msp.view_ranges(
    dfx,
    xcats=xcatx,
    kind="bar",
    sort_cids_by=None,
    start=sdate,
    xcat_labels=dict_labels,
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=True,
    aspect=2,
    xcat_labels=dict_labels,
    cid_labels=dict_countries,
    title="Sovereign-credit-related macro risk premium scores (higher score means higher premium)",
    title_fontsize=25,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/80b31aa533855e408fc9cc50db7d0f1d777e716823091e06184104f516d9df84.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/f4c5a7fe4443f691e963468c69bd69217c94bf57d54ef03bc3828b887cf32f15.png

Conceptual macro risk premium scores #

# Conceptual risk premium scores

calcs = []
for macro in macroz:
    calcs += f"{macro[:-3]}_RPS = MARKETRISK_ZN - {macro}",

dfa = msp.panel_calculator(dfx, calcs=calcs, cids=cidx)
dfx = msm.update_df(dfx, dfa)

crps = list(dfa['xcat'].unique())

# Re-z-scoring conceptual risk premium scores

for crp in crps:
    dfa = msp.make_zn_scores(
        dfx,
        xcat=crp,
        cids=cidx,
        sequential=True,
        min_obs=261 * 3,
        neutral="zero",
        pan_weight=1,
        thresh=3,
        postfix="_ZN",
        est_freq="m",
    )
    dfx = msm.update_df(dfx, dfa)

crpz = [crp + "_ZN" for crp in crps]

dict_labels['GFINRISK_RPS_ZN'] = 'Government finance conceptual macro risk premium score'
dict_labels['XBALRISK_RPS_ZN'] = 'External balances conceptual macro risk premium score'
dict_labels['XLIABRISK_RPS_ZN'] = 'International position conceptual macro risk premium score'
dict_labels['XDEBTRISK_RPS_ZN'] = 'Foreign-currency debt conceptual macro risk premium score'
dict_labels['GOVRISK_RPS_ZN'] = 'Governance conceptual macro risk premium score'
dict_labels['GROWTHRISK_RPS_ZN'] = 'Growth risk conceptual macro risk premium score'
dict_labels['INFLRISK_RPS_ZN'] = 'Inflation risk conceptual macro risk premium score'
xcatx = crpz
cidx = cids_fc
sdate = "2000-01-01"

msp.view_ranges(
    dfx,
    xcats=xcatx,
    kind="bar",
    sort_cids_by=None,
    start=sdate,
    xcat_labels=dict_labels,
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=True,
    aspect=2,
    xcat_labels=dict_labels,
    cid_labels=dict_countries,
    title=None,
    title_fontsize=22,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/5a5c577c0c3535bf0920aa6874899ee3f58a7c1db3393b372676628c157b4c03.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/3a340d0b03b04ed473482d1b70d341b7e08fa7c6e82bac49edd2f5476ae48c16.png

Relative aggregate macro risk premium scores #

cidx = cids_fc
xcatx = xrpz + ["MARKETRISK_ZN", "FCBIXR_NSA", "FCBIXR_VT10"]

dfa = msp.make_relative_value(
    df = dfx,
    xcats = xcatx,
    cids = cidx,
    start="2000-01-01",
    blacklist=black_fc,
    postfix="vEM",
)

dfx = msm.update_df(dfx, dfa)

xrpzr = [xcat + "vEM" for xcat in xrpz]

dict_labels["MACROSPREAD_RPS_ZNvEM"] = "Relative macro-spread risk premium score"
dict_labels["MACRORATING_RPS_ZNvEM"] = "Relative macro-rating risk premium score"
dict_labels["MACROALL_RPS_ZNvEM"] = "Relative macro risk premium score"

dict_labels["MARKETRISK_ZNvEM"] = "Relative market risk score"

dict_labels["MACROSPREAD_RPS_CWS_ZNvEM"] = "Relative macro-spread risk premium score, custom weights"
dict_labels["MACRORATING_RPS_CWS_ZNvEM"] = "Relative macro-rating risk premium score, custom weights"
dict_labels["MACROALL_RPS_CWS_ZNvEM"] = "Relative macro risk premium score, custom weights"
cidx = cids_fc
xcatx = [rp + "vEM" for rp in rpz]
sdate = "2000-01-01"

msp.view_ranges(
    dfx,
    xcats=xcatx,
    kind="bar",
    sort_cids_by=None,
    start=sdate,
    xcat_labels=dict_labels,
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=True,
    aspect=2,
    xcat_labels=dict_labels,
    cid_labels=dict_countries,
    title="Relative macro risk premium scores (all versus 24 EM average)",
    title_fontsize=25,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/1e8822dec93760c61f62e4b46d1a660cbef5421e08a6c18363618b053760a493.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/1698ba573159e28724857ab66a65fdeb1413ca934afee005b97eca727a9fd074.png
cidx = cids_fc
xcatx = ["LTFCRATING_INV_ZN"]
sdate = "2000-01-01"

msp.view_ranges(
    dfx,
    xcats=xcatx,
    kind="bar",
    sort_cids_by=None,
    start=sdate,
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=True,
    cid_labels=dict_countries,
    aspect=2,
    title='Long term credit rating, inverted',
    title_fontsize=22,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/96984ff169fb3fce233a42004b14936f25013aebedcf45075e9348c569ea454f.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/eea6a28c6e8805f0006907b761f6c9c791a9e6538f419557e45e1445db56faed.png

Relative conceptual macro risk premium scores #

cidx = cids_fc
xcatx = crpz

dfa = msp.make_relative_value(
    df = dfx,
    xcats = xcatx,
    cids = cidx,
    start="2000-01-01",
    blacklist=black_fc,
    postfix="vEM",
)

dfx = msm.update_df(dfx, dfa)

crpzr = [xcat + "vEM" for xcat in crpz]
dict_labels['GFINRISK_RPS_ZNvEM'] = 'Relative government finance conceptual macro risk premium score'
dict_labels['GOVRISK_RPS_ZNvEM'] = 'Relative governance conceptual macro risk premium score'
dict_labels['GROWTHRISK_RPS_ZNvEM'] = 'Relative growth risk conceptual macro risk premium score'
dict_labels['INFLRISK_RPS_ZNvEM'] =  'Relative inflation risk conceptual macro risk premium score'
dict_labels['XBALRISK_RPS_ZNvEM'] = 'Relative external balances conceptual macro risk premium score'
dict_labels['XDEBTRISK_RPS_ZNvEM'] = 'Relative foreign-currency debt conceptual macro risk premium score'
dict_labels['XLIABRISK_RPS_ZNvEM'] = 'Relative international position conceptual macro risk premium score'

Value checks #

Composite directional signals #

Specs and panel test #

dict_dir = {
    "sigs": ['MACROSPREAD_RPS_ZN','MACRORATING_RPS_ZN', 'MACROALL_RPS_ZN', 'MARKETRISK_ZN'],
    "targs": ["FCBIXR_VT10", "FCBIXR_NSA"],
    "cidx": cids_fc,
    "start": "2000-01-01",
    "black": black_fc,
}
dix = dict_dir

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

catregs = {}
for sig in sigs:
    catregs[sig] = msp.CategoryRelations(
        dfx,
        xcats=[sig, ret],
        cids=cidx,
        freq="Q",
        lag=1,
        xcat_aggs=["last", "sum"],
        start=start,
        blacklist=black,
    )

msv.multiple_reg_scatter(
    cat_rels=[v for k, v in catregs.items()],
    ncol=2,
    nrow=2,
    figsize=(14, 12),
    title="Risk scores and subsequent foreign currency bond index excess returns, 24 countries since 2000",
    title_fontsize=20,
    xlab="End-of-quarter score",
    ylab="Foreign currency bond index excess returns, vol targeted, %, next quarter",
    coef_box="lower right",
    prob_est="map",
    single_chart=True,
    subplot_titles=[dict_labels[key] for key in sigs]
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/f899e6ab98538d9ccc1288a845a972ba5a6860aba84a0624e8a44365326f061c.png
dix = dict_dir

sig = dix["sigs"][2]
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

cr = msp.CategoryRelations(
    dfx,
    xcats=[sig, ret],
    cids=cidx,
    freq="Q",
    years=None,
    lag=1,
    xcat_aggs=["last", "sum"],  # period mean adds stability
    start=start,
    blacklist=black,
)

cr.reg_scatter(
    title="Macro risk premia and subsequent foreign currency bond index excess returns, 24 countries since 2000",
    labels=False,
    xlab="Sovereign credit macro risk premium score, end of quarter",
    ylab="Foreign currency bond index excess returns, vol targeted, %, next quarter",
    coef_box="lower right",
    prob_est="map",
    separator=2013,
    size=(10, 8),
)

cr.reg_scatter(
    title="Macro risk premia and subsequent foreign currency bond index excess returns, 24 countries since 2000",
    labels=False,
    xlab="Macro risk premium",
    ylab="Vol-adjusted returns",
    coef_box="lower right",
    prob_est="pool",
    separator="cids",
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/6d152108b1a000f1e28467d63be181d8d797138e4f82cfe032b43a435f139ef1.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/13c6e214a1e1ec74a74bd2d2c58477ddd09f7c1dc7f36dbee4e6fa65d11c1bba.png

Accuracy and correlation check #

dix = dict_dir

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

srr = mss.SignalReturnRelations(
    dfx,
    rets=ret,
    cids=cidx,
    sigs=sigs,
    # cosp=True,
    freqs="M",
    agg_sigs=["last"],  # for stability
    start=start,
)

dix["srr"] = srr
dix = dict_dir
srr = dix["srr"]

tbl=srr.multiple_relations_table(signal_name_dict=dict_labels).round(3)
display(tbl.transpose())
Return Vol-targeted foreign-currency sovereign bond index return, %
Signal Composite market risk score Spread-based macro risk premium score Ratings-based macro risk premium score Macro risk premium score
Frequency M M M M
Aggregation last last last last
accuracy 0.501 0.451 0.474 0.464
bal_accuracy 0.510 0.511 0.510 0.515
pos_sigr 0.462 0.239 0.336 0.282
pos_retr 0.610 0.608 0.608 0.610
pos_prec 0.620 0.625 0.622 0.631
neg_prec 0.399 0.397 0.399 0.399
pearson 0.020 0.040 0.035 0.042
pearson_pval 0.122 0.003 0.009 0.001
kendall 0.025 0.045 0.028 0.038
kendall_pval 0.004 0.000 0.002 0.000
auc 0.510 0.508 0.510 0.513
dix = dict_dir
srr = dix["srr"]

srr.accuracy_bars(type='cross_section', sigs="MACROALL_RPS_ZN", size=(16, 4))
srr.accuracy_bars(type='signals', size=(16, 4))
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/0ad7031731b70d930295e6732b5fe0c68ce47ff899e5bd1bfaa7b9396ca6a4a7.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/cd077e53dea223d284853bade08908f9a95a828be15146ea02358c50888dee16.png
dix = dict_dir
srr = dix["srr"]

srr.correlation_bars(type='cross_section', sigs="MACROALL_RPS_ZN", size=(16, 4))
srr.correlation_bars(type='signals', size=(16, 4), x_labels=dict_labels)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/5b338e29555e298c90472a1d7b00b8d1208b4e15fa112464a47a12f04bd8f79e.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/505593a5f1721c55a1336ceb0855a37c0d13ac8e0ffde7700c0b4b3da0c6ec7b.png

Naive PnLs #

dix = dict_dir

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

rt = ret.split('_')[-1]  # 'NSA' or 'VT10'

pnls = msn.NaivePnL(
    df=dfx,
    ret=ret,
    sigs=sigs,
    cids=cidx,
    start=start,
    blacklist=black,
    bms=bms,
)
for sig in sigs:
    for bias in [0, 1]:
        pnls.make_pnl(
            sig=sig,
            sig_op="zn_score_pan",
            thresh=2,
            sig_add = bias,
            rebal_freq="monthly",
            neutral="zero",
            pnl_name=sig + "_PNL" + rt + str(bias),
            rebal_slip=1,
            vol_scale=10,
    )
pnls.make_long_pnl(vol_scale=10, label="Long only")

dix["pnls_"+rt.lower()] = pnls
dix = dict_dir
rt = "VT10"
bias = 1
pnls = dix["pnls_"+rt.lower()] 

sigs = ["MACROALL_RPS_ZN", "MARKETRISK_ZN"]
strats = [sig + "_PNL" + rt + str(bias) for sig in sigs]

pnl_labels = {
    "MACROALL_RPS_ZN_PNL" + rt + str(bias): "Macro risk premium score with long bias",
    "MARKETRISK_ZN_PNL" + rt + str(bias): "Market risk score with long bias",
    "Long only": "Long only risk parity",
}

pnls.plot_pnls(
    title="Naive PnL for risk-premia and benchmark strategies, 24 EM sovereigns, vol-targeted positions",
    pnl_cats=strats + ["Long only"],
    xcat_labels=pnl_labels,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats + ["Long only"]).round(3))
pnls.signal_heatmap(pnl_name=f"MACROALL_RPS_ZN_PNL" + rt + str(bias), figsize=(20, 10))
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/42f7b08d5aba32a7d6268bc24b77a3fa1fa150193a9fc321208f0caacffa8be6.png
xcat MACROALL_RPS_ZN_PNLVT101 MARKETRISK_ZN_PNLVT101 Long only
Return % 11.983004 8.314899 7.025648
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 1.1983 0.83149 0.702565
Sortino Ratio 1.672573 1.112942 0.925355
Max 21-Day Draw % -39.285473 -41.390234 -42.691999
Max 6-Month Draw % -57.286435 -41.88914 -37.994371
Peak to Trough Draw % -67.5839 -48.768828 -62.285155
Top 5% Monthly PnL Share 0.489217 0.622572 0.760984
USD_EQXR_NSA correl 0.216862 0.293824 0.214687
UHY_CRXR_NSA correl 0.2623 0.350987 0.273763
UIG_CRXR_NSA correl 0.257732 0.332196 0.253393
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/f7097a3a046e4a4851a440e3097b838478a4fa19cc19f8ce9a8fe1d3767bce4f.png
dix = dict_dir

sigs = dix['sigs']
ret = dix["targs"][1]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

rt = ret.split('_')[-1]  # 'NSA' or 'VT10'

pnls = msn.NaivePnL(
    df=dfx,
    ret=ret,
    sigs=sigs,
    cids=cidx,
    start=start,
    blacklist=black,
    bms=bms,
)
for sig in sigs:
    for bias in [0, 1]:
        pnls.make_pnl(
            sig=sig,
            sig_op="zn_score_pan",
            thresh=2,
            sig_add = bias,
            rebal_freq="monthly",
            neutral="zero",
            pnl_name=sig + "_PNL" + rt + str(bias),
            rebal_slip=1,
            vol_scale=10,
    )
pnls.make_long_pnl(vol_scale=10, label="Long only")

dix["pnls_"+rt.lower()] = pnls
dix = dict_dir
rt = "NSA"
bias = 1
pnls = dix["pnls_"+rt.lower()] 

sigs = ["MACROALL_RPS_ZN", "MARKETRISK_ZN"]
strats = [sig + "_PNL" + rt + str(bias) for sig in sigs]

pnl_labels = {
    "MACROALL_RPS_ZN_PNL" + rt + str(bias): "Macro risk premium score with long bias",
    "MARKETRISK_ZN_PNL" + rt + str(bias): "Market risk score with long bias",
    "Long only": "Long only risk parity",
}

pnls.plot_pnls(
    title="Naive PnL for risk-premia and benchmark strategies, 24 EM sovereigns, nominal positions",
    pnl_cats=strats + ["Long only"],
    xcat_labels=pnl_labels,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats + ["Long only"], label_dict=pnl_labels).round(3))
pnls.signal_heatmap(pnl_name=f"MACROALL_RPS_ZN_PNL" + rt + str(bias), figsize=(20, 10))
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/59530522e9c9868e5b95cfc9c7a6a09cda329a052c301ca3c3ffc89034687540.png
xcat Macro risk premium score with long bias Market risk score with long bias Long only risk parity
Return % 11.273791 9.300272 8.004047
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 1.127379 0.930027 0.800405
Sortino Ratio 1.609415 1.291543 1.079887
Max 21-Day Draw % -50.839917 -37.453612 -40.898679
Max 6-Month Draw % -58.26404 -42.623356 -44.785424
Peak to Trough Draw % -58.850524 -45.725342 -55.021649
Top 5% Monthly PnL Share 0.569486 0.619495 0.641037
USD_EQXR_NSA correl 0.247441 0.308603 0.270744
UHY_CRXR_NSA correl 0.304675 0.379014 0.343803
UIG_CRXR_NSA correl 0.332395 0.376879 0.330702
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/f7097a3a046e4a4851a440e3097b838478a4fa19cc19f8ce9a8fe1d3767bce4f.png

Conceptual directional signals #

Specs and panel test #

dict_cds = {
    "sigs": crpz + ['MARKETRISK_ZN'],
    "targs": ["FCBIXR_VT10", "FCBIXR_NSA"],
    "cidx": cids_fc,
    "start": "2000-01-01",
    "black": black_fc,
}
dix = dict_cds

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

catregs = {}
for sig in sigs:
    catregs[sig] = msp.CategoryRelations(
        dfx,
        xcats=[sig, ret],
        cids=cidx,
        freq="Q",
        lag=1,
        xcat_aggs=["mean", "sum"],
        start=start,
        blacklist=black,
    )

msv.multiple_reg_scatter(
    cat_rels=[v for k, v in catregs.items()],
    ncol=2,
    nrow=4,
    figsize=(14, 24),
    title="Spread-based premium scores and sovereign bond index returns, 24 EMBI countries, since 2000 or inception",
    title_fontsize=20,
    xlab="End-of-quarter score",
    ylab="Foreign currency bond index excess returns, vol targeted, %, next quarter",
    coef_box="lower right",
    prob_est="map",
    single_chart=True,
    subplot_titles=[dict_labels[key] for key in sigs]
)
XLIABRISK_RPS_ZN misses: ['AED', 'OMR', 'QAR', 'SAR'].
XDEBTRISK_RPS_ZN misses: ['QAR'].
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/3b34f4cb2cfc19528b7e395679b0981192c887399722ffa0dca50700ab88e242.png

Accuracy and correlation check #

dix = dict_cds

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

srr = mss.SignalReturnRelations(
    dfx,
    rets=ret,
    cids=cidx,
    sigs=sigs,
    # cosp=True,
    freqs="M",
    agg_sigs=["mean"],  # for stability
    start=start,
)

dix["srr"] = srr
dix = dict_cds
srr = dix["srr"]

tbl=srr.multiple_relations_table(signal_name_dict=dict_labels).round(3)
display(tbl.transpose())
Return Vol-targeted foreign-currency sovereign bond index return, %
Signal Composite market risk score Government finance conceptual macro risk premium score External balances conceptual macro risk premium score International position conceptual macro risk premium score Foreign-currency debt conceptual macro risk premium score Governance conceptual macro risk premium score Growth risk conceptual macro risk premium score Inflation risk conceptual macro risk premium score
Frequency M M M M M M M M
Aggregation mean mean mean mean mean mean mean mean
accuracy 0.500 0.482 0.482 0.513 0.444 0.470 0.485 0.509
bal_accuracy 0.509 0.505 0.510 0.520 0.501 0.491 0.508 0.514
pos_sigr 0.459 0.393 0.371 0.468 0.244 0.403 0.399 0.481
pos_retr 0.610 0.609 0.609 0.604 0.610 0.610 0.609 0.610
pos_prec 0.620 0.616 0.622 0.625 0.611 0.599 0.619 0.624
neg_prec 0.399 0.395 0.399 0.414 0.390 0.383 0.397 0.403
pearson 0.022 0.025 0.011 0.033 0.019 0.019 0.010 0.052
pearson_pval 0.086 0.051 0.400 0.023 0.144 0.135 0.448 0.000
kendall 0.026 0.027 0.024 0.028 0.020 0.011 0.010 0.030
kendall_pval 0.003 0.002 0.007 0.004 0.024 0.201 0.240 0.001
auc 0.510 0.505 0.510 0.520 0.501 0.491 0.508 0.514
dix = dict_cds
srr = dix["srr"]

sig = dix['sigs'][0]
srr.accuracy_bars(type='cross_section', sigs=sig, size=(16, 4))
srr.accuracy_bars(type='signals', size=(16, 4), x_labels=dict_labels, x_labels_rotate= 60)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/8e99d4b4202c2c0dd8c2fc3031e3175e9314da154674561eba8a291e34a70093.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/3a9a3a8b9e3dc96ab664591b826a1beea7fed9d2b0ab3ab5a2509ec4cca21092.png
dix = dict_cds
srr = dix["srr"]

sig = dix['sigs'][0]
srr.correlation_bars(type='cross_section', sigs=sig, size=(16, 4))
srr.correlation_bars(type='signals', size=(16, 4), x_labels=dict_labels,x_labels_rotate=70 )
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/daa46812772ebd4bcaafd27446af1be94985fe70215ba4da98a13a2693fa2205.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/75eb7dd19044ce8c9c5cb9c15aa3f53750cc7ed02c0902af12458214b2580a8e.png

Naive PnLs #

dix = dict_cds

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

rt = ret.split('_')[-1]  # 'NSA' or 'VT10'

pnls = msn.NaivePnL(
    df=dfx,
    ret=ret,
    sigs=sigs,
    cids=cidx,
    start=start,
    blacklist=black,
    bms=bms,
)
for sig in sigs:
    for bias in [0, 1]:
        pnls.make_pnl(
            sig=sig,
            sig_op="zn_score_pan",
            thresh=2,
            sig_add = bias,
            rebal_freq="monthly",
            neutral="zero",
            pnl_name=sig + "_PNL" + rt + str(bias),
            rebal_slip=1,
            vol_scale=10,
    )
pnls.make_long_pnl(vol_scale=10, label="Long only")

dix["pnls_"+rt.lower()] = pnls
dix = dict_cds
rt = "VT10"
bias = 1
pnls = dix["pnls_"+rt.lower()] 

sigs = dix["sigs"]
strats = [sig + "_PNL" + rt + str(bias) for sig in sigs]

pnl_labels = {
    'GFINRISK_RPS_ZN_PNLVT101': "Government finance conceptual macro risk premium score",
    'XBALRISK_RPS_ZN_PNLVT101': "External balances conceptual macro risk premium score",
    'XLIABRISK_RPS_ZN_PNLVT101': "International position conceptual macro risk premium score",
    'XDEBTRISK_RPS_ZN_PNLVT101': "Foreign-currency debt conceptual macro risk premium score",
    'GOVRISK_RPS_ZN_PNLVT101': "Governance conceptual macro risk premium score",
    'GROWTHRISK_RPS_ZN_PNLVT101': "Growth risk conceptual macro risk premium score",
    'INFLRISK_RPS_ZN_PNLVT101': "Inflation risk conceptual macro risk premium score",
    'MARKETRISK_ZN_PNLVT101': "Market risk score",
    'Long only': 'Long only'
}

pnls.plot_pnls(
    title=None,
    pnl_cats=strats + ["Long only"],
    xcat_labels=pnl_labels,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats + ["Long only"], label_dict=pnl_labels).round(3))
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/dbdb8a7789375985d9a1ca7727092a610e214a9211177a12b7bcdd631ccdad9f.png
xcat Government finance conceptual macro risk premium score External balances conceptual macro risk premium score International position conceptual macro risk premium score Foreign-currency debt conceptual macro risk premium score Governance conceptual macro risk premium score Growth risk conceptual macro risk premium score Inflation risk conceptual macro risk premium score Market risk score Long only
Return % 9.102722 7.888097 7.871175 9.385148 7.544993 7.249389 9.423029 8.314899 7.025648
St. Dev. % 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
Sharpe Ratio 0.910272 0.78881 0.787117 0.938515 0.754499 0.724939 0.942303 0.83149 0.702565
Sortino Ratio 1.228459 1.059816 1.088246 1.257191 1.014222 0.951667 1.259327 1.112942 0.925355
Max 21-Day Draw % -40.261492 -45.127431 -42.388371 -44.931992 -41.720205 -48.349838 -46.330392 -41.390234 -42.691999
Max 6-Month Draw % -62.213966 -31.774385 -30.870158 -64.954393 -33.972294 -75.896825 -29.852892 -41.88914 -37.994371
Peak to Trough Draw % -70.445424 -54.782295 -52.09107 -76.673907 -52.115205 -80.591062 -47.747054 -48.768828 -62.285155
Top 5% Monthly PnL Share 0.567847 0.606462 0.720914 0.603385 0.72878 0.676996 0.633494 0.622572 0.760984
USD_EQXR_NSA correl 0.265838 0.27471 0.268902 0.236804 0.233093 0.216432 0.224113 0.293824 0.214687
UHY_CRXR_NSA correl 0.326448 0.328438 0.318467 0.289352 0.286193 0.260598 0.295552 0.350987 0.273763
UIG_CRXR_NSA correl 0.327828 0.307758 0.297411 0.308355 0.250892 0.261908 0.267713 0.332196 0.253393
Traded Months 307 307 307 307 307 307 307 307 307

Composite relative signals #

Specs and panel test #

dict_rel = {
    "sigs": ['MACROSPREAD_RPS_ZNvEM','MACRORATING_RPS_ZNvEM', 'MACROALL_RPS_ZNvEM', 'MARKETRISK_ZNvEM'],
    "targs": ["FCBIXR_VT10vEM", "FCBIXR_NSAvEM"],
    "cidx": cids_fc,
    "start": "2000-01-01",
    "black": black_fc,
}
dix = dict_rel

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

catregs = {}
for sig in sigs:
    catregs[sig] = msp.CategoryRelations(
        dfx,
        xcats=[sig, ret],
        cids=cidx,
        freq="Q",
        lag=1,
        xcat_aggs=["mean", "sum"],
        start=start,
        blacklist=black,
    )

msv.multiple_reg_scatter(
    cat_rels=[v for k, v in catregs.items()],
    ncol=2,
    nrow=2,
    figsize=(14, 12),
    title="Relative risk scores and subsequent relative excess returns, 24 EM sovereigns since 2000",
    title_fontsize=20,
    xlab="End-of-quarter score",
    ylab="Foreign currency bond index relative excess returns, vol targeted, %, next quarter",
    coef_box="lower right",
    prob_est="map",
    single_chart=True,
    subplot_titles=[dict_labels[key] for key in sigs]
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/357ab406470395f5c597a8d736007b40aa63c8fc7c446a874a34c648c604fc83.png
dix = dict_rel

sig = dix["sigs"][2]
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

cr = msp.CategoryRelations(
    dfx,
    xcats=[sig, ret],
    cids=cidx,
    freq="Q",
    years=None,
    lag=1,
    xcat_aggs=["mean", "sum"],  # period mean adds stability
    start=start,
    blacklist=black,
)

cr.reg_scatter(
    title="Relative macro risk premia and subsequent foreign currency bond index excess returns, 24 countries since 2000",
    labels=False,
    xlab="Relative sovereign credit macro risk premium score, end of quarter",
    ylab="Foreign currency bond index excess returns, vol targeted, %, next quarter",
    coef_box="lower right",
    prob_est="map",
    separator=2012,
    size=(12, 8),
)

cr.reg_scatter(
    title="Relative macro risk premia and subsequent foreign currency bond index excess returns, 24 countries since 2000",
    labels=False,
    xlab="Relative macro risk premium",
    ylab="Returns",
    coef_box="lower right",
    prob_est="pool",
    separator="cids",
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/2e5d26325cdeb0dcb1ebf938c76fd7132342672ec516499752f671dd4f92f6d8.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/a8e5f9881d68a8efa6cffb79fa4694f9503489e0b6b50ad0a0fad2eaf643687a.png

Accuracy and correlation check #

dix = dict_rel

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

srr = mss.SignalReturnRelations(
    dfx,
    rets=ret,
    cids=cidx,
    sigs=sigs,
    # cosp=True,
    freqs="M",
    agg_sigs=["mean"],  # for stability
    start=start,
)

dix["srr"] = srr
dix = dict_rel
srr = dix["srr"]

tbl=srr.multiple_relations_table(signal_name_dict=dict_labels, return_name_dict={'FCBIXR_VT10vEM': 'Relative foreign currency bond index returns, volatility adjusted'}).round(3)
display(tbl.transpose())
Return Relative foreign currency bond index returns, volatility adjusted
Signal Relative macro-spread risk premium score Relative macro-rating risk premium score Relative macro risk premium score Relative market risk score
Frequency M M M M
Aggregation mean mean mean mean
accuracy 0.525 0.521 0.527 0.532
bal_accuracy 0.525 0.521 0.527 0.532
pos_sigr 0.501 0.497 0.514 0.491
pos_retr 0.501 0.500 0.500 0.500
pos_prec 0.526 0.521 0.526 0.533
neg_prec 0.524 0.522 0.527 0.531
pearson 0.015 0.046 0.032 0.031
pearson_pval 0.273 0.001 0.013 0.018
kendall 0.026 0.038 0.036 0.042
kendall_pval 0.003 0.000 0.000 0.000
auc 0.525 0.521 0.527 0.532
dix = dict_rel
srr = dix["srr"]

srr.accuracy_bars(type='cross_section', sigs="MACROALL_RPS_ZNvEM", size=(16, 4))
srr.accuracy_bars(type='signals', size=(16, 4), x_labels=dict_labels, x_labels_rotate= 60)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/fbd478e2e034f0fcfe272e345dd0c93b9b000115c31843af2076eb0cb1a53030.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/90df8959859325e75b06a7026e966e3bcf767e8fbd27d82c9dfb86a65409a573.png
dix = dict_rel
srr = dix["srr"]

srr.correlation_bars(type='cross_section', sigs="MACROALL_RPS_ZNvEM", size=(16, 4))
srr.correlation_bars(type='signals', size=(16, 4),x_labels=dict_labels, x_labels_rotate= 60)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/60312604c0e29aaee6e3c35aa43b18b0e1f4cb35704491eddeb93cf3d2566ae3.png https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/e2517c9205a5bf4b912271f5011ca2ee589115a5f22797f9e1acfd11dd8083aa.png

Naive PnLs #

dix = dict_rel

sigs = dix["sigs"]
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

pnls = msn.NaivePnL(
    df=dfx,
    ret=ret,
    sigs=sigs,
    cids=cidx,
    start=start,
    blacklist=black,
    bms=bms,
)
for sig in sigs:
    pnls.make_pnl(
        sig=sig,
        sig_op="zn_score_pan",
        thresh=2,
        sig_add=0,
        rebal_freq="monthly",
        neutral="zero",
        pnl_name=sig + "_PNL",
        rebal_slip=1,
        vol_scale=10,
    )

dix["pnls"] = pnls
dix = dict_rel
bias = 0
pnls = dix["pnls"]
sigs = dix["sigs"]

sigs = ["MACROSPREAD_RPS_ZNvEM", "MACRORATING_RPS_ZNvEM", "MACROALL_RPS_ZNvEM"]
strats = [sig + "_PNL" for sig in sigs]

pnl_labels = {
    "MACROSPREAD_RPS_ZNvEM_PNL": "Spread-based relative macro risk premium score",
    "MACRORATING_RPS_ZNvEM_PNL": "Ratings-based relative macro risk premium score",
    "MACROALL_RPS_ZNvEM_PNL": "Composite relative macro risk premium score",
}

pnls.plot_pnls(
    title="Naive PnL for relative risk-premia strategies, 24 EM sovereigns, 7-factor macro risk",
    pnl_cats=strats,
    xcat_labels=pnl_labels,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats).round(3))
pnls.signal_heatmap(
    pnl_name=f"MACROALL_RPS_ZNvEM_PNL",
    figsize=(16, 6),
    title="Signal heatmap for relative macro risk premium score, 24 EM sovereigns, 7-factor macro risk",
    tick_fontsize=10,
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/1ad69ae74f2179695d49a3a89d1fc7564f27a1c3d964d681be5126983f92f123.png
xcat MACROSPREAD_RPS_ZNvEM_PNL MACRORATING_RPS_ZNvEM_PNL MACROALL_RPS_ZNvEM_PNL
Return % 3.292463 4.938308 4.331788
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.329246 0.493831 0.433179
Sortino Ratio 0.463184 0.701141 0.616736
Max 21-Day Draw % -14.293858 -21.644961 -17.736543
Max 6-Month Draw % -19.453042 -29.289245 -24.167777
Peak to Trough Draw % -42.26745 -50.514495 -46.696056
Top 5% Monthly PnL Share 1.22197 0.852256 1.023519
USD_EQXR_NSA correl 0.014102 0.09413 0.093127
UHY_CRXR_NSA correl 0.010985 0.092003 0.092805
UIG_CRXR_NSA correl -0.011349 0.093237 0.084996
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/9015c52e36099dcc884049d356bb0277bb74f3ab6ace92a2fc9f0bf49cef91f5.png

Conceptual relative signals #

Specs and panel test #

dict_crs = {
    "sigs": crpzr + ["MARKETRISK_ZNvEM"],
    "targs": ["FCBIXR_VT10vEM", "FCBIXR_NSAvEM"],
    "cidx": cids_fc,
    "start": "2000-01-01",
    "black": black_fc,
}
dix = dict_crs

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

catregs = {}
for sig in sigs:
    catregs[sig] = msp.CategoryRelations(
        dfx,
        xcats=[sig, ret],
        cids=cidx,
        freq="Q",
        lag=1,
        xcat_aggs=["mean", "sum"],
        start=start,
        blacklist=black,
    )

msv.multiple_reg_scatter(
    cat_rels=[v for k, v in catregs.items()],
    ncol=2,
    nrow=4,
    figsize=(14, 24),
    title=None,
    title_fontsize=20,
    xlab="End-of-quarter score",
    ylab="Foreign currency bond index excess returns, vol targeted, %, next quarter",
    coef_box="lower right",
    prob_est="map",
    single_chart=True,
    subplot_titles=['Relative ' + dict_labels[key[:-3]] for key in sigs]
)
XLIABRISK_RPS_ZNvEM misses: ['AED', 'OMR', 'QAR', 'SAR'].
XDEBTRISK_RPS_ZNvEM misses: ['QAR'].
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/59570aa89d9a9b16fe766f24de3612c7bccde1e7d18ed6da2dd3fbee553c3efb.png

Accuracy and correlation check #

dix = dict_crs

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

srr = mss.SignalReturnRelations(
    dfx,
    rets=ret,
    cids=cidx,
    sigs=sigs,
    # cosp=True,
    freqs="M",
    agg_sigs=["mean"],  # for stability
    start=start,
)

dix["srr"] = srr
dix = dict_crs
srr = dix["srr"]
tbl=srr.multiple_relations_table(signal_name_dict=dict_labels,return_name_dict={'FCBIXR_VT10vEM': 'Relative foreign currency bond index returns, volatility adjusted'}).round(3)
display(tbl.transpose())
Return Relative foreign currency bond index returns, volatility adjusted
Signal Relative market risk score Relative government finance conceptual macro risk premium score Relative governance conceptual macro risk premium score Relative growth risk conceptual macro risk premium score Relative inflation risk conceptual macro risk premium score Relative external balances conceptual macro risk premium score Relative foreign-currency debt conceptual macro risk premium score Relative international position conceptual macro risk premium score
Frequency M M M M M M M M
Aggregation mean mean mean mean mean mean mean mean
accuracy 0.532 0.519 0.512 0.525 0.512 0.526 0.516 0.538
bal_accuracy 0.532 0.519 0.512 0.525 0.512 0.526 0.517 0.538
pos_sigr 0.491 0.500 0.525 0.467 0.499 0.479 0.442 0.503
pos_retr 0.500 0.500 0.500 0.499 0.501 0.501 0.500 0.499
pos_prec 0.533 0.519 0.512 0.526 0.513 0.528 0.519 0.537
neg_prec 0.531 0.519 0.513 0.524 0.511 0.525 0.514 0.540
pearson 0.031 0.021 0.016 0.031 0.008 0.026 0.012 0.051
pearson_pval 0.018 0.106 0.208 0.021 0.557 0.047 0.368 0.001
kendall 0.042 0.024 0.016 0.031 0.011 0.039 0.022 0.054
kendall_pval 0.000 0.006 0.069 0.000 0.206 0.000 0.013 0.000
auc 0.532 0.519 0.512 0.525 0.512 0.526 0.516 0.538

Naive PnLs #

dix = dict_crs

sigs = dix["sigs"]
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

pnls = msn.NaivePnL(
    df=dfx,
    ret=ret,
    sigs=sigs,
    cids=cidx,
    start=start,
    blacklist=black,
    bms=bms,
)
for sig in sigs:
    pnls.make_pnl(
        sig=sig,
        sig_op="zn_score_pan",
        thresh=2,
        sig_add=0,
        rebal_freq="monthly",
        neutral="zero",
        pnl_name=sig + "_PNL",
        rebal_slip=1,
        vol_scale=10,
    )

dix["pnls"] = pnls
dix = dict_crs
bias = 0
pnls = dix["pnls"] 

sigs = dix["sigs"]
strats = [sig + "_PNL" for sig in sigs]

pnl_labels = {}

for sig in sigs:
    pnl_labels[sig+'_PNL'] = dict_labels[sig]
    

pnls.plot_pnls(
    title=None,
    pnl_cats=strats,
    xcat_labels=pnl_labels,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats, label_dict=pnl_labels).round(3))
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/e81a54a51489caa9aa98be3e3ade6e41e200ec899c55eed501f8b6479710fcfd.png
xcat Relative government finance conceptual macro risk premium score Relative external balances conceptual macro risk premium score Relative international position conceptual macro risk premium score Relative foreign-currency debt conceptual macro risk premium score Relative governance conceptual macro risk premium score Relative growth risk conceptual macro risk premium score Relative inflation risk conceptual macro risk premium score Relative market risk score
Return % 2.475957 3.457089 4.129918 1.370682 2.083336 3.867337 0.6258 3.01279
St. Dev. % 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
Sharpe Ratio 0.247596 0.345709 0.412992 0.137068 0.208334 0.386734 0.06258 0.301279
Sortino Ratio 0.34623 0.4799 0.582635 0.191157 0.287121 0.548374 0.085569 0.414655
Max 21-Day Draw % -19.312203 -24.724539 -19.28101 -14.348855 -20.310091 -15.013302 -28.955906 -26.064021
Max 6-Month Draw % -28.775048 -29.931264 -40.067388 -26.604977 -30.363695 -26.347951 -32.913732 -35.632727
Peak to Trough Draw % -49.086153 -49.167892 -67.021808 -87.677165 -57.302893 -56.970072 -51.151695 -68.512847
Top 5% Monthly PnL Share 1.54643 1.097971 1.007643 4.000611 2.074613 1.26767 6.750153 1.523972
USD_EQXR_NSA correl 0.197908 0.220893 0.185761 0.085947 0.107351 0.053354 0.182118 0.252821
UHY_CRXR_NSA correl 0.222083 0.233174 0.184688 0.072803 0.108581 0.030994 0.203018 0.262586
UIG_CRXR_NSA correl 0.231844 0.229121 0.184093 0.087584 0.049048 0.018669 0.207435 0.248194
Traded Months 307 307 307 307 307 307 307 307

Customized directional signals #

Specs and panel test #

dict_dirc = {
    "sigs": ['MACROSPREAD_RPS_CWS_ZN','MACRORATING_RPS_CWS_ZN', 'MACROALL_RPS_CWS_ZN', 'MARKETRISK_ZN'],
    "targs": ["FCBIXR_VT10", "FCBIXR_NSA"],
    "cidx": cids_fc,
    "start": "2000-01-01",
    "black": black_fc,
}
dix = dict_dirc

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

catregs = {}
for sig in sigs:
    catregs[sig] = msp.CategoryRelations(
        dfx,
        xcats=[sig, ret],
        cids=cidx,
        freq="Q",
        lag=1,
        xcat_aggs=["last", "sum"],
        start=start,
        blacklist=black,
    )

msv.multiple_reg_scatter(
    cat_rels=[v for k, v in catregs.items()],
    ncol=2,
    nrow=2,
    figsize=(14, 12),
    title=None,
    title_fontsize=20,
    xlab="End-of-quarter score",
    ylab="Foreign currency bond index excess returns, vol targeted, %, next quarter",
    coef_box="lower right",
    prob_est="map",
    single_chart=True,
    subplot_titles=[dict_labels[key] for key in sigs]
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/9e92394344c768333f988eec1a91636bce9fa27293577fc21d4f12fddbfc27dc.png

Accuracy and correlation check #

dix = dict_dirc

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

srr = mss.SignalReturnRelations(
    dfx,
    rets=ret,
    cids=cidx,
    sigs=sigs,
    # cosp=True,
    freqs="M",
    agg_sigs=["last"],  # for stability
    start=start,
)

dix["srr"] = srr
dix = dict_dirc
srr = dix["srr"]

tbl=srr.multiple_relations_table(signal_name_dict=dict_labels,return_name_dict={'FCBIXR_VT10vEM': 'Relative foreign currency bond index returns, volatility adjusted'}).round(3)
display(tbl.transpose())
Return Vol-targeted foreign-currency sovereign bond index return, %
Signal Composite market risk score Spread-based macro risk premium score, custom weights Ratings-based macro risk premium score, custom weights Macro risk premium score, custom weights
Frequency M M M M
Aggregation last last last last
accuracy 0.501 0.475 0.499 0.485
bal_accuracy 0.510 0.515 0.516 0.513
pos_sigr 0.462 0.322 0.423 0.375
pos_retr 0.610 0.609 0.608 0.610
pos_prec 0.620 0.629 0.626 0.626
neg_prec 0.399 0.401 0.406 0.400
pearson 0.020 0.029 0.024 0.031
pearson_pval 0.122 0.030 0.077 0.016
kendall 0.025 0.041 0.022 0.034
kendall_pval 0.004 0.000 0.013 0.000
auc 0.510 0.514 0.516 0.513

Naive PnLs #

dix = dict_dirc

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

rt = ret.split('_')[-1]  # 'NSA' or 'VT10'

pnls = msn.NaivePnL(
    df=dfx,
    ret=ret,
    sigs=sigs,
    cids=cidx,
    start=start,
    blacklist=black,
    bms=bms,
)
for sig in sigs:
    for bias in [0, 1]:
        pnls.make_pnl(
            sig=sig,
            sig_op="zn_score_pan",
            thresh=2,
            sig_add = bias,
            rebal_freq="monthly",
            neutral="zero",
            pnl_name=sig + "_PNL" + rt + str(bias),
            rebal_slip=1,
            vol_scale=10,
    )
pnls.make_long_pnl(vol_scale=10, label="Long only")

dix["pnls_"+rt.lower()] = pnls
dix = dict_dirc
rt = "VT10"
bias = 1
pnls = dix["pnls_"+rt.lower()] 

sigs = ["MACROALL_RPS_CWS_ZN", "MARKETRISK_ZN"]
strats = [sig + "_PNL" + rt + str(bias) for sig in sigs]

pnl_labels = {
    'MACROALL_RPS_CWS_ZN_PNLVT101': 'Macro risk premium customised directional score, vol targeted returns',
    'MARKETRISK_ZN_PNLVT101': 'Market risk score, directional, vol targeted returns',
    'Long only': 'Long only'
}

pnls.plot_pnls(
    title=None,
    pnl_cats=strats + ["Long only"],
    xcat_labels=pnl_labels,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats + ["Long only"], label_dict=pnl_labels).round(3))
pnls.signal_heatmap(pnl_name=f"MACROALL_RPS_CWS_ZN_PNL" + rt + str(bias), figsize=(20, 10))
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/ccaba261d3134da654c08f0a6e1d4d2941f1637ea728cd6fa8df01ce8bcc69e5.png
xcat Macro risk premium customised directional score, vol targeted returns Market risk score, directional, vol targeted returns Long only
Return % 9.765168 8.314899 7.025648
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.976517 0.83149 0.702565
Sortino Ratio 1.336394 1.112942 0.925355
Max 21-Day Draw % -36.565285 -41.390234 -42.691999
Max 6-Month Draw % -45.77502 -41.88914 -37.994371
Peak to Trough Draw % -54.041833 -48.768828 -62.285155
Top 5% Monthly PnL Share 0.556433 0.622572 0.760984
USD_EQXR_NSA correl 0.264455 0.293824 0.214687
UHY_CRXR_NSA correl 0.31816 0.350987 0.273763
UIG_CRXR_NSA correl 0.29464 0.332196 0.253393
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/8512c1fad493a76e5a247bb1d4d55ef470929ad60da16aeec922d36a3f6fedd4.png
dix = dict_dirc

sigs = dix['sigs']
ret = dix["targs"][1]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

rt = ret.split('_')[-1]  # 'NSA' or 'VT10'

pnls = msn.NaivePnL(
    df=dfx,
    ret=ret,
    sigs=sigs,
    cids=cidx,
    start=start,
    blacklist=black,
    bms=bms,
)
for sig in sigs:
    for bias in [0, 1]:
        pnls.make_pnl(
            sig=sig,
            sig_op="zn_score_pan",
            thresh=2,
            sig_add = bias,
            rebal_freq="monthly",
            neutral="zero",
            pnl_name=sig + "_PNL" + rt + str(bias),
            rebal_slip=1,
            vol_scale=10,
    )
pnls.make_long_pnl(vol_scale=10, label="Long only")

dix["pnls_"+rt.lower()] = pnls
dix = dict_dirc
rt = "NSA"
bias = 1
pnls = dix["pnls_"+rt.lower()] 

sigs = ["MACROALL_RPS_CWS_ZN", "MARKETRISK_ZN"]
strats = [sig + "_PNL" + rt + str(bias) for sig in sigs]

pnl_labels = {
    'MACROALL_RPS_CWS_ZN_PNLNSA1': 'Macro risk premium customised directional score',
    'MARKETRISK_ZN_PNLNSA1': 'Market risk score, directional',
    'Long only': 'Long only'
}
pnls.plot_pnls(
    title=None,
    pnl_cats=strats + ["Long only"],
    xcat_labels=pnl_labels,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats + ["Long only"], label_dict=pnl_labels).round(3))
pnls.signal_heatmap(pnl_name=f"MACROALL_RPS_CWS_ZN_PNL" + rt + str(bias), figsize=(20, 10))
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/801a15bebcbb8b39a6db7b9c620f4a1a1879e6827b3f0a6987b2e41e9207dd95.png
xcat Macro risk premium customised directional score Market risk score, directional Long only
Return % 10.08657 9.300272 8.004047
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 1.008657 0.930027 0.800405
Sortino Ratio 1.418757 1.291543 1.079887
Max 21-Day Draw % -40.415401 -37.453612 -40.898679
Max 6-Month Draw % -46.012824 -42.623356 -44.785424
Peak to Trough Draw % -46.605959 -45.725342 -55.021649
Top 5% Monthly PnL Share 0.595555 0.619495 0.641037
USD_EQXR_NSA correl 0.281896 0.308603 0.270744
UHY_CRXR_NSA correl 0.349204 0.379014 0.343803
UIG_CRXR_NSA correl 0.349488 0.376879 0.330702
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/8512c1fad493a76e5a247bb1d4d55ef470929ad60da16aeec922d36a3f6fedd4.png

Customized relative signals #

Specs and panel test #

dict_relc = {
    "sigs": ['MACROSPREAD_RPS_CWS_ZNvEM','MACRORATING_RPS_CWS_ZNvEM', 'MACROALL_RPS_CWS_ZNvEM', 'MARKETRISK_ZNvEM'],
    "targs": ["FCBIXR_VT10vEM", "FCBIXR_NSAvEM"],
    "cidx": cids_fc,
    "start": "2000-01-01",
    "black": black_fc,
}
dix = dict_relc

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

catregs = {}
for sig in sigs:
    catregs[sig] = msp.CategoryRelations(
        dfx,
        xcats=[sig, ret],
        cids=cidx,
        freq="Q",
        lag=1,
        xcat_aggs=["mean", "sum"],
        start=start,
        blacklist=black,
    )

msv.multiple_reg_scatter(
    cat_rels=[v for k, v in catregs.items()],
    ncol=2,
    nrow=2,
    figsize=(14, 12),
    title=None,
    title_fontsize=20,
    xlab="End-of-quarter score",
    ylab="Foreign currency bond index excess returns, vol targeted, %, next quarter",
    coef_box="lower right",
    prob_est="map",
    single_chart=True,
    subplot_titles=[dict_labels[key] for key in sigs]
)
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/b1ad60399ab7e74faa7547259a33f69dc09e047303a3a383509d87ff6c08199d.png

Accuracy and correlation check #

dix = dict_relc

sigs = dix['sigs']
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

srr = mss.SignalReturnRelations(
    dfx,
    rets=ret,
    cids=cidx,
    sigs=sigs,
    # cosp=True,
    freqs="M",
    agg_sigs=["mean"],  # for stability
    start=start,
)

dix["srr"] = srr
dix = dict_relc
srr = dix["srr"]

tbl=srr.multiple_relations_table(signal_name_dict=dict_labels,return_name_dict={'FCBIXR_VT10vEM': 'Relative foreign currency bond index returns, volatility adjusted'}).round(3)
display(tbl.transpose())
Return Relative foreign currency bond index returns, volatility adjusted
Signal Relative market risk score Relative macro-spread risk premium score, custom weights Relative macro-rating risk premium score, custom weights Relative macro risk premium score, custom weights
Frequency M M M M
Aggregation mean mean mean mean
accuracy 0.532 0.528 0.525 0.534
bal_accuracy 0.532 0.528 0.525 0.534
pos_sigr 0.491 0.489 0.522 0.498
pos_retr 0.500 0.501 0.500 0.500
pos_prec 0.533 0.530 0.523 0.534
neg_prec 0.531 0.527 0.526 0.533
pearson 0.031 0.024 0.050 0.040
pearson_pval 0.018 0.073 0.000 0.002
kendall 0.042 0.030 0.041 0.039
kendall_pval 0.000 0.001 0.000 0.000
auc 0.532 0.528 0.525 0.534

Naive PnLs #

dix = dict_relc

sigs = dix["sigs"]
ret = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
black = dix["black"]

pnls = msn.NaivePnL(
    df=dfx,
    ret=ret,
    sigs=sigs,
    cids=cidx,
    start=start,
    blacklist=black,
    bms=bms,
)
for sig in sigs:
    pnls.make_pnl(
        sig=sig,
        sig_op="zn_score_pan",
        thresh=2,
        sig_add=0,
        rebal_freq="monthly",
        neutral="zero",
        pnl_name=sig + "_PNL",
        rebal_slip=1,
        vol_scale=10,
    )

dix["pnls"] = pnls
dix = dict_relc
bias = 0
pnls = dix["pnls"]
sigs = dix["sigs"]

sigs = ["MACROSPREAD_RPS_CWS_ZNvEM", "MACRORATING_RPS_CWS_ZNvEM", "MACROALL_RPS_CWS_ZNvEM"]
strats = [sig + "_PNL" for sig in sigs]

pnl_labels = {
    "MACROSPREAD_RPS_CWS_ZNvEM_PNL": "Spread-based relative macro risk premium score",
    "MACRORATING_RPS_CWS_ZNvEM_PNL": "Ratings-based relative macro risk premium score",
    "MACROALL_RPS_CWS_ZNvEM_PNL": "Composite relative macro risk premium score",
}

pnls.plot_pnls(
    title="Naive PnL for relative risk-premia strategies, 24 EM sovereigns, 4-factor macro risk",
    pnl_cats=strats,
    xcat_labels=pnl_labels,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats,label_dict=pnl_labels).round(3))
pnls.signal_heatmap(pnl_name=f"MACROALL_RPS_CWS_ZNvEM_PNL", figsize=(20, 10))
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/b9bcd07d36e898cf93734a674ec2a24ea1fa80c1b1395574c91c3a81f8bd5a72.png
xcat Spread-based relative macro risk premium score Ratings-based relative macro risk premium score Composite relative macro risk premium score
Return % 4.252493 5.308314 4.99858
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.425249 0.530831 0.499858
Sortino Ratio 0.598804 0.75004 0.704273
Max 21-Day Draw % -16.47829 -20.289363 -19.03669
Max 6-Month Draw % -24.380391 -28.480566 -27.770239
Peak to Trough Draw % -46.541167 -49.70223 -49.975228
Top 5% Monthly PnL Share 0.992853 0.784579 0.837347
USD_EQXR_NSA correl 0.118336 0.177049 0.171281
UHY_CRXR_NSA correl 0.14116 0.189587 0.190359
UIG_CRXR_NSA correl 0.120715 0.173418 0.173881
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/estimating-em-sovereign-risk-premia/_images/133139323608033bd98c0fd831593a2fbd9c027ae64ec070f4eac3c25a52b076.png