Files
2026-06-22 23:27:56 +00:00

3345 lines
167 KiB
HTML
Raw Permalink 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="../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 down">
<div class="ticker-name">标普500</div>
<div class="ticker-value">7,472.79</div>
<div class="ticker-change down">▼ -0.37%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">纳斯达克综合指数</div>
<div class="ticker-value">26,166.60</div>
<div class="ticker-change down">▼ -1.32%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">道琼斯工业指数</div>
<div class="ticker-value">51,712.71</div>
<div class="ticker-change up">▲ +0.29%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">罗素2000</div>
<div class="ticker-value">3,004.40</div>
<div class="ticker-change up">▲ +0.83%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">上证综指</div>
<div class="ticker-value">4,164.00</div>
<div class="ticker-change up">▲ +1.81%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">恒生指数</div>
<div class="ticker-value">23,768.52</div>
<div class="ticker-change down">▼ -0.65%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">日经225</div>
<div class="ticker-value">72,353.96</div>
<div class="ticker-change up">▲ +1.55%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">德国DAX</div>
<div class="ticker-value">25,139.69</div>
<div class="ticker-change up">▲ +0.62%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">黄金现货</div>
<div class="ticker-value">4,190.32</div>
<div class="ticker-change up">▲ +0.93%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">WTI原油</div>
<div class="ticker-value">74.17</div>
<div class="ticker-change down">▼ -4.09%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">比特币</div>
<div class="ticker-value">120,000</div>
<div class="ticker-change up">▲ +1.69%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">美元指数</div>
<div class="ticker-value">105.2</div>
<div class="ticker-change up">▲ +0.29%</div>
</div>
<!-- INDICES:END -->
<!-- INDICES:END -->
<!-- duplicate for seamless loop -->
<!-- INDICES:START -->
<div class="ticker-card down">
<div class="ticker-name">标普500</div>
<div class="ticker-value">7,472.79</div>
<div class="ticker-change down">▼ -0.37%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">纳斯达克综合指数</div>
<div class="ticker-value">26,166.60</div>
<div class="ticker-change down">▼ -1.32%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">道琼斯工业指数</div>
<div class="ticker-value">51,712.71</div>
<div class="ticker-change up">▲ +0.29%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">罗素2000</div>
<div class="ticker-value">3,004.40</div>
<div class="ticker-change up">▲ +0.83%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">上证综指</div>
<div class="ticker-value">4,164.00</div>
<div class="ticker-change up">▲ +1.81%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">恒生指数</div>
<div class="ticker-value">23,768.52</div>
<div class="ticker-change down">▼ -0.65%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">日经225</div>
<div class="ticker-value">72,353.96</div>
<div class="ticker-change up">▲ +1.55%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">德国DAX</div>
<div class="ticker-value">25,139.69</div>
<div class="ticker-change up">▲ +0.62%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">黄金现货</div>
<div class="ticker-value">4,190.32</div>
<div class="ticker-change up">▲ +0.93%</div>
</div>
<div class="ticker-card down">
<div class="ticker-name">WTI原油</div>
<div class="ticker-value">74.17</div>
<div class="ticker-change down">▼ -4.09%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">比特币</div>
<div class="ticker-value">120,000</div>
<div class="ticker-change up">▲ +1.69%</div>
</div>
<div class="ticker-card up">
<div class="ticker-name">美元指数</div>
<div class="ticker-value">105.2</div>
<div class="ticker-change up">▲ +0.29%</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">17.28</span></span>
</div>
<div class="summary-headline">大科技回调拖累纳指跌1.3%,小盘股创历史新高</div>
<ul class="key-points"><li class="kp-item"><span class="kp-arrow"></span>科技巨头集体回调,通讯服务板块跌超3%</li><li class="kp-item"><span class="kp-arrow"></span>罗素2000首破3000,小盘股轮动启动</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">美股周一走势分化,道指微涨0.29%,标普500跌0.37%,纳指重挫1.32%。Alphabet因AI人才流失暴跌5%SpaceX连跌三日累计下挫16%。相比之下,罗素2000指数首次突破3000点大关,涨0.83%,显示市场资金正从大型科技股转向小盘股。美伊和平谈判取得进展,油价下跌4%至74美元,黄金反弹至4190美元。新任美联储主席Kevin Warsh在首次会议上放弃前瞻指引,暗示年内可能加息,VIX升至17.28。</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">Alphabet因AI人才流失暴跌5%,科技板块领跌</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>持有QQQ、科技ETF的投资者本周承压,建议关注回调后分批买入机会,长期AI趋势未变</div>
<div class="news-body-collapse">Alphabet周一暴跌5%,市值蒸发超1000亿美元,因其DeepMind AI部门关键人才离职。亚马逊跌4.8%,Meta跌2.3%,微软跌3%。通讯服务板块重挫3.37%,创2025年4月以来最大单日跌幅。科技巨头高昂的AI资本支出引发投资者担忧。</div>
<div class="news-footer">
<span class="importance-badge breaking">🔥 BREAKING</span>
<div class="tags"><span class="tag">#科技股</span><span class="tag">#AI</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">SpaceX连跌三日累计暴跌16%,IPO泡沫破裂</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>散户追高SpaceX IPO者损失惨重,提醒投资者警惕高估值IPO,耐心等待估值回归理性</div>
<div class="news-body-collapse">SpaceX股价周一再跌16.4%,连续第三日下挫,三天累计蒸发6000亿美元市值,较6月12日IPO以来已跌去近四分之一。公司宣布发行200亿美元债券引发抛售,CNBC Jim Cramer称'SpaceX无法维持meme地位'。尽管如此,股价仍较IPO价高31%。</div>
<div class="news-footer">
<span class="importance-badge breaking">🔥 BREAKING</span>
<div class="tags"><span class="tag">#IPO</span><span class="tag">#SpaceX</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">美伊和谈突破,油价暴跌4%创3月来新低</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>油价下跌利好通胀回落,持有能源股的投资者面临压力,但对整体经济和消费者是利好</div>
<div class="news-body-collapse">伊朗和美国在瑞士会谈取得'重大进展',同意在60天内达成最终和平协议框架。霍尔木兹海峡重新开放,周末仍有数百万桶原油通过。WTI原油暴跌4.09%至74.17美元,创3月初以来新低。美国财政部授权伊朗石油生产和销售60天,供应恢复预期推动油价大跌。</div>
<div class="news-footer">
<span class="importance-badge breaking">🔥 BREAKING</span>
<div class="tags"><span class="tag">#原油</span><span class="tag">#地缘政治</span></div>
</div>
</div>
<div class="news-item breaking" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot breaking"></span>
<div class="news-title">罗素2000首破3000点,小盘股轮动启动</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>小盘股补涨行情启动,持有IWM等小盘ETF的投资者迎来收获期,建议关注估值合理的中小盘股</div>
<div class="news-body-collapse">罗素2000指数周一涨0.83%,盘中触及3015.03点历史新高,收盘报3004.40点,首次站上3000点大关。今年以来涨幅已达43.8%,从去年52周低点2088.07反弹超44%。市场资金从大型科技股转向此前表现落后的小盘股,显示投资者寻求更广泛的市场敞口。</div>
<div class="news-footer">
<span class="importance-badge breaking">🔥 BREAKING</span>
<div class="tags"><span class="tag">#罗素2000</span><span class="tag">#小盘股</span></div>
</div>
</div>
<div class="news-item breaking" onclick="toggleNews(this)">
<div class="news-header">
<span class="imp-dot breaking"></span>
<div class="news-title">美联储主席Warsh放弃前瞻指引,暗示年内可能加息</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>加息预期升温利空股市,固定收益投资者可关注短期国债,股票投资者需降低杠杆控制风险</div>
<div class="news-body-collapse">新任美联储主席Kevin Warsh在6月17日首次FOMC会议后宣布终止前瞻指引传统,强调'前瞻指引不是我们该做的事'。点阵图显示19位官员中有9位预计年内至少加息一次,6位支持加息两次。Warsh将通胀归咎于前任Powell和特朗普的伊朗战争,强调美联储对抗通胀的决心'强烈、一致且明确'。</div>
<div class="news-footer">
<span class="importance-badge breaking">🔥 BREAKING</span>
<div class="tags"><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">中国对美关键矿产公司实施出口管制</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>中美科技脱钩加速,持有美国稀土概念股可能受益,但供应链重构将是长期过程</div>
<div class="news-body-collapse">中国周一对美国稀土企业MP Materials和USA Rare Earth实施出口管制。MP Materials运营美国唯一稀土矿,USA Rare Earth正在特朗普政府支持下建设国内供应链。两家公司股价小幅上涨。稀土是国防、芯片和汽车等战略产业的关键投入,中国寻求利用全球供应链主导地位作为美国贸易冲突筹码。</div>
<div class="news-footer">
<span class="importance-badge high">• HIGH</span>
<div class="tags"><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周三公布财报,与Anthropic达成重磅合作</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>Micron财报前大涨,看好AI基础设施的投资者可关注,但需警惕财报后获利回吐风险</div>
<div class="news-body-collapse">Micron股价周一飙升近7%,因宣布与AI开发商Anthropic达成重大合作协议,为其提供HBM4高带宽内存。分析师预计Micron Q3财季收入347亿美元,EPS 20美元,HBM业务到2028年将达1000亿美元规模。周三财报将成为AI基础设施需求的重要风向标。</div>
<div class="news-footer">
<span class="importance-badge high">• HIGH</span>
<div class="tags"><span class="tag">#财报</span><span class="tag">#AI芯片</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">美国拟对60国征收强迫劳动关税,中国在列</div>
<span class="news-expand-icon"></span>
</div>
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>新一轮关税威胁重现,进口商品价格或上涨,持有消费类股票需关注成本传导影响</div>
<div class="news-body-collapse">美国贸易代表办公室6月2日提议对60个经济体征收10%-12.5%的301条款关税,理由是这些国家未能禁止强迫劳动产品进口。中国、欧盟、日本等主要贸易伙伴均在列。中国商务部回应称反对'一切单边限制',欧盟称关税理由'不合理'。最高法院2月推翻IEEPA关税后,特朗普政府寻求通过301条款恢复关税。</div>
<div class="news-footer">
<span class="importance-badge high">• HIGH</span>
<div class="tags"><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">208.31</div><div class="wc-price-chg down">-1.1%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge HOLD">HOLD</span>
<span class="wc-score">评分 <span>72</span>/100</span>
</div>
<div class="wc-conclusion">AI龙头短期整固,中长期趋势未变</div>
<div class="wc-driver">Vera Rubin平台推动HBM4需求,但高估值面临调整压力</div>
<div class="wc-targets"><span class="wc-target-up">↑ 238</span><span class="wc-target-down">↓ 195</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">当前22倍PS估值偏高,建议等待回调至200美元附近分批建仓,长期持有者可持股不动</div>
<div class="tags" style="margin-top:8px"><span class="tag">#AI</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">505.32</div><div class="wc-price-chg down">-1.3%</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">大型科技股估值高企遭遇获利回吐,但AI基础设施投资持续</div>
<div class="wc-targets"><span class="wc-target-up">↑ 535</span><span class="wc-target-down">↓ 480</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">建议持有者保持仓位,新进投资者等待回调至490-500区间分批建仓</div>
<div class="tags" style="margin-top:8px"><span class="tag">#科技</span><span class="tag">#ETF</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">746.74</div><div class="wc-price-chg down">-0.4%</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">大型科技股回调被金融和小盘股部分抵消,整体估值偏高</div>
<div class="wc-targets"><span class="wc-target-up">↑ 780</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">建议保持中性配置,关注回调至730-740区间加仓机会,分散至小盘股和防御板块</div>
<div class="tags" style="margin-top:8px"><span class="tag">#大盘</span><span class="tag">#ETF</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">120,000</div><div class="wc-price-chg up">+1.7%</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">突破12万关口,牛市延续</div>
<div class="wc-driver">国会推进加密监管立法,机构通过ETF持续买入,市值超2.4万亿美元</div>
<div class="wc-targets"><span class="wc-target-up">↑ 135,000</span><span class="wc-target-down">↓ 108,000</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">激进投资者可逢回调至11.5-11.8万区间分批买入,保守者等待调整,止损设在10.5万</div>
<div class="tags" style="margin-top:8px"><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">5.03</div><div class="wc-price-chg up">+2.1%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge BUY">BUY</span>
<span class="wc-score">评分 <span>70</span>/100</span>
</div>
<div class="wc-conclusion">A股反弹延续,估值具吸引力</div>
<div class="wc-driver">宽松政策预期和经济数据改善推动,北向资金持续流入</div>
<div class="wc-targets"><span class="wc-target-up">↑ 5.50</span><span class="wc-target-down">↓ 4.70</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">建议5.0附近分批建仓,目标看至5.3-5.5,止损设在4.8以下</div>
<div class="tags" style="margin-top:8px"><span class="tag">#A股</span><span class="tag">#ETF</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,190.32</div><div class="wc-price-chg up">+0.9%</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">美伊和谈降低避险需求,但持续通胀和央行购金支撑价格</div>
<div class="wc-targets"><span class="wc-target-up">↑ 4,400</span><span class="wc-target-down">↓ 4,000</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">建议长期配置5-10%作为组合对冲工具,短期交易者可4150-4200区间逢低买入</div>
<div class="tags" style="margin-top:8px"><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">74.17</div><div class="wc-price-chg down">-4.1%</div></div>
</div>
<div class="wc-signal-row">
<span class="signal-badge SELL">SELL</span>
<span class="wc-score">评分 <span>35</span>/100</span>
</div>
<div class="wc-conclusion">和平进展重创油价,下行风险加大</div>
<div class="wc-driver">霍尔木兹海峡重开,伊朗石油恢复出口,供应过剩担忧升温</div>
<div class="wc-targets"><span class="wc-target-up">↑ 82</span><span class="wc-target-down">↓ 68</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">建议减持能源股仓位,短期交易者可等待反弹至78-80美元做空,止损设在85</div>
<div class="tags" style="margin-top:8px"><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">405.19</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>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">↑ 450</span><span class="wc-target-down">↓ 370</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">估值仍偏高,建议持有者保持仓位,新进投资者等待回调至380以下考虑分批建仓</div>
<div class="tags" style="margin-top:8px"><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">VIX恐慌指数</div>
<div class="macro-value macro-value-up">17.28</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 16.78</div>
<div class="macro-desc">波动率指数上涨2.98%,反映市场对美联储鹰派转向和科技股回调的担忧</div>
</div>
<div class="macro-card dir-up">
<div class="macro-indicator">10年期美债收益率</div>
<div class="macro-value macro-value-up">4.51%</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 4.45%</div>
<div class="macro-desc">长债收益率上涨6个基点,反映市场对加息预期升温和通胀持续的担忧</div>
</div>
<div class="macro-card dir-down">
<div class="macro-indicator">WTI原油</div>
<div class="macro-value macro-value-down">$74.17</div>
<div class="macro-prev"><span class="arrow down"></span> 前值: $77.33</div>
<div class="macro-desc">美伊和谈突破推动油价暴跌4.09%,霍尔木兹海峡重新开放缓解供应担忧</div>
</div>
<div class="macro-card dir-up">
<div class="macro-indicator">美元指数DXY</div>
<div class="macro-value macro-value-up">105.2</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 104.9</div>
<div class="macro-desc">美元续涨至13个月新高,美联储鹰派立场和避险需求支撑美元走强</div>
</div>
<div class="macro-card dir-up">
<div class="macro-indicator">核心PCE通胀(4月)</div>
<div class="macro-value macro-value-down">3.3%</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 3.2%</div>
<div class="macro-desc">美联储首选通胀指标继续高于2%目标,本周四将公布5月数据,预期升至3.4%</div>
</div>
<div class="macro-card dir-up">
<div class="macro-indicator">CPI同比(5月预期)</div>
<div class="macro-value macro-value-down">4.2%</div>
<div class="macro-prev"><span class="arrow up"></span> 前值: 3.8%</div>
<div class="macro-desc">5月CPI创三年新高,能源价格飙升是主要推手,核心CPI预计维持2.6%</div>
</div>
<div class="macro-card dir-down">
<div class="macro-indicator">初请失业金人数</div>
<div class="macro-value macro-value-down">226,000</div>
<div class="macro-prev"><span class="arrow down"></span> 前值: 230,000</div>
<div class="macro-desc">劳动力市场保持韧性,5月新增就业17.2万,连续三个月稳健增长</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>油价暴跌缓解通胀压力,有利估值修复</div>
<div class="debate-point"><span class="conf-badge high">high</span>小盘股轮动启动,市场广度改善</div>
<div class="debate-point"><span class="conf-badge medium">medium</span>Micron财报若超预期将提振AI板块信心</div>
</div>
<div class="debate-side bear">
<div class="debate-side-title">🐻 空方看跌</div>
<div class="debate-point"><span class="conf-badge high">high</span>美联储鹰派转向,加息预期压制估值</div>
<div class="debate-point"><span class="conf-badge high">high</span>科技巨头AI支出担忧引发抛售潮</div>
<div class="debate-point"><span class="conf-badge medium">medium</span>周四PCE数据若超预期将加剧加息恐慌</div>
</div>
</div>
<div class="debate-verdict">
<div class="verdict-label">裁判结论 <span class="verdict-lean bearish">BEARISH</span></div>
<div class="verdict-text">短期震荡加剧,建议防守为主。美联储鹰派立场和科技股回调构成主要压力,尽管油价下跌提供通胀缓解希望。本周PCE数据和Micron财报将成关键催化剂。建议投资者降低仓位至70-80%,增配防御板块和小盘股,等待7200-7300点支撑区企稳再加仓。</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">MU</div>
<div class="earnings-company">Micron</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">$预计20.00</div>
</div>
<div class="eps-item">
<div class="eps-label">EPS EST.</div>
<div class="eps-value est">$18.50</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>预计$347亿</span></div>
<div class="earnings-highlight">与Anthropic达成AI合作,HBM4内存需求强劲,2028年HBM业务规模将达1000亿美元</div>
</div>
<div class="earnings-card miss">
<div class="earnings-ticker">NFLX</div>
<div class="earnings-company">Netflix</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">$0.79</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>预计$125.7亿</span></div>
<div class="earnings-highlight">近一个月股价下跌12.66%,投资者等待会员增长和广告业务数据</div>
</div>
<div class="earnings-card miss">
<div class="earnings-ticker">AMD</div>
<div class="earnings-company">AMD</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">$1.60</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>预计$112.7亿</span></div>
<div class="earnings-highlight">近一个月涨15%,AI芯片需求强劲,全年EPS预期增长72%</div>
</div>
<div class="earnings-card miss">
<div class="earnings-ticker">TSM</div>
<div class="earnings-company">TSMC</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">$N/A</div>
</div>
</div>
<div class="earnings-revenue">收入: <span>待公布</span></div>
<div class="earnings-highlight">近一个月涨15.52%,先进制程需求旺盛,股价创历史新高</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">Communication Services</div></div>
<div class="sector-etf">XLC</div>
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:100%"></div></div>
<div class="sector-pct down">-3.37%</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 down" style="width:64%"></div></div>
<div class="sector-pct down">-2.05%</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:34%"></div></div>
<div class="sector-pct down">-0.92%</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:40%"></div></div>
<div class="sector-pct down">-1.16%</div>
</div>
<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:15%"></div></div>
<div class="sector-pct up">+0.22%</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 up" style="width:30%"></div></div>
<div class="sector-pct up">+0.76%</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 up" style="width:30%"></div></div>
<div class="sector-pct up">+0.76%</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 up" style="width:27%"></div></div>
<div class="sector-pct up">+0.65%</div>
</div>
<div class="sector-row">
<div><div class="sector-name">医疗保健</div><div class="sector-name-en">Health Care</div></div>
<div class="sector-etf">XLV</div>
<div class="sector-bar-wrap"><div class="sector-bar up" style="width:22%"></div></div>
<div class="sector-pct up">+0.47%</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 up" style="width:11%"></div></div>
<div class="sector-pct up">+0.06%</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:10%"></div></div>
<div class="sector-pct up">+0.03%</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">大型科技股回调拖累,小盘股创历史新高,市场呈明显分化</div>
<div class="ad-bar-wrap">
<span class="ad-label-up">↑3,240</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">↓1,820</span>
</div>
<div class="replay-stats">
<div class="replay-stat"><div class="replay-stat-label">热门板块</div><div class="replay-stat-val">金融</div></div>
<div class="replay-stat"><div class="replay-stat-label">领涨标的</div><div class="replay-stat-val">Micron (MU) +6.9%</div></div>
<div class="replay-stat"><div class="replay-stat-label">创52周新高</div><div class="replay-stat-val">142</div></div>
</div>
</div><div class="replay-card">
<div class="replay-card-title">🇨🇳 A股</div>
<div class="replay-summary">A股放量大涨,北向资金持续流入,宽松预期推动反弹</div>
<div class="ad-bar-wrap">
<span class="ad-label-up">↑2,800</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">↓1,500</span>
</div>
<div class="replay-stats">
<div class="replay-stat"><div class="replay-stat-label">热门板块</div><div class="replay-stat-val">新能源、半导体</div></div>
<div class="replay-stat"><div class="replay-stat-label">领涨标的</div><div class="replay-stat-val">新华保险 (601336) +10.01%</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 medium">
<div class="cal-date">周二 6/24<br><span style="font-size:0.6rem;color:var(--dimmed)">10:00 AM ET</span></div>
<div>
<div class="cal-event">S&amp;P Global Flash PMI (制造业和服务业)</div>
<div class="cal-values">预期: <span>51.5</span> &nbsp;&middot;&nbsp; 前值: 51.3</div>
</div>
</div>
<div class="cal-item high">
<div class="cal-date">周二 6/24<br><span style="font-size:0.6rem;color:var(--dimmed)">4:30 PM ET</span></div>
<div>
<div class="cal-event">Micron Q3财报</div>
<div class="cal-values">预期: <span>EPS $20.00, 营收$347亿</span> &nbsp;&middot;&nbsp; 前值: EPS $18.50</div>
</div>
</div>
<div class="cal-item medium">
<div class="cal-date">周三 6/25<br><span style="font-size:0.6rem;color:var(--dimmed)">10:00 AM ET</span></div>
<div>
<div class="cal-event">5月新屋销售</div>
<div class="cal-values">预期: <span>64.0万户</span> &nbsp;&middot;&nbsp; 前值: 63.4万户</div>
</div>
</div>
<div class="cal-item high">
<div class="cal-date">周四 6/26<br><span style="font-size:0.6rem;color:var(--dimmed)">8:30 AM ET</span></div>
<div>
<div class="cal-event">5月核心PCE物价指数</div>
<div class="cal-values">预期: <span>3.4% YoY</span> &nbsp;&middot;&nbsp; 前值: 3.3% YoY</div>
</div>
</div>
<div class="cal-item high">
<div class="cal-date">周四 6/26<br><span style="font-size:0.6rem;color:var(--dimmed)">8:30 AM ET</span></div>
<div>
<div class="cal-event">5月个人收入和支出</div>
<div class="cal-values">预期: <span>收入+0.4%, 支出+0.3%</span> &nbsp;&middot;&nbsp; 前值: 收入+0.3%, 支出+0.2%</div>
</div>
</div>
<div class="cal-item medium">
<div class="cal-date">周四 6/26<br><span style="font-size:0.6rem;color:var(--dimmed)">8:30 AM ET</span></div>
<div>
<div class="cal-event">5月耐用品订单</div>
<div class="cal-values">预期: <span>+0.5%</span> &nbsp;&middot;&nbsp; 前值: +0.7%</div>
</div>
</div>
<div class="cal-item medium">
<div class="cal-date">周四 6/26<br><span style="font-size:0.6rem;color:var(--dimmed)">8:30 AM ET</span></div>
<div>
<div class="cal-event">Q1 GDP终值</div>
<div class="cal-values">预期: <span>2.3%</span> &nbsp;&middot;&nbsp; 前值: 2.3%</div>
</div>
</div>
<div class="cal-item medium">
<div class="cal-date">周五 6/27<br><span style="font-size:0.6rem;color:var(--dimmed)">10:00 AM ET</span></div>
<div>
<div class="cal-event">密歇根大学6月消费者信心指数终值</div>
<div class="cal-values">预期: <span>70.0</span> &nbsp;&middot;&nbsp; 前值: 初值69.6</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></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">5月</div>
</div>
<div class="leader-quote">"利率对投资回报的影响最为关键"</div>
<div class="leader-body">巴菲特在1999年《财富》杂志文章中的经典论述在2026年再次应验。他强调利率是决定资产估值的核心因素,当前环境下投资者应寻求价值标的。5月宣布卸任CEO后,巴菲特仍保留董事席位。</div>
<div class="tags"><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">Kevin Warsh <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">新任美联储主席Warsh在6月17日首次FOMC会议后宣布放弃前瞻指引,强调美联储对抗通胀的决心。他暗示若通胀居高不下,年内可能加息,点阵图显示9位官员预计年内至少加息一次。市场解读为鹰派信号,股市当日大跌。</div>
<div class="tags"><span class="tag">#美联储</span><span class="tag">#加息</span></div>
</div>
<div class="leader-card">
<div class="leader-header">
<div class="leader-avatar rd">RD</div>
<div class="leader-meta">
<div class="leader-name">雷·达利欧 <span style="color:var(--muted);font-weight:400;font-size:0.78rem;">Ray Dalio</span></div>
<div class="leader-role">桥水基金创始人</div>
</div>
<div class="leader-date">2022年10月</div>
</div>
<div class="leader-quote">"经济范式转变将是痛苦的"</div>
<div class="leader-body">达利欧在2022年曾警告美国经济从低利率和'免费货币'时代转向的'完美风暴'将带来痛苦。尽管预言未能在短期应验,但其对结构性力量的分析仍被市场广泛关注。</div>
<div class="tags"><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-31</span></div>
<div class="cb-note">新主席Warsh放弃前瞻指引,9位官员预计年内加息,强调对抗通胀决心</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 neutral">Neutral</span>
</div>
<div class="cb-rate">3.25%</div>
<div class="cb-action">维持主要再融资利率3.25%</div>
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">2026-07-18</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">People's Bank of China</div>
</div>
<span class="bias-badge dovish">Dovish</span>
</div>
<div class="cb-rate">3.35%</div>
<div class="cb-action">维持LPR 1年期3.35%不变</div>
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">2026-07-22</span></div>
<div class="cb-note">保持宽松立场支持经济复苏,A股连续上涨反映市场对政策宽松预期</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 neutral">Neutral</span>
</div>
<div class="cb-rate">0.25%</div>
<div class="cb-action">维持政策利率0.25%</div>
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">2026-07-31</span></div>
<div class="cb-note">植田和男表示将根据经济和物价形势灵活调整政策</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>