"Next open" always the best

I don’t know how many of you have developed a European RS, but for some reason, the use of open vs. close doesn’t work the same way in Europe.

Can anyone confirm this?

For me it works the same: next open is best, next close is worst.

I made a spreadsheet to compare sell and buy transactions - If you make a copy of the spreadsheet you can copy/past your own transactions in to it.

Thank you! I will test it!

Do I understand your findings correctly that the best idea is to close the sellers at the open, and buy the buys at the close?

image

image

image

In my sample data it looks like the best buy is on the previous close, best sell in next open (with a small margin to previous close).

When I click on Rebalance now for a live strategy, it says “Recommendations will be based on fundamental data as of 2023-08-26.”, that’s two days ago. In a simulation, do we simulate on fresh data from today, or two day old data (as in live strategies)?

Im getting some weird results!

Im trying to compare the same strategy, but buy close vs. buy open.

I downloaded the whole transaction history, which should be identical. But it isn’t. As early as line 28, the difference starts. Why?

TL;DR: I hate munging data a little less since ChatGPT came along. And do not let this fool you. I suck as programmer. I did not get inner and outer merge right. I called it “external merge” and did not have the right use, for example. :slight_smile:

Here are the results for 20 years of data for the sim above. ChatGPT allowed me to upload the entire file:

Difference of open compared to close (buy then sell). I.e. buy open and sell open just as Yuval says above (for my model too); Or for buys the close price is higher than the open and for sells the close is lower than the open (on average over 20 years). We have the same result FOR A SIM RUN ON MONDAY:

So I do not know why the columns do not line up but I was pretty sure they would not. Maybe this is important and Yuval can tell us why if Whycliffes wants to know.

Above I mentioned an “external merge” the correct term would have been ‘outer merge’ and I really needed an inner merge. Above was not correct.

One needs to do an’ inner merge.’ ChatGPT walked me through that. And BTW, you can upload the full 20 years of transactions.

Code:

// Perform an inner merge on the ‘Date’ and ‘Symbol’ columns
merged_df = pd.merge(tran_df[[‘Date_open’, ‘Symbol_open’, ‘Open’, ‘Price_open’]], tran_df[[‘Date_close’, ‘Symbol_close’, ‘Close’, ‘Price_close’]],
left_on=[‘Date_open’, ‘Symbol_open’], right_on=[‘Date_close’, ‘Symbol_close’], how=‘inner’)

// Extract the buy and sell rows from the merged dataframe
merged_buy = merged_df[merged_df[‘Open’] == ‘BUY’]
merged_sell = merged_df[merged_df[‘Open’] == ‘SELL’]

// Reset the index
merged_buy = merged_buy.reset_index(drop=True)
merged_sell = merged_sell.reset_index(drop=True)

// Compute the percentage difference in buy prices and sell prices
buy_price_diff_merged = ((merged_buy[‘Price_close’] - merged_buy[‘Price_open’]) / merged_buy[‘Price_open’]) * 100
sell_price_diff_merged = ((merged_sell[‘Price_close’] - merged_sell[‘Price_open’]) / merged_sell[‘Price_open’]) * 100

buy_price_diff_merged.mean(), sell_price_diff_merged.mean()

Jim

BTW, same sim run on Friday (WeekDay = 6). People can draw their own inferences which may or may not apply to their models:

But maybe consistent with what Yuval has said, that as a general rule there is not much change in the prices during the day.

Jim

You will not get the exact same transactions if the account size differs over time, that’s why I made the spreadsheet, to only compare the transactions that matches.

I have used your spreadsheet on a model with 100 positions of the S&P 500. The model has over 21,000 transactions. Your sheet returns that it is best to buy at the next open and sell at the next close.

BUY transaction difference
0.07% If positive, better to buy in the open If negative, better to buy at Next Close
SELL transaction difference
0.04% If negative, better to sell in the open If Positive, better sell at next close

Is that trades on Mondays or any day?

All trades on 1st trading day of the week.

Did this ever get fully resolved? I’m running a strategy that is showing absurd differences (~18% CAGR) whether I run Next Open or Next Close. Average of High/Low/2x Close is only slightly better than Next Close.

Next close:

Next open:

Rebalance is bi-weekly. Obviously if I dial that out to monthly and beyond the spread narrows, but that’s due to less turnover. The two photos above are product of me literally only toggling between open/close execution.

It also begs the question, which one does the ranking system go off of? We can’t change it there.

Just to follow up...I've done about 125 trades since that comment and recorded my live execution prices versus the modeled Next Open and Next Close prices. What I've found is that the average slippage compared to Next Close is less. So when backtesting with the new Next Open and Next Close slippage figures independently, the performance stats come out closer to even. I was doing $10-15k per position without much patience (often times mobile) and clocked in slippage compared to Next Open at ~0.5% and ~0.2% compared to Next Close. I discovered a rule for myself that I don't enter the position if the price opens 4-5% in the green that day. That really helped my average once I did that after about 25 trades. If I throw out the first 25ish trades before I implemented that rule, slippage decreased.

There's something else going on here that my earlier replies might have missed.

When a new earnings report is issued, on the Monday after the report is issued the stock will frequently go up or down according to how good the report was. If your simulation is liable to agree with the market on the quality of the report, then--whether you're selling or buying--it'll be somewhat advantageous to start trading early in the day.

