AI 시스템 엔지니어링 · 금융 도메인

AI에게 코드를 시키는 일과
AI를 운용하는 일
다른 문제입니다.

LLM 파이프라인과 금융 ML을 설계하고, AI가 내놓은 결과를 자동으로 반증하는 구조를 만듭니다. 5개월간 5개 시스템에 31.1만 줄을 작성했는데, 그중 상당 부분은 코드가 아니라 같은 실수를 두 번 하지 않게 만드는 체계였습니다.

고보성 · 2000년생 · 서울

작성 코드
311,313
커밋
1,202
설계 문서
393
기간
5개월

01 — AI 개발 체계

하네스(Harness) — 코드를 쓰기 전에 읽히는 체크리스트

AI는 지난주에 무엇이 잘못됐는지 기억하지 못합니다. 그래서 기억해야 할 것을 파일로 만들고, 작업 종류를 감지하면 자동으로 읽히게 했습니다. "차트 지표를 추가해줘"라고 말하면 12단계 절차와 과거 결함 5종이 함께 따라옵니다.

작업 요청 감지
  │
  ├─ 1. 트리거 매칭   키워드 → 해당 도메인 하네스 문서 자동 로드
  │                    "OCX를 다루는 화면"이면 키움 하네스가 반드시 동반
  │
  ├─ 2. 계획         분해 · 의존성 · 위험 식별
  │                    사용자 승인 전에는 코드를 건드리지 않음
  │
  ├─ 3. 구현         테스트 우선 (RED → GREEN → 리팩토링)
  │
  ├─ 4. 교차 검토     code-reviewer · security-reviewer 병렬 실행
  │                    서로 모르는 상태로 같은 코드를 보게 함
  │
  ├─ 5. 배선 검증     순수 함수 테스트로는 못 잡는 결함 —
  │                    콜백을 일부러 끊고 정확히 1건만 실패하는지 실측
  │
  └─ 6. 박제         재발 가능한 결함이면 하네스·규칙으로 승격
                       "이번만 예외"로 넘기지 않는다
16

작업 유형별 하네스

화면 추가, 버튼, 리스트, 팝업, 드래그-드롭, 백그라운드 서비스, 키움 OCX 호스팅, 전략 엔진까지. 각 문서가 절차 + 골격 코드 + 과거에 실제로 터진 결함 목록을 갖습니다. 작업 후 항목별로 통과 여부를 검증합니다.

20

역할별 서브에이전트

계획·아키텍처·디버깅·보안·DB·테스트·빌드오류로 역할을 나눠 직접 정의했습니다. 프로젝트 전용 5종은 그 프로젝트에서만 통하는 함정을 압니다 — 키움 OCX 규칙 검사기, WPF 빌더 등.

50

영구 메모리

세션이 끊겨도 남는 지식 파일. 결론만이 아니라 기각된 시도와 그 이유를 같이 적습니다. "이 방법은 개선율 −69.8%로 실패했다"가 성공 기록보다 자주 쓰입니다.

17

위반 시 중단 규칙

권고가 아니라 어기면 작업을 멈추는 규칙입니다. 전부 실제로 사고가 난 뒤 승격된 항목이고, 상당수는 사람이 지키는 대신 테스트와 빌드 스크립트가 차단합니다.

순수 함수는 전부 통과하는데 배선만 끊긴 사고가 하루에 세 번 났습니다. 그래서 테스트를 셋으로 나눴습니다 — 순수 로직, 끝에서 끝까지 배선, 그리고 일부러 코드를 망가뜨려 테스트가 실제로 잡는지 확인하는 것. — 배선 테스트를 도입한 이유

에이전트를 여러 개 띄워 사실 검토 / 시니어 리뷰 / 보안 / 일관성 / 중복 각각의 관점으로 같은 코드를 보게 하는 방식도 씁니다. 실전 투입 전 감사에서 두 에이전트가 독립적으로 찾은 최상위 결함이 알고 보니 같은 근본 원인이었던 적이 있는데, 따로 도달한 결론은 신뢰도가 다릅니다. 반대로 한쪽만 지적한 항목은 우선 의심합니다.

공개 저장소 github.com/bosung2000/ai-dev-harness 이 체계를 문서와 실행 가능한 도구로 정리해 공개했습니다. 커밋 전 API 키를 자동 차단하는 검사기와 훅은 그대로 복사해 쓰실 수 있습니다.

02 — 실시간 관제 시스템

먼저, 열어서 확인하실 수 있는
프로젝트 하나

아래에 이어지는 금융 작업물은 상용화를 전제로 비공개라 설명으로만 드릴 수 있습니다. 그래서 코드를 그대로 열어보실 수 있는 시스템을 하나 공개해 두었습니다. 전국 매장의 센서 1,000대를 실시간으로 받아 저장하고 이상을 판정해 화면에 띄우는 관제 시스템입니다. 도메인은 금융이 아니지만 초당 수천 건이 쏟아질 때 무엇이 먼저 무너지는가는 시세 데이터와 같은 문제입니다.

