Yahoo Finance에서 주식 정보 가져오기 (4)

https://overmt.com/yahoo-finance에서-주식-정보-가져오기-1/
의 코드 중 코드 2를 기준으로 chrono crate을 이용한 format_timestamp 함수와 tokio main 매크로에 대해 알아보겠습니다.

Ⅰ. format_timestamp 함수에 대해 알아보기

fn format_timestamp(timestamp: i64) -> String {
match Utc.timestamp_opt(timestamp, 0) {
chrono::LocalResult::Single(datetime) => datetime.format("%Y-%m-%d %H:%M:%S").to_string(),
_ => "Invalid timestamp".to_string(),
}
}

1. 입력값

timestamp: i64 : 이 값은 유닉스 타임스탬프(1970-01-01 00:00:00 UTC 기준의 초 단위 정수) 입니다.

2. Utc.timestamp_opt(timestamp, 0)

  • chrono::Utc는 UTC(협정 세계시) 타임존을 나타냅니다.
  • timestamp_opt(secs, nsecs)는 주어진 초(secs)와 나노초(nsecs)를 UTC 시각으로 변환하려고 시도합니다.
  • 반환값은 -chrono::LocalResult> enum인데, 이에는 세 가지 경우가 있습니다.
    – Single(datetime) → 정상적으로 변환됨
    – None → 변환 불가
    – Ambiguous(, ) → 모호한 시간 (주로 로컬 타임존에서 섬머타임 전환 시 발생, UTC에서는 거의 없음)

3. match 표현식

  • chrono::LocalResult::Single(datetime)일 경우에는 변환된 datetime을 format(“%Y-%m-%d %H:%M:%S”)로 지정한 문자열 포맷(연-월-일 시:분:초)으로 변환하고,
  • 그 밖의 경우(None, Ambiguous)는 “Invalid timestamp”라는 문자열을 반환합니다.

Ⅱ. tokio main 매크로에 대해 알아보기

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let symbols = [
"005930.KS", // 삼성전자
"AAPL", // Apple
"TSLA", // Tesla
"LIT", // Global X Lithium & Battery Tech ETF
"BRK-B", // Berkshire Hathaway Class B
"AMZN", // Amazon
"O", // Realty Income Corporation
"TQQQ", // ProShares UltraPro QQQ
"XOM", // Exxon Mobil
"WMT", // Walmart
];

println!("Fetching stock data...\n");

let results = fetch_multiple_stocks(&symbols).await;

// 테이블 헤더 출력
println!("{:<3} {:<10} {:<35} {:<15} {:<8} {:<20}",
"No.", "Symbol", "Long Name", "Regular Price", "Currency", "Regular Market Time");
println!("{}", "-".repeat(95));

for (i, result) in results.iter().enumerate() {
let row_number = i + 1;
match result {
Ok(stock) => {
println!("{:<3} {:<10} {:<35} {:<15.2} {:<8} {:<20}",
row_number,
stock.symbol,
if stock.long_name.len() > 35 {
format!("{}...", &stock.long_name[..32])
} else {
stock.long_name.clone()
},
stock.regular_market_price,
stock.currency,
format_timestamp(stock.regular_market_time)
);
}
Err(e) => {
println!("{:<3} {:<10} {:<35} {:<15} {:<8} {:<20}",
row_number,
symbols[i],
"Error fetching data",
"N/A",
"N/A",
"N/A"
);
}
}
}

Ok(())
}

1. Tokio 런타임

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
  • #[tokio::main]은 Tokio 비동기 런타임을 사용하는 매크로.
  • async fn main() → 메인 함수 자체가 비동기 함수로 실행됨.
  • 반환 타입이 Result<(), Box<dyn std::error::Error + Send + Sync>>으로서 성공했을 때는 (), 다시 말해 빈 튜플을 반환하므로 아무 값도 안돌려주고, 오류가 발생했을 때 다양한 에러 타입을 동적으로 담아 반환합니다.

2. 주식 심볼 배열

let symbols = [
"005930.KS", // 삼성전자
"AAPL", // Apple
"TSLA", // Tesla
"LIT", // Global X Lithium & Battery Tech ETF
"BRK-B", // Berkshire Hathaway Class B
"AMZN", // Amazon
"O", // Realty Income Corporation
"TQQQ", // ProShares UltraPro QQQ
"XOM", // Exxon Mobil
"WMT", // Walmart
];
  • fetch_multiple_stocks함수의 인수로 전달하기 위해 여러 주식의 티커(symbol)를 배열로 정의합니다.

3. 주식 데이터 가져오기

println!("Fetching stock data...\n");

let results = fetch_multiple_stocks(&symbols).await;
  • “Fetching stock data…” → 데이터 가져오기 시작 알림 출력.
  • fetch_multiple_stocks 함수는 비동기 함수로, 각 심볼에 대해 API 호출을 시도하여 Vec<Result<StockData, Error>> 를 반환함

4. 표 헤더 출력

println!("{:<3} {:<10} {:<35} {:<15} {:<8} {:<20}",
"No.", "Symbol", "Long Name", "Regular Price", "Currency", "Regular Market Time");
println!("{}", "-".repeat(95));
  • {:<n} 포맷은 왼쪽 정렬(Left Align) 하여 n 자리 확보.
  • 따라서 표 형태로 깔끔하게 정렬됨.
  • 이어서 “-“.repeat(95)로 구분선 출력.

5. 각 결과 출력

for (i, result) in results.iter().enumerate() {
let row_number = i + 1;
match result {
Ok(stock) => {
println!("{:<3} {:<10} {:<35} {:<15.2} {:<8} {:<20}",
row_number,
stock.symbol,
if stock.long_name.len() > 35 {
format!("{}...", &stock.long_name[..32])
} else {
stock.long_name.clone()
},
stock.regular_market_price,
stock.currency,
format_timestamp(stock.regular_market_time)
);
}
Err(e) => {
println!("{:<3} {:<10} {:<35} {:<15} {:<8} {:<20}",
row_number,
symbols[i],
"Error fetching data",
"N/A",
"N/A",
"N/A"
);
}
}
}
  • enumerate()를 쓰면 (index, result) 튜플이 넘어옴. row_number = i + 1로 1씩 증가하는 번호를 출력.
    • match result:
      ① 성공(Ok(stock))하면
      – stock(StockData 구조체)를 이용해 주식 데이터를 출력하는데, stock은 result가 성공했을 때 값입니다.
      – stock.symbol 값을 symbol로 출력하고,
      – stock.long_name은 너무 길면 앞의 32자만 출력하고, + “…” 붙여서 가독성을 유지하고,
      – stock.regular_market_price는 소수점 둘째 자리까지 표시하고,({:.2}),
      – 화폐 단위(currency)를 출력하고,
      – stock.regular_market_time은 format_timestamp 함수로 변환하여 표시함

      ② 실패(Err)하면
      – 주어진 symbols[i] 심볼과 함께 “Error fetching data”, “N/A” 값들을 표시.

6. 종료

Ok(())
  • main 함수가 정상 종료됨을 의미.