기본 콘텐츠로 건너뛰기

추천 가젯

7월 M&A 시장은 여섯 건의 초대형 딜이 움직였다

2026년 7월 한국 M&A·투자 시장은 101건 가운데 단 6건의 대형 거래가 전체 공개 금액 91.8조원을 사실상 끌어올린 달이었다. 금액이 공개된 딜은 24건, 비공개는 77건이었다. 공개 거래의 평균 금액은 3.8조원으로 집계됐다. 거래 상태를 보면 완료가 34건으로 가장 많았지만, 검토 중인 딜도 33건에 달했다. 계약 체결은 19건, 협상 중은 15건이었다. 시장이 멈춘 건 아니지만, 이미 끝난 거래보다 아직 가격과 조건을 맞추는 거래가 만만치 않게 많았다는 뜻이다. 한눈에 보기 총 딜 금액 공개 거래액 합계 평균 거래액 101건 24건 91.8조원 3.8조원 87.2조원을 만든 여섯 건과 176억원짜리 다섯 건 7월 시장은 금액 기준으로는 대형 딜, 건수와 산업의 폭으로 보면 중형 이하 딜이 나눠 가진 구조였다. 1조원 이상 대형 거래는 6건에 불과했지만 합계가 87.2조원, 평균은 14.5조원이었다. 핀테크와 바이오·의약품 위탁생산에 대형 자금이 몰렸고, 스트라이프·애드벤트인터내셔널과 페이팔 인수 제안이 대표 사례로 잡혔다. 1천억원 이상 1조원 미만 중형 거래는 13건, 합계 4.5조원, 평균 3,474억원이었다. 방산·항공우주와 호텔·부동산개발이 눈에 띄었고 한화에어로스페이스·한화시스템의 KAI 지분 매입이 대표 딜이었다. 반면 500억원 이하 초소형 거래는 5건, 합계 882억원, 평균 176억원으로 유통과 헬스케어에 집중됐다. 비리오 그로스의 펜실베이니아 대마 사업 자산 인수처럼, 작은 금액으로 특정 사업에 들어가는 거래도 이어졌다. 구간 건수 거래액 합계 평균 주요 산업 대표 딜 대형 (1조원↑) 6건 87.2조원 14.5조원 핀테크(1), 바이오/의약품 위탁생산(1) 스트라이프·애드벤트인터내셔널, 페이팔 인수 제안 중형 (1천억~1조) 13건 4.5조원 3,474억원 방산/항공우주(1), 호텔·부동산개발(1) 한화에어로스페이스·한화시스템, KAI 지분 매입 초소형 (500억↓) 5건 882억원 176억원 유통(2), 헬스케어...

[자동매매] 토스증권 API로 매매 시스템을 붙이면서

나는 몇 달째 산업 밸류체인과 기업 재무를 다루는 플랫폼을 만들고 있다. 국내 상장사 천오백 곳의 재무를 모아 저평가 점수를 매기는 스크리너가 있고, 산업별로 가상 투자자들이 토론해 심리를 추정하는 시뮬레이터가 있다. 매일 배치가 돌아 순위가 갱신된다.

그런데 그것으로 끝이었다. 화면에 저평가 상위 종목이 떠 있어도, 나는 그것을 보고 앱을 열어 손으로 주문을 냈다. 보통은 그러지도 않았다. 화면을 보는 시간과 장이 열리는 시간이 어긋났기 때문이다.

고르는 일과 사는 일 사이에 사람이 끼어 있었고, 그 사람이 병목이었다.

무엇을 원했나

자동화의 진짜 강점은 속도가 아니라고 생각했다. 사람은 서른 종목의 가격을 동시에 지켜볼 수 없다. 며칠짜리 호흡과 몇 달짜리 호흡을 한 계좌에서 같이 굴리기도 어렵다. 기계는 그것을 한다.

