EM sovereign risk premia indices with EMBI adjustment #

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
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import display

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 23214 tickers.
Removed 82/840 expressions that are not in the JPMaQS catalogue.
Downloading data from JPMaQS.
Timestamp UTC:  2025-07-09 08:45:06
Connection successful!
Requesting data: 100%|███████████████████████████████████| 38/38 [00:07<00:00,  4.92it/s]
Downloading data: 100%|██████████████████████████████████| 38/38 [00:31<00:00,  1.21it/s]
Time taken to download data: 	40.69 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: 4678657 entries, 0 to 4678656
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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/5ed57ded5b8b965cafeab9e78c5a8c72ca750ba368b76e1661216170c7d9ee5e.png
xcatx = xbal
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/cd490ca55628976be05284271a7fe0ef693fa9e7297025147071d8479b80f29a.png
xcatx = xliab
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/b4078ab4754657dc94d75ab5b0a997f5911a7b15025fa416c43577de2f661b46.png
xcatx = xdebt
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/f4734242772164baf2229472945d254c13f6edd5de6eb53f73ca7f5fefe5c344.png
xcatx = risk_metrics
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/1ff71aadd687ca49a182f56bce9e691e596fc0b2e2407256af341b955cb73da4.png
xcatx = rets
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/db635b39f942dedde8f4a2171efdd3dbed37388e3772babd7f9607bd1be3a99e.png
xcatx = growth
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/d1d73f401a58f8d79bdf03a2265659f4bb2fcedcf1da6116d33dc81ecd09506e.png
xcatx = infl
msm.check_availability(df=dfx, xcats=xcatx, cids=cids_em, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/9afb27e54139a6a51a0f9983cb799dabf44507ce3a561f4e9415a807904fde6e.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 (percentage)")
plt.ylabel("Presumed impact on default risk")
plt.grid(True)
plt.show()
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/75fadff925fd6d24d3a88810b84c9265f05942c4a8769bbe5dac3c85cec67641.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",
    aspect=2,
    same_y=False,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/a2213c5e36d125c1b2b7f2010ee0d593ba1a1995d5ad157093eb20a1f8a6a73f.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"
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"
# 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,
    title=None,
    title_fontsize=22,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/eba52961f7887ddd551625121b1d538652c57cfe58747840aaa2dac7a8a196b3.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/8f46c2ebe45c4d3349e0ff34a8e6440aae17c0df2d7e2100e2814ea8951b9f67.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,
    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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/b55d06ef494d3c3e2cb981f21d454d7d13d671383fb64fe947cbf47e07690a1d.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/fbe6ba73c8f23c9e792a342b1a98b2cdb9bf21869866e2b41d42d3b0f09a8dd4.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,
}
# Weighted composite macro risk scores

cidx = cids_fc
xcatx = macroz

equal_weights = [1/len(macroz)] * len(macroz)
custom_weights = [dict_custom_weights[m] for m in macroz]
weights = {
    "EWS": equal_weights,
    "CWS": custom_weights,
}

