목차
AI 기반 재무 분석 · 모듈 2
환율/시장지표 모니터링과 비즈니스 영향 분석
모듈 2

환율/시장지표 모니터링과
비즈니스 영향 분석

Open API로 환율을 받아 엑셀 Power Query로 자동 갱신하고, 우리 회사의 외화 노출에 곱해 영향액을 계산한 뒤, 누가 무엇을 확인해야 하는지 알려 주는 경보까지 설계합니다.

예시 회사: 가상 E사 · 2026년 9월 실습 파일: 02_환율영향경보_실습본_v2.xlsx 도구: Excel Power Query · ChatGPT · 한국수출입은행 API

1API와 Open API 소개

1-1API란?

API(Application Programming Interface): 프로그램과 프로그램이 서로 기능이나 데이터를 주고받기 위한 약속된 통로(규칙).

데이터 요청 창구 예시

사용자
우리 서버
OpenDART재무제표 / 공시 / 기업정보
한국수출입은행환율
한국은행금리 / 경제지표
기타 API주가 / 원자재가격 등

여기서 OpenDART나 한국수출입은행 등이 만들어 놓은 데이터 요청 창구 하나하나가 API입니다.

프로그램 기능 호출 예시

내 웹사이트
“이 주소의 위치를 알려줘”
지도 API네이버지도, 카카오지도 등
위도/경도, 지도 데이터
내 웹사이트에 지도 표시

지도 시스템 전체를 직접 개발할 필요 없이, 지도 서비스가 제공하는 API를 호출해서 해당 기능을 가져와 사용합니다.

일반적인 API 요청 방법

  • 서비스 제공자가 발급하는 API Key를 받아서, 일정한 규칙의 API 요청 구문에 추가
  • 서비스 제공자가 정해 놓은 규칙에 맞춰 요청하면 각 요청에 매칭되는 결과(데이터 등)를 반환
  • 일반적으로 호출 횟수 제한, 인증, 유료 요금제 등이 있을 수 있음

1-2Open API란?

Open API(공개 API): 일반적으로 외부 사용자가 사용할 수 있도록 공개된 API.

한국수출입은행이 환율 데이터를 Open API로 제공하는 예시

한국수출입은행 서버
Open API
내 컴퓨터
각종 환율 정보, 금리 정보 등
  • 한국수출입은행 홈페이지에서 API Key 발급 신청이 가능하며, 특별한 사유가 없는 한 바로 발급
  • API Key를 API 요청에 첨부하여 필요한 데이터를 요청할 수 있음

실제 API 요청 예시

https://oapi.koreaexim.go.kr기준 주소
/site/program/financial/exchangeJSON경로
?authkey=발급받은키&searchdate=20260928&data=AP01요청 변수
요청 변수값설명
authkey발급받은 인증키필수
searchdate20260928 (YYYYMMDD)조회일. 생략하면 오늘
dataAP01AP01 환율 / AP02 대출금리 / AP03 국제금리

실제 요청 구문

요청 URL URL
https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON?authkey=ABqpelJFfhPPo7xayg5VCKlz6ZDN3JTO&searchdate=20260928&data=AP01

실제 응답 결과 (한 줄로 길게 옵니다 — 가로로 스크롤)

응답 JSON
[{"result":1,"cur_unit":"CNH","ttb":"199.71","tts":"203.74","deal_bas_r":"201.73","bkpr":"201","yy_efee_r":"0","ten_dd_efee_r":"0","kftc_bkpr":"201","kftc_deal_bas_r":"201.73","cur_nm":"위안화"},{"result":1,"cur_unit":"EUR","ttb":"1,522.65","tts":"1,553.42","deal_bas_r":"1,538.04","bkpr":"1,538","yy_efee_r":"0","ten_dd_efee_r":"0","kftc_bkpr":"1,538","kftc_deal_bas_r":"1,538.04","cur_nm":"유로"},{"result":1,"cur_unit":"GBP","ttb":"1,770.2","tts":"1,805.97","deal_bas_r":"1,788.09","bkpr":"1,788","yy_efee_r":"0","ten_dd_efee_r":"0","kftc_bkpr":"1,788","kftc_deal_bas_r":"1,788.09","cur_nm":"영국 파운드"},{"result":1,"cur_unit":"JPY(100)","ttb":"849.32","tts":"866.47","deal_bas_r":"857.9","bkpr":"857","yy_efee_r":"0","ten_dd_efee_r":"0","kftc_bkpr":"857","kftc_deal_bas_r":"857.9","cur_nm":"일본 옌"},{"result":1,"cur_unit":"USD","ttb":"1,338.48","tts":"1,365.52","deal_bas_r":"1,352","bkpr":"1,352","yy_efee_r":"0","ten_dd_efee_r":"0","kftc_bkpr":"1,352","kftc_deal_bas_r":"1,352","cur_nm":"미국 달러"}]
응답 필드의 뜻
필드뜻
cur_unit통화 코드. 엔화는 JPY(100)
cur_nm통화명
deal_bas_r매매기준율 — 이번 실습에서 쓰는 값
ttb전신환 매입률(송금 받을 때)
tts전신환 매도율(송금 보낼 때)
bkpr장부가격
kftc_deal_bas_r서울외국환중개 매매기준율
yy_efee_r, ten_dd_efee_r년·10일 환가료율
result1 성공 / 2 DATA 코드 오류 / 3 인증 코드 오류 / 4 일일 제한 초과

1-3API 요청 방법

Key = ABqpelJFfhPPo7xayg5VCKlz6ZDN3JTO

① 브라우저 주소창
가장 간단. 단, 추가적인 데이터 처리 불가
② PowerShell
요청하고 받은 데이터를 간단하게 추출
③ Python
프로그래밍으로 복잡한 데이터 분석
④ Excel Power Query
엑셀로 데이터를 불러와 엑셀 안에서 분석 — 이번 모듈의 주 도구

① 브라우저 주소창

브라우저 주소창에 API 요청 구문을 그대로 입력합니다.

브라우저 주소창 URL
https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON?authkey=발급받은키&searchdate=20260928&data=AP01
브라우저 주소창에 API 요청 구문을 넣고 받은 JSON 환율 응답 화면
브라우저 주소창 API 요청 — 통화별 환율이 JSON으로 표시됨 (클릭하면 크게 보기)

② PowerShell

윈도우즈 PowerShell에서 API 요청. 여기서는 USD 한 줄만 추출합니다.

PowerShell PS
$key = "발급받은키"
$r = Invoke-RestMethod "https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON?authkey=$key&searchdate=20260928&data=AP01"
$r | Where-Object { $_.cur_unit -eq "USD" } | Select-Object cur_unit, deal_bas_r, ttb, tts
PowerShell에서 API를 호출해 USD 매매기준율만 추출한 화면
PowerShell API 요청 결과

③ Python

Python PY
import json, urllib.parse, urllib.request

KEY = "발급받은키"
params = urllib.parse.urlencode({"authkey": KEY, "searchdate": "20260928", "data": "AP01"})
url = f"https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON?{params}"

rows = json.load(urllib.request.urlopen(url, timeout=30))
    
