diff --git a/설계/01/1차 요구사항정의서.md b/설계/01/1차 요구사항정의서.md index 03745bb..51e1e11 100644 --- a/설계/01/1차 요구사항정의서.md +++ b/설계/01/1차 요구사항정의서.md @@ -37,25 +37,33 @@ - **FR-009**: 시스템은 투자 상품 관련 뉴스를 수집해야 한다 - **FR-010**: 시스템은 캔들 데이터(OHLCV)를 수집하고 저장해야 한다 -### 2.4 수익률 시뮬레이션 -- **FR-011**: 시스템은 AI 분석 결과를 기반으로 수익률 시뮬레이션을 제공해야 한다 -- **FR-012**: 사용자는 투자 금액을 입력하여 예상 수익/손실을 계산할 수 있어야 한다 -- **FR-013**: 시뮬레이션 결과는 목표가 달성시, 손절가 도달시 시나리오를 포함해야 한다 +### 2.4 상세 분석 및 수익률 시뮬레이션 +- **FR-011**: 시스템은 투자 상품별 상세 분석 페이지를 제공해야 한다 +- **FR-012**: 상세 분석 페이지는 캔들차트, AI 분석 결과, 관련 뉴스를 포함해야 한다 +- **FR-013**: 시스템은 상세 페이지에서 AI 분석 결과를 기반으로 수익률 시뮬레이션을 제공해야 한다 +- **FR-014**: 사용자는 여러 AI 분석 결과 중 원하는 것을 선택하여 시뮬레이션할 수 있어야 한다 +- **FR-015**: 사용자는 투자 금액(기본값 1,000만원)을 입력하여 예상 수익/손실을 계산할 수 있어야 한다 +- **FR-016**: 시뮬레이션 결과는 선택된 AI 분석의 목표가 달성시, 손절가 도달시 수익률을 표시해야 한다 +- **FR-017**: 시뮬레이션을 통해 AI 분석 결과의 신뢰도와 유효성을 검증할 수 있어야 한다 +- **FR-018**: 시스템은 AI 분석 결과를 날짜, 점수, 상태별로 필터링할 수 있어야 한다 +- **FR-019**: 시스템은 AI 분석 결과의 간략히보기/상세보기 모드를 제공해야 한다 +- **FR-020**: 시스템은 AI 분석 결과를 페이지네이션 또는 무한스크롤로 처리해야 한다 +- **FR-021**: 사용자는 AI 분석 결과를 일괄 선택/해제할 수 있어야 한다 ### 2.5 사용자 인터페이스 -- **FR-014**: 메인 대시보드는 모든 투자 상품을 그리드 형태로 표시해야 한다 -- **FR-015**: 투자 상품 클릭시 상세 분석 패널이 표시되어야 한다 -- **FR-016**: 상세 패널은 캔들차트, AI 분석 결과, 수익률 시뮬레이션을 포함해야 한다 -- **FR-017**: 웹 인터페이스는 모바일 반응형으로 구현되어야 한다 -- **FR-018**: 시스템은 다크모드/일반모드 테마 전환 기능을 제공해야 한다 -- **FR-019**: 테마 설정은 브라우저 로컬스토리지에 저장되어야 한다 +- **FR-022**: 메인 대시보드는 모든 투자 상품을 그리드 형태로 표시해야 한다 +- **FR-023**: 투자 상품 클릭시 상세 분석 페이지가 표시되어야 한다 +- **FR-024**: 상세 분석 페이지는 캔들차트, AI 분석 결과, 수익률 시뮬레이션 섹션을 포함해야 한다 +- **FR-025**: 웹 인터페이스는 모바일 반응형으로 구현되어야 한다 +- **FR-026**: 시스템은 다크모드/일반모드 테마 전환 기능을 제공해야 한다 +- **FR-027**: 테마 설정은 브라우저 로컬스토리지에 저장되어야 한다 ### 2.6 다국어 지원 -- **FR-020**: 시스템은 사용자의 IP 주소를 기반으로 자동 언어 감지 기능을 제공해야 한다 -- **FR-021**: 시스템은 한국어, 영어, 중국어(간체)를 지원해야 한다 -- **FR-022**: 언어 설정은 수동으로 변경 가능해야 한다 -- **FR-023**: 모든 UI 텍스트, 버튼, 메뉴는 다국어로 표시되어야 한다 -- **FR-024**: 투자 상품명과 기본 정보는 해당 언어로 표시되어야 한다 +- **FR-028**: 시스템은 사용자의 IP 주소를 기반으로 자동 언어 감지 기능을 제공해야 한다 +- **FR-029**: 시스템은 한국어, 영어, 중국어(간체)를 지원해야 한다 +- **FR-030**: 언어 설정은 수동으로 변경 가능해야 한다 +- **FR-031**: 모든 UI 텍스트, 버튼, 메뉴는 다국어로 표시되어야 한다 +- **FR-032**: 투자 상품명과 기본 정보는 해당 언어로 표시되어야 한다 ## 3. 비기능적 요구사항 (Non-Functional Requirements) @@ -105,13 +113,13 @@ - Actor: 개인 투자자 - Flow: 메인 페이지 접속 → 투자 상품 리스트 확인 → 실시간 가격 조회 -2. **AI 분석 결과 확인** +2. **투자 상품 상세 분석** - Actor: 개인 투자자 - - Flow: 투자 상품 클릭 → AI 분석 결과 패널 표시 → 목표가/손절가/진입가 확인 + - Flow: 투자 상품 클릭 → 상세 분석 페이지 진입 → 캔들차트, AI 분석 결과, 관련 뉴스 확인 3. **수익률 시뮬레이션** - Actor: 개인 투자자 - - Flow: 1000만원을 투자했다면?(고정) → 원하는 AI 분석 결과 체크 → 체크된 AI 분석 결과인 목표가/손절가/진입가를 기반한 수익률 계산 → 결과 확인 + - Flow: 상세 분석 페이지 → 시뮬레이션 섹션 → 여러 AI 분석 결과 중 선택 → 투자 금액 입력(기본 1,000만원) → 선택된 AI 분석의 목표가/손절가 기준 수익률 계산 → 결과 확인 및 AI 분석 신뢰도 검증 ### 5.2 System Use Cases 1. **데이터 수집** @@ -131,8 +139,10 @@ ### 6.1 MVP 포함 기능 ✅ **포함** - 코인 5종 + 주식 5종 실시간 가격 표시 +- 투자 상품별 상세 분석 페이지 (캔들차트, AI 분석, 뉴스) - AI 분석 결과 (목표가, 손절가, 진입가, 매력도) -- 수익률 시뮬레이션 +- 상세 페이지 내 수익률 시뮬레이션 (다중 AI 분석 선택) +- AI 분석 신뢰도 검증 기능 - 반응형 웹 인터페이스 - 실시간 데이터 수집 및 처리 - 다크모드/일반모드 테마 전환 diff --git a/설계/01/화면설계서/index.html b/설계/01/화면설계서/index.html index f9187cd..8501b75 100644 --- a/설계/01/화면설계서/index.html +++ b/설계/01/화면설계서/index.html @@ -877,8 +877,6 @@
@@ -1179,20 +1177,160 @@
- -
-
-