for k, w in weights.items():
    dfa = msp.linear_composite(
        dfx,
        xcats=xcatx,
        cids=cidx,
        weights=w,
        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'] = 'Equally weighted 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,
    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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/f2942155cc3fecfd6ede64a110a01816dcf50e88821c7b58dcb12d088b20ee78.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/3d156bc9919c83382a7c4d8000cd2a6efbc91c2d7c2efe2d5a9e9b1541f7a3a8.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,
    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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/603abedbee6a1752f08e784678968b6c8f758243e82d4d8c99f664396cdf62fe.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,
    aspect=2,
    height=2,
    blacklist=black_fc
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/6b4a8f6a3eb82d8f22e45c5e4f94e89af071dc1ed971e2f00a2b6befffa60b5b.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/56f5332a4207549ee995fcac6aacd0ce6cc6f635fc005f63b8847d2de696fb53.png

Distribution bias analysis #

Macro risk distribution #

xcat = 'INFLRISK_ZN' # 'GFINRISK_ZN', 'XBALRISK_ZN', 'XLIABRISK_ZN', 'XDEBTRISK_ZN', 'GOVRISK_ZN', 'GROWTHRISK_ZN', 'INFLRISK_ZN' # MACRORISK_EWS_ZN, MACRORISK_CWS_ZN
dfxa = dfx[(dfx['xcat'] == xcat)]  

plt.figure(figsize=(10, 6))
sns.histplot(dfxa['value'], kde=True, bins=40, color='steelblue', edgecolor='black')

mean_val = dfxa['value'].mean()
median_val = dfxa['value'].median()
plt.axvline(mean_val, color='red', linestyle='--', label=f'Mean: {mean_val:.2f}')
plt.axvline(median_val, color='green', linestyle='--', label=f'Median: {median_val:.2f}')

plt.title(f"Distribution of {dict_labels[xcat]} with bias", fontsize=14)
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.legend()

plt.tight_layout()
plt.show()
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/65a7342ac9033483b023f5f3d79e6ab4de3a7d6274c6e88be0705c2cc0b80aa9.png
summary_stats = dfx[dfx['xcat'].isin(macroz)].groupby('xcat')['value'].agg(['mean', 'median']).reset_index()
summary_long = summary_stats.melt(id_vars='xcat', value_vars=['mean', 'median'], var_name='stat')
summary_long['xcat_lab'] = summary_long['xcat'].map(dict_labels)

# Plot using the new column
plt.figure(figsize=(10, 6))
sns.barplot(data=summary_long, x='xcat_lab', y='value', hue='stat')
plt.title("Mean and Median per macro score")
plt.ylabel("Value")
plt.xlabel("Category")
plt.axhline(0, linestyle='--', color='gray')

# Rotate x-axis labels
plt.xticks(rotation=30)

plt.tight_layout()
plt.show()
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/4cf1a8ac3af521ac35bb060ddf320dfd0fafe1f90310e4ec64df0790d12a63b8.png
macroz_total = macroz + ['MACRORISK_EWS_ZN'] + ['MACRORISK_CWS_ZN']
dfxa = dfx[dfx['xcat'].isin(macroz_total)].copy()

dfxa['is_positive'] = dfxa['value'] > 0
dfxa['is_negative'] = dfxa['value'] < 0

category_stats = (
    dfxa.groupby('xcat')
    .agg(
        positives=('is_positive', 'sum'),
        negatives=('is_negative', 'sum'),
        total=('value', 'count')
    )
    .reset_index()
)

category_stats['share_positive'] = (
    category_stats['positives'] / category_stats['total']
).map("{:.2%}".format)

category_stats['xcat_label'] = category_stats['xcat'].map(dict_labels)

category_stats = category_stats[['xcat_label', 'positives', 'negatives', 'total', 'share_positive']]
display(category_stats.sort_values('share_positive', ascending=False))
xcat_label positives negatives total share_positive
5 Equally weighted macro risk score 109641 62151 171792 63.82%
7 Foreign-currency debt risk score 123060 80451 203511 60.47%
2 Growth risk score 111166 76724 187955 59.15%
4 Custom weighted macro risk score 99074 72718 171792 57.67%
0 Government finances risk score 112877 104438 217315 51.94%
6 External balances risk score 102714 97850 200564 51.21%
1 Governance risk score 113187 108711 221898 51.01%
3 Inflation risk score 64800 92403 157226 41.21%
8 International position risk score 63389 90920 155237 40.83%

From the above, we can conclude that the distribution is not excessively weighted in either direction - however the number of positives is higher than 50% in all categories except for the inflation and the international position scores. Therefore, we find a positive bias in the scores.

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=10,
    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 decades, since 2000",
    title_fontsize=16,
    xlab="Rated risk score, decade average",
    ylab="Credit spread score, decade average",
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/cb95af09d495a4f1a4c09f8e4038072f067e7ce8186ef907f1e8e79cf3d57ae1.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=10,
    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 decades, since 2000",
    title_fontsize=16,
    xlab=None,
    ylab=None,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/e7f2cfef34bf821968dce8ca3769d239e46327dc2563d6e0248d38204a10bf09.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=10,
    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 decades, since 2000",
    title_fontsize=16,
    xlab=None,
    ylab=None,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/8ea9b220d5b6b89ca758580944b9855c138a7247be1f2c0675662d9d417483cc.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=10,
    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 decades, 24 sovereigns, since 2000",
    title_fontsize=16,
    xlab="Sovereign credit-related macro risk score, decade average (as far as available)",
    ylab="Market risk score, decade average (as far as available)",
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/95ed976d07e10e207f93a4f7a39850c57bbae6419498a3bb33ae910d3c46b254.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 and subsequent return measures 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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/8c8a710b4d649eeee86467f78e15c7b0fc729784ac67d77bb92e893ca72563a3.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)
        all_titles.append(risk + " vs. " + ret)

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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/589ef58a9a77ec336612f692aa77b61f43967a108bb9e82d17ffbdd705a7caea.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"] = "Broad 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"] = "Broad 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,
    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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/a3c3cb5d4fc4c9c943511a28fba06684689dab2b41a487207c45e651c88793e6.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/8c9967b1331b357489cc18029e77eba267d05c09cc346304184f7ce2e54c6f38.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]
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,
    title=None,
    title_fontsize=22,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/2569afa27dbff055ce104551340a759f197dc76ae8db51b90a8d66dd7ee0c80a.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/2fe00b0c82de2b7bdca7cfc9f993cfd8c12cb2ebcc08a8307569c56cfeb8d643.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,
    title="Relative macro risk premium scores (all versus EM average)",
    title_fontsize=25,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/cb54ce4b8542586d6acc9a3f7d70ba4798e639bd04349e4876132a40ff0ec3d5.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/072c9d527234a2bd379f02e55af57055995fe1129a0679c1126db5a4e5b85c81.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,
    aspect=2,
    title=None,
    title_fontsize=22,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/21909829e0a7b8b827a0bf5782b270213f6713c372e958a02ffae2a4b898342d.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/bca37f97efd2f1000fda4828dccd629341f6f0077e6d681467ae36d6ec2dbb3a.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]

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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/48b699bbf0c0f601f3829daa51159f266c4051a3e34a4ddad48eaa13bc351134.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="Broad 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=(11, 7),
)

