TT Lab
블로그 시작하기
배우기 러닝패스 코스

은행 현장의 언어

AML 룰 엔진 만들기

TT Lab 에서 이어서 보기

목표

의심 거래 탐지 규칙 다섯 개를 SQL 과 파이썬으로 구현해 고객별 경보 점수를 내고, 가장 점수가 높은 고객의 의심거래보고 초안을 사실만으로 작성합니다.

왜 중요한가

자금세탁방지(AML)는 은행 IT 가 가장 자주 만나는 규제 업무입니다. 법은 은행에 두 가지 보고 의무를 지웁니다. 하루에 일정 금액 이상의 현금이 오가면 그 자체로 보고하는 고액현금거래보고(CTR), 그리고 금액과 무관하게 자금세탁이 의심되면 보고하는 의심거래보고(STR)입니다. CTR 은 기계적이고, STR 은 판단입니다. 그 판단을 돕는 것이 룰 엔진입니다.

룰 엔진은 화려한 모델이 아닙니다. "하루 현금 합계가 기준을 넘는가", "기준 바로 아래 금액으로 여러 번 쪼갰는가", "고위험 국가와 거래했는가", "고객 확인이 오래됐는가", "오래 쉬던 계좌가 갑자기 큰돈을 움직이는가" 같은 규칙의 묶음입니다. 규칙 하나는 오탐이 많지만, 한 사람에게 여러 규칙이 겹치면 신호가 됩니다. 그래서 규칙마다 가중치를 두고 합산합니다.

이 일에는 두 가지 제약이 따라옵니다. 보고서에는 사실만 적습니다 — 거래 번호, 금액, 날짜, 걸린 규칙. "수상하다" 는 결론이 아니라 근거입니다. 그리고 보고했다는 사실을 고객에게 알리지 않습니다. 이것은 법이 정한 비밀유지 의무이고, 시스템은 그 사실이 채널 화면이나 고객 알림으로 새지 않게 설계돼야 합니다.

이 실습의 규칙 (기준일 2026-08-31)

단계

  1. 오른쪽 예시의 생성기를 /root/bank/make_aml.py 로 저장하고 python3 make_aml.py 로 실행하세요. aml.db 에 고객 20명, 거래 124건, 고위험국 3개가 들어갑니다.
  2. R1 결과를 /root/bank/ctr.csv 에 cust_id,biz_date,direction,cash_total 머리글로 적으세요. direction 은 DEP 또는 WDR 입니다.
  3. R2 결과를 /root/bank/structuring.csv 에 cust_id,txn_count,cash_total,first_date,last_date 머리글로 적으세요.
  4. R3 결과를 /root/bank/highrisk.csv 에 txn_id,cust_id,type,cp_country,amount 머리글로 적으세요.
  5. R4 결과를 /root/bank/kyc_due.csv 에 cust_id,risk_grade,pep,kyc_date,days_since 머리글로, R5 결과를 /root/bank/dormant.csv 에 cust_id,last_activity,first_txn_date,dormant_days,amount 머리글로 적으세요.
  6. 규칙에 하나라도 걸린 고객을 /root/bank/alerts.csv 에 cust_id,rules,score 머리글로, 점수 내림차순(같으면 cust_id 오름차순)으로 적으세요.
  7. 점수가 가장 높은 고객의 보고 초안을 /root/bank/str_<cust_id>.json 에 쓰세요. 키는 cust_id, rules(목록), score, txn_ids(그 고객이 규칙에 걸린 거래 번호 목록), total_amount(그 거래들의 금액 합), narrative(100자 이상, 사실만), prepared_by(사람 이름이 아니라 역할), customer_notified(반드시 false) 입니다.
  8. /root/bank/aml_report.md 에 ## Detection rules and results(탐지 규칙과 결과), ## Reporting targets(보고 대상), ## False positives and limitations(오탐과 한계), ## Confidentiality and personal information(비밀유지와 개인정보) 네 절로 보고서를 쓰세요.

참고

고객·거래 데이터 만들기

오른쪽 예시의 생성기를 /root/bank/make_aml.py 로 저장하고 python3 make_aml.py 로 실행하세요. aml.db 에 고객 20명, 거래 124건, 고위험국 3개가 들어갑니다.

실습 안내에 있는 생성기를 /root/bank/make_aml.py 로 저장하고 python3 로 실행하세요. 손으로 고치면 뒤 단계의 숫자가 전부 어긋납니다.

