commit 1dae56415c352c89d995d2b555e5b5c46caada13 Author: Dasemu Date: Sun Aug 30 19:18:46 2026 +0200 Initial commit: investment dashboard with contributions panel and forecast chart React + Vite frontend with a local-JSON-backed API (Vite middleware) for tracking portfolio holdings, contributions/withdrawals, recurring contribution plans, and a forecast chart comparing the portfolio's real value against a same-contributions S&P 500 benchmark. Co-Authored-By: Claude Sonnet 5 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000..6fa991d --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,8 @@ +{ + "$schema": "./node_modules/oxlint/configuration_schema.json", + "plugins": ["react", "typescript", "oxc"], + "rules": { + "react/rules-of-hooks": "error", + "react/only-export-components": ["warn", { "allowConstantExport": true }] + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..7543055 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# Investment Visualizer + +A personal investment dashboard: track contributions, see asset allocation, and +compare your portfolio's performance against the S&P 500. + +## Stack + +- **Frontend**: React + TypeScript + Vite, charts with Recharts. +- **Backend**: a small REST API implemented as a Vite dev-server middleware + (`server/apiPlugin.ts`) backed by local JSON files in `data/`. No database, + no separate process — `npm run dev` starts both. +- **Data**: everything lives under `data/*.json`. The API layer + (`src/api/client.ts`) is the only place that knows the data lives in local + files — swapping it for a real backend later means only changing that file. + +## Data model (`data/`) + +- `portfolio.json` — current holdings snapshot (values, asset class, region, + RV/RF allocation). +- `history.json` — periodic total-account-value snapshots, used to compute + time-weighted return (TWR). Add more snapshots over time for a more accurate + performance line. +- `contributions.json` — the movements ledger (external contributions/ + withdrawals plus internal fund subscriptions/redemptions) and recurring + contribution plans (weekly/monthly/etc.) used to project future cash flows. +- `settings.json` — portfolio inception date, forecast horizon (years), and + the assumed annual return used for the projected part of the chart + (historical TWR-derived or a manual assumption). +- `sp500.json` — cached daily S&P 500 closes, refreshed with: + + ```bash + node scripts/fetch-sp500.mjs + ``` + +## Performance methodology + +- **Portfolio return**: simplified chain-linked time-weighted return (TWR) + computed from `history.json` snapshots and external cash flows in + `contributions.json`. Internal fund subscriptions/redemptions net to zero on + total account value and don't affect it. +- **S&P 500 line**: percentage change of the index since the portfolio's + inception date, for an apples-to-apples "who's outperforming whom" + comparison against the portfolio's TWR line. +- **Forecast segment**: continues the portfolio line past today using either + the historical annualized TWR or a manual rate, applied to the current value + plus projected future contributions from active recurring plans. +- **0% baseline**: cumulative net contributions (actual + projected) with no + investment return at all — the reference line for "what if it just sat in + cash." + +## Development + +```bash +npm install +npm run dev +``` + +This starts Vite (frontend + local JSON API) on http://localhost:5173. diff --git a/data/contributions.json b/data/contributions.json new file mode 100644 index 0000000..4b4ad40 --- /dev/null +++ b/data/contributions.json @@ -0,0 +1,133 @@ +{ + "recurringPlans": [ + { + "id": "207651b6-78ef-4e53-9a89-e877606e2e8e", + "amount": 250, + "frequency": "monthly", + "startDate": "2026-09-05", + "active": true + }, + { + "id": "0fab786b-962d-4ed8-bf7a-4c5973212239", + "amount": 100, + "frequency": "weekly", + "startDate": "2026-09-07", + "active": true, + "note": "Karaoke" + } + ], + "movements": [ + { + "id": "m1", + "date": "2026-08-09", + "kind": "apertura", + "amount": 0, + "description": "Apertura de la cartera" + }, + { + "id": "m2", + "date": "2026-08-11", + "kind": "aportacion", + "amount": 8000, + "description": "Abono por traspaso: aportación a mi cartera" + }, + { + "id": "m3", + "date": "2026-08-12", + "kind": "suscripcion_fondo", + "amount": 398, + "description": "Suscripción BGIF EM Mkt Gover Bond Index D" + }, + { + "id": "m4", + "date": "2026-08-13", + "kind": "suscripcion_fondo", + "amount": 2706.4, + "description": "Suscripción Ishares US Index Fund IE S EUR" + }, + { + "id": "m5", + "date": "2026-08-13", + "kind": "suscripcion_fondo", + "amount": 1194, + "description": "Suscripción Ishares ESG Screened Glb Corp" + }, + { + "id": "m6", + "date": "2026-08-13", + "kind": "suscripcion_fondo", + "amount": 636.8, + "description": "Suscripción Fidelity MSCI Europe Index P A" + }, + { + "id": "m7", + "date": "2026-08-13", + "kind": "suscripcion_fondo", + "amount": 796, + "description": "Suscripción Vanguard 20+ Year Euro Treasury" + }, + { + "id": "m8", + "date": "2026-08-13", + "kind": "suscripcion_fondo", + "amount": 796, + "description": "Suscripción Vanguard US Government Bond Index" + }, + { + "id": "m9", + "date": "2026-08-14", + "kind": "suscripcion_fondo", + "amount": 636.8, + "description": "Suscripción Ishares Emerging Markets Index" + }, + { + "id": "m10", + "date": "2026-08-14", + "kind": "suscripcion_fondo", + "amount": 636.8, + "description": "Suscripción Fidelity MSCI Japan Index P Ac" + }, + { + "id": "m11", + "date": "2026-08-14", + "kind": "suscripcion_fondo", + "amount": 138.38, + "description": "Suscripción Fidelity MSCI Pacific Ex-Japan Idx" + }, + { + "id": "m12", + "date": "2026-08-18", + "kind": "aportacion", + "amount": 100, + "description": "Transferencia Sepa Dario Sevilla Muñoz" + }, + { + "id": "m13", + "date": "2026-08-18", + "kind": "aportacion", + "amount": 350, + "description": "Transferencia Sepa Dario Sevilla Muñoz" + }, + { + "id": "m14", + "date": "2026-08-18", + "kind": "aportacion", + "amount": 100, + "description": "Transferencia Sepa Dario Sevilla Muñoz" + }, + { + "id": "m15", + "date": "2026-08-25", + "kind": "aportacion", + "amount": 100, + "description": "Transferencia Sepa Dario Sevilla Muñoz" + }, + { + "id": "m16", + "date": "2026-08-27", + "kind": "reembolso_fondo", + "amount": 301.1, + "description": "Reembolso Ishares ESG Screened Glb Corp" + } + ] +} diff --git a/data/history.json b/data/history.json new file mode 100644 index 0000000..69a7588 --- /dev/null +++ b/data/history.json @@ -0,0 +1,6 @@ +{ + "snapshots": [ + { "date": "2026-08-11", "marketValue": 8000.00 }, + { "date": "2026-08-29", "marketValue": 8596.15 } + ] +} diff --git a/data/portfolio.json b/data/portfolio.json new file mode 100644 index 0000000..54cc6c5 --- /dev/null +++ b/data/portfolio.json @@ -0,0 +1,26 @@ +{ + "asOf": "2026-08-29", + "cash": 1011.92, + "invested": 7638.08, + "marketValueChange": -53.85, + "marketValueChangePercent": -0.71, + "assetAllocation": { + "Renta Variable": 74.43, + "Renta Fija": 25.57 + }, + "holdings": [ + { "name": "Ishares Us Equity Index Fund Clase S", "value": 2676.25, "changeAmount": -30.13, "changePercent": -1.11, "assetClass": "Renta Variable", "region": "EE.UU." }, + { "name": "Fidelity S&P 500 Index Fund P-Acc-EUR", "value": 982.14, "changeAmount": 8.8, "changePercent": 0.9, "assetClass": "Renta Variable", "region": "EE.UU." }, + { "name": "Ishares ESG Screened Global Corporate Bond Index Fund EUR Hedged", "value": 894.65, "changeAmount": 1.39, "changePercent": 0.16, "assetClass": "Renta Fija", "region": "Global" }, + { "name": "Ishares Emerging Markets Index Fund (IE) Acc EUR Clase S", "value": 641.85, "changeAmount": 5.16, "changePercent": 0.81, "assetClass": "Renta Variable", "region": "Emergentes" }, + { "name": "Goldman Sachs Global Enhanced Index Sustainable Equity - I Cap EUR", "value": 417.91, "changeAmount": 2.52, "changePercent": 0.61, "assetClass": "Renta Variable", "region": "Global" }, + { "name": "Ishares EM Government Bond Index Fund", "value": 395.35, "changeAmount": -2.45, "changePercent": -0.62, "assetClass": "Renta Fija", "region": "Emergentes" }, + { "name": "Vanguard US Government Bond Index Fund EUR Hedged", "value": 353.64, "changeAmount": 1.01, "changePercent": 0.29, "assetClass": "Renta Fija", "region": "EE.UU." }, + { "name": "Ishares Emerging Markets Index Fund (IE) D Acc EUR", "value": 326.14, "changeAmount": 0.0, "changePercent": 0.0, "assetClass": "Renta Variable", "region": "Emergentes" }, + { "name": "Vanguard 20+ Year Euro Treasury Index Fund", "value": 295.95, "changeAmount": -5.3, "changePercent": -1.76, "assetClass": "Renta Fija", "region": "Europa" }, + { "name": "Fidelity MSCI Japan Index Fund P-Acc-EUR", "value": 274.12, "changeAmount": -7.73, "changePercent": -2.74, "assetClass": "Renta Variable", "region": "Japón" }, + { "name": "Fidelity MSCI Europe Index Fund P-Acc-EUR", "value": 206.43, "changeAmount": -2.24, "changePercent": -1.08, "assetClass": "Renta Variable", "region": "Europa" }, + { "name": "Fidelity MSCI Pacific Ex-Japan Index Fund P-Acc-USD", "value": 59.92, "changeAmount": 0.37, "changePercent": 0.62, "assetClass": "Renta Variable", "region": "Asia-Pacífico" }, + { "name": "Vanguard US Equity Index Fund EUR Hedged", "value": 59.86, "changeAmount": 0.42, "changePercent": 0.7, "assetClass": "Renta Variable", "region": "EE.UU." } + ] +} diff --git a/data/settings.json b/data/settings.json new file mode 100644 index 0000000..a7be6c9 --- /dev/null +++ b/data/settings.json @@ -0,0 +1,6 @@ +{ + "inceptionDate": "2026-08-11", + "forecastYears": 10, + "returnAssumption": "custom", + "customAnnualReturnPct": 7 +} diff --git a/data/sp500.json b/data/sp500.json new file mode 100644 index 0000000..bfc7c6c --- /dev/null +++ b/data/sp500.json @@ -0,0 +1,10062 @@ +{ + "source": "yahoo-finance:^GSPC", + "updatedAt": "2026-08-29T20:28:00.065Z", + "series": [ + { + "date": "2016-08-29", + "close": 2180.38 + }, + { + "date": "2016-08-30", + "close": 2176.12 + }, + { + "date": "2016-08-31", + "close": 2170.95 + }, + { + "date": "2016-09-01", + "close": 2170.86 + }, + { + "date": "2016-09-02", + "close": 2179.98 + }, + { + "date": "2016-09-06", + "close": 2186.48 + }, + { + "date": "2016-09-07", + "close": 2186.16 + }, + { + "date": "2016-09-08", + "close": 2181.3 + }, + { + "date": "2016-09-09", + "close": 2127.81 + }, + { + "date": "2016-09-12", + "close": 2159.04 + }, + { + "date": "2016-09-13", + "close": 2127.02 + }, + { + "date": "2016-09-14", + "close": 2125.77 + }, + { + "date": "2016-09-15", + "close": 2147.26 + }, + { + "date": "2016-09-16", + "close": 2139.16 + }, + { + "date": "2016-09-19", + "close": 2139.12 + }, + { + "date": "2016-09-20", + "close": 2139.76 + }, + { + "date": "2016-09-21", + "close": 2163.12 + }, + { + "date": "2016-09-22", + "close": 2177.18 + }, + { + "date": "2016-09-23", + "close": 2164.69 + }, + { + "date": "2016-09-26", + "close": 2146.1 + }, + { + "date": "2016-09-27", + "close": 2159.93 + }, + { + "date": "2016-09-28", + "close": 2171.37 + }, + { + "date": "2016-09-29", + "close": 2151.13 + }, + { + "date": "2016-09-30", + "close": 2168.27 + }, + { + "date": "2016-10-03", + "close": 2161.2 + }, + { + "date": "2016-10-04", + "close": 2150.49 + }, + { + "date": "2016-10-05", + "close": 2159.73 + }, + { + "date": "2016-10-06", + "close": 2160.77 + }, + { + "date": "2016-10-07", + "close": 2153.74 + }, + { + "date": "2016-10-10", + "close": 2163.66 + }, + { + "date": "2016-10-11", + "close": 2136.73 + }, + { + "date": "2016-10-12", + "close": 2139.18 + }, + { + "date": "2016-10-13", + "close": 2132.55 + }, + { + "date": "2016-10-14", + "close": 2132.98 + }, + { + "date": "2016-10-17", + "close": 2126.5 + }, + { + "date": "2016-10-18", + "close": 2139.6 + }, + { + "date": "2016-10-19", + "close": 2144.29 + }, + { + "date": "2016-10-20", + "close": 2141.34 + }, + { + "date": "2016-10-21", + "close": 2141.16 + }, + { + "date": "2016-10-24", + "close": 2151.33 + }, + { + "date": "2016-10-25", + "close": 2143.16 + }, + { + "date": "2016-10-26", + "close": 2139.43 + }, + { + "date": "2016-10-27", + "close": 2133.04 + }, + { + "date": "2016-10-28", + "close": 2126.41 + }, + { + "date": "2016-10-31", + "close": 2126.15 + }, + { + "date": "2016-11-01", + "close": 2111.72 + }, + { + "date": "2016-11-02", + "close": 2097.94 + }, + { + "date": "2016-11-03", + "close": 2088.66 + }, + { + "date": "2016-11-04", + "close": 2085.18 + }, + { + "date": "2016-11-07", + "close": 2131.52 + }, + { + "date": "2016-11-08", + "close": 2139.56 + }, + { + "date": "2016-11-09", + "close": 2163.26 + }, + { + "date": "2016-11-10", + "close": 2167.48 + }, + { + "date": "2016-11-11", + "close": 2164.45 + }, + { + "date": "2016-11-14", + "close": 2164.2 + }, + { + "date": "2016-11-15", + "close": 2180.39 + }, + { + "date": "2016-11-16", + "close": 2176.94 + }, + { + "date": "2016-11-17", + "close": 2187.12 + }, + { + "date": "2016-11-18", + "close": 2181.9 + }, + { + "date": "2016-11-21", + "close": 2198.18 + }, + { + "date": "2016-11-22", + "close": 2202.94 + }, + { + "date": "2016-11-23", + "close": 2204.72 + }, + { + "date": "2016-11-25", + "close": 2213.35 + }, + { + "date": "2016-11-28", + "close": 2201.72 + }, + { + "date": "2016-11-29", + "close": 2204.66 + }, + { + "date": "2016-11-30", + "close": 2198.81 + }, + { + "date": "2016-12-01", + "close": 2191.08 + }, + { + "date": "2016-12-02", + "close": 2191.95 + }, + { + "date": "2016-12-05", + "close": 2204.71 + }, + { + "date": "2016-12-06", + "close": 2212.23 + }, + { + "date": "2016-12-07", + "close": 2241.35 + }, + { + "date": "2016-12-08", + "close": 2246.19 + }, + { + "date": "2016-12-09", + "close": 2259.53 + }, + { + "date": "2016-12-12", + "close": 2256.96 + }, + { + "date": "2016-12-13", + "close": 2271.72 + }, + { + "date": "2016-12-14", + "close": 2253.28 + }, + { + "date": "2016-12-15", + "close": 2262.03 + }, + { + "date": "2016-12-16", + "close": 2258.07 + }, + { + "date": "2016-12-19", + "close": 2262.53 + }, + { + "date": "2016-12-20", + "close": 2270.76 + }, + { + "date": "2016-12-21", + "close": 2265.18 + }, + { + "date": "2016-12-22", + "close": 2260.96 + }, + { + "date": "2016-12-23", + "close": 2263.79 + }, + { + "date": "2016-12-27", + "close": 2268.88 + }, + { + "date": "2016-12-28", + "close": 2249.92 + }, + { + "date": "2016-12-29", + "close": 2249.26 + }, + { + "date": "2016-12-30", + "close": 2238.83 + }, + { + "date": "2017-01-03", + "close": 2257.83 + }, + { + "date": "2017-01-04", + "close": 2270.75 + }, + { + "date": "2017-01-05", + "close": 2269 + }, + { + "date": "2017-01-06", + "close": 2276.98 + }, + { + "date": "2017-01-09", + "close": 2268.9 + }, + { + "date": "2017-01-10", + "close": 2268.9 + }, + { + "date": "2017-01-11", + "close": 2275.32 + }, + { + "date": "2017-01-12", + "close": 2270.44 + }, + { + "date": "2017-01-13", + "close": 2274.64 + }, + { + "date": "2017-01-17", + "close": 2267.89 + }, + { + "date": "2017-01-18", + "close": 2271.89 + }, + { + "date": "2017-01-19", + "close": 2263.69 + }, + { + "date": "2017-01-20", + "close": 2271.31 + }, + { + "date": "2017-01-23", + "close": 2265.2 + }, + { + "date": "2017-01-24", + "close": 2280.07 + }, + { + "date": "2017-01-25", + "close": 2298.37 + }, + { + "date": "2017-01-26", + "close": 2296.68 + }, + { + "date": "2017-01-27", + "close": 2294.69 + }, + { + "date": "2017-01-30", + "close": 2280.9 + }, + { + "date": "2017-01-31", + "close": 2278.87 + }, + { + "date": "2017-02-01", + "close": 2279.55 + }, + { + "date": "2017-02-02", + "close": 2280.85 + }, + { + "date": "2017-02-03", + "close": 2297.42 + }, + { + "date": "2017-02-06", + "close": 2292.56 + }, + { + "date": "2017-02-07", + "close": 2293.08 + }, + { + "date": "2017-02-08", + "close": 2294.67 + }, + { + "date": "2017-02-09", + "close": 2307.87 + }, + { + "date": "2017-02-10", + "close": 2316.1 + }, + { + "date": "2017-02-13", + "close": 2328.25 + }, + { + "date": "2017-02-14", + "close": 2337.58 + }, + { + "date": "2017-02-15", + "close": 2349.25 + }, + { + "date": "2017-02-16", + "close": 2347.22 + }, + { + "date": "2017-02-17", + "close": 2351.16 + }, + { + "date": "2017-02-21", + "close": 2365.38 + }, + { + "date": "2017-02-22", + "close": 2362.82 + }, + { + "date": "2017-02-23", + "close": 2363.81 + }, + { + "date": "2017-02-24", + "close": 2367.34 + }, + { + "date": "2017-02-27", + "close": 2369.75 + }, + { + "date": "2017-02-28", + "close": 2363.64 + }, + { + "date": "2017-03-01", + "close": 2395.96 + }, + { + "date": "2017-03-02", + "close": 2381.92 + }, + { + "date": "2017-03-03", + "close": 2383.12 + }, + { + "date": "2017-03-06", + "close": 2375.31 + }, + { + "date": "2017-03-07", + "close": 2368.39 + }, + { + "date": "2017-03-08", + "close": 2362.98 + }, + { + "date": "2017-03-09", + "close": 2364.87 + }, + { + "date": "2017-03-10", + "close": 2372.6 + }, + { + "date": "2017-03-13", + "close": 2373.47 + }, + { + "date": "2017-03-14", + "close": 2365.45 + }, + { + "date": "2017-03-15", + "close": 2385.26 + }, + { + "date": "2017-03-16", + "close": 2381.38 + }, + { + "date": "2017-03-17", + "close": 2378.25 + }, + { + "date": "2017-03-20", + "close": 2373.47 + }, + { + "date": "2017-03-21", + "close": 2344.02 + }, + { + "date": "2017-03-22", + "close": 2348.45 + }, + { + "date": "2017-03-23", + "close": 2345.96 + }, + { + "date": "2017-03-24", + "close": 2343.98 + }, + { + "date": "2017-03-27", + "close": 2341.59 + }, + { + "date": "2017-03-28", + "close": 2358.57 + }, + { + "date": "2017-03-29", + "close": 2361.13 + }, + { + "date": "2017-03-30", + "close": 2368.06 + }, + { + "date": "2017-03-31", + "close": 2362.72 + }, + { + "date": "2017-04-03", + "close": 2358.84 + }, + { + "date": "2017-04-04", + "close": 2360.16 + }, + { + "date": "2017-04-05", + "close": 2352.95 + }, + { + "date": "2017-04-06", + "close": 2357.49 + }, + { + "date": "2017-04-07", + "close": 2355.54 + }, + { + "date": "2017-04-10", + "close": 2357.16 + }, + { + "date": "2017-04-11", + "close": 2353.78 + }, + { + "date": "2017-04-12", + "close": 2344.93 + }, + { + "date": "2017-04-13", + "close": 2328.95 + }, + { + "date": "2017-04-17", + "close": 2349.01 + }, + { + "date": "2017-04-18", + "close": 2342.19 + }, + { + "date": "2017-04-19", + "close": 2338.17 + }, + { + "date": "2017-04-20", + "close": 2355.84 + }, + { + "date": "2017-04-21", + "close": 2348.69 + }, + { + "date": "2017-04-24", + "close": 2374.15 + }, + { + "date": "2017-04-25", + "close": 2388.61 + }, + { + "date": "2017-04-26", + "close": 2387.45 + }, + { + "date": "2017-04-27", + "close": 2388.77 + }, + { + "date": "2017-04-28", + "close": 2384.2 + }, + { + "date": "2017-05-01", + "close": 2388.33 + }, + { + "date": "2017-05-02", + "close": 2391.17 + }, + { + "date": "2017-05-03", + "close": 2388.13 + }, + { + "date": "2017-05-04", + "close": 2389.52 + }, + { + "date": "2017-05-05", + "close": 2399.29 + }, + { + "date": "2017-05-08", + "close": 2399.38 + }, + { + "date": "2017-05-09", + "close": 2396.92 + }, + { + "date": "2017-05-10", + "close": 2399.63 + }, + { + "date": "2017-05-11", + "close": 2394.44 + }, + { + "date": "2017-05-12", + "close": 2390.9 + }, + { + "date": "2017-05-15", + "close": 2402.32 + }, + { + "date": "2017-05-16", + "close": 2400.67 + }, + { + "date": "2017-05-17", + "close": 2357.03 + }, + { + "date": "2017-05-18", + "close": 2365.72 + }, + { + "date": "2017-05-19", + "close": 2381.73 + }, + { + "date": "2017-05-22", + "close": 2394.02 + }, + { + "date": "2017-05-23", + "close": 2398.42 + }, + { + "date": "2017-05-24", + "close": 2404.39 + }, + { + "date": "2017-05-25", + "close": 2415.07 + }, + { + "date": "2017-05-26", + "close": 2415.82 + }, + { + "date": "2017-05-30", + "close": 2412.91 + }, + { + "date": "2017-05-31", + "close": 2411.8 + }, + { + "date": "2017-06-01", + "close": 2430.06 + }, + { + "date": "2017-06-02", + "close": 2439.07 + }, + { + "date": "2017-06-05", + "close": 2436.1 + }, + { + "date": "2017-06-06", + "close": 2429.33 + }, + { + "date": "2017-06-07", + "close": 2433.14 + }, + { + "date": "2017-06-08", + "close": 2433.79 + }, + { + "date": "2017-06-09", + "close": 2431.77 + }, + { + "date": "2017-06-12", + "close": 2429.39 + }, + { + "date": "2017-06-13", + "close": 2440.35 + }, + { + "date": "2017-06-14", + "close": 2437.92 + }, + { + "date": "2017-06-15", + "close": 2432.46 + }, + { + "date": "2017-06-16", + "close": 2433.15 + }, + { + "date": "2017-06-19", + "close": 2453.46 + }, + { + "date": "2017-06-20", + "close": 2437.03 + }, + { + "date": "2017-06-21", + "close": 2435.61 + }, + { + "date": "2017-06-22", + "close": 2434.5 + }, + { + "date": "2017-06-23", + "close": 2438.3 + }, + { + "date": "2017-06-26", + "close": 2439.07 + }, + { + "date": "2017-06-27", + "close": 2419.38 + }, + { + "date": "2017-06-28", + "close": 2440.69 + }, + { + "date": "2017-06-29", + "close": 2419.7 + }, + { + "date": "2017-06-30", + "close": 2423.41 + }, + { + "date": "2017-07-03", + "close": 2429.01 + }, + { + "date": "2017-07-05", + "close": 2432.54 + }, + { + "date": "2017-07-06", + "close": 2409.75 + }, + { + "date": "2017-07-07", + "close": 2425.18 + }, + { + "date": "2017-07-10", + "close": 2427.43 + }, + { + "date": "2017-07-11", + "close": 2425.53 + }, + { + "date": "2017-07-12", + "close": 2443.25 + }, + { + "date": "2017-07-13", + "close": 2447.83 + }, + { + "date": "2017-07-14", + "close": 2459.27 + }, + { + "date": "2017-07-17", + "close": 2459.14 + }, + { + "date": "2017-07-18", + "close": 2460.61 + }, + { + "date": "2017-07-19", + "close": 2473.83 + }, + { + "date": "2017-07-20", + "close": 2473.45 + }, + { + "date": "2017-07-21", + "close": 2472.54 + }, + { + "date": "2017-07-24", + "close": 2469.91 + }, + { + "date": "2017-07-25", + "close": 2477.13 + }, + { + "date": "2017-07-26", + "close": 2477.83 + }, + { + "date": "2017-07-27", + "close": 2475.42 + }, + { + "date": "2017-07-28", + "close": 2472.1 + }, + { + "date": "2017-07-31", + "close": 2470.3 + }, + { + "date": "2017-08-01", + "close": 2476.35 + }, + { + "date": "2017-08-02", + "close": 2477.57 + }, + { + "date": "2017-08-03", + "close": 2472.16 + }, + { + "date": "2017-08-04", + "close": 2476.83 + }, + { + "date": "2017-08-07", + "close": 2480.91 + }, + { + "date": "2017-08-08", + "close": 2474.92 + }, + { + "date": "2017-08-09", + "close": 2474.02 + }, + { + "date": "2017-08-10", + "close": 2438.21 + }, + { + "date": "2017-08-11", + "close": 2441.32 + }, + { + "date": "2017-08-14", + "close": 2465.84 + }, + { + "date": "2017-08-15", + "close": 2464.61 + }, + { + "date": "2017-08-16", + "close": 2468.11 + }, + { + "date": "2017-08-17", + "close": 2430.01 + }, + { + "date": "2017-08-18", + "close": 2425.55 + }, + { + "date": "2017-08-21", + "close": 2428.37 + }, + { + "date": "2017-08-22", + "close": 2452.51 + }, + { + "date": "2017-08-23", + "close": 2444.04 + }, + { + "date": "2017-08-24", + "close": 2438.97 + }, + { + "date": "2017-08-25", + "close": 2443.05 + }, + { + "date": "2017-08-28", + "close": 2444.24 + }, + { + "date": "2017-08-29", + "close": 2446.3 + }, + { + "date": "2017-08-30", + "close": 2457.59 + }, + { + "date": "2017-08-31", + "close": 2471.65 + }, + { + "date": "2017-09-01", + "close": 2476.55 + }, + { + "date": "2017-09-05", + "close": 2457.85 + }, + { + "date": "2017-09-06", + "close": 2465.54 + }, + { + "date": "2017-09-07", + "close": 2465.1 + }, + { + "date": "2017-09-08", + "close": 2461.43 + }, + { + "date": "2017-09-11", + "close": 2488.11 + }, + { + "date": "2017-09-12", + "close": 2496.48 + }, + { + "date": "2017-09-13", + "close": 2498.37 + }, + { + "date": "2017-09-14", + "close": 2495.62 + }, + { + "date": "2017-09-15", + "close": 2500.23 + }, + { + "date": "2017-09-18", + "close": 2503.87 + }, + { + "date": "2017-09-19", + "close": 2506.65 + }, + { + "date": "2017-09-20", + "close": 2508.24 + }, + { + "date": "2017-09-21", + "close": 2500.6 + }, + { + "date": "2017-09-22", + "close": 2502.22 + }, + { + "date": "2017-09-25", + "close": 2496.66 + }, + { + "date": "2017-09-26", + "close": 2496.84 + }, + { + "date": "2017-09-27", + "close": 2507.04 + }, + { + "date": "2017-09-28", + "close": 2510.06 + }, + { + "date": "2017-09-29", + "close": 2519.36 + }, + { + "date": "2017-10-02", + "close": 2529.12 + }, + { + "date": "2017-10-03", + "close": 2534.58 + }, + { + "date": "2017-10-04", + "close": 2537.74 + }, + { + "date": "2017-10-05", + "close": 2552.07 + }, + { + "date": "2017-10-06", + "close": 2549.33 + }, + { + "date": "2017-10-09", + "close": 2544.73 + }, + { + "date": "2017-10-10", + "close": 2550.64 + }, + { + "date": "2017-10-11", + "close": 2555.24 + }, + { + "date": "2017-10-12", + "close": 2550.93 + }, + { + "date": "2017-10-13", + "close": 2553.17 + }, + { + "date": "2017-10-16", + "close": 2557.64 + }, + { + "date": "2017-10-17", + "close": 2559.36 + }, + { + "date": "2017-10-18", + "close": 2561.26 + }, + { + "date": "2017-10-19", + "close": 2562.1 + }, + { + "date": "2017-10-20", + "close": 2575.21 + }, + { + "date": "2017-10-23", + "close": 2564.98 + }, + { + "date": "2017-10-24", + "close": 2569.13 + }, + { + "date": "2017-10-25", + "close": 2557.15 + }, + { + "date": "2017-10-26", + "close": 2560.4 + }, + { + "date": "2017-10-27", + "close": 2581.07 + }, + { + "date": "2017-10-30", + "close": 2572.83 + }, + { + "date": "2017-10-31", + "close": 2575.26 + }, + { + "date": "2017-11-01", + "close": 2579.36 + }, + { + "date": "2017-11-02", + "close": 2579.85 + }, + { + "date": "2017-11-03", + "close": 2587.84 + }, + { + "date": "2017-11-06", + "close": 2591.13 + }, + { + "date": "2017-11-07", + "close": 2590.64 + }, + { + "date": "2017-11-08", + "close": 2594.38 + }, + { + "date": "2017-11-09", + "close": 2584.62 + }, + { + "date": "2017-11-10", + "close": 2582.3 + }, + { + "date": "2017-11-13", + "close": 2584.84 + }, + { + "date": "2017-11-14", + "close": 2578.87 + }, + { + "date": "2017-11-15", + "close": 2564.62 + }, + { + "date": "2017-11-16", + "close": 2585.64 + }, + { + "date": "2017-11-17", + "close": 2578.85 + }, + { + "date": "2017-11-20", + "close": 2582.14 + }, + { + "date": "2017-11-21", + "close": 2599.03 + }, + { + "date": "2017-11-22", + "close": 2597.08 + }, + { + "date": "2017-11-24", + "close": 2602.42 + }, + { + "date": "2017-11-27", + "close": 2601.42 + }, + { + "date": "2017-11-28", + "close": 2627.04 + }, + { + "date": "2017-11-29", + "close": 2626.07 + }, + { + "date": "2017-11-30", + "close": 2647.58 + }, + { + "date": "2017-12-01", + "close": 2642.22 + }, + { + "date": "2017-12-04", + "close": 2639.44 + }, + { + "date": "2017-12-05", + "close": 2629.57 + }, + { + "date": "2017-12-06", + "close": 2629.27 + }, + { + "date": "2017-12-07", + "close": 2636.98 + }, + { + "date": "2017-12-08", + "close": 2651.5 + }, + { + "date": "2017-12-11", + "close": 2659.99 + }, + { + "date": "2017-12-12", + "close": 2664.11 + }, + { + "date": "2017-12-13", + "close": 2662.85 + }, + { + "date": "2017-12-14", + "close": 2652.01 + }, + { + "date": "2017-12-15", + "close": 2675.81 + }, + { + "date": "2017-12-18", + "close": 2690.16 + }, + { + "date": "2017-12-19", + "close": 2681.47 + }, + { + "date": "2017-12-20", + "close": 2679.25 + }, + { + "date": "2017-12-21", + "close": 2684.57 + }, + { + "date": "2017-12-22", + "close": 2683.34 + }, + { + "date": "2017-12-26", + "close": 2680.5 + }, + { + "date": "2017-12-27", + "close": 2682.62 + }, + { + "date": "2017-12-28", + "close": 2687.54 + }, + { + "date": "2017-12-29", + "close": 2673.61 + }, + { + "date": "2018-01-02", + "close": 2695.81 + }, + { + "date": "2018-01-03", + "close": 2713.06 + }, + { + "date": "2018-01-04", + "close": 2723.99 + }, + { + "date": "2018-01-05", + "close": 2743.15 + }, + { + "date": "2018-01-08", + "close": 2747.71 + }, + { + "date": "2018-01-09", + "close": 2751.29 + }, + { + "date": "2018-01-10", + "close": 2748.23 + }, + { + "date": "2018-01-11", + "close": 2767.56 + }, + { + "date": "2018-01-12", + "close": 2786.24 + }, + { + "date": "2018-01-16", + "close": 2776.42 + }, + { + "date": "2018-01-17", + "close": 2802.56 + }, + { + "date": "2018-01-18", + "close": 2798.03 + }, + { + "date": "2018-01-19", + "close": 2810.3 + }, + { + "date": "2018-01-22", + "close": 2832.97 + }, + { + "date": "2018-01-23", + "close": 2839.13 + }, + { + "date": "2018-01-24", + "close": 2837.54 + }, + { + "date": "2018-01-25", + "close": 2839.25 + }, + { + "date": "2018-01-26", + "close": 2872.87 + }, + { + "date": "2018-01-29", + "close": 2853.53 + }, + { + "date": "2018-01-30", + "close": 2822.43 + }, + { + "date": "2018-01-31", + "close": 2823.81 + }, + { + "date": "2018-02-01", + "close": 2821.98 + }, + { + "date": "2018-02-02", + "close": 2762.13 + }, + { + "date": "2018-02-05", + "close": 2648.94 + }, + { + "date": "2018-02-06", + "close": 2695.14 + }, + { + "date": "2018-02-07", + "close": 2681.66 + }, + { + "date": "2018-02-08", + "close": 2581 + }, + { + "date": "2018-02-09", + "close": 2619.55 + }, + { + "date": "2018-02-12", + "close": 2656 + }, + { + "date": "2018-02-13", + "close": 2662.94 + }, + { + "date": "2018-02-14", + "close": 2698.63 + }, + { + "date": "2018-02-15", + "close": 2731.2 + }, + { + "date": "2018-02-16", + "close": 2732.22 + }, + { + "date": "2018-02-20", + "close": 2716.26 + }, + { + "date": "2018-02-21", + "close": 2701.33 + }, + { + "date": "2018-02-22", + "close": 2703.96 + }, + { + "date": "2018-02-23", + "close": 2747.3 + }, + { + "date": "2018-02-26", + "close": 2779.6 + }, + { + "date": "2018-02-27", + "close": 2744.28 + }, + { + "date": "2018-02-28", + "close": 2713.83 + }, + { + "date": "2018-03-01", + "close": 2677.67 + }, + { + "date": "2018-03-02", + "close": 2691.25 + }, + { + "date": "2018-03-05", + "close": 2720.94 + }, + { + "date": "2018-03-06", + "close": 2728.12 + }, + { + "date": "2018-03-07", + "close": 2726.8 + }, + { + "date": "2018-03-08", + "close": 2738.97 + }, + { + "date": "2018-03-09", + "close": 2786.57 + }, + { + "date": "2018-03-12", + "close": 2783.02 + }, + { + "date": "2018-03-13", + "close": 2765.31 + }, + { + "date": "2018-03-14", + "close": 2749.48 + }, + { + "date": "2018-03-15", + "close": 2747.33 + }, + { + "date": "2018-03-16", + "close": 2752.01 + }, + { + "date": "2018-03-19", + "close": 2712.92 + }, + { + "date": "2018-03-20", + "close": 2716.94 + }, + { + "date": "2018-03-21", + "close": 2711.93 + }, + { + "date": "2018-03-22", + "close": 2643.69 + }, + { + "date": "2018-03-23", + "close": 2588.26 + }, + { + "date": "2018-03-26", + "close": 2658.55 + }, + { + "date": "2018-03-27", + "close": 2612.62 + }, + { + "date": "2018-03-28", + "close": 2605 + }, + { + "date": "2018-03-29", + "close": 2640.87 + }, + { + "date": "2018-04-02", + "close": 2581.88 + }, + { + "date": "2018-04-03", + "close": 2614.45 + }, + { + "date": "2018-04-04", + "close": 2644.69 + }, + { + "date": "2018-04-05", + "close": 2662.84 + }, + { + "date": "2018-04-06", + "close": 2604.47 + }, + { + "date": "2018-04-09", + "close": 2613.16 + }, + { + "date": "2018-04-10", + "close": 2656.87 + }, + { + "date": "2018-04-11", + "close": 2642.19 + }, + { + "date": "2018-04-12", + "close": 2663.99 + }, + { + "date": "2018-04-13", + "close": 2656.3 + }, + { + "date": "2018-04-16", + "close": 2677.84 + }, + { + "date": "2018-04-17", + "close": 2706.39 + }, + { + "date": "2018-04-18", + "close": 2708.64 + }, + { + "date": "2018-04-19", + "close": 2693.13 + }, + { + "date": "2018-04-20", + "close": 2670.14 + }, + { + "date": "2018-04-23", + "close": 2670.29 + }, + { + "date": "2018-04-24", + "close": 2634.56 + }, + { + "date": "2018-04-25", + "close": 2639.4 + }, + { + "date": "2018-04-26", + "close": 2666.94 + }, + { + "date": "2018-04-27", + "close": 2669.91 + }, + { + "date": "2018-04-30", + "close": 2648.05 + }, + { + "date": "2018-05-01", + "close": 2654.8 + }, + { + "date": "2018-05-02", + "close": 2635.67 + }, + { + "date": "2018-05-03", + "close": 2629.73 + }, + { + "date": "2018-05-04", + "close": 2663.42 + }, + { + "date": "2018-05-07", + "close": 2672.63 + }, + { + "date": "2018-05-08", + "close": 2671.92 + }, + { + "date": "2018-05-09", + "close": 2697.79 + }, + { + "date": "2018-05-10", + "close": 2723.07 + }, + { + "date": "2018-05-11", + "close": 2727.72 + }, + { + "date": "2018-05-14", + "close": 2730.13 + }, + { + "date": "2018-05-15", + "close": 2711.45 + }, + { + "date": "2018-05-16", + "close": 2722.46 + }, + { + "date": "2018-05-17", + "close": 2720.13 + }, + { + "date": "2018-05-18", + "close": 2712.97 + }, + { + "date": "2018-05-21", + "close": 2733.01 + }, + { + "date": "2018-05-22", + "close": 2724.44 + }, + { + "date": "2018-05-23", + "close": 2733.29 + }, + { + "date": "2018-05-24", + "close": 2727.76 + }, + { + "date": "2018-05-25", + "close": 2721.33 + }, + { + "date": "2018-05-29", + "close": 2689.86 + }, + { + "date": "2018-05-30", + "close": 2724.01 + }, + { + "date": "2018-05-31", + "close": 2705.27 + }, + { + "date": "2018-06-01", + "close": 2734.62 + }, + { + "date": "2018-06-04", + "close": 2746.87 + }, + { + "date": "2018-06-05", + "close": 2748.8 + }, + { + "date": "2018-06-06", + "close": 2772.35 + }, + { + "date": "2018-06-07", + "close": 2770.37 + }, + { + "date": "2018-06-08", + "close": 2779.03 + }, + { + "date": "2018-06-11", + "close": 2782 + }, + { + "date": "2018-06-12", + "close": 2786.85 + }, + { + "date": "2018-06-13", + "close": 2775.63 + }, + { + "date": "2018-06-14", + "close": 2782.49 + }, + { + "date": "2018-06-15", + "close": 2779.66 + }, + { + "date": "2018-06-18", + "close": 2773.75 + }, + { + "date": "2018-06-19", + "close": 2762.59 + }, + { + "date": "2018-06-20", + "close": 2767.32 + }, + { + "date": "2018-06-21", + "close": 2749.76 + }, + { + "date": "2018-06-22", + "close": 2754.88 + }, + { + "date": "2018-06-25", + "close": 2717.07 + }, + { + "date": "2018-06-26", + "close": 2723.06 + }, + { + "date": "2018-06-27", + "close": 2699.63 + }, + { + "date": "2018-06-28", + "close": 2716.31 + }, + { + "date": "2018-06-29", + "close": 2718.37 + }, + { + "date": "2018-07-02", + "close": 2726.71 + }, + { + "date": "2018-07-03", + "close": 2713.22 + }, + { + "date": "2018-07-05", + "close": 2736.61 + }, + { + "date": "2018-07-06", + "close": 2759.82 + }, + { + "date": "2018-07-09", + "close": 2784.17 + }, + { + "date": "2018-07-10", + "close": 2793.84 + }, + { + "date": "2018-07-11", + "close": 2774.02 + }, + { + "date": "2018-07-12", + "close": 2798.29 + }, + { + "date": "2018-07-13", + "close": 2801.31 + }, + { + "date": "2018-07-16", + "close": 2798.43 + }, + { + "date": "2018-07-17", + "close": 2809.55 + }, + { + "date": "2018-07-18", + "close": 2815.62 + }, + { + "date": "2018-07-19", + "close": 2804.49 + }, + { + "date": "2018-07-20", + "close": 2801.83 + }, + { + "date": "2018-07-23", + "close": 2806.98 + }, + { + "date": "2018-07-24", + "close": 2820.4 + }, + { + "date": "2018-07-25", + "close": 2846.07 + }, + { + "date": "2018-07-26", + "close": 2837.44 + }, + { + "date": "2018-07-27", + "close": 2818.82 + }, + { + "date": "2018-07-30", + "close": 2802.6 + }, + { + "date": "2018-07-31", + "close": 2816.29 + }, + { + "date": "2018-08-01", + "close": 2813.36 + }, + { + "date": "2018-08-02", + "close": 2827.22 + }, + { + "date": "2018-08-03", + "close": 2840.35 + }, + { + "date": "2018-08-06", + "close": 2850.4 + }, + { + "date": "2018-08-07", + "close": 2858.45 + }, + { + "date": "2018-08-08", + "close": 2857.7 + }, + { + "date": "2018-08-09", + "close": 2853.58 + }, + { + "date": "2018-08-10", + "close": 2833.28 + }, + { + "date": "2018-08-13", + "close": 2821.93 + }, + { + "date": "2018-08-14", + "close": 2839.96 + }, + { + "date": "2018-08-15", + "close": 2818.37 + }, + { + "date": "2018-08-16", + "close": 2840.69 + }, + { + "date": "2018-08-17", + "close": 2850.13 + }, + { + "date": "2018-08-20", + "close": 2857.05 + }, + { + "date": "2018-08-21", + "close": 2862.96 + }, + { + "date": "2018-08-22", + "close": 2861.82 + }, + { + "date": "2018-08-23", + "close": 2856.98 + }, + { + "date": "2018-08-24", + "close": 2874.69 + }, + { + "date": "2018-08-27", + "close": 2896.74 + }, + { + "date": "2018-08-28", + "close": 2897.52 + }, + { + "date": "2018-08-29", + "close": 2914.04 + }, + { + "date": "2018-08-30", + "close": 2901.13 + }, + { + "date": "2018-08-31", + "close": 2901.52 + }, + { + "date": "2018-09-04", + "close": 2896.72 + }, + { + "date": "2018-09-05", + "close": 2888.6 + }, + { + "date": "2018-09-06", + "close": 2878.05 + }, + { + "date": "2018-09-07", + "close": 2871.68 + }, + { + "date": "2018-09-10", + "close": 2877.13 + }, + { + "date": "2018-09-11", + "close": 2887.89 + }, + { + "date": "2018-09-12", + "close": 2888.92 + }, + { + "date": "2018-09-13", + "close": 2904.18 + }, + { + "date": "2018-09-14", + "close": 2904.98 + }, + { + "date": "2018-09-17", + "close": 2888.8 + }, + { + "date": "2018-09-18", + "close": 2904.31 + }, + { + "date": "2018-09-19", + "close": 2907.95 + }, + { + "date": "2018-09-20", + "close": 2930.75 + }, + { + "date": "2018-09-21", + "close": 2929.67 + }, + { + "date": "2018-09-24", + "close": 2919.37 + }, + { + "date": "2018-09-25", + "close": 2915.56 + }, + { + "date": "2018-09-26", + "close": 2905.97 + }, + { + "date": "2018-09-27", + "close": 2914 + }, + { + "date": "2018-09-28", + "close": 2913.98 + }, + { + "date": "2018-10-01", + "close": 2924.59 + }, + { + "date": "2018-10-02", + "close": 2923.43 + }, + { + "date": "2018-10-03", + "close": 2925.51 + }, + { + "date": "2018-10-04", + "close": 2901.61 + }, + { + "date": "2018-10-05", + "close": 2885.57 + }, + { + "date": "2018-10-08", + "close": 2884.43 + }, + { + "date": "2018-10-09", + "close": 2880.34 + }, + { + "date": "2018-10-10", + "close": 2785.68 + }, + { + "date": "2018-10-11", + "close": 2728.37 + }, + { + "date": "2018-10-12", + "close": 2767.13 + }, + { + "date": "2018-10-15", + "close": 2750.79 + }, + { + "date": "2018-10-16", + "close": 2809.92 + }, + { + "date": "2018-10-17", + "close": 2809.21 + }, + { + "date": "2018-10-18", + "close": 2768.78 + }, + { + "date": "2018-10-19", + "close": 2767.78 + }, + { + "date": "2018-10-22", + "close": 2755.88 + }, + { + "date": "2018-10-23", + "close": 2740.69 + }, + { + "date": "2018-10-24", + "close": 2656.1 + }, + { + "date": "2018-10-25", + "close": 2705.57 + }, + { + "date": "2018-10-26", + "close": 2658.69 + }, + { + "date": "2018-10-29", + "close": 2641.25 + }, + { + "date": "2018-10-30", + "close": 2682.63 + }, + { + "date": "2018-10-31", + "close": 2711.74 + }, + { + "date": "2018-11-01", + "close": 2740.37 + }, + { + "date": "2018-11-02", + "close": 2723.06 + }, + { + "date": "2018-11-05", + "close": 2738.31 + }, + { + "date": "2018-11-06", + "close": 2755.45 + }, + { + "date": "2018-11-07", + "close": 2813.89 + }, + { + "date": "2018-11-08", + "close": 2806.83 + }, + { + "date": "2018-11-09", + "close": 2781.01 + }, + { + "date": "2018-11-12", + "close": 2726.22 + }, + { + "date": "2018-11-13", + "close": 2722.18 + }, + { + "date": "2018-11-14", + "close": 2701.58 + }, + { + "date": "2018-11-15", + "close": 2730.2 + }, + { + "date": "2018-11-16", + "close": 2736.27 + }, + { + "date": "2018-11-19", + "close": 2690.73 + }, + { + "date": "2018-11-20", + "close": 2641.89 + }, + { + "date": "2018-11-21", + "close": 2649.93 + }, + { + "date": "2018-11-23", + "close": 2632.56 + }, + { + "date": "2018-11-26", + "close": 2673.45 + }, + { + "date": "2018-11-27", + "close": 2682.17 + }, + { + "date": "2018-11-28", + "close": 2743.79 + }, + { + "date": "2018-11-29", + "close": 2737.8 + }, + { + "date": "2018-11-30", + "close": 2760.17 + }, + { + "date": "2018-12-03", + "close": 2790.37 + }, + { + "date": "2018-12-04", + "close": 2700.06 + }, + { + "date": "2018-12-06", + "close": 2695.95 + }, + { + "date": "2018-12-07", + "close": 2633.08 + }, + { + "date": "2018-12-10", + "close": 2637.72 + }, + { + "date": "2018-12-11", + "close": 2636.78 + }, + { + "date": "2018-12-12", + "close": 2651.07 + }, + { + "date": "2018-12-13", + "close": 2650.54 + }, + { + "date": "2018-12-14", + "close": 2599.95 + }, + { + "date": "2018-12-17", + "close": 2545.94 + }, + { + "date": "2018-12-18", + "close": 2546.16 + }, + { + "date": "2018-12-19", + "close": 2506.96 + }, + { + "date": "2018-12-20", + "close": 2467.42 + }, + { + "date": "2018-12-21", + "close": 2416.62 + }, + { + "date": "2018-12-24", + "close": 2351.1 + }, + { + "date": "2018-12-26", + "close": 2467.7 + }, + { + "date": "2018-12-27", + "close": 2488.83 + }, + { + "date": "2018-12-28", + "close": 2485.74 + }, + { + "date": "2018-12-31", + "close": 2506.85 + }, + { + "date": "2019-01-02", + "close": 2510.03 + }, + { + "date": "2019-01-03", + "close": 2447.89 + }, + { + "date": "2019-01-04", + "close": 2531.94 + }, + { + "date": "2019-01-07", + "close": 2549.69 + }, + { + "date": "2019-01-08", + "close": 2574.41 + }, + { + "date": "2019-01-09", + "close": 2584.96 + }, + { + "date": "2019-01-10", + "close": 2596.64 + }, + { + "date": "2019-01-11", + "close": 2596.26 + }, + { + "date": "2019-01-14", + "close": 2582.61 + }, + { + "date": "2019-01-15", + "close": 2610.3 + }, + { + "date": "2019-01-16", + "close": 2616.1 + }, + { + "date": "2019-01-17", + "close": 2635.96 + }, + { + "date": "2019-01-18", + "close": 2670.71 + }, + { + "date": "2019-01-22", + "close": 2632.9 + }, + { + "date": "2019-01-23", + "close": 2638.7 + }, + { + "date": "2019-01-24", + "close": 2642.33 + }, + { + "date": "2019-01-25", + "close": 2664.76 + }, + { + "date": "2019-01-28", + "close": 2643.85 + }, + { + "date": "2019-01-29", + "close": 2640 + }, + { + "date": "2019-01-30", + "close": 2681.05 + }, + { + "date": "2019-01-31", + "close": 2704.1 + }, + { + "date": "2019-02-01", + "close": 2706.53 + }, + { + "date": "2019-02-04", + "close": 2724.87 + }, + { + "date": "2019-02-05", + "close": 2737.7 + }, + { + "date": "2019-02-06", + "close": 2731.61 + }, + { + "date": "2019-02-07", + "close": 2706.05 + }, + { + "date": "2019-02-08", + "close": 2707.88 + }, + { + "date": "2019-02-11", + "close": 2709.8 + }, + { + "date": "2019-02-12", + "close": 2744.73 + }, + { + "date": "2019-02-13", + "close": 2753.03 + }, + { + "date": "2019-02-14", + "close": 2745.73 + }, + { + "date": "2019-02-15", + "close": 2775.6 + }, + { + "date": "2019-02-19", + "close": 2779.76 + }, + { + "date": "2019-02-20", + "close": 2784.7 + }, + { + "date": "2019-02-21", + "close": 2774.88 + }, + { + "date": "2019-02-22", + "close": 2792.67 + }, + { + "date": "2019-02-25", + "close": 2796.11 + }, + { + "date": "2019-02-26", + "close": 2793.9 + }, + { + "date": "2019-02-27", + "close": 2792.38 + }, + { + "date": "2019-02-28", + "close": 2784.49 + }, + { + "date": "2019-03-01", + "close": 2803.69 + }, + { + "date": "2019-03-04", + "close": 2792.81 + }, + { + "date": "2019-03-05", + "close": 2789.65 + }, + { + "date": "2019-03-06", + "close": 2771.45 + }, + { + "date": "2019-03-07", + "close": 2748.93 + }, + { + "date": "2019-03-08", + "close": 2743.07 + }, + { + "date": "2019-03-11", + "close": 2783.3 + }, + { + "date": "2019-03-12", + "close": 2791.52 + }, + { + "date": "2019-03-13", + "close": 2810.92 + }, + { + "date": "2019-03-14", + "close": 2808.48 + }, + { + "date": "2019-03-15", + "close": 2822.48 + }, + { + "date": "2019-03-18", + "close": 2832.94 + }, + { + "date": "2019-03-19", + "close": 2832.57 + }, + { + "date": "2019-03-20", + "close": 2824.23 + }, + { + "date": "2019-03-21", + "close": 2854.88 + }, + { + "date": "2019-03-22", + "close": 2800.71 + }, + { + "date": "2019-03-25", + "close": 2798.36 + }, + { + "date": "2019-03-26", + "close": 2818.46 + }, + { + "date": "2019-03-27", + "close": 2805.37 + }, + { + "date": "2019-03-28", + "close": 2815.44 + }, + { + "date": "2019-03-29", + "close": 2834.4 + }, + { + "date": "2019-04-01", + "close": 2867.19 + }, + { + "date": "2019-04-02", + "close": 2867.24 + }, + { + "date": "2019-04-03", + "close": 2873.4 + }, + { + "date": "2019-04-04", + "close": 2879.39 + }, + { + "date": "2019-04-05", + "close": 2892.74 + }, + { + "date": "2019-04-08", + "close": 2895.77 + }, + { + "date": "2019-04-09", + "close": 2878.2 + }, + { + "date": "2019-04-10", + "close": 2888.21 + }, + { + "date": "2019-04-11", + "close": 2888.32 + }, + { + "date": "2019-04-12", + "close": 2907.41 + }, + { + "date": "2019-04-15", + "close": 2905.58 + }, + { + "date": "2019-04-16", + "close": 2907.06 + }, + { + "date": "2019-04-17", + "close": 2900.45 + }, + { + "date": "2019-04-18", + "close": 2905.03 + }, + { + "date": "2019-04-22", + "close": 2907.97 + }, + { + "date": "2019-04-23", + "close": 2933.68 + }, + { + "date": "2019-04-24", + "close": 2927.25 + }, + { + "date": "2019-04-25", + "close": 2926.17 + }, + { + "date": "2019-04-26", + "close": 2939.88 + }, + { + "date": "2019-04-29", + "close": 2943.03 + }, + { + "date": "2019-04-30", + "close": 2945.83 + }, + { + "date": "2019-05-01", + "close": 2923.73 + }, + { + "date": "2019-05-02", + "close": 2917.52 + }, + { + "date": "2019-05-03", + "close": 2945.64 + }, + { + "date": "2019-05-06", + "close": 2932.47 + }, + { + "date": "2019-05-07", + "close": 2884.05 + }, + { + "date": "2019-05-08", + "close": 2879.42 + }, + { + "date": "2019-05-09", + "close": 2870.72 + }, + { + "date": "2019-05-10", + "close": 2881.4 + }, + { + "date": "2019-05-13", + "close": 2811.87 + }, + { + "date": "2019-05-14", + "close": 2834.41 + }, + { + "date": "2019-05-15", + "close": 2850.96 + }, + { + "date": "2019-05-16", + "close": 2876.32 + }, + { + "date": "2019-05-17", + "close": 2859.53 + }, + { + "date": "2019-05-20", + "close": 2840.23 + }, + { + "date": "2019-05-21", + "close": 2864.36 + }, + { + "date": "2019-05-22", + "close": 2856.27 + }, + { + "date": "2019-05-23", + "close": 2822.24 + }, + { + "date": "2019-05-24", + "close": 2826.06 + }, + { + "date": "2019-05-28", + "close": 2802.39 + }, + { + "date": "2019-05-29", + "close": 2783.02 + }, + { + "date": "2019-05-30", + "close": 2788.86 + }, + { + "date": "2019-05-31", + "close": 2752.06 + }, + { + "date": "2019-06-03", + "close": 2744.45 + }, + { + "date": "2019-06-04", + "close": 2803.27 + }, + { + "date": "2019-06-05", + "close": 2826.15 + }, + { + "date": "2019-06-06", + "close": 2843.49 + }, + { + "date": "2019-06-07", + "close": 2873.34 + }, + { + "date": "2019-06-10", + "close": 2886.73 + }, + { + "date": "2019-06-11", + "close": 2885.72 + }, + { + "date": "2019-06-12", + "close": 2879.84 + }, + { + "date": "2019-06-13", + "close": 2891.64 + }, + { + "date": "2019-06-14", + "close": 2886.98 + }, + { + "date": "2019-06-17", + "close": 2889.67 + }, + { + "date": "2019-06-18", + "close": 2917.75 + }, + { + "date": "2019-06-19", + "close": 2926.46 + }, + { + "date": "2019-06-20", + "close": 2954.18 + }, + { + "date": "2019-06-21", + "close": 2950.46 + }, + { + "date": "2019-06-24", + "close": 2945.35 + }, + { + "date": "2019-06-25", + "close": 2917.38 + }, + { + "date": "2019-06-26", + "close": 2913.78 + }, + { + "date": "2019-06-27", + "close": 2924.92 + }, + { + "date": "2019-06-28", + "close": 2941.76 + }, + { + "date": "2019-07-01", + "close": 2964.33 + }, + { + "date": "2019-07-02", + "close": 2973.01 + }, + { + "date": "2019-07-03", + "close": 2995.82 + }, + { + "date": "2019-07-05", + "close": 2990.41 + }, + { + "date": "2019-07-08", + "close": 2975.95 + }, + { + "date": "2019-07-09", + "close": 2979.63 + }, + { + "date": "2019-07-10", + "close": 2993.07 + }, + { + "date": "2019-07-11", + "close": 2999.91 + }, + { + "date": "2019-07-12", + "close": 3013.77 + }, + { + "date": "2019-07-15", + "close": 3014.3 + }, + { + "date": "2019-07-16", + "close": 3004.04 + }, + { + "date": "2019-07-17", + "close": 2984.42 + }, + { + "date": "2019-07-18", + "close": 2995.11 + }, + { + "date": "2019-07-19", + "close": 2976.61 + }, + { + "date": "2019-07-22", + "close": 2985.03 + }, + { + "date": "2019-07-23", + "close": 3005.47 + }, + { + "date": "2019-07-24", + "close": 3019.56 + }, + { + "date": "2019-07-25", + "close": 3003.67 + }, + { + "date": "2019-07-26", + "close": 3025.86 + }, + { + "date": "2019-07-29", + "close": 3020.97 + }, + { + "date": "2019-07-30", + "close": 3013.18 + }, + { + "date": "2019-07-31", + "close": 2980.38 + }, + { + "date": "2019-08-01", + "close": 2953.56 + }, + { + "date": "2019-08-02", + "close": 2932.05 + }, + { + "date": "2019-08-05", + "close": 2844.74 + }, + { + "date": "2019-08-06", + "close": 2881.77 + }, + { + "date": "2019-08-07", + "close": 2883.98 + }, + { + "date": "2019-08-08", + "close": 2938.09 + }, + { + "date": "2019-08-09", + "close": 2918.65 + }, + { + "date": "2019-08-12", + "close": 2882.7 + }, + { + "date": "2019-08-13", + "close": 2926.32 + }, + { + "date": "2019-08-14", + "close": 2840.6 + }, + { + "date": "2019-08-15", + "close": 2847.6 + }, + { + "date": "2019-08-16", + "close": 2888.68 + }, + { + "date": "2019-08-19", + "close": 2923.65 + }, + { + "date": "2019-08-20", + "close": 2900.51 + }, + { + "date": "2019-08-21", + "close": 2924.43 + }, + { + "date": "2019-08-22", + "close": 2922.95 + }, + { + "date": "2019-08-23", + "close": 2847.11 + }, + { + "date": "2019-08-26", + "close": 2878.38 + }, + { + "date": "2019-08-27", + "close": 2869.16 + }, + { + "date": "2019-08-28", + "close": 2887.94 + }, + { + "date": "2019-08-29", + "close": 2924.58 + }, + { + "date": "2019-08-30", + "close": 2926.46 + }, + { + "date": "2019-09-03", + "close": 2906.27 + }, + { + "date": "2019-09-04", + "close": 2937.78 + }, + { + "date": "2019-09-05", + "close": 2976 + }, + { + "date": "2019-09-06", + "close": 2978.71 + }, + { + "date": "2019-09-09", + "close": 2978.43 + }, + { + "date": "2019-09-10", + "close": 2979.39 + }, + { + "date": "2019-09-11", + "close": 3000.93 + }, + { + "date": "2019-09-12", + "close": 3009.57 + }, + { + "date": "2019-09-13", + "close": 3007.39 + }, + { + "date": "2019-09-16", + "close": 2997.96 + }, + { + "date": "2019-09-17", + "close": 3005.7 + }, + { + "date": "2019-09-18", + "close": 3006.73 + }, + { + "date": "2019-09-19", + "close": 3006.79 + }, + { + "date": "2019-09-20", + "close": 2992.07 + }, + { + "date": "2019-09-23", + "close": 2991.78 + }, + { + "date": "2019-09-24", + "close": 2966.6 + }, + { + "date": "2019-09-25", + "close": 2984.87 + }, + { + "date": "2019-09-26", + "close": 2977.62 + }, + { + "date": "2019-09-27", + "close": 2961.79 + }, + { + "date": "2019-09-30", + "close": 2976.74 + }, + { + "date": "2019-10-01", + "close": 2940.25 + }, + { + "date": "2019-10-02", + "close": 2887.61 + }, + { + "date": "2019-10-03", + "close": 2910.63 + }, + { + "date": "2019-10-04", + "close": 2952.01 + }, + { + "date": "2019-10-07", + "close": 2938.79 + }, + { + "date": "2019-10-08", + "close": 2893.06 + }, + { + "date": "2019-10-09", + "close": 2919.4 + }, + { + "date": "2019-10-10", + "close": 2938.13 + }, + { + "date": "2019-10-11", + "close": 2970.27 + }, + { + "date": "2019-10-14", + "close": 2966.15 + }, + { + "date": "2019-10-15", + "close": 2995.68 + }, + { + "date": "2019-10-16", + "close": 2989.69 + }, + { + "date": "2019-10-17", + "close": 2997.95 + }, + { + "date": "2019-10-18", + "close": 2986.2 + }, + { + "date": "2019-10-21", + "close": 3006.72 + }, + { + "date": "2019-10-22", + "close": 2995.99 + }, + { + "date": "2019-10-23", + "close": 3004.52 + }, + { + "date": "2019-10-24", + "close": 3010.29 + }, + { + "date": "2019-10-25", + "close": 3022.55 + }, + { + "date": "2019-10-28", + "close": 3039.42 + }, + { + "date": "2019-10-29", + "close": 3036.89 + }, + { + "date": "2019-10-30", + "close": 3046.77 + }, + { + "date": "2019-10-31", + "close": 3037.56 + }, + { + "date": "2019-11-01", + "close": 3066.91 + }, + { + "date": "2019-11-04", + "close": 3078.27 + }, + { + "date": "2019-11-05", + "close": 3074.62 + }, + { + "date": "2019-11-06", + "close": 3076.78 + }, + { + "date": "2019-11-07", + "close": 3085.18 + }, + { + "date": "2019-11-08", + "close": 3093.08 + }, + { + "date": "2019-11-11", + "close": 3087.01 + }, + { + "date": "2019-11-12", + "close": 3091.84 + }, + { + "date": "2019-11-13", + "close": 3094.04 + }, + { + "date": "2019-11-14", + "close": 3096.63 + }, + { + "date": "2019-11-15", + "close": 3120.46 + }, + { + "date": "2019-11-18", + "close": 3122.03 + }, + { + "date": "2019-11-19", + "close": 3120.18 + }, + { + "date": "2019-11-20", + "close": 3108.46 + }, + { + "date": "2019-11-21", + "close": 3103.54 + }, + { + "date": "2019-11-22", + "close": 3110.29 + }, + { + "date": "2019-11-25", + "close": 3133.64 + }, + { + "date": "2019-11-26", + "close": 3140.52 + }, + { + "date": "2019-11-27", + "close": 3153.63 + }, + { + "date": "2019-11-29", + "close": 3140.98 + }, + { + "date": "2019-12-02", + "close": 3113.87 + }, + { + "date": "2019-12-03", + "close": 3093.2 + }, + { + "date": "2019-12-04", + "close": 3112.76 + }, + { + "date": "2019-12-05", + "close": 3117.43 + }, + { + "date": "2019-12-06", + "close": 3145.91 + }, + { + "date": "2019-12-09", + "close": 3135.96 + }, + { + "date": "2019-12-10", + "close": 3132.52 + }, + { + "date": "2019-12-11", + "close": 3141.63 + }, + { + "date": "2019-12-12", + "close": 3168.57 + }, + { + "date": "2019-12-13", + "close": 3168.8 + }, + { + "date": "2019-12-16", + "close": 3191.45 + }, + { + "date": "2019-12-17", + "close": 3192.52 + }, + { + "date": "2019-12-18", + "close": 3191.14 + }, + { + "date": "2019-12-19", + "close": 3205.37 + }, + { + "date": "2019-12-20", + "close": 3221.22 + }, + { + "date": "2019-12-23", + "close": 3224.01 + }, + { + "date": "2019-12-24", + "close": 3223.38 + }, + { + "date": "2019-12-26", + "close": 3239.91 + }, + { + "date": "2019-12-27", + "close": 3240.02 + }, + { + "date": "2019-12-30", + "close": 3221.29 + }, + { + "date": "2019-12-31", + "close": 3230.78 + }, + { + "date": "2020-01-02", + "close": 3257.85 + }, + { + "date": "2020-01-03", + "close": 3234.85 + }, + { + "date": "2020-01-06", + "close": 3246.28 + }, + { + "date": "2020-01-07", + "close": 3237.18 + }, + { + "date": "2020-01-08", + "close": 3253.05 + }, + { + "date": "2020-01-09", + "close": 3274.7 + }, + { + "date": "2020-01-10", + "close": 3265.35 + }, + { + "date": "2020-01-13", + "close": 3288.13 + }, + { + "date": "2020-01-14", + "close": 3283.15 + }, + { + "date": "2020-01-15", + "close": 3289.29 + }, + { + "date": "2020-01-16", + "close": 3316.81 + }, + { + "date": "2020-01-17", + "close": 3329.62 + }, + { + "date": "2020-01-21", + "close": 3320.79 + }, + { + "date": "2020-01-22", + "close": 3321.75 + }, + { + "date": "2020-01-23", + "close": 3325.54 + }, + { + "date": "2020-01-24", + "close": 3295.47 + }, + { + "date": "2020-01-27", + "close": 3243.63 + }, + { + "date": "2020-01-28", + "close": 3276.24 + }, + { + "date": "2020-01-29", + "close": 3273.4 + }, + { + "date": "2020-01-30", + "close": 3283.66 + }, + { + "date": "2020-01-31", + "close": 3225.52 + }, + { + "date": "2020-02-03", + "close": 3248.92 + }, + { + "date": "2020-02-04", + "close": 3297.59 + }, + { + "date": "2020-02-05", + "close": 3334.69 + }, + { + "date": "2020-02-06", + "close": 3345.78 + }, + { + "date": "2020-02-07", + "close": 3327.71 + }, + { + "date": "2020-02-10", + "close": 3352.09 + }, + { + "date": "2020-02-11", + "close": 3357.75 + }, + { + "date": "2020-02-12", + "close": 3379.45 + }, + { + "date": "2020-02-13", + "close": 3373.94 + }, + { + "date": "2020-02-14", + "close": 3380.16 + }, + { + "date": "2020-02-18", + "close": 3370.29 + }, + { + "date": "2020-02-19", + "close": 3386.15 + }, + { + "date": "2020-02-20", + "close": 3373.23 + }, + { + "date": "2020-02-21", + "close": 3337.75 + }, + { + "date": "2020-02-24", + "close": 3225.89 + }, + { + "date": "2020-02-25", + "close": 3128.21 + }, + { + "date": "2020-02-26", + "close": 3116.39 + }, + { + "date": "2020-02-27", + "close": 2978.76 + }, + { + "date": "2020-02-28", + "close": 2954.22 + }, + { + "date": "2020-03-02", + "close": 3090.23 + }, + { + "date": "2020-03-03", + "close": 3003.37 + }, + { + "date": "2020-03-04", + "close": 3130.12 + }, + { + "date": "2020-03-05", + "close": 3023.94 + }, + { + "date": "2020-03-06", + "close": 2972.37 + }, + { + "date": "2020-03-09", + "close": 2746.56 + }, + { + "date": "2020-03-10", + "close": 2882.23 + }, + { + "date": "2020-03-11", + "close": 2741.38 + }, + { + "date": "2020-03-12", + "close": 2480.64 + }, + { + "date": "2020-03-13", + "close": 2711.02 + }, + { + "date": "2020-03-16", + "close": 2386.13 + }, + { + "date": "2020-03-17", + "close": 2529.19 + }, + { + "date": "2020-03-18", + "close": 2398.1 + }, + { + "date": "2020-03-19", + "close": 2409.39 + }, + { + "date": "2020-03-20", + "close": 2304.92 + }, + { + "date": "2020-03-23", + "close": 2237.4 + }, + { + "date": "2020-03-24", + "close": 2447.33 + }, + { + "date": "2020-03-25", + "close": 2475.56 + }, + { + "date": "2020-03-26", + "close": 2630.07 + }, + { + "date": "2020-03-27", + "close": 2541.47 + }, + { + "date": "2020-03-30", + "close": 2626.65 + }, + { + "date": "2020-03-31", + "close": 2584.59 + }, + { + "date": "2020-04-01", + "close": 2470.5 + }, + { + "date": "2020-04-02", + "close": 2526.9 + }, + { + "date": "2020-04-03", + "close": 2488.65 + }, + { + "date": "2020-04-06", + "close": 2663.68 + }, + { + "date": "2020-04-07", + "close": 2659.41 + }, + { + "date": "2020-04-08", + "close": 2749.98 + }, + { + "date": "2020-04-09", + "close": 2789.82 + }, + { + "date": "2020-04-13", + "close": 2761.63 + }, + { + "date": "2020-04-14", + "close": 2846.06 + }, + { + "date": "2020-04-15", + "close": 2783.36 + }, + { + "date": "2020-04-16", + "close": 2799.55 + }, + { + "date": "2020-04-17", + "close": 2874.56 + }, + { + "date": "2020-04-20", + "close": 2823.16 + }, + { + "date": "2020-04-21", + "close": 2736.56 + }, + { + "date": "2020-04-22", + "close": 2799.31 + }, + { + "date": "2020-04-23", + "close": 2797.8 + }, + { + "date": "2020-04-24", + "close": 2836.74 + }, + { + "date": "2020-04-27", + "close": 2878.48 + }, + { + "date": "2020-04-28", + "close": 2863.39 + }, + { + "date": "2020-04-29", + "close": 2939.51 + }, + { + "date": "2020-04-30", + "close": 2912.43 + }, + { + "date": "2020-05-01", + "close": 2830.71 + }, + { + "date": "2020-05-04", + "close": 2842.74 + }, + { + "date": "2020-05-05", + "close": 2868.44 + }, + { + "date": "2020-05-06", + "close": 2848.42 + }, + { + "date": "2020-05-07", + "close": 2881.19 + }, + { + "date": "2020-05-08", + "close": 2929.8 + }, + { + "date": "2020-05-11", + "close": 2930.19 + }, + { + "date": "2020-05-12", + "close": 2870.12 + }, + { + "date": "2020-05-13", + "close": 2820 + }, + { + "date": "2020-05-14", + "close": 2852.5 + }, + { + "date": "2020-05-15", + "close": 2863.7 + }, + { + "date": "2020-05-18", + "close": 2953.91 + }, + { + "date": "2020-05-19", + "close": 2922.94 + }, + { + "date": "2020-05-20", + "close": 2971.61 + }, + { + "date": "2020-05-21", + "close": 2948.51 + }, + { + "date": "2020-05-22", + "close": 2955.45 + }, + { + "date": "2020-05-26", + "close": 2991.77 + }, + { + "date": "2020-05-27", + "close": 3036.13 + }, + { + "date": "2020-05-28", + "close": 3029.73 + }, + { + "date": "2020-05-29", + "close": 3044.31 + }, + { + "date": "2020-06-01", + "close": 3055.73 + }, + { + "date": "2020-06-02", + "close": 3080.82 + }, + { + "date": "2020-06-03", + "close": 3122.87 + }, + { + "date": "2020-06-04", + "close": 3112.35 + }, + { + "date": "2020-06-05", + "close": 3193.93 + }, + { + "date": "2020-06-08", + "close": 3232.39 + }, + { + "date": "2020-06-09", + "close": 3207.18 + }, + { + "date": "2020-06-10", + "close": 3190.14 + }, + { + "date": "2020-06-11", + "close": 3002.1 + }, + { + "date": "2020-06-12", + "close": 3041.31 + }, + { + "date": "2020-06-15", + "close": 3066.59 + }, + { + "date": "2020-06-16", + "close": 3124.74 + }, + { + "date": "2020-06-17", + "close": 3113.49 + }, + { + "date": "2020-06-18", + "close": 3115.34 + }, + { + "date": "2020-06-19", + "close": 3097.74 + }, + { + "date": "2020-06-22", + "close": 3117.86 + }, + { + "date": "2020-06-23", + "close": 3131.29 + }, + { + "date": "2020-06-24", + "close": 3050.33 + }, + { + "date": "2020-06-25", + "close": 3083.76 + }, + { + "date": "2020-06-26", + "close": 3009.05 + }, + { + "date": "2020-06-29", + "close": 3053.24 + }, + { + "date": "2020-06-30", + "close": 3100.29 + }, + { + "date": "2020-07-01", + "close": 3115.86 + }, + { + "date": "2020-07-02", + "close": 3130.01 + }, + { + "date": "2020-07-06", + "close": 3179.72 + }, + { + "date": "2020-07-07", + "close": 3145.32 + }, + { + "date": "2020-07-08", + "close": 3169.94 + }, + { + "date": "2020-07-09", + "close": 3152.05 + }, + { + "date": "2020-07-10", + "close": 3185.04 + }, + { + "date": "2020-07-13", + "close": 3155.22 + }, + { + "date": "2020-07-14", + "close": 3197.52 + }, + { + "date": "2020-07-15", + "close": 3226.56 + }, + { + "date": "2020-07-16", + "close": 3215.57 + }, + { + "date": "2020-07-17", + "close": 3224.73 + }, + { + "date": "2020-07-20", + "close": 3251.84 + }, + { + "date": "2020-07-21", + "close": 3257.3 + }, + { + "date": "2020-07-22", + "close": 3276.02 + }, + { + "date": "2020-07-23", + "close": 3235.66 + }, + { + "date": "2020-07-24", + "close": 3215.63 + }, + { + "date": "2020-07-27", + "close": 3239.41 + }, + { + "date": "2020-07-28", + "close": 3218.44 + }, + { + "date": "2020-07-29", + "close": 3258.44 + }, + { + "date": "2020-07-30", + "close": 3246.22 + }, + { + "date": "2020-07-31", + "close": 3271.12 + }, + { + "date": "2020-08-03", + "close": 3294.61 + }, + { + "date": "2020-08-04", + "close": 3306.51 + }, + { + "date": "2020-08-05", + "close": 3327.77 + }, + { + "date": "2020-08-06", + "close": 3349.16 + }, + { + "date": "2020-08-07", + "close": 3351.28 + }, + { + "date": "2020-08-10", + "close": 3360.47 + }, + { + "date": "2020-08-11", + "close": 3333.69 + }, + { + "date": "2020-08-12", + "close": 3380.35 + }, + { + "date": "2020-08-13", + "close": 3373.43 + }, + { + "date": "2020-08-14", + "close": 3372.85 + }, + { + "date": "2020-08-17", + "close": 3381.99 + }, + { + "date": "2020-08-18", + "close": 3389.78 + }, + { + "date": "2020-08-19", + "close": 3374.85 + }, + { + "date": "2020-08-20", + "close": 3385.51 + }, + { + "date": "2020-08-21", + "close": 3397.16 + }, + { + "date": "2020-08-24", + "close": 3431.28 + }, + { + "date": "2020-08-25", + "close": 3443.62 + }, + { + "date": "2020-08-26", + "close": 3478.73 + }, + { + "date": "2020-08-27", + "close": 3484.55 + }, + { + "date": "2020-08-28", + "close": 3508.01 + }, + { + "date": "2020-08-31", + "close": 3500.31 + }, + { + "date": "2020-09-01", + "close": 3526.65 + }, + { + "date": "2020-09-02", + "close": 3580.84 + }, + { + "date": "2020-09-03", + "close": 3455.06 + }, + { + "date": "2020-09-04", + "close": 3426.96 + }, + { + "date": "2020-09-08", + "close": 3331.84 + }, + { + "date": "2020-09-09", + "close": 3398.96 + }, + { + "date": "2020-09-10", + "close": 3339.19 + }, + { + "date": "2020-09-11", + "close": 3340.97 + }, + { + "date": "2020-09-14", + "close": 3383.54 + }, + { + "date": "2020-09-15", + "close": 3401.2 + }, + { + "date": "2020-09-16", + "close": 3385.49 + }, + { + "date": "2020-09-17", + "close": 3357.01 + }, + { + "date": "2020-09-18", + "close": 3319.47 + }, + { + "date": "2020-09-21", + "close": 3281.06 + }, + { + "date": "2020-09-22", + "close": 3315.57 + }, + { + "date": "2020-09-23", + "close": 3236.92 + }, + { + "date": "2020-09-24", + "close": 3246.59 + }, + { + "date": "2020-09-25", + "close": 3298.46 + }, + { + "date": "2020-09-28", + "close": 3351.6 + }, + { + "date": "2020-09-29", + "close": 3335.47 + }, + { + "date": "2020-09-30", + "close": 3363 + }, + { + "date": "2020-10-01", + "close": 3380.8 + }, + { + "date": "2020-10-02", + "close": 3348.42 + }, + { + "date": "2020-10-05", + "close": 3408.6 + }, + { + "date": "2020-10-06", + "close": 3360.97 + }, + { + "date": "2020-10-07", + "close": 3419.44 + }, + { + "date": "2020-10-08", + "close": 3446.83 + }, + { + "date": "2020-10-09", + "close": 3477.14 + }, + { + "date": "2020-10-12", + "close": 3534.22 + }, + { + "date": "2020-10-13", + "close": 3511.93 + }, + { + "date": "2020-10-14", + "close": 3488.67 + }, + { + "date": "2020-10-15", + "close": 3483.34 + }, + { + "date": "2020-10-16", + "close": 3483.81 + }, + { + "date": "2020-10-19", + "close": 3426.92 + }, + { + "date": "2020-10-20", + "close": 3443.12 + }, + { + "date": "2020-10-21", + "close": 3435.56 + }, + { + "date": "2020-10-22", + "close": 3453.49 + }, + { + "date": "2020-10-23", + "close": 3465.39 + }, + { + "date": "2020-10-26", + "close": 3400.97 + }, + { + "date": "2020-10-27", + "close": 3390.68 + }, + { + "date": "2020-10-28", + "close": 3271.03 + }, + { + "date": "2020-10-29", + "close": 3310.11 + }, + { + "date": "2020-10-30", + "close": 3269.96 + }, + { + "date": "2020-11-02", + "close": 3310.24 + }, + { + "date": "2020-11-03", + "close": 3369.16 + }, + { + "date": "2020-11-04", + "close": 3443.44 + }, + { + "date": "2020-11-05", + "close": 3510.45 + }, + { + "date": "2020-11-06", + "close": 3509.44 + }, + { + "date": "2020-11-09", + "close": 3550.5 + }, + { + "date": "2020-11-10", + "close": 3545.53 + }, + { + "date": "2020-11-11", + "close": 3572.66 + }, + { + "date": "2020-11-12", + "close": 3537.01 + }, + { + "date": "2020-11-13", + "close": 3585.15 + }, + { + "date": "2020-11-16", + "close": 3626.91 + }, + { + "date": "2020-11-17", + "close": 3609.53 + }, + { + "date": "2020-11-18", + "close": 3567.79 + }, + { + "date": "2020-11-19", + "close": 3581.87 + }, + { + "date": "2020-11-20", + "close": 3557.54 + }, + { + "date": "2020-11-23", + "close": 3577.59 + }, + { + "date": "2020-11-24", + "close": 3635.41 + }, + { + "date": "2020-11-25", + "close": 3629.65 + }, + { + "date": "2020-11-27", + "close": 3638.35 + }, + { + "date": "2020-11-30", + "close": 3621.63 + }, + { + "date": "2020-12-01", + "close": 3662.45 + }, + { + "date": "2020-12-02", + "close": 3669.01 + }, + { + "date": "2020-12-03", + "close": 3666.72 + }, + { + "date": "2020-12-04", + "close": 3699.12 + }, + { + "date": "2020-12-07", + "close": 3691.96 + }, + { + "date": "2020-12-08", + "close": 3702.25 + }, + { + "date": "2020-12-09", + "close": 3672.82 + }, + { + "date": "2020-12-10", + "close": 3668.1 + }, + { + "date": "2020-12-11", + "close": 3663.46 + }, + { + "date": "2020-12-14", + "close": 3647.49 + }, + { + "date": "2020-12-15", + "close": 3694.62 + }, + { + "date": "2020-12-16", + "close": 3701.17 + }, + { + "date": "2020-12-17", + "close": 3722.48 + }, + { + "date": "2020-12-18", + "close": 3709.41 + }, + { + "date": "2020-12-21", + "close": 3694.92 + }, + { + "date": "2020-12-22", + "close": 3687.26 + }, + { + "date": "2020-12-23", + "close": 3690.01 + }, + { + "date": "2020-12-24", + "close": 3703.06 + }, + { + "date": "2020-12-28", + "close": 3735.36 + }, + { + "date": "2020-12-29", + "close": 3727.04 + }, + { + "date": "2020-12-30", + "close": 3732.04 + }, + { + "date": "2020-12-31", + "close": 3756.07 + }, + { + "date": "2021-01-04", + "close": 3700.65 + }, + { + "date": "2021-01-05", + "close": 3726.86 + }, + { + "date": "2021-01-06", + "close": 3748.14 + }, + { + "date": "2021-01-07", + "close": 3803.79 + }, + { + "date": "2021-01-08", + "close": 3824.68 + }, + { + "date": "2021-01-11", + "close": 3799.61 + }, + { + "date": "2021-01-12", + "close": 3801.19 + }, + { + "date": "2021-01-13", + "close": 3809.84 + }, + { + "date": "2021-01-14", + "close": 3795.54 + }, + { + "date": "2021-01-15", + "close": 3768.25 + }, + { + "date": "2021-01-19", + "close": 3798.91 + }, + { + "date": "2021-01-20", + "close": 3851.85 + }, + { + "date": "2021-01-21", + "close": 3853.07 + }, + { + "date": "2021-01-22", + "close": 3841.47 + }, + { + "date": "2021-01-25", + "close": 3855.36 + }, + { + "date": "2021-01-26", + "close": 3849.62 + }, + { + "date": "2021-01-27", + "close": 3750.77 + }, + { + "date": "2021-01-28", + "close": 3787.38 + }, + { + "date": "2021-01-29", + "close": 3714.24 + }, + { + "date": "2021-02-01", + "close": 3773.86 + }, + { + "date": "2021-02-02", + "close": 3826.31 + }, + { + "date": "2021-02-03", + "close": 3830.17 + }, + { + "date": "2021-02-04", + "close": 3871.74 + }, + { + "date": "2021-02-05", + "close": 3886.83 + }, + { + "date": "2021-02-08", + "close": 3915.59 + }, + { + "date": "2021-02-09", + "close": 3911.23 + }, + { + "date": "2021-02-10", + "close": 3909.88 + }, + { + "date": "2021-02-11", + "close": 3916.38 + }, + { + "date": "2021-02-12", + "close": 3934.83 + }, + { + "date": "2021-02-16", + "close": 3932.59 + }, + { + "date": "2021-02-17", + "close": 3931.33 + }, + { + "date": "2021-02-18", + "close": 3913.97 + }, + { + "date": "2021-02-19", + "close": 3906.71 + }, + { + "date": "2021-02-22", + "close": 3876.5 + }, + { + "date": "2021-02-23", + "close": 3881.37 + }, + { + "date": "2021-02-24", + "close": 3925.43 + }, + { + "date": "2021-02-25", + "close": 3829.34 + }, + { + "date": "2021-02-26", + "close": 3811.15 + }, + { + "date": "2021-03-01", + "close": 3901.82 + }, + { + "date": "2021-03-02", + "close": 3870.29 + }, + { + "date": "2021-03-03", + "close": 3819.72 + }, + { + "date": "2021-03-04", + "close": 3768.47 + }, + { + "date": "2021-03-05", + "close": 3841.94 + }, + { + "date": "2021-03-08", + "close": 3821.35 + }, + { + "date": "2021-03-09", + "close": 3875.44 + }, + { + "date": "2021-03-10", + "close": 3898.81 + }, + { + "date": "2021-03-11", + "close": 3939.34 + }, + { + "date": "2021-03-12", + "close": 3943.34 + }, + { + "date": "2021-03-15", + "close": 3968.94 + }, + { + "date": "2021-03-16", + "close": 3962.71 + }, + { + "date": "2021-03-17", + "close": 3974.12 + }, + { + "date": "2021-03-18", + "close": 3915.46 + }, + { + "date": "2021-03-19", + "close": 3913.1 + }, + { + "date": "2021-03-22", + "close": 3940.59 + }, + { + "date": "2021-03-23", + "close": 3910.52 + }, + { + "date": "2021-03-24", + "close": 3889.14 + }, + { + "date": "2021-03-25", + "close": 3909.52 + }, + { + "date": "2021-03-26", + "close": 3974.54 + }, + { + "date": "2021-03-29", + "close": 3971.09 + }, + { + "date": "2021-03-30", + "close": 3958.55 + }, + { + "date": "2021-03-31", + "close": 3972.89 + }, + { + "date": "2021-04-01", + "close": 4019.87 + }, + { + "date": "2021-04-05", + "close": 4077.91 + }, + { + "date": "2021-04-06", + "close": 4073.94 + }, + { + "date": "2021-04-07", + "close": 4079.95 + }, + { + "date": "2021-04-08", + "close": 4097.17 + }, + { + "date": "2021-04-09", + "close": 4128.8 + }, + { + "date": "2021-04-12", + "close": 4127.99 + }, + { + "date": "2021-04-13", + "close": 4141.59 + }, + { + "date": "2021-04-14", + "close": 4124.66 + }, + { + "date": "2021-04-15", + "close": 4170.42 + }, + { + "date": "2021-04-16", + "close": 4185.47 + }, + { + "date": "2021-04-19", + "close": 4163.26 + }, + { + "date": "2021-04-20", + "close": 4134.94 + }, + { + "date": "2021-04-21", + "close": 4173.42 + }, + { + "date": "2021-04-22", + "close": 4134.98 + }, + { + "date": "2021-04-23", + "close": 4180.17 + }, + { + "date": "2021-04-26", + "close": 4187.62 + }, + { + "date": "2021-04-27", + "close": 4186.72 + }, + { + "date": "2021-04-28", + "close": 4183.18 + }, + { + "date": "2021-04-29", + "close": 4211.47 + }, + { + "date": "2021-04-30", + "close": 4181.17 + }, + { + "date": "2021-05-03", + "close": 4192.66 + }, + { + "date": "2021-05-04", + "close": 4164.66 + }, + { + "date": "2021-05-05", + "close": 4167.59 + }, + { + "date": "2021-05-06", + "close": 4201.62 + }, + { + "date": "2021-05-07", + "close": 4232.6 + }, + { + "date": "2021-05-10", + "close": 4188.43 + }, + { + "date": "2021-05-11", + "close": 4152.1 + }, + { + "date": "2021-05-12", + "close": 4063.04 + }, + { + "date": "2021-05-13", + "close": 4112.5 + }, + { + "date": "2021-05-14", + "close": 4173.85 + }, + { + "date": "2021-05-17", + "close": 4163.29 + }, + { + "date": "2021-05-18", + "close": 4127.83 + }, + { + "date": "2021-05-19", + "close": 4115.68 + }, + { + "date": "2021-05-20", + "close": 4159.12 + }, + { + "date": "2021-05-21", + "close": 4155.86 + }, + { + "date": "2021-05-24", + "close": 4197.05 + }, + { + "date": "2021-05-25", + "close": 4188.13 + }, + { + "date": "2021-05-26", + "close": 4195.99 + }, + { + "date": "2021-05-27", + "close": 4200.88 + }, + { + "date": "2021-05-28", + "close": 4204.11 + }, + { + "date": "2021-06-01", + "close": 4202.04 + }, + { + "date": "2021-06-02", + "close": 4208.12 + }, + { + "date": "2021-06-03", + "close": 4192.85 + }, + { + "date": "2021-06-04", + "close": 4229.89 + }, + { + "date": "2021-06-07", + "close": 4226.52 + }, + { + "date": "2021-06-08", + "close": 4227.26 + }, + { + "date": "2021-06-09", + "close": 4219.55 + }, + { + "date": "2021-06-10", + "close": 4239.18 + }, + { + "date": "2021-06-11", + "close": 4247.44 + }, + { + "date": "2021-06-14", + "close": 4255.15 + }, + { + "date": "2021-06-15", + "close": 4246.59 + }, + { + "date": "2021-06-16", + "close": 4223.7 + }, + { + "date": "2021-06-17", + "close": 4221.86 + }, + { + "date": "2021-06-18", + "close": 4166.45 + }, + { + "date": "2021-06-21", + "close": 4224.79 + }, + { + "date": "2021-06-22", + "close": 4246.44 + }, + { + "date": "2021-06-23", + "close": 4241.84 + }, + { + "date": "2021-06-24", + "close": 4266.49 + }, + { + "date": "2021-06-25", + "close": 4280.7 + }, + { + "date": "2021-06-28", + "close": 4290.61 + }, + { + "date": "2021-06-29", + "close": 4291.8 + }, + { + "date": "2021-06-30", + "close": 4297.5 + }, + { + "date": "2021-07-01", + "close": 4319.94 + }, + { + "date": "2021-07-02", + "close": 4352.34 + }, + { + "date": "2021-07-06", + "close": 4343.54 + }, + { + "date": "2021-07-07", + "close": 4358.13 + }, + { + "date": "2021-07-08", + "close": 4320.82 + }, + { + "date": "2021-07-09", + "close": 4369.55 + }, + { + "date": "2021-07-12", + "close": 4384.63 + }, + { + "date": "2021-07-13", + "close": 4369.21 + }, + { + "date": "2021-07-14", + "close": 4374.3 + }, + { + "date": "2021-07-15", + "close": 4360.03 + }, + { + "date": "2021-07-16", + "close": 4327.16 + }, + { + "date": "2021-07-19", + "close": 4258.49 + }, + { + "date": "2021-07-20", + "close": 4323.06 + }, + { + "date": "2021-07-21", + "close": 4358.69 + }, + { + "date": "2021-07-22", + "close": 4367.48 + }, + { + "date": "2021-07-23", + "close": 4411.79 + }, + { + "date": "2021-07-26", + "close": 4422.3 + }, + { + "date": "2021-07-27", + "close": 4401.46 + }, + { + "date": "2021-07-28", + "close": 4400.64 + }, + { + "date": "2021-07-29", + "close": 4419.15 + }, + { + "date": "2021-07-30", + "close": 4395.26 + }, + { + "date": "2021-08-02", + "close": 4387.16 + }, + { + "date": "2021-08-03", + "close": 4423.15 + }, + { + "date": "2021-08-04", + "close": 4402.66 + }, + { + "date": "2021-08-05", + "close": 4429.1 + }, + { + "date": "2021-08-06", + "close": 4436.52 + }, + { + "date": "2021-08-09", + "close": 4432.35 + }, + { + "date": "2021-08-10", + "close": 4436.75 + }, + { + "date": "2021-08-11", + "close": 4442.41 + }, + { + "date": "2021-08-12", + "close": 4460.83 + }, + { + "date": "2021-08-13", + "close": 4468 + }, + { + "date": "2021-08-16", + "close": 4479.71 + }, + { + "date": "2021-08-17", + "close": 4448.08 + }, + { + "date": "2021-08-18", + "close": 4400.27 + }, + { + "date": "2021-08-19", + "close": 4405.8 + }, + { + "date": "2021-08-20", + "close": 4441.67 + }, + { + "date": "2021-08-23", + "close": 4479.53 + }, + { + "date": "2021-08-24", + "close": 4486.23 + }, + { + "date": "2021-08-25", + "close": 4496.19 + }, + { + "date": "2021-08-26", + "close": 4470 + }, + { + "date": "2021-08-27", + "close": 4509.37 + }, + { + "date": "2021-08-30", + "close": 4528.79 + }, + { + "date": "2021-08-31", + "close": 4522.68 + }, + { + "date": "2021-09-01", + "close": 4524.09 + }, + { + "date": "2021-09-02", + "close": 4536.95 + }, + { + "date": "2021-09-03", + "close": 4535.43 + }, + { + "date": "2021-09-07", + "close": 4520.03 + }, + { + "date": "2021-09-08", + "close": 4514.07 + }, + { + "date": "2021-09-09", + "close": 4493.28 + }, + { + "date": "2021-09-10", + "close": 4458.58 + }, + { + "date": "2021-09-13", + "close": 4468.73 + }, + { + "date": "2021-09-14", + "close": 4443.05 + }, + { + "date": "2021-09-15", + "close": 4480.7 + }, + { + "date": "2021-09-16", + "close": 4473.75 + }, + { + "date": "2021-09-17", + "close": 4432.99 + }, + { + "date": "2021-09-20", + "close": 4357.73 + }, + { + "date": "2021-09-21", + "close": 4354.19 + }, + { + "date": "2021-09-22", + "close": 4395.64 + }, + { + "date": "2021-09-23", + "close": 4448.98 + }, + { + "date": "2021-09-24", + "close": 4455.48 + }, + { + "date": "2021-09-27", + "close": 4443.11 + }, + { + "date": "2021-09-28", + "close": 4352.63 + }, + { + "date": "2021-09-29", + "close": 4359.46 + }, + { + "date": "2021-09-30", + "close": 4307.54 + }, + { + "date": "2021-10-01", + "close": 4357.04 + }, + { + "date": "2021-10-04", + "close": 4300.46 + }, + { + "date": "2021-10-05", + "close": 4345.72 + }, + { + "date": "2021-10-06", + "close": 4363.55 + }, + { + "date": "2021-10-07", + "close": 4399.76 + }, + { + "date": "2021-10-08", + "close": 4391.34 + }, + { + "date": "2021-10-11", + "close": 4361.19 + }, + { + "date": "2021-10-12", + "close": 4350.65 + }, + { + "date": "2021-10-13", + "close": 4363.8 + }, + { + "date": "2021-10-14", + "close": 4438.26 + }, + { + "date": "2021-10-15", + "close": 4471.37 + }, + { + "date": "2021-10-18", + "close": 4486.46 + }, + { + "date": "2021-10-19", + "close": 4519.63 + }, + { + "date": "2021-10-20", + "close": 4536.19 + }, + { + "date": "2021-10-21", + "close": 4549.78 + }, + { + "date": "2021-10-22", + "close": 4544.9 + }, + { + "date": "2021-10-25", + "close": 4566.48 + }, + { + "date": "2021-10-26", + "close": 4574.79 + }, + { + "date": "2021-10-27", + "close": 4551.68 + }, + { + "date": "2021-10-28", + "close": 4596.42 + }, + { + "date": "2021-10-29", + "close": 4605.38 + }, + { + "date": "2021-11-01", + "close": 4613.67 + }, + { + "date": "2021-11-02", + "close": 4630.65 + }, + { + "date": "2021-11-03", + "close": 4660.57 + }, + { + "date": "2021-11-04", + "close": 4680.06 + }, + { + "date": "2021-11-05", + "close": 4697.53 + }, + { + "date": "2021-11-08", + "close": 4701.7 + }, + { + "date": "2021-11-09", + "close": 4685.25 + }, + { + "date": "2021-11-10", + "close": 4646.71 + }, + { + "date": "2021-11-11", + "close": 4649.27 + }, + { + "date": "2021-11-12", + "close": 4682.85 + }, + { + "date": "2021-11-15", + "close": 4682.8 + }, + { + "date": "2021-11-16", + "close": 4700.9 + }, + { + "date": "2021-11-17", + "close": 4688.67 + }, + { + "date": "2021-11-18", + "close": 4704.54 + }, + { + "date": "2021-11-19", + "close": 4697.96 + }, + { + "date": "2021-11-22", + "close": 4682.94 + }, + { + "date": "2021-11-23", + "close": 4690.7 + }, + { + "date": "2021-11-24", + "close": 4701.46 + }, + { + "date": "2021-11-26", + "close": 4594.62 + }, + { + "date": "2021-11-29", + "close": 4655.27 + }, + { + "date": "2021-11-30", + "close": 4567 + }, + { + "date": "2021-12-01", + "close": 4513.04 + }, + { + "date": "2021-12-02", + "close": 4577.1 + }, + { + "date": "2021-12-03", + "close": 4538.43 + }, + { + "date": "2021-12-06", + "close": 4591.67 + }, + { + "date": "2021-12-07", + "close": 4686.75 + }, + { + "date": "2021-12-08", + "close": 4701.21 + }, + { + "date": "2021-12-09", + "close": 4667.45 + }, + { + "date": "2021-12-10", + "close": 4712.02 + }, + { + "date": "2021-12-13", + "close": 4668.97 + }, + { + "date": "2021-12-14", + "close": 4634.09 + }, + { + "date": "2021-12-15", + "close": 4709.85 + }, + { + "date": "2021-12-16", + "close": 4668.67 + }, + { + "date": "2021-12-17", + "close": 4620.64 + }, + { + "date": "2021-12-20", + "close": 4568.02 + }, + { + "date": "2021-12-21", + "close": 4649.23 + }, + { + "date": "2021-12-22", + "close": 4696.56 + }, + { + "date": "2021-12-23", + "close": 4725.79 + }, + { + "date": "2021-12-27", + "close": 4791.19 + }, + { + "date": "2021-12-28", + "close": 4786.35 + }, + { + "date": "2021-12-29", + "close": 4793.06 + }, + { + "date": "2021-12-30", + "close": 4778.73 + }, + { + "date": "2021-12-31", + "close": 4766.18 + }, + { + "date": "2022-01-03", + "close": 4796.56 + }, + { + "date": "2022-01-04", + "close": 4793.54 + }, + { + "date": "2022-01-05", + "close": 4700.58 + }, + { + "date": "2022-01-06", + "close": 4696.05 + }, + { + "date": "2022-01-07", + "close": 4677.03 + }, + { + "date": "2022-01-10", + "close": 4670.29 + }, + { + "date": "2022-01-11", + "close": 4713.07 + }, + { + "date": "2022-01-12", + "close": 4726.35 + }, + { + "date": "2022-01-13", + "close": 4659.03 + }, + { + "date": "2022-01-14", + "close": 4662.85 + }, + { + "date": "2022-01-18", + "close": 4577.11 + }, + { + "date": "2022-01-19", + "close": 4532.76 + }, + { + "date": "2022-01-20", + "close": 4482.73 + }, + { + "date": "2022-01-21", + "close": 4397.94 + }, + { + "date": "2022-01-24", + "close": 4410.13 + }, + { + "date": "2022-01-25", + "close": 4356.45 + }, + { + "date": "2022-01-26", + "close": 4349.93 + }, + { + "date": "2022-01-27", + "close": 4326.51 + }, + { + "date": "2022-01-28", + "close": 4431.85 + }, + { + "date": "2022-01-31", + "close": 4515.55 + }, + { + "date": "2022-02-01", + "close": 4546.54 + }, + { + "date": "2022-02-02", + "close": 4589.38 + }, + { + "date": "2022-02-03", + "close": 4477.44 + }, + { + "date": "2022-02-04", + "close": 4500.53 + }, + { + "date": "2022-02-07", + "close": 4483.87 + }, + { + "date": "2022-02-08", + "close": 4521.54 + }, + { + "date": "2022-02-09", + "close": 4587.18 + }, + { + "date": "2022-02-10", + "close": 4504.08 + }, + { + "date": "2022-02-11", + "close": 4418.64 + }, + { + "date": "2022-02-14", + "close": 4401.67 + }, + { + "date": "2022-02-15", + "close": 4471.07 + }, + { + "date": "2022-02-16", + "close": 4475.01 + }, + { + "date": "2022-02-17", + "close": 4380.26 + }, + { + "date": "2022-02-18", + "close": 4348.87 + }, + { + "date": "2022-02-22", + "close": 4304.76 + }, + { + "date": "2022-02-23", + "close": 4225.5 + }, + { + "date": "2022-02-24", + "close": 4288.7 + }, + { + "date": "2022-02-25", + "close": 4384.65 + }, + { + "date": "2022-02-28", + "close": 4373.94 + }, + { + "date": "2022-03-01", + "close": 4306.26 + }, + { + "date": "2022-03-02", + "close": 4386.54 + }, + { + "date": "2022-03-03", + "close": 4363.49 + }, + { + "date": "2022-03-04", + "close": 4328.87 + }, + { + "date": "2022-03-07", + "close": 4201.09 + }, + { + "date": "2022-03-08", + "close": 4170.7 + }, + { + "date": "2022-03-09", + "close": 4277.88 + }, + { + "date": "2022-03-10", + "close": 4259.52 + }, + { + "date": "2022-03-11", + "close": 4204.31 + }, + { + "date": "2022-03-14", + "close": 4173.11 + }, + { + "date": "2022-03-15", + "close": 4262.45 + }, + { + "date": "2022-03-16", + "close": 4357.86 + }, + { + "date": "2022-03-17", + "close": 4411.67 + }, + { + "date": "2022-03-18", + "close": 4463.12 + }, + { + "date": "2022-03-21", + "close": 4461.18 + }, + { + "date": "2022-03-22", + "close": 4511.61 + }, + { + "date": "2022-03-23", + "close": 4456.24 + }, + { + "date": "2022-03-24", + "close": 4520.16 + }, + { + "date": "2022-03-25", + "close": 4543.06 + }, + { + "date": "2022-03-28", + "close": 4575.52 + }, + { + "date": "2022-03-29", + "close": 4631.6 + }, + { + "date": "2022-03-30", + "close": 4602.45 + }, + { + "date": "2022-03-31", + "close": 4530.41 + }, + { + "date": "2022-04-01", + "close": 4545.86 + }, + { + "date": "2022-04-04", + "close": 4582.64 + }, + { + "date": "2022-04-05", + "close": 4525.12 + }, + { + "date": "2022-04-06", + "close": 4481.15 + }, + { + "date": "2022-04-07", + "close": 4500.21 + }, + { + "date": "2022-04-08", + "close": 4488.28 + }, + { + "date": "2022-04-11", + "close": 4412.53 + }, + { + "date": "2022-04-12", + "close": 4397.45 + }, + { + "date": "2022-04-13", + "close": 4446.59 + }, + { + "date": "2022-04-14", + "close": 4392.59 + }, + { + "date": "2022-04-18", + "close": 4391.69 + }, + { + "date": "2022-04-19", + "close": 4462.21 + }, + { + "date": "2022-04-20", + "close": 4459.45 + }, + { + "date": "2022-04-21", + "close": 4393.66 + }, + { + "date": "2022-04-22", + "close": 4271.78 + }, + { + "date": "2022-04-25", + "close": 4296.12 + }, + { + "date": "2022-04-26", + "close": 4175.2 + }, + { + "date": "2022-04-27", + "close": 4183.96 + }, + { + "date": "2022-04-28", + "close": 4287.5 + }, + { + "date": "2022-04-29", + "close": 4131.93 + }, + { + "date": "2022-05-02", + "close": 4155.38 + }, + { + "date": "2022-05-03", + "close": 4175.48 + }, + { + "date": "2022-05-04", + "close": 4300.17 + }, + { + "date": "2022-05-05", + "close": 4146.87 + }, + { + "date": "2022-05-06", + "close": 4123.34 + }, + { + "date": "2022-05-09", + "close": 3991.24 + }, + { + "date": "2022-05-10", + "close": 4001.05 + }, + { + "date": "2022-05-11", + "close": 3935.18 + }, + { + "date": "2022-05-12", + "close": 3930.08 + }, + { + "date": "2022-05-13", + "close": 4023.89 + }, + { + "date": "2022-05-16", + "close": 4008.01 + }, + { + "date": "2022-05-17", + "close": 4088.85 + }, + { + "date": "2022-05-18", + "close": 3923.68 + }, + { + "date": "2022-05-19", + "close": 3900.79 + }, + { + "date": "2022-05-20", + "close": 3901.36 + }, + { + "date": "2022-05-23", + "close": 3973.75 + }, + { + "date": "2022-05-24", + "close": 3941.48 + }, + { + "date": "2022-05-25", + "close": 3978.73 + }, + { + "date": "2022-05-26", + "close": 4057.84 + }, + { + "date": "2022-05-27", + "close": 4158.24 + }, + { + "date": "2022-05-31", + "close": 4132.15 + }, + { + "date": "2022-06-01", + "close": 4101.23 + }, + { + "date": "2022-06-02", + "close": 4176.82 + }, + { + "date": "2022-06-03", + "close": 4108.54 + }, + { + "date": "2022-06-06", + "close": 4121.43 + }, + { + "date": "2022-06-07", + "close": 4160.68 + }, + { + "date": "2022-06-08", + "close": 4115.77 + }, + { + "date": "2022-06-09", + "close": 4017.82 + }, + { + "date": "2022-06-10", + "close": 3900.86 + }, + { + "date": "2022-06-13", + "close": 3749.63 + }, + { + "date": "2022-06-14", + "close": 3735.48 + }, + { + "date": "2022-06-15", + "close": 3789.99 + }, + { + "date": "2022-06-16", + "close": 3666.77 + }, + { + "date": "2022-06-17", + "close": 3674.84 + }, + { + "date": "2022-06-21", + "close": 3764.79 + }, + { + "date": "2022-06-22", + "close": 3759.89 + }, + { + "date": "2022-06-23", + "close": 3795.73 + }, + { + "date": "2022-06-24", + "close": 3911.74 + }, + { + "date": "2022-06-27", + "close": 3900.11 + }, + { + "date": "2022-06-28", + "close": 3821.55 + }, + { + "date": "2022-06-29", + "close": 3818.83 + }, + { + "date": "2022-06-30", + "close": 3785.38 + }, + { + "date": "2022-07-01", + "close": 3825.33 + }, + { + "date": "2022-07-05", + "close": 3831.39 + }, + { + "date": "2022-07-06", + "close": 3845.08 + }, + { + "date": "2022-07-07", + "close": 3902.62 + }, + { + "date": "2022-07-08", + "close": 3899.38 + }, + { + "date": "2022-07-11", + "close": 3854.43 + }, + { + "date": "2022-07-12", + "close": 3818.8 + }, + { + "date": "2022-07-13", + "close": 3801.78 + }, + { + "date": "2022-07-14", + "close": 3790.38 + }, + { + "date": "2022-07-15", + "close": 3863.16 + }, + { + "date": "2022-07-18", + "close": 3830.85 + }, + { + "date": "2022-07-19", + "close": 3936.69 + }, + { + "date": "2022-07-20", + "close": 3959.9 + }, + { + "date": "2022-07-21", + "close": 3998.95 + }, + { + "date": "2022-07-22", + "close": 3961.63 + }, + { + "date": "2022-07-25", + "close": 3966.84 + }, + { + "date": "2022-07-26", + "close": 3921.05 + }, + { + "date": "2022-07-27", + "close": 4023.61 + }, + { + "date": "2022-07-28", + "close": 4072.43 + }, + { + "date": "2022-07-29", + "close": 4130.29 + }, + { + "date": "2022-08-01", + "close": 4118.63 + }, + { + "date": "2022-08-02", + "close": 4091.19 + }, + { + "date": "2022-08-03", + "close": 4155.17 + }, + { + "date": "2022-08-04", + "close": 4151.94 + }, + { + "date": "2022-08-05", + "close": 4145.19 + }, + { + "date": "2022-08-08", + "close": 4140.06 + }, + { + "date": "2022-08-09", + "close": 4122.47 + }, + { + "date": "2022-08-10", + "close": 4210.24 + }, + { + "date": "2022-08-11", + "close": 4207.27 + }, + { + "date": "2022-08-12", + "close": 4280.15 + }, + { + "date": "2022-08-15", + "close": 4297.14 + }, + { + "date": "2022-08-16", + "close": 4305.2 + }, + { + "date": "2022-08-17", + "close": 4274.04 + }, + { + "date": "2022-08-18", + "close": 4283.74 + }, + { + "date": "2022-08-19", + "close": 4228.48 + }, + { + "date": "2022-08-22", + "close": 4137.99 + }, + { + "date": "2022-08-23", + "close": 4128.73 + }, + { + "date": "2022-08-24", + "close": 4140.77 + }, + { + "date": "2022-08-25", + "close": 4199.12 + }, + { + "date": "2022-08-26", + "close": 4057.66 + }, + { + "date": "2022-08-29", + "close": 4030.61 + }, + { + "date": "2022-08-30", + "close": 3986.16 + }, + { + "date": "2022-08-31", + "close": 3955 + }, + { + "date": "2022-09-01", + "close": 3966.85 + }, + { + "date": "2022-09-02", + "close": 3924.26 + }, + { + "date": "2022-09-06", + "close": 3908.19 + }, + { + "date": "2022-09-07", + "close": 3979.87 + }, + { + "date": "2022-09-08", + "close": 4006.18 + }, + { + "date": "2022-09-09", + "close": 4067.36 + }, + { + "date": "2022-09-12", + "close": 4110.41 + }, + { + "date": "2022-09-13", + "close": 3932.69 + }, + { + "date": "2022-09-14", + "close": 3946.01 + }, + { + "date": "2022-09-15", + "close": 3901.35 + }, + { + "date": "2022-09-16", + "close": 3873.33 + }, + { + "date": "2022-09-19", + "close": 3899.89 + }, + { + "date": "2022-09-20", + "close": 3855.93 + }, + { + "date": "2022-09-21", + "close": 3789.93 + }, + { + "date": "2022-09-22", + "close": 3757.99 + }, + { + "date": "2022-09-23", + "close": 3693.23 + }, + { + "date": "2022-09-26", + "close": 3655.04 + }, + { + "date": "2022-09-27", + "close": 3647.29 + }, + { + "date": "2022-09-28", + "close": 3719.04 + }, + { + "date": "2022-09-29", + "close": 3640.47 + }, + { + "date": "2022-09-30", + "close": 3585.62 + }, + { + "date": "2022-10-03", + "close": 3678.43 + }, + { + "date": "2022-10-04", + "close": 3790.93 + }, + { + "date": "2022-10-05", + "close": 3783.28 + }, + { + "date": "2022-10-06", + "close": 3744.52 + }, + { + "date": "2022-10-07", + "close": 3639.66 + }, + { + "date": "2022-10-10", + "close": 3612.39 + }, + { + "date": "2022-10-11", + "close": 3588.84 + }, + { + "date": "2022-10-12", + "close": 3577.03 + }, + { + "date": "2022-10-13", + "close": 3669.91 + }, + { + "date": "2022-10-14", + "close": 3583.07 + }, + { + "date": "2022-10-17", + "close": 3677.95 + }, + { + "date": "2022-10-18", + "close": 3719.98 + }, + { + "date": "2022-10-19", + "close": 3695.16 + }, + { + "date": "2022-10-20", + "close": 3665.78 + }, + { + "date": "2022-10-21", + "close": 3752.75 + }, + { + "date": "2022-10-24", + "close": 3797.34 + }, + { + "date": "2022-10-25", + "close": 3859.11 + }, + { + "date": "2022-10-26", + "close": 3830.6 + }, + { + "date": "2022-10-27", + "close": 3807.3 + }, + { + "date": "2022-10-28", + "close": 3901.06 + }, + { + "date": "2022-10-31", + "close": 3871.98 + }, + { + "date": "2022-11-01", + "close": 3856.1 + }, + { + "date": "2022-11-02", + "close": 3759.69 + }, + { + "date": "2022-11-03", + "close": 3719.89 + }, + { + "date": "2022-11-04", + "close": 3770.55 + }, + { + "date": "2022-11-07", + "close": 3806.8 + }, + { + "date": "2022-11-08", + "close": 3828.11 + }, + { + "date": "2022-11-09", + "close": 3748.57 + }, + { + "date": "2022-11-10", + "close": 3956.37 + }, + { + "date": "2022-11-11", + "close": 3992.93 + }, + { + "date": "2022-11-14", + "close": 3957.25 + }, + { + "date": "2022-11-15", + "close": 3991.73 + }, + { + "date": "2022-11-16", + "close": 3958.79 + }, + { + "date": "2022-11-17", + "close": 3946.56 + }, + { + "date": "2022-11-18", + "close": 3965.34 + }, + { + "date": "2022-11-21", + "close": 3949.94 + }, + { + "date": "2022-11-22", + "close": 4003.58 + }, + { + "date": "2022-11-23", + "close": 4027.26 + }, + { + "date": "2022-11-25", + "close": 4026.12 + }, + { + "date": "2022-11-28", + "close": 3963.94 + }, + { + "date": "2022-11-29", + "close": 3957.63 + }, + { + "date": "2022-11-30", + "close": 4080.11 + }, + { + "date": "2022-12-01", + "close": 4076.57 + }, + { + "date": "2022-12-02", + "close": 4071.7 + }, + { + "date": "2022-12-05", + "close": 3998.84 + }, + { + "date": "2022-12-06", + "close": 3941.26 + }, + { + "date": "2022-12-07", + "close": 3933.92 + }, + { + "date": "2022-12-08", + "close": 3963.51 + }, + { + "date": "2022-12-09", + "close": 3934.38 + }, + { + "date": "2022-12-12", + "close": 3990.56 + }, + { + "date": "2022-12-13", + "close": 4019.65 + }, + { + "date": "2022-12-14", + "close": 3995.32 + }, + { + "date": "2022-12-15", + "close": 3895.75 + }, + { + "date": "2022-12-16", + "close": 3852.36 + }, + { + "date": "2022-12-19", + "close": 3817.66 + }, + { + "date": "2022-12-20", + "close": 3821.62 + }, + { + "date": "2022-12-21", + "close": 3878.44 + }, + { + "date": "2022-12-22", + "close": 3822.39 + }, + { + "date": "2022-12-23", + "close": 3844.82 + }, + { + "date": "2022-12-27", + "close": 3829.25 + }, + { + "date": "2022-12-28", + "close": 3783.22 + }, + { + "date": "2022-12-29", + "close": 3849.28 + }, + { + "date": "2022-12-30", + "close": 3839.5 + }, + { + "date": "2023-01-03", + "close": 3824.14 + }, + { + "date": "2023-01-04", + "close": 3852.97 + }, + { + "date": "2023-01-05", + "close": 3808.1 + }, + { + "date": "2023-01-06", + "close": 3895.08 + }, + { + "date": "2023-01-09", + "close": 3892.09 + }, + { + "date": "2023-01-10", + "close": 3919.25 + }, + { + "date": "2023-01-11", + "close": 3969.61 + }, + { + "date": "2023-01-12", + "close": 3983.17 + }, + { + "date": "2023-01-13", + "close": 3999.09 + }, + { + "date": "2023-01-17", + "close": 3990.97 + }, + { + "date": "2023-01-18", + "close": 3928.86 + }, + { + "date": "2023-01-19", + "close": 3898.85 + }, + { + "date": "2023-01-20", + "close": 3972.61 + }, + { + "date": "2023-01-23", + "close": 4019.81 + }, + { + "date": "2023-01-24", + "close": 4016.95 + }, + { + "date": "2023-01-25", + "close": 4016.22 + }, + { + "date": "2023-01-26", + "close": 4060.43 + }, + { + "date": "2023-01-27", + "close": 4070.56 + }, + { + "date": "2023-01-30", + "close": 4017.77 + }, + { + "date": "2023-01-31", + "close": 4076.6 + }, + { + "date": "2023-02-01", + "close": 4119.21 + }, + { + "date": "2023-02-02", + "close": 4179.76 + }, + { + "date": "2023-02-03", + "close": 4136.48 + }, + { + "date": "2023-02-06", + "close": 4111.08 + }, + { + "date": "2023-02-07", + "close": 4164 + }, + { + "date": "2023-02-08", + "close": 4117.86 + }, + { + "date": "2023-02-09", + "close": 4081.5 + }, + { + "date": "2023-02-10", + "close": 4090.46 + }, + { + "date": "2023-02-13", + "close": 4137.29 + }, + { + "date": "2023-02-14", + "close": 4136.13 + }, + { + "date": "2023-02-15", + "close": 4147.6 + }, + { + "date": "2023-02-16", + "close": 4090.41 + }, + { + "date": "2023-02-17", + "close": 4079.09 + }, + { + "date": "2023-02-21", + "close": 3997.34 + }, + { + "date": "2023-02-22", + "close": 3991.05 + }, + { + "date": "2023-02-23", + "close": 4012.32 + }, + { + "date": "2023-02-24", + "close": 3970.04 + }, + { + "date": "2023-02-27", + "close": 3982.24 + }, + { + "date": "2023-02-28", + "close": 3970.15 + }, + { + "date": "2023-03-01", + "close": 3951.39 + }, + { + "date": "2023-03-02", + "close": 3981.35 + }, + { + "date": "2023-03-03", + "close": 4045.64 + }, + { + "date": "2023-03-06", + "close": 4048.42 + }, + { + "date": "2023-03-07", + "close": 3986.37 + }, + { + "date": "2023-03-08", + "close": 3992.01 + }, + { + "date": "2023-03-09", + "close": 3918.32 + }, + { + "date": "2023-03-10", + "close": 3861.59 + }, + { + "date": "2023-03-13", + "close": 3855.76 + }, + { + "date": "2023-03-14", + "close": 3919.29 + }, + { + "date": "2023-03-15", + "close": 3891.93 + }, + { + "date": "2023-03-16", + "close": 3960.28 + }, + { + "date": "2023-03-17", + "close": 3916.64 + }, + { + "date": "2023-03-20", + "close": 3951.57 + }, + { + "date": "2023-03-21", + "close": 4002.87 + }, + { + "date": "2023-03-22", + "close": 3936.97 + }, + { + "date": "2023-03-23", + "close": 3948.72 + }, + { + "date": "2023-03-24", + "close": 3970.99 + }, + { + "date": "2023-03-27", + "close": 3977.53 + }, + { + "date": "2023-03-28", + "close": 3971.27 + }, + { + "date": "2023-03-29", + "close": 4027.81 + }, + { + "date": "2023-03-30", + "close": 4050.83 + }, + { + "date": "2023-03-31", + "close": 4109.31 + }, + { + "date": "2023-04-03", + "close": 4124.51 + }, + { + "date": "2023-04-04", + "close": 4100.6 + }, + { + "date": "2023-04-05", + "close": 4090.38 + }, + { + "date": "2023-04-06", + "close": 4105.02 + }, + { + "date": "2023-04-10", + "close": 4109.11 + }, + { + "date": "2023-04-11", + "close": 4108.94 + }, + { + "date": "2023-04-12", + "close": 4091.95 + }, + { + "date": "2023-04-13", + "close": 4146.22 + }, + { + "date": "2023-04-14", + "close": 4137.64 + }, + { + "date": "2023-04-17", + "close": 4151.32 + }, + { + "date": "2023-04-18", + "close": 4154.87 + }, + { + "date": "2023-04-19", + "close": 4154.52 + }, + { + "date": "2023-04-20", + "close": 4129.79 + }, + { + "date": "2023-04-21", + "close": 4133.52 + }, + { + "date": "2023-04-24", + "close": 4137.04 + }, + { + "date": "2023-04-25", + "close": 4071.63 + }, + { + "date": "2023-04-26", + "close": 4055.99 + }, + { + "date": "2023-04-27", + "close": 4135.35 + }, + { + "date": "2023-04-28", + "close": 4169.48 + }, + { + "date": "2023-05-01", + "close": 4167.87 + }, + { + "date": "2023-05-02", + "close": 4119.58 + }, + { + "date": "2023-05-03", + "close": 4090.75 + }, + { + "date": "2023-05-04", + "close": 4061.22 + }, + { + "date": "2023-05-05", + "close": 4136.25 + }, + { + "date": "2023-05-08", + "close": 4138.12 + }, + { + "date": "2023-05-09", + "close": 4119.17 + }, + { + "date": "2023-05-10", + "close": 4137.64 + }, + { + "date": "2023-05-11", + "close": 4130.62 + }, + { + "date": "2023-05-12", + "close": 4124.08 + }, + { + "date": "2023-05-15", + "close": 4136.28 + }, + { + "date": "2023-05-16", + "close": 4109.9 + }, + { + "date": "2023-05-17", + "close": 4158.77 + }, + { + "date": "2023-05-18", + "close": 4198.05 + }, + { + "date": "2023-05-19", + "close": 4191.98 + }, + { + "date": "2023-05-22", + "close": 4192.63 + }, + { + "date": "2023-05-23", + "close": 4145.58 + }, + { + "date": "2023-05-24", + "close": 4115.24 + }, + { + "date": "2023-05-25", + "close": 4151.28 + }, + { + "date": "2023-05-26", + "close": 4205.45 + }, + { + "date": "2023-05-30", + "close": 4205.52 + }, + { + "date": "2023-05-31", + "close": 4179.83 + }, + { + "date": "2023-06-01", + "close": 4221.02 + }, + { + "date": "2023-06-02", + "close": 4282.37 + }, + { + "date": "2023-06-05", + "close": 4273.79 + }, + { + "date": "2023-06-06", + "close": 4283.85 + }, + { + "date": "2023-06-07", + "close": 4267.52 + }, + { + "date": "2023-06-08", + "close": 4293.93 + }, + { + "date": "2023-06-09", + "close": 4298.86 + }, + { + "date": "2023-06-12", + "close": 4338.93 + }, + { + "date": "2023-06-13", + "close": 4369.01 + }, + { + "date": "2023-06-14", + "close": 4372.59 + }, + { + "date": "2023-06-15", + "close": 4425.84 + }, + { + "date": "2023-06-16", + "close": 4409.59 + }, + { + "date": "2023-06-20", + "close": 4388.71 + }, + { + "date": "2023-06-21", + "close": 4365.69 + }, + { + "date": "2023-06-22", + "close": 4381.89 + }, + { + "date": "2023-06-23", + "close": 4348.33 + }, + { + "date": "2023-06-26", + "close": 4328.82 + }, + { + "date": "2023-06-27", + "close": 4378.41 + }, + { + "date": "2023-06-28", + "close": 4376.86 + }, + { + "date": "2023-06-29", + "close": 4396.44 + }, + { + "date": "2023-06-30", + "close": 4450.38 + }, + { + "date": "2023-07-03", + "close": 4455.59 + }, + { + "date": "2023-07-05", + "close": 4446.82 + }, + { + "date": "2023-07-06", + "close": 4411.59 + }, + { + "date": "2023-07-07", + "close": 4398.95 + }, + { + "date": "2023-07-10", + "close": 4409.53 + }, + { + "date": "2023-07-11", + "close": 4439.26 + }, + { + "date": "2023-07-12", + "close": 4472.16 + }, + { + "date": "2023-07-13", + "close": 4510.04 + }, + { + "date": "2023-07-14", + "close": 4505.42 + }, + { + "date": "2023-07-17", + "close": 4522.79 + }, + { + "date": "2023-07-18", + "close": 4554.98 + }, + { + "date": "2023-07-19", + "close": 4565.72 + }, + { + "date": "2023-07-20", + "close": 4534.87 + }, + { + "date": "2023-07-21", + "close": 4536.34 + }, + { + "date": "2023-07-24", + "close": 4554.64 + }, + { + "date": "2023-07-25", + "close": 4567.46 + }, + { + "date": "2023-07-26", + "close": 4566.75 + }, + { + "date": "2023-07-27", + "close": 4537.41 + }, + { + "date": "2023-07-28", + "close": 4582.23 + }, + { + "date": "2023-07-31", + "close": 4588.96 + }, + { + "date": "2023-08-01", + "close": 4576.73 + }, + { + "date": "2023-08-02", + "close": 4513.39 + }, + { + "date": "2023-08-03", + "close": 4501.89 + }, + { + "date": "2023-08-04", + "close": 4478.03 + }, + { + "date": "2023-08-07", + "close": 4518.44 + }, + { + "date": "2023-08-08", + "close": 4499.38 + }, + { + "date": "2023-08-09", + "close": 4467.71 + }, + { + "date": "2023-08-10", + "close": 4468.83 + }, + { + "date": "2023-08-11", + "close": 4464.05 + }, + { + "date": "2023-08-14", + "close": 4489.72 + }, + { + "date": "2023-08-15", + "close": 4437.86 + }, + { + "date": "2023-08-16", + "close": 4404.33 + }, + { + "date": "2023-08-17", + "close": 4370.36 + }, + { + "date": "2023-08-18", + "close": 4369.71 + }, + { + "date": "2023-08-21", + "close": 4399.77 + }, + { + "date": "2023-08-22", + "close": 4387.55 + }, + { + "date": "2023-08-23", + "close": 4436.01 + }, + { + "date": "2023-08-24", + "close": 4376.31 + }, + { + "date": "2023-08-25", + "close": 4405.71 + }, + { + "date": "2023-08-28", + "close": 4433.31 + }, + { + "date": "2023-08-29", + "close": 4497.63 + }, + { + "date": "2023-08-30", + "close": 4514.87 + }, + { + "date": "2023-08-31", + "close": 4507.66 + }, + { + "date": "2023-09-01", + "close": 4515.77 + }, + { + "date": "2023-09-05", + "close": 4496.83 + }, + { + "date": "2023-09-06", + "close": 4465.48 + }, + { + "date": "2023-09-07", + "close": 4451.14 + }, + { + "date": "2023-09-08", + "close": 4457.49 + }, + { + "date": "2023-09-11", + "close": 4487.46 + }, + { + "date": "2023-09-12", + "close": 4461.9 + }, + { + "date": "2023-09-13", + "close": 4467.44 + }, + { + "date": "2023-09-14", + "close": 4505.1 + }, + { + "date": "2023-09-15", + "close": 4450.32 + }, + { + "date": "2023-09-18", + "close": 4453.53 + }, + { + "date": "2023-09-19", + "close": 4443.95 + }, + { + "date": "2023-09-20", + "close": 4402.2 + }, + { + "date": "2023-09-21", + "close": 4330 + }, + { + "date": "2023-09-22", + "close": 4320.06 + }, + { + "date": "2023-09-25", + "close": 4337.44 + }, + { + "date": "2023-09-26", + "close": 4273.53 + }, + { + "date": "2023-09-27", + "close": 4274.51 + }, + { + "date": "2023-09-28", + "close": 4299.7 + }, + { + "date": "2023-09-29", + "close": 4288.05 + }, + { + "date": "2023-10-02", + "close": 4288.39 + }, + { + "date": "2023-10-03", + "close": 4229.45 + }, + { + "date": "2023-10-04", + "close": 4263.75 + }, + { + "date": "2023-10-05", + "close": 4258.19 + }, + { + "date": "2023-10-06", + "close": 4308.5 + }, + { + "date": "2023-10-09", + "close": 4335.66 + }, + { + "date": "2023-10-10", + "close": 4358.24 + }, + { + "date": "2023-10-11", + "close": 4376.95 + }, + { + "date": "2023-10-12", + "close": 4349.61 + }, + { + "date": "2023-10-13", + "close": 4327.78 + }, + { + "date": "2023-10-16", + "close": 4373.63 + }, + { + "date": "2023-10-17", + "close": 4373.2 + }, + { + "date": "2023-10-18", + "close": 4314.6 + }, + { + "date": "2023-10-19", + "close": 4278 + }, + { + "date": "2023-10-20", + "close": 4224.16 + }, + { + "date": "2023-10-23", + "close": 4217.04 + }, + { + "date": "2023-10-24", + "close": 4247.68 + }, + { + "date": "2023-10-25", + "close": 4186.77 + }, + { + "date": "2023-10-26", + "close": 4137.23 + }, + { + "date": "2023-10-27", + "close": 4117.37 + }, + { + "date": "2023-10-30", + "close": 4166.82 + }, + { + "date": "2023-10-31", + "close": 4193.8 + }, + { + "date": "2023-11-01", + "close": 4237.86 + }, + { + "date": "2023-11-02", + "close": 4317.78 + }, + { + "date": "2023-11-03", + "close": 4358.34 + }, + { + "date": "2023-11-06", + "close": 4365.98 + }, + { + "date": "2023-11-07", + "close": 4378.38 + }, + { + "date": "2023-11-08", + "close": 4382.78 + }, + { + "date": "2023-11-09", + "close": 4347.35 + }, + { + "date": "2023-11-10", + "close": 4415.24 + }, + { + "date": "2023-11-13", + "close": 4411.55 + }, + { + "date": "2023-11-14", + "close": 4495.7 + }, + { + "date": "2023-11-15", + "close": 4502.88 + }, + { + "date": "2023-11-16", + "close": 4508.24 + }, + { + "date": "2023-11-17", + "close": 4514.02 + }, + { + "date": "2023-11-20", + "close": 4547.38 + }, + { + "date": "2023-11-21", + "close": 4538.19 + }, + { + "date": "2023-11-22", + "close": 4556.62 + }, + { + "date": "2023-11-24", + "close": 4559.34 + }, + { + "date": "2023-11-27", + "close": 4550.43 + }, + { + "date": "2023-11-28", + "close": 4554.89 + }, + { + "date": "2023-11-29", + "close": 4550.58 + }, + { + "date": "2023-11-30", + "close": 4567.8 + }, + { + "date": "2023-12-01", + "close": 4594.63 + }, + { + "date": "2023-12-04", + "close": 4569.78 + }, + { + "date": "2023-12-05", + "close": 4567.18 + }, + { + "date": "2023-12-06", + "close": 4549.34 + }, + { + "date": "2023-12-07", + "close": 4585.59 + }, + { + "date": "2023-12-08", + "close": 4604.37 + }, + { + "date": "2023-12-11", + "close": 4622.44 + }, + { + "date": "2023-12-12", + "close": 4643.7 + }, + { + "date": "2023-12-13", + "close": 4707.09 + }, + { + "date": "2023-12-14", + "close": 4719.55 + }, + { + "date": "2023-12-15", + "close": 4719.19 + }, + { + "date": "2023-12-18", + "close": 4740.56 + }, + { + "date": "2023-12-19", + "close": 4768.37 + }, + { + "date": "2023-12-20", + "close": 4698.35 + }, + { + "date": "2023-12-21", + "close": 4746.75 + }, + { + "date": "2023-12-22", + "close": 4754.63 + }, + { + "date": "2023-12-26", + "close": 4774.75 + }, + { + "date": "2023-12-27", + "close": 4781.58 + }, + { + "date": "2023-12-28", + "close": 4783.35 + }, + { + "date": "2023-12-29", + "close": 4769.83 + }, + { + "date": "2024-01-02", + "close": 4742.83 + }, + { + "date": "2024-01-03", + "close": 4704.81 + }, + { + "date": "2024-01-04", + "close": 4688.68 + }, + { + "date": "2024-01-05", + "close": 4697.24 + }, + { + "date": "2024-01-08", + "close": 4763.54 + }, + { + "date": "2024-01-09", + "close": 4756.5 + }, + { + "date": "2024-01-10", + "close": 4783.45 + }, + { + "date": "2024-01-11", + "close": 4780.24 + }, + { + "date": "2024-01-12", + "close": 4783.83 + }, + { + "date": "2024-01-16", + "close": 4765.98 + }, + { + "date": "2024-01-17", + "close": 4739.21 + }, + { + "date": "2024-01-18", + "close": 4780.94 + }, + { + "date": "2024-01-19", + "close": 4839.81 + }, + { + "date": "2024-01-22", + "close": 4850.43 + }, + { + "date": "2024-01-23", + "close": 4864.6 + }, + { + "date": "2024-01-24", + "close": 4868.55 + }, + { + "date": "2024-01-25", + "close": 4894.16 + }, + { + "date": "2024-01-26", + "close": 4890.97 + }, + { + "date": "2024-01-29", + "close": 4927.93 + }, + { + "date": "2024-01-30", + "close": 4924.97 + }, + { + "date": "2024-01-31", + "close": 4845.65 + }, + { + "date": "2024-02-01", + "close": 4906.19 + }, + { + "date": "2024-02-02", + "close": 4958.61 + }, + { + "date": "2024-02-05", + "close": 4942.81 + }, + { + "date": "2024-02-06", + "close": 4954.23 + }, + { + "date": "2024-02-07", + "close": 4995.06 + }, + { + "date": "2024-02-08", + "close": 4997.91 + }, + { + "date": "2024-02-09", + "close": 5026.61 + }, + { + "date": "2024-02-12", + "close": 5021.84 + }, + { + "date": "2024-02-13", + "close": 4953.17 + }, + { + "date": "2024-02-14", + "close": 5000.62 + }, + { + "date": "2024-02-15", + "close": 5029.73 + }, + { + "date": "2024-02-16", + "close": 5005.57 + }, + { + "date": "2024-02-20", + "close": 4975.51 + }, + { + "date": "2024-02-21", + "close": 4981.8 + }, + { + "date": "2024-02-22", + "close": 5087.03 + }, + { + "date": "2024-02-23", + "close": 5088.8 + }, + { + "date": "2024-02-26", + "close": 5069.53 + }, + { + "date": "2024-02-27", + "close": 5078.18 + }, + { + "date": "2024-02-28", + "close": 5069.76 + }, + { + "date": "2024-02-29", + "close": 5096.27 + }, + { + "date": "2024-03-01", + "close": 5137.08 + }, + { + "date": "2024-03-04", + "close": 5130.95 + }, + { + "date": "2024-03-05", + "close": 5078.65 + }, + { + "date": "2024-03-06", + "close": 5104.76 + }, + { + "date": "2024-03-07", + "close": 5157.36 + }, + { + "date": "2024-03-08", + "close": 5123.69 + }, + { + "date": "2024-03-11", + "close": 5117.94 + }, + { + "date": "2024-03-12", + "close": 5175.27 + }, + { + "date": "2024-03-13", + "close": 5165.31 + }, + { + "date": "2024-03-14", + "close": 5150.48 + }, + { + "date": "2024-03-15", + "close": 5117.09 + }, + { + "date": "2024-03-18", + "close": 5149.42 + }, + { + "date": "2024-03-19", + "close": 5178.51 + }, + { + "date": "2024-03-20", + "close": 5224.62 + }, + { + "date": "2024-03-21", + "close": 5241.53 + }, + { + "date": "2024-03-22", + "close": 5234.18 + }, + { + "date": "2024-03-25", + "close": 5218.19 + }, + { + "date": "2024-03-26", + "close": 5203.58 + }, + { + "date": "2024-03-27", + "close": 5248.49 + }, + { + "date": "2024-03-28", + "close": 5254.35 + }, + { + "date": "2024-04-01", + "close": 5243.77 + }, + { + "date": "2024-04-02", + "close": 5205.81 + }, + { + "date": "2024-04-03", + "close": 5211.49 + }, + { + "date": "2024-04-04", + "close": 5147.21 + }, + { + "date": "2024-04-05", + "close": 5204.34 + }, + { + "date": "2024-04-08", + "close": 5202.39 + }, + { + "date": "2024-04-09", + "close": 5209.91 + }, + { + "date": "2024-04-10", + "close": 5160.64 + }, + { + "date": "2024-04-11", + "close": 5199.06 + }, + { + "date": "2024-04-12", + "close": 5123.41 + }, + { + "date": "2024-04-15", + "close": 5061.82 + }, + { + "date": "2024-04-16", + "close": 5051.41 + }, + { + "date": "2024-04-17", + "close": 5022.21 + }, + { + "date": "2024-04-18", + "close": 5011.12 + }, + { + "date": "2024-04-19", + "close": 4967.23 + }, + { + "date": "2024-04-22", + "close": 5010.6 + }, + { + "date": "2024-04-23", + "close": 5070.55 + }, + { + "date": "2024-04-24", + "close": 5071.63 + }, + { + "date": "2024-04-25", + "close": 5048.42 + }, + { + "date": "2024-04-26", + "close": 5099.96 + }, + { + "date": "2024-04-29", + "close": 5116.17 + }, + { + "date": "2024-04-30", + "close": 5035.69 + }, + { + "date": "2024-05-01", + "close": 5018.39 + }, + { + "date": "2024-05-02", + "close": 5064.2 + }, + { + "date": "2024-05-03", + "close": 5127.79 + }, + { + "date": "2024-05-06", + "close": 5180.74 + }, + { + "date": "2024-05-07", + "close": 5187.7 + }, + { + "date": "2024-05-08", + "close": 5187.67 + }, + { + "date": "2024-05-09", + "close": 5214.08 + }, + { + "date": "2024-05-10", + "close": 5222.68 + }, + { + "date": "2024-05-13", + "close": 5221.42 + }, + { + "date": "2024-05-14", + "close": 5246.68 + }, + { + "date": "2024-05-15", + "close": 5308.15 + }, + { + "date": "2024-05-16", + "close": 5297.1 + }, + { + "date": "2024-05-17", + "close": 5303.27 + }, + { + "date": "2024-05-20", + "close": 5308.13 + }, + { + "date": "2024-05-21", + "close": 5321.41 + }, + { + "date": "2024-05-22", + "close": 5307.01 + }, + { + "date": "2024-05-23", + "close": 5267.84 + }, + { + "date": "2024-05-24", + "close": 5304.72 + }, + { + "date": "2024-05-28", + "close": 5306.04 + }, + { + "date": "2024-05-29", + "close": 5266.95 + }, + { + "date": "2024-05-30", + "close": 5235.48 + }, + { + "date": "2024-05-31", + "close": 5277.51 + }, + { + "date": "2024-06-03", + "close": 5283.4 + }, + { + "date": "2024-06-04", + "close": 5291.34 + }, + { + "date": "2024-06-05", + "close": 5354.03 + }, + { + "date": "2024-06-06", + "close": 5352.96 + }, + { + "date": "2024-06-07", + "close": 5346.99 + }, + { + "date": "2024-06-10", + "close": 5360.79 + }, + { + "date": "2024-06-11", + "close": 5375.32 + }, + { + "date": "2024-06-12", + "close": 5421.03 + }, + { + "date": "2024-06-13", + "close": 5433.74 + }, + { + "date": "2024-06-14", + "close": 5431.6 + }, + { + "date": "2024-06-17", + "close": 5473.23 + }, + { + "date": "2024-06-18", + "close": 5487.03 + }, + { + "date": "2024-06-20", + "close": 5473.17 + }, + { + "date": "2024-06-21", + "close": 5464.62 + }, + { + "date": "2024-06-24", + "close": 5447.87 + }, + { + "date": "2024-06-25", + "close": 5469.3 + }, + { + "date": "2024-06-26", + "close": 5477.9 + }, + { + "date": "2024-06-27", + "close": 5482.87 + }, + { + "date": "2024-06-28", + "close": 5460.48 + }, + { + "date": "2024-07-01", + "close": 5475.09 + }, + { + "date": "2024-07-02", + "close": 5509.01 + }, + { + "date": "2024-07-03", + "close": 5537.02 + }, + { + "date": "2024-07-05", + "close": 5567.19 + }, + { + "date": "2024-07-08", + "close": 5572.85 + }, + { + "date": "2024-07-09", + "close": 5576.98 + }, + { + "date": "2024-07-10", + "close": 5633.91 + }, + { + "date": "2024-07-11", + "close": 5584.54 + }, + { + "date": "2024-07-12", + "close": 5615.35 + }, + { + "date": "2024-07-15", + "close": 5631.22 + }, + { + "date": "2024-07-16", + "close": 5667.2 + }, + { + "date": "2024-07-17", + "close": 5588.27 + }, + { + "date": "2024-07-18", + "close": 5544.59 + }, + { + "date": "2024-07-19", + "close": 5505 + }, + { + "date": "2024-07-22", + "close": 5564.41 + }, + { + "date": "2024-07-23", + "close": 5555.74 + }, + { + "date": "2024-07-24", + "close": 5427.13 + }, + { + "date": "2024-07-25", + "close": 5399.22 + }, + { + "date": "2024-07-26", + "close": 5459.1 + }, + { + "date": "2024-07-29", + "close": 5463.54 + }, + { + "date": "2024-07-30", + "close": 5436.44 + }, + { + "date": "2024-07-31", + "close": 5522.3 + }, + { + "date": "2024-08-01", + "close": 5446.68 + }, + { + "date": "2024-08-02", + "close": 5346.56 + }, + { + "date": "2024-08-05", + "close": 5186.33 + }, + { + "date": "2024-08-06", + "close": 5240.03 + }, + { + "date": "2024-08-07", + "close": 5199.5 + }, + { + "date": "2024-08-08", + "close": 5319.31 + }, + { + "date": "2024-08-09", + "close": 5344.16 + }, + { + "date": "2024-08-12", + "close": 5344.39 + }, + { + "date": "2024-08-13", + "close": 5434.43 + }, + { + "date": "2024-08-14", + "close": 5455.21 + }, + { + "date": "2024-08-15", + "close": 5543.22 + }, + { + "date": "2024-08-16", + "close": 5554.25 + }, + { + "date": "2024-08-19", + "close": 5608.25 + }, + { + "date": "2024-08-20", + "close": 5597.12 + }, + { + "date": "2024-08-21", + "close": 5620.85 + }, + { + "date": "2024-08-22", + "close": 5570.64 + }, + { + "date": "2024-08-23", + "close": 5634.61 + }, + { + "date": "2024-08-26", + "close": 5616.84 + }, + { + "date": "2024-08-27", + "close": 5625.8 + }, + { + "date": "2024-08-28", + "close": 5592.18 + }, + { + "date": "2024-08-29", + "close": 5591.96 + }, + { + "date": "2024-08-30", + "close": 5648.4 + }, + { + "date": "2024-09-03", + "close": 5528.93 + }, + { + "date": "2024-09-04", + "close": 5520.07 + }, + { + "date": "2024-09-05", + "close": 5503.41 + }, + { + "date": "2024-09-06", + "close": 5408.42 + }, + { + "date": "2024-09-09", + "close": 5471.05 + }, + { + "date": "2024-09-10", + "close": 5495.52 + }, + { + "date": "2024-09-11", + "close": 5554.13 + }, + { + "date": "2024-09-12", + "close": 5595.76 + }, + { + "date": "2024-09-13", + "close": 5626.02 + }, + { + "date": "2024-09-16", + "close": 5633.09 + }, + { + "date": "2024-09-17", + "close": 5634.58 + }, + { + "date": "2024-09-18", + "close": 5618.26 + }, + { + "date": "2024-09-19", + "close": 5713.64 + }, + { + "date": "2024-09-20", + "close": 5702.55 + }, + { + "date": "2024-09-23", + "close": 5718.57 + }, + { + "date": "2024-09-24", + "close": 5732.93 + }, + { + "date": "2024-09-25", + "close": 5722.26 + }, + { + "date": "2024-09-26", + "close": 5745.37 + }, + { + "date": "2024-09-27", + "close": 5738.17 + }, + { + "date": "2024-09-30", + "close": 5762.48 + }, + { + "date": "2024-10-01", + "close": 5708.75 + }, + { + "date": "2024-10-02", + "close": 5709.54 + }, + { + "date": "2024-10-03", + "close": 5699.94 + }, + { + "date": "2024-10-04", + "close": 5751.07 + }, + { + "date": "2024-10-07", + "close": 5695.94 + }, + { + "date": "2024-10-08", + "close": 5751.13 + }, + { + "date": "2024-10-09", + "close": 5792.04 + }, + { + "date": "2024-10-10", + "close": 5780.05 + }, + { + "date": "2024-10-11", + "close": 5815.03 + }, + { + "date": "2024-10-14", + "close": 5859.85 + }, + { + "date": "2024-10-15", + "close": 5815.26 + }, + { + "date": "2024-10-16", + "close": 5842.47 + }, + { + "date": "2024-10-17", + "close": 5841.47 + }, + { + "date": "2024-10-18", + "close": 5864.67 + }, + { + "date": "2024-10-21", + "close": 5853.98 + }, + { + "date": "2024-10-22", + "close": 5851.2 + }, + { + "date": "2024-10-23", + "close": 5797.42 + }, + { + "date": "2024-10-24", + "close": 5809.86 + }, + { + "date": "2024-10-25", + "close": 5808.12 + }, + { + "date": "2024-10-28", + "close": 5823.52 + }, + { + "date": "2024-10-29", + "close": 5832.92 + }, + { + "date": "2024-10-30", + "close": 5813.67 + }, + { + "date": "2024-10-31", + "close": 5705.45 + }, + { + "date": "2024-11-01", + "close": 5728.8 + }, + { + "date": "2024-11-04", + "close": 5712.69 + }, + { + "date": "2024-11-05", + "close": 5782.76 + }, + { + "date": "2024-11-06", + "close": 5929.04 + }, + { + "date": "2024-11-07", + "close": 5973.1 + }, + { + "date": "2024-11-08", + "close": 5995.54 + }, + { + "date": "2024-11-11", + "close": 6001.35 + }, + { + "date": "2024-11-12", + "close": 5983.99 + }, + { + "date": "2024-11-13", + "close": 5985.38 + }, + { + "date": "2024-11-14", + "close": 5949.17 + }, + { + "date": "2024-11-15", + "close": 5870.62 + }, + { + "date": "2024-11-18", + "close": 5893.62 + }, + { + "date": "2024-11-19", + "close": 5916.98 + }, + { + "date": "2024-11-20", + "close": 5917.11 + }, + { + "date": "2024-11-21", + "close": 5948.71 + }, + { + "date": "2024-11-22", + "close": 5969.34 + }, + { + "date": "2024-11-25", + "close": 5987.37 + }, + { + "date": "2024-11-26", + "close": 6021.63 + }, + { + "date": "2024-11-27", + "close": 5998.74 + }, + { + "date": "2024-11-29", + "close": 6032.38 + }, + { + "date": "2024-12-02", + "close": 6047.15 + }, + { + "date": "2024-12-03", + "close": 6049.88 + }, + { + "date": "2024-12-04", + "close": 6086.49 + }, + { + "date": "2024-12-05", + "close": 6075.11 + }, + { + "date": "2024-12-06", + "close": 6090.27 + }, + { + "date": "2024-12-09", + "close": 6052.85 + }, + { + "date": "2024-12-10", + "close": 6034.91 + }, + { + "date": "2024-12-11", + "close": 6084.19 + }, + { + "date": "2024-12-12", + "close": 6051.25 + }, + { + "date": "2024-12-13", + "close": 6051.09 + }, + { + "date": "2024-12-16", + "close": 6074.08 + }, + { + "date": "2024-12-17", + "close": 6050.61 + }, + { + "date": "2024-12-18", + "close": 5872.16 + }, + { + "date": "2024-12-19", + "close": 5867.08 + }, + { + "date": "2024-12-20", + "close": 5930.85 + }, + { + "date": "2024-12-23", + "close": 5974.07 + }, + { + "date": "2024-12-24", + "close": 6040.04 + }, + { + "date": "2024-12-26", + "close": 6037.59 + }, + { + "date": "2024-12-27", + "close": 5970.84 + }, + { + "date": "2024-12-30", + "close": 5906.94 + }, + { + "date": "2024-12-31", + "close": 5881.63 + }, + { + "date": "2025-01-02", + "close": 5868.55 + }, + { + "date": "2025-01-03", + "close": 5942.47 + }, + { + "date": "2025-01-06", + "close": 5975.38 + }, + { + "date": "2025-01-07", + "close": 5909.03 + }, + { + "date": "2025-01-08", + "close": 5918.25 + }, + { + "date": "2025-01-10", + "close": 5827.04 + }, + { + "date": "2025-01-13", + "close": 5836.22 + }, + { + "date": "2025-01-14", + "close": 5842.91 + }, + { + "date": "2025-01-15", + "close": 5949.91 + }, + { + "date": "2025-01-16", + "close": 5937.34 + }, + { + "date": "2025-01-17", + "close": 5996.66 + }, + { + "date": "2025-01-21", + "close": 6049.24 + }, + { + "date": "2025-01-22", + "close": 6086.37 + }, + { + "date": "2025-01-23", + "close": 6118.71 + }, + { + "date": "2025-01-24", + "close": 6101.24 + }, + { + "date": "2025-01-27", + "close": 6012.28 + }, + { + "date": "2025-01-28", + "close": 6067.7 + }, + { + "date": "2025-01-29", + "close": 6039.31 + }, + { + "date": "2025-01-30", + "close": 6071.17 + }, + { + "date": "2025-01-31", + "close": 6040.53 + }, + { + "date": "2025-02-03", + "close": 5994.57 + }, + { + "date": "2025-02-04", + "close": 6037.88 + }, + { + "date": "2025-02-05", + "close": 6061.48 + }, + { + "date": "2025-02-06", + "close": 6083.57 + }, + { + "date": "2025-02-07", + "close": 6025.99 + }, + { + "date": "2025-02-10", + "close": 6066.44 + }, + { + "date": "2025-02-11", + "close": 6068.5 + }, + { + "date": "2025-02-12", + "close": 6051.97 + }, + { + "date": "2025-02-13", + "close": 6115.07 + }, + { + "date": "2025-02-14", + "close": 6114.63 + }, + { + "date": "2025-02-18", + "close": 6129.58 + }, + { + "date": "2025-02-19", + "close": 6144.15 + }, + { + "date": "2025-02-20", + "close": 6117.52 + }, + { + "date": "2025-02-21", + "close": 6013.13 + }, + { + "date": "2025-02-24", + "close": 5983.25 + }, + { + "date": "2025-02-25", + "close": 5955.25 + }, + { + "date": "2025-02-26", + "close": 5956.06 + }, + { + "date": "2025-02-27", + "close": 5861.57 + }, + { + "date": "2025-02-28", + "close": 5954.5 + }, + { + "date": "2025-03-03", + "close": 5849.72 + }, + { + "date": "2025-03-04", + "close": 5778.15 + }, + { + "date": "2025-03-05", + "close": 5842.63 + }, + { + "date": "2025-03-06", + "close": 5738.52 + }, + { + "date": "2025-03-07", + "close": 5770.2 + }, + { + "date": "2025-03-10", + "close": 5614.56 + }, + { + "date": "2025-03-11", + "close": 5572.07 + }, + { + "date": "2025-03-12", + "close": 5599.3 + }, + { + "date": "2025-03-13", + "close": 5521.52 + }, + { + "date": "2025-03-14", + "close": 5638.94 + }, + { + "date": "2025-03-17", + "close": 5675.12 + }, + { + "date": "2025-03-18", + "close": 5614.66 + }, + { + "date": "2025-03-19", + "close": 5675.29 + }, + { + "date": "2025-03-20", + "close": 5662.89 + }, + { + "date": "2025-03-21", + "close": 5667.56 + }, + { + "date": "2025-03-24", + "close": 5767.57 + }, + { + "date": "2025-03-25", + "close": 5776.65 + }, + { + "date": "2025-03-26", + "close": 5712.2 + }, + { + "date": "2025-03-27", + "close": 5693.31 + }, + { + "date": "2025-03-28", + "close": 5580.94 + }, + { + "date": "2025-03-31", + "close": 5611.85 + }, + { + "date": "2025-04-01", + "close": 5633.07 + }, + { + "date": "2025-04-02", + "close": 5670.97 + }, + { + "date": "2025-04-03", + "close": 5396.52 + }, + { + "date": "2025-04-04", + "close": 5074.08 + }, + { + "date": "2025-04-07", + "close": 5062.25 + }, + { + "date": "2025-04-08", + "close": 4982.77 + }, + { + "date": "2025-04-09", + "close": 5456.9 + }, + { + "date": "2025-04-10", + "close": 5268.05 + }, + { + "date": "2025-04-11", + "close": 5363.36 + }, + { + "date": "2025-04-14", + "close": 5405.97 + }, + { + "date": "2025-04-15", + "close": 5396.63 + }, + { + "date": "2025-04-16", + "close": 5275.7 + }, + { + "date": "2025-04-17", + "close": 5282.7 + }, + { + "date": "2025-04-21", + "close": 5158.2 + }, + { + "date": "2025-04-22", + "close": 5287.76 + }, + { + "date": "2025-04-23", + "close": 5375.86 + }, + { + "date": "2025-04-24", + "close": 5484.77 + }, + { + "date": "2025-04-25", + "close": 5525.21 + }, + { + "date": "2025-04-28", + "close": 5528.75 + }, + { + "date": "2025-04-29", + "close": 5560.83 + }, + { + "date": "2025-04-30", + "close": 5569.06 + }, + { + "date": "2025-05-01", + "close": 5604.14 + }, + { + "date": "2025-05-02", + "close": 5686.67 + }, + { + "date": "2025-05-05", + "close": 5650.38 + }, + { + "date": "2025-05-06", + "close": 5606.91 + }, + { + "date": "2025-05-07", + "close": 5631.28 + }, + { + "date": "2025-05-08", + "close": 5663.94 + }, + { + "date": "2025-05-09", + "close": 5659.91 + }, + { + "date": "2025-05-12", + "close": 5844.19 + }, + { + "date": "2025-05-13", + "close": 5886.55 + }, + { + "date": "2025-05-14", + "close": 5892.58 + }, + { + "date": "2025-05-15", + "close": 5916.93 + }, + { + "date": "2025-05-16", + "close": 5958.38 + }, + { + "date": "2025-05-19", + "close": 5963.6 + }, + { + "date": "2025-05-20", + "close": 5940.46 + }, + { + "date": "2025-05-21", + "close": 5844.61 + }, + { + "date": "2025-05-22", + "close": 5842.01 + }, + { + "date": "2025-05-23", + "close": 5802.82 + }, + { + "date": "2025-05-27", + "close": 5921.54 + }, + { + "date": "2025-05-28", + "close": 5888.55 + }, + { + "date": "2025-05-29", + "close": 5912.17 + }, + { + "date": "2025-05-30", + "close": 5911.69 + }, + { + "date": "2025-06-02", + "close": 5935.94 + }, + { + "date": "2025-06-03", + "close": 5970.37 + }, + { + "date": "2025-06-04", + "close": 5970.81 + }, + { + "date": "2025-06-05", + "close": 5939.3 + }, + { + "date": "2025-06-06", + "close": 6000.36 + }, + { + "date": "2025-06-09", + "close": 6005.88 + }, + { + "date": "2025-06-10", + "close": 6038.81 + }, + { + "date": "2025-06-11", + "close": 6022.24 + }, + { + "date": "2025-06-12", + "close": 6045.26 + }, + { + "date": "2025-06-13", + "close": 5976.97 + }, + { + "date": "2025-06-16", + "close": 6033.11 + }, + { + "date": "2025-06-17", + "close": 5982.72 + }, + { + "date": "2025-06-18", + "close": 5980.87 + }, + { + "date": "2025-06-20", + "close": 5967.84 + }, + { + "date": "2025-06-23", + "close": 6025.17 + }, + { + "date": "2025-06-24", + "close": 6092.18 + }, + { + "date": "2025-06-25", + "close": 6092.16 + }, + { + "date": "2025-06-26", + "close": 6141.02 + }, + { + "date": "2025-06-27", + "close": 6173.07 + }, + { + "date": "2025-06-30", + "close": 6204.95 + }, + { + "date": "2025-07-01", + "close": 6198.01 + }, + { + "date": "2025-07-02", + "close": 6227.42 + }, + { + "date": "2025-07-03", + "close": 6279.35 + }, + { + "date": "2025-07-07", + "close": 6229.98 + }, + { + "date": "2025-07-08", + "close": 6225.52 + }, + { + "date": "2025-07-09", + "close": 6263.26 + }, + { + "date": "2025-07-10", + "close": 6280.46 + }, + { + "date": "2025-07-11", + "close": 6259.75 + }, + { + "date": "2025-07-14", + "close": 6268.56 + }, + { + "date": "2025-07-15", + "close": 6243.76 + }, + { + "date": "2025-07-16", + "close": 6263.7 + }, + { + "date": "2025-07-17", + "close": 6297.36 + }, + { + "date": "2025-07-18", + "close": 6296.79 + }, + { + "date": "2025-07-21", + "close": 6305.6 + }, + { + "date": "2025-07-22", + "close": 6309.62 + }, + { + "date": "2025-07-23", + "close": 6358.91 + }, + { + "date": "2025-07-24", + "close": 6363.35 + }, + { + "date": "2025-07-25", + "close": 6388.64 + }, + { + "date": "2025-07-28", + "close": 6389.77 + }, + { + "date": "2025-07-29", + "close": 6370.86 + }, + { + "date": "2025-07-30", + "close": 6362.9 + }, + { + "date": "2025-07-31", + "close": 6339.39 + }, + { + "date": "2025-08-01", + "close": 6238.01 + }, + { + "date": "2025-08-04", + "close": 6329.94 + }, + { + "date": "2025-08-05", + "close": 6299.19 + }, + { + "date": "2025-08-06", + "close": 6345.06 + }, + { + "date": "2025-08-07", + "close": 6340 + }, + { + "date": "2025-08-08", + "close": 6389.45 + }, + { + "date": "2025-08-11", + "close": 6373.45 + }, + { + "date": "2025-08-12", + "close": 6445.76 + }, + { + "date": "2025-08-13", + "close": 6466.58 + }, + { + "date": "2025-08-14", + "close": 6468.54 + }, + { + "date": "2025-08-15", + "close": 6449.8 + }, + { + "date": "2025-08-18", + "close": 6449.15 + }, + { + "date": "2025-08-19", + "close": 6411.37 + }, + { + "date": "2025-08-20", + "close": 6395.78 + }, + { + "date": "2025-08-21", + "close": 6370.17 + }, + { + "date": "2025-08-22", + "close": 6466.91 + }, + { + "date": "2025-08-25", + "close": 6439.32 + }, + { + "date": "2025-08-26", + "close": 6465.94 + }, + { + "date": "2025-08-27", + "close": 6481.4 + }, + { + "date": "2025-08-28", + "close": 6501.86 + }, + { + "date": "2025-08-29", + "close": 6460.26 + }, + { + "date": "2025-09-02", + "close": 6415.54 + }, + { + "date": "2025-09-03", + "close": 6448.26 + }, + { + "date": "2025-09-04", + "close": 6502.08 + }, + { + "date": "2025-09-05", + "close": 6481.5 + }, + { + "date": "2025-09-08", + "close": 6495.15 + }, + { + "date": "2025-09-09", + "close": 6512.61 + }, + { + "date": "2025-09-10", + "close": 6532.04 + }, + { + "date": "2025-09-11", + "close": 6587.47 + }, + { + "date": "2025-09-12", + "close": 6584.29 + }, + { + "date": "2025-09-15", + "close": 6615.28 + }, + { + "date": "2025-09-16", + "close": 6606.76 + }, + { + "date": "2025-09-17", + "close": 6600.35 + }, + { + "date": "2025-09-18", + "close": 6631.96 + }, + { + "date": "2025-09-19", + "close": 6664.36 + }, + { + "date": "2025-09-22", + "close": 6693.75 + }, + { + "date": "2025-09-23", + "close": 6656.92 + }, + { + "date": "2025-09-24", + "close": 6637.97 + }, + { + "date": "2025-09-25", + "close": 6604.72 + }, + { + "date": "2025-09-26", + "close": 6643.7 + }, + { + "date": "2025-09-29", + "close": 6661.21 + }, + { + "date": "2025-09-30", + "close": 6688.46 + }, + { + "date": "2025-10-01", + "close": 6711.2 + }, + { + "date": "2025-10-02", + "close": 6715.35 + }, + { + "date": "2025-10-03", + "close": 6715.79 + }, + { + "date": "2025-10-06", + "close": 6740.28 + }, + { + "date": "2025-10-07", + "close": 6714.59 + }, + { + "date": "2025-10-08", + "close": 6753.72 + }, + { + "date": "2025-10-09", + "close": 6735.11 + }, + { + "date": "2025-10-10", + "close": 6552.51 + }, + { + "date": "2025-10-13", + "close": 6654.72 + }, + { + "date": "2025-10-14", + "close": 6644.31 + }, + { + "date": "2025-10-15", + "close": 6671.06 + }, + { + "date": "2025-10-16", + "close": 6629.07 + }, + { + "date": "2025-10-17", + "close": 6664.01 + }, + { + "date": "2025-10-20", + "close": 6735.13 + }, + { + "date": "2025-10-21", + "close": 6735.35 + }, + { + "date": "2025-10-22", + "close": 6699.4 + }, + { + "date": "2025-10-23", + "close": 6738.44 + }, + { + "date": "2025-10-24", + "close": 6791.69 + }, + { + "date": "2025-10-27", + "close": 6875.16 + }, + { + "date": "2025-10-28", + "close": 6890.89 + }, + { + "date": "2025-10-29", + "close": 6890.59 + }, + { + "date": "2025-10-30", + "close": 6822.34 + }, + { + "date": "2025-10-31", + "close": 6840.2 + }, + { + "date": "2025-11-03", + "close": 6851.97 + }, + { + "date": "2025-11-04", + "close": 6771.55 + }, + { + "date": "2025-11-05", + "close": 6796.29 + }, + { + "date": "2025-11-06", + "close": 6720.32 + }, + { + "date": "2025-11-07", + "close": 6728.8 + }, + { + "date": "2025-11-10", + "close": 6832.43 + }, + { + "date": "2025-11-11", + "close": 6846.61 + }, + { + "date": "2025-11-12", + "close": 6850.92 + }, + { + "date": "2025-11-13", + "close": 6737.49 + }, + { + "date": "2025-11-14", + "close": 6734.11 + }, + { + "date": "2025-11-17", + "close": 6672.41 + }, + { + "date": "2025-11-18", + "close": 6617.32 + }, + { + "date": "2025-11-19", + "close": 6642.16 + }, + { + "date": "2025-11-20", + "close": 6538.76 + }, + { + "date": "2025-11-21", + "close": 6602.99 + }, + { + "date": "2025-11-24", + "close": 6705.12 + }, + { + "date": "2025-11-25", + "close": 6765.88 + }, + { + "date": "2025-11-26", + "close": 6812.61 + }, + { + "date": "2025-11-28", + "close": 6849.09 + }, + { + "date": "2025-12-01", + "close": 6812.63 + }, + { + "date": "2025-12-02", + "close": 6829.37 + }, + { + "date": "2025-12-03", + "close": 6849.72 + }, + { + "date": "2025-12-04", + "close": 6857.12 + }, + { + "date": "2025-12-05", + "close": 6870.4 + }, + { + "date": "2025-12-08", + "close": 6846.51 + }, + { + "date": "2025-12-09", + "close": 6840.51 + }, + { + "date": "2025-12-10", + "close": 6886.68 + }, + { + "date": "2025-12-11", + "close": 6901 + }, + { + "date": "2025-12-12", + "close": 6827.41 + }, + { + "date": "2025-12-15", + "close": 6816.51 + }, + { + "date": "2025-12-16", + "close": 6800.26 + }, + { + "date": "2025-12-17", + "close": 6721.43 + }, + { + "date": "2025-12-18", + "close": 6774.76 + }, + { + "date": "2025-12-19", + "close": 6834.5 + }, + { + "date": "2025-12-22", + "close": 6878.49 + }, + { + "date": "2025-12-23", + "close": 6909.79 + }, + { + "date": "2025-12-24", + "close": 6932.05 + }, + { + "date": "2025-12-26", + "close": 6929.94 + }, + { + "date": "2025-12-29", + "close": 6905.74 + }, + { + "date": "2025-12-30", + "close": 6896.24 + }, + { + "date": "2025-12-31", + "close": 6845.5 + }, + { + "date": "2026-01-02", + "close": 6858.47 + }, + { + "date": "2026-01-05", + "close": 6902.05 + }, + { + "date": "2026-01-06", + "close": 6944.82 + }, + { + "date": "2026-01-07", + "close": 6920.93 + }, + { + "date": "2026-01-08", + "close": 6921.46 + }, + { + "date": "2026-01-09", + "close": 6966.28 + }, + { + "date": "2026-01-12", + "close": 6977.27 + }, + { + "date": "2026-01-13", + "close": 6963.74 + }, + { + "date": "2026-01-14", + "close": 6926.6 + }, + { + "date": "2026-01-15", + "close": 6944.47 + }, + { + "date": "2026-01-16", + "close": 6940.01 + }, + { + "date": "2026-01-20", + "close": 6796.86 + }, + { + "date": "2026-01-21", + "close": 6875.62 + }, + { + "date": "2026-01-22", + "close": 6913.35 + }, + { + "date": "2026-01-23", + "close": 6915.61 + }, + { + "date": "2026-01-26", + "close": 6950.23 + }, + { + "date": "2026-01-27", + "close": 6978.6 + }, + { + "date": "2026-01-28", + "close": 6978.03 + }, + { + "date": "2026-01-29", + "close": 6969.01 + }, + { + "date": "2026-01-30", + "close": 6939.03 + }, + { + "date": "2026-02-02", + "close": 6976.44 + }, + { + "date": "2026-02-03", + "close": 6917.81 + }, + { + "date": "2026-02-04", + "close": 6882.72 + }, + { + "date": "2026-02-05", + "close": 6798.4 + }, + { + "date": "2026-02-06", + "close": 6932.3 + }, + { + "date": "2026-02-09", + "close": 6964.82 + }, + { + "date": "2026-02-10", + "close": 6941.81 + }, + { + "date": "2026-02-11", + "close": 6941.47 + }, + { + "date": "2026-02-12", + "close": 6832.76 + }, + { + "date": "2026-02-13", + "close": 6836.17 + }, + { + "date": "2026-02-17", + "close": 6843.22 + }, + { + "date": "2026-02-18", + "close": 6881.31 + }, + { + "date": "2026-02-19", + "close": 6861.89 + }, + { + "date": "2026-02-20", + "close": 6909.51 + }, + { + "date": "2026-02-23", + "close": 6837.75 + }, + { + "date": "2026-02-24", + "close": 6890.07 + }, + { + "date": "2026-02-25", + "close": 6946.13 + }, + { + "date": "2026-02-26", + "close": 6908.86 + }, + { + "date": "2026-02-27", + "close": 6878.88 + }, + { + "date": "2026-03-02", + "close": 6881.62 + }, + { + "date": "2026-03-03", + "close": 6816.63 + }, + { + "date": "2026-03-04", + "close": 6869.5 + }, + { + "date": "2026-03-05", + "close": 6830.71 + }, + { + "date": "2026-03-06", + "close": 6740.02 + }, + { + "date": "2026-03-09", + "close": 6795.99 + }, + { + "date": "2026-03-10", + "close": 6781.48 + }, + { + "date": "2026-03-11", + "close": 6775.8 + }, + { + "date": "2026-03-12", + "close": 6672.62 + }, + { + "date": "2026-03-13", + "close": 6632.19 + }, + { + "date": "2026-03-16", + "close": 6699.38 + }, + { + "date": "2026-03-17", + "close": 6716.09 + }, + { + "date": "2026-03-18", + "close": 6624.7 + }, + { + "date": "2026-03-19", + "close": 6606.49 + }, + { + "date": "2026-03-20", + "close": 6506.48 + }, + { + "date": "2026-03-23", + "close": 6581 + }, + { + "date": "2026-03-24", + "close": 6556.37 + }, + { + "date": "2026-03-25", + "close": 6591.9 + }, + { + "date": "2026-03-26", + "close": 6477.16 + }, + { + "date": "2026-03-27", + "close": 6368.85 + }, + { + "date": "2026-03-30", + "close": 6343.72 + }, + { + "date": "2026-03-31", + "close": 6528.52 + }, + { + "date": "2026-04-01", + "close": 6575.32 + }, + { + "date": "2026-04-02", + "close": 6582.69 + }, + { + "date": "2026-04-06", + "close": 6611.83 + }, + { + "date": "2026-04-07", + "close": 6616.85 + }, + { + "date": "2026-04-08", + "close": 6782.81 + }, + { + "date": "2026-04-09", + "close": 6824.66 + }, + { + "date": "2026-04-10", + "close": 6816.89 + }, + { + "date": "2026-04-13", + "close": 6886.24 + }, + { + "date": "2026-04-14", + "close": 6967.38 + }, + { + "date": "2026-04-15", + "close": 7022.95 + }, + { + "date": "2026-04-16", + "close": 7041.28 + }, + { + "date": "2026-04-17", + "close": 7126.06 + }, + { + "date": "2026-04-20", + "close": 7109.14 + }, + { + "date": "2026-04-21", + "close": 7064.01 + }, + { + "date": "2026-04-22", + "close": 7137.9 + }, + { + "date": "2026-04-23", + "close": 7108.4 + }, + { + "date": "2026-04-24", + "close": 7165.08 + }, + { + "date": "2026-04-27", + "close": 7173.91 + }, + { + "date": "2026-04-28", + "close": 7138.8 + }, + { + "date": "2026-04-29", + "close": 7135.95 + }, + { + "date": "2026-04-30", + "close": 7209.01 + }, + { + "date": "2026-05-01", + "close": 7230.12 + }, + { + "date": "2026-05-04", + "close": 7200.75 + }, + { + "date": "2026-05-05", + "close": 7259.22 + }, + { + "date": "2026-05-06", + "close": 7365.12 + }, + { + "date": "2026-05-07", + "close": 7337.11 + }, + { + "date": "2026-05-08", + "close": 7398.93 + }, + { + "date": "2026-05-11", + "close": 7412.84 + }, + { + "date": "2026-05-12", + "close": 7400.96 + }, + { + "date": "2026-05-13", + "close": 7444.25 + }, + { + "date": "2026-05-14", + "close": 7501.24 + }, + { + "date": "2026-05-15", + "close": 7408.5 + }, + { + "date": "2026-05-18", + "close": 7403.05 + }, + { + "date": "2026-05-19", + "close": 7353.61 + }, + { + "date": "2026-05-20", + "close": 7432.97 + }, + { + "date": "2026-05-21", + "close": 7445.72 + }, + { + "date": "2026-05-22", + "close": 7473.47 + }, + { + "date": "2026-05-26", + "close": 7519.12 + }, + { + "date": "2026-05-27", + "close": 7520.36 + }, + { + "date": "2026-05-28", + "close": 7563.63 + }, + { + "date": "2026-05-29", + "close": 7580.06 + }, + { + "date": "2026-06-01", + "close": 7599.96 + }, + { + "date": "2026-06-02", + "close": 7609.78 + }, + { + "date": "2026-06-03", + "close": 7553.68 + }, + { + "date": "2026-06-04", + "close": 7584.31 + }, + { + "date": "2026-06-05", + "close": 7383.74 + }, + { + "date": "2026-06-08", + "close": 7405.73 + }, + { + "date": "2026-06-09", + "close": 7386.65 + }, + { + "date": "2026-06-10", + "close": 7266.99 + }, + { + "date": "2026-06-11", + "close": 7394.3 + }, + { + "date": "2026-06-12", + "close": 7431.46 + }, + { + "date": "2026-06-15", + "close": 7554.29 + }, + { + "date": "2026-06-16", + "close": 7511.35 + }, + { + "date": "2026-06-17", + "close": 7420.1 + }, + { + "date": "2026-06-18", + "close": 7500.58 + }, + { + "date": "2026-06-22", + "close": 7472.79 + }, + { + "date": "2026-06-23", + "close": 7365.46 + }, + { + "date": "2026-06-24", + "close": 7358.22 + }, + { + "date": "2026-06-25", + "close": 7357.49 + }, + { + "date": "2026-06-26", + "close": 7354.02 + }, + { + "date": "2026-06-29", + "close": 7440.43 + }, + { + "date": "2026-06-30", + "close": 7499.36 + }, + { + "date": "2026-07-01", + "close": 7483.23 + }, + { + "date": "2026-07-02", + "close": 7483.24 + }, + { + "date": "2026-07-06", + "close": 7537.43 + }, + { + "date": "2026-07-07", + "close": 7503.85 + }, + { + "date": "2026-07-08", + "close": 7482.71 + }, + { + "date": "2026-07-09", + "close": 7543.64 + }, + { + "date": "2026-07-10", + "close": 7575.39 + }, + { + "date": "2026-07-13", + "close": 7515.34 + }, + { + "date": "2026-07-14", + "close": 7543.59 + }, + { + "date": "2026-07-15", + "close": 7572.4 + }, + { + "date": "2026-07-16", + "close": 7533.77 + }, + { + "date": "2026-07-17", + "close": 7457.69 + }, + { + "date": "2026-07-20", + "close": 7443.28 + }, + { + "date": "2026-07-21", + "close": 7509.2 + }, + { + "date": "2026-07-22", + "close": 7498.96 + }, + { + "date": "2026-07-23", + "close": 7408.3 + }, + { + "date": "2026-07-24", + "close": 7411.98 + }, + { + "date": "2026-07-27", + "close": 7413.18 + }, + { + "date": "2026-07-28", + "close": 7428.78 + }, + { + "date": "2026-07-29", + "close": 7316.15 + }, + { + "date": "2026-07-30", + "close": 7437.63 + }, + { + "date": "2026-07-31", + "close": 7489.72 + }, + { + "date": "2026-08-03", + "close": 7600.5 + }, + { + "date": "2026-08-04", + "close": 7736.52 + }, + { + "date": "2026-08-05", + "close": 7723.55 + }, + { + "date": "2026-08-06", + "close": 7709.96 + }, + { + "date": "2026-08-07", + "close": 7757.64 + }, + { + "date": "2026-08-10", + "close": 7753.11 + }, + { + "date": "2026-08-11", + "close": 7728.2 + }, + { + "date": "2026-08-12", + "close": 7748.5 + }, + { + "date": "2026-08-13", + "close": 7798.99 + }, + { + "date": "2026-08-14", + "close": 7785.76 + }, + { + "date": "2026-08-17", + "close": 7745.06 + }, + { + "date": "2026-08-18", + "close": 7691.76 + }, + { + "date": "2026-08-19", + "close": 7707.98 + }, + { + "date": "2026-08-20", + "close": 7641.16 + }, + { + "date": "2026-08-21", + "close": 7674.37 + }, + { + "date": "2026-08-24", + "close": 7652.86 + }, + { + "date": "2026-08-25", + "close": 7677.28 + }, + { + "date": "2026-08-26", + "close": 7675.7 + }, + { + "date": "2026-08-27", + "close": 7730.99 + }, + { + "date": "2026-08-28", + "close": 7711.76 + } + ] +} \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..5a92fd4 --- /dev/null +++ b/index.html @@ -0,0 +1,13 @@ + + + + + + + Mis inversiones + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..1f6551d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1748 @@ +{ + "name": "investmentvisualizer", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "investmentvisualizer", + "version": "0.0.0", + "dependencies": { + "react": "^19.2.8", + "react-dom": "^19.2.8", + "recharts": "^3.10.1" + }, + "devDependencies": { + "@types/node": "^24.13.3", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.4", + "@vitejs/plugin-react": "^6.1.0", + "oxlint": "^1.79.0", + "typescript": "~6.0.2", + "vite": "^8.2.2" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.147.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.147.0.tgz", + "integrity": "sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.80.0.tgz", + "integrity": "sha512-RM3Plj+biQpxa5d1GOOX6ciDlcUROmm4OZ/pLTpitkQt2mJv4jhtY4cbgaetOm5UKWZe05/TGQ6o1Vl8EOHkrA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.80.0.tgz", + "integrity": "sha512-YlO5JEf0Yr2bUUlu8O8daVcUxtcGGbcSmyV7E7nSbJbfAdxTE0PFPwgnIlw7wXJaTYjb+qs5hI5q3jxUkI7cAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.80.0.tgz", + "integrity": "sha512-BULDOyO3AhsmdWfQeIUCykDt3dd7XZBGLhp1eIh56skRv01O+cNjNPwXMIbeW1x4+pxcln5if72wcRgViVo7PA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.80.0.tgz", + "integrity": "sha512-YJ4JzLw7N5TDSQFlA0hAQGHvnDZgyypm1yunObVWcWiF9KM7eGCJKYKLgTC2Fi/57OdnBhbj4OkzPGdFQJ6HyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.80.0.tgz", + "integrity": "sha512-AYUIk5QnL0s8oWAYsREZwkRYy1SupJTXALo93J1TgzHywxQtdM99FecRMQ87MXEdPQ0j1TmEpeeq3fGNkpvMqg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.80.0.tgz", + "integrity": "sha512-9hBZVANupQ89W9dXyE0n8doCyaW5pDyGn3y6XlIMPZ+rIKuyqkr3SNUXmVJIhuvUq0NBU3RBiSXXE69l4XI6KA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.80.0.tgz", + "integrity": "sha512-SvS2uKqzY+pbfuvAHzH4338R6Zwo805GAwrIMVvK1KxoOWCIjZUdfzTCvilD7z6JK91v011+zYMryabhDo2AsQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.80.0.tgz", + "integrity": "sha512-tCLadyqRVL3pQTRPNg7cjXKvcvS4fbyXeQHhKk5BTJ1oftQln5/yIIWbu/Xom/DX41zv2P9QGt6+D/TtQVtY3A==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.80.0.tgz", + "integrity": "sha512-XfpCNRlOPcLlJl4Bn/FUhjqlR6BVavEykERBf/MV7YA9VZDa5g5znVqYhyviMafcxS9Pe/i/kPvHNO0U6svEHQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.80.0.tgz", + "integrity": "sha512-3I4yMwcFG9NeO8ioY6JBBuKsIm5GL/x7MATt1S4tVWaxPu5HcJ+XnLUbcVBTxG8q2Wu56HSj+NmXQiVYb1lp6A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.80.0.tgz", + "integrity": "sha512-E1wAKymkpe1/E8helzBKdm81OBOF+ezxRyXRMEuik3ZpWDER5CPOKZwF66RsdwW98uwZv8UTFremUQtC1CzdJA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.80.0.tgz", + "integrity": "sha512-+gLRGD4sIo3+VA++iham5UxD9tKSoJ/VOrROCEXIcknrYtQg6iIQgvjN0cpiRF7N6UYC7pJbvHJlDnMge5LRpQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.80.0.tgz", + "integrity": "sha512-aR0PrzHj9leW3NmzBAAP4EzdoBNoJcs9sjnIQPIwyRnBGYrRbXUIpEB5Q39AqK3PLY5JK5uEhDQDiUa1QSAstw==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.80.0.tgz", + "integrity": "sha512-vSVh5cSo3Xxs6ghBCcFJlpbkbENzDog1qXtoXLa/HC3aCrR4XO76GZbXmQoCPHnu99nQpdCeC3H9tdNICfDh7A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.80.0.tgz", + "integrity": "sha512-FfzBXpNQ8u7/ZI/p8bl73MeZ508Ax3hxWp3SiJpEFiC+BB9XcXy5FAZHTLKDPSzrUpxQZSZJAVdDmuJp/+HDBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.80.0.tgz", + "integrity": "sha512-zMzbkumtmprCgRwoYNzcB3iC39fXdJIMLMU33KdCjEGLlJGOEt1+LwQ4LF8ndLzAEKVz4BR0y3V6Xrkk3Nm3yA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.80.0.tgz", + "integrity": "sha512-ib6iRcrXsk4t1fm3iKcwksyWh1ZkZXC/2mEzakl0ai2+6HZunf1WWMZ/xP9EJAvw9g9K4UVTC3NF/+G2qLrbTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.80.0.tgz", + "integrity": "sha512-xhRWBMpLxZvgKAH6+DJZmpP+W8Y8UdQOSU1JfxSWNXsaBaRGW77j+1hCuNHlzj7OH4SPN8fYd1q0o2qrDtoVyw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.80.0.tgz", + "integrity": "sha512-yAnO7lwBYQnz2pcfBPIGQQZWIX5zd5R/1aAKIF3oE+TVj7IhoHcROjOkz3sRDngzqhfPKfFaXqug5j5rE5dn6Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", + "integrity": "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.6.tgz", + "integrity": "sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.6.tgz", + "integrity": "sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.6.tgz", + "integrity": "sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.6.tgz", + "integrity": "sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.6.tgz", + "integrity": "sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.6.tgz", + "integrity": "sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.6.tgz", + "integrity": "sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.6.tgz", + "integrity": "sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.6.tgz", + "integrity": "sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.6.tgz", + "integrity": "sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.6.tgz", + "integrity": "sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.6.tgz", + "integrity": "sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.6.tgz", + "integrity": "sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.6.tgz", + "integrity": "sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.6.tgz", + "integrity": "sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.13.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz", + "integrity": "sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-fMPwH9v7r/pp43yUd2/Mbiex5KouJwwR3dzHkhLREUC6764VyDsqxhAxv6OFEYR1RhjOyD1naqba8ECDBe7ZQg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.1.1.tgz", + "integrity": "sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "oxc-transform-react": "^0.145.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "oxc-transform-react": { + "optional": true + } + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/es-toolkit": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks", + "tests/types", + "tests/browser-compat" + ] + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/immer": { + "version": "11.1.18", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.1.18.tgz", + "integrity": "sha512-EQyQtLiYW029lyoczMl/Hh4Xu7cDecSc58JRYpHyL4tIAu3eqd1yJzQX04d2BZHDkzFFvm6qJEJWOtfDSWAXbQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/oxlint": { + "version": "1.80.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.80.0.tgz", + "integrity": "sha512-5nTiSps4qdbCWLbxzuO00alHkEO2exR9YMN/ig6QXWrLsYSG0KaObOAM+l6oU2LcKPWoSAGYbkZIGEu1ViiWKA==", + "dev": true, + "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.80.0", + "@oxlint/binding-android-arm64": "1.80.0", + "@oxlint/binding-darwin-arm64": "1.80.0", + "@oxlint/binding-darwin-x64": "1.80.0", + "@oxlint/binding-freebsd-x64": "1.80.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.80.0", + "@oxlint/binding-linux-arm-musleabihf": "1.80.0", + "@oxlint/binding-linux-arm64-gnu": "1.80.0", + "@oxlint/binding-linux-arm64-musl": "1.80.0", + "@oxlint/binding-linux-ppc64-gnu": "1.80.0", + "@oxlint/binding-linux-riscv64-gnu": "1.80.0", + "@oxlint/binding-linux-riscv64-musl": "1.80.0", + "@oxlint/binding-linux-s390x-gnu": "1.80.0", + "@oxlint/binding-linux-x64-gnu": "1.80.0", + "@oxlint/binding-linux-x64-musl": "1.80.0", + "@oxlint/binding-openharmony-arm64": "1.80.0", + "@oxlint/binding-win32-arm64-msvc": "1.80.0", + "@oxlint/binding-win32-ia32-msvc": "1.80.0", + "@oxlint/binding-win32-x64-msvc": "1.80.0" + }, + "peerDependencies": { + "oxlint-tsgolint": ">=7.0.2001", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + }, + "vite-plus": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/react-is": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.8.tgz", + "integrity": "sha512-s5un28nYxKJw5gvUHyW5PCC28CvBqLu9r3cWgzHT4Vo/5fqqkFcdRYsGcKf50WMPpjjFZS5d76fn3YCo2njKwQ==", + "license": "MIT", + "peer": true + }, + "node_modules/react-redux": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", + "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/recharts": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.10.1.tgz", + "integrity": "sha512-QXFrvt6IVcw7eeZCoyXTwkIJAX3Dv1nyVhMicXJ47GsGDDpcN8z6o644DibE9XjpBTThtsomLKnTV6lc+cVFUA==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "^1.9.0 || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^11.1.8", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.2.0", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, + "node_modules/reselect": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.2.0.tgz", + "integrity": "sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==", + "license": "MIT" + }, + "node_modules/rolldown": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.6.tgz", + "integrity": "sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.147.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.6", + "@rolldown/binding-android-arm64": "1.2.6", + "@rolldown/binding-darwin-arm64": "1.2.6", + "@rolldown/binding-darwin-x64": "1.2.6", + "@rolldown/binding-freebsd-x64": "1.2.6", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.6", + "@rolldown/binding-linux-arm64-gnu": "1.2.6", + "@rolldown/binding-linux-arm64-musl": "1.2.6", + "@rolldown/binding-linux-ppc64-gnu": "1.2.6", + "@rolldown/binding-linux-s390x-gnu": "1.2.6", + "@rolldown/binding-linux-x64-gnu": "1.2.6", + "@rolldown/binding-linux-x64-musl": "1.2.6", + "@rolldown/binding-openharmony-arm64": "1.2.6", + "@rolldown/binding-win32-arm64-msvc": "1.2.6", + "@rolldown/binding-win32-x64-msvc": "1.2.6" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/vite": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..467b5b8 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "investmentvisualizer", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "oxlint", + "preview": "vite preview" + }, + "dependencies": { + "react": "^19.2.8", + "react-dom": "^19.2.8", + "recharts": "^3.10.1" + }, + "devDependencies": { + "@types/node": "^24.13.3", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.4", + "@vitejs/plugin-react": "^6.1.0", + "oxlint": "^1.79.0", + "typescript": "~6.0.2", + "vite": "^8.2.2" + } +} diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 0000000..6893eb1 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/icons.svg b/public/icons.svg new file mode 100644 index 0000000..e952219 --- /dev/null +++ b/public/icons.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/fetch-sp500.mjs b/scripts/fetch-sp500.mjs new file mode 100644 index 0000000..3351c29 --- /dev/null +++ b/scripts/fetch-sp500.mjs @@ -0,0 +1,33 @@ +// Refreshes data/sp500.json with daily S&P 500 close prices from Yahoo Finance's +// public chart endpoint (no API key required). Run with: node scripts/fetch-sp500.mjs +import { writeFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { dirname, join } from "node:path"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const OUT_PATH = join(__dirname, "..", "data", "sp500.json"); +const URL = + "https://query1.finance.yahoo.com/v8/finance/chart/%5EGSPC?range=10y&interval=1d"; + +const res = await fetch(URL, { headers: { "User-Agent": "Mozilla/5.0" } }); +if (!res.ok) { + throw new Error(`Yahoo Finance request failed: ${res.status} ${res.statusText}`); +} +const data = await res.json(); +const result = data?.chart?.result?.[0]; +if (!result) { + throw new Error("Unexpected response shape from Yahoo Finance"); +} + +const { timestamp } = result; +const closes = result.indicators.quote[0].close; + +const series = []; +for (let i = 0; i < timestamp.length; i++) { + if (closes[i] == null) continue; + const date = new Date(timestamp[i] * 1000).toISOString().slice(0, 10); + series.push({ date, close: Number(closes[i].toFixed(2)) }); +} + +writeFileSync(OUT_PATH, JSON.stringify({ source: "yahoo-finance:^GSPC", updatedAt: new Date().toISOString(), series }, null, 2)); +console.log(`Wrote ${series.length} points to ${OUT_PATH}`); diff --git a/server/apiPlugin.ts b/server/apiPlugin.ts new file mode 100644 index 0000000..d16f5cd --- /dev/null +++ b/server/apiPlugin.ts @@ -0,0 +1,200 @@ +import type { IncomingMessage, ServerResponse } from "node:http"; +import type { Plugin, Connect } from "vite"; +import { randomUUID } from "node:crypto"; +import { readJson, writeJson } from "./jsonStore.ts"; +import type { Contributions, History, Movement, Portfolio, RecurringPlan, Settings } from "./types.ts"; + +function send(res: ServerResponse, status: number, body: unknown): void { + const payload = JSON.stringify(body); + res.statusCode = status; + res.setHeader("Content-Type", "application/json"); + res.end(payload); +} + +function readBody(req: IncomingMessage): Promise { + return new Promise((resolve, reject) => { + let raw = ""; + req.on("data", (chunk) => (raw += chunk)); + req.on("end", () => { + if (!raw) return resolve({}); + try { + resolve(JSON.parse(raw)); + } catch (err) { + reject(err); + } + }); + req.on("error", reject); + }); +} + +type Handler = (req: IncomingMessage, res: ServerResponse, params: Record) => Promise | void; + +interface Route { + method: string; + pattern: RegExp; + paramNames: string[]; + handler: Handler; +} + +function route(method: string, path: string, handler: Handler): Route { + const paramNames: string[] = []; + const patternStr = path + .split("/") + .map((segment) => { + if (segment.startsWith(":")) { + paramNames.push(segment.slice(1)); + return "([^/]+)"; + } + return segment; + }) + .join("/"); + return { method, pattern: new RegExp(`^${patternStr}$`), paramNames, handler }; +} + +export function apiPlugin(): Plugin { + const routes: Route[] = [ + route("GET", "/api/portfolio", (_req, res) => { + send(res, 200, readJson("portfolio.json")); + }), + + route("GET", "/api/history", (_req, res) => { + send(res, 200, readJson("history.json")); + }), + + route("POST", "/api/history/snapshots", async (req, res) => { + const body = await readBody(req); + if (typeof body.date !== "string" || typeof body.marketValue !== "number") { + return send(res, 400, { error: "date (string) y marketValue (number) son obligatorios" }); + } + const history = readJson("history.json"); + const withoutSameDate = history.snapshots.filter((s) => s.date !== body.date); + const snapshots = [...withoutSameDate, { date: body.date, marketValue: body.marketValue }].sort((a, b) => + a.date.localeCompare(b.date), + ); + const next: History = { snapshots }; + writeJson("history.json", next); + send(res, 201, next); + }), + + route("DELETE", "/api/history/snapshots/:date", (_req, res, params) => { + const history = readJson("history.json"); + const snapshots = history.snapshots.filter((s) => s.date !== params.date); + const next: History = { snapshots }; + writeJson("history.json", next); + send(res, 200, next); + }), + + route("GET", "/api/contributions", (_req, res) => { + send(res, 200, readJson("contributions.json")); + }), + + route("POST", "/api/contributions/movements", async (req, res) => { + const body = await readBody(req); + if (typeof body.date !== "string" || typeof body.amount !== "number" || !body.kind) { + return send(res, 400, { error: "date, amount y kind son obligatorios" }); + } + const data = readJson("contributions.json"); + const movement: Movement = { + id: randomUUID(), + date: body.date, + kind: body.kind, + amount: body.amount, + description: body.description ?? undefined, + }; + data.movements = [...data.movements, movement].sort((a, b) => a.date.localeCompare(b.date)); + writeJson("contributions.json", data); + send(res, 201, movement); + }), + + route("DELETE", "/api/contributions/movements/:id", (_req, res, params) => { + const data = readJson("contributions.json"); + data.movements = data.movements.filter((m) => m.id !== params.id); + writeJson("contributions.json", data); + send(res, 200, data); + }), + + route("POST", "/api/contributions/plans", async (req, res) => { + const body = await readBody(req); + if (typeof body.amount !== "number" || !body.frequency || typeof body.startDate !== "string") { + return send(res, 400, { error: "amount, frequency y startDate son obligatorios" }); + } + const data = readJson("contributions.json"); + const plan: RecurringPlan = { + id: randomUUID(), + amount: body.amount, + frequency: body.frequency, + startDate: body.startDate, + endDate: body.endDate ?? undefined, + active: body.active ?? true, + note: body.note ?? undefined, + }; + data.recurringPlans = [...data.recurringPlans, plan]; + writeJson("contributions.json", data); + send(res, 201, plan); + }), + + route("PATCH", "/api/contributions/plans/:id", async (req, res, params) => { + const body = await readBody(req); + const data = readJson("contributions.json"); + const idx = data.recurringPlans.findIndex((p) => p.id === params.id); + if (idx === -1) return send(res, 404, { error: "Plan no encontrado" }); + data.recurringPlans[idx] = { ...data.recurringPlans[idx], ...body, id: params.id }; + writeJson("contributions.json", data); + send(res, 200, data.recurringPlans[idx]); + }), + + route("DELETE", "/api/contributions/plans/:id", (_req, res, params) => { + const data = readJson("contributions.json"); + data.recurringPlans = data.recurringPlans.filter((p) => p.id !== params.id); + writeJson("contributions.json", data); + send(res, 200, data); + }), + + route("GET", "/api/settings", (_req, res) => { + send(res, 200, readJson("settings.json")); + }), + + route("PUT", "/api/settings", async (req, res) => { + const body = await readBody(req); + const current = readJson("settings.json"); + const next: Settings = { ...current, ...body }; + writeJson("settings.json", next); + send(res, 200, next); + }), + + route("GET", "/api/sp500", (_req, res) => { + send(res, 200, readJson("sp500.json")); + }), + ]; + + const middleware: Connect.NextHandleFunction = (req, res, next) => { + if (!req.url?.startsWith("/api/")) return next(); + const [pathname] = req.url.split("?"); + const method = (req.method ?? "GET").toUpperCase(); + + for (const r of routes) { + if (r.method !== method) continue; + const match = r.pattern.exec(pathname); + if (!match) continue; + const params: Record = {}; + r.paramNames.forEach((name, i) => (params[name] = decodeURIComponent(match[i + 1]))); + Promise.resolve(r.handler(req, res, params)).catch((err) => { + console.error(err); + send(res, 500, { error: "Error interno del servidor", detail: String(err?.message ?? err) }); + }); + return; + } + + send(res, 404, { error: `Ruta no encontrada: ${method} ${pathname}` }); + }; + + return { + name: "local-json-api", + configureServer(server) { + server.middlewares.use(middleware); + }, + configurePreviewServer(server) { + server.middlewares.use(middleware); + }, + }; +} diff --git a/server/jsonStore.ts b/server/jsonStore.ts new file mode 100644 index 0000000..e62d255 --- /dev/null +++ b/server/jsonStore.ts @@ -0,0 +1,17 @@ +import { readFileSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; + +const DATA_DIR = join(process.cwd(), "data"); + +export function dataPath(file: string): string { + return join(DATA_DIR, file); +} + +export function readJson(file: string): T { + const raw = readFileSync(dataPath(file), "utf-8"); + return JSON.parse(raw) as T; +} + +export function writeJson(file: string, data: T): void { + writeFileSync(dataPath(file), JSON.stringify(data, null, 2) + "\n", "utf-8"); +} diff --git a/server/types.ts b/server/types.ts new file mode 100644 index 0000000..110f11e --- /dev/null +++ b/server/types.ts @@ -0,0 +1,86 @@ +export type AssetClass = "Renta Variable" | "Renta Fija" | "Liquidez"; + +export interface Holding { + name: string; + value: number; + changeAmount: number; + changePercent: number; + assetClass: AssetClass; + region: string; +} + +export interface Portfolio { + asOf: string; + cash: number; + invested: number; + marketValueChange: number; + marketValueChangePercent: number; + assetAllocation: Record; + holdings: Holding[]; +} + +export interface HistorySnapshot { + date: string; + marketValue: number; +} + +export interface History { + snapshots: HistorySnapshot[]; +} + +/** + * aportacion/retirada = external cash flow (bank <-> account) and count toward TWR/baseline math. + * suscripcion_fondo/reembolso_fondo = internal moves between cash and a fund; net-zero on total + * account value, so they're excluded from flow math but still shown in the movements ledger. + * apertura = informational account-opening marker. + */ +export type MovementKind = + | "aportacion" + | "retirada" + | "suscripcion_fondo" + | "reembolso_fondo" + | "apertura" + | "otro"; + +export interface Movement { + id: string; + date: string; + kind: MovementKind; + amount: number; + description?: string; +} + +export type Frequency = "weekly" | "biweekly" | "monthly" | "quarterly" | "yearly"; + +export interface RecurringPlan { + id: string; + amount: number; + frequency: Frequency; + startDate: string; + endDate?: string; + active: boolean; + note?: string; +} + +export interface Contributions { + recurringPlans: RecurringPlan[]; + movements: Movement[]; +} + +export interface Settings { + inceptionDate: string; + forecastYears: number; + returnAssumption: "historical" | "custom"; + customAnnualReturnPct?: number; +} + +export interface SP500Point { + date: string; + close: number; +} + +export interface SP500Data { + source: string; + updatedAt: string; + series: SP500Point[]; +} diff --git a/src/App.css b/src/App.css new file mode 100644 index 0000000..bc83a2b --- /dev/null +++ b/src/App.css @@ -0,0 +1,319 @@ +.app-shell { + max-width: 1180px; + margin: 0 auto; + padding: 24px 20px 64px; +} + +.app-header { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 16px; + margin-bottom: 20px; + flex-wrap: wrap; +} + +.app-title { + font-size: 22px; + letter-spacing: -0.2px; +} + +.app-subtitle { + color: var(--text-secondary); + font-size: 13px; + margin-top: 2px; +} + +.tabs { + display: flex; + gap: 4px; + background: var(--surface-1); + border: 1px solid var(--border); + border-radius: 10px; + padding: 4px; +} + +.tab { + border: none; + background: transparent; + padding: 8px 16px; + border-radius: 7px; + cursor: pointer; + font-size: 14px; + color: var(--text-secondary); +} + +.tab.active { + background: var(--series-1); + color: white; +} + +.card { + background: var(--surface-1); + border: 1px solid var(--border); + border-radius: 14px; + padding: 20px; +} + +.card + .card { + margin-top: 20px; +} + +.card-title { + font-size: 15px; + margin-bottom: 4px; +} + +.card-caption { + font-size: 12.5px; + color: var(--text-muted); + margin-bottom: 16px; +} + +.grid-2 { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 20px; +} + +@media (max-width: 760px) { + .grid-2 { + grid-template-columns: 1fr; + } +} + +.stat-row { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 16px; + margin-bottom: 20px; +} + +@media (max-width: 760px) { + .stat-row { + grid-template-columns: repeat(2, 1fr); + } +} + +.stat-tile { + background: var(--surface-1); + border: 1px solid var(--border); + border-radius: 14px; + padding: 16px 18px; +} + +.stat-label { + font-size: 12.5px; + color: var(--text-muted); + margin-bottom: 6px; +} + +.stat-value { + font-size: 22px; + font-variant-numeric: tabular-nums; +} + +.stat-delta { + font-size: 12.5px; + margin-top: 4px; + font-variant-numeric: tabular-nums; +} + +.stat-delta.good { + color: var(--success); +} + +.stat-delta.bad { + color: var(--danger); +} + +.state-message { + padding: 60px 20px; + text-align: center; + color: var(--text-secondary); +} + +.chart-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + flex-wrap: wrap; + margin-bottom: 12px; +} + +.period-buttons { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.period-btn { + border: 1px solid var(--border); + background: transparent; + color: var(--text-secondary); + padding: 6px 12px; + border-radius: 999px; + font-size: 12.5px; + cursor: pointer; +} + +.period-btn.active { + background: var(--series-1); + border-color: var(--series-1); + color: white; +} + +.legend-row { + display: flex; + flex-wrap: wrap; + gap: 14px; + font-size: 12.5px; + color: var(--text-secondary); + margin-top: 10px; +} + +.legend-item { + display: flex; + align-items: center; + gap: 6px; +} + +.legend-swatch { + width: 12px; + height: 12px; + border-radius: 3px; + flex-shrink: 0; +} + +.legend-swatch.dashed { + border: 1.5px dashed currentColor; + background: transparent; +} + +.movements-table th { + text-align: left; + font-size: 11.5px; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--text-muted); + padding: 8px 10px; + border-bottom: 1px solid var(--gridline); +} + +.movements-table td { + padding: 9px 10px; + border-bottom: 1px solid var(--gridline); + font-size: 13.5px; +} + +.movements-table tr:last-child td { + border-bottom: none; +} + +.amount { + font-variant-numeric: tabular-nums; + text-align: right; + white-space: nowrap; +} + +.tag { + display: inline-block; + font-size: 11px; + padding: 2px 8px; + border-radius: 999px; + background: var(--gridline); + color: var(--text-secondary); +} + +.tag.in { + background: color-mix(in srgb, var(--success) 16%, transparent); + color: var(--success); +} + +.tag.out { + background: color-mix(in srgb, var(--danger) 16%, transparent); + color: var(--danger); +} + +.form-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 12px; + align-items: end; +} + +.field { + display: flex; + flex-direction: column; + gap: 5px; +} + +.field label { + font-size: 12.5px; + color: var(--text-secondary); +} + +.field input, +.field select { + padding: 8px 10px; + border-radius: 8px; + border: 1px solid var(--border); + background: var(--page); + color: var(--text-primary); +} + +.btn { + padding: 9px 16px; + border-radius: 8px; + border: none; + background: var(--series-1); + color: white; + cursor: pointer; + font-size: 13.5px; +} + +.btn.secondary { + background: transparent; + border: 1px solid var(--border); + color: var(--text-primary); +} + +.btn.danger-ghost { + background: transparent; + border: none; + color: var(--text-muted); + padding: 4px 8px; + font-size: 12.5px; +} + +.btn.danger-ghost:hover { + color: var(--danger); +} + +.plan-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 0; + border-bottom: 1px solid var(--gridline); + gap: 12px; + flex-wrap: wrap; +} + +.plan-row:last-child { + border-bottom: none; +} + +.plan-meta { + font-size: 13px; + color: var(--text-secondary); +} + +.section-label { + font-size: 13px; + color: var(--text-muted); + margin: 24px 0 10px; + text-transform: uppercase; + letter-spacing: 0.05em; +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..4775021 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,38 @@ +import { useState } from "react"; +import "./App.css"; +import { useAppData } from "./hooks/useAppData.ts"; +import { Dashboard } from "./pages/Dashboard.tsx"; +import { ContributionsPanel } from "./pages/ContributionsPanel.tsx"; + +type Tab = "dashboard" | "contributions"; + +function App() { + const { data, loading, error, refresh } = useAppData(); + const [tab, setTab] = useState("dashboard"); + + return ( +
+
+
+

