Files
openclaw/agents/stock/workspace/memory/2026-04-27.md
T
hyowons 549545bde6 Initial commit: OpenClaw 워크스페이스 버전관리 시작
설정·스크립트·스킬·문서·큐레이션 메모리 추적.
시크릿(credentials/identity)·런타임 상태(state/logs/sessions/sqlite)·
백업(clobbered/bak)·dream 캐시는 .gitignore로 제외.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 15:10:57 +09:00

7.1 KiB
Raw Blame History

name, description, type
name description type
2026-04-27 감시종목 웹 뷰 신규 + 종목분석 메일 등락 표기 수정 비하이브 종목분석 메일의 현재가 등락 표기를 매입가 대비로 정정. 감시종목 실시간 웹 뷰(`https://stock.hyowons.net/`)와 launchd 서비스 신규. project

1. 종목분석 메일 등락 표기 버그 수정

증상

관리자님이 받으시는 비하이브 종목분석 메일·텔레그램의 "현재가" 줄에 붙는 등락이 전부 +0원, +0.00%으로 잘못 표기됨.

원인

behive_youtube_digest.py:fetch_current_price가 키움 ka10001의 change/change_pct 필드(전일대비)를 그대로 출력. 관리자님 의도는 매입가(entry['buy']['primary']) 대비 등락이었음.

수정

  • fetch_current_price(stock, buy_price=None) 시그니처로 변경. buy_price 주어지면 (price - buy_primary, pct) 계산해서 ± N원, ± N% vs 매입가 표기. 없으면 가격만 표시.
  • _buy_primary(entry) 헬퍼로 {primary, raw, levels} dict에서 numeric primary 안전 추출.
  • 이메일 경로(format_entry_block) + 텔레그램 경로(format_telegram_block) 둘 다 매입가 전달하도록 수정.

검증: 워치리스트 7종목 전부 매입가 대비 정상 표기 확인 (예: 미래반도체 21,750원 (+2,750원, +14.47% vs 매입가)).

2. 감시종목 실시간 웹 뷰 신규

동기

관리자님이 매번 레이한테 "워치리스트 어떻게 됐어?" 물어보기 번거로워서 웹페이지로 보고 싶다 요청. 외부망에서도 폰으로 접근 가능해야 함.

결정 (대화 누적)

검토 사항 최종 결정 이유
정적 cron 푸시 vs 실시간 서버 실시간 Mac 서버 페이지 안 볼 땐 호출 0건이라는 관리자님 logic이 cron 모델과 안 맞음
자격증명 위치 Mac에만 유지 키움 자격증명을 NAS로 옮기지 않음. 워크스페이스 분리 원칙
인증 없음 read-only 페이지, 잔고 노출 없음(워치리스트만), 거래 권한 0. 위생 차원 noindex,nofollow + Referrer-Policy: no-referrer만 적용
URL 형태 서브도메인 stock.hyowons.net 폰 PWA 추가 시 깔끔, path 파싱 부담 0
외부 노출 경로 NAS reverse proxy 경유 NAS가 외부 노출(DDNS) 갖고 있어서 활용. Mac은 LAN/Tailscale 인터페이스만 응답

구현

  • scripts/behive_web.py (신규) — Python stdlib http.server. GET / 한 라우트. watchlist 읽고 키움 ka10001 병렬 호출(8 thread) → 카드형 HTML 반환. JS 0, 인라인 CSS만. 새로고침 버튼은 <a href="/">↻</a> (anchor — 페이지 GET이 곧 키움 새 호출).
  • ~/Library/LaunchAgents/ai.openclaw.stock.behive-web.plist (신규) — KeepAlive=true, ThrottleInterval=10, 부팅 자동 기동.
  • 모바일 UI: sticky 헤더, safe-area 처리, 40×40 터치 타겟, 720px 이하 1열 레이아웃, PWA 메타(apple-mobile-web-app-*, theme-color).

외부 노출 인프라

폰/PC → https://stock.hyowons.net/    (Cafe24 도메인)
        → CNAME → stock.hyowons.duckdns.org    (사용자 NAS DDNS)
        → 공인 IP 112.147.127.79 (NAS WAN)
        → Synology DSM reverse proxy
        → http://192.168.219.142:18790    (Mac mini LAN IP)
        → behive_web.py
  • 인증서: Synology Let's Encrypt — web.hyowons.net 인증서에 SAN으로 stock.hyowons.net 포함 (관리자님 발급 완료).
  • Mac 서버 바인딩: 0.0.0.0:18790 (모든 인터페이스). 외부망 직접 도달은 공유기 NAT 차단으로 보호.
  • macOS 방화벽: Application Firewall ON 상태에서 Python inbound 허용.