cr.reg_scatter(
    title="Macro risk premia and subsequent foreign currency bond index excess returns, 24 countries since 2000",
    labels=False,
    xlab=None,
    ylab=None,
    coef_box="lower right",
    prob_est="pool",
    separator="cids",
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/34fd6f9c207df439cd01c6dd870ad1a40f4c7101d633e764ddc2dbf561a58e97.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/86a6b2b53fbf798c9b0af6e229e400d38ce9996e0229361cbb4c2ca69ae3702a.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().round(3)
display(tbl.transpose())
Return FCBIXR_VT10
Signal MACROALL_RPS_ZN MACRORATING_RPS_ZN MACROSPREAD_RPS_ZN MARKETRISK_ZN
Frequency M M M M
Aggregation last last last last
accuracy 0.465 0.474 0.452 0.502
bal_accuracy 0.515 0.511 0.511 0.510
pos_sigr 0.282 0.336 0.239 0.462
pos_retr 0.609 0.607 0.607 0.608
pos_prec 0.630 0.621 0.624 0.619
neg_prec 0.400 0.400 0.398 0.401
pearson 0.042 0.035 0.040 0.020
pearson_pval 0.001 0.009 0.003 0.122
kendall 0.038 0.028 0.045 0.025
kendall_pval 0.000 0.002 0.000 0.004
auc 0.513 0.510 0.508 0.511
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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/d29c521ab3f59effb1419b5307124d6379d98c70f88ef3247308adc806efbffc.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/3506cdcb092507f3970350739d2d1a520efc051fa323a89a2925a9a9a900b146.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))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/c8765303edee2c11054fee579cacce8ecf5cabbdc044e91ce8f37df3b632dd4f.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/9224ea35f04ee4eaaa5043b6141808ea588f18691c418430b451b8614857b980.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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/4c2a3634cce222fea580e79220c4792ad01659105189afe08ba0046664d12a0b.png
xcat MACROALL_RPS_ZN_PNLVT101 MARKETRISK_ZN_PNLVT101 Long only
Return % 11.941121 8.271644 6.981771
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 1.194112 0.827164 0.698177
Sortino Ratio 1.666455 1.107006 0.919443
Max 21-Day Draw % -39.285979 -41.389511 -42.691756
Max 6-Month Draw % -57.287173 -41.888409 -37.994155
Peak to Trough Draw % -67.584771 -48.767977 -62.284802
Top 5% Monthly PnL Share 0.491087 0.626005 0.765992
USD_EQXR_NSA correl 0.216796 0.293771 0.214621
UHY_CRXR_NSA correl 0.262238 0.350945 0.273707
UIG_CRXR_NSA correl 0.257687 0.332166 0.253349
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/e5c36c38fab6ffb123b3d8ce2617c700428dada67cd295cd48e0ab94b90981f0.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"]).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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/d5e831d303e959a03b0c1e8cb77febb567587f7c84b2904a0cdbfc2b9f34f84e.png
xcat MACROALL_RPS_ZN_PNLNSA1 MARKETRISK_ZN_PNLNSA1 Long only
Return % 11.258397 9.279441 7.977636
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 1.12584 0.927944 0.797764
Sortino Ratio 1.607187 1.288616 1.076272
Max 21-Day Draw % -50.833232 -37.448958 -40.894491
Max 6-Month Draw % -58.256379 -42.61806 -44.780838
Peak to Trough Draw % -58.842786 -45.719661 -55.016014
Top 5% Monthly PnL Share 0.570361 0.620995 0.643287
USD_EQXR_NSA correl 0.247415 0.308574 0.270703
UHY_CRXR_NSA correl 0.304648 0.37899 0.343767
UIG_CRXR_NSA correl 0.332373 0.376858 0.330674
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/e5c36c38fab6ffb123b3d8ce2617c700428dada67cd295cd48e0ab94b90981f0.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=sigs,
)
XLIABRISK_RPS_ZN misses: ['AED', 'OMR', 'QAR', 'SAR'].
XDEBTRISK_RPS_ZN misses: ['QAR'].
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/0d7538734e64c615361ad8b61fb46c37519d7184f9549281194739bce26da2ce.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().round(3)
display(tbl.transpose())
Return FCBIXR_VT10
Signal GFINRISK_RPS_ZN GOVRISK_RPS_ZN GROWTHRISK_RPS_ZN INFLRISK_RPS_ZN MARKETRISK_ZN XBALRISK_RPS_ZN XDEBTRISK_RPS_ZN XLIABRISK_RPS_ZN
Frequency M M M M M M M M
Aggregation mean mean mean mean mean mean mean mean
accuracy 0.483 0.470 0.486 0.509 0.501 0.482 0.446 0.512
bal_accuracy 0.506 0.491 0.508 0.513 0.510 0.510 0.502 0.519
pos_sigr 0.393 0.403 0.399 0.481 0.459 0.371 0.244 0.468
pos_retr 0.608 0.609 0.608 0.609 0.609 0.608 0.609 0.603
pos_prec 0.616 0.598 0.618 0.623 0.619 0.620 0.611 0.623
neg_prec 0.396 0.384 0.398 0.404 0.400 0.400 0.392 0.415
pearson 0.025 0.019 0.010 0.051 0.022 0.011 0.019 0.033
pearson_pval 0.050 0.135 0.451 0.000 0.086 0.401 0.141 0.024
kendall 0.027 0.011 0.010 0.030 0.025 0.024 0.020 0.028
kendall_pval 0.002 0.204 0.246 0.001 0.003 0.008 0.023 0.005
auc 0.506 0.491 0.508 0.514 0.510 0.510 0.501 0.520
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))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/034751bf90a1cd087ed7b2a62544511f627b9f00a0f235baf333cfa6da443c6d.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/9d931a3affe18ec8b2a82e2b4a4af8203f5370cd3dc26cd93f09e5f6263d95ba.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))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/a9f0c8138dbf897ce8087c4169b5014cfc4ed0acfc3381b5c32211900b7f6383.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/7ea5ff21f4c07de8f1a19f729029156ec83e3debb3dd09e5ab8b2236c41b6047.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]

