chore: 미사용 파일/의존성 정리

- HtsHeader.tsx/css 삭제 (레거시, 미사용)
- realtime/examples.py 삭제 (예제 파일, 프로덕션 미사용)
- backtest_results/ 삭제 + .gitignore 추가
- .env.bak 삭제
- requirements.txt: celery 제거 (미사용), httpx 중복 제거
- package.json: recharts 제거 (미사용)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-26 20:29:54 +09:00
parent f92479f3b0
commit e8ab41d164
21 changed files with 5 additions and 104021 deletions

View File

@@ -60,7 +60,8 @@
"Bash(for f:*)",
"Bash(do python:*)",
"Bash(echo \"$f OK\")",
"Bash(done)"
"Bash(done)",
"Bash(find /Users/commylife/myproject/java/workspace/auto-stock -type f \\\\\\(-name *.tmp -o -name *.bak -o -name *.swap \\\\\\))"
]
},
"enableAllProjectMcpServers": true,

4
.gitignore vendored
View File

@@ -76,6 +76,8 @@ summary_output.json
*.bak
.env.bak
# Backtest results (runtime generated)
backend/backtest_results/
# Virtual environments
.venv/
.venv/

View File

@@ -1,238 +0,0 @@
"""
Realtime Module Usage Examples
Realtime 모듈 사용 예시
"""
import asyncio
import logging
from typing import Dict, Any
from app.realtime import KISWebSocketClient, event_handler, EventType, market_scheduler
from app.realtime.websocket_client import create_websocket_client
from app.strategy import strategy_manager
from app.trading import order_manager, market_data_provider
logger = logging.getLogger(__name__)
# ── 예시 1: 기본 실시간 시세 수신 ────────────────────────
async def example_basic_price_stream():
"""기본 실시간 시세 수신 예시"""
# 핸들러 등록
async def on_price_update(event_data: Dict[str, Any]):
stock_code = event_data['stock_code']
price = event_data['current_price']
print(f"💰 {stock_code}: {price}원")
event_handler.register(EventType.PRICE_UPDATE, on_price_update)
# WebSocket 연결
ws_client = create_websocket_client()
await ws_client.connect()
# 종목 구독
await ws_client.subscribe_price("005930") # 삼성전자
await ws_client.subscribe_price("000660") # SK하이닉스
# 메시지 수신 (무한 루프)
await ws_client.listen()
# ── 예시 2: 실시간 전략 실행 ───────────────────────────
async def example_realtime_strategy():
"""실시간 시세로 전략 실행"""
from app.strategy.strategies import DayTradingStrategy
# 전략 등록
strategy = DayTradingStrategy()
strategy_manager.register_strategy(strategy)
# 실시간 시세 수신 시 전략 실행
async def on_price_update(event_data: Dict[str, Any]):
stock_code = event_data['stock_code']
current_price = event_data['current_price']
# 시장 데이터 구성
market_data = {
"current_price": current_price,
"minute_chart": await market_data_provider.get_minute_chart(stock_code),
}
# 전략 실행
signal = await strategy_manager.run_strategy(
"DayTrading",
stock_code=stock_code,
market_data=market_data
)
# 신호 발생 시 주문
if signal:
logger.info(f"📡 신호 발생: {signal}")
result = await order_manager.place_order(
stock_code=signal.stock_code,
order_type=signal.signal_type.value,
quantity=10,
price=signal.price
)
logger.info(f"📤 주문 결과: {result}")
event_handler.register(EventType.PRICE_UPDATE, on_price_update)
# WebSocket 실행
ws_client = create_websocket_client()
await ws_client.run() # 자동 재연결 포함
# ── 예시 3: 장 스케줄러 활용 ───────────────────────────
async def example_market_scheduler():
"""장 스케줄러 활용 예시"""
ws_client = None
# 장 시작 콜백
async def on_market_open():
nonlocal ws_client
logger.info("🔔 장 시작 - WebSocket 연결 및 구독")
ws_client = create_websocket_client()
await ws_client.connect()
# 관심 종목 구독
watch_list = ["005930", "000660", "035420"]
for stock_code in watch_list:
await ws_client.subscribe_price(stock_code)
# 수신 시작
asyncio.create_task(ws_client.listen())
# 장 종료 콜백
async def on_market_close():
logger.info("🔕 장 종료 - WebSocket 연결 해제")
if ws_client:
await ws_client.disconnect()
# 콜백 등록
market_scheduler.register_callbacks(
on_open=on_market_open,
on_close=on_market_close
)
# 스케줄러 실행
await market_scheduler.run()
# ── 예시 4: 복합 예시 (전체 시스템) ──────────────────────
async def example_full_system():
"""전체 자동매매 시스템 예시"""
from app.strategy.strategies import DayTradingStrategy
# 1. 전략 등록
strategy = DayTradingStrategy(
config={
"max_positions": 3,
"stop_loss_pct": 0.025
}
)
strategy_manager.register_strategy(strategy, priority=10)
# 2. 이벤트 핸들러 등록
async def on_price_update(event_data: Dict[str, Any]):
"""실시간 시세 → 전략 실행 → 주문"""
stock_code = event_data['stock_code']
current_price = event_data['current_price']
# 시장 데이터 수집
market_data = {
"current_price": current_price,
"minute_chart": await market_data_provider.get_minute_chart(stock_code),
}
# 포트폴리오 데이터
balance = await order_manager.get_balance()
# ... 보유 종목 파싱
# 전략 실행
signal = await strategy_manager.run_strategy(
"DayTrading",
stock_code=stock_code,
market_data=market_data
)
if signal:
# 주문 실행
from app.strategy.signal import SignalType
if signal.signal_type == SignalType.BUY:
await order_manager.place_order(
stock_code=signal.stock_code,
order_type="BUY",
quantity=10,
price=signal.price
)
elif signal.signal_type in [SignalType.SELL, SignalType.STOP_LOSS, SignalType.TAKE_PROFIT]:
await order_manager.place_order(
stock_code=signal.stock_code,
order_type="SELL",
quantity=signal.quantity,
price=signal.price
)
event_handler.register(EventType.PRICE_UPDATE, on_price_update)
# 3. 장 스케줄러 설정
ws_client = None
async def on_market_open():
nonlocal ws_client
logger.info("🔔 장 시작")
# WebSocket 연결
ws_client = create_websocket_client()
await ws_client.connect()
# 관심 종목 구독
watch_list = ["005930", "000660", "035420", "005380"]
for code in watch_list:
await ws_client.subscribe_price(code)
# 수신 시작
asyncio.create_task(ws_client.listen())
async def on_market_close():
logger.info("🔕 장 종료")
# WebSocket 연결 해제
if ws_client:
await ws_client.disconnect()
market_scheduler.register_callbacks(
on_open=on_market_open,
on_close=on_market_close
)
# 4. 시스템 실행
logger.info("🚀 자동매매 시스템 시작")
await market_scheduler.run()
# ── 메인 함수 ─────────────────────────────────────────
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
# 예시 선택 실행
# asyncio.run(example_basic_price_stream())
# asyncio.run(example_realtime_strategy())
# asyncio.run(example_market_scheduler())
asyncio.run(example_full_system())