usd = next(r for r in rows if r["cur_unit"] == "USD")
rate = float(usd["deal_bas_r"].replace(",", ""))
print("USD 매매기준율:", rate)
Python으로 API를 호출해 USD 매매기준율을 출력한 화면
Python API 요청 결과

④ Excel Power Query

Power Query (M 코드) M
let
    인증키 = "발급받은키",   // 실제 파일에서는 설정 시트에서 읽는다
    응답 = Json.Document(
        Web.Contents(
            "https://oapi.koreaexim.go.kr",
            [
                RelativePath = "site/program/financial/exchangeJSON",
                Query = [authkey = 인증키, searchdate = "20260928", data = "AP01"]
            ]
        )
    ),
    달러 = List.Select(응답, each _[cur_unit] = "USD"),
    결과 = if List.IsEmpty(달러)
           then #table({"통화", "매매기준율"}, {})
           else #table({"통화", "매매기준율"},
                {{"USD", Number.FromText(Text.Remove(달러{0}[deal_bas_r], ","), "en-US")}})
in
    결과
Power Query 고급 편집기에 M 코드를 붙여넣은 화면
① 고급 편집기에 M 코드 붙여넣기
Power Query 편집기에서 USD 매매기준율 1352가 미리보기로 표시되고 적용된 단계가 보이는 화면
② 편집기 미리보기와 적용된 단계
엑셀 시트에 통화와 매매기준율 표가 로드된 화면
③ 엑셀 시트에 표로 로드

2Open API 연동 기초

2-1주요 API 제공 사이트

출처활용Open API 주소
한국은행 ECOS금리·환율·경제통계 시계열ecos.bok.or.kr/api
한국수출입은행 환율 API통화별 고시 환율koreaexim.go.kr/ir/HPHKIR019M01
전자공시시스템(DART)기업 공시 정보(사업보고서, 감사보고서 등)opendart.fss.or.kr
EIA원유·석유제품 가격·재고eia.gov/opendata

각각의 Open API 제공 웹페이지에 들어가면 API Key 발급을 요청할 수 있습니다.

2-2한국수출입은행 환율 API 연결 순서

  1. Open API Key 신청https://www.koreaexim.go.kr/ir/HPHKIR019M01
  2. 발급된 Key 확인ABqpelJFfhPPo7xayg5VCKlz6ZDN3JTO
  3. Open API 개발명세 확인

    요청 URL

    https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON

    요청 변수

    변수명타입변수설명값설명
    authkeyString(필수)인증키OpenAPI 신청 시 발급된 인증키
    searchdateString검색요청날짜예) 2025-01-01, 20250101, (Default) 현재일
    dataString(필수)검색요청API타입AP01: 환율, AP02: 대출금리, AP03: 국제금리

    요청 예시

    https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON요청 URL
    ?authkey=발급받은키authkey
    &searchdate=20260928searchdate
    &data=AP01data

    출력 결과

    출력 결과 (USD 한 건, 주석 포함) JSON
    {
        "result":1,           # 조회 결과(1:성공, 2:data코드오류, 3:인증코드오류, 4:일일제한횟수 마감
        "cur_unit":"USD",     # 통화코드
        "ttb":"1,338.48",     # 전신환(송금) 받으실때
        "tts":"1,365.52",     # 전신환(송금) 보내실때
        "deal_bas_r":"1,352", # 매매 기준율
        "bkpr":"1,352",       # 장부가격
        "yy_efee_r":"0",      # 년환가료율
        "ten_dd_efee_r":"0",  # 10일환가료율
        "kftc_bkpr":"1,352",  # 서울외국환중개 장부가격
        "kftc_deal_bas_r":"1,352",  # 서울외국환중개 매매기준율
        "cur_nm":"미국 달러"    # 국가/통화명
    }

이용 시 유의사항

비영업일의 데이터, 혹은 영업 당일 11시 이전에 해당일의 데이터를 요청할 경우 null 값이 반환됩니다.

2-3메타데이터의 중요성

하나의 “환율” 데이터에도 다양한 정보가 숨어 있습니다.

시각
기준 시각과 타임존
정의
매매기준율, 종가, 중앙값 등 값의 정의
휴일
휴일·주말에는 최근 영업일 값이 반환되거나 결과가 없을 수 있음
단위
JPY는 100엔당 원화로 표시되는 경우가 있음
자릿수
소수점, 반올림 규칙이 다를 수 있음

3엑셀 Power Query 구성하기

3-1엑셀 Power Query 기능 설명

Power Query: 엑셀에서 데이터를 가져오고 정리하는 과정을 기록해 두었다가, 버튼 하나로 다시 실행해 주는 기능.

  • 위치: 데이터 탭 → 데이터 가져오기(가져오기 및 변환)
  • Windows Excel 2016 이상에 기본 내장. Mac용·웹용 Excel은 지원 범위가 다름
복사-붙여넣기와의 차이
항목복사-붙여넣기Power Query
처음 한 번빠름설정이 조금 필요
다음 달처음부터 다시새로 고침 한 번
무엇을 했는지남지 않음단계별로 기록됨
실수사람마다, 매번 다름같은 순서로 반복 → 결과가 같음
핵심Power Query의 장점은 속도가 아니라 재현성. 같은 작업을 매번 똑같이 다시 할 수 있다.
복사-붙여넣기

매번 눈대중으로 요리하는 것

Power Query = 요리 레시피

레시피를 적어 두고, 재료(데이터)만 새로 넣으면 같은 요리가 나오는 것

(1) 기본 흐름 : 가져오기 → 정리 → 내보내기 → 새로 고침

가져오기웹(API), 엑셀, CSV, 폴더 등
정리(변환)필요한 열만 남기기, 글자를 숫자로, 날짜 형식, 필터, 합치기, 피벗
내보내기(로드)엑셀 시트에 표로 (또는 연결만)
새로 고침다음 날·다음 달엔 버튼 하나로 ①~③ 반복
단계하는 일환율 실습에서는
가져오기데이터가 있는 곳에 연결한국수출입은행 API에 날짜별로 요청
정리필요한 형태로 다듬기USD·JPY(100)·CNH·EUR만 남기기, "1,352" → 1352 숫자로
내보내기엑셀 시트에 결과 표 만들기Raw_FX 시트에 로드
새로 고침같은 과정을 다시 실행기간만 바꾸고 [모두 새로 고침]

가져올 수 있는 데이터

  • 파일: 엑셀, CSV, 텍스트, PDF, 폴더(같은 형식 파일 여러 개를 한 번에)
  • 웹: 웹페이지 표, API(JSON·XML)
  • 데이터베이스: SQL Server, Oracle 등 (회사 권한 필요)

(2) Power Query 편집기 화면

데이터 → 데이터 가져오기 → 원본 선택 후 [데이터 변환]을 누르면 편집기가 열립니다.

  • 적용된 단계: 지금까지 한 작업이 순서대로 쌓임. 단계를 클릭하면 그 시점의 데이터를 볼 수 있음. 잘못된 단계는 X로 지우면 됨
  • 수식 입력줄: 선택한 단계가 M 코드 한 줄로 보임
  • 고급 편집기: 모든 단계를 M 코드 전체로 보는 창. 3-2에서 ChatGPT가 준 코드를 붙여넣는 곳
  • 미리 보기: 전체가 아니라 앞부분만 보여 줌. 전체 결과는 시트에 로드해야 확인 가능