IoTSensorDashboard

단독 개발 40/40 소스 공개

전국 매장 20곳의 출입구에 드나드는 사람을 세는 센서 1,000대가 붙어 있다고 가정한 시스템입니다. 들어온 수와 나간 수를 따로 받아 지금 매장 안에 몇 명이 있는지를 냅니다. 센서가 보내는 순간부터 관제 화면에 뜨기까지 다섯 단계 전부를 하나의 프로그램 묶음으로 만들었습니다.

기간
2026.08
커밋
40 / 40
코드
+23,319줄
테스트
377건
문서
12건

무엇을 만들었나

센서 1,000대  매장 20곳 출입구 · 들어옴(in)과 나감(out)을 따로 보고한다
  │
  ▼
MQTT 브로커  메시지를 받아 나눠주는 우체국. 외부 서버 없이 앱 안에 넣었다
  │
  ▼
수집        같은 사건이 두 번 오면 한 건으로 접고, 시각·값이 이상하면 격리한다
  │
  ▼
저장        SQLite · 묶어서 쓰기 · 오래된 건 요약본으로 접고 지운다
  │
  ▼
판정        조용해진 센서 · 불가능한 값 · 권한 · 알림을 어디까지 올릴지
  │
  ├─ 대시보드   매장별 상태와 추이를 한 화면에 (패널 10장)
  ├─ 관제실     지금 이 순간 파이프라인이 어디까지 소화하는지
  └─ 센서팜     센서 1,000대 개별 상태 + 부하를 직접 만들어 던지는 발생기
  • 센서가 말을 멈추면 알아챕니다. 값이 안 오는 것과 값이 이상한 것은 다른 사고라서 따로 판정합니다. 센서마다 발신 주기가 달라 주기를 관측해 기준을 스스로 맞춥니다 — 고정 기준을 두면 느린 센서가 매번 고장으로 잡힙니다.
  • 있을 수 없는 값은 격리합니다. 문 하나로 1초에 수천 명이 들어올 수는 없습니다. 그런 값은 버리는 게 아니라 따로 세어 둡니다 — 지운 것과 걸러낸 것은 다르게 취급해야 나중에 원인을 찾습니다.
  • 알림을 단계로 올립니다. 한 번 튄 값과 10분째 응답 없는 센서를 같은 무게로 알리면 아무도 안 봅니다. 담당자 → 관리자 → 비상으로 올라가고, 복구되면 내려옵니다.
  • 오래된 데이터는 스스로 접습니다. 원본을 영원히 두면 디스크가 먼저 죽습니다. 시간이 지나면 분·시간 단위 요약으로 접고, 더 지나면 지우고, 빈 공간을 회수합니다.
  • 부하를 직접 만들어 던질 수 있게 했습니다. 발신 속도를 현실(분당 1건) · 정상(17/s) · 빠름(500/s) · 폭주(5,000/s) · 극한(20,000/s) 로 눌러서 바꾸고, 이상치도 주입합니다. 아래 발견들은 전부 이 발생기로 재현한 것입니다.
관제실 화면 — 파이프라인 처리 현황과 감지 피드
관제실센서 → 수집 큐 → 저장 → 중복 접음 → 화면까지, 각 단계가 지금 몇 건을 안고 있는지를 그대로 보여줍니다. 아래 「중복 접음 0」이 01번 결함을 5초 만에 드러낸 그 카운터입니다. 처리 지연 108.5µs · 백로그 0.
대시보드 화면 — 매장별 상태 패널
대시보드매장별 유입·유출과 현재 체류 인원, 본사–본부–매장 계통도, 가동률, 상위 센서, 최근 사건을 한 화면에 모았습니다. 「이번 세션」·「전체 기간」처럼 기준을 라벨에 적어둔 것이 04번 결함을 고친 결과입니다.
센서팜 화면 — 센서 1,000대 타일 격자와 부하 발생기
센서팜센서 1,000대를 타일 하나씩으로 그립니다. 상단 버튼으로 발신 속도를 현실부터 극한(20,000/s)까지 바꾸고 이상치를 주입합니다. 실측 발신량과 유실 건수가 아래에 붙습니다.

그래서 무엇을 발견했나

