feat: include current holdings in realtime trading loop for exit evaluation (#165) #168

Closed
agentson wants to merge 1 commits from feature/issue-165-holdings-in-trading-loop into main
Collaborator

Summary

  • 실시간 트레이딩 루프에서 Smart Scanner 후보 종목 외에 현재 보유 종목도 포함하도록 변경
  • 스캐너에서 사라진 종목도 매 사이클마다 stop-loss / take-profit 평가 가능
  • '매수만 열심히 하는' 근본 원인 해결

변경 내용

src/db.pyget_open_positions_by_market() 추가

def get_open_positions_by_market(conn, market) -> list[str]:
    """Net BUY - SELL 집계로 실제 보유 종목 코드 반환"""
    cursor = conn.execute(
        """
        SELECT stock_code FROM trades WHERE market = ?
        GROUP BY stock_code
        HAVING SUM(CASE WHEN action='BUY' THEN quantity ELSE -quantity END) > 0
        """,
        (market,),
    )

단순 "최신 레코드 = BUY" 방식 대신 집계 쿼리 사용 → 봇 자신의 SELL 후 이중 매도 방지.

src/main.py — 실시간 루프 보유 종목 병합

scanner_codes = active_stocks.get(market.code, [])
held_codes = get_open_positions_by_market(db_conn, market.code)
stock_codes = list(dict.fromkeys(scanner_codes + held_codes))

동작 방식

보유 종목이 스캐너 후보에 없으면:

  1. Playbook에 해당 종목 entry 없음
  2. ScenarioEngine → HOLD 반환
  3. HOLD 블록에서 stop-loss / take-profit 체크 (기존 로직)
  4. 조건 충족 시 SELL 자동 실행

반박 에이전트 검토 결과 반영

지적 사항 대응
"최신 BUY" 조회의 이중 매도 위험 net_qty 집계 쿼리로 대체
외부 수동 매도 미감지 향후 이슈로 분리 (pre-existing 문제)
API 비용 증가 get_balance는 이미 각 사이클 호출 중, 추가 없음

Test plan

  • test_get_open_positions_by_market_returns_net_positive_stocks
  • test_get_open_positions_by_market_excludes_fully_sold_stocks
  • test_get_open_positions_by_market_includes_partially_sold_stocks
  • test_get_open_positions_by_market_is_market_scoped
  • test_get_open_positions_by_market_returns_empty_when_no_trades
  • 675 tests passed

Closes #165

🤖 Generated with Claude Code

## Summary - 실시간 트레이딩 루프에서 Smart Scanner 후보 종목 외에 **현재 보유 종목도 포함**하도록 변경 - 스캐너에서 사라진 종목도 매 사이클마다 stop-loss / take-profit 평가 가능 - '매수만 열심히 하는' 근본 원인 해결 ## 변경 내용 ### `src/db.py` — `get_open_positions_by_market()` 추가 ```python def get_open_positions_by_market(conn, market) -> list[str]: """Net BUY - SELL 집계로 실제 보유 종목 코드 반환""" cursor = conn.execute( """ SELECT stock_code FROM trades WHERE market = ? GROUP BY stock_code HAVING SUM(CASE WHEN action='BUY' THEN quantity ELSE -quantity END) > 0 """, (market,), ) ``` 단순 "최신 레코드 = BUY" 방식 대신 집계 쿼리 사용 → 봇 자신의 SELL 후 이중 매도 방지. ### `src/main.py` — 실시간 루프 보유 종목 병합 ```python scanner_codes = active_stocks.get(market.code, []) held_codes = get_open_positions_by_market(db_conn, market.code) stock_codes = list(dict.fromkeys(scanner_codes + held_codes)) ``` ## 동작 방식 보유 종목이 스캐너 후보에 없으면: 1. Playbook에 해당 종목 entry 없음 2. ScenarioEngine → HOLD 반환 3. HOLD 블록에서 stop-loss / take-profit 체크 (기존 로직) 4. 조건 충족 시 SELL 자동 실행 ## 반박 에이전트 검토 결과 반영 | 지적 사항 | 대응 | |---|---| | "최신 BUY" 조회의 이중 매도 위험 | net_qty 집계 쿼리로 대체 | | 외부 수동 매도 미감지 | 향후 이슈로 분리 (pre-existing 문제) | | API 비용 증가 | get_balance는 이미 각 사이클 호출 중, 추가 없음 | ## Test plan - [x] `test_get_open_positions_by_market_returns_net_positive_stocks` - [x] `test_get_open_positions_by_market_excludes_fully_sold_stocks` - [x] `test_get_open_positions_by_market_includes_partially_sold_stocks` - [x] `test_get_open_positions_by_market_is_market_scoped` - [x] `test_get_open_positions_by_market_returns_empty_when_no_trades` - [x] 675 tests passed Closes #165 🤖 Generated with [Claude Code](https://claude.com/claude-code)
agentson added 1 commit 2026-02-20 03:09:07 +09:00
feat: include current holdings in realtime trading loop for exit evaluation (#165)
Some checks failed
CI / test (pull_request) Has been cancelled
d19e5b0de6
스캐너 후보 종목뿐 아니라 현재 보유 종목도 매 사이클마다 평가해
stop-loss / take-profit이 실제로 동작하도록 개선.

- db.py: get_open_positions_by_market() 추가
  - net BUY - SELL 집계 쿼리로 실제 보유 종목 코드 목록 반환
  - 단순 "최신 레코드 = BUY" 방식보다 안전 (이중 매도 방지)
- main.py: 실시간 루프에서 스캐너 후보 + 보유 종목을 union으로 구성
  - dict.fromkeys로 순서 유지하며 중복 제거
  - 스캐너에 없는 보유 종목은 로그로 명시
  - 보유 종목은 Playbook 없으면 HOLD → stop-loss/take-profit 체크
- tests/test_db.py: get_open_positions_by_market 테스트 5개 추가
  - net 양수 종목 포함, 전량 매도 제외, 부분 매도 포함
  - 마켓 범위 격리, 거래 없을 때 빈 리스트

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Owner

이것도 db만 봐도 될까? 매수할때 주문량과 체결량이 다를 수 있고, 매도 후 결과도 마찬가지로 다를 수 있어. db 기록이 잔량과 언제든지 다를 수 있는데 언제 싱크되는지도 모르지 않아?

이것도 db만 봐도 될까? 매수할때 주문량과 체결량이 다를 수 있고, 매도 후 결과도 마찬가지로 다를 수 있어. db 기록이 잔량과 언제든지 다를 수 있는데 언제 싱크되는지도 모르지 않아?
agentson closed this pull request 2026-02-20 07:40:55 +09:00
Some checks failed
CI / test (pull_request) Has been cancelled

Pull request closed

Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: jihoson/The-Ouroboros#168