2801 lines
145 KiB
HTML
2801 lines
145 KiB
HTML
<!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; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<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">归档</a>
|
||
<a href="../feed.xml" style="color:var(--dimmed)">RSS</a>
|
||
</nav>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- NAV -->
|
||
<nav class="jump-nav" id="jump-nav">
|
||
<a href="#sec-summary">📊 大势</a>
|
||
<a href="#sec-ai-trading">🤖 AI操盘</a>
|
||
<a href="#sec-news">📰 要闻</a>
|
||
<a href="#sec-watchlist">🎯 AI分析</a>
|
||
<a href="#sec-macro">📈 宏观</a>
|
||
<a href="#sec-earnings">💼 财报</a>
|
||
<a href="#sec-sectors">🏭 行业</a>
|
||
<a href="#sec-debate">⚔️ 辩论</a>
|
||
<a href="#sec-calendar">📅 日历</a>
|
||
<a href="#sec-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,403.05</div>
|
||
<div class="ticker-change down">▼ -0.07%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">道琼斯</div>
|
||
<div class="ticker-value">49,686.12</div>
|
||
<div class="ticker-change up">▲ +0.32%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">纳斯达克</div>
|
||
<div class="ticker-value">26,090.73</div>
|
||
<div class="ticker-change down">▼ -0.51%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">罗素2000</div>
|
||
<div class="ticker-value">2,775.10</div>
|
||
<div class="ticker-change down">▼ -0.65%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">上证综指</div>
|
||
<div class="ticker-value">4,137.97</div>
|
||
<div class="ticker-change up">▲ +0.06%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">恒生指数</div>
|
||
<div class="ticker-value">26,160.33</div>
|
||
<div class="ticker-change down">▼ -0.89%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">日经225</div>
|
||
<div class="ticker-value">61,409.29</div>
|
||
<div class="ticker-change down">▼ -1.99%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">德国DAX</div>
|
||
<div class="ticker-value">21,850</div>
|
||
<div class="ticker-change down">▼ -0.55%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">黄金现货</div>
|
||
<div class="ticker-value">4,576.00</div>
|
||
<div class="ticker-change up">▲ +0.39%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">WTI原油</div>
|
||
<div class="ticker-value">101.02</div>
|
||
<div class="ticker-change up">▲ +4.20%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">布伦特原油</div>
|
||
<div class="ticker-value">109.26</div>
|
||
<div class="ticker-change down">▼ -2.53%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">比特币</div>
|
||
<div class="ticker-value">77,076.16</div>
|
||
<div class="ticker-change down">▼ -1.13%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">美元指数</div>
|
||
<div class="ticker-value">99.21</div>
|
||
<div class="ticker-change up">▲ +0.49%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">离岸人民币</div>
|
||
<div class="ticker-value">7.24</div>
|
||
<div class="ticker-change up">▲ -0.28%</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,403.05</div>
|
||
<div class="ticker-change down">▼ -0.07%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">道琼斯</div>
|
||
<div class="ticker-value">49,686.12</div>
|
||
<div class="ticker-change up">▲ +0.32%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">纳斯达克</div>
|
||
<div class="ticker-value">26,090.73</div>
|
||
<div class="ticker-change down">▼ -0.51%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">罗素2000</div>
|
||
<div class="ticker-value">2,775.10</div>
|
||
<div class="ticker-change down">▼ -0.65%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">上证综指</div>
|
||
<div class="ticker-value">4,137.97</div>
|
||
<div class="ticker-change up">▲ +0.06%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">恒生指数</div>
|
||
<div class="ticker-value">26,160.33</div>
|
||
<div class="ticker-change down">▼ -0.89%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">日经225</div>
|
||
<div class="ticker-value">61,409.29</div>
|
||
<div class="ticker-change down">▼ -1.99%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">德国DAX</div>
|
||
<div class="ticker-value">21,850</div>
|
||
<div class="ticker-change down">▼ -0.55%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">黄金现货</div>
|
||
<div class="ticker-value">4,576.00</div>
|
||
<div class="ticker-change up">▲ +0.39%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">WTI原油</div>
|
||
<div class="ticker-value">101.02</div>
|
||
<div class="ticker-change up">▲ +4.20%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">布伦特原油</div>
|
||
<div class="ticker-value">109.26</div>
|
||
<div class="ticker-change down">▼ -2.53%</div>
|
||
</div>
|
||
<div class="ticker-card down">
|
||
<div class="ticker-name">比特币</div>
|
||
<div class="ticker-value">77,076.16</div>
|
||
<div class="ticker-change down">▼ -1.13%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">美元指数</div>
|
||
<div class="ticker-value">99.21</div>
|
||
<div class="ticker-change up">▲ +0.49%</div>
|
||
</div>
|
||
<div class="ticker-card up">
|
||
<div class="ticker-name">离岸人民币</div>
|
||
<div class="ticker-value">7.24</div>
|
||
<div class="ticker-change up">▲ -0.28%</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.82</span></span>
|
||
</div>
|
||
<div class="summary-headline">美伊谈判缓和油价,科技股承压拖累纳指</div>
|
||
<ul class="key-points"><li class="kp-item"><span class="kp-arrow">▸</span>英伟达周三财报成焦点</li><li class="kp-item"><span class="kp-arrow">▸</span>10年期美债收益率破4.6%</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.32%,标普500微跌0.07%,纳指跌0.51%。特朗普推迟对伊朗军事行动引发油价从111美元回落至109美元,缓解通胀担忧,但国债收益率升破4.6%令科技股承压。市场焦点转向周三英伟达财报,这将是本周最大催化剂。北美华人投资者需关注:持有科技股ETF(如QQQ)的短期波动加大,建议降低仓位;持有能源股的可考虑部分获利了结。</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">特朗普推迟对伊朗军事行动,油价从高位回落</div>
|
||
<span class="news-expand-icon">+</span>
|
||
</div>
|
||
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>油价短期回落缓解通胀压力,但持有能源股ETF的投资者建议部分获利,关注谈判进展</div>
|
||
<div class="news-body-collapse">特朗普周日表示应卡塔尔、沙特和阿联酋请求,推迟原定周二对伊朗的军事打击,称'认真谈判正在进行'。布伦特原油从盘中112美元高位回落至109美元,WTI从104美元降至102.5美元。但市场仍警惕谈判破裂,若冲突升级能源通胀可能进一步加速。</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 featured" onclick="toggleNews(this)">
|
||
<div class="news-header">
|
||
<span class="imp-dot breaking"></span>
|
||
<div class="news-title">10年期美债收益率破4.6%创一年新高,科技股承压</div>
|
||
<span class="news-expand-icon">+</span>
|
||
</div>
|
||
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>债券收益率飙升打压科技股,持有QQQ等成长型ETF的投资者应降低仓位或对冲</div>
|
||
<div class="news-body-collapse">周一10年期美债收益率升破4.6%,创52周新高,20年期和30年期触及2007年以来高点。高收益率令科技股盘中一度跌超2.3%,终盘跌1.1%,拖累纳指跌0.51%。分析师警告,若美联储因通胀持续而加息,估值偏高的成长股将面临更大压力。</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 featured" onclick="toggleNews(this)">
|
||
<div class="news-header">
|
||
<span class="imp-dot breaking"></span>
|
||
<div class="news-title">英伟达周三盘后发布财报,市场屏息以待</div>
|
||
<span class="news-expand-icon">+</span>
|
||
</div>
|
||
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>英伟达财报是本周最大事件,持有NVDA的投资者应做好双向波动准备,考虑期权对冲</div>
|
||
<div class="news-body-collapse">英伟达周三盘后公布Q1财报,华尔街预期营收780亿美元、EPS 1.77美元。KeyBanc上调目标价至300美元,预计Blackwell GPU出货量环比增15-20万片。但上季英伟达即使超预期仍下跌,分析师警告预期和仓位已极度拥挤,财报后波动可能剧烈。</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 high" onclick="toggleNews(this)">
|
||
<div class="news-header">
|
||
<span class="imp-dot high"></span>
|
||
<div class="news-title">三星工会同意延长谈判避免18天罢工,芯片供应链暂缓危机</div>
|
||
<span class="news-expand-icon">+</span>
|
||
</div>
|
||
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>芯片供应链危机暂缓,但存储芯片供需失衡风险仍存,关注相关半导体股短期波动</div>
|
||
<div class="news-body-collapse">三星电子工会周日同意周二继续谈判,避免可能持续18天的罢工。罢工将冲击全球最大存储芯片制造商产能,加剧AI数据中心对内存组件的争夺。周一美光跌3%,英伟达、博通和英特尔跟跌,希捷因CEO称新工厂'耗时过长'暴跌7%。</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 medium" onclick="toggleNews(this)">
|
||
<div class="news-header">
|
||
<span class="imp-dot medium"></span>
|
||
<div class="news-title">马斯克诉OpenAI案陪审团裁定OpenAI并未违约</div>
|
||
<span class="news-expand-icon">+</span>
|
||
</div>
|
||
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>OpenAI法律风险解除,AI行业竞争格局维持现状,对微软和相关AI股中性</div>
|
||
<div class="news-body-collapse">加州奥克兰联邦陪审团周一裁定OpenAI未违反与马斯克的创始协议,驳回马斯克关于OpenAI应保持非营利性质的主张。陪审团还裁定马斯克对微软'协助违反慈善信托'的指控超过诉讼时效。马斯克原索赔1500亿美元。微软股价收盘持平。</div>
|
||
<div class="news-footer">
|
||
<span class="importance-badge medium">• MEDIUM</span>
|
||
<div class="tags"><span class="tag">#AI</span><span class="tag">#法律</span></div>
|
||
</div>
|
||
</div>
|
||
<div class="news-item high" onclick="toggleNews(this)">
|
||
<div class="news-header">
|
||
<span class="imp-dot high"></span>
|
||
<div class="news-title">零售巨头本周集中发布财报,检验消费者抗通胀能力</div>
|
||
<span class="news-expand-icon">+</span>
|
||
</div>
|
||
<div class="news-tldr"><span class="tldr-label">💡 新手解读</span>零售财报将揭示消费者健康度,关注可选消费vs必需消费分化,沃尔玛等折扣商或跑赢</div>
|
||
<div class="news-body-collapse">沃尔玛(周四)、塔吉特(周三)、家得宝和劳氏(周二-周三)本周发布财报。4月CPI同比上涨3.8%背景下,市场密切关注零售商如何应对关税、高房贷利率和谨慎消费支出。沃尔玛预期EPS 0.65美元,营收1725亿美元,股价年初至今涨15%。</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">227.75</div><div class="wc-price-chg down">-1.33%</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">财报前观望,波动加剧</div>
|
||
<div class="wc-driver">周三盘后财报是最大催化剂,预期和仓位极度拥挤,即使超预期也可能'利好出尽'</div>
|
||
<div class="wc-targets"><span class="wc-target-up">↑ 250</span><span class="wc-target-down">↓ 210</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">建议持有者在财报前减半仓位或买入保护性看跌期权对冲,财报后再根据指引决定。空仓者等财报后再进场</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">707.75</div><div class="wc-price-chg down">-0.51%</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">10年期美债收益率破4.6%打压估值,但AI投资周期仍完整,回调是加仓机会</div>
|
||
<div class="wc-targets"><span class="wc-target-up">↑ 727</span><span class="wc-target-down">↓ 690</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">短线交易者可在690-695区间分批建仓,长线投资者无需操作,回撤5-8%是正常技术调整</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">737.50</div><div class="wc-price-chg down">-0.07%</div></div>
|
||
</div>
|
||
<div class="wc-signal-row">
|
||
<span class="signal-badge HOLD">HOLD</span>
|
||
<span class="wc-score">评分 <span>68</span>/100</span>
|
||
</div>
|
||
<div class="wc-conclusion">大盘在高位盘整,等待方向</div>
|
||
<div class="wc-driver">英伟达财报和零售财报将决定短期方向,技术面737-742区间是关键支撑</div>
|
||
<div class="wc-targets"><span class="wc-target-up">↑ 753</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考虑减仓10-15%,突破750可加仓至满仓</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">77,076</div><div class="wc-price-chg down">-1.13%</div></div>
|
||
</div>
|
||
<div class="wc-signal-row">
|
||
<span class="signal-badge SELL">SELL</span>
|
||
<span class="wc-score">评分 <span>45</span>/100</span>
|
||
</div>
|
||
<div class="wc-conclusion">风险资产属性强化,短期承压</div>
|
||
<div class="wc-driver">美债收益率飙升令流动性收紧,比特币表现更像高beta科技股而非避险资产,85.4%相关性与纳指同步</div>
|
||
<div class="wc-targets"><span class="wc-target-up">↑ 82000</span><span class="wc-target-down">↓ 72000</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">建议减仓至30%以下仓位,等待油价回落和美联储立场明朗后再配置,短期支撑72000-75000区间</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">4.12</div><div class="wc-price-chg up">+0.05%</div></div>
|
||
</div>
|
||
<div class="wc-signal-row">
|
||
<span class="signal-badge HOLD">HOLD</span>
|
||
<span class="wc-score">评分 <span>58</span>/100</span>
|
||
</div>
|
||
<div class="wc-conclusion">A股独立行情有限,观望为主</div>
|
||
<div class="wc-driver">国内政策支持vs外部需求疲软,人民币汇率压力限制央行宽松空间</div>
|
||
<div class="wc-targets"><span class="wc-target-up">↑ 4.35</span><span class="wc-target-down">↓ 3.95</span></div>
|
||
<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px"><span class="risk-badge medium">风险:medium</span></div>
|
||
<div class="wc-action">建议北美投资者保持低配(不超过组合10%),等待更明确政策信号,短期3.95-4.20区间震荡</div>
|
||
<div class="tags" style="margin-top:8px"><span class="tag">#A股</span><span class="tag">#中国</span></div>
|
||
</div>
|
||
<div class="watchlist-card">
|
||
<div class="wc-header">
|
||
<div><div class="wc-ticker">GC=F</div><div class="wc-name">黄金期货</div></div>
|
||
<div class="wc-price"><div class="wc-price-val">4,576</div><div class="wc-price-chg up">+0.39%</div></div>
|
||
</div>
|
||
<div class="wc-signal-row">
|
||
<span class="signal-badge BUY">BUY</span>
|
||
<span class="wc-score">评分 <span>78</span>/100</span>
|
||
</div>
|
||
<div class="wc-conclusion">2026年最强避险资产,回调是机会</div>
|
||
<div class="wc-driver">今年涨65%远超比特币,央行持续购金、美元疲软和地缘风险支撑,较1月高点5595美元回撤13%属健康调整</div>
|
||
<div class="wc-targets"><span class="wc-target-up">↑ 5000</span><span class="wc-target-down">↓ 4350</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%,4350-4500区间分批加仓,长期目标高盛预期4900美元</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">101.02</div><div class="wc-price-chg up">+4.20%</div></div>
|
||
</div>
|
||
<div class="wc-signal-row">
|
||
<span class="signal-badge SELL">SELL</span>
|
||
<span class="wc-score">评分 <span>52</span>/100</span>
|
||
</div>
|
||
<div class="wc-conclusion">地缘溢价过高,谨慎获利</div>
|
||
<div class="wc-driver">美伊谈判令油价从104美元回落,但谈判破裂风险仍存。历史显示油价高峰往往对应加密货币底部</div>
|
||
<div class="wc-targets"><span class="wc-target-up">↑ 110</span><span class="wc-target-down">↓ 90</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">建议能源股持有者部分获利(减仓30-50%),若谈判成功油价可能回落至90美元,可在85-90区间重新配置</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">418.57</div><div class="wc-price-chg down">-0.2%</div></div>
|
||
</div>
|
||
<div class="wc-signal-row">
|
||
<span class="signal-badge HOLD">HOLD</span>
|
||
<span class="wc-score">评分 <span>60</span>/100</span>
|
||
</div>
|
||
<div class="wc-conclusion">马斯克诉讼落地,基本面关注产销</div>
|
||
<div class="wc-driver">马斯克诉OpenAI败诉消除不确定性,但传闻SpaceX-特斯拉合并引发估值疑问,周六Model Y涨价1000美元是正面信号</div>
|
||
<div class="wc-targets"><span class="wc-target-up">↑ 455</span><span class="wc-target-down">↓ 380</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">380-400区间是支撑位可考虑建仓,突破450有望测试年内高点498美元,但仓位控制在5%以内</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">CPI YoY (4月)</div>
|
||
<div class="macro-value macro-value-down">3.8%</div>
|
||
<div class="macro-prev"><span class="arrow up">↑</span> 前值: 3.5%</div>
|
||
<div class="macro-desc">4月CPI同比上涨3.8%,高于3月的3.5%,主要受能源价格飙升驱动,降息预期进一步推迟</div>
|
||
</div>
|
||
<div class="macro-card dir-up">
|
||
<div class="macro-indicator">10年期美债收益率</div>
|
||
<div class="macro-value macro-value-up">4.62%</div>
|
||
<div class="macro-prev"><span class="arrow up">↑</span> 前值: 4.50%</div>
|
||
<div class="macro-desc">5月18日升破4.6%创52周新高,反映市场预期美联储可能维持高利率至年底甚至加息</div>
|
||
</div>
|
||
<div class="macro-card dir-neutral">
|
||
<div class="macro-indicator">联邦基金利率</div>
|
||
<div class="macro-value ">3.50-3.75%</div>
|
||
<div class="macro-prev"><span class="arrow ">→</span> 前值: 3.50-3.75%</div>
|
||
<div class="macro-desc">美联储4月会议维持利率不变,鲍威尔最后一次会议强调需观察美伊战争和关税影响</div>
|
||
</div>
|
||
<div class="macro-card dir-up">
|
||
<div class="macro-indicator">工业生产(4月)</div>
|
||
<div class="macro-value macro-value-up">+0.7%</div>
|
||
<div class="macro-prev"><span class="arrow up">↑</span> 前值: -0.5%</div>
|
||
<div class="macro-desc">4月工业生产环比增0.7%,3月下修至-0.5%,产能利用率76.1%超预期75.8%</div>
|
||
</div>
|
||
<div class="macro-card dir-up">
|
||
<div class="macro-indicator">NY Empire State制造业指数(5月)</div>
|
||
<div class="macro-value macro-value-up">19.6</div>
|
||
<div class="macro-prev"><span class="arrow up">↑</span> 前值: 11.0</div>
|
||
<div class="macro-desc">5月纽约帝国州制造业指数跳升至19.6,大超预期7.0,显示制造业活动意外反弹</div>
|
||
</div>
|
||
<div class="macro-card dir-up">
|
||
<div class="macro-indicator">PCE通胀预期(2026)</div>
|
||
<div class="macro-value macro-value-down">2.7%</div>
|
||
<div class="macro-prev"><span class="arrow up">↑</span> 前值: 2.4%</div>
|
||
<div class="macro-desc">美联储4月会议将2026年PCE通胀预期中值上调至2.7%,远高于2%目标</div>
|
||
</div>
|
||
<div class="macro-card dir-down">
|
||
<div class="macro-indicator">布伦特原油</div>
|
||
<div class="macro-value macro-value-down">$109.26</div>
|
||
<div class="macro-prev"><span class="arrow down">↓</span> 前值: $112.10</div>
|
||
<div class="macro-desc">周一从盘中112美元高位回落至109美元,因特朗普宣布推迟对伊朗军事行动</div>
|
||
</div>
|
||
<div class="macro-card dir-up">
|
||
<div class="macro-indicator">美国汽油价格</div>
|
||
<div class="macro-value macro-value-up">$4.22/加仑</div>
|
||
<div class="macro-prev"><span class="arrow up">↑</span> 前值: $2.98/加仑</div>
|
||
<div class="macro-desc">AAA数据显示全美汽油均价4.22美元/加仑,2月28日美以袭击伊朗前仅2.98美元</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 medium">medium</span>英伟达财报超预期将带动AI产业链上涨</div>
|
||
<div class="debate-point"><span class="conf-badge medium">medium</span>美伊谈判进展缓解油价和通胀压力</div>
|
||
<div class="debate-point"><span class="conf-badge low">low</span>零售财报若强劲验证消费韧性,支撑经济软着陆</div>
|
||
</div>
|
||
<div class="debate-side bear">
|
||
<div class="debate-side-title">🐻 空方看跌</div>
|
||
<div class="debate-point"><span class="conf-badge high">high</span>10年期美债收益率破4.6%持续打压估值</div>
|
||
<div class="debate-point"><span class="conf-badge high">high</span>英伟达即使超预期也可能'利好出尽',预期过高</div>
|
||
<div class="debate-point"><span class="conf-badge medium">medium</span>美伊谈判破裂将令油价重回110美元以上</div>
|
||
</div>
|
||
</div>
|
||
<div class="debate-verdict">
|
||
<div class="verdict-label">裁判结论 <span class="verdict-lean neutral">NEUTRAL</span></div>
|
||
<div class="verdict-text">本周标普500可能在7350-7450区间震荡,英伟达财报是最大变量。若财报超预期且指引强劲,有望突破7500;若令人失望,可能回踩7250-7300支撑。建议降低仓位至80%,保留现金应对波动,英伟达财报后再决定加仓或减仓方向。</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 pending">
|
||
<div class="earnings-ticker">NVDA</div>
|
||
<div class="earnings-company">英伟达</div>
|
||
<span class="earnings-beat-badge pending">UPCOMING</span>
|
||
<div class="earnings-eps">
|
||
<div class="eps-item">
|
||
<div class="eps-label">EPS EST.</div>
|
||
<div class="eps-value est">$1.77</div>
|
||
</div>
|
||
<div class="eps-item">
|
||
<div class="eps-label">REPORT DATE</div>
|
||
<div class="eps-value est" style="font-size:0.75rem;">2026-05-20</div>
|
||
</div>
|
||
</div>
|
||
<div class="earnings-revenue">收入: <span>预期780亿美元</span></div>
|
||
<div class="earnings-highlight">华尔街最关注财报,KeyBanc目标价上调至300美元,预计Blackwell GPU出货量环比增15-20万</div>
|
||
</div>
|
||
<div class="earnings-card pending">
|
||
<div class="earnings-ticker">TGT</div>
|
||
<div class="earnings-company">塔吉特</div>
|
||
<span class="earnings-beat-badge pending">UPCOMING</span>
|
||
<div class="earnings-eps">
|
||
<div class="eps-item">
|
||
<div class="eps-label">EPS EST.</div>
|
||
<div class="eps-value est">$待公布</div>
|
||
</div>
|
||
<div class="eps-item">
|
||
<div class="eps-label">REPORT DATE</div>
|
||
<div class="eps-value est" style="font-size:0.75rem;">2026-05-20</div>
|
||
</div>
|
||
</div>
|
||
<div class="earnings-revenue">收入: <span>待公布</span></div>
|
||
<div class="earnings-highlight">周三盘前发布,与家得宝、劳氏同日,将揭示可选消费健康度和关税影响</div>
|
||
</div>
|
||
<div class="earnings-card pending">
|
||
<div class="earnings-ticker">WMT</div>
|
||
<div class="earnings-company">沃尔玛</div>
|
||
<span class="earnings-beat-badge pending">UPCOMING</span>
|
||
<div class="earnings-eps">
|
||
<div class="eps-item">
|
||
<div class="eps-label">EPS EST.</div>
|
||
<div class="eps-value est">$0.65</div>
|
||
</div>
|
||
<div class="eps-item">
|
||
<div class="eps-label">REPORT DATE</div>
|
||
<div class="eps-value est" style="font-size:0.75rem;">2026-05-21</div>
|
||
</div>
|
||
</div>
|
||
<div class="earnings-revenue">收入: <span>预期1725亿美元</span></div>
|
||
<div class="earnings-highlight">周四盘前发布,同店销售预期+3.9%,高收入家庭为省钱向沃尔玛迁移</div>
|
||
</div>
|
||
<div class="earnings-card pending">
|
||
<div class="earnings-ticker">HD</div>
|
||
<div class="earnings-company">家得宝</div>
|
||
<span class="earnings-beat-badge pending">UPCOMING</span>
|
||
<div class="earnings-eps">
|
||
<div class="eps-item">
|
||
<div class="eps-label">EPS EST.</div>
|
||
<div class="eps-value est">$待公布</div>
|
||
</div>
|
||
<div class="eps-item">
|
||
<div class="eps-label">REPORT DATE</div>
|
||
<div class="eps-value est" style="font-size:0.75rem;">2026-05-19</div>
|
||
</div>
|
||
</div>
|
||
<div class="earnings-revenue">收入: <span>待公布</span></div>
|
||
<div class="earnings-highlight">周二盘前发布,CEO称房屋装修周期将恢复但时间不确定,受困于高房贷利率</div>
|
||
</div>
|
||
<div class="earnings-card pending">
|
||
<div class="earnings-ticker">LOW</div>
|
||
<div class="earnings-company">劳氏</div>
|
||
<span class="earnings-beat-badge pending">UPCOMING</span>
|
||
<div class="earnings-eps">
|
||
<div class="eps-item">
|
||
<div class="eps-label">EPS EST.</div>
|
||
<div class="eps-value est">$待公布</div>
|
||
</div>
|
||
<div class="eps-item">
|
||
<div class="eps-label">REPORT DATE</div>
|
||
<div class="eps-value est" style="font-size:0.75rem;">2026-05-20</div>
|
||
</div>
|
||
</div>
|
||
<div class="earnings-revenue">收入: <span>待公布</span></div>
|
||
<div class="earnings-highlight">周三发布,与家得宝共同反映美国房屋装修市场冻结状况</div>
|
||
</div>
|
||
<div class="earnings-card pending">
|
||
<div class="earnings-ticker">MU</div>
|
||
<div class="earnings-company">美光科技</div>
|
||
<span class="earnings-beat-badge pending">UPCOMING</span>
|
||
<div class="earnings-eps">
|
||
<div class="eps-item">
|
||
<div class="eps-label">EPS EST.</div>
|
||
<div class="eps-value est">$待查</div>
|
||
</div>
|
||
<div class="eps-item">
|
||
<div class="eps-label">REPORT DATE</div>
|
||
<div class="eps-value est" style="font-size:0.75rem;">已公布</div>
|
||
</div>
|
||
</div>
|
||
<div class="earnings-revenue">收入: <span>待查</span></div>
|
||
<div class="earnings-highlight">周一因三星罢工担忧和存储芯片供应紧张跌3%</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">Energy</div></div>
|
||
<div class="sector-etf">XLE</div>
|
||
<div class="sector-bar-wrap"><div class="sector-bar up" style="width:86%"></div></div>
|
||
<div class="sector-pct up">+2.3%</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 down" style="width:46%"></div></div>
|
||
<div class="sector-pct down">-1.1%</div>
|
||
</div>
|
||
<div class="sector-row">
|
||
<div><div class="sector-name">材料</div><div class="sector-name-en">Materials</div></div>
|
||
<div class="sector-etf">XLB</div>
|
||
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:100%"></div></div>
|
||
<div class="sector-pct down">-2.7%</div>
|
||
</div>
|
||
<div class="sector-row">
|
||
<div><div class="sector-name">公用事业</div><div class="sector-name-en">Utilities</div></div>
|
||
<div class="sector-etf">XLU</div>
|
||
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:90%"></div></div>
|
||
<div class="sector-pct down">-2.4%</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:70%"></div></div>
|
||
<div class="sector-pct down">-1.8%</div>
|
||
</div>
|
||
<div class="sector-row">
|
||
<div><div class="sector-name">金融</div><div class="sector-name-en">Financials</div></div>
|
||
<div class="sector-etf">XLF</div>
|
||
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:36%"></div></div>
|
||
<div class="sector-pct down">-0.8%</div>
|
||
</div>
|
||
<div class="sector-row">
|
||
<div><div class="sector-name">医疗保健</div><div class="sector-name-en">Health Care</div></div>
|
||
<div class="sector-etf">XLV</div>
|
||
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:50%"></div></div>
|
||
<div class="sector-pct down">-1.2%</div>
|
||
</div>
|
||
<div class="sector-row">
|
||
<div><div class="sector-name">可选消费</div><div class="sector-name-en">Consumer Discretionary</div></div>
|
||
<div class="sector-etf">XLY</div>
|
||
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:76%"></div></div>
|
||
<div class="sector-pct down">-2.0%</div>
|
||
</div>
|
||
<div class="sector-row">
|
||
<div><div class="sector-name">必需消费</div><div class="sector-name-en">Consumer Staples</div></div>
|
||
<div class="sector-etf">XLP</div>
|
||
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:20%"></div></div>
|
||
<div class="sector-pct down">-0.3%</div>
|
||
</div>
|
||
<div 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:36%"></div></div>
|
||
<div class="sector-pct down">-0.8%</div>
|
||
</div>
|
||
<div class="sector-row">
|
||
<div><div class="sector-name">房地产</div><div class="sector-name-en">Real Estate</div></div>
|
||
<div class="sector-etf">XLRE</div>
|
||
<div class="sector-bar-wrap"><div class="sector-bar down" style="width:53%"></div></div>
|
||
<div class="sector-pct down">-1.3%</div>
|
||
</div>
|
||
</div>
|
||
<!-- SECTORS:END -->
|
||
<!-- SECTORS:END -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- REPLAY + CALENDAR (2-up) -->
|
||
<div class="two-up">
|
||
<div class="section-block sec-anchor" id="sec-replay">
|
||
<div class="card">
|
||
<div class="section-label">📽️ 大盘复盘 · Replay</div>
|
||
<!-- MARKET_REPLAY:START -->
|
||
<div class="replay-grid"><div class="replay-card">
|
||
<div class="replay-card-title">🇺🇸 美股</div>
|
||
<div class="replay-summary">道指一枝独秀涨0.32%,科技股拖累纳指跌0.51%</div>
|
||
<div class="ad-bar-wrap">
|
||
<span class="ad-label-up">↑1820</span>
|
||
<div class="ad-bar adv" style="width:36px;max-width:80px"></div>
|
||
<div class="ad-bar dec" style="width:64px;max-width:80px"></div>
|
||
<span class="ad-label-dn">↓3240</span>
|
||
</div>
|
||
<div class="replay-stats">
|
||
<div class="replay-stat"><div class="replay-stat-label">热门板块</div><div class="replay-stat-val">能源 +2.3%</div></div>
|
||
<div class="replay-stat"><div class="replay-stat-label">领涨标的</div><div class="replay-stat-val">LiveRamp(RAMP) +27%(Publicis 25亿美元全现金收购)</div></div>
|
||
<div class="replay-stat"><div class="replay-stat-label">创52周新高</div><div class="replay-stat-val">85</div></div>
|
||
</div>
|
||
</div><div class="replay-card">
|
||
<div class="replay-card-title">🇨🇳 A股</div>
|
||
<div class="replay-summary">A股微涨,沪指守住4100点,北向资金小幅流入</div>
|
||
<div class="ad-bar-wrap">
|
||
<span class="ad-label-up">↑2800</span>
|
||
<div class="ad-bar adv" style="width:65px;max-width:80px"></div>
|
||
<div class="ad-bar dec" style="width:35px;max-width:80px"></div>
|
||
<span class="ad-label-dn">↓1500</span>
|
||
</div>
|
||
<div class="replay-stats">
|
||
<div class="replay-stat"><div class="replay-stat-label">热门板块</div><div class="replay-stat-val">半导体设备</div></div>
|
||
<div class="replay-stat"><div class="replay-stat-label">领涨标的</div><div class="replay-stat-val">蒙娜丽莎连板,利仁科技4连板</div></div>
|
||
<div class="replay-stat"><div class="replay-stat-label">北向资金</div><div class="replay-stat-val">+18亿</div></div>
|
||
</div>
|
||
</div></div>
|
||
<!-- MARKET_REPLAY:END -->
|
||
<!-- MARKET_REPLAY:END -->
|
||
</div>
|
||
</div>
|
||
<div class="section-block sec-anchor" id="sec-calendar">
|
||
<div class="card">
|
||
<div class="section-label">📅 本周日程 · Calendar</div>
|
||
<!-- CALENDAR:START -->
|
||
<div class="calendar-grid">
|
||
<div class="cal-item high">
|
||
<div class="cal-date">周二 5/19<br><span style="font-size:0.6rem;color:var(--dimmed)">08:30 AM</span></div>
|
||
<div>
|
||
<div class="cal-event">家得宝财报</div>
|
||
<div class="cal-values">预期: <span>待查</span> · 前值: 待查</div>
|
||
</div>
|
||
</div>
|
||
<div class="cal-item high">
|
||
<div class="cal-date">周三 5/20<br><span style="font-size:0.6rem;color:var(--dimmed)">02:00 PM</span></div>
|
||
<div>
|
||
<div class="cal-event">FOMC会议纪要(4月会议)</div>
|
||
<div class="cal-values">预期: <span>市场关注委员分歧和新主席Kevin Warsh立场</span> · 前值: 鲍威尔最后一次会议</div>
|
||
</div>
|
||
</div>
|
||
<div class="cal-item high">
|
||
<div class="cal-date">周三 5/20<br><span style="font-size:0.6rem;color:var(--dimmed)">盘后</span></div>
|
||
<div>
|
||
<div class="cal-event">英伟达Q1财报</div>
|
||
<div class="cal-values">预期: <span>EPS 1.77美元,营收780亿美元</span> · 前值: EPS超预期但股价下跌</div>
|
||
</div>
|
||
</div>
|
||
<div class="cal-item medium">
|
||
<div class="cal-date">周三 5/20<br><span style="font-size:0.6rem;color:var(--dimmed)">盘前</span></div>
|
||
<div>
|
||
<div class="cal-event">塔吉特财报</div>
|
||
<div class="cal-values">预期: <span>可选消费健康度晴雨表</span> · 前值: 待查</div>
|
||
</div>
|
||
</div>
|
||
<div class="cal-item high">
|
||
<div class="cal-date">周四 5/21<br><span style="font-size:0.6rem;color:var(--dimmed)">盘前</span></div>
|
||
<div>
|
||
<div class="cal-event">沃尔玛Q1财报</div>
|
||
<div class="cal-values">预期: <span>EPS 0.65美元,营收1725亿美元</span> · 前值: 待查</div>
|
||
</div>
|
||
</div>
|
||
<div class="cal-item medium">
|
||
<div class="cal-date">周五 5/22<br><span style="font-size:0.6rem;color:var(--dimmed)">09:45 AM</span></div>
|
||
<div>
|
||
<div class="cal-event">美国5月PMI初值</div>
|
||
<div class="cal-values">预期: <span>制造业和服务业活动指标</span> · 前值: 待查</div>
|
||
</div>
|
||
</div>
|
||
<div class="cal-item medium">
|
||
<div class="cal-date">周五 5/22<br><span style="font-size:0.6rem;color:var(--dimmed)">10:00 AM</span></div>
|
||
<div>
|
||
<div class="cal-event">成屋销售(4月)</div>
|
||
<div class="cal-values">预期: <span>高房贷利率持续打压房屋销售</span> · 前值: 待查</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月11日</div>
|
||
</div>
|
||
<div class="leader-quote">"利率如同引力作用于几乎所有资产价格"</div>
|
||
<div class="leader-body">戴蒙在4月股东信中呼应巴菲特26年前的警告,强调当前经济环境下通胀上升(而非衰退)是更大担忧,这将导致更高利率。他指出美联储2026年通胀预期中值已升至2.7%,降息前景显著恶化,期货交易员甚至开始定价加息可能性。</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">1999年11月</div>
|
||
</div>
|
||
<div class="leader-quote">"利率对金融估值的作用就像引力对物质的作用"</div>
|
||
<div class="leader-body">巴菲特1999年在《财富》杂志撰文警告,利率是影响投资回报最重要因素之一。2026年市场再次印证这一观点:当前标普500估值偏高,投资者预期回报需要大幅降息才能实现,但美伊战争推高油价令降息希望渺茫。</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 jp">JP</div>
|
||
<div class="leader-meta">
|
||
<div class="leader-name">杰罗姆·鲍威尔 <span style="color:var(--muted);font-weight:400;font-size:0.78rem;">Jerome Powell</span></div>
|
||
<div class="leader-role">美联储主席(5月15日卸任)</div>
|
||
</div>
|
||
<div class="leader-date">3月30日</div>
|
||
</div>
|
||
<div class="leader-quote">"通胀预期似乎在短期之外得到良好锚定"</div>
|
||
<div class="leader-body">鲍威尔在3月30日哈佛大学演讲中表示,当前3.5-3.75%利率区间是美联储观察美伊战争和关税影响的'好位置'。他强调尽管油价飙升,美联储尚未面临是否加息的决定,因经济影响尚不明朗。市场不再定价年内加息重大概率。</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">JH</div>
|
||
<div class="leader-meta">
|
||
<div class="leader-name">黄仁勋 <span style="color:var(--muted);font-weight:400;font-size:0.78rem;">Jensen Huang</span></div>
|
||
<div class="leader-role">英伟达CEO</div>
|
||
</div>
|
||
<div class="leader-date">3月</div>
|
||
</div>
|
||
<div class="leader-quote">"Vera Rubin和Blackwell产品营收预期翻倍至超1万亿美元"</div>
|
||
<div class="leader-body">黄仁勋3月表示英伟达硬件和软件需求'爆表',将Vera Rubin和Blackwell产品2026年底营收预期从5000亿美元上调至超1万亿美元。英伟达股价今年已涨20%,周三财报将成市场最大催化剂,华尔街预期营收780亿美元、EPS 1.77美元。</div>
|
||
<div class="tags"><span class="tag">#AI</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-06-17</span></div>
|
||
<div class="cb-note">鲍威尔5月15日卸任,Kevin Warsh提名受阻。4月会议维持利率,强调需观察美伊战争和关税对通胀影响,2026年PCE通胀预期上调至2.7%</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.00%</div>
|
||
<div class="cb-action">维持存款利率3.00%</div>
|
||
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">2026-06-06</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">1年期LPR 3.45%</div>
|
||
<div class="cb-action">维持LPR不变</div>
|
||
<div class="cb-next">下次会议: <span class="font-mono" style="color:var(--neutral)">2026-05-20</span></div>
|
||
<div class="cb-note">保持宽松立场支持经济复苏,但人民币汇率压力限制降息空间</div>
|
||
</div>
|
||
<div class="cb-card">
|
||
<div class="cb-header">
|
||
<div>
|
||
<div class="cb-name">日本央行</div>
|
||
<div class="cb-name-en">Bank of Japan</div>
|
||
</div>
|
||
<span class="bias-badge 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-06-13</span></div>
|
||
<div class="cb-note">日元兑美元在145附近波动,央行密切关注汇率和通胀动态</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 | 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)} 股 × $${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&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}</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 => {
|
||
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 pnl = pv - startCap;
|
||
const ret = pnl / startCap * 100;
|
||
const c = ret >= 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};">${(pnl>=0?'+':'')}${fmt$(pnl)} (${(ret>=0?'+':'')}${ret.toFixed(2)}%)</div></td>`;
|
||
}).join('');
|
||
const spyRec = (ranked[0]?.pf.history||[]).find(h => h.date === date);
|
||
const spyV = spyRec ? spyRec.baseline_value : startCap;
|
||
const spyPnlR = spyV - startCap;
|
||
const spyR = spyPnlR / startCap * 100;
|
||
const sc = spyR >= 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};">${(spyPnlR>=0?'+':'')}${fmt$(spyPnlR)} (${(spyR>=0?'+':'')}${spyR.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>
|
||
<div id="share-toast">✅ 链接已复制</div>
|
||
|
||
</body>
|
||
</html> |