View File

@@ -22,13 +22,11 @@ ta==0.11.0
python-dotenv==1.0.0
pytz>=2024.1
holidays>=0.45
celery==5.3.4
pytest==7.4.3
pytest-asyncio==0.21.1
feedparser==6.0.11
joblib>=1.3.0
beautifulsoup4>=4.12.0
httpx>=0.27.1
finance-datareader>=0.9.50
# ML Ensemble
torch>=2.1.0

View File

@@ -21,7 +21,6 @@
"react-chartjs-2": "^5.3.1",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0",
"recharts": "^2.10.3",
"tailwind-merge": "^2.1.0"
},
"devDependencies": {

View File

@@ -1,123 +0,0 @@
.hts-header {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
padding: 12px 20px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #00ff88;
box-shadow: 0 2px 10px rgba(0, 255, 136, 0.3);
}
.header-left {
display: flex;
align-items: center;
gap: 15px;
}
.header-left h1 {
margin: 0;
font-size: 20px;
font-weight: 700;
color: #00ff88;
text-shadow: 0 0 10px rgba(0, 255, 136, 0.5);
}
.header-center {
flex: 1;
display: flex;
justify-content: center;
}
.hts-nav {
display: flex;
gap: 5px;
background: rgba(0, 0, 0, 0.3);
padding: 5px;
border-radius: 8px;
}
.nav-item {
padding: 8px 20px;
color: #8892b0;
text-decoration: none;
font-size: 14px;
font-weight: 500;
border-radius: 6px;
transition: all 0.3s ease;
cursor: pointer;
}
.nav-item:hover {
background: rgba(0, 255, 136, 0.1);
color: #00ff88;
}
.nav-item.active {
background: #00ff88;
color: #0a192f;
font-weight: 600;
}
.header-right {
display: flex;
align-items: center;
gap: 20px;
}
.live-indicator {
font-size: 11px;
padding: 3px 8px;
background: rgba(244, 67, 54, 0.2);
border: 1px solid #f44336;
border-radius: 3px;
}
.header-right .time {
font-size: 13px;
color: #999;
}
.mcp-status-inline {
display: flex;
align-items: center;
gap: 6px;
margin-left: 10px;
}
.status-indicator.connected {
width: 10px;
height: 10px;
background: #00ff88;
border-radius: 50%;
border: 1px solid #00ff88;
margin-right: 2px;
}
.status-indicator.disconnected {
width: 10px;
height: 10px;
background: #f44336;
border-radius: 50%;
border: 1px solid #f44336;
margin-right: 2px;
}
.mcp-indicator {
font-size: 11px;
padding: 3px 8px;
background: rgba(0, 255, 136, 0.15);
border: 1px solid #00ff88;
border-radius: 3px;
margin-left: 8px;
color: #00ff88;
font-weight: 600;
letter-spacing: 1px;
display: inline-flex;
align-items: center;
}
.mcp-indicator.offline {
background: rgba(244, 67, 54, 0.15);
border: 1px solid #f44336;
color: #f44336;
}

View File

@@ -1,122 +0,0 @@
/**
* @deprecated 이 컴포넌트는 더 이상 사용되지 않습니다.
* Layout.tsx가 메인 헤더 역할을 담당하며, App.tsx에서도 import하지 않습니다.
* 삭제 여부는 팀 확인 후 결정하세요.
*
* HtsHeader.tsx — HTS 스타일 상단 헤더 컴포넌트 (레거시)
*
* 역할:
* - 네비게이션 메뉴, MCP 연결 상태, 현재 시각 표시
* - 리스크 체크 버튼을 통한 MCP 포트폴리오 리스크 평가 요청
*/
import { useEffect, useState } from 'react'
import { Link, useLocation } from 'react-router-dom'
import { useQuery } from '@tanstack/react-query'
import api from '../lib/api'
import './HtsHeader.css'
/** 네비게이션 메뉴 항목 정의 */
const navItems = [
{ path: '/', label: '대시보드' },
{ path: '/rules', label: '트레이딩 규칙' },
{ path: '/trades', label: '거래 내역' },
{ path: '/mcp', label: 'MCP 상태' },
]
/**
* HtsHeader — HTS(홈 트레이딩 시스템) 스타일 헤더
*
* 상태(State):
* - currentTime: 1초마다 갱신되는 현재 시각 (setInterval)
*
* 쿼리:
* - mcp-status: MCP 서버 연결 상태 (5초 폴링)
*/
const HtsHeader = () => {
const location = useLocation()
// 현재 시각 — 1초 간격 갱신
const [currentTime, setCurrentTime] = useState(() => new Date())
// 1초마다 현재 시각 업데이트
useEffect(() => {
const timer = setInterval(() => {
setCurrentTime(new Date())
}, 1000)
return () => clearInterval(timer)
}, [])
// MCP 서버 연결 상태 가져오기 (5초 폴링)
const { data: mcpStatus } = useQuery({
queryKey: ['mcp-status'],
queryFn: async () => (await api.get('/mcp/status')).data,
refetchInterval: 5000,
})
/**
* 리스크 체크 핸들러
* MCP 서버에 RISK_ASSESSMENT 분석을 요청하고 결과를 alert로 표시
*/
const handleRiskCheck = async () => {
try {
const response = await api.post('/mcp/analyze', {
analysis_type: 'RISK_ASSESSMENT',
data: { message: '현재 포트폴리오 리스크를 분석해주세요' }
});
const result = response.data;
alert(`포트폴리오 리스크 평가:\n\n${result.analysis || result.result}`);
} catch (error) {
console.error('리스크 평가 실패:', error);
alert('리스크 평가에 실패했습니다. MCP 서버를 확인해주세요.');
}
}
return (
<div className="hts-header">
<div className="header-left">
<h1>📊 Auto Stock Trading Dashboard</h1>
</div>
<div className="header-center">
<nav className="hts-nav">
{navItems.map((item) => (
<Link
key={item.path}
to={item.path}
className={`nav-item ${location.pathname === item.path ? 'active' : ''}`}
>
{item.label}
</Link>
))}
</nav>
</div>
<div className="header-right">
{/* MCP 상태 표시 */}
<span className={`mcp-indicator ${mcpStatus?.status === 'connected' ? 'live' : 'offline'}`}>
{mcpStatus?.status === 'connected' ? '🟢 MCP LIVE' : '⚫ MCP'}
</span>
<span className="live-indicator" style={{ marginLeft: '8px' }}>🔴 LIVE</span>
<button
onClick={handleRiskCheck}
style={{
marginLeft: '16px',
padding: '6px 12px',
background: '#f59e0b',
color: '#fff',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '12px',
fontWeight: '600'
}}
onMouseOver={(e) => e.currentTarget.style.background = '#d97706'}
onMouseOut={(e) => e.currentTarget.style.background = '#f59e0b'}
>
⚠️ 리스크 체크
</button>
<span className="time" style={{ marginLeft: '16px' }}>{currentTime.toLocaleTimeString('ko-KR')}</span>
</div>
</div>
)
}
export default HtsHeader