ftw.tradeblog
← All posts
5 min readftw.trade

Buy the close, sell the open: the overnight hold on onchain SPY

We built a one-click strategy that holds tokenized SPY only while the US stock market is shut, taught Flowscript the exchange's real calendar, and gated it on a daily news read.

flowscriptstrategiesbacktestingequitiesrobinhood-chain

There's an old, well documented quirk in US stocks: most of the S&P 500's gains since the early 1990s have come while the market was shut, between one day's close and the next day's open. Hold SPY only overnight and you caught most of the move. Hold it only during the session and you caught very little. Same fund, same days, two very different assets depending on the clock.

We wanted that to be one click on ftw.trade. Here's what it took, and what the first six weeks of onchain data say.

The strategy is two lines

In Flowscript the whole idea fits in two when blocks: buy in the last few minutes of the session, sell on the first bar of the next one.

const session = nyseSession(t);
const toClose = nyseMinutesToClose(t);

when (session && toClose <= entryMinutes && moodOk && !inPosition()) { paper.buy({ quote: size }); }
when (sessionStarts(session) && inPosition()) { paper.sell({}); }

The hard part was not those two lines. It was knowing when "the close" and "the open" actually are.

One round trip: buy on the 15:45 bar, fill at 15:50, hold while the exchange is shut, sell on the first bar of the next session

Flowscript now knows the exchange's calendar

Before this, Flowscript knew New York's clock but not the New York Stock Exchange's calendar. A naive strategy would happily buy into Good Friday, or sell at 16:00 on the day after Thanksgiving, three hours after the market had already closed at 13:00.

Thanksgiving week 2026 by the exchange's calendar: Thursday closed, Friday closing at 13:00

So we added nyseClose(t), a built-in that returns the exchange's close on any date: 16:00, 13:00 on an early close, or nothing when the market is shut. It follows the exchange's own rules: holidays that fall on a weekend are observed on the Friday or Monday, Juneteenth counts from 2022, Good Friday comes from the Easter date, and one-off closures like 11 September 2001, Hurricane Sandy and national days of mourning are listed by name. It is checked against the exchange's published calendars for 2021 to 2027.

On top of it sit plain helpers: nyseSession, nyseTradingDay, nyseHoliday, nyseEarlyClose and nyseMinutesToClose. Any strategy can use them, not just this one.

We first wrote the calendar in Flowscript itself. Easter alone made each call expand to 1.7 MB, past the 1 MB a program may compile to. Moving it into the engine as a native built-in made it free, and the interpreter, the JIT and the backtester all answer the same way because they share one table of math functions.

The onchain SPY token trades all night

Tokenized SPY on Robinhood Chain trades around the clock in an onchain pool. That matters: if the token only moved during market hours, there would be nothing to capture overnight.

Mean absolute hourly move of onchain SPY by New York hour

It does move. On weekdays the token moves about 4 to 7 basis points an hour while the exchange is shut, and 9 to 16 basis points an hour for most of the session. The hours just before the open, when US economic data comes out at 8:30, are nearly as busy as the session. Weekends are quiet, at 3.5 basis points an hour. The token keeps repricing overnight, so the overnight gap is there to hold.

Fees decide everything

A strategy that trades twice a day lives or dies on its fee. Our backtester used to charge a flat 0.3% for spot trades in a multi-market run. The SPY/USDG pool actually charges 0.005%, sixty times less. We fixed the backtester to charge each pool its own fee.

The difference is not subtle. Over the same 30 round trips with $1,000 a trade:

Fee per trade Overnight fees Overnight return Intraday return
0.005% (the real pool) $2.95 +0.30% +0.26%
0.3% (a typical DEX pool) $165.60 −15.73% −16.03%

Overnight and intraday returns after fees at 0.005% and at 0.3% a trade

At a typical DEX fee, the anomaly is gone many times over. On this pool, it is cheap enough to try.

What six weeks show

We ran the starter on every 5-minute bar of the SPY/USDG pool from 10 September to 22 October 2026.

Overnight vs intraday returns on onchain SPY, 10 Sep to 22 Oct 2026

Overnight made +0.30% after fees, intraday +0.26%, and simply holding the token +0.54%. That is a tie, and six weeks is far too short to say anything. The clearest sign of that: buying at 16:00 instead of 15:50 turns the overnight result from −0.23% into +0.52% over the same 29 nights. The anomaly is a decades-long average, not something a month and a half will show.

What the run does show is that the plumbing works end to end on real onchain bars: 30 round trips in six weeks, each bought before the close and sold at the next open. The window has no exchange holidays or early closes, so those are covered by the calendar's tests against the exchange's own published lists, not by this run.

Only buy when the news is calm

The second idea: most bad overnight gaps come from bad news. So we added a shared feed, us-news-mood, that reads the day's US market headlines and rates the evening from 1 (very bearish) to 99 (very bullish).

Every weekday at 15:30 New York, it pulls the headlines published since the previous rating from GDELT's news index and asks the assistant's language model to rate them. Each rating is stored with the headlines it read and the model that read them, and written into the feed's history, so a backtest sees exactly what a live run would have seen that day. The feed backfills about three months of past weekdays, one at a time.

The news gate: GDELT headlines, rated by the language model, stored in the feed, read by the strategy at its buy window

The strategy only buys when the mood is at or above its minMood. The template offers three presets: neutral or better (40), always (0), and bullish only (61).

One honest caveat: a model rating days from before its training ended may already know how those days turned out. So a backtest of the gate over older days carries hindsight. Days after the model's training are clean, and those are the ones that count.

We will publish gated vs ungated results once the feed has filled in.

Try it

On ftw.trade, start a new project from the Overnight hold template. Pick the SPY pool, the number of wallets and the size, and choose a news preset. It sets up the wallets, the strategy and a dashboard tab with the mood feed next to the chart. Everything runs on paper until you turn live trading on for the project.