원한 것을 정리하면 이랬다. 플랫폼이 고른 종목만 감시할 것. 국내 주식만 다룰 것. 가격이 내려오면 사고 목표에 닿으면 팔되, 그 판단이 하루 안에 끝나도 되고 며칠에 걸쳐도 될 것. 그리고 자동매매에 허용할 금액을 정해두고, 그 안에서 어떤 종목을 얼마씩 살지가 정해질 것.

마지막 항목이 가장 어려웠는데, 그 이야기는 뒤에서 하겠다.

왜 맥미니인가

처음에는 이미 쓰고 있는 인프라에 얹으려 했다. 웹은 Vercel에 올라가 있고 배치는 GitHub Actions가 돌린다. 둘 다 안 됐다.

Vercel의 서버리스 함수는 무료 플랜에서 십 초 안에 끝나야 한다. 장중 여섯 시간 반 동안 이십 초마다 도는 루프를 올릴 방법이 없다. 크론으로 쪼개려 해도 무료 플랜은 하루 한 번이다. 게다가 서버리스는 요청이 끝나면 메모리가 사라지므로, 어느 종목을 얼마에 샀는지가 호출 사이에 남지 않는다.

GitHub Actions는 계산해보고 접었다. 저장소가 비공개라 무료 한도가 월 이천 분인데, 하루 여섯 시간씩 평일에 돌리면 월 칠천팔백 분이 필요하다. 초과분이 유료다. 크론이 몇십 분씩 늦게 시작하는 것도 개장 시각을 맞춰야 하는 작업에는 맞지 않았다.

남은 것은 상시 켜져 있는 기계였다. 책상 아래 맥미니가 있었다.

맥미니에 무엇을 올렸나

스크리너·심리 시뮬 (플랫폼, 평일 18:30 갱신)      토스증권 API
        │ 오늘의 선정 종목                              │ 시세·주문
        ▼                                               ▼
                  맥미니 (07:50 ~ 20:00)
        ├─ 08:30  아침 메일: 오늘 건드리지 말 종목
        ├─ 07:50~ 엔진: 프리마켓·정규장·애프터마켓
        └─ 20:05  저녁 메일: 당일 매매 결과
                          │ 기록
                          ▼
                      Supabase
                          │
                          ▼
                  웹 화면 (조회만)

실행은 맥미니가 하고 조회는 웹이 한다. 웹은 토스를 부르지 않는다. 이유는 뒤에 쓰겠지만, 부르면 안 되기 때문이다.

엔진은 아침 일곱 시 오십 분에 떠서 저녁 여덟 시에 끝난다. 정규장만 보는 것이 아니라 프리마켓과 애프터마켓까지 한 프로세스가 이어서 커버한다.

시간표는 코드에 박아두지 않았다. 토스가 market-calendar 엔드포인트로 그날의 세션 시간을 주는데, 넥스트레이드까지 포함한 통합 기준이라 프리마켓 08:00, 정규장 09:00부터 15:30, 애프터마켓 15:30부터 20:00이 그대로 내려온다. 휴장일이나 임시 변경도 이쪽이 반영하므로 내가 관리할 것이 없다.

다만 시간외에 모든 종목이 거래되는 것은 아니다. 그래서 프리마켓과 애프터마켓에서는 넥스트레이드 지원 종목만 신규 진입 대상으로 둔다. 나머지는 시세가 정규장 마지막 값에 멈춰 있어서, 그것을 보고 판단하면 몇 시간 전 가격으로 매매하는 셈이 된다. 반대로 청산은 시간외에도 전 종목에 대해 계속 판단한다. 손절을 몇 시간 미루는 것이 훨씬 비싸기 때문이다.

자동 실행은 cron이 아니라 launchd로 걸었다. 맥이 자거나 꺼져 있어 실행 시각을 놓쳤을 때, cron은 그냥 건너뛰지만 launchd는 깨어난 직후에 한 번 실행해준다. 장중에 맥이 잠들지 않도록 caffeinate로 감쌌고, 정전 후 자동 재부팅도 켜뒀다.

