1차 화면설계 최종 확정.

This commit is contained in:
eld_master 2025-09-02 22:51:26 +09:00
parent 3dba643339
commit fa21edf0bc
2 changed files with 514 additions and 37 deletions

View File

@ -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 분석 신뢰도 검증 기능
- 반응형 웹 인터페이스
- 실시간 데이터 수집 및 처리
- 다크모드/일반모드 테마 전환

View File

@ -877,8 +877,6 @@
</div>
<nav class="nav">
<a class="nav-item active" onclick="showPage('dashboard')" data-ko="대시보드" data-en="Dashboard" data-zh="仪表板">대시보드</a>
<a class="nav-item" onclick="showPage('analysis')" data-ko="분석" data-en="Analysis" data-zh="分析">분석</a>
<a class="nav-item" onclick="showPage('simulation')" data-ko="시뮬레이션" data-en="Simulation" data-zh="模拟">시뮬레이션</a>
<a class="nav-item" onclick="showPage('settings')" data-ko="설정" data-en="Settings" data-zh="设置">설정</a>
</nav>
<div class="settings-controls">
@ -1179,20 +1177,160 @@
</div>
</div>
<!-- 기타 페이지 플레이스홀더 -->
<div id="analysis" class="page">
<div style="text-align: center; padding: 100px 20px; color: #a0a0a0;">
<h2 style="font-size: 2rem; margin-bottom: 20px; color: #667eea;" data-ko="🔍 상세 분석" data-en="🔍 Detailed Analysis" data-zh="🔍 详细分析">🔍 상세 분석</h2>
<p data-ko="투자 상품별 상세 분석 페이지가 여기에 표시됩니다." data-en="Detailed analysis page for investment products will be displayed here." data-zh="投资产品的详细分析页面将在此显示。">투자 상품별 상세 분석 페이지가 여기에 표시됩니다.</p>
<p style="margin-top: 10px;" data-ko="차트, AI 분석 리포트, 뉴스 등이 포함됩니다." data-en="Includes charts, AI analysis reports, news, and more." data-zh="包括图表、AI分析报告、新闻等。">차트, AI 분석 리포트, 뉴스 등이 포함됩니다.</p>
</div>
</div>
<!-- 상세 분석 페이지 (시뮬레이션 포함) -->
<div id="detail" class="page">
<div style="padding: 20px;">
<!-- 상세 페이지 헤더 -->
<div style="display: flex; align-items: center; margin-bottom: 30px; border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 20px;">
<button onclick="showPage('dashboard')" style="background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); color: white; padding: 8px 16px; border-radius: 8px; margin-right: 20px; cursor: pointer;">← 뒤로가기</button>
<div>
<h1 style="font-size: 2rem; margin-bottom: 5px; color: #ffffff;" id="detailTitle">Bitcoin (BTC)</h1>
<div style="display: flex; align-items: center; gap: 15px;">
<span style="font-size: 1.5rem; font-weight: bold; color: #22c55e;" id="detailPrice">$43,250.00</span>
<span style="background: rgba(34, 197, 94, 0.2); color: #22c55e; padding: 4px 10px; border-radius: 8px;" id="detailChange">+2.35% (+$992.50)</span>
</div>
</div>
</div>
<div id="simulation" class="page">
<div style="text-align: center; padding: 100px 20px; color: #a0a0a0;">
<h2 style="font-size: 2rem; margin-bottom: 20px; color: #667eea;" data-ko="📊 수익률 시뮬레이션" data-en="📊 Return Simulation" data-zh="📊 收益模拟">📊 수익률 시뮬레이션</h2>
<p data-ko="AI 추천 종목에 대한 투자 시뮬레이션 페이지입니다." data-en="Investment simulation page for AI-recommended stocks." data-zh="AI推荐股票的投资模拟页面。">AI 추천 종목에 대한 투자 시뮬레이션 페이지입니다.</p>
<p style="margin-top: 10px;" data-ko="투자 금액과 전략을 설정하여 예상 수익률을 확인할 수 있습니다." data-en="You can set investment amount and strategy to check expected returns." data-zh="您可以设置投资金额和策略来查看预期收益。">투자 금액과 전략을 설정하여 예상 수익률을 확인할 수 있습니다.</p>
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 30px;">
<!-- 메인 콘텐츠 -->
<div>
<!-- 차트 섹션 -->
<div style="background: rgba(26, 31, 46, 0.8); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px; padding: 24px; margin-bottom: 30px;">
<h3 style="font-size: 1.3rem; margin-bottom: 20px; color: #ffffff;" data-ko="📈 캔들차트" data-en="📈 Candlestick Chart" data-zh="📈 K线图">📈 캔들차트</h3>
<div style="height: 400px; background: rgba(0,0,0,0.2); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: #a0a0a0;">
[TradingView 차트 위젯 영역]
</div>
</div>
<!-- AI 분석 결과 섹션 -->
<div style="background: rgba(26, 31, 46, 0.8); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px; padding: 24px; margin-bottom: 30px;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
<h3 style="font-size: 1.3rem; margin: 0; color: #ffffff;" data-ko="🤖 AI 분석 결과" data-en="🤖 AI Analysis Results" data-zh="🤖 AI分析结果">🤖 AI 분석 결과</h3>
<div style="display: flex; align-items: center; gap: 15px;">
<span style="color: #a0a0a0; font-size: 0.9rem;" id="analysisCount" data-ko="총 247건" data-en="247 Total" data-zh="共247个">총 247건</span>
<div style="display: flex; gap: 10px;">
<button id="viewModeToggle" onclick="toggleViewMode()" style="background: rgba(102, 126, 234, 0.2); border: 1px solid rgba(102, 126, 234, 0.3); color: #667eea; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 0.8rem;" data-ko="간략히보기" data-en="Compact View" data-zh="简洁视图">간략히보기</button>
<button onclick="toggleFilters()" style="background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); color: white; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 0.8rem;">🔍 필터</button>
</div>
</div>
</div>
<!-- 필터 섹션 -->
<div id="filtersPanel" style="display: none; background: rgba(102, 126, 234, 0.05); border: 1px solid rgba(102, 126, 234, 0.2); border-radius: 12px; padding: 20px; margin-bottom: 20px;">
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin-bottom: 15px;">
<div>
<label style="display: block; color: #a0a0a0; margin-bottom: 8px; font-size: 0.9rem;" data-ko="날짜 범위" data-en="Date Range" data-zh="日期范围">날짜 범위</label>
<select id="dateFilter" style="width: 100%; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; padding: 8px; color: white;">
<option value="all" data-ko="전체" data-en="All" data-zh="全部">전체</option>
<option value="today" data-ko="오늘" data-en="Today" data-zh="今天">오늘</option>
<option value="week" data-ko="최근 7일" data-en="Last 7 days" data-zh="最近7天">최근 7일</option>
<option value="month" data-ko="최근 30일" data-en="Last 30 days" data-zh="最近30天">최근 30일</option>
</select>
</div>
<div>
<label style="display: block; color: #a0a0a0; margin-bottom: 8px; font-size: 0.9rem;" data-ko="신뢰도 점수" data-en="Confidence Score" data-zh="置信度评分">신뢰도 점수</label>
<select id="scoreFilter" style="width: 100%; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; padding: 8px; color: white;">
<option value="all" data-ko="전체" data-en="All" data-zh="全部">전체</option>
<option value="high" data-ko="8.0 이상" data-en="8.0+" data-zh="8.0以上">8.0 이상</option>
<option value="medium" data-ko="6.0-7.9" data-en="6.0-7.9" data-zh="6.0-7.9">6.0-7.9</option>
<option value="low" data-ko="6.0 미만" data-en="Under 6.0" data-zh="6.0以下">6.0 미만</option>
</select>
</div>
<div>
<label style="display: block; color: #a0a0a0; margin-bottom: 8px; font-size: 0.9rem;" data-ko="분석 상태" data-en="Analysis Status" data-zh="分析状态">분석 상태</label>
<select id="statusFilter" style="width: 100%; background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); border-radius: 6px; padding: 8px; color: white;">
<option value="all" data-ko="전체" data-en="All" data-zh="全部">전체</option>
<option value="active" data-ko="활성" data-en="Active" data-zh="活跃">활성</option>
<option value="expired" data-ko="만료" data-en="Expired" data-zh="过期">만료</option>
<option value="hit" data-ko="적중" data-en="Hit Target" data-zh="命中">적중</option>
<option value="stop" data-ko="손절" data-en="Stop Loss" data-zh="止损">손절</option>
</select>
</div>
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<div style="display: flex; gap: 10px;">
<button onclick="selectAllAnalyses()" style="background: rgba(34, 197, 94, 0.2); border: 1px solid rgba(34, 197, 94, 0.3); color: #22c55e; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 0.8rem;" data-ko="전체 선택" data-en="Select All" data-zh="全选">전체 선택</button>
<button onclick="deselectAllAnalyses()" style="background: rgba(239, 68, 68, 0.2); border: 1px solid rgba(239, 68, 68, 0.3); color: #ef4444; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 0.8rem;" data-ko="전체 해제" data-en="Deselect All" data-zh="取消全选">전체 해제</button>
</div>
<button onclick="applyFilters()" style="background: linear-gradient(135deg, #667eea, #764ba2); border: none; color: white; padding: 8px 16px; border-radius: 6px; cursor: pointer; font-weight: 600;" data-ko="필터 적용" data-en="Apply Filters" data-zh="应用过滤器">필터 적용</button>
</div>
</div>
<!-- 일괄 선택 영역 -->
<div style="background: rgba(255, 255, 255, 0.05); border-radius: 8px; padding: 12px; margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
<div style="display: flex; align-items: center; gap: 10px;">
<input type="checkbox" id="selectAllVisible" onclick="toggleAllVisible()" style="width: 16px; height: 16px;">
<span style="color: #ffffff; font-size: 0.9rem;" data-ko="표시된 분석 전체 선택" data-en="Select all visible analyses" data-zh="选择所有可见分析">표시된 분석 전체 선택</span>
</div>
<span id="selectedCount" style="color: #667eea; font-size: 0.9rem;" data-ko="0개 선택됨" data-en="0 selected" data-zh="已选择0个">0개 선택됨</span>
</div>
<!-- AI 분석 카드들 -->
<div id="analysisContainer" style="display: grid; gap: 15px; max-height: 600px; overflow-y: auto; padding-right: 10px;">
<!-- AI 분석 카드들이 동적으로 생성됨 -->
</div>
<!-- 더 보기 버튼 -->
<div style="text-align: center; margin-top: 20px;">
<button id="loadMoreBtn" onclick="loadMoreAnalyses()" style="background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.2); color: white; padding: 10px 20px; border-radius: 8px; cursor: pointer;" data-ko="더 보기 (남은 235개)" data-en="Load More (235 remaining)" data-zh="加载更多 (剩余235个)">더 보기 (남은 235개)</button>
</div>
</div>
<!-- 수익률 시뮬레이션 섹션 -->
<div style="background: rgba(26, 31, 46, 0.8); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px; padding: 24px;">
<h3 style="font-size: 1.3rem; margin-bottom: 20px; color: #ffffff;" data-ko="📊 수익률 시뮬레이션" data-en="📊 Return Simulation" data-zh="📊 收益模拟">📊 수익률 시뮬레이션</h3>
<div style="background: rgba(102, 126, 234, 0.1); border: 1px solid rgba(102, 126, 234, 0.2); border-radius: 12px; padding: 20px; margin-bottom: 20px;">
<div style="display: flex; align-items: center; gap: 15px; margin-bottom: 15px;">
<label style="color: #ffffff; font-weight: 600;" data-ko="투자 금액:" data-en="Investment Amount:" data-zh="投资金额:">투자 금액:</label>
<input type="text" id="investmentAmount" value="10,000,000" style="background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2); border-radius: 8px; padding: 8px 12px; color: white; width: 150px;">
<span style="color: #a0a0a0;"></span>
<button onclick="runSimulation()" style="background: linear-gradient(135deg, #667eea, #764ba2); border: none; color: white; padding: 8px 16px; border-radius: 8px; cursor: pointer; margin-left: auto;" data-ko="시뮬레이션 실행" data-en="Run Simulation" data-zh="运行模拟">시뮬레이션 실행</button>
</div>
<p style="color: #a0a0a0; font-size: 0.9rem;" data-ko="위에서 선택한 AI 분석 결과를 기반으로 시뮬레이션합니다." data-en="Simulation based on selected AI analysis results above." data-zh="基于上面选择的AI分析结果进行模拟。">위에서 선택한 AI 분석 결과를 기반으로 시뮬레이션합니다.</p>
</div>
<!-- 시뮬레이션 결과 -->
<div id="simulationResults" style="display: none;">
<h4 style="color: #667eea; margin-bottom: 15px;" data-ko="시뮬레이션 결과" data-en="Simulation Results" data-zh="模拟结果">시뮬레이션 결과</h4>
<div id="simulationCards" style="display: grid; gap: 15px;">
<!-- 결과 카드들이 동적으로 생성됨 -->
</div>
</div>
</div>
</div>
<!-- 사이드바 -->
<div>
<!-- 관련 뉴스 -->
<div style="background: rgba(26, 31, 46, 0.8); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 16px; padding: 24px; margin-bottom: 20px;">
<h3 style="font-size: 1.2rem; margin-bottom: 20px; color: #ffffff;" data-ko="📰 관련 뉴스" data-en="📰 Related News" data-zh="📰 相关新闻">📰 관련 뉴스</h3>
<div style="display: flex; flex-direction: column; gap: 15px;">
<div style="border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 15px;">
<h4 style="font-size: 0.9rem; color: #ffffff; margin-bottom: 8px; line-height: 1.4;">비트코인 ETF 승인으로 기관 자금 대거 유입</h4>
<p style="font-size: 0.8rem; color: #a0a0a0;">2시간 전 • 코인데스크</p>
</div>
<div style="border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 15px;">
<h4 style="font-size: 0.9rem; color: #ffffff; margin-bottom: 8px; line-height: 1.4;">마이크로스트래티지, 추가 BTC 매입 발표</h4>
<p style="font-size: 0.8rem; color: #a0a0a0;">4시간 전 • 블룸버그</p>
</div>
<div>
<h4 style="font-size: 0.9rem; color: #ffffff; margin-bottom: 8px; line-height: 1.4;">테슬라 BTC 보유량 증가 시사</h4>
<p style="font-size: 0.8rem; color: #a0a0a0;">6시간 전 • 로이터</p>
</div>
</div>
</div>
<!-- 광고 -->
<div class="sidebar-ad">
<div>
<div style="font-size: 1rem; font-weight: bold; margin-bottom: 8px;">📊 [상세 페이지 광고]</div>
<div style="font-size: 0.85rem; opacity: 0.8; line-height: 1.4;">상세 분석 페이지<br>타겟 광고 영역<br>320x200px</div>
</div>
</div>
</div>
</div>
</div>
</div>
@ -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 = `
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
<h5 style="color: #667eea; margin: 0;">${aiId === 'ai1' ? 'AI 분석 #1' : 'AI 분석 #2'} 시뮬레이션</h5>
<span style="background: ${mockData.profit > 0 ? 'rgba(34, 197, 94, 0.2)' : 'rgba(239, 68, 68, 0.2)'}; color: ${mockData.profit > 0 ? '#22c55e' : '#ef4444'}; padding: 4px 8px; border-radius: 6px; font-weight: bold;">
${mockData.profit > 0 ? '+' : ''}${mockData.profitRate.toFixed(2)}%
</span>
</div>
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin-bottom: 15px;">
<div>
<div style="font-size: 0.9rem; color: #a0a0a0; margin-bottom: 4px;">목표가 달성시</div>
<div style="font-size: 1.2rem; font-weight: bold; color: #22c55e;">+${mockData.targetProfit.toLocaleString()}원</div>
<div style="font-size: 0.8rem; color: #22c55e;">(+${mockData.targetRate.toFixed(2)}%)</div>
</div>
<div>
<div style="font-size: 0.9rem; color: #a0a0a0; margin-bottom: 4px;">손절가 도달시</div>
<div style="font-size: 1.2rem; font-weight: bold; color: #ef4444;">-${Math.abs(mockData.stopLoss).toLocaleString()}원</div>
<div style="font-size: 0.8rem; color: #ef4444;">(${mockData.stopRate.toFixed(2)}%)</div>
</div>
</div>
<div style="background: rgba(255,255,255,0.05); border-radius: 8px; padding: 12px;">
<div style="font-size: 0.9rem; color: #ffffff; margin-bottom: 8px;">AI 분석 신뢰도 검증</div>
<div style="display: flex; justify-content: space-between; font-size: 0.8rem;">
<span style="color: #a0a0a0;">과거 30일 적중률:</span>
<span style="color: #f59e0b; font-weight: bold;">${mockData.accuracy}%</span>
</div>
<div style="display: flex; justify-content: space-between; font-size: 0.8rem;">
<span style="color: #a0a0a0;">평균 수익률:</span>
<span style="color: ${mockData.avgReturn > 0 ? '#22c55e' : '#ef4444'}; font-weight: bold;">${mockData.avgReturn > 0 ? '+' : ''}${mockData.avgReturn.toFixed(2)}%</span>
</div>
</div>
`;
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 = `
<input type="checkbox" class="ai-select" data-id="${analysis.id}" style="width: 16px; height: 16px;" ${selectedAnalyses.has(analysis.id) ? 'checked' : ''}>
<div style="display: flex; align-items: center; gap: 8px; min-width: 120px;">
<div style="background: linear-gradient(135deg, #667eea, #764ba2); border-radius: 50%; width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; font-size: 10px;">🤖</div>
<span style="font-size: 0.8rem; color: #a0a0a0;">${analysis.hoursAgo}시간 전</span>
</div>
<div style="flex: 1; font-size: 0.9rem; color: #e0e0e0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
${analysis.text}
</div>
<div style="display: flex; gap: 8px; font-size: 0.8rem;">
<span style="color: #3b82f6;">$${analysis.entryPrice.toLocaleString()}</span>
<span style="color: #f59e0b;">$${analysis.targetPrice.toLocaleString()}</span>
<span style="color: #ef4444;">$${analysis.stopPrice.toLocaleString()}</span>
</div>
<span style="background: ${getScoreColor(analysis.score).bg}; color: ${getScoreColor(analysis.score).text}; padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; min-width: 40px; text-align: center;">
${analysis.score}/10
</span>
`;
} 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 = `
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 15px;">
<div>
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
<div style="background: linear-gradient(135deg, #667eea, #764ba2); border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; font-size: 12px;">🤖</div>
<span style="font-weight: 600; color: #667eea;">AI 분석 #${analysis.id.replace('ai', '')} (${analysis.hoursAgo}시간 전)</span>
<span style="background: ${getScoreColor(analysis.score).bg}; color: ${getScoreColor(analysis.score).text}; padding: 2px 8px; border-radius: 4px; font-size: 0.8rem;">${analysis.score}/10</span>
<span style="background: ${getStatusColor(analysis.status).bg}; color: ${getStatusColor(analysis.status).text}; padding: 2px 8px; border-radius: 4px; font-size: 0.75rem;">${getStatusText(analysis.status)}</span>
</div>
<p style="color: #e0e0e0; line-height: 1.5; margin-bottom: 15px;">${analysis.text}</p>
</div>
<input type="checkbox" class="ai-select" data-id="${analysis.id}" style="width: 18px; height: 18px; margin-left: 10px;" ${selectedAnalyses.has(analysis.id) ? 'checked' : ''}>
</div>
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;">
<div style="text-align: center; padding: 10px; background: rgba(255,255,255,0.05); border-radius: 8px;">
<div style="font-size: 0.8rem; color: #a0a0a0; margin-bottom: 4px;">진입가</div>
<div style="font-weight: 700; color: #3b82f6;">$${analysis.entryPrice.toLocaleString()}</div>
</div>
<div style="text-align: center; padding: 10px; background: rgba(255,255,255,0.05); border-radius: 8px;">
<div style="font-size: 0.8rem; color: #a0a0a0; margin-bottom: 4px;">목표가</div>
<div style="font-weight: 700; color: #f59e0b;">$${analysis.targetPrice.toLocaleString()}</div>
</div>
<div style="text-align: center; padding: 10px; background: rgba(255,255,255,0.05); border-radius: 8px;">
<div style="font-size: 0.8rem; color: #a0a0a0; margin-bottom: 4px;">손절가</div>
<div style="font-weight: 700; color: #ef4444;">$${analysis.stopPrice.toLocaleString()}</div>
</div>
</div>
`;
}
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);
});
</script>