구글 시트 (Google Sheets) 는 매크로 분석가의 스크래치 패드입니다: 업데이트가 빠르고 공유가 쉽고 이미 구글 작업 공간의 나머지 부분과 연결됩니다. 구글 앱 스크립트 ( Google Apps Script) 시트의 내장 자바스크립트 실행 시간 ( JavaScript runtime) 은 브라우저를 떠나지 않고 스프레드시트에서 모든 REST API를 호출할 수 있습니다. 이 가이드는 FXMacroData 발표 데이터를 셰이트 탭으로 끌어내어 셰이트 (Sheets) 탭에 가져갑니다. UrlFetchApp, 속도 제한 및 재시험을 처리, 순수한 행으로 다중 지표 응답을 정상화, 자동 갱신 스케줄 매크로 대시보드가 수동 개입 없이 업데이트 유지.
당신이 무엇을 만들 것인가
- 재사용 가능한 검색 보조기 FXMacroData를 통해 호출합니다.
UrlFetchApp내장된 재시험과 백오프 로직 - 다중 표시기 로더 여러 화폐/지표 쌍을 검색하고 평면 스프레드시트 행으로 각각 정상화합니다
- 시트 작가 이름 붙인 탭을 생성하거나 리셋하고, 헤더를 작성하고, 실행할 때마다 행을 추가합니다
- 시간적 요동 평일 아침마다 자동으로 윗 페이지를 갱신합니다
필수 조건
- 구글 계정 구글 시트 및 앱 스크립트 접속이 가능한 모든 계정
- FXMacroData API 키 등록하세요 / 가입많은 USD 발표 엔드포인트는 초기 테스트를 위한 키 없이 공개적으로 액세스 할 수 있습니다.
- 추가 소프트웨어가 없습니다. 앱 스크립트는 브라우저에서 완전히 실행됩니다. Node.js, 파이썬 또는 로컬 툴링이 필요하지 않습니다.
- 1단계
단계 1 구글 시트를 만들고 앱 스크립트 편집기를 열
열어 sheets.google.com 그리고 새 빈 스프레드시트를 만들어서 FXMacroData 대시보드다음 스크립트 편집기를 열어요:
- 클릭하세요 확장 맨 위에 있는 메뉴 바에서
- 선택하세요 앱 스크립트- 그래요
- 편집기는 기본으로 새 탭으로 열립니다.
Code.gs파일 - 프로젝트의 이름을 바꾸어 (왼쪽 상단 필드) FXMacroData 로더 명확하게 하기 위해서요.
여기서 작성한 모든 코드는 구글의 인프라에서 서버 쪽에서 실행됩니다. UrlFetchApp 을 통해 스프레드시트를 읽고 쓸 수 있습니다.
SpreadsheetApp 서비스
팁: 스크립트 속성으로 API 키를 저장
API 키를 스크립트에서 직접 코드를 입력하지 마세요.
프로젝트 설정 → 스크립트 속성 → 속성 추가 그리고 라는 속성을 추가합니다
FXMACRODATA_API_KEY 아래의 보조 함수들은 이 속성을 실행 시에 PropertiesService.getScriptProperties()-
- 2단계
단계 2 재시험 논리로 검색 보조자를 작성
다음 코드를 에 붙여주세요 Code.gs, 위치 표시기 기능을 대체합니다. 이 보조는 롤링 UrlFetchApp.fetch 지수적 역효율이 있기 때문에 일시적인 오류나 짧은 속도 제한 반응은 전체 실행을 죽이지 않습니다.
/**
* Fetches a FXMacroData endpoint with automatic retry and exponential back-off.
*
* @param {string} currency - e.g. "usd", "eur", "chf"
* @param {string} indicator - e.g. "policy_rate", "gdp", "inflation"
* @returns {Object|null} - Parsed JSON response, or null on permanent failure
*/
function fetchAnnouncement(currency, indicator) {
const apiKey = PropertiesService.getScriptProperties()
.getProperty('FXMACRODATA_API_KEY') || '';
const url = `https://fxmacrodata.com/api/v1/announcements/${currency}/${indicator}`
+ (apiKey ? `?api_key=${apiKey}` : '');
const maxRetries = 4;
let delay = 1000; // 1 second initial back-off
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
const status = response.getResponseCode();
if (status === 200) {
return JSON.parse(response.getContentText());
}
if (status === 429) {
// Rate limited — honour the back-off and retry
Logger.log(`Rate limited on attempt ${attempt}. Waiting ${delay}ms.`);
Utilities.sleep(delay);
delay *= 2; // exponential back-off
continue;
}
if (status === 404) {
Logger.log(`No data for ${currency}/${indicator} (404). Skipping.`);
return null;
}
// Other non-retryable errors
Logger.log(`HTTP ${status} for ${currency}/${indicator}.`);
return null;
} catch (e) {
Logger.log(`Network error on attempt ${attempt}: ${e.message}`);
Utilities.sleep(delay);
delay *= 2;
}
}
Logger.log(`Permanently failed after ${maxRetries} attempts: ${currency}/${indicator}`);
return null;
}
이 보조기에 주목할 만한 몇 가지 사항은:
muteHttpExceptions: true앱 스크립트가 200이 아닌 코드를 던지는 것을 막습니다. 상태 코드를 받아서 무엇을 해야 할지 결정할 수 있습니다.- HTTP 429 (서로 많은 요청) 는 두 배의 지연으로 재시기를 유발합니다. FXMacroData는 키당 비율 제한을 강제합니다. 소박한 백오프 전략은 전체 지표 스웨어에서 스크립트를 예산 내에서 유지합니다.
- HTTP 404 일반적으로 지표가 아직 그 통화에 사용할 수 없다는 것을 의미합니다
null그래서 순서가 깨끗하게 건너뛰어집니다. Logger.log출력도 아래에서 볼 수 있습니다. 보기 → 로그 앱 스크립트 편집기에서 디버깅을 간단하게 합니다.
- 3단계
단계 3 JSON 응답을 스프레드시트 행으로 정규화
FXMacroData 발표 엔드포인트는 통화/지표 쌍 당 단일 객체를 반환합니다. 유용한 스프레드시트를 만들기 위해서는 요청 목록을 일관된 행 구조로 평평화해야합니다. 아래의 정상화 함수를 추가하십시오. fetchAnnouncement
/**
* Converts a FXMacroData announcement response object into a flat array
* suitable for appending as a single Sheets row.
*
* Columns: Timestamp, Currency, Indicator, Value, Prior, Consensus,
* Announcement DateTime, Direction
*
* @param {Object} data - Parsed JSON from fetchAnnouncement()
* @returns {Array} - Flat row array
*/
function toRow(data) {
if (!data) return null;
const direction =
data.val > data.prior ? 'Beat' :
data.val < data.prior ? 'Miss' : 'In line';
return [
new Date().toISOString(), // Run timestamp
(data.currency || '').toUpperCase(),
(data.indicator || '').replace(/_/g, ' '),
data.val ?? '',
data.prior ?? '',
data.consensus ?? '',
data.announcement_datetime || '',
direction
];
}
- announcement_datetime FXMacroData에서 필드는 두 번째 수준의 정확성을 가지고 있습니다. 중앙 은행이나 통계 기관이 판독을 발표 한 정확한 순간입니다. 그 시간표는 중복 키로 이상적입니다. 이 시간표가있는 행이 이미 페이지에 있는지 확인 할 수 있습니다.
- 그 에 대해 consensus 필드
모든 지표가 합의/예보 값을 가지고 있는 것은 아닙니다. 필드가 없는 경우 API는 응답 객체에서 그것을 생략합니다. data.consensus ?? '' 문자열 대신 빈 셀을 안전하게 입력합니다 "undefined"-
4단계
단계 4 데이터 를 Google 셰이트 탭에 입력
이제 모든 것을 연결하는 메인 로더 기능을 추가합니다. 통화/지표 쌍 목록, 통화 fetchAnnouncement, 각 결과를 로 변환합니다.
toRow, 그리고 줄들을 전용 탭으로 추가합니다.
/**
* Defines the currency/indicator pairs to track.
* Extend this list to cover additional signals for your strategy.
*/
const INDICATORS = [
{ currency: 'usd', indicator: 'policy_rate' },
{ currency: 'usd', indicator: 'inflation' },
{ currency: 'usd', indicator: 'non_farm_payrolls' },
{ currency: 'eur', indicator: 'policy_rate' },
{ currency: 'eur', indicator: 'inflation' },
{ currency: 'chf', indicator: 'gdp' },
{ currency: 'chf', indicator: 'consumer_confidence' },
{ currency: 'chf', indicator: 'gov_bond_10y' },
{ currency: 'gbp', indicator: 'policy_rate' },
{ currency: 'gbp', indicator: 'inflation' },
];
const SHEET_NAME = 'MacroData';
const HEADERS = [
'Run Timestamp', 'Currency', 'Indicator', 'Value',
'Prior', 'Consensus', 'Announcement DateTime', 'Direction'
];
/**
* Main entry point — fetches all configured indicators and
* appends new rows to the MacroData sheet tab.
*/
function loadMacroData() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(SHEET_NAME);
// Create the tab if it does not exist yet
if (!sheet) {
sheet = ss.insertSheet(SHEET_NAME);
sheet.appendRow(HEADERS);
sheet.getRange(1, 1, 1, HEADERS.length)
.setFontWeight('bold')
.setBackground('#1a73e8')
.setFontColor('#ffffff');
sheet.setFrozenRows(1);
}
// Build a set of existing announcement_datetimes to avoid duplicates
const lastRow = sheet.getLastRow();
const existing = new Set();
if (lastRow > 1) {
const dtCol = 7; // "Announcement DateTime" is column 7 (index 6, 1-based col 7)
const values = sheet.getRange(2, dtCol, lastRow - 1, 1).getValues();
values.forEach(([dt]) => { if (dt) existing.add(String(dt)); });
}
const newRows = [];
INDICATORS.forEach(({ currency, indicator }) => {
// Throttle requests — 200 ms between calls keeps well within rate limits
Utilities.sleep(200);
const data = fetchAnnouncement(currency, indicator);
const row = toRow(data);
if (!row) return; // skip null / error responses
const announcementDt = row[6]; // announcement_datetime column
if (existing.has(announcementDt)) {
Logger.log(`Skipping duplicate: ${currency}/${indicator} @ ${announcementDt}`);
return;
}
newRows.push(row);
existing.add(announcementDt); // guard against duplicates within the same run
});
if (newRows.length > 0) {
sheet.getRange(sheet.getLastRow() + 1, 1, newRows.length, HEADERS.length)
.setValues(newRows);
Logger.log(`Appended ${newRows.length} new row(s) to "${SHEET_NAME}".`);
} else {
Logger.log('No new rows — all announcements already present.');
}
}
도망가 loadMacroData 편집기에서 수동으로 (클릭 ▶ 달아나첫 실행은 스크립트를 승인하도록 요청합니다 클릭합니다
검토 권한 → 허용 스프레드시트 및 외부 네트워크 요청에 대한 액세스를 허용합니다.
팁: 개발을 위해 "리셋" 기능을 추가
개발 도중에는 시트를 청소하고 처음부터 다시 실행하는 것이 유용합니다. 작은 보조자를 추가하십시오:
function resetSheet() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(SHEET_NAME);
if (sheet) ss.deleteSheet(sheet);
loadMacroData(); // recreates with fresh headers and data
}
- 5단계
단계 5 더 큰 지표 스웨어에서 비율 제한을 조정
The 200 ms inter-request delay in Step 4 is sufficient for the ten-indicator list shown above. If you expand to 50 or more pairs — covering multiple currencies across the full announcement catalogue — you should implement more deliberate throttling. Replace the constant sleep with a counter-based pause:
/**
* Fetches a larger list of indicators with adaptive throttling.
* Pauses for 1 second every 10 requests to respect rate limits.
*/
function loadMacroDataBulk(indicators) {
const ss = SpreadsheetApp.getActiveSpreadsheet();
let sheet = ss.getSheetByName(SHEET_NAME) || (() => {
const s = ss.insertSheet(SHEET_NAME);
s.appendRow(HEADERS);
s.getRange(1, 1, 1, HEADERS.length)
.setFontWeight('bold')
.setBackground('#1a73e8')
.setFontColor('#ffffff');
s.setFrozenRows(1);
return s;
})();
const newRows = [];
let count = 0;
indicators.forEach(({ currency, indicator }) => {
count++;
// Longer pause every 10 requests
if (count % 10 === 0) {
Logger.log(`Pausing after ${count} requests…`);
Utilities.sleep(1500);
} else {
Utilities.sleep(150);
}
const data = fetchAnnouncement(currency, indicator);
const row = toRow(data);
if (row) newRows.push(row);
});
if (newRows.length > 0) {
sheet.getRange(sheet.getLastRow() + 1, 1, newRows.length, HEADERS.length)
.setValues(newRows);
}
Logger.log(`Bulk load complete — ${newRows.length} rows appended.`);
}
FXMacroData 발표 엔드포인트는 빠르다. 각 응답은 일반적으로 Google Apps 스크립트 실행 환경에서 100ms 미만으로 반환됩니다. 큰 스웨이에서 주요 병목은 대기 시간보다는 키 당 요청 예산입니다. Utilities.sleep 방치나 캐시 로직 없이 계획의 한계 안에 있는 가장 간단한 방법입니다.
- 6단계 -
단계 6 시간 조절 트리거로 자동 업데이트를 스케줄링
앱 스크립트 발동기 이 시스템은 전용 서버 없이 일정에서 어떤 함수를 실행할 수 있습니다. 다음 보조는 일일 아침 트리거를 프로그래밍 방식으로 생성합니다.
/**
* Registers a time-driven trigger that runs loadMacroData()
* every weekday between 07:00 and 08:00 UTC.
*
* Run this function ONCE from the Apps Script editor to set up the trigger.
* You do not need to call it again — it persists in the project.
*/
function createWeekdayTrigger() {
// Remove any existing triggers for loadMacroData to avoid duplicates
ScriptApp.getProjectTriggers()
.filter(t => t.getHandlerFunction() === 'loadMacroData')
.forEach(t => ScriptApp.deleteTrigger(t));
ScriptApp.newTrigger('loadMacroData')
.timeBased()
.everyWeeks(1)
.onWeekDay(ScriptApp.WeekDay.MONDAY)
.atHour(7)
.create();
// Also register Tuesday through Friday
[
ScriptApp.WeekDay.TUESDAY,
ScriptApp.WeekDay.WEDNESDAY,
ScriptApp.WeekDay.THURSDAY,
ScriptApp.WeekDay.FRIDAY,
].forEach(day => {
ScriptApp.newTrigger('loadMacroData')
.timeBased()
.everyWeeks(1)
.onWeekDay(day)
.atHour(7)
.create();
});
Logger.log('Weekday triggers registered for loadMacroData.');
}
도망친 후 createWeekdayTrigger열어 발동기 (편집기의 왼쪽 사이드바에 있는 경보 벨 아이콘) 확인하기 위해 다섯 개의 트리거가 나타납니다. 일일마다 하나씩. 각 트리그는 Google 계정으로 구성된 시간대에 07:00에서 08:00 사이에 발사됩니다.
발매 일정에 맞춰
더 수술적인 접근을 위해, FXMacroData 발매 달력 최종점 이 모든 일간을 시작으로, 고효과 발표가 예정된 날을 찾아내기 위해, 그 날에만 전체 지표 스웨어를 실행합니다. 이것은 실행 시간을 짧게하고 API 사용량을 조용한 달력 주에서 낮게 유지합니다.
7단계
단계 7 이벤트 날에 의해 사전 필터링을 출시 달력을 가져오기
- /v1/calendar/{currency} 엔드포인트는 화폐의 예정된 출시를 반환합니다. 월요일에 사용해서 주간 발표 날짜를 세우고, 이벤트 없는 날에는 가져오기 단계를 건너뛰십시오.
/**
* Returns a Set of date strings ("YYYY-MM-DD") for which at least one
* high-impact announcement is scheduled this week for the given currency.
*
* @param {string} currency - e.g. "usd"
* @returns {Set}
*/
function getAnnouncementDatesThisWeek(currency) {
const apiKey = PropertiesService.getScriptProperties()
.getProperty('FXMACRODATA_API_KEY') || '';
const url = `https://fxmacrodata.com/api/v1/calendar/${currency}`
+ (apiKey ? `?api_key=${apiKey}` : '');
const response = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
if (response.getResponseCode() !== 200) return new Set();
const releases = JSON.parse(response.getContentText());
const today = new Date();
const weekEnd = new Date(today);
weekEnd.setDate(today.getDate() + 7);
const dates = new Set();
(releases || []).forEach(event => {
if (!event.release_date) return;
const d = new Date(event.release_date);
if (d >= today && d <= weekEnd) {
dates.add(event.release_date.slice(0, 10));
}
});
return dates;
}
/**
* Calendar-aware version of loadMacroData. * Only runs the full indicator fetch if today has scheduled releases. */ 함수 로드MacroDataCalendarAware (() { const today = new Date (().toISOString (().slice ((0, 10); const currencies = ['usd', 'eur', 'chf', 'gbp']; const hasEvents = currencies.some(c => { const dates = getAnnouncementDatesThisWeek(c); return dates.has(today); }); if (!hasEvents) { Logger.log`오늘 예정된 발매가 없습니다 (${today}).
이 패턴을 사용하려면 등록하세요 loadMacroDataCalendarAware 대신 트리거 핸들러로 loadMacroData 함수 이름 문자열을 로 교체합니다. createWeekdayTrigger
따라서
── 요약 ──
요약
이제 FXMacroData를 앱 스크립트 (Apps Script) 를 통해 Google 시트 (Google Sheets) 에 연결하는 완전한 생산 준비 파이프 라인을 갖게 되었습니다.
- 재시험과 기하급수적인 백오프가 있는 검색 보조기
- 각 발표 응답을 일관성 있고 복제 방지 스프레드시트 행으로 변환하는 정상화 함수
- 첫 실행에서 헤더를 생성하고, 새로운 릴리스만 첨부하고, 이전에 보였던 것을 건너뛰는 시트 라이터
announcement_datetime가치 - 수십 개의 통화/지표 쌍을 가로 질러 대용량 스웨이프에 대한 적응형 스트로틀링
- 일일 시간 조절 트리거로 자동화된 매일 업데이트를 합니다.
- 일정이 정해진 출시가 없는 날에는 불필요한 API 호출을 피하는 선택적인 캘린더 사전 확인.
다음 단계
-
지표 목록 확장 전체 카탈로그를
/api-data-docs
그리고 전략에 맞는 쌍을 추가합니다 (예를 들어
chf/gov_bond_10yeur/pmigbp/employment) -
조건형 형식을 추가 을 강조하는 줄 방향
Beat녹색과Miss빨간색으로 쓰여진SpreadsheetAppConditionalFormatRuleBuilder한눈에 신호를 읽는 데 사용되죠. -
슬랙 또는 이메일로 알림을 푸시 행을 추가한 후, 사용
MailApp.sendEmail또는 웹후크로 전화하는 것loadMacroData높은 영향력 있는 인쇄물이 도착하면 팀에 알릴 수 있습니다. -
역사적인 가치를 추적
발표 최종점
또한 받아들이고 있습니다
start_date/end_date매개 변수 더 긴 날짜 범위에서 일회성 백필을 실행하여 실시간 피드 옆에 역사 탭을 심어줍니다.