Inflation as equity trading signal#

This notebook serves as an illustration of the points discussed in the post “Inflation as equity trading signal” available on the Macrosynergy website.

Academic research suggests that high and rising consumer price inflation puts upward pressure on real discount rates and is a headwind for equity market performance. A fresh analysis of 17 international markets since 2000 confirms an ongoing pervasive negative relation between published CPI dynamics and subsequent equity returns. Global equity index portfolios that have respected the inflation dynamics of major currency areas significantly outperformed equally weighted portfolios. Even the simplest metrics have served well as warning signals at the outset of large market drawdowns and as heads-ups for opportunities before recoveries. The evident predictive power of inflation for country equity indices has broad implications for the use of real-time CPI metrics in equity portfolio management.

This notebook provides the essential code required to replicate the analysis discussed in the post.

The notebook covers the three main parts:

  • Get Packages and JPMaQS Data: This section is responsible for installing and importing the necessary Python packages that are used throughout the analysis.

  • Transformations and Checks: In this part, the notebook performs various calculations and transformations on the data to derive the relevant signals and targets used for the analysis, including excess inflation indicators, effective excess inflation, relative excess inflation, and other metrics or ratios used in the analysis.

  • Value Checks: This is the most critical section, where the notebook calculates and implements the trading strategies based on the hypotheses tested in the post. Depending on the analysis, this section involves backtesting various trading strategies targeting equity returns. The strategies utilize the inflation indicators and other signals derived in the previous section.

It’s important to note that while the notebook covers a selection of indicators and strategies used for the post’s main findings, there are countless other possible indicators and approaches that can be explored by users, as mentioned in the post. Users can modify the code to test different hypotheses and strategies based on their own research and ideas. Best of luck with your research!

Get packages and JPMaQS data#

This notebook primarily relies on the standard packages available in the Python data science stack. However, there is an additional package macrosynergy that is required for two purposes:

  • Downloading JPMaQS data: The macrosynergy package facilitates the retrieval of JPMaQS data, which is used in the notebook.

  • For the analysis of quantamental data and value propositions: The macrosynergy package provides functionality for performing quick analyses of quantamental data and exploring value propositions.

For detailed information and a comprehensive understanding of the macrosynergy package and its functionalities, please refer to the “Introduction to Macrosynergy package” notebook on the Macrosynergy Quantamental Academy or visit the following link on Kaggle.

