Skip to content
  • Research
    Macro Information Inefficiency
    • Understanding Macro Information Efficiency
    • Quantitative Methods for Macro Information Efficiency
    • Managing Systemic Risk
    • Understanding Macro Information Efficiency
    • Quantitative Methods for Macro Information Efficiency
    • Managing Systemic Risk
    Types of Systematic Macro Strategies
    • Fundamental Value Estimates
    • Macro Trends
    • Implicit Subsidies in Financial Markets
    • Endogenous Market Risk
    • Price Distortions
    • Fundamental Value Estimates
    • Macro Trends
    • Implicit Subsidies in Financial Markets
    • Endogenous Market Risk
    • Price Distortions
    Our Research
  • Quantamental Academy
    Macro-Quantamental Indicators
    • What Are Macro Quantamental Indicators?
    • Introductory Tutorials
    • Quantamental Indicators on JPMaQS
    • What Are Macro Quantamental Indicators?
    • Introductory Tutorials
    • Quantamental Indicators on JPMaQS
    Developing Macro Trading Factors
    • Value Generation Based on Quantamental Factors
    • Data Science with Quantamental Indicators
    • Examples of Macro Trading Factors
    • Value Generation Based on Quantamental Factors
    • Data Science with Quantamental Indicators
    • Examples of Macro Trading Factors
    Quantamental Academy
  • About Us
    About Macrosynergy
    • The Opportunity
    • Our Leadership
    • Our History
    • Careers
    • The Opportunity
    • Our Leadership
    • Our History
    • Careers
    About Us
Skip to main content
Ctrl + K

Robust equity trends

  • .ipynb

Robust equity trends

Contents

  • Get packages and JPMaQS data
  • Renaming and availability check
    • Renaming
    • Availability check
  • Feature engineering and checks
    • Domestic spending growth
      • Transformations
      • Structuring and scoring
    • CPI inflation
      • Transformations
      • Structuring and scoring
    • Equity carry
      • Transformations
      • Structuring and scoring
    • Intervention-driven liquidity expansion
      • Structuring and scoring
    • Cross-category scores
      • Thematic factor scores
      • Aggregate macro support scores
  • Robust equity returns trends and modification
    • Robust trend
    • Modified robust trend
    • Balanced trends
  • Targets review
  • Value checks
    • Modified robust trends (short sample)
      • Specs and panel test
      • Accuracy and correlation check
      • Naive PnL
    • Modified robust trends (long sample)
      • Specs and panel test
      • Accuracy and correlation check
      • Naive PnL
    • Balanced robust trends (short sample)
      • Specs and panel test
      • Accuracy and correlation check
      • Naive PnL
    • Balanced robust trends (long sample)
      • Specs and panel test
      • Accuracy and correlation check
      • Naive PnL
    • Checks
      • Specs and panel test
      • Accuracy and correlation check

Robust equity trends #

Get packages and JPMaQS data #

import numpy as np
import pandas as pd
from pandas import Timestamp
import matplotlib.pyplot as plt
import seaborn as sns
from scipy.stats import norm
import itertools

import warnings
import os
from datetime import date

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.management.utils import merge_categories

warnings.simplefilter("ignore")
# Equity cross-section lists

cids_g3 = ["EUR", "JPY", "USD"]  # DM large
cids_dmxg3 = ["AUD", "CAD", "CHF", "GBP", "SEK"]  # DM small
cids_dmeq = sorted(cids_g3 + cids_dmxg3)
cids = cids_dmeq

cids_dm90 = ["GBP", "JPY", "USD"]  # countries with sufficient data for 1990s
# Domestic spending growth
imports = ["IMPORTS_SA_P6M6ML6AR", "IMPORTS_SA_P1M1ML12_3MMA"]
rsales = [
    "NRSALES_SA_P1M1ML12_3MMA",
    "RRSALES_SA_P1M1ML12_3MMA",
    "NRSALES_SA_P1Q1QL4",
    "RRSALES_SA_P1Q1QL4",
]
pcons = ["RPCONS_SA_P1M1ML12_3MMA", "RPCONS_SA_P1Q1QL4"]
domspend = imports + rsales + pcons

# CPI inflation
cpi = [
    "CPIH_SA_P1M1ML12",
    "CPIH_SJA_P6M6ML6AR",
    "CPIC_SA_P1M1ML12",
    "CPIC_SJA_P6M6ML6AR",
]

liq = [
# liquidity intervention
    "INTLIQGDP_NSA_D1M1ML1",
    "INTLIQGDP_NSA_D1M1ML6",
    ]

# Real equity index carry
rcry = ["EQCRR_VT10", "EQCRR_NSA"]

# Supporting economic indicators
wforce = ["WFORCE_NSA_P1Y1YL1_5YMM"]
nomgdp = ["RGDP_SA_P1Q1QL4_20QMM", "INFTEFF_NSA", "INFTARGET_NSA", "USDGDPWGT_SA_3YMA"]


# Market indicators
markets = ["EQXR_NSA"]

# Composite lists

mains = domspend + cpi + rcry + liq
supports = wforce + nomgdp

xcats = mains + supports + markets

# 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 176
client_id: str = os.getenv("DQ_CLIENT_ID")
client_secret: str = os.getenv("DQ_CLIENT_SECRET")

with JPMaQSDownload(oauth=True, client_id=client_id, client_secret=client_secret) as dq:
    assert dq.check_connection()
    df = dq.download(
        tickers=tickers,
        start_date="1990-01-01",
        suppress_warning=True,
        metrics=["value"],
        show_progress=True,
    )
    assert isinstance(df, pd.DataFrame) and not df.empty

