Files
openclaw/CLAUDE.md
T
hyowons 300a4c9ca9 feat(budget): 가희 증권 자산 후잉·결산 반영 (securities_balance v2)
- send_balance_to_budget.py: 본인+가희 계좌 소유자별(by_owner) 집계, schema v1→v2
- inbox_handler.py: OWNER_ASSET 맵으로 소유자별 reconcile(self→증권(효원)/gahee→증권(가희)),
  asset_name 기반 출력, v2 payload 검증 추가(v1 하위호환 유지)
- monthly_settlement.py: 텔레그램 reconcile 라인 소유자별 라벨
- INBOX_TOPICS.md / CLAUDE.md: v2 스키마 문서화

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 18:51:15 +09:00

58 KiB
Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Who I Am (코디 🛠)

  • Name: 코디 (Claude Code)
  • Role: 정비공 — 이 OpenClaw 워크스페이스의 구조·스크립트·문서를 직접 손보는 외부 작업자
  • Channel: 폰/웹 claude.ai/code의 'openclaw' 세션 (claude-code-session 스킬로 on-demand 기동)
  • 관계: 클로(메인 비서)·레이(주식)·골디(가계부)와는 다른 런타임. OpenClaw 에이전트가 아니라 Anthropic CLI로 동작하며, 파일 수준에서 워크스페이스를 정비한다.
  • 응답 규칙: 한국어 / 존댓말 / 관리자님 호칭 / [진행중] 또는 [답변완료]로 마무리

Session Startup (코디 부트스트랩)

세션 기동 직후, 관리자님 첫 메시지에 답하기 전에 agents/cody/inbox/incoming/ 개수만 확인:

  • 0 → 침묵, 통상 모드
  • 1개 이상 → "📥 코디 인박스에 N개 처리 대기 중입니다." 한 줄 알림만. 상세 요약·검증·개선은 관리자님 명시 요청을 받기 전엔 시작 X
  • 수동 호출 어휘: "검증 큐", "코디 인박스 확인", "incoming 확인해줘" → 그때 비로소 envelope from/summary/priority를 상세 출력하고 우선순위 위임. 처리 흐름은 아래 "Cody Inbox" 섹션 참조

What This Is

This is an OpenClaw personal AI assistant workspace (~/.openclaw). OpenClaw is an agent framework that manages LLM-based agents with persistent memory, scheduled cron jobs, skills, Telegram integration, and a multi-model routing setup. All agents respond in Korean (존댓말, 호칭은 "관리자님").

Resident entities:

  • 클로 🦞 — main personal assistant (workspace/)
  • 레이 🪎 — stock specialist (agents/stock/)
  • 골디 📒 — budget/accounting specialist (agents/budget/)
  • 코디 🛠 — Claude Code (me, the maintainer; not an OpenClaw agent)

Directory Structure

  • openclaw.json — Main configuration: auth profiles, model routing, agent definitions, channel settings, gateway config, plugin registry
  • workspace/ — Primary agent workspace containing identity, memory, skills, scripts, and templates
  • agents/ — Per-agent directories (e.g., stock/ has its own workspace with SOUL/IDENTITY/TOOLS)
  • cron/jobs.json — Scheduled cron jobs (briefings, behive digest, monthly settlement)
  • flows/registry.sqlite — Flow execution registry
  • tasks/runs.sqlite — Task execution history
  • credentials/ — Telegram auth tokens, 키움 REST API 자격증명(kiwoom.json, 조회 전용)
  • docs/ — 외부 공급사·서비스 공식 문서 보관소(키움 REST API PDF 등). 모든 에이전트 공유. 카탈로그는 docs/README.md. 하위 폴더 만들지 않고 직속에 둔다.
  • identity/ — Device identity and auth
  • completions/ — Shell completion scripts (bash/zsh/fish/ps1)

Version Control (Git)

이 워크스페이스는 git 모노레포로 관리됨. Remote git.hyowons.net/hyowons/openclaw (NAS 사설 Gitea), 시크릿·런타임·백업은 .gitignore로 제외(openclaw.json은 의도적 추적), 토큰 저장돼 git push 입력 불필요.

Workspace Files (Boot Order)

Agents follow this startup sequence defined in workspace/AGENTS.md:

  1. SOUL.md — Agent personality and behavioral rules
  2. IDENTITY.md — Name, emoji, vibe
  3. USER.md — Owner profile (효원, addressed as 관리자님, timezone Asia/Seoul, Korean preferred)
  4. memory/YYYY-MM-DD.md — Daily memory logs (today + yesterday)
  5. MEMORY.md — Long-term curated memory (main session only, not in group chats for security)

Key Configuration (openclaw.json)

  • Primary model: openai-codex/gpt-5.5 with fallbacks to OpenRouter free models 및 gpt-5.5-pro
  • Agents: main (default, 클로), stock (레이), budget (골디) — each with own workspace
  • Channels: Telegram enabled (DM allowlist + group allowlist with requireMention)
  • Gateway: Local mode on port 18789 with Tailscale serve, token auth
  • Plugins: Brave search, Telegram, OpenAI, OpenRouter, memory-core (dreaming disabled)

Skills

Main workspace skills (workspace/skills/):

  • briefing-mail — Morning/evening briefing emails via scripts/briefing_mail.py {morning|evening}
  • find-skills — Discover and install skills from the ecosystem (npx skills find)
  • claude-code-session — On-demand claude remote-control daemon 다중 세션 제어. 관리자님이 "클로드 세션 열어줘"/"X 세션 열어줘"/"openclaw-2 닫아줘"/"세션 목록"/"프로필 추가" 등 자연어로 부탁하면 scripts/session_tool.py {profile|session} ... 호출. 프로필(이름↔workdir)은 ~/.openclaw/state/claude_sessions.json에 저장, 세션 plist는 ~/Library/LaunchAgents/ai.claude-session.<profile>-<N>.plist로 ephemeral 관리. 레거시 단일 세션은 ensure_session.sh가 계속 운영.
  • summarize-pro — 텍스트·문서·기사·미팅·트랜스크립트 요약 전용 (로컬 처리, 외부 API 호출 없음)
  • web-search — DuckDuckGo 검색 API 기반 웹 검색 (text/markdown/json 출력)

Budget agent skills (agents/budget/workspace/skills/):

  • whooing-sync — iMessage 카드결제 알림 → 후잉 가계부 자동 동기화. 매핑은 state/whooing_account_map.json, 진행상태는 state/whooing_synced.json
  • monthly-settlement — 매월 1일 05:00 cron으로 전월 결산 리포트 생성

