주식자동매매 AI 프로그램 초기 모델

This commit is contained in:
2026-02-04 23:29:06 +09:00
parent 41df1a38d3
commit 7d5f62f844
20 changed files with 2987 additions and 0 deletions

242
watchlist_manager.py Normal file
View File

@@ -0,0 +1,242 @@
import json
import os
from datetime import datetime
from dotenv import load_dotenv
from modules.services.kis import KISClient
from modules.services.ollama import OllamaManager
from modules.services.news import NewsCollector
load_dotenv()
class WatchlistManager:
"""
매일 아침 8시에 뉴스와 시장 동향을 분석하여
Watchlist를 자동으로 업데이트하는 관리자
"""
def __init__(self, kis_client, watchlist_file="watchlist.json"):
self.kis = kis_client
self.watchlist_file = watchlist_file
self.ollama = OllamaManager()
self.news = NewsCollector()
# 섹터별 대표 종목 풀 (30개)
self.sector_pool = {
# 반도체/전자 (8개)
"005930": "삼성전자",
"000660": "SK하이닉스",
"006400": "삼성SDI",
"009150": "삼성전기",
"042700": "한미반도체",
"403870": "HPSP",
"357780": "솔브레인",
"058470": "리노공업",
# IT/플랫폼 (5개)
"035420": "NAVER",
"035720": "카카오",
"017670": "SK텔레콤",
"030200": "KT",
"259960": "크래프톤",
# 2차전지/화학 (5개)
"373220": "LG에너지솔루션",
"051910": "LG화학",
"096770": "SK이노베이션",
"066970": "엘앤에프",
"247540": "에코프로비엠",
# 바이오/제약 (4개)
"207940": "삼성바이오로직스",
"068270": "셀트리온",
"326030": "SK바이오팜",
"196170": "알테오젠",
# 금융 (3개)
"105560": "KB금융",
"055550": "신한지주",
"086790": "하나금융지주",
# 자동차/중공업 (3개)
"005380": "현대차",
"000270": "기아",
"034020": "두산에너빌리티",
# 기타 (2개)
"005490": "POSCO홀딩스",
"028260": "삼성물산"
}
def load_watchlist(self):
"""현재 Watchlist 로드"""
if not os.path.exists(self.watchlist_file):
return {}
with open(self.watchlist_file, "r", encoding="utf-8") as f:
return json.load(f)
def save_watchlist(self, watchlist):
"""Watchlist 저장"""
with open(self.watchlist_file, "w", encoding="utf-8") as f:
json.dump(watchlist, f, ensure_ascii=False, indent=4)
print(f"✅ [Watchlist] Updated: {len(watchlist)} stocks")
def analyze_market_trends(self):
"""
뉴스와 시장 데이터를 분석하여 주목해야 할 섹터/종목 파악
Returns: dict {sector: priority_score}
"""
print("📰 [Watchlist] Analyzing market news and trends...")
# 1. 최신 뉴스 수집
news_items = self.news.get_market_news("주식 시장 경제 뉴스")
# 2. AI에게 섹터 분석 요청
prompt = f"""
[System Instruction]
You are a market analyst. Analyze today's news and identify which sectors are HOT.
News Data:
{json.dumps(news_items[:10], ensure_ascii=False)}
Task:
1. Identify top 3 sectors that will perform well today
2. Rate each sector's priority (0.0 to 1.0)
Output Format (JSON only):
{{
"semiconductor": 0.9,
"battery": 0.7,
"bio": 0.5,
"it": 0.6,
"finance": 0.4,
"auto": 0.3
}}
"""
ai_response = self.ollama.request_inference(prompt)
sector_scores = {
"semiconductor": 0.5,
"battery": 0.5,
"bio": 0.5,
"it": 0.5,
"finance": 0.5,
"auto": 0.5
}
try:
sector_scores = json.loads(ai_response)
print(f"🧠 [AI Analysis] Sector Scores: {sector_scores}")
except:
print("⚠️ [AI] Failed to parse sector analysis, using defaults")
return sector_scores
def get_volume_leaders(self, limit=10):
"""거래량 상위 종목 조회"""
try:
hot_stocks = self.kis.get_volume_rank(limit=limit)
return {item['code']: item['name'] for item in hot_stocks}
except Exception as e:
print(f"⚠️ [Watchlist] Volume rank failed: {e}")
return {}
def update_watchlist_daily(self):
"""
매일 아침 Watchlist를 업데이트하는 메인 로직
- 뉴스 분석 기반 섹터 선정
- 거래량 상위 종목 추가
- 20~30개 유지
"""
print("🔄 [Watchlist] Starting daily update...")
# 1. 현재 Watchlist 로드
current_watchlist = self.load_watchlist()
print(f"📋 [Current] {len(current_watchlist)} stocks in watchlist")
# 2. 시장 트렌드 분석 (AI 기반)
sector_scores = self.analyze_market_trends()
# 3. 섹터별 우선순위에 따라 종목 선정
new_watchlist = {}
# 섹터별 매핑
sector_mapping = {
"semiconductor": ["005930", "000660", "006400", "009150", "042700", "403870", "357780", "058470"],
"it": ["035420", "035720", "017670", "030200", "259960"],
"battery": ["373220", "051910", "096770", "066970", "247540"],
"bio": ["207940", "068270", "326030", "196170"],
"finance": ["105560", "055550", "086790"],
"auto": ["005380", "000270", "034020"]
}
# 섹터 점수 기준 정렬
sorted_sectors = sorted(sector_scores.items(), key=lambda x: x[1], reverse=True)
# 상위 섹터부터 종목 추가 (최대 25개)
for sector, score in sorted_sectors:
if sector not in sector_mapping:
continue
# 섹터 점수에 따라 종목 수 결정
if score >= 0.8:
num_stocks = 5 # 핫한 섹터는 5개
elif score >= 0.6:
num_stocks = 3 # 보통 섹터는 3개
else:
num_stocks = 2 # 약한 섹터는 2개
sector_codes = sector_mapping[sector][:num_stocks]
for code in sector_codes:
if code in self.sector_pool:
new_watchlist[code] = self.sector_pool[code]
if len(new_watchlist) >= 25:
break
if len(new_watchlist) >= 25:
break
# 4. 거래량 상위 종목 추가 (최대 5개)
volume_leaders = self.get_volume_leaders(limit=10)
added_from_volume = 0
for code, name in volume_leaders.items():
if code not in new_watchlist and len(new_watchlist) < 30:
new_watchlist[code] = name
added_from_volume += 1
print(f" ✨ Added from volume rank: {name} ({code})")
if added_from_volume >= 5:
break
# 5. 저장
self.save_watchlist(new_watchlist)
# 6. 변경 사항 요약
added = set(new_watchlist.keys()) - set(current_watchlist.keys())
removed = set(current_watchlist.keys()) - set(new_watchlist.keys())
summary = f"📊 **[Watchlist Updated]**\n"
summary += f"Total: {len(new_watchlist)} stocks\n\n"
if added:
summary += f" **Added ({len(added)}):**\n"
for code in added:
summary += f"{new_watchlist[code]} ({code})\n"
if removed:
summary += f"\n **Removed ({len(removed)}):**\n"
for code in removed:
summary += f"{current_watchlist[code]} ({code})\n"
print(summary)
return summary
if __name__ == "__main__":
# 테스트 실행
kis = KISClient()
manager = WatchlistManager(kis)
manager.update_watchlist_daily()