R1 고액현금 — 하루 합계로 세기

R1 결과를 /root/bank/ctr.csv 에 cust_id,biz_date,direction,cash_total 머리글로 적으세요. direction 은 DEP 또는 WDR 입니다.

현금 유형만 골라 cust_id · substr(ts,1,10) · 방향으로 GROUP BY 하고 HAVING SUM(amount) >= 10000000 을 거세요. 입금과 출금은 따로 합치고, 합계가 딱 1천만 원인 날도 포함합니다. 한 건이 아니라 하루 합계입니다.

R2 분할 의심 — 기준 바로 아래를 세기

R2 결과를 /root/bank/structuring.csv 에 cust_id,txn_count,cash_total,first_date,last_date 머리글로 적으세요.

현금 유형이면서 amount 가 8,000,000 이상 10,000,000 미만인 건을 cust_id 로 묶어 COUNT(*) >= 3 인 사람만 남기세요. 날짜는 MIN/MAX 로 뽑습니다.

R3 고위험국 — 목록과 대조하기

R3 결과를 /root/bank/highrisk.csv 에 txn_id,cust_id,type,cp_country,amount 머리글로 적으세요.

txn 과 high_risk_country 를 cp_country 로 INNER JOIN 하면 끝입니다. 금액 조건은 없습니다. AE 로 나간 2천만 원은 걸리지 않아야 합니다.

R4·R5 — 고객확인 경과와 휴면 후 활동

R4 결과를 /root/bank/kyc_due.csv 에 cust_id,risk_grade,pep,kyc_date,days_since 머리글로, R5 결과를 /root/bank/dormant.csv 에 cust_id,last_activity,first_txn_date,dormant_days,amount 머리글로 적으세요.

R4 는 customer 만으로 됩니다: (risk_grade='HIGH' OR pep=1) AND julianday('2026-08-31')-julianday(kyc_date) >= 365. R5 는 고객별 MIN(ts) 를 먼저 구해(CTE) 그 거래를 다시 조인하세요. 오래 쉬었지만 소액인 사람은 걸리지 않아야 합니다.

규칙을 합쳐 경보 점수 내기

규칙에 하나라도 걸린 고객을 /root/bank/alerts.csv 에 cust_id,rules,score 머리글로, 점수 내림차순(같으면 cust_id 오름차순)으로 적으세요.

2~5단계의 CSV 다섯 개에서 cust_id 를 모아 고객별 규칙 집합을 만들고, 가중치(R1 1 · R2 3 · R3 2 · R4 1 · R5 2)를 더하세요. rules 는 번호순으로 + 로 잇고, 정렬은 점수 내림차순·cust_id 오름차순입니다.

의심거래보고 초안을 사실만으로 쓰기

점수가 가장 높은 고객의 보고 초안을 /root/bank/str_<cust_id>.json 에 쓰세요. 키는 cust_id, rules(목록), score, txn_ids(그 고객이 규칙에 걸린 거래 번호 목록), total_amount(그 거래들의 금액 합), narrative(100자 이상, 사실만), prepared_by(사람 이름이 아니라 역할), customer_notified(반드시 false) 입니다.

alerts.csv 첫 줄이 대상입니다. 그 고객이 걸린 규칙마다 해당 거래(R1 은 그날의 현금, R2 는 8백만~1천만 현금, R3 는 고위험국 거래, R5 는 8월 첫 거래)를 모아 중복을 빼고 정렬하세요. 규칙에 안 걸린 거래는 넣지 않습니다. json.dump 로 쓰고, customer_notified 는 파이썬 False 입니다.

AML 점검 보고서 쓰기

/root/bank/aml_report.md 에 ## Detection rules and results(탐지 규칙과 결과), ## Reporting targets(보고 대상), ## False positives and limitations(오탐과 한계), ## Confidentiality and personal information(비밀유지와 개인정보) 네 절로 보고서를 쓰세요.

task 의 절 제목 네 개(백틱 안의 영어 제목, 또는 괄호 안의 한국어 제목이나 같은 뜻의 일본어·중국어 제목)를 각각 ## 로 시작하는 한 줄로 쓰세요. 탐지 규칙 절에는 경보 고객 수를 「N명」 처럼, 보고 대상 절에는 최고 점수 고객 번호를, 비밀유지 절에는 보고 사실을 고객에게 알리지 않는다는 문장(no tipping-off — 예: the customer is not notified)을 넣으세요. 실명은 적지 마세요.