[ Power Query 편집기 화면 이미지 — 준비 중 ]

(3) 적용된 단계 = M 코드

화면에서 클릭으로 한 작업은 모두 M 코드라는 언어로 자동 기록됩니다. 반대로, M 코드를 붙여넣으면 그 내용이 적용된 단계로 보입니다.

let
1원본 = ...,적용된 단계 1
2필터 = ...,적용된 단계 2 (앞 단계 이름을 받아서 다음 작업)
3정렬 = ...적용된 단계 3
in정렬최종 결과로 내보낼 단계
  • let 아래에 단계를 쓰고, in 아래에 최종 결과 단계를 씀
  • 각 단계는 바로 앞 단계의 결과를 받아서 다음 작업을 함. 엑셀 셀에서 앞 셀을 참조하는 것과 같은 구조
M 코드를 직접 짤 줄 몰라도 됩니다. 읽을 수 있으면 충분. 코드는 ChatGPT에 요청하고(3-2), 결과는 적용된 단계를 하나씩 눌러 보며 확인합니다.

(4) 내보내기(로드) 방법

편집기에서 홈 → [닫기 및 로드] 또는 [닫기 및 다음으로 로드…]

로드 방법언제 쓰나
표결과를 시트에서 보고 수식으로 계산할 때 (Raw_FX)
연결만 만들기다른 쿼리가 가져다 쓰는 중간 단계, 함수(fn설정)
피벗 테이블 보고서시트에 펼치지 않고 바로 요약할 때

(5) 새로 고침

  • 데이터 → [모두 새로 고침]: 파일 안의 모든 쿼리를 다시 실행
  • 쿼리 및 연결 창 → 쿼리 오른쪽 클릭 → [새로 고침]: 그 쿼리만 다시 실행
  • 쿼리 속성에서 설정 가능한 것
    • 파일을 열 때 새로 고침
    • 다음 간격으로 새로 고침(○분마다): 모니터링 시트를 켜 두면 일정 간격으로 자동 갱신
    • 백그라운드에서 새로 고침: 끄면 오류가 바로 보임 (실습에서는 끄는 것을 권장)

결과 표의 숫자를 손으로 고치면?

  • 새로 고침하면 원래 데이터로 다시 덮어씀. 손으로 고친 값은 사라짐
  • → 결과 표(Raw_FX)는 고치지 않음. 계산은 다른 시트에서 결과 표를 참조해서 함

(6) 처음 연결할 때 만나는 창 두 가지

① 자격 증명 (웹 콘텐츠 액세스)

  • 웹·API에 처음 연결할 때 “어떤 방법으로 접속할지” 묻는 창
  • 공개 API는 익명 선택 → [연결]
  • 한 번 정하면 PC에 저장됨. 잘못 골랐으면 데이터 → 데이터 가져오기 → 데이터 원본 설정 → 권한 지우기

② 개인 정보 수준 (Formula.Firewall 오류)

  • 엑셀 셀 값(Settings의 키·기간)과 웹 데이터를 한 쿼리에서 합치면 뜨는 경고
  • “회사 내부 데이터가 외부 사이트로 새어 나가지 않게” 막는 장치
  • 실습 파일에서는 데이터 → 데이터 가져오기 → 쿼리 옵션 → 현재 통합 문서 → 개인 정보 → 개인 정보 수준 무시
사내 데이터가 든 파일에서는 ‘개인 정보 수준 무시’를 켜지 않습니다. 공개 API와 공개 설정값만 쓰는 실습 파일에서만 사용합니다.

(7) 3장 환율 쿼리를 단계로 읽어 보기

3-2에서 ChatGPT가 만든 코드를 적용된 단계와 짝지어 보면 아래와 같습니다.

M 코드 단계하는 일Power Query 화면에서라면
ApiKey, StartDate, EndDate설정값(Settings 시트에서 읽도록 바꿀 수 있음, 4-1)
DateList9/1~9/30 날짜 목록 만들기목록 만들기
GetExchangeRate하루치 API 요청 → 표로 변환웹에서 가져오기 + JSON을 표로 변환
Filtered4개 통화만 남기기필터(▼)
Converted"1,352" → 1352값 바꾸기(쉼표 제거) + 데이터 형식 변경
Combined30일치 표를 하나로 합치기쿼리 추가(합치기)
Sorted날짜·통화 순 정렬오름차순 정렬
핵심코드가 길어 보여도 결국 가져오기 → 정리 → 합치기 → 정렬의 반복. 단계를 말로 설명하고 코드는 ChatGPT에게 받는다.

3-2ChatGPT 이용하여 Power Query 설정하기

ChatGPT 프롬프트 작성 요령

  1. 기본적인 Open API 정보 제공: 요청URL, 요청변수의 정의 등
  2. 참고 목적의 Open API 개발명세 문서 또는 URL 제공: PDF 파일 또는 URL 주소 등
  3. 사용할 도구 명시: 엑셀 Power Query, Python 등
  4. 얻고자 하는 구체적인 데이터 형태
    • 데이터 값: 매매기준율(deal_bas_r), 환 종류(USD, JPY 등)
    • 데이터 기간: 시작일과 종료일 등으로 설정
ChatGPT 프롬프트 예시 — Power Query 구성 요청
요청URL: https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON

요청변수:
- authkey: 인증키
- searchdate: 검색요청날짜, ex) 2025-01-01, 20250101
- data: 검색요청API타입, AP01: 환율, AP02: 대출금리, AP03: 국제금리

위와 같은 한국수출입은행 Open API에 대해서 엑셀 Power Query를 이용해서 환율 데이터를 가져오려고 해.

더 자세한 내용은 아래 Open API 문서를 참고해줘.
https://www.koreaexim.go.kr/ir/HPHKIR020M01?apino=2&viewtype=C#tab1


아래 조건에 맞게 데이터를 가져올 수 있도록 Power Query를 구성해줘.

API Key: 받은APIKey
요청데이터: deal_bas_r
시작일: 20260901
종료일: 20260930

요청 값 목록:
- 미국 달러(USD)
- 유로(EUR)
- 일본 옌(JPY(100))
- 위안화(CNH)
ChatGPT 프롬프트 결과 답변 원문 보기 펼치기 / 접기

가능합니다. 한국수출입은행 환율 API는 searchdate별로 조회하므로, Power Query에서 2026-09-01부터 2026-09-30까지 날짜 목록을 만든 뒤 하루씩 API를 호출하고 결과를 합치는 방식이 가장 적합합니다.

API 응답에는 cur_unit, cur_nm, deal_bas_r 등의 필드가 포함되고, 요청하신 통화 코드는 실제 응답 기준으로 USD, EUR, JPY(100), CNH입니다. deal_bas_r는 문자열로 반환되며 "1,329.9"처럼 천 단위 쉼표가 포함될 수 있어서 숫자로 변환하는 처리도 넣는 것이 좋습니다. [Dev Log]

