auto: 일일 백업 2026-06-27 02:00
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -84,6 +84,7 @@ Stock agent skills (`agents/stock/workspace/skills/`):
|
||||
|
||||
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_card`가 `overseas_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:20~08:30 KST, 예정=화~토) / `get_behive_market_summary()`=비하이브 투자자문(`UCHTRF5r154igU2gXjudUMzg`) '주식시황'(장전 시황, 05:40~06:50 KST, 예정=월~금) / `get_behive_close_summary()`=같은 채널 '마감시황'(장 마감 해설, 16:45~18: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`:
|
||||
@@ -96,7 +97,7 @@ Stock agent (`agents/stock/workspace/scripts/`), run with `python3`:
|
||||
- `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).
|
||||
- `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_multi` → `handler.propose_trade_multi`(레그별 독립 검증, SELL+LIMIT/MARKET 한정, 같은 그룹만) → **카드 1장+PIN 1개**(iMessage `매도(2계좌)`)가 두 레그 승인 → verify 시 `_submit_multi_legs`가 레그 독립 제출(idem_hash 계좌별 분리)·독립 fill_watcher, 한 레그 실패해도 나머지 시도(ok=하나라도 접수).
|
||||
|
||||
@@ -105,6 +106,8 @@ Stock agent (`agents/stock/workspace/scripts/`), run with `python3`:
|
||||
**신규 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. 본인 계좌(가희 제외)별 잔액·예수금·평가액을 집계해 `agents/budget/inbox/incoming/`에 envelope(`topic: securities_balance`)로 떨어뜨린다. 골디 월간 결산(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 데이터원으로 사용
|
||||
@@ -149,6 +152,7 @@ OpenClaw 자동화는 두 갈래로 동작한다 (모두 Asia/Seoul):
|
||||
- **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_signals`로 `state/sim/auto_seen.json`에 기록). 하나 실패해도 나머지 시도. 로그는 `logs/stock-trade-journal.{log,err.log}` 한 곳에 합쳐짐.
|
||||
- **stock.sim-scan** — 평일 09:00–15: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 없음
|
||||
|
||||
|
||||
Reference in New Issue
Block a user