Quant BuffetRelax, Not Over Thinking

End-of-Month Treasury Returns

Log in to collect

Academic paper

Predictable End-of-Month Treasury Returns

AuthorsJonathan Hartley; Krista Schwarz

Institute
  • Stanford University
  • Federal Reserve Board of Governors
  • Federal Reserve
  • ?Board of Governors of the Federal Reserve System

Strategy in a nutshell

The strategy trades 30-year Treasury futures, buying five days before month-end and selling on the last day.

Economic rationale

Life insurers drive month-end Treasury price patterns through large purchases of long-term securities to match liabilities. This creates a feedback loop where lower yields increase duration mismatches, further boosting demand. Their activity, sometimes influenced by window dressing or portfolio rebalancing, also affects Treasury futures and related interest rate markets, shaping benchmark rates.

Backtest performance

Annualised return3.96%
Volatility7.65%
Beta0
Sharpe ratio0.52
Sortino ratio0.103
Win rate59%

Full Python code

from AlgorithmImports import *
from pandas.tseries.offsets import BDay
from pandas.tseries.offsets import BMonthEnd
class EOMTreasuryReturns(QCAlgorithm):
def initialize(self) -> None:
self.set_start_date(2000, 1, 1)
self.set_cash(100_000)
self.set_brokerage_model(BrokerageName.INTERACTIVE_BROKERS_BROKERAGE, AccountType.MARGIN)
self.settings.minimum_order_margin_portfolio_percentage = 0
self.settings.daily_precise_end_time = True

self._traded_symbol: Symbol = self.add_equity('TLT', Resolution.MINUTE).symbol
minute_offset: int = 1
self._eom_trigger_day_offset: int = 6
self._month_close_flag: bool = False
self._day_close_flag: bool = False
# schedule functions
self.schedule.on(
    self.date_rules.every_day(self._traded_symbol), self.time_rules.before_market_close(self._traded_symbol, minute_offset), self._before_eod
)
self.schedule.on(
    self.date_rules.month_end(self._traded_symbol), self.time_rules.before_market_close(self._traded_symbol, minute_offset), self._month_close
)

def on_data(self, slice: Slice) -> None:
# close position
if self._month_close_flag:
    self._month_close_flag = False
    if self.portfolio[self._traded_symbol].invested:
        self.liquidate(self._traded_symbol)
    
if self._day_close_flag:
    self._day_close_flag = False
    if slice.contains_key(self._traded_symbol) and slice[self._traded_symbol]:
        offset = BMonthEnd()
        last_day: datetime = offset.rollforward(self.time)
        while not self.securities[self._traded_symbol].exchange.hours.is_date_open(last_day):
            last_day = last_day - timedelta(days=1)
        trigger_day: datetime = last_day - BDay(self._eom_trigger_day_offset)
        if self.time == trigger_day:
            self.set_holdings(self._traded_symbol, 1.)

def _before_eod(self) -> None:
self._day_close_flag = True

def _month_close(self) -> None:
self._month_close_flag = True