🔍 상세 분석

-

투자 상품별 상세 분석 페이지가 여기에 표시됩니다.

-

차트, AI 분석 리포트, 뉴스 등이 포함됩니다.

-
-
- -
-
-

📊 수익률 시뮬레이션

-

AI 추천 종목에 대한 투자 시뮬레이션 페이지입니다.

-

투자 금액과 전략을 설정하여 예상 수익률을 확인할 수 있습니다.

+ +
+
+ +
+ +
+

Bitcoin (BTC)

+
+ $43,250.00 + +2.35% (+$992.50) +
+
+
+ +
+ +
+ +
+

📈 캔들차트

+
+ [TradingView 차트 위젯 영역] +
+
+ + +
+
+

🤖 AI 분석 결과

+
+ 총 247건 +
+ + +
+
+
+ + + + + +
+
+ + 표시된 분석 전체 선택 +
+ 0개 선택됨 +
+ + +
+ +
+ + +
+ +
+
+ + +
+

📊 수익률 시뮬레이션

+ +
+
+ + + + +
+

위에서 선택한 AI 분석 결과를 기반으로 시뮬레이션합니다.

+
+ + + +
+
+ + +
+ +
+

📰 관련 뉴스

+
+
+

비트코인 ETF 승인으로 기관 자금 대거 유입

