I've got 60 million sales of 800 different liquid products whose price change daily
Without seeing the execution plan, it's impossible to say exactly what the problem was. However, the root cause seemed to be with the way the optimizer was handling joining the queries within your CTEs (or something along those lines).

In SQL Server CTEs aren't currently materialized or fenced off (unless you use TOP inside one). In many cases, breaking up queries (whether they use CTEs or not) can be helpful to the optimizer. 

As of this answer, there are no hints to alter the way CTEs are handled.