One way to test this is to lag your trades by, say, two weeks. Let's say you're running a 20-stock sim. Put as a buy rule RankPosPrev (2) < 21. As a sell rule use RankPosPrev(2) > 60. Then run the sim both with next open and next close and see if there's a difference. If there's still a large difference, then my explanation can't be correct.

That was always my interpretation. Especially for Microcap strategies I see a clear return tendency in most of the simulations:

Prev Close > Next Open > Avg OHL2C > Next Close

Daily > Weekly > 4 Weeks etc.

I even tried some stuff like "barssince(latestnewsdate)=1 & Rel%Chg(1) < -5" to enforce a daily technical rule for "bad earnings report"...

In live trading, I often see the first tick at open after a "bad" earnings report being somewhat favorable but basically unrealistic to catch. Sometimes it revert on the day, but often it's just straight down from there over the next hours and days. So if there is new information, "faster reaction" equals "better exit". Same seems to go for entries after good reports that also please your ranking.

Imo those forces are stronger in US and with ML component.

Unfortunately, the sim ranks of a daily rebal sim are not daily but weekly Saturday, so unless the underlying stock did report on Friday, you have no way of catching barssince(latestnewsdate)=1 on pure rank rules, only with a conditional technical rule like shown above which distorts the picture of the rank/timing question.
Still, maybe the few trades from late-week reporters have enough impact to show the "Next Open = best" effect. But maybe it comes from something like overnight sector news instead?

A test I am thinking of now (but have not done yet):

Test the same sim with all available transaction price settings in 3 configurations:

  1. basic
  2. addtional buy rule "barssince(latestnewsdate)>1"
  3. adding "& barssince(latestnewsdate)>1" to each sell rule.

This way, maybe you can pinpoint how much of the "extra Next Open return" comes from fast entries or exits on fresh numbers.

The more I research the slippage in my own realized portfolio the more nuanced the story becomes. My median slippage per transaction is really surprisingly low, and a brokerage like Schwab will often get a fill below the ask (I assume from their internal pools), but it's the tails that get me. It's really when I have to go chase a stock that has run away at open is really where most of the slippage penalization comes from. So then the question becomes whether it's better to chase it or just let it go or move on to the next stock. Sometimes the stocks run on new information that hasn't completely disseminated into the market fully. That's currently one of the things I'm trying to research. Another thing is we give this blanket round trip slippage number, but I've found that my Buy orders run away at open about 3x as often as my sell orders.

That was very interesting, especially how 'to run away' is much higher when buying than selling :slight_smile: I hope you share your findings when you discover more.

Do you mostly use VWAP orders when trading?

When you're chasing "run aways" at the open, have you tried to investigate if you could have gotten yours at a lower price later in the day, or later in the week?

What day of the week do you trade, and would it help to change it?

I discovered the same thing, and I'm also on Schwab. Medians are very low, but the means are what we pay. Therefore, on the buy side, I set a rule for myself never to chase a surging stock that is up 4-5%+ that day by the time I'm trading. If a stock is surging, I move on to the next in the ranking system, similar to rank tolerance. Hopefully that next stock isn't one you just sold.

I only do this for buying because that's where we can't execute right at market open. I need my stock sales to execute first in order to free up cash for going long other stocks. So that's where I've incorporated this execution rule outside of P123. It's done enough to reduce those tail cases, which keeps my slippage satisfactory (defining slippage as simply the difference between 'Open' and my execution average).

Obviously, on the selling side, we can't really control if a stock falls out of our screener at the same time that it plummets in price. We're supposed to sell anyway, so I take whatever I can get. The kicker is whether the stock gets reintroduced into the screener/ranker by that price drop, given factors like P/S, P/FCF, P/E, etc.

I trade on Fridays after work, often times from my phone. So this has been a way to reduce slippage without unique order types or spending a lot of time adjusting limits and bite-sized orders.

Very few VWAP. ~70% of my trades are at brokerages who don't offer VWAP at retail size or orders for non-US stocks which don't have algorithmic trading options on IB. I set plain limit orders on Sunday night for Monday's open and routinely bump up my limits throughout the day if I don't get a fill. My measurements say trading at the day's average instead of the open costs about +142 bps/side on my buys. VWAP is roughly the day's average, so it's the wrong benchmark to target for the leg that has drift in it.

The sell side is a different story. There I measure essentially zero intraday drift, so a VWAP-style fill would be neutral on price and would cut my timing dispersion (median ~58 bps and ~319 bps at the 90th percentile of the distribution). If I could use VWAP on the sell leg it would probably help.

On whether the run-aways come back: On average, later in the day is worse — I ran a version of Yuval's lag test, staling the signal by two weeks, and the buy-side intraday drift still comes in at +58 bps while sells sit at −1 bps and aren't significant. So it isn't just the market reacting to the same news my ranking read; something slower keeps pushing my buys up through the session.

But that's measured on trades that filled. The names that gapped away and ran that I never got fills and gave up are absent from the sample — I can't yet say whether that subset mean-reverts later in the week. I just started logging every deferral with its outcome to find out. I guess about 30 deferrals in I should have a pretty good picture.

For buys I trade Monday, off a Sunday signal. Whether to change the day is questionable — I haven't tested a whole-cycle shift, and it's confounded, since a Friday rebalance also means a day-older ranking. I've recently implemented a split week: sells Friday close, where the overnight drift measures zero, buys Monday where the drift favors the open. That also happens to solve a settlement constraints in one of my retirement accounts.