Power Query M 코드

Excel에서 데이터 → 데이터 가져오기 → 기타 원본에서 → 빈 쿼리 → 고급 편집기로 들어가서 아래 코드를 그대로 붙여 넣으면 됩니다.

M 코드 — 세로형(날짜·통화별 한 줄) M
let
    // ==============================
    // 설정값
    // ==============================
    ApiKey = "받은APIKey",

    StartDate = #date(2026, 9, 1),
    EndDate   = #date(2026, 9, 30),

    TargetCurrencies = {
        "USD",
        "EUR",
        "JPY(100)",
        "CNH"
    },

    BaseUrl =
        "https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON",

    // ==============================
    // 날짜 목록 생성
    // ==============================
    DateList =
        List.Dates(
            StartDate,
            Duration.Days(EndDate - StartDate) + 1,
            #duration(1, 0, 0, 0)
        ),

    // ==============================
    // 날짜별 API 호출 함수
    // ==============================
    GetExchangeRate = (RequestDate as date) as table =>
        let
            SearchDate =
                Date.ToText(RequestDate, "yyyyMMdd"),

            JsonData =
                try
                    Json.Document(
                        Web.Contents(
                            BaseUrl,
                            [
                                Query = [
                                    authkey = ApiKey,
                                    searchdate = SearchDate,
                                    data = "AP01"
                                ],
                                Timeout = #duration(0, 0, 30, 0)
                            ]
                        )
                    )
                otherwise
                    null,

            // 주말/공휴일 등 데이터가 없는 경우 빈 테이블 반환
            Result =
                if
                    JsonData = null
                    or not Value.Is(JsonData, type list)
                    or List.Count(JsonData) = 0
                then
                    #table(
                        {
                            "date",
                            "cur_unit",
                            "cur_nm",
                            "deal_bas_r"
                        },
                        {}
                    )
                else
                    let
                        Source =
                            Table.FromRecords(JsonData),

                        // 요청 통화만 필터
                        Filtered =
                            Table.SelectRows(
                                Source,
                                each
                                    List.Contains(
                                        TargetCurrencies,
                                        [cur_unit]
                                    )
                            ),

                        // 필요한 컬럼만 선택
                        Selected =
                            Table.SelectColumns(
                                Filtered,
                                {
                                    "cur_unit",
                                    "cur_nm",
                                    "deal_bas_r"
                                },
                                MissingField.UseNull
                            ),

                        // 조회 기준일 추가
                        AddedDate =
                            Table.AddColumn(
                                Selected,
                                "date",
                                each RequestDate,
                                type date
                            ),

                        Reordered =
                            Table.ReorderColumns(
                                AddedDate,
                                {
                                    "date",
                                    "cur_unit",
                                    "cur_nm",
                                    "deal_bas_r"
                                }
                            ),

                        // "1,329.90" → 1329.90 숫자로 변환
                        Converted =
                            Table.TransformColumns(
                                Reordered,
                                {
                                    {
                                        "deal_bas_r",
                                        each
                                            try
                                                Number.FromText(
                                                    Text.Replace(
                                                        Text.From(_),
                                                        ",",
                                                        ""
                                                    ),
                                                    "en-US"
                                                )
                                            otherwise
                                                null,
                                        type number
                                    }
                                }
                            )
                    in
                        Converted
        in
            Result,

    // ==============================
    // 전체 날짜 API 호출
    // ==============================
    DailyTables =
        List.Transform(
            DateList,
            each GetExchangeRate(_)
        ),

    Combined =
        Table.Combine(DailyTables),

    // ==============================
    // 정렬
    // ==============================
    Sorted =
        Table.Sort(
            Combined,
            {
                {"date", Order.Ascending},
                {"cur_unit", Order.Ascending}
            }
        )
in
    Sorted

이렇게 하면 최종 결과는 대략 아래 형태가 됩니다.

datecur_unitcur_nmdeal_bas_r
2026-09-01CNH위안화환율
2026-09-01EUR유로환율
2026-09-01JPY(100)일본 옌환율
2026-09-01USD미국 달러환율
2026-09-02CNH위안화환율
…………

JPY(100)은 100엔 기준 환율이라는 점에 유의하시면 됩니다. 한국수출입은행 API 응답에서도 JPY(100) 형태로 제공됩니다.

주말·공휴일 처리

위 코드에서 중요한 부분은 이 부분입니다.

주말·공휴일 처리 M
if
    JsonData = null
    or not Value.Is(JsonData, type list)
    or List.Count(JsonData) = 0
then
    #table(...)

2026년 9월의 모든 날짜를 조회하되, 주말이나 공휴일 등 환율 데이터가 없는 날은 자동으로 제외합니다. 따라서 결과에는 실제 API에서 데이터를 반환한 영업일만 남게 됩니다.

결과를 날짜별 가로 형태로 만들고 싶다면

실무에서는 아래처럼 만드는 편이 더 편할 수 있습니다.

dateUSDEURJPY(100)CNH
2026-09-011,xxx.xx1,xxx.xxxxx.xxxxx.xx
2026-09-021,xxx.xx1,xxx.xxxxx.xxxxx.xx
……………

그 경우 위 쿼리의 마지막 부분을 다음과 같이 바꾸면 됩니다.

마지막 부분 교체 M
    Combined =
        Table.Combine(DailyTables),

    Pivoted =
        Table.Pivot(
            Combined,
            List.Distinct(Combined[cur_unit]),
            "cur_unit",
            "deal_bas_r",
            List.First
        ),

    RemovedCurrencyName =
        Table.RemoveColumns(
            Pivoted,
            {"cur_nm"}
        ),

    Sorted =
        Table.Sort(
            RemovedCurrencyName,
            {
                {"date", Order.Ascending}
            }
        )
in
    Sorted

다만 cur_nm이 피벗 과정에 들어가는 것을 피하려면 처음부터 피벗 전용 쿼리로 조금 더 깔끔하게 만드는 것이 좋습니다. 원하시는 결과가 일반적으로 Excel에서 사용하는 날짜 | USD | EUR | JPY | CNH 형태라면, 아래처럼 완성형으로 쓰는 것을 추천합니다.

