This report explains how the market data results were produced. The methodology proceeds in two main scripts:
claude_v5.py — Fetches latest
prices from Yahoo Finance (yfinance), computes prior-close changes,
appends snapshots to Parquet, fetches one year of history, and computes
1D/5D/1M/3M/6M/1Y performance returns. Outputs:
claude-market-data_*.csv,
claude-market-data_*.md,
claude-market-performance_*.csv.
market_ytd.py — Imports the asset
list from claude_v5.py, fetches latest prices and
prior-close changes, plus the value at the start of the calendar year
(nearest available close on or before Jan 1). Outputs:
market-ytd_*.csv, market-ytd_*.md.
Both scripts use parallel fetching (ThreadPoolExecutor, max 10 threads) for speed. Data source: Yahoo Finance (yfinance). Full source code is provided in the appendices — copy and paste each script to run it independently (see run instructions above each appendix).
Edit the ASSETS list in claude_v5.py (lines
66–147). Each entry: ("Display Name", "Yahoo Symbol").
Examples: ("Bitcoin", "BTC-USD"),
("Apple", "AAPL"). market_ytd.py imports from
claude_v5.py. Bond yields: CBOE symbols
(^TNX). International bonds: ETF proxies
(IGLT.L, 2561.T).
Latest price, prior close, % change.
Order: US Treasury yields first in yield-curve order (13W → 5Y → 10Y → 30Y); remaining assets by latest timestamp (most recent first).
| Latest prices and prior-close change | |||||||
| Source: claude_v5.py — claude-market-data_20260312_190024.csv | |||||||
| Asset | Latest | Price | Prior Close | % Chg | Opens (ET) | Closes (ET) | Source |
|---|---|---|---|---|---|---|---|
| US 13W T-Bill Yield | 2026-03-11 14:59 ET | 3.600000 | 3.595000 | N/A (yield) | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| US 5Y Treasury Yield | 2026-03-11 14:59 ET | 3.782000 | 3.715000 | N/A (yield) | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| US 10Y Treasury Yield | 2026-03-11 14:59 ET | 4.208000 | 4.136000 | N/A (yield) | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| US 30Y Treasury Yield | 2026-03-11 14:59 ET | 4.857000 | 4.771000 | N/A (yield) | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| USD/JPY | 2026-03-12 06:59 ET | 158.709000 | 159.074000 | -0.23 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| USD/CHF | 2026-03-12 06:59 ET | 0.780820 | 0.781780 | -0.12 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| AUD/USD | 2026-03-12 06:58 ET | 0.713725 | 0.713114 | 0.09 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| USD/CNY | 2026-03-12 06:58 ET | 6.869600 | 6.865000 | 0.07 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| GBP/USD | 2026-03-12 06:58 ET | 1.339400 | 1.338200 | 0.09 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| EUR/USD | 2026-03-12 06:58 ET | 1.156100 | 1.154600 | 0.13 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Bitcoin | 2026-03-12 06:57 ET | 70432.110000 | 70190.370000 | 0.34 | 24/7 | 24/7 | Yahoo Finance (yfinance) |
| Solana | 2026-03-12 06:57 ET | 86.728500 | 86.610300 | 0.14 | 24/7 | 24/7 | Yahoo Finance (yfinance) |
| Ethereum | 2026-03-12 06:56 ET | 2071.250000 | 2050.460000 | 1.01 | 24/7 | 24/7 | Yahoo Finance (yfinance) |
| XRP | 2026-03-12 06:56 ET | 1.389900 | 1.384900 | 0.36 | 24/7 | 24/7 | Yahoo Finance (yfinance) |
| US Dollar Index (DXY) | 2026-03-12 06:49 ET | 99.327000 | 99.474000 | -0.15 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Copper | 2026-03-12 06:49 ET | 5.887000 | 5.838500 | 0.83 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| WTI Crude Oil | 2026-03-12 06:49 ET | 90.950000 | 94.490000 | -3.75 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Wheat | 2026-03-12 06:49 ET | 600.500000 | 600.500000 | 0.00 | 7:00 PM Sun | 1:20 PM Fri | Yahoo Finance (yfinance) |
| Silver | 2026-03-12 06:49 ET | 87.315000 | 85.060000 | 2.65 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Brent Crude Oil | 2026-03-12 06:49 ET | 92.710000 | 95.970000 | -3.40 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Gold | 2026-03-12 06:49 ET | 5188.100000 | 5158.200000 | 0.58 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Natural Gas | 2026-03-12 06:49 ET | 3.219000 | 3.257000 | -1.17 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Corn | 2026-03-12 06:48 ET | 465.000000 | 463.500000 | 0.32 | 7:00 PM Sun | 1:20 PM Fri | Yahoo Finance (yfinance) |
| DAX | 2026-03-12 06:44 ET | 23608.470000 | 23587.330000 | 0.09 | 3:00 AM Mon | 11:30 AM Fri | Yahoo Finance (yfinance) |
| CAC 40 | 2026-03-12 06:44 ET | 8006.500000 | 8014.990000 | -0.11 | 3:00 AM Mon | 11:30 AM Fri | Yahoo Finance (yfinance) |
| FTSE 100 | 2026-03-12 06:44 ET | 10311.000000 | 10318.920000 | -0.08 | 3:00 AM Mon | 11:30 AM Fri | Yahoo Finance (yfinance) |
| iShares UK Gilts ETF | 2026-03-12 06:39 ET | 9.875000 | 9.892500 | -0.18 | 3:00 AM Mon | 11:30 AM Fri | Yahoo Finance (yfinance) |
| Hongkong Land | 2026-03-12 04:59 ET | 8.450000 | 8.350000 | 1.20 | 8:00 PM Sun | ~4:00 AM Fri | Yahoo Finance (yfinance) |
| Hang Seng | 2026-03-12 04:08 ET | 25716.760000 | 25898.760000 | -0.70 | 8:30 PM Sun | 3:00 AM Fri | Yahoo Finance (yfinance) |
| Swire Pacific | 2026-03-12 04:08 ET | 82.750000 | 80.400000 | 2.92 | 8:30 PM Sun | 3:00 AM Fri | Yahoo Finance (yfinance) |
| Hysan Development | 2026-03-12 04:08 ET | 18.420000 | 18.810000 | -2.07 | 8:30 PM Sun | 3:00 AM Fri | Yahoo Finance (yfinance) |
| Sino Land | 2026-03-12 04:08 ET | 11.280000 | 11.700000 | -3.59 | 8:30 PM Sun | 3:00 AM Fri | Yahoo Finance (yfinance) |
| Nikkei 225 | 2026-03-12 02:29 ET | 54384.470000 | 54984.460000 | -1.09 | 7:00 PM Sun | 2:00 AM Fri | Yahoo Finance (yfinance) |
| Suzuki Motor | 2026-03-12 02:24 ET | 2034.500000 | 2099.000000 | -3.07 | 7:00 PM Sun | 2:00 AM Fri | Yahoo Finance (yfinance) |
| Toyota Motor | 2026-03-12 02:24 ET | 3451.000000 | 3521.000000 | -1.99 | 7:00 PM Sun | 2:00 AM Fri | Yahoo Finance (yfinance) |
| iShares JPY Govt Bond | 2026-03-12 01:40 ET | 2093.000000 | 2099.000000 | -0.29 | 7:00 PM Sun | 2:00 AM Fri | Yahoo Finance (yfinance) |
| ASX 200 | 2026-03-12 01:11 ET | 8629.000000 | 8743.500000 | -1.31 | ~6:00 PM Sun | ~12:00 AM Fri | Yahoo Finance (yfinance) |
| BHP Group | 2026-03-12 01:11 ET | 50.980000 | 51.960000 | -1.89 | ~6:00 PM Sun | ~12:00 AM Fri | Yahoo Finance (yfinance) |
| NZX 50 | 2026-03-11 23:46 ET | 13181.770000 | 13281.050000 | -0.75 | ~4:00 PM Sun | ~11:45 PM Thu | Yahoo Finance (yfinance) |
| VIX (Fear Index) | 2026-03-11 15:59 ET | 24.320000 | 24.230000 | N/A (yield) | 9:30 AM Mon | 4:15 PM Fri | Yahoo Finance (yfinance) |
| S&P 500 | 2026-03-11 15:59 ET | 6774.760000 | 6781.480000 | -0.10 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Dow Jones | 2026-03-11 15:59 ET | 47414.250000 | 47706.510000 | -0.61 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| NASDAQ Composite | 2026-03-11 15:59 ET | 22713.000000 | 22697.100000 | 0.07 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Russell 2000 | 2026-03-11 15:59 ET | 2542.660000 | 2548.080000 | -0.21 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Microsoft | 2026-03-11 15:59 ET | 404.820000 | 402.100000 | 0.68 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Apple | 2026-03-11 15:59 ET | 260.810000 | 259.300000 | 0.58 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| NVIDIA | 2026-03-11 15:59 ET | 186.010000 | 184.420000 | 0.86 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Meta | 2026-03-11 15:59 ET | 654.700000 | 648.410000 | 0.97 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Amazon | 2026-03-11 15:59 ET | 212.640000 | 210.720000 | 0.91 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Tesla | 2026-03-11 15:59 ET | 407.840000 | 404.810000 | 0.75 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| ProShares Bitcoin ETF | 2026-03-11 15:59 ET | 9.735000 | 9.670000 | 0.67 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Lululemon | 2026-03-11 15:59 ET | 162.800000 | 162.550000 | 0.15 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Alphabet (Google) | 2026-03-11 15:59 ET | 308.710000 | 305.800000 | 0.95 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| JPMorgan Chase | 2026-03-11 15:59 ET | 287.420000 | 284.500000 | 1.03 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| SPDR Gold Shares | 2026-03-11 15:59 ET | 476.260000 | 471.600000 | 0.99 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
1D, 5D, 1M, 3M, 6M, 1Y % returns from historical daily data.
Order: By 1Y return descending (best performers first). Blank/— = insufficient history (e.g. fewer than 252 trading days for 1Y).
| Performance returns (1D to 1Y) | ||||||||
| Source: claude_v5.py — claude-market-performance_20260312_190024.csv | ||||||||
| Asset | Symbol | Latest | 1D % | 5D % | 1M % | 3M % | 6M % | 1Y % |
|---|---|---|---|---|---|---|---|---|
| Silver | SI=F | 87.290000 | 2.62 | 6.86 | 8.82 | 45.07 | 112.21 | 160.69 |
| Hongkong Land | H78.SI | 8.490000 | 1.07 | 4.17 | 1.43 | 29.03 | 33.28 | 104.02 |
| Alphabet (Google) | GOOGL | 308.700000 | 0.54 | 1.91 | -4.75 | -1.53 | 29 | 86.75 |
| Tesla | TSLA | 407.820000 | 2.15 | 0.46 | -2.28 | -7.23 | 17.54 | 83.58 |
| SPDR Gold Shares | GLD | 476.240000 | -0.34 | 0.94 | 1.97 | 23.56 | 42.56 | 79.01 |
| Gold | GC=F | 5188.600000 | 0.41 | 2.43 | 3.69 | 23.34 | 42.4 | 76.54 |
| NVIDIA | NVDA | 186.030000 | 0.69 | 1.64 | -2.1 | 0.26 | 8.96 | 73.95 |
| Hysan Development | 0014.HK | 18.420000 | -2.07 | -6.59 | -13.49 | 7.29 | 26.77 | 55.46 |
| Sino Land | 0083.HK | 11.280000 | -2.34 | -2.34 | -5.64 | 7.7 | 24.52 | 54.12 |
| Nikkei 225 | ^N225 | 54452.960000 | -1.04 | -1.49 | -3.39 | 7.85 | 28.7 | 46.55 |
| BHP Group | BHP.AX | 50.980000 | -1.89 | -7.56 | 1.72 | 17.27 | 29 | 38.87 |
| WTI Crude Oil | CL=F | 90.900000 | 4.18 | 12.21 | 42.12 | 56.05 | 42.77 | 34.31 |
| Toyota Motor | 7203.T | 3467.000000 | -1.23 | -0.4 | -7.03 | 14.35 | 22.7 | 33.27 |
| Swire Pacific | 0019.HK | 82.750000 | 1.85 | 1.1 | 5.41 | 24.81 | 26.75 | 32.21 |
| Brent Crude Oil | BZ=F | 92.710000 | 0.79 | 8.55 | 34.75 | 49.68 | 37.37 | 30.67 |
| NASDAQ Composite | ^IXIC | 22716.130000 | 0.08 | -0.4 | -2.25 | -3.52 | 3.82 | 30.04 |
| JPMorgan Chase | JPM | 287.520000 | -0.42 | -3.96 | -10.74 | -8.37 | -2.56 | 26.35 |
| Russell 2000 | ^RUT | 2542.900000 | -0.2 | -3.53 | -5.44 | 0.87 | 6.76 | 25.94 |
| Copper | HG=F | 5.886500 | 0.7 | 2.32 | -0.16 | 12.33 | 29.37 | 22.1 |
| FTSE 100 | ^FTSE | 10311.970000 | -0.4 | -0.98 | -1.53 | 6.8 | 11.08 | 20.71 |
| S&P 500 | ^GSPC | 6775.800000 | -0.08 | -1.36 | -2.71 | -1.03 | 4.04 | 20.68 |
| Apple | AAPL | 260.810000 | -0.01 | -0.65 | -5.03 | -6.06 | 11.5 | 15.15 |
| Suzuki Motor | 7269.T | 2036.500000 | -2.77 | -2.16 | -9.93 | -11.19 | 2.2 | 14.2 |
| Dow Jones | ^DJI | 47417.270000 | -0.61 | -2.71 | -5.42 | -0.67 | 3.73 | 13.14 |
| AUD/USD | AUDUSD=X | 0.713725 | 0.23 | 0.87 | 0.88 | 6.93 | 7.34 | 12.2 |
| Hang Seng | ^HSI | 25716.760000 | -0.7 | 1.56 | -3.17 | -1.41 | 2.63 | 12.1 |
| ASX 200 | ^AXJO | 8629.000000 | -1.31 | -3.48 | -4.28 | 0.5 | -2 | 11.35 |
| Wheat | ZW=F | 600.250000 | 2 | 3 | 13.63 | 11.93 | 21.26 | 10.95 |
| Meta | META | 654.860000 | 0.12 | -1.93 | -3.3 | -1.71 | -14.35 | 9.86 |
| Amazon | AMZN | 212.650000 | -0.78 | -1.92 | 1.88 | -6.28 | -10.74 | 9.31 |
| Microsoft | MSFT | 404.880000 | -0.22 | -0.08 | -1.88 | -17.35 | -18.43 | 7.32 |
| US 30Y Treasury Yield | ^TYX | 4.857000 | 1.8 | 2.99 | 0.19 | 0.85 | 2.95 | 7.01 |
| USD/JPY | JPY=X | 158.718000 | 0.38 | 1.11 | 2.74 | 1.88 | 7.48 | 6.2 |
| EUR/USD | EURUSD=X | 1.156200 | -0.42 | -0.63 | -2.76 | -1.19 | -1.4 | 5.69 |
| NZX 50 | ^NZ50 | 13199.290000 | -0.71 | -2.54 | -2.48 | -2.29 | -0.41 | 5.46 |
| DAX | ^GDAXI | 23611.170000 | -0.12 | -0.86 | -5.01 | -1.81 | -0.09 | 4.63 |
| iShares UK Gilts ETF | IGLT.L | 9.875000 | -0.2 | -1.05 | -0.93 | -0.23 | 1.93 | 4.41 |
| GBP/USD | GBPUSD=X | 1.339400 | -0.19 | 0.18 | -1.77 | 0.04 | -1.18 | 3.02 |
| Corn | ZC=F | 465.000000 | 4.67 | 5.32 | 8.45 | 5.5 | 17.05 | 1.86 |
| US 10Y Treasury Yield | ^TNX | 4.208000 | 1.74 | 3.14 | 0.24 | 0.86 | 3.29 | -0.12 |
| CAC 40 | ^FCHI | 8006.750000 | -0.44 | -0.49 | -3.69 | -0.2 | 2.32 | -0.83 |
| US Dollar Index (DXY) | DX-Y.NYB | 99.332000 | 0.1 | 0.01 | 2.62 | 0.11 | 1.59 | -4.13 |
| US 5Y Treasury Yield | ^FVX | 3.782000 | 1.8 | 3.11 | 1.1 | 0.77 | 5.03 | -4.83 |
| USD/CNY | USDCNY=X | 6.869600 | -0.1 | -0.4 | -0.59 | -2.75 | -3.57 | -4.95 |
| VIX (Fear Index) | ^VIX | 25.240000 | 4.17 | 6.27 | 41.88 | 49.08 | 64.43 | -6.24 |
| iShares JPY Govt Bond | 2561.T | 2091.000000 | -0.9 | -0.57 | 1.11 | -1.22 | -3.54 | -7.6 |
| USD/CHF | CHF=X | 0.780810 | 0.29 | 0.21 | 1.59 | -2.32 | -1.99 | -10.94 |
| US 13W T-Bill Yield | ^IRX | 3.600000 | 0.14 | 0.14 | 0.19 | -0.5 | -8.7 | -13.98 |
| ProShares Bitcoin ETF | BITO | 9.730000 | 0.83 | -3.38 | -0.36 | -22.77 | -37.79 | -14.43 |
| Ethereum | ETH-USD | 2071.210000 | 0.96 | 5.17 | 6.31 | -33.28 | -37.47 | -20.06 |
| Natural Gas | NG=F | 3.216000 | 0.22 | 7.09 | 3.24 | -29.69 | 6.17 | -21.25 |
| Bitcoin | BTC-USD | 70430.220000 | 0.32 | 4.69 | 5.19 | -22.63 | -30.47 | -35.77 |
| XRP | XRP-USD | 1.390100 | 0.38 | 2.48 | -1.16 | -34.49 | -37.12 | -38.43 |
| Solana | SOL-USD | 86.745600 | 0.21 | 4.29 | 5.28 | -37.27 | -44.06 | -43.08 |
| Lululemon | LULU | 162.790000 | -2.19 | -6.02 | -7.34 | -11.06 | -1.75 | -51.23 |
Latest price, prior close, % change, and year-to-date (YTD) change from the nearest available close on or before 1 January to latest.
Order: By latest timestamp (most recent first).
| Prior close and YTD change | |||||||||||
| Source: market_ytd.py — market-ytd_20260312_173752.csv | |||||||||||
| Asset | Symbol | Latest | Price | Prior Close | % Chg | YTD Date | YTD Value | YTD % Chg | Opens | Closes | Source |
|---|---|---|---|---|---|---|---|---|---|---|---|
| USD/CHF | CHF=X | 2026-03-12 05:37 ET | 0.780820 | 0.781780 | -0.12 | 2025-12-31 | 0.7917 | -1.37 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| USD/CNY | USDCNY=X | 2026-03-12 05:37 ET | 6.872300 | 6.865000 | 0.11 | 2025-12-31 | 6.9961 | -1.77 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| USD/JPY | JPY=X | 2026-03-12 05:37 ET | 158.830000 | 159.074000 | -0.15 | 2025-12-31 | 156.4130 | 1.55 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| AUD/USD | AUDUSD=X | 2026-03-12 05:36 ET | 0.713419 | 0.713114 | 0.04 | 2025-12-31 | 0.6698 | 6.51 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| GBP/USD | GBPUSD=X | 2026-03-12 05:36 ET | 1.338800 | 1.338200 | 0.04 | 2025-12-31 | 1.3467 | -0.59 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| EUR/USD | EURUSD=X | 2026-03-12 05:36 ET | 1.156100 | 1.154600 | 0.13 | 2025-12-31 | 1.1747 | -1.59 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Solana | SOL-USD | 2026-03-12 05:35 ET | 85.708600 | 86.610300 | -1.04 | 2026-01-01 | 126.7611 | -32.39 | 24/7 | 24/7 | Yahoo Finance (yfinance) |
| Bitcoin | BTC-USD | 2026-03-12 05:35 ET | 69795.990000 | 70190.370000 | -0.56 | 2026-01-01 | 88731.9800 | -21.34 | 24/7 | 24/7 | Yahoo Finance (yfinance) |
| Ethereum | ETH-USD | 2026-03-12 05:34 ET | 2041.480000 | 2050.460000 | -0.44 | 2026-01-01 | 3000.3900 | -31.96 | 24/7 | 24/7 | Yahoo Finance (yfinance) |
| XRP | XRP-USD | 2026-03-12 05:34 ET | 1.377200 | 1.384900 | -0.55 | 2026-01-01 | 1.8779 | -26.66 | 24/7 | 24/7 | Yahoo Finance (yfinance) |
| US Dollar Index (DXY) | DX-Y.NYB | 2026-03-12 05:27 ET | 99.349000 | 99.474000 | -0.13 | 2025-12-31 | 98.2800 | 1.09 | 5:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Gold | GC=F | 2026-03-12 05:27 ET | 5185.800000 | 5158.200000 | 0.54 | 2025-12-31 | 4325.6000 | 19.89 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Brent Crude Oil | BZ=F | 2026-03-12 05:27 ET | 94.420000 | 95.970000 | -1.62 | 2025-12-31 | 60.8500 | 55.17 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Copper | HG=F | 2026-03-12 05:27 ET | 5.889000 | 5.838500 | 0.86 | 2025-12-31 | 5.6300 | 4.60 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Silver | SI=F | 2026-03-12 05:27 ET | 87.065000 | 85.060000 | 2.36 | 2025-12-31 | 70.1340 | 24.14 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| WTI Crude Oil | CL=F | 2026-03-12 05:27 ET | 92.780000 | 94.490000 | -1.81 | 2025-12-31 | 57.4200 | 61.58 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Natural Gas | NG=F | 2026-03-12 05:27 ET | 3.265000 | 3.257000 | 0.25 | 2025-12-31 | 3.6860 | -11.42 | 6:00 PM Sun | 5:00 PM Fri | Yahoo Finance (yfinance) |
| Corn | ZC=F | 2026-03-12 05:27 ET | 465.000000 | 463.500000 | 0.32 | 2025-12-31 | 440.2500 | 5.62 | 7:00 PM Sun | 1:20 PM Fri | Yahoo Finance (yfinance) |
| Wheat | ZW=F | 2026-03-12 05:27 ET | 602.000000 | 600.500000 | 0.25 | 2025-12-31 | 507.0000 | 18.74 | 7:00 PM Sun | 1:20 PM Fri | Yahoo Finance (yfinance) |
| DAX | ^GDAXI | 2026-03-12 05:22 ET | 23493.710000 | 23587.330000 | -0.40 | 2025-12-30 | 24490.4100 | -4.07 | 3:00 AM Mon | 11:30 AM Fri | Yahoo Finance (yfinance) |
| CAC 40 | ^FCHI | 2026-03-12 05:22 ET | 7978.550000 | 8014.990000 | -0.45 | 2025-12-31 | 8149.5000 | -2.10 | 3:00 AM Mon | 11:30 AM Fri | Yahoo Finance (yfinance) |
| FTSE 100 | ^FTSE | 2026-03-12 05:22 ET | 10288.940000 | 10318.920000 | -0.29 | 2025-12-31 | 9931.4000 | 3.60 | 3:00 AM Mon | 11:30 AM Fri | Yahoo Finance (yfinance) |
| iShares UK Gilts ETF | IGLT.L | 2026-03-12 05:16 ET | 9.867500 | 9.892500 | -0.25 | 2025-12-31 | 9.9125 | -0.45 | 3:00 AM Mon | 11:30 AM Fri | Yahoo Finance (yfinance) |
| Hongkong Land | H78.SI | 2026-03-12 04:59 ET | 8.450000 | 8.350000 | 1.20 | 2025-12-31 | 6.9500 | 21.58 | 8:00 PM Sun | ~4:00 AM Fri | Yahoo Finance (yfinance) |
| Hang Seng | ^HSI | 2026-03-12 04:08 ET | 25716.760000 | 25898.760000 | -0.70 | 2025-12-31 | 25630.5400 | 0.34 | 8:30 PM Sun | 3:00 AM Fri | Yahoo Finance (yfinance) |
| Hysan Development | 0014.HK | 2026-03-12 04:08 ET | 18.420000 | 18.810000 | -2.07 | 2025-12-31 | 18.0601 | 1.99 | 8:30 PM Sun | 3:00 AM Fri | Yahoo Finance (yfinance) |
| Swire Pacific | 0019.HK | 2026-03-12 04:08 ET | 82.750000 | 80.400000 | 2.92 | 2025-12-31 | 62.7000 | 31.98 | 8:30 PM Sun | 3:00 AM Fri | Yahoo Finance (yfinance) |
| HK & China Gas | 0083.HK | 2026-03-12 04:08 ET | 11.280000 | 11.700000 | -3.59 | 2025-12-31 | 10.0791 | 11.91 | 8:30 PM Sun | 3:00 AM Fri | Yahoo Finance (yfinance) |
| Nikkei 225 | ^N225 | 2026-03-12 02:29 ET | 54384.470000 | 54984.460000 | -1.09 | 2025-12-30 | 50339.4800 | 8.04 | 7:00 PM Sun | 2:00 AM Fri | Yahoo Finance (yfinance) |
| Suzuki Motor | 7269.T | 2026-03-12 02:24 ET | 2034.500000 | 2099.000000 | -3.07 | 2025-12-30 | 2334.5000 | -12.85 | 7:00 PM Sun | 2:00 AM Fri | Yahoo Finance (yfinance) |
| Toyota Motor | 7203.T | 2026-03-12 02:24 ET | 3451.000000 | 3521.000000 | -1.99 | 2025-12-30 | 3356.0000 | 2.83 | 7:00 PM Sun | 2:00 AM Fri | Yahoo Finance (yfinance) |
| iShares JPY Govt Bond | 2561.T | 2026-03-12 01:40 ET | 2093.000000 | 2099.000000 | -0.29 | 2025-12-30 | 2098.9700 | -0.28 | 7:00 PM Sun | 2:00 AM Fri | Yahoo Finance (yfinance) |
| ASX 200 | ^AXJO | 2026-03-12 01:11 ET | 8629.000000 | 8743.500000 | -1.31 | 2025-12-31 | 8714.3000 | -0.98 | ~6:00 PM Sun | ~12:00 AM Fri | Yahoo Finance (yfinance) |
| BHP Group | BHP.AX | 2026-03-12 01:11 ET | 50.980000 | 51.960000 | -1.89 | 2025-12-31 | 44.6416 | 14.20 | ~6:00 PM Sun | ~12:00 AM Fri | Yahoo Finance (yfinance) |
| NZX 50 | ^NZ50 | 2026-03-11 23:46 ET | 13181.770000 | 13281.050000 | -0.75 | 2025-12-31 | 13548.4200 | -2.71 | ~4:00 PM Sun | ~11:45 PM Thu | Yahoo Finance (yfinance) |
| VIX (Fear Index) | ^VIX | 2026-03-11 15:59 ET | 24.320000 | 24.230000 | N/A (yield) | 2025-12-31 | 14.9500 | 62.68 | 9:30 AM Mon | 4:15 PM Fri | Yahoo Finance (yfinance) |
| S&P 500 | ^GSPC | 2026-03-11 15:59 ET | 6774.760000 | 6781.480000 | -0.10 | 2025-12-31 | 6845.5000 | -1.03 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Dow Jones | ^DJI | 2026-03-11 15:59 ET | 47414.250000 | 47706.510000 | -0.61 | 2025-12-31 | 48063.2900 | -1.35 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| NASDAQ Composite | ^IXIC | 2026-03-11 15:59 ET | 22713.000000 | 22697.100000 | 0.07 | 2025-12-31 | 23241.9900 | -2.28 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Russell 2000 | ^RUT | 2026-03-11 15:59 ET | 2542.660000 | 2548.080000 | -0.21 | 2025-12-31 | 2481.9100 | 2.45 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Apple | AAPL | 2026-03-11 15:59 ET | 260.810000 | 259.300000 | 0.58 | 2025-12-31 | 271.6058 | -3.97 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Amazon | AMZN | 2026-03-11 15:59 ET | 212.640000 | 210.720000 | 0.91 | 2025-12-31 | 230.8200 | -7.88 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Meta | META | 2026-03-11 15:59 ET | 654.700000 | 648.410000 | 0.97 | 2025-12-31 | 660.0900 | -0.82 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| NVIDIA | NVDA | 2026-03-11 15:59 ET | 186.010000 | 184.420000 | 0.86 | 2025-12-31 | 186.4899 | -0.26 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Alphabet (Google) | GOOGL | 2026-03-11 15:59 ET | 308.710000 | 305.800000 | 0.95 | 2025-12-31 | 312.7798 | -1.30 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Tesla | TSLA | 2026-03-11 15:59 ET | 407.840000 | 404.810000 | 0.75 | 2025-12-31 | 449.7200 | -9.31 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| ProShares Bitcoin ETF | BITO | 2026-03-11 15:59 ET | 9.735000 | 9.670000 | 0.67 | 2025-12-31 | 12.1307 | -19.75 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Lululemon | LULU | 2026-03-11 15:59 ET | 162.800000 | 162.550000 | 0.15 | 2025-12-31 | 207.8100 | -21.66 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| Microsoft | MSFT | 2026-03-11 15:59 ET | 404.820000 | 402.100000 | 0.68 | 2025-12-31 | 482.5187 | -16.10 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| SPDR Gold Shares | GLD | 2026-03-11 15:59 ET | 476.260000 | 471.600000 | 0.99 | 2025-12-31 | 396.3100 | 20.17 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| JPMorgan Chase | JPM | 2026-03-11 15:59 ET | 287.420000 | 284.500000 | 1.03 | 2025-12-31 | 320.7731 | -10.40 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| US 13W T-Bill Yield | ^IRX | 2026-03-11 14:59 ET | 3.600000 | 3.595000 | N/A (yield) | 2025-12-31 | 3.5470 | 1.49 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| US 10Y Treasury Yield | ^TNX | 2026-03-11 14:59 ET | 4.208000 | 4.136000 | N/A (yield) | 2025-12-31 | 4.1630 | 1.08 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| US 30Y Treasury Yield | ^TYX | 2026-03-11 14:59 ET | 4.857000 | 4.771000 | N/A (yield) | 2025-12-31 | 4.8400 | 0.35 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
| US 5Y Treasury Yield | ^FVX | 2026-03-11 14:59 ET | 3.782000 | 3.715000 | N/A (yield) | 2025-12-31 | 3.7220 | 1.61 | 9:30 AM Mon | 4:00 PM Fri | Yahoo Finance (yfinance) |
To run independently: Copy the entire code block
below, save as claude_v5.py, then run
python claude_v5.py from a terminal. Prerequisites:
pip install yfinance (optionally
pandas pyarrow for Parquet storage). Outputs go to a
reports/ folder created automatically.
#!/usr/bin/env python3
"""
Fetch latest market data from Yahoo Finance (open source, free).
Outputs MD and CSV tables with: Asset, Latest Date/Time, Latest Price, Prior Close, % Chg, Opens, Closes, Source.
Output files: reports/claude-market-data_YYYYMMDD_HHMMSS.csv, reports/claude-market-data_YYYYMMDD_HHMMSS.md,
reports/claude-market-performance_YYYYMMDD_HHMMSS.csv (with latest_price, 1D/5D/1M/3M/6M/1Y %)
Improvements over v1:
- Bond yields (US 2Y/10Y/30Y, UK, Germany, Japan)
- VIX, DXY, more commodities, more crypto
- Parallel fetching via ThreadPoolExecutor (~5–10x faster)
- Robust prior-close logic (fast_info first, daily fallback)
- Fixed naive-datetime TZ assumption (daily bars are date-only)
- sort_key not exposed in public API
- fmt_price handles negatives correctly
Usage from Python:
from fetch_market_data import get_prices
prices = get_prices()
# list of dicts: asset, symbol, latest_datetime, latest_price,
# prior_close, pct_change, opens, closes, source
"""
import csv
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Tuple
try:
import pytz
ET = pytz.timezone("America/New_York")
except ImportError:
try:
from dateutil import tz
ET = tz.gettz("America/New_York")
except ImportError:
ET = None
try:
import yfinance as yf
except ImportError:
print("Installing yfinance...")
import subprocess
subprocess.check_call(["pip", "install", "yfinance", "-q"])
import yfinance as yf
try:
import pandas as pd
_HAS_PANDAS = True
except ImportError:
_HAS_PANDAS = False
try:
import pyarrow
_HAS_PARQUET = True
except ImportError:
_HAS_PARQUET = False
# ---------------------------------------------------------------------------
# Asset universe — ordered by market open chronology (ET)
# Sections: 24/7 | Bond Yields | Forex | Commodities | Volatility/Dollar |
# Asia-Pacific Indices | European Indices | US Indices | US Megacaps
# ---------------------------------------------------------------------------
ASSETS = [
# 24/7 — never closes
("Bitcoin", "BTC-USD"),
("Ethereum", "ETH-USD"),
("Solana", "SOL-USD"),
("XRP", "XRP-USD"),
# Bond Yields — only CBOE ^-series work reliably on Yahoo Finance
# International =X yield tickers (GB10Y=X, DE10Y=X, JP10Y=X) are broken/delisted.
# Use liquid bond ETFs as proxies for UK, EU, Japan instead.
("US 13W T-Bill Yield", "^IRX"), # short end
("US 5Y Treasury Yield", "^FVX"),
("US 10Y Treasury Yield", "^TNX"),
("US 30Y Treasury Yield", "^TYX"),
("iShares UK Gilts ETF", "IGLT.L"), # UK gilt proxy (LSE-listed)
("iShares EUR Govt Bond", "IBGM.DE"), # EUR/Bund proxy (XETRA)
("iShares JPY Govt Bond", "2561.T"), # Japan JGB ETF (TSE)
# Forex — opens 5:00 PM Sun ET
("EUR/USD", "EURUSD=X"),
("GBP/USD", "GBPUSD=X"),
("USD/JPY", "JPY=X"),
("USD/CHF", "CHF=X"),
("AUD/USD", "AUDUSD=X"),
("USD/CNY", "USDCNY=X"),
# USD Index & Volatility
("US Dollar Index (DXY)", "DX-Y.NYB"),
("VIX (Fear Index)", "^VIX"),
# NZX (New Zealand) — opens ~4:00–5:00 PM Sun ET
("NZX 50", "^NZ50"),
# CME Globex — opens 6:00 PM Sun ET
("WTI Crude Oil", "CL=F"),
("Brent Crude Oil", "BZ=F"),
("Gold", "GC=F"),
("Silver", "SI=F"),
("Copper", "HG=F"),
("Natural Gas", "NG=F"),
("Corn", "ZC=F"),
("Wheat", "ZW=F"),
# ASX (Australia) — opens ~6:00–7:00 PM Sun ET
("ASX 200", "^AXJO"),
# Tokyo (TSE) — opens 7:00 PM Sun ET
("Nikkei 225", "^N225"),
# Hong Kong (HKEX) — opens 8:30 PM Sun ET
("Hang Seng", "^HSI"),
# London / Europe — opens 3:00 AM Mon ET
("FTSE 100", "^FTSE"),
("DAX", "^GDAXI"),
("CAC 40", "^FCHI"),
# New York — opens 9:30 AM Mon ET
("S&P 500", "^GSPC"),
("Dow Jones", "^DJI"),
("NASDAQ Composite", "^IXIC"),
("Russell 2000", "^RUT"),
("Apple", "AAPL"),
("Microsoft", "MSFT"),
("NVIDIA", "NVDA"),
("Amazon", "AMZN"),
("Alphabet (Google)", "GOOGL"),
("Tesla", "TSLA"),
("Meta", "META"),
# Additional stocks
("BHP Group", "BHP.AX"),
("ProShares Bitcoin ETF", "BITO"),
("Lululemon", "LULU"),
("Hongkong Land", "H78.SI"),
("Suzuki Motor", "7269.T"),
("Toyota Motor", "7203.T"),
("Swire Pacific", "0019.HK"),
("Hysan Development", "0014.HK"),
("JPMorgan Chase", "JPM"),
("Sino Land", "0083.HK"),
("SPDR Gold Shares", "GLD"),
]
SOURCE = "Yahoo Finance (yfinance)"
# Trading hours (ET) per asset
TRADING_HOURS: Dict[str, Tuple[str, str]] = {
"Bitcoin": ("24/7", "24/7"),
"Ethereum": ("24/7", "24/7"),
"Solana": ("24/7", "24/7"),
"XRP": ("24/7", "24/7"),
# Bond yields
"US 13W T-Bill Yield": ("9:30 AM Mon", "4:00 PM Fri"),
"US 5Y Treasury Yield": ("9:30 AM Mon", "4:00 PM Fri"),
"US 10Y Treasury Yield": ("9:30 AM Mon", "4:00 PM Fri"),
"US 30Y Treasury Yield": ("9:30 AM Mon", "4:00 PM Fri"),
"iShares UK Gilts ETF": ("3:00 AM Mon", "11:30 AM Fri"),
"iShares EUR Govt Bond": ("3:00 AM Mon", "11:30 AM Fri"),
"iShares JPY Govt Bond": ("7:00 PM Sun", "2:00 AM Fri"),
"EUR/USD": ("5:00 PM Sun", "5:00 PM Fri"),
"GBP/USD": ("5:00 PM Sun", "5:00 PM Fri"),
"USD/JPY": ("5:00 PM Sun", "5:00 PM Fri"),
"USD/CHF": ("5:00 PM Sun", "5:00 PM Fri"),
"AUD/USD": ("5:00 PM Sun", "5:00 PM Fri"),
"USD/CNY": ("5:00 PM Sun", "5:00 PM Fri"),
"US Dollar Index (DXY)": ("5:00 PM Sun", "5:00 PM Fri"),
"VIX (Fear Index)": ("9:30 AM Mon", "4:15 PM Fri"),
"NZX 50": ("~4:00 PM Sun", "~11:45 PM Thu"),
"WTI Crude Oil": ("6:00 PM Sun", "5:00 PM Fri"),
"Brent Crude Oil": ("6:00 PM Sun", "5:00 PM Fri"),
"Gold": ("6:00 PM Sun", "5:00 PM Fri"),
"Silver": ("6:00 PM Sun", "5:00 PM Fri"),
"Copper": ("6:00 PM Sun", "5:00 PM Fri"),
"Natural Gas": ("6:00 PM Sun", "5:00 PM Fri"),
"Corn": ("7:00 PM Sun", "1:20 PM Fri"),
"Wheat": ("7:00 PM Sun", "1:20 PM Fri"),
"ASX 200": ("~6:00 PM Sun", "~12:00 AM Fri"),
"Nikkei 225": ("7:00 PM Sun", "2:00 AM Fri"),
"Hang Seng": ("8:30 PM Sun", "3:00 AM Fri"),
"FTSE 100": ("3:00 AM Mon", "11:30 AM Fri"),
"DAX": ("3:00 AM Mon", "11:30 AM Fri"),
"CAC 40": ("3:00 AM Mon", "11:30 AM Fri"),
"S&P 500": ("9:30 AM Mon", "4:00 PM Fri"),
"Dow Jones": ("9:30 AM Mon", "4:00 PM Fri"),
"NASDAQ Composite": ("9:30 AM Mon", "4:00 PM Fri"),
"Russell 2000": ("9:30 AM Mon", "4:00 PM Fri"),
"Apple": ("9:30 AM Mon", "4:00 PM Fri"),
"Microsoft": ("9:30 AM Mon", "4:00 PM Fri"),
"NVIDIA": ("9:30 AM Mon", "4:00 PM Fri"),
"Amazon": ("9:30 AM Mon", "4:00 PM Fri"),
"Alphabet (Google)": ("9:30 AM Mon", "4:00 PM Fri"),
"Tesla": ("9:30 AM Mon", "4:00 PM Fri"),
"Meta": ("9:30 AM Mon", "4:00 PM Fri"),
"BHP Group": ("~6:00 PM Sun", "~12:00 AM Fri"),
"ProShares Bitcoin ETF": ("9:30 AM Mon", "4:00 PM Fri"),
"Lululemon": ("9:30 AM Mon", "4:00 PM Fri"),
"Hongkong Land": ("8:00 PM Sun", "~4:00 AM Fri"),
"Suzuki Motor": ("7:00 PM Sun", "2:00 AM Fri"),
"Toyota Motor": ("7:00 PM Sun", "2:00 AM Fri"),
"Swire Pacific": ("8:30 PM Sun", "3:00 AM Fri"),
"Hysan Development": ("8:30 PM Sun", "3:00 AM Fri"),
"JPMorgan Chase": ("9:30 AM Mon", "4:00 PM Fri"),
"Sino Land": ("8:30 PM Sun", "3:00 AM Fri"),
"SPDR Gold Shares": ("9:30 AM Mon", "4:00 PM Fri"),
}
# Assets whose values are already in % (yields) — suppress pct-change, show as X.XXX%
YIELD_ASSETS = {
"US 13W T-Bill Yield", "US 5Y Treasury Yield",
"US 10Y Treasury Yield", "US 30Y Treasury Yield",
"VIX (Fear Index)",
}
# ETF proxies — shown as regular prices (not yields), but grouped with bonds
BOND_ETF_ASSETS = {
"iShares UK Gilts ETF", "iShares EUR Govt Bond", "iShares JPY Govt Bond",
}
MAX_WORKERS = 10 # parallel fetch threads
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _to_et(ts) -> object:
"""Convert a pandas Timestamp (tz-aware or naive-UTC) to ET. Returns as-is on failure."""
if ET is None:
return ts
try:
import pandas as pd
ts = pd.Timestamp(ts)
if ts.tzinfo is None:
# Daily bars have no time component — treat as date only, no TZ conversion
return ts
return ts.astimezone(ET)
except Exception:
return ts
def fmt_price(v: float, commas: bool = False) -> str:
"""Format price with appropriate decimal places. Handles negatives correctly."""
abs_v = abs(v)
if abs_v >= 1000:
formatted = f"{v:,.2f}" if commas else f"{v:.2f}"
elif abs_v >= 1:
formatted = f"{v:.4f}"
elif abs_v == 0:
formatted = "0.00"
else:
formatted = f"{v:.6f}"
return formatted
# ---------------------------------------------------------------------------
# Core fetch
# ---------------------------------------------------------------------------
def fetch_asset_data(name: str, symbol: str) -> Optional[dict]:
"""
Fetch latest price, prior close, and timestamp for one asset.
Prior-close priority:
1. fast_info.previous_close (most reliable for stocks/ETFs)
2. hist_daily.iloc[-2] (fallback for futures/forex/yields)
3. last_price itself (last resort — pct_change will be 0)
"""
try:
ticker = yf.Ticker(symbol)
# --- price history --------------------------------------------------
hist_intra = ticker.history(period="1d", interval="1m")
hist_daily = ticker.history(period="5d")
if not hist_intra.empty:
hist = hist_intra
use_intra = True
elif not hist_daily.empty:
hist = hist_daily
use_intra = False
else:
print(f" ✗ {name}: no data returned")
return None
last_price = float(hist["Close"].iloc[-1])
raw_dt = hist.index[-1]
# --- timestamp → ET -------------------------------------------------
last_dt_et = _to_et(raw_dt)
if hasattr(last_dt_et, "tzinfo") and last_dt_et.tzinfo is not None:
dt_str = last_dt_et.strftime("%Y-%m-%d %H:%M ET")
sort_key = last_dt_et.strftime("%Y-%m-%dT%H:%M:%S")
elif hasattr(last_dt_et, "strftime"):
# Date-only (daily bar) — no time conversion needed
dt_str = last_dt_et.strftime("%Y-%m-%d")
sort_key = last_dt_et.strftime("%Y-%m-%dT00:00:00")
else:
dt_str = str(last_dt_et)[:16].replace("T", " ")
sort_key = dt_str.replace(" ", "T")
# --- prior close ----------------------------------------------------
prev_close: Optional[float] = None
# 1. fast_info (best for stocks; often None for futures/forex)
try:
fi_prev = getattr(ticker.fast_info, "previous_close", None)
if fi_prev is not None:
prev_close = float(fi_prev)
except Exception:
pass
# 2. daily history fallback
if prev_close is None and not hist_daily.empty and len(hist_daily) >= 2:
prev_close = float(hist_daily["Close"].iloc[-2])
# 3. last resort
if prev_close is None:
prev_close = last_price
pct_change = ((last_price - prev_close) / prev_close * 100) if prev_close else 0.0
opens, closes = TRADING_HOURS.get(name, ("—", "—"))
is_yield = name in YIELD_ASSETS
is_bond_etf = name in BOND_ETF_ASSETS
return {
"asset": name,
"symbol": symbol,
"latest_datetime": dt_str,
"_sort_key": sort_key, # internal — stripped before public API return
"latest_price": last_price,
"prior_close": prev_close,
"pct_change": pct_change,
"is_yield": is_yield,
"is_bond_etf": is_bond_etf,
"opens": opens,
"closes": closes,
"source": SOURCE,
}
except Exception as e:
print(f" ✗ {name} ({symbol}): {e}")
return None
# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------
def get_prices(max_workers: int = MAX_WORKERS) -> List[dict]:
"""
Fetch all asset prices in parallel. Returns list of dicts sorted by
latest_datetime descending (most recent first). Internal sort key is
removed before returning.
"""
rows: List[dict] = []
with ThreadPoolExecutor(max_workers=max_workers) as pool:
futures = {pool.submit(fetch_asset_data, name, sym): name for name, sym in ASSETS}
for fut in as_completed(futures):
result = fut.result()
if result:
rows.append(result)
rows.sort(key=lambda r: r["_sort_key"], reverse=True)
for r in rows:
r.pop("_sort_key", None)
return rows
# ---------------------------------------------------------------------------
# Parquet storage & performance
# ---------------------------------------------------------------------------
PARQUET_DIR = Path(__file__).parent / "market_data"
SNAPSHOTS_FILE = PARQUET_DIR / "snapshots.parquet"
HISTORY_FILE = PARQUET_DIR / "history.parquet"
def _ensure_parquet_dir() -> Path:
PARQUET_DIR.mkdir(exist_ok=True)
return PARQUET_DIR
def save_snapshots_to_parquet(rows: List[dict]) -> Optional[Path]:
"""
Append current snapshot to parquet. Each row gets a fetch_timestamp.
Returns path if saved, None if parquet unavailable.
"""
if not (_HAS_PANDAS and _HAS_PARQUET):
return None
_ensure_parquet_dir()
fetch_ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
records = []
for r in rows:
records.append({
"fetch_timestamp": fetch_ts,
"asset": r["asset"],
"symbol": r["symbol"],
"latest_datetime": r["latest_datetime"],
"latest_price": float(r["latest_price"]),
"prior_close": float(r["prior_close"]),
"pct_change": float(r["pct_change"]),
})
df_new = pd.DataFrame(records)
if SNAPSHOTS_FILE.exists():
df_old = pd.read_parquet(SNAPSHOTS_FILE)
df = pd.concat([df_old, df_new], ignore_index=True)
else:
df = df_new
df.to_parquet(SNAPSHOTS_FILE, index=False)
return SNAPSHOTS_FILE
def fetch_and_save_history(period: str = "1y") -> Optional[Path]:
"""
Fetch historical daily OHLCV for all assets from yfinance, save to parquet.
Returns path if saved, None if parquet unavailable.
"""
if not (_HAS_PANDAS and _HAS_PARQUET):
return None
_ensure_parquet_dir()
all_dfs = []
for name, symbol in ASSETS:
try:
ticker = yf.Ticker(symbol)
hist = ticker.history(period=period)
if hist.empty or len(hist) < 2:
continue
hist = hist.reset_index()
hist["symbol"] = symbol
hist["asset"] = name
hist["date"] = hist["Date"].dt.strftime("%Y-%m-%d")
all_dfs.append(hist[["date", "symbol", "asset", "Open", "High", "Low", "Close", "Volume"]])
except Exception as e:
print(f" ✗ {name} ({symbol}): {e}")
if not all_dfs:
return None
df = pd.concat(all_dfs, ignore_index=True)
df = df.rename(columns={"Open": "open", "High": "high", "Low": "low", "Close": "close", "Volume": "volume"})
df.to_parquet(HISTORY_FILE, index=False)
return HISTORY_FILE
def get_performance_report() -> List[dict]:
"""
Compute 1D, 5D, 1M, 3M, 6M, 1Y % returns from history parquet.
Returns list of dicts: asset, symbol, latest_price, ret_1d, ret_5d, ret_1m, ret_3m, ret_6m, ret_1y.
"""
if not (_HAS_PANDAS and _HAS_PARQUET) or not HISTORY_FILE.exists():
return []
df = pd.read_parquet(HISTORY_FILE)
df["date"] = pd.to_datetime(df["date"])
df = df.sort_values(["symbol", "date"])
report = []
for symbol, g in df.groupby("symbol"):
g = g.drop_duplicates(subset=["date"], keep="last").sort_values("date")
if len(g) < 2:
continue
asset = g["asset"].iloc[0]
latest = g["close"].iloc[-1]
if latest <= 0:
continue
periods = [
("ret_1d", 1),
("ret_5d", 5),
("ret_1m", 21),
("ret_3m", 63),
("ret_6m", 126),
("ret_1y", 252),
]
row = {"asset": asset, "symbol": symbol, "latest_price": latest}
for key, n in periods:
if len(g) > n:
past = g["close"].iloc[-1 - n]
row[key] = ((latest - past) / past * 100) if past and past > 0 else None
else:
row[key] = None
report.append(row)
return report
# ---------------------------------------------------------------------------
# CLI entry point
# ---------------------------------------------------------------------------
def main():
base = Path(__file__).parent
reports_dir = base / "reports"
reports_dir.mkdir(exist_ok=True)
rows: List[dict] = []
print(f"Fetching {len(ASSETS)} assets in parallel (max {MAX_WORKERS} threads)…")
t0 = datetime.now()
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool:
futures = {pool.submit(fetch_asset_data, name, sym): (name, sym) for name, sym in ASSETS}
for fut in as_completed(futures):
name, sym = futures[fut]
result = fut.result()
if result:
rows.append(result)
print(f" ✓ {name}")
elapsed = (datetime.now() - t0).total_seconds()
print(f"\nFetched {len(rows)}/{len(ASSETS)} assets in {elapsed:.1f}s")
if not rows:
print("No data retrieved.")
return
rows.sort(key=lambda r: r["_sort_key"], reverse=True)
for r in rows:
r.pop("_sort_key", None)
# --- Parquet snapshots (append) -----------------------------------------
if _HAS_PANDAS and _HAS_PARQUET:
p = save_snapshots_to_parquet(rows)
if p:
print(f"Appended to {p}")
else:
print("(Install pandas and pyarrow for parquet: pip install pandas pyarrow)")
# --- Parquet history & performance --------------------------------------
perf_rows: List[dict] = []
if _HAS_PANDAS and _HAS_PARQUET:
print("Fetching historical data for performance…")
fetch_and_save_history(period="2y") # 2y ensures 253+ days for 1Y return
perf_rows = get_performance_report()
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
# --- CSV ----------------------------------------------------------------
csv_path = reports_dir / f"claude-market-data_{ts}.csv"
with open(csv_path, "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=[
"asset", "latest_datetime", "latest_price", "prior_close",
"pct_change", "opens", "closes", "source",
])
w.writeheader()
for r in rows:
is_yield = r.get("is_yield", False)
pct_str = "N/A (yield)" if is_yield else f"{r['pct_change']:.2f}"
w.writerow({
"asset": r["asset"],
"latest_datetime": r["latest_datetime"],
"latest_price": fmt_price(r["latest_price"]),
"prior_close": fmt_price(r["prior_close"]),
"pct_change": pct_str,
"opens": r["opens"],
"closes": r["closes"],
"source": r["source"],
})
print(f"Wrote {csv_path}")
# --- Markdown -----------------------------------------------------------
md_path = reports_dir / f"claude-market-data_{ts}.md"
lines = [
"# Market Data — Latest Prices",
"",
f"*Generated: {datetime.now().strftime('%Y-%m-%d %H:%M ET')}*",
"",
"*Sorted by latest timestamp (most recent first). Bond yields shown in % terms.*",
"",
"| Asset | Latest | Price | Prior Close | % Chg | Opens (ET) | Closes (ET) | Source |",
"|-------|--------|-------|-------------|-------|------------|-------------|--------|",
]
for r in rows:
lp = fmt_price(r["latest_price"], commas=True)
pc = fmt_price(r["prior_close"], commas=True)
is_yield = r.get("is_yield", False)
is_bond_etf = r.get("is_bond_etf", False)
if is_yield:
pct_str = "—"
lp = f"{r['latest_price']:.3f}%"
pc = f"{r['prior_close']:.3f}%"
else:
pct = r["pct_change"]
pct_str = f"{pct:+.2f}%"
if is_bond_etf:
lp = f"{lp} (ETF)"
lines.append(
f"| {r['asset']} | {r['latest_datetime']} | {lp} | {pc} "
f"| {pct_str} | {r['opens']} | {r['closes']} | {r['source']} |"
)
lines += [
"",
f"*Data source: {SOURCE}*",
"",
"**Notes:**",
"- All timestamps normalized to Eastern Time (ET) where time data is available.",
"- US Treasury yields (^IRX, ^FVX, ^TNX, ^TYX) are shown as absolute % values — % change column is suppressed.",
"- VIX is shown as absolute points value.",
"- **International bond proxies:** Yahoo Finance does not provide reliable yield tickers for UK/EU/Japan.",
" `IGLT.L` (iShares UK Gilts, LSE), `IBGM.DE` (iShares EUR Govt Bond, XETRA), and `2561.T` (iShares JPY Govt Bond, TSE)",
" are ETF price proxies — price moves *inversely* to yield direction.",
"- Prices for futures (Oil, Gold, etc.) reflect the front-month contract.",
]
# --- Performance (from parquet history) ----------------------------------
if perf_rows:
perf_csv = reports_dir / f"claude-market-performance_{ts}.csv"
with open(perf_csv, "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=[
"asset", "symbol", "latest_price", "1D %", "5D %", "1M %", "3M %", "6M %", "1Y %",
])
w.writeheader()
for r in perf_rows:
w.writerow({
"asset": r["asset"],
"symbol": r["symbol"],
"latest_price": fmt_price(r.get("latest_price", 0)),
"1D %": f"{r.get('ret_1d'):.2f}" if r.get("ret_1d") is not None else "",
"5D %": f"{r.get('ret_5d'):.2f}" if r.get("ret_5d") is not None else "",
"1M %": f"{r.get('ret_1m'):.2f}" if r.get("ret_1m") is not None else "",
"3M %": f"{r.get('ret_3m'):.2f}" if r.get("ret_3m") is not None else "",
"6M %": f"{r.get('ret_6m'):.2f}" if r.get("ret_6m") is not None else "",
"1Y %": f"{r.get('ret_1y'):.2f}" if r.get("ret_1y") is not None else "",
})
print(f"Wrote {perf_csv}")
lines += [
"",
"---",
"",
"## Performance (from historical data)",
"",
"| Asset | Symbol | Latest | 1D % | 5D % | 1M % | 3M % | 6M % | 1Y % |",
"|-------|--------|--------|------|------|------|------|------|------|",
]
for r in sorted(perf_rows, key=lambda x: (x.get("ret_1y") or -999), reverse=True):
def _pct(v):
return f"{v:+.2f}%" if v is not None else "—"
lp = fmt_price(r.get("latest_price", 0), commas=True)
lines.append(
f"| {r['asset']} | {r['symbol']} | {lp} | {_pct(r.get('ret_1d'))} | {_pct(r.get('ret_5d'))} | "
f"{_pct(r.get('ret_1m'))} | {_pct(r.get('ret_3m'))} | {_pct(r.get('ret_6m'))} | {_pct(r.get('ret_1y'))} |"
)
lines.append("")
Path(md_path).write_text("\n".join(lines), encoding="utf-8")
print(f"Wrote {md_path}")
if __name__ == "__main__":
main()
To run independently: Copy the entire code block
below, save as market_ytd.py. Place it in the same
directory as claude_v5.py (market_ytd imports the asset
list from it). Run python market_ytd.py. Prerequisites:
pip install yfinance. Outputs go to
reports/.
#!/usr/bin/env python3
"""
Market data with prior-close change and YTD (start-of-year) change.
Outputs CSV and MD with:
- Latest price, prior close, % change since prior close
- Value at start of calendar year (nearest available trading day)
- % change from start of year to latest
Usage:
python market_ytd.py
"""
import csv
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Optional, Tuple
try:
import yfinance as yf
except ImportError:
import subprocess
subprocess.check_call(["pip", "install", "yfinance", "-q"])
import yfinance as yf
# Import asset list from claude_v5
from claude_v5 import ASSETS, TRADING_HOURS, YIELD_ASSETS, BOND_ETF_ASSETS, SOURCE
MAX_WORKERS = 10
def _to_et(ts) -> object:
try:
import pytz
ET = pytz.timezone("America/New_York")
except ImportError:
return ts
try:
import pandas as pd
t = pd.Timestamp(ts)
if t.tzinfo is None:
return t
return t.astimezone(ET)
except Exception:
return ts
def fmt_price(v: float, commas: bool = False) -> str:
abs_v = abs(v)
if abs_v >= 1000:
return f"{v:,.2f}" if commas else f"{v:.2f}"
if abs_v >= 1:
return f"{v:.4f}"
if abs_v == 0:
return "0.00"
return f"{v:.6f}"
def fetch_asset_with_ytd(name: str, symbol: str, year_start: str) -> Optional[dict]:
"""
Fetch latest price, prior close, and start-of-year value for one asset.
year_start: "YYYY-01-01" — we find the nearest available close on or before this date.
"""
try:
ticker = yf.Ticker(symbol)
hist_intra = ticker.history(period="1d", interval="1m")
hist_daily = ticker.history(period="5d")
# Need data before Jan 1 to get last trading day of prior year
y = int(year_start[:4])
hist_ytd = ticker.history(start=f"{y - 1}-12-01", end=datetime.now().strftime("%Y-%m-%d"))
if not hist_intra.empty:
hist = hist_intra
elif not hist_daily.empty:
hist = hist_daily
else:
print(f" ✗ {name}: no data")
return None
last_price = float(hist["Close"].iloc[-1])
raw_dt = hist.index[-1]
last_dt_et = _to_et(raw_dt)
if hasattr(last_dt_et, "strftime"):
dt_str = last_dt_et.strftime("%Y-%m-%d %H:%M ET") if getattr(last_dt_et, "tzinfo", None) else last_dt_et.strftime("%Y-%m-%d")
sort_key = last_dt_et.strftime("%Y-%m-%dT%H:%M:%S") if getattr(last_dt_et, "tzinfo", None) else last_dt_et.strftime("%Y-%m-%dT00:00:00")
else:
dt_str = str(last_dt_et)[:16].replace("T", " ")
sort_key = dt_str.replace(" ", "T")
# Prior close
prev_close = None
try:
fi_prev = getattr(ticker.fast_info, "previous_close", None)
if fi_prev is not None:
prev_close = float(fi_prev)
except Exception:
pass
if prev_close is None and not hist_daily.empty and len(hist_daily) >= 2:
prev_close = float(hist_daily["Close"].iloc[-2])
if prev_close is None:
prev_close = last_price
pct_change = ((last_price - prev_close) / prev_close * 100) if prev_close else 0.0
# Start-of-year value: nearest available close on or before Jan 1
ytd_value = None
ytd_date = None
ytd_pct_change = None
if not hist_ytd.empty:
hist_ytd = hist_ytd[hist_ytd.index <= year_start]
if not hist_ytd.empty:
ytd_value = float(hist_ytd["Close"].iloc[-1])
ytd_date = hist_ytd.index[-1]
if hasattr(ytd_date, "strftime"):
ytd_date = ytd_date.strftime("%Y-%m-%d")
else:
ytd_date = str(ytd_date)[:10]
if ytd_value and ytd_value > 0:
ytd_pct_change = ((last_price - ytd_value) / ytd_value * 100)
opens, closes = TRADING_HOURS.get(name, ("—", "—"))
is_yield = name in YIELD_ASSETS
is_bond_etf = name in BOND_ETF_ASSETS
return {
"asset": name,
"symbol": symbol,
"latest_datetime": dt_str,
"_sort_key": sort_key,
"latest_price": last_price,
"prior_close": prev_close,
"pct_change": pct_change,
"ytd_value": ytd_value,
"ytd_date": ytd_date,
"ytd_pct_change": ytd_pct_change,
"is_yield": is_yield,
"is_bond_etf": is_bond_etf,
"opens": opens,
"closes": closes,
"source": SOURCE,
}
except Exception as e:
print(f" ✗ {name} ({symbol}): {e}")
return None
def main():
base = Path(__file__).parent
reports_dir = base / "reports"
reports_dir.mkdir(exist_ok=True)
year = datetime.now().year
year_start = f"{year}-01-01"
print(f"Fetching market data (prior close + YTD vs {year_start})…")
rows: List[dict] = []
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as pool:
futures = {pool.submit(fetch_asset_with_ytd, name, sym, year_start): (name, sym) for name, sym in ASSETS}
for fut in as_completed(futures):
result = fut.result()
if result:
rows.append(result)
print(f" ✓ {result['asset']}")
if not rows:
print("No data retrieved.")
return
rows.sort(key=lambda r: r["_sort_key"], reverse=True)
for r in rows:
r.pop("_sort_key", None)
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
# --- CSV ---
csv_path = reports_dir / f"market-ytd_{ts}.csv"
with open(csv_path, "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=[
"asset", "symbol", "latest_datetime", "latest_price", "prior_close",
"pct_change", "ytd_date", "ytd_value", "ytd_pct_change", "opens", "closes", "source",
])
w.writeheader()
for r in rows:
is_yield = r.get("is_yield", False)
pct_str = "N/A (yield)" if is_yield else f"{r['pct_change']:.2f}"
ytd_val = fmt_price(r["ytd_value"]) if r.get("ytd_value") is not None else ""
ytd_pct = f"{r['ytd_pct_change']:.2f}" if r.get("ytd_pct_change") is not None else ""
w.writerow({
"asset": r["asset"],
"symbol": r["symbol"],
"latest_datetime": r["latest_datetime"],
"latest_price": fmt_price(r["latest_price"]),
"prior_close": fmt_price(r["prior_close"]),
"pct_change": pct_str,
"ytd_date": r.get("ytd_date") or "",
"ytd_value": ytd_val,
"ytd_pct_change": ytd_pct,
"opens": r["opens"],
"closes": r["closes"],
"source": r["source"],
})
print(f"Wrote {csv_path}")
# --- Markdown ---
md_path = reports_dir / f"market-ytd_{ts}.md"
lines = [
"# Market Data — Prior Close & YTD",
"",
f"*Generated: {datetime.now().strftime('%Y-%m-%d %H:%M ET')}*",
"",
f"*YTD = change from nearest available close on/before {year}-01-01 to latest.*",
"",
"| Asset | Latest | Price | Prior Close | % Chg | YTD Date | YTD Value | YTD % Chg | Opens | Closes | Source |",
"|-------|--------|-------|-------------|-------|----------|-----------|-----------|-------|--------|--------|",
]
for r in rows:
lp = fmt_price(r["latest_price"], commas=True)
pc = fmt_price(r["prior_close"], commas=True)
is_yield = r.get("is_yield", False)
is_bond_etf = r.get("is_bond_etf", False)
if is_yield:
pct_str = "—"
lp = f"{r['latest_price']:.3f}%"
pc = f"{r['prior_close']:.3f}%"
else:
pct_str = f"{r['pct_change']:+.2f}%"
if is_bond_etf:
lp = f"{lp} (ETF)"
ytd_date = r.get("ytd_date") or "—"
ytd_val = fmt_price(r["ytd_value"], commas=True) if r.get("ytd_value") is not None else "—"
ytd_pct = f"{r['ytd_pct_change']:+.2f}%" if r.get("ytd_pct_change") is not None else "—"
lines.append(
f"| {r['asset']} | {r['latest_datetime']} | {lp} | {pc} | {pct_str} | "
f"{ytd_date} | {ytd_val} | {ytd_pct} | {r['opens']} | {r['closes']} | {r['source']} |"
)
lines += ["", f"*Data source: {SOURCE}*"]
Path(md_path).write_text("\n".join(lines), encoding="utf-8")
print(f"Wrote {md_path}")
if __name__ == "__main__":
main()