모니터는 연결하지 않았다. Tailscale에 물려 있어서 어디서든 SSH로 들어가 로그를 볼 수 있다. 다만 LaunchAgent는 사용자 세션 안에서 돌기 때문에 자동 로그인을 켜둬야 한다. 재부팅 후 로그인 화면에 멈춰 있으면 엔진도 뜨지 않는다.

하루에 두 번 메일이 온다

엔진은 맥미니 안에서 조용히 돈다. 로그는 파일에 쌓이지만 그것을 보려면 SSH로 들어가야 하고, 무엇보다 조용한 날과 죽은 날이 로그만으로는 잘 구분되지 않는다. 아무 일도 없어서 비어 있는 것인지, 프로세스가 새벽에 넘어져서 비어 있는 것인지 알 수 없다.

그래서 결과를 밀어서 보내기로 했다. 아침에 한 통, 저녁에 한 통이다.

아침 여덟 시 반에 오늘 건드리지 말 종목이 온다. 엔진이 관리하는 종목을 내가 앱에서 직접 사고팔면 장부와 실계좌가 어긋난다. 엔진은 다음 주기에 그것을 감지하고 신규 진입을 멈추는데, 그러면 그날 매매는 거기서 끝난다.

실제로 겪었다. 엔진이 인수해 관리하던 종목을 내가 밖에서 스물여섯 주 팔았고, 장부가 갈라졌다. 그날 엔진은 아무것도 하지 못했다. 목록은 매일 바뀐다. 스크리너가 평일 저녁 여섯 시 반에 갱신되고 엔진이 다음 날 아침에 그것을 읽기 때문이다. 그러니 어제 목록을 기억하고 있어도 소용이 없다.

저녁 여덟 시 오 분에 오늘 무슨 일이 있었는지 온다. 애프터마켓이 끝나고 엔진이 스스로 종료한 직후다. 실현손익과 미실현손익, 청산 건수를 담는다. 청산된 거래는 하나하나 적는다. 왜 팔았는지, 얼마에 사서 얼마에 팔았는지, 비용을 뺀 순손익이 얼마인지. 남은 보유와 평가손익도 함께 넣는다.

두 가지를 특히 신경 썼다. 청산이 0건이면 0건이라고 분명히 말한다. 아무것도 없는 메일과 아무 일도 없었다고 말하는 메일은 다르다. 그리고 승률을 적을 때는 손익분기 승률을 나란히 놓고, 표본이 적으면 믿지 말라고 명시한다. 사흘치 승률 100퍼센트는 아무 뜻이 없기 때문이다.

토큰이 하나뿐이라는 제약

여기서부터가 API 이야기다.

토스증권 API 신청은 심사도 대기도 없다. 삼 분이면 client_id와 secret이 나온다. 인증은 OAuth2 client credentials 방식이고, 여기까지는 흔하다.

문서 설명란에 이런 문장이 있다. client 당 유효한 access token은 1개이며, 재발급 시 이전에 발급된 token은 즉시 무효화된다.

이 한 줄이 앞의 구조를 결정했다. 두 곳에서 토큰을 받으면 서로를 로그아웃시킨다. 웹 페이지가 계좌를 직접 조회하면, 내가 화면을 새로고침할 때마다 맥미니에서 돌고 있는 매매 프로그램이 인증을 잃는다.

나는 이것을 뒤늦게 알았다. 웹에서 직접 부르는 코드를 먼저 만들었고, 계좌 화면이 비어 있는 것을 보고서야 다시 생각했다. 자격증명을 배포 환경에 넣으면 화면은 채워지지만 엔진이 끊긴다. 넣지 않으면 화면이 빈다. 어느 쪽도 답이 아니었다.

