Invest in 16 ETFs tracking country indexes. Short top 4 and long bottom 4 based on 36-month returns. Rebalance triennially.

STRATEGY IN A NUTSHELL

The strategy involves 16 ETFs, each representing a different country’s equity index. The approach is to invest long in the four ETFs representing countries with the lowest 36-month returns and short the four with the highest returns over the same period. This portfolio is adjusted every three years to account for changes in market performance, aiming to capitalize on the potential for reversal in the fortunes of underperforming and outperforming countries. This contrarian strategy seeks to exploit long-term cyclical shifts in market valuations.

ECONOMIC RATIONALE

The study investigates why national stock markets experience performance reversals over years, highlighting challenges in pinpointing a definitive cause due to short data samples, limited country numbers, market integration issues, and the absence of a universal asset pricing model. This complexity mirrors the ongoing debate about price anomalies in the U.S. market. Crucially, the research finds no evidence linking these reversals to risk differentials, dismissing the idea that prior underperformers were riskier based on their volatility or correlation with global market returns or other risk factors. However, reversals were more pronounced in smaller markets, suggesting a potential “small-country effect” or market imperfections. Additionally, the limited impact of cross-border equity flows on correcting mispricings, possibly due to fears of expropriation or capital controls, offers another explanation. The study also entertains the possibility that arbitrage might not fully eliminate price discrepancies due to equities’ uncertain valuation, return volatility, and the time needed for market correction. Interestingly, increased cross-border flows might exacerbate mispricings by attracting more momentum investors, further complicating the market dynamics.

SOURCE PAPER

Winner-Loser Reversals in National Stock Market Indices: Can They be Explained? [Click to Open PDF]

Anthony J. Richards, affiliation unknown

<Abstract>

This paper examines possible explanations for “winner-loser reversals” in the national stock market indices of 16 countries. There is no evidence that loser countries are riskier than winner countries either in terms of standard deviations, covariance with the world market or other risk factors, or performance in adverse economic states of the world. While there is evidence that small markets are subject to larger reversals than large markets, perhaps because of some form of market imperfection, the reversals are not just a small-market phenomenon. The apparent anomaly of winner-loser reversals in national market indices therefore remains unresolved.

BACKTEST PERFORMANCE

Annualised Return6.4%
VolatilityN/A
Beta-0.07
Sharpe Ratio-0.28
Sortino Rato-0.3
Maximum Drawdown80.3%
Win Rate41%

FULL PYTHON CODE

from AlgoLib import *

class InternationalEquityReversals(XXX):
    '''
    This class implements an international equity reversal strategy using the XXX framework.
    It focuses on identifying and trading based on momentum reversals in international ETFs.
    '''

    def Initialize(self):
        '''
        Initializes the algorithm settings, including start date, initial cash, 
        the list of ETF symbols to trade, momentum score dictionary, analysis period, 
        and rebalance interval.
        '''
        
        self.SetStartDate(2000, 1, 1)  # Set the start date of the algorithm
        self.SetCash(100000)  # Set the initial cash balance

        self.momentum_scores = {}  # Initialize a dictionary to store momentum scores

        self.analysis_period = 36 * 21  # Define the analysis period in trading days (approx. 36 months)
        self.SetWarmUp(self.analysis_period, Resolution.Daily)  # Warm-up period for indicators

        # Define a list of ETF symbols representing various international markets
        self.etf_symbols = [
            "EWA",  # Australia
            "EWO",  # Austria
            "EWK",  # Belgium
            "EWZ",  # Brazil
            "EWC",  # Canada
            "FXI",  # China
            "EWQ",  # France
            "EWG",  # Germany
            "EWH",  # Hong Kong
            "EWI",  # Italy
            "EWJ",  # Japan
            "EWM",  # Malaysia
            "EWW",  # Mexico
            "EWN",  # Netherlands
            "EWS",  # Singapore
            "EZA",  # South Africa
            "EWY",  # South Korea
            "EWP",  # Spain
            "EWD",  # Sweden
            "EWL",  # Switzerland
            "EWT",  # Taiwan
            "THD",  # Thailand
            "EWU",  # UK
            "SPY",  # USA
        ]

        # Add each ETF symbol to the algorithm, set fee model and leverage, and initialize momentum scores
        for symbol in self.etf_symbols:
            equity = self.AddEquity(symbol, Resolution.Daily)
            equity.SetFeeModel(EnhancedFeeModel())  # Set a custom fee model
            equity.SetLeverage(15)  # Set leverage for each equity

            # Calculate the Rate of Change (ROC) indicator for each symbol for the analysis period
            self.momentum_scores[symbol] = self.ROC(symbol, self.analysis_period, Resolution.Daily)
        
        self.rebalance_interval = 36  # Set rebalance interval in months
        self.last_rebalance_month = -1  # Initialize the last rebalance month

    def OnData(self, data: Slice):
        '''
        This method is called whenever new data is received. It checks if the warm-up period is complete, 
        then rebalances the portfolio based on momentum scores if the rebalance interval has been reached.
        '''
        
        if self.IsWarmingUp:
            return  # Do nothing if the algorithm is still warming up

        current_month = self.Time.month  # Get the current month

        # Check if the current month is the same as the last rebalance month to avoid multiple rebalances within the same month
        if current_month == self.last_rebalance_month:
            return

        self.last_rebalance_month = current_month  # Update the last rebalance month
        self.rebalance_interval += 1  # Increment the rebalance interval counter

        # Check if the rebalance interval is less than or equal to 36 months
        if self.rebalance_interval <= 36:
            return
        self.rebalance_interval = 1  # Reset the rebalance interval

        # Sort ETFs by momentum scores and select the top and bottom 4 for long and short positions
        momentum_sorted = sorted([x for x in self.momentum_scores.items() if x[1].IsReady and x[0] in data], key=lambda x: x[1].Current.Value, reverse=True)
        to_long = [x[0] for x in momentum_sorted[-4:]]  # Symbols to take long positions in
        to_short = [x[0] for x in momentum_sorted[:4]]  # Symbols to take short positions in

        # Adjust portfolio by liquidating positions not in the to_long or to_short lists and setting holdings for new positions
        for symbol in self.Portfolio:
            if symbol.Value not in to_long + to_short:
                self.Liquidate(symbol.Value)  # Liquidate positions not being held

        for symbol in to_long:
            self.SetHoldings(symbol, 1 / len(to_long))  # Set long positions equally weighted
        for symbol in to_short:
            self.SetHoldings(symbol, -1 / len(to_short))  # Set short positions equally weighted

class EnhancedFeeModel(FeeModel):
    '''
    This class defines a custom fee model for the algorithm, calculating fees based on a specified rate.
    '''
    
    def GetOrderFee(self, parameters: OrderFeeParameters):
        fee = parameters.Security.Price * parameters.Order.AbsoluteQuantity * 0.00005  # Custom fee rate
        return OrderFee(CashAmount(fee, "USD"))
        

Leave a Reply

Discover more from Quant Buffet

Subscribe now to keep reading and get access to the full archive.

Continue reading