This commit is contained in:
YeoJeongHun1 2025-08-22 17:27:37 +09:00
commit 5d043bfd0f
28 changed files with 5599 additions and 0 deletions

10
.tmp.driveupload/192376 Normal file
View File

@ -0,0 +1,10 @@
[core]
repositoryformatversion = 0
filemode = false
bare = false
logallrefupdates = true
symlinks = false
ignorecase = true
[remote "origin"]
url = http://eldsoft.com:4000/eld_master/ai_invest.git
fetch = +refs/heads/*:refs/remotes/origin/*

24
imai-invest-manager-AI/.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@ -0,0 +1,69 @@
# React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
## Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
```js
export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Remove tseslint.configs.recommended and replace with this
...tseslint.configs.recommendedTypeChecked,
// Alternatively, use this for stricter rules
...tseslint.configs.strictTypeChecked,
// Optionally, add this for stylistic rules
...tseslint.configs.stylisticTypeChecked,
// Other configs...
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
```js
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])
```

View File

@ -0,0 +1,23 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'
import { globalIgnores } from 'eslint/config'
export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
js.configs.recommended,
tseslint.configs.recommended,
reactHooks.configs['recommended-latest'],
reactRefresh.configs.vite,
],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
},
])

View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

3027
imai-invest-manager-AI/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
{
"name": "imai-invest-manager-ai",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"react": "^19.1.1",
"react-dom": "^19.1.1"
},
"devDependencies": {
"@eslint/js": "^9.33.0",
"@types/react": "^19.1.10",
"@types/react-dom": "^19.1.7",
"@vitejs/plugin-react-swc": "^4.0.0",
"eslint": "^9.33.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.20",
"globals": "^16.3.0",
"typescript": "~5.8.3",
"typescript-eslint": "^8.39.1",
"vite": "^7.1.2"
}
}

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,42 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}
@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
}

View File

@ -0,0 +1,35 @@
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App() {
const [count, setCount] = useState(0)
return (
<>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
)
}
export default App

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,68 @@
:root {
font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}

View File

@ -0,0 +1,10 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)

View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -0,0 +1,27 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
"jsx": "react-jsx",
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["src"]
}

View File

@ -0,0 +1,7 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

View File

@ -0,0 +1,25 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2023",
"lib": ["ES2023"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"moduleDetection": "force",
"noEmit": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
"noUncheckedSideEffectImports": true
},
"include": ["vite.config.ts"]
}

View File

@ -0,0 +1,7 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
})

View File

@ -0,0 +1,615 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI 투자 시스템</title>
<script src="https://cdn.tailwindcss.com"></script>
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect } = React;
// 설정
const COIN_LIST = [
{ code: 'KRW-BTC', name: '비트코인', symbol: 'BTC' },
{ code: 'KRW-ETH', name: '이더리움', symbol: 'ETH' },
{ code: 'KRW-SOL', name: '솔라나', symbol: 'SOL' },
{ code: 'KRW-XRP', name: '리플', symbol: 'XRP' },
{ code: 'KRW-ADA', name: '에이다', symbol: 'ADA' }
];
// API 함수들
const getUpbitCurrentPrice = async (markets) => {
try {
const response = await fetch(`https://api.upbit.com/v1/ticker?markets=${markets.join(',')}`);
const data = await response.json();
return data.map(item => ({
market: item.market,
trade_price: item.trade_price,
change: item.change,
change_price: item.change_price,
change_rate: item.change_rate
}));
} catch (error) {
console.error('업비트 API 호출 실패:', error);
return [];
}
};
// 더미 캔들 데이터 생성 함수
const generateDummyCandles = (count, basePrice) => {
const candles = [];
let currentPrice = basePrice;
const now = new Date();
for (let i = count - 1; i >= 0; i--) {
const date = new Date(now.getTime() - i * 60 * 1000);
const variation = (Math.random() - 0.5) * 0.02;
const open = currentPrice;
const change = basePrice * variation;
const high = open + Math.abs(change) * Math.random();
const low = open - Math.abs(change) * Math.random();
const close = open + change;
candles.push({
target_dt: date.toISOString(),
open,
high: Math.max(open, high, close),
low: Math.min(open, low, close),
close,
volume: Math.random() * 1000
});
currentPrice = close;
}
return candles;
};
// 차트 컴포넌트
const CoinChart = ({ coinCode, coinName, currentPrice }) => {
const [chartData, setChartData] = useState([]);
const [selectedInterval, setSelectedInterval] = useState('1d');
useEffect(() => {
// 더미 캔들 데이터 생성
const basePrices = {
'KRW-BTC': 90000000,
'KRW-ETH': 4000000,
'KRW-SOL': 300000,
'KRW-XRP': 3000,
'KRW-ADA': 1200
};
const basePrice = basePrices[coinCode] || 100000;
const data = [
{
interval: '1d',
description: '일봉',
data: generateDummyCandles(30, basePrice)
},
{
interval: '1h',
description: '시간봉',
data: generateDummyCandles(24, basePrice)
},
{
interval: '1m',
description: '분봉',
data: generateDummyCandles(60, basePrice)
}
];
setChartData(data);
}, [coinCode]);
const selectedData = chartData.find(dataset => dataset.interval === selectedInterval);
const formatPrice = (price) => new Intl.NumberFormat('ko-KR').format(price);
return (
<div className="bg-white rounded-lg shadow p-6">
<div className="flex justify-between items-center mb-4">
<div>
<h3 className="text-lg font-semibold text-gray-900">{coinName}</h3>
{currentPrice && (
<p className="text-sm text-gray-600">
현재가: <span className="font-medium text-blue-600">{formatPrice(currentPrice)}원</span>
</p>
)}
</div>
<div className="flex space-x-2">
{chartData.map((dataset) => (
<button
key={dataset.interval}
onClick={() => setSelectedInterval(dataset.interval)}
className={`px-3 py-1 text-xs rounded ${
selectedInterval === dataset.interval
? 'bg-blue-500 text-white'
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
}`}
>
{dataset.description}
</button>
))}
</div>
</div>
{selectedData && (
<div className="h-64 relative">
<div className="flex items-end justify-between h-full border-b border-gray-200 px-2">
{selectedData.data.slice(-20).map((candle, index) => {
const maxPrice = Math.max(...selectedData.data.map(c => c.high));
const minPrice = Math.min(...selectedData.data.map(c => c.low));
const priceRange = maxPrice - minPrice;
const height = ((candle.high - candle.low) / priceRange) * 200;
const bottomOffset = ((candle.low - minPrice) / priceRange) * 200;
const isGreen = candle.close >= candle.open;
return (
<div key={index} className="flex flex-col items-center group relative" style={{ width: '4%' }}>
<div
className={`w-1 ${isGreen ? 'bg-red-500' : 'bg-blue-500'}`}
style={{
height: `${height}px`,
marginBottom: `${bottomOffset}px`
}}
/>
<div className="absolute bottom-full mb-2 hidden group-hover:block bg-gray-800 text-white text-xs rounded px-2 py-1 whitespace-nowrap z-10">
<div>시가: {formatPrice(candle.open)}</div>
<div>고가: {formatPrice(candle.high)}</div>
<div>저가: {formatPrice(candle.low)}</div>
<div>종가: {formatPrice(candle.close)}</div>
</div>
</div>
);
})}
</div>
</div>
)}
</div>
);
};
// 인증 모달 컴포넌트
const AuthModal = ({ isOpen, onClose, onLogin }) => {
const [isLoginMode, setIsLoginMode] = useState(true);
const [email, setEmail] = useState('');
const [nickname, setNickname] = useState('');
if (!isOpen) return null;
const handleSubmit = (e) => {
e.preventDefault();
// 간단한 로컬스토리지 기반 인증
const users = JSON.parse(localStorage.getItem('users') || '[]');
if (isLoginMode) {
const user = users.find(u => u.email === email);
if (user) {
onLogin(user);
onClose();
} else {
alert('등록되지 않은 이메일입니다.');
}
} else {
if (users.find(u => u.email === email)) {
alert('이미 등록된 이메일입니다.');
return;
}
const newUser = {
user_seq: Date.now(),
email,
nickname: nickname || '사용자',
cash_balance: 10000000,
invested_amount: 0,
selected_invest_code: 'KRW-BTC',
invest_run_flag: false
};
users.push(newUser);
localStorage.setItem('users', JSON.stringify(users));
onLogin(newUser);
onClose();
}
};
return (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-6 w-full max-w-md">
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-semibold">
{isLoginMode ? '로그인' : '회원가입'}
</h2>
<button onClick={onClose} className="text-gray-400 hover:text-gray-600"></button>
</div>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">이메일</label>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="이메일을 입력하세요"
required
/>
</div>
{!isLoginMode && (
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">닉네임</label>
<input
type="text"
value={nickname}
onChange={(e) => setNickname(e.target.value)}
className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
placeholder="닉네임을 입력하세요"
/>
</div>
)}
<button
type="submit"
className="w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700"
>
{isLoginMode ? '로그인' : '회원가입'}
</button>
</form>
<div className="mt-4 text-center">
<button
onClick={() => setIsLoginMode(!isLoginMode)}
className="text-blue-600 hover:text-blue-800 text-sm"
>
{isLoginMode ? '계정이 없으신가요? 회원가입' : '이미 계정이 있으신가요? 로그인'}
</button>
</div>
</div>
</div>
);
};
// 사용자 패널 컴포넌트
const UserPanel = ({ user, onUserUpdate, onLogout }) => {
const [isEditing, setIsEditing] = useState(false);
const [editData, setEditData] = useState({
cash_balance: user.cash_balance,
selected_invest_code: user.selected_invest_code,
invest_run_flag: user.invest_run_flag
});
const formatPrice = (price) => new Intl.NumberFormat('ko-KR').format(price);
const selectedCoin = COIN_LIST.find(coin => coin.code === user.selected_invest_code);
const handleSave = () => {
// 투자중일 때 현금 변경 방지
if (user.invest_run_flag && editData.cash_balance !== user.cash_balance) {
alert('투자 진행 중에는 현금을 변경할 수 없습니다.');
return;
}
// 투자상품 변경 시 확인
if (editData.selected_invest_code !== user.selected_invest_code && user.invested_amount > 0) {
if (!confirm('투자상품을 변경하면 현재 보유중인 모든 투자상품이 자동으로 매도됩니다. 계속하시겠습니까?')) {
return;
}
}
// 투자 진행 플래그를 false로 변경 시 확인
if (user.invest_run_flag && !editData.invest_run_flag && user.invested_amount > 0) {
if (!confirm('투자를 중지하면 현재 보유중인 모든 투자상품이 자동으로 매도됩니다. 계속하시겠습니까?')) {
return;
}
}
const updatedUser = { ...user, ...editData };
// 로컬스토리지 업데이트
const users = JSON.parse(localStorage.getItem('users') || '[]');
const userIndex = users.findIndex(u => u.user_seq === user.user_seq);
if (userIndex !== -1) {
users[userIndex] = updatedUser;
localStorage.setItem('users', JSON.stringify(users));
}
onUserUpdate(updatedUser);
setIsEditing(false);
};
return (
<div className="bg-white rounded-lg shadow p-6">
<div className="flex justify-between items-center mb-4">
<h3 className="text-lg font-semibold text-gray-900">내 투자 정보</h3>
<button onClick={onLogout} className="text-sm text-gray-600 hover:text-gray-800">
로그아웃
</button>
</div>
<div className="space-y-4">
<div>
<p className="text-sm text-gray-600">사용자</p>
<p className="font-medium">{user.nickname} ({user.email})</p>
</div>
<div>
<p className="text-sm text-gray-600">보유 현금</p>
{isEditing ? (
<input
type="number"
value={editData.cash_balance}
onChange={(e) => setEditData({...editData, cash_balance: parseFloat(e.target.value) || 0})}
disabled={user.invest_run_flag}
className="w-full px-3 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500 disabled:bg-gray-100"
/>
) : (
<p className="font-medium text-blue-600">{formatPrice(user.cash_balance)}원</p>
)}
</div>
<div>
<p className="text-sm text-gray-600">투자 금액</p>
<p className="font-medium text-green-600">{formatPrice(user.invested_amount)}원</p>
</div>
<div>
<p className="text-sm text-gray-600">선택 투자상품</p>
{isEditing ? (
<select
value={editData.selected_invest_code}
onChange={(e) => setEditData({...editData, selected_invest_code: e.target.value})}
className="w-full px-3 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
>
{COIN_LIST.map((coin) => (
<option key={coin.code} value={coin.code}>
{coin.name} ({coin.symbol})
</option>
))}
</select>
) : (
<p className="font-medium">{selectedCoin?.name} ({selectedCoin?.symbol})</p>
)}
</div>
<div>
<p className="text-sm text-gray-600">투자 진행 상태</p>
{isEditing ? (
<label className="flex items-center space-x-2">
<input
type="checkbox"
checked={editData.invest_run_flag}
onChange={(e) => setEditData({...editData, invest_run_flag: e.target.checked})}
className="rounded"
/>
<span className="text-sm">투자 진행</span>
</label>
) : (
<p className={`font-medium ${user.invest_run_flag ? 'text-green-600' : 'text-red-600'}`}>
{user.invest_run_flag ? '투자 진행 중' : '투자 중지'}
</p>
)}
</div>
<div className="flex space-x-2">
{isEditing ? (
<>
<button
onClick={handleSave}
className="flex-1 bg-blue-600 text-white py-2 px-4 rounded hover:bg-blue-700"
>
저장
</button>
<button
onClick={() => {
setEditData({
cash_balance: user.cash_balance,
selected_invest_code: user.selected_invest_code,
invest_run_flag: user.invest_run_flag
});
setIsEditing(false);
}}
className="flex-1 bg-gray-300 text-gray-700 py-2 px-4 rounded hover:bg-gray-400"
>
취소
</button>
</>
) : (
<button
onClick={() => setIsEditing(true)}
className="w-full bg-gray-600 text-white py-2 px-4 rounded hover:bg-gray-700"
>
정보 수정
</button>
)}
</div>
</div>
</div>
);
};
// 메인 앱 컴포넌트
const App = () => {
const [user, setUser] = useState(null);
const [showAuthModal, setShowAuthModal] = useState(false);
const [coinPrices, setCoinPrices] = useState({});
const [selectedCoins, setSelectedCoins] = useState(['KRW-BTC', 'KRW-ETH', 'KRW-SOL', 'KRW-XRP', 'KRW-ADA']);
// 로그인 상태 복원
useEffect(() => {
const savedUser = localStorage.getItem('currentUser');
if (savedUser) {
setUser(JSON.parse(savedUser));
}
}, []);
// 현재가 업데이트
useEffect(() => {
const updatePrices = async () => {
try {
const prices = await getUpbitCurrentPrice(selectedCoins);
const priceMap = {};
prices.forEach(price => {
priceMap[price.market] = price.trade_price;
});
setCoinPrices(priceMap);
} catch (error) {
console.error('가격 업데이트 실패:', error);
}
};
updatePrices();
const interval = setInterval(updatePrices, 5000);
return () => clearInterval(interval);
}, [selectedCoins]);
const handleLogin = (loggedInUser) => {
setUser(loggedInUser);
localStorage.setItem('currentUser', JSON.stringify(loggedInUser));
setShowAuthModal(false);
};
const handleLogout = () => {
setUser(null);
localStorage.removeItem('currentUser');
};
const handleUserUpdate = (updatedUser) => {
setUser(updatedUser);
localStorage.setItem('currentUser', JSON.stringify(updatedUser));
};
const formatPrice = (price) => new Intl.NumberFormat('ko-KR').format(price);
const getCoinName = (code) => COIN_LIST.find(coin => coin.code === code)?.name || code;
return (
<div className="min-h-screen bg-gray-100">
<header className="bg-white shadow-sm border-b">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
<div className="flex items-center">
<h1 className="text-xl font-bold text-gray-900">AI 투자 시스템</h1>
</div>
<div className="flex items-center space-x-4">
<div className="hidden md:flex items-center space-x-4 text-sm">
{selectedCoins.slice(0, 3).map(coinCode => (
<div key={coinCode} className="text-center">
<div className="text-gray-600">{getCoinName(coinCode)}</div>
<div className="font-medium text-blue-600">
{coinPrices[coinCode] ? formatPrice(coinPrices[coinCode]) : '로딩중...'}
</div>
</div>
))}
</div>
{user ? (
<div className="text-sm text-gray-700">
안녕하세요, <span className="font-medium">{user.nickname}</span>
</div>
) : (
<div className="flex space-x-2">
<button
onClick={() => setShowAuthModal(true)}
className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700"
>
로그인
</button>
<button
onClick={() => setShowAuthModal(true)}
className="bg-gray-600 text-white px-4 py-2 rounded hover:bg-gray-700"
>
회원가입
</button>
</div>
)}
</div>
</div>
</div>
</header>
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div className="flex flex-col lg:flex-row gap-8">
<div className="flex-1">
<h2 className="text-2xl font-bold text-gray-900 mb-6">코인 차트</h2>
<div className="mb-6">
<div className="flex flex-wrap gap-2">
{COIN_LIST.map((coin) => (
<button
key={coin.code}
onClick={() => {
if (selectedCoins.includes(coin.code)) {
setSelectedCoins(selectedCoins.filter(c => c !== coin.code));
} else if (selectedCoins.length < 5) {
setSelectedCoins([...selectedCoins, coin.code]);
}
}}
className={`px-3 py-2 rounded text-sm ${
selectedCoins.includes(coin.code)
? 'bg-blue-500 text-white'
: 'bg-gray-200 text-gray-700 hover:bg-gray-300'
}`}
disabled={!selectedCoins.includes(coin.code) && selectedCoins.length >= 5}
>
{coin.name} ({coin.symbol})
{coinPrices[coin.code] && (
<div className="text-xs mt-1">
{formatPrice(coinPrices[coin.code])}원
</div>
)}
</button>
))}
</div>
<p className="text-sm text-gray-600 mt-2">
최대 5개의 코인을 선택할 수 있습니다. (현재 {selectedCoins.length}/5)
</p>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
{selectedCoins.map((coinCode) => (
<CoinChart
key={coinCode}
coinCode={coinCode}
coinName={getCoinName(coinCode)}
currentPrice={coinPrices[coinCode]}
/>
))}
</div>
</div>
{user && (
<div className="lg:w-80">
<UserPanel
user={user}
onUserUpdate={handleUserUpdate}
onLogout={handleLogout}
/>
</div>
)}
</div>
</main>
<AuthModal
isOpen={showAuthModal}
onClose={() => setShowAuthModal(false)}
onLogin={handleLogin}
/>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
</script>
</body>
</html>

22
설계/앱아이디어.md Normal file
View File

@ -0,0 +1,22 @@
# 앱 제목: Invest Manager AI(I'm AI)
## 앱 아이디어
1. AI를 활용한 투자(주식, 코인 등) 가이드라인 제공
2. 모든 서비스는 무료로 제공하되, 노출 광고 수익으로 AI API요금 충당
3. 부가 수입은 후원으로 충당
## I'm AI 가 제공하는 서비스
- MVP단계에서는 코인 5종류로 서비스 시작
1. 웹 서비스 : 코인 5종류에 대한 현재가, 목표가, 손절가, 진입가 -> 해당 값들을 산출하게 된 근거(뉴스, 캔들데이터 등)
2. 앱 서비스 : 안드로이드/IOS 앱으로 웹서비스와 같은 기능 제공
3. 목표가, 손절가, 진입가 진입시 알람 제공
4. I'm AI가 서비스중인 투자상품중 매수 점수를 AI를 통해 부여하고 매우 높은 점수를 받았을 경우 추천 알람 제공
5. 투자 상품별 사용자의 투자 성향에 맞는 맞춤식 투자 선택지 제공.
## 서비스는 단순하고 쉽게
1. 웹은 딱 1개의 페이지만 제공 - 투자상품 현재가, AI분석을 통한 정보 제공, 개인 맞춤식 설정, 광고 영역
2. 앱은 3개 페이지로 제공 - 투자상품 현재가, AI분석을 통한 젱보 페이지, 개인 맞춤식 설정 페이지 (각 페이지에 광고영역을 두던, 페이지 전환시 동영상광고를 진행하던 해서 수익을 얻기)
## 서버 설계
1. 로컬서버 - AIRFLOW : 투자 상품에 대한 상품별 AI를 통한 분석 수행, 분석 결과를 AWS-S3에 저장 - json 타입으로 모든 사용자가 동일한 데이터를 받아 모든 투자상품 서비스에 적절히 활용 가능하게 정제
2. AWS - Lambda : API Gateway, cloudfront를 통해 단순히 잘 정리된 데이터를 제공

View File

@ -0,0 +1,906 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>I'm AI App Design - Mobile Investment Guide Service</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background-color: #f5f5f5;
padding: 20px;
}
/* 디바이스 컨테이너 - 3개 앱 화면을 나란히 배치 */
.device-container {
display: flex;
justify-content: center;
gap: 30px;
flex-wrap: wrap;
}
/* 모바일 디바이스 프레임 */
.phone {
width: 375px; /* iPhone 기준 너비 */
height: 812px; /* iPhone 기준 높이 */
background: #000;
border-radius: 40px;
padding: 10px;
box-shadow: 0 0 30px rgba(0,0,0,0.3);
position: relative;
}
/* 디바이스 스크린 영역 */
.screen {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #0f0f0f 0%, #1a1a1a 100%);
border-radius: 30px;
overflow: hidden;
position: relative;
}
/* 상태바 영역 (시간, 배터리 등) */
.status-bar {
height: 44px;
background: transparent;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
color: #fff;
font-size: 14px;
font-weight: 600;
}
/* 상단 네비게이션 바 */
.nav-bar {
height: 60px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 18px;
font-weight: bold;
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
}
/* 메인 콘텐츠 영역 */
.content {
height: calc(100% - 104px - 80px); /* 전체 높이에서 상단바와 하단바 제외 */
padding: 15px;
overflow-y: auto;
}
/* 하단 탭 네비게이션 */
.bottom-nav {
height: 80px;
background: #1a1a1a;
display: flex;
justify-content: space-around;
align-items: center;
border-top: 1px solid #333;
}
/* 하단 네비게이션 아이템 */
.nav-item {
display: flex;
flex-direction: column;
align-items: center;
color: #999;
font-size: 12px;
cursor: pointer;
transition: color 0.3s;
}
.nav-item.active {
color: #667eea;
}
/* 네비게이션 아이콘 */
.nav-icon {
width: 24px;
height: 24px;
margin-bottom: 4px;
background: currentColor;
border-radius: 4px;
}
/* 투자상품 리스트 */
.coin-list {
display: flex;
flex-direction: column;
gap: 15px;
}
/* 개별 투자상품 카드 */
.coin-item {
background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
border-radius: 15px;
padding: 20px;
border: 1px solid #333;
}
/* 투자상품 헤더 (이름, 심볼, 가격) */
.coin-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
/* 투자상품 정보 (아이콘, 이름) */
.coin-info {
display: flex;
align-items: center;
gap: 12px;
}
/* 투자상품 아이콘 */
.coin-icon {
width: 40px;
height: 40px;
background: #667eea;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 14px;
}
.coin-details h3 {
color: #fff;
font-size: 16px;
margin-bottom: 4px;
}
.coin-symbol {
color: #999;
font-size: 12px;
}
/* 가격 정보 영역 */
.coin-price {
text-align: right;
}
.current-price {
color: #4ade80;
font-size: 18px;
font-weight: bold;
margin-bottom: 4px;
}
.price-change {
font-size: 12px;
padding: 4px 8px;
border-radius: 8px;
}
/* 가격 상승/하락 색상 구분 */
.price-up {
background: #22c55e;
color: white;
}
.price-down {
background: #ef4444;
color: white;
}
/* AI 분석 결과 표시 */
.ai-analysis {
background: rgba(102, 126, 234, 0.1);
border: 1px solid #667eea;
border-radius: 10px;
padding: 12px;
margin: 15px 0;
}
.analysis-title {
color: #667eea;
font-size: 12px;
font-weight: bold;
margin-bottom: 6px;
}
.analysis-text {
color: #ccc;
font-size: 12px;
line-height: 1.4;
}
/* 투자 목표가 표시 영역 */
.price-targets {
display: flex;
justify-content: space-between;
gap: 10px;
margin-top: 15px;
}
.target-item {
flex: 1;
text-align: center;
padding: 8px;
background: rgba(255,255,255,0.05);
border-radius: 8px;
}
.target-label {
color: #999;
font-size: 10px;
margin-bottom: 4px;
}
.target-value {
font-weight: bold;
font-size: 12px;
}
/* 목표가별 색상 구분 */
.entry-price { color: #4ade80; }
.target-price { color: #fbbf24; }
.stop-loss { color: #ef4444; }
/* AI 투자 점수 표시 */
.ai-score {
display: flex;
align-items: center;
justify-content: space-between;
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 10px;
padding: 12px;
margin-top: 15px;
}
.score-label {
color: white;
font-size: 12px;
}
.score-value {
color: white;
font-size: 16px;
font-weight: bold;
}
/* 페이지별 스타일 */
.page-2 .content {
padding: 20px;
}
/* 상세 분석 카드 */
.detail-card {
background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
border-radius: 15px;
padding: 25px;
border: 1px solid #333;
margin-bottom: 20px;
}
/* 상세 분석 헤더 */
.detail-header {
display: flex;
align-items: center;
gap: 15px;
margin-bottom: 20px;
}
/* 큰 투자상품 아이콘 */
.large-coin-icon {
width: 60px;
height: 60px;
background: #667eea;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
font-size: 20px;
}
/* 큰 가격 표시 */
.large-price {
font-size: 28px;
color: #4ade80;
font-weight: bold;
margin-bottom: 10px;
}
/* 상세 AI 분석 영역 */
.detail-analysis {
background: rgba(102, 126, 234, 0.1);
border: 1px solid #667eea;
border-radius: 12px;
padding: 20px;
margin: 20px 0;
}
/* 분석 섹션 */
.analysis-section {
margin-bottom: 15px;
}
.analysis-section h4 {
color: #667eea;
font-size: 14px;
margin-bottom: 8px;
}
.analysis-section p {
color: #ccc;
font-size: 13px;
line-height: 1.5;
}
/* 페이지 3 설정 리스트 */
.page-3 .settings-list {
display: flex;
flex-direction: column;
gap: 15px;
}
/* 설정 카드 */
.setting-card {
background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
border-radius: 12px;
padding: 20px;
border: 1px solid #333;
}
/* 설정 제목 */
.setting-title {
color: #667eea;
font-size: 16px;
font-weight: bold;
margin-bottom: 15px;
}
/* 설정 아이템 */
.setting-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
padding-bottom: 12px;
border-bottom: 1px solid #333;
}
.setting-item:last-child {
border-bottom: none;
margin-bottom: 0;
padding-bottom: 0;
}
/* 설정 라벨 */
.setting-label {
color: #ccc;
font-size: 14px;
}
/* 설정 값 */
.setting-value {
color: #fff;
font-size: 14px;
padding: 6px 12px;
background: #333;
border-radius: 6px;
border: none;
}
/* 토글 스위치 */
.switch {
width: 50px;
height: 24px;
background: #333;
border-radius: 12px;
position: relative;
cursor: pointer;
}
.switch.active {
background: #667eea;
}
.switch::after {
content: '';
width: 20px;
height: 20px;
background: white;
border-radius: 50%;
position: absolute;
top: 2px;
left: 2px;
transition: transform 0.3s;
}
.switch.active::after {
transform: translateX(26px);
}
/* 모바일 광고 배너 */
.ad-banner-mobile {
background: linear-gradient(45deg, #333, #555);
border-radius: 10px;
padding: 15px;
text-align: center;
margin: 15px 0;
border: 1px dashed #666;
}
.ad-banner-mobile h4 {
color: #999;
font-size: 12px;
margin-bottom: 5px;
}
.ad-banner-mobile p {
color: #777;
font-size: 10px;
}
/* 설명 텍스트 스타일 */
.description-text {
background: #333;
color: #ccc;
padding: 6px 10px;
border-radius: 6px;
font-size: 11px;
border: 1px solid #555;
margin: 5px 0;
}
</style>
</head>
<body>
<div class="device-container">
<!--
페이지 1: 메인 투자 현황 화면
- 하단 탭 네비게이션의 "홈" 탭
- 5개 투자상품의 실시간 정보 표시
- 각 카드에 AI 분석 결과와 투자 점수 포함
-->
<div class="phone">
<div class="screen">
<!-- iOS 스타일 상태바 -->
<div class="status-bar">
<span>[STATUS] 9:41</span>
<span>[BATTERY] 100%</span>
</div>
<!-- 상단 네비게이션 바 -->
<div class="nav-bar">
[NAV TITLE] I'm AI - Investment Status
</div>
<!-- 메인 콘텐츠 영역 -->
<div class="content">
<div class="coin-list">
<!--
투자상품 #1: Bitcoin
- 현재가, 변동률 표시
- AI 분석 요약
- 목표가 정보 (진입/목표/손절)
- AI 투자 점수
-->
<div class="coin-item">
<div class="coin-header">
<div class="coin-info">
<div class="coin-icon">[ICON] BTC</div>
<div class="coin-details">
<h3>[COIN NAME] Bitcoin</h3>
<div class="coin-symbol">[SYMBOL] BTC</div>
</div>
</div>
<div class="coin-price">
<div class="current-price">[PRICE] $43,250</div>
<div class="price-change price-up">[CHANGE] +2.35%</div>
</div>
</div>
<!-- AI 분석 요약 -->
<div class="ai-analysis">
<div class="analysis-title">[AI TITLE] AI Market Analysis</div>
<div class="analysis-text description-text">[AI SUMMARY] Institutional investment inflow sustains upward momentum. Technical bullish signals detected.</div>
</div>
<!-- 투자 목표가 표시 -->
<div class="price-targets">
<div class="target-item">
<div class="target-label">[LABEL] Entry</div>
<div class="target-value entry-price">[ENTRY] $42,800</div>
</div>
<div class="target-item">
<div class="target-label">[LABEL] Target</div>
<div class="target-value target-price">[TARGET] $46,500</div>
</div>
<div class="target-item">
<div class="target-label">[LABEL] Stop</div>
<div class="target-value stop-loss">[STOP] $40,200</div>
</div>
</div>
<!-- AI 투자 점수 -->
<div class="ai-score">
<span class="score-label">[SCORE LABEL] AI Investment Score</span>
<span class="score-value">[SCORE] 8.5/10</span>
</div>
</div>
<!--
투자상품 #2: Ethereum
동일한 구조로 이더리움 정보 표시
-->
<div class="coin-item">
<div class="coin-header">
<div class="coin-info">
<div class="coin-icon">[ICON] ETH</div>
<div class="coin-details">
<h3>[COIN NAME] Ethereum</h3>
<div class="coin-symbol">[SYMBOL] ETH</div>
</div>
</div>
<div class="coin-price">
<div class="current-price">[PRICE] $2,580</div>
<div class="price-change price-down">[CHANGE] -1.20%</div>
</div>
</div>
<div class="ai-analysis">
<div class="analysis-title">[AI TITLE] AI Market Analysis</div>
<div class="analysis-text description-text">[AI SUMMARY] Short-term correction phase but long-term upward outlook. Positive DeFi growth.</div>
</div>
<div class="price-targets">
<div class="target-item">
<div class="target-label">[LABEL] Entry</div>
<div class="target-value entry-price">[ENTRY] $2,520</div>
</div>
<div class="target-item">
<div class="target-label">[LABEL] Target</div>
<div class="target-value target-price">[TARGET] $2,850</div>
</div>
<div class="target-item">
<div class="target-label">[LABEL] Stop</div>
<div class="target-value stop-loss">[STOP] $2,350</div>
</div>
</div>
<div class="ai-score">
<span class="score-label">[SCORE LABEL] AI Investment Score</span>
<span class="score-value">[SCORE] 7.2/10</span>
</div>
</div>
<!--
광고 영역: 모바일 배너
- 투자상품 목록 중간에 삽입
- 사용자 경험을 해치지 않는 선에서 배치
-->
<div class="ad-banner-mobile">
<h4>[AD TITLE] Advertisement</h4>
<p class="description-text">[AD DESCRIPTION] Mobile Banner Advertisement Area<br>Revenue Generation Through Ad Display</p>
</div>
<!--
투자상품 #3: Ripple
높은 AI 점수를 받은 추천 종목
-->
<div class="coin-item">
<div class="coin-header">
<div class="coin-info">
<div class="coin-icon">[ICON] XRP</div>
<div class="coin-details">
<h3>[COIN NAME] Ripple</h3>
<div class="coin-symbol">[SYMBOL] XRP</div>
</div>
</div>
<div class="coin-price">
<div class="current-price">[PRICE] $0.625</div>
<div class="price-change price-up">[CHANGE] +5.80%</div>
</div>
</div>
<div class="ai-score">
<span class="score-label">[SCORE LABEL] AI Investment Score</span>
<span class="score-value">[SCORE] 9.1/10</span>
</div>
</div>
</div>
</div>
<!-- 하단 탭 네비게이션 -->
<div class="bottom-nav">
<div class="nav-item active">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Home</span>
</div>
<div class="nav-item">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Analysis</span>
</div>
<div class="nav-item">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Settings</span>
</div>
</div>
</div>
</div>
<!--
페이지 2: AI 분석 상세 화면
- 하단 탭 네비게이션의 "분석" 탭
- 선택한 투자상품의 상세 AI 분석 결과
- 기술적 분석, 뉴스 분석, 투자 전략 제공
-->
<div class="phone page-2">
<div class="screen">
<div class="status-bar">
<span>[STATUS] 9:41</span>
<span>[BATTERY] 100%</span>
</div>
<div class="nav-bar">
[NAV TITLE] AI Analysis Detail
</div>
<div class="content">
<!--
상세 분석 카드
- 투자상품 기본 정보 (큰 아이콘, 이름, 가격)
- 상세 AI 분석 (기술적/뉴스/전략 분석)
- 종합 AI 투자 점수
-->
<div class="detail-card">
<div class="detail-header">
<div class="large-coin-icon">[BIG ICON] BTC</div>
<div>
<h2 style="color: white; margin-bottom: 5px;">[COIN NAME] Bitcoin</h2>
<div class="large-price">[LARGE PRICE] $43,250.00</div>
<div class="price-change price-up">[PRICE CHANGE] +2.35% (+$992.50)</div>
</div>
</div>
<!-- 상세 AI 분석 영역 -->
<div class="detail-analysis">
<!-- 기술적 분석 섹션 -->
<div class="analysis-section">
<h4>[SECTION TITLE] Technical Analysis</h4>
<p class="description-text">[TECHNICAL ANALYSIS] RSI indicator at 65 level shows bullish signals. Moving average breakout strengthens upward momentum.</p>
</div>
<!-- 뉴스 분석 섹션 -->
<div class="analysis-section">
<h4>[SECTION TITLE] News Analysis</h4>
<p class="description-text">[NEWS ANALYSIS] Major institutional Bitcoin ETF approvals by BlackRock and others drive significant capital inflow.</p>
</div>
<!-- 투자 전략 섹션 -->
<div class="analysis-section">
<h4>[SECTION TITLE] Investment Strategy</h4>
<p class="description-text">[STRATEGY] Recommend entry at $42,800, hold until target $46,500. Strict adherence to stop-loss at $40,200 required.</p>
</div>
</div>
<!-- 종합 AI 점수 -->
<div class="ai-score">
<span class="score-label">[TOTAL SCORE LABEL] Comprehensive AI Investment Score</span>
<span class="score-value">[TOTAL SCORE] 8.5/10</span>
</div>
</div>
<!--
광고 영역: 전면 또는 동영상 광고
- 상세 분석 하단에 배치
- 더 높은 광고 단가 기대
-->
<div class="ad-banner-mobile">
<h4>[PREMIUM AD] Premium Advertisement</h4>
<p class="description-text">[AD DESCRIPTION] Full-screen or Video Advertisement Area<br>Higher Revenue Premium Ad Space</p>
</div>
</div>
<div class="bottom-nav">
<div class="nav-item">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Home</span>
</div>
<div class="nav-item active">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Analysis</span>
</div>
<div class="nav-item">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Settings</span>
</div>
</div>
</div>
</div>
<!--
페이지 3: 개인 맞춤 설정 화면
- 하단 탭 네비게이션의 "설정" 탭
- 투자 성향 설정
- 알림 설정
- 앱 설정
-->
<div class="phone page-3">
<div class="screen">
<div class="status-bar">
<span>[STATUS] 9:41</span>
<span>[BATTERY] 100%</span>
</div>
<div class="nav-bar">
[NAV TITLE] Personal Settings
</div>
<div class="content">
<div class="settings-list">
<!--
투자 성향 설정 카드
- 투자 유형 선택 (보수적/균형/적극적/공격적)
- 투자 기간 설정
- 위험 허용도 조절
-->
<div class="setting-card">
<div class="setting-title">[CARD TITLE] Investment Preferences</div>
<div class="setting-item">
<span class="setting-label">[LABEL] Investment Type</span>
<select class="setting-value">
<option>[OPTION] Conservative</option>
<option>[OPTION] Balanced</option>
<option>[OPTION] Aggressive</option>
<option>[OPTION] High Risk</option>
</select>
</div>
<div class="setting-item">
<span class="setting-label">[LABEL] Investment Period</span>
<select class="setting-value">
<option>[OPTION] Short Term (1-3 months)</option>
<option>[OPTION] Medium Term (3-12 months)</option>
<option>[OPTION] Long Term (1+ years)</option>
</select>
</div>
<div class="setting-item">
<span class="setting-label">[LABEL] Risk Tolerance</span>
<span class="setting-value">[VALUE] Medium (5/10)</span>
</div>
</div>
<!--
알림 설정 카드
- 목표가 도달 알림 on/off
- 손절가 도달 알림 on/off
- 진입가 도달 알림 on/off
- AI 추천 알림 on/off
-->
<div class="setting-card">
<div class="setting-title">[CARD TITLE] Notification Settings</div>
<div class="setting-item">
<span class="setting-label">[ALERT LABEL] Target Price Alert</span>
<div class="switch active">[SWITCH] ON</div>
</div>
<div class="setting-item">
<span class="setting-label">[ALERT LABEL] Stop Loss Alert</span>
<div class="switch active">[SWITCH] ON</div>
</div>
<div class="setting-item">
<span class="setting-label">[ALERT LABEL] Entry Price Alert</span>
<div class="switch active">[SWITCH] ON</div>
</div>
<div class="setting-item">
<span class="setting-label">[ALERT LABEL] AI Recommendation Alert</span>
<div class="switch active">[SWITCH] ON</div>
</div>
</div>
<!--
광고 영역: 설정 페이지 광고
- 설정 카드들 사이에 자연스럽게 삽입
- 사용자가 설정을 변경하는 동안 노출
-->
<div class="ad-banner-mobile">
<h4>[SETTINGS AD] Settings Page Ad</h4>
<p class="description-text">[AD DESCRIPTION] Advertisement in Settings Area<br>Targeted Ad Based on User Preferences</p>
</div>
<!--
앱 설정 카드
- 다크 모드 on/off
- 자동 업데이트 on/off
- 데이터 절약 모드 on/off
-->
<div class="setting-card">
<div class="setting-title">[CARD TITLE] App Settings</div>
<div class="setting-item">
<span class="setting-label">[SETTING LABEL] Dark Mode</span>
<div class="switch active">[SWITCH] ON</div>
</div>
<div class="setting-item">
<span class="setting-label">[SETTING LABEL] Auto Update</span>
<div class="switch active">[SWITCH] ON</div>
</div>
<div class="setting-item">
<span class="setting-label">[SETTING LABEL] Data Saving Mode</span>
<div class="switch">[SWITCH] OFF</div>
</div>
</div>
</div>
</div>
<div class="bottom-nav">
<div class="nav-item">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Home</span>
</div>
<div class="nav-item">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Analysis</span>
</div>
<div class="nav-item active">
<div class="nav-icon">[ICON]</div>
<span>[TAB] Settings</span>
</div>
</div>
</div>
</div>
</div>
<script>
// 토글 스위치 기능
// 실제 구현시 사용자 설정을 서버에 저장하고 동기화
document.querySelectorAll('.switch').forEach(switchEl => {
switchEl.addEventListener('click', function() {
this.classList.toggle('active');
// 실제 구현시 여기서 서버로 설정값 전송
console.log('Setting changed:', this.previousElementSibling.textContent);
});
});
// 실시간 가격 업데이트 시뮬레이션 (모바일용)
// 실제로는 WebSocket 연결을 통해 실시간 데이터 수신
function updateMobilePrices() {
const priceElements = document.querySelectorAll('.current-price');
priceElements.forEach(element => {
// 실제로는 API에서 실시간 데이터를 받아와 업데이트
const currentText = element.textContent;
console.log('Mobile price update simulation for:', currentText);
// 푸시 알림 조건 확인
// 실제 구현시 목표가/손절가 도달시 알림 발송
});
}
// 30초마다 가격 업데이트 (데모용)
setInterval(updateMobilePrices, 30000);
// 페이지 전환 애니메이션
// 실제 앱에서는 React Native Navigation 또는 Flutter Navigator 사용
function navigateToPage(pageIndex) {
console.log('Navigate to page:', pageIndex);
}
</script>
</body>
</html>

View File

View File

View File

View File

@ -0,0 +1,637 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>I'm AI Web Design - Investment Guide Service</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background-color: #0f0f0f;
color: #ffffff;
}
/* 헤더 영역 스타일 */
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 20px;
text-align: center;
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
}
.logo {
font-size: 2.5rem;
font-weight: bold;
margin-bottom: 10px;
}
.subtitle {
font-size: 1.1rem;
opacity: 0.9;
}
/* 메인 컨테이너 - 2열 그리드 레이아웃 */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
display: grid;
grid-template-columns: 2fr 1fr; /* 좌측 콘텐츠 영역 : 우측 사이드바 = 2:1 */
gap: 20px;
}
/* 좌측 메인 콘텐츠 영역 */
.main-content {
display: flex;
flex-direction: column;
gap: 20px;
}
/* 투자상품 카드 그리드 */
.coin-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 20px;
}
/* 개별 투자상품 카드 */
.coin-card {
background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
border-radius: 15px;
padding: 25px;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
border: 1px solid #333;
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.coin-card:hover {
transform: translateY(-5px);
box-shadow: 0 15px 40px rgba(0,0,0,0.5);
}
/* 투자상품 헤더 (이름, 심볼) */
.coin-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.coin-name {
font-size: 1.3rem;
font-weight: bold;
color: #667eea;
}
.coin-symbol {
background: #667eea;
color: white;
padding: 5px 10px;
border-radius: 20px;
font-size: 0.9rem;
}
/* 가격 정보 영역 */
.price-info {
margin-bottom: 20px;
}
.current-price {
font-size: 2rem;
font-weight: bold;
color: #4ade80;
margin-bottom: 10px;
}
.price-change {
font-size: 1rem;
padding: 5px 10px;
border-radius: 10px;
}
.price-up {
background: #22c55e;
color: white;
}
.price-down {
background: #ef4444;
color: white;
}
/* AI 분석 결과 표시 영역 */
.ai-analysis {
background: rgba(102, 126, 234, 0.1);
border: 1px solid #667eea;
border-radius: 10px;
padding: 15px;
margin-bottom: 20px;
}
.analysis-title {
color: #667eea;
font-weight: bold;
margin-bottom: 10px;
}
/* 투자 가격 목표 표시 */
.price-targets {
display: flex;
justify-content: space-between;
gap: 10px;
}
.target-item {
text-align: center;
flex: 1;
}
.target-label {
font-size: 0.9rem;
color: #999;
margin-bottom: 5px;
}
.target-price {
font-weight: bold;
font-size: 1.1rem;
}
/* 목표가별 색상 구분 */
.entry-price { color: #4ade80; }
.target-price-val { color: #fbbf24; }
.stop-loss { color: #ef4444; }
/* AI 투자 점수 표시 */
.ai-score {
background: linear-gradient(45deg, #667eea, #764ba2);
border-radius: 10px;
padding: 15px;
text-align: center;
margin-top: 15px;
}
.score-label {
font-size: 0.9rem;
margin-bottom: 5px;
}
.score-value {
font-size: 2rem;
font-weight: bold;
}
/* 우측 사이드바 */
.sidebar {
display: flex;
flex-direction: column;
gap: 20px;
}
/* 광고 배너 영역 */
.ad-banner {
background: linear-gradient(45deg, #333, #555);
border-radius: 10px;
padding: 20px;
text-align: center;
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
border: 2px dashed #666;
font-size: 14px;
color: #ccc;
}
/* 개인 설정 패널 */
.settings-panel {
background: linear-gradient(145deg, #1a1a1a, #2d2d2d);
border-radius: 15px;
padding: 25px;
border: 1px solid #333;
}
.panel-title {
font-size: 1.2rem;
font-weight: bold;
color: #667eea;
margin-bottom: 20px;
}
.setting-item {
margin-bottom: 15px;
}
.setting-label {
display: block;
margin-bottom: 5px;
color: #ccc;
}
select, input[type="range"] {
width: 100%;
padding: 8px;
background: #333;
border: 1px solid #555;
border-radius: 5px;
color: #fff;
}
/* 알림 설정 영역 */
.notification-settings {
background: rgba(102, 126, 234, 0.1);
border: 1px solid #667eea;
border-radius: 10px;
padding: 15px;
margin-top: 20px;
}
.notification-title {
color: #667eea;
font-weight: bold;
margin-bottom: 10px;
}
.checkbox-item {
display: flex;
align-items: center;
margin-bottom: 10px;
}
.checkbox-item input {
margin-right: 10px;
}
/* 설명 텍스트 스타일 */
.description-text {
background: #333;
color: #ccc;
padding: 8px 12px;
border-radius: 6px;
font-size: 12px;
border: 1px solid #555;
}
/* 모바일 반응형 */
@media (max-width: 768px) {
.container {
grid-template-columns: 1fr;
padding: 10px;
}
.coin-grid {
grid-template-columns: 1fr;
}
.price-targets {
flex-direction: column;
gap: 15px;
}
}
</style>
</head>
<body>
<!-- 웹사이트 헤더: 로고와 서비스 설명 -->
<header class="header">
<div class="logo">I'm AI</div>
<div class="subtitle">[HEADER] AI Investment Guide Service Logo & Title Area</div>
</header>
<div class="container">
<!-- 좌측 메인 콘텐츠 영역: 투자상품 정보 표시 -->
<main class="main-content">
<div class="coin-grid">
<!--
투자상품 카드 #1: Bitcoin
- 실시간 가격 정보
- AI 분석 결과
- 투자 목표가 (진입/목표/손절)
- AI 투자 점수
-->
<div class="coin-card">
<div class="coin-header">
<div class="coin-name">[COIN NAME] Bitcoin</div>
<div class="coin-symbol">[SYMBOL] BTC</div>
</div>
<div class="price-info">
<!-- 실시간 현재가 표시 -->
<div class="current-price">[CURRENT PRICE] $43,250.00</div>
<!-- 가격 변동률 및 변동액 표시 -->
<div class="price-change price-up">[PRICE CHANGE] +2.35% (+$992.50)</div>
</div>
<!-- AI 분석 결과 표시 영역 -->
<div class="ai-analysis">
<div class="analysis-title">[AI ANALYSIS TITLE] AI Market Analysis</div>
<div class="description-text">[AI ANALYSIS] Recent institutional investment inflow sustains upward momentum. Technical analysis shows bullish signals detected.</div>
</div>
<!-- 투자 목표가 설정 표시 -->
<div class="price-targets">
<div class="target-item">
<div class="target-label">[ENTRY PRICE LABEL] Entry</div>
<div class="target-price entry-price">[ENTRY PRICE] $42,800</div>
</div>
<div class="target-item">
<div class="target-label">[TARGET PRICE LABEL] Target</div>
<div class="target-price target-price-val">[TARGET PRICE] $46,500</div>
</div>
<div class="target-item">
<div class="target-label">[STOP LOSS LABEL] Stop Loss</div>
<div class="target-price stop-loss">[STOP LOSS] $40,200</div>
</div>
</div>
<!-- AI 투자 점수 표시 -->
<div class="ai-score">
<div class="score-label">[SCORE LABEL] AI Investment Score</div>
<div class="score-value">[AI SCORE] 8.5/10</div>
</div>
</div>
<!--
투자상품 카드 #2: Ethereum
동일한 구조로 이더리움 정보 표시
-->
<div class="coin-card">
<div class="coin-header">
<div class="coin-name">[COIN NAME] Ethereum</div>
<div class="coin-symbol">[SYMBOL] ETH</div>
</div>
<div class="price-info">
<div class="current-price">[CURRENT PRICE] $2,580.00</div>
<div class="price-change price-down">[PRICE CHANGE] -1.20% (-$31.20)</div>
</div>
<div class="ai-analysis">
<div class="analysis-title">[AI ANALYSIS TITLE] AI Market Analysis</div>
<div class="description-text">[AI ANALYSIS] Short-term correction phase but long-term upward outlook. Positive DeFi ecosystem growth.</div>
</div>
<div class="price-targets">
<div class="target-item">
<div class="target-label">[ENTRY PRICE LABEL] Entry</div>
<div class="target-price entry-price">[ENTRY PRICE] $2,520</div>
</div>
<div class="target-item">
<div class="target-label">[TARGET PRICE LABEL] Target</div>
<div class="target-price target-price-val">[TARGET PRICE] $2,850</div>
</div>
<div class="target-item">
<div class="target-label">[STOP LOSS LABEL] Stop Loss</div>
<div class="target-price stop-loss">[STOP LOSS] $2,350</div>
</div>
</div>
<div class="ai-score">
<div class="score-label">[SCORE LABEL] AI Investment Score</div>
<div class="score-value">[AI SCORE] 7.2/10</div>
</div>
</div>
<!--
투자상품 카드 #3: Ripple
높은 AI 점수를 받은 추천 종목 예시
-->
<div class="coin-card">
<div class="coin-header">
<div class="coin-name">[COIN NAME] Ripple</div>
<div class="coin-symbol">[SYMBOL] XRP</div>
</div>
<div class="price-info">
<div class="current-price">[CURRENT PRICE] $0.625</div>
<div class="price-change price-up">[PRICE CHANGE] +5.80% (+$0.034)</div>
</div>
<div class="ai-analysis">
<div class="analysis-title">[AI ANALYSIS TITLE] AI Market Analysis</div>
<div class="description-text">[AI ANALYSIS] Surge due to SEC lawsuit resolution expectations. Technical breakthrough pattern forming.</div>
</div>
<div class="price-targets">
<div class="target-item">
<div class="target-label">[ENTRY PRICE LABEL] Entry</div>
<div class="target-price entry-price">[ENTRY PRICE] $0.610</div>
</div>
<div class="target-item">
<div class="target-label">[TARGET PRICE LABEL] Target</div>
<div class="target-price target-price-val">[TARGET PRICE] $0.720</div>
</div>
<div class="target-item">
<div class="target-label">[STOP LOSS LABEL] Stop Loss</div>
<div class="target-price stop-loss">[STOP LOSS] $0.550</div>
</div>
</div>
<div class="ai-score">
<div class="score-label">[SCORE LABEL] AI Investment Score</div>
<div class="score-value">[AI SCORE] 9.1/10</div>
</div>
</div>
<!--
투자상품 카드 #4: Cardano
중간 점수 종목 예시
-->
<div class="coin-card">
<div class="coin-header">
<div class="coin-name">[COIN NAME] Cardano</div>
<div class="coin-symbol">[SYMBOL] ADA</div>
</div>
<div class="price-info">
<div class="current-price">[CURRENT PRICE] $0.485</div>
<div class="price-change price-up">[PRICE CHANGE] +3.20% (+$0.015)</div>
</div>
<div class="ai-analysis">
<div class="analysis-title">[AI ANALYSIS TITLE] AI Market Analysis</div>
<div class="description-text">[AI ANALYSIS] Increased developer activity after smart contract upgrade. Medium-term growth expected.</div>
</div>
<div class="price-targets">
<div class="target-item">
<div class="target-label">[ENTRY PRICE LABEL] Entry</div>
<div class="target-price entry-price">[ENTRY PRICE] $0.470</div>
</div>
<div class="target-item">
<div class="target-label">[TARGET PRICE LABEL] Target</div>
<div class="target-price target-price-val">[TARGET PRICE] $0.550</div>
</div>
<div class="target-item">
<div class="target-label">[STOP LOSS LABEL] Stop Loss</div>
<div class="target-price stop-loss">[STOP LOSS] $0.420</div>
</div>
</div>
<div class="ai-score">
<div class="score-label">[SCORE LABEL] AI Investment Score</div>
<div class="score-value">[AI SCORE] 6.8/10</div>
</div>
</div>
<!--
투자상품 카드 #5: Solana
고성장 가능성 종목 예시
-->
<div class="coin-card">
<div class="coin-header">
<div class="coin-name">[COIN NAME] Solana</div>
<div class="coin-symbol">[SYMBOL] SOL</div>
</div>
<div class="price-info">
<div class="current-price">[CURRENT PRICE] $102.30</div>
<div class="price-change price-up">[PRICE CHANGE] +4.75% (+$4.64)</div>
</div>
<div class="ai-analysis">
<div class="analysis-title">[AI ANALYSIS TITLE] AI Market Analysis</div>
<div class="description-text">[AI ANALYSIS] Network usage surge due to NFT and DeFi ecosystem activation. Technical strength continues.</div>
</div>
<div class="price-targets">
<div class="target-item">
<div class="target-label">[ENTRY PRICE LABEL] Entry</div>
<div class="target-price entry-price">[ENTRY PRICE] $98.50</div>
</div>
<div class="target-item">
<div class="target-label">[TARGET PRICE LABEL] Target</div>
<div class="target-price target-price-val">[TARGET PRICE] $115.00</div>
</div>
<div class="target-item">
<div class="target-label">[STOP LOSS LABEL] Stop Loss</div>
<div class="target-price stop-loss">[STOP LOSS] $88.00</div>
</div>
</div>
<div class="ai-score">
<div class="score-label">[SCORE LABEL] AI Investment Score</div>
<div class="score-value">[AI SCORE] 8.3/10</div>
</div>
</div>
</div>
</main>
<!-- 우측 사이드바: 광고 및 개인설정 -->
<aside class="sidebar">
<!--
광고 영역 #1: 주요 광고 배너
- 크기: 320x200px 권장
- 수익 모델의 핵심 영역
-->
<div class="ad-banner">
<div>
<div style="font-size: 16px; margin-bottom: 10px;">[AD BANNER #1]</div>
<div class="description-text">Advertisement Banner Area<br>320x200px Recommended<br>Primary Revenue Source</div>
</div>
</div>
<!--
개인 맞춤 설정 패널
- 사용자 투자 성향 설정
- 알림 설정
- 위험 허용도 조절
-->
<div class="settings-panel">
<div class="panel-title">[SETTINGS TITLE] Personal Investment Settings</div>
<!-- 투자 성향 선택 -->
<div class="setting-item">
<label class="setting-label">[INVESTMENT TYPE LABEL] Investment Style</label>
<select>
<option>[OPTION] Conservative</option>
<option>[OPTION] Balanced</option>
<option>[OPTION] Aggressive</option>
<option>[OPTION] High Risk</option>
</select>
</div>
<!-- 투자 기간 선택 -->
<div class="setting-item">
<label class="setting-label">[INVESTMENT PERIOD LABEL] Investment Period</label>
<select>
<option>[OPTION] Short Term (1-3 months)</option>
<option>[OPTION] Medium Term (3-12 months)</option>
<option>[OPTION] Long Term (1+ years)</option>
</select>
</div>
<!-- 위험 허용도 슬라이더 -->
<div class="setting-item">
<label class="setting-label">[RISK TOLERANCE LABEL] Risk Tolerance: <span id="riskValue">5</span></label>
<input type="range" min="1" max="10" value="5" id="riskSlider">
</div>
<!-- 알림 설정 영역 -->
<div class="notification-settings">
<div class="notification-title">[NOTIFICATION TITLE] Alert Settings</div>
<div class="checkbox-item">
<input type="checkbox" id="targetAlert" checked>
<label for="targetAlert">[ALERT OPTION] Target Price Alert</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="stopLossAlert" checked>
<label for="stopLossAlert">[ALERT OPTION] Stop Loss Alert</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="entryAlert" checked>
<label for="entryAlert">[ALERT OPTION] Entry Price Alert</label>
</div>
<div class="checkbox-item">
<input type="checkbox" id="recommendAlert" checked>
<label for="recommendAlert">[ALERT OPTION] AI Recommendation Alert</label>
</div>
</div>
</div>
<!--
광고 영역 #2: 보조 광고 배너
- 크기: 320x150px 권장
- 추가 수익원
-->
<div class="ad-banner">
<div>
<div style="font-size: 16px; margin-bottom: 10px;">[AD BANNER #2]</div>
<div class="description-text">Secondary Advertisement Area<br>320x150px Recommended<br>Additional Revenue Stream</div>
</div>
</div>
</aside>
</div>
<script>
// 위험 허용도 슬라이더 기능
const riskSlider = document.getElementById('riskSlider');
const riskValue = document.getElementById('riskValue');
riskSlider.addEventListener('input', function() {
riskValue.textContent = this.value;
});
// 실시간 가격 업데이트 시뮬레이션
// 실제 구현시 WebSocket 또는 API 폴링 방식으로 교체
function updatePrices() {
const priceElements = document.querySelectorAll('.current-price');
const changeElements = document.querySelectorAll('.price-change');
priceElements.forEach((element, index) => {
// 실제로는 API에서 실시간 데이터를 받아와 업데이트
const currentText = element.textContent;
console.log('Price update simulation for:', currentText);
});
}
// 30초마다 가격 업데이트 (데모용)
setInterval(updatePrices, 30000);
</script>
</body>
</html>

View File

View File

View File