돌아가는 것까지는 어렵지 않았습니다. 부하를 올리자 전부 여기서 갈렸습니다.

  1. 01
    수신은 되는데 저장이 0 — 그런데 아무 흔적도 없었습니다 센서는 보내고 있고 화면의 수신 건수도 오르는데, 저장만 되지 않았습니다. 대기열도 0, 폐기도 0이라 어디로 샜는지 단서가 없었습니다. 원인은 버려진 게 아니라 접힌 것이었습니다 — 처리 주기가 밀리면 한 주기에 같은 센서를 두 번 세게 되고, 그러면 같은 센서·같은 밀리초가 만들어져 중복 방지 규칙이 전부 하나로 합쳐버립니다. 유실을 막으려고 넣은 장치가 유실을 만들고 있었습니다. 한 주기에 명부를 한 바퀴까지만 돌도록 상한을 걸어 중복 22,426건 → 0건, 저장량 +25%.
  2. 02
    추측으로 두 번 헛짚고, 진단을 먼저 만들어 5초 만에 찾았습니다 위 문제를 고친 방법입니다. 화면의 정합성 표시가 "중복으로 접은 건수"를 보고 있지 않아서, 시스템이 스스로 "유실 0 · 정상"이라고 말하고 있었습니다. 코드를 고치는 대신 그 숫자를 화면에 올리자 원인이 즉시 드러났습니다. 재현 조건이 까다로워 세 번 만에 잡았는데, 앞의 두 번이 실패한 이유는 같았습니다 — 화면 없이 검증했습니다. 거기엔 UI가 없으니 "화면이 멈춘다"가 재현될 리 없었습니다.
  3. 03
    한 번은 무해한 호출이, 초당 수천 번이면 흉기입니다 화면이 매 프레임 "이 센서 살아있나?"를 물었고, 그 호출이 잠금을 잡았는데 같은 잠금을 수집 쪽이 쓰고 있었습니다. 화면 한 장이 프레임당 잠금을 1,000번 잡아 수집을 굶겼습니다. 900만 행짜리 전체 집계를 매 주기 두 곳에서 부르던 것도 같은 부류였습니다. 한 번에 복사해 오는 방식으로 잠금 1회로 줄였습니다. 함수 하나만 보면 멀쩡한데 호출 빈도를 보면 아니었던 경우이고, 이 프로젝트에서만 세 번 나와 규칙으로 승격했습니다.
  4. 04
    계산이 전부 맞아도 화면은 거짓말을 합니다 기준이 다른 수를 나란히 놓은 것만으로 세 곳이 틀렸습니다. 상단에 저장 176만 건과 수신 1,720건을 붙여놨는데 하나는 DB 전체 누적이고 하나는 이번 실행분이라 1,000배가 났습니다. 가동률이 화면마다 865/1,000과 1,000/1,000으로 갈린 것은 한쪽만 응답 확인까지 셌기 때문이고, 3,722 → 1,862로 반이 증발한 것은 하나가 사건 수, 하나가 메시지 수였기 때문입니다. 해법은 설명을 덧붙이는 게 아니라 라벨에 기준을 적고, 단위가 안 맞는 자리는 숫자를 비우는 것이었습니다.
C# / .NET 8WPF · 직접 렌더링MQTT (브로커 내장 · TLS)SQLite · WAL · 롤업백그라운드 워커xUnit 377건PowerShell 검증 도구
12

제가 낸 결함을 지우지 않고 남겼습니다

결함 12건을 증상 · 원인 · 왜 못 봤는지까지 문서로 정리했습니다. 그중 하나는 제가 추가한 관측 지표가 그 자체로 부하가 된 사례입니다 — 좋은 의도의 계측이 시스템을 느리게 만들 수 있다는 것을 남겨뒀습니다.

377

테스트가 결함을 지키고 있던 경우

기존 테스트 한 건이 "모든 관측이 같은 시각"을 정답으로 고정하고 있어서, 01번 결함을 오히려 보호하고 있었습니다. 테스트가 있다는 것과 테스트가 옳은 것을 지키고 있다는 것은 다른 이야기였습니다.

공개 저장소 github.com/bosung2000/IoTSensorDashboard 코드·테스트 377건·설계 문서 12건이 전부 공개돼 있습니다. docs/ 에 구조 지도와 위 결함 기록을, tools/ 에 기동 점검과 부하 검사 스크립트를 넣어 뒀습니다. 받아서 바로 실행해 보실 수 있습니다.

03 — LLM 파이프라인

공시 원문으로 답하는 종목 분석 AI

미국 SEC 공시(10-K / 10-Q)를 근거로 질문에 답하는 시스템입니다. 수집 → LLM 압축 → 청킹 → 임베딩 → 검색 → 답변 생성 전 구간을 직접 설계했고, 핵심은 모델을 고르는 일이 아니라 모델이 틀렸을 때 그것을 어떻게 아느냐였습니다.

Alpha-Redline AI

단독 개발 123/123 Gemini · RAG

구독형 미국 주식 분석 서비스를 목표로 설계했습니다. 도메인·애플리케이션·인프라를 분리한 계층 구조에, 목적별로 나눈 프롬프트 7종(압축 · 차이 분석 · 인사이트 · 리스크 · 종합 · 어조 · 대화)을 코드로 관리합니다.

기간
2026.03 — 2026.07
커밋
123 / 123
코드
+35,646줄
문서
47건

무엇을 만들었나

공시 수집    미국 상장사가 의무로 내는 보고서 — 연차(10-K)·분기(10-Q)
  │            한 건이 수백 페이지라 사람도 통째로는 못 읽는다
  ▼
LLM 압축    핵심만 남기고 반복되는 법률 문구를 걷어낸다
  │
  ▼
쪼개기      의미가 끊기지 않는 단위로 자른다  자르는 기준이 답변 품질을 좌우한다
  │
  ▼