pnls.plot_pnls(
    title=None,
    pnl_cats=strats + ["Long only"],
    xcat_labels=None,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats + ["Long only"]).round(3))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/9d5d76636d546746fc3dd5e2aed12c4487311017b5ea0d7b36ee04c7fe9f03be.png
xcat GFINRISK_RPS_ZN_PNLVT101 XBALRISK_RPS_ZN_PNLVT101 XLIABRISK_RPS_ZN_PNLVT101 XDEBTRISK_RPS_ZN_PNLVT101 GOVRISK_RPS_ZN_PNLVT101 GROWTHRISK_RPS_ZN_PNLVT101 INFLRISK_RPS_ZN_PNLVT101 MARKETRISK_ZN_PNLVT101 Long only
Return % 9.069923 7.845259 7.809989 9.365857 7.504711 7.198478 9.37071 8.271644 6.981771
St. Dev. % 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
Sharpe Ratio 0.906992 0.784526 0.780999 0.936586 0.750471 0.719848 0.937071 0.827164 0.698177
Sortino Ratio 1.223952 1.053887 1.079442 1.254567 1.008694 0.944812 1.252072 1.107006 0.919443
Max 21-Day Draw % -40.2581 -45.128045 -42.395547 -44.926691 -41.718641 -48.35131 -46.333155 -41.389511 -42.691756
Max 6-Month Draw % -62.208723 -31.774818 -30.875384 -64.946729 -33.97102 -75.899135 -29.854672 -41.888409 -37.994155
Peak to Trough Draw % -70.439488 -54.783041 -52.099888 -76.664861 -52.11325 -80.593515 -47.749902 -48.767977 -62.284802
Top 5% Monthly PnL Share 0.570024 0.609965 0.726904 0.604738 0.732884 0.682009 0.637261 0.626005 0.765992
USD_EQXR_NSA correl 0.265795 0.274654 0.268843 0.23677 0.233034 0.216362 0.224042 0.293771 0.214621
UHY_CRXR_NSA correl 0.326415 0.328388 0.318423 0.289318 0.286144 0.260542 0.295498 0.350945 0.273707
UIG_CRXR_NSA correl 0.327803 0.307722 0.297385 0.308329 0.25085 0.261868 0.267672 0.332166 0.253349
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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/4f39fc361fcad960d8110246d4913e226d3e43166ff5128eb3bc81e81ba63b4c.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=None,
    labels=False,
    xlab=None,
    ylab=None,
    coef_box="lower right",
    prob_est="map",
    separator=2012,
    size=(12, 8),
)

