Generate multiple running totals with GROUP BY day
I see a couple of issues. This should do it:

SELECT * -- ⑥
FROM   (  -- ①
   SELECT the_day::date
   FROM   generate_series(timestamp '2020-01-01', date_trunc('day', localtimestamp), interval '1 day') the_day
   ) d 
LEFT   JOIN ( -- ②
   SELECT customer_id
        , created_at::date AS the_day -- ⑥
        , sum(sum(t.amount) FILTER (WHERE stock_ticker = 'tsla')) OVER w AS tsla_running_amount -- ③
        , sum(sum(t.amount) FILTER (WHERE stock_ticker = 'goog')) OVER w AS goog_running_amount
   FROM   transactions t
   WHERE  created_at &gt;= timestamp '2020-01-01'  -- ④
   GROUP  BY customer_id, created_at::date  -- ⑤
   WINDOW w AS (PARTITION BY customer_id ORDER BY created_at::date) -- ③
   ) t USING (the_day) -- ⑥
ORDER  BY customer_id, the_day; -- ⑦


db&lt;>fiddle here

① Generating all days of the current year in optimized fashion. See:


Generating time series between two dates in PostgreSQL


② The LEFT JOIN you had in mind. You may really want one row per combination of (customer_id, day). See:


Fill missing dates within groups


③ While you also GROUP BY customer_id the Window frame needs to lead with PARTITION BY customer_id.  

Drop rows unbounded preceding. The default window frame should be just fine. The manual:


  The default framing option is RANGE UNBOUNDED PRECEDING, which is the
  same as RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.


Use the aggregate FILTER clause instead of the CASE expression. Shorter, faster, cleaner. See:


Return counts for multiple ranges in a single SELECT statement


Finally wrap the result of the aggregation in another sum() for the window function. See:


Get the distinct sum of a joined table column


The separate WINDOW clause avoids spelling out the same repeatedly. No effect on performance.

④ The WHERE is logically redundant, but assuming there are older rows, too, it excludes irrelevant rows early, improving performance.
  Asuming no or almost no future timestamps, so no upper bound.

⑤ You cannot have t.stock_ticker, t.amount in GROUP BY as you want one row per (customer_id, the_day).

⑥ Use the same column alias (the_day in my example) to allow the simple USING (the_day) in the JOIN clause, and SELECT * at the top level.

⑦ Not sure about the final sort order. This seems more useful to me. Adjust to your preference.