Skip to content

refactor: shortcuts/strategies 경계 재정의 #35

@interruping

Description

@interruping

shortcuts / strategies 경계 재정의

Context

PR #34에서 shortcuts 네임스페이스가 도입되었으나, 기존 strategies에 전략이 아닌 편의 헬퍼(market_buy_krw, get_portfolio 등)가 섞여 있어 두 네임스페이스의 경계가 모호하다.

구분 기준: "매매 전략인가?" 로 나눈다.

  • shortcuts = API의 불편한 부분을 해결하는 편의 헬퍼
  • strategies = 매매 전략 (dca, rebalance, price_alert)

변경 후 구조

shortcuts/                      # API 편의 헬퍼
├── __init__.py                 # SyncShortcuts, AsyncShortcuts (facade)
├── _accounts.py                # find_account (기존 유지)
├── _portfolio.py               # get_portfolio, get_portfolio_value, PortfolioItem (strategies에서 이동)
└── _order_helpers.py           # market_buy_krw, place_and_wait, cancel_all_orders (strategies에서 이동)

strategies/                     # 매매 전략만
├── __init__.py                 # SyncStrategies, AsyncStrategies (축소)
├── _base.py                    # RebalanceOrder, RebalanceResult, DCAResult (PortfolioItem 제거)
├── dca.py                      # dca (유지, import 경로만 변경)
├── rebalance.py                # rebalance (유지, import 경로만 변경)
└── alerts.py                   # price_alert (유지, import 경로만 변경)

_protocols.py                   # SyncClientProtocol, AsyncClientProtocol (strategies/_base.py에서 추출)

구현 단계

1. src/upbeat/_protocols.py 생성 (신규)

  • strategies/_base.py에서 SyncClientProtocol, AsyncClientProtocol 추출
  • shortcuts와 strategies 양쪽에서 import하는 공유 프로토콜

2. src/upbeat/shortcuts/_portfolio.py 생성 (strategies/portfolio.py 이동)

  • get_portfolio_value, async_get_portfolio_value 이동
  • get_portfolio, async_get_portfolio 이동
  • PortfolioItem 모델도 이 파일로 이동 (생성하는 곳에 위치)
  • import: _protocols에서 프로토콜, types.account에서 Account

3. src/upbeat/shortcuts/_order_helpers.py 생성 (strategies/order_helpers.py 이동)

  • market_buy_krw, async_market_buy_krw 이동
  • place_and_wait, async_place_and_wait 이동
  • cancel_all_orders, async_cancel_all_orders 이동
  • import: _protocols에서 프로토콜

4. src/upbeat/shortcuts/__init__.py 수정

  • SyncShortcuts에 메서드 추가: get_portfolio_value, get_portfolio, market_buy_krw, place_and_wait, cancel_all_orders
  • AsyncShortcuts에 동일 async 메서드 추가
  • __all__PortfolioItem 추가

5. src/upbeat/strategies/_base.py 수정

  • SyncClientProtocol, AsyncClientProtocol 제거 (→ _protocols.py로)
  • PortfolioItem 제거 (→ shortcuts/_portfolio.py로)
  • RebalanceOrder, RebalanceResult, DCAResult만 유지

6. src/upbeat/strategies/__init__.py 수정

  • SyncStrategies, AsyncStrategies에서 이동된 메서드 제거 (portfolio, order_helpers 관련)
  • dca, rebalance, price_alert만 남김
  • import문 정리, PortfolioItem re-export 제거

7. strategies 내부 import 경로 수정

  • strategies/dca.py: from upbeat.strategies.order_helpersfrom upbeat.shortcuts._order_helpers
  • strategies/rebalance.py: from upbeat.strategies.portfoliofrom upbeat.shortcuts._portfolio
  • strategies/dca.py, rebalance.py, alerts.py: 프로토콜 import를 from upbeat._protocols 로 변경

8. 이전 파일 삭제

  • src/upbeat/strategies/portfolio.py 삭제
  • src/upbeat/strategies/order_helpers.py 삭제

9. 테스트 이동

  • tests/strategies/test_portfolio.pytests/shortcuts/test_portfolio.py (import 경로 수정)
  • tests/strategies/test_order_helpers.pytests/shortcuts/test_order_helpers.py (import 경로 수정)

10. README 업데이트

  • README.md, README.en.md는 이미 client.shortcuts.get_account("BTC") 사용 중 → 변경 불필요

의존성 그래프 (변경 후)

_protocols.py (공유)
    ↑              ↑
shortcuts/      strategies/
  _portfolio.py    dca.py ──→ shortcuts._order_helpers
  _order_helpers.py rebalance.py ──→ shortcuts._portfolio
  _accounts.py     alerts.py

strategies → shortcuts 방향 의존만 존재 (순환 없음)

변경하지 않는 파일

  • src/upbeat/_client.pyclient.shortcuts, client.strategies 프로퍼티 그대로 유지
  • src/upbeat/__init__.py — shortcuts/strategies 미노출 (기존과 동일)
  • src/upbeat/strategies/dca.py, rebalance.py, alerts.py — 로직 변경 없음, import만 수정

검증

uv run ruff check src/
uv run ruff format src/
uv run pytest tests/shortcuts/ tests/strategies/
uv run pytest  # 전체 테스트

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions