🟡 카카오따뜻한 노랑 · 친근한 느낌
🏛 헤리티지딥 네이비 골드 · 프리미엄
🟠 클로드베이지 오렌지 · 지적인 느낌
🔵 구글Material 4색 · 깔끔 모던
💎 PlanX딥블루 · PlanX 브랜딩
📊 시황 개요
💡 중동 리스크 완화 + 기술주 반등으로 상승 출발 예상
🔥 오늘의 핫픽 종목 3개
① 한미반도체 — HBM 수요 지속 · 외국인 3일 연속 순매수단기
② HD현대일렉트릭 — 데이터센터 변압기 신규 수주중기
③ 삼성바이오로직스 — 바이오 섹터 외국인 매수세 유입분할매수
🗝️ 오늘의 핵심 키워드
HBM3E → 한미반도체, SK하이닉스, 에이팩트
데이터센터 전력 → HD현대일렉트릭, 효성중공업
3차 상법 개정 → 기관 매수세 확대, 대형 우량주 수혜
📝 오늘의 총평 3줄
1. 중동 리스크 완화 + 기술주 반등으로 코스피 상승 출발 예상
2. 반도체·전력기기 주도 유지, 2차전지는 아직 관망
3. KOSPI 5,700 돌파 여부 주목, 실패 시 신규 매수 보류 권고
📊 이번 주 시장 성적
KOSPI 주간
▲ 2.8%
5,480→5,634
📌 최대 이슈: 중동 유가 급등 후 안정화, 3차 상법 개정 통과
🏆 섹터별 성적표
🏆 최강: 반도체, 전력기기, 방산 — AI 수요 · 지정학 수혜
😞 최약: 2차전지, 화학, 건설 — 수요 둔화 · PF 리스크
📅 다음 주 주요 일정
화 — 미국 CPI 발표 (인플레이션 지표)
수 — FOMC 의사록 공개
목 — 삼성전자 잠정 실적 발표
📝 이번 주 총평 3줄
1. 중동 리스크 완화로 코스피 반등 성공, 5,600대 안착
2. 외국인 수급 개선되며 반도체·전력 주도 섹터 유지
3. 다음 주 미국 CPI 결과가 추가 상승의 핵심 변수
📊 2월 리뷰
KOSPI 2월
▲ 4.1%
5,200→5,413
🌍 3월 거시경제 전망
금리 — 동결 유지 예상 → 주식 중립적
환율 — 달러/원 1,320~1,360 박스권
유가 — 중동 상황에 따라 변동성 ↑
📝 3월 총평 3줄
1. AI 인프라 사이클 지속으로 반도체·전력 비중 유지 권고
2. 중동 변수로 변동성 확대 구간, 현금 30% 이상 확보
3. 하락 시 우량주 분할 매수 기회로 활용할 것
📊 시황 개요
💡 중동 리스크 완화 + 기술주 반등으로 상승 출발 예상
🔥 오늘의 핫픽 종목 3개
① 한미반도체 — HBM 수요 지속 · 외국인 3일 연속 순매수단기
② HD현대일렉트릭 — 데이터센터 변압기 신규 수주중기
③ 삼성바이오로직스 — 바이오 섹터 외국인 매수세 유입분할매수
🗝️ 오늘의 핵심 키워드
HBM3E → 한미반도체, SK하이닉스, 에이팩트
데이터센터 전력 → HD현대일렉트릭, 효성중공업
3차 상법 개정 → 기관 매수세 확대, 대형 우량주 수혜
📝 오늘의 총평 3줄
1. 중동 리스크 완화 + 기술주 반등으로 코스피 상승 출발 예상
2. 반도체·전력기기 주도 유지, 2차전지는 아직 관망
3. KOSPI 5,700 돌파 여부 주목, 실패 시 신규 매수 보류 권고
📊 이번 주 시장 성적
KOSPI 주간
▲ 2.8%
5,480→5,634
📌 최대 이슈: 중동 유가 급등 후 안정화, 3차 상법 개정 통과
🏆 섹터별 성적표
🏆 최강: 반도체, 전력기기, 방산 — AI 수요 · 지정학 수혜
😞 최약: 2차전지, 화학, 건설 — 수요 둔화 · PF 리스크
📅 다음 주 주요 일정
화 — 미국 CPI 발표 (인플레이션 지표)
수 — FOMC 의사록 공개
목 — 삼성전자 잠정 실적 발표
📝 이번 주 총평 3줄
1. 중동 리스크 완화로 코스피 반등 성공, 5,600대 안착
2. 외국인 수급 개선되며 반도체·전력 주도 섹터 유지
3. 다음 주 미국 CPI 결과가 추가 상승의 핵심 변수
📋 Apps Script — 🟡 카카오
Google 스프레드시트 → 확장 프로그램 → Apps Script에 붙여넣기
SCRIPT
// ══════════════════════════════════════════
// PlanX 시황 리포트 — KAKAO 테마 (daily)
// Gemini 2.5 Flash + Apps Script
// ══════════════════════════════════════════
const CONFIG = {
GEMINI_API_KEY: 'YOUR_GEMINI_API_KEY', // ← API 키
MODEL: 'gemini-2.5-flash-preview-05-20',
RECIPIENTS: '[email protected] ', // ← 수신 이메일
REPORT_TYPE: 'daily',
THEME: 'kakao',
};
function generateReport() {
const prompt = `Analyze today's Korean stock market. Return JSON: {"market_overview":{"kospi":"","kospi_change":"","kosdaq_change":"","foreign_flow":"","institution_flow":"","mood":""},"hot_picks":[{"name":"","reason":"","strategy":""}],"keywords":[{"keyword":"","related_stocks":""}],"summary":["","",""]}`;
const data = callGemini(prompt);
const html = buildHTML(data);
sendEmail(html);
}
function callGemini(prompt) {
const url = `https://generativelanguage.googleapis.com/v1beta/models/${CONFIG.MODEL}:generateContent?key=${CONFIG.GEMINI_API_KEY}`;
const payload = {
contents: [{ parts: [{ text: prompt }] }],
generationConfig: { temperature: 0.3, responseMimeType: "application/json" }
};
const res = UrlFetchApp.fetch(url, {
method: 'post', contentType: 'application/json',
payload: JSON.stringify(payload), muteHttpExceptions: true
});
const result = JSON.parse(res.getContentText());
return JSON.parse(result.candidates[0].content.parts[0].text);
}
function buildHTML(data) {
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd (E) · a h:mm');
// ── 여기에 테마별 HTML 조립 로직 ──
// data 객체에서 각 섹션을 HTML 테이블로 변환
// 색상/레이아웃은 테마에 맞게 적용
let sections = '';
if (CONFIG.REPORT_TYPE === 'daily') {
const m = data.market_overview;
const picks = data.hot_picks.map((p,i) =>
`<tr><td style="padding:8px;font-weight:700;">{['①','②','③'][i]}</td>` +
`<td style="padding:8px;font-weight:700;">${p.name}</td>` +
`<td style="padding:8px;">${p.reason}</td>` +
`<td style="padding:8px;"><span style="background:#1a73e8;color:#fff;padding:2px 8px;border-radius:8px;font-size:12px;">${p.strategy}</span></td></tr>`
).join('');
const kws = data.keywords.map(k =>
`<tr><td style="padding:8px;font-weight:700;">${k.keyword}</td><td style="padding:8px;">→ ${k.related_stocks}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 시황 개요</h3>
<table style="width:100%;"><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${m.kospi} ${m.kospi_change}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${m.kosdaq_change}</b></td>
</tr><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">외국인<br><b>${m.foreign_flow}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">기관<br><b>${m.institution_flow}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">💡 ${m.mood}</div>
<h3 style="margin:16px 0 8px;">🔥 핫픽 종목</h3>
<table style="width:100%;">${picks}</table>
<h3 style="margin:16px 0 8px;">🗝️ 핵심 키워드</h3>
<table style="width:100%;">${kws}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'weekly') {
const wp = data.weekly_performance;
const sr = data.sector_ranking;
const evts = data.next_week_events.map(e =>
`<tr><td style="padding:6px;font-weight:700;">${e.day}</td><td style="padding:6px;">${e.event}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 주간 성적</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${wp.kospi_weekly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${wp.kosdaq_weekly}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">📌 ${wp.top_issue}</div>
<h3 style="margin:16px 0 8px;">🏆 섹터 성적</h3>
<div>🏆 최강: ${sr.best}</div><div>😞 최약: ${sr.worst}</div>
<h3 style="margin:16px 0 8px;">📅 다음 주 일정</h3>
<table style="width:100%;">${evts}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'monthly') {
const lr = data.last_month_review;
const mc = data.macro_outlook.map(m =>
`<tr><td style="padding:6px;font-weight:700;">${m.factor}</td><td style="padding:6px;">${m.outlook}</td></tr>`
).join('');
const al = data.allocation.map(a =>
`<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">${a.asset}<br><b>${a.weight}</b></td>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 전월 리뷰</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${lr.kospi_monthly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">핫픽 평균<br><b style="color:#d93025;">${lr.hotpick_avg}</b></td>
</tr></table>
<h3 style="margin:16px 0 8px;">🌍 거시경제</h3>
<table style="width:100%;">${mc}</table>
<h3 style="margin:16px 0 8px;">💼 자산 배분</h3>
<table style="width:100%;"><tr>${al}</tr></table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
return `<div style="max-width:480px;margin:0 auto;font-family:sans-serif;">
<div style="background:#1a73e8;color:#fff;padding:16px;text-align:center;border-radius:12px 12px 0 0;">
<div style="font-size:11px;opacity:0.7;letter-spacing:2px;">PLANX AI</div>
<div style="font-size:20px;font-weight:900;">${
CONFIG.REPORT_TYPE==='daily'?'일간 시황':'weekly'?'주간 시장':'월간 전략'
} 리포트</div>
<div style="font-size:12px;opacity:0.6;">${today}</div>
</div>
<div style="background:#fff;padding:16px;border-radius:0 0 12px 12px;">${sections}</div>
<div style="text-align:center;padding:10px;font-size:11px;color:#999;">⚠️ AI 참고자료 · 투자권유 아님 · © 2026 PlanX</div>
</div>`;
}
function sendEmail(html) {
const titles = { daily:'일간 시황', weekly:'주간 시장', monthly:'월간 전략' };
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd');
GmailApp.sendEmail(CONFIG.RECIPIENTS, `[PlanX] ${titles[CONFIG.REPORT_TYPE]} (${today})`, '', {
htmlBody: html, name: 'PlanX AI 리포트'
});
}
function testRun() {
generateReport();
Logger.log('발송 완료!');
}
📋 스크립트 전체 복사
📋 Apps Script — 🏛 헤리티지
Google 스프레드시트 → 확장 프로그램 → Apps Script에 붙여넣기
SCRIPT
// ══════════════════════════════════════════
// PlanX 시황 리포트 — HERITAGE 테마 (weekly)
// Gemini 2.5 Flash + Apps Script
// ══════════════════════════════════════════
const CONFIG = {
GEMINI_API_KEY: 'YOUR_GEMINI_API_KEY', // ← API 키
MODEL: 'gemini-2.5-flash-preview-05-20',
RECIPIENTS: '[email protected] ', // ← 수신 이메일
REPORT_TYPE: 'weekly',
THEME: 'heritage',
};
function generateReport() {
const prompt = `Analyze this week's Korean stock market. Return JSON: {"weekly_performance":{"kospi_weekly":"","kosdaq_weekly":"","top_issue":""},"sector_ranking":{"best":"","worst":""},"next_week_events":[{"day":"","event":""}],"summary":["","",""]}`;
const data = callGemini(prompt);
const html = buildHTML(data);
sendEmail(html);
}
function callGemini(prompt) {
const url = `https://generativelanguage.googleapis.com/v1beta/models/${CONFIG.MODEL}:generateContent?key=${CONFIG.GEMINI_API_KEY}`;
const payload = {
contents: [{ parts: [{ text: prompt }] }],
generationConfig: { temperature: 0.3, responseMimeType: "application/json" }
};
const res = UrlFetchApp.fetch(url, {
method: 'post', contentType: 'application/json',
payload: JSON.stringify(payload), muteHttpExceptions: true
});
const result = JSON.parse(res.getContentText());
return JSON.parse(result.candidates[0].content.parts[0].text);
}
function buildHTML(data) {
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd (E) · a h:mm');
// ── 여기에 테마별 HTML 조립 로직 ──
// data 객체에서 각 섹션을 HTML 테이블로 변환
// 색상/레이아웃은 테마에 맞게 적용
let sections = '';
if (CONFIG.REPORT_TYPE === 'daily') {
const m = data.market_overview;
const picks = data.hot_picks.map((p,i) =>
`<tr><td style="padding:8px;font-weight:700;">{['①','②','③'][i]}</td>` +
`<td style="padding:8px;font-weight:700;">${p.name}</td>` +
`<td style="padding:8px;">${p.reason}</td>` +
`<td style="padding:8px;"><span style="background:#1a73e8;color:#fff;padding:2px 8px;border-radius:8px;font-size:12px;">${p.strategy}</span></td></tr>`
).join('');
const kws = data.keywords.map(k =>
`<tr><td style="padding:8px;font-weight:700;">${k.keyword}</td><td style="padding:8px;">→ ${k.related_stocks}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 시황 개요</h3>
<table style="width:100%;"><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${m.kospi} ${m.kospi_change}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${m.kosdaq_change}</b></td>
</tr><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">외국인<br><b>${m.foreign_flow}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">기관<br><b>${m.institution_flow}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">💡 ${m.mood}</div>
<h3 style="margin:16px 0 8px;">🔥 핫픽 종목</h3>
<table style="width:100%;">${picks}</table>
<h3 style="margin:16px 0 8px;">🗝️ 핵심 키워드</h3>
<table style="width:100%;">${kws}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'weekly') {
const wp = data.weekly_performance;
const sr = data.sector_ranking;
const evts = data.next_week_events.map(e =>
`<tr><td style="padding:6px;font-weight:700;">${e.day}</td><td style="padding:6px;">${e.event}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 주간 성적</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${wp.kospi_weekly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${wp.kosdaq_weekly}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">📌 ${wp.top_issue}</div>
<h3 style="margin:16px 0 8px;">🏆 섹터 성적</h3>
<div>🏆 최강: ${sr.best}</div><div>😞 최약: ${sr.worst}</div>
<h3 style="margin:16px 0 8px;">📅 다음 주 일정</h3>
<table style="width:100%;">${evts}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'monthly') {
const lr = data.last_month_review;
const mc = data.macro_outlook.map(m =>
`<tr><td style="padding:6px;font-weight:700;">${m.factor}</td><td style="padding:6px;">${m.outlook}</td></tr>`
).join('');
const al = data.allocation.map(a =>
`<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">${a.asset}<br><b>${a.weight}</b></td>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 전월 리뷰</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${lr.kospi_monthly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">핫픽 평균<br><b style="color:#d93025;">${lr.hotpick_avg}</b></td>
</tr></table>
<h3 style="margin:16px 0 8px;">🌍 거시경제</h3>
<table style="width:100%;">${mc}</table>
<h3 style="margin:16px 0 8px;">💼 자산 배분</h3>
<table style="width:100%;"><tr>${al}</tr></table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
return `<div style="max-width:480px;margin:0 auto;font-family:sans-serif;">
<div style="background:#1a73e8;color:#fff;padding:16px;text-align:center;border-radius:12px 12px 0 0;">
<div style="font-size:11px;opacity:0.7;letter-spacing:2px;">PLANX AI</div>
<div style="font-size:20px;font-weight:900;">${
CONFIG.REPORT_TYPE==='daily'?'일간 시황':'weekly'?'주간 시장':'월간 전략'
} 리포트</div>
<div style="font-size:12px;opacity:0.6;">${today}</div>
</div>
<div style="background:#fff;padding:16px;border-radius:0 0 12px 12px;">${sections}</div>
<div style="text-align:center;padding:10px;font-size:11px;color:#999;">⚠️ AI 참고자료 · 투자권유 아님 · © 2026 PlanX</div>
</div>`;
}
function sendEmail(html) {
const titles = { daily:'일간 시황', weekly:'주간 시장', monthly:'월간 전략' };
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd');
GmailApp.sendEmail(CONFIG.RECIPIENTS, `[PlanX] ${titles[CONFIG.REPORT_TYPE]} (${today})`, '', {
htmlBody: html, name: 'PlanX AI 리포트'
});
}
function testRun() {
generateReport();
Logger.log('발송 완료!');
}
📋 스크립트 전체 복사
📋 Apps Script — 🟠 클로드
Google 스프레드시트 → 확장 프로그램 → Apps Script에 붙여넣기
SCRIPT
// ══════════════════════════════════════════
// PlanX 시황 리포트 — CLAUDE 테마 (monthly)
// Gemini 2.5 Flash + Apps Script
// ══════════════════════════════════════════
const CONFIG = {
GEMINI_API_KEY: 'YOUR_GEMINI_API_KEY', // ← API 키
MODEL: 'gemini-2.5-flash-preview-05-20',
RECIPIENTS: '[email protected] ', // ← 수신 이메일
REPORT_TYPE: 'monthly',
THEME: 'claude',
};
function generateReport() {
const prompt = `Analyze monthly Korean stock strategy. Return JSON: {"last_month_review":{"kospi_monthly":"","hotpick_avg":""},"macro_outlook":[{"factor":"","outlook":""}],"allocation":[{"asset":"","weight":""}],"summary":["","",""]}`;
const data = callGemini(prompt);
const html = buildHTML(data);
sendEmail(html);
}
function callGemini(prompt) {
const url = `https://generativelanguage.googleapis.com/v1beta/models/${CONFIG.MODEL}:generateContent?key=${CONFIG.GEMINI_API_KEY}`;
const payload = {
contents: [{ parts: [{ text: prompt }] }],
generationConfig: { temperature: 0.3, responseMimeType: "application/json" }
};
const res = UrlFetchApp.fetch(url, {
method: 'post', contentType: 'application/json',
payload: JSON.stringify(payload), muteHttpExceptions: true
});
const result = JSON.parse(res.getContentText());
return JSON.parse(result.candidates[0].content.parts[0].text);
}
function buildHTML(data) {
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd (E) · a h:mm');
// ── 여기에 테마별 HTML 조립 로직 ──
// data 객체에서 각 섹션을 HTML 테이블로 변환
// 색상/레이아웃은 테마에 맞게 적용
let sections = '';
if (CONFIG.REPORT_TYPE === 'daily') {
const m = data.market_overview;
const picks = data.hot_picks.map((p,i) =>
`<tr><td style="padding:8px;font-weight:700;">{['①','②','③'][i]}</td>` +
`<td style="padding:8px;font-weight:700;">${p.name}</td>` +
`<td style="padding:8px;">${p.reason}</td>` +
`<td style="padding:8px;"><span style="background:#1a73e8;color:#fff;padding:2px 8px;border-radius:8px;font-size:12px;">${p.strategy}</span></td></tr>`
).join('');
const kws = data.keywords.map(k =>
`<tr><td style="padding:8px;font-weight:700;">${k.keyword}</td><td style="padding:8px;">→ ${k.related_stocks}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 시황 개요</h3>
<table style="width:100%;"><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${m.kospi} ${m.kospi_change}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${m.kosdaq_change}</b></td>
</tr><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">외국인<br><b>${m.foreign_flow}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">기관<br><b>${m.institution_flow}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">💡 ${m.mood}</div>
<h3 style="margin:16px 0 8px;">🔥 핫픽 종목</h3>
<table style="width:100%;">${picks}</table>
<h3 style="margin:16px 0 8px;">🗝️ 핵심 키워드</h3>
<table style="width:100%;">${kws}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'weekly') {
const wp = data.weekly_performance;
const sr = data.sector_ranking;
const evts = data.next_week_events.map(e =>
`<tr><td style="padding:6px;font-weight:700;">${e.day}</td><td style="padding:6px;">${e.event}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 주간 성적</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${wp.kospi_weekly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${wp.kosdaq_weekly}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">📌 ${wp.top_issue}</div>
<h3 style="margin:16px 0 8px;">🏆 섹터 성적</h3>
<div>🏆 최강: ${sr.best}</div><div>😞 최약: ${sr.worst}</div>
<h3 style="margin:16px 0 8px;">📅 다음 주 일정</h3>
<table style="width:100%;">${evts}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'monthly') {
const lr = data.last_month_review;
const mc = data.macro_outlook.map(m =>
`<tr><td style="padding:6px;font-weight:700;">${m.factor}</td><td style="padding:6px;">${m.outlook}</td></tr>`
).join('');
const al = data.allocation.map(a =>
`<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">${a.asset}<br><b>${a.weight}</b></td>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 전월 리뷰</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${lr.kospi_monthly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">핫픽 평균<br><b style="color:#d93025;">${lr.hotpick_avg}</b></td>
</tr></table>
<h3 style="margin:16px 0 8px;">🌍 거시경제</h3>
<table style="width:100%;">${mc}</table>
<h3 style="margin:16px 0 8px;">💼 자산 배분</h3>
<table style="width:100%;"><tr>${al}</tr></table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
return `<div style="max-width:480px;margin:0 auto;font-family:sans-serif;">
<div style="background:#1a73e8;color:#fff;padding:16px;text-align:center;border-radius:12px 12px 0 0;">
<div style="font-size:11px;opacity:0.7;letter-spacing:2px;">PLANX AI</div>
<div style="font-size:20px;font-weight:900;">${
CONFIG.REPORT_TYPE==='daily'?'일간 시황':'weekly'?'주간 시장':'월간 전략'
} 리포트</div>
<div style="font-size:12px;opacity:0.6;">${today}</div>
</div>
<div style="background:#fff;padding:16px;border-radius:0 0 12px 12px;">${sections}</div>
<div style="text-align:center;padding:10px;font-size:11px;color:#999;">⚠️ AI 참고자료 · 투자권유 아님 · © 2026 PlanX</div>
</div>`;
}
function sendEmail(html) {
const titles = { daily:'일간 시황', weekly:'주간 시장', monthly:'월간 전략' };
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd');
GmailApp.sendEmail(CONFIG.RECIPIENTS, `[PlanX] ${titles[CONFIG.REPORT_TYPE]} (${today})`, '', {
htmlBody: html, name: 'PlanX AI 리포트'
});
}
function testRun() {
generateReport();
Logger.log('발송 완료!');
}
📋 스크립트 전체 복사
📋 Apps Script — 🔵 구글
Google 스프레드시트 → 확장 프로그램 → Apps Script에 붙여넣기
SCRIPT
// ══════════════════════════════════════════
// PlanX 시황 리포트 — GOOGLE 테마 (daily)
// Gemini 2.5 Flash + Apps Script
// ══════════════════════════════════════════
const CONFIG = {
GEMINI_API_KEY: 'YOUR_GEMINI_API_KEY', // ← API 키
MODEL: 'gemini-2.5-flash-preview-05-20',
RECIPIENTS: '[email protected] ', // ← 수신 이메일
REPORT_TYPE: 'daily',
THEME: 'google',
};
function generateReport() {
const prompt = `Analyze today's Korean stock market. Return JSON: {"market_overview":{"kospi":"","kospi_change":"","kosdaq_change":"","foreign_flow":"","institution_flow":"","mood":""},"hot_picks":[{"name":"","reason":"","strategy":""}],"keywords":[{"keyword":"","related_stocks":""}],"summary":["","",""]}`;
const data = callGemini(prompt);
const html = buildHTML(data);
sendEmail(html);
}
function callGemini(prompt) {
const url = `https://generativelanguage.googleapis.com/v1beta/models/${CONFIG.MODEL}:generateContent?key=${CONFIG.GEMINI_API_KEY}`;
const payload = {
contents: [{ parts: [{ text: prompt }] }],
generationConfig: { temperature: 0.3, responseMimeType: "application/json" }
};
const res = UrlFetchApp.fetch(url, {
method: 'post', contentType: 'application/json',
payload: JSON.stringify(payload), muteHttpExceptions: true
});
const result = JSON.parse(res.getContentText());
return JSON.parse(result.candidates[0].content.parts[0].text);
}
function buildHTML(data) {
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd (E) · a h:mm');
// ── 여기에 테마별 HTML 조립 로직 ──
// data 객체에서 각 섹션을 HTML 테이블로 변환
// 색상/레이아웃은 테마에 맞게 적용
let sections = '';
if (CONFIG.REPORT_TYPE === 'daily') {
const m = data.market_overview;
const picks = data.hot_picks.map((p,i) =>
`<tr><td style="padding:8px;font-weight:700;">{['①','②','③'][i]}</td>` +
`<td style="padding:8px;font-weight:700;">${p.name}</td>` +
`<td style="padding:8px;">${p.reason}</td>` +
`<td style="padding:8px;"><span style="background:#1a73e8;color:#fff;padding:2px 8px;border-radius:8px;font-size:12px;">${p.strategy}</span></td></tr>`
).join('');
const kws = data.keywords.map(k =>
`<tr><td style="padding:8px;font-weight:700;">${k.keyword}</td><td style="padding:8px;">→ ${k.related_stocks}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 시황 개요</h3>
<table style="width:100%;"><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${m.kospi} ${m.kospi_change}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${m.kosdaq_change}</b></td>
</tr><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">외국인<br><b>${m.foreign_flow}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">기관<br><b>${m.institution_flow}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">💡 ${m.mood}</div>
<h3 style="margin:16px 0 8px;">🔥 핫픽 종목</h3>
<table style="width:100%;">${picks}</table>
<h3 style="margin:16px 0 8px;">🗝️ 핵심 키워드</h3>
<table style="width:100%;">${kws}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'weekly') {
const wp = data.weekly_performance;
const sr = data.sector_ranking;
const evts = data.next_week_events.map(e =>
`<tr><td style="padding:6px;font-weight:700;">${e.day}</td><td style="padding:6px;">${e.event}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 주간 성적</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${wp.kospi_weekly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${wp.kosdaq_weekly}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">📌 ${wp.top_issue}</div>
<h3 style="margin:16px 0 8px;">🏆 섹터 성적</h3>
<div>🏆 최강: ${sr.best}</div><div>😞 최약: ${sr.worst}</div>
<h3 style="margin:16px 0 8px;">📅 다음 주 일정</h3>
<table style="width:100%;">${evts}</table>
background:#f8f9fa;border-radius:8px;">${a.asset}<br><b>${a.weight}</b></td>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 전월 리뷰</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${lr.kospi_monthly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">핫픽 평균<br><b style="color:#d93025;">${lr.hotpick_avg}</b></td>
</tr></table>
<h3 style="margin:16px 0 8px;">🌍 거시경제</h3>
<table style="width:100%;">${mc}</table>
<h3 style="margin:16px 0 8px;">💼 자산 배분</h3>
<table style="width:100%;"><tr>${al}</tr></table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
return `<div style="max-width:480px;margin:0 auto;font-family:sans-serif;">
<div style="background:#1a73e8;color:#fff;padding:16px;text-align:center;border-radius:12px 12px 0 0;">
<div style="font-size:11px;opacity:0.7;letter-spacing:2px;">PLANX AI</div>
<div style="font-size:20px;font-weight:900;">${
CONFIG.REPORT_TYPE==='daily'?'일간 시황':'weekly'?'주간 시장':'월간 전략'
} 리포트</div>
<div style="font-size:12px;opacity:0.6;">${today}</div>
</div>
<div style="background:#fff;padding:16px;border-radius:0 0 12px 12px;">${sections}</div>
<div style="text-align:center;padding:10px;font-size:11px;color:#999;">⚠️ AI 참고자료 · 투자권유 아님 · © 2026 PlanX</div>
</div>`;
}
function sendEmail(html) {
const titles = { daily:'일간 시황', weekly:'주간 시장', monthly:'월간 전략' };
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd');
GmailApp.sendEmail(CONFIG.RECIPIENTS, `[PlanX] ${titles[CONFIG.REPORT_TYPE]} (${today})`, '', {
htmlBody: html, name: 'PlanX AI 리포트'
});
}
function testRun() {
generateReport();
Logger.log('발송 완료!');
}
📋 스크립트 전체 복사
📋 Apps Script — 💎 PlanX
Google 스프레드시트 → 확장 프로그램 → Apps Script에 붙여넣기
SCRIPT
// ══════════════════════════════════════════
// PlanX 시황 리포트 — PLANX 테마 (weekly)
// Gemini 2.5 Flash + Apps Script
// ══════════════════════════════════════════
const CONFIG = {
GEMINI_API_KEY: 'YOUR_GEMINI_API_KEY', // ← API 키
MODEL: 'gemini-2.5-flash-preview-05-20',
RECIPIENTS: 'your@email.com', // ← 수신 이메일
REPORT_TYPE: 'weekly',
THEME: 'planx',
};
function generateReport() {
const prompt = `Analyze this week's Korean stock market. Return JSON: {"weekly_performance":{"kospi_weekly":"","kosdaq_weekly":"","top_issue":""},"sector_ranking":{"best":"","worst":""},"next_week_events":[{"day":"","event":""}],"summary":["","",""]}`;
const data = callGemini(prompt);
const html = buildHTML(data);
sendEmail(html);
}
function callGemini(prompt) {
const url = `https://generativelanguage.googleapis.com/v1beta/models/${CONFIG.MODEL}:generateContent?key=${CONFIG.GEMINI_API_KEY}`;
const payload = {
contents: [{ parts: [{ text: prompt }] }],
generationConfig: { temperature: 0.3, responseMimeType: "application/json" }
};
const res = UrlFetchApp.fetch(url, {
method: 'post', contentType: 'application/json',
payload: JSON.stringify(payload), muteHttpExceptions: true
});
const result = JSON.parse(res.getContentText());
return JSON.parse(result.candidates[0].content.parts[0].text);
}
function buildHTML(data) {
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd (E) · a h:mm');
// ── 여기에 테마별 HTML 조립 로직 ──
// data 객체에서 각 섹션을 HTML 테이블로 변환
// 색상/레이아웃은 테마에 맞게 적용
let sections = '';
if (CONFIG.REPORT_TYPE === 'daily') {
const m = data.market_overview;
const picks = data.hot_picks.map((p,i) =>
`<tr><td style="padding:8px;font-weight:700;">{['①','②','③'][i]}</td>` +
`<td style="padding:8px;font-weight:700;">${p.name}</td>` +
`<td style="padding:8px;">${p.reason}</td>` +
`<td style="padding:8px;"><span style="background:#1a73e8;color:#fff;padding:2px 8px;border-radius:8px;font-size:12px;">${p.strategy}</span></td></tr>`
).join('');
const kws = data.keywords.map(k =>
`<tr><td style="padding:8px;font-weight:700;">${k.keyword}</td><td style="padding:8px;">→ ${k.related_stocks}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 시황 개요</h3>
<table style="width:100%;"><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${m.kospi} ${m.kospi_change}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${m.kosdaq_change}</b></td>
</tr><tr>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">외국인<br><b>${m.foreign_flow}</b></td>
<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">기관<br><b>${m.institution_flow}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">💡 ${m.mood}</div>
<h3 style="margin:16px 0 8px;">🔥 핫픽 종목</h3>
<table style="width:100%;">${picks}</table>
<h3 style="margin:16px 0 8px;">🗝️ 핵심 키워드</h3>
<table style="width:100%;">${kws}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'weekly') {
const wp = data.weekly_performance;
const sr = data.sector_ranking;
const evts = data.next_week_events.map(e =>
`<tr><td style="padding:6px;font-weight:700;">${e.day}</td><td style="padding:6px;">${e.event}</td></tr>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 주간 성적</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${wp.kospi_weekly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSDAQ<br><b style="color:#d93025;">${wp.kosdaq_weekly}</b></td>
</tr></table>
<div style="background:#e8f0fe;padding:10px;border-radius:8px;margin:8px 0;">📌 ${wp.top_issue}</div>
<h3 style="margin:16px 0 8px;">🏆 섹터 성적</h3>
<div>🏆 최강: ${sr.best}</div><div>😞 최약: ${sr.worst}</div>
<h3 style="margin:16px 0 8px;">📅 다음 주 일정</h3>
<table style="width:100%;">${evts}</table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
if (CONFIG.REPORT_TYPE === 'monthly') {
const lr = data.last_month_review;
const mc = data.macro_outlook.map(m =>
`<tr><td style="padding:6px;font-weight:700;">${m.factor}</td><td style="padding:6px;">${m.outlook}</td></tr>`
).join('');
const al = data.allocation.map(a =>
`<td style="padding:8px;text-align:center;background:#f8f9fa;border-radius:8px;">${a.asset}<br><b>${a.weight}</b></td>`
).join('');
const sum = data.summary.map((s,i) => `<div style="padding:4px 0;">${i+1}. ${s}</div>`).join('');
sections = `
<h3 style="margin:16px 0 8px;">📊 전월 리뷰</h3>
<table style="width:100%;"><tr>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">KOSPI<br><b style="color:#d93025;">${lr.kospi_monthly}</b></td>
<td style="padding:10px;text-align:center;background:#f8f9fa;border-radius:8px;">핫픽 평균<br><b style="color:#d93025;">${lr.hotpick_avg}</b></td>
</tr></table>
<h3 style="margin:16px 0 8px;">🌍 거시경제</h3>
<table style="width:100%;">${mc}</table>
<h3 style="margin:16px 0 8px;">💼 자산 배분</h3>
<table style="width:100%;"><tr>${al}</tr></table>
<h3 style="margin:16px 0 8px;">📝 총평</h3>${sum}`;
}
return `<div style="max-width:480px;margin:0 auto;font-family:sans-serif;">
<div style="background:#1a73e8;color:#fff;padding:16px;text-align:center;border-radius:12px 12px 0 0;">
<div style="font-size:11px;opacity:0.7;letter-spacing:2px;">PLANX AI</div>
<div style="font-size:20px;font-weight:900;">${
CONFIG.REPORT_TYPE==='daily'?'일간 시황':'weekly'?'주간 시장':'월간 전략'
} 리포트</div>
<div style="font-size:12px;opacity:0.6;">${today}</div>
</div>
<div style="background:#fff;padding:16px;border-radius:0 0 12px 12px;">${sections}</div>
<div style="text-align:center;padding:10px;font-size:11px;color:#999;">⚠️ AI 참고자료 · 투자권유 아님 · © 2026 PlanX</div>
</div>`;
}
function sendEmail(html) {
const titles = { daily:'일간 시황', weekly:'주간 시장', monthly:'월간 전략' };
const today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy.MM.dd');
GmailApp.sendEmail(CONFIG.RECIPIENTS, `[PlanX] ${titles[CONFIG.REPORT_TYPE]} (${today})`, '', {
htmlBody: html, name: 'PlanX AI 리포트'
});
}
function testRun() {
generateReport();
Logger.log('발송 완료!');
}
📋 스크립트 전체 복사
📊 시황 자동화 스크립트 모음
결과물을 확인하고 스크립트를 복사하세요.
📊 시황 요약
🏭 섹터 분석
🔍 종목 분석
🌅 장전 기대 섹터
🌙 장후 특징 종목
주요 지수 + 매크로 + 수급 + 시나리오
📊 시황 요약 리포트
2026.03.20 · 네이버증권 + GOOGLEFINANCE 실시간
핵심 한줄
코스피 5,763 (-2.73%), 중동 리스크+매파 연준에 글로벌 동반 약세
📈 주요 지수 (실시간)
KOSPI
5,763
▼ 161.81 (-2.73%)
KOSDAQ
1,143
▼ 20.90 (-1.79%)
S&P 500
6,577
▼ 47 (-0.71%)
💰 투자자별 매매동향
🌍
외국인
순매도
-1조 8,000억
중동 리스크+환차손 우려로 대규모 매도세
🏦
기관
순매도
-6,659억
외국인 동반 매도에 경계심, 차익 실현
👤
개인
순매수
+2조 4,000억
저가 매수 기회 활용, 시장 하단 방어
🔥 주목 종목 (AI 분석)
1
CJ
매수
비상장 자회사 호실적 + 지배구조 개편 기대감
2
에이디테크놀로지
매수
삼성 파운드리 DSP 전환 대규모 수주, AI/HPC 고부가 비중 급증
3
브이엠
매수
SK하이닉스 M15x 신규 투자 및 미세공정 전환 수혜 집중
🏷️ 핵심 키워드
중동 지정학적 리스크
→
유가 관련주, 방산주
반도체 업황 회복
→
삼성전자, SK하이닉스, 에이디테크놀로지
금리 인하 지연/고환율
→
은행주, 보험주, 수출주
📝 총평
📊
중동 리스크 확산과 매파적 연준 기조에 글로벌 증시 동반 약세
💰
반도체·방산 섹터 상대적 강세, 2차전지·소비재 약세 지속
🔮
급락 이후 기술적 반등 가능성 존재, 분할 매수 전략 추천
⚠️ AI 분석 참고자료 · 투자 판단과 책임은 본인에게 있습니다
데이터: 네이버증권 + GOOGLEFINANCE · 분석: Gemini 2.5 Flash
© 2026 PlanX Solution
샘플 미리보기 · 실제 발송 시 실시간 데이터 반영
';
}
// 키워드 — 태그형
var kws=ai.keywords||[], kwH='';
var kwColors = ['#1a73e8','#7C3AED','#059669','#D97706','#DC2626'];
for(var i=0;i
';
kwH+=''+kws[i].keyword+' ';
kwH+='→ ';
kwH+=''+kws[i].related+' ';
kwH+=' ';
}
// 총평 — 번호 카드형
var sums=ai.summary||[], smH='';
var sumIcons = ['📊','💰','🔮'];
for(var i=0;i
';
smH+=''+(sumIcons[i]||'📌')+'
';
smH+=''+sums[i]+'
';
smH+=' ';
}
// 조립
var h='';
// 헤더
h+='
';
h+='
PlanX
';
h+='
📊 시황 요약 리포트
';
h+='
'+today+' · 네이버증권+구글파이낸스 실시간
';
h+='
'+(ai.mood||'')+' '+(ai.mood_score||'')+'점 ';
h+=''+(ai.trend||'')+'
';
h+='
💡 '+(ai.one_line||'')+'
';
h+='
';
// 본문
h+='
';
h+=sec('📈','주요 지수 (실시간)');
h+='
'+th(['지수','현재','전일대비','등락률'])+idxR+'
';
h+=sec('💰','투자자별 매매동향');
h+='
'+monR+'
';
h+=sec('🔥','주목 종목 (AI 분석)');
h+='
'+pkR+'
';
h+=sec('🏷️','핵심 키워드');
h+='
'+kwH+'
';
h+=sec('📝','총평');
h+='
'+smH+'
';
h+='
';
// 푸터
h+='
';
h+='
⚠️ AI 분석 참고자료 · 투자 판단과 책임은 본인에게 있습니다
';
h+='
시세: 네이버증권+GOOGLEFINANCE · 분석: Gemini
';
h+='
© 2026 PlanX
';
h+='
';
return h;
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 실행 함수들
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
function run_market() {
Logger.log('📡 1단계: 시세 수집...');
var md = fetchMarketData();
Logger.log('코스피: ' + md.kospi.value + ' / 코스닥: ' + md.kosdaq.value);
Logger.log('S&P500: ' + md.sp500.value + ' / 나스닥: ' + md.nasdaq.value);
Logger.log('원달러: ' + md.usdkrw.value);
Logger.log('🤖 2단계: Gemini 분석...');
var prompt = buildPrompt(md);
var ai = callGemini(prompt);
Logger.log('분위기: ' + ai.mood + ' ' + ai.mood_score + '점');
Logger.log('📧 3단계: 이메일 발송...');
var html = buildHTML(ai, md);
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy-MM-dd');
MailApp.sendEmail({
to: CONFIG.SEND_TO,
subject: '[PlanX] 📊 시황요약 (' + today + ')',
htmlBody: html
});
Logger.log('✅ 완료!');
}
// ▶ 이 함수를 실행하세요
function testRun() {
run_market();
}
// 시세만 테스트 (API키 없이도 실행 가능)
function testFetchData() {
var d = fetchMarketData();
Logger.log('=== 국내 (네이버증권) ===');
Logger.log('코스피: ' + d.kospi.value + ' (' + d.kospi.change + ', ' + d.kospi.changePercent + '%)');
Logger.log('코스닥: ' + d.kosdaq.value + ' (' + d.kosdaq.change + ', ' + d.kosdaq.changePercent + '%)');
Logger.log('=== 해외 (GOOGLEFINANCE) ===');
Logger.log('S&P500: ' + d.sp500.value + ' (' + d.sp500.change + ', ' + d.sp500.changePercent + '%)');
Logger.log('나스닥: ' + d.nasdaq.value + ' (' + d.nasdaq.change + ', ' + d.nasdaq.changePercent + '%)');
Logger.log('다우: ' + d.dji.value + ' (' + d.dji.change + ', ' + d.dji.changePercent + '%)');
Logger.log('=== 환율 ===');
Logger.log('원/달러: ' + d.usdkrw.value + ' (' + d.usdkrw.change + ')');
Logger.log('=== 수급 ===');
Logger.log('외국인: ' + d.investor.foreigner);
Logger.log('기관: ' + d.investor.institution);
Logger.log('개인: ' + d.investor.individual);
}
SCRIPT
// =============================================
// 📊 PlanX 시황 요약 리포트 v3 (최종)
//
// 시세: 네이버증권(국내) + GOOGLEFINANCE(해외/환율)
// 분석: Gemini AI (Google Search grounding)
//
// [사용법]
// 1. Google 스프레드시트에서 확장프로그램 → Apps Script
// 2. 이 코드 전체를 붙여넣기
// 3. CONFIG에서 API키와 이메일만 수정
// 4. testFetchData 먼저 실행 → 시세 확인
// 5. testRun 실행 → 이메일 발송
// =============================================
var CONFIG = {
GEMINI_API_KEY: '여기에_API키_붙여넣기',
MODEL: 'gemini-2.5-flash',
SEND_TO: '여기에_이메일_입력',
};
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 1단계: 시세 데이터 수집
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 네이버 증권 API (국내 지수)
function fetchNaverIndex(market) {
try {
var url = 'https://m.stock.naver.com/api/index/' + market + '/basic';
var res = UrlFetchApp.fetch(url, {muteHttpExceptions: true});
var j = JSON.parse(res.getContentText());
return {
value: j.closePrice || '',
change: j.compareToPreviousClosePrice || '',
changePercent: j.fluctuationsRatio || '',
date: j.localTradedAt || ''
};
} catch(e) {
return {value: '-', change: '-', changePercent: '-'};
}
}
// Google Sheets GOOGLEFINANCE (해외 지수, 환율)
function fetchGoogleFinance(ticker) {
try {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var tempSheet = ss.getSheetByName('_temp_finance');
if (!tempSheet) {
tempSheet = ss.insertSheet('_temp_finance');
}
// 현재가
tempSheet.getRange('A1').setFormula('=GOOGLEFINANCE("' + ticker + '","price")');
// 전일 종가
tempSheet.getRange('A2').setFormula('=GOOGLEFINANCE("' + ticker + '","closeyest")');
SpreadsheetApp.flush();
Utilities.sleep(2000); // 데이터 로딩 대기
var price = tempSheet.getRange('A1').getValue();
var prevClose = tempSheet.getRange('A2').getValue();
// #N/A 또는 에러 체크
if (!price || typeof price === 'string' && price.indexOf('N/A') >= 0) {
tempSheet.clear();
return {value: '-', change: '-', changePercent: '-'};
}
var change = 0;
var changePct = 0;
if (price && prevClose && prevClose !== 0) {
change = price - prevClose;
changePct = (change / prevClose) * 100;
}
// 정리
tempSheet.clear();
return {
value: typeof price === 'number' ? price.toFixed(2) : String(price),
change: change >= 0 ? '+' + change.toFixed(2) : change.toFixed(2),
changePercent: changePct >= 0 ? '+' + changePct.toFixed(2) : changePct.toFixed(2)
};
} catch(e) {
return {value: '-', change: '-', changePercent: '-'};
}
}
// 전체 시세 수집
function fetchMarketData() {
var data = {};
// 국내 (네이버 증권 - 정확)
data.kospi = fetchNaverIndex('KOSPI');
data.kosdaq = fetchNaverIndex('KOSDAQ');
// 해외 (GOOGLEFINANCE)
data.sp500 = fetchGoogleFinance('.INX');
data.nasdaq = fetchGoogleFinance('.IXIC');
data.dji = fetchGoogleFinance('.DJI');
// 환율 (여러 방법 시도)
data.usdkrw = fetchExchangeRate();
// 투자자별 매매동향 (네이버)
data.investor = fetchInvestorFlow();
return data;
}
// 환율 수집 (네이버 시장지표 크롤링)
function fetchExchangeRate() {
// 방법1: 네이버 시장지표 HTML 크롤링
try {
var url = 'https://finance.naver.com/marketindex/';
var res = UrlFetchApp.fetch(url, {
muteHttpExceptions: true,
headers: {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'}
});
var html = res.getContentText();
// 원/달러 환율 추출 (첫 번째 blind 값이 USD/KRW)
var matches = html.match(/class="value">[0-9,\.]+/g);
if (matches && matches.length > 0) {
var val = matches[0].replace('class="value">', '');
// 등락폭 추출
var changeMatches = html.match(/class="change">[0-9,\.]+/g);
var chg = changeMatches && changeMatches[0] ? changeMatches[0].replace('class="change">', '') : '';
// 상승/하락 판단
var isDown = html.indexOf('ico_down') < html.indexOf('ico_up') || html.indexOf('downdown') > -1;
return {
value: val,
change: chg ? (isDown ? '-' + chg : '+' + chg) : '',
changePercent: ''
};
}
} catch(e) { Logger.log('네이버 환율 크롤링 실패: ' + e.message); }
// 방법2: 두나무 API
try {
var url2 = 'https://quotation-api-cdn.dunamu.com/v1/forex/recent?codes=FRX.KRWUSD';
var res2 = UrlFetchApp.fetch(url2, {muteHttpExceptions: true});
if (res2.getResponseCode() === 200) {
var j = JSON.parse(res2.getContentText());
if (j && j[0]) {
return {
value: String(j[0].basePrice || ''),
change: String(j[0].change || ''),
changePercent: String(j[0].changePercent || '')
};
}
}
} catch(e) {}
// 방법3: GOOGLEFINANCE
var tickers = ['USDKRW', 'KRW=X', 'CURRENCY:USDKRW'];
for (var i = 0; i < tickers.length; i++) {
try {
var r = fetchGoogleFinance(tickers[i]);
if (r.value && r.value !== '-' && String(r.value).indexOf('N/A') < 0) return r;
} catch(e) {}
}
return {value: 'Gemini 검색', change: '-', changePercent: '-'};
}
function fetchInvestorFlow() {
try {
var url = 'https://m.stock.naver.com/api/index/KOSPI/investorBuySellDaily';
var res = UrlFetchApp.fetch(url, {muteHttpExceptions: true});
var json = JSON.parse(res.getContentText());
if (json && json.length > 0) {
var latest = json[0];
return {
foreigner: latest.foreignerPureBuyQuant || 0,
institution: latest.institutionPureBuyQuant || 0,
individual: latest.individualPureBuyQuant || 0,
date: latest.tradingDate || ''
};
}
} catch(e) {}
// 실패 시 Gemini에게 맡기기
return {foreigner: 'API 미제공', institution: 'API 미제공', individual: 'API 미제공', date: ''};
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 2단계: Gemini 분석
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
function callGemini(prompt) {
if (!prompt) throw new Error('프롬프트가 비어있습니다.');
var url = 'https://generativelanguage.googleapis.com/v1beta/models/'
+ CONFIG.MODEL + ':generateContent?key=' + CONFIG.GEMINI_API_KEY;
var res = UrlFetchApp.fetch(url, {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({
contents: [{parts: [{text: String(prompt)}]}],
generationConfig: {temperature: 0.3},
tools: [{google_search: {}}]
}),
muteHttpExceptions: true
});
var code = res.getResponseCode();
var raw = res.getContentText();
if (code !== 200) throw new Error('Gemini 오류 (' + code + '): ' + raw.substring(0, 300));
var data = JSON.parse(raw);
var text = '';
var parts = data.candidates[0].content.parts || [];
for (var i = 0; i < parts.length; i++) {
if (parts[i].text) text += parts[i].text;
}
text = text.replace(/```json/g, '').replace(/```/g, '').trim();
var jsonStart = text.indexOf('{');
var jsonEnd = text.lastIndexOf('}');
if (jsonStart >= 0 && jsonEnd > jsonStart) {
text = text.substring(jsonStart, jsonEnd + 1);
}
try {
return JSON.parse(text);
} catch(e) {
throw new Error('JSON 파싱 실패. 응답: ' + text.substring(0, 300));
}
}
function buildPrompt(md) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 (E)');
var invText = '';
if (md.investor.foreigner !== 'API 미제공') {
var f = Number(md.investor.foreigner);
var inst = Number(md.investor.institution);
var ind = Number(md.investor.individual);
invText = '외국인: ' + (f >= 0 ? '순매수 ' : '순매도 ') + Math.abs(Math.round(f/100000000)).toLocaleString() + '억원';
invText += ' / 기관: ' + (inst >= 0 ? '순매수 ' : '순매도 ') + Math.abs(Math.round(inst/100000000)).toLocaleString() + '억원';
invText += ' / 개인: ' + (ind >= 0 ? '순매수 ' : '순매도 ') + Math.abs(Math.round(ind/100000000)).toLocaleString() + '억원';
} else {
invText = '(수급 데이터 API 미제공. 반드시 구글 검색으로 오늘 코스피 외국인/기관/개인 순매수 순매도 금액을 KRX/네이버증권에서 확인하여 정확한 수치를 제공하라.)';
}
var p = '';
p += '[필수 지침]\n';
p += '1. 모든 응답은 반드시 한국어. 영어 절대 금지.\n';
p += '2. 아래 실시간 시세는 네이버증권/구글파이낸스에서 가져온 정확한 데이터다. 그대로 사용.\n';
p += '3. 분석/해석/종목추천만 네가 담당. 시세 수치는 절대 변경하지 마라.\n';
p += '4. 구글 검색으로 오늘 주요 뉴스, 공시, 증권사 리포트를 확인하여 반영.\n';
p += '5. 증권사 리포트 (미래에셋, 삼성, KB, 한투, NH) 분석 참조.\n';
p += '6. 매크로(금리/환율/유가) + 수급 + 테마 관점 종합 분석.\n';
p += '7. 반드시 오늘(' + today + ') 데이터만 사용. 전일 데이터를 오늘로 혼동 금지.\n\n';
p += '[날짜] ' + today + '\n\n';
p += '[실시간 시세 데이터]\n';
p += '코스피: ' + md.kospi.value + ' (전일대비 ' + md.kospi.change + ', ' + md.kospi.changePercent + '%) [기준: ' + (md.kospi.date||today) + ']\n';
p += '코스닥: ' + md.kosdaq.value + ' (전일대비 ' + md.kosdaq.change + ', ' + md.kosdaq.changePercent + '%) [기준: ' + (md.kosdaq.date||today) + ']\n';
p += 'S&P500: ' + md.sp500.value + ' (' + md.sp500.change + ', ' + md.sp500.changePercent + '%)\n';
p += '나스닥: ' + md.nasdaq.value + ' (' + md.nasdaq.change + ', ' + md.nasdaq.changePercent + '%)\n';
p += '다우: ' + md.dji.value + ' (' + md.dji.change + ', ' + md.dji.changePercent + '%)\n';
var fxText = md.usdkrw.value;
if (!fxText || fxText === 'Gemini 검색' || fxText === '-') {
p += '원/달러: (구글 검색으로 확인)\n';
} else {
p += '원/달러: ' + md.usdkrw.value + ' (' + md.usdkrw.change + ')\n';
}
p += '수급: ' + invText + '\n\n';
p += '[역할] 증권사 수석 스트래티지스트. 기관 투자자 대상 시황 리포트.\n\n';
p += '[분석 요구사항]\n';
p += '- 시장 분위기: 공포/탐욕/관망/혼조 판단 + 근거 (VIX, 풋콜비율 등)\n';
p += '- 수급 해석: 외국인/기관/개인 각각의 매매 의미와 향후 수급 전망\n';
p += '- 주목 종목 3개: 증권사 리포트/수급/테마 기반, 구체적 매매 전략 포함\n';
p += '- 키워드 3개: 오늘 시장을 움직인 핵심 테마 + 관련 종목 체인\n';
p += '- 총평 3문장: (1)시장 핵심 (2)수급 해석 (3)내일 전략\n\n';
p += 'JSON으로만 응답:\n{\n';
p += ' "one_line": "시장 한줄 요약 (위 시세 수치 반드시 포함)",\n';
p += ' "mood": "공포/탐욕/관망/혼조",\n';
p += ' "mood_score": 50,\n';
p += ' "trend": "상승/하락/횡보",\n';
p += ' "investor_flow": {\n';
p += ' "foreigner": {"action":"순매수/순매도","amount":"X,XXX억원","analysis":"외국인 매매 배경과 의미 + 향후 전망 2문장"},\n';
p += ' "institution": {"action":"순매수/순매도","amount":"X,XXX억원","analysis":"기관 매매 배경과 의미 2문장"},\n';
p += ' "individual": {"action":"순매수/순매도","amount":"X,XXX억원","analysis":"개인 매매 특징과 시사점 2문장"}\n';
p += ' },\n';
p += ' "hot_picks": [\n';
p += ' {"name":"종목명","reason":"구체적 이유 (수급+실적+테마 근거)","strategy":"매수/관망/주의 + 목표가 또는 기준가"},\n';
p += ' {"name":"종목명","reason":"구체적 이유","strategy":"매수/관망/주의"},\n';
p += ' {"name":"종목명","reason":"구체적 이유","strategy":"매수/관망/주의"}\n';
p += ' ],\n';
p += ' "keywords": [\n';
p += ' {"keyword":"테마 키워드","related":"관련 종목 3~5개","catalyst":"촉매 이벤트"},\n';
p += ' {"keyword":"테마 키워드","related":"관련 종목","catalyst":"촉매"},\n';
p += ' {"keyword":"테마 키워드","related":"관련 종목","catalyst":"촉매"}\n';
p += ' ],\n';
p += ' "summary": ["총평1 (시장 핵심 흐름 + 수치)","총평2 (수급 분석 + 의미)","총평3 (내일 전략 + 주목 포인트)"]\n';
p += '}';
p += '\n\n위 JSON 형식으로만 응답하라. JSON 외에 어떤 텍스트도 포함하지 마라. 순수 JSON만 출력.';
return p;
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 3단계: HTML 이메일 빌더
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
function buildHTML(ai, md) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 (E) HH:mm');
var moodColors = {'공포':'#DC2626','탐욕':'#16A34A','관망':'#78716C','혼조':'#D97706'};
var moodColor = moodColors[ai.mood] || '#78716C';
function chgColor(v) { return String(v||'').indexOf('-')>=0 ? '#DC2626' : '#16A34A'; }
function sec(icon, title) { return '<div style="background:#0B1426;color:#F5A623;padding:8px 14px;font-size:14px;font-weight:bold;border-radius:6px;margin-top:18px;">'+icon+' '+title+'</div>'; }
function th(cols) {
var h='<tr style="background:#1E293B;color:#CBD5E1;">';
for(var i=0;i<cols.length;i++) h+='<th style="padding:7px 12px;text-align:left;font-weight:500;">'+cols[i]+'</th>';
return h+'</tr>';
}
// 지수 테이블 (실제 데이터)
var indices = [
{n:'코스피',d:md.kospi}, {n:'코스닥',d:md.kosdaq},
{n:'S&P500',d:md.sp500}, {n:'나스닥',d:md.nasdaq},
{n:'다우',d:md.dji}, {n:'원/달러',d:md.usdkrw}
];
var idxR = '';
for(var i=0;i<indices.length;i++){
var x=indices[i], d=x.d||{}, bg=i%2===0?'#fff':'#F8FAFC', cc=chgColor(d.change);
idxR+='<tr style="background:'+bg+';"><td style="padding:8px 12px;font-weight:600;border-bottom:1px solid #E2E8F0;">'+x.n+'</td>';
idxR+='<td style="padding:8px 12px;font-weight:bold;border-bottom:1px solid #E2E8F0;">'+(d.value||'-')+(d.date?' <span style="font-size:10px;color:#94A3B8;">('+d.date.substring(5)+')</span>':'')+'</td>';
idxR+='<td style="padding:8px 12px;color:'+cc+';font-weight:bold;border-bottom:1px solid #E2E8F0;">'+(d.change||'-')+'</td>';
idxR+='<td style="padding:8px 12px;color:'+cc+';border-bottom:1px solid #E2E8F0;">'+(d.changePercent?d.changePercent+'%':'-')+'</td></tr>';
}
// 수급 테이블 (API 데이터 또는 AI 분석) — 카드형 디자인
var inv = md.investor||{};
var aiInv = ai.investor_flow||{};
var monR = '';
function fmtB(v){
var n=Number(v); if(isNaN(n)) return String(v);
var b=Math.round(n/100000000);
var formatted = Math.abs(b).toLocaleString ? Math.abs(b).toLocaleString() : Math.abs(b);
return (b>=0?'+':'-') + formatted + '억원';
}
var investorList = [
{name:'외국인', emoji:'🌍', apiVal:inv.foreigner, aiData:aiInv.foreigner},
{name:'기관', emoji:'🏦', apiVal:inv.institution, aiData:aiInv.institution},
{name:'개인', emoji:'👤', apiVal:inv.individual, aiData:aiInv.individual}
];
for(var i=0;i<investorList.length;i++){
var item=investorList[i];
var action, amount, analysis, actionColor, actionBg;
if(item.apiVal && item.apiVal !== 'API 미제공') {
var n = Number(item.apiVal);
action = n >= 0 ? '순매수' : '순매도';
actionColor = n >= 0 ? '#16A34A' : '#DC2626';
actionBg = n >= 0 ? '#DCFCE7' : '#FEE2E2';
amount = fmtB(item.apiVal);
analysis = (item.aiData && item.aiData.analysis) ? item.aiData.analysis : '';
} else {
var ad = item.aiData || {};
action = ad.action || '-';
actionColor = (action.indexOf('매수')>=0) ? '#16A34A' : (action.indexOf('매도')>=0) ? '#DC2626' : '#78716C';
actionBg = (action.indexOf('매수')>=0) ? '#DCFCE7' : (action.indexOf('매도')>=0) ? '#FEE2E2' : '#F3F4F6';
amount = ad.amount || '(AI 추정)';
analysis = ad.analysis || '';
}
monR+='<div style="display:flex;align-items:flex-start;gap:12px;padding:14px 16px;border-bottom:1px solid #F1F5F9;'+(i===0?'':'')+ '">';
monR+='<div style="flex-shrink:0;width:44px;height:44px;border-radius:10px;background:'+actionBg+';display:flex;align-items:center;justify-content:center;font-size:20px;">'+item.emoji+'</div>';
monR+='<div style="flex:1;min-width:0;">';
monR+='<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px;">';
monR+='<span style="font-size:15px;font-weight:700;color:#0F172A;">'+item.name+'</span>';
monR+='<span style="background:'+actionBg+';color:'+actionColor+';padding:2px 10px;border-radius:12px;font-size:12px;font-weight:700;">'+action+'</span>';
monR+='<span style="font-size:15px;font-weight:800;color:'+actionColor+';">'+amount+'</span>';
monR+='</div>';
if(analysis) {
monR+='<div style="font-size:13px;color:#64748B;line-height:1.6;">'+analysis+'</div>';
}
monR+='</div></div>';
}
// 종목 — 카드형
var picks=ai.hot_picks||[], pkR='';
var strategyStyle = {
'매수': 'background:#DCFCE7;color:#16A34A;',
'관망': 'background:#FEF3C7;color:#92400E;',
'주의': 'background:#FEE2E2;color:#DC2626;'
};
for(var i=0;i<picks.length;i++){
var p=picks[i];
var sStyle = strategyStyle[p.strategy] || 'background:#EFF6FF;color:#1D4ED8;';
pkR+='<div style="padding:14px 16px;border-bottom:1px solid #F1F5F9;">';
pkR+='<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">';
pkR+='<span style="background:#0B1426;color:#F5A623;width:26px;height:26px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:800;flex-shrink:0;">'+(i+1)+'</span>';
pkR+='<span style="font-size:16px;font-weight:800;color:#0F172A;">'+p.name+'</span>';
pkR+='<span style="'+sStyle+'padding:2px 12px;border-radius:12px;font-size:12px;font-weight:700;margin-left:auto;">'+p.strategy+'</span>';
pkR+='</div>';
pkR+='<div style="font-size:13px;color:#475569;line-height:1.7;padding-left:34px;">'+p.reason+'</div>';
pkR+='</div>';
}
// 키워드 — 태그형
var kws=ai.keywords||[], kwH='';
var kwColors = ['#1a73e8','#7C3AED','#059669','#D97706','#DC2626'];
for(var i=0;i<kws.length;i++){
var kc = kwColors[i % kwColors.length];
kwH+='<div style="padding:10px 14px;border-left:4px solid '+kc+';background:#F8FAFC;border-radius:0 8px 8px 0;margin:6px 0;">';
kwH+='<span style="font-size:14px;font-weight:700;color:'+kc+';">'+kws[i].keyword+'</span>';
kwH+='<span style="color:#94A3B8;margin:0 6px;">→</span>';
kwH+='<span style="font-size:13px;color:#475569;">'+kws[i].related+'</span>';
kwH+='</div>';
}
// 총평 — 번호 카드형
var sums=ai.summary||[], smH='';
var sumIcons = ['📊','💰','🔮'];
for(var i=0;i<sums.length;i++){
smH+='<div style="display:flex;gap:10px;padding:10px 0;'+(i<sums.length-1?'border-bottom:1px solid #F1F5F9;':'')+'">';
smH+='<div style="flex-shrink:0;width:32px;height:32px;border-radius:8px;background:#EFF6FF;display:flex;align-items:center;justify-content:center;font-size:16px;">'+(sumIcons[i]||'📌')+'</div>';
smH+='<div style="font-size:14px;color:#334155;line-height:1.8;">'+sums[i]+'</div>';
smH+='</div>';
}
// 조립
var h='<div style="max-width:680px;margin:16px auto;font-family:Arial,sans-serif;">';
// 헤더
h+='<div style="background:linear-gradient(135deg,#0B1426,#1E3A5F);padding:20px 24px;border-radius:12px 12px 0 0;">';
h+='<div style="display:inline-block;background:#1a73e8;color:white;font-size:12px;font-weight:900;padding:3px 12px;border-radius:5px;letter-spacing:1.5px;">PlanX</div>';
h+='<div style="color:#F5A623;font-size:20px;font-weight:bold;margin-top:10px;">📊 시황 요약 리포트</div>';
h+='<div style="color:#94A3B8;font-size:12px;margin-top:2px;">'+today+' · 네이버증권+구글파이낸스 실시간</div>';
h+='<div style="margin-top:10px;"><span style="background:'+moodColor+';color:white;padding:4px 16px;border-radius:20px;font-size:14px;font-weight:bold;">'+(ai.mood||'')+' '+(ai.mood_score||'')+'점</span>';
h+='<span style="color:#94A3B8;font-size:12px;margin-left:10px;">'+(ai.trend||'')+'</span></div>';
h+='<div style="background:rgba(255,255,255,0.08);border-radius:8px;padding:12px 16px;margin-top:14px;"><span style="color:#F5A623;font-size:15px;font-weight:bold;">💡 '+(ai.one_line||'')+'</span></div>';
h+='</div>';
// 본문
h+='<div style="background:#fff;border:1px solid #E2E8F0;padding:20px;">';
h+=sec('📈','주요 지수 (실시간)');
h+='<table style="width:100%;border-collapse:collapse;font-size:13px;margin-top:2px;">'+th(['지수','현재','전일대비','등락률'])+idxR+'</table>';
h+=sec('💰','투자자별 매매동향');
h+='<div style="background:#FFFFFF;border:1px solid #E2E8F0;border-radius:8px;margin-top:4px;">'+monR+'</div>';
h+=sec('🔥','주목 종목 (AI 분석)');
h+='<div style="background:#FFFFFF;border:1px solid #E2E8F0;border-radius:8px;margin-top:4px;">'+pkR+'</div>';
h+=sec('🏷️','핵심 키워드');
h+='<div style="padding:2px 0;">'+kwH+'</div>';
h+=sec('📝','총평');
h+='<div style="padding:8px 12px;">'+smH+'</div>';
h+='</div>';
// 푸터
h+='<div style="background:#F8FAFC;padding:12px 20px;border-radius:0 0 12px 12px;border:1px solid #E2E8F0;border-top:none;text-align:center;">';
h+='<div style="color:#94A3B8;font-size:11px;">⚠️ AI 분석 참고자료 · 투자 판단과 책임은 본인에게 있습니다</div>';
h+='<div style="color:#94A3B8;font-size:10px;margin-top:2px;">시세: 네이버증권+GOOGLEFINANCE · 분석: Gemini</div>';
h+='<div style="color:#FCD34D;font-size:11px;font-weight:600;margin-top:4px;">© 2026 PlanX</div>';
h+='</div></div>';
return h;
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 실행 함수들
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
function run_market() {
Logger.log('📡 1단계: 시세 수집...');
var md = fetchMarketData();
Logger.log('코스피: ' + md.kospi.value + ' / 코스닥: ' + md.kosdaq.value);
Logger.log('S&P500: ' + md.sp500.value + ' / 나스닥: ' + md.nasdaq.value);
Logger.log('원달러: ' + md.usdkrw.value);
Logger.log('🤖 2단계: Gemini 분석...');
var prompt = buildPrompt(md);
var ai = callGemini(prompt);
Logger.log('분위기: ' + ai.mood + ' ' + ai.mood_score + '점');
Logger.log('📧 3단계: 이메일 발송...');
var html = buildHTML(ai, md);
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy-MM-dd');
MailApp.sendEmail({
to: CONFIG.SEND_TO,
subject: '[PlanX] 📊 시황요약 (' + today + ')',
htmlBody: html
});
Logger.log('✅ 완료!');
}
// ▶ 이 함수를 실행하세요
function testRun() {
run_market();
}
// 시세만 테스트 (API키 없이도 실행 가능)
function testFetchData() {
var d = fetchMarketData();
Logger.log('=== 국내 (네이버증권) ===');
Logger.log('코스피: ' + d.kospi.value + ' (' + d.kospi.change + ', ' + d.kospi.changePercent + '%)');
Logger.log('코스닥: ' + d.kosdaq.value + ' (' + d.kosdaq.change + ', ' + d.kosdaq.changePercent + '%)');
Logger.log('=== 해외 (GOOGLEFINANCE) ===');
Logger.log('S&P500: ' + d.sp500.value + ' (' + d.sp500.change + ', ' + d.sp500.changePercent + '%)');
Logger.log('나스닥: ' + d.nasdaq.value + ' (' + d.nasdaq.change + ', ' + d.nasdaq.changePercent + '%)');
Logger.log('다우: ' + d.dji.value + ' (' + d.dji.change + ', ' + d.dji.changePercent + '%)');
Logger.log('=== 환율 ===');
Logger.log('원/달러: ' + d.usdkrw.value + ' (' + d.usdkrw.change + ')');
Logger.log('=== 수급 ===');
Logger.log('외국인: ' + d.investor.foreigner);
Logger.log('기관: ' + d.investor.institution);
Logger.log('개인: ' + d.investor.individual);
}
📋 스크립트 전체 복사
복사 → script.google.com → 붙여넣기 → API키 수정 → 실행
업종별 강약 + 자금 흐름 + 로테이션
🏭 섹터 분석 리포트
2026.03.20 · 네이버증권 업종 데이터 + Gemini 분석
🏆 강세 섹터 TOP 3
🥇 반도체 +3.8%
HBM 수주 확대 기대감 + TSMC 실적 호조
대장: SK하이닉스
🥈 전력기기 +2.9%
데이터센터 변압기 신규 수주 + 인프라 투자 확대
대장: HD현대일렉트릭
🥉 방산/조선 +2.1%
중동 리스크 장기화 수혜 + 수출 모멘텀
대장: 한화에어로스페이스
📉 약세 섹터
2차전지 -2.4%
EV 보조금 축소 우려 + 원자재 가격 부담
소비재 -1.8%
내수 경기 둔화 + 고금리 부담 지속
🔄 자금 흐름 인사이트
📌 성장주 → 경기방어주로 자금 이동 중
📌 외국인 반도체 집중 매수, 2차전지 이탈 가속
📌 기관 배당주·가치주 비중 확대 포착
⚠️ AI 분석 참고자료 · 투자 판단과 책임은 본인에게 있습니다
데이터: 네이버증권 + GOOGLEFINANCE · 분석: Gemini 2.5 Flash
© 2026 PlanX Solution
샘플 미리보기 · 실제 발송 시 실시간 데이터 반영
';
h += '
';
h += '
⚠️ AI 참고자료 · 투자권유 아님
';
h += '
© 2026 PlanX
';
h += '
';
return h;
}
function run_sector() {
var md = fetchSectorData();
var ai = callGemini(buildSectorPrompt(md));
var html = buildSectorHTML(ai, md);
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy-MM-dd');
MailApp.sendEmail({to:CONFIG.SEND_TO, subject:'[PlanX] 🏭 섹터분석 (' + today + ')', htmlBody:html});
}
function testRun() { run_sector(); }
SCRIPT
// ═══════════════════════════════════════
// 🏭 섹터 분석 리포트
// 네이버증권 업종 데이터 + Gemini 분석
// ═══════════════════════════════════════
var CONFIG = {
GEMINI_API_KEY: '여기에_API키_붙여넣기',
MODEL: 'gemini-2.5-flash',
SEND_TO: '본인이메일입력',
};
function callGemini(prompt) {
if (!prompt) throw new Error('프롬프트 비어있음');
var url = 'https://generativelanguage.googleapis.com/v1beta/models/' + CONFIG.MODEL + ':generateContent?key=' + CONFIG.GEMINI_API_KEY;
var res = UrlFetchApp.fetch(url, {
method: 'post', contentType: 'application/json',
payload: JSON.stringify({contents:[{parts:[{text:String(prompt)}]}], generationConfig:{temperature:0.3}, tools:[{google_search:{}}]}),
muteHttpExceptions: true
});
var code = res.getResponseCode(), raw = res.getContentText();
if (code !== 200) throw new Error('API ' + code + ': ' + raw.substring(0,300));
var data = JSON.parse(raw);
var text = '';
var parts = data.candidates[0].content.parts || [];
for (var i = 0; i < parts.length; i++) {
if (parts[i].text) text += parts[i].text;
}
text = text.replace(/```json/g,'').replace(/```/g,'').trim();
var jsonStart = text.indexOf('{');
var jsonEnd = text.lastIndexOf('}');
if (jsonStart >= 0 && jsonEnd > jsonStart) {
text = text.substring(jsonStart, jsonEnd + 1);
}
try {
return JSON.parse(text);
} catch(e) {
throw new Error('JSON 파싱 실패. 응답: ' + text.substring(0, 300));
}
}
function fetchNaverIndex(market) {
try {
var res = UrlFetchApp.fetch('https://m.stock.naver.com/api/index/' + market + '/basic', {muteHttpExceptions:true});
var j = JSON.parse(res.getContentText());
return {value:j.closePrice||'', change:j.compareToPreviousClosePrice||'', changePercent:j.fluctuationsRatio||'', date:j.localTradedAt||''};
} catch(e) { return {value:'-',change:'-',changePercent:'-'}; }
}
function fetchSectorData() {
var kospi = fetchNaverIndex('KOSPI');
var kosdaq = fetchNaverIndex('KOSDAQ');
return {kospi:kospi, kosdaq:kosdaq};
}
function buildSectorPrompt(md) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 (E)');
var p = '';
p += '[필수 지침]\n';
p += '1. 모든 응답 한국어. 영어 절대 금지.\n';
p += '2. 구글 검색으로 오늘(' + today + ') KRX/네이버증권 업종별 등락률을 반드시 확인하라.\n';
p += '3. 데이터 출처: KRX 업종지수 > 네이버증권 업종 > 증권사 섹터 리포트 (미래에셋, 삼성, KB, 한투)\n';
p += '4. 각 섹터의 등락률은 반드시 실제 수치를 사용. 불확실하면 "추정" 표기.\n';
p += '5. 외국인/기관 순매매 금액도 실제 데이터 기반.\n';
p += '6. 반드시 오늘(' + today + ') 데이터만 사용. 전일 데이터 혼동 금지.\n\n';
p += '[실시간 데이터]\n코스피: ' + md.kospi.value + ' (' + md.kospi.changePercent + '%)\n코스닥: ' + md.kosdaq.value + ' (' + md.kosdaq.changePercent + '%)\n\n';
p += '[역할] 증권사 수석 섹터 애널리스트. 기관 투자자 대상 섹터 분석 리포트 수준.\n\n';
p += '[분석 요구사항]\n';
p += '- 강세 섹터: KRX 업종지수 기준 상위 5개 섹터의 정확한 등락률, 외국인/기관 수급, 대장주, 상승 촉매(catalyst)\n';
p += '- 약세 섹터: 하위 3개 섹터의 정확한 등락률, 하락 원인, 반등 가능성 판단\n';
p += '- 섹터 로테이션: 최근 1주 자금 흐름 방향성 (성장주↔가치주, 대형↔중소형 등)\n';
p += '- 다음 주목 섹터: 증권사 리포트/정책/글로벌 이슈 기반 근거 제시\n\n';
p += 'JSON:\n{\n';
p += ' "sector_ranking": [\n';
p += ' {"rank":1,"name":"섹터명","change":"+X.XX%","foreign":"순매수 X,XXX억","institution":"순매수 X,XXX억","top_stock":"대장주명","catalyst":"상승 촉매 구체적으로","outlook":"단기 전망 1문장"},\n';
p += ' {"rank":2,"name":"섹터명","change":"+X.XX%","foreign":"순매수/매도","institution":"순매수/매도","top_stock":"대장주","catalyst":"촉매","outlook":"전망"},\n';
p += ' {"rank":3,"name":"섹터명","change":"+X.XX%","foreign":"동향","institution":"동향","top_stock":"대장주","catalyst":"촉매","outlook":"전망"},\n';
p += ' {"rank":4,"name":"섹터명","change":"+X.XX%","foreign":"동향","institution":"동향","top_stock":"대장주","catalyst":"촉매","outlook":"전망"},\n';
p += ' {"rank":5,"name":"섹터명","change":"+X.XX%","foreign":"동향","institution":"동향","top_stock":"대장주","catalyst":"촉매","outlook":"전망"}\n';
p += ' ],\n';
p += ' "worst_sectors": [\n';
p += ' {"name":"섹터명","change":"-X.XX%","reason":"하락 원인 구체적으로","rebound_chance":"반등 가능성 높음/낮음 + 근거","outlook":"향후 1~2주 전망"}\n';
p += ' ],\n';
p += ' "rotation": {"direction":"자금 이동 방향 (예: IT→방어주)","reason":"로테이션 원인","duration":"지속 예상 기간"},\n';
p += ' "next_hot": {"sector":"다음 주목 섹터","reason":"근거 (정책/실적/글로벌)","timing":"진입 시점 제안","related_stocks":"관련 종목 3~5개"},\n';
p += ' "summary": ["섹터 총평1 (오늘 핵심 흐름)","섹터 총평2 (수급 특징)","섹터 총평3 (다음주 전략 제안)"]\n';
p += '}';
p += '\n\n위 JSON 형식으로만 응답하라. JSON 외에 어떤 텍스트도 포함하지 마라. 순수 JSON만 출력.';
return p;
}
function buildSectorHTML(ai, md) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 (E) HH:mm');
var h = '<div style="max-width:680px;margin:16px auto;font-family:Arial,sans-serif;">';
h += '<div style="background:linear-gradient(135deg,#1E3A5F,#0B1426);padding:20px 24px;border-radius:12px 12px 0 0;">';
h += '<div style="display:inline-block;background:#1a73e8;color:white;font-size:12px;font-weight:900;padding:3px 12px;border-radius:5px;">PlanX</div>';
h += '<div style="color:#60A5FA;font-size:20px;font-weight:bold;margin-top:10px;">🏭 섹터 분석 리포트</div>';
h += '<div style="color:#94A3B8;font-size:12px;">' + today + '</div>';
h += '<div style="display:flex;gap:12px;margin-top:12px;">';
h += '<div style="background:rgba(255,255,255,0.1);border-radius:8px;padding:8px 16px;text-align:center;"><div style="font-size:11px;color:#94A3B8;">코스피</div><div style="font-size:18px;font-weight:bold;color:' + (String(md.kospi.change).indexOf('-')>=0?'#F87171':'#4ADE80') + ';">' + md.kospi.value + '</div></div>';
h += '<div style="background:rgba(255,255,255,0.1);border-radius:8px;padding:8px 16px;text-align:center;"><div style="font-size:11px;color:#94A3B8;">코스닥</div><div style="font-size:18px;font-weight:bold;color:' + (String(md.kosdaq.change).indexOf('-')>=0?'#F87171':'#4ADE80') + ';">' + md.kosdaq.value + '</div></div>';
h += '</div></div>';
h += '<div style="background:#fff;border:1px solid #E2E8F0;padding:20px;">';
// 강세 섹터
h += '<div style="background:#0B1426;color:#F5A623;padding:8px 14px;font-weight:bold;border-radius:6px;">🏆 강세 섹터 TOP 3</div>';
h += '<div style="border:1px solid #E2E8F0;border-radius:8px;margin-top:4px;">';
var ranks = ai.sector_ranking || [];
var medals = ['🥇','🥈','🥉'];
for (var i=0; i<ranks.length; i++) {
var r = ranks[i];
var cc = String(r.change||'').indexOf('-')>=0 ? '#DC2626' : '#16A34A';
h += '<div style="padding:14px 16px;border-bottom:' + (i<ranks.length-1?'1px solid #F1F5F9':'none') + ';">';
h += '<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">';
h += '<span style="font-size:20px;">' + (medals[i]||'') + '</span>';
h += '<span style="font-size:16px;font-weight:800;color:#0F172A;">' + r.name + '</span>';
h += '<span style="color:' + cc + ';font-size:15px;font-weight:800;margin-left:auto;">' + r.change + '</span>';
h += '</div>';
h += '<div style="display:flex;gap:8px;padding-left:28px;font-size:12px;">';
h += '<span style="background:#EFF6FF;color:#1D4ED8;padding:2px 8px;border-radius:10px;">대장: ' + r.top_stock + '</span>';
h += '<span style="background:#F8FAFC;color:#64748B;padding:2px 8px;border-radius:10px;">외국인: ' + r.foreign + '</span>';
h += '</div>';
h += '<div style="font-size:13px;color:#475569;padding-left:28px;margin-top:4px;">' + r.reason + '</div>';
h += '</div>';
}
h += '</div>';
// 약세 섹터
h += '<div style="background:#0B1426;color:#F87171;padding:8px 14px;font-weight:bold;border-radius:6px;margin-top:18px;">📉 약세 섹터</div>';
var worsts = ai.worst_sectors || [];
for (var i=0; i<worsts.length; i++) {
var w = worsts[i];
h += '<div style="background:#FEF2F2;border-left:4px solid #DC2626;border-radius:0 8px 8px 0;padding:12px 16px;margin:6px 0;">';
h += '<div style="display:flex;align-items:center;gap:8px;"><span style="font-weight:700;color:#DC2626;">' + w.name + '</span><span style="color:#DC2626;font-weight:800;">' + w.change + '</span></div>';
h += '<div style="font-size:13px;color:#64748B;margin-top:4px;">' + w.reason + '</div>';
h += '<div style="font-size:12px;color:#92400E;margin-top:2px;">전망: ' + (w.outlook||'') + '</div>';
h += '</div>';
}
// 로테이션
h += '<div style="background:#EFF6FF;border:1px solid #BFDBFE;border-radius:8px;padding:14px 16px;margin-top:18px;">';
h += '<div style="font-size:13px;font-weight:700;color:#1D4ED8;">🔄 섹터 로테이션</div>';
h += '<div style="font-size:14px;color:#334155;margin-top:4px;">' + (ai.rotation||'') + '</div>';
h += '</div>';
// 다음 주목
h += '<div style="background:#F0FDF4;border:1px solid #BBF7D0;border-radius:8px;padding:14px 16px;margin-top:8px;">';
h += '<div style="font-size:13px;font-weight:700;color:#16A34A;">🔮 다음 주목 섹터</div>';
h += '<div style="font-size:14px;color:#334155;margin-top:4px;">' + (ai.next_hot||'') + '</div>';
h += '</div>';
// 총평
h += '<div style="background:#0B1426;color:#F5A623;padding:8px 14px;font-weight:bold;border-radius:6px;margin-top:18px;">📝 총평</div>';
var sums = ai.summary || [];
for (var i=0; i<sums.length; i++) {
h += '<div style="padding:8px 12px;font-size:14px;line-height:1.8;">' + (i+1) + '. ' + sums[i] + '</div>';
}
h += '</div>';
h += '<div style="background:#F8FAFC;padding:12px;border-radius:0 0 12px 12px;border:1px solid #E2E8F0;border-top:none;text-align:center;">';
h += '<div style="color:#94A3B8;font-size:11px;">⚠️ AI 참고자료 · 투자권유 아님</div>';
h += '<div style="color:#FCD34D;font-size:11px;font-weight:600;margin-top:2px;">© 2026 PlanX</div>';
h += '</div></div>';
return h;
}
function run_sector() {
var md = fetchSectorData();
var ai = callGemini(buildSectorPrompt(md));
var html = buildSectorHTML(ai, md);
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy-MM-dd');
MailApp.sendEmail({to:CONFIG.SEND_TO, subject:'[PlanX] 🏭 섹터분석 (' + today + ')', htmlBody:html});
}
function testRun() { run_sector(); }
📋 스크립트 전체 복사
복사 → script.google.com → 붙여넣기 → API키 수정 → 실행
120점 스코어링 + 투자 포인트/리스크
🔍 종목 분석: SK하이닉스
000660 · 반도체 · 시가총액 180조원
📐 스코어 상세 (120점 만점)
🌅 Early Bird 보너스 +5점 적용 (시장 미반영 모멘텀)
✅ 투자 포인트
• HBM3E 시장 사실상 독점
• AI 서버 수요 폭발적 증가
• TSMC 협력 심화로 기술 격차 확대
⚠️ 리스크
• 메모리 사이클 하락 가능성
• 미중 반도체 갈등 심화
• 삼성전자 HBM 추격 속도
⚠️ AI 분석 참고자료 · 투자 판단과 책임은 본인에게 있습니다
데이터: 네이버증권 + GOOGLEFINANCE · 분석: Gemini 2.5 Flash
© 2026 PlanX Solution
샘플 미리보기 · 실제 발송 시 실시간 데이터 반영
';
h += '
';
h += '
⚠️ AI 참고자료 · 투자권유 아님
';
h += '
© 2026 PlanX
';
return h;
}
function run_stock() {
var ai = callGemini(buildStockPrompt());
var html = buildStockHTML(ai);
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy-MM-dd');
MailApp.sendEmail({to:CONFIG.SEND_TO, subject:'[PlanX] 🔍 '+CONFIG.TICKER+' 분석 ('+today+')', htmlBody:html});
}
function testRun() { run_stock(); }
SCRIPT
// ═══════════════════════════════════════
// 🔍 종목 분석 리포트 (120점 스코어링)
// 네이버증권 재무 데이터 + Gemini 분석
// ═══════════════════════════════════════
var CONFIG = {
GEMINI_API_KEY: '여기에_API키_붙여넣기',
MODEL: 'gemini-2.5-flash',
SEND_TO: '본인이메일입력',
TICKER: 'SK하이닉스', // ← 분석할 종목명
};
function callGemini(prompt) {
if (!prompt) throw new Error('프롬프트 비어있음');
var url = 'https://generativelanguage.googleapis.com/v1beta/models/' + CONFIG.MODEL + ':generateContent?key=' + CONFIG.GEMINI_API_KEY;
var res = UrlFetchApp.fetch(url, {
method:'post', contentType:'application/json',
payload: JSON.stringify({contents:[{parts:[{text:String(prompt)}]}], generationConfig:{temperature:0.3}, tools:[{google_search:{}}]}),
muteHttpExceptions:true
});
var code=res.getResponseCode(), raw=res.getContentText();
if(code!==200) throw new Error('API '+code+': '+raw.substring(0,300));
var data = JSON.parse(raw);
var text = '';
var parts = data.candidates[0].content.parts || [];
for (var i = 0; i < parts.length; i++) {
if (parts[i].text) text += parts[i].text;
}
text = text.replace(/```json/g,'').replace(/```/g,'').trim();
// JSON 블록만 추출 (앞뒤 텍스트 제거)
var jsonStart = text.indexOf('{');
var jsonEnd = text.lastIndexOf('}');
if (jsonStart >= 0 && jsonEnd > jsonStart) {
text = text.substring(jsonStart, jsonEnd + 1);
}
try {
return JSON.parse(text);
} catch(e) {
throw new Error('JSON 파싱 실패. 응답: ' + text.substring(0, 300));
}
}
function buildStockPrompt() {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일');
var ticker = CONFIG.TICKER;
var p = '';
p += '[필수 지침]\n';
p += '1. 모든 응답 한국어. 영어 금지.\n';
p += '2. 구글 검색으로 ' + ticker + '의 최신 시세, 재무제표(최근 4분기), 증권사 목표가/투자의견을 반드시 확인.\n';
p += '3. 데이터 출처: KRX > 네이버증권 > 전자공시(DART) > 증권사 리포트 (미래에셋, 삼성, KB, 한투, NH)\n';
p += '4. 모든 수치는 실제 데이터. 불확실하면 "추정" 표기. 거짓 금지.\n';
p += '5. 증권사 컨센서스(목표가 평균/최고/최저, 매수/중립/매도 비율) 반드시 포함.\n\n';
p += '[날짜] ' + today + '\n[종목] ' + ticker + '\n\n';
p += '[120점 스코어링 기준 - 엄격 적용]\n';
p += '시장지배력(20점): 글로벌/국내 점유율 %, 경쟁사 대비 지위, 진입장벽\n';
p += '수익성(20점): ROE, ROA, 영업이익률, 순이익률 - 최근 4분기 추이\n';
p += '밸류에이션(20점): PER/PBR/PSR 업종 평균 대비, PEG, EV/EBITDA\n';
p += '성장성(15점): 매출/영업이익 성장률(YoY), 신사업 매출 비중, R&D 투자\n';
p += '재무안정성(15점): 부채비율, 유동비율, 이자보상배율, FCF 추이\n';
p += '배당(10점): 배당수익률, 배당성향, 배당성장률 3개년\n';
p += '보너스-기술해자(10점): 특허/독점기술/전환비용 - 구체적 기술명 명시\n';
p += '보너스-얼리버드(10점): 현재 PER이 업종 대비 저평가 + 성장 모멘텀 존재시\n\n';
p += 'JSON:\n{\n';
p += ' "company": {\n';
p += ' "name":"정확한 종목명","code":"6자리 종목코드","sector":"업종",\n';
p += ' "market_cap":"시가총액 (조원)","current_price":"현재 주가",\n';
p += ' "change":"오늘 등락률","52w_high":"52주 최고가","52w_low":"52주 최저가"\n';
p += ' },\n';
p += ' "financials": {\n';
p += ' "revenue":"최근 연간 매출","revenue_growth":"매출 성장률 YoY",\n';
p += ' "operating_profit":"영업이익","op_margin":"영업이익률",\n';
p += ' "net_income":"순이익","roe":"ROE","per":"PER","pbr":"PBR",\n';
p += ' "debt_ratio":"부채비율","fcf":"잉여현금흐름(양수/음수)"\n';
p += ' },\n';
p += ' "consensus": {\n';
p += ' "target_avg":"증권사 평균 목표가","target_high":"최고 목표가","target_low":"최저 목표가",\n';
p += ' "buy_ratio":"매수 의견 비율","analyst_count":"분석 증권사 수"\n';
p += ' },\n';
p += ' "scores": [\n';
p += ' {"area":"시장지배력","score":0,"max":20,"reason":"점유율 X%, 경쟁지위 구체적"},\n';
p += ' {"area":"수익성","score":0,"max":20,"reason":"ROE X%, 영업이익률 X%, 추이"},\n';
p += ' {"area":"밸류에이션","score":0,"max":20,"reason":"PER X배 (업종 X배), PBR X배"},\n';
p += ' {"area":"성장성","score":0,"max":15,"reason":"매출성장률 X%, 신사업 비중 X%"},\n';
p += ' {"area":"재무안정성","score":0,"max":15,"reason":"부채비율 X%, FCF X억"},\n';
p += ' {"area":"배당","score":0,"max":10,"reason":"배당수익률 X%, 배당성향 X%"}\n';
p += ' ],\n';
p += ' "bonus": {\n';
p += ' "tech_moat":{"score":0,"max":10,"reason":"구체적 기술/특허명"},\n';
p += ' "early_bird":{"score":0,"max":10,"reason":"저평가 근거"}\n';
p += ' },\n';
p += ' "total": 0,\n';
p += ' "grade": "S(100+)/A(85~99)/B(70~84)/C(55~69)/D(55미만)",\n';
p += ' "bull_points": ["투자포인트1 (구체적 수치/사실 포함)","투자포인트2","투자포인트3"],\n';
p += ' "risks": ["리스크1 (확률/영향도 포함)","리스크2","리스크3"],\n';
p += ' "verdict": "최종 투자 의견 3~4문장 (현재가 대비 목표가 괴리율, 진입 시점 제안 포함)"\n';
p += '}';
p += '\n\n위 JSON 형식으로만 응답하라. JSON 외에 어떤 텍스트도 포함하지 마라. 순수 JSON만 출력.';
return p;
}
function buildStockHTML(ai) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 HH:mm');
var c = ai.company || {};
var gradeColors = {'S':'#F59E0B','A':'#7C3AED','B':'#1a73e8','C':'#64748B','D':'#DC2626'};
var gc = gradeColors[ai.grade] || '#64748B';
var h = '<div style="max-width:680px;margin:16px auto;font-family:Arial,sans-serif;">';
h += '<div style="background:linear-gradient(135deg,#4C1D95,#7C3AED);padding:20px 24px;border-radius:12px 12px 0 0;">';
h += '<div style="display:inline-block;background:#1a73e8;color:white;font-size:12px;font-weight:900;padding:3px 12px;border-radius:5px;">PlanX</div>';
h += '<div style="color:white;font-size:20px;font-weight:bold;margin-top:10px;">🔍 종목 분석: ' + (c.name||'') + '</div>';
h += '<div style="color:rgba(255,255,255,0.7);font-size:12px;">' + (c.code||'') + ' · ' + (c.sector||'') + ' · 시총 ' + (c.market_cap||'') + '</div>';
h += '<div style="display:flex;gap:12px;margin-top:12px;">';
h += '<div style="background:rgba(255,255,255,0.15);border-radius:8px;padding:8px 16px;text-align:center;"><div style="font-size:11px;color:rgba(255,255,255,0.6);">현재가</div><div style="font-size:20px;font-weight:bold;color:white;">' + (c.current_price||'') + '</div></div>';
h += '<div style="background:rgba(255,255,255,0.15);border-radius:8px;padding:8px 16px;text-align:center;"><div style="font-size:11px;color:rgba(255,255,255,0.6);">등락</div><div style="font-size:20px;font-weight:bold;color:' + (String(c.change||'').indexOf('-')>=0?'#F87171':'#4ADE80') + ';">' + (c.change||'') + '</div></div>';
h += '<div style="background:' + gc + ';border-radius:8px;padding:8px 16px;text-align:center;"><div style="font-size:11px;color:rgba(255,255,255,0.6);">등급</div><div style="font-size:24px;font-weight:900;color:white;">' + (ai.grade||'') + '</div></div>';
h += '</div></div>';
h += '<div style="background:#fff;border:1px solid #E2E8F0;padding:20px;">';
// 스코어 카드
h += '<div style="background:#4C1D95;color:#C4B5FD;padding:8px 14px;font-weight:bold;border-radius:6px;">📐 스코어 카드 (' + (ai.total||0) + '점/120점)</div>';
// 점수 바
var pct = Math.round(((ai.total||0)/120)*100);
h += '<div style="background:#E2E8F0;border-radius:8px;height:16px;margin:8px 0;overflow:hidden;"><div style="background:' + gc + ';height:100%;width:' + pct + '%;border-radius:8px;"></div></div>';
h += '<table style="width:100%;border-collapse:collapse;font-size:13px;">';
h += '<tr style="background:#1E293B;color:#CBD5E1;"><th style="padding:7px 12px;text-align:left;">영역</th><th style="width:60px;">점수</th><th style="width:50px;">배점</th><th>근거</th></tr>';
var scores = ai.scores || [];
for (var i=0; i<scores.length; i++) {
var s = scores[i], bg = i%2===0?'#fff':'#F8FAFC';
h += '<tr style="background:'+bg+';"><td style="padding:8px 12px;font-weight:600;border-bottom:1px solid #E2E8F0;">'+s.area+'</td>';
h += '<td style="padding:8px 12px;font-weight:bold;color:'+gc+';border-bottom:1px solid #E2E8F0;text-align:center;">'+s.score+'</td>';
h += '<td style="padding:8px 12px;color:#94A3B8;border-bottom:1px solid #E2E8F0;text-align:center;">/'+s.max+'</td>';
h += '<td style="padding:8px 12px;font-size:12px;color:#475569;border-bottom:1px solid #E2E8F0;">'+s.reason+'</td></tr>';
}
// 보너스
var bn = ai.bonus || {};
if (bn.tech_moat && bn.tech_moat.score > 0) {
h += '<tr style="background:#FEF3C7;"><td style="padding:8px 12px;font-weight:600;">🌟 기술해자</td><td style="padding:8px 12px;font-weight:bold;color:#D97706;text-align:center;">+'+bn.tech_moat.score+'</td><td style="padding:8px 12px;color:#94A3B8;text-align:center;">/'+bn.tech_moat.max+'</td><td style="padding:8px 12px;font-size:12px;">'+bn.tech_moat.reason+'</td></tr>';
}
if (bn.early_bird && bn.early_bird.score > 0) {
h += '<tr style="background:#DBEAFE;"><td style="padding:8px 12px;font-weight:600;">🐦 얼리버드</td><td style="padding:8px 12px;font-weight:bold;color:#1D4ED8;text-align:center;">+'+bn.early_bird.score+'</td><td style="padding:8px 12px;color:#94A3B8;text-align:center;">/'+bn.early_bird.max+'</td><td style="padding:8px 12px;font-size:12px;">'+bn.early_bird.reason+'</td></tr>';
}
// 합계
h += '<tr style="background:#F5F3FF;font-weight:bold;font-size:15px;"><td style="padding:10px 12px;">합계</td><td style="padding:10px 12px;color:'+gc+';text-align:center;">'+ai.total+'점</td><td style="padding:10px 12px;text-align:center;">/120</td>';
h += '<td style="padding:10px 12px;"><span style="background:'+gc+';color:white;padding:3px 14px;border-radius:6px;font-size:14px;">'+ai.grade+'등급</span></td></tr>';
h += '</table>';
// 투자포인트 / 리스크
h += '<div style="display:flex;gap:12px;margin-top:18px;flex-wrap:wrap;">';
h += '<div style="flex:1;min-width:200px;background:#F0FDF4;border:1px solid #BBF7D0;border-radius:8px;padding:14px;">';
h += '<div style="font-weight:700;color:#16A34A;margin-bottom:6px;">✅ 투자 포인트</div>';
var bulls = ai.bull_points || [];
for(var i=0;i<bulls.length;i++) h += '<div style="font-size:13px;padding:3px 0;color:#334155;">' + (i+1) + '. ' + bulls[i] + '</div>';
h += '</div>';
h += '<div style="flex:1;min-width:200px;background:#FEF2F2;border:1px solid #FECACA;border-radius:8px;padding:14px;">';
h += '<div style="font-weight:700;color:#DC2626;margin-bottom:6px;">⚠️ 리스크</div>';
var risks = ai.risks || [];
for(var i=0;i<risks.length;i++) h += '<div style="font-size:13px;padding:3px 0;color:#334155;">' + (i+1) + '. ' + risks[i] + '</div>';
h += '</div></div>';
// 목표가 + 최종의견
h += '<div style="background:#EFF6FF;border:1px solid #BFDBFE;border-radius:8px;padding:14px 16px;margin-top:14px;">';
h += '<div style="font-weight:700;color:#1D4ED8;">🎯 증권사 목표가: ' + (ai.target_price||'') + '</div>';
h += '<div style="font-size:14px;color:#334155;margin-top:6px;line-height:1.8;">' + (ai.verdict||'') + '</div>';
h += '</div>';
h += '</div>';
h += '<div style="background:#F8FAFC;padding:12px;border-radius:0 0 12px 12px;border:1px solid #E2E8F0;border-top:none;text-align:center;">';
h += '<div style="color:#94A3B8;font-size:11px;">⚠️ AI 참고자료 · 투자권유 아님</div>';
h += '<div style="color:#FCD34D;font-size:11px;font-weight:600;margin-top:2px;">© 2026 PlanX</div></div></div>';
return h;
}
function run_stock() {
var ai = callGemini(buildStockPrompt());
var html = buildStockHTML(ai);
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy-MM-dd');
MailApp.sendEmail({to:CONFIG.SEND_TO, subject:'[PlanX] 🔍 '+CONFIG.TICKER+' 분석 ('+today+')', htmlBody:html});
}
function testRun() { run_stock(); }
📋 스크립트 전체 복사
복사 → script.google.com → 붙여넣기 → API키 수정 → 실행
';
return h;
}
function run_premarket() {
var md = fetchPremarketData();
var ai = callGemini(buildPrePrompt(md));
MailApp.sendEmail({to:CONFIG.SEND_TO, subject:'[PlanX] 🌅 장전 기대섹터 ('+Utilities.formatDate(new Date(),'Asia/Seoul','yyyy-MM-dd')+')', htmlBody:buildPreHTML(ai,md)});
}
function testRun() { run_premarket(); }
SCRIPT
// ═══════════════════════════════════════
// 🌅 장전 기대 섹터 리포트
// GOOGLEFINANCE 해외시세 + Gemini 분석
// 매일 오전 8시 트리거 추천
// ═══════════════════════════════════════
var CONFIG = {
GEMINI_API_KEY: '여기에_API키_붙여넣기',
MODEL: 'gemini-2.5-flash',
SEND_TO: '본인이메일입력',
};
function callGemini(prompt) {
if (!prompt) throw new Error('프롬프트 비어있음');
var url = 'https://generativelanguage.googleapis.com/v1beta/models/' + CONFIG.MODEL + ':generateContent?key=' + CONFIG.GEMINI_API_KEY;
var res = UrlFetchApp.fetch(url, {
method:'post', contentType:'application/json',
payload: JSON.stringify({contents:[{parts:[{text:String(prompt)}]}], generationConfig:{temperature:0.3}, tools:[{google_search:{}}]}),
muteHttpExceptions:true
});
var code=res.getResponseCode(), raw=res.getContentText();
if(code!==200) throw new Error('API '+code+': '+raw.substring(0,300));
var data = JSON.parse(raw);
var text = '';
var parts = data.candidates[0].content.parts || [];
for (var i = 0; i < parts.length; i++) {
if (parts[i].text) text += parts[i].text;
}
text = text.replace(/```json/g,'').replace(/```/g,'').trim();
// JSON 블록만 추출 (앞뒤 텍스트 제거)
var jsonStart = text.indexOf('{');
var jsonEnd = text.lastIndexOf('}');
if (jsonStart >= 0 && jsonEnd > jsonStart) {
text = text.substring(jsonStart, jsonEnd + 1);
}
try {
return JSON.parse(text);
} catch(e) {
throw new Error('JSON 파싱 실패. 응답: ' + text.substring(0, 300));
}
}
function fetchGoogleFinance(ticker) {
try {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('_temp_finance');
if (!sh) sh = ss.insertSheet('_temp_finance');
sh.getRange('A1').setFormula('=GOOGLEFINANCE("' + ticker + '","price")');
sh.getRange('A2').setFormula('=GOOGLEFINANCE("' + ticker + '","closeyest")');
SpreadsheetApp.flush(); Utilities.sleep(2000);
var price = sh.getRange('A1').getValue();
var prev = sh.getRange('A2').getValue();
sh.clear();
if (!price || String(price).indexOf('N/A')>=0) return {value:'-',change:'-',changePct:'-'};
var chg = price-prev, pct = prev?((chg/prev)*100):0;
return {value:Number(price).toFixed(2), change:(chg>=0?'+':'')+chg.toFixed(2), changePct:(pct>=0?'+':'')+pct.toFixed(2)+'%'};
} catch(e) { return {value:'-',change:'-',changePct:'-'}; }
}
function fetchPremarketData() {
return {
sp500: fetchGoogleFinance('.INX'),
nasdaq: fetchGoogleFinance('.IXIC'),
dji: fetchGoogleFinance('.DJI'),
sox: fetchGoogleFinance('SOXX'),
vix: fetchGoogleFinance('.VIX')
};
}
function buildPrePrompt(md) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 (E)');
var p = '';
p += '[필수 지침]\n';
p += '1. 모든 응답 한국어. 영어 금지.\n';
p += '2. 아래 해외 시세는 GOOGLEFINANCE 실시간 데이터. 그대로 사용.\n';
p += '3. 구글 검색으로 오늘 장 개장 전 주요 뉴스, 증권사 모닝브리프를 확인하라.\n';
p += '4. 미국 개별 종목 등락이 한국 관련주에 미치는 영향을 구체적으로 연결하라.\n';
p += '5. NXT 프리마켓(08:00~) 동향도 가능하면 반영.\n';
p += '6. 반드시 오늘(' + today + ') 데이터만 사용. 전일 데이터 혼동 금지.\n\n';
p += '[날짜] ' + today + ' 오전 장 개장 전\n\n';
p += '[해외 시세 (전일 마감)]\n';
p += 'S&P500: ' + md.sp500.value + ' (' + md.sp500.changePct + ')\n';
p += '나스닥: ' + md.nasdaq.value + ' (' + md.nasdaq.changePct + ')\n';
p += '다우: ' + md.dji.value + ' (' + md.dji.changePct + ')\n';
p += 'SOX(반도체지수): ' + md.sox.value + ' (' + md.sox.changePct + ')\n';
p += 'VIX(공포지수): ' + md.vix.value + '\n\n';
p += '[역할] 증권사 모닝브리프 작성자. 기관 투자자 대상 장전 전략 리포트.\n\n';
p += '[분석 요구사항]\n';
p += '- 해외 시장 마감 핵심: 주요 이슈 2~3개, 특정 종목 등락(엔비디아/TSMC/애플 등)이 한국에 미칠 영향\n';
p += '- 기대 섹터 TOP 3: 해외 연동 근거 + 한국 관련주 3~5개씩 + 구체적 진입 전략\n';
p += '- 주의 섹터: 해외 악재로 영향 받을 섹터 + 회피 이유\n';
p += '- 오프닝 전략: 갭상승/갭하락 시나리오별 대응, 분할매수 기준가 제안\n\n';
p += 'JSON:\n{\n';
p += ' "overnight_summary": "해외 시장 마감 핵심 요약 2~3문장 (수치 포함)",\n';
p += ' "key_movers": [\n';
p += ' {"us_stock":"미국 종목명","change":"+X.X%","korea_impact":"한국 관련주와 예상 영향"}\n';
p += ' ],\n';
p += ' "korea_expected": "오늘 코스피/코스닥 예상 방향 + 예상 등락폭 + 근거",\n';
p += ' "hot_sectors": [\n';
p += ' {"rank":1,"name":"섹터명","reason":"기대 이유 (해외 연동 + 국내 촉매)","stocks":["종목1","종목2","종목3"],"entry_strategy":"진입 전략 구체적","risk":"주의할 점"},\n';
p += ' {"rank":2,"name":"섹터명","reason":"기대 이유","stocks":["종목1","종목2"],"entry_strategy":"진입 전략","risk":"주의점"},\n';
p += ' {"rank":3,"name":"섹터명","reason":"기대 이유","stocks":["종목1","종목2"],"entry_strategy":"진입 전략","risk":"주의점"}\n';
p += ' ],\n';
p += ' "risk_sectors": [{"name":"섹터명","reason":"회피 이유 구체적","affected_stocks":"영향 받을 종목"}],\n';
p += ' "opening_strategy": {\n';
p += ' "gap_up": "갭상승 시 대응 전략",\n';
p += ' "gap_down": "갭하락 시 대응 전략",\n';
p += ' "key_levels": "코스피 주요 지지/저항 수준"\n';
p += ' }\n';
p += '}';
p += '\n\n위 JSON 형식으로만 응답하라. JSON 외에 어떤 텍스트도 포함하지 마라. 순수 JSON만 출력.';
return p;
}
function buildPreHTML(ai, md) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 (E) HH:mm');
var h = '<div style="max-width:680px;margin:16px auto;font-family:Arial,sans-serif;">';
h += '<div style="background:linear-gradient(135deg,#D97706,#F59E0B);padding:20px 24px;border-radius:12px 12px 0 0;">';
h += '<div style="display:inline-block;background:#1a73e8;color:white;font-size:12px;font-weight:900;padding:3px 12px;border-radius:5px;">PlanX</div>';
h += '<div style="color:white;font-size:20px;font-weight:bold;margin-top:10px;">🌅 장전 기대 섹터</div>';
h += '<div style="color:rgba(255,255,255,0.8);font-size:12px;">' + today + ' · 장 개장 전 분석</div></div>';
h += '<div style="background:#fff;border:1px solid #E2E8F0;padding:20px;">';
// 해외 시세 카드
h += '<div style="background:#92400E;color:#FDE68A;padding:8px 14px;font-weight:bold;border-radius:6px;">🌍 해외 마감 시세</div>';
h += '<div style="display:flex;gap:8px;flex-wrap:wrap;margin-top:8px;">';
var world = [{n:'S&P500',d:md.sp500},{n:'나스닥',d:md.nasdaq},{n:'다우',d:md.dji},{n:'SOX',d:md.sox},{n:'VIX',d:md.vix}];
for(var i=0;i<world.length;i++){
var w=world[i],d=w.d||{},cc=String(d.change||'').indexOf('-')>=0?'#DC2626':'#16A34A';
if(w.n==='VIX') cc = Number(d.value)>20?'#DC2626':'#16A34A';
h+='<div style="flex:1;min-width:100px;background:#F8FAFC;border:1px solid #E2E8F0;border-radius:8px;padding:10px;text-align:center;">';
h+='<div style="font-size:11px;color:#64748B;">'+w.n+'</div>';
h+='<div style="font-size:18px;font-weight:bold;color:'+cc+';margin:2px 0;">'+(d.value||'-')+'</div>';
h+='<div style="font-size:11px;color:'+cc+';">'+(d.changePct||d.change||'')+'</div>';
h+='</div>';
}
h+='</div>';
// 한국 예상
h += '<div style="background:#FEF3C7;border:1px solid #FDE68A;border-radius:8px;padding:14px;margin-top:14px;">';
h += '<div style="font-weight:700;color:#92400E;">🇰🇷 오늘 한국 장 예상</div>';
h += '<div style="font-size:14px;color:#334155;margin-top:4px;">' + (ai.korea_expected||'') + '</div></div>';
// 기대 섹터
h += '<div style="background:#92400E;color:#FDE68A;padding:8px 14px;font-weight:bold;border-radius:6px;margin-top:18px;">🔥 기대 섹터 TOP 3</div>';
h += '<div style="border:1px solid #E2E8F0;border-radius:8px;margin-top:4px;">';
var secs = ai.hot_sectors || [];
for(var i=0;i<secs.length;i++){
var s=secs[i];
var stStyle = s.strategy==='매수'?'background:#DCFCE7;color:#16A34A;':s.strategy==='주의'?'background:#FEE2E2;color:#DC2626;':'background:#FEF3C7;color:#92400E;';
h+='<div style="padding:14px 16px;border-bottom:'+(i<secs.length-1?'1px solid #F1F5F9;':'none')+'">';
h+='<div style="display:flex;align-items:center;gap:8px;margin-bottom:6px;">';
h+='<span style="background:#F59E0B;color:white;width:24px;height:24px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:12px;font-weight:800;">'+s.rank+'</span>';
h+='<span style="font-size:16px;font-weight:800;">'+s.name+'</span>';
h+='<span style="'+stStyle+'padding:2px 10px;border-radius:10px;font-size:11px;font-weight:700;margin-left:auto;">'+s.strategy+'</span></div>';
h+='<div style="font-size:13px;color:#475569;padding-left:32px;">'+s.reason+'</div>';
h+='<div style="padding-left:32px;margin-top:4px;">';
var stocks = s.stocks||[];
for(var j=0;j<stocks.length;j++) h+='<span style="background:#EFF6FF;color:#1D4ED8;padding:2px 8px;border-radius:10px;font-size:11px;margin-right:4px;">'+stocks[j]+'</span>';
h+='</div></div>';
}
h+='</div>';
// 주의 섹터
var risks = ai.risk_sectors || [];
if (risks.length > 0) {
h += '<div style="background:#FEF2F2;border-left:4px solid #DC2626;border-radius:0 8px 8px 0;padding:12px 16px;margin-top:12px;">';
h += '<div style="font-weight:700;color:#DC2626;margin-bottom:4px;">⚠️ 주의 섹터</div>';
for(var i=0;i<risks.length;i++) h+='<div style="font-size:13px;color:#64748B;">'+risks[i].name+' — '+risks[i].reason+'</div>';
h+='</div>';
}
// 전략
h += '<div style="background:#F0FDF4;border:1px solid #BBF7D0;border-radius:8px;padding:14px;margin-top:14px;">';
h += '<div style="font-weight:700;color:#16A34A;">🎯 오프닝 전략</div>';
h += '<div style="font-size:14px;color:#334155;margin-top:4px;line-height:1.8;">' + (ai.opening_strategy||'') + '</div></div>';
h += '</div>';
h += '<div style="background:#F8FAFC;padding:12px;border-radius:0 0 12px 12px;border:1px solid #E2E8F0;border-top:none;text-align:center;">';
h += '<div style="color:#94A3B8;font-size:11px;">⚠️ AI 참고자료 · 투자권유 아님</div>';
h += '<div style="color:#FCD34D;font-size:11px;font-weight:600;margin-top:2px;">© 2026 PlanX</div></div></div>';
return h;
}
function run_premarket() {
var md = fetchPremarketData();
var ai = callGemini(buildPrePrompt(md));
MailApp.sendEmail({to:CONFIG.SEND_TO, subject:'[PlanX] 🌅 장전 기대섹터 ('+Utilities.formatDate(new Date(),'Asia/Seoul','yyyy-MM-dd')+')', htmlBody:buildPreHTML(ai,md)});
}
function testRun() { run_premarket(); }
📋 스크립트 전체 복사
복사 → script.google.com → 붙여넣기 → API키 수정 → 실행
특징 섹터 + 급등/급락 종목
🌙 장후 특징 섹터 & 종목
2026.03.20 장 마감 기준
📈 급등 TOP 3
1 한미반도체 ++8.2%
HBM 수혜 집중 + 외국인 3일 연속 순매수
2 HD현대일렉트릭 ++5.4%
변압기 수주 1조 돌파 + 데이터센터 전력 수요
3 한화에어로스페이스 ++4.1%
중동 리스크 + 폴란드 수출 모멘텀
📉 급락 TOP 3
1 에코프로 -5.1%
EV 보조금 정책 변경 우려 + 실적 하향 조정
2 LG에너지솔루션 -3.8%
GM 전기차 생산 축소 발표 영향
3 삼성SDI -3.2%
2차전지 업종 전반 약세 동조
📋 장후 총평
📊 중동 리스크 + 매파 연준 → 외국인 대규모 매도 주도 하락
📌 반도체·방산 상대적 강세 vs 2차전지·소비재 약세
🔮 내일 전망: 기술적 반등 가능, VIX 상승 구간 비중 조절 유의
⚠️ AI 분석 참고자료 · 투자 판단과 책임은 본인에게 있습니다
데이터: 네이버증권 + GOOGLEFINANCE · 분석: Gemini 2.5 Flash
© 2026 PlanX Solution
샘플 미리보기 · 실제 발송 시 실시간 데이터 반영
';
// 급락 종목 TOP 5
h += '
📉 급락 종목 TOP 5
';
h += '
';
var losers = ai.top_losers||[];
for(var i=0;i
';
h+='';
h+=''+(i+1)+' ';
h+=''+l.name+' ';
if(l.code) h+='('+l.code+') ';
h+=''+l.change+'
';
h+=''+l.reason+'
';
if(l.action) {
var actColor = l.action.indexOf('손절')>=0 ? '#DC2626' : l.action.indexOf('추가매수')>=0 ? '#16A34A' : '#D97706';
var actBg = l.action.indexOf('손절')>=0 ? '#FEE2E2' : l.action.indexOf('추가매수')>=0 ? '#DCFCE7' : '#FEF3C7';
h+=''+l.action+'
';
}
h+=' ';
}
h+='
';
// 내일 주목 (객체 처리)
var tw = ai.tomorrow_watch || {};
if (typeof tw === 'string') {
// 문자열이면 그대로
h += '';
h += '
🔮 내일 주목 포인트
';
h += '
'+tw+'
';
} else {
// 객체면 각 항목 표시
h += '';
h += '
🔮 내일 주목 포인트
';
if(tw.direction) h += '
방향 '+tw.direction+'
';
if(tw.key_events) h += '
이벤트 '+tw.key_events+'
';
if(tw.watch_sectors) h += '
섹터 '+tw.watch_sectors+'
';
if(tw.watch_stocks) h += '
종목 '+tw.watch_stocks+'
';
h += '
';
}
// 총평
h += '📝 총평
';
var sums=ai.summary||[];
var sumIcons = ['📊','💰','🔮'];
for(var i=0;i';
h+=''+(sumIcons[i]||'📌')+'
';
h+=''+sums[i]+'
';
}
h += '';
h += '';
h += '
⚠️ AI 분석 참고자료 · 투자 판단과 책임은 본인에게 있습니다
';
h += '
시세: 네이버증권 · 분석: Gemini + Google Search
';
h += '
© 2026 PlanX
';
h += '
';
return h;
}
function run_postmarket() {
var md = fetchPostData();
var ai = callGemini(buildPostPrompt(md));
MailApp.sendEmail({to:CONFIG.SEND_TO, subject:'[PlanX] 🌙 장후특징 ('+Utilities.formatDate(new Date(),'Asia/Seoul','yyyy-MM-dd')+')', htmlBody:buildPostHTML(ai,md)});
}
function testRun() { run_postmarket(); }
SCRIPT
// ═══════════════════════════════════════
// 🌙 장후 특징 섹터 & 종목 리포트
// 네이버증권 실시간 + Gemini 분석
// 매일 오후 4시 트리거 추천
// ═══════════════════════════════════════
var CONFIG = {
GEMINI_API_KEY: '여기에_API키_붙여넣기',
MODEL: 'gemini-2.5-flash',
SEND_TO: '본인이메일입력',
};
function callGemini(prompt) {
if (!prompt) throw new Error('프롬프트 비어있음');
var url = 'https://generativelanguage.googleapis.com/v1beta/models/' + CONFIG.MODEL + ':generateContent?key=' + CONFIG.GEMINI_API_KEY;
var res = UrlFetchApp.fetch(url, {
method:'post', contentType:'application/json',
payload: JSON.stringify({contents:[{parts:[{text:String(prompt)}]}], generationConfig:{temperature:0.3}, tools:[{google_search:{}}]}),
muteHttpExceptions:true
});
var code=res.getResponseCode(), raw=res.getContentText();
if(code!==200) throw new Error('API '+code+': '+raw.substring(0,300));
var data = JSON.parse(raw);
var text = '';
var parts = data.candidates[0].content.parts || [];
for (var i = 0; i < parts.length; i++) {
if (parts[i].text) text += parts[i].text;
}
text = text.replace(/```json/g,'').replace(/```/g,'').trim();
// JSON 블록만 추출 (앞뒤 텍스트 제거)
var jsonStart = text.indexOf('{');
var jsonEnd = text.lastIndexOf('}');
if (jsonStart >= 0 && jsonEnd > jsonStart) {
text = text.substring(jsonStart, jsonEnd + 1);
}
try {
return JSON.parse(text);
} catch(e) {
throw new Error('JSON 파싱 실패. 응답: ' + text.substring(0, 300));
}
}
function fetchNaverIndex(market) {
try {
var res = UrlFetchApp.fetch('https://m.stock.naver.com/api/index/' + market + '/basic', {muteHttpExceptions:true});
var j = JSON.parse(res.getContentText());
return {value:j.closePrice||'', change:j.compareToPreviousClosePrice||'', changePercent:j.fluctuationsRatio||'', date:j.localTradedAt||''};
} catch(e) { return {value:'-',change:'-',changePercent:'-'}; }
}
function fetchPostData() {
return {
kospi: fetchNaverIndex('KOSPI'),
kosdaq: fetchNaverIndex('KOSDAQ')
};
}
function buildPostPrompt(md) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 (E)');
var p = '';
p += '[필수 지침]\n';
p += '1. 모든 응답 한국어. 영어 금지.\n';
p += '2. 아래 종가 데이터는 네이버증권 실시간. 그대로 사용.\n';
p += '3. 구글 검색으로 오늘 급등/급락 종목 TOP 5, 특징 섹터, 거래대금 상위 종목을 확인하라.\n';
p += '4. 각 종목의 급등/급락 사유를 뉴스/공시/수급 기반으로 구체적 설명.\n';
p += '5. 거래량 폭증 여부, 신고가/신저가 돌파 여부도 체크.\n';
p += '6. 반드시 오늘(' + today + ') 데이터만 사용. 전일/전주 데이터를 오늘로 혼동하지 마라.\n\n';
p += '[날짜] ' + today + ' 장 마감 후\n\n';
p += '[종가 데이터 (네이버증권 기준)]\n';
p += '코스피: ' + md.kospi.value + ' (' + md.kospi.change + ', ' + md.kospi.changePercent + '%) — 기준일: ' + (md.kospi.date || today) + '\n';
p += '코스닥: ' + md.kosdaq.value + ' (' + md.kosdaq.change + ', ' + md.kosdaq.changePercent + '%) — 기준일: ' + (md.kosdaq.date || today) + '\n\n';
p += '[역할] 증권사 장후 마켓리뷰 작성자. 기관 투자자 대상.\n\n';
p += '[분석 요구사항]\n';
p += '- 강세 섹터: 상위 3개 섹터의 등락률, 수급(외국인/기관), 상승 촉매, 대장주\n';
p += '- 약세 섹터: 하위 2개 섹터의 등락률, 하락 원인, 내일 반등 가능성\n';
p += '- 급등 TOP 5: 종목명, 등락률, 급등 사유(공시/뉴스/테마), 거래량 변화, 내일 연속성 판단\n';
p += '- 급락 TOP 5: 종목명, 등락률, 급락 사유, 손절/보유 판단\n';
p += '- 내일 전망: 야간 선물, 글로벌 이벤트 기반 내일 시장 방향 + 주목 섹터/종목\n\n';
p += 'JSON:\n{\n';
p += ' "market_summary": "오늘 장 핵심 한줄 요약 (수치 포함)",\n';
p += ' "hot_sectors": [\n';
p += ' {"name":"섹터명","change":"+X.XX%","reason":"상승 촉매 구체적","top_stock":"대장주","foreign":"외국인 순매수/매도 금액","volume_note":"거래량 특이사항"}\n';
p += ' ],\n';
p += ' "cold_sectors": [\n';
p += ' {"name":"섹터명","change":"-X.XX%","reason":"하락 원인 구체적","rebound":"내일 반등 가능성 + 근거"}\n';
p += ' ],\n';
p += ' "top_gainers": [\n';
p += ' {"name":"종목명","code":"종목코드","change":"+XX.X%","reason":"급등 사유 (공시/뉴스/테마 구체적)","volume":"거래량 전일대비 X배","continuation":"내일 연속 상승 가능성 높음/낮음 + 근거"},\n';
p += ' {"name":"종목명","code":"코드","change":"등락","reason":"사유","volume":"거래량","continuation":"연속성"},\n';
p += ' {"name":"종목명","code":"코드","change":"등락","reason":"사유","volume":"거래량","continuation":"연속성"},\n';
p += ' {"name":"종목명","code":"코드","change":"등락","reason":"사유","volume":"거래량","continuation":"연속성"},\n';
p += ' {"name":"종목명","code":"코드","change":"등락","reason":"사유","volume":"거래량","continuation":"연속성"}\n';
p += ' ],\n';
p += ' "top_losers": [\n';
p += ' {"name":"종목명","code":"코드","change":"-XX.X%","reason":"급락 사유 구체적","action":"손절/보유/추가매수 판단 + 근거"},\n';
p += ' {"name":"종목명","code":"코드","change":"등락","reason":"사유","action":"판단"},\n';
p += ' {"name":"종목명","code":"코드","change":"등락","reason":"사유","action":"판단"}\n';
p += ' ],\n';
p += ' "tomorrow_watch": {\n';
p += ' "direction":"내일 예상 방향 (상승/하락/횡보) + 근거",\n';
p += ' "key_events":"내일 주요 이벤트/발표",\n';
p += ' "watch_sectors":"주목 섹터 2~3개",\n';
p += ' "watch_stocks":"주목 종목 3~5개 + 이유"\n';
p += ' },\n';
p += ' "summary": ["장후 총평1 (오늘 핵심)","장후 총평2 (수급 분석)","장후 총평3 (내일 전략)"]\n';
p += '}';
p += '\n\n위 JSON 형식으로만 응답하라. JSON 외에 어떤 텍스트도 포함하지 마라. 순수 JSON만 출력.';
return p;
}
function buildPostHTML(ai, md) {
var today = Utilities.formatDate(new Date(), 'Asia/Seoul', 'yyyy년 MM월 dd일 (E) HH:mm');
var kc = String(md.kospi.change||'').indexOf('-')>=0;
var kdc = String(md.kosdaq.change||'').indexOf('-')>=0;
var h = '<div style="max-width:680px;margin:16px auto;font-family:Arial,sans-serif;">';
// 헤더
h += '<div style="background:linear-gradient(135deg,#0F172A,#1E293B);padding:20px 24px;border-radius:12px 12px 0 0;">';
h += '<div style="display:inline-block;background:#1a73e8;color:white;font-size:12px;font-weight:900;padding:3px 12px;border-radius:5px;">PlanX</div>';
h += '<div style="color:white;font-size:20px;font-weight:bold;margin-top:10px;">🌙 장후 특징 섹터 & 종목</div>';
h += '<div style="color:#94A3B8;font-size:12px;">' + today + ' · 네이버증권 종가 기준</div>';
h += '<div style="display:flex;gap:12px;margin-top:12px;">';
h += '<div style="background:rgba(255,255,255,0.1);border:1px solid '+(kc?'#F87171':'#4ADE80')+';border-radius:8px;padding:8px 20px;text-align:center;"><div style="font-size:11px;color:#94A3B8;">코스피</div><div style="font-size:20px;font-weight:bold;color:'+(kc?'#F87171':'#4ADE80')+';">'+md.kospi.value+'</div><div style="font-size:12px;color:'+(kc?'#F87171':'#4ADE80')+';">'+md.kospi.change+' ('+md.kospi.changePercent+'%)</div></div>';
h += '<div style="background:rgba(255,255,255,0.1);border:1px solid '+(kdc?'#F87171':'#4ADE80')+';border-radius:8px;padding:8px 20px;text-align:center;"><div style="font-size:11px;color:#94A3B8;">코스닥</div><div style="font-size:20px;font-weight:bold;color:'+(kdc?'#F87171':'#4ADE80')+';">'+md.kosdaq.value+'</div><div style="font-size:12px;color:'+(kdc?'#F87171':'#4ADE80')+';">'+md.kosdaq.change+' ('+md.kosdaq.changePercent+'%)</div></div>';
h += '</div>';
h += '<div style="background:rgba(255,255,255,0.08);border-radius:8px;padding:10px 16px;margin-top:12px;color:#F5A623;font-size:14px;font-weight:bold;">💡 '+(ai.market_summary||'')+'</div>';
h += '</div>';
h += '<div style="background:#fff;border:1px solid #E2E8F0;padding:20px;">';
// 강세 섹터
h += '<div style="background:#0F172A;color:#4ADE80;padding:8px 14px;font-weight:bold;border-radius:6px;">🔥 강세 섹터</div>';
h += '<div style="border:1px solid #E2E8F0;border-radius:8px;margin-top:4px;">';
var hots = ai.hot_sectors||[];
for(var i=0;i<hots.length;i++){
var s=hots[i];
h+='<div style="display:flex;align-items:flex-start;gap:10px;padding:14px 16px;border-bottom:'+(i<hots.length-1?'1px solid #F1F5F9;':'none')+'">';
h+='<div style="flex-shrink:0;width:40px;height:40px;border-radius:8px;background:#DCFCE7;display:flex;align-items:center;justify-content:center;font-size:16px;">🏆</div>';
h+='<div style="flex:1;">';
h+='<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px;"><span style="font-weight:800;font-size:15px;">'+s.name+'</span><span style="color:#16A34A;font-weight:800;font-size:15px;">'+s.change+'</span></div>';
h+='<div style="font-size:13px;color:#475569;line-height:1.6;">'+s.reason+'</div>';
h+='<div style="display:flex;flex-wrap:wrap;gap:6px;margin-top:6px;">';
h+='<span style="background:#EFF6FF;color:#1D4ED8;padding:2px 10px;border-radius:10px;font-size:11px;font-weight:600;">대장: '+(s.top_stock||'')+'</span>';
if(s.foreign) h+='<span style="background:#F8FAFC;color:#64748B;padding:2px 10px;border-radius:10px;font-size:11px;">외국인: '+s.foreign+'</span>';
if(s.volume_note) h+='<span style="background:#FEF3C7;color:#92400E;padding:2px 10px;border-radius:10px;font-size:11px;">'+s.volume_note+'</span>';
h+='</div></div></div>';
}
h+='</div>';
// 약세 섹터
var colds = ai.cold_sectors||[];
if(colds.length>0){
h += '<div style="background:#0F172A;color:#F87171;padding:8px 14px;font-weight:bold;border-radius:6px;margin-top:18px;">📉 약세 섹터</div>';
for(var i=0;i<colds.length;i++){
var c=colds[i];
h+='<div style="background:#FEF2F2;border-left:4px solid #DC2626;border-radius:0 8px 8px 0;padding:12px 16px;margin:6px 0;">';
h+='<div style="display:flex;align-items:center;gap:8px;margin-bottom:4px;">';
h+='<span style="font-weight:700;color:#DC2626;font-size:15px;">'+c.name+'</span>';
h+='<span style="color:#DC2626;font-weight:800;font-size:15px;">'+c.change+'</span></div>';
h+='<div style="font-size:13px;color:#64748B;">'+c.reason+'</div>';
if(c.rebound) h+='<div style="font-size:12px;color:#92400E;margin-top:4px;background:#FEF3C7;padding:4px 8px;border-radius:4px;display:inline-block;">반등 전망: '+c.rebound+'</div>';
h+='</div>';
}
}
// 급등 종목 TOP 5
h += '<div style="background:#0F172A;color:#4ADE80;padding:8px 14px;font-weight:bold;border-radius:6px;margin-top:18px;">📈 급등 종목 TOP 5</div>';
h += '<div style="border:1px solid #E2E8F0;border-radius:8px;margin-top:4px;">';
var gainers = ai.top_gainers||[];
for(var i=0;i<gainers.length;i++){
var g=gainers[i];
h+='<div style="padding:14px 16px;border-bottom:'+(i<gainers.length-1?'1px solid #F1F5F9;':'none')+'">';
h+='<div style="display:flex;align-items:center;gap:8px;">';
h+='<span style="background:#DCFCE7;color:#16A34A;width:26px;height:26px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:800;">'+(i+1)+'</span>';
h+='<span style="font-weight:800;font-size:15px;">'+g.name+'</span>';
if(g.code) h+='<span style="font-size:11px;color:#94A3B8;">('+g.code+')</span>';
h+='<span style="color:#16A34A;font-weight:800;font-size:16px;margin-left:auto;">'+g.change+'</span></div>';
h+='<div style="font-size:13px;color:#475569;padding-left:34px;margin-top:4px;line-height:1.6;">'+g.reason+'</div>';
h+='<div style="display:flex;flex-wrap:wrap;gap:6px;padding-left:34px;margin-top:4px;">';
if(g.volume) h+='<span style="background:#F8FAFC;color:#64748B;padding:2px 8px;border-radius:10px;font-size:11px;">거래량: '+g.volume+'</span>';
if(g.continuation) {
var contColor = g.continuation.indexOf('높음')>=0 ? '#16A34A' : g.continuation.indexOf('낮음')>=0 ? '#DC2626' : '#64748B';
var contBg = g.continuation.indexOf('높음')>=0 ? '#DCFCE7' : g.continuation.indexOf('낮음')>=0 ? '#FEE2E2' : '#F8FAFC';
h+='<span style="background:'+contBg+';color:'+contColor+';padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;">내일: '+g.continuation+'</span>';
}
h+='</div></div>';
}
h+='</div>';
// 급락 종목 TOP 5
h += '<div style="background:#0F172A;color:#F87171;padding:8px 14px;font-weight:bold;border-radius:6px;margin-top:18px;">📉 급락 종목 TOP 5</div>';
h += '<div style="border:1px solid #E2E8F0;border-radius:8px;margin-top:4px;">';
var losers = ai.top_losers||[];
for(var i=0;i<losers.length;i++){
var l=losers[i];
h+='<div style="padding:14px 16px;border-bottom:'+(i<losers.length-1?'1px solid #F1F5F9;':'none')+'">';
h+='<div style="display:flex;align-items:center;gap:8px;">';
h+='<span style="background:#FEE2E2;color:#DC2626;width:26px;height:26px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:13px;font-weight:800;">'+(i+1)+'</span>';
h+='<span style="font-weight:800;font-size:15px;">'+l.name+'</span>';
if(l.code) h+='<span style="font-size:11px;color:#94A3B8;">('+l.code+')</span>';
h+='<span style="color:#DC2626;font-weight:800;font-size:16px;margin-left:auto;">'+l.change+'</span></div>';
h+='<div style="font-size:13px;color:#475569;padding-left:34px;margin-top:4px;line-height:1.6;">'+l.reason+'</div>';
if(l.action) {
var actColor = l.action.indexOf('손절')>=0 ? '#DC2626' : l.action.indexOf('추가매수')>=0 ? '#16A34A' : '#D97706';
var actBg = l.action.indexOf('손절')>=0 ? '#FEE2E2' : l.action.indexOf('추가매수')>=0 ? '#DCFCE7' : '#FEF3C7';
h+='<div style="padding-left:34px;margin-top:4px;"><span style="background:'+actBg+';color:'+actColor+';padding:3px 10px;border-radius:10px;font-size:12px;font-weight:600;">'+l.action+'</span></div>';
}
h+='</div>';
}
h+='</div>';
// 내일 주목 (객체 처리)
var tw = ai.tomorrow_watch || {};
if (typeof tw === 'string') {
// 문자열이면 그대로
h += '<div style="background:#EFF6FF;border:1px solid #BFDBFE;border-radius:8px;padding:14px;margin-top:18px;">';
h += '<div style="font-weight:700;color:#1D4ED8;font-size:15px;">🔮 내일 주목 포인트</div>';
h += '<div style="font-size:14px;color:#334155;margin-top:4px;line-height:1.8;">'+tw+'</div></div>';
} else {
// 객체면 각 항목 표시
h += '<div style="background:#EFF6FF;border:1px solid #BFDBFE;border-radius:8px;padding:16px;margin-top:18px;">';
h += '<div style="font-weight:700;color:#1D4ED8;font-size:15px;margin-bottom:10px;">🔮 내일 주목 포인트</div>';
if(tw.direction) h += '<div style="display:flex;gap:8px;margin-bottom:8px;"><span style="background:#1D4ED8;color:white;padding:2px 10px;border-radius:10px;font-size:12px;font-weight:600;flex-shrink:0;">방향</span><span style="font-size:14px;color:#334155;">'+tw.direction+'</span></div>';
if(tw.key_events) h += '<div style="display:flex;gap:8px;margin-bottom:8px;"><span style="background:#D97706;color:white;padding:2px 10px;border-radius:10px;font-size:12px;font-weight:600;flex-shrink:0;">이벤트</span><span style="font-size:14px;color:#334155;">'+tw.key_events+'</span></div>';
if(tw.watch_sectors) h += '<div style="display:flex;gap:8px;margin-bottom:8px;"><span style="background:#16A34A;color:white;padding:2px 10px;border-radius:10px;font-size:12px;font-weight:600;flex-shrink:0;">섹터</span><span style="font-size:14px;color:#334155;">'+tw.watch_sectors+'</span></div>';
if(tw.watch_stocks) h += '<div style="display:flex;gap:8px;"><span style="background:#7C3AED;color:white;padding:2px 10px;border-radius:10px;font-size:12px;font-weight:600;flex-shrink:0;">종목</span><span style="font-size:14px;color:#334155;">'+tw.watch_stocks+'</span></div>';
h += '</div>';
}
// 총평
h += '<div style="background:#0F172A;color:#F5A623;padding:8px 14px;font-weight:bold;border-radius:6px;margin-top:18px;">📝 총평</div>';
var sums=ai.summary||[];
var sumIcons = ['📊','💰','🔮'];
for(var i=0;i<sums.length;i++){
h+='<div style="display:flex;gap:10px;padding:10px 12px;'+(i<sums.length-1?'border-bottom:1px solid #F1F5F9;':'')+'">';
h+='<div style="flex-shrink:0;font-size:16px;">'+(sumIcons[i]||'📌')+'</div>';
h+='<div style="font-size:14px;color:#334155;line-height:1.8;">'+sums[i]+'</div></div>';
}
h += '</div>';
h += '<div style="background:#F8FAFC;padding:12px 20px;border-radius:0 0 12px 12px;border:1px solid #E2E8F0;border-top:none;text-align:center;">';
h += '<div style="color:#94A3B8;font-size:11px;">⚠️ AI 분석 참고자료 · 투자 판단과 책임은 본인에게 있습니다</div>';
h += '<div style="color:#94A3B8;font-size:10px;margin-top:2px;">시세: 네이버증권 · 분석: Gemini + Google Search</div>';
h += '<div style="color:#FCD34D;font-size:11px;font-weight:600;margin-top:4px;">© 2026 PlanX</div>';
h += '</div></div>';
return h;
}
function run_postmarket() {
var md = fetchPostData();
var ai = callGemini(buildPostPrompt(md));
MailApp.sendEmail({to:CONFIG.SEND_TO, subject:'[PlanX] 🌙 장후특징 ('+Utilities.formatDate(new Date(),'Asia/Seoul','yyyy-MM-dd')+')', htmlBody:buildPostHTML(ai,md)});
}
function testRun() { run_postmarket(); }
📋 스크립트 전체 복사
복사 → script.google.com → 붙여넣기 → API키 수정 → 실행