임베딩      각 조각을 좌표로 바꿔 저장 — "비슷한 뜻"을 거리로 찾기 위해
  │
  ▼
검색 → 답변  질문과 가까운 조각을 꺼내, 그 대목을 근거로만 답하게 한다
  • "이 회사 부채가 늘었나?" 같은 질문에 공시 원문을 근거로 답합니다. 모델이 알고 있는 지식이 아니라 실제 제출 문서에서 찾아온 대목으로 답하게 만드는 것이 핵심입니다.
  • 재무 수치는 LLM에게 맡기지 않습니다. 표에서 직접 뽑고, 빠진 항목만 LLM이 채웁니다. 숫자를 지어내는 것이 가장 위험하기 때문입니다.
  • 뽑아낸 수치가 회계적으로 말이 되는지 스스로 검사합니다. 자산과 부채+자본이 맞지 않으면 그 자리에서 걸립니다.
  • 같은 것을 두 번 부르지 않습니다. 이미 받은 공시는 요청 자체를 하지 않고, 호출이 거절당하면 예비 키로 넘어가 중단된 지점부터 이어서 진행합니다.

그래서 무엇을 발견했나

  1. LLM에 전부 맡기지 않는 하이브리드 파서 재무 수치는 HTML 테이블 파싱을 1차로 두고, 누락된 항목만 LLM 보충 패스로 채웁니다. 비용과 환각을 동시에 줄이는 구조입니다. 한국 DART는 XBRL 표준계정ID가 있어 LLM 파싱이 아예 불필요하다는 것도 확인해서, 같은 문제에 다른 해법을 적용했습니다.
  2. LLM 출력을 회계 항등식으로 검증 추출된 수치가 자산 = 부채 + 자본을 만족하는지 교차 확인합니다. 계정을 잘못 매핑하면 오차가 100% 단위로 튀기 때문에 즉시 걸립니다. 실제로 이 검증이 자본총계 대신 총자산을 읽던 결함을 잡았습니다 — LIKE '%자본총계%'부채와자본총계에 걸린 경우였습니다.
  3. 프롬프트에도 테스트를 붙였습니다 프롬프트는 코드가 아니라는 이유로 검증 밖에 놓이기 쉽습니다. 필수 경고 문구가 빠지지 않았는지, 지시가 서로 충돌하지 않는지를 단위 테스트로 고정했습니다. 프롬프트를 수정하다 안전 문구를 지우는 사고를 구조적으로 막습니다.
  4. 파이프라인 전체 정독 리뷰 · 결함 12건 문서화 돌아가는 코드를 처음부터 끝까지 다시 읽어 HIGH 3 · MED 4 · 잠복 5를 목록화했습니다. 가장 위험한 건 임베딩 차원이 안 맞을 때 유사도 함수가 예외도 로그도 없이 0을 반환하는 부분 — 모델을 교체하면 검색이 조용히 전멸합니다. 같은 코드가 3개 저장소에 복제돼 있다는 사실까지 확인해 "한 곳만 고치면 재발한다"를 문서에 박았습니다.
  5. API 한도·비용 설계 섹션별 토큰 예산, 보일러플레이트 제거, 키 이중화(429/503 시 백업 키 자동 폴백), 수집 로그 기반 재개 — 이미 받은 건 API 호출 자체를 하지 않습니다. 이 설계로 DART 재무 27,729건을 한도에 한 번도 걸리지 않고 완주했습니다(421만 행).
종목 대화 화면 — 답변에 근거 각주가 붙어 있다
종목 대화 · 근거 표시"경영진의 향후 전망을 정리해줘"에 대한 답변입니다. 중요한 건 답의 내용이 아니라 문장마다 붙은 각주와 맨 아래 출처 목록입니다 — 어느 보고서의 어느 항목에서 가져왔는지가 제출일·문서종류까지 찍힙니다. 근거를 못 찾으면 지어내지 않고 그렇게 말하도록 했습니다.
두 종목 비교 화면
두 회사 비교같은 항목을 두 회사에서 각각 꺼내 나란히 놓습니다. 회계연도가 다르면 비교가 성립하지 않으므로 어느 해 보고서에서 나온 수치인지를 함께 적게 했습니다.
공시 조회 화면 — 제출 목록과 분석 리포트
공시 조회 · 리포트 생성종목을 넣으면 실제 제출 이력(연차·분기·내부자 거래·대량 보유)을 끌어와 목록으로 놓고, 거기서 분석 리포트를 만듭니다. 왼쪽 탭이 「어조 변화」·「내용 변화」인 이유는 이번 보고서가 지난번과 무엇이 달라졌는지가 실제 신호이기 때문입니다.
C# / .NETGoogle Gemini API임베딩 · 벡터 검색청킹 전략프롬프트 엔지니어링SEC EDGARDART OpenAPISQLite · DapperxUnit

04 — 금융 ML

확률을 내놓는 것보다
그 확률을 믿어도 되는지 재는 일