cr.reg_scatter(
    title=None,
    labels=False,
    xlab=None,
    ylab=None,
    coef_box="lower right",
    prob_est="pool",
    separator="cids",
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/3280ad88bbc7a52c2394adf467b42850eb4111b6df2d8fb1f31416c32c379f1b.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/3eea6254ed26c199283c384787b87b6f416b1bb8f3c0572b41aebbe33ee3c3af.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().round(3)
display(tbl.transpose())
Return FCBIXR_VT10vEM
Signal MACROALL_RPS_ZNvEM MACRORATING_RPS_ZNvEM MACROSPREAD_RPS_ZNvEM MARKETRISK_ZNvEM
Frequency M M M M
Aggregation mean mean mean mean
accuracy 0.527 0.521 0.525 0.532
bal_accuracy 0.527 0.521 0.525 0.532
pos_sigr 0.514 0.497 0.501 0.491
pos_retr 0.500 0.499 0.501 0.500
pos_prec 0.526 0.521 0.526 0.533
neg_prec 0.528 0.522 0.524 0.531
pearson 0.033 0.046 0.015 0.031
pearson_pval 0.013 0.001 0.272 0.018
kendall 0.036 0.038 0.026 0.043
kendall_pval 0.000 0.000 0.003 0.000
auc 0.527 0.521 0.525 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))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/1b9aedec140c567ec662f22569f6ea46b4924e5d11c9652757274d55a70a079c.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/c0df28b010fc8cc7ff4343d69f7536ee5dd98e5acc4727ca90883b371f3fe39a.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))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/77fd2122a2ad31a5471676fd4003b8d9f1cf570380070d5ddcba82bc212aa300.png https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/399d80a4546710292b9eb4ac4ea6e63df0568e2eccfd07642ddcf8d66e06a1bd.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=(20, 10))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/052fd44ee972160d85b2b94c0e14cf95ab3418ba54251e292f8088a8e43bd102.png
xcat MACROSPREAD_RPS_ZNvEM_PNL MACRORATING_RPS_ZNvEM_PNL MACROALL_RPS_ZNvEM_PNL
Return % 3.288327 4.940587 4.336086
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.328833 0.494059 0.433609
Sortino Ratio 0.462594 0.701466 0.617352
Max 21-Day Draw % -14.292397 -21.642034 -17.734183
Max 6-Month Draw % -19.451053 -29.285285 -24.164561
Peak to Trough Draw % -42.26313 -50.507665 -46.689844
Top 5% Monthly PnL Share 1.22375 0.852004 1.022676
USD_EQXR_NSA correl 0.014075 0.094128 0.093128
UHY_CRXR_NSA correl 0.010943 0.091992 0.092796
UIG_CRXR_NSA correl -0.011382 0.09323 0.084991
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/1f2117c516389fdd1b6d2a4ad2da6678491ea9c98d5ca57d744ca00279514f88.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=sigs,
)
XLIABRISK_RPS_ZNvEM misses: ['AED', 'OMR', 'QAR', 'SAR'].
XDEBTRISK_RPS_ZNvEM misses: ['QAR'].
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/28ea8714483e9dc341d39ae311f9d88d537628b2f64d6efbbc31f8da8e2fcce0.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().round(3)
display(tbl.transpose())
Return FCBIXR_VT10vEM
Signal GFINRISK_RPS_ZNvEM GOVRISK_RPS_ZNvEM GROWTHRISK_RPS_ZNvEM INFLRISK_RPS_ZNvEM MARKETRISK_ZNvEM XBALRISK_RPS_ZNvEM XDEBTRISK_RPS_ZNvEM XLIABRISK_RPS_ZNvEM
Frequency M M M M M M M M
Aggregation mean mean mean mean mean mean mean mean
accuracy 0.518 0.513 0.525 0.512 0.532 0.527 0.517 0.538
bal_accuracy 0.518 0.513 0.525 0.512 0.532 0.527 0.517 0.538
pos_sigr 0.500 0.525 0.467 0.499 0.491 0.479 0.442 0.503
pos_retr 0.500 0.500 0.499 0.500 0.500 0.500 0.500 0.498
pos_prec 0.518 0.512 0.526 0.512 0.533 0.529 0.519 0.536
neg_prec 0.519 0.513 0.524 0.511 0.531 0.525 0.515 0.540
pearson 0.021 0.017 0.031 0.008 0.031 0.027 0.012 0.051
pearson_pval 0.106 0.203 0.020 0.560 0.018 0.045 0.364 0.001
kendall 0.024 0.016 0.032 0.011 0.043 0.039 0.022 0.054
kendall_pval 0.006 0.064 0.000 0.209 0.000 0.000 0.012 0.000
auc 0.518 0.513 0.525 0.512 0.532 0.527 0.517 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]

pnls.plot_pnls(
    title=None,
    pnl_cats=strats,
    xcat_labels=None,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats).round(3))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/c3c0ed80732933568eb920a5a52ea5e7d48bbcd2e1cb603556b11f30530b5dd8.png
xcat GFINRISK_RPS_ZNvEM_PNL XBALRISK_RPS_ZNvEM_PNL XLIABRISK_RPS_ZNvEM_PNL XDEBTRISK_RPS_ZNvEM_PNL GOVRISK_RPS_ZNvEM_PNL GROWTHRISK_RPS_ZNvEM_PNL INFLRISK_RPS_ZNvEM_PNL MARKETRISK_ZNvEM_PNL
Return % 2.47308 3.473918 4.12682 1.383826 2.109722 3.8722 0.616067 3.02565
St. Dev. % 10.0 10.0 10.0 10.0 10.0 10.0 10.0 10.0
Sharpe Ratio 0.247308 0.347392 0.412682 0.138383 0.210972 0.38722 0.061607 0.302565
Sortino Ratio 0.345823 0.482246 0.582193 0.192992 0.290773 0.549068 0.084237 0.416436
Max 21-Day Draw % -19.310212 -24.721489 -19.278482 -14.346869 -20.308393 -15.011376 -28.951867 -26.061055
Max 6-Month Draw % -28.772082 -29.927572 -40.062134 -26.601295 -30.361158 -26.344571 -32.909141 -35.628673
Peak to Trough Draw % -49.081092 -49.161827 -67.013019 -87.665029 -57.298105 -56.962764 -51.144561 -68.505051
Top 5% Monthly PnL Share 1.548534 1.092845 1.00857 3.963254 2.049111 1.266296 6.857896 1.517778
USD_EQXR_NSA correl 0.197936 0.220929 0.18575 0.085974 0.107427 0.053381 0.182097 0.252877
UHY_CRXR_NSA correl 0.222129 0.233202 0.184669 0.072825 0.108661 0.031029 0.202996 0.262652
UIG_CRXR_NSA correl 0.231882 0.229148 0.184079 0.087605 0.049114 0.018697 0.207417 0.24825
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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/713b8939abe53994efeecfa898707665490f26c58763a903ba32f95e18cca101.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().round(3)
display(tbl.transpose())
Return FCBIXR_VT10
Signal MACROALL_RPS_CWS_ZN MACRORATING_RPS_CWS_ZN MACROSPREAD_RPS_CWS_ZN MARKETRISK_ZN
Frequency M M M M
Aggregation last last last last
accuracy 0.486 0.500 0.475 0.502
bal_accuracy 0.514 0.516 0.515 0.510
pos_sigr 0.375 0.423 0.322 0.462
pos_retr 0.609 0.606 0.608 0.608
pos_prec 0.625 0.626 0.628 0.619
neg_prec 0.402 0.407 0.402 0.401
pearson 0.031 0.024 0.028 0.020
pearson_pval 0.016 0.076 0.031 0.122
kendall 0.034 0.022 0.041 0.025
kendall_pval 0.000 0.014 0.000 0.004
auc 0.513 0.517 0.514 0.511

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]

