The recommended investment for this strategy is the CSI300 index, which includes 300 representative stocks in the overall Chinese securities market (you can use index futures, ETF, or CFD, for example). (Astronomical information is extracted from the website Astro Seek .) Lag 1 week corresponds to one week following the entire (non-) Mercury retrograde period.

I. STRATEGY IN A NUTSHELL

Universe: CSI300 index (futures, ETF, or CFD). Trade based on Mercury retrograde cycles: short one week after retrograde starts, cover and go long five days after retrograde ends, hold until the next retrograde onset. Strategy uses full capital (100%) and is dynamically rebalanced.

II. ECONOMIC RATIONALE

Behavioral finance explains the pattern: high retail participation in China leads to excess volatility and overtrading. Mercury retrograde correlates with increased selling and loss aversion, reflecting superstition-driven investor behavior.

III. SOURCE PAPER

A Natural Experiment in the Chinese Stock Market [Click to Open PDF]

Shubo Kou, Xiyuan Ma, Tsinghua University, PBC School of Finance, Students

<Abstract>

This paper examines the effects of superstitious psychology on investors’ decision making in the contextof Mercury retrograde, a special astronomical phenomenon meaning “everything going wrong”. Usingnatural experiments in the Chinese stock market, we find a significant decline in stock prices, approximately -3.14% in the vicinity of Mercury retrogrades, with a subsequent reversal following these periods. The Mercury effect is robust after considering seasonality, the calendar effect, and well-known firm-level characteristics. Our mechanism tests are consistent with model-implied conjectures that stocks covered by higher investor attention are more influenced by superstitious psychology in the extensive and intensive channels. A superstitious hedge strategy motivated by our findings can generate an average annualized market-adjusted return of 8.73%.

IV. BACKTEST PERFORMANCE

Annualised Return22.12%
Volatility40.28%
Beta0.039
Sharpe Ratio0.55
Sortino RatioN/A
Maximum DrawdownN/A
Win Rate57%

V. FULL PYTHON CODE

from AlgorithmImports import *
import data_tools
from pandas.tseries.offsets import BDay
# endregion

class MercuryRetrogradeAstrologyTradingStrategyinChineseMarket(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2000, 1, 1)
        self.SetCash(100000)
        
        self.leverage:int = 5
        self.lag:int = 5
        self.counter:Union[None, int] = None
        self.trade_direction:Union[None, int] = None

        # load custom data
        self.mercury_retrograde_calendar:Symbol = self.AddData(data_tools.MercuryRetrogradeCalendar, 'mercury_retrograde_calendar', Resolution.Daily).Symbol
        self.market:Symbol = self.AddData(data_tools.QuantpediaCSI300, 'CSI_300', Resolution.Daily).Symbol
        self.Securities[self.market].SetLeverage(self.leverage)
        self.Securities[self.market].SetFeeModel(data_tools.CustomFeeModel())

    def OnData(self, data: Slice):
        market_last_update_date:datetime.date = data_tools.QuantpediaCSI300._last_update_date
        calendar_last_update_date:datetime.date = data_tools.MercuryRetrogradeCalendar._last_update_date

        # check if data is still coming
        if self.Securities[self.market].GetLastData() and self.Time.date() >= market_last_update_date \
            or self.Securities[self.mercury_retrograde_calendar].GetLastData() and self.Time.date() >= calendar_last_update_date:
            self.Liquidate()
            return

        if self.counter is not None:
            if self.market in data and data[self.market]:
                self.counter += 1
                if self.counter == self.lag:
                    self.SetHoldings(self.market, self.trade_direction)
                    self.trade_direction = None

        if self.mercury_retrograde_calendar in data and data[self.mercury_retrograde_calendar] and self.Securities[self.market].GetLastData():
            if self.trade_direction is None:
                self.trade_direction = -1 if data[self.mercury_retrograde_calendar].status == 'start' else 1
                self.counter = 0

Leave a Reply

Discover more from Quant Buffet

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

Continue reading