항목	퀀트 관점
매도 로직 통합	매수 전략이 하나면 매도도 하나로 통합하는 게 맞고, 유지보수·일관성 측면에서 유리함.
동기화 타이밍	매수/매도와 같은 주기에서 “동기화 → 매도 → 매수” 순서로 묶어서 진행하는 게 좋음.
변동성 역가중 + 금액 균등화	역가중은 유지하고, 종목당 원화 상한(슬롯)을 추가해서 “비싼 것/싼 것 금액 비슷 → 손익률 비슷하면 원화 손익도 비슷”하게 가져가는 설계가 합리적임.
이 세 가지 모두 현재 코드 구조와 앞에서 말씀하신 요구(매도 통합, 동기화 동시성, 금액 균등화)와 잘 맞는 방향입니다.
하기 전
This commit is contained in:
2026-02-12 12:12:41 +09:00
parent ab09a221ba
commit d8652acaa5

View File

@@ -1569,10 +1569,16 @@ class TradingBotV2:
logger.info(f"🔍 [Pass-피뢰침] {name} {code}: 당일 변동폭 {daily_change_pct:.1f}% 과도 (최대 {max_daily_change}%)")
return None
# [필터 3] 20일 이동평균선(MA20) 아래인지?
# [필터 3] 20선 아래면 스킵 / 20선에서 너무 멀리 올라온 과열 구간도 스킵
if current_price < ma20:
logger.info(f"🔍 [Pass-MA20] {name} {code}: 현재가({current_price}) < MA20({ma20:.2f})")
return None
# 20선 초과 상한: MA20 대비 N% 이상 위면 고점 매수로 간주 → 스킵
ma20_cap_pct = get_env_float("MA20_MAX_ABOVE_PCT", "3.0") # 기본 3% 초과 시 스킵
if ma20 > 0 and current_price > ma20 * (1 + ma20_cap_pct / 100):
gap_pct = (current_price - ma20) / ma20 * 100
logger.info(f"🔍 [Pass-MA20과열] {name} {code}: 20선 대비 {gap_pct:.1f}% 위 (최대 {ma20_cap_pct}%)")
return None
# [필터 4] 최소 거래량 필터 (평균의 30%도 안되면 패스)
if current_vol < avg_vol * 0.3:
@@ -2349,20 +2355,21 @@ class TradingBotV2:
time.sleep(60)
continue
# [유니버스 갱신] 5분 주기 (개미털기 스캔 + 계좌 동기화!)
# 🔥 [계좌↔DB 동기화] 2분마다 (한온시스템 등 계좌에만 있는 종목 빠르게 반영!)
if self.is_first_run or (current_minute % 2 == 0 and current_second < 5):
self.sync_portfolio_from_api()
if self.is_first_run:
logger.info(f"🔄 [첫실행] 동기화 완료")
# [유니버스 갱신] 5분 주기 (개미털기 스캔)
if self.is_first_run or (current_minute % 5 == 0 and current_second < 5):
logger.info(f"🔄 [스캔 주기] 첫실행:{self.is_first_run} | 시각:{current_hour:02d}:{current_minute:02d}:{current_second:02d}")
# 🔥 실제 계좌 ↔ DB 동기화 (Dual처럼 5분마다!)
self.sync_portfolio_from_api()
# 유니버스 갱신
self.update_universe()
# 금지 종목 정리 (만료된 항목 제거)
self.cleanup_banned_list()
self.is_first_run = False
logger.info("⏳ [주기] 유니버스 갱신 + 동기화 완료, 5초 대기")
logger.info("⏳ [주기] 유니버스 갱신 완료, 5초 대기")
time.sleep(5)
# 생존 신고 (1분마다)
@@ -2372,15 +2379,18 @@ class TradingBotV2:
logger.info(f"👀 [생존] 타겟:{len(targets)} | 보유:{active_count}/{self.max_stocks} | 예수금:{self.current_cash:,.0f}")
time.sleep(2)
# 2. 시간대별 리포트 (리포트 전 계좌 조회!)
# 2. 시간대별 리포트 (리포트 전 계좌 조회 + 동기화!)
if current_hour == 13 and current_minute == 0 and not self.morning_report_sent:
self.refresh_account() # 최신 정보 조회
self.refresh_account()
self.sync_portfolio_from_api() # 리포트 전 DB 동기화
self.send_morning_report()
elif current_hour == 15 and current_minute == 15 and not self.closing_report_sent:
self.refresh_account() # 최신 정보 조회
self.refresh_account()
self.sync_portfolio_from_api()
self.send_closing_report()
elif current_hour == 15 and current_minute >= 35 and not self.final_report_sent:
self.refresh_account() # 최신 정보 조회
self.refresh_account()
self.sync_portfolio_from_api()
self.send_final_report()
# 2-1. 뉴스 AI 분석 (하루 1회)