# Run only if needed!
"""
!pip install macrosynergy --upgrade
"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import os

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

from macrosynergy.download import JPMaQSDownload

import warnings

warnings.simplefilter("ignore")

The JPMaQS indicators we consider are downloaded using the J.P. Morgan Dataquery API interface within the macrosynergy package. This is done by specifying ticker strings, formed by appending an indicator category code to a currency area code <cross_section>. These constitute the main part of a full quantamental indicator ticker, taking the form DB(JPMAQS,<cross_section>_<category>,<info>), where denotes the time series of information for the given cross-section and category. The following types of information are available:

value giving the latest available values for the indicator eop_lag referring to days elapsed since the end of the observation period mop_lag referring to the number of days elapsed since the mean observation period grade denoting a grade of the observation, giving a metric of real-time information quality.

After instantiating the JPMaQSDownload class within the macrosynergy.download module, one can use the download(tickers,start_date,metrics) method to easily download the necessary data, where tickers is an array of ticker strings, start_date is the first collection date to be considered and metrics is an array comprising the times series information to be downloaded. For more information see here.

cids_g3eq = ["EUR", "JPY", "USD"]
cids_dmeq = ["AUD", "CAD", "CHF", "GBP", "SEK"]
cids_emeq = ["BRL", "INR", "KRW", "MXN", "MYR", "SGD", "THB", "TRY", "TWD", "ZAR"]
cids_eq = cids_g3eq + cids_dmeq + cids_emeq
cids = cids_eq

cids_extr = list(set(cids_eq) - set(["TRY"]))  # equity ex Turkey
cids_exus = list(set(cids_eq) - set(["USD"]))  # equity ex U.S.
cids_extu = list(set(cids_eq) - set(["USD", "TRY"]))  # US excluded for RV trading
main = [
    "CPIH_SA_P1M1ML12",
    "CPIH_SJA_P3M3ML3AR",
    "CPIH_SJA_P6M6ML6AR",
    "CPIC_SA_P1M1ML12",
    "CPIC_SJA_P3M3ML3AR",
    "CPIC_SJA_P6M6ML6AR",
    "CPIH_SA_P1M1ML12_D1M1ML3",
    "CPIC_SA_P1M1ML12_D1M1ML3",
]
xtra = ["INFTEFF_NSA"]
rets = [
    "EQXR_NSA",
    "EQXR_VT10",
]

xcats = main + xtra + rets

# Resultant tickers

tickers = [cid + "_" + xcat for cid in cids for xcat in xcats]
print(f"Maximum number of tickers is {len(tickers)}")
Maximum number of tickers is 198

JPMaQS indicators are conveniently grouped into 6 main categories: Economic Trends, Macroeconomic balance sheets, Financial conditions, Shocks and risk measures, Stylized trading factors, and Generic returns. Each indicator has a separate page with notes, description, availability, statistical measures, and timelines for main currencies. The description of each JPMaQS category is available under Macro quantamental academy. For tickers used in this notebook see Consumer price inflation trends, Inflation targets, and Equity index future returns.

start_date = "2000-01-01"
end_date = "2023-05-01"

# Retrieve credentials

client_id: str = os.getenv("DQ_CLIENT_ID")
client_secret: str = os.getenv("DQ_CLIENT_SECRET")

with JPMaQSDownload(client_id=client_id, client_secret=client_secret) as dq:
    df = dq.download(
        tickers=tickers,
        start_date=start_date,
        # end_date=end_date,
        suppress_warning=True,
        metrics=["all"],
        report_time_taken=True,
        show_progress=True,
    )
Downloading data from JPMaQS.
Timestamp UTC:  2024-03-21 14:33:13
Connection successful!
Requesting data: 100%|██████████| 40/40 [00:08<00:00,  4.95it/s]
Downloading data: 100%|██████████| 40/40 [00:40<00:00,  1.02s/it]
Time taken to download data: 	51.76 seconds.
Some dates are missing from the downloaded data. 
3 out of 6321 dates are missing.

Availability#

It is important to assess data availability before conducting any analysis. It allows identifying any potential gaps or limitations in the dataset, which can impact the validity and reliability of analysis and ensure that a sufficient number of observations for each selected category and cross-section is available as well as determining the appropriate time periods for analysis.

msm.check_availability(df, xcats=xcats, cids=cids)
_images/Inflation as equity trading signal_13_0.png _images/Inflation as equity trading signal_13_1.png

Transformations and checks#

In this part, we perform simple calculations and transformations on the data to derive the relevant signals and targets used for the analysis, including excess inflation indicators, simple scaling to enable comparison between countries, z-scoring and other metrics or ratios used in the analysis. For this notebook only feature variables were transformed. Target variables used here are simple equity index future returns.

Features#

Excess inflation in equity country groups#

The cell below defines INFTEBASIS as the maximum of the effective inflation target and two. INFTEBASIS is used as the denominator for inflation excesses. This scaling is a standard procedure to make the effects of inflation changes comparable across the range of 17 developed and emerging countries.

dfx = df.copy()
dfa = msp.panel_calculator(
    dfx, ["INFTEBASIS = INFTEFF_NSA.clip(lower=2)"], cids=cids_eq
)
dfx = msm.update_df(dfx, dfa)


infs = [
    "CPIH_SA_P1M1ML12",  # Standard annual headline consumer price inflation.
    "CPIH_SJA_P6M6ML6AR",  # Seasonally and jump-adjusted headline consumer price trends,  % 6m/6m ar.
    "CPIC_SA_P1M1ML12",  # Annual core consumer price inflation
    "CPIC_SJA_P6M6ML6AR",  # Seasonally and jump-adjusted core consumer price trends, % 6m/6m ar
]

for inf in infs:
    calc_iet = f"{inf}vIET = ( {inf} - INFTEFF_NSA ) / INFTEBASIS"
    dfa = msp.panel_calculator(dfx, calcs=[calc_iet], cids=cids_eq)
    dfx = msm.update_df(dfx, dfa)

To display and compare the values for the resulting (scaled) reported changes in inflation we use view_ranges() and view_timelines() function from the macrosynergy package

xcatx = ["CPIH_SA_P1M1ML12vIET", "CPIC_SA_P1M1ML12vIET"]

msp.view_ranges(
    dfx,
    cids=cids_eq,
    xcats=xcatx,
    kind="box",
    sort_cids_by="std",
    ylab="% daily rate",
    start="2000-01-01",
)
msp.view_timelines(
    dfx,
    xcats=xcatx[0:2],
    cids=cids_eq,
    ncol=4,
    cumsum=False,
    start="2000-01-01",
    same_y=False,
    size=(12, 12),
    all_xticks=True,
    title_fontsize=20,
    title="Excess inflation",
 
)
_images/Inflation as equity trading signal_21_0.png _images/Inflation as equity trading signal_21_1.png

Reported changes in inflation#

Changes in inflation rates are scaled to the effective inflation target for cross-country comparability. The resulting indicators are displayed with view_ranges() and view_timelines() functions from the macrosynergy package. Here we use Change in headline consumer price inflation (CPIH_SA_P1M1ML12_D1M1ML3) and Change in annual core consumer price inflation (CPIC_SA_P1M1ML12_D1M1ML3)

dfa = msp.panel_calculator(
    dfx,
    [
        "CPIH_SA_P1M1ML12_D1M1ML3vIET = CPIH_SA_P1M1ML12_D1M1ML3 / INFTEBASIS",
        "CPIC_SA_P1M1ML12_D1M1ML3vIET = CPIC_SA_P1M1ML12_D1M1ML3 / INFTEBASIS",
    ],
    cids=cids_eq,
)
dfx = msm.update_df(dfx, dfa)

xcatx = ["CPIH_SA_P1M1ML12_D1M1ML3vIET", "CPIC_SA_P1M1ML12_D1M1ML3vIET"]

msp.view_ranges(
    dfx,
    cids=cids_eq,
    xcats=xcatx,
    kind="box",
    sort_cids_by="std",
    ylab="% daily rate",
    start="2000-01-01",
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cids_eq,
    ncol=4,
    cumsum=False,
    start="2000-01-01",
    same_y=False,
    size=(12, 12),
    all_xticks=True,
    title_fontsize=20,
    title="Reported changes in inflation",
  
)
_images/Inflation as equity trading signal_24_0.png _images/Inflation as equity trading signal_24_1.png

Zn-scores#

To start with zn-scoring of the newly calculated indicators, we first change the sign of the inflation indicators created earlier and normalize the indicators using make_zn_scores() function. This is a standard procedure aimed at making various categories comparable, in particular summing or averaging categories with different units and time series properties.

infs = [
    "CPIH_SA_P1M1ML12vIET",
    "CPIC_SA_P1M1ML12vIET",
    "CPIH_SJA_P6M6ML6ARvIET",
    "CPIC_SJA_P6M6ML6ARvIET",
    "CPIH_SA_P1M1ML12_D1M1ML3",
    "CPIC_SA_P1M1ML12_D1M1ML3",
    "CPIH_SA_P1M1ML12_D1M1ML3vIET",
    "CPIC_SA_P1M1ML12_D1M1ML3vIET",
]

calcs = []
for inf in infs:
    calc = [f"{inf}_NEG = -1 * {inf}"]
    calcs = calcs + calc

dfa = msp.panel_calculator(dfx, calcs, cids=cids_eq)
dfx = msm.update_df(dfx, dfa)
infs_neg = [inf + "_NEG" for inf in infs]

for xcat_sel in infs_neg:
    dfa = msp.make_zn_scores(
        dfx,
        xcat=xcat_sel,
        cids=cids_eq,
        sequential=True,
        min_obs=261,  #  oos scaling after 1 year of panel data
        neutral="zero",
        pan_weight=1,  #  panel basis means no consideration of country-specific SDs
        thresh=2,  #  maximum score is 2 SDs to de-emphasize extreme values
        postfix="ZN",
    )
    dfx = msm.update_df(dfx, dfa)
calcs = []
for neg in infs_neg:
    calc = [f"{neg}XZN = {neg}ZN + 1"]
    calcs = calcs + calc

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

Targets#

Equity index returns#

In this analysis, we are comparing the returns of equity index futures without applying any transformations to them. However, potentially it is interesting to investigate relative value strategies, which could involve comparing the performance of different equity index futures relative to each other or relative to a benchmark index like the S&P 500. This could lead to the development of relative value strategies, to identify opportunities based on the relative underperformance or outperformance of specific index futures. The plots below display the timelines of the target (unmodified) variables.

xcatx = ["EQXR_NSA", "EQXR_VT10"]

msp.view_ranges(
    dfx,
    cids=cids_eq,
    xcats=xcatx,
    kind="box",
    sort_cids_by="std",
    ylab="% daily rate",
    start="2000-01-01",
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cids_eq,
    ncol=4,
    cumsum=True,
    start="2000-01-01",
    same_y=True,
    size=(12, 12),
    all_xticks=True,
    title_fontsize=22,
    title="Equity index returns",

)
_images/Inflation as equity trading signal_33_0.png _images/Inflation as equity trading signal_33_1.png

Value checks#

In this part of the analysis, the notebook calculates the naive PnLs (Profit and Loss) for directional Equity strategies, using the previously created inflation measures. The PnLs are calculated based on simple trading strategies that utilize the created inflation measures as signals (no regression analysis is involved). The strategies involve going long (buying) or short (selling) on Equity positions based purely on the direction of the excess inflation signals.

To evaluate the performance of these strategies, the notebook computes various metrics and ratios, including:

  • Correlation: Measures the relationship between the inflation-based strategy returns and the actual returns. Positive correlations indicate that the strategy moves in the same direction as the market, while negative correlations indicate an opposite movement.

  • Accuracy Metrics: These metrics assess the accuracy of inflation-based strategies in predicting market movements. Common accuracy metrics include accuracy rate, balanced accuracy, precision etc.

  • Performance Ratios: Various performance ratios, such as Sharpe ratio, Sortino ratio, Max draws etc.

The notebook compares the performance of these simple inflation-based strategies with the long-only performance of the respective asset classes.

It’s important to note that the analysis deliberately disregards transaction costs and risk management considerations. This is done to provide a more straightforward comparison of the strategies’ raw performance without the additional complexity introduced by transaction costs and risk management, which can vary based on trading size, institutional rules, and regulations.

The analysis in the post and sample code in the notebook is a proof of concept only, using the simplest design, including only directional index returns.

Reported changes in inflation and directional equity returns#

Headline inflation#

As the first step, we display a correlation for the whole panel between recorded inflation changes and subsequent returns on a quarterly basis. As the main signal we use (scaled) headline inflation indicator CPIH_SA_P1M1ML12_D1M1ML3vIET (change in headline consumer price inflation). The scaling, as explained in this notebook above, allows effective comparison between high a low inflation zones.

The correlation is negative and highly significant as displayed below

xcats_rdhi = ["CPIH_SA_P1M1ML12_D1M1ML3vIET", "EQXR_NSA"]

xcats_sel = xcats_rdhi
cids_sel = cids_extr
cr = msp.CategoryRelations(
    dfx,
    xcats=xcats_sel,
    cids=cids_sel,
    freq="M",
    lag=1,
    xcat_aggs=["last", "mean"],  # replace with sum
    start="2000-01-01",
    end="2023-01-01",
    xcat_trims=[None, None],
)
cr.reg_scatter(
    labels=False,
    coef_box="lower left",
    title="Reported changes in CPI inflation (scaled) and subsequent equity index future returns (17 countries since 2000)",
    xlab="Change in the inflation rate over the last three months, public information at the end of quarter ",
    ylab="Main equity index future return over the next quarter (%qr)",
)
_images/Inflation as equity trading signal_39_0.png

Looking at the same correlation between recorded inflation changes and subsequent returns by country, we can see that negative correlation prevailed all 17 analysed countries on a quarterly basis and monthly basis.

cr.reg_scatter(
    labels=False,
    coef_box="lower left",
    title="Reported changes in annual CPI inflation (scaled) and subsequent quarterly equity market returns (since 2000)",
    xlab="Change in inflation ",
    ylab="Equity return, next quarter",
    title_adj=1.02,
    separator="cids",
)
_images/Inflation as equity trading signal_41_0.png

The table below displays the accuracy of the CPIH_SA_P1M1ML12_D1M1ML3vIET signal using standard accuracy metrics

xcats_sel = xcats_rdhi
cids_sel = cids_extr
srr = mss.SignalReturnRelations(
    dfx,
    cids=cids_sel,
    sigs=xcats_sel[0],
    rets=xcats_sel[1],
    sig_neg=True,
    freqs="M",
    start="2000-01-01",
)
display(srr.summary_table().astype("float").round(3))
accuracy bal_accuracy pos_sigr pos_retr pos_prec neg_prec pearson pearson_pval kendall kendall_pval auc
Panel 0.521 0.522 0.490 0.592 0.615 0.430 0.092 0.000 0.055 0.000 0.523
Mean years 0.527 0.514 0.499 0.591 0.604 0.423 0.020 0.349 0.024 0.287 0.513
Positive ratio 0.600 0.680 0.400 0.680 0.800 0.360 0.480 0.400 0.560 0.480 0.680
Mean cids 0.519 0.521 0.490 0.592 0.613 0.428 0.094 0.229 0.056 0.271 0.522
Positive ratio 0.647 0.647 0.294 1.000 1.000 0.118 1.000 0.765 0.941 0.765 0.647

NaivePnl() class is designed to provide a quick and simple overview of a stylized PnL profile of a set of trading signals. The class carries the label naive because its methods do not take into account transaction costs or position limitations, such as risk management considerations. This is deliberate because costs and limitations are specific to trading size, institutional rules, and regulations. As target we keep ‘EQXR_NSA’ and as the main signal the same reported changes in CPI inflation (scaled) (Negative and zn-scored). Details on NaivePnl() class please see here

xcats_sel = xcats_rdhi
cids_sel = cids_extr
start_date = "2000-01-01"
sig = xcats_sel[0] + "_NEG"

naive_pnl = msn.NaivePnL(
    dfx,
    ret=xcats_sel[1],
    sigs=[sig],
    cids=cids_sel,
    start=start_date,
)

naive_pnl.make_pnl(
    sig,
    sig_op="zn_score_pan",
    thresh=2,
    rebal_freq="monthly",
    vol_scale=10,
    rebal_slip=1,
    pnl_name=sig + "PZN",
)
naive_pnl.make_pnl(
    sig,
    sig_op="binary",
    rebal_freq="monthly",
    vol_scale=10,
    rebal_slip=1,
    pnl_name=sig + "DIG",
)

# Now create signals with an encoded long bias

naive_pnl.make_pnl(
    sig,
    sig_op="zn_score_pan",
    sig_add = 1,
    thresh=2,
    rebal_freq="monthly",
    vol_scale=10,
    rebal_slip=1,
    pnl_name=sig + "XZNPZN",
)
naive_pnl.make_pnl(
    sig,
    sig_op="binary",
    sig_add = 1,
    rebal_freq="monthly",
    vol_scale=10,
    rebal_slip=1,
    pnl_name=sig + "XZNDIG",
)

naive_pnl.make_long_pnl(vol_scale=10, label="Long")

The below position heatmaps (red shorts, blue longs) for crisis periods illustrate the typical patterns. Prior to crisis escalation at least some country positions sent warning signals and a few months after the crisis escalation, when resulting disinflationary effects showed in CPI dynamics, the signals turned strongly positive.

naive_pnl.signal_heatmap(
    pnl_name=xcats_sel[0] + "_NEGXZNPZN",
    freq="m",
    start="2007-01-31",
    end="2009-12-31",
    title="Average monthly traded signals during the great financial crisis",
    figsize=(10, 5),
)
_images/Inflation as equity trading signal_47_0.png
naive_pnl.signal_heatmap(
    pnl_name=xcats_sel[0] + "_NEGXZNPZN",
    freq="m",
    start="2019-12-31",
    end=None,
    title="Average monthly traded signals during the pandemic and recent inflation surge",
    figsize=(10, 5),
)
_images/Inflation as equity trading signal_48_0.png

The plot_pnls() method of the NaivePnl() class is used to plot a line chart of cumulative PnL.

The post draws following conclsions based on the analysis:

  • First, the inflation-based strategy reduced or fully avoided drawdowns in some of the most turbulent periods for equity. Naturally, this would not always be the case but would happen in periods where rising inflation either triggers a shift to monetary tightening or compromises central banks’ ability to respond to financial or economic headwinds.

  • Second, the inflation-based signal has bolstered performance in post-crisis recoveries, by consistently tracking disinflationary impetus to central bank support actions.

  • Third, while inflation-based equity management has added great value in crisis times it has not significantly subtracted performance in normal times. This sets it apart from other tail-risk strategies, such as options and trend-following strategies. While the inflation overlay signal has a small aggregate short bias on its own, its ability to calibrate exposure across countries and minor inflation cycles has apparently offset the related shortfall of risk premia.

pnls = [xcats_sel[0] + "_NEGXZNPZN", "Long"]
dict_labels= {
    "CPIH_SA_P1M1ML12_D1M1ML3vIET_NEGXZNPZN": "managed based on inflation change score ",
    "Long": "simple equal-weight long-only",
}

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start_date,
    title="PnLs of global equity index future portfolios with and without inflation-based management (17 countries)",
    xcat_labels=dict_labels,
    figsize=(15, 8),
)
_images/Inflation as equity trading signal_51_0.png

Excess inflation and directional equity returns#

Here we plot excess CPI inflation and subsequent equity returns separately for before and after 2010

xcats_xhi = ["CPIH_SA_P1M1ML12vIET", "EQXR_NSA"]

xcats_sel = xcats_xhi
cids_sel = cids_extr
cr = msp.CategoryRelations(
    dfx,
    xcats=xcats_sel,
    cids=cids_sel,
    freq="Q",
    lag=1,
    xcat_aggs=["last", "mean"],  # replace with sum
    start="2000-01-01",
    xcat_trims=[None, None],
)
cr.reg_scatter(
    labels=False,
    coef_box="lower left",
    title="Excess CPI inflation (scaled) and subsequent equity market returns (17 countries since 2000)",
    xlab="CPI inflation minus effective estimated target (scaled to target), public information at quarter end",
    ylab="Main equity index future return over the next quarter (%qr)",
    separator=2010,
)
_images/Inflation as equity trading signal_54_0.png
xcats_sel = xcats_xhi
cids_sel = cids_extr
start_date = "2000-01-01"
sig = xcats_sel[0] + "_NEG"

naive_pnl = msn.NaivePnL(
    dfx,
    ret=xcats_sel[1],
    sigs=[sig],
    cids=cids_sel,
    start=start_date,
)

naive_pnl.make_pnl(
    sig,
    sig_op="zn_score_pan",
    thresh=2,
    rebal_freq="monthly",
    vol_scale=10,
    rebal_slip=1,
    pnl_name=sig + "PZN",
)
naive_pnl.make_pnl(
    sig,
    sig_op="binary",
    rebal_freq="monthly",
    vol_scale=10,
    rebal_slip=1,
    pnl_name=sig + "DIG",
)

# Now create signals with an encoded long bias

naive_pnl.make_pnl(
    sig,
    sig_op="zn_score_pan",
    sig_add=1,
    thresh=2,
    rebal_freq="monthly",
    vol_scale=10,
    rebal_slip=1,
    pnl_name=sig + "XZNPZN",
)
naive_pnl.make_pnl(
    sig,
    sig_op="binary",
    sig_add=1,
    rebal_freq="monthly",
    vol_scale=10,
    rebal_slip=1,
    pnl_name=sig + "XZNDIG",
)

naive_pnl.make_long_pnl(vol_scale=10, label="Long")
pnls = [xcats_sel[0] + "_NEGPZN", xcats_sel[0] + "_NEGDIG"]
dict_labels= {
    "CPIH_SA_P1M1ML12vIET_NEGPZN": "z-score signal ",
    "CPIH_SA_P1M1ML12vIET_NEGDIG": "binary signal",
}


naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start_date,
    title="Naive global equity index future PnLs based on excess inflation signal alone (short bias)",
    xcat_labels=dict_labels,
)
df_eval = naive_pnl.evaluate_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start_date,
)
display(df_eval)
_images/Inflation as equity trading signal_56_0.png
xcat CPIH_SA_P1M1ML12vIET_NEGDIG CPIH_SA_P1M1ML12vIET_NEGPZN
Return (pct ar) 3.415955 4.72016
St. Dev. (pct ar) 10.0 10.0
Sharpe Ratio 0.341595 0.472016
Sortino Ratio 0.499795 0.709941
Max 21-day draw -19.026666 -17.784021
Max 6-month draw -15.891042 -17.574082
Traded Months 291 291
pnls = [xcats_sel[0] + "_NEGXZNPZN", "Long"]

dict_labels= {
    "CPIH_SA_P1M1ML12vIET_NEGXZNPZN": "Positions based on excess inflation score ",
    "Long": "Equal long-only in all country indices",
}

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start_date,
    title="PnLs of global equity index future portfolios (17 countries)",
    xcat_labels=dict_labels,
)
_images/Inflation as equity trading signal_57_0.png