Source code · Python
report_model.py
"""AMD equity research report model. Reported facts: AMD Form 10-Q for the quarter ended June 27, 2026.2026 to 2030: Street consensus (Koyfin, 14 Oct 2026 for 2025A-2028E revenue andEPS; 7 Oct 2026 for 2029E-2030E and free cash flow margins).2031 to 2035 and the terminal value are the analyst's assumptions.Owner free cash flow = free cash flow minus stock based compensation.Per share values include dilution from the OpenAI and Meta warrants."""import json # ---- reported, $M (10-Q, quarter ended June 27, 2026) ----Q2 = dict(revenue=11536, revenue_py=7685, gross_profit=6203, gaap_op=1990, gaap_op_py=-134, net_income=2297, eps_diluted=1.38, diluted_shares=1659, sbc=503)H1 = dict(revenue=21789, revenue_py=15123, gaap_op=3466, ocf=5321, capex=1197, sbc=990, buybacks=221)H1['fcf'] = H1['ocf'] - H1['capex']SEGMENTS_Q2 = { # revenue, prior year revenue, operating income, prior year operating income 'Data Center': (6718, 3240, 2103, -155), 'Client': (3062, 2499, None, None), 'Gaming': (779, 1122, None, None), 'Client and Gaming': (3841, 3621, 582, 767), 'Embedded': (977, 824, 386, 275),}BAL = dict(cash=5086, st_investments=8025, debt_current=875, debt_long=2351, goodwill=25470, intangibles=15635, total_assets=84464, purchase_commitments=30300)SHARES_OUT = 1632 # million, June 27, 2026WARRANT_SHARES = 320 # OpenAI and Meta, up to 160M each at $0.01, vesting on GPU purchase milestonesBUYBACK_REMAINING = 9200 # $M available under the repurchase program # ---- Street consensus ----STREET = dict( as_of='2026-10-14', source='Koyfin', price=572.17, market_cap_b=934.05, forward_pe=51.5, revenue={'2025': 34640, '2026': 50950, '2027': 88940, '2028': 123760, '2029': 161900, '2030': 225000}, ebitda={'2025': 6700, '2026': 13440, '2027': 30050, '2028': 45940}, eps_adj={'2025': 4.17, '2026': 7.59, '2027': 15.72, '2028': 22.82, '2029': 31.48, '2030': 44.31}, eps_gaap={'2025': 2.65, '2026': 5.73, '2027': 13.49, '2028': 20.39, '2029': 27.06, '2030': 40.51}, fcf_margin={'2026': 0.1455, '2027': 0.1843, '2028': 0.2452, '2029': 0.2630, '2030': 0.2714}, gross_margin={'2026': 0.5554, '2027': 0.5531, '2028': 0.5528, '2029': 0.5567, '2030': 0.5666}, target=dict(low=365.0, avg=636.21, high=1250.0), analysts=55, ratings={'Strong buy': 5, 'Buy': 39, 'Hold': 11, 'Sell': 0, 'Strong sell': 0}, next_earnings='2026-11-03', q3_guide_revenue=13000) YEARS = [2026, 2027, 2028, 2029, 2030] def build(c): """Owner FCF path: consensus (scaled per scenario) to 2030, then a fade to terminal growth.""" rows = [] rev_prev = STREET['revenue']['2025'] for i, y in enumerate(YEARS): cons_g = STREET['revenue'][str(y)] / STREET['revenue'][str(y - 1)] - 1 g = cons_g * (1 if y == 2026 else c['growth_scale']) rev = rev_prev * (1 + g) m = STREET['fcf_margin'][str(y)] if y < 2030 else c['fcf_margin_2030'] if y > 2026 and c['fcf_margin_2030'] != STREET['fcf_margin']['2030']: # interpolate toward the scenario's 2030 margin m = STREET['fcf_margin']['2026'] + (c['fcf_margin_2030'] - STREET['fcf_margin']['2026']) * (y - 2026) / 4 sbc_pct = c['sbc_start'] + (c['sbc_end'] - c['sbc_start']) * i / 4 rows.append(dict(year=y, revenue=rev, growth=g, fcf=rev * m, fcf_margin=m, sbc=rev * sbc_pct)) rev_prev = rev g0 = rows[-1]['growth'] for k in range(1, c['fade_years'] + 1): g = g0 + (c['g'] - g0) * k / c['fade_years'] rev = rev_prev * (1 + g) m = rows[-1]['fcf_margin'] if k == 1 else rows[-1]['fcf_margin'] rows.append(dict(year=2030 + k, revenue=rev, growth=g, fcf=rev * c['fcf_margin_2030'], fcf_margin=c['fcf_margin_2030'], sbc=rev * c['sbc_end'])) rev_prev = rev for r in rows: r['owner_fcf'] = r['fcf'] - r['sbc'] return rows def value(c, wacc=None, g=None, warrants=None): wacc = c['wacc'] if wacc is None else wacc g = c['g'] if g is None else g cc = dict(c, g=g) rows = build(cc) # valuation date 14 Oct 2026: remaining 2026 owner FCF (full year less first half) arrives ~0.1y out rem26 = rows[0]['owner_fcf'] - (H1['fcf'] - H1['sbc']) pv = rem26 / (1 + wacc) ** 0.1 for k, r in enumerate(rows[1:]): r['pv'] = r['owner_fcf'] / (1 + wacc) ** (0.71 + k) pv += r['pv'] tv = rows[-1]['owner_fcf'] * (1 + g) / (wacc - g) pv_tv = tv / (1 + wacc) ** (0.71 + len(rows) - 2) net_cash = BAL['cash'] + BAL['st_investments'] - BAL['debt_current'] - BAL['debt_long'] equity = pv + pv_tv + net_cash w = c['warrant_vest'] if warrants is None else warrants shares = SHARES_OUT + WARRANT_SHARES * w return dict(per_share=equity / shares, per_share_before_warrants=equity / SHARES_OUT, equity=equity, pv_fcf=pv, pv_tv=pv_tv, tv_share=pv_tv / (pv + pv_tv), net_cash=net_cash, shares=shares, rows=rows) BASE = dict(growth_scale=1.0, fcf_margin_2030=STREET['fcf_margin']['2030'], sbc_start=0.039, sbc_end=0.025, fade_years=5, wacc=0.132, g=0.03, warrant_vest=1.0)BEAR = dict(BASE, growth_scale=0.6, fcf_margin_2030=0.22, sbc_end=0.03, warrant_vest=0.0)BULL = dict(BASE, growth_scale=1.15, fcf_margin_2030=0.30, sbc_end=0.02, wacc=0.12) def solve(fn, target, lo, hi): for _ in range(80): mid = (lo + hi) / 2 if fn(mid) > target: lo = mid else: hi = mid return mid # Writes the October 14, 2026 valuation illustration. update_2026_10_17.py imports# the functions above without re-running it.def main(): out = {} for name, c in (('base', BASE), ('bear', BEAR), ('bull', BULL)): v = value(c) out[name] = dict(fair_value=round(v['per_share']), before_warrants=round(v['per_share_before_warrants']), pv_fcf=round(v['pv_fcf']), pv_tv=round(v['pv_tv']), tv_share=round(v['tv_share'], 3), shares=round(v['shares']), assumptions=c, rows=[{k: (round(x, 4) if k in ('growth', 'fcf_margin') else round(x, 1) if isinstance(x, float) else x) for k, x in r.items()} for r in v['rows']]) print(f"{name}: ${v['per_share']:.0f} per share (before warrants ${v['per_share_before_warrants']:.0f}) | TV {v['tv_share']:.0%} | 2030 revenue ${v['rows'][4]['revenue']/1000:.0f}B") b = value(BASE) for r in b['rows']: print(f" {r['year']}: revenue {r['revenue']:8.0f} ({r['growth']:+.1%}) FCF {r['fcf']:7.0f} ({r['fcf_margin']:.1%}) SBC {r['sbc']:5.0f} owner {r['owner_fcf']:7.0f}") grid = {} for w in (0.10, 0.11, 0.12, 0.132, 0.14): grid[str(w)] = {str(g): round(value(BASE, w, g)['per_share']) for g in (0.02, 0.025, 0.03, 0.035, 0.04)} out['sensitivity'] = grid print('sensitivity:'); [print(' ', k, v) for k, v in grid.items()] price = STREET['price'] implied_wacc = solve(lambda w: value(BASE, w)['per_share'], price, 0.06, 0.2) implied_scale = solve(lambda s: -value(dict(BASE, growth_scale=s))['per_share'], -price, 0.5, 2.0) implied_rev_2030 = build(dict(BASE, growth_scale=implied_scale))[4]['revenue'] out['reverse_dcf'] = dict(price=price, implied_wacc=round(implied_wacc, 4), implied_growth_scale=round(implied_scale, 3), implied_revenue_2030=round(implied_rev_2030)) print(f'reverse DCF at ${price}: implied cost of capital {implied_wacc:.2%}; or at 13.2%, 2030 revenue of ${implied_rev_2030/1000:.0f}B (growth scale {implied_scale:.2f})') out['street'] = STREET out['facts'] = dict(Q2=Q2, H1=H1, segments_q2=SEGMENTS_Q2, balance=BAL, shares_out=SHARES_OUT, warrant_shares=WARRANT_SHARES, buyback_remaining=BUYBACK_REMAINING) # Street check: the cost of capital at which the DCF reaches the Street targets, # with stock pay and warrants counted, without the warrants, and the usual # Street treatment with neither. no_warrants = dict(BASE, warrant_vest=0.0) street_style = dict(no_warrants, sbc_start=0.0, sbc_end=0.0) target = STREET['target'] implied = lambda c, t: round(solve(lambda w: value(c, w)['per_share'], t, 0.04, 0.3), 4) out['street_check'] = dict( wacc_at_avg_full=implied(BASE, target['avg']), wacc_at_avg_no_warrants=implied(no_warrants, target['avg']), wacc_at_avg_street_style=implied(street_style, target['avg']), wacc_at_low_full=implied(BASE, target['low']), wacc_at_high_full=implied(BASE, target['high']), ) print('street check:', out['street_check']) json.dump(out, open('amd_report.json', 'w'), indent=1) if __name__ == "__main__": main()