결국 토스를 부르는 곳을 맥미니 하나로 모았다. 같은 기계 안에서는 토큰을 파일에 캐시해 나눠 쓰므로 재발급이 일어나지 않는다. 맥미니가 계좌를 읽어 데이터베이스에 적어두고, 웹은 그것만 읽는다. 메일을 보내는 스크립트도 같은 이유로 맥미니에서 돈다.

문서만 봐서는 모르는 것들

경로는 /api/v1/... 이다. 검색해서 나오는 글 몇 개가 /v1/... 로 적어두었는데 그대로 따라 하면 404를 받는다. 정본은 openapi.tossinvest.com 에 있는 사백 킬로바이트짜리 OpenAPI 명세다. 남의 글보다 이걸 먼저 받는 편이 빠르다.

매수 가능 금액 조회에서 한 번 막혔다. 그냥 부르면 400이 오는데, 응답에 field: currency 라고 적혀 있다. 통화 코드가 필수인데 계좌 조회의 연장선으로 생각하면 넣을 생각을 못 한다.

수급 데이터가 생각보다 풍부하다. 종목별로 투자자별 매매동향과 외국인 보유율, 공매도 거래량과 비중, 프로그램 매매의 차익과 비차익, 신용융자 잔고, 대차잔고가 일간으로 나온다. 개인이 이만큼을 API로 받을 수 있는 것은 흔치 않다.

분봉은 소급 조회가 된다. 한 번에 이백 개씩, before 파라미터로 계속 과거로 넘어간다. 실시간 시세를 쌓아둘 필요가 없다는 뜻이다. 나중에 다시 받으면 되니까.

스프레드가 세금만큼 크다

호가창이 매수·매도 열 단계씩 다 나온다. 이것이 생각보다 중요했다.

모의 실행을 만들 때 처음에는 현재가로 체결된다고 가정했다. 실제로는 살 때 매도호가를 치고 팔 때 매수호가를 쳐야 한다. 그 차이가 스프레드다.

어떤 소형주는 현재가 8,640원에 매도호가가 8,660원이었다. 0.23퍼센트다. 수수료와 거래세를 전부 합친 값보다 크다. 현재가로 계산하면 이 돈이 공짜 수익으로 잡혀 성적표가 통째로 부풀려진다.

비용은 물어보면 알려준다. 수수료율은 별도 엔드포인트가 주고, 세금은 종료된 주문 내역의 각 체결에 들어 있다. 내 계좌의 지난 체결 아흔아홉 건으로 계산했더니 매수 수수료 0.0123퍼센트, 매도 수수료 0.0117퍼센트, 매도 거래세 0.1844퍼센트가 나왔다. 왕복 0.2085퍼센트다.

추정하지 말고 재는 편이 낫다. 1퍼센트에 팔고 나오는 전략이라면 비용이 수익의 오분의 일을 먹는다. 손익분기 승률을 계산해보면 칠십 퍼센트가 넘는 설정도 있다. 열 번 중 일곱 번을 이겨야 본전이라는 뜻이다.

남는 생각

API 자체는 깔끔했다. 하루 만에 조회부터 주문까지 다 붙었다.

어려운 것은 API가 아니라 그 위에 얹는 판단이었다. 익절을 몇 퍼센트로 할지, 종목을 몇 개나 담을지. 이런 것들은 문서에 답이 없고 사실 어디에도 없다. 시장이 계속 바뀌기 때문이다.

지금은 실제 주문을 아주 작은 금액으로만 내보내고 나머지는 모의로 돌리며 기록을 쌓고 있다. 매주 신호가 고른 종목을 그 시점에 확정해 적어두고, 같은 유니버스에서 무작위로 뽑은 대조군을 나란히 둔다. 몇 주가 지나면 내 신호가 우연보다 나은지 알게 될 것이다.

지금까지 나온 숫자로는 아직 구분되지 않는다. 돌아간다는 것과 이긴다는 것은 다른 이야기다.

댓글

가장 많이 본 글