M 코드 — 가로형(날짜 × 통화) 완성형 M
let
    ApiKey = "받은APIKey",

    StartDate = #date(2026, 9, 1),
    EndDate   = #date(2026, 9, 30),

    TargetCurrencies = {
        "USD",
        "EUR",
        "JPY(100)",
        "CNH"
    },

    BaseUrl =
        "https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON",

    DateList =
        List.Dates(
            StartDate,
            Duration.Days(EndDate - StartDate) + 1,
            #duration(1, 0, 0, 0)
        ),

    GetExchangeRate = (RequestDate as date) as table =>
        let
            SearchDate =
                Date.ToText(RequestDate, "yyyyMMdd"),

            JsonData =
                try
                    Json.Document(
                        Web.Contents(
                            BaseUrl,
                            [
                                Query = [
                                    authkey = ApiKey,
                                    searchdate = SearchDate,
                                    data = "AP01"
                                ]
                            ]
                        )
                    )
                otherwise
                    null,

            Result =
                if
                    JsonData = null
                    or not Value.Is(JsonData, type list)
                    or List.Count(JsonData) = 0
                then
                    #table(
                        {"date", "cur_unit", "deal_bas_r"},
                        {}
                    )
                else
                    let
                        T =
                            Table.FromRecords(JsonData),

                        Filtered =
                            Table.SelectRows(
                                T,
                                each
                                    List.Contains(
                                        TargetCurrencies,
                                        [cur_unit]
                                    )
                            ),

                        Selected =
                            Table.SelectColumns(
                                Filtered,
                                {
                                    "cur_unit",
                                    "deal_bas_r"
                                }
                            ),

                        AddedDate =
                            Table.AddColumn(
                                Selected,
                                "date",
                                each RequestDate,
                                type date
                            ),

                        Converted =
                            Table.TransformColumns(
                                AddedDate,
                                {
                                    {
                                        "deal_bas_r",
                                        each
                                            try
                                                Number.FromText(
                                                    Text.Replace(
                                                        Text.From(_),
                                                        ",",
                                                        ""
                                                    ),
                                                    "en-US"
                                                )
                                            otherwise
                                                null,
                                        type number
                                    }
                                }
                            )
                    in
                        Converted
        in
            Result,

    DailyTables =
        List.Transform(
            DateList,
            each GetExchangeRate(_)
        ),

    Combined =
        Table.Combine(DailyTables),

    Pivoted =
        Table.Pivot(
            Combined,
            TargetCurrencies,
            "cur_unit",
            "deal_bas_r",
            List.First
        ),

    Sorted =
        Table.Sort(
            Pivoted,
            {
                {"date", Order.Ascending}
            }
        )
in
    Sorted

Excel에서 최종 사용하기에는 두 번째 코드가 더 적합합니다. 조회 기간이나 API Key도 코드 위쪽의 ApiKey, StartDate, EndDate 세 곳만 수정하면 됩니다.

참고로 API 주소는 사용자께서 주신 oapi.koreaexim.go.kr를 그대로 사용했습니다. 한국수출입은행 API의 일반적인 호출 형태 역시 authkey, searchdate, data=AP01 조합이며, 응답의 매매기준율 필드가 deal_bas_r임을 확인할 수 있습니다. — 출처 표기: Dev Log

ChatGPT가 준 코드 설정하기

데이터→ 데이터 가져오기→ 기타 원본에서→ 빈 쿼리→ 고급 편집기→ 아래 코드 붙여넣기
붙여넣을 M 코드 — 2026-09-01 ~ 09-30, USD·EUR·JPY(100)·CNH M
let
    // ==============================
    // 설정값
    // ==============================
    ApiKey = "받은APIKey",

    StartDate = #date(2026, 9, 1),
    EndDate   = #date(2026, 9, 30),

    TargetCurrencies = {
        "USD",
        "EUR",
        "JPY(100)",
        "CNH"
    },

    BaseUrl =
        "https://oapi.koreaexim.go.kr/site/program/financial/exchangeJSON",

    // ==============================
    // 날짜 목록 생성
    // ==============================
    DateList =
        List.Dates(
            StartDate,
            Duration.Days(EndDate - StartDate) + 1,
            #duration(1, 0, 0, 0)
        ),

    // ==============================
    // 날짜별 API 호출 함수
    // ==============================
    GetExchangeRate = (RequestDate as date) as table =>
        let
            SearchDate =
                Date.ToText(RequestDate, "yyyyMMdd"),

            JsonData =
                try
                    Json.Document(
                        Web.Contents(
                            BaseUrl,
                            [
                                Query = [
                                    authkey = ApiKey,
                                    searchdate = SearchDate,
                                    data = "AP01"
                                ],
                                Timeout = #duration(0, 0, 30, 0)
                            ]
                        )
                    )
                otherwise
                    null,

            // 주말/공휴일 등 데이터가 없는 경우 빈 테이블 반환
            Result =
                if
                    JsonData = null
                    or not Value.Is(JsonData, type list)
                    or List.Count(JsonData) = 0
                then
                    #table(
                        {
                            "date",
                            "cur_unit",
                            "cur_nm",
                            "deal_bas_r"
                        },
                        {}
                    )
                else
                    let
                        Source =
                            Table.FromRecords(JsonData),

                        // 요청 통화만 필터
                        Filtered =
                            Table.SelectRows(
                                Source,
                                each
                                    List.Contains(
                                        TargetCurrencies,
                                        [cur_unit]
                                    )
                            ),

                        // 필요한 컬럼만 선택
                        Selected =
                            Table.SelectColumns(
                                Filtered,
                                {
                                    "cur_unit",
                                    "cur_nm",
                                    "deal_bas_r"
                                },
                                MissingField.UseNull
                            ),

                        // 조회 기준일 추가
                        AddedDate =
                            Table.AddColumn(
                                Selected,
                                "date",
                                each RequestDate,
                                type date
                            ),

                        Reordered =
                            Table.ReorderColumns(
                                AddedDate,
                                {
                                    "date",
                                    "cur_unit",
                                    "cur_nm",
                                    "deal_bas_r"
                                }
                            ),

                        // "1,329.90" → 1329.90 숫자로 변환
                        Converted =
                            Table.TransformColumns(
                                Reordered,
                                {
                                    {
                                        "deal_bas_r",
                                        each
                                            try
                                                Number.FromText(
                                                    Text.Replace(
                                                        Text.From(_),
                                                        ",",
                                                        ""
                                                    ),
                                                    "en-US"
                                                )
                                            otherwise
                                                null,
                                        type number
                                    }
                                }
                            )
                    in
                        Converted
        in
            Result,

    // ==============================
    // 전체 날짜 API 호출
    // ==============================
    DailyTables =
        List.Transform(
            DateList,
            each GetExchangeRate(_)
        ),

    Combined =
        Table.Combine(DailyTables),

    // ==============================
    // 정렬
    // ==============================
    Sorted =
        Table.Sort(
            Combined,
            {
                {"date", Order.Ascending},
                {"cur_unit", Order.Ascending}
            }
        )
in
    Sorted
붙여넣기 전에 ApiKey = "받은APIKey"를 본인이 발급받은 키로 바꿉니다.

4외화 순노출액과 영향 계산

4-1실습 파일 구성

실습 파일: 02_실습데이터/02_환율영향경보_실습본_v2.xlsx (완성본: 02_환율영향경보_완성본_v2.xlsx)

3장에서 만든 쿼리는 API Key와 기간이 코드 안에 직접 들어 있어서, 기간을 바꾸려면 매번 고급 편집기를 열어야 합니다.