Mis inversiones

+

{data ? `Datos a ${data.portfolio.asOf}` : "Cargando…"}

+
+ +
+ + {loading &&
Cargando datos…
} + {error &&
Error cargando los datos: {error}
} + {data && tab === "dashboard" && } + {data && tab === "contributions" && } +
+ ); +} + +export default App; diff --git a/src/api/client.ts b/src/api/client.ts new file mode 100644 index 0000000..feee866 --- /dev/null +++ b/src/api/client.ts @@ -0,0 +1,38 @@ +import type { Contributions, History, Movement, Portfolio, RecurringPlan, SP500Data, Settings } from "../../server/types.ts"; + +async function request(path: string, init?: RequestInit): Promise { + const res = await fetch(path, { + ...init, + headers: { "Content-Type": "application/json", ...init?.headers }, + }); + if (!res.ok) { + const body = await res.json().catch(() => ({})); + throw new Error(body.error ?? `Error ${res.status} en ${path}`); + } + return res.json(); +} + +export const api = { + getPortfolio: () => request("/api/portfolio"), + getHistory: () => request("/api/history"), + addSnapshot: (date: string, marketValue: number) => + request("/api/history/snapshots", { method: "POST", body: JSON.stringify({ date, marketValue }) }), + removeSnapshot: (date: string) => request(`/api/history/snapshots/${encodeURIComponent(date)}`, { method: "DELETE" }), + + getContributions: () => request("/api/contributions"), + addMovement: (movement: Pick) => + request("/api/contributions/movements", { method: "POST", body: JSON.stringify(movement) }), + removeMovement: (id: string) => request(`/api/contributions/movements/${id}`, { method: "DELETE" }), + + addPlan: (plan: Omit) => + request("/api/contributions/plans", { method: "POST", body: JSON.stringify(plan) }), + updatePlan: (id: string, patch: Partial) => + request(`/api/contributions/plans/${id}`, { method: "PATCH", body: JSON.stringify(patch) }), + removePlan: (id: string) => request(`/api/contributions/plans/${id}`, { method: "DELETE" }), + + getSettings: () => request("/api/settings"), + updateSettings: (patch: Partial) => + request("/api/settings", { method: "PUT", body: JSON.stringify(patch) }), + + getSP500: () => request("/api/sp500"), +}; diff --git a/src/components/AllocationPie.tsx b/src/components/AllocationPie.tsx new file mode 100644 index 0000000..1dd8d90 --- /dev/null +++ b/src/components/AllocationPie.tsx @@ -0,0 +1,65 @@ +import { Cell, Pie, PieChart, ResponsiveContainer, Tooltip } from "recharts"; +import { categoricalColor } from "../lib/palette.ts"; +import { usePrefersDark } from "../hooks/usePrefersDark.ts"; + +export interface Slice { + name: string; + value: number; +} + +interface Props { + data: Slice[]; + valueFormatter?: (v: number) => string; +} + +function CustomTooltip({ active, payload, valueFormatter }: any) { + if (!active || !payload?.length) return null; + const p = payload[0]; + return ( +
+
{p.name}
+
{valueFormatter ? valueFormatter(p.value) : p.value}
+
+ ); +} + +export function AllocationPie({ data, valueFormatter }: Props) { + const dark = usePrefersDark(); + const total = data.reduce((s, d) => s + d.value, 0); + + return ( +
+ + + + {data.map((_, i) => ( + + ))} + + } /> + + +
+ {data.map((d, i) => ( +
+ + {d.name} + + {total > 0 ? `${((d.value / total) * 100).toFixed(1)}%` : "—"} + +
+ ))} +
+
+ ); +} diff --git a/src/components/ForecastChart.tsx b/src/components/ForecastChart.tsx new file mode 100644 index 0000000..0236513 --- /dev/null +++ b/src/components/ForecastChart.tsx @@ -0,0 +1,153 @@ +import { useMemo, useState } from "react"; +import { Brush, CartesianGrid, Line, LineChart, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis } from "recharts"; +import type { ChartSeriesPoint } from "../lib/finance.ts"; +import { addYears, parseISO, toISODate } from "../lib/dates.ts"; +import { formatDate, formatDateAxis, formatEUR, formatEURAxis } from "../lib/format.ts"; + +interface Props { + points: ChartSeriesPoint[]; + todayISO: string; + forecastYears: number; +} + +const SERIES_LABEL: Record = { + sp500Value: "Si hubieras invertido en el S&P 500", + portfolioValue: "Tu cartera", + portfolioForecastValue: "Tu cartera (previsión)", + baselineValue: "Aportado sin rendimiento (0%)", +}; + +function tsToISO(ts: number): string { + return new Date(ts).toISOString().slice(0, 10); +} + +function formatTsAxis(ts: number): string { + return formatDateAxis(tsToISO(ts)); +} + +function CustomTooltip({ active, payload, label }: any) { + if (!active || !payload?.length) return null; + return ( +
+
{formatDate(tsToISO(label))}
+ {payload + .filter((p: any) => p.value !== undefined && p.value !== null) + .map((p: any) => ( +
+ {SERIES_LABEL[p.dataKey]} + {formatEUR(p.value)} +
+ ))} +
+ ); +} + +export function ForecastChart({ points, todayISO, forecastYears }: Props) { + const today = useMemo(() => parseISO(todayISO), [todayISO]); + const [rangeYears, setRangeYears] = useState(Math.min(1, forecastYears)); + const [expanded, setExpanded] = useState(false); + + const presets = useMemo(() => { + const options = [{ label: "Histórico", years: 0 }]; + for (const y of [1, 5, 10]) { + if (y < forecastYears) options.push({ label: `+${y} año${y > 1 ? "s" : ""}`, years: y }); + } + options.push({ label: `Previsión completa (${forecastYears} años)`, years: forecastYears }); + return options; + }, [forecastYears]); + + const visiblePoints = useMemo(() => { + const cutoff = toISODate(addYears(today, rangeYears)); + return points.filter((p) => p.date <= cutoff); + }, [points, today, rangeYears]); + + return ( +
+
+
+ {presets.map((preset) => ( + + ))} +
+ +
+ + + + + + + } /> + + + + + + + + + + +
+ + + Si hubieras invertido tus aportaciones en el S&P 500 + + + + Tu cartera (real) + + + + Tu cartera (previsión, incluye aportaciones) + + + + Aportado sin rendimiento (0%) + +
+
+ ); +} diff --git a/src/components/MovementsList.tsx b/src/components/MovementsList.tsx new file mode 100644 index 0000000..6b54cbc --- /dev/null +++ b/src/components/MovementsList.tsx @@ -0,0 +1,73 @@ +import type { Movement, MovementKind } from "../../server/types.ts"; +import { formatDate, formatEUR } from "../lib/format.ts"; + +const KIND_LABEL: Record = { + aportacion: "Aportación", + retirada: "Retirada", + suscripcion_fondo: "Compra de fondo", + reembolso_fondo: "Venta de fondo", + apertura: "Apertura", + otro: "Otro", +}; + +const KIND_TAG: Record = { + aportacion: "in", + retirada: "out", + suscripcion_fondo: "", + reembolso_fondo: "", + apertura: "", + otro: "", +}; + +interface Props { + movements: Movement[]; + onDelete?: (id: string) => void; +} + +export function MovementsList({ movements, onDelete }: Props) { + const sorted = [...movements].sort((a, b) => b.date.localeCompare(a.date)); + + return ( +
+ + + + + + + + {onDelete && + + + {sorted.map((m) => ( + + + + + + {onDelete && ( + + )} + + ))} + {sorted.length === 0 && ( + + + + )} + +
FechaTipoDescripciónImporte} +
{formatDate(m.date)} + {KIND_LABEL[m.kind]} + {m.description ?? "—"}{formatEUR(m.amount)} + {m.kind === "aportacion" || m.kind === "retirada" ? ( + + ) : null} +
+ Todavía no hay movimientos +
+
+ ); +} diff --git a/src/hooks/useAppData.ts b/src/hooks/useAppData.ts new file mode 100644 index 0000000..288b998 --- /dev/null +++ b/src/hooks/useAppData.ts @@ -0,0 +1,48 @@ +import { useCallback, useEffect, useState } from "react"; +import { api } from "../api/client.ts"; +import type { Contributions, History, Portfolio, SP500Data, Settings } from "../../server/types.ts"; + +export interface AppData { + portfolio: Portfolio; + history: History; + contributions: Contributions; + settings: Settings; + sp500: SP500Data; +} + +interface UseAppData { + data: AppData | null; + loading: boolean; + error: string | null; + refresh: () => Promise; +} + +export function useAppData(): UseAppData { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + const refresh = useCallback(async () => { + try { + setError(null); + const [portfolio, history, contributions, settings, sp500] = await Promise.all([ + api.getPortfolio(), + api.getHistory(), + api.getContributions(), + api.getSettings(), + api.getSP500(), + ]); + setData({ portfolio, history, contributions, settings, sp500 }); + } catch (err) { + setError(err instanceof Error ? err.message : String(err)); + } finally { + setLoading(false); + } + }, []); + + useEffect(() => { + refresh(); + }, [refresh]); + + return { data, loading, error, refresh }; +} diff --git a/src/hooks/usePrefersDark.ts b/src/hooks/usePrefersDark.ts new file mode 100644 index 0000000..6780f46 --- /dev/null +++ b/src/hooks/usePrefersDark.ts @@ -0,0 +1,14 @@ +import { useEffect, useState } from "react"; + +export function usePrefersDark(): boolean { + const [dark, setDark] = useState(() => window.matchMedia?.("(prefers-color-scheme: dark)").matches ?? false); + + useEffect(() => { + const mql = window.matchMedia("(prefers-color-scheme: dark)"); + const onChange = (e: MediaQueryListEvent) => setDark(e.matches); + mql.addEventListener("change", onChange); + return () => mql.removeEventListener("change", onChange); + }, []); + + return dark; +} diff --git a/src/index.css b/src/index.css new file mode 100644 index 0000000..4628d1e --- /dev/null +++ b/src/index.css @@ -0,0 +1,110 @@ +:root { + color-scheme: light; + --surface-1: #fcfcfb; + --page: #f9f9f7; + --text-primary: #0b0b0b; + --text-secondary: #52514e; + --text-muted: #898781; + --gridline: #e1e0d9; + --baseline: #c3c2b7; + --border: rgba(11, 11, 11, 0.1); + --success: #006300; + --danger: #d03b3b; + + --series-1: #2a78d6; + --series-2: #eb6834; + --series-3: #1baf7a; + --series-4: #eda100; + --series-5: #e87ba4; + --series-6: #008300; + --series-7: #4a3aa7; + --series-8: #e34948; + + font: 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif; + color: var(--text-primary); + background: var(--page); + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +@media (prefers-color-scheme: dark) { + :root:where(:not([data-theme="light"])) { + color-scheme: dark; + --surface-1: #1a1a19; + --page: #0d0d0d; + --text-primary: #ffffff; + --text-secondary: #c3c2b7; + --text-muted: #898781; + --gridline: #2c2c2a; + --baseline: #383835; + --border: rgba(255, 255, 255, 0.1); + --success: #0ca30c; + --danger: #e66767; + + --series-1: #3987e5; + --series-2: #d95926; + --series-3: #199e70; + --series-4: #c98500; + --series-5: #d55181; + --series-6: #008300; + --series-7: #9085e9; + --series-8: #e66767; + } +} + +:root[data-theme="dark"] { + color-scheme: dark; + --surface-1: #1a1a19; + --page: #0d0d0d; + --text-primary: #ffffff; + --text-secondary: #c3c2b7; + --text-muted: #898781; + --gridline: #2c2c2a; + --baseline: #383835; + --border: rgba(255, 255, 255, 0.1); + --success: #0ca30c; + --danger: #e66767; + + --series-1: #3987e5; + --series-2: #d95926; + --series-3: #199e70; + --series-4: #c98500; + --series-5: #d55181; + --series-6: #008300; + --series-7: #9085e9; + --series-8: #e66767; +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; +} + +#root { + min-height: 100svh; +} + +h1, h2, h3 { + font-weight: 600; + margin: 0; + color: var(--text-primary); +} + +p { + margin: 0; +} + +button, input, select { + font: inherit; + color: inherit; +} + +table { + border-collapse: collapse; + width: 100%; +} diff --git a/src/lib/dates.ts b/src/lib/dates.ts new file mode 100644 index 0000000..f8b67ea --- /dev/null +++ b/src/lib/dates.ts @@ -0,0 +1,85 @@ +import type { Frequency } from "../../server/types.ts"; + +export function parseISO(iso: string): Date { + return new Date(`${iso}T00:00:00Z`); +} + +export function toISODate(d: Date): string { + return d.toISOString().slice(0, 10); +} + +export function daysBetween(a: string, b: string): number { + return Math.round((parseISO(b).getTime() - parseISO(a).getTime()) / 86_400_000); +} + +export function addInterval(date: Date, frequency: Frequency): Date { + const d = new Date(date.getTime()); + switch (frequency) { + case "weekly": + d.setUTCDate(d.getUTCDate() + 7); + return d; + case "biweekly": + d.setUTCDate(d.getUTCDate() + 14); + return d; + case "monthly": + return addMonths(d, 1); + case "quarterly": + return addMonths(d, 3); + case "yearly": + return addMonths(d, 12); + } +} + +function addMonths(date: Date, months: number): Date { + const day = date.getUTCDate(); + const d = new Date(date.getTime()); + d.setUTCDate(1); + d.setUTCMonth(d.getUTCMonth() + months); + const lastDayOfTargetMonth = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth() + 1, 0)).getUTCDate(); + d.setUTCDate(Math.min(day, lastDayOfTargetMonth)); + return d; +} + +export function addYears(date: Date, years: number): Date { + return addMonths(date, years * 12); +} + +function dedupeSorted(dates: Date[]): Date[] { + const uniqueByTime = new Map(dates.map((d) => [d.getTime(), d])); + return Array.from(uniqueByTime.values()).sort((a, b) => a.getTime() - b.getTime()); +} + +/** Fixed-day-count grid from `start` to `end` (inclusive), plus any `mustInclude` dates. */ +export function stepGrid(start: Date, end: Date, stepDays: number, mustInclude: Date[] = []): Date[] { + const dates: Date[] = []; + let cursor = new Date(start.getTime()); + while (cursor.getTime() < end.getTime()) { + dates.push(new Date(cursor.getTime())); + cursor = new Date(cursor.getTime() + stepDays * 86_400_000); + } + dates.push(new Date(end.getTime())); + for (const d of mustInclude) { + if (d.getTime() >= start.getTime() && d.getTime() <= end.getTime()) dates.push(d); + } + return dedupeSorted(dates); +} + +/** Monthly grid from `start` to `end` (inclusive), plus `mustInclude` dates (e.g. "today"). */ +export function monthlyGrid(start: Date, end: Date, mustInclude: Date[] = []): Date[] { + const dates: Date[] = []; + let cursor = new Date(start.getTime()); + while (cursor.getTime() < end.getTime()) { + dates.push(new Date(cursor.getTime())); + cursor = addMonths(cursor, 1); + } + dates.push(new Date(end.getTime())); + for (const d of mustInclude) { + if (d.getTime() >= start.getTime() && d.getTime() <= end.getTime()) dates.push(d); + } + return dedupeSorted(dates); +} + +/** Merges and dedupes several date arrays into one sorted grid. */ +export function mergeGrids(...grids: Date[][]): Date[] { + return dedupeSorted(grids.flat()); +} diff --git a/src/lib/finance.ts b/src/lib/finance.ts new file mode 100644 index 0000000..ba6ef03 --- /dev/null +++ b/src/lib/finance.ts @@ -0,0 +1,213 @@ +import type { History, Movement, RecurringPlan, SP500Point, Settings } from "../../server/types.ts"; +import { addInterval, daysBetween, mergeGrids, monthlyGrid, parseISO, stepGrid, toISODate } from "./dates.ts"; + +/** Only external cash flows count as "capital aportado"; internal fund + * subscriptions/redemptions and the opening marker net to zero on total account value. */ +function signedAmount(m: Movement): number { + if (m.kind === "aportacion") return m.amount; + if (m.kind === "retirada") return -m.amount; + return 0; +} + +export interface ProjectedFlow { + date: string; + amount: number; +} + +/** Future cash flows implied by active recurring plans, strictly after `fromExclusive`. */ +export function projectFutureFlows(plans: RecurringPlan[], fromExclusive: Date, toInclusive: Date): ProjectedFlow[] { + const flows: ProjectedFlow[] = []; + for (const plan of plans) { + if (!plan.active) continue; + const planEnd = plan.endDate ? parseISO(plan.endDate) : toInclusive; + const horizon = planEnd.getTime() < toInclusive.getTime() ? planEnd : toInclusive; + let occurrence = parseISO(plan.startDate); + // Fast-forward to the first occurrence after `fromExclusive` without an unbounded loop. + while (occurrence.getTime() <= fromExclusive.getTime()) { + occurrence = addInterval(occurrence, plan.frequency); + } + while (occurrence.getTime() <= horizon.getTime()) { + flows.push({ date: toISODate(occurrence), amount: plan.amount }); + occurrence = addInterval(occurrence, plan.frequency); + } + } + return flows; +} + +/** Cumulative net contributions (capital aportado) at date `t`: real movements up to + * `t`, plus projected recurring flows for any `t` beyond today. */ +export function cumulativeContributionsAt( + t: Date, + movements: Movement[], + projectedFlows: ProjectedFlow[], +): number { + const iso = toISODate(t); + let total = 0; + for (const m of movements) if (m.date <= iso) total += signedAmount(m); + for (const f of projectedFlows) if (f.date <= iso) total += f.amount; + return total; +} + +export interface GainPoint { + date: string; + /** valor total / capital aportado at this snapshot. 1 = break-even. */ + gainRatio: number; +} + +/** Simple money-weighted return at each snapshot: valor total vs. capital aportado + * to date, no per-period flow chaining. */ +export function computeGainSeries(history: History, movements: Movement[]): GainPoint[] { + const snapshots = [...history.snapshots].sort((a, b) => a.date.localeCompare(b.date)); + return snapshots.map((s) => { + const contributed = cumulativeContributionsAt(parseISO(s.date), movements, []); + return { date: s.date, gainRatio: contributed > 0 ? s.marketValue / contributed : 1 }; + }); +} + +/** Annualized rate implied by the overall gain from the first to the last snapshot. */ +export function annualizedRate(gainSeries: GainPoint[]): number { + if (gainSeries.length < 2) return 0; + const first = gainSeries[0]; + const last = gainSeries[gainSeries.length - 1]; + const years = daysBetween(first.date, last.date) / 365.25; + if (years <= 0 || first.gainRatio <= 0) return 0; + return Math.pow(last.gainRatio / first.gainRatio, 1 / years) - 1; +} + +function interpolateGainRatio(gainSeries: GainPoint[], date: Date): number { + const t = date.getTime(); + if (t <= parseISO(gainSeries[0].date).getTime()) return gainSeries[0].gainRatio; + for (let i = 1; i < gainSeries.length; i++) { + const prevT = parseISO(gainSeries[i - 1].date).getTime(); + const curT = parseISO(gainSeries[i].date).getTime(); + if (t <= curT) { + const frac = curT === prevT ? 1 : (t - prevT) / (curT - prevT); + return gainSeries[i - 1].gainRatio + frac * (gainSeries[i].gainRatio - gainSeries[i - 1].gainRatio); + } + } + return gainSeries[gainSeries.length - 1].gainRatio; +} + +/** Portfolio € value at any historical date: capital aportado to date, scaled by the + * gain ratio (valor total / aportado) interpolated between the surrounding snapshots. */ +function portfolioValueAt(t: Date, movements: Movement[], gainSeries: GainPoint[]): number { + const contributed = cumulativeContributionsAt(t, movements, []); + return contributed * interpolateGainRatio(gainSeries, t); +} + +/** € value at `t` if every external flow up to `t` had instead been invested in the + * S&P 500 on the day it happened (a "same contributions, different fund" benchmark). */ +function sp500BenchmarkValueAt(t: Date, movements: Movement[], sp500: SP500Point[]): number | undefined { + const iso = toISODate(t); + let units = 0; + for (const m of movements) { + if (m.date > iso) continue; + const amount = signedAmount(m); + if (amount === 0) continue; + const price = closestClose(sp500, m.date); + if (!price) continue; + units += amount / price; + } + const priceNow = closestClose(sp500, iso); + if (!priceNow) return undefined; + return units * priceNow; +} + +function closestClose(series: SP500Point[], iso: string): number | undefined { + let before: SP500Point | undefined; + let after: SP500Point | undefined; + for (const p of series) { + if (p.date <= iso) before = p; + if (p.date >= iso && !after) after = p; + } + return (before ?? after)?.close; +} + +export interface ChartSeriesPoint { + date: string; + /** Epoch ms, for a genuine time-scale X axis — a category axis would space points + * by index instead of by elapsed time, which distorts the mixed daily/monthly grid. */ + ts: number; + sp500Value?: number; + portfolioValue?: number; + portfolioForecastValue?: number; + baselineValue: number; +} + +export interface ForecastResult { + points: ChartSeriesPoint[]; + annualizedHistoricalRatePct: number; + assumedForecastRatePct: number; +} + +export function buildForecast( + history: History, + contributions: { movements: Movement[]; recurringPlans: RecurringPlan[] }, + sp500: SP500Point[], + settings: Settings, + todayRaw: Date = new Date(), +): ForecastResult { + // Normalize to midnight UTC so "today" collapses onto the same grid point as other + // dates (parsed from date-only ISO strings) instead of surviving as a near-duplicate. + const today = parseISO(toISODate(todayRaw)); + const gainSeries = computeGainSeries(history, contributions.movements); + const inception = parseISO(settings.inceptionDate); + const forecastEnd = new Date(today.getTime()); + forecastEnd.setUTCFullYear(forecastEnd.getUTCFullYear() + settings.forecastYears); + + const historicalRate = annualizedRate(gainSeries); + const forecastRate = + settings.returnAssumption === "custom" && typeof settings.customAnnualReturnPct === "number" + ? settings.customAnnualReturnPct / 100 + : historicalRate; + + const lastSnapshot = history.snapshots[history.snapshots.length - 1]; + const lastSnapshotDate = parseISO(lastSnapshot.date); + + const projectedFlows = projectFutureFlows(contributions.recurringPlans, today, forecastEnd); + + // The historical window is usually tiny compared to the multi-year forecast — a + // uniform monthly grid would collapse it to 1-2 points and hide the S&P/portfolio + // comparison. Use finer steps there (daily/weekly/monthly depending on span) and + // keep the forecast segment on a monthly cadence. + const historicalSpanDays = daysBetween(settings.inceptionDate, lastSnapshot.date); + const historicalStepDays = historicalSpanDays <= 120 ? 1 : historicalSpanDays <= 730 ? 7 : 30; + const historicalGrid = stepGrid(inception, lastSnapshotDate, historicalStepDays, [lastSnapshotDate]); + const forecastGrid = monthlyGrid(lastSnapshotDate, forecastEnd, [today]); + const grid = mergeGrids(historicalGrid, forecastGrid); + + const points: ChartSeriesPoint[] = grid.map((d) => { + const iso = toISODate(d); + const isFuture = d.getTime() > lastSnapshotDate.getTime(); + + let portfolioValue: number | undefined; + let portfolioForecastValue: number | undefined; + if (!isFuture) { + portfolioValue = portfolioValueAt(d, contributions.movements, gainSeries); + } else { + const years = daysBetween(lastSnapshot.date, iso) / 365.25; + const growthOfCurrentValue = lastSnapshot.marketValue * Math.pow(1 + forecastRate, years); + const growthOfFutureFlows = projectedFlows + .filter((f) => f.date <= iso) + .reduce((sum, f) => { + const flowYears = daysBetween(f.date, iso) / 365.25; + return sum + f.amount * Math.pow(1 + forecastRate, flowYears); + }, 0); + portfolioForecastValue = growthOfCurrentValue + growthOfFutureFlows; + } + // Bridge the two segments so the line is visually continuous at "today". + if (d.getTime() === lastSnapshotDate.getTime()) portfolioForecastValue = portfolioValue; + + const sp500Value = !isFuture ? sp500BenchmarkValueAt(d, contributions.movements, sp500) : undefined; + + const baselineValue = cumulativeContributionsAt(d, contributions.movements, projectedFlows); + + return { date: iso, ts: d.getTime(), sp500Value, portfolioValue, portfolioForecastValue, baselineValue }; + }); + + return { + points, + annualizedHistoricalRatePct: historicalRate * 100, + assumedForecastRatePct: forecastRate * 100, + }; +} diff --git a/src/lib/format.ts b/src/lib/format.ts new file mode 100644 index 0000000..48dcd55 --- /dev/null +++ b/src/lib/format.ts @@ -0,0 +1,49 @@ +export function formatEUR(value: number): string { + return new Intl.NumberFormat("es-ES", { style: "currency", currency: "EUR", maximumFractionDigits: 2 }).format( + value, + ); +} + +export function formatEURCompact(value: number): string { + return new Intl.NumberFormat("es-ES", { + style: "currency", + currency: "EUR", + notation: "compact", + maximumFractionDigits: 1, + }).format(value); +} + +/** Short axis-tick label ("140k €", "8,6k €"). Deliberately narrower than + * `formatEURCompact`'s "mil"/"M" wording, which reads ambiguous at small tick widths. */ +export function formatEURAxis(value: number): string { + const abs = Math.abs(value); + if (abs >= 1_000_000) { + return `${(value / 1_000_000).toLocaleString("es-ES", { maximumFractionDigits: 1 })}M €`; + } + if (abs >= 1_000) { + return `${(value / 1_000).toLocaleString("es-ES", { maximumFractionDigits: 1 })}k €`; + } + return `${Math.round(value)} €`; +} + +export function formatPct(value: number, digits = 1): string { + const sign = value > 0 ? "+" : ""; + return `${sign}${value.toFixed(digits)}%`; +} + +export function formatDate(iso: string): string { + return new Intl.DateTimeFormat("es-ES", { day: "2-digit", month: "short", year: "numeric" }).format( + new Date(`${iso}T00:00:00Z`), + ); +} + +export function formatDateShort(iso: string): string { + return new Intl.DateTimeFormat("es-ES", { day: "2-digit", month: "short" }).format(new Date(`${iso}T00:00:00Z`)); +} + +/** Compact axis-tick label that still carries the year ("14 ago 26"). */ +export function formatDateAxis(iso: string): string { + return new Intl.DateTimeFormat("es-ES", { day: "2-digit", month: "short", year: "2-digit" }).format( + new Date(`${iso}T00:00:00Z`), + ); +} diff --git a/src/lib/palette.ts b/src/lib/palette.ts new file mode 100644 index 0000000..dad3112 --- /dev/null +++ b/src/lib/palette.ts @@ -0,0 +1,31 @@ +// Reference categorical palette from the dataviz skill — fixed hue order, never cycled. +export const CATEGORICAL_LIGHT = [ + "#2a78d6", // 1 blue + "#eb6834", // 2 orange + "#1baf7a", // 3 aqua + "#eda100", // 4 yellow + "#e87ba4", // 5 magenta + "#008300", // 6 green + "#4a3aa7", // 7 violet + "#e34948", // 8 red +]; + +export const CATEGORICAL_DARK = [ + "#3987e5", + "#d95926", + "#199e70", + "#c98500", + "#d55181", + "#008300", + "#9085e9", + "#e66767", +]; + +export function categoricalColor(index: number, dark: boolean): string { + const ramp = dark ? CATEGORICAL_DARK : CATEGORICAL_LIGHT; + return ramp[index % ramp.length]; +} + +export function prefersDark(): boolean { + return typeof window !== "undefined" && window.matchMedia?.("(prefers-color-scheme: dark)").matches; +} diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..bef5202 --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,10 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import './index.css' +import App from './App.tsx' + +createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/src/pages/ContributionsPanel.tsx b/src/pages/ContributionsPanel.tsx new file mode 100644 index 0000000..4847ebf --- /dev/null +++ b/src/pages/ContributionsPanel.tsx @@ -0,0 +1,225 @@ +import { useState } from "react"; +import type { AppData } from "../hooks/useAppData.ts"; +import { api } from "../api/client.ts"; +import type { Frequency, MovementKind } from "../../server/types.ts"; +import { formatDate, formatEUR } from "../lib/format.ts"; +import { MovementsList } from "../components/MovementsList.tsx"; +import { toISODate } from "../lib/dates.ts"; + +const FREQUENCY_LABEL: Record = { + weekly: "Semanal", + biweekly: "Quincenal", + monthly: "Mensual", + quarterly: "Trimestral", + yearly: "Anual", +}; + +export function ContributionsPanel({ data, onRefresh }: { data: AppData; onRefresh: () => Promise }) { + const { contributions, settings } = data; + + const [movDate, setMovDate] = useState(toISODate(new Date())); + const [movKind, setMovKind] = useState("aportacion"); + const [movAmount, setMovAmount] = useState(""); + const [movDesc, setMovDesc] = useState(""); + const [savingMov, setSavingMov] = useState(false); + + const [planAmount, setPlanAmount] = useState(""); + const [planFrequency, setPlanFrequency] = useState("monthly"); + const [planStart, setPlanStart] = useState(toISODate(new Date())); + const [planNote, setPlanNote] = useState(""); + const [savingPlan, setSavingPlan] = useState(false); + + const [inceptionDate, setInceptionDate] = useState(settings.inceptionDate); + const [forecastYears, setForecastYears] = useState(String(settings.forecastYears)); + const [returnAssumption, setReturnAssumption] = useState(settings.returnAssumption); + const [customRate, setCustomRate] = useState(String(settings.customAnnualReturnPct ?? 7)); + const [savingSettings, setSavingSettings] = useState(false); + + async function submitMovement(e: React.FormEvent) { + e.preventDefault(); + const amount = Number(movAmount); + if (!amount || amount <= 0) return; + setSavingMov(true); + try { + await api.addMovement({ date: movDate, kind: movKind, amount, description: movDesc || undefined }); + setMovAmount(""); + setMovDesc(""); + await onRefresh(); + } finally { + setSavingMov(false); + } + } + + async function submitPlan(e: React.FormEvent) { + e.preventDefault(); + const amount = Number(planAmount); + if (!amount || amount <= 0) return; + setSavingPlan(true); + try { + await api.addPlan({ amount, frequency: planFrequency, startDate: planStart, active: true, note: planNote || undefined }); + setPlanAmount(""); + setPlanNote(""); + await onRefresh(); + } finally { + setSavingPlan(false); + } + } + + async function togglePlan(id: string, active: boolean) { + await api.updatePlan(id, { active: !active }); + await onRefresh(); + } + + async function deletePlan(id: string) { + await api.removePlan(id); + await onRefresh(); + } + + async function deleteMovement(id: string) { + await api.removeMovement(id); + await onRefresh(); + } + + async function saveSettings(e: React.FormEvent) { + e.preventDefault(); + setSavingSettings(true); + try { + await api.updateSettings({ + inceptionDate, + forecastYears: Number(forecastYears) || 1, + returnAssumption, + customAnnualReturnPct: Number(customRate) || 0, + }); + await onRefresh(); + } finally { + setSavingSettings(false); + } + } + + return ( +
+
+
Nueva aportación o retirada
+
Registra un movimiento puntual de dinero entre tu banco y la cartera
+
+
+ + setMovDate(e.target.value)} required /> +
+
+ + +
+
+ + setMovAmount(e.target.value)} required /> +
+
+ + setMovDesc(e.target.value)} placeholder="p. ej. paga extra" /> +
+ +
+
+ +
+
Aportación recurrente
+
Define un plan periódico (semanal, mensual…) que se usará para proyectar la previsión
+
+
+ + setPlanAmount(e.target.value)} required /> +
+
+ + +
+
+ + setPlanStart(e.target.value)} required /> +
+
+ + setPlanNote(e.target.value)} placeholder="p. ej. nómina" /> +
+ +
+ + {contributions.recurringPlans.length > 0 && ( +
+ {contributions.recurringPlans.map((plan) => ( +
+
+ {formatEUR(plan.amount)}{" "} + + {FREQUENCY_LABEL[plan.frequency]} · desde {formatDate(plan.startDate)} + {plan.note ? ` · ${plan.note}` : ""} + +
+
+ {plan.active ? "Activo" : "Pausado"} + + +
+
+ ))} +
+ )} +
+ +
+
Ajustes de previsión
+
Fecha de inicio de la cartera, horizonte y rentabilidad asumida para la parte proyectada del gráfico
+
+
+ + setInceptionDate(e.target.value)} required /> +
+
+ + setForecastYears(e.target.value)} required /> +
+
+ + +
+ {returnAssumption === "custom" && ( +
+ + setCustomRate(e.target.value)} /> +
+ )} + +
+
+ +
+
Movimientos
+
Puedes borrar aportaciones o retiradas registradas manualmente
+ +
+
+ ); +} diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx new file mode 100644 index 0000000..adb9408 --- /dev/null +++ b/src/pages/Dashboard.tsx @@ -0,0 +1,100 @@ +import { useMemo } from "react"; +import type { AppData } from "../hooks/useAppData.ts"; +import { buildForecast } from "../lib/finance.ts"; +import { toISODate } from "../lib/dates.ts"; +import { formatEUR, formatPct } from "../lib/format.ts"; +import { ForecastChart } from "../components/ForecastChart.tsx"; +import { AllocationPie } from "../components/AllocationPie.tsx"; +import { MovementsList } from "../components/MovementsList.tsx"; + +const TOP_HOLDINGS = 7; + +export function Dashboard({ data }: { data: AppData }) { + const { portfolio, history, contributions, settings, sp500 } = data; + const today = useMemo(() => new Date(), []); + + const forecast = useMemo( + () => buildForecast(history, contributions, sp500.series, settings, today), + [history, contributions, sp500, settings, today], + ); + + const totalValue = portfolio.holdings.reduce((s, h) => s + h.value, 0) + portfolio.cash; + const totalContributed = portfolio.invested + portfolio.cash; + const currentReturnPct = totalContributed > 0 ? ((totalValue - totalContributed) / totalContributed) * 100 : 0; + const historyDays = history.snapshots.length >= 2 + ? Math.round((new Date(history.snapshots[history.snapshots.length - 1].date).getTime() - new Date(history.snapshots[0].date).getTime()) / 86_400_000) + : 0; + + const holdingsPie = useMemo(() => { + const sorted = [...portfolio.holdings].sort((a, b) => b.value - a.value); + const top = sorted.slice(0, TOP_HOLDINGS).map((h) => ({ name: h.name, value: h.value })); + const restTotal = sorted.slice(TOP_HOLDINGS).reduce((s, h) => s + h.value, 0); + return restTotal > 0 ? [...top, { name: "Otros", value: restTotal }] : top; + }, [portfolio.holdings]); + + const allocationPie = useMemo( + () => Object.entries(portfolio.assetAllocation).map(([name, value]) => ({ name, value })), + [portfolio.assetAllocation], + ); + + return ( +
+
+
+
Valor total
+
{formatEUR(totalValue)}
+
+
+
Aportado
+
{formatEUR(totalContributed)}
+
+
+
Rendimiento
+
= 0 ? "" : ""}`}>{formatPct(currentReturnPct)}
+
= 0 ? "good" : "bad"}`}> + {formatEUR(portfolio.marketValueChange)} desde el inicio +
+
+
+
Previsión anual asumida
+
{formatPct(forecast.assumedForecastRatePct)}
+ {settings.returnAssumption === "historical" && ( +
basada en {historyDays} días de histórico
+ )} +
+
+ +
+
Previsión de la cartera
+
+ Valor de la cartera en euros (aportaciones incluidas) desde el inicio, comparado con qué habría pasado + invirtiendo esas mismas aportaciones en el S&P 500, y proyectado a {settings.forecastYears} años vista + con las aportaciones programadas. + {historyDays > 0 && historyDays < 90 && ( + <> Aviso: con solo {historyDays} días de histórico la previsión es poco fiable — añade más puntos de historial con el tiempo. + )} +
+ +
+ +
+
+
Activos por fondo
+
Peso de cada fondo sobre el valor invertido
+ +
+
+
Renta variable vs. renta fija
+
Distribución por tipo de activo
+ `${v.toFixed(2)}%`} /> +
+
+ +
+
Movimientos
+
Historial completo de la cartera
+ +
+
+ ); +} diff --git a/tsconfig.app.json b/tsconfig.app.json new file mode 100644 index 0000000..6830b6f --- /dev/null +++ b/tsconfig.app.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "es2023", + "lib": ["ES2023", "DOM"], + "module": "esnext", + "types": ["vite/client"], + "allowArbitraryExtensions": true, + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..8455dcb --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "es2023", + "lib": ["ES2023"], + "types": ["node"], + "skipLibCheck": true, + + /* Bundler mode */ + "module": "nodenext", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..5f4d5b7 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,8 @@ +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite' +import { apiPlugin } from './server/apiPlugin.ts' + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), apiPlugin()], +})