pnls.plot_pnls(
    title=None,
    pnl_cats=strats + ["Long only"],
    xcat_labels=None,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats + ["Long only"]).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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/5861032cb157b10ef821dbf9b7b2aab0f01ef5d45f2e04defdba168836429511.png
xcat MACROALL_RPS_CWS_ZN_PNLVT101 MARKETRISK_ZN_PNLVT101 Long only
Return % 9.723982 8.271644 6.981771
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.972398 0.827164 0.698177
Sortino Ratio 1.330586 1.107006 0.919443
Max 21-Day Draw % -36.552005 -41.389511 -42.691756
Max 6-Month Draw % -45.795554 -41.888409 -37.994155
Peak to Trough Draw % -54.065154 -48.767977 -62.284802
Top 5% Monthly PnL Share 0.559016 0.626005 0.765992
USD_EQXR_NSA correl 0.264369 0.293771 0.214621
UHY_CRXR_NSA correl 0.318083 0.350945 0.273707
UIG_CRXR_NSA correl 0.294593 0.332166 0.253349
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/22a31724fea26134ad742b1a269752c2a2e76a20194b4b68fd558a4fb5ec0ce4.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]

pnls.plot_pnls(
    title=None,
    pnl_cats=strats + ["Long only"],
    xcat_labels=None,
    title_fontsize=14,
)
display(pnls.evaluate_pnls(pnl_cats=strats + ["Long only"]).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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/f5f1da03727dfb58836468487a4fcd3433cba1f66e6fcdb56b46d7dd67576204.png
xcat MACROALL_RPS_CWS_ZN_PNLNSA1 MARKETRISK_ZN_PNLNSA1 Long only
Return % 10.068208 9.279441 7.977636
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 1.006821 0.927944 0.797764
Sortino Ratio 1.416162 1.288616 1.076272
Max 21-Day Draw % -40.423659 -37.448958 -40.894491
Max 6-Month Draw % -46.023889 -42.61806 -44.780838
Peak to Trough Draw % -46.616176 -45.719661 -55.016014
Top 5% Monthly PnL Share 0.596812 0.620995 0.643287
USD_EQXR_NSA correl 0.281831 0.308574 0.270703
UHY_CRXR_NSA correl 0.349138 0.37899 0.343767
UIG_CRXR_NSA correl 0.349461 0.376858 0.330674
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/22a31724fea26134ad742b1a269752c2a2e76a20194b4b68fd558a4fb5ec0ce4.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/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/318123c488841763a4f2355bc311a6354956e3b8404c3d17a0e5db477e952389.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().round(3)
display(tbl.transpose())
Return FCBIXR_VT10vEM
Signal MACROALL_RPS_CWS_ZNvEM MACRORATING_RPS_CWS_ZNvEM MACROSPREAD_RPS_CWS_ZNvEM MARKETRISK_ZNvEM
Frequency M M M M
Aggregation mean mean mean mean
accuracy 0.534 0.525 0.529 0.532
bal_accuracy 0.534 0.525 0.529 0.532
pos_sigr 0.498 0.522 0.488 0.491
pos_retr 0.500 0.499 0.501 0.500
pos_prec 0.534 0.523 0.530 0.533
neg_prec 0.534 0.527 0.527 0.531
pearson 0.040 0.050 0.024 0.031
pearson_pval 0.002 0.000 0.072 0.018
kendall 0.039 0.041 0.030 0.043
kendall_pval 0.000 0.000 0.001 0.000
auc 0.534 0.525 0.529 0.532

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).round(3))
pnls.signal_heatmap(pnl_name=f"MACROALL_RPS_CWS_ZNvEM_PNL", figsize=(20, 10))
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/a2c1081dbc2572871cf2fc7861e28c924a8efac89f0cb12782dc8492399c5a84.png
xcat MACROSPREAD_RPS_CWS_ZNvEM_PNL MACRORATING_RPS_CWS_ZNvEM_PNL MACROALL_RPS_CWS_ZNvEM_PNL
Return % 4.255976 5.319186 5.008264
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.425598 0.531919 0.500826
Sortino Ratio 0.599296 0.751592 0.705644
Max 21-Day Draw % -16.477927 -20.290186 -19.037499
Max 6-Month Draw % -24.371469 -28.475671 -27.764184
Peak to Trough Draw % -46.543223 -49.702669 -49.978826
Top 5% Monthly PnL Share 0.992143 0.783188 0.835917
USD_EQXR_NSA correl 0.118208 0.176955 0.171197
UHY_CRXR_NSA correl 0.141007 0.18947 0.190258
UIG_CRXR_NSA correl 0.120558 0.173319 0.173795
Traded Months 307 307 307
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/cf4ee299e409d9a4dea030393ee4b87d3b880237182139e99e7049678d9e50d5.png

EMBI Global proxy and modification #

Import EMBI global weights #

# Dictionary for labelling and mapping