Key와 기간을 Settings 시트에서 읽도록 바꾸고, 쿼리는 데이터를 가져오는 일만 하게 합니다. (M 코드: 02_실습데이터/scripts/fx_query/)
Settings키·기간·기준값 Power Queryq환율 Raw_FX FX_Wide Quality데이터 상태 Exposure Scenario Alert등급·알림 문장
시트하는 일
Settings인증키, 시작일·종료일, 데이터원본(API/저장본), 경보 기준, 시나리오 충격. 바꾸는 곳은 여기뿐
Raw_FXPower Query 결과가 들어오는 자리. 직접 고치지 않음
저장본9월 데이터 사본. API가 막히면 데이터원본을 ‘저장본’으로 바꿔서 같은 실습 진행
FX_Wide날짜 × 통화 가로표, 전일 대비·N영업일 대비 변화율
Quality통화별 데이터 상태(OK / MISSING / INVALID / DUPLICATE / STALE / CHECK)
Exposure외화 순노출액과 월초 대비 1차 영향액
Scenario최신 환율에서 ±3%·±5% 움직일 때의 영향
Alert경보 등급과 알림 미리보기 문장
Test방향성 검산, 오류 테스트
칸 색 규칙
파란 글씨+노란 칸 = 입력
연한 노란 칸 = 실습에서 직접 수식을 넣는 칸 (메모에 힌트)
기준값은 이름으로 참조
기준값(3%, 1억 등)은 수식 안에 직접 쓰지 않고 Settings의 이름(기준_Amber변화율 등)으로 참조. 기준을 바꿀 때 수식을 고칠 필요가 없음

4-2순노출액

환율이 움직일 때 회사가 얼마나 영향을 받는지는 외화를 받을 돈과 줄 돈의 차이로 결정됩니다.

순노출액외화 기준
=
예상 외화 유입받을 돈
−
예상 외화 유출줄 돈
+ 양수
외화를 받을 돈이 더 많음 (수취 초과)
− 음수
외화로 줄 돈이 더 많음 (지급 초과)
E사 가상 노출 교육용 가상 데이터모듈 3·4와 같은 회사
통화예상 유입예상 유출순노출액원화 약세(환율 상승) 시
USD5,000,000 USD8,000,000 USD−3,000,000 USD불리
JPY200,000,000 JPY80,000,000 JPY+120,000,000 JPY유리
CNH12,000,000 CNH17,000,000 CNH−5,000,000 CNH불리
EUR000영향 없음
  • 달러를 300만 달러 더 줘야 하는 회사에게 달러 강세는 같은 달러를 사는 데 원화가 더 든다는 뜻. 그래서 불리
  • 엔화를 1.2억 엔 더 받는 회사에게 엔화 강세는 받은 엔화를 원화로 바꾸면 더 많아진다는 뜻. 그래서 유리
  • EUR은 노출이 없음. 환율이 움직여도 영향이 0이어야 함 (검산용으로 남겨 둠)

참고) 실무의 노출은 더 복잡함

  • 외화 자산·부채, 확정 계약, 예상 거래, 파생상품(헤지), 결제 시점, 회계처리가 추가됨
  • 여기서 계산하는 것은 헤지와 가격 전가를 빼고 본 1차 민감도

4-3환율 영향 산식

일반 통화

1차 영향액(원) = 순노출액(외화) × (나중 환율 − 처음 환율)

100엔 기준 JPY

1차 영향액(원) = 순노출액(JPY) ÷ 100 × (나중 환율 − 처음 환율)

왜 JPY만 100으로 나누나?

  • 한국수출입은행 API는 엔화를 JPY(100), 즉 100엔당 원화로 줌 (2026-09-30 기준 863.16원 = 100엔)
  • 1.2억 엔에 863.16원을 그대로 곱하면 100배 큰 숫자가 나옴
  • → Exposure 시트의 표기단위 열이 API코드에 (100)이 있으면 100, 없으면 1을 자동으로 넣음
표기단위 Excel
=IF(ISNUMBER(SEARCH("(100)",B5)),100,1)
이 부호 규칙에서는
환율순노출영향
상승 ↑양수 (수취 초과)+ 유리
상승 ↑음수 (지급 초과)− 불리

4-4Exposure 시트 — 9월 한 달 동안 얼마나 영향을 받았나

“월초(9/1) 대비 최신일(9/30)” 기준으로 영향액을 계산합니다. 월초 환율과 최신 환율은 FX_Wide에서 자동으로 가져옵니다.

열수식실습
순노출액(F)=D5-E5직접 입력
월초환율(H)=INDEX(FX_Wide!$B$4:$E$203,1,MATCH(B5,FX_Wide!$B$3:$E$3,0))제공
최신환율(J)=INDEX(FX_Wide!$B$4:$E$203,값_일수,MATCH(B5,FX_Wide!$B$3:$E$3,0))제공
환율변화(K)=J5-H5제공
1차 영향액(M)=F5/C5*K5직접 입력
E사 9월 결과 한국수출입은행 매매기준율
통화순노출액9/19/30환율변화1차 영향액방향
USD−3,000,0001,373.601,358.40−15.20+45,600,000원유리
JPY(100)+120,000,000859.49863.16+3.67+4,404,000원유리
CNH−5,000,000204.54202.51−2.03+10,150,000원유리
EUR01,595.231,540.29−54.940원영향 없음
합계+60,154,000원유리
[ Exposure 시트 이미지 — 준비 중 ]

주요 포인트

  1. USD줄 달러가 더 많은데, 달러 환율이 15.2원 떨어짐 → 같은 달러를 더 싸게 살 수 있음 → 유리.
  2. JPY받을 엔화가 더 많은데, 엔화 환율이 올라감 → 받은 엔화의 원화 가치가 커짐 → 유리.
  3. CNH줄 위안화가 더 많은데, 위안화 환율이 떨어짐 → 유리.
  4. EUR환율은 3.4%로 가장 크게 움직였지만 노출이 0 → 영향 0. 환율이 많이 움직인 통화가 꼭 중요한 통화는 아님.

9월은 세 통화 모두 유리하게 움직였음. 좋은 소식?

  • 1차 영향일 뿐. 헤지 계약, 실제 결제일, 판매가격 조정은 반영하지 않았음
  • 같은 노출을 그대로 들고 있으면, 환율이 반대로 움직일 때 같은 크기로 불리해짐
  • → “지금까지 얼마”보다 “앞으로 움직이면 얼마”를 같이 봐야 함 (4-5)

4-5Scenario 시트 — 앞으로 움직이면 얼마인가

최신 환율(9/30)에서 일정 비율만큼 움직인다고 가정하고 영향을 계산합니다.

①시나리오환율= 최신환율 × (1 + 충격)
②1차 영향액= 순노출액 ÷ 표기단위 × (시나리오환율 − 최신환율)
Scenario 시트 E5 Excel
=$C5/$B5*($D5*(1+E$3)-$D5)        ← 3행에 충격 비율(Settings에서 연결)
통화별 시나리오 영향 단위: 원
통화Moderate 상승(+3%)Moderate 하락(−3%)Stress 상승(+5%)Stress 하락(−5%)
USD−122,256,000+122,256,000−203,760,000+203,760,000
JPY+31,073,760−31,073,760+51,789,600−51,789,600
CNH−30,376,500+30,376,500−50,627,500+50,627,500
EUR0000
합계−121,558,740+121,558,740−202,597,900+202,597,900

Stress 상승(+5%) 시 통화별 1차 영향액

단위: 백만원 · 막대에 마우스를 올리면 정확한 값이 보입니다