전략 신호의 성공 확률을 예측하는 LightGBM 모델과, 그 예측이 실제로 맞는지 검증하는 진단 도구를 만들었습니다. 금융 시계열은 데이터 누수가 나기 쉬워서 일반적인 교차검증을 쓰면 성능이 부풀려집니다.

  1. CPCV — 누수를 막는 교차검증 학습·검증 구간이 시간적으로 겹치면 미래 정보가 새어 들어옵니다. Combinatorial Purged Cross-Validation으로 구간을 조합하고 경계를 소거해 이를 차단했습니다. 레짐 라벨(강세/약세)과 섹터 층화를 함께 적용해, 특정 시장 국면에서만 통하는 모델을 골라냅니다.
  2. 캘리브레이션 — "70%"가 정말 70%인가 모델이 0.7이라고 말할 때 실제로 70%가 맞는지를 reliability diagram과 Brier score로 측정합니다. 예측 확률이 실제 빈도와 어긋나면 그 숫자로 포지션 크기를 정할 수 없습니다. 시간 구간(60봉/240봉)과 목표(승리 / 2R 도달 / 손절 히트)별로 나눠 리포트를 생성합니다.
  3. 특성 수를 늘려도 좋아지지 않는다는 것을 실측 25개 · 26개 · 30개 특성 조합으로 각각 리포트를 뽑아 비교했습니다. ablation study로 특성을 하나씩 빼보고, SHAP으로 기여도를 확인하고, 상관행렬로 중복 특성을 찾았습니다. 결과를 근거로 특성 집합을 결정했습니다.
  4. C# ↔ Python 사이드카 구조 학습 데이터는 C#에서 내보내고(HtfTrainingDataExporter), 학습·추론은 Python이 맡고, FastAPI 추론 서버로 다시 붙입니다. 언어를 억지로 통일하지 않고 각 생태계가 잘하는 일을 시켰습니다 — ML은 Python, 실시간 매매는 C#.
추론 화면 — 봉별 확률과 SHAP 기여도 분해
추론 · 왜 그 확률인지종목과 날짜를 넣으면 특성 33개를 자동으로 뽑아 Python 서버가 봉마다 확률을 냅니다. 오른쪽이 그 숫자가 왜 나왔는지의 분해입니다 — 무엇이 확률을 올렸고 무엇이 끌어내렸는지. 확률만 나오면 믿을 근거가 없습니다.
확률 게이트 백테스트 비교 — 원본 대비 필터 적용
모델을 실제로 끼워 본 결과확률이 임계값을 넘을 때만 진입하도록 걸어 3년치를 다시 돌렸습니다. 거래가 332건 → 20건으로 줄고 손익비가 1.96 → 14.77이 됐습니다. 다만 20건은 결론을 내기엔 적은 표본이라, 이 숫자를 성과로 쓰지 않고 "게이트가 실제로 작동한다"는 확인까지만 씁니다.
신뢰도 곡선 — 예측 확률 대비 실제 빈도
신뢰도 곡선 · 승리 예측가로가 모델이 말한 확률, 세로가 실제로 그렇게 된 비율입니다. 대각선에 붙을수록 그 숫자를 믿어도 된다는 뜻이고, 아래로 처지면 모델이 자신을 과신하고 있다는 뜻입니다.
신뢰도 곡선 — 목표 수익 도달 예측
신뢰도 곡선 · 목표 도달같은 모델도 무엇을 맞히라고 시키느냐에 따라 신뢰도가 다릅니다. 그래서 목표(승리 / 목표가 도달 / 손절 히트)와 기간(60봉 / 240봉)별로 따로 뽑아 비교했습니다.
Python 3,554줄LightGBMscikit-learnSHAPpandas · numpyFastAPI · uvicornpytestmatplotlib

이 영역은 2인 프로젝트 안에 있지만 ML·LLM 모듈은 제가 단독으로 작성했습니다ml/ 17커밋 중 17건, Filings.Pro/ 19커밋 중 19건이 제 커밋입니다. 반대로 차트 렌더링 엔진은 동료가 주도한 영역이라 제 실적으로 넣지 않았습니다.

05 — 시스템 설계

파는 물건으로 만들기

혼자 쓰는 도구와 남에게 파는 제품은 요구가 다릅니다. 고객마다 전략이 다르고, 알고리즘은 디컴파일로 새고, 잘못된 주문 한 번이 실제 돈을 잃습니다.

FrozenOlaf

단독 개발 644/659 상용화 진행

키움증권 OpenAPI 기반 한국 주식 자동매매 시스템. 2020년에 직접 만들어 실제 계좌로 운용했던 반자동 프로그램을, 완전 무인 자동매매 + 판매 가능한 제품으로 재설계하고 있습니다.

기간
2026.06 — 진행 중
커밋
644 / 659
코드
+161,795줄
문서
91건

무엇을 만들었나

후보 좁히기   조건에 맞는 종목만 남긴다 — 실시간 구독은 100종목이 물리 상한이다
  │
  ▼