트러블슈팅 기록 (재발 방지용)

NAS → Mac 도달 실패 케이스를 겪었다. 진단 순서:

  1. macOS Application Firewall — Python 허용됐는지 (socketfilterfw --getappblocked /usr/bin/python3).
  2. Tailscale ShieldsUp — tailscale debug prefs | grep ShieldsUp 가 false인지.
  3. NAS 호스트 OS의 Tailscale 라우트 — Synology Tailscale 패키지가 컨테이너로 돌면 host shell에 100.64.0.0/10 라우트가 안 잡혀서 NAS의 일반 프로세스(reverse proxy nginx 포함)가 Tailscale IP로 outbound 못 함.
  4. 우회 방법(현재 채택): LAN IP 직접 사용192.168.219.142:18790 으로 reverse proxy 대상 지정. 같은 LAN 세그먼트라 라우팅 문제 0.

LAN IP 안정화는 공유기 DHCP 예약(192.168.219.142 고정).

3. 문서·메모리 갱신

  • 루트 CLAUDE.md — stock skills/scripts 섹션에 behive_web.py 추가
  • agents/stock/workspace/MEMORY.md — launchd 표에 ai.openclaw.stock.behive-web 등록 (상시 실행)

4. 운영 노트

  • "감시종목 페이지 어디서 봐?" 질문에는 → https://stock.hyowons.net/
  • 새로고침 = 키움 ka10001 호출 — 가만히 보고 있으면 키움 호출 0건, 새로고침 누르면 그 시점 가격으로 갱신.
  • 종목 추가 흐름은 변경 없음 — 비하이브 신규 영상 자동 감지 또는 수동 behive_youtube_digest.py add. watchlist.json 변경되면 다음 페이지 GET부터 자동 반영.
  • 카드 색상: 매입가 대비 +면 녹색 좌측 라인, -면 빨간색, 매입가 미설정 또는 0이면 회색.
  • "조회 불가" 카드: 키움 API 실패 시 그 종목만 fallback 표기, 나머지는 정상 렌더 (페이지 전체가 죽지 않음).

4-2. 감시 삭제 기능 (2단계) 추가

데이터 모델

워치리스트 entry에 status·pending_delete_at 필드 도입:

  • 없음 또는 "active" = 정상 감시중
  • "pending_delete" = 삭제예정 (UI에서 "삭제예정" 섹션, opacity 0.5로 흐리게)

웹 라우트 (behive_web.py)

  • POST /delete — status=pending_delete + pending_delete_at 기록
  • POST /restore — status/pending_at 제거 (active 복귀)
  • POST /purge — entry 완전 삭제 (onsubmit="return confirm()" 한 번 더 확인)
  • 모두 form-urlencoded stock=<종목명> 받고 303 → / redirect
  • 인증 없음 — 외부 접근 시 NAS reverse proxy + URL 비밀성에 의존, 2단계 자체가 안전망

충돌 방지 가드

위치 변경 이유
behive_youtube_digest.py:cmd_save 기존 entry가 pending_delete면 mark_seen만 하고 덮어쓰기 skip 비하이브 재분석으로 사용자 의도 무력화 방지
watchlist_monitor.py:run pending_delete entry는 continue로 스킵 삭제예정 종목에 buy/target/stop 알림 안 가도록

자동 삭제 트리거는 원래 없었음 (모니터·save 둘 다 read 또는 add only). 따라서 자동/수동 충돌은 위 두 가드만으로 해결됨.

UI 동작

  • active 종목 자세히 보기 → "감시 삭제" 버튼 → pending_delete로 이동 (페이지 하단 "삭제예정" 섹션에 흐리게)
  • pending_delete 종목 자세히 보기 → "복원" / "완전 삭제" 두 버튼. 완전 삭제는 confirm 다이얼로그 한 번 더.

매매 절대 원칙

  • 이번 작업은 read-only 조회 인프라 + 워치리스트 메타 관리(삭제). 매수·매도 함수 추가 없음. 웹 페이지에 거래 액션 버튼 절대 추가 금지 (조회 전용 원칙).