토스증권 Open API를 위한 비공식 Swift SDK.
Swift Concurrency, 자동 OAuth2 토큰 관리, 정확한 Decimal 금융 모델을 외부 의존성 없이 제공합니다.
English · API Coverage · Changelog · Contributing
Important
TossInvestKit은 토스증권이 제작하거나 보증하는 공식 SDK가 아닙니다. 토스증권 Open API는 본인 계좌 용도로 사용해야 하며, 사용자는 공식 약관과 투자 위험을 직접 확인해야 합니다.
- Swift-native —
async/await, actor,Sendable기반 - 안전한 인증 흐름 — 토큰 캐싱, 동시 발급 방지, 401 자동 복구
- 금융 데이터 정확성 — 금액·수량·비율을
Decimal로 처리 - 운영 친화적 오류 — 도메인 오류와 429
Retry-After메타데이터 제공 - 테스트 가능 — 공개
HTTPTransport와TossInvestClientProtocol - Zero dependencies — Foundation 외 런타임 의존성 없음
공식 OpenAPI v1.2.4를 기준으로 구현되어 있습니다. 지원 범위는 API_COVERAGE.md에서 확인할 수 있습니다.
- Swift 6.0+
- Xcode 16+
- iOS 16+ / macOS 13+
- 토스증권 계좌와 Open API
client_id/client_secret
Xcode의 File → Add Package Dependencies에 다음 URL을 입력합니다.
https://github.com/jea0716/TossInvestKit.git
다른 Swift Package에서 사용할 때:
dependencies: [
.package(
url: "https://github.com/jea0716/TossInvestKit.git",
from: "0.1.0"
)
]import TossInvestKit
// 앱 전체에서 하나의 client 인스턴스를 공유하는 것을 권장합니다.
let client = TossInvestClient(
credentials: TossInvestCredentials(
clientID: clientID,
clientSecret: secretFromKeychain
)
)
let accounts = try await client.accounts()
guard let account = accounts.first else { return }
let holdings = try await client.holdings(accountSeq: account.accountSeq)
let quotes = try await client.prices(symbols: ["005930", "AAPL"])
let chart = try await client.candles(
symbol: "005930",
interval: .daily,
count: 100
)let orderbook = try await client.orderbook(symbol: "005930")
let trades = try await client.trades(symbol: "AAPL", count: 20)
let usdKrw = try await client.exchangeRate()
let stocks = try await client.stocks(symbols: ["005930", "AAPL"])
let krCalendar = try await client.krMarketCalendar()
let usCalendar = try await client.usMarketCalendar()429는 자동 재시도하지 않습니다. 서버가 제공한 대기 시간을 확인한 뒤 앱 정책에 맞게 재시도하세요.
do {
let quotes = try await client.prices(symbols: ["005930"])
print(quotes)
} catch let TossInvestError.rateLimited(_, code, message, requestID, info) {
print("\(code): \(message), requestId=\(requestID)")
if let seconds = info.retryAfter {
try await Task.sleep(for: .seconds(seconds))
}
}응답 모델은 공개 initializer와 Hashable을 제공하므로 키 없이 Preview 데이터를 만들 수 있습니다.
let previewQuote = Quote(
symbol: "AAPL",
timestamp: nil,
lastPrice: APIDecimal(185.70),
currency: "USD"
)앱 서비스 계층은 TossInvestClientProtocol에 의존해 mock으로 교체할 수 있습니다.
git clone https://github.com/jea0716/TossInvestKit.git
cd TossInvestKit
swift build
swift test단위 테스트는 MockTransport를 사용하므로 API 키와 네트워크가 필요하지 않습니다.
- 토스증권 PC 웹 → 설정 → Open API에서 키를 발급합니다.
- 현재 공인 IP를 Open API 허용 IP에 등록합니다.
- 키를 환경변수로 주입해 실행합니다.
read -s "TOSS_CLIENT_ID?client_id 입력: " && export TOSS_CLIENT_ID && echo
read -s "TOSS_CLIENT_SECRET?client_secret 입력: " && export TOSS_CLIENT_SECRET && echo
swift run TossInvestSmokeTest스모크 테스트는 계좌번호를 마스킹하고 개인 금액을 출력하지 않습니다.
- 키를 소스 코드,
.env커밋, UserDefaults에 저장하지 마세요. - 앱에서는 사용자가 입력한 secret을 Keychain에 저장하세요.
TossInvestClient는 가능한 한 앱 전체에서 하나만 공유하세요.invalid-token또는expired-token401 응답은 토큰을 갱신한 뒤 한 번만 자동 재시도합니다.- 네트워크가 바뀌면 공인 IP도 바뀔 수 있으므로 토스증권 허용 IP를 다시 확인하세요.
공식 문서상 호출량은 클라이언트 × API 그룹 단위로 제한되며 운영 정책에 따라 변경될 수 있습니다.
아래 수치보다 응답 헤더 X-RateLimit-*를 우선하세요.
| 그룹 | 현재 문서상 TPS | 구현 API |
|---|---|---|
| AUTH | 5 | 토큰 발급 |
| ACCOUNT | 1 | 계좌 목록 |
| ASSET | 5 | 보유 주식 |
| STOCK | 5 | 종목 정보 |
| MARKET_INFO | 3 | 환율, KR/US 캘린더 |
| MARKET_DATA | 10 | 현재가, 호가, 체결 |
| MARKET_DATA_CHART | 5 | 캔들 |
현재 0.x 개발 단계입니다. 읽기 API를 먼저 안정화한 뒤 주문 API를 추가합니다.
- OAuth2 토큰 캐싱·동시성·401 복구
- 계좌, 보유 주식, 현재가
- 캔들, 호가, 체결, 환율, 종목 정보, 장 캘린더
- 429 rate-limit 메타데이터
- 상·하한가, 매수 유의사항
- 랭킹과 시장 지표
- 매수 가능 금액, 판매 가능 수량, 수수료
- 주문과 조건주문
- 시세 폴링
AsyncStream
| 증상 | 확인할 내용 |
|---|---|
| HTTP 403 | 현재 공인 IP가 토스증권 허용 IP에 등록되었는지 확인 |
| HTTP 429 | RateLimitInfo.retryAfter 뒤 재시도하고 호출 그룹별 TPS 확인 |
| 인증 실패 | client ID/secret, 키 재발급 여부, 허용 IP 확인 |
XCTest 모듈 없음 |
Command Line Tools가 아닌 전체 Xcode가 선택되었는지 확인 |
sudo xcode-select -s /Applications/Xcode.app기여 방법은 CONTRIBUTING.md를 참고해주세요. 민감한 취약점은 공개 Issue 대신 Security Advisory로 신고해주세요.
TossInvestKit은 MIT License로 배포됩니다.