dict_cids = {
    "AED": ["AE", "UAE"],
    "ARS": ["AR", "Argentina"],
    "BRL": ["BR", "Brazil"],
    "CLP": ["CL", "Chile"],
    "CNY": ["CN", "China"],
    "COP": ["CO", "Colombia"],
    "EGP": ["EG", "Egypt"],
    "DOP": ["DO", "Dominican Republic"],
    "HUF": ["HU", "Hungary"],
    "IDR": ["ID", "Indonesia"],
    "INR": ["IN", "India"],
    "MXN": ["MX", "Mexico"],
    "MYR": ["MY", "Malaysia"],
    "NGN": ["NG", "Nigeria"],
    "OMR": ["OM", "Oman"],
    "PAB": ["PA", "Panama"],
    "PEN": ["PE", "Peru"],
    "PHP": ["PH", "Philippines"],
    "PLN": ["PL", "Poland"],
    "QAR": ["QA", "Qatar"],
    "SAR": ["SA", "Saudi Arabia"],
    "RON": ["RO", "Romania"],
    "RSD": ["CS", "Serbia"],
    "RUB": ["RU", "Russia"],
    "THB": ["TH", "Thailand"],
    "TRY": ["TR", "Turkey"],
    "UYU": ["UY", "Uruguay"],
    "VEF": ["VE", "Venezuela"],
    "ZAR": ["ZA", "South Africa"],
}
cids_fc
['AED',
 'BRL',
 'CLP',
 'CNY',
 'COP',
 'DOP',
 'EGP',
 'HUF',
 'IDR',
 'INR',
 'MXN',
 'NGN',
 'OMR',
 'PEN',
 'PHP',
 'PLN',
 'QAR',
 'RON',
 'RSD',
 'RUB',
 'SAR',
 'TRY',
 'UYU',
 'ZAR']
# Import EMBI weights from DataQuery

## Mapping dataframe

expression_mapping_csv = "expression,country,cid\n"
DQ_ticker = "StatIndxWght"

for cid in cids_fc:
    expression_mapping_csv += f'"DB(SAGE,FC_EMBIG_{dict_cids[cid][0]},{DQ_ticker})",{dict_cids[cid][0]},{cid}\n'
df_map = pd.read_csv(io.StringIO(expression_mapping_csv), sep=",")

extra_expression = {
    "expression": "DB(SAGE,EMBIG,AM_IDX_TOT)",
    "country": "ALL",
    "cid": "ALL",
    "ticker": "ALL_EMBI_IDX",
}
df_map["ticker"] = df_map["cid"] + "_" + "EMBIWGT"
df_map = pd.concat([df_map, pd.DataFrame([extra_expression])], ignore_index=True)

## Download wide dataframe from J.P. Morgan DataQuery

with JPMaQSDownload() as downloader:

    dfw_weights = downloader.download(
        expressions=df_map["expression"].tolist(),
        start_date="1998-01-01",
        dataframe_format="wide",
        show_progress=True,
    )

    dfw_weights = dfw_weights.rename(columns=df_map.set_index("expression")["ticker"].to_dict())

st, ed = dfw_weights.index.min(), dfw_weights.index.max()
bdates = pd.bdate_range(st, ed, freq="B")

# Forward filling weights and convert to quantamental dataframe (and merge)

dfw_weights = dfw_weights.reindex(bdates).ffill()
dfw_weights.index.name = "real_date"
df_embi = msm.utils.ticker_df_to_qdf(dfw_weights)

dfx = msm.update_df(dfx, df_embi)
Downloading data from JPMaQS.
Timestamp UTC:  2025-07-09 08:56:12
Connection successful!
Requesting data: 100%|█████████████████████████████████████| 2/2 [00:00<00:00,  4.90it/s]
Downloading data: 100%|████████████████████████████████████| 2/2 [00:13<00:00,  6.93s/it]
Some dates are missing from the downloaded data. 
305 out of 7179 dates are missing.
risk_macros = ['MACROSPREAD_RPS_ZN','MACRORATING_RPS_ZN', 'MACROALL_RPS_ZN', 'MARKETRISK_ZN']
mask = dfx["xcat"] == "EMBIWGT"
dfx.loc[mask, "value"] = dfx.loc[mask].groupby("real_date")["value"].transform(lambda x: (x / x.sum() ) * 1 )

Modified weights #

Calculation #

# Define appropriate sigmoid function for adjusting weights

amplitude = 2
steepness = 5
midpoint = 0

def sigmoid(x, a=amplitude, b=steepness, c=midpoint):
    return a / (1 + np.exp(-b * (x - c)))


ar = np.array([i / 4 for i in range(-16, 18)])
plt.figure(figsize=(10, 6), dpi=80)
plt.plot(ar, sigmoid(ar))
plt.title("Sigmoid function that transforms normalized risk-macro scores into weight modifiers")
plt.show()

# Calculate adjusted weights

dfj = adjust_weights(
    dfx,
    weights_xcat="EMBIWGT",
    adj_zns_xcat="MACROALL_RPS_ZN",
    method="generic",
    adj_func=sigmoid,
    blacklist=black_fc,
    cids=cidx,
    adj_name="EMBIWGT_MOD",
)
dfj["value"] = dfj["value"]  # remove after change in function
dfx = msm.update_df(dfx, dfj)

dict_labels["EMBIWGT"] = "EMBI Global proxy weights"
dict_labels["EMBIWGT_MOD"] = "EMBIG weights modified by macro risk premia"
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/d86506a26c95581b3bc974413875106b49a73ff4c00335cd075c05531b01e347.png
# View timelines of weights

