Source code · Python

report_model.py

154 lines · Part of AMD equity research · All code · Read only; the files run as published

"""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()