실시간 시세   증권사 서버에서 체결·호가를 계속 받는다
  │
  ▼
신호 판정    전략이 "지금 사라 / 팔아라"를 판단  전략은 갈아끼울 수 있는 부품
  │
  ▼
주문 · 체결  주문을 내고, 안 채워지면 취소하고, 채워진 만큼만 관리한다
  │
  ▼
청산 · 방어  손절 · 시간 마감 · 비상 정지 · 응답이 끊기면 스스로 정리
  • 사람이 화면을 보고 있지 않아도 돌아갑니다. 종목을 고르고, 사고, 지키고, 파는 것까지 프로그램이 합니다. 사람은 어떤 전략을 켤지와 언제 멈출지만 정합니다.
  • 전략을 부품처럼 갈아끼웁니다. 고객마다 매매 방식이 다르기 때문에, 전략 하나를 파일로 만들어 끼우면 본체를 고치지 않고 동작하도록 경계를 나눴습니다.
  • 과거 데이터로 먼저 검증합니다. 실제 돈을 넣기 전에 20년치 시세로 같은 전략을 돌려 성과·최대 손실·거래 횟수를 봅니다.
  • 위험할 때 멈추는 장치를 여러 겹 넣었습니다. 비상 정지, 주문 폭주 차단, 미체결 자동 취소, 프로그램이 응답을 멈추면 스스로 정리하는 장치까지. 실제 돈이 걸린 시스템에서 가장 많이 손본 부분입니다.
  • 밖에서도 확인하고 멈출 수 있습니다. 텔레그램으로 현재 상태를 받고 원격으로 정지시킵니다.
FrozenOlaf 홈 화면 — 기능 전체와 시장 요약·알럿·텔레그램
홈 · 이 프로그램이 하는 일 전부기능을 차트 · 조회/모니터링 · 분석/신호 · 자동매매 네 갈래로 나눠 놓았습니다. 위쪽은 지금 시장이 어떤지(지수·관심종목), 가운데는 전략이 잡아낸 신호를 시각별로 쌓은 알럿, 오른쪽은 텔레그램 연결입니다 — 자리에 없을 때 상태를 받고 원격으로 멈추는 통로입니다.
백테스트 화면 — 전략 성과 곡선과 거래 내역
백테스트 랩오른쪽에서 돌린 결과가 왼쪽 차트와 이어집니다. 결과 목록에서 종목을 클릭하면 차트가 그 종목으로 바뀌고 진입·청산 지점이 봉 위에 찍혀, 숫자만 보고 판단하지 않고 어디서 사고 팔았는지를 눈으로 확인합니다. 전략은 목록에서 골라 바꿔 끼우고, 고르면 그 전략의 설정값이 아래에 나타납니다 — RSI 기간·과매도선·추세 필터 같은 것을 노코드 방식으로 UI에서 조정합니다. 종목 범위(전체 / 표본 / 직접 입력), 기간, 종목당 투입 비율, 최대 보유 수, 슬리피지도 같은 방식이고, 자주 쓰는 조합은 프리셋으로 저장해 다시 부릅니다.
자동매매 관리 화면
자동매매 관리 · 모의투자오늘 무엇을 샀고 팔았는지, 어떤 전략이 켜져 있는지, 다음 후보로 무엇이 대기 중인지를 한 화면에서 봅니다. 종목마다 어느 전략이 낸 거래인지가 붙습니다 — 여러 전략이 같이 돌 때 한 종목을 두고 다투지 않도록 소유권을 정해뒀습니다.
모의투자 계좌 화면입니다. 손익은 그날 시장 상황 그대로이고 보정하지 않았습니다.
텔레그램 원격 알림 — 주문 전송·거부·청산이 실시간으로 전달된다
텔레그램 원격자리에 없을 때 무슨 일이 일어나는지가 그대로 옵니다. 눈여겨볼 것은 성공 기록이 아니라 「주문 거부 — 주문 쿨다운 중」이 세 번 연속 찍힌 부분입니다. 폭주 차단 장치가 실제로 작동한 흔적이고, 이런 것이 안 보이면 시스템이 조용히 무엇을 막았는지 알 방법이 없습니다. 아래로는 손절 청산과 슬롯 해제까지 이어집니다.

그래서 무엇을 발견했나

  1. 전략 교체가 가능한 프레임워크 구조 고객 전략을 DLL 하나로 끼우면 본체 수정 없이 동작하도록 계약 인터페이스를 분리했습니다. "계약 표면 = 고객 진입점의 전이 폐포"로 경계를 정의해, 어디까지가 공개 API이고 어디부터가 내부인지를 명확히 했습니다.
  2. 알고리즘 유출 방지를 빌드로 강제 전략 로직이 판매본 DLL에 섞이면 디컴파일로 노출됩니다. 어셈블리를 8개로 쪼개고 DTO 경계 + 참조 방향 + 빌드 구성 3겹으로 막았습니다. 사람이 조심하는 대신 빌드 스크립트가 위반을 차단합니다.
  3. 실계좌 진입 전 하드닝 감사 독립된 관점으로 전수 감사해 CRITICAL 4건을 잡았습니다. 그중 하나는 비상 정지 스위치가 신규 매수뿐 아니라 청산까지 막고 있던 것 — 위험할 때 팔지도 못하게 되는 결함이었습니다. 청산은 방어 주문으로 분류해 폭주 방지 게이트에서 면제하도록 고쳤습니다.
  4. 거래 안전장치 매도 초과 주문 방지(매도가능수량 소비 모델), 동시호가 시각 계단 처리, 미체결 자동 취소, 재시작 시 보유종목 실시간 구독 유실 복구, dead-man's switch. 실시간 구독 100종목 물리 상한이라는 제약에서 출발해 유니버스를 먼저 좁히는 구조로 재설계했습니다.