+

2시간 전 • 코인데스크

+
+
+

마이크로스트래티지, 추가 BTC 매입 발표

+

4시간 전 • 블룸버그

+
+
+

테슬라 BTC 보유량 증가 시사

+

6시간 전 • 로이터

+
+
+
+ + + +
+
@@ -1235,8 +1373,333 @@ // 상세 페이지 열기 function openDetail(symbol) { - console.log(`Opening detail for ${symbol}`); - alert(`${symbol} 상세 분석 페이지를 열겠습니다.`); + document.getElementById('detailTitle').textContent = getSymbolName(symbol); + showPage('detail'); + } + + function getSymbolName(symbol) { + const names = { + 'BTC': 'Bitcoin (BTC)', + 'ETH': 'Ethereum (ETH)', + 'AAPL': 'Apple Inc. (AAPL)', + 'TSLA': 'Tesla Inc. (TSLA)' + }; + return names[symbol] || symbol; + } + + // 시뮬레이션 실행 + function runSimulation() { + const selectedAI = document.querySelectorAll('.ai-select:checked'); + const amount = document.getElementById('investmentAmount').value.replace(/,/g, ''); + + if (selectedAI.length === 0) { + alert('시뮬레이션할 AI 분석을 선택해주세요.'); + return; + } + + const resultsContainer = document.getElementById('simulationCards'); + resultsContainer.innerHTML = ''; + + selectedAI.forEach((checkbox, index) => { + const aiId = checkbox.getAttribute('data-id'); + const mockData = getMockSimulationData(aiId, parseInt(amount)); + + const resultCard = document.createElement('div'); + resultCard.style.cssText = 'background: rgba(102, 126, 234, 0.1); border: 1px solid rgba(102, 126, 234, 0.3); border-radius: 12px; padding: 20px;'; + + resultCard.innerHTML = ` +
+
${aiId === 'ai1' ? 'AI 분석 #1' : 'AI 분석 #2'} 시뮬레이션
+ + ${mockData.profit > 0 ? '+' : ''}${mockData.profitRate.toFixed(2)}% + +
+
+
+
목표가 달성시
+
+${mockData.targetProfit.toLocaleString()}원
+
(+${mockData.targetRate.toFixed(2)}%)
+
+
+
손절가 도달시
+
-${Math.abs(mockData.stopLoss).toLocaleString()}원
+
(${mockData.stopRate.toFixed(2)}%)
+
+
+
+
AI 분석 신뢰도 검증
+
+ 과거 30일 적중률: + ${mockData.accuracy}% +
+
+ 평균 수익률: + ${mockData.avgReturn > 0 ? '+' : ''}${mockData.avgReturn.toFixed(2)}% +
+
+ `; + + resultsContainer.appendChild(resultCard); + }); + + document.getElementById('simulationResults').style.display = 'block'; + } + + function getMockSimulationData(aiId, amount) { + const data = { + 'ai1': { + targetProfit: Math.round(amount * 0.086), + targetRate: 8.6, + stopLoss: Math.round(amount * 0.061), + stopRate: -6.1, + accuracy: 76.8, + avgReturn: 5.2 + }, + 'ai2': { + targetProfit: Math.round(amount * 0.103), + targetRate: 10.3, + stopLoss: Math.round(amount * 0.041), + stopRate: -4.1, + accuracy: 71.2, + avgReturn: 6.8 + } + }; + + const result = data[aiId]; + result.profit = Math.round((Math.random() > 0.7 ? result.targetProfit : -result.stopLoss)); + result.profitRate = (result.profit / amount) * 100; + + return result; + } + + // AI 분석 관리 변수 + let isCompactView = false; + let currentPage = 0; + let totalAnalyses = 247; + let loadedAnalyses = 12; + let selectedAnalyses = new Set(); + let mockAnalyses = []; + + // 목 데이터 생성 + function generateMockAnalyses() { + const statuses = ['active', 'expired', 'hit', 'stop']; + const analysisTexts = [ + '기관 자금 유입 지속으로 상승 모멘텀 유지. 기술적 분석에서 강세 신호 감지됨.', + '단기 조정 가능성이 있으나 중장기 상승 트렌드는 유효. 지지선 근처에서 매수 기회.', + 'RSI 과매도 구간 진입으로 반등 가능성 높음. 거래량 증가 신호 포착.', + '이동평균선 돌파로 상승 추세 전환. 목표가 상향 조정 필요.', + '변동성 확대로 단기 트레이딩 기회 발생. 리스크 관리 필수.', + '시장 전반적 조정 영향으로 중립적 관점 유지. 관망 권장.', + '펀더멘털 분석 결과 저평가 상태. 중장기 투자 매력도 높음.', + '차트상 삼각수렴 패턴 완성. 방향성 돌파 임박.' + ]; + + for (let i = 0; i < totalAnalyses; i++) { + const hoursAgo = Math.floor(Math.random() * 720) + 1; // 1~720시간 전 + const score = (Math.random() * 4 + 6).toFixed(1); // 6.0~10.0 + const status = statuses[Math.floor(Math.random() * statuses.length)]; + const textIndex = Math.floor(Math.random() * analysisTexts.length); + + mockAnalyses.push({ + id: `ai${i + 1}`, + hoursAgo: hoursAgo, + score: parseFloat(score), + status: status, + text: analysisTexts[textIndex], + entryPrice: Math.round(42000 + (Math.random() * 2000 - 1000)), + targetPrice: Math.round(46000 + (Math.random() * 2000 - 1000)), + stopPrice: Math.round(40000 + (Math.random() * 1000)) + }); + } + } + + // 뷰 모드 토글 + function toggleViewMode() { + isCompactView = !isCompactView; + const toggle = document.getElementById('viewModeToggle'); + + if (isCompactView) { + toggle.textContent = getTranslatedText('상세보기', 'Detailed View', '详细视图'); + toggle.style.background = 'rgba(245, 158, 11, 0.2)'; + toggle.style.borderColor = 'rgba(245, 158, 11, 0.3)'; + toggle.style.color = '#f59e0b'; + } else { + toggle.textContent = getTranslatedText('간략히보기', 'Compact View', '简洁视图'); + toggle.style.background = 'rgba(102, 126, 234, 0.2)'; + toggle.style.borderColor = 'rgba(102, 126, 234, 0.3)'; + toggle.style.color = '#667eea'; + } + + renderAnalyses(); + } + + // 필터 토글 + function toggleFilters() { + const panel = document.getElementById('filtersPanel'); + panel.style.display = panel.style.display === 'none' ? 'block' : 'none'; + } + + // 분석 결과 렌더링 + function renderAnalyses() { + const container = document.getElementById('analysisContainer'); + const analyses = mockAnalyses.slice(0, loadedAnalyses); + container.innerHTML = ''; + + analyses.forEach(analysis => { + const card = document.createElement('div'); + card.className = 'ai-analysis-card'; + + if (isCompactView) { + // 간략히보기 모드 + card.style.cssText = 'background: rgba(102, 126, 234, 0.1); border: 1px solid rgba(102, 126, 234, 0.3); border-radius: 8px; padding: 12px; display: flex; align-items: center; gap: 15px;'; + card.innerHTML = ` + +
+
🤖
+ ${analysis.hoursAgo}시간 전 +
+
+ ${analysis.text} +
+
+ $${analysis.entryPrice.toLocaleString()} + $${analysis.targetPrice.toLocaleString()} + $${analysis.stopPrice.toLocaleString()} +
+ + ${analysis.score}/10 + + `; + } else { + // 상세보기 모드 + card.style.cssText = 'background: rgba(102, 126, 234, 0.1); border: 1px solid rgba(102, 126, 234, 0.3); border-radius: 12px; padding: 20px;'; + card.innerHTML = ` +
+
+
+
🤖
+ AI 분석 #${analysis.id.replace('ai', '')} (${analysis.hoursAgo}시간 전) + ${analysis.score}/10 + ${getStatusText(analysis.status)} +
+

