Files
finance-daily-site/index.html
T
2026-07-10 14:13:44 +00:00

3399 lines
173 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="金融日报 — 北美华人投资者专属每日金融简报,由 Claude AI + Web Search 自动生成,每日两次更新">
<meta property="og:title" content="金融日报 | Financial Daily">
<meta property="og:description" content="北美华人投资者专属:全球指数·市场要闻·宏观数据·财报追踪·经济日历,每日自动更新">
<meta property="og:type" content="website">
<meta name="keywords" content="金融日报,北美投资,美股,A股,港股,宏观经济,财报,经济日历">
<meta name="theme-color" content="#070b14">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="金融日报">
<link rel="manifest" href="manifest.json">
<title>金融日报 | Financial Daily — 北美华人投资者日报</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
/* =========================================================
RESET & TOKENS
========================================================= */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #070b14;
--card: #0c1525;
--card2: #0f1c30;
--border: #192840;
--border-l: #22386a;
--accent: #00d4aa;
--up: #00e676;
--down: #ff5252;
--neutral: #4fc3f7;
--warn: #ffb300;
--text: #e2e8f0;
--muted: #7a8fa8;
--dimmed: #3a4e68;
--mono: 'JetBrains Mono','Fira Code',monospace;
--sans: 'Inter',system-ui,-apple-system,sans-serif;
--r: 8px;
--rl: 14px;
}
html { font-size: 14px; scroll-behavior: smooth; }
body { font-family: var(--sans); background: var(--bg); color: var(--text); line-height: 1.6; -webkit-font-smoothing: antialiased; }
a { color: var(--accent); text-decoration: none; }
a:hover { color: #33e0be; }
/* =========================================================
READING PROGRESS
========================================================= */
#reading-progress { position: fixed; top: 0; left: 0; height: 3px; width: 0; background: linear-gradient(90deg,var(--accent),#4fc3f7); z-index: 9999; transition: width .1s; }
/* =========================================================
HEADER
========================================================= */
.site-header {
position: sticky; top: 0; z-index: 100;
background: rgba(7,11,20,.96); backdrop-filter: blur(16px);
border-bottom: 1px solid var(--border);
padding: 10px 0;
}
.header-inner { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.logo-block { display: flex; align-items: baseline; gap: 8px; }
.site-title { font-size: 1.1rem; font-weight: 800; color: var(--accent); letter-spacing: -.02em; }
.site-sub { font-size: .65rem; color: var(--muted); font-family: var(--mono); }
.header-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.header-date { font-family: var(--mono); font-size: .68rem; color: var(--muted); }
.header-badge { display: flex; align-items: center; gap: 5px; font-size: .62rem; color: var(--muted); background: rgba(0,212,170,.08); border: 1px solid rgba(0,212,170,.2); border-radius: 20px; padding: 2px 9px; }
.pulse-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: pulse 2s ease-in-out infinite; }
@keyframes pulse { 0%,100%{opacity:1;transform:scale(1)} 50%{opacity:.4;transform:scale(.7)} }
.header-nav { display: flex; gap: 10px; }
.header-nav a { font-size: .68rem; color: var(--muted); }
.header-nav a:hover { color: var(--accent); }
.streak-badge { font-size: .62rem; font-family: var(--mono); background: rgba(255,179,0,.12); color: var(--warn); border: 1px solid rgba(255,179,0,.25); border-radius: 20px; padding: 2px 8px; }
/* =========================================================
NAV BAR
========================================================= */
.jump-nav {
position: sticky; top: 47px; z-index: 90;
background: rgba(7,11,20,.95); backdrop-filter: blur(14px);
border-bottom: 1px solid var(--border);
display: flex; overflow-x: auto; scrollbar-width: none;
}
.jump-nav::-webkit-scrollbar { display: none; }
.jump-nav a {
flex-shrink: 0; padding: 8px 14px; font-size: .72rem;
color: var(--muted); white-space: nowrap;
border-bottom: 2px solid transparent; transition: color .15s, border-color .15s;
}
.jump-nav a:hover { color: var(--text); text-decoration: none; }
.jump-nav a.active { color: var(--accent); border-bottom-color: var(--accent); }
.nav-sep { width: 1px; background: var(--border); margin: 8px 0; flex-shrink: 0; }
/* =========================================================
TICKER STRIP
========================================================= */
.indices-section { border-bottom: 1px solid var(--border); background: rgba(0,0,0,.2); }
.indices-scroll-wrapper { overflow: hidden; position: relative; }
.indices-track { display: flex; gap: 0; animation: ticker 60s linear infinite; width: max-content; }
.indices-track:hover { animation-play-state: paused; }
@keyframes ticker { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.ticker-card { padding: 8px 18px; border-right: 1px solid var(--border); white-space: nowrap; cursor: default; }
.ticker-name { font-size: .62rem; color: var(--muted); font-family: var(--mono); margin-bottom: 2px; }
.ticker-value { font-size: .9rem; font-weight: 700; font-family: var(--mono); }
.ticker-change { font-size: .68rem; font-family: var(--mono); }
.ticker-change.up,.ticker-value.up { color: var(--up); }
.ticker-change.down,.ticker-value.down { color: var(--down); }
.ticker-card.up .ticker-value { color: var(--text); }
.ticker-card.down .ticker-value { color: var(--text); }
/* =========================================================
LAYOUT
========================================================= */
.container { max-width: 1360px; margin: 0 auto; padding: 0 20px; }
.page-body { padding: 20px 0 40px; }
/* Primary grid: content + sidebar */
.content-grid {
display: grid;
grid-template-columns: 1fr 380px;
gap: 20px;
align-items: start;
}
@media (max-width: 1024px) { .content-grid { grid-template-columns: 1fr; } }
/* 2-col within a column */
.two-up { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start; }
@media (max-width: 640px) { .two-up { grid-template-columns: 1fr; } }
/* =========================================================
CARDS & SECTIONS
========================================================= */
.card {
background: var(--card); border: 1px solid var(--border);
border-radius: var(--rl); padding: 18px 20px;
transition: border-color .2s;
}
.section-label {
font-size: .65rem; font-family: var(--mono); color: var(--accent);
letter-spacing: .1em; text-transform: uppercase;
margin-bottom: 14px; padding-bottom: 10px;
border-bottom: 1px solid var(--border);
display: flex; align-items: center; gap: 8px;
}
.section-label::before { content:''; width:3px; height:12px; background:var(--accent); border-radius:2px; flex-shrink:0; }
.section-label .sec-count { margin-left:auto; color:var(--dimmed); font-size:.6rem; }
.sec-anchor { scroll-margin-top: 100px; }
.mb16 { margin-bottom: 16px; }
/* =========================================================
SUMMARY HERO
========================================================= */
.summary-section { padding: 16px 0 0; }
.summary-card {
border-radius: var(--rl); padding: 22px 26px;
border: 1px solid var(--border); margin-bottom: 16px;
}
.summary-card.bullish { background: linear-gradient(135deg,rgba(0,230,118,.07),rgba(0,212,170,.03)); border-color:rgba(0,230,118,.28); }
.summary-card.bearish { background: linear-gradient(135deg,rgba(255,82,82,.07),rgba(255,82,82,.02)); border-color:rgba(255,82,82,.28); }
.summary-card.neutral { background: linear-gradient(135deg,rgba(79,195,247,.06),rgba(0,212,170,.03)); border-color:rgba(79,195,247,.22); }
.summary-top { display:flex; align-items:center; gap:10px; margin-bottom:14px; flex-wrap:wrap; }
.sentiment-pill { font-size:.72rem; font-family:var(--mono); font-weight:700; padding:4px 14px; border-radius:20px; letter-spacing:.06em; }
.sentiment-pill.bullish { background:rgba(0,230,118,.15); color:var(--up); border:1px solid rgba(0,230,118,.3); }
.sentiment-pill.bearish { background:rgba(255,82,82,.15); color:var(--down); border:1px solid rgba(255,82,82,.3); }
.sentiment-pill.neutral { background:rgba(79,195,247,.12); color:var(--neutral);border:1px solid rgba(79,195,247,.25); }
.vix-badge { font-family:var(--mono); font-size:.72rem; color:var(--muted); }
.vix-num { color:var(--warn); font-weight:700; font-size:.9rem; }
.summary-headline { font-size:1.22rem; font-weight:800; color:var(--text); line-height:1.38; margin-bottom:14px; letter-spacing:-.02em; }
.key-points { list-style:none; display:flex; flex-direction:column; gap:7px; margin-bottom:14px; padding:0; }
.kp-item { font-size:.83rem; color:var(--text); padding:9px 14px; background:rgba(255,255,255,.04); border-radius:7px; border-left:3px solid var(--accent); display:flex; align-items:center; gap:8px; font-weight:500; line-height:1.4; }
.kp-arrow { color:var(--accent); font-size:.7rem; flex-shrink:0; }
.summary-details { margin-top:4px; }
.summary-details-toggle { font-size:.72rem; color:var(--muted); cursor:pointer; user-select:none; padding:4px 0; list-style:none; }
.summary-details-toggle:hover { color:var(--accent); }
.summary-context { font-size:.82rem; color:var(--muted); line-height:1.7; padding-top:8px; }
/* legacy hide */
.summary-icon,.summary-content,.summary-meta,.summary-label,.vix-display,.sentiment-badge { display:none !important; }
/* =========================================================
NEWS
========================================================= */
.news-item {
background: var(--card); border-radius: var(--r);
border: 1px solid var(--border); margin-bottom: 6px;
cursor: pointer; overflow: hidden; transition: border-color .18s;
}
.news-item:hover { border-color: var(--border-l); }
.news-item.expanded { border-color: var(--border-l); }
.news-header { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px 9px; }
.imp-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink:0; margin-top:5px; }
.imp-dot.breaking { background:var(--down); box-shadow:0 0 5px rgba(255,82,82,.5); }
.imp-dot.major { background:var(--warn); }
.imp-dot.normal { background:var(--neutral); opacity:.35; }
.news-title { font-size:.86rem; font-weight:600; color:var(--text); line-height:1.42; flex:1; }
.news-title a { color:var(--text); }
.news-title a:hover { color:var(--accent); }
.news-expand-icon { color:var(--dimmed); flex-shrink:0; font-size:1rem; transition:transform .2s; }
.news-item.expanded .news-expand-icon { transform:rotate(45deg); color:var(--accent); }
.news-tldr { padding:0 14px 9px 31px; font-size:.76rem; color:var(--accent); line-height:1.5; }
.tldr-label { margin-right:3px; }
.news-body-collapse { display:none; padding:9px 14px 12px 31px; font-size:.79rem; color:var(--muted); line-height:1.65; border-top:1px solid var(--border); }
.news-item.expanded .news-body-collapse { display:block; }
.news-footer { display:flex; align-items:center; gap:7px; padding:7px 14px; flex-wrap:wrap; border-top:1px solid rgba(255,255,255,.035); }
.news-item.breaking { border-left:3px solid var(--down); }
.news-item.major { border-left:3px solid var(--warn); }
.news-item.normal { border-left:3px solid transparent; }
.importance-badge { font-size:.6rem; font-family:var(--mono); padding:2px 6px; border-radius:3px; }
.importance-badge.breaking { background:rgba(255,82,82,.12); color:var(--down); }
.importance-badge.major { background:rgba(255,179,0,.12); color:var(--warn); }
.importance-badge.normal { background:rgba(79,195,247,.08); color:var(--neutral); }
.new-badge { font-size:.58rem; font-family:var(--mono); padding:1px 5px; border-radius:3px; background:rgba(0,212,170,.15); color:var(--accent); border:1px solid rgba(0,212,170,.3); }
/* =========================================================
TAGS
========================================================= */
.tag { font-size:.6rem; font-family:var(--mono); padding:2px 6px; border-radius:3px; background:rgba(255,255,255,.06); color:var(--muted); }
/* =========================================================
LEADERS
========================================================= */
.leader-card { background:var(--bg); border:1px solid var(--border); border-radius:var(--r); padding:14px; margin-bottom:8px; transition:border-color .2s; }
.leader-card:hover { border-color:var(--border-l); }
.leader-header { display:flex; align-items:center; gap:10px; margin-bottom:10px; }
.leader-avatar { width:38px; height:38px; border-radius:50%; display:flex; align-items:center; justify-content:center; font-size:.7rem; font-weight:700; font-family:var(--mono); flex-shrink:0; }
.leader-avatar.wb { background:linear-gradient(135deg,#4a3800,#8b6914); color:#ffd700; }
.leader-avatar.rd { background:linear-gradient(135deg,#1a3a5c,#2563a8); color:#60a5fa; }
.leader-avatar.jd { background:linear-gradient(135deg,#3a1a1a,#8b2525); color:#f87171; }
.leader-avatar.jp { background:linear-gradient(135deg,#1a3a2a,#256b40); color:#4ade80; }
.leader-avatar.default { background:rgba(0,212,170,.15); color:var(--accent); }
.leader-meta { flex:1; }
.leader-name { font-size:.83rem; font-weight:600; }
.leader-role { font-size:.68rem; color:var(--muted); }
.leader-date { font-size:.62rem; color:var(--dimmed); font-family:var(--mono); white-space:nowrap; }
.leader-quote { font-size:.82rem; color:var(--accent); font-style:italic; margin-bottom:8px; line-height:1.5; }
.leader-body { font-size:.78rem; color:var(--muted); line-height:1.6; margin-bottom:8px; }
/* =========================================================
MACRO
========================================================= */
.macro-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:10px; }
.macro-card { background:var(--bg); border:1px solid var(--border); border-radius:var(--r); padding:12px 14px; transition:border-color .2s; }
.macro-card:hover { border-color:var(--border-l); }
.macro-card.dir-up { border-left:3px solid var(--up); }
.macro-card.dir-down{ border-left:3px solid var(--down); }
.macro-card.dir-neutral { border-left:3px solid var(--neutral); }
.macro-indicator { font-size:.65rem; font-family:var(--mono); color:var(--muted); margin-bottom:5px; text-transform:uppercase; }
.macro-value { font-size:1.1rem; font-weight:700; font-family:var(--mono); margin-bottom:4px; }
.macro-value-up { color:var(--up); }
.macro-value-down { color:var(--down); }
.macro-prev { font-size:.66rem; color:var(--dimmed); margin-bottom:5px; }
.macro-desc { font-size:.72rem; color:var(--muted); line-height:1.5; }
.arrow.up { color:var(--up); }
.arrow.down { color:var(--down); }
/* =========================================================
EARNINGS
========================================================= */
.earnings-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:10px; }
.earnings-card { background:var(--bg); border:1px solid var(--border); border-radius:var(--r); padding:14px; transition:border-color .2s; }
.earnings-card:hover { border-color:var(--border-l); }
.earnings-card.beat { border-top:2px solid var(--up); }
.earnings-card.miss { border-top:2px solid var(--down); }
.earnings-card.pending{ border-top:2px solid var(--neutral); }
.e-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; }
.e-ticker { font-family:var(--mono); font-size:.85rem; font-weight:700; }
.e-company { font-size:.7rem; color:var(--muted); }
.e-badge { font-size:.6rem; font-family:var(--mono); padding:2px 7px; border-radius:3px; }
.e-badge.beat { background:rgba(0,230,118,.15); color:var(--up); }
.e-badge.miss { background:rgba(255,82,82,.15); color:var(--down); }
.e-badge.pending{ background:rgba(79,195,247,.1); color:var(--neutral); }
.earnings-eps { display:flex; gap:10px; margin-bottom:8px; }
.eps-item { flex:1; }
.eps-label { font-size:.6rem; font-family:var(--mono); color:var(--dimmed); margin-bottom:3px; }
.eps-value { font-size:.9rem; font-weight:700; font-family:var(--mono); }
.eps-value.actual.beat { color:var(--up); }
.eps-value.actual.miss { color:var(--down); }
.eps-value.est { color:var(--muted); }
.e-revenue { font-size:.72rem; color:var(--muted); margin-bottom:5px; }
.e-highlight { font-size:.72rem; color:var(--text); line-height:1.4; }
/* =========================================================
SECTORS
========================================================= */
.sectors-list { display:flex; flex-direction:column; gap:6px; }
.sector-row { display:grid; grid-template-columns:1fr auto 120px auto; gap:8px; align-items:center; padding:8px 10px; background:var(--bg); border-radius:var(--r); border:1px solid var(--border); font-size:.78rem; }
@media(max-width:480px){ .sector-row { grid-template-columns:1fr auto; } .sector-bar-wrap,.sector-etf{ display:none; } }
.sector-name { font-weight:500; }
.sector-name-en { font-size:.65rem; color:var(--muted); }
.sector-etf { font-family:var(--mono); font-size:.65rem; color:var(--dimmed); }
.sector-bar-wrap { height:5px; background:var(--border); border-radius:3px; overflow:hidden; }
.sector-bar { height:100%; border-radius:3px; }
.sector-bar.up { background:var(--up); }
.sector-bar.down { background:var(--down); }
.sector-pct { font-family:var(--mono); font-size:.78rem; font-weight:600; text-align:right; }
.sector-pct.up { color:var(--up); }
.sector-pct.down { color:var(--down); }
/* =========================================================
CENTRAL BANKS
========================================================= */
.cb-grid { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
@media(max-width:600px){ .cb-grid { grid-template-columns:1fr; } }
.cb-card { background:var(--bg); border:1px solid var(--border); border-radius:var(--r); padding:14px; transition:border-color .2s; }
.cb-card:hover { border-color:var(--border-l); }
.cb-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:8px; gap:8px; flex-wrap:wrap; }
.cb-name { font-size:.82rem; font-weight:600; }
.cb-rate { font-family:var(--mono); font-size:.78rem; color:var(--accent); }
.cb-action { font-size:.75rem; color:var(--text); margin-bottom:6px; font-weight:500; }
.cb-note { font-size:.72rem; color:var(--muted); line-height:1.5; margin-bottom:8px; }
.cb-bias { font-size:.6rem; font-family:var(--mono); padding:2px 7px; border-radius:3px; }
.cb-bias.hawkish { background:rgba(255,82,82,.12); color:var(--down); }
.cb-bias.dovish { background:rgba(0,230,118,.12); color:var(--up); }
.cb-bias.neutral { background:rgba(79,195,247,.1); color:var(--neutral); }
.cb-next { font-size:.65rem; color:var(--dimmed); font-family:var(--mono); }
/* =========================================================
CALENDAR
========================================================= */
.calendar-grid { display:flex; flex-direction:column; gap:6px; }
.cal-item { background:var(--bg); border:1px solid var(--border); border-radius:var(--r); padding:10px 12px; display:flex; gap:12px; align-items:flex-start; border-left-width:3px; transition:border-color .2s; }
.cal-item.high { border-left-color:var(--down); }
.cal-item.medium { border-left-color:var(--warn); }
.cal-item.low { border-left-color:var(--neutral); }
.cal-date { font-family:var(--mono); font-size:.62rem; color:var(--muted); min-width:54px; line-height:1.5; }
.cal-event { font-size:.78rem; color:var(--text); font-weight:500; margin-bottom:3px; }
.cal-values { font-family:var(--mono); font-size:.64rem; color:var(--muted); }
.cal-values span { color:var(--neutral); }
/* =========================================================
AI WATCHLIST
========================================================= */
.watchlist-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:10px; }
.watchlist-card { background:var(--bg); border:1px solid var(--border); border-radius:var(--r); padding:14px; transition:border-color .18s,transform .18s; }
.watchlist-card:hover { border-color:var(--border-l); transform:translateY(-2px); }
.wc-header { display:flex; justify-content:space-between; align-items:flex-start; margin-bottom:8px; }
.wc-ticker { font-family:var(--mono); font-size:.9rem; font-weight:700; color:var(--accent); }
.wc-name { font-size:.65rem; color:var(--muted); margin-top:1px; }
.wc-price { text-align:right; }
.wc-price-val { font-family:var(--mono); font-size:.85rem; font-weight:600; }
.wc-price-chg { font-size:.68rem; }
.wc-price-chg.up { color:var(--up); }
.wc-price-chg.down { color:var(--down); }
.wc-signal-row { display:flex; align-items:center; gap:8px; margin-bottom:7px; }
.signal-badge { font-family:var(--mono); font-size:.65rem; font-weight:700; padding:2px 9px; border-radius:4px; }
.signal-badge.BUY { background:rgba(0,230,118,.15); color:var(--up); border:1px solid rgba(0,230,118,.3); }
.signal-badge.SELL { background:rgba(255,82,82,.15); color:var(--down);border:1px solid rgba(255,82,82,.3); }
.signal-badge.HOLD { background:rgba(255,179,0,.15); color:var(--warn);border:1px solid rgba(255,179,0,.3); }
.wc-score { font-family:var(--mono); font-size:.68rem; color:var(--muted); }
.wc-score span { color:var(--text); font-weight:600; }
.wc-conclusion { font-size:.78rem; color:var(--text); margin-bottom:3px; font-weight:500; line-height:1.4; }
.wc-driver { font-size:.68rem; color:var(--muted); margin-bottom:8px; line-height:1.4; }
.wc-targets { display:flex; gap:6px; font-size:.66rem; margin-bottom:6px; flex-wrap:wrap; }
.wc-target-up { color:var(--up); background:rgba(0,230,118,.1); padding:2px 7px; border-radius:3px; }
.wc-target-down { color:var(--down); background:rgba(255,82,82,.1); padding:2px 7px; border-radius:3px; }
.risk-badge { font-size:.58rem; font-family:var(--mono); padding:2px 6px; border-radius:3px; text-transform:uppercase; }
.risk-badge.low { background:rgba(0,230,118,.12); color:var(--up); }
.risk-badge.medium { background:rgba(255,179,0,.12); color:var(--warn); }
.risk-badge.high { background:rgba(255,82,82,.12); color:var(--down); }
.wc-action { font-size:.68rem; color:var(--muted); line-height:1.4; margin-top:5px; }
/* =========================================================
MARKET DEBATE
========================================================= */
.debate-container { display:flex; flex-direction:column; gap:12px; }
.debate-header { font-family:var(--mono); font-size:.68rem; color:var(--muted); text-transform:uppercase; letter-spacing:.08em; }
.debate-sides { display:grid; grid-template-columns:1fr 1fr; gap:10px; }
@media(max-width:600px){ .debate-sides { grid-template-columns:1fr; } }
.debate-side { background:var(--bg); border-radius:var(--r); padding:12px; }
.debate-side.bull { border-top:2px solid var(--up); }
.debate-side.bear { border-top:2px solid var(--down); }
.debate-side-title { font-size:.68rem; font-weight:600; text-transform:uppercase; letter-spacing:.08em; margin-bottom:8px; }
.debate-side.bull .debate-side-title { color:var(--up); }
.debate-side.bear .debate-side-title { color:var(--down); }
.debate-point { display:flex; align-items:flex-start; gap:7px; margin-bottom:7px; font-size:.76rem; line-height:1.4; }
.conf-badge { font-size:.57rem; font-family:var(--mono); padding:1px 4px; border-radius:3px; flex-shrink:0; margin-top:2px; }
.conf-badge.high { background:rgba(79,195,247,.15); color:var(--neutral); }
.conf-badge.medium { background:rgba(255,179,0,.12); color:var(--warn); }
.debate-verdict { background:var(--bg); border-radius:var(--r); padding:12px 14px; border-left:3px solid var(--accent); }
.verdict-label { font-size:.62rem; font-family:var(--mono); text-transform:uppercase; letter-spacing:.1em; color:var(--muted); margin-bottom:5px; }
.verdict-text { font-size:.81rem; line-height:1.5; }
.verdict-lean { display:inline-block; margin-left:7px; font-size:.62rem; font-family:var(--mono); padding:2px 6px; border-radius:3px; }
.verdict-lean.bullish { background:rgba(0,230,118,.15); color:var(--up); }
.verdict-lean.bearish { background:rgba(255,82,82,.15); color:var(--down); }
.verdict-lean.neutral { background:rgba(79,195,247,.12); color:var(--neutral); }
/* =========================================================
MARKET REPLAY
========================================================= */
.replay-grid { display:grid; grid-template-columns:1fr 1fr; gap:12px; }
@media(max-width:600px){ .replay-grid { grid-template-columns:1fr; } }
.replay-card { background:var(--bg); border:1px solid var(--border); border-radius:var(--r); padding:14px; }
.replay-card-title { font-size:.65rem; font-family:var(--mono); text-transform:uppercase; letter-spacing:.1em; color:var(--accent); margin-bottom:5px; }
.replay-summary { font-size:.82rem; font-weight:500; margin-bottom:10px; line-height:1.4; }
.ad-bar-wrap { display:flex; align-items:center; gap:6px; margin-bottom:8px; font-size:.7rem; }
.ad-bar { height:5px; border-radius:3px; }
.ad-bar.adv { background:var(--up); }
.ad-bar.dec { background:var(--down); }
.ad-label-up { color:var(--up); min-width:45px; font-family:var(--mono); font-size:.68rem; }
.ad-label-dn { color:var(--down); min-width:45px; font-family:var(--mono); font-size:.68rem; }
.replay-stats { display:grid; grid-template-columns:1fr 1fr 1fr; gap:5px; }
.replay-stat { background:rgba(255,255,255,.025); border-radius:5px; padding:6px 8px; }
.replay-stat-label { font-size:.58rem; color:var(--muted); margin-bottom:1px; }
.replay-stat-val { font-size:.76rem; font-weight:600; font-family:var(--mono); }
/* =========================================================
PERSONAL / MY DASHBOARD (collapsible drawer)
========================================================= */
.my-drawer { margin-top: 20px; }
.my-drawer-toggle {
width:100%; padding:11px 16px; background:var(--card); border:1px solid var(--border);
border-radius:var(--r); color:var(--muted); font-size:.78rem; cursor:pointer;
display:flex; align-items:center; justify-content:space-between; font-family:var(--sans);
transition:border-color .18s;
}
.my-drawer-toggle:hover { border-color:var(--border-l); color:var(--text); }
.my-drawer-toggle .drawer-icon { transition:transform .25s; }
.my-drawer-toggle.open .drawer-icon { transform:rotate(180deg); }
.my-drawer-body { display:none; margin-top:8px; }
.my-drawer-body.open { display:block; }
/* =========================================================
SUBSCRIBE STRIP (compact)
========================================================= */
.subscribe-strip {
background: rgba(0,212,170,.05); border: 1px solid rgba(0,212,170,.15);
border-radius: var(--r); padding: 12px 16px;
display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
margin-bottom: 16px;
}
.subscribe-strip-icon { font-size: 1.1rem; flex-shrink: 0; }
.subscribe-strip-body { flex: 1; min-width: 160px; }
.subscribe-strip-body strong { display:block; color:var(--accent); font-size:.82rem; }
.subscribe-strip-body span { font-size:.7rem; color:var(--muted); }
.subscribe-strip-actions { display:flex; gap:7px; flex-wrap:wrap; align-items:center; }
.btn-sub-email, .btn-sub-tg {
font-size:.72rem; padding:6px 12px; border-radius:var(--r); cursor:pointer;
display:flex; align-items:center; gap:5px; white-space:nowrap;
}
.btn-sub-email { background:rgba(0,212,170,.15); color:var(--accent); border:1px solid rgba(0,212,170,.3); }
.btn-sub-tg { background:rgba(79,195,247,.12); color:var(--neutral); border:1px solid rgba(79,195,247,.25); text-decoration:none; }
/* =========================================================
SIMPLE MODE
========================================================= */
body.simple-mode .card-secondary { display: none; }
body.simple-mode .news-item:not(.featured) { display: none; }
/* =========================================================
FAB CLUSTER
========================================================= */
.fab-cluster { position:fixed; bottom:20px; right:16px; display:flex; flex-direction:column; gap:8px; z-index:500; }
.fab { width:40px; height:40px; border-radius:50%; background:var(--card); border:1px solid var(--border); color:var(--text); font-size:1rem; cursor:pointer; display:flex; align-items:center; justify-content:center; transition:border-color .18s; box-shadow:0 4px 16px rgba(0,0,0,.4); }
.fab:hover { border-color:var(--border-l); }
#share-toast { position:fixed; bottom:70px; right:16px; background:var(--card); border:1px solid var(--border); border-radius:var(--r); padding:8px 14px; font-size:.75rem; color:var(--accent); display:none; z-index:600; }
@media(max-width:640px){ .fab-cluster { bottom:70px; } }
/* =========================================================
FOOTER
========================================================= */
.site-footer { border-top:1px solid var(--border); padding:20px 0; margin-top:20px; }
.footer-inner { display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; font-size:.7rem; color:var(--muted); }
/* =========================================================
ANIMATIONS
========================================================= */
.sec-anchor { animation: fadeUp .3s ease both; }
@keyframes fadeUp { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:none} }
@media (max-width: 640px) {
.jump-nav { position:fixed; bottom:0; top:auto; left:0; right:0; border-bottom:none; border-top:1px solid var(--border); justify-content:space-around; padding-bottom:env(safe-area-inset-bottom); z-index:200; }
.jump-nav a { padding:7px 3px; font-size:.58rem; flex-direction:column; gap:1px; text-align:center; }
body { padding-bottom: 60px; }
}
/* =========================================================
TRADINGVIEW OVERRIDE
========================================================= */
.tradingview-widget-container { border-radius:var(--r); overflow:hidden; }
.section-block { margin-bottom: 16px; }
/* =========================================================
INTRO OVERLAY ANIMATION
========================================================= */
#intro-overlay {
position: fixed; inset: 0; z-index: 10000;
background: #030609;
display: flex; align-items: center; justify-content: center;
flex-direction: column; overflow: hidden;
transition: opacity .7s ease;
}
#intro-overlay.fade-out { opacity: 0; pointer-events: none; }
#intro-overlay.gone { display: none; }
#intro-canvas { position: absolute; inset: 0; width: 100%; height: 100%; }
#intro-content {
position: relative; z-index: 2;
display: flex; flex-direction: column; align-items: center; gap: 18px;
text-align: center; padding: 0 20px;
}
.intro-badge {
font-size: .62rem; font-family: var(--mono); letter-spacing: .15em;
color: var(--accent); border: 1px solid rgba(0,212,170,.3);
background: rgba(0,212,170,.08); padding: 4px 14px; border-radius: 20px;
animation: fadeUp .6s .4s both;
}
.intro-logo {
display: flex; flex-direction: column; align-items: center; gap: 6px;
animation: fadeUp .7s .7s both;
}
.intro-title-zh {
font-size: clamp(2.2rem, 6vw, 4rem); font-weight: 900;
background: linear-gradient(135deg, #00d4aa, #4fc3f7, #00d4aa);
background-size: 200% 200%;
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
background-clip: text; animation: shimmer 3s ease infinite;
letter-spacing: -.03em;
}
.intro-title-en {
font-size: clamp(.9rem, 2.5vw, 1.4rem); font-weight: 300;
color: rgba(226,232,240,.55); letter-spacing: .25em;
text-transform: uppercase; font-family: var(--mono);
}
@keyframes shimmer {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
.intro-sub {
font-size: .7rem; color: var(--muted); font-family: var(--mono);
letter-spacing: .08em;
animation: fadeUp .6s 1s both;
}
.intro-ticker-row {
display: flex; gap: 18px; flex-wrap: wrap; justify-content: center;
animation: fadeUp .6s 1.2s both;
}
.intro-tick {
font-family: var(--mono); font-size: .72rem;
background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.08);
border-radius: 6px; padding: 5px 12px; white-space: nowrap;
}
.intro-tick .it-name { color: var(--muted); font-size: .58rem; display: block; margin-bottom: 2px; }
.intro-tick .it-val { color: var(--text); font-weight: 600; }
.intro-tick .it-chg { margin-left: 6px; font-size: .65rem; }
.intro-tick .it-chg.up { color: var(--up); }
.intro-tick .it-chg.down { color: var(--down); }
#intro-skip {
font-size: .7rem; color: var(--muted); background: rgba(255,255,255,.04);
border: 1px solid rgba(255,255,255,.1); border-radius: 20px;
padding: 6px 18px; cursor: pointer; font-family: var(--sans);
transition: color .15s, border-color .15s;
animation: fadeUp .5s 1.6s both;
}
#intro-skip:hover { color: var(--accent); border-color: rgba(0,212,170,.4); }
#intro-progress {
position: absolute; bottom: 0; left: 0; height: 2px;
background: linear-gradient(90deg, var(--accent), #4fc3f7);
width: 0%; transition: width linear;
}
/* =========================================================
LANG TOGGLE
========================================================= */
#lang-btn {
display: flex; align-items: center; gap: 0;
background: rgba(255,255,255,.04); border: 1px solid var(--border);
border-radius: 20px; overflow: hidden; cursor: pointer;
font-size: .62rem; font-family: var(--mono);
transition: border-color .15s;
flex-shrink: 0;
}
#lang-btn:hover { border-color: var(--border-l); }
.lang-opt {
padding: 3px 9px; transition: background .15s, color .15s;
color: var(--muted);
}
.lang-opt.active { background: rgba(0,212,170,.15); color: var(--accent); }
/* =========================================================
I18N: hide/show per lang
========================================================= */
body.lang-en .zh-only { display: none !important; }
body.lang-zh .en-only { display: none !important; }
/* =========================================================
HIDE GOOGLE TRANSLATE CHROME (keep translation, drop UI)
========================================================= */
.goog-te-banner-frame,
.goog-te-balloon-frame,
#goog-gt-tt,
.goog-te-balloon-frame,
.goog-tooltip,
.goog-tooltip:hover,
.goog-text-highlight { display: none !important; }
.skiptranslate { display: none !important; }
body { top: 0 !important; }
iframe.goog-te-menu-frame { display: none !important; }
/* Prevent GT from injecting font-size changes on html */
html.translated-ltr, html.translated-rtl { margin-top: 0 !important; }
</style>
<!-- Google Translate hidden widget -->
<div id="google_translate_element" style="display:none;visibility:hidden;position:absolute;width:0;height:0;"></div>
<script>
function googleTranslateElementInit() {
new google.translate.TranslateElement({
pageLanguage: 'zh-CN',
includedLanguages: 'en,zh-CN',
autoDisplay: false,
gaTrack: false
}, 'google_translate_element');
}
</script>
<script src="https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit" defer></script>
</head>
<body>
<!-- =========================================================
INTRO OVERLAY
========================================================= -->
<div id="intro-overlay">
<canvas id="intro-canvas"></canvas>
<div id="intro-content">
<div class="intro-badge">AI-POWERED · NORTH AMERICA MARKETS</div>
<div class="intro-logo">
<span class="intro-title-zh">金融日报</span>
<span class="intro-title-en">Financial Daily</span>
</div>
<div class="intro-sub" id="intro-sub">北美华人投资者 · 每日智能金融简报</div>
<div class="intro-ticker-row" id="intro-tickers">
<div class="intro-tick"><span class="it-name">S&amp;P 500</span><span class="it-val" id="it-spy"></span><span class="it-chg" id="it-spy-chg"></span></div>
<div class="intro-tick"><span class="it-name">NASDAQ</span><span class="it-val" id="it-qqq"></span><span class="it-chg" id="it-qqq-chg"></span></div>
<div class="intro-tick"><span class="it-name">BTC</span><span class="it-val" id="it-btc"></span><span class="it-chg" id="it-btc-chg"></span></div>
<div class="intro-tick"><span class="it-name">GOLD</span><span class="it-val" id="it-gld"></span><span class="it-chg" id="it-gld-chg"></span></div>
</div>
<button id="intro-skip" onclick="dismissIntro()">进入 · Enter →</button>
</div>
<div id="intro-progress"></div>
</div>
<div id="reading-progress"></div>
<!-- HEADER -->
<header class="site-header">
<div class="container">
<div class="header-inner">
<div class="logo-block">
<span class="site-title">金融日报</span>
<span class="site-sub">Financial Daily</span>
</div>
<div class="header-meta">
<span class="header-date" id="current-date">Loading...</span>
<div class="header-badge"><span class="pulse-dot"></span>Claude AI</div>
<nav class="header-nav">
<a href="archive/index.html" data-i18n="nav-archive">归档</a>
<a href="feed.xml" style="color:var(--dimmed)">RSS</a>
</nav>
<button id="lang-btn" onclick="toggleLang()" title="切换语言 / Switch Language">
<span class="lang-opt" id="lang-zh">ZH</span>
<span class="lang-opt" id="lang-en">EN</span>
</button>
</div>
</div>
</div>
</header>
<!-- NAV -->
<nav class="jump-nav" id="jump-nav">
<a href="#sec-summary" data-i18n="nav-summary">📊 大势</a>
<a href="#sec-ai-trading" data-i18n="nav-ai-trading">🤖 AI操盘</a>
<a href="#sec-news" data-i18n="nav-news">📰 要闻</a>
<a href="#sec-watchlist" data-i18n="nav-watchlist">🎯 AI分析</a>
<a href="#sec-macro" data-i18n="nav-macro">📈 宏观</a>
<a href="#sec-earnings" data-i18n="nav-earnings">💼 财报</a>
<a href="#sec-sectors" data-i18n="nav-sectors">🏭 行业</a>
<a href="#sec-debate" data-i18n="nav-debate">⚔️ 辩论</a>
<a href="#sec-calendar" data-i18n="nav-calendar">📅 日历</a>
<a href="#sec-my" data-i18n="nav-my">⭐ 我的</a>
</nav>
<!-- INDICES TICKER -->
<section class="indices-section">
<div class="indices-scroll-wrapper">
<div class="indices-track">
<!-- INDICES:START -->
<div class="ticker-card up">
<div class="ticker-name">S&P 500</div>
<div class="ticker-value">7,543.64</div>
<div class="ticker-change up">▲ +0.81%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">纳斯达克综合指数</div>
<div class="ticker-value">26,206.89</div>
<div class="ticker-change up">▲ +1.30%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">道琼斯工业指数</div>
<div class="ticker-value">52,478.41</div>
<div class="ticker-change up">▲ +0.27%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">上证综指</div>
<div class="ticker-value">4,036.59</div>
<div class="ticker-change up">▲ +1.65%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">恒生指数</div>
<div class="ticker-value">24,030.18</div>
<div class="ticker-change down">▼ -0.70%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">日经225指数</div>
<div class="ticker-value">69,001.00</div>
<div class="ticker-change up">▲ +1.86%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">德国DAX指数</div>
<div class="ticker-value">24,897.45</div>
<div class="ticker-change down">▼ -2.23%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">黄金现货</div>
<div class="ticker-value">4,108.10</div>
<div class="ticker-change down">▼ -0.79%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">WTI原油</div>
<div class="ticker-value">72.00</div>
<div class="ticker-change up">▲ +0.40%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">比特币</div>
<div class="ticker-value">64,455.20</div>
<div class="ticker-change up">▲ +2.36%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">美元指数</div>
<div class="ticker-value">100.54</div>
<div class="ticker-change down">▼ -0.18%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">离岸人民币</div>
<div class="ticker-value">6.7947</div>
<div class="ticker-change up">▲ +0.14%</div>
</div>
<!-- INDICES:END -->
<!-- INDICES:END -->
<!-- duplicate for seamless loop -->
<!-- INDICES:START -->
<div class="ticker-card up">
<div class="ticker-name">S&P 500</div>
<div class="ticker-value">7,543.64</div>
<div class="ticker-change up">▲ +0.81%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">纳斯达克综合指数</div>
<div class="ticker-value">26,206.89</div>
<div class="ticker-change up">▲ +1.30%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">道琼斯工业指数</div>
<div class="ticker-value">52,478.41</div>
<div class="ticker-change up">▲ +0.27%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">上证综指</div>
<div class="ticker-value">4,036.59</div>
<div class="ticker-change up">▲ +1.65%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">恒生指数</div>
<div class="ticker-value">24,030.18</div>
<div class="ticker-change down">▼ -0.70%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">日经225指数</div>
<div class="ticker-value">69,001.00</div>
<div class="ticker-change up">▲ +1.86%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">德国DAX指数</div>
<div class="ticker-value">24,897.45</div>
<div class="ticker-change down">▼ -2.23%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">黄金现货</div>
<div class="ticker-value">4,108.10</div>
<div class="ticker-change down">▼ -0.79%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">WTI原油</div>
<div class="ticker-value">72.00</div>
<div class="ticker-change up">▲ +0.40%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">比特币</div>
<div class="ticker-value">64,455.20</div>
<div class="ticker-change up">▲ +2.36%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">美元指数</div>
<div class="ticker-value">100.54</div>
<div class="ticker-change down">▼ -0.18%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">离岸人民币</div>
<div class="ticker-value">6.7947</div>
<div class="ticker-change up">▲ +0.14%</div>
</div>
<!-- INDICES:END -->
</div>
</div>
</section>
<!-- SUMMARY HERO -->
<section class="summary-section sec-anchor" id="sec-summary">
<div class="container">
<!-- SUMMARY:START -->
<div class="summary-card neutral">
<div class="summary-top">
<span class="sentiment-pill neutral">🟡 中性 · Neutral</span>
<span class="vix-badge">VIX <span class="vix-num">15.56</span></span>
</div>
<div class="summary-headline">美股震荡收涨,AI芯片股反弹,SK Hynix今日纳斯达克上市</div>
<ul class="key-points"><li class="kp-item"><span class="kp-arrow"></span>SK Hynix今日上市测试AI热度</li><li class="kp-item"><span class="kp-arrow"></span>美联储或9月加息概率过半</li><li class="kp-item"><span class="kp-arrow"></span>美伊冲突反复油价波动加剧</li></ul>
<details class="summary-details">
<summary class="summary-details-toggle">深度解读 ▸</summary>
<div class="summary-context">标普500周四收涨0.8%至7543点,纳指大涨1.3%,AI相关芯片股强势反弹。尽管美伊冲突升级推高油价,但市场聚焦SK Hynix今日265亿美元纳斯达克IPO(超额认购7倍),提振AI产业链情绪。新任美联储主席Warsh鹰派立场明确,市场预期7月或9月加息25基点,利率长期维持高位对北美华人房贷和投资组合构成持续压力。</div>
</details>
</div>
<!-- SUMMARY:END -->
<!-- SUMMARY:END -->
</div>
</section>
<!-- PODCAST PLAYER -->
<div class="podcast-bar" id="podcast-bar">
<div class="container">
<div class="podcast-inner">
<div class="podcast-left">
<span class="podcast-icon">🎙️</span>
<div class="podcast-info">
<div class="podcast-title">金融日报早报 · 今日播客</div>
<div class="podcast-sub" id="podcast-date">欣欣 & 建国 · 约3分钟</div>
</div>
</div>
<div class="podcast-controls">
<audio id="podcast-audio" preload="none">
<source src="audio/latest.mp3" type="audio/mpeg">
</audio>
<button class="pod-btn" id="pod-play" onclick="togglePodcast()">▶ 播放</button>
<div class="pod-progress-wrap" onclick="seekPodcast(event)">
<div class="pod-progress-bar" id="pod-progress"></div>
</div>
<span class="pod-time" id="pod-time">0:00</span>
<button class="pod-btn pod-btn-sm" onclick="document.getElementById('podcast-audio').playbackRate=document.getElementById('podcast-audio').playbackRate===1?1.5:1;this.textContent=document.getElementById('podcast-audio').playbackRate+'x'">1x</button>
<a class="pod-btn pod-btn-sm" href="audio/latest.mp3" download="金融日报早报.mp3" title="下载"></a>
</div>
</div>
</div>
</div>
<style>
.podcast-bar {
background: linear-gradient(90deg, rgba(0,212,170,.08), rgba(79,195,247,.05));
border-bottom: 1px solid rgba(0,212,170,.2);
padding: 10px 0;
}
.podcast-inner { display:flex; align-items:center; justify-content:space-between; gap:14px; flex-wrap:wrap; }
.podcast-left { display:flex; align-items:center; gap:10px; }
.podcast-icon { font-size:1.4rem; animation: pulse-pod 3s ease-in-out infinite; }
@keyframes pulse-pod { 0%,100%{transform:scale(1)} 50%{transform:scale(1.1)} }
.podcast-title { font-size:.82rem; font-weight:600; color:var(--text); }
.podcast-sub { font-size:.65rem; color:var(--muted); font-family:var(--mono); margin-top:1px; }
.podcast-controls { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.pod-btn {
background: rgba(0,212,170,.15); color:var(--accent);
border: 1px solid rgba(0,212,170,.3); border-radius:6px;
padding: 5px 14px; font-size:.75rem; cursor:pointer;
font-family:var(--sans); transition:background .15s; white-space:nowrap;
}
.pod-btn:hover { background:rgba(0,212,170,.25); }
.pod-btn.playing { background:rgba(255,82,82,.12); color:var(--down); border-color:rgba(255,82,82,.3); }
.pod-btn-sm { padding:5px 9px; font-size:.68rem; }
.pod-btn-sm[download] { color:var(--muted); background:rgba(255,255,255,.05); border-color:var(--border); text-decoration:none; }
.pod-progress-wrap { width:160px; height:4px; background:var(--border); border-radius:2px; cursor:pointer; }
@media(max-width:640px){ .pod-progress-wrap { width:80px; } }
.pod-progress-bar { height:100%; background:var(--accent); border-radius:2px; width:0%; transition:width .3s linear; }
.pod-time { font-family:var(--mono); font-size:.65rem; color:var(--muted); min-width:32px; }
</style>
<script>
(function(){
var audio = document.getElementById('podcast-audio');
var btn = document.getElementById('pod-play');
var bar = document.getElementById('pod-progress');
var time = document.getElementById('pod-time');
if (!audio) return;
// Check if audio exists
fetch('audio/latest-meta.json').then(r=>r.json()).then(m=>{
document.getElementById('podcast-date').textContent = '欣欣 & 建国 · ' + m.date + ' · 约3分钟';
}).catch(()=>{
document.getElementById('podcast-bar').style.opacity = '0.4';
btn.textContent = '暂无音频';
btn.disabled = true;
});
audio.addEventListener('timeupdate', function(){
if (!audio.duration) return;
bar.style.width = (audio.currentTime / audio.duration * 100) + '%';
var m = Math.floor(audio.currentTime/60);
var s = Math.floor(audio.currentTime%60);
time.textContent = m + ':' + (s<10?'0':'')+s;
});
audio.addEventListener('ended', function(){
btn.textContent = '▶ 播放';
btn.classList.remove('playing');
bar.style.width = '0%';
});
window.togglePodcast = function(){
if (audio.paused) {
audio.play();
btn.textContent = '⏸ 暂停';
btn.classList.add('playing');
} else {
audio.pause();
btn.textContent = '▶ 播放';
btn.classList.remove('playing');
}
};
window.seekPodcast = function(e){
if (!audio.duration) return;
var rect = e.currentTarget.getBoundingClientRect();
audio.currentTime = ((e.clientX - rect.left) / rect.width) * audio.duration;
};
})();
</script>
<!-- MAIN PAGE BODY -->
<div class="page-body">
<div class="container">
<!-- SUBSCRIBE (dismissible) -->
<div class="subscribe-strip" id="subscribe-strip">
<div class="subscribe-strip-icon">📬</div>
<div class="subscribe-strip-body">
<strong>订阅每日金融早报</strong>
<span>每个交易日自动更新,开盘前 + 收盘后各一次</span>
</div>
<div class="subscribe-strip-actions">
<form action="https://buttondown.email/api/emails/embed-subscribe/yangbai0110" method="post" target="_blank" style="display:flex;gap:6px;">
<input type="email" name="email" placeholder="your@email.com" required style="padding:6px 10px;border-radius:6px;border:1px solid var(--border);background:rgba(255,255,255,.05);color:var(--text);font-size:.73rem;width:148px;outline:none;" />
<button type="submit" class="btn-sub-email">📧 邮件</button>
</form>
<a href="https://t.me/GGmanm_bot?start=subscribe" target="_blank" class="btn-sub-tg">
<svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm5.894 8.221-1.97 9.28c-.145.658-.537.818-1.084.508l-3-2.21-1.447 1.394c-.16.16-.295.295-.605.295l.213-3.053 5.56-5.023c.242-.213-.054-.333-.373-.12L7.44 13.55l-2.955-.924c-.643-.204-.657-.643.136-.953l11.566-4.461c.537-.194 1.006.131.707.009z"/></svg>
Telegram
</a>
<button onclick="document.getElementById('subscribe-strip').style.display='none';localStorage.setItem('fd_sub_dismissed','1');" style="background:none;border:none;color:var(--dimmed);cursor:pointer;font-size:1rem;padding:2px 4px;" title="关闭">×</button>
</div>
</div>
<!-- PRIMARY GRID: main content + sidebar -->
<div class="content-grid">
<!-- ── LEFT / MAIN COLUMN ─────────────────────────────── -->
<div class="main-col">
<!-- NEWS -->
<div class="section-block sec-anchor" id="sec-news">
<div class="card">
<div class="section-label">📰 市场要闻 · Market News</div>
<!-- NEWS:START -->
<div class="news-item breaking featured" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot breaking"></span>
<div class="news-title">SK Hynix今日纳斯达克上市,265亿美元IPO超额认购7倍</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>持有半导体ETF或Micron的投资者需关注竞争格局变化,SK Hynix上市可能分流资金并重塑AI供应链估值体系</div>
<div class="news-body-collapse">韩国存储芯片巨头SK Hynix周五在纳斯达克挂牌交易(代码SKHY),定价149美元/股,募资约280亿美元,成为史上最大外国公司美国上市。订单超额认购7倍,反映市场对AI存储器需求的强烈信心。SK Hynix是英伟达HBM芯片核心供应商,2026年营收同比暴增265%,与美国竞争对手Micron估值差距有望缩小。</div>
<div class="news-footer">
<span class="importance-badge breaking">🔥 BREAKING</span>
<div class="tags"><span class="tag">#AI芯片</span><span class="tag">#IPO</span><span class="tag">#半导体</span></div>
</div>
</div>
<div class="news-item breaking featured" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot breaking"></span>
<div class="news-title">美伊冲突升级,原油价格反复波动加剧市场不确定性</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>油价波动直接影响通胀预期和美联储政策路径,持有能源股或通胀保护资产的投资者可能受益,但整体市场面临滞胀风险</div>
<div class="news-body-collapse">美国周三对伊朗发动90多个目标打击,伊朗誓言关闭霍尔木兹海峡并进行报复。WTI原油周三一度飙升4.4%至73.52美元,但随后回落至72美元附近。特朗普称不认为会重返全面战争,但美国已撤销伊朗石油销售豁免。IEA称这是历史上最大石油供应中断,20%全球石油供应受影响,分析师警告持续中断可能推高油价至100美元。</div>
<div class="news-footer">
<span class="importance-badge breaking">🔥 BREAKING</span>
<div class="tags"><span class="tag">#地缘政治</span><span class="tag">#原油</span><span class="tag">#通胀</span></div>
</div>
</div>
<div class="news-item breaking featured" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot breaking"></span>
<div class="news-title">美联储9月加息概率超50%,市场彻底告别降息预期</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>持有成长股和长久期债券的投资者需警惕估值回调风险,可考虑增配短久期债券、金融股和防御性板块</div>
<div class="news-body-collapse">CME FedWatch工具显示,7月加息25基点概率25%,9月加息概率超50%,年底前加息1-3次概率高达80%。新主席沃什6月会议将2026年PCE通胀预期从2.7%上调至3.6%,9位官员预期年内至少加息一次。这与年初市场预期2-3次降息形成鲜明对比,长期高利率环境对科技成长股估值构成持续压力。</div>
<div class="news-footer">
<span class="importance-badge breaking">🔥 BREAKING</span>
<div class="tags"><span class="tag">#美联储</span><span class="tag">#加息</span><span class="tag">#债券</span></div>
</div>
</div>
<div class="news-item high" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot high"></span>
<div class="news-title">Micron宣布投资2500亿美元,内存芯片行业进入超级周期</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>内存芯片股短期动能强劲但估值透支严重,追高风险极高,建议等待回调或分批建仓,关注设备商ASML供应瓶颈</div>
<div class="news-body-collapse">Micron周四宣布将美国投资从2000亿上调至2500亿美元,并投资30亿美元支持GlobalWafers硅晶圆生产。公司股价年内暴涨超800%,周四再涨5.2%。SanDisk涨7.6%Applied Materials涨3.2%。分析师警告AI基础设施投资虽持续强劲,但估值已达极端水平,获利回吐风险上升。</div>
<div class="news-footer">
<span class="importance-badge high">• HIGH</span>
<div class="tags"><span class="tag">#AI芯片</span><span class="tag">#Micron</span><span class="tag">#投资</span></div>
</div>
</div>
<div class="news-item high" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot high"></span>
<div class="news-title">Meta宣布9月启动自研AI芯片生产,挑战英伟达垄断地位</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>英伟达面临客户自研芯片长期威胁,但短期1-2年内仍将主导市场,持有者需关注2027年后竞争格局变化</div>
<div class="news-body-collapse">Meta周四宣布将于9月开始生产自研AI芯片,寻求降低对英伟达依赖。消息推动Meta股价飙升4%。Google、亚马逊等科技巨头均在研发定制AI芯片,威胁英伟达长期定价权。分析师认为这一趋势可能在2027-2028年开始侵蚀英伟达市场份额,但短期内英伟达技术领先优势仍难撼动。</div>
<div class="news-footer">
<span class="importance-badge high">• HIGH</span>
<div class="tags"><span class="tag">#Meta</span><span class="tag">#AI芯片</span><span class="tag">#英伟达</span></div>
</div>
</div>
<div class="news-item high" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot high"></span>
<div class="news-title">中国6月CPI降至1.0%,PPI加速至4.1%,经济复苏不均衡</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>中国经济呈现供强需弱格局,关注消费刺激政策落地,港股和A股消费板块或有反弹机会,但需警惕房地产拖累</div>
<div class="news-body-collapse">中国6月CPI同比上涨1.0%,低于5月的1.2%,显示终端消费需求疲软。但PPI同比上涨4.1%,高于5月的3.9%,为2022年7月以来最快增速,反映上游成本压力。央行承诺维持适度宽松政策,加大对国内消费的金融支持。A股周四收涨1.65%,但恒指下跌0.7%,反映投资者对内需复苏持谨慎态度。</div>
<div class="news-footer">
<span class="importance-badge high">• HIGH</span>
<div class="tags"><span class="tag">#中国经济</span><span class="tag">#A股</span><span class="tag">#通胀</span></div>
</div>
</div>
<div class="news-item medium" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot medium"></span>
<div class="news-title">Delta财报显示航空业进入甜蜜期,但油价上涨构成隐忧</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>航空股短期面临油价上涨和经济放缓双重压力,不建议追高,但长期受益于旅行需求复苏,可等待回调后布局</div>
<div class="news-body-collapse">Delta Air Lines周五公布Q2财报,营收同比增9.4%创纪录,非GAAP每股收益飙升42%,高票价和低油价(当时)推动业绩。但分析师警告,美伊冲突导致油价近期上涨,可能在Q3侵蚀航空公司利润率。美国航空、联合航空等股票周四下跌,投资者重新评估成本压力。</div>
<div class="news-footer">
<span class="importance-badge medium">• MEDIUM</span>
<div class="tags"><span class="tag">#航空</span><span class="tag">#财报</span><span class="tag">#原油</span></div>
</div>
</div>
<!-- NEWS:END -->
<!-- NEWS:END -->
</div>
</div>
<!-- AI 操盘实验 -->
<div class="section-block sec-anchor" id="sec-ai-trading">
<div class="card">
<div class="section-label">🤖 AI 操盘实验 · AI Trading Challenge</div>
<div id="ai-portfolio-loading" style="color:var(--muted);font-size:0.82rem;padding:8px 0;">加载中…</div>
<div id="ai-portfolio-content" style="display:none">
<!-- 排行榜 -->
<div style="font-size:0.72rem;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);margin-bottom:10px;">🏆 排行榜 · Leaderboard <span style="font-size:0.68rem;color:var(--dimmed);margin-left:6px;">初始资金 $10,000 · 基线 SPY买入持有</span></div>
<div id="ai-leaderboard" style="display:flex;flex-direction:column;gap:8px;margin-bottom:18px;"></div>
<!-- 各模型详情 Tab -->
<div style="display:flex;gap:6px;margin-bottom:12px;" id="ai-model-tabs"></div>
<div id="ai-model-detail"></div>
<!-- 历史对比表 -->
<div id="ai-history-wrap" style="margin-top:16px;">
<div style="font-size:0.72rem;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);margin-bottom:8px;">📈 历史表现对比</div>
<div id="ai-history-table" style="font-family:var(--mono);font-size:0.76rem;"></div>
</div>
</div>
</div>
</div>
<!-- AI WATCHLIST -->
<section class="section-block sec-anchor" id="sec-watchlist">
<div class="card">
<div class="section-label">🎯 AI 决策仪表盘 · AI Watchlist</div>
<!-- WATCHLIST_ANALYSIS:START -->
<div class="watchlist-grid">
<div class="watchlist-card">
<div class="wc-header">
<div><div class="wc-ticker">NVDA</div><div class="wc-name">英伟达</div></div>
<div class="wc-price"><div class="wc-price-val">204.27</div><div class="wc-price-chg up">+0.07%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge HOLD">HOLD</span>
<span class="wc-score">评分 <span>68</span>/100</span>
</div>
<div class="wc-conclusion">技术面震荡,基本面强劲但估值透支</div>
<div class="wc-driver">SK Hynix上市分流资金,Meta等客户自研芯片构成长期威胁,但短期AI需求仍强劲支撑</div>
<div class="wc-targets"><span class="wc-target-up">↑ 220</span><span class="wc-target-down">↓ 190</span></div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge high">风险:high</span></div>
<div class="wc-action">当前位置不建议追高,等待回调至190-195美元区间再考虑加仓。关注7月28-29日FOMC会议影响,加息预期可能引发科技股估值回调。持有者可考虑设置止损于200美元。</div>
<div class="tags" style="margin-top:8px"><span class="tag">#AI芯片</span><span class="tag">#高估值</span><span class="tag">#竞争加剧</span></div>
</div>
<div class="watchlist-card">
<div class="wc-header">
<div><div class="wc-ticker">QQQ</div><div class="wc-name">纳斯达克100 ETF</div></div>
<div class="wc-price"><div class="wc-price-val">712.50</div><div class="wc-price-chg up">+0.85%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge HOLD">HOLD</span>
<span class="wc-score">评分 <span>62</span>/100</span>
</div>
<div class="wc-conclusion">短期反弹但面临加息和估值压力</div>
<div class="wc-driver">AI板块反弹推动,但美联储鹰派转向和长期高利率环境构成估值下行压力</div>
<div class="wc-targets"><span class="wc-target-up">↑ 735</span><span class="wc-target-down">↓ 675</span></div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge high">风险:high</span></div>
<div class="wc-action">适合作为核心配置长期持有,但短期不宜大幅加仓。建议与SPY搭配以平衡科技集中度风险,或配置10-15%现金应对7月加息风险。52周高点748美元附近阻力明显。</div>
<div class="tags" style="margin-top:8px"><span class="tag">#科技ETF</span><span class="tag">#利率敏感</span><span class="tag">#估值风险</span></div>
</div>
<div class="watchlist-card">
<div class="wc-header">
<div><div class="wc-ticker">SPY</div><div class="wc-name">标普500 ETF</div></div>
<div class="wc-price"><div class="wc-price-val">755.10</div><div class="wc-price-chg up">+0.81%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge HOLD">HOLD</span>
<span class="wc-score">评分 <span>65</span>/100</span>
</div>
<div class="wc-conclusion">宽基配置稳健,但短期上行空间有限</div>
<div class="wc-driver">板块轮动支撑指数韧性,但9个板块下跌显示市场分化严重,VIX低位反映风险定价不足</div>
<div class="wc-targets"><span class="wc-target-up">↑ 770</span><span class="wc-target-down">↓ 720</span></div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge medium">风险:medium</span></div>
<div class="wc-action">作为退休账户核心持仓长期配置,短期可维持现有仓位不动。建议搭配10%防御性板块(XLV、XLU)对冲风险。7月CPI和FOMC会议前可考虑轻仓对冲(买入VIX看涨期权或卖出部分涨幅过大个股)。</div>
<div class="tags" style="margin-top:8px"><span class="tag">#宽基ETF</span><span class="tag">#核心配置</span><span class="tag">#防御</span></div>
</div>
<div class="watchlist-card">
<div class="wc-header">
<div><div class="wc-ticker">BTC-USD</div><div class="wc-name">比特币</div></div>
<div class="wc-price"><div class="wc-price-val">64,455.20</div><div class="wc-price-chg up">+2.36%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge BUY">BUY</span>
<span class="wc-score">评分 <span>72</span>/100</span>
</div>
<div class="wc-conclusion">技术面突破,风险偏好回升支撑</div>
<div class="wc-driver">美元走弱和风险资产反弹带动,7月17日期权到期前波动加剧,但长期高利率仍是压制因素</div>
<div class="wc-targets"><span class="wc-target-up">↑ 70000</span><span class="wc-target-down">↓ 58000</span></div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge high">风险:high</span></div>
<div class="wc-action">可小幅加仓至投资组合5-8%(风险承受能力高者),设置止损于60000美元。关注7/14 CPI数据,超预期将引发回调。长期看好突破前高,但需警惕短期波动,不建议杠杆操作。</div>
<div class="tags" style="margin-top:8px"><span class="tag">#加密货币</span><span class="tag">#风险资产</span><span class="tag">#波动</span></div>
</div>
<div class="watchlist-card">
<div class="wc-header">
<div><div class="wc-ticker">510300.SS</div><div class="wc-name">沪深300 ETF</div></div>
<div class="wc-price"><div class="wc-price-val">4.12</div><div class="wc-price-chg up">+1.2%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge HOLD">HOLD</span>
<span class="wc-score">评分 <span>58</span>/100</span>
</div>
<div class="wc-conclusion">政策支撑短期反弹,但内需疲软限制上行</div>
<div class="wc-driver">央行宽松承诺和国企项目推动,但CPI降至1.0%显示消费需求不足,房地产拖累持续</div>
<div class="wc-targets"><span class="wc-target-up">↑ 4.35</span><span class="wc-target-down">↓ 3.85</span></div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge medium">风险:medium</span></div>
<div class="wc-action">适合长期定投分散配置,但短期不建议大举加仓。关注7月14日Q2 GDP数据,若低于预期可能引发调整。建议配置比例不超过海外资产的20%,与港股ETF(恒生科技)搭配分散风险。</div>
<div class="tags" style="margin-top:8px"><span class="tag">#A股</span><span class="tag">#政策驱动</span><span class="tag">#内需疲软</span></div>
</div>
<div class="watchlist-card">
<div class="wc-header">
<div><div class="wc-ticker">GC=F</div><div class="wc-name">黄金期货</div></div>
<div class="wc-price"><div class="wc-price-val">4,107.00</div><div class="wc-price-chg down">-0.82%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge BUY">BUY</span>
<span class="wc-score">评分 <span>75</span>/100</span>
</div>
<div class="wc-conclusion">回调提供低吸机会,通胀和避险需求支撑</div>
<div class="wc-driver">短期因美元反弹和风险偏好回升承压,但长期高通胀+地缘冲突+央行购金支撑4100美元支撑位</div>
<div class="wc-targets"><span class="wc-target-up">↑ 4300</span><span class="wc-target-down">↓ 3950</span></div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge low">风险:low</span></div>
<div class="wc-action">当前回调至4100美元附近是加仓良机,建议配置投资组合10-15%作为通胀对冲和避险资产。关注美伊冲突升级和7月CPI数据,超预期通胀将推动金价突破4200美元。可通过GLD ETF或实物金币配置。</div>
<div class="tags" style="margin-top:8px"><span class="tag">#避险资产</span><span class="tag">#通胀对冲</span><span class="tag">#央行购金</span></div>
</div>
<div class="watchlist-card">
<div class="wc-header">
<div><div class="wc-ticker">CL=F</div><div class="wc-name">WTI原油期货</div></div>
<div class="wc-price"><div class="wc-price-val">72.00</div><div class="wc-price-chg up">+0.40%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge HOLD">HOLD</span>
<span class="wc-score">评分 <span>60</span>/100</span>
</div>
<div class="wc-conclusion">地缘风险溢价vs经济放缓预期拉锯</div>
<div class="wc-driver">美伊冲突升级支撑油价,但IEA下调需求预期和经济放缓担忧限制上行空间</div>
<div class="wc-targets"><span class="wc-target-up">↑ 85</span><span class="wc-target-down">↓ 65</span></div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge high">风险:high</span></div>
<div class="wc-action">不建议直接投资原油期货,波动极大且跟踪误差高。可通过XLE(能源ETF)或Chevron、ExxonMobil等能源股间接配置,比例不超过5%。关注霍尔木兹海峡局势,若冲突持续升级可能推动油价突破80美元。</div>
<div class="tags" style="margin-top:8px"><span class="tag">#大宗商品</span><span class="tag">#地缘政治</span><span class="tag">#高波动</span></div>
</div>
<div class="watchlist-card">
<div class="wc-header">
<div><div class="wc-ticker">TSLA</div><div class="wc-name">特斯拉</div></div>
<div class="wc-price"><div class="wc-price-val">406.55</div><div class="wc-price-chg up">+3.17%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge SELL">SELL</span>
<span class="wc-score">评分 <span>48</span>/100</span>
</div>
<div class="wc-conclusion">叙事驱动估值极端,7月财报前风险大</div>
<div class="wc-driver">Q2交付超预期支撑股价,但资本开支飙升和自动驾驶/Optimus进展不确定性大,财报历史上波动±15-25%</div>
<div class="wc-targets"><span class="wc-target-up">↑ 455</span><span class="wc-target-down">↓ 365</span></div>
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge high">风险:high</span></div>
<div class="wc-action">当前位置建议减仓或止盈,7/22财报前风险收益比不佳。分析师预测财报后股价将下跌至365-380美元区间,可等待回调后再考虑重新建仓。持有者可卖出406美元看涨期权锁定部分利润,或设置止损于390美元。</div>
<div class="tags" style="margin-top:8px"><span class="tag">#电动车</span><span class="tag">#叙事驱动</span><span class="tag">#高波动</span></div>
</div>
</div>
<!-- WATCHLIST_ANALYSIS:END -->
<!-- WATCHLIST_ANALYSIS:END -->
</div>
</section>
<!-- MACRO + DEBATE (2-up) -->
<div class="two-up">
<div class="section-block sec-anchor" id="sec-macro">
<div class="card" style="height:100%">
<div class="section-label">📈 宏观指标 · Macro</div>
<!-- MACRO:START -->
<div class="macro-grid">
<div class="macro-card dir-up">
<div class="macro-indicator">PCE通胀 YoY</div>
<div class="macro-value macro-value-down">4.1%</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 3.1%</div>
<div class="macro-desc">5月PCE通胀创三年新高,美联储首选通胀指标大幅反弹,核心PCE为3.4%,远超2%目标,强化加息预期</div>
</div>
<div class="macro-card dir-up">
<div class="macro-indicator">CPI YoY</div>
<div class="macro-value macro-value-down">4.2%</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 3.3%</div>
<div class="macro-desc">5月CPI同比上涨4.2%,核心CPI为2.8%,能源价格飙升是主因,美伊冲突推高油价导致通胀意外反弹</div>
</div>
<div class="macro-card dir-neutral">
<div class="macro-indicator">美国失业率</div>
<div class="macro-value ">4.3%</div>
<div class="macro-prev"><span class="arrow "></span> 前值: 4.3%</div>
<div class="macro-desc">失业率维持低位但就业增长放缓,持续申请失业救济人数增至181.4万,劳动力市场韧性支持美联储加息空间</div>
</div>
<div class="macro-card dir-up">
<div class="macro-indicator">美国10年期国债收益率</div>
<div class="macro-value macro-value-up">4.60%</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 4.50%</div>
<div class="macro-desc">收益率升至4.6%附近,反映市场对长期高利率和通胀预期上升,抵押贷款和企业借贷成本维持高位</div>
</div>
<div class="macro-card dir-down">
<div class="macro-indicator">中国CPI YoY</div>
<div class="macro-value macro-value-up">1.0%</div>
<div class="macro-prev"><span class="arrow down"></span> 前值: 1.2%</div>
<div class="macro-desc">6月CPI降至三个月低点1.0%,显示终端消费需求疲软,尽管上游PPI加速至4.1%,价格传导不畅</div>
</div>
<div class="macro-card dir-up">
<div class="macro-indicator">中国PPI YoY</div>
<div class="macro-value macro-value-down">4.1%</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 3.9%</div>
<div class="macro-desc">6月PPI同比上涨4.1%,为2022年7月以来最快增速,反映大宗商品价格上涨和上游成本压力,但下游需求不足</div>
</div>
<div class="macro-card dir-down">
<div class="macro-indicator">美国既有房屋销售</div>
<div class="macro-value macro-value-down">409万套</div>
<div class="macro-prev"><span class="arrow down"></span> 前值: 419万套</div>
<div class="macro-desc">6月既有房屋销售意外下滑至409万套,低于预期的419万套,高利率持续抑制购房需求,房地产市场承压</div>
</div>
<div class="macro-card dir-up">
<div class="macro-indicator">美国持续申请失业救济人数</div>
<div class="macro-value macro-value-up">181.4万</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 180.6万</div>
<div class="macro-desc">截至6月27日当周持续申请人数升至181.4万,显示失业者找工作难度增加,但整体劳动力市场仍相对健康</div>
</div>
</div>
<!-- MACRO:END -->
<!-- MACRO:END -->
</div>
</div>
<div class="section-block sec-anchor" id="sec-debate">
<div class="card" style="height:100%">
<div class="section-label">⚔️ 多空辩论 · Bull vs Bear</div>
<!-- MARKET_DEBATE:START -->
<div class="debate-container">
<div class="debate-header">标普500 本周展望</div>
<div class="debate-sides">
<div class="debate-side bull">
<div class="debate-side-title">🐂 多方看涨</div>
<div class="debate-point"><span class="conf-badge high">high</span>AI芯片需求爆发,SK Hynix上市提振情绪</div>
<div class="debate-point"><span class="conf-badge medium">medium</span>企业盈利韧性强,Q2财报季预期乐观</div>
<div class="debate-point"><span class="conf-badge medium">medium</span>美伊冲突未全面升级,油价回落缓解通胀压力</div>
</div>
<div class="debate-side bear">
<div class="debate-side-title">🐻 空方看跌</div>
<div class="debate-point"><span class="conf-badge high">high</span>美联储9月加息概率过半,估值承压</div>
<div class="debate-point"><span class="conf-badge high">high</span>7/14 CPI或超预期,强化加息路径</div>
<div class="debate-point"><span class="conf-badge medium">medium</span>VIX低位显示风险定价不足,回调一触即发</div>
</div>
</div>
<div class="debate-verdict">
<div class="verdict-label">裁判结论 <span class="verdict-lean bearish">BEARISH</span></div>
<div class="verdict-text">短期市场处于敏感时期,7/14 CPI数据和7/28 FOMC会议是关键节点。技术面标普500在7543点附近面临阻力,VIX低于16显示市场过度乐观。建议谨慎操作,减少追高,增持防御性板块和黄金对冲风险。若CPI超预期,标普500可能回调至7300-7400区间。</div>
</div>
</div>
<!-- MARKET_DEBATE:END -->
<!-- MARKET_DEBATE:END -->
</div>
</div>
</div>
<!-- EARNINGS + SECTORS (2-up) -->
<div class="two-up">
<div class="section-block sec-anchor" id="sec-earnings">
<div class="card">
<div class="section-label">💼 财报追踪 · Earnings</div>
<!-- EARNINGS:START -->
<div class="earnings-grid">
<div class="earnings-card beat">
<div class="earnings-ticker">META</div>
<div class="earnings-company">Meta Platforms</div>
<span class="earnings-beat-badge beat">BEAT ✓</span>
<div class="earnings-eps">
<div class="eps-item">
<div class="eps-label">EPS ACTUAL</div>
<div class="eps-value actual beat">$未披露</div>
</div>
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$未披露</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>未披露</span></div>
<div class="earnings-highlight">宣布9月开始生产自研AI芯片,股价周四暴涨4%,挑战英伟达垄断地位,广告业务保持强劲</div>
</div>
<div class="earnings-card beat">
<div class="earnings-ticker">DAL</div>
<div class="earnings-company">Delta Air Lines</div>
<span class="earnings-beat-badge beat">BEAT ✓</span>
<div class="earnings-eps">
<div class="eps-item">
<div class="eps-label">EPS ACTUAL</div>
<div class="eps-value actual beat">$未披露</div>
</div>
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$未披露</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>创纪录</span></div>
<div class="earnings-highlight">Q2营收同比增9.4%创新高,非GAAP EPS飙升42%,高端旅客持续支撑票价,但Q2燃料成本大幅上升引发担忧</div>
</div>
<div class="earnings-card miss">
<div class="earnings-ticker">PEP</div>
<div class="earnings-company">PepsiCo</div>
<span class="earnings-beat-badge miss">MISS ✗</span>
<div class="earnings-eps">
<div class="eps-item">
<div class="eps-label">EPS ACTUAL</div>
<div class="eps-value actual miss">$未披露</div>
</div>
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$未披露</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>未披露</span></div>
<div class="earnings-highlight">Q2财报似乎令投资者失望,股价盘前下跌,谨慎消费支出和成本上涨压力持续,下调全年指引可能性上升</div>
</div>
<div class="earnings-card pending">
<div class="earnings-ticker">MU</div>
<div class="earnings-company">Micron Technology</div>
<span class="earnings-beat-badge pending">UPCOMING</span>
<div class="earnings-eps">
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$未披露</div>
</div>
<div class="eps-item">
<div class="eps-label">REPORT DATE</div>
<div class="eps-value est" style="font-size:0.75rem;">未来</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>预期强劲</span></div>
<div class="earnings-highlight">宣布投资2500亿美元扩产,年内股价暴涨超800%,AI存储器需求爆发式增长,但估值极端透支需警惕回调</div>
</div>
<div class="earnings-card pending">
<div class="earnings-ticker">JPM</div>
<div class="earnings-company">JPMorgan Chase</div>
<span class="earnings-beat-badge pending">UPCOMING</span>
<div class="earnings-eps">
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$未披露</div>
</div>
<div class="eps-item">
<div class="eps-label">REPORT DATE</div>
<div class="eps-value est" style="font-size:0.75rem;">2026-07-14</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>未披露</span></div>
<div class="earnings-highlight">将于7月14日公布Q2财报,与CPI数据同日发布,银行业受益于高利率环境,净息差改善,交易收入预期强劲</div>
</div>
<div class="earnings-card pending">
<div class="earnings-ticker">GS</div>
<div class="earnings-company">Goldman Sachs</div>
<span class="earnings-beat-badge pending">UPCOMING</span>
<div class="earnings-eps">
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$未披露</div>
</div>
<div class="eps-item">
<div class="eps-label">REPORT DATE</div>
<div class="eps-value est" style="font-size:0.75rem;">2026-07-14</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>未披露</span></div>
<div class="earnings-highlight">Q2财报同日发布,投行业务和交易收入预期表现强劲,受益于M&A活动回暖和市场波动加剧</div>
</div>
<div class="earnings-card pending">
<div class="earnings-ticker">TSLA</div>
<div class="earnings-company">Tesla</div>
<span class="earnings-beat-badge pending">UPCOMING</span>
<div class="earnings-eps">
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$未披露</div>
</div>
<div class="eps-item">
<div class="eps-label">REPORT DATE</div>
<div class="eps-value est" style="font-size:0.75rem;">2026-07-22</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>未披露</span></div>
<div class="earnings-highlight">Q2交付量超预期已公布,但投资者关注资本开支指引和FSD/Optimus进展,财报后股价历史上波动剧烈(±15-25%)</div>
</div>
<div class="earnings-card beat">
<div class="earnings-ticker">601138.SS</div>
<div class="earnings-company">工业富联</div>
<span class="earnings-beat-badge beat">BEAT ✓</span>
<div class="earnings-eps">
<div class="eps-item">
<div class="eps-label">EPS ACTUAL</div>
<div class="eps-value actual beat">$未披露</div>
</div>
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$未披露</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>未披露</span></div>
<div class="earnings-highlight">预计上半年归母净利润234-244亿元,同比增长93-101%Q2单季128-138亿元,AI服务器需求强劲推动业绩</div>
</div>
</div>
<!-- EARNINGS:END -->
<!-- EARNINGS:END -->
</div>
</div>
<div class="section-block sec-anchor" id="sec-sectors">
<div class="card">
<div class="section-label">🏭 板块表现 · Sectors</div>
<!-- SECTORS:START -->
<div class="sectors-list">
<div class="sector-row">
<div><div class="sector-name">信息科技</div><div class="sector-name-en">Technology</div></div>
<div class="sector-etf">XLK</div>
<div class="sector-bar-wrap"><div class="sector-bar up" style="width:51%"></div></div>
<div class="sector-pct up">+1.2%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">能源</div><div class="sector-name-en">Energy</div></div>
<div class="sector-etf">XLE</div>
<div class="sector-bar-wrap"><div class="sector-bar up" style="width:72%"></div></div>
<div class="sector-pct up">+1.8%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">金融</div><div class="sector-name-en">Financials</div></div>
<div class="sector-etf">XLF</div>
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:75%"></div></div>
<div class="sector-pct down">-1.9%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">非必需消费品</div><div class="sector-name-en">Consumer Discretionary</div></div>
<div class="sector-etf">XLY</div>
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:72%"></div></div>
<div class="sector-pct down">-1.8%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">原材料</div><div class="sector-name-en">Materials</div></div>
<div class="sector-etf">XLB</div>
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:100%"></div></div>
<div class="sector-pct down">-2.6%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">工业</div><div class="sector-name-en">Industrials</div></div>
<div class="sector-etf">XLI</div>
<div class="sector-bar-wrap"><div class="sector-bar up" style="width:27%"></div></div>
<div class="sector-pct up">+0.5%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">医疗保健</div><div class="sector-name-en">Healthcare</div></div>
<div class="sector-etf">XLV</div>
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:37%"></div></div>
<div class="sector-pct down">-0.8%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">通信服务</div><div class="sector-name-en">Communication Services</div></div>
<div class="sector-etf">XLC</div>
<div class="sector-bar-wrap"><div class="sector-bar up" style="width:96%"></div></div>
<div class="sector-pct up">+2.5%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">公用事业</div><div class="sector-name-en">Utilities</div></div>
<div class="sector-etf">XLU</div>
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:27%"></div></div>
<div class="sector-pct down">-0.5%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">房地产</div><div class="sector-name-en">Real Estate</div></div>
<div class="sector-etf">XLRE</div>
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:51%"></div></div>
<div class="sector-pct down">-1.2%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">必需消费品</div><div class="sector-name-en">Consumer Staples</div></div>
<div class="sector-etf">XLP</div>
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:20%"></div></div>
<div class="sector-pct down">-0.3%</div>
</div>
</div>
<!-- SECTORS:END -->
<!-- SECTORS:END -->
</div>
</div>
</div>
<!-- REPLAY + CALENDAR (2-up) -->
<div class="two-up">
<div class="section-block sec-anchor" id="sec-replay">
<div class="card">
<div class="section-label">📽️ 大盘复盘 · Replay</div>
<!-- MARKET_REPLAY:START -->
<div class="replay-grid"><div class="replay-card">
<div class="replay-card-title">🇺🇸 美股</div>
<div class="replay-summary">AI芯片反弹带动科技股,但9个板块下跌显示市场分化严重</div>
<div class="ad-bar-wrap">
<span class="ad-label-up">↑3240</span>
<div class="ad-bar adv" style="width:64px;max-width:80px"></div>
<div class="ad-bar dec" style="width:36px;max-width:80px"></div>
<span class="ad-label-dn">↓1820</span>
</div>
<div class="replay-stats">
<div class="replay-stat"><div class="replay-stat-label">热门板块</div><div class="replay-stat-val">科技+1.2%</div></div>
<div class="replay-stat"><div class="replay-stat-label">领涨标的</div><div class="replay-stat-val">SanDisk (+7.6%)</div></div>
<div class="replay-stat"><div class="replay-stat-label">创52周新高</div><div class="replay-stat-val">32</div></div>
</div>
</div><div class="replay-card">
<div class="replay-card-title">🇨🇳 A股</div>
<div class="replay-summary">政策宽松预期推动反弹,但恒指跌0.7%显示港资谨慎</div>
<div class="ad-bar-wrap">
<span class="ad-label-up">↑2800</span>
<div class="ad-bar adv" style="width:65px;max-width:80px"></div>
<div class="ad-bar dec" style="width:35px;max-width:80px"></div>
<span class="ad-label-dn">↓1500</span>
</div>
<div class="replay-stats">
<div class="replay-stat"><div class="replay-stat-label">热门板块</div><div class="replay-stat-val">半导体/AI芯片</div></div>
<div class="replay-stat"><div class="replay-stat-label">领涨标的</div><div class="replay-stat-val">工业富联(业绩预增93-101%</div></div>
<div class="replay-stat"><div class="replay-stat-label">北向资金</div><div class="replay-stat-val">+52亿</div></div>
</div>
</div></div>
<!-- MARKET_REPLAY:END -->
<!-- MARKET_REPLAY:END -->
</div>
</div>
<div class="section-block sec-anchor" id="sec-calendar">
<div class="card">
<div class="section-label">📅 本周日程 · Calendar</div>
<!-- CALENDAR:START -->
<div class="calendar-grid">
<div class="cal-item high">
<div class="cal-date">周二 7/14<br><span style="font-size:0.6rem;color:var(--dimmed)">8:30 AM ET</span></div>
<div>
<div class="cal-event">美国6月CPI</div>
<div class="cal-values">预期: <span>预期4.0-4.3%</span> &nbsp;&middot;&nbsp; 前值: 4.2%</div>
</div>
</div>
<div class="cal-item high">
<div class="cal-date">周二 7/14<br><span style="font-size:0.6rem;color:var(--dimmed)">盘前</span></div>
<div>
<div class="cal-event">JPMorgan、Goldman Sachs Q2财报</div>
<div class="cal-values">预期: <span>交易收入预期强</span> &nbsp;&middot;&nbsp; 前值: 强劲</div>
</div>
</div>
<div class="cal-item medium">
<div class="cal-date">周三 7/15<br><span style="font-size:0.6rem;color:var(--dimmed)">8:30 AM ET</span></div>
<div>
<div class="cal-event">美国6月PPI</div>
<div class="cal-values">预期: <span>关注上游通胀压力</span> &nbsp;&middot;&nbsp; 前值: 未公布</div>
</div>
</div>
<div class="cal-item high">
<div class="cal-date">周四 7/16<br><span style="font-size:0.6rem;color:var(--dimmed)">8:30 AM ET</span></div>
<div>
<div class="cal-event">美国6月零售销售</div>
<div class="cal-values">预期: <span>关注消费韧性</span> &nbsp;&middot;&nbsp; 前值: 下滑</div>
</div>
</div>
<div class="cal-item high">
<div class="cal-date">周一 7/14<br><span style="font-size:0.6rem;color:var(--dimmed)">全天</span></div>
<div>
<div class="cal-event">中国Q2 GDP及6月工业增加值、零售销售</div>
<div class="cal-values">预期: <span>关注内需复苏</span> &nbsp;&middot;&nbsp; 前值: GDP增长放缓</div>
</div>
</div>
<div class="cal-item high">
<div class="cal-date">周一-周二 7/28-29<br><span style="font-size:0.6rem;color:var(--dimmed)">2:00 PM ET</span></div>
<div>
<div class="cal-event">美联储FOMC会议</div>
<div class="cal-values">预期: <span>25%概率加息25基点</span> &nbsp;&middot;&nbsp; 前值: 维持3.50-3.75%</div>
</div>
</div>
<div class="cal-item medium">
<div class="cal-date">周五 7/17<br><span style="font-size:0.6rem;color:var(--dimmed)">全天</span></div>
<div>
<div class="cal-event">Deribit比特币期权到期</div>
<div class="cal-values">预期: <span>短期波动加剧</span> &nbsp;&middot;&nbsp; 前值: 标准周度到期</div>
</div>
</div>
</div>
<!-- CALENDAR:END -->
<!-- CALENDAR:END -->
</div>
</div>
</div>
</div><!-- end main-col -->
<!-- ── RIGHT / SIDEBAR ────────────────────────────────── -->
<div class="sidebar-col">
<!-- LEADERS -->
<div class="section-block sec-anchor mb16" id="sec-leaders">
<div class="card">
<div class="section-label">👔 领袖观点 · Leaders</div>
<!-- LEADERS:START -->
<div class="leader-card">
<div class="leader-header">
<div class="leader-avatar jd">JD</div>
<div class="leader-meta">
<div class="leader-name">杰米·戴蒙 <span style="color:var(--muted);font-weight:400;font-size:0.78rem;">Jamie Dimon</span></div>
<div class="leader-role">摩根大通CEO</div>
</div>
<div class="leader-date">4月</div>
</div>
<div class="leader-quote">"利率就像引力,影响几乎所有资产价格"</div>
<div class="leader-body">戴蒙在2026年度股东信中呼应巴菲特26年前警告,强调通胀风险仍是市场最大威胁。他警告即使不发生衰退,通胀上升也可能推高利率,对资产估值构成持续下行压力。这一观点在当前美联储鹰派转向背景下引发市场对估值回调的担忧。</div>
<div class="tags"><span class="tag">#利率</span><span class="tag">#通胀</span><span class="tag">#美股估值</span></div>
</div>
<div class="leader-card">
<div class="leader-header">
<div class="leader-avatar default">KW</div>
<div class="leader-meta">
<div class="leader-name">凯文·沃什 <span style="color:var(--muted);font-weight:400;font-size:0.78rem;">Kevin Warsh</span></div>
<div class="leader-role">美联储主席</div>
</div>
<div class="leader-date">6月17日</div>
</div>
<div class="leader-quote">"本委员会将实现价格稳定"</div>
<div class="leader-body">5月接任的新主席沃什在首次会议上放弃前瞻指引,强调将根据数据决策。6月FOMC会议上,18位官员中有9位预期年内至少加息一次,PCE通胀预期上调至3.6%。市场预计7月加息概率25%,9月加息概率超50%,彻底推翻此前降息预期。</div>
<div class="tags"><span class="tag">#美联储</span><span class="tag">#加息</span><span class="tag">#通胀</span></div>
</div>
<div class="leader-card">
<div class="leader-header">
<div class="leader-avatar wb">WB</div>
<div class="leader-meta">
<div class="leader-name">沃伦·巴菲特 <span style="color:var(--muted);font-weight:400;font-size:0.78rem;">Warren Buffett</span></div>
<div class="leader-role">伯克希尔哈撒韦CEO</div>
</div>
<div class="leader-date">4月</div>
</div>
<div class="leader-quote">"利率是资产价格的引力"</div>
<div class="leader-body">巴菲特在1999年《财富》杂志文章中提出的利率对资产估值影响的核心观点,在26年后被戴蒙重新引用,警示当前市场高估值风险。当利率上升时,无风险收益率提高,股票等风险资产必须通过价格下跌来提供更高预期回报,这一铁律在2022年已验证过一次。</div>
<div class="tags"><span class="tag">#价值投资</span><span class="tag">#利率</span><span class="tag">#估值</span></div>
</div>
<div class="leader-card">
<div class="leader-header">
<div class="leader-avatar default">CW</div>
<div class="leader-meta">
<div class="leader-name">克里斯托弗·沃勒 <span style="color:var(--muted);font-weight:400;font-size:0.78rem;">Christopher Waller</span></div>
<div class="leader-role">美联储理事</div>
</div>
<div class="leader-date">7月6日</div>
</div>
<div class="leader-quote">"风险天平已完全倾向通胀而非就业"</div>
<div class="leader-body">沃勒7月6日在意大利央行活动上表示,美联储政策关注点已从劳动力市场转向通胀控制。他提及2021-2022年周期,指出市场往往提前6个月定价政策变化,暗示当前债券收益率上升可能已反映未来加息预期。对投资者而言,这意味政策滞后期缩短,市场反应将更迅速。</div>
<div class="tags"><span class="tag">#美联储</span><span class="tag">#通胀</span><span class="tag">#利率</span></div>
</div>
<!-- LEADERS:END -->
<!-- LEADERS:END -->
</div>
</div>
<!-- CENTRAL BANKS -->
<div class="section-block sec-anchor mb16" id="sec-banks">
<div class="card">
<div class="section-label">🏦 央行动态 · Central Banks</div>
<!-- CENTRAL_BANKS:START -->
<div class="cb-grid">
<div class="cb-card">
<div class="cb-header">
<div>
<div class="cb-name">美联储</div>
<div class="cb-name-en">Federal Reserve</div>
</div>
<span class="bias-badge hawkish">Hawkish</span>
</div>
<div class="cb-rate">3.50-3.75%</div>
<div class="cb-action">维持利率3.50-3.75%不变,但释放鹰派信号</div>
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">2026-07-28</span></div>
<div class="cb-note">新主席沃什6月会议上调通胀预期至3.6%,9位官员预期年内至少加息一次,市场预计7月或9月加息25基点</div>
</div>
<div class="cb-card">
<div class="cb-header">
<div>
<div class="cb-name">中国人民银行</div>
<div class="cb-name-en">People's Bank of China</div>
</div>
<span class="bias-badge dovish">Dovish</span>
</div>
<div class="cb-rate">MLF 2.50%</div>
<div class="cb-action">维持利率不变,承诺适度宽松货币政策</div>
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">未公布</span></div>
<div class="cb-note">央行承诺加大金融支持力度提振内需,但6月CPI降至1.0%显示需求疲软,房地产拖累经济复苏,预计维持宽松</div>
</div>
<div class="cb-card">
<div class="cb-header">
<div>
<div class="cb-name">欧洲央行</div>
<div class="cb-name-en">European Central Bank</div>
</div>
<span class="bias-badge hawkish">Hawkish</span>
</div>
<div class="cb-rate">3.75%</div>
<div class="cb-action">6月加息25基点至3.75%</div>
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">2026-07-25</span></div>
<div class="cb-note">通胀仍顽固高于目标,与美联储同步收紧政策,但欧元区经济增长疲软限制进一步加息空间</div>
</div>
<div class="cb-card">
<div class="cb-header">
<div>
<div class="cb-name">日本银行</div>
<div class="cb-name-en">Bank of Japan</div>
</div>
<span class="bias-badge hawkish">Hawkish</span>
</div>
<div class="cb-rate">0.25%</div>
<div class="cb-action">6月加息10基点至0.25%</div>
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">2026-07-30</span></div>
<div class="cb-note">日元跌至1986年以来最低水平迫使央行加息,但加息幅度温和,关注日元汇率干预可能性</div>
</div>
</div>
<!-- CENTRAL_BANKS:END -->
<!-- CENTRAL_BANKS:END -->
</div>
</div>
<!-- TRADINGVIEW CHARTS -->
<div class="section-block mb16">
<div class="card" style="padding:14px 16px">
<div class="section-label">📈 行情图表 · Live Charts</div>
<div class="tradingview-widget-container">
<div class="tradingview-widget-container__widget"></div>
<script type="text/javascript" src="https://s3.tradingview.com/external-embedding/embed-widget-market-overview.js" async>
{
"colorTheme": "dark",
"dateRange": "1D",
"showChart": true,
"locale": "zh_CN",
"isTransparent": true,
"showSymbolLogo": true,
"showFloatingTooltip": false,
"width": "100%",
"height": "480",
"tabs": [
{
"title": "🇺🇸 美股",
"symbols": [
{"s":"FOREXCOM:SPXUSD","d":"S&P 500"},
{"s":"FOREXCOM:NSXUSD","d":"Nasdaq 100"},
{"s":"FOREXCOM:DJI","d":"道琼斯"},
{"s":"CBOE:VIX","d":"VIX 恐慌指数"},
{"s":"TVC:US10Y","d":"美10年债"}
],
"originalTitle": "US"
},
{
"title": "🇨🇳 中国",
"symbols": [
{"s":"SSE:000001","d":"上证指数"},
{"s":"SZSE:399006","d":"创业板指"},
{"s":"HKEX:HSI","d":"恒生指数"},
{"s":"FX:USDCNH","d":"离岸人民币"},
{"s":"HKEX:2318","d":"中国平安"}
],
"originalTitle": "China"
},
{
"title": "🛢️ 大宗",
"symbols": [
{"s":"TVC:GOLD","d":"黄金"},
{"s":"NYMEX:CL1!","d":"原油 WTI"},
{"s":"COMEX:SI1!","d":"白银"},
{"s":"TVC:DXY","d":"美元指数"}
],
"originalTitle": "Commodities"
},
{
"title": "₿ 加密",
"symbols": [
{"s":"BINANCE:BTCUSDT","d":"Bitcoin"},
{"s":"BINANCE:ETHUSDT","d":"Ethereum"},
{"s":"BINANCE:SOLUSDT","d":"Solana"}
],
"originalTitle": "Crypto"
}
]
}
</script>
</div>
</div>
</div>
</div><!-- end sidebar-col -->
</div><!-- end content-grid -->
<!-- MY DASHBOARD (collapsed drawer) -->
<div class="my-drawer sec-anchor" id="sec-my">
<button class="my-drawer-toggle" onclick="this.classList.toggle('open');this.nextElementSibling.classList.toggle('open')">
<span>⭐ 我的工作台 · My Dashboard</span>
<span class="drawer-icon"></span>
</button>
<div class="my-drawer-body">
<div class="card">
<div class="profile-bar">
<span class="profile-label">👤 用户:</span>
<select id="profile-select" onchange="profileSwitch()"></select>
<button onclick="profileNew()"> 新建</button>
<button onclick="profileDelete()">删除</button>
</div>
<div class="personal-header">
<div class="section-label">⭐ 我的工作台 · My Dashboard</div>
<span class="personal-privacy">🔒 数据存本地 · 不上传服务器</span>
</div>
<div class="ptabs">
<button class="ptab active" id="ptab-wl" onclick="switchTab(event,'wl')">📋 自选股</button>
<button class="ptab" id="ptab-pf" onclick="switchTab(event,'pf')">💼 持仓盈亏</button>
<button class="ptab" id="ptab-sim" onclick="switchTab(event,'sim')">📊 模拟器</button>
</div>
<div id="panel-wl">
<div class="add-row">
<input id="wl-sym" placeholder="代码,如 AAPL / 000001.SS / BTC-USD" />
<input id="wl-name" placeholder="备注名(可选)" />
<button onclick="wlAdd()"> 添加</button>
</div>
<div id="wl-empty" class="p-empty">还没有自选股,输入代码开始追踪 →</div>
<div id="wl-list" class="wl-list"></div>
</div>
<div id="panel-pf" style="display:none">
<div class="add-row">
<input id="pf-sym" placeholder="代码,如 AAPL / TSLA" />
<input id="pf-shares" type="number" min="0.0001" step="0.0001" placeholder="数量" />
<input id="pf-cost" type="number" min="0" step="0.01" placeholder="买入均价 ($)" />
<button onclick="pfAdd()"> 添加持仓</button>
</div>
<div id="pf-empty" class="p-empty">还没有持仓记录,输入持仓开始计算浮盈浮亏 →</div>
<div id="pf-summary" class="pf-summary" style="display:none">
<div class="pf-sum-item">总成本<span id="sum-cost"></span></div>
<div class="pf-sum-item">总市值<span id="sum-value"></span></div>
<div class="pf-sum-item">总盈亏<span id="sum-pnl"></span></div>
<div class="pf-sum-item">盈亏率<span id="sum-pct"></span></div>
</div>
<div id="pf-list" class="pf-list"></div>
</div>
<div id="panel-sim" style="display:none">
<div class="sim-section">
<div>
<div class="sim-label">总投资金额</div>
<div class="sim-capital-row">
<input type="number" id="sim-capital" min="0" step="100" value="10000" oninput="simUpdate()" />
<select id="sim-currency" onchange="simUpdate()">
<option value="USD">USD $</option>
<option value="CAD">CAD $</option>
<option value="CNY">CNY ¥</option>
</select>
</div>
</div>
<div>
<div class="sim-label">资产配置</div>
<div class="sim-add-row">
<input id="sim-sym" placeholder="代码,如 AAPL" style="width:100px" />
<input id="sim-alias" placeholder="备注名" style="width:85px" />
<input type="number" id="sim-pct" placeholder="分配%" min="0" max="100" step="1" style="width:65px" />
<input type="number" id="sim-entry" placeholder="买入价(选填)" min="0" step="0.01" style="width:110px" />
<button onclick="simAddAsset()"> 添加</button>
<span style="font-size:0.68rem;color:var(--dimmed)">不填则自动记录当前价</span>
</div>
<div id="sim-pct-total" class="sim-pct-total" style="margin-top:4px">已分配:0%</div>
</div>
<div id="sim-alloc-bar" class="sim-alloc-bar" style="display:none"></div>
<div id="sim-assets-wrap" style="display:none">
<table class="sim-assets-table">
<thead><tr><th>代码</th><th>备注</th><th>分配%</th><th>投入金额</th><th>买入价</th><th>操作</th></tr></thead>
<tbody id="sim-assets-tbody"></tbody>
</table>
</div>
<div id="sim-scenario-section" style="display:none">
<div class="sim-label">收益情景(年化%</div>
<div class="sim-scenario-row">
<label>😨 悲观 <input type="number" id="sim-bear" value="-20" step="1" oninput="simUpdate()" /></label>
<label>📊 中性 <input type="number" id="sim-base" value="8" step="1" oninput="simUpdate()" /></label>
<label>🚀 乐观 <input type="number" id="sim-bull" value="25" step="1" oninput="simUpdate()" /></label>
</div>
<div class="sim-horizon-row">
<span>时间跨度:</span>
<button class="sim-hbtn" data-h="1m" onclick="simSetHorizon(this,'1m')">1月</button>
<button class="sim-hbtn" data-h="3m" onclick="simSetHorizon(this,'3m')">3月</button>
<button class="sim-hbtn" data-h="6m" onclick="simSetHorizon(this,'6m')">6月</button>
<button class="sim-hbtn active" data-h="1y" onclick="simSetHorizon(this,'1y')">1年</button>
<button class="sim-hbtn" data-h="3y" onclick="simSetHorizon(this,'3y')">3年</button>
<button class="sim-hbtn" data-h="5y" onclick="simSetHorizon(this,'5y')">5年</button>
</div>
</div>
<div id="sim-returns-wrap" style="display:none">
<div class="sim-label">预期收益预测</div>
<table class="sim-returns-table">
<thead>
<tr>
<th style="text-align:left">资产</th>
<th>投入</th>
<th>📈 实际</th>
<th>😨 悲观</th>
<th>📊 中性</th>
<th>🚀 乐观</th>
</tr>
</thead>
<tbody id="sim-returns-tbody"></tbody>
</table>
</div>
<div class="sim-actions">
<button class="sim-btn sim-btn-secondary" onclick="simReset()">🗑 重置</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div><!-- end container -->
</div><!-- end page-body -->
<!-- =========================================================
FOOTER
========================================================= -->
<footer class="site-footer">
<div class="container">
<div class="footer-inner">
<span>© 2025 金融日报 · Financial Daily &nbsp;|&nbsp; Powered by <a href="https://www.anthropic.com" target="_blank">Claude AI</a></span>
<span>内容由AI自动生成,仅供参考,不构成投资建议</span>
<a href="feed.xml">RSS Feed</a>
</div>
<div style="display:flex;gap:24px;justify-content:center;margin-top:12px;font-size:0.75rem;color:var(--muted);">
<span>👁 访客 <strong id="footer-visitors" style="color:var(--accent)"></strong></span>
<span>📄 浏览 <strong id="footer-pageviews" style="color:var(--accent)"></strong></span>
</div>
</div>
</footer>
<script>
// Set current date
(function() {
const el = document.getElementById('current-date');
if (!el) return;
const now = new Date();
const opts = { year: 'numeric', month: 'long', day: 'numeric', weekday: 'short' };
el.textContent = now.toLocaleDateString('zh-CN', opts);
})();
// Data age indicator
(function() {
const metaEl = document.querySelector('meta[name="last-updated"]');
if (!metaEl) return;
const updated = new Date(metaEl.content);
const ageH = (Date.now() - updated) / 3600000;
const badge = document.querySelector('.header-badge');
if (!badge) return;
const ageMin = Math.round(ageH * 60);
const ageStr = ageH < 1 ? ageMin + '分钟前更新' : Math.round(ageH) + '小时前更新';
badge.title = ageStr;
if (ageH > 14) badge.classList.add('data-stale');
})();
// Simple / Advanced mode toggle
(function() {
const btn = document.getElementById('mode-btn');
if (!btn) return;
const stored = localStorage.getItem('fd-mode') || 'advanced';
applyMode(stored);
btn.addEventListener('click', function() {
const isSimple = document.body.classList.contains('simple-mode');
const next = isSimple ? 'advanced' : 'simple';
localStorage.setItem('fd-mode', next);
applyMode(next);
});
function applyMode(mode) {
const label = btn.querySelector('.mode-label');
const icon = btn.querySelector('.mode-icon');
if (mode === 'simple') {
document.body.classList.add('simple-mode');
label.textContent = '专业模式';
icon.textContent = '📊';
} else {
document.body.classList.remove('simple-mode');
label.textContent = '新手模式';
icon.textContent = '📖';
}
}
})();
// Live quotes from data/quotes.json (populated by live-quotes workflow)
(function() {
fetch('data/quotes.json?' + Date.now())
.then(r => r.ok ? r.json() : null)
.then(data => {
if (!data || !data.quotes) return;
const track = document.querySelector('.indices-track');
if (!track) return;
data.quotes.forEach(q => {
track.querySelectorAll('.ticker-card').forEach(card => {
const nameEl = card.querySelector('.ticker-name');
if (nameEl && nameEl.textContent.trim() === q.name) {
card.className = 'ticker-card ' + q.direction;
card.querySelector('.ticker-value').textContent = q.value;
const chgEl = card.querySelector('.ticker-change');
const arrow = q.direction === 'up' ? '▲' : '▼';
chgEl.textContent = arrow + ' ' + q.change_pct;
chgEl.className = 'ticker-change ' + q.direction;
}
});
});
// Show live badge
const badge = document.querySelector('.header-badge');
if (badge) {
const updated = new Date(data.updated);
const mins = Math.round((Date.now() - updated) / 60000);
badge.title = '行情数据: ' + (mins < 60 ? mins + '分钟前' : Math.round(mins/60) + '小时前');
badge.classList.remove('data-stale');
}
})
.catch(() => {});
})();
// Auto-tooltip for financial jargon
const FIN_TERMS = {
'VIX': 'VIX = 标普期权隐含波动率,越高越恐慌',
'PCE': 'PCE = 个人消费支出物价指数,美联储首选通胀指标',
'NFP': 'NFP = 非农就业人数,衡量美国就业市场健康度',
'CPI': 'CPI = 消费者物价指数,最常见通胀衡量指标',
'PMI': 'PMI > 50 = 经济扩张;PMI < 50 = 经济收缩',
'QE': 'QE = 量化宽松,央行购买债券向市场注入流动性',
'鹰派': '鹰派 = 倾向加息/收紧货币政策,对抗通胀',
'鸽派': '鸽派 = 倾向降息/宽松货币政策,刺激经济',
'EPS': 'EPS = 每股收益,公司盈利能力的核心指标',
'DXY': 'DXY = 美元指数,衡量美元对六大货币的强弱',
};
document.addEventListener('DOMContentLoaded', function() {
const walker = document.createTreeWalker(
document.querySelector('.macro-section') || document.body,
NodeFilter.SHOW_TEXT
);
// Only apply to macro + news sections to avoid performance issues
['macro-section','news-section','cb-grid'].forEach(cls => {
const sec = document.querySelector('.' + cls);
if (!sec) return;
Object.entries(FIN_TERMS).forEach(([term, tip]) => {
sec.querySelectorAll('.macro-indicator, .cb-action, .news-body').forEach(el => {
if (el.innerHTML.includes(term) && !el.innerHTML.includes('fin-term')) {
el.innerHTML = el.innerHTML.replace(
new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g,'\\$&') + ')', 'g'),
`<span class="fin-term" data-tip="${tip}">$1</span>`
);
}
});
});
});
});
function copyRSS(e) {
e.preventDefault();
const url = 'https://yang1bai.github.io/finance-daily-site/feed.xml';
navigator.clipboard.writeText(url).then(() => {
const btn = document.getElementById('copy-rss');
btn.textContent = '✅ 已复制';
setTimeout(() => { btn.textContent = '📋 复制链接'; }, 2000);
}).catch(() => {
prompt('RSS 链接:', url);
});
}
// ═══════════════════════════════════════════════════════════
// PERSONAL DASHBOARD — Watchlist + Portfolio
// ═══════════════════════════════════════════════════════════
// ── Multi-user Profiles ──────────────────────────────────────
function profileLoad() {
return JSON.parse(localStorage.getItem('fd-profiles-v1') || 'null') || [{ id: 'default', name: '默认用户' }];
}
function profileSave(list) { localStorage.setItem('fd-profiles-v1', JSON.stringify(list)); }
function profileActive() { return localStorage.getItem('fd-active-profile-v1') || 'default'; }
function profileSetActive(id) { localStorage.setItem('fd-active-profile-v1', id); }
function profileRenderSelect() {
const list = profileLoad();
const active = profileActive();
const sel = document.getElementById('profile-select');
if (!sel) return;
sel.innerHTML = list.map(p => `<option value="${p.id}" ${p.id === active ? 'selected' : ''}>${p.name}</option>`).join('');
}
function profileSwitch() {
const sel = document.getElementById('profile-select');
if (!sel) return;
profileSetActive(sel.value);
wlRender(); pfRender(); simRender();
}
function profileNew() {
const name = prompt('输入用户名:', '用户' + (profileLoad().length + 1));
if (!name || !name.trim()) return;
const id = 'user_' + Date.now();
const list = profileLoad();
list.push({ id, name: name.trim() });
profileSave(list);
profileSetActive(id);
profileRenderSelect();
wlRender(); pfRender(); simRender();
}
function profileDelete() {
const list = profileLoad();
if (list.length <= 1) { alert('至少保留一个用户'); return; }
const active = profileActive();
const idx = list.findIndex(p => p.id === active);
if (idx === -1) return;
if (!confirm(`确认删除用户"${list[idx].name}"的所有数据?`)) return;
['watchlist-v1','portfolio-v1','sim-v1'].forEach(k => {
localStorage.removeItem(`fd-${active}-${k}`);
});
list.splice(idx, 1);
profileSave(list);
profileSetActive(list[0].id);
profileRenderSelect();
wlRender(); pfRender(); simRender();
}
// ── Dynamic localStorage keys ──────────────────────────
function lsWL() { return `fd-${profileActive()}-watchlist-v1`; }
function lsPF() { return `fd-${profileActive()}-portfolio-v1`; }
function lsSIM() { return `fd-${profileActive()}-sim-v1`; }
const priceCache = {};
function wlLoad() { return JSON.parse(localStorage.getItem(lsWL()) || '[]'); }
function wlSave(d) { localStorage.setItem(lsWL(), JSON.stringify(d)); }
function pfLoad() { return JSON.parse(localStorage.getItem(lsPF()) || '[]'); }
function pfSave(d) { localStorage.setItem(lsPF(), JSON.stringify(d)); }
function switchTab(e, tab) {
['wl','pf','sim'].forEach(t => {
document.getElementById('panel-' + t).style.display = t === tab ? 'block' : 'none';
document.getElementById('ptab-' + t).classList.toggle('active', t === tab);
});
}
// ── Price fetching (Yahoo Finance → CORS proxy fallback) ───
function toYahooSym(raw) {
if (!raw.includes(':')) return raw;
const [exch, ticker] = raw.split(':');
const map = { SSE:'', SZSE:'', HKEX:'.HK', TSX:'.TO', LSE:'.L', FWB:'.DE' };
if (exch === 'SSE') return ticker + '.SS';
if (exch === 'SZSE') return ticker + '.SZ';
return ticker + (map[exch] || '');
}
async function fetchPrice(rawSym) {
const key = rawSym;
if (priceCache[key] && Date.now() - priceCache[key].ts < 300000) return priceCache[key];
const ySym = toYahooSym(rawSym);
const yUrl = `https://query1.finance.yahoo.com/v8/finance/chart/${encodeURIComponent(ySym)}?range=1d&interval=1m&includePrePost=false`;
const proxies = [
yUrl,
`https://corsproxy.io/?${encodeURIComponent(yUrl)}`,
`https://api.allorigins.win/get?url=${encodeURIComponent(yUrl)}`
];
for (const url of proxies) {
try {
const resp = await fetch(url, { signal: AbortSignal.timeout(7000) });
if (!resp.ok) continue;
let json = await resp.json();
// allorigins wraps in {contents: '...'}
if (json.contents) json = JSON.parse(json.contents);
const result = json.chart?.result?.[0];
if (!result) continue;
const meta = result.meta;
const price = meta.regularMarketPrice;
const prev = meta.chartPreviousClose || meta.previousClose || price;
const chgPct = prev ? (price - prev) / prev * 100 : 0;
const chgAbs = price - prev;
const info = { price, prev, chgPct, chgAbs, currency: meta.currency || 'USD', ts: Date.now() };
priceCache[key] = info;
return info;
} catch(e) {}
}
return null;
}
function fmtNum(n, dec=2) {
return n.toLocaleString('en-US', { minimumFractionDigits: dec, maximumFractionDigits: dec });
}
// ── Watchlist ───────────────────────────────────────────────
function wlAdd() {
const sym = (document.getElementById('wl-sym').value || '').trim().toUpperCase();
const name = (document.getElementById('wl-name').value || '').trim();
if (!sym) return;
const list = wlLoad();
if (list.find(i => i.symbol === sym)) { alert('已在自选列表'); return; }
list.push({ symbol: sym, alias: name });
wlSave(list);
document.getElementById('wl-sym').value = '';
document.getElementById('wl-name').value = '';
wlRender();
}
function wlRemove(sym) {
wlSave(wlLoad().filter(i => i.symbol !== sym));
wlRender();
}
function wlRender() {
const list = wlLoad();
const grid = document.getElementById('wl-list');
const empty = document.getElementById('wl-empty');
if (!list.length) { empty.style.display = 'block'; grid.innerHTML = ''; return; }
empty.style.display = 'none';
grid.innerHTML = list.map(item => {
const id = 'wlp-' + item.symbol.replace(/[^a-z0-9]/gi, '_');
return `<div class="wl-card">
<div class="wl-card-top">
<div>
<div class="wl-sym">${item.symbol}</div>
${item.alias ? `<div class="wl-alias">${item.alias}</div>` : ''}
</div>
<button class="wl-rm" onclick="wlRemove('${item.symbol.replace(/'/g,"\'")}')">×</button>
</div>
<div id="${id}"><span class="wl-loading">加载中…</span></div>
</div>`;
}).join('');
list.forEach(item => {
const id = 'wlp-' + item.symbol.replace(/[^a-z0-9]/gi, '_');
fetchPrice(item.symbol).then(info => {
const el = document.getElementById(id);
if (!el) return;
if (!info) { el.innerHTML = '<span class="wl-loading">获取失败</span>'; return; }
const dir = info.chgPct >= 0 ? 'up' : 'down';
const arrow = info.chgPct >= 0 ? '▲' : '▼';
el.innerHTML = `
<div class="wl-price-block">
<span class="wl-cur">${info.currency}</span>
<span class="wl-price">${fmtNum(info.price)}</span>
<span class="ticker-change ${dir}" style="font-size:0.72rem;">${arrow} ${Math.abs(info.chgPct).toFixed(2)}%</span>
</div>
<div class="wl-prev">昨收 ${fmtNum(info.prev)}</div>
`;
});
});
}
// ── Portfolio ───────────────────────────────────────────────
function pfAdd() {
const sym = (document.getElementById('pf-sym').value || '').trim().toUpperCase();
const shares = parseFloat(document.getElementById('pf-shares').value);
const cost = parseFloat(document.getElementById('pf-cost').value);
if (!sym || !shares || !cost || isNaN(shares) || isNaN(cost)) {
alert('请完整填写代码、数量和买入均价');
return;
}
const list = pfLoad();
list.push({ symbol: sym, shares, costBasis: cost, addedAt: Date.now() });
pfSave(list);
['pf-sym','pf-shares','pf-cost'].forEach(id => document.getElementById(id).value = '');
pfRender();
}
function pfRemove(idx) {
const list = pfLoad(); list.splice(idx, 1); pfSave(list); pfRender();
}
function pfRender() {
const list = pfLoad();
const grid = document.getElementById('pf-list');
const empty = document.getElementById('pf-empty');
const sumEl = document.getElementById('pf-summary');
if (!list.length) { empty.style.display='block'; grid.innerHTML=''; sumEl.style.display='none'; return; }
empty.style.display = 'none';
sumEl.style.display = 'flex';
const totalCost = list.reduce((s, i) => s + i.shares * i.costBasis, 0);
document.getElementById('sum-cost').textContent = '$' + fmtNum(totalCost);
grid.innerHTML = list.map((item, idx) => {
const id = 'pfp-' + idx;
const itemCost = item.shares * item.costBasis;
return `<div class="pf-card">
<div class="pf-card-top">
<span class="pf-sym">${item.symbol}</span>
<button class="wl-rm" onclick="pfRemove(${idx})">×</button>
</div>
<div class="pf-meta">
${fmtNum(item.shares, 4)} 股 &nbsp;×&nbsp; $${fmtNum(item.costBasis)} 成本<br>
持仓成本 <strong>$${fmtNum(itemCost)}</strong>
</div>
<div class="pf-pnl-row" id="${id}"><span class="wl-loading">计算盈亏中…</span></div>
</div>`;
}).join('');
let fetchedCount = 0, totalValue = 0;
list.forEach((item, idx) => {
fetchPrice(item.symbol).then(info => {
fetchedCount++;
const el = document.getElementById('pfp-' + idx);
if (!el) return;
if (!info) { el.innerHTML = '<span class="wl-loading">价格获取失败</span>'; return; }
const curVal = item.shares * info.price;
const pnlAbs = curVal - item.shares * item.costBasis;
const pnlPct = pnlAbs / (item.shares * item.costBasis) * 100;
const dir = pnlAbs >= 0 ? 'pos' : 'neg';
const sign = pnlAbs >= 0 ? '+' : '';
totalValue += curVal;
el.innerHTML = `
<span class="pf-cur-price">${info.currency} ${fmtNum(info.price)}</span>
<span class="pf-gain ${dir}">${sign}$${fmtNum(pnlAbs)} (${sign}${pnlPct.toFixed(2)}%)</span>
`;
if (fetchedCount === list.length) {
document.getElementById('sum-value').textContent = '$' + fmtNum(totalValue);
const totPnl = totalValue - totalCost;
const totPct = totPnl / totalCost * 100;
const sign2 = totPnl >= 0 ? '+' : '';
const cls = totPnl >= 0 ? 'pf-pnl-pos' : 'pf-pnl-neg';
document.getElementById('sum-pnl').innerHTML = `<span class="${cls}">${sign2}$${fmtNum(totPnl)}</span>`;
document.getElementById('sum-pct').innerHTML = `<span class="${cls}">${sign2}${totPct.toFixed(2)}%</span>`;
}
});
});
}
// ── Investment Simulator ─────────────────────────────────
function simLoad() {
return JSON.parse(localStorage.getItem(lsSIM()) || 'null') || {
capital: 10000, currency: 'USD',
assets: [],
scenarios: { bear: -20, base: 8, bull: 25 },
horizon: '1y'
};
}
function simSave(d) { localStorage.setItem(lsSIM(), JSON.stringify(d)); }
function simRender() {
const d = simLoad();
const capEl = document.getElementById('sim-capital');
const curEl = document.getElementById('sim-currency');
const bearEl = document.getElementById('sim-bear');
const baseEl = document.getElementById('sim-base');
const bullEl = document.getElementById('sim-bull');
if (capEl) capEl.value = d.capital;
if (curEl) curEl.value = d.currency;
if (bearEl) bearEl.value = d.scenarios.bear;
if (baseEl) baseEl.value = d.scenarios.base;
if (bullEl) bullEl.value = d.scenarios.bull;
document.querySelectorAll('.sim-hbtn').forEach(b => {
b.classList.toggle('active', b.dataset.h === d.horizon);
});
simRenderAssets(d);
simCalcReturns(d);
}
function simRenderAssets(d) {
const capital = parseFloat(d.capital) || 0;
const totalPct = d.assets.reduce((s, a) => s + (parseFloat(a.pct)||0), 0);
const pctEl = document.getElementById('sim-pct-total');
if (pctEl) {
pctEl.textContent = `已分配:${totalPct.toFixed(1)}%`;
pctEl.className = 'sim-pct-total' + (totalPct > 100 ? ' over' : '');
}
if (!d.assets.length) {
['sim-assets-wrap','sim-alloc-bar','sim-scenario-section','sim-returns-wrap'].forEach(id => {
const el = document.getElementById(id);
if (el) el.style.display = 'none';
});
return;
}
['sim-assets-wrap','sim-scenario-section','sim-returns-wrap'].forEach(id => {
const el = document.getElementById(id);
if (el) el.style.display = 'block';
});
const bar = document.getElementById('sim-alloc-bar');
if (bar) {
bar.style.display = 'flex';
bar.innerHTML = d.assets.map((a, i) => {
const w = Math.min(parseFloat(a.pct)||0, 100);
return `<div class="sim-alloc-seg" title="${a.symbol} ${a.pct}%" style="width:${w}%;background:hsl(${i*47},65%,50%);"></div>`;
}).join('');
}
const tbody = document.getElementById('sim-assets-tbody');
if (tbody) {
const cur = d.currency === 'CNY' ? '¥' : '$';
tbody.innerHTML = d.assets.map((a, idx) => {
const invest = capital * (parseFloat(a.pct)||0) / 100;
return `<tr>
<td><strong>${a.symbol}</strong></td>
<td>${a.alias || '—'}</td>
<td><input type="number" min="0" max="100" step="1" value="${a.pct}" onchange="simUpdatePct(${idx},this.value)" style="width:55px;background:transparent;border:1px solid var(--border);color:var(--text);border-radius:3px;padding:2px 5px;" /></td>
<td>${cur}${fmtNum(invest)}</td>
<td style="font-size:0.72rem;color:var(--dimmed)">${a.entryPrice ? cur + fmtNum(a.entryPrice) : '—'}</td>
<td><button class="wl-rm" onclick="simRemoveAsset(${idx})">×</button></td>
</tr>`;
}).join('');
}
}
async function simCalcReturns(d) {
const tbody = document.getElementById('sim-returns-tbody');
if (!tbody || !d.assets.length) return;
const capital = parseFloat(d.capital) || 0;
const horizonMap = { '1m': 1/12, '3m': 0.25, '6m': 0.5, '1y': 1, '3y': 3, '5y': 5 };
const years = horizonMap[d.horizon] || 1;
const bear = parseFloat(d.scenarios.bear) / 100;
const base = parseFloat(d.scenarios.base) / 100;
const bull = parseFloat(d.scenarios.bull) / 100;
const cur = d.currency === 'CNY' ? '¥' : '$';
function calcProfit(invest, rate, yrs) { return invest * Math.pow(1 + rate, yrs) - invest; }
function sCell(v, invest) {
const p = invest ? (v / invest * 100).toFixed(1) : '0.0';
const sign = v >= 0 ? '+' : '';
const cls = v >= 0 ? 'sim-ret-pos' : 'sim-ret-neg';
return `<span class="${cls}">${sign}${cur}${fmtNum(Math.abs(v))}<br><small>${sign}${p}%</small></span>`;
}
let totBear = 0, totBase = 0, totBull = 0, totInvest = 0;
// Render scenario columns immediately
tbody.innerHTML = d.assets.map(a => {
const invest = capital * (parseFloat(a.pct)||0) / 100;
const pb = calcProfit(invest, bear, years);
const pn = calcProfit(invest, base, years);
const pu = calcProfit(invest, bull, years);
totBear += pb; totBase += pn; totBull += pu; totInvest += invest;
const rid = 'simreal-' + a.symbol.replace(/[^a-z0-9]/gi,'_');
const realCell = a.entryPrice
? `<td id="${rid}"><span style="color:var(--dimmed);font-size:0.72rem">拉取中…</span></td>`
: `<td style="color:var(--dimmed);font-size:0.72rem">无买入价</td>`;
return `<tr>
<td><strong>${a.symbol}</strong>${a.alias ? `<br><small style="color:var(--muted)">${a.alias}</small>` : ''}</td>
<td>${cur}${fmtNum(invest)}</td>
${realCell}
<td>${sCell(pb, invest)}</td>
<td>${sCell(pn, invest)}</td>
<td>${sCell(pu, invest)}</td>
</tr>`;
}).join('');
tbody.innerHTML += `<tr class="total-row">
<td>合计</td>
<td>${cur}${fmtNum(totInvest)}</td>
<td id="simreal-total">—</td>
<td>${sCell(totBear, totInvest)}</td>
<td>${sCell(totBase, totInvest)}</td>
<td>${sCell(totBull, totInvest)}</td>
</tr>`;
// Async: fetch live prices for real P&L column
const realResults = new Array(d.assets.length).fill(null);
let fetched = 0;
d.assets.forEach(async (a, idx) => {
if (!a.entryPrice) { fetched++; return; }
const rid = 'simreal-' + a.symbol.replace(/[^a-z0-9]/gi,'_');
const el = document.getElementById(rid);
const info = await fetchPrice(a.symbol).catch(() => null);
fetched++;
if (!el) return;
if (!info) { el.innerHTML = '<span style="color:var(--dimmed);font-size:0.72rem">获取失败</span>'; return; }
const invest = capital * (parseFloat(a.pct)||0) / 100;
const realPnl = invest * (info.price - a.entryPrice) / a.entryPrice;
realResults[idx] = realPnl;
el.innerHTML = sCell(realPnl, invest);
// Update total row when all fetched
if (fetched === d.assets.length) {
const totEl = document.getElementById('simreal-total');
if (totEl) {
const validResults = realResults.filter(r => r !== null);
if (validResults.length) {
const totReal = validResults.reduce((s,v) => s+v, 0);
totEl.innerHTML = sCell(totReal, totInvest);
}
}
}
});
}
function simUpdate() {
const d = simLoad();
d.capital = parseFloat(document.getElementById('sim-capital').value) || 10000;
d.currency = document.getElementById('sim-currency').value;
d.scenarios.bear = parseFloat(document.getElementById('sim-bear').value) || -20;
d.scenarios.base = parseFloat(document.getElementById('sim-base').value) || 8;
d.scenarios.bull = parseFloat(document.getElementById('sim-bull').value) || 25;
simSave(d);
simRenderAssets(d);
simCalcReturns(d);
}
function simSetHorizon(btn, h) {
const d = simLoad();
d.horizon = h;
simSave(d);
document.querySelectorAll('.sim-hbtn').forEach(b => b.classList.toggle('active', b.dataset.h === h));
simCalcReturns(d);
}
async function simAddAsset() {
const sym = (document.getElementById('sim-sym').value || '').trim().toUpperCase();
const alias = (document.getElementById('sim-alias').value || '').trim();
const pct = parseFloat(document.getElementById('sim-pct').value) || 0;
const manualEntry = parseFloat(document.getElementById('sim-entry').value) || null;
if (!sym) return;
const d = simLoad();
if (d.assets.find(a => a.symbol === sym)) { alert('该资产已在列表中'); return; }
let entryPrice = manualEntry;
if (!entryPrice) {
const btn = document.querySelector('#panel-sim .sim-add-row button');
if (btn) { btn.textContent = '抓取中…'; btn.disabled = true; }
const info = await fetchPrice(sym).catch(() => null);
if (btn) { btn.textContent = ' 添加'; btn.disabled = false; }
entryPrice = info ? info.price : null;
if (!entryPrice) { alert(`无法获取 ${sym} 当前价格,请手动填入买入价`); return; }
}
d.assets.push({ symbol: sym, alias, pct, entryPrice, entryDate: new Date().toISOString().slice(0,10) });
simSave(d);
document.getElementById('sim-sym').value = '';
document.getElementById('sim-alias').value = '';
document.getElementById('sim-pct').value = '';
document.getElementById('sim-entry').value = '';
simRender();
}
function simRemoveAsset(idx) {
const d = simLoad();
d.assets.splice(idx, 1);
simSave(d);
simRender();
}
function simUpdatePct(idx, val) {
const d = simLoad();
d.assets[idx].pct = parseFloat(val) || 0;
simSave(d);
simRenderAssets(d);
simCalcReturns(d);
}
function simReset() {
if (!confirm('确认重置模拟器数据?')) return;
localStorage.removeItem(lsSIM());
simRender();
}
// Init personal dashboard on load
document.addEventListener('DOMContentLoaded', function() {
profileRenderSelect();
wlRender();
pfRender();
simRender();
// Enter key triggers add
document.getElementById('wl-name').addEventListener('keydown', e => { if(e.key==='Enter') wlAdd(); });
document.getElementById('pf-cost').addEventListener('keydown', e => { if(e.key==='Enter') pfAdd(); });
});
// ── Reading progress bar ──────────────────────────────────────────────────────────
(function() {
const bar = document.getElementById('reading-progress');
if (!bar) return;
window.addEventListener('scroll', function() {
const scrolled = window.scrollY;
const total = document.documentElement.scrollHeight - window.innerHeight;
bar.style.width = (total > 0 ? (scrolled / total * 100) : 0) + '%';
}, { passive: true });
})();
// ── Back-to-top FAB visibility ───────────────────────────────────────────────────
(function() {
const btn = document.getElementById('fab-top');
if (!btn) return;
window.addEventListener('scroll', function() {
btn.classList.toggle('visible', window.scrollY > 400);
}, { passive: true });
})();
// ── Share / copy URL ────────────────────────────────────────────────────────────
function shareOrCopy() {
const url = window.location.href;
const toast = document.getElementById('share-toast');
if (navigator.share) {
navigator.share({ title: '金融日报 | Financial Daily', url });
} else {
navigator.clipboard.writeText(url).then(function() {
toast.classList.add('show');
setTimeout(function() { toast.classList.remove('show'); }, 2000);
});
}
}
// ── Jump nav active highlight on scroll ────────────────────────────────────────
(function() {
const sections = document.querySelectorAll('.sec-anchor[id]');
const links = document.querySelectorAll('.jump-nav a');
if (!sections.length || !links.length) return;
const obs = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
links.forEach(function(l) { l.classList.remove('active'); });
const a = document.querySelector('.jump-nav a[href="#' + entry.target.id + '"]');
if (a) a.classList.add('active');
}
});
}, { rootMargin: '-20% 0px -70% 0px' });
sections.forEach(function(s) { obs.observe(s); });
})();
// ── Dismiss subscribe strip if already dismissed ────────────────────────────
(function() {
if (localStorage.getItem('fd_sub_dismissed')) {
var el = document.getElementById('subscribe-strip');
if (el) el.style.display = 'none';
}
})();
// ── Subscriber count (Telegram) ───────────────────────────────────────
(function loadSubCount() {
const el = document.getElementById('subscriber-count');
if (!el) return;
fetch('data/investment-subscribers.json')
.then(r => r.json())
.then(d => {
const count = Object.values(d.subscribers || {}).filter(s => s.active).length;
if (count > 0) el.textContent = `📱 ${count} 人已订阅Telegram早报`;
})
.catch(() => {});
})();
// ── AI 操盘实验(多模型对比)─────────────────────────────────────────
(function loadAIPortfolio() {
const fmt$ = v => '$' + v.toLocaleString('en-US', {minimumFractionDigits:2, maximumFractionDigits:2});
const fmtPct = v => (v >= 0 ? '+' : '') + v.toFixed(2) + '%';
function renderModelDetail(modelId, pf, contest) {
const history = pf.history || [];
const latest = history[history.length - 1] || {};
const holdings = pf.holdings || [];
const startCap = contest.start_capital || 10000;
const pv = latest.portfolio_value || 0;
const bv = latest.baseline_value || 0;
const cash = latest.cash || 0;
const positions = latest.positions || {};
const trades = latest.trades || [];
let html = '';
// 持仓明细
html += `<div style="font-size:0.72rem;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);margin-bottom:8px;">📊 当前持仓</div>`;
html += `<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:14px;">`;
Object.entries(positions).forEach(([t, pos]) => {
const h = holdings.find(x => x.ticker === t);
const avg = h ? h.avg_cost : pos.price;
const pl = pos.price - avg;
const plP = avg > 0 ? pl / avg * 100 : 0;
const pct = pv > 0 ? pos.value / pv * 100 : 0;
const c = pl >= 0 ? 'var(--up)' : 'var(--down)';
html += `<div style="display:flex;align-items:center;gap:8px;padding:5px 8px;background:rgba(255,255,255,0.03);border-radius:6px;font-size:0.79rem;">
<span style="font-family:var(--mono);font-weight:600;min-width:44px;color:var(--accent);">${t}</span>
<span style="color:var(--muted);min-width:46px;">${pos.shares}股</span>
<span style="font-family:var(--mono);min-width:66px;">$${pos.price.toFixed(2)}</span>
<span style="font-family:var(--mono);min-width:72px;">${fmt$(pos.value)}</span>
<span style="color:${c};min-width:62px;">${(pl>=0?'+':'')}${fmtPct(plP)}</span>
<div style="flex:1;height:3px;background:rgba(255,255,255,0.06);border-radius:2px;"><div style="width:${Math.min(pct,100).toFixed(1)}%;height:100%;background:var(--accent);border-radius:2px;"></div></div>
<span style="color:var(--muted);min-width:34px;text-align:right;">${pct.toFixed(1)}%</span>
</div>`;
});
if (cash > 0) {
const cp = pv > 0 ? cash / pv * 100 : 0;
html += `<div style="display:flex;align-items:center;gap:8px;padding:5px 8px;background:rgba(255,255,255,0.03);border-radius:6px;font-size:0.79rem;">
<span style="font-family:var(--mono);font-weight:600;min-width:44px;color:#ffb300;">CASH</span>
<span style="color:var(--muted);min-width:46px;">—</span>
<span style="font-family:var(--mono);min-width:66px;">—</span>
<span style="font-family:var(--mono);min-width:72px;">${fmt$(cash)}</span>
<span style="color:var(--muted);min-width:62px;">现金</span>
<div style="flex:1;height:3px;background:rgba(255,255,255,0.06);border-radius:2px;"><div style="width:${Math.min(cp,100).toFixed(1)}%;height:100%;background:#ffb300;border-radius:2px;"></div></div>
<span style="color:var(--muted);min-width:34px;text-align:right;">${cp.toFixed(1)}%</span>
</div>`;
}
html += '</div>';
// 交易记录
if (trades.length) {
html += `<div style="font-size:0.72rem;text-transform:uppercase;letter-spacing:0.08em;color:var(--muted);margin-bottom:8px;">📋 今日交易</div>`;
html += trades.map(t => {
const ic = t.action==='BUY'?'🟢':t.action==='SELL'?'🔴':'🟡';
const c2 = t.action==='BUY'?'var(--up)':t.action==='SELL'?'var(--down)':'var(--warn)';
return `<div style="padding:5px 0;border-bottom:1px solid var(--border);font-size:0.8rem;">${ic} <strong style="color:${c2};">${t.action} ${t.ticker}</strong> ${t.shares}股 @ $${(t.price||0).toFixed(2)} <span style="color:var(--muted);">${t.reason||''}</span></div>`;
}).join('');
html += '<div style="margin-bottom:12px;"></div>';
}
// 备注
if (latest.note) {
html += `<div style="font-size:0.8rem;color:var(--muted);padding:8px 10px;background:rgba(0,212,170,0.04);border-left:2px solid var(--accent);border-radius:4px;">${latest.note}</div>`;
}
document.getElementById('ai-model-detail').innerHTML = html;
}
fetch('data/ai-portfolio.json?v=' + Date.now())
.then(r => r.json())
.then(data => {
const contest = data.contest || {};
const portfolios = data.portfolios || {};
const startCap = contest.start_capital || 10000;
const startDate = new Date(contest.start_date || '2026-05-13');
// 计算排名
const ranked = Object.entries(portfolios).map(([id, pf]) => {
const hist = pf.history || [];
const latest = hist[hist.length - 1] || {};
const pv = latest.portfolio_value || startCap;
const bv = latest.baseline_value || startCap;
const d = new Date(latest.date || contest.start_date);
const days = Math.round((d - startDate) / 86400000) + 1;
return { id, pf, pv, bv, days, latest };
}).sort((a, b) => b.pv - a.pv);
// 排行榜
const lbEl = document.getElementById('ai-leaderboard');
// 标题行:说明这是累计净值
lbEl.innerHTML = `<div style="font-size:0.72rem;color:var(--muted);margin-bottom:8px;">📅 累计净值 — 初始资金 ${fmt$(startCap)},自 ${contest.start_date} 起</div>`;
lbEl.innerHTML += ranked.map((r, i) => {
const pv = r.pv;
const bv = r.bv;
const pnl = pv - startCap;
const ret = pnl / startCap * 100;
const alpha = pv - bv;
const alphaP = bv > 0 ? alpha / bv * 100 : 0;
const retC = ret >= 0 ? 'var(--up)' : 'var(--down)';
const alpC = alpha >= 0 ? 'var(--up)' : 'var(--down)';
const medal = i===0 ? '🥇' : i===1 ? '🥈' : '🥉';
const pf = r.pf;
return `<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;background:rgba(255,255,255,0.04);border:1px solid var(--border);border-radius:8px;">
<span style="font-size:1.2rem;min-width:28px;">${medal}</span>
<span style="font-size:1.1rem;">${pf.emoji||'🤖'}</span>
<div style="flex:1;">
<div style="font-weight:600;font-size:0.9rem;">${pf.display_name||r.id}</div>
<div style="font-size:0.75rem;color:var(--muted);">${r.latest.note||''}</div>
</div>
<div style="text-align:right;min-width:90px;">
<div style="font-family:var(--mono);font-weight:600;font-size:0.95rem;">${fmt$(pv)}</div>
<div style="font-size:0.72rem;color:var(--muted);">累计净值</div>
</div>
<div style="text-align:right;min-width:90px;">
<div style="font-family:var(--mono);font-size:0.9rem;font-weight:600;color:${retC};">${(pnl>=0?'+':'')}${fmt$(pnl)}</div>
<div style="font-size:0.72rem;color:${retC};">${(ret>=0?'+':'')}${ret.toFixed(2)}% 累计</div>
</div>
<div style="text-align:right;min-width:80px;">
<div style="font-family:var(--mono);font-size:0.85rem;color:${alpC};">${(alpha>=0?'+':'')}${fmt$(alpha)}</div>
<div style="font-size:0.75rem;color:var(--muted);">vs SPY</div>
</div>
</div>`;
}).join('');
// SPY 基线行
const anyLatest = ranked[0]?.latest || {};
const spyVal = anyLatest.baseline_value || startCap;
const spyPnl = spyVal - startCap;
const spyRet = spyPnl / startCap * 100;
const spyC = spyRet >= 0 ? 'var(--up)' : 'var(--down)';
lbEl.innerHTML += `<div style="display:flex;align-items:center;gap:10px;padding:10px 12px;background:rgba(255,255,255,0.02);border:1px solid var(--border);border-radius:8px;opacity:0.7;">
<span style="font-size:1.2rem;min-width:28px;">📊</span>
<span style="font-size:1.1rem;">—</span>
<div style="flex:1;"><div style="font-weight:600;font-size:0.9rem;">SPY 基线(买入持有)</div><div style="font-size:0.75rem;color:var(--muted);">S&amp;P 500 ETF · ${contest.baseline?.shares||13.5296} 股</div></div>
<div style="text-align:right;min-width:90px;">
<div style="font-family:var(--mono);font-weight:600;font-size:0.95rem;">${fmt$(spyVal)}</div>
<div style="font-size:0.72rem;color:var(--muted);">累计净值</div>
</div>
<div style="text-align:right;min-width:90px;">
<div style="font-family:var(--mono);font-size:0.9rem;font-weight:600;color:${spyC};">${(spyPnl>=0?'+':'')}${fmt$(spyPnl)}</div>
<div style="font-size:0.72rem;color:${spyC};">${(spyRet>=0?'+':'')}${spyRet.toFixed(2)}% 累计</div>
</div>
<div style="text-align:right;min-width:80px;">
<div style="font-family:var(--mono);font-size:0.85rem;color:var(--muted);">—</div>
<div style="font-size:0.75rem;color:var(--muted);">基准</div>
</div>
</div>`;
// 模型 Tab
const tabsEl = document.getElementById('ai-model-tabs');
let activeModel = ranked[0]?.id;
function setActiveTab(id) {
activeModel = id;
tabsEl.querySelectorAll('button').forEach(b => {
b.style.background = b.dataset.id === id ? 'rgba(0,212,170,0.15)' : 'rgba(255,255,255,0.04)';
b.style.borderColor = b.dataset.id === id ? 'var(--accent)' : 'var(--border)';
b.style.color = b.dataset.id === id ? 'var(--accent)' : 'var(--text)';
});
const pf = portfolios[id];
if (pf) renderModelDetail(id, pf, contest);
}
tabsEl.innerHTML = ranked.map(r => {
const pf = r.pf;
return `<button data-id="${r.id}" onclick="(function(id){window._aiSetTab&&window._aiSetTab(id)})('${r.id}')" style="padding:6px 12px;border-radius:6px;border:1px solid var(--border);background:rgba(255,255,255,0.04);color:var(--text);cursor:pointer;font-size:0.8rem;">${pf.emoji||'🤖'} ${pf.display_name||r.id}</button>`;
}).join('');
window._aiSetTab = setActiveTab;
setActiveTab(activeModel);
// 历史对比表
const histEl = document.getElementById('ai-history-table');
const allDates = [...new Set(ranked.flatMap(r => (r.pf.history||[]).map(h => h.date)))].sort().reverse();
if (allDates.length > 1) {
const headers = ['<th style="text-align:left;padding:4px 6px;font-size:0.72rem;">日期</th>',
...ranked.map(r => `<th style="text-align:right;padding:4px 6px;font-size:0.72rem;">${r.pf.emoji||'📊'} ${r.pf.display_name||r.id}</th>`),
'<th style="text-align:right;padding:4px 6px;font-size:0.72rem;">SPY 基线</th>'
].join('');
const subHeaders = ['<th style="text-align:left;padding:2px 6px;font-size:0.65rem;color:var(--muted);">日期</th>',
...ranked.map(() => '<th style="text-align:right;padding:2px 6px;font-size:0.65rem;color:var(--muted);">净值 / 今日盈亏</th>'),
'<th style="text-align:right;padding:2px 6px;font-size:0.65rem;color:var(--muted);">净值 / 今日盈亏</th>'
].join('');
const rows = allDates.map((date, dateIndex) => {
const prevDate = allDates[dateIndex + 1]; // previous trading day (sorted descending)
const cells = ranked.map(r => {
const rec = (r.pf.history||[]).find(h => h.date === date);
if (!rec) return '<td style="text-align:right;padding:4px 6px;color:var(--muted);">—</td>';
const pv = rec.portfolio_value;
const prevRec = prevDate ? (r.pf.history||[]).find(h => h.date === prevDate) : null;
const prevVal = prevRec ? prevRec.portfolio_value : startCap;
const dailyPnl = pv - prevVal;
const dailyRet = dailyPnl / prevVal * 100;
const c = dailyRet >= 0 ? 'var(--up)' : 'var(--down)';
return `<td style="text-align:right;padding:4px 6px;"><div style="font-family:var(--mono);font-size:0.8rem;font-weight:600;">${fmt$(pv)}</div><div style="font-size:0.72rem;color:${c};">${(dailyPnl>=0?'+':'')}${fmt$(dailyPnl)} (${(dailyRet>=0?'+':'')}${dailyRet.toFixed(2)}% 今日)</div></td>`;
}).join('');
const spyRec = (ranked[0]?.pf.history||[]).find(h => h.date === date);
const spyV = spyRec ? spyRec.baseline_value : startCap;
const spyPrevRec = prevDate ? (ranked[0]?.pf.history||[]).find(h => h.date === prevDate) : null;
const spyPrevV = spyPrevRec ? spyPrevRec.baseline_value : startCap;
const spyDailyPnl = spyV - spyPrevV;
const spyDailyR = spyDailyPnl / spyPrevV * 100;
const sc = spyDailyR >= 0 ? 'var(--up)' : 'var(--down)';
return `<tr style="border-top:1px solid var(--border);"><td style="padding:4px 6px;color:var(--muted);font-size:0.8rem;">${date}</td>${cells}<td style="text-align:right;padding:4px 6px;"><div style="font-family:var(--mono);font-size:0.8rem;font-weight:600;">${fmt$(spyV)}</div><div style="font-size:0.72rem;color:${sc};">${(spyDailyPnl>=0?'+':'')}${fmt$(spyDailyPnl)} (${(spyDailyR>=0?'+':'')}${spyDailyR.toFixed(2)}% 今日)</div></td></tr>`;
}).join('');
histEl.innerHTML = `<div style="font-size:0.72rem;color:var(--muted);margin-bottom:6px;">📈 净值走势(自 ${contest.start_date} 起,初始 ${fmt$(startCap)}</div><table style="width:100%;border-collapse:collapse;"><thead><tr style="color:var(--text);border-bottom:1px solid var(--border);">${headers}</tr></thead><tbody>${rows}</tbody></table>`;
} else {
histEl.innerHTML = '<span style="color:var(--muted);font-size:0.8rem;">天数超过1天后显示对比曲线…</span>';
}
document.getElementById('ai-portfolio-loading').style.display='none';
document.getElementById('ai-portfolio-content').style.display='';
})
.catch(()=>{ const el=document.getElementById('ai-portfolio-loading'); if(el) el.textContent='数据加载失败'; });
})();
// ── Visitor counter (Cloudflare Worker + KV) ──────────────────────────
document.addEventListener('DOMContentLoaded', function () {
const WORKER = 'https://finance-daily-counter.yangbai0110.workers.dev';
const LS_KEY = 'fd_visited';
const visEl = document.getElementById('footer-visitors');
const pvEl = document.getElementById('footer-pageviews');
function fmt(n) { return Number(n).toLocaleString('en-US'); }
function animate(el, target) {
if (!el) return;
if (target === 0) { el.textContent = '0'; return; }
const dur = 900; let t0 = null;
const step = ts => {
if (!t0) t0 = ts;
const p = Math.min((ts - t0) / dur, 1);
el.textContent = fmt(Math.round((1 - Math.pow(1 - p, 3)) * target));
if (p < 1) requestAnimationFrame(step);
};
requestAnimationFrame(step);
}
const isNew = !localStorage.getItem(LS_KEY);
fetch(WORKER + (isNew ? '?newVisitor=1' : '?newVisitor=0'))
.then(r => r.json())
.then(data => {
localStorage.setItem(LS_KEY, '1');
animate(visEl, data.visitors || 0);
animate(pvEl, data.pageViews || 0);
})
.catch(() => {
if (visEl) visEl.textContent = '--';
if (pvEl) pvEl.textContent = '--';
});
});
</script>
<script>
// ─── Streak counter ────────────────────────────────────────────────────────
(function() {
var today = new Date().toISOString().slice(0,10);
var last = localStorage.getItem('fd_last_visit') || '';
var streak = parseInt(localStorage.getItem('fd_streak') || '0');
if (last !== today) {
var yesterday = new Date(Date.now() - 86400000).toISOString().slice(0,10);
streak = (last === yesterday) ? streak + 1 : 1;
localStorage.setItem('fd_last_visit', today);
localStorage.setItem('fd_streak', streak);
}
if (streak >= 2) {
var meta = document.querySelector('.header-meta');
if (meta) {
var sb = document.createElement('span');
sb.className = 'streak-badge';
sb.title = '连续访问天数';
sb.innerHTML = '🔥 ' + streak + ' 天';
meta.appendChild(sb);
}
}
})();
// ─── Mark first breaking news as NEW ────────────────────────────────────────
document.querySelectorAll('.news-item.breaking, .news-item.major').forEach(function(n, i) {
if (i < 2) {
var title = n.querySelector('.news-title');
if (title) {
var badge = document.createElement('span');
badge.className = 'new-badge';
badge.textContent = '新';
badge.style.cssText = 'display:inline-block;font-size:.58rem;font-family:var(--mono);padding:1px 5px;border-radius:3px;background:rgba(0,212,170,.15);color:var(--accent);border:1px solid rgba(0,212,170,.3);margin-right:6px;vertical-align:middle;';
title.insertBefore(badge, title.firstChild);
}
}
});
// ─── News toggle ────────────────────────────────────────────────────────────
function toggleNews(el) { el.classList.toggle('expanded'); }
</script>
<!-- Floating action cluster -->
<div class="fab-cluster">
<button class="fab" id="fab-share" title="分享此页" onclick="shareOrCopy()">🔗</button>
<button class="fab" id="fab-top" title="回到顶部" onclick="window.scrollTo({top:0,behavior:'smooth'})"></button>
</div>
<div id="share-toast">✅ 链接已复制</div>
<!-- =======================================================
INTRO ANIMATION
======================================================= -->
<script>
(function() {
'use strict';
// Skip if user already visited this session
if (sessionStorage.getItem('fd-intro-done')) {
var ov = document.getElementById('intro-overlay');
if (ov) ov.classList.add('gone');
return;
}
var canvas = document.getElementById('intro-canvas');
var overlay = document.getElementById('intro-overlay');
if (!canvas || !overlay) return;
var ctx = canvas.getContext('2d');
var W, H;
function resize() {
W = canvas.width = window.innerWidth;
H = canvas.height = window.innerHeight;
}
resize();
window.addEventListener('resize', resize);
// --- Candlestick data (simulated) ---
var candles = [];
for (var i = 0; i < 60; i++) {
var base = 400 + Math.sin(i * 0.18) * 40 + Math.random() * 20;
var o = base + (Math.random() - 0.5) * 15;
var c = base + (Math.random() - 0.5) * 15;
var h = Math.max(o, c) + Math.random() * 12;
var l = Math.min(o, c) - Math.random() * 12;
candles.push({ o: o, c: c, h: h, l: l });
}
// --- Streaming ticker lines ---
var tickers = [
'NVDA +2.47%', 'SPY +0.31%', 'QQQ +0.19%', 'AAPL -0.12%', 'TSLA +1.04%',
'META +0.88%', 'MSFT +0.55%', 'BTC +0.24%', 'GLD -0.42%', 'AMD +3.21%',
'GOOGL +0.37%', 'AMZN +0.62%', 'TLT -0.35%', 'INTC +4.60%', 'AVGO +1.14%',
'VIX 16.76', 'DXY 99.25', 'WTI $98.05', 'AU $4524', 'ETH +1.18%'
];
var streamLines = [];
for (var j = 0; j < 18; j++) {
streamLines.push({
x: Math.random() * W,
y: Math.random() * H,
speed: 0.3 + Math.random() * 0.5,
text: tickers[j % tickers.length],
opacity: 0.04 + Math.random() * 0.12,
size: 10 + Math.floor(Math.random() * 4)
});
}
var progress = document.getElementById('intro-progress');
var startTime = performance.now();
var DURATION = 3500; // ms total
var animDone = false;
var rafId;
function draw(now) {
if (animDone) return;
var elapsed = now - startTime;
var t = Math.min(elapsed / DURATION, 1);
ctx.clearRect(0, 0, W, H);
// -- Background gradient --
var grad = ctx.createRadialGradient(W/2, H/2, 0, W/2, H/2, Math.max(W,H) * 0.7);
grad.addColorStop(0, 'rgba(7,20,35,.85)');
grad.addColorStop(1, 'rgba(3,6,9,1)');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, W, H);
// -- Grid lines --
ctx.strokeStyle = 'rgba(0,212,170,0.04)';
ctx.lineWidth = 1;
var step = 60;
for (var gx = 0; gx < W; gx += step) {
ctx.beginPath(); ctx.moveTo(gx, 0); ctx.lineTo(gx, H); ctx.stroke();
}
for (var gy = 0; gy < H; gy += step) {
ctx.beginPath(); ctx.moveTo(0, gy); ctx.lineTo(W, gy); ctx.stroke();
}
// -- Streaming tickers --
ctx.font = '11px JetBrains Mono, monospace';
streamLines.forEach(function(l) {
l.y -= l.speed;
if (l.y < -20) { l.y = H + 20; l.x = Math.random() * W; l.text = tickers[Math.floor(Math.random()*tickers.length)]; }
var isUp = l.text.indexOf('-') === -1 || l.text.indexOf('+') !== -1;
ctx.fillStyle = isUp
? 'rgba(0,230,118,' + l.opacity + ')'
: 'rgba(255,82,82,' + l.opacity + ')';
ctx.fillText(l.text, l.x, l.y);
});
// -- Candlestick chart (bottom area) --
var revealCandles = Math.floor(t * candles.length);
var cW = Math.min(W * 0.7, 600);
var cH = 90;
var cX = (W - cW) / 2;
var cY = H * 0.72;
var maxP = Math.max.apply(null, candles.map(function(c){return c.h;}));
var minP = Math.min.apply(null, candles.map(function(c){return c.l;}));
var range = maxP - minP || 1;
var barW = cW / candles.length * 0.7;
ctx.globalAlpha = Math.min(t * 3, 1) * 0.7;
for (var ci = 0; ci < revealCandles; ci++) {
var cd = candles[ci];
var cx = cX + (ci + 0.5) * (cW / candles.length);
var cy_o = cY + (1 - (cd.o - minP) / range) * cH;
var cy_c = cY + (1 - (cd.c - minP) / range) * cH;
var cy_h = cY + (1 - (cd.h - minP) / range) * cH;
var cy_l = cY + (1 - (cd.l - minP) / range) * cH;
var isGreen = cd.c >= cd.o;
ctx.strokeStyle = isGreen ? '#00e676' : '#ff5252';
ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(cx, cy_h); ctx.lineTo(cx, cy_l); ctx.stroke();
ctx.fillStyle = isGreen ? '#00e676' : '#ff5252';
var bh = Math.abs(cy_c - cy_o);
ctx.fillRect(cx - barW/2, Math.min(cy_o, cy_c), barW, Math.max(bh, 1.5));
}
ctx.globalAlpha = 1;
// -- Progress bar --
if (progress) progress.style.width = (t * 100) + '%';
if (elapsed >= DURATION) {
dismissIntro();
return;
}
rafId = requestAnimationFrame(draw);
}
rafId = requestAnimationFrame(draw);
// -- Populate intro tickers from quotes.json --
fetch('data/quotes.json?' + Date.now())
.then(function(r){ return r.ok ? r.json() : null; })
.then(function(data) {
if (!data || !data.quotes) return;
var map = {};
data.quotes.forEach(function(q){ map[q.name] = q; });
var bindings = [
['it-spy', 'it-spy-chg', '标晥00'],
['it-qqq', 'it-qqq-chg', '纳斯达克'],
['it-btc', 'it-btc-chg', '比特币'],
['it-gld', 'it-gld-chg', '黄金现货'],
];
bindings.forEach(function(b){
var q = map[b[2]];
var el = document.getElementById(b[0]);
var chgEl = document.getElementById(b[1]);
if (!el || !q) return;
el.textContent = q.value || '—';
if (chgEl && q.change_pct) {
chgEl.textContent = (q.direction === 'up' ? '▲ ' : '▼ ') + q.change_pct;
chgEl.className = 'it-chg ' + q.direction;
}
});
}).catch(function(){});
window.dismissIntro = function() {
if (animDone) return;
animDone = true;
cancelAnimationFrame(rafId);
overlay.classList.add('fade-out');
sessionStorage.setItem('fd-intro-done', '1');
setTimeout(function(){ overlay.classList.add('gone'); }, 750);
};
// Keyboard shortcut: any key skips intro
document.addEventListener('keydown', function handler(e) {
dismissIntro();
document.removeEventListener('keydown', handler);
}, { once: true });
})();
</script>
<!-- =======================================================
I18N / LANGUAGE TOGGLE
======================================================= -->
<script>
(function() {
'use strict';
var LANG = {
zh: {
'nav-archive': '归档',
'nav-summary': '📊 大势',
'nav-ai-trading': '🤖 AI操盘',
'nav-news': '📰 要闻',
'nav-watchlist': '🎯 AI分析',
'nav-macro': '📈 宏观',
'nav-earnings': '💼 财报',
'nav-sectors': '🏭 行业',
'nav-debate': '⚔️ 辩论',
'nav-calendar': '📅 日历',
'nav-my': '⭐ 我的',
},
en: {
'nav-archive': 'Archive',
'nav-summary': '📊 Market',
'nav-ai-trading': '🤖 AI Trade',
'nav-news': '📰 News',
'nav-watchlist': '🎯 Watchlist',
'nav-macro': '📈 Macro',
'nav-earnings': '💼 Earnings',
'nav-sectors': '🏭 Sectors',
'nav-debate': '⚔️ Bull/Bear',
'nav-calendar': '📅 Calendar',
'nav-my': '⭐ My Dashboard',
}
};
// Section label maps (by section id + .section-label text)
var SECTION_LABELS = {
zh: {
'sec-news': '📰 市场要闻 · Market News',
'sec-ai-trading': '🤖 AI 操盘实验 · AI Trading Challenge',
'sec-watchlist': '🎯 AI 决策仪表盘 · AI Watchlist',
'sec-macro': '📈 宏观指标 · Macro',
'sec-debate': '⚔️ 多空辩论 · Bull vs Bear',
'sec-earnings': '💼 财报追踪 · Earnings',
'sec-sectors': '🏭 板块表现 · Sectors',
'sec-replay': '🎥 大盘复盘 · Replay',
'sec-calendar': '📅 本周日程 · Calendar',
'sec-leaders': '👔 领袖观点 · Leaders',
'sec-banks': '🏦 幂行动态 · Central Banks',
},
en: {
'sec-news': '📰 Market News',
'sec-ai-trading': '🤖 AI Trading Challenge',
'sec-watchlist': '🎯 AI Watchlist',
'sec-macro': '📈 Macro Indicators',
'sec-debate': '⚔️ Bull vs Bear',
'sec-earnings': '💼 Earnings Tracker',
'sec-sectors': '🏭 Sector Performance',
'sec-replay': '🎥 Market Replay',
'sec-calendar': '📅 Economic Calendar',
'sec-leaders': '👔 Market Leaders',
'sec-banks': '🏦 Central Banks',
}
};
// Static UI strings (selectors → text)
var STATIC_EN = [
['.site-title', 'Financial Daily'],
['.site-sub', 'AI-Powered · Daily Briefing'],
['.subscribe-strip-body strong', 'Subscribe to Daily Briefing'],
['.subscribe-strip-body span', 'Updated twice daily, every trading day'],
['.btn-sub-email', '📧 Email'],
['#pod-play', '▶ Play'],
['.podcast-title', 'Financial Daily · Today\'s Podcast'],
['.my-drawer-toggle span:first-child', '⭐ My Dashboard'],
['#ptab-wl', '📋 Watchlist'],
['#ptab-pf', '💼 Portfolio P&L'],
['#ptab-sim', '📊 Simulator'],
['#wl-empty', 'No stocks yet. Enter a symbol to start tracking →'],
['#pf-empty', 'No positions yet. Add holdings to track P&L →'],
['.footer-inner span:nth-child(2)', 'AI-generated content for informational purposes only. Not investment advice.'],
];
var STATIC_ZH = [
['.site-title', '金融日报'],
['.site-sub', 'Financial Daily'],
['.subscribe-strip-body strong', '订阅每日金融早报'],
['.subscribe-strip-body span', '每个交易日自动更新,开盘前 + 收盘后各一次'],
['.btn-sub-email', '📧 邮件'],
['#pod-play', '▶ 播放'],
['.podcast-title', '金融日报早报 · 今日播客'],
['.my-drawer-toggle span:first-child', '⭐ 我的工作台 · My Dashboard'],
['#ptab-wl', '📋 自选股'],
['#ptab-pf', '💼 持仓盈亏'],
['#ptab-sim', '📊 模拟器'],
['#wl-empty', '还没有自选股,输入代码开始追踪 →'],
['#pf-empty', '还没有持仓记录,输入持仓开始计算浮盈浮亏 →'],
['.footer-inner span:nth-child(2)', '内容由AI自动生成,仅供参考,不构成投资建议'],
];
function applyLang(lang) {
// Toggle body class
document.body.classList.remove('lang-zh', 'lang-en');
document.body.classList.add('lang-' + lang);
// Update toggle button active state
var elZH = document.getElementById('lang-zh');
var elEN = document.getElementById('lang-en');
if (elZH) elZH.classList.toggle('active', lang === 'zh');
if (elEN) elEN.classList.toggle('active', lang === 'en');
// data-i18n nav items
var map = LANG[lang];
document.querySelectorAll('[data-i18n]').forEach(function(el) {
var key = el.getAttribute('data-i18n');
if (map[key]) el.textContent = map[key];
});
// Section labels
var slMap = SECTION_LABELS[lang];
Object.entries(slMap).forEach(function(entry) {
var secId = entry[0], text = entry[1];
var sec = document.getElementById(secId);
if (!sec) return;
var lbl = sec.querySelector('.section-label');
if (lbl) lbl.childNodes.forEach(function(n){ if (n.nodeType === 3 && n.textContent.trim()) n.textContent = ' ' + text; });
});
// Static UI strings
var statics = lang === 'en' ? STATIC_EN : STATIC_ZH;
statics.forEach(function(pair) {
try {
var el = document.querySelector(pair[0]);
if (el) el.textContent = pair[1];
} catch(e) {}
});
// date format
var dateEl = document.getElementById('current-date');
if (dateEl) {
var now = new Date();
var opts = lang === 'en'
? { year: 'numeric', month: 'short', day: 'numeric', weekday: 'short' }
: { year: 'numeric', month: 'long', day: 'numeric', weekday: 'short' };
dateEl.textContent = now.toLocaleDateString(lang === 'en' ? 'en-US' : 'zh-CN', opts);
}
// AI portfolio section heading (dynamic)
var lbHdr = document.querySelector('#ai-portfolio-content > div:first-child');
if (lbHdr) lbHdr.innerHTML = lang === 'en'
? '🏆 Leaderboard <span style="font-size:.68rem;color:var(--dimmed);margin-left:6px;">Starting capital $10,000 · Baseline: SPY buy &amp; hold</span>'
: '🏆 排行榜 · Leaderboard <span style="font-size:.68rem;color:var(--dimmed);margin-left:6px;">初始资金 $10,000 · 基线 SPY买入持有</span>';
localStorage.setItem('fd-lang', lang);
// ── Google Translate for dynamic content ───────────────────
triggerGoogleTranslate(lang);
}
// ── Google Translate helper ─────────────────────────────────
var _gtRetries = 0;
function triggerGoogleTranslate(lang) {
var targetLang = lang === 'en' ? 'en' : 'zh-CN';
// Method 1: drive the hidden <select> that GT injects
function driveSelect() {
var sel = document.querySelector('.goog-te-combo');
if (sel) {
sel.value = targetLang;
sel.dispatchEvent(new Event('change', { bubbles: true }));
return true;
}
return false;
}
// Method 2: cookie + reload fallback
function cookieFallback() {
var exp = new Date();
exp.setTime(exp.getTime() + 30 * 24 * 60 * 60 * 1000);
var expStr = '; expires=' + exp.toUTCString() + '; path=/';
if (lang === 'en') {
document.cookie = 'googtrans=/zh-CN/en' + expStr;
document.cookie = 'googtrans=/zh-CN/en' + expStr + '; domain=.' + window.location.hostname;
} else {
document.cookie = 'googtrans=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC';
document.cookie = 'googtrans=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC; domain=.' + window.location.hostname;
}
// Small delay then reload so cookie takes effect
setTimeout(function() { window.location.reload(); }, 150);
}
// Try select-drive first; retry up to 8 times while GT loads
if (driveSelect()) { _gtRetries = 0; return; }
if (_gtRetries < 8) {
_gtRetries++;
setTimeout(function() { triggerGoogleTranslate(lang); }, 400);
} else {
// GT never loaded (e.g. blocked) — use cookie+reload
_gtRetries = 0;
cookieFallback();
}
}
window.toggleLang = function() {
var current = localStorage.getItem('fd-lang') || 'zh';
applyLang(current === 'zh' ? 'en' : 'zh');
};
// Apply saved lang on load (after DOM ready)
var savedLang = localStorage.getItem('fd-lang') || 'zh';
document.addEventListener('DOMContentLoaded', function() {
applyLang(savedLang);
});
// Also expose for external call after dynamic content loads
window.applyCurrentLang = function() {
applyLang(localStorage.getItem('fd-lang') || 'zh');
};
})();
</script>
</body>
</html>