C# / .NET Framework 4.7.2 (x86).NET 8WPF · MVVM · DI키움 OpenAPI (COM/OCX)SQLiteMS AccessTelegram BotxUnit

TradingAi_Ver01

2인 공동 개발 365/695 WPF · .NET 8

미국 주식 트레이딩 플랫폼. UI·차트를 제외한 설계와 로직을 담당했습니다 — 도메인 Core, AI·ML 모듈, 데이터 파이프라인, 문서 체계. 지표·전략·드로잉 도구를 플러그인 구조로 설계해 신규 추가가 "구현 1클래스 + 등록 1줄"로 끝나게 만들었습니다.

기간
2026.04 — 2026.07
커밋
365 / 695
코드
+87,377줄
문서
226건
  1. 회귀 결함을 기억이 아니라 검출로 막기 같은 유형의 버그가 반복되자 "세 곳 동시 수정"을 테스트로 강제했습니다. 옵션을 하나 추가하면 저장·복원·렌더 세 곳에 결선해야 하는데, 빠뜨리면 리플렉션 회귀 테스트가 잡습니다. 빌드는 통과하는데 런타임에만 조용히 실패하는 종류를 겨냥한 장치입니다.
  2. Gemini 배치 분류 종목 3,000개를 배치 10 × 동시 3으로 처리해 테마·촉매·실적 요약을 생성합니다. 키 이중화와 재시도 헬퍼를 두어 호출이 거절당해도 작업 전체가 멈추지 않고 이어지게 했습니다.
C# / .NET 8WPF · CommunityToolkit.MvvmGemini APIYahoo FinanceSQLite플러그인 아키텍처

06 — 데이터 검증

제 백테스트 수익률을
제 손으로 1,322%에서 397%로 내렸습니다.

전략을 잘못 만들어서가 아닙니다. 데이터가 거짓말을 하고 있었고, 그걸 찾아내서 내린 숫자입니다. 좋게 나온 결과를 그대로 믿었다면 이 차이만큼 실제 돈으로 확인했을 것입니다.

처음 나온 수치손에 있던 데이터 1,321종목
+1,322.9%
데이터를 고친 뒤거래소 전수 3,211종목
+397.3%
  1. 01
    망한 회사를 지운 데이터로 수익률을 재고 있었습니다 과거 주가를 종목 코드로 요청하면 지금 남아 있는 회사만 돌아옵니다. 망해서 사라진 회사는 목록에 아예 없습니다. 2016년에 실제로 2,065개가 거래되고 있었는데 제 데이터에는 1,321개뿐이었고, 빠진 783개 대부분이 상장폐지된 회사였습니다. 그 종목을 사서 본 손실은 통째로 사라지고 살아남은 종목의 수익만 남으니, 성적이 좋을 수밖에 없었습니다. 요청 방식을 「이 종목의 과거」가 아니라 「이 날짜에 거래된 전부」로 바꾸자 폐지 종목 863개가 저절로 들어왔고, 그때 나온 숫자가 397%입니다.
  2. 02
    검사 결과가 나빠지는 것이 옳은 방향일 때가 있습니다 주가에는 액면분할처럼 회사 사정으로 생긴 인위적인 가격 변동이 섞여 있어 이를 걷어내는 보정을 합니다. 보정이 잘 됐는지 재는 검사에서 이상 건수가 48건 → 2,259건으로 나빠졌는데, 그게 맞는 방향이었습니다. 전에 깨끗했던 이유는 상장폐지 직전의 진짜 폭락까지 인위적 변동으로 오해해 지우고 있었기 때문입니다. 이 검사 수치를 좋게 만들려고 들면 정확히 반대로 갑니다. 지표를 만들 때는 그 지표가 무엇을 보상하는지 먼저 봐야 했습니다.
  3. 03
    수익이 2배가 됐을 때, 실력인지 운인지 재봤습니다 적은 종목에 몰아서 사는 방식이 나눠 사는 것보다 수익이 2배로 나왔습니다. 좋은 발견 같았지만 한 번 돌린 결과로는 실력과 운을 구별할 수 없습니다. 종목 목록에서 70%만 무작위로 뽑아 40번 반복해 성적 분포를 만들었더니, 좋은 결과는 전부 상위 10%에 몰려 있었고 하위 10%는 조금도 나아지지 않았습니다 — 운이었습니다. 잘 나온 실행 하나만 보고 채택했다면 그대로 실계좌에 들어갔을 것입니다.