print("Last updated:", date.today())
Downloading data from JPMaQS.
Timestamp UTC:  2025-05-07 15:10:48
Connection successful!
Requesting data: 100%|██████████| 9/9 [00:01<00:00,  4.93it/s]
Downloading data: 100%|██████████| 9/9 [00:25<00:00,  2.88s/it]
Some expressions are missing from the downloaded data. Check logger output for complete list.
24 out of 176 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()`.
Last updated: 2025-05-07
dfx = df.copy().sort_values(["cid", "xcat", "real_date"])
dfx.info()
<class 'pandas.core.frame.DataFrame'>
Index: 1150040 entries, 97680 to 1116954
Data columns (total 4 columns):
 #   Column     Non-Null Count    Dtype         
---  ------     --------------    -----         
 0   real_date  1150040 non-null  datetime64[ns]
 1   cid        1150040 non-null  object        
 2   xcat       1150040 non-null  object        
 3   value      1150040 non-null  float64       
dtypes: datetime64[ns](1), float64(1), object(2)
memory usage: 43.9+ MB

Rename quarterly tickers to roughly equivalent monthly tickers to simplify subsequent operations.

Renaming and availability check #

Renaming #

dict_repl = {
    # Labour
    "RPCONS_SA_P1Q1QL4": "RPCONS_SA_P1M1ML12_3MMA",
    "RRSALES_SA_P1Q1QL4": "RRSALES_SA_P1M1ML12_3MMA",
    "NRSALES_SA_P1Q1QL4": "NRSALES_SA_P1M1ML12_3MMA",
}

# Ensure 'xcat' exists in dfx before replacement
if "xcat" in dfx.columns:
    dfx["xcat"] = dfx["xcat"].replace(dict_repl, regex=False)
else:
    print("Column 'xcat' not found in dfx.")

Availability check #

xcatx = [xc for xc in mains if xc not in dict_repl.keys()]
msm.check_availability(dfx, xcats=xcatx, cids=cids_dmeq, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/550fd9159579ac373244dd57dbd2ba5f2d979358996a19d6320041260d896ccf.png
xcatx = [xc for xc in supports if xc not in dict_repl.keys()]
msm.check_availability(dfx, xcats=xcatx, cids=cids_dmeq, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/165ffa2115d405361dadfb54620ba690c2c0c8ffc9c91c7489b0b4eb4605028c.png
msm.check_availability(dfx, xcats=markets, cids=cids, missing_recent=False)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/98d59c356865f48d42277faac317c4aa17394f63200f36e5185fbfb2a50b34c3.png

Feature engineering and checks #

Domestic spending growth #

Transformations #

# Backward-extension of INFTARGET_NSA

# Duplicate targets
cidx = cids_dmeq
calcs = [f"INFTARGET_BX = INFTARGET_NSA"]
dfa = msp.panel_calculator(dfx, calcs, cids=cidx)

# Add all dates back to 1990 to the frame, filling "value " with NaN
all_dates = np.sort(dfx['real_date'].unique())
all_combinations = pd.DataFrame(
    list(itertools.product(dfa['cid'].unique(), dfa['xcat'].unique(), all_dates)),
    columns=['cid', 'xcat', 'real_date']
)
dfax = pd.merge(all_combinations, dfa, on=['cid', 'xcat', 'real_date'], how='left')

# Backfill the values with first target value
dfax = dfax.sort_values(by=['cid', 'xcat', 'real_date'])
dfax['value'] = dfax.groupby(['cid', 'xcat'])['value'].bfill()

dfx = msm.update_df(dfx, dfax)
# Extended effective inflation target by hierarchical merging

hierarchy = ["INFTEFF_NSA", "INFTARGET_BX"]
dfa = merge_categories(dfx, xcats=hierarchy, new_xcat="INFTEFF_BX")
dfx = msm.update_df(dfx, dfa)
# Excess growth

xcatx_nominal = [
    "IMPORTS_SA_P6M6ML6AR",
    "IMPORTS_SA_P1M1ML12_3MMA",
    "NRSALES_SA_P1M1ML12_3MMA",
]
xcatx_real = ["RRSALES_SA_P1M1ML12_3MMA", "RPCONS_SA_P1M1ML12_3MMA"]

calcs = [f"X{xc} = {xc} - RGDP_SA_P1Q1QL4_20QMM - INFTEFF_BX" for xc in xcatx_nominal]
calcs += [f"X{xc} = {xc} - RGDP_SA_P1Q1QL4_20QMM" for xc in xcatx_real]

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

Structuring and scoring #

# Un-scored indicators and weights

dict_domspend = {
    "XIMPORTS_SA_P6M6ML6AR": 0.5,
    "XIMPORTS_SA_P1M1ML12_3MMA": 0.5,
    "XNRSALES_SA_P1M1ML12_3MMA": 0.5,
    "XRRSALES_SA_P1M1ML12_3MMA": 0.5,
    "XRPCONS_SA_P1M1ML12_3MMA": 1,
}
# Normalization of excess spending growth indicators

cidx = cids_dmeq
xcatx = list(dict_domspend.keys())
sdate = "1990-01-01"

for xc in xcatx:
    dfaa = msp.make_zn_scores(
        dfx,
        xcat=xc,
        cids=cidx,
        sequential=True,
        min_obs=261 * 5,
        neutral="zero",
        pan_weight=0.5,  # variance estimated based on panel and cross-sectional variation
        thresh=2,
        postfix="_ZN",
        est_freq="m",
    )
    dfa = msm.update_df(dfa, dfaa)

dfx = msm.update_df(dfx, dfa)
xspendz = [k + "_ZN" for k in list(dict_domspend.keys())]
xcatx = xspendz
cidx = cids
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Domestic spending growth scores",
    title_fontsize=27,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/95e7a4391efdd7fd4ee38c02278e8d6816b455b2cb5f665d988bcb13b5af89ed.png
# Weighted linear combination

cidx = cids_dmeq
xcatx = xspendz
weights = list(dict_domspend.values())
czs = "XSPEND"

dfa = msp.linear_composite(
    dfx,
    xcats=xcatx,
    cids=cidx,
    weights=weights,
    normalize_weights=True,
    complete_xcats=False,
    new_xcat=czs,
)
dfx = msm.update_df(dfx, dfa)

# Re-scoring

dfa = msp.make_zn_scores(
    dfx,
    xcat=czs,
    cids=cidx,
    sequential=True,
    min_obs=261 * 5,
    neutral="zero",
    pan_weight=1,
    thresh=2,
    postfix="_ZN",
    est_freq="m",
)
dfx = msm.update_df(dfx, dfa)
xcatx = "XSPEND_ZN"
cidx = cids
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Aggregate domestic spending growth score",
    title_fontsize=27,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/65edf4b85bc012d14fd226014f78c868271fe122984a5f2f9b0b710f793457e7.png

CPI inflation #

Transformations #

xcatx = cpi
calcs = [f"X{xc} = {xc} - INFTEFF_BX" for xc in xcatx]

dfa = msp.panel_calculator(
    dfx,
    calcs=calcs,
    cids=cids,
)
dfx = msm.update_df(dfx, dfa)
xinfs = list(dfa['xcat'].unique())

Structuring and scoring #

# Normalization of inflation indicators

cidx = cids_dmeq
xcatx = xinfs
sdate = "1990-01-01"

for xc in xcatx:
    dfaa = msp.make_zn_scores(
        dfx,
        xcat=xc,
        cids=cidx,
        sequential=True,
        min_obs=261 * 5,
        neutral="zero",
        pan_weight=0.5,  # variance estimated based on panel and cross-sectional variation
        thresh=2,
        postfix="_ZN",
        est_freq="m",
    )
    dfa = msm.update_df(dfa, dfaa)

dfx = msm.update_df(dfx, dfa)
xinfz = [xc + "_ZN" for xc in xinfs]
xcatx = xinfz
cidx = cids
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Excess CPI inflation scores",
    title_fontsize=27,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/f6c7fa939d1c92e0c3fc8d271943ec8e30559a2a4729313c5ab4dbf98a595509.png
# Weighted linear combination

cidx = cids_dmeq
xcatx = xinfz
czs = "XINF"

dfa = msp.linear_composite(
    dfx,
    xcats=xcatx,
    cids=cidx,
    complete_xcats=False,
    new_xcat=czs,
)
dfx = msm.update_df(dfx, dfa)

# Re-scoring

dfa = msp.make_zn_scores(
    dfx,
    xcat=czs,
    cids=cidx,
    sequential=True,
    min_obs=261 * 5,
    neutral="zero",
    pan_weight=1,
    thresh=2,
    postfix="_ZN",
    est_freq="m",
)
dfx = msm.update_df(dfx, dfa)
xcatx = "XINF_ZN"
cidx = cids
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Aggregate excess CPI inflation score",
    title_fontsize=27,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/cec5d4a9cfe4e76831650f4f6ed26c89d5ea08e945de192ce71ac2c2d882852b.png

Equity carry #

Transformations #

# Excess real carry based on minimum carry Sharpe of approximately 0.3

calcs = [
    "XEQCRR_NSA = EQCRR_NSA - 4",
    "XEQCRR_VT10 = EQCRR_VT10 - 3",
]
dfa = msp.panel_calculator(
    dfx,
    calcs=calcs,
    cids=cids,
)
dfx = msm.update_df(dfx, dfa)

xcrs = dfa["xcat"].unique().tolist()

Structuring and scoring #

# Normalization of excess spending growth indicators

cidx = cids_dmeq
xcatx = xcrs
sdate = "1990-01-01"

for xc in xcatx:
    dfaa = msp.make_zn_scores(
        dfx,
        xcat=xc,
        cids=cidx,
        sequential=True,
        min_obs=261 * 5,
        neutral="zero",
        pan_weight=0.5,  # variance estimated based on panel and cross-sectional variation
        thresh=2,
        postfix="_ZN",
        est_freq="m",
    )
    dfa = msm.update_df(dfa, dfaa)

dfx = msm.update_df(dfx, dfa)
xcrz = [xc + "_ZN" for xc in xcrs]
xcatx = xcrz
cidx = cids
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Excess carry scores",
    title_fontsize=27,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/609bdbba379f3abfed55b7929123f1a1daed995b2b1cae2036a117a0745766c4.png
# Weighted linear combination

cidx = cids_dmeq
xcatx = xcrz
czs = "XCRR"

dfa = msp.linear_composite(
    dfx,
    xcats=xcatx,
    cids=cidx,
    complete_xcats=False,
    new_xcat=czs,
)
dfx = msm.update_df(dfx, dfa)

# Re-scoring

dfa = msp.make_zn_scores(
    dfx,
    xcat=czs,
    cids=cidx,
    sequential=True,
    min_obs=261 * 5,
    neutral="zero",
    pan_weight=1,
    thresh=2,
    postfix="_ZN",
    est_freq="m",
)
dfx = msm.update_df(dfx, dfa)
xcatx = "XCRR_ZN"
cidx = cids
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Aggregate real carry score",
    title_fontsize=27,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/e815399d296633795cd7a168fb62ea733caa9c105e5102c05e482d84c9e900cc.png

Intervention-driven liquidity expansion #

Structuring and scoring #

# Normalization of liquidity intervention indicators

cidx = cids_dmeq
xcatx = liq
sdate = "1990-01-01"

for xc in xcatx:
    dfaa = msp.make_zn_scores(
        dfx,
        xcat=xc,
        cids=cidx,
        sequential=True,
        min_obs=261 * 5,
        neutral="zero",
        pan_weight=0.5,  # variance estimated based on panel and cross-sectional variation
        thresh=2,
        postfix="_ZN",
        est_freq="m",
    )
    dfa = msm.update_df(dfa, dfaa)

dfx = msm.update_df(dfx, dfa)
xinfz = [xc + "_ZN" for xc in xinfs]
xcatx = liq
cidx = cids_dmeq
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Intervention-driven liquidity expansion, as % pf GDP ",
    title_fontsize=27,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/1fee15ccfeaf6547baf05b85c81213d88d12c5acbb7c52257708a6ed2b98172e.png
# Weighted linear combination

cidx = cids_dmeq
xcatx = liq
czs = "LIQINT"

dfa = msp.linear_composite(
    dfx,
    xcats=xcatx,
    cids=cidx,
    complete_xcats=False,
    new_xcat=czs,
)
dfx = msm.update_df(dfx, dfa)

# Re-scoring

dfa = msp.make_zn_scores(
    dfx,
    xcat=czs,
    cids=cidx,
    sequential=True,
    min_obs=261 * 5,
    neutral="zero",
    pan_weight=1,
    thresh=2,
    postfix="_ZN",
    est_freq="m",
)
dfx = msm.update_df(dfx, dfa)
xcatx = "LIQINT_ZN"
cidx = cids
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Intervention-driven liquidity expansion aggregated score",
    title_fontsize=27,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/25131b557df8ca9a01257a38c387f2aa205b81947f078eb7058f95838febfb5d.png

Cross-category scores #

Thematic factor scores #

# Initiate dictionary for factor names

dict_names = {}
# Thematic support factors

xcatx_negs = ["XSPEND_ZN", "XINF_ZN"]

calcs = [f"{xc}_NEG = - {xc} " for xc in xcatx_negs]
dfa = msp.panel_calculator(
    dfx,
    calcs=calcs,
    cids=cids,
)

dfx = msm.update_df(dfx, dfa)
factorz_xcr = dfa["xcat"].unique().tolist()  + ["LIQINT_ZN"]
factorz = factorz_xcr + ["XCRR_ZN"]

dict_names["XSPEND_ZN_NEG"] = "Domestic spending growth (negative)"
dict_names["XINF_ZN_NEG"] = "CPI inflation (negative)"
dict_names["XCRR_ZN"] = "Real equity index carry"
dict_names["LIQINT_ZN"] = "Intervention liquidity"
xcatx = factorz
cidx = cids
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Macro support scores for local equity markets",
    title_fontsize=27,
    xcat_labels=dict_names,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/d553021deb449e5e37b150da916f79bfd5f1a3a35f9d6d80c2ae180b38bf4140.png
xcatx = factorz
cidx = cids_dmeq

msp.correl_matrix(
    dfx,
    xcats=xcatx,
    xcat_labels=[dict_names[xc] for xc in xcatx],
    cids=cidx,
    freq="M",
    title="Cross-sectional correlation matrix of macro composite scores",
    size=(20, 10),
    show=True,
    annot=True
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/0ba0b1ccaad1c4c140e822f6e4af3ae8e08643d5c26536bfb1df7866bef3a940.png

Aggregate macro support scores #

# Weighted linear combinations

dict_macro = {
    "MACRO": (factorz, cids_dmeq, "2004-01-01"),
    "MACROX": (factorz_xcr, cids_dmeq, "2004-01-01"),
    "MACROX90": (factorz_xcr, cids_dm90, "1990-01-01"),
}

for k, v in dict_macro.items():
    xcatx = v[0]
    cidx = v[1]
    sdate = v[2]

    dfa = msp.linear_composite(
        dfx,
        xcats=xcatx,
        cids=cidx,
        complete_xcats=False,
        start=sdate,
        new_xcat=k,
    )
    dfx = msm.update_df(dfx, dfa)

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

dict_names["MACRO_ZN"] = "Equity support score"
dict_names["MACROX_ZN"] = "Equity support score ex real carry"
dict_names["MACROX90_ZN"] = "Equity support score ex real carry"
xcatx = ["MACRO_ZN", "MACROX_ZN"]
cidx = cids_dmeq

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Aggregate macro support scores for the short sample period",
    title_fontsize=27,
    xcat_labels=dict_names,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/b4d32e47ae8c2480886497019d19bba6c024dca25bd23458ea1a5e7e6ec6e47c.png
xcatx = ["MACROX90_ZN"]
cidx = cids_dm90
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=1,
    aspect=7,
    all_xticks=True,
    legend_fontsize=17,
    title="Aggregate macro support scores (ex carry) for the long sample period",
    title_fontsize=27,
    start=sdate,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/589e470cfa316dc8cb105878b18e3228c8c08d8db61ec560c616a9b0998eca74.png

Robust equity returns trends and modification #

Robust trend #

We use a trend-following signal following Tzotchev, D. (2018) , allowing us to test the macro-enhanced strategy using a different trend-following approach

# Creating a function that returns the cdf as dataframe
def norm_cdf_df(df):
    """Apply scipy.stats.norm.cdf to a DataFrame and return a DataFrame."""
    return pd.DataFrame(norm.cdf(df.values), index=df.index, columns=df.columns)
# T-stat trend following strategy (Tzotchev, D. (2018).
fxrs = ["EQXR_NSA"]
cidx = cids
lookbacks = [32, 64, 126, 252, 504]

calcs = []
for fxr in fxrs:
    
    signals = []
    for lb in lookbacks:
        mean_calc = f"{fxr}_MEAN_{lb} = {fxr}.rolling( {lb} ).mean( )"
        std_calc = f"{fxr}_STD_{lb} = {fxr}.rolling( {lb} ).std( ddof=1 )"
        tstat_calc = (
            f"{fxr}_TSTAT_{lb} = {fxr}_MEAN_{lb} / ( {fxr}_STD_{lb} / np.sqrt( {lb} ) )"
        )
        prob_calc = f"{fxr}_PROB_{lb} = norm_cdf_df( {fxr}_TSTAT_{lb} )"
        signal_calc = f"{fxr}_SIGNAL_{lb} = 2 * {fxr}_PROB_{lb} - 1"

        signals.append( f"{fxr}_SIGNAL_{lb}" )
        
        calcs += [mean_calc, std_calc, tstat_calc, prob_calc, signal_calc]

    composite_signal = f"{fxr}_RTS = ( {' + '.join(signals)} ) / {len(lookbacks)}"
    calcs.append(composite_signal)


# Calculate the signals
dfa = msp.panel_calculator(dfx, calcs, cids=cidx, external_func={"norm_cdf_df": norm_cdf_df})
dfx = msm.update_df(dfx, dfa)

# Composite signals names:
eqtrends = [f"{fxr}_RTS" for fxr in fxrs]

dict_names["EQXR_NSA_RTS"] = "Equity trend signal"
# Normalize trend signals sequentially (for modification)

xcatx = eqtrends
cidx = cids

for xc in xcatx:
    dfaa = msp.make_zn_scores(
        dfx,
        xcat=xc,
        cids=cidx,
        sequential=True,
        min_obs=522,  # oos scaling after 2 years of panel data
        est_freq="m",
        neutral="zero",
        pan_weight=1,
        thresh=3,
        postfix="Z",
    )
    dfa = msm.update_df(dfa, dfaa)

dfx = msm.update_df(dfx, dfa)

eqtrendz = [tr + "Z" for tr in eqtrends]
xcatx = eqtrends
cidx = cids_dmeq
sdate = "1990-01-01"
labels = [dict_names[xcat] for xcat in xcatx]

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Robust equity trend signals",
    title_fontsize=27,
    xcat_labels=labels,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/a0da08d68a4112bbd8464d9f592797b8500713027d0fca4a1702590216452e96.png
xcatx = eqtrends[0]
cidx = cids_dmeq

msp.correl_matrix(
    dfx,
    xcats=xcatx,
    cids=cidx,
    freq="W",
    title="Cross-sectional correlation matrix of robust equity trend signals",
    size=(18, 8),
    show=True,
    annot=True
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/e0ac849b2ad6525a610b1f66acd8e46b09069960e95eddfa62cdd51949afb8ac.png

Modified robust trend #

Adjustments to the strength of the trend signal based on the quantamental information captured by macro scores. The trend remains the dominant signal, but we allow quantamental information to increase the trend signal by up to 100% and to reduce it by up to zero. However, quantamental information does not “flip” the signal. The modification coefficient ensures that the adjustment remains within [0,2] interval, hence preventing extreme flips or amplifications of the trend signal.

The linear modification coefficient applied to the trend is based on the macro z-scores. The application depends on the sign of the concurrent trend signal.

  • If the trend signal is positive external strength it enhances it and external weakness reduces it. The modification coefficient uses a sigmoid function that translates the external strength score such that for a value of zero it is 1, for values of -1 and 1 it is 0.25 and 1.75 respectively and for its minimum and maximum of -3 and 3 it is 0 zero and 2 respectively.

  • If the trend signal is negative the modification coefficient depends negatively on external strength but in the same way.

This can be expressed by the following equation:

(1) # \[\begin{equation} \text{adtrend} = ((1 - \text{sign}(\text{trend})) + \text{sign}(\text{trend}) * \text{coef}) * \text{trend} \end{equation}\]

where

(2) # \[\begin{equation} \text{coef}= \frac{2}{1 + e^{-2 * \text{strength}}} \end{equation}\]

This means for a positive trend:

(3) # \[\begin{equation} \text{adtrend} = \text{coef} * \text{trend} \end{equation}\]

and for a negative trend:

(4) # \[\begin{equation} \text{adtrend} = (2 - \text{coef}) * \text{trend} \end{equation}\]
def sigmoid(x):
    return 2 / (1 + np.exp(-2 * x))


ar = np.arange(-2, 2, 0.1)
plt.figure(figsize=(9, 4), dpi=80)
plt.plot(ar, sigmoid(ar))
plt.title(
    "Sigmoid function that translates macro support scores into modification coefficients"
)
plt.show()
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/2f0f292b4a90e520ad0a41cf3dfc0c415826941cbe4f61b6dd6eadd4bbf1bb1c.png
# Calculate adjustment coefficients based on macro factors

macroz = factorz + ["MACRO_ZN", "MACROX_ZN", "MACROX90_ZN"]


calcs = []
for zd in macroz:
    calcs += [f"{zd}_C = ( {zd} ).applymap( lambda x: 2 / (1 + np.exp( - 2 * x)) ) "]
dfa = msp.panel_calculator(dfx, calcs=calcs, cids=cidx)
dfx = msm.update_df(dfx, dfa)

coefs = list(dfa["xcat"].unique())
# Calculate modified trend signals based on macro factors

calcs = []
for tr in eqtrendz:
    for xs in macroz:
        trxs = tr + "m" + xs.split("_")[0]
        calcs += [f"{trxs}_C = (1 - np.sign( {tr} )) + np.sign( {tr} ) * {xs}_C"]
        calcs += [f"{trxs} = {trxs}_C * {tr}"]

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

eqtrendz_mod = [xc for xc in dfa["xcat"].unique() if not xc.endswith("_C")]

dict_names["EQXR_NSA_RTSZ"] = "Outright equity trend score"
dict_names["EQXR_NSA_RTSZmMACRO"] = "Equity trend modified by broad macro support"
dict_names["EQXR_NSA_RTSZmMACROX"] = "Equity trend modified by macro support ex carry"
dict_names["EQXR_NSA_RTSZmMACROX90"] = "Equity trend modified by macro support ex carry (long sample)"
xcatx = ['EQXR_NSA_RTSZ', 'EQXR_NSA_RTSZmMACRO']
cidx = cids_dmeq
sdate = "2004-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Outright and modified equity trend signals, using broad macro support scores",
    title_fontsize=27,
    xcat_labels=dict_names,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/4ff81607294d62b0912de7b1e2fc7cd1d2247778ec597ea968718dca43dd8161.png
xcatx = ['EQXR_NSA_RTSZ', 'EQXR_NSA_RTSZmMACROX90']
cidx = cids_dm90
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Outright and modified equity trend signals for the long samples",
    title_fontsize=27,
    xcat_labels=dict_names,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/f73f5930cf2c618e1789fcf1043adfeff5981253375ad82668c6c00d1990a2e6.png

Balanced trends #

cidx = cids_dmeq

eqtrendz_bal = []
for tr in eqtrendz:
    for macro in macroz:
        xcatx = [tr, macro]
        newcat = tr + "b" + macro.split("_")[0]

        dfa = msp.linear_composite(
            df=dfx,
            xcats=xcatx,
            cids=cidx,
            complete_xcats=True,
            new_xcat=newcat,
        )
        eqtrendz_bal.append(newcat)
        dfx = msm.update_df(dfx, dfa)
dict_names["EQXR_NSA_RTSZbMACRO"] = "Trend balanced with broad macro support"
dict_names["EQXR_NSA_RTSZbMACROX"] = "Trend balanced with macro support ex carry"
dict_names["EQXR_NSA_RTSZbMACROX90"] = "Trend balanced with macro support ex carry (long sample)"
xcatx = ['EQXR_NSA_RTSZ', 'EQXR_NSA_RTSZbMACRO']
cidx = cids_dmeq
sdate = "2004-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Outright and balanced equity trend signals",
    title_fontsize=27,
    xcat_labels=dict_names,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/a506749455227fe79fc13fadc473b21e42355b22ae16a453b88db3fa3af90c37.png
xcatx = ['EQXR_NSA_RTSZ', 'EQXR_NSA_RTSZbMACROX90']
cidx = cids_dm90
sdate = "1990-01-01"

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=2,
    aspect=3,
    cumsum=False,
    start=sdate,
    same_y=False,
    all_xticks=True,
    legend_fontsize=17,
    title="Outright and balanced equity trend signals for the long samples",
    title_fontsize=27,
    xcat_labels=dict_names,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/0c4dbb7c5a65c3f061cdcd99f0aec3c2e111a5aebede8f670e730b2a5f69909a.png

Targets review #

As target we choose standard Equity index future returns EQXR_NSA

xcatx = ["EQXR_NSA"]
cidx = cids
sdate = "1990-01-01"

msp.view_ranges(
    dfx,
    cids=cidx,
    xcats=xcatx,
    kind="box",
    sort_cids_by="std",
    ylab="% daily rate",
    start=sdate,
    title="Boxplots of equity index future returns, all available history",
)

msp.view_timelines(
    dfx,
    xcats=xcatx,
    cids=cidx,
    ncol=4,
    cumsum=True,
    start=sdate,
    same_y=True,
    size=(12, 12),
    all_xticks=True,
    title="Equity index future returns",
    title_fontsize=27,
    legend_fontsize=17,
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/95222d3003e91a3f5855df2ea1b123c08a3d85ad6c9addbfcbe5ba97e5cf24f5.png https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/283107d53cbacb06ece4a5d2e1f8c2e1ee54d8d35a9dc03b6406b0bbfc4bd10e.png
xcatx = ["EQXR_NSA"]
cidx = cids

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

for xc in xcatx:
    dfaa = msp.linear_composite(
        df=dfx,
        xcats=xc,
        cids=cidx,
        complete_xcats=False,
        weights="USDGDPWGT_SA_3YMA",
        new_cid="GDM",
    )
    dfa = msm.update_df(dfa, dfaa)

dfx = msm.update_df(dfx, dfa)

Value checks #

Modified robust trends (short sample) #

Specs and panel test #

dict_m04 = {
    "sigs": ["EQXR_NSA_RTSZ", "EQXR_NSA_RTSZmMACROX", "EQXR_NSA_RTSZmMACRO"],
    "targs": ["EQXR_NSA"],
    "cidx": cids_dmeq,
    "start": "2004-01-01",
    "crs": None,
    "srr": None,
    "pnls": None,
}
dix = dict_m04

sigs = dix["sigs"]
targs = dix["targs"]
cidx = dix["cidx"]
start = dix["start"]

# Initialize the dictionary to store CategoryRelations instances

dict_cr = {}

for targ in targs:
    for sig in sigs:
        lab = sig + "_" + targ
        dict_cr[lab] = msp.CategoryRelations(
            dfx,
            xcats=[sig, targ],
            cids=cidx,
            freq="M",
            lag=1,
            xcat_aggs=["last", "sum"],
            start=start,
        )

dix["crs"] = dict_cr
# Plotting panel scatters

dix = dict_m04
dict_cr = dix["crs"]
sigs = dix["sigs"]
targs = dix["targs"]

crs = list(dict_cr.values())
crs_keys = list(dict_cr.keys())
ncol = len(sigs)
nrow = len(targs)
           
msv.multiple_reg_scatter(
    cat_rels=crs,
    ncol=ncol,
    nrow=nrow,
    figsize=(16, 8),
    prob_est="map",
    coef_box="lower left",
    title=None,
    subplot_titles=None,
    xlab="end-of-month information state",
    ylab="next month's return",
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/f8a8e186980eddb65340e5e771226e8be94c78e7d440bf86831d0c891e47650a.png

Accuracy and correlation check #

dix = dict_m04

sigs = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]

srr = mss.SignalReturnRelations(
    dfx,
    cids=cidx,
    sigs=sigs,
    rets=targ,
    freqs="M",
    start=start,
)

dix["srr"] = srr
display(srr.signals_table().sort_index().astype("float").round(3))
accuracy bal_accuracy pos_sigr pos_retr pos_prec neg_prec pearson pearson_pval kendall kendall_pval auc
Return Signal Frequency Aggregation
EQXR_NSA EQXR_NSA_RTSZ M last 0.576 0.504 0.808 0.619 0.621 0.388 -0.033 0.139 -0.060 0.000 0.503
EQXR_NSA_RTSZmMACRO M last 0.576 0.504 0.808 0.619 0.621 0.388 0.008 0.720 -0.030 0.042 0.503
EQXR_NSA_RTSZmMACROX M last 0.576 0.504 0.808 0.619 0.621 0.388 0.015 0.496 -0.021 0.154 0.503

Naive PnL #

dix = dict_m04

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]

naive_pnl = msn.NaivePnL(
    dfx,
    ret=targ,
    sigs=sigx,
    cids=cidx,
    start=start,
    bms=["USD_EQXR_NSA"],
)

for sig in sigx:
    for bias in [0, 1]:
        naive_pnl.make_pnl(
            sig,
            sig_add=bias,
            sig_op="zn_score_pan",
            thresh=2,
            rebal_freq="monthly",
            vol_scale=10,
            rebal_slip=1,
            pnl_name=sig + "_PZN" + str(bias),
        )

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

dix["pnls"] = naive_pnl

dict_names["EQXR_NSA_RTSZmMACROX_PZN0"] = "Trend modified by macro support ex carry"
dict_names["EQXR_NSA_RTSZmMACRO_PZN0"] = "Trend modified by broad macro support"
dict_names["EQXR_NSA_RTSZ_PZN0"] = "Outright trend score, no bias"

dict_names["EQXR_NSA_RTSZmMACROX_PZN1"] = "Trend modified by macro support ex carry, long only"
dict_names["EQXR_NSA_RTSZmMACRO_PZN1"] = "Trend modified by broad macro support, long only"
dict_names["EQXR_NSA_RTSZ_PZN1"] = "Outright trend score, long only"

dict_names["Long only"] = "Constant long exposure"
dix = dict_m04

sigx = dix["sigs"]
cidx = dix["cidx"]
start = dix["start"]
naive_pnl = dix["pnls"]


pnls = [s + "_PZN0" for s in sigx] # + ["Long only"]
pnls_labels = [dict_names[s] for s in pnls]

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start,
    title="Long-short equity strategy PnL based on robust trend signals, short sample (8 countries)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

display(naive_pnl.evaluate_pnls(pnl_cats=pnls))

naive_pnl.signal_heatmap(pnl_name=sigx[0] + "_PZN0", freq="q", start=start, figsize=(16, 4))
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/6f115e3b9bc0530bfb1e04b86de1ce7a918192af07f3c727f664dd5e478dd76f.png
xcat EQXR_NSA_RTSZ_PZN0 EQXR_NSA_RTSZmMACROX_PZN0 EQXR_NSA_RTSZmMACRO_PZN0
Return % 3.00801 4.368954 4.840765
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.300801 0.436895 0.484076
Sortino Ratio 0.417169 0.624887 0.688369
Max 21-Day Draw % -17.143799 -11.617564 -12.278842
Max 6-Month Draw % -20.00846 -13.411511 -13.613407
Peak to Trough Draw % -28.08338 -22.853598 -20.8773
Top 5% Monthly PnL Share 1.081811 0.734239 0.687547
USD_EQXR_NSA correl 0.010331 0.017555 0.072778
Traded Months 257 257 257
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/0b31e6a2155742fe4b5d5c8ef6379c46d5652683b8b559eefaa5606e24e25dd6.png
dix = dict_m04

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
naive_pnl = dix["pnls"]


pnls = [s + "_PZN1" for s in sigx] + ["Long only"]
pnls_labels = [dict_names[s] for s in pnls]

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start,
    title="Long-biased equity index strategy PnL based on robust trend signals (short sample, 8 countries)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    compounding=True,
    start=start,
    title="Compounding long-biased equity index strategy PnL based on robust trend signals (short sample, 8 countries)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

display(naive_pnl.evaluate_pnls(pnl_cats=pnls))
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/dd8383f74cea275bf57ec7f1928e0769a896bdc565e36eb534b752e15f0a022c.png https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/c6e1591e14d1b5b3dbb2659f3f661268f40401638671b07e11cd1d56c087be72.png
xcat EQXR_NSA_RTSZ_PZN1 EQXR_NSA_RTSZmMACROX_PZN1 EQXR_NSA_RTSZmMACRO_PZN1 Long only
Return % 5.934983 6.710851 6.864653 5.625408
St. Dev. % 10.0 10.0 10.0 10.0
Sharpe Ratio 0.593498 0.671085 0.686465 0.562541
Sortino Ratio 0.808506 0.92523 0.94491 0.771831
Max 21-Day Draw % -20.390284 -25.027067 -24.78558 -25.720094
Max 6-Month Draw % -16.94752 -16.34379 -16.192094 -34.088434
Peak to Trough Draw % -23.675527 -26.029361 -25.763425 -48.854809
Top 5% Monthly PnL Share 0.524517 0.492619 0.475674 0.558079
USD_EQXR_NSA correl 0.541642 0.509897 0.527897 0.714851
Traded Months 257 257 257 257

Modified robust trends (long sample) #

Specs and panel test #

dict_m92 = {
    "sigs": ["EQXR_NSA_RTSZ", "EQXR_NSA_RTSZmMACROX90"], 
    "targs": ["EQXR_NSA"],
    "cidx": cids_dm90,
    "start": "1992-01-01",
    "crs": None,
    "srr": None,
    "pnls": None,
}
dix = dict_m92

sigs = dix["sigs"]
targs = dix["targs"]
cidx = dix["cidx"]
start = dix["start"]

# Initialize the dictionary to store CategoryRelations instances

dict_cr = {}

for targ in targs:
    for sig in sigs:
        lab = sig + "_" + targ
        dict_cr[lab] = msp.CategoryRelations(
            dfx,
            xcats=[sig, targ],
            cids=cidx,
            freq="M",
            lag=1,
            xcat_aggs=["last", "sum"],
            start=start,
        )

dix["crs"] = dict_cr
# Plotting panel scatters

dix = dict_m92
dict_cr = dix["crs"]
sigs = dix["sigs"]
targs = dix["targs"]

crs = list(dict_cr.values())
crs_keys = list(dict_cr.keys())
ncol = len(sigs)
nrow = len(targs)
           
msv.multiple_reg_scatter(
    cat_rels=crs,
    ncol=ncol,
    nrow=nrow,
    figsize=(16, 8),
    prob_est="map",
    coef_box="lower left",
    title=None,
    subplot_titles=None,
    xlab="end-of-month information state",
    ylab="next month's return",
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/fb6879f18940f56a775777261a459d5fbc9f6d843836d88894661882af272034.png

Accuracy and correlation check #

dix = dict_m92

sigs = dix["sigs"]
targs = dix["targs"]
cidx = dix["cidx"]
start = dix["start"]

srr = mss.SignalReturnRelations(
    dfx,
    cids=cidx,
    sigs=sigs,
    rets=targs[0],
    freqs="M",
    start=start,
)

dix["srr"] = srr
display(srr.signals_table().sort_index().astype("float").round(3))
accuracy bal_accuracy pos_sigr pos_retr pos_prec neg_prec pearson pearson_pval kendall kendall_pval auc
Return Signal Frequency Aggregation
EQXR_NSA EQXR_NSA_RTSZ M last 0.565 0.521 0.734 0.604 0.615 0.426 0.028 0.332 -0.016 0.415 0.517
EQXR_NSA_RTSZmMACROX90 M last 0.565 0.521 0.734 0.604 0.615 0.426 0.056 0.055 0.017 0.379 0.517

Naive PnL #

dix = dict_m92

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]

naive_pnl = msn.NaivePnL(
    dfx,
    ret=targ,
    sigs=sigx,
    cids=cidx,
    start=start,
    bms=["USD_EQXR_NSA"],
)

for sig in sigx:
    for bias in [0, 1]:
        naive_pnl.make_pnl(
            sig,
            sig_add=bias,
            sig_op="zn_score_pan",
            thresh=2,
            rebal_freq="monthly",
            vol_scale=10,
            rebal_slip=1,
            pnl_name=sig + "_PZN" + str(bias),
        )

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

dix["pnls"] = naive_pnl

dict_names["EQXR_NSA_RTSZmMACROX90_PZN0"] = "Trend modified by macro support ex carry"
dict_names["EQXR_NSA_RTSZmMACROX90_PZN1"] = "Trend modified by macro support ex carry, long only"
dict_names["Long only"] = "Constant long exposure"
dix = dict_m92

sigx = dix["sigs"]
cidx = dix["cidx"]
start = dix["start"]
naive_pnl = dix["pnls"]


pnls = [s + "_PZN0" for s in sigx] # + ["Long only"]
pnls_labels = [dict_names[s] for s in pnls]

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start,
    title="Long-short equity strategy PnL based on robust trend signals, long sample (U.S., Japan and UK)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

display(naive_pnl.evaluate_pnls(pnl_cats=pnls))

naive_pnl.signal_heatmap(pnl_name=sigx[0] + "_PZN0", freq="q", start=start, figsize=(16, 4))
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/f538f7bf8cd9b038e6999b1a5afca88a3d5de60ef9f1a1b3b4ea10eca6dd4da1.png
xcat EQXR_NSA_RTSZ_PZN0 EQXR_NSA_RTSZmMACROX90_PZN0
Return % 3.253595 4.545353
St. Dev. % 10.0 10.0
Sharpe Ratio 0.32536 0.454535
Sortino Ratio 0.456422 0.643846
Max 21-Day Draw % -16.51266 -14.034125
Max 6-Month Draw % -20.108218 -16.567987
Peak to Trough Draw % -31.93561 -24.502898
Top 5% Monthly PnL Share 1.1362 0.754926
USD_EQXR_NSA correl -0.021696 0.077164
Traded Months 400 400
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/f63644b228793bfe97e141ec919d283032d64694188d0e1fc01a3c4c3a756314.png
[s + "_PZN1" for s in sigx] + ["Long only"]
['EQXR_NSA_RTSZ_PZN1', 'EQXR_NSA_RTSZmMACROX90_PZN1', 'Long only']
dix = dict_m92

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
naive_pnl = dix["pnls"]


pnls = [s + "_PZN1" for s in sigx] + ["Long only"]
pnls_labels = [dict_names[s] for s in pnls]

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start,
    title="Long-biased equity index strategy PnL based on robust trend signals, long sample (U.S., Japan and UK)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    compounding=True,
    start=start,
    title="Compounding long-biased equity index strategy PnL based on robust trend signals, long sample (U.S., Japan and UK)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

display(naive_pnl.evaluate_pnls(pnl_cats=pnls))
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/ed2ef4782e08f38b1443ab45dca2ef1539b196ac517508b23462515177925fe4.png https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/e441ef40f4f078c1163ed28001c05c1ca19819810838cfbbd656182635f81a3e.png
xcat EQXR_NSA_RTSZ_PZN1 EQXR_NSA_RTSZmMACROX90_PZN1 Long only
Return % 5.478812 5.704669 4.222745
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.547881 0.570467 0.422275
Sortino Ratio 0.757201 0.796081 0.588262
Max 21-Day Draw % -15.513942 -21.514109 -24.565113
Max 6-Month Draw % -17.431189 -17.099608 -35.080736
Peak to Trough Draw % -22.973599 -29.890305 -50.743907
Top 5% Monthly PnL Share 0.588493 0.603846 0.739787
USD_EQXR_NSA correl 0.478217 0.519246 0.706071
Traded Months 401 401 401

Balanced robust trends (short sample) #

Specs and panel test #

dict_b04 = {
    "sigs": ["EQXR_NSA_RTSZ", "EQXR_NSA_RTSZbMACRO", "EQXR_NSA_RTSZbMACROX"],
    "targs": ["EQXR_NSA"],
    "cidx": cids_dmeq,
    "start": "2004-01-01",
    "crs": None,
    "srr": None,
    "pnls": None,
}
dix = dict_b04

sigs = dix["sigs"]
targs = dix["targs"]
cidx = dix["cidx"]
start = dix["start"]

# Initialize the dictionary to store CategoryRelations instances

dict_cr = {}

for targ in targs:
    for sig in sigs:
        lab = sig + "_" + targ
        dict_cr[lab] = msp.CategoryRelations(
            dfx,
            xcats=[sig, targ],
            cids=cidx,
            freq="M",
            lag=1,
            xcat_aggs=["last", "sum"],
            start=start,
        )

dix["crs"] = dict_cr
# Plotting panel scatters

dix = dict_b04
dict_cr = dix["crs"]
sigs = dix["sigs"]
targs = dix["targs"]

crs = list(dict_cr.values())
crs_keys = list(dict_cr.keys())
ncol = len(sigs)
nrow = len(targs)
           
msv.multiple_reg_scatter(
    cat_rels=crs,
    ncol=ncol,
    nrow=nrow,
    figsize=(16, 8),
    prob_est="map",
    coef_box="lower left",
    title=None,
    subplot_titles=None,
    xlab="end-of-month information state",
    ylab="next month's return",
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/3b7056f0f71462aec4dc787cb636b3a92e72bdbbc4da83f254af55fe5248b3b8.png

Accuracy and correlation check #

dix = dict_b04

sigs = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]

srr = mss.SignalReturnRelations(
    dfx,
    cids=cidx,
    sigs=sigs,
    rets=targ,
    freqs="M",
    start=start,
)

dix["srr"] = srr
display(srr.signals_table().sort_index().astype("float").round(3))
accuracy bal_accuracy pos_sigr pos_retr pos_prec neg_prec pearson pearson_pval kendall kendall_pval auc
Return Signal Frequency Aggregation
EQXR_NSA EQXR_NSA_RTSZ M last 0.576 0.504 0.808 0.619 0.621 0.388 -0.033 0.139 -0.060 0.000 0.503
EQXR_NSA_RTSZbMACRO M last 0.602 0.544 0.816 0.619 0.636 0.453 0.072 0.001 0.016 0.270 0.528
EQXR_NSA_RTSZbMACROX M last 0.599 0.549 0.772 0.619 0.642 0.456 0.069 0.002 0.020 0.186 0.537

Naive PnL #

dix = dict_b04

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]

naive_pnl = msn.NaivePnL(
    dfx,
    ret=targ,
    sigs=sigx,
    cids=cidx,
    start=start,
    bms=["USD_EQXR_NSA"],
)

for sig in sigx:
    for bias in [0, 1]:
        naive_pnl.make_pnl(
            sig,
            sig_add=bias,
            sig_op="zn_score_pan",
            thresh=2,
            rebal_freq="monthly",
            vol_scale=10,
            rebal_slip=1,
            pnl_name=sig + "_PZN" + str(bias),
        )

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

dix["pnls"] = naive_pnl

dict_names["EQXR_NSA_RTSZbMACROX_PZN0"] = "Trend balanced with macro support ex carry"
dict_names["EQXR_NSA_RTSZbMACRO_PZN0"] = "Trend balanced with broad macro support"

dict_names["EQXR_NSA_RTSZbMACROX_PZN1"] = "Trend balanced with macro support ex carry, long bias"
dict_names["EQXR_NSA_RTSZbMACRO_PZN1"] = "Trend balanced with broad macro support, long bias"


dix["pnls"] = naive_pnl
dix = dict_b04

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
naive_pnl = dix["pnls"]


pnls = [s + "_PZN0" for s in sigx] # + ["Long only"]
pnls_labels = [dict_names[s] for s in pnls]

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start,
    title="Long-short equity strategy PnL based on balanced trend signals, short sample (8 countries)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

display(naive_pnl.evaluate_pnls(pnl_cats=pnls))

naive_pnl.signal_heatmap(pnl_name=sigx[0] + "_PZN0", freq="q", start=start, figsize=(16, 4))
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/755a226b11dd7781eced6d135269729f89ba5a73d3d1edfe59d14775b9efab2c.png
xcat EQXR_NSA_RTSZ_PZN0 EQXR_NSA_RTSZbMACRO_PZN0 EQXR_NSA_RTSZbMACROX_PZN0
Return % 3.00801 6.635022 5.869284
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.300801 0.663502 0.586928
Sortino Ratio 0.417169 0.946428 0.842703
Max 21-Day Draw % -17.143799 -21.941315 -19.807307
Max 6-Month Draw % -20.00846 -14.353689 -13.37829
Peak to Trough Draw % -28.08338 -22.867175 -20.997939
Top 5% Monthly PnL Share 1.081811 0.588157 0.667426
USD_EQXR_NSA correl 0.010331 0.182508 0.081519
Traded Months 257 257 257
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/0b31e6a2155742fe4b5d5c8ef6379c46d5652683b8b559eefaa5606e24e25dd6.png

Balanced robust trends (long sample) #

Specs and panel test #

dict_b92 = {
    "sigs": ["EQXR_NSA_RTSZ", "EQXR_NSA_RTSZbMACROX90"], 
    "targs": ["EQXR_NSA"],
    "cidx": cids_dm90,
    "start": "1992-01-01",
    "crs": None,
    "srr": None,
    "pnls": None,
}
dix = dict_b92

sigs = dix["sigs"]
targs = dix["targs"]
cidx = dix["cidx"]
start = dix["start"]

# Initialize the dictionary to store CategoryRelations instances

dict_cr = {}

for targ in targs:
    for sig in sigs:
        lab = sig + "_" + targ
        dict_cr[lab] = msp.CategoryRelations(
            dfx,
            xcats=[sig, targ],
            cids=cidx,
            freq="M",
            lag=1,
            xcat_aggs=["last", "sum"],
            start=start,
        )

dix["crs"] = dict_cr
# Plotting panel scatters

dix = dict_b92
dict_cr = dix["crs"]
sigs = dix["sigs"]
targs = dix["targs"]

crs = list(dict_cr.values())
crs_keys = list(dict_cr.keys())
ncol = len(sigs)
nrow = len(targs)
           
msv.multiple_reg_scatter(
    cat_rels=crs,
    ncol=ncol,
    nrow=nrow,
    figsize=(16, 8),
    prob_est="map",
    coef_box="lower left",
    title=None,
    subplot_titles=None,
    xlab="end-of-month information state",
    ylab="next month's return",
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/7a445020d3407d5402ac8d60e2d995e10ad2c33711e87ececc38dd4245f7529d.png

Accuracy and correlation check #

dix = dict_b92

sigs = dix["sigs"]
targs = dix["targs"]
cidx = dix["cidx"]
start = dix["start"]

srr = mss.SignalReturnRelations(
    dfx,
    cids=cidx,
    sigs=sigs,
    rets=targs[0],
    freqs="M",
    start=start,
)

dix["srr"] = srr
display(srr.signals_table().sort_index().astype("float").round(3))
accuracy bal_accuracy pos_sigr pos_retr pos_prec neg_prec pearson pearson_pval kendall kendall_pval auc
Return Signal Frequency Aggregation
EQXR_NSA EQXR_NSA_RTSZ M last 0.565 0.521 0.734 0.604 0.615 0.426 0.028 0.332 -0.016 0.415 0.517
EQXR_NSA_RTSZbMACROX90 M last 0.572 0.527 0.746 0.604 0.618 0.436 0.070 0.015 0.037 0.057 0.521

Naive PnL #

dix = dict_b92

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]

naive_pnl = msn.NaivePnL(
    dfx,
    ret=targ,
    sigs=sigx,
    cids=cidx,
    start=start,
    bms=["USD_EQXR_NSA"],
)

for sig in sigx:
    for bias in [0, 1]:
        naive_pnl.make_pnl(
            sig,
            sig_add=bias,
            sig_op="zn_score_pan",
            thresh=2,
            rebal_freq="monthly",
            vol_scale=10,
            rebal_slip=1,
            pnl_name=sig + "_PZN" + str(bias),
        )

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

dix["pnls"] = naive_pnl

dict_names["EQXR_NSA_RTSZbMACROX90_PZN0"] = "Trend balanced with macro support ex carry"
dict_names["EQXR_NSA_RTSZbMACROX90_PZN1"] = "Trend balanced with macro support ex carry, long bias"
dix = dict_b92

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
naive_pnl = dix["pnls"]


pnls = [s + "_PZN0" for s in sigx] # + ["Long only"]
pnls_labels = [dict_names[s] for s in pnls]

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start,
    title="Long-short equity strategy PnL based on balanced trend signals, long sample (U.S., Japan and UK)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

display(naive_pnl.evaluate_pnls(pnl_cats=pnls))

naive_pnl.signal_heatmap(pnl_name=sigx[0] + "_PZN0", freq="q", start=start, figsize=(16, 4))
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/e2491c137bd33648e946246908656a780f5afedb7ca920c10c0c884b33756a38.png
xcat EQXR_NSA_RTSZ_PZN0 EQXR_NSA_RTSZbMACROX90_PZN0
Return % 3.253595 5.125461
St. Dev. % 10.0 10.0
Sharpe Ratio 0.32536 0.512546
Sortino Ratio 0.456422 0.728339
Max 21-Day Draw % -16.51266 -18.892908
Max 6-Month Draw % -20.108218 -16.506721
Peak to Trough Draw % -31.93561 -26.347129
Top 5% Monthly PnL Share 1.1362 0.737678
USD_EQXR_NSA correl -0.021696 0.136339
Traded Months 400 400
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/f63644b228793bfe97e141ec919d283032d64694188d0e1fc01a3c4c3a756314.png
dix = dict_b92

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]
naive_pnl = dix["pnls"]


pnls = [s + "_PZN1" for s in sigx] + ["Long only"]
pnls_labels = [dict_names[s] for s in pnls]

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    start=start,
    title="Long-biased equity index strategy PnL based on balanced trend signals, long sample (U.S., Japan and UK)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

naive_pnl.plot_pnls(
    pnl_cats=pnls,
    pnl_cids=["ALL"],
    compounding=True,
    start=start,
    title="Compounding long-biased equity index strategy PnL based on balanced trend signals, long sample (U.S., Japan and UK)",
    title_fontsize=18,
    figsize=(17, 7),
    xcat_labels=pnls_labels,
)

display(naive_pnl.evaluate_pnls(pnl_cats=pnls))
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/8cab5fe5ed22974a8f511b67c4890257f106f54f2be06db129468e76b0b0de33.png https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/af98a5a35445b58335b074b3058af81144e13b8d112f569dea08d3f5804af0af.png
xcat EQXR_NSA_RTSZ_PZN1 EQXR_NSA_RTSZbMACROX90_PZN1 Long only
Return % 5.478812 5.610129 4.222745
St. Dev. % 10.0 10.0 10.0
Sharpe Ratio 0.547881 0.561013 0.422275
Sortino Ratio 0.757201 0.787341 0.588262
Max 21-Day Draw % -15.513942 -29.365603 -24.565113
Max 6-Month Draw % -17.431189 -22.925864 -35.080736
Peak to Trough Draw % -22.973599 -36.239345 -50.743907
Top 5% Monthly PnL Share 0.588493 0.653801 0.739787
USD_EQXR_NSA correl 0.478217 0.523885 0.706071
Traded Months 401 401 401

Checks #

Specs and panel test #

eqtrendz_bal
['EQXR_NSA_RTSZbXSPEND',
 'EQXR_NSA_RTSZbXINF',
 'EQXR_NSA_RTSZbLIQINT',
 'EQXR_NSA_RTSZbXCRR',
 'EQXR_NSA_RTSZbMACRO',
 'EQXR_NSA_RTSZbMACROX',
 'EQXR_NSA_RTSZbMACROX90']
tests = [
    "EQXR_NSA_RTSZbXSPEND",
    "EQXR_NSA_RTSZbXINF",
    "EQXR_NSA_RTSZbMACROX90",
]

dict_test = {
    "sigs": ["EQXR_NSA_RTSZ"] + tests,
    "targs": ["EQXR_NSA"],
    "cidx": cids_dm90,
    "start": "1992-01-01",
    "crs": None,
    "srr": None,
    "pnls": None,
}
dix = dict_test

sigs = dix["sigs"]
targs = dix["targs"]
cidx = dix["cidx"]
start = dix["start"]

# Initialize the dictionary to store CategoryRelations instances

dict_cr = {}

for targ in targs:
    for sig in sigs:
        lab = sig + "_" + targ
        dict_cr[lab] = msp.CategoryRelations(
            dfx,
            xcats=[sig, targ],
            cids=cidx,
            freq="M",
            lag=1,
            xcat_aggs=["last", "sum"],
            start=start,
        )

dix["crs"] = dict_cr
dix = dict_test
dict_cr = dix["crs"]
sigs = dix["sigs"]
targs = dix["targs"]

crs = list(dict_cr.values())
crs_keys = list(dict_cr.keys())
ncol = 2
nrow = 2
           
msv.multiple_reg_scatter(
    cat_rels=crs,
    ncol=ncol,
    nrow=nrow,
    figsize=(15, 15),
    prob_est="map",
    coef_box="lower left",
    title=None,
    subplot_titles=None,
    xlab="end-of-month information state",
    ylab="next month's return",
)
https://macrosynergy.com/notebooks.build/trading-factors/robust-equity-trends-and-headwinds/_images/bf8fe42e0c6547b6910ddcfe21185f9750bb74a77fb1680c792dee42683db7e0.png

Accuracy and correlation check #

dix = dict_test

sigs = dix["sigs"]
targs = dix["targs"]
cidx = dix["cidx"]
start = dix["start"]

srr = mss.SignalReturnRelations(
    dfx,
    cids=cidx,
    sigs=sigs,
    rets=targs[0],
    freqs="M",
    start=start,
)

dix["srr"] = srr
display(srr.signals_table().sort_index().astype("float").round(3))
accuracy bal_accuracy pos_sigr pos_retr pos_prec neg_prec pearson pearson_pval kendall kendall_pval auc
Return Signal Frequency Aggregation
EQXR_NSA EQXR_NSA_RTSZ M last 0.565 0.521 0.734 0.604 0.615 0.426 0.028 0.332 -0.016 0.415 0.517
EQXR_NSA_RTSZbMACROX90 M last 0.572 0.527 0.746 0.604 0.618 0.436 0.070 0.015 0.037 0.057 0.521
EQXR_NSA_RTSZbXINF M last 0.576 0.540 0.703 0.604 0.628 0.452 0.069 0.017 0.024 0.214 0.535
EQXR_NSA_RTSZbXSPEND M last 0.557 0.523 0.676 0.604 0.619 0.427 0.031 0.291 0.006 0.762 0.521
dix = dict_test

sigx = dix["sigs"]
targ = dix["targs"][0]
cidx = dix["cidx"]
start = dix["start"]

naive_pnl = msn.NaivePnL(
    dfx,
    ret=targ,
    sigs=sigx,
    cids=cidx,
    start=start,
    bms=["USD_EQXR_NSA"],
)

for sig in sigx:
    for bias in [0, 1]:
        naive_pnl.make_pnl(
            sig,
            sig_add=bias,
            sig_op="zn_score_pan",
            thresh=2,
            rebal_freq="monthly",
            vol_scale=10,
            rebal_slip=1,
            pnl_name=sig + "_PZN" + str(bias),
        )

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

dix["pnls"] = naive_pnl
Contents
  • Get packages and JPMaQS data
  • Renaming and availability check
    • Renaming
    • Availability check
  • Feature engineering and checks
    • Domestic spending growth
      • Transformations
      • Structuring and scoring
    • CPI inflation
      • Transformations
      • Structuring and scoring
    • Equity carry
      • Transformations
      • Structuring and scoring
    • Intervention-driven liquidity expansion
      • Structuring and scoring
    • Cross-category scores
      • Thematic factor scores
      • Aggregate macro support scores
  • Robust equity returns trends and modification
    • Robust trend
    • Modified robust trend
    • Balanced trends
  • Targets review
  • Value checks
    • Modified robust trends (short sample)
      • Specs and panel test
      • Accuracy and correlation check
      • Naive PnL
    • Modified robust trends (long sample)
      • Specs and panel test
      • Accuracy and correlation check
      • Naive PnL
    • Balanced robust trends (short sample)
      • Specs and panel test
      • Accuracy and correlation check
      • Naive PnL
    • Balanced robust trends (long sample)
      • Specs and panel test
      • Accuracy and correlation check
      • Naive PnL
    • Checks
      • Specs and panel test
      • Accuracy and correlation check

By Macrosynergy Ltd.

© Copyright 2023.

ABOUT US

Macrosynergy is a London based macroeconomic research and technology company whose founders have developed and employed macro quantamental investment strategies in liquid, tradable asset classes, across many markets and for a variety of different factors to generate competitive, uncorrelated investment returns for institutional investors for two decades. Our quantitative-fundamental (quantamental) computing system tracks a broad range of real-time macroeconomic trends in developed and emerging countries, transforming them into macro systematic quantamental investment strategies. In June 2020 Macrosynergy and J.P. Morgan started a collaboration to scale the quantamental system and to popularize tradable economics across financial markets.

FOLLOW US
Linkedin
LEGAL
  • Terms of business
  • Cookie Policy
  • Acceptable use policy
  • Privacy Policy
  • Terms of business
  • Cookie Policy
  • Acceptable use policy
  • Privacy Policy
© 2023 Macrosynergy Ltd. | All rights reserved
  • The Opportunity
  • Our Leadership
  • Our History
  • Careers
  • The Opportunity
  • Our Leadership
  • Our History
  • Careers
Manage Cookie Consent
To provide the best experiences on macrosynergy.com, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
Manage options Manage services Manage {vendor_count} vendors Read more about these purposes
View preferences
{title} {title} {title}
  • Research
    • Macro Information Efficiency
    • Quantitative methods for macro information efficiency
    • Fundamental Value Estimates
    • Macro Trends
    • Implicit Subsidies in Financial Markets
    • Endogenous Market Risk
    • Price Distortions
    • Basics of systemic risk management
    • Non-Conventional Monetary Policies
    • Financial System Risk
    • Government Finances
  • Quantamental Academy
    • What Are Macro Quantamental Indicators?
    • Introductory Tutorials
    • Quantamental indicators on JPMaQS
    • Value Generation Based On Quantamental Factors
    • Statistics Packages With Quantamental Indicators
    • Examples of Macro Trading Factors
  • About Us
    • The Opportunity
    • Our Leadership
    • Our History
    • Careers
Research
Quantamental Academy
About Us