Original paper
Abstract
European currencies have positive average returns during US business hours and negative average returns during foreign business hours. I propose a risk-based explanation: Because news about US growth prospects arrives mostly during US business hours, US investors require higher risk premia to hold risky foreign currencies in these hours. Consistent with this argument, I find the difference in a currency's returns between US and foreign business hours widens if the currency has a higher risk exposure, and when its exchange rate becomes more volatile. These results connect currency returns in different time zones to currency risk premia observable at lower frequencies, and support asset pricing models with recursive preferences and long-run risks.
Keywords:Â Exchange Rates; Currency Risk Premia; Long-Run Risks
Trading rules
- Target asset: EUR/USD forex pair.
- During EU business hours (from 8 AM to 4 PM London time), take a short position in EUR/USD.
- Switch to a long position in EUR/USD during US business hours (from 4 PM London to 5 PM New York time).
- Trading cost: subtract 1 bps (bid/ask spread).
Python code
Backtrader
import datetime
import pytz
import backtrader as bt
class IntradayCurrencySeasonality(bt.Strategy):
def __init__(self):
self.currency_pair = "EUR/USD"
self.pip = 0.0001
self.spread = self.pip
self.london_tz = pytz.timezone('Europe/London')
self.new_york_tz = pytz.timezone('America/New_York')
def next(self):
current_time_london = datetime.datetime.now(self.london_tz).time()
current_time_new_york = datetime.datetime.now(self.new_york_tz).time()
eu_open = datetime.time(8, 0)
eu_close = datetime.time(16, 0)
us_open = datetime.time(9, 0)
us_close = datetime.time(17, 0)
if eu_open <= current_time_london < eu_close:
self.sell(size=1)
self.buy(size=1, exectype=bt.Order.Stop, price=self.data.close[0] + self.spread)
if us_open <= current_time_new_york < us_close:
self.buy(size=1)
self.sell(size=1, exectype=bt.Order.Stop, price=self.data.close[0] - self.spread)
cerebro = bt.Cerebro()
data = bt.feeds.GenericCSVData(
dataname='path_to_your_EURUSD_data',
fromdate=datetime.datetime(2021, 1, 1),
todate=datetime.datetime(2021, 12, 31),
timeframe=bt.TimeFrame.Minutes,
compression=1,
dtformat='%Y-%m-%d %H:%M:%S',
openinterest=-1)
cerebro.adddata(data)
cerebro.addstrategy(IntradayCurrencySeasonality)
cerebro.run()
Replace 'path_to_your_EURUSD_data'
with the actual path to your EUR/USD data file. The data file should contain at least the columns: datetime
, open
, high
, low
, close
, and volume
.