xcatx = ["EMBIWGT", "EMBIWGT_MOD"]
cidx = cids_fc
sdate = "2002-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=False,
    xcat_labels=dict_labels,
    title="Standard weights and modified weights for the EMBI proxy index",
    title_fontsize=22,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/6093c1e8584a16f85d7d5dea054a50b0c760c6c536c505efcf9cfd5f7c1e98fd.png

Evaluation #

dict_mod = {
    "sigs": ["EMBIWGT_MOD", "EMBIWGT"],
    "targ": "FCBIR_NSA",
    "cidx": cids_fc,
    "start": "2002-01-01",
    "black": black_fc,
    "srr": None,
    "pnls": None,
}
dix = dict_mod

sigs = dix["sigs"]
ret = dix["targ"]
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="raw",
        rebal_freq="monthly",
        neutral="zero",
        rebal_slip=1,
        vol_scale=None,
    )

dix["pnls"] = pnls
dix = dict_mod
pnls = dix["pnls"]
sigs = dix["sigs"]
pnl_cats=["PNL_" + sig for sig in sigs]

pnls.plot_pnls(
    title="EMBI proxy index and modified weights based on macro risk premia: naive PnLs",
    pnl_cats=pnl_cats,
    xcat_labels=[dict_labels[k] for k in sigs],
    title_fontsize=14,
    compounding=True,
)
pnls.evaluate_pnls(pnl_cats=pnl_cats)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/e16ef041272a8acb4d45d90ccf48b235a895d8fc6011b08916079fa323627edc.png
xcat PNL_EMBIWGT_MOD PNL_EMBIWGT
Return % 9.165722 7.09129
St. Dev. % 7.747423 6.2589
Sharpe Ratio 1.183067 1.132993
Sortino Ratio 1.637671 1.561661
Max 21-Day Draw % -30.643599 -25.999432
Max 6-Month Draw % -34.396888 -29.848671
Peak to Trough Draw % -35.156008 -30.147379
Top 5% Monthly PnL Share 0.473556 0.467006
USD_EQXR_NSA correl 0.283995 0.293117
UHY_CRXR_NSA correl 0.354631 0.372223
UIG_CRXR_NSA correl 0.368565 0.383069
Traded Months 282 282

Adjusted weights #

dfa = msp.adjust_weights(
    df=dfx,
    weights_xcat="EMBIWGT",
    adj_zns_xcat="MACROALL_RPS_ZN",
    method="lincomb",
    params=dict(min_score=-3, coeff_new=0.5),
    blacklist=black_fc,
    adj_name="EMBIWGT_ADJ",
)

dfx = msm.update_df(dfx, dfa)

dict_labels["EMBIWGT_ADJ"] = (
    "EMBIG weights adjusted towards weights of macro risk premium scores"
)
# View timelines of weights

xcatx = ["EMBIWGT", "EMBIWGT_ADJ"]
cidx = cids_fc
sdate = "2002-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    start=sdate,
    same_y=False,
    xcat_labels=dict_labels,
    title="Standard weights and adjusted weights for the EMBI proxy index",
    title_fontsize=22,
    legend_fontsize=16,
    height=2,
)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/a8123c38209184cc98aaae80d14be7c00b69f4e0509697f403d897f5e5c22ffa.png

Evaluation #

dict_adj = {
    "sigs": ["EMBIWGT_ADJ", "EMBIWGT"],
    "targ": "FCBIR_NSA",
    "cidx": cids_fc,
    "start": "2002-01-01",
    "black": black_fc,
    "srr": None,
    "pnls": None,
}
dix = dict_adj

sigs = dix["sigs"]
ret = dix["targ"]
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="raw",
        rebal_freq="monthly",
        neutral="zero",
        rebal_slip=1,
        vol_scale=None,
    )

dix["pnls"] = pnls
dix = dict_adj
pnls = dix["pnls"]
sigs = dix["sigs"]
pnl_cats=["PNL_" + sig for sig in sigs]

pnls.plot_pnls(
    title="EMBI proxy index and adjusted weights based on macro risk premium scores: naive PnLs",
    pnl_cats=pnl_cats,
    xcat_labels=[dict_labels[k] for k in sigs],
    title_fontsize=14,
    compounding=True,
)
pnls.evaluate_pnls(pnl_cats=pnl_cats)
https://macrosynergy.com/notebooks.build/trading-factors/em-sovereign-risk-premia-indices-with-embi-adjustment/_images/6985ff0390966b5c4114ba320d5b58882c1ec8785b06f98865dcb1fd59acb153.png
xcat PNL_EMBIWGT_ADJ PNL_EMBIWGT
Return % 7.381873 7.09129
St. Dev. % 6.098419 6.2589
Sharpe Ratio 1.210457 1.132993
Sortino Ratio 1.658746 1.561661
Max 21-Day Draw % -26.731977 -25.999432
Max 6-Month Draw % -30.531728 -29.848671
Peak to Trough Draw % -30.938537 -30.147379
Top 5% Monthly PnL Share 0.45935 0.467006
USD_EQXR_NSA correl 0.289818 0.293117
UHY_CRXR_NSA correl 0.364825 0.372223
UIG_CRXR_NSA correl 0.370317 0.383069
Traded Months 282 282