${analysis.text}

+
+ +
+
+
+
진입가
+
$${analysis.entryPrice.toLocaleString()}
+
+
+
목표가
+
$${analysis.targetPrice.toLocaleString()}
+
+
+
손절가
+
$${analysis.stopPrice.toLocaleString()}
+
+
+ `; + } + + container.appendChild(card); + }); + + // 체크박스 이벤트 리스너 추가 + document.querySelectorAll('.ai-select').forEach(checkbox => { + checkbox.addEventListener('change', updateSelectedCount); + }); + + updateSelectedCount(); + } + + // 헬퍼 함수들 + function getScoreColor(score) { + if (score >= 8.0) return { bg: 'rgba(34, 197, 94, 0.2)', text: '#22c55e' }; + if (score >= 6.0) return { bg: 'rgba(245, 158, 11, 0.2)', text: '#f59e0b' }; + return { bg: 'rgba(239, 68, 68, 0.2)', text: '#ef4444' }; + } + + function getStatusColor(status) { + const colors = { + 'active': { bg: 'rgba(59, 130, 246, 0.2)', text: '#3b82f6' }, + 'expired': { bg: 'rgba(107, 114, 128, 0.2)', text: '#6b7280' }, + 'hit': { bg: 'rgba(34, 197, 94, 0.2)', text: '#22c55e' }, + 'stop': { bg: 'rgba(239, 68, 68, 0.2)', text: '#ef4444' } + }; + return colors[status] || colors.active; + } + + function getStatusText(status) { + const texts = { + 'active': '활성', + 'expired': '만료', + 'hit': '적중', + 'stop': '손절' + }; + return texts[status] || '활성'; + } + + // 선택 관리 함수들 + function updateSelectedCount() { + selectedAnalyses.clear(); + document.querySelectorAll('.ai-select:checked').forEach(cb => { + selectedAnalyses.add(cb.getAttribute('data-id')); + }); + + const count = selectedAnalyses.size; + document.getElementById('selectedCount').textContent = getTranslatedText( + `${count}개 선택됨`, + `${count} selected`, + `已选择${count}个` + ); + } + + function toggleAllVisible() { + const selectAll = document.getElementById('selectAllVisible'); + const checkboxes = document.querySelectorAll('.ai-select'); + + checkboxes.forEach(cb => { + cb.checked = selectAll.checked; + }); + + updateSelectedCount(); + } + + function selectAllAnalyses() { + document.querySelectorAll('.ai-select').forEach(cb => cb.checked = true); + document.getElementById('selectAllVisible').checked = true; + updateSelectedCount(); + } + + function deselectAllAnalyses() { + document.querySelectorAll('.ai-select').forEach(cb => cb.checked = false); + document.getElementById('selectAllVisible').checked = false; + updateSelectedCount(); + } + + function loadMoreAnalyses() { + loadedAnalyses = Math.min(loadedAnalyses + 12, totalAnalyses); + renderAnalyses(); + + const remaining = totalAnalyses - loadedAnalyses; + const btn = document.getElementById('loadMoreBtn'); + if (remaining > 0) { + btn.textContent = getTranslatedText( + `더 보기 (남은 ${remaining}개)`, + `Load More (${remaining} remaining)`, + `加载更多 (剩余${remaining}个)` + ); + } else { + btn.style.display = 'none'; + } + } + + function applyFilters() { + // 필터 로직 구현 + console.log('Filters applied'); + // 실제로는 필터 조건에 맞는 데이터를 다시 로드하고 renderAnalyses() 호출 } // 실시간 가격 업데이트 시뮬레이션 @@ -1401,6 +1864,10 @@ // 초기 데이터 로드 시뮬레이션 setTimeout(() => { console.log('실시간 데이터 연결 완료'); + + // AI 분석 데이터 초기화 + generateMockAnalyses(); + renderAnalyses(); }, 3500); });