유리(+)불리(−)
  • 네 통화가 모두 같은 방향으로 움직이는 가정. 원화가 전체적으로 5% 약세가 되면 약 2억 원 불리
  • 가장 큰 위험은 USD. 노출 300만 달러 × 환율 1,358원 × 5% ≈ 2억 원

혼합 시나리오 — 통화마다 다르게 움직이는 경우

통화충격1차 영향액
USD+5%−203,760,000
JPY+5%+51,789,600
CNH−5%+50,627,500
합계−101,342,900
  • USD 손실 2억 원 중 절반가량을 JPY·CNH가 메워 줌
핵심통화별 영향은 서로 상쇄될 수 있다. 합계만 보면 USD의 큰 위험이 가려지므로, 통화별 숫자를 같이 본다.

참고) 민감도와 시나리오

  • 민감도: 한 가지만 움직여 봄 (USD만 +5%)
  • 시나리오: 여러 가지가 함께 움직이는 하나의 이야기 (원화 약세 + 위안화 약세)
  • 같은 환율 영향을 원재료비 계산에 한 번 더 넣지 않도록 주의 (중복 반영)

4-6방향성 검산

수식을 믿기 전에 방향이 맞는지 먼저 시험합니다. (Test 시트)

테스트순노출기준환율시나리오환율기대 결과
순노출 001,3501,400영향 0
환율 변화 0−3,000,0001,3501,350영향 0
지급 초과 + 환율 상승−3,000,0001,3501,417.5음수 (−202,500,000)
수취 초과 + 환율 상승 (JPY)+120,000,000900945양수 (+54,000,000)
하나라도 FAIL이면 부호(유입−유출 순서) 또는 표기단위부터 다시 확인합니다.

4-7ChatGPT로 수식 받기

수식을 처음부터 외울 필요는 없습니다. 계산 규칙을 말로 설명하고 수식을 받은 뒤, 검산은 직접 합니다.

ChatGPT 요청 — 1차 영향액 수식
엑셀 Exposure 시트에서 외화 환율 영향액을 계산하려고 해.

열 구성:
- B열: API코드 (USD, JPY(100), CNH, EUR)
- C열: 표기단위 (JPY(100)은 100, 나머지는 1)
- F열: 순노출액(외화) = 유입 - 유출. 음수면 지급 초과
- H열: 월초환율, J열: 최신환율 (원화, 매매기준율)

M열에 1차 영향액(원)을 구하는 수식을 5행 기준으로 만들어 줘.
- JPY는 100엔당 환율이라는 점을 반영할 것
- 환율이 비어 있으면 빈칸으로 둘 것(0으로 채우지 말 것)
- Excel 2016에서도 동작하는 함수만 사용

수식과 함께, 아래 두 경우에 결과가 양수인지 음수인지 설명해 줘.
1) 순노출 -3,000,000 USD, 환율 1,350 → 1,417.5
2) 순노출 +120,000,000 JPY, 환율 900 → 945
  • 받은 수식을 넣은 뒤 Test 시트 4개가 모두 PASS인지 확인
원칙AI가 설명한 부호와 Test 시트 결과가 다르면, AI가 아니라 시트 결과를 믿는다.

5경보 설계

5-1경보의 세 층

경보는 한 종류가 아닙니다. 무엇이 잘못됐는지에 따라 세 층으로 나눕니다.

층무엇을 보나예받는 사람
① 데이터 경보데이터 자체가 믿을 만한가값 누락, 0 이하, 중복, 오래된 데이터데이터 담당자
② 시장 경보환율이 기준 이상 움직였나5영업일 동안 3% 이상 변동모니터링 담당
③ 비즈니스 경보우리 회사 영향이 큰가1차 영향액 1억 원 이상자금·구매·영업 담당
데이터 상태가 OK가 아니면 시장·비즈니스 경보를 계산하지 않습니다. 잘못된 숫자로 울린 경보가 가장 위험합니다.
Quality 시트의 데이터 상태 규칙
상태조건조치
MISSING해당 통화 데이터가 한 건도 없음영향 계산 중단
INVALID환율이 0 이하데이터 오류 후보
DUPLICATE같은 날짜·통화가 2건 이상중복 제거
STALE최신일이 분석 기준일보다 3일 넘게 오래됨원인 확인
CHECK빠진 날이 있거나, 전일 대비 20% 이상 급변원출처 교차 확인
OK위에 해당 없음계산 진행
데이터 상태 판정 Excel
=IF(B4=0,"MISSING",IF(D4>0,"INVALID",IF(E4>0,"DUPLICATE",
 IF(H4>기준_Stale일,"STALE",IF(OR(F4>0,G4>=기준_급변),"CHECK","OK")))))
  • 9월 저장본은 네 통화 모두 20영업일, 상태 OK
  • 실습에서는 Test 시트의 오류 테스트로 일부러 값을 망가뜨려 DATA_CHECK가 뜨는지 확인함

참고) 분석 기준일

  • 실습 파일은 “데이터의 가장 최근 영업일”을 기준으로 오래됨(STALE)을 판단함
  • 실무에서는 TODAY()와 비교해서, 데이터가 갱신되지 않고 멈춰 있는 것도 잡아야 함

5-2나쁜 경보와 좋은 경보

✕ 나쁜 경보

“EUR 3% 하락!”

✓ 좋은 경보

AMBER 2026-09-30 기준 EUR 매매기준율 1,540.29원, 5영업일 전 대비 −3.0%. 순노출 0 EUR, 월초 대비 1차 영향 0원. 헤지·결제시점 미반영. 확인 담당: 자금팀 / 출처: 한국수출입은행 매매기준율

좋은 경보에 들어가는 것

  1. 등급얼마나 급한가
  2. 기준일과 값언제, 무엇이, 얼마나
  3. 우리 노출과 영향액그래서 우리 회사에 얼마인가
  4. 가정무엇을 빼고 계산했나
  5. 담당과 출처누가 확인하고, 숫자는 어디서 왔나
핵심나쁜 경보는 “그래서 뭘 해야 하지?”를 남기고, 좋은 경보는 다음 행동을 알려 준다.

5-3네 종류의 임계값

유형예장점한계
절대 수준USD 1,400원 초과이해가 쉬움기준이 바뀌면 다시 정해야 함
변화율5영업일 ±3%급격한 변화를 잡음노출과 무관하게 울림
변동성과거 움직임 범위 이탈평소와 비교 가능설명이 어려움
영향액1차 영향 1억 원 이상업무 중요성과 바로 연결노출 데이터가 정확해야 함
실습 파일의 기준 Settings
Amber 변화율
3%
Red 변화율
5%
Red 영향액
1억원
100,000,000원
비교 영업일 수(N)
5
Stale 기준
3일
급변 기준
20%

5-4경보 등급 수식