Stock agent skills (agents/stock/workspace/skills/):

  • kiwoom-rest — 키움증권 REST API 조회 전용 클라이언트 (잔고·보유종목·계좌평가·실시간 시세·당일매매일지·종목코드 매핑·미체결 조회). 주문(매수/매도/정정/취소)은 별도 orders/kiwoom_order.py. scripts/kiwoom_client.py {token|summary|balance|positions|quote|resolve|refresh-codes|journal|open}. ka10170 당일매매일지로 round-trip·풀매도 거래까지 포착 (kt00018 잔고만으로는 누락됨). 다종목 시세는 get_watchlist_quotes(codes) ka10095 한 콜로 처리 (단건 ka10001 × N 대비 100배 빠름). ka10075 미체결 조회로 정정/취소 대상 자동 추출
  • stock-agent — Daily portfolio report (키움 REST 기반, owner 그룹(본인/가희)별 블록 표시, --by-account는 계좌별 추가 분리) via scripts/stock_portfolio_report.py {run|send} [--by-account]
  • behive-watchlist — 비하이브 종목분석 요약·이메일·텔레그램 알림 + 수동 워치리스트 추가(add) + 장중 15분 간격 시세 모니터링(scripts/watchlist_monitor.py check — buy/target/stop 트리거 → 레이 텔레그램, LLM 경유 없음) + 웹 뷰(scripts/behive_web.py servehttps://stock.hyowons.net/, launchd 상시, 페이지 로드 시점에 키움 호출. CSS 라디오 탭으로 감시종목 / 관리자 / 가희 3개 패널: 워치리스트, 본인·가희 계좌현황(KPI·예수금·당일정산·보유종목 — stock.briefing 메일과 동일 데이터). day_change 정확도용 ka10001 보정은 web 경로에선 생략, kt00018 raw 사용)

Scripts

Main workspace (workspace/scripts/), run with python3:

  • briefing_mail.py — Gmail/Calendar/YouTube 뉴스 브리핑 composer (네이버 지수 KOSPI/KOSDAQ/나스닥 조회 포함, 월요일 오전엔 stock agent의 ipo_calendar_sync.py 호출). 오전 브리핑은 youtube_briefing_digest를 import해 상단에 🌎 해외 증시·이슈 + 🇰🇷 국내 증시·이슈 카드 2개 삽입. prepare morning [--final]us_market(@futuresnow)·behive_market(비하이브 주식시황) 블록(available_today·recap_expected_today·video·transcript)을 산출. ⚠️ 비하이브 주식시황이 미국증시도 다뤄 @futuresnow와 해외부분 겹침 → LLM이 두 자막을 합쳐 중복제거 후 해외(overseas_summary)/국내(domestic_summary)로 재정리(해외=두 소스 병합, 미국수치는 @futuresnow 우선 / 국내=비하이브 국내부분만). 발송 게이트 us_send_directive(proceed/wait): 둘 중 하나라도 available이면 proceed, 평일(둘 중 하나라도 게시예정)인데 둘 다 미게시면 wait(다음 폴백 재시도), 주말/--final은 proceed. cron이 directive==wait면 발송 보류. 카드 요약은 LLM이 카테고리 그룹 배열([{label,items[]}])로 작성, compose의 _video_summary_cardoverseas_summary/domestic_summary 있을 때만 렌더(해외=파랑·국내=초록 팔레트, 그룹 라벨에 안 맞는 내용은 '기타' 그룹). 오후 브리핑은 behive_close(비하이브 '마감시황')로 📕 마감시황 카드(갈색 팔레트, close_summary 그룹배열, best-effort) — 시장 체크 다음·뉴스 앞에 렌더. 요약·뉴스 본문의 **강조** 마크다운은 _emphasize가 굵게+진한 강조색(글자색 #c62828, 배경 안 건드림)으로 변환 — LLM이 핵심 수치·키워드만 절제해서 표시(시황 카드·뉴스 요약 공통). 국내 증시에 큰 영향 줄 뉴스는 LLM이 article에 kr_impact:true_article_card🔥'국내증시 영향' 배지+빨강 강조 테두리로 부각(반도체·환율·미 금리·외국인 수급·정책 등, 남발 금지). 해외/국내/마감시황 카드 불릿도 국내 영향 큰 항목은 LLM이 맨 앞에 🔥 접두 → _us_items_html이 강조 배경 밴드(#fff7f6)로 표시. 시장 체크의 코스피 야간선물·MSCI는 비하이브 자막 언급값으로 오버라이드 — LLM이 kospi_futures_override/msci_override(라인 문자열) 작성 시 build_html_body가 스크랩값(investing.com, 전날 것일 수 있음) 대신 사용, 미작성·불명확이면 스크랩 유지. ⚠️ @futuresnow '오늘의 요약'엔 코스피/MSCI 언급 없음(미국 전용) — 이 값 출처는 비하이브뿐
  • gmail_label_classify.py — Gmail 라벨 자동 분류 (조회 전용 Gmail API, 계정 mini.snowoyh@gmail.com). self-sent 메일을 제목 룰로 라벨링: [오전/오후 브리핑]브리핑, [비하이브 종목분석]종목분석(주식 라벨 제거), [주식 리포트]주식브리핑(주식 제거) + 24h 지난 테스트메일 휴지통 이동. 로그 state/gmail_label_classify.log. launchd ai.openclaw.gmail-label-classify 매일 01:00(LLM 미경유, 2026-06-26 cron에서 이관). CLI: python3 gmail_label_classify.py [--dry-run]
  • youtube_briefing_digest.py — 오전 브리핑용 유튜브 시황 영상 감지+자막 (두 채널 공용). get_us_summary()=오선의 미국 증시 라이브(@futuresnow, UC_JJ_NhRqPKcIOj5Ko3W_3w) '오늘의 요약'(미국장 마감 후 07:2008:30 KST, 예정=화토) / get_behive_market_summary()=비하이브 투자자문(UCHTRF5r154igU2gXjudUMzg) '주식시황'(장전 시황, 05:4006:50 KST, 예정=월금) / get_behive_close_summary()=같은 채널 '마감시황'(장 마감 해설, 16:4518:10 KST, 예정=월금, 오후 브리핑용). 공통: 채널 영상 페이지 lockupViewModel 스크랩(RSS 피드 IP 404 잦아 미사용)→제목필터→최신영상→watch publishDate(PT→KST)로 오늘게시 판정(제목 날짜는 신뢰X)→자막. CLI: python3 youtube_briefing_digest.py {latest|transcript} [us|behive]. ⚠️ 레이의 behive_youtube_digest.py(종목분석→워치리스트)와 별개 — 같은 채널이지만 목적·소유자 다름

Stock agent (agents/stock/workspace/scripts/), run with python3:

  • kiwoom_client.py — 키움 REST API 조회 전용 클라이언트 (본인 2계좌 일반/ISA + 가희 2계좌 가희_일반/가희_ISA, 토큰 캐싱, 주문 함수 없음). CLI: token | summary | balance | positions | quote | resolve | refresh-codes | journal

  • fnguide_client.py — FnGuide 컴퍼니가이드 펀더멘털 조회 (조회 전용, 키움에 없는 데이터 보강). Snapshot_all/{code}.xml(EUC-KR, JS 미경유 직접 파싱) 1콜 → 연간 재무 시계열·매출/EPS/영업이익 증가율·컨센서스(목표주가·투자의견·추정EPS/PER·참여기관수). get_fundamentals(code), state/fnguide_cache/{code}.json 12h 캐시, 실패·ETF는 None (절대 raise X). ⚠️ FnGuide 저작권 회색지대 → 보유·관심 종목 on-demand만. ⚠️ 현재 피드는 forward 추정 EPS가 trailing 대비 크게 높게 나옴(예 하이닉스 2025 58,955→2026E 297,725) — 추정 PER이 현재 PER보다 훨씬 낮은 건 이익 급증 기대 반영이지 버그 아님. CLI: python3 fnguide_client.py <code> [--fresh]

  • wisereport_client.py — WISEreport(comp.wisereport.co.kr, FnGuide 계열 동일 벤더) 컨센서스·증권사 리포트 조회 (순수 JSON, encparam 불필요). get_consensus(code): 연도별 추정 재무(IFRS연결 A실적/E추정, c1050001_data.aspx flag=2)·목표주가+추정EPS 3개월 리비전 추이(cF5001)·어닝 서프라이즈(flag=5 매출/영익 실적 vs 직전 컨센서스 괴리율). get_reports(code): 최근 증권사 분석리포트(c1080001_data.aspx — 날짜·증권사·제목·목표가+상향/하향 액션·투자의견·애널리스트·요약 bullet, PDF 원문은 게이팅·저작권으로 제외). state/wisereport_cache/ 캐시(컨센서스 12h·리포트 6h), 실패·ETF는 None. 동일 벤더 회색지대. CLI: <code> [--fresh] [--reports]

  • stock_analysis.py — 종목 분석 보고서 엔진 (behive_web /stock/<code>가 import, CLI 없음). 키움 기본정보·일봉·수급 + LLM 코멘트 + SVG 차트 + 투자의견 게이지 → 종목별 HTML 보고서(state/stock_reports/<code>/). FnGuide 성장성·컨센서스 + WISEreport 추정·리비전·서프라이즈 섹션 포함(LLM 데이터블록에도 주입). 레이아웃: 결론(투자의견) 최상단 + 보조 섹션 2단 그리드(.rpt-cols), 지표마다 평이한 캡션(.rpt-cap) + ⓘ 탭 설명(_KV_HINTS/_lbl). enqueue / render_stock_page / add_peer. 새 섹션은 신규 생성 보고서부터 반영(기존 저장본은 옛 구조).

  • stock_portfolio_report.py — Daily portfolio report. 키움 kt00018(보유)·kt00001(예수금)·ka10170(당일매매일지) ground truth. --by-account로 계좌 분리 뷰. 당일정산(round-trip·풀매도)은 잔고에 없어 별도 [당일정산] 카드로 표시

  • ipo_calendar_sync.py — Sync IPO subscription/listing dates to Google Calendar

  • holiday_sync.py — investing.com에서 한국(KRX) 휴장일 fetch → state/market_holidays.json. behive_web.py 자동갱신 토글이 휴장일·평일·시간대로 비활성 판정. CLI: python3 holiday_sync.py [--show]

  • behive_youtube_digest.py — 비하이브 YouTube 종목분석 수집·요약·발송 + 수동 워치리스트 추가(add)/조회·삭제

  • watchlist_monitor.py — 워치리스트 종목 장중 15분 시세 감시, buy/target/stop 트리거 발생 시 레이 텔레그램 알림 (LLM 없이 동작). 미보유 종목은 ka10095 batch 1콜 + 단건 ka10001 fallback. 보유 종목은 kt00018 재활용

  • behive_web.py — 워치리스트 실시간 웹 뷰 + 매매 진입점. serve(launchd, Tailscale IP 100.75.148.12:18790 바인드, 페이지 GET마다 키움 ka10095 batch 1콜로 워치리스트 시세 + kt00018·kt00001·ka10170 병렬 호출 후 HTML 응답. RENDER 캐시 10s, 종목별 quote 캐시 30s) / render(디버깅용 1회 렌더). 외부 노출은 NAS Synology reverse proxy(stock.hyowons.net → mac:18790) 경유. 인증 없음 — Tailnet 내부망 한정 운영. 보유종목 day_change 보정은 brifing 과 동일 A-4 정책. KPI 순서·라벨도 stock_portfolio_report 와 통일. 보유종목 행마다 📋 거래내역 + 💰 거래 + 📝 메모 버튼. 자산정보 탭 sub-tab 3개 (자산보기·차트보기·시장정보) + 우측 별도 [💰 거래] 버튼 (본인 첫 보유종목 자동 선택). 관심·감시종목 행에도 💰 거래 (보유 모드면 매도 default).

    거래 모달 시스템 (order-modal + pin-modal + open-orders-modal) — 매매 진입점. 흐름: 종목 select(상단, 보유/관심/감시 통합) → 매수·매도 토글 → 호가창(ka10004 10단계, 1초 polling, visibility 가드) + 입력(계좌·주문유형 LIMIT/MARKET·단가·금액(매수만 양방향)·수량) → 매수/매도 버튼 → propose → PIN 모달(modal-top z-index) 카드 요약 + PIN 입력(autocomplete="one-time-code") + 만료 카운트다운 → verify → 결과 토스트 + 자동 닫기. [📋 진행중] 탭은 활성 PIN 카드 → PIN 모달, 미체결만 → open-orders 모달(4계좌 통합 + 행별 취소). 매수 시 금액↔수량 양방향 자동(programmatic .value, 무한루프 X). 매도 토글 시 수량 자동 100%(max_qty). 시장 phase 라벨 + NXT 시간대+nxt_enable=false📵 NXT 거래불가 + 매수/매도 버튼 disable. 우상단 X 없음 — 하단 [닫기]/[취소] + overlay 클릭. 2계좌 동시 매도(2026-06-12): 매도 버튼 시 전량매도(입력 수량=max_qty) 이고 같은 소유자 그룹(본인 일반↔ISA / 가희끼리)의 다른 계좌에도 같은 종목 보유(accStatus.trde_able_qty>0)면 sell-choice-modal 팝업 — [두 계좌 모두 매도](두 계좌 모두 매도가능 전량, 단가 동일) / [선택 계좌만] / [취소]. 일부매도는 팝업 없이 단일 진행. 매도 정보영역은 그룹 내 다른 계좌도 보유 시 보유: 141주 / 전체 280주 병기. 모두 매도는 POST /api/order/propose_multihandler.propose_trade_multi(레그별 독립 검증, SELL+LIMIT/MARKET 한정, 같은 그룹만) → 카드 1장+PIN 1개(iMessage 매도(2계좌))가 두 레그 승인 → verify 시 _submit_multi_legs가 레그 독립 제출(idem_hash 계좌별 분리)·독립 fill_watcher, 한 레그 실패해도 나머지 시도(ok=하나라도 접수).

    텔레그램 발송 정책 (웹 매매) — 거부·검증 에러는 토스트만, 매매등록(submit_with_pin 성공)·매매체결(fill_watcher)만 텔레그램. PIN 메시지는 iMessage (Apple 도메인 바인딩 @stock.hyowons.net #PIN, iOS Safari OTP 자동입력). handler.send_imessage_pin (fire-and-forget Popen, AppleEvent timeout -1712 떠도 메시지는 큐로). credential credentials/admin_imessage.json {"handle": "01012345678"}. 자기 자신 iMessage self-send 가능 (mac → 본인 iCloud handle).

    신규 endpoint: /api/quote_book?code (ka10004 호가 10단계 + ka10001 현재가 + nxt_enable), /api/order/check?code&account&side&price (잔액·보유·max_qty·매도 손익 미리보기), POST /api/order/propose (handler.propose_trade wrapper, 성공 시만 텔레그램·iMessage), POST /api/order/propose_multi (2계좌 동시 매도 — accounts/qtys 콤마 동수 리스트, handler.propose_trade_multi wrapper), POST /api/order/verify (handler.submit_with_pin wrapper, 성공 시만 텔레그램), POST /api/order/cancel (handler.cancel_active_card, 텔레그램 X), /api/order/active (PinStore.peek + 4계좌 미체결 카운트), /api/orders/open (ka10075 4계좌), POST /api/orders/cancel?ord_no&account (handler.cancel_open_order + 텔레그램), /api/market_state (regular/nxt/closed/holiday/weekend phase), /api/symbols/all (보유+관심+감시 통합 dedup)

    기업정보 모달 (4탭) — 종목 행 기업정보 버튼 → /api/stock_info?code(키움 ka10001 + 네이버 분기영업이익 + fnguide_client 펀더멘털·컨센서스 + wisereport_client 리비전·서프라이즈·최근리포트) fetch → 단일 종목은 4탭 렌더: 요약(현재가·목표주가·리비전·증가율·서프라이즈 + 최신 리포트 1건) / 기업정보·가치(PER·PBR·EPS·BPS·ROE·영업이익·52주·유통비율·외국인) / 성장성·컨센서스(매출/EPS 증가율·목표주가·투자의견·추정PER〔현재PER 병기〕·목표가 리비전·서프라이즈) / 투자리포트(최근 증권사 리포트 목록, 목표가 ▲상향/▼하향). 탭은 모달 전용 클래스(.info-tabs/.info-tabbtn/.info-tabpanel + data-info-tab/data-info-panel)와 독립 핸들러로 자산탭 .sub-tab과 격리(전역 restoreSubs 충돌 회피). 항목별 ⓘ 탭 팝업 설명(INFO_SPECS/INFO_DESC, document 위임 .info-label). 비교 모드(여러 종목)는 탭 없이 기존 비교표 유지. ETF 등 데이터 없으면 해당 탭 "데이터 없어요".

    메모 모달 (note-modal)(2026-06-26) — 보유·관심·감시종목 행 모두에 📝 메모 버튼. 클릭 → 팝업 textarea(최대 1000자, 여러 줄)에 기존 메모 prefill → [저장]은 /notes/set POST(submit 핸들러가 note-form을 fetch로 가로채 현재 탭 유지 — 네이티브 폼이면 303→/ 리다이렉트로 자산정보 탭으로 튐) 후 패널 새로고침, [삭제]는 버튼 왼쪽 위 작은 확인 팝업(예/아니오) 후 빈 텍스트 submit으로 항목 제거(오삭제 방지, note-confirm). 메모 있으면 버튼이 📝 메모 ● 노란 강조(has-note)+hover 툴팁. 저장소 state/behive_stock_notes.json({by_code, by_name}, code 우선→name fallback, stock_tags와 동일한 fcntl lock·atomic write). 종목 단위 공용(계좌 분리 X). 백엔드 _load/_get/_set_stock_note·_note_button_html·_render_note_modal, 태그 모달 패턴 복제.

  • send_balance_to_budget.py — 매월 1일 04:30 launchd. 본인+가희 계좌를 소유자별(self/gahee)로 잔액·예수금·평가액 집계해 agents/budget/inbox/incoming/에 envelope(topic: securities_balance, schema v2 by_owner)로 떨어뜨린다. 골디가 self→증권(효원)·gahee→증권(가희)로 reconcile 분개. 골디 월간 결산(05:00) 입력. LLM 미경유, 실패 시 레이 텔레그램으로 자가 알림.

  • trade_journal.py — 종목별 매매 기록 누적. 키움 REST에 기간 거래내역 API 부재 → 평일 21:00 launchd(NXT 야간 마감 후)로 ka10170 4계좌 호출해 state/trade_journal.jsonl에 적재. (date, account) 단위 idempotent, 휴장일/주말 self-skip(--force로 우회). 적재 시작일 2026-05-13 이전 보유분은 seed 명령(1회)으로 현재 평단가×(보유-당일매수+당일매도) 단일 행으로 압축 적재됨(seed=true 플래그·* 마커). CLI: collect [--date YYYYMMDD] / seed / show <code|name> / query [--from --to --account --code]

  • market_indicators_sync.py — 시장 단위 ADR·투자자별 매매 누적. 네이버 m.stock /api/index/{KOSPI|KOSDAQ}/integration 한 콜로 dealTrendInfo·upDownStockInfo 수집 → state/market_indicators_history.jsonl. (date, market) 단위 idempotent, 휴장/주말 self-skip(--force). 평일 21:00 stock.trade-journal launchd에 통합 발화 (별도 plist 없음). KRX 정보데이터시스템은 응답 패턴 변경으로 백필 보류 — 매일 누적만 시작. behive_web 자산정보 탭의 시장정보 sub-tab이 sparkline 데이터원으로 사용

  • sim/ (스크립트 아닌 별도 패키지agents/stock/workspace/sim/) — 자동매매 시뮬레이션(페이퍼 트레이딩) 엔진. 실주문 orders/와 완전 분리, 가상자본 1억으로만 동작(INITIAL_CAPITAL, 2026-06-10 1천만→1억). 구성: config.py(파라미터)·indicators.py(SMA/RSI/ATR/고저/거래량 순수함수)·universe.py(누적 관찰목록 state/sim/watchlist.json — 비하이브 워치+관심+본인보유를 매 스캔 자동 편입하되 자동 삭제 X(수동만). sync_watchlist/add_manual/removedata.py(시세 batch·일봉 캐시 우선·수급 60m캐시·애널〔fnguide/wisereport 12h 캐시, 캐시 미스 때만 0.4s 페이싱으로 연속 크롤링 차단 회피〕)·signals.py(진입/청산 규칙 + 손절·목표 계산 + dashboard용 체크리스트)·portfolio.py(가상 체결·비용·손익·MDD)·engine.py(스캔 오케스트레이션 — _gather(extra_codes)보유 종목은 관찰목록에서 빠져도 청산 추적benchmark.py(기준지수 대비 알파 — 네이버 m.stock 지수 일별종가를 state/sim/index_history.json에 누적〔KOSPI/KOSDAQ, pageSize≤50, 구간 등락률·초과수익 계산. 스캔마다 update_today 1회 갱신, 실패 무시)·__main__.py(CLI)·sim_web.py(별도 대시보드 서버 18792). 전략: 방향=애널 약한게이트+가점, 타이밍=수급·기술. ETF/ETN은 자동매수 제외(2026-06-09 — 방향성 엔진인 애널 컨센서스가 ETF엔 None이라 전략 부정합. universe.is_etf()가 운용사 프리픽스(KODEX/TIGER/ACE…)로 판별, engine 미보유 매수 분기 직전에 ETF — 자동매매 제외 SKIP. 보유 ETF는 청산까지 추적(매수 분기 전 처리라 무관)). 매수=거래량+전고점 돌파 즉시 / 평소 눌림목(max(20일선, 전일종가−ATR)) 지정가. 시장 국면 필터(6단계): market_regime_map()이 상승비율(폭)+지수추세(방향, 20일선)+당일등락(강도)을 조합해 engine.REGIME 6단계로 분류 — 🔥강세·📈반등(상승비율↑ & 지수 20일선 아래=약세탈출)·🌤완만상승 / 혼조·📉약세·❄️급락. 앞 3개=매수허용, 뒤 3개=보류(market_ok_mapREGIME[g][2]로 파생). 상승비율은 항상 네이버 실시간(_live_breadth 60s 캐시, 실패 시 EOD). 약세장이어도 돌파 진입은 허용, 눌림목만 보류(soft gate). 시장탭에 국면 배지+설명 표시(매수판단과 동일 소스). code_market_map()이 종목→KOSPI/KOSDAQ 매핑. (2026-06-09 강세/약세 2단계→6단계 국면으로 세분화) 2026-06-09 4종 추가: ⓐ 리스크 기반 사이징(signals.target_value — 수량=자산×RISK_PER_TRADE_PCT ÷ 손절폭, 균등비중 자산/MAX_POSITIONS 상한 캡, 0=끔. 변동성 큰 종목 자동 축소·종목당 리스크 균등화. 엔진·백테스트 공용) ⓑ RSI 필터(indicators.rsi 활성화 — 돌파 시 RSI_OVERBOUGHT↑ 과열 추격 보류 / 눌림목 시 RSI_OVERSOLD↓ 낙하 중 보류, 데이터 없으면 통과) ⓒ 시장 국면 6단계(market_regime_mapengine.REGIME, 위 시장 국면 필터 참조. _index_trend_ok·_index_daily_change 보조. ⚠️2026-06-09 강세/약세 2단계가 84% 반등일을 약세로 오판해 6단계 국면으로 세분화) ⓓ 시간손절(MAX_HOLD_DAYS 경과 & 미진전〔트레일링 전+진입가 이하〕 시 청산해 자본 회전, evaluate_holding(held_days) — 엔진=달력일·백테스트=entry_date 달력일). ⓖ 스캔 메모 4종(2026-06-10): 변이 수가 늘어도 스캔이 선형 폭증하지 않게 — 호가(data._BOOK_MEMO, 체결 공정성 겸용)·일봉(engine._SCAN_CANDLES)·지표(engine._IND_MEMO, (code,지표파라미터) 키)·수급/애널(data._FLOW_MEMO_SCAN/_ANL_MEMO_SCAN)을 스캔 1회 동안 공유, _gather가 매 스캔 리셋. 핵심은 애널 캐시 stale 시 0.4s 페이싱이 변이 수만큼 반복되던 것 — 108계좌 판단 38s→2s. ⓕ 2026-06-10 코드리뷰 3종: 재진입 쿨다운(전량청산 종목 당일 재매수 금지Portfolio.last_exit/exited_today, backtest 동일 규칙. 휩쏘 churn 방지)·장중 거래량 환산(_session_elapsed_frac 0.151.0을 ind['vol_time_frac']로 주입 → signals가 돌파 거래량·회전율을 하루치로 환산 비교, '(환산)' 표기. 이전엔 오전 돌파가 구조적으로 불가했음. backtest는 1.0=무영향)·일별 성과이력(state/sim/equity_history.json — 매 스캔 당일 항목 덮어써 EOD값 보존, {date:[{id,ph(파라미터해시),equity,ret}]}. 변이 id 재사용돼도 ph로 식별. 국면별 사후분석용) ⓔ 추세 질 보강(2026-06-09 trend_ok 게이트 강화: 기존 현재가>20일선+정배열(5>20)에 더해 ①20일선 우상향 기울기sma_long_slope_up, TREND_SLOPE_DAYS전 대비〕 ②중기 정배열 5>SMA_MID(60) — 둘 다 종목데이터라 백테스트 반영, 데이터 부족 시 통과. ③상대강도rel_strength=종목−지수 REL_STRENGTH_DAYS(20)일 수익률, engine이 주입하는 라이브 전용, 백테스트 None=중립, 체크표시만〕). 분할매수·추격매수: 목표비중을 ENTRY_TRANCHES(기본 3)로 나눠 1/3씩 진입, 직전 진입가+ATR×ADD_ATR_MULT 돌파 & 추세 지속 시 다음 트랜치 추가매수(평단 가중평균, 손절 위로만 래칫)·트레일링/일부익절 시작 후엔 추가 종료. 매도=손절(max(진입−ATR×2, 10일저점))·분할매도(목표 도달 시 SCALE_OUT_FRAC(기본 50%) 익절 후 잔량 트레일링(고점−ATR×1.5))·추세수급 이탈 시 전량 청산. 부분매도는 closed/win 미카운트(전량 청산 시만 카운트). 결정론적(LLM 미경유). 기준지수 대비(알파): 가상계좌/백테스트 수익률을 같은 기간 KOSPI·KOSDAQ '매수후보유' 대비로 평가(수익률만으론 지수 못 이기면 무의미하므로). 라이브는 계좌 시작일오늘, 백테스트는 윈도우 구간 대비. KPI '코스피/코스닥 대비(알파)' + 백테스트·비교 탭 알파 행. 경과기간 0(시작 당일)·캐시 부재 시 None('데이터 없음'). 상태 state/sim/{portfolio.json,trades.jsonl,last_scan.json,index_history.json}. CLI: python3 -m sim {scan [--force]|status|report|reset --yes|sweep [frac]|backtest|backfill [--pages N] [--force]|backfill-index [--pages N]|variants {seed N|list|reset|clear}} (cwd=workspace). launchd stock.sim-scan(15분)·stock.sim-web(상시).

    • 체크리스트 라벨 동적화(2026-06-15): 추세(N일선 위)·정배열(5>N)의 N은 **변이별 config.SMA_LONG(10/20/40)**을 읽어 표기. 이전엔 "20"으로 하드코딩돼 SMA_LONG=10/40 변이도 "20일선"으로 거짓 표기됨(차트의 5>20 정배열과 어긋나 보이던 원인). 하드코딩이 signals.py(buy_signal·evaluate_holding·trend 보강)와 engine.py 추세미충족 분기 두 곳에 있었음. ⚠️ 과거 trades.jsonl 판단근거는 거래 시점 baked라 옛 라벨 잔존(새 거래부터 정상). 라이브 판단은 judge_view가 변이 params 적용 후 계산하므로 즉시 정확. 추세 체크리스트는 signals.trend_checks(ind)로 추출해 매수판단·제외(SKIP)카드 공유(2026-06-15 — 제외 카드가 추세/정배열 2개만 보여 ①②통과인데 왜 SKIP인지 헷갈리던 것 → 4조건〔현재가>장기선·정배열·장기선 기울기·중기정배열〕+상대강도 전부 표시).
    • 즉시매수 토글 + 40일선 제거(2026-06-15): IMMEDIATE_ENTRY(기본 0) — 추세·정배열·수급·애널 다 통과한 종목이 돌파·눌림목 둘 다 아니어도(=안 내려오는 상승 종목) 강세장·RSI정상이면 현재가 즉시 매수(signals 눌림목 WAIT 직전 분기, buy_path='immediate'). 꾸준한 상승 놓침 방지. 40일선 추세선 제거(어중간·관리자님 지시, 스윕 GRID도 [10,20,60]). 변이: 40 72 후, 백테스트 검증 결과 즉시매수가 명확히 불리(전체기간 10/20/60 모두 즉시ON이 수익률 1/3·승률 −10~25%p·PF 반토막·MDD↑ — 눌림목/돌파 기다림 규칙이 핵심 알파). 그래서 즉시매수는 라이브 강세장 한정 확인용 3개만(10/20/60 안정·보수게이트) 유지 → 총 219개(비즉시216+즉시3). 즉시매수는 GRID 미포함이라 백테스트 기본은 OFF(검증은 위 수동 비교로 수행). 웹 초록 즉시 칩(_immediate_chip_html)·드롭다운 [안정 즉시]. ⚠️ 기존 216은 IMMEDIATE_ENTRY 기본 0이라 불변.
    • 물타기(애버리징) 토글(2026-06-16): AVERAGING_ENTRY(기본 0)·AVERAGING_DROP_PCT(0.10)·CRASH_DROP_PCT(0.10). 켜면 보유 중 직전매수가 대비 -10% 하락 시 손절 대신 추가매수로 평단↓(종목당 10% 한도=ENTRY_TRANCHES 분할). 가드: 당일 -10%↓ 급락=물타기 금지·손절(그림 #3), 약세장(market_ok=False)=물타기 금지(그림 #4). 첫 매수는 기존 검증 진입(추세·정배열+돌파/눌림목) 그대로 — "우량주만 물타기". evaluate_holding(market_ok) 0번 분기, add_kind='down'이면 손절선을 낮아진 평단 기준으로 재설정(추격매수 up은 위로만 래칫, engine·backtest 공용). 백테스트 검증: 즉시매수와 반대로 유리(10/20/60 모두 수익·승률↑, MDD 비슷 — 우량주+10%한도+급락손절 가드 덕). 라이브 변이 3개 추가(v301/302/303=10/20/60 안정·물타기ON) → 223개. 웹 노랑 물타기 칩(_avg_chip_html). ⚠️ 백테스트는 시장중립이라 약세장 가드 미반영 — 진짜 하락장은 라이브 검증.
    • 추세선 60일 추가(2026-06-15): 스윕 GRID SMA_LONG에 60 추가([10,20,40,60], 1152→1536조합). 60일선 상위 12조합 × 약세대처3 × 진입게이트2 = 72변이 추가 → 총 288개(10/20/40/60 각 72). ⚠️ 60일선은 base 정배열(5>60)이 중기게이트(SMA_MID=60, 5>60)와 동일 — 중기게이트가 추가 필터링 없음(무해, 관리자님 인지·승인). ⚠️ 스윕 첫 실행이 워커 조용히 죽는 일회성 deadlock(메인 SN 0%CPU·워커0) → kill 후 재실행으로 정상화. 장중엔 sim-scan/web과 CPU 경쟁으로 20분+ 소요.
    • 추세 게이트 완화 토글(2026-06-15): TREND_SLOPE_GATE·MID_ARRAY_GATE(기본 1=현행). trend_okgetattr로 참조 — 0이면 장기선 우상향/중기정배열(5>60) 게이트 미적용. 보수성(3거래일 매수 2건, 추세미충족이 비ETF의 93% 차단) 완화 실험용. 완화 변이(2026-06-15 최종: 기울기 게이트만 OFF, 중기정배열(5>60)은 유지TREND_SLOPE_GATE=0, MID_ARRAY_GATE=1. 관리자님: "중기정배열은 살려야지". 144개 완화변이 전부 이 규칙, 계좌 초기화). 웹: 보라 완화 칩(_relax_chip_html)·드롭다운 [안정 완화]. trend_checks가 게이트 OFF 조건을 ok=None('게이트 끔')로 표기. ⚠️ TUNABLE에 추가돼 기존 108개는 apply_params에서 기본 1(현행)로 적용돼 불변.
    • 런타임 튜닝: config.TUNABLE 29개 파라미터(분할매수 횟수·추격 ATR 배수·분할매도 익절 비율·종목당 리스크 비율·RSI 과열/과매도 컷·시간손절 일수·약세장 매수모드BEAR_ENTRY_MODE 0현금화/1돌파만/2눌림허용, signals에서 market_ok False일 때 분기, backtest는 market중립이라 무영향, 병렬변이로 라이브 비교〕 포함)를 state/sim/params.json로 오버라이드(웹 튜닝 탭에서 저장). config import 시 기본값 위에 덮어써 엔진이 다음 스캔부터 반영. config._DEFAULTS가 원본 기본값. load_params/save_params/reset_params.
    • 백테스트·스윕 (backtest.py/sweep.py): signals.py 그대로 재사용해 과거 일봉 되감기(지표 t까지·종가체결·애널 중립·수급은 flow_history 사용). sweep은 9파라미터(SMA_LONG·RR·STOP_ATR·PULLBACK_ATR·VOLUME_BREAKOUT + 신규 RSI_OVERBOUGHT·RSI_OVERSOLD·MAX_HOLD_DAYS·RISK_PER_TRADE_PCT) 1152조합을 학습/검증(out-of-sample 0.7) 분리 비교 (애널·시장필터는 backtest 중립이라 스윕 제외) → state/sim/backtest_results.json. 체결 현실화(2026-06-10): backtest가 당일 종가 판단→다음날 시가 체결(pending 주문 큐, look-ahead 제거) + BT_SLIPPAGE 0.2%(매수 비싸게/매도 싸게). 체결 낙관분 5%p 제거 확인. 거래 없는 날 주문은 소멸(신호 지속 시 재큐잉). 3분할 꾸준함 순위(2026-06-10): 전체기간 3분할 구간별 수익(windows/worst_ret)을 측정, 순위 1순위=최악구간 수익(한 구간 운빨 배제)·2순위=검증수익. 웹 행에 '구간별 검증(3분할)' 표시. 멀티프로세싱(2026-06-10): sweep이 조합을 코어에 분배(get_context('spawn'), 워커=코어−2). 일봉·수급은 _hist_cached/_flow_cached 프로세스 메모이즈로 종목당 sqlite 1회만 읽음. **44분 → 약 57분**(10코어 기준). 데이터는 이미 sqlite 캐시 전용(키움 API 0회) — 병목은 네트워크가 아니라 지표 재계산(파이썬). spawn이라 워커가 메인 재import하지만 sim/__main__.py 가드로 안전. ⚠️ GRID 늘릴 때 곱셈 폭발 주의. ⚠️ 종가체결·현 워치리스트(생존편향)라 절대수익 아닌 상대순위로만 해석. 2026-06-09 스윕: 핵심 레버는 VOLUME_BREAKOUT=1.3(거래량 문턱 낮춤, 중앙 +19%) — 신규 4종은 강세 검증창에선 미미(RSI·시간손절=하락장 보험). 적용 균형값 params.json 저장(RISK 0.01 보수 유지, 0.02 고수익은 강세장 레버리지라 채택 X).
    • 수급 백필 (backfill_flow.py): ka10059 연속조회로 종목별 투자자 순매수 다년치(기본 6페이지≈2.4년) → state/sim/flow_history.sqlite(code,date,foreign_net,inst_net,indiv_net 천주). idempotent·rate limit 페이싱+429 백오프. backtest가 이 DB로 수급(외/기) 반영 (없으면 중립). 2026-06-08 54종목 3만행 1회 적재 완료.
    • 병렬 페이퍼 (variants.py + engine.scan_all): 스윕 상위 튜닝들을 각자 가상계좌(state/sim/variants/<id>/)로 실시간 동시 운영 → 비교(variants_compare.json). scan_all이 라이브 데이터 1회 수집 후 메인+모든 변이를 같은 시세로 평가(_gather+_run_scan 분리, Portfolio가 경로 인자 받음). 변이는 애널 게이트까지 실반영(백테스트가 못 보는 부분). variants seed N은 backtest_results 상위 N개 등록. launchd sim-scan은 이제 scan→내부적으로 scan_all 실행(메인+변이 매 스캔 갱신, 트리거·명령 동일).
    • 웹 3메인탭(sim_web — 전략/관심종목/시장 순, 기본=전략·비교. 기준전략(M) 폐지(2026-06-10): scan_all의 메인 패스는 execute=False 판단 전용(last_scan=화면·상태점용, 메인 계좌 매매 동결), 실매매·비교는 변이 36개만. sync_label_tops 메인 제외 규칙 삭제(유형별 1위 전부 변이). 비교탭 행마다 마킹 아이콘 피커(2026-06-10 ☆토글→6종 아이콘 🔥💎🎯👀🚀 선택, FAV_ICONS/favorites.json{아이콘: vid}아이콘 하나당 전략 1개(다른 전략에 쓰면 이동)·전략당 아이콘 1개. 칩 클릭→바텀시트 피커→POST /fav_set(fetch). 구버전 list는 자동 마이그레이션), 관심종목 탭 기본 시각 = 첫 마킹(FAV_ICONS 순) → 없으면 1위 변이. 약세모드 단어 칩(2026-06-10): 비교 행 vid 옆 + 드롭다운 + 펼침 body '약세장대처' 행에 회피(0 현금화)/안정(1 돌파만·기본, 2026-06-11 '돌파'→'안정' 개명 — 적극과 혼동)/적극(2 눌림허용) 색 칩(_BEAR_WORD/_bear_chip_html, 클릭 시 설명 토스트. 아이콘→단어는 관리자님 요청). 전략 이름 = 4카테고리 두글자(2026-06-15 _cat_name/_cat_labels — 추세〔민감10/표준20/둔감40/장기60〕·진입〔적극 vol≤1.5/신중〕·매도〔한방 RR≥2.5/균형/단타 RR≤1.5〕·베팅〔집중 risk≥2%/분산〕. 예 '표준·적극·균형·분산'). 비교 행·드롭다운·상세 헤더에 적용. 펼침/상세에 _cat_detail_html 4요소 풀이(라벨+실제값+쉬운설명). 긴 문장형 _market_fit_summary(상승장에 강한…)는 '시장적합' 행 ⓘ로 유지. bt매칭은 _btkey(swept_params만) — BEAR_ENTRY_MODE 등 백테스트 중립 키가 params에 있어도 같은 bt행에 매칭(모드 3형제는 bt순위 공유, 백테스트 탭은 36종만 표시가 정상). 헤더 상태점 자산줄은 '전략 N개 · 평균/1위 수익률'. 2026-06-10 내계좌 탭 삭제〔계좌 정보는 비교탭 메인 행으로〕·튜닝 보조탭 삭제〔params 변경은 백테스트 "이 튜닝 적용"으로만, /save_params 리다이렉트도 s=bt〕. 탭 라우팅 ?t=+보조탭 ?s=, 레거시 t=acct/tune→lab): 헤더 타이틀 옆 시뮬 상태점(_engine_status#health 점: 🟢 장중 가동(최근 스캔 ≤12분)·🟡 장외 대기·🔴 장중 멈춤 의심, 클릭 시 상태 토스트). 관심종목(종목별 신호 체크리스트 + 각 평가항목 ⓘ 버튼 → 쉬운 설명 토스트_CHK_HELP/_chk_key/_CHK_HELP_JS, 바텀시트 #chk-toast, 열려있으면 자동새로고침 멈춤〕 + 상단 종목 추가 폼〔코드/이름〕 + 카드별 ✕ 삭제〔수동만, 보유 중이면 청산 추적〕 + origin 라벨〔워치/관심/보유/수동〕 + 미스캔분 '스캔 대기' 표시) · 시장(지수·ADR·상승하락·투자자 순매수 — 항상 네이버 m.stock 실시간_get_live_market 60s 캐시, market_indicators_sync.fetch_market 재사용. 네이버가 장 마감 후에도 당일 최종값 제공하므로 세션 무관 최신 사용〕, 조회 실패 시에만 market_indicators_history.jsonl EOD 폴백. note는 장중='장중 실시간'·장외='직전 장 마감 기준'. 2026-06-09 초기엔 장중만 실시간이라 마감 후 어제 EOD를 보이던 빈틈을 항상-실시간으로 수정) · 전략(2026-06-11 보조탭 버튼 제거 — 기본=비교만 표시, 백테스트는 비교 타이틀 우측 [📊 모의결과보기] 라벨(라디오 sub-bt 토글)로 진입·bt 패널 상단 [← 비교로]로 복귀. 그 옆 [📋 거래목록](sub-day/_day_trades_panel(sel_date) — 전 전략 거래를 달력형 날짜 선택(_DAY_CAL_JS — 거래일만 밝게·클릭가능, 비거래일 어둡게, 월 이동 JS 클라이언트〔범위 밖 ‹›disabled〕, 오늘 강조. 컴팩트 max-width 300px. 날짜 클릭 시 달력 안 닫고 fetch로 #day-rows·#day-sub·라벨만 갱신history.replaceState로 ?d= 보존〕, 별도 [닫기] 버튼. 접이식 details, 기본=오늘(거래 없어도 자동선택·클릭가능, today-open 점선 셀), 2026-06-15. 빈 날도 #day-rows 컨테이너 유지해 fetch 전환 정상)으로 (종목,방향)별 아이템(같은 종목 매수·매도 동시면 2아이템 분리, 요약=종목명+🟢매수/🔴매도 배지+전략수)으로 집계: 전략수·전략번호칩(상세링크)·가격대·평균손익·사유. 날짜는 simURL이 &d=로 보존). ?s=bt 라우팅·60s 새로고침 라디오 보존은 유지. 구성 2: 백테스트유형별(세부 라벨 ~36종) 대표 요약 — 2026-06-10 단순화: 시장 성격별 그룹(상승장/추세장/조정장/출렁이는 장/보통 장에 강한 유형) 안에 각 유형 1위만 표시(꾸준함=worst_ret 순), 행=제목+최악·검증수익, 펼치면 구간별 검증·MDD·승률·PF·알파·파라미터·🌐. 비교군 추가/제거·이 튜닝 적용 버튼 제거(읽기전용) — variants.sync_label_tops()수동 전용(2026-06-10 자동 동기화 끔 — sweep은 결과 파일만 갱신, 비교군 변경은 관리자님 명시 요청 시 python3 -m sim variants sync 또는 코디가 수동 등록)(같은 params 변이는 계좌 유지·신규 추가·탈락 삭제, 메인 조합 제외). 메인 변경은 코디/CLI로만. + '↻ 다시 계산'〔백그라운드 sweep — 결과 파일만 갱신, 비교군은 불변〕〕/비교〔병렬 변이 실시간 성적, 변이별 성적초기화/삭제 + 전체 삭제(메인 제외) /variants_clear_allvmod.clear(). 펼침 body 첫 행=유형(긴 문장형+ⓘ→🌐 시장적합 토스트, 2026-06-10 하단 🌐 버튼 대체)→둘째 행 약세장대처(돌파 (기본) 모드명만+ⓘ 토스트). bt 등록근거 행은 모의평가로 개명(1행 N위/36+2행 최악구간·검증, 모드 3형제는 _btkey로 같은 bt행 공유). 전략 상세 페이지(2026-06-11): 행 펼침 [📈 자세히보기] → GET /strategy?id=vN 독립 페이지 — 일별 수익률 SVG 차트(equity_history id+ph 매칭, KOSPI 같은 구간 점선 오버레이) + 결정론 종합 코멘트(순위·알파·과최적 경고) + 현재 성적·모의평가·전략 성격·약세장대처·파라미터 표(_TUNE_HELP 라벨)·보유/관심/거래. 평가순 정렬은 고유번호 오름차순(#1→#108). 행 표기(2026-06-10): 순위 배지 N위가 앞, 고유번호는 #N(_vid_disp — 'v37'→'#37' 표시 전용, 내부 id·URL은 raw. 드롭다운·👁토스트·사유 라벨 동일 표기)〕). 🌐data-detail 통합 토스트 핸들러로 헤더 상태점(#health)과 공유. sticky 헤더, 당겨서 새로고침. 새로고침 상태 보존(2026-06-10): 60s 자동새로고침이 전체 리로드지만 펼침(details open)·스크롤을 sessionStorage(simOpen/simScroll, key=패널id+summary텍스트)로 저장·복원해 보던 화면 유지. 입력 중·토스트 열림엔 새로고침 멈춤. 탭 보존(2026-06-11): 탭/서브탭 라디오 변경 시 URL 즉시 동기화(window._simURL+history.replaceState) — 당겨서·브라우저·마킹저장 등 모든 리로드가 보던 탭에 착지. HTML 응답에 Cache-Control: no-store(Safari 휴리스틱 캐싱이 옛 JS를 재사용해 탭 복원이 안 먹던 문제). 깜빡임 제거(2026-06-12): 활성 탭/서브탭을 render_html(tab,sub)이 라디오 checked로 서버에서 미리 박음(GET이 ?t/?s 파싱+레거시 보정) — 이전엔 기본탭 렌더→JS가 로드 후 전환하며 깜빡였음. do_POST: /save_params·/run_sweep·/variants_{add,reset_one,remove,clear_all}·/watch_{add,remove}·/fav_set(마킹 아이콘 지정/이동/해제 → state/sim/favorites.json) (그 외 읽기전용)
  • Portfolio data: memory/portfolio.json (v2 스키마 참고용 스냅샷, accounts.{일반,ISA}.positions), state/portfolio_daily_snapshot.json, state/kiwoom_tokens/{일반,ISA}.json, state/stock_codes.json(키움 ka10099 lazy 캐시), state/watchlist_alerts.json(알림 중복 방지), state/ipo_calendar_sync.json, state/behive_*.json, state/fnguide_cache/{code}.json(FnGuide 펀더멘털 12h), state/wisereport_cache/{code}.json·{code}_reports.json(컨센서스 12h·리포트 6h), state/stock_reports/<code>/(분석 보고서 HTML)

Scheduled Jobs

OpenClaw 자동화는 두 갈래로 동작한다 (모두 Asia/Seoul):

Cron (cron/jobs.json, OpenClaw 에이전트 세션 — LLM 경유)

  • 오전 브리핑 (main) — Daily 07:30 — 뉴스 브리핑 메일 + 🇺🇸 미국증시 요약(@futuresnow). 영상이 아직 미게시면(KST 화~토 게시예정일) 발송 보류
  • 오전 브리핑 (fallback 0755) (main) — Daily 07:55 — 1차 폴백. 07:30에 미국증시 요약 미게시로 보류된 경우 재시도(여전히 미게시면 또 보류). already_sent로 idempotent
  • 오전 브리핑 (fallback 0830) (main) — Daily 08:30 — 2차 폴백·최종. prepare morning --final로 US 미게시여도 무조건 발송. 07:30·07:55에 정상 발송됐으면 already_sent로 스킵
  • 오후 브리핑 (main) — Daily 19:00 — 뉴스 브리핑 메일
  • 비하이브 종목분석 요약 (stock) — Weekdays 07/12/18시
  • 월간 결산 (budget) — 매월 1일 05:00 — 자산 변동 메일 + 골디 텔레그램

launchd (~/Library/LaunchAgents/ai.openclaw.*.plist — LLM 미경유, 직접 실행)

  • gateway — 상시 daemon (포트 18789)
  • claude-remote-control — on-demand daemon (코디 세션, claude-code-session 스킬이 띄움)
  • stock.behive-web — 상시 daemon (워치리스트 웹뷰, Tailscale 18790)
  • stock.briefing — 평일 20:10 — 일일 포트폴리오 리포트 메일
  • stock.briefing-fallback-2030 — 평일 20:30 — 오늘 스냅샷 없으면 stock.briefing 재실행 (idempotent)
  • stock.briefing-fallback-2100 — 평일 21:00 — 무조건 fresh fetch로 스냅샷 갱신 (briefing_fallback.py force → 스냅샷 있으면 stock_portfolio_report.py run 메일·텔레그램 X, 없으면 send 폴백 + 실패 시 알림). 20:10 데이터 부정확 케이스 보완용
  • stock.watchlist-monitor — 평일 10:00 / 12:00 / 14:00 — 워치리스트 buy/target/stop 알림 (2026-05-12: 15분 간격 → 3회로 축소)
  • stock.ipo-calendar-sync — 매주 금요일 17:00 — IPO 청약·상장 일정 캘린더 등록
  • stock.holiday-sync — 매주 일요일 03:00 — investing.com KRX 휴장일 → state/market_holidays.json (behive_web 자동갱신 토글이 참조)
  • stock.send-balance — 매월 1일 04:30 — 본인 잔액 → 골디 inbox (securities_balance)
  • stock.trade-journal — 평일 21:00 — EOD 데이터 누적 묶음. ProgramArguments는 /bin/sh -c wrapper로 세 명령 sequential 실행: ①trade_journal.py collect (ka10170 4계좌 → state/trade_journal.jsonl) ②market_indicators_sync.py collect (네이버 m.stock KOSPI/KOSDAQ ADR·투자자별 매매 → state/market_indicators_history.jsonl) ③cd workspace && python3 -m sim.backfill_flow --pages 1 --force (수급 DB flow_history.sqlite 일일 증분 — 2026-06-10 추가, 1회성 백필 후 stale해져 백테스트 수급게이트가 중립으로 비활성되던 문제 해소. INSERT OR REPLACE idempotent, 행수기준 skip이라 --force 필수) ④python3 -m sim universe all (2026-06-15 추가 — sim 관찰목록 자동편입+자동제외. 키움 순위정보 ka90009 외인·기관 순매수 + ka10023 거래량급증 상위에서 ETF·하락·급증률 이상치 제외하고 각 15개·총 120 상한 편입(origin='auto'), origin=auto·미보유·10거래일 무신호는 자동 제외. 보유·watch·interest·manual은 불가침. 신호추적은 scan_all이 universe.mark_signalsstate/sim/auto_seen.json에 기록). 하나 실패해도 나머지 시도. 로그는 logs/stock-trade-journal.{log,err.log} 한 곳에 합쳐짐.
  • stock.sim-scan — 평일 09:0015:30 매 2분 (StartCalendarInterval 196엔트리, 엔진이 장외/휴장 self-skip) — 자동매매 시뮬(페이퍼) 1회 스캔. (2026-06-09 15분→5분, 2026-06-17 5분→2분 단축 — 스캔 1회 실측 ~3.6초라 2분 cadence에 오버랩·rate limit 여유. 1분이 캘린더 트리거 한계지만 일봉 기반 신호라 2분으로 충분 판단) ⚠️ 2026-06-09 StartInterval 900s → StartCalendarInterval 전환: GUI LaunchAgent의 StartInterval은 세션 idle/디스플레이 sleep 시 timer coalescing으로 발화가 보류(pended)돼 장중에 안 도는 문제 발견 (calendar 잡인 git-autopush는 새벽 02:00에도 정상 발화하는 게 비교 증거). 월시간 기준이라 idle 지연 없음. python3 -m sim scan (cwd agents/stock/workspace). 가상자본 1억, 규칙 엔진(LLM 미경유). universe=누적 관찰목록(워치+관심+보유 자동편입·수동삭제), 방향=애널 약한게이트+가점, 타이밍=수급·기술. 결과 state/sim/. 실주문 orders/ 불가침. 상세는 아래 sim 모듈 섹션·레이 MEMORY.md
  • stock.sim-web — 상시 (KeepAlive) — 시뮬 대시보드 별도 서버 포트 18792 (behive-web 18790과 분리). python3 -m sim.sim_web serve. sim state 읽기전용 렌더. sim.hyowons.net → mac:18792 (Synology reverse proxy, 수동 등록 대기). ⚠️ 18791은 node 점유라 18792 사용
  • gmail-label-classify (main/클로) — 매일 01:00 — workspace/scripts/gmail_label_classify.py: self-sent 브리핑·종목분석·주식 리포트 메일을 Gmail 라벨로 자동 분류 + 24h 지난 테스트메일 휴지통 이동. LLM 미경유(gog CLI 직접 호출). 로그 logs/gmail-label-classify.{log,err.log} + 상태 state/gmail_label_classify.log. ⚠️ 2026-06-26 OpenClaw cron(main 01:00)에서 이관 — 본문 생성 없는 단순 스크립트라 모델 세션 불필요(TASKS.md §3-3 원칙)
  • git-autopush — 매일 02:00 — scripts/git_autopush.sh: 변경 있으면 git add -A + 자동 커밋 + git push origin main. 변경 없으면 skip(빈 커밋 X). 인증은 HTTPS + credential.helper=store(~/.git-credentials), GUI 키체인 불필요. 로그 logs/git-autopush.{log,err.log}. 워크스페이스 버전관리 백업용 (시크릿·sqlite는 .gitignore 제외라 별도 백업 필요)
  • budget.whooing-sync — 매시 0/15/30/45분 — iMessage 결제문자 → 후잉. 매 사이클 끝에 gahee_reminder.run 추가 호출 (매월 25일 10:00 KST 이후 가희님께 iMessage 리마인더 1회 발신 → 답신 폴링 → 텍스트면 후잉 가희주머니 차액 자동분개, 이미지면 골디 텔레그램 알림). 별도 plist 없음

Agent Inbox Convention

에이전트 간 데이터 hand-off는 파일 기반 inbox로만 한다. LLM-to-LLM 자연어 통신은 프롬프트 인젝션·할루시네이션 증폭 위험이 있어 금지.

디렉터리 구조 (수신자 소유)

agents/<recipient>/inbox/
  ├─ incoming/   ← 새 메시지
  ├─ processed/  ← 처리 완료 후 이동
  └─ failed/     ← 처리 실패 (스키마 오류·미등록 topic 등)

수신자는 자기 inbox를 책임진다 (정기 폴링·청소·감사). 송신자는 incoming/에 쓰는 것까지만.

Envelope (불변 — v1)

{
  "message_id": "uuid",
  "from": "stock",
  "to": "budget",
  "topic": "securities_balance",
  "created_at": "2026-04-26T20:10:00+09:00",
  "schema_version": 1,
  "payload": { ... }
}

파일명: <from>__<topic>__<isoTime>.json (정렬·검색 용이)

원칙

  • payload는 순수 데이터 — 자연어 지시문 금지 (프롬프트 인젝션 차단)
  • idempotency — 수신자는 message_id 중복 처리 안 함
  • 새 topic은 INBOX_TOPICS.md에 등록 필수 — 미등록 topic은 자동 failed/
  • 응답 필요 시 — 수신자가 송신자 inbox에 새 메시지 작성 (양방향 ack 메커니즘 없음)
  • GCprocessed/는 30일 후 정리, failed/는 사람이 검토해서 수동 삭제

상세한 topic 스키마와 운영 규칙은 INBOX_TOPICS.md 참조.

Cody Inbox (agents/cody/inbox/)

코디는 OpenClaw 에이전트가 아니지만 한 가지 예외로 inbox를 가진다. 에이전트가 자체 개선한 결과를 코디에게 검증·후속 개선 위탁하는 단방향 채널이다.

  • 토픽: improvement_review (스키마는 INBOX_TOPICS.md)
  • 자연어 허용 예외: payload summary/rationale/self_review_notes/concerns[].question은 자연어 OK. 단 "X 해줘" 류 지시문 금지, 사실·관찰·우려만
  • 처리 흐름:
    1. 코디 세션 기동 시 incoming/ 개수만 확인 → 1개 이상이면 한 줄 알림 ("📥 코디 인박스에 N개 처리 대기 중입니다.")
    2. 관리자님 명시 요청 전엔 상세 보고·검증·개선 시작 X — 자동 처리 금지
    3. 관리자님이 "검증 큐 확인해줘" 등 호출하면 그때 envelope 상세 요약 → 우선순위 위임
    4. 코디가 changed_paths 검증 → 필요 시 직접 개선 (위험 작업은 별도 컨펌)
    5. envelope을 processed/로 이동, 같은 basename + _report.md에 검증 결과·후속 개선·잔여 위험 기록
    6. GC (같은 시점): processed/의 mtime 7일 초과 항목을 trash로 정리 (envelope JSON + report MD 짝으로). failed/는 손대지 않는다
    7. 스키마 위반은 failed/로 이동 후 관리자님에게 보고
  • 헬퍼 미정: 송신측은 에이전트가 직접 envelope JSON 작성. 패턴 굳으면 추후 추출
  • 회신 envelope 없음: 결과는 processed/의 report 파일로만 남는다. 송신 에이전트가 후속 사이클에서 직접 조회

Communication Rules

  • Respond in Korean (한글)
  • Use polite speech (존댓말)
  • Address the owner as 관리자님
  • End responses with status on a new line: [진행중] or [답변완료]
  • Keep responses short, action-oriented, result-first
  • Avoid unnecessary explanation — How > Why
  • Use trash over rm for deletions

Coding Behavior Rules

LLM 흔한 실수를 줄이기 위한 행동 규칙. 사소한 작업은 판단으로 생략 가능하지만, 불확실하면 caution 쪽으로 기운다.

1. 코딩 전에 생각 (Think Before Coding)

가정하지 말고, 혼동을 숨기지 말고, 트레이드오프를 드러낼 것.

  • 가정은 명시적으로 말한다. 불확실하면 질문한다.
  • 해석이 여러 개면 전부 제시한다 — 조용히 하나 고르지 않는다.
  • 더 단순한 길이 보이면 먼저 말한다. 정당하면 반박한다.
  • 모호하면 멈춘다. 무엇이 헷갈리는지 이름 붙이고 묻는다. (선택지는 AskUserQuestion)

2. 단순함 우선 (Simplicity First)

문제를 푸는 최소 코드. 추측성 코드 금지.

  • 요청 범위를 벗어난 기능 X
  • 1회용 코드의 추상화 X
  • 요청되지 않은 "유연성"·"설정 가능성" X
  • 일어날 수 없는 상황 대비 에러 핸들링 X
  • 200줄 짠 게 50줄로 줄겠다 싶으면 다시 쓴다.

자문: "시니어 엔지니어가 이거 과설계라 할까?" 그렇다면 단순화.

3. 외과적 변경 (Surgical Changes)

필요한 것만 건드린다. 자기가 만든 잔재만 정리한다.

  • 인접 코드·주석·포맷 임의 "개선" 금지
  • 안 망가진 것 리팩토링 금지
  • 다르게 하고 싶어도 기존 스타일 유지
  • 무관한 dead code 발견하면 보고만 — 삭제 X
  • 변경 때문에 생긴 import/변수/함수 orphan은 본인이 정리
  • 사전 존재하던 dead code는 요청 없이 삭제 X

테스트: 변경된 모든 라인은 관리자님 요청에 직결되어야 한다.

4. 목표 기반 실행 (Goal-Driven Execution)

성공 기준을 정의하고, 검증될 때까지 루프.

  • "validation 추가" → "잘못된 입력 테스트 작성 → 통과시키기"
  • "버그 고쳐" → "재현 테스트 작성 → 통과시키기"
  • "X 리팩토링" → "전후 테스트 통과 확인"

다단계 작업은 짧은 plan을 먼저 말한다:

1. [단계] → 검증: [확인]
2. [단계] → 검증: [확인]

강한 성공 기준은 독립적 루프를 가능케 하고, 약한 기준("동작하게")은 끊임없는 명세 요청을 부른다.