“안전한 쪽으로 틀리면 괜찮다”는 것은 착각이었습니다. 사라진 회사를 전부 0원으로 처리하면, 다른 회사에 인수돼 정상적으로 사라진 우량주를 산 전략이 부당하게 벌점을 받습니다. 어느 방향으로 틀리든 전략의 순위는 바뀝니다. — 상장폐지 손실을 어떻게 셀지 정하면서

07 — 기술 스택

쓸 수 있는 것

AI · LLM
Google Gemini API · 임베딩 기반 RAG · 청킹 전략 · 프롬프트 엔지니어링(목적별 분리 · 프롬프트 단위 테스트) · 토큰 예산 설계 · 출력 검증층 · 키 이중화와 폴백
ML
LightGBM · scikit-learn · CPCV(누수 방지 교차검증) · 확률 캘리브레이션(Brier · reliability) · SHAP · ablation study · FastAPI 추론 서버
AI 개발 운용
Claude Code 서브에이전트 정의 · 훅 · 커스텀 스킬 · 트리거 기반 문서 라우팅 · 하네스 체계 설계 · 다중 에이전트 교차 검증
언어
C# (.NET 8 / .NET Framework 4.7.2) · Python · SQL
애플리케이션
WPF · MVVM · 의존성 주입 · 플러그인 아키텍처 · WinForms · COM/OCX 상호운용 · 어셈블리 경계 설계 · 직접 렌더링(고빈도 화면 갱신)
실시간 · 동시성
MQTT(브로커 내장 · TLS · 무한 재연결) · 백그라운드 워커 · 배치 커밋 · 잠금 경합 진단 · 멱등 처리(중복 방지) · 부하 상한 설계 · 백프레셔
데이터
SQLite(WAL · 롤업 · 보존정책) · Dapper · MS Access(Jet OLEDB) · 스키마 마이그레이션 · 900만 행 규모 수집 파이프라인 · PIT(시점 정합) 데이터 설계
외부 연동
키움 OpenAPI · KRX OpenAPI · DART OpenAPI · SEC EDGAR · Yahoo Finance · Telegram Bot · MQTT
테스트
xUnit · FluentAssertions · pytest · 배선(end-to-end) 테스트 · 뮤테이션 실측 · 리플렉션 회귀 가드 · UI 자동화 기반 부하·응답성 검증
도메인
증권 매매 체결·주문 흐름 · 백테스트 엔진 설계 · 생존편향/룩어헤드 제거 · 상장폐지 손실 모델링 · 수정주가 보정 · 재무제표(XBRL) 구조 · 포트폴리오 자본 시뮬레이션

08 — 기여 범위

어디까지가 제 작업인지

포트폴리오에서 가장 검증하기 어려운 부분이라 수치로 먼저 밝혀 둡니다.

프로젝트영역내 커밋전체내 코드
FrozenOlaf전체644659+161,795
Alpha-Redline AI전체123123+35,646
TradingAi_Ver01ML (Python)17173,554줄
TradingAi_Ver01LLM 모듈1919
TradingAi_Ver01Core 로직152251
TradingAi_Ver01차트 엔진19102동료 주도
IoTSensorDashboard전체 · 소스 공개4040+23,319
FrozenStudio전체3030+3,176

단독 개발 — FrozenOlaf · Alpha-Redline AI · IoTSensorDashboard · FrozenStudio(매매 성과를 콘텐츠로 만들어 SNS에 게시하는 Python 파이프라인). 설계부터 구현·검증까지 전부 제 작업입니다.

공동 개발 — TradingAi_Ver01은 2인 프로젝트입니다. 저는 UI·차트를 제외한 설계와 로직을 맡았고, ML·LLM 모듈은 단독으로 작성했습니다. 차트 렌더링은 동료의 영역이라 제 실적에 포함하지 않았습니다.

AI 활용 — 위 코드는 Claude Code를 도구로 사용해 작성했습니다. 숨길 이유가 없다고 생각합니다. 다만 설계 결정·검증 방법·기각 판단은 전부 제가 내렸고, 이 문서에 적힌 발견들은 대부분 AI가 내놓은 결과를 제가 의심해서 나온 것입니다. 어느 줄이든 왜 그렇게 됐는지 설명드릴 수 있습니다.

소스 공개 — 금융 프로젝트 소스는 상용화를 전제로 비공개이고, 일부는 공동 소유라 단독으로 공개할 수 없습니다. 대신 제 코드를 직접 보실 수 있도록 IoTSensorDashboard(실시간 관제 시스템 전체 · 코드 2.3만 줄 · 테스트 377건)와 ai-dev-harness(개발 체계)를 공개해 두었습니다. 그 외 구조·설계 결정·검증 근거는 요청 시 상세히 설명드리며, 화면 공유로 코드 리뷰 자리를 만들 수 있습니다.