Lunar Monthly Effect in Chinese Stocks
Log in to collectAcademic paper
Strategy in a nutshell
The strategy invests in Chinese A-share stocks by going long on six major market indices at the start of Lunar January. Positions are value-weighted and held for the full lunar month (28 days) without rebalancing. The approach aims to capture short-term market gains associated with the Lunar New Year period.
Economic rationale
The Lunar January effect in Chinese markets is driven by seasonal patterns in trading volumes, buy proportions, and daily returns, especially in smaller firms. Significant macro events, such as the National People’s Congress and the Chinese People’s Political Consultative Conference (LIANGHUI), also positively impact stock performance. Traditional explanations like tax-loss selling or window dressing do not account for this effect in China.
Backtest performance
Full Python code
from AlgorithmImports import *
from data_tools import CustomFeeModel, GregorianLunarDates, ChinaIndexData
# endregion
class LunarMonthlyEffectInChineseStocks(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2000, 1, 1)
self.SetCash(100000)
self.leverage:int = 5
self.liquidate_period:int = 28
self.liquidate_on_date_flag:bool = False
self.open_date:Union[datetime.date, None] = None
self.liquidate_date:Union[datetime.date, None] = None
self.fxi_flag:bool = True
data = self.AddEquity('FXI', Resolution.Daily) if self.fxi_flag else self.AddData(ChinaIndexData, 'HANG_SENG', Resolution.Daily)
data.SetFeeModel(CustomFeeModel())
data.SetLeverage(self.leverage)
self.china_market:Symbol = data.Symbol
self.gregorian_dates:Symbol = self.AddData(GregorianLunarDates, 'gregorian_lunar_dates', Resolution.Daily).Symbol
def OnData(self, data: Slice):
if self.gregorian_dates in data and data[self.gregorian_dates]:
date:str = data[self.gregorian_dates].GetProperty('gregorian_date_end_first_lunar_month')
self.liquidate_date = datetime.strptime(date, '%d.%m.%Y').date()
self.open_date = self.Time.date()
if self.Time.year != 2005: # data error prevention
if self.Securities[self.china_market].Price != 0 and self.Securities[self.china_market].IsTradable:
self.SetHoldings(self.china_market, 1)
if self.Portfolio.Invested:
if self.liquidate_on_date_flag and self.Time.date() >= self.liquidate_date:
self.Liquidate()
elif not self.liquidate_on_date_flag and (self.Time.date() - self.open_date).days >= self.liquidate_period:
self.Liquidate()