판정 순서 위에서부터 먼저 걸리는 것
순서조건등급
1데이터 상태가 OK 아님DATA_CHECK
2|영향액| ≥ Red 영향액(1억)RED
3|N영업일 변화율| ≥ Red 변화율(5%)RED
4|N영업일 변화율| ≥ Amber 변화율(3%)AMBER
5그 외GREEN
경보 등급 Excel
=IF(OR(C5<>"OK",H5="",J5=""),"DATA_CHECK",
 IF(ABS(J5)>=기준_Red영향액,"RED",
 IF(ABS(H5)>=기준_Red변화율,"RED",
 IF(ABS(H5)>=기준_Amber변화율,"AMBER","GREEN"))))
9월 30일 결과
통화데이터 상태5영업일 변화율
(9/21 → 9/30)
영향액(월초 대비)등급
USDOK−1.8%+45,600,000GREEN
JPY(100)OK−2.0%+4,404,000GREEN
CNHOK−2.1%+10,150,000GREEN
EUROK−3.0%0AMBER
[ Alert 시트 이미지 — 준비 중 ]

EUR은 노출이 0인데 AMBER가 뜸. 이 경보는 필요한가?

  • 변화율 기준만 쓰면 우리와 상관없는 통화에도 경보가 울림
  • 반대로 USD는 영향액이 가장 크지만 변화율이 작아서 GREEN
  • → 그래서 변화율과 영향액 기준을 함께 써야 함. 노출 0인 통화는 “참고용”으로 따로 표시하는 방법도 있음

해 보기

  • Settings의 Amber 변화율을 3% → 1.5%로 바꿔 봄 → 네 통화 모두 AMBER
  • Red 영향액을 1억 → 4천만 원으로 바꿔 봄 → USD가 RED

→ 기준값 하나로 경보 개수가 크게 달라짐. 기준은 감으로 정하지 않고 백테스트(5-7)로 확인합니다.

5-5알림 미리보기 문장

수업에서는 메일·메신저를 실제로 보내지 않고, Alert 시트에 보낼 문장을 수식으로 만들어 봅니다.

문장 틀

[등급] 기준일 기준 통화 매매기준율 ○○원, N영업일 전 대비 ±○.○%.
순노출 ○○ 통화, 월초 대비 1차 영향 ±○○원. 헤지·결제시점 미반영.
확인 담당: ○○ / 출처: 한국수출입은행 매매기준율

수식 (핵심 부분)

알림 문장 Excel
="["&K5&"] "&TEXT(D5,"yyyy-mm-dd")&" 기준 "&A5&" 매매기준율 "&TEXT(E5,"#,##0.00")&"원, "
 &기준_비교영업일&"영업일 전 대비 "&TEXT(H5,"+0.0%;-0.0%;0.0%")
 &". 순노출 "&TEXT(I5,"#,##0")&" "&A5&", 월초 대비 1차 영향 "&TEXT(J5,"+#,##0;-#,##0;0")&"원. ..."
TEXT(값, "형식")
숫자를 보기 좋은 글자로 바꿈. 날짜, 쉼표, 부호(+/−)를 맞춤
&
글자를 이어 붙임
IF
GREEN이면 “(경보 없음)”, DATA_CHECK면 “데이터 상태 확인” 문장이 나오도록 나눔
ChatGPT 요청 — 알림 문장 수식
엑셀 Alert 시트에서 경보 알림 문장을 수식으로 만들고 싶어.
열: A 통화, D 최신일, E 최신환율, H N영업일 변화율, I 순노출액, J 영향액(원), K 등급, L 확인 담당
이름 정의: 기준_비교영업일

문장 틀:
[등급] 날짜 기준 통화 매매기준율 ○○원, N영업일 전 대비 ±○.○%. 순노출 ○○ 통화, 월초 대비 1차 영향 ±○○원. 헤지·결제시점 미반영. 확인 담당: ○○ / 출처: 한국수출입은행 매매기준율

조건:
- K가 GREEN이면 "(경보 없음)"
- K가 DATA_CHECK면 "[DATA_CHECK] 통화 데이터 상태 확인 필요. 확인 담당: ○○"
- 날짜는 yyyy-mm-dd, 환율은 소수 둘째 자리, 금액은 천 단위 쉼표와 +/- 부호
- Excel 2016에서 동작하는 함수만 사용
5행 기준 수식 하나로 만들어 줘.

5-6알림 피로를 줄이는 규칙

경보가 너무 자주 울리면 아무도 보지 않게 됩니다. (양치기 소년)

같은 사건을 새로 고침할 때마다 반복해서 보내지 않음
등급이 바뀌거나 영향이 더 커질 때만 다시 알림
해제 조건을 정해 둠 (예: 2영업일 연속 GREEN이면 해제)
경보마다 담당자와 확인 기한을 정함
데이터 경보와 시장 경보는 받는 채널을 나눔
임계값을 바꾸면 언제, 왜 바꿨는지 기록을 남김

운영 상태 흐름

NEW→ DATA_CHECKED→ IMPACT_CALCULATED→ OWNER_ASSIGNED→ ACKNOWLEDGED→ ACTIONED 또는 CLOSED
핵심경보는 “울리는 것”이 끝이 아니라, 누가 확인하고 무엇을 했는지까지가 한 묶음.

5-7백테스트 — 이 기준이면 9월에 몇 번 울렸나

지금 정한 기준을 과거 데이터에 적용해서, 경보가 몇 번 울렸을지 세어 봅니다. (Alert 시트 아래쪽)

통화계산된 일수AMBER 이상(±3%)RED(±5%)참고: 기준 1.5%면
USD15109일
JPY(100)15005일
CNH15309일
EUR151010일
  • 9월 20영업일 중 앞의 5일은 비교할 5영업일 전 값이 없어서 15일만 계산됨
  • 3% 기준이면 한 달에 몇 번 정도 울리는 수준
  • 기준을 1.5%로 낮추면 USD 9일, JPY 5일, CNH 9일, EUR 10일로 훨씬 자주 울림. Settings 값을 바꿔 가며 개수를 비교해 봄
AMBER 이상 일수 Excel
=COUNTIF(범위,">="&기준_Amber변화율)+COUNTIF(범위,"<="&-기준_Amber변화율)
“민감한 경보”가 항상 좋은 경보는 아닙니다. 중요한 사건을 놓치는 비용과 불필요한 경보의 비용을 같이 봐야 합니다.

5-8실습 정리

실습본의 연한 노란 칸을 순서대로 채웁니다. 막히면 칸에 달린 메모(힌트)를 보거나 ChatGPT에 수식을 요청합니다.

순서시트할 일확인
1Settings데이터원본 확인(API / 저장본), 기간 확인Raw_FX에 80행
2Quality데이터 상태 확인네 통화 OK
3Exposure순노출액(F), 1차 영향액(M) 수식합계 +60,154,000
4Test방향성 검산 영향액(F) 수식4개 PASS
5Scenario±3%·±5% 영향(E~I), 혼합 영향(L) 수식혼합 합계 −101,342,900
6Alert등급(K), 알림 미리보기(M) 수식EUR만 AMBER
7Settings기준값을 바꿔 보며 등급·백테스트 변화 관찰
8Test오류 테스트 7개 중 2개 이상 해 보기DATA_CHECK가 뜨는지
한 줄환율이 움직였다 → 우리 노출에 곱해 보니 얼마다 → 그래서 누가 무엇을 확인한다.