mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-01 01:50:00 -07:00
general: snapshot
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
export const xthCohorts = [
|
||||
{
|
||||
id: "sth",
|
||||
key: "sth",
|
||||
name: "Short Term Holders",
|
||||
legend: "STH",
|
||||
},
|
||||
{
|
||||
id: "lth",
|
||||
key: "lth",
|
||||
name: "Long Term Holders",
|
||||
legend: "LTH",
|
||||
@@ -12,75 +14,86 @@ export const xthCohorts = [
|
||||
] as const;
|
||||
|
||||
export const upToCohorts = [
|
||||
{ key: "up_to_1d", name: "Up To 1 Day", legend: "1D" },
|
||||
{ key: "up_to_1w", name: "Up To 1 Week", legend: "1W" },
|
||||
{ key: "up_to_1m", name: "Up To 1 Month", legend: "1M" },
|
||||
{ key: "up_to_2m", name: "Up To 2 Months", legend: "2M" },
|
||||
{ key: "up_to_3m", name: "Up To 3 Months", legend: "3M" },
|
||||
{ key: "up_to_4m", name: "Up To 4 Months", legend: "4M" },
|
||||
{ key: "up_to_5m", name: "Up To 5 Months", legend: "5M" },
|
||||
{ key: "up_to_6m", name: "Up To 6 Months", legend: "6M" },
|
||||
{ key: "up_to_1y", name: "Up To 1 Year", legend: "1Y" },
|
||||
{ key: "up_to_2y", name: "Up To 2 Years", legend: "2Y" },
|
||||
{ key: "up_to_3y", name: "Up To 3 Years", legend: "3Y" },
|
||||
{ key: "up_to_5y", name: "Up To 5 Years", legend: "5Y" },
|
||||
{ key: "up_to_7y", name: "Up To 7 Years", legend: "7Y" },
|
||||
{ key: "up_to_10y", name: "Up To 10 Years", legend: "10Y" },
|
||||
{ key: "up_to_15y", name: "Up To 15 Years", legend: "15Y" },
|
||||
{ id: "up-to-1d", key: "up_to_1d", name: "Up To 1 Day", legend: "1D" },
|
||||
{ id: "up-to-1w", key: "up_to_1w", name: "Up To 1 Week", legend: "1W" },
|
||||
{ id: "up-to-1m", key: "up_to_1m", name: "Up To 1 Month", legend: "1M" },
|
||||
{ id: "up-to-2m", key: "up_to_2m", name: "Up To 2 Months", legend: "2M" },
|
||||
{ id: "up-to-3m", key: "up_to_3m", name: "Up To 3 Months", legend: "3M" },
|
||||
{ id: "up-to-4m", key: "up_to_4m", name: "Up To 4 Months", legend: "4M" },
|
||||
{ id: "up-to-5m", key: "up_to_5m", name: "Up To 5 Months", legend: "5M" },
|
||||
{ id: "up-to-6m", key: "up_to_6m", name: "Up To 6 Months", legend: "6M" },
|
||||
{ id: "up-to-1y", key: "up_to_1y", name: "Up To 1 Year", legend: "1Y" },
|
||||
{ id: "up-to-2y", key: "up_to_2y", name: "Up To 2 Years", legend: "2Y" },
|
||||
{ id: "up-to-3y", key: "up_to_3y", name: "Up To 3 Years", legend: "3Y" },
|
||||
{ id: "up-to-5y", key: "up_to_5y", name: "Up To 5 Years", legend: "5Y" },
|
||||
{ id: "up-to-7y", key: "up_to_7y", name: "Up To 7 Years", legend: "7Y" },
|
||||
{ id: "up-to-10y", key: "up_to_10y", name: "Up To 10 Years", legend: "10Y" },
|
||||
{ id: "up-to-15y", key: "up_to_15y", name: "Up To 15 Years", legend: "15Y" },
|
||||
] as const;
|
||||
|
||||
export const fromXToYCohorts = [
|
||||
{
|
||||
id: "from-1d-to-1w",
|
||||
key: "from_1d_to_1w",
|
||||
name: "From 1 Day To 1 Week",
|
||||
legend: "1D - 1W",
|
||||
},
|
||||
{
|
||||
id: "from-1w-to-1m",
|
||||
key: "from_1w_to_1m",
|
||||
name: "From 1 Week To 1 Month",
|
||||
legend: "1W - 1M",
|
||||
},
|
||||
{
|
||||
id: "from-1m-to-3m",
|
||||
key: "from_1m_to_3m",
|
||||
name: "From 1 Month To 3 Months",
|
||||
legend: "1M - 3M",
|
||||
},
|
||||
{
|
||||
id: "from-3m-to-6m",
|
||||
key: "from_3m_to_6m",
|
||||
name: "From 3 Months To 6 Months",
|
||||
legend: "3M - 6M",
|
||||
},
|
||||
{
|
||||
id: "from-6m-to-1y",
|
||||
key: "from_6m_to_1y",
|
||||
name: "From 6 Months To 1 Year",
|
||||
legend: "6M - 1Y",
|
||||
},
|
||||
{
|
||||
id: "from-1y-to-2y",
|
||||
key: "from_1y_to_2y",
|
||||
name: "From 1 Year To 2 Years",
|
||||
legend: "1Y - 2Y",
|
||||
},
|
||||
{
|
||||
id: "from-2y-to-3y",
|
||||
key: "from_2y_to_3y",
|
||||
name: "From 2 Years To 3 Years",
|
||||
legend: "2Y - 3Y",
|
||||
},
|
||||
{
|
||||
id: "from-3y-to-5y",
|
||||
key: "from_3y_to_5y",
|
||||
name: "From 3 Years To 5 Years",
|
||||
legend: "3Y - 5Y",
|
||||
},
|
||||
{
|
||||
id: "from-5y-to-7y",
|
||||
key: "from_5y_to_7y",
|
||||
name: "From 5 Years To 7 Years",
|
||||
legend: "5Y - 7Y",
|
||||
},
|
||||
{
|
||||
id: "from-7y-to-10y",
|
||||
key: "from_7y_to_10y",
|
||||
name: "From 7 Years To 10 Years",
|
||||
legend: "7Y - 10Y",
|
||||
},
|
||||
{
|
||||
id: "from-10y-to-15y",
|
||||
key: "from_10y_to_15y",
|
||||
name: "From 10 Years To 15 Years",
|
||||
legend: "10Y - 15Y",
|
||||
@@ -89,26 +102,31 @@ export const fromXToYCohorts = [
|
||||
|
||||
export const fromXCohorts = [
|
||||
{
|
||||
id: "from-1y",
|
||||
key: "from_1y",
|
||||
name: "From 1 Year",
|
||||
legend: "1Y+",
|
||||
},
|
||||
{
|
||||
id: "from-2y",
|
||||
key: "from_2y",
|
||||
name: "From 2 Years",
|
||||
legend: "2Y+",
|
||||
},
|
||||
{
|
||||
id: "from-4y",
|
||||
key: "from_4y",
|
||||
name: "From 4 Years",
|
||||
legend: "4Y+",
|
||||
},
|
||||
{
|
||||
id: "from-10y",
|
||||
key: "from_10y",
|
||||
name: "From 10 Years",
|
||||
legend: "10Y+",
|
||||
},
|
||||
{
|
||||
id: "from-15y",
|
||||
key: "from_15y",
|
||||
name: "From 15 Years",
|
||||
legend: "15Y+",
|
||||
@@ -116,27 +134,28 @@ export const fromXCohorts = [
|
||||
] as const;
|
||||
|
||||
export const yearCohorts = [
|
||||
{ key: "year_2009", name: "2009" },
|
||||
{ key: "year_2010", name: "2010" },
|
||||
{ key: "year_2011", name: "2011" },
|
||||
{ key: "year_2012", name: "2012" },
|
||||
{ key: "year_2013", name: "2013" },
|
||||
{ key: "year_2014", name: "2014" },
|
||||
{ key: "year_2015", name: "2015" },
|
||||
{ key: "year_2016", name: "2016" },
|
||||
{ key: "year_2017", name: "2017" },
|
||||
{ key: "year_2018", name: "2018" },
|
||||
{ key: "year_2019", name: "2019" },
|
||||
{ key: "year_2020", name: "2020" },
|
||||
{ key: "year_2021", name: "2021" },
|
||||
{ key: "year_2022", name: "2022" },
|
||||
{ key: "year_2023", name: "2023" },
|
||||
{ key: "year_2024", name: "2024" },
|
||||
{ id: "year-2009", key: "year_2009", name: "2009" },
|
||||
{ id: "year-2010", key: "year_2010", name: "2010" },
|
||||
{ id: "year-2011", key: "year_2011", name: "2011" },
|
||||
{ id: "year-2012", key: "year_2012", name: "2012" },
|
||||
{ id: "year-2013", key: "year_2013", name: "2013" },
|
||||
{ id: "year-2014", key: "year_2014", name: "2014" },
|
||||
{ id: "year-2015", key: "year_2015", name: "2015" },
|
||||
{ id: "year-2016", key: "year_2016", name: "2016" },
|
||||
{ id: "year-2017", key: "year_2017", name: "2017" },
|
||||
{ id: "year-2018", key: "year_2018", name: "2018" },
|
||||
{ id: "year-2019", key: "year_2019", name: "2019" },
|
||||
{ id: "year-2020", key: "year_2020", name: "2020" },
|
||||
{ id: "year-2021", key: "year_2021", name: "2021" },
|
||||
{ id: "year-2022", key: "year_2022", name: "2022" },
|
||||
{ id: "year-2023", key: "year_2023", name: "2023" },
|
||||
{ id: "year-2024", key: "year_2024", name: "2024" },
|
||||
] as const;
|
||||
|
||||
export const ageCohorts = [
|
||||
{
|
||||
key: "",
|
||||
id: "",
|
||||
name: "",
|
||||
},
|
||||
...xthCohorts,
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
export const liquidities = [
|
||||
{
|
||||
key: "illiquid",
|
||||
id: "illiquid",
|
||||
name: "Illiquid",
|
||||
},
|
||||
{ key: "liquid", name: "Liquid" },
|
||||
{ key: "liquid", id: "liquid", name: "Liquid" },
|
||||
{
|
||||
key: "highly_liquid",
|
||||
id: "highly-liquid",
|
||||
name: "Highly Liquid",
|
||||
},
|
||||
] as const;
|
||||
|
||||
@@ -1,114 +1,133 @@
|
||||
export const percentiles = [
|
||||
{
|
||||
key: "median_price_paid",
|
||||
id: "median-price-paid",
|
||||
name: "Median",
|
||||
title: "Median Paid",
|
||||
value: 50,
|
||||
},
|
||||
{
|
||||
key: "95p_price_paid",
|
||||
id: "95p-price-paid",
|
||||
name: `95%`,
|
||||
title: `95th Percentile Paid`,
|
||||
value: 95,
|
||||
},
|
||||
{
|
||||
key: "90p_price_paid",
|
||||
id: "90p-price-paid",
|
||||
name: `90%`,
|
||||
title: `90th Percentile Paid`,
|
||||
value: 90,
|
||||
},
|
||||
{
|
||||
key: "85p_price_paid",
|
||||
id: "85p-price-paid",
|
||||
name: `85%`,
|
||||
title: `85th Percentile Paid`,
|
||||
value: 85,
|
||||
},
|
||||
{
|
||||
key: "80p_price_paid",
|
||||
id: "80p-price-paid",
|
||||
name: `80%`,
|
||||
title: `80th Percentile Paid`,
|
||||
value: 80,
|
||||
},
|
||||
{
|
||||
key: "75p_price_paid",
|
||||
id: "75p-price-paid",
|
||||
name: `75%`,
|
||||
title: `75th Percentile Paid`,
|
||||
value: 75,
|
||||
},
|
||||
{
|
||||
key: "70p_price_paid",
|
||||
id: "70p-price-paid",
|
||||
name: `70%`,
|
||||
title: `70th Percentile Paid`,
|
||||
value: 70,
|
||||
},
|
||||
{
|
||||
key: "65p_price_paid",
|
||||
id: "65p-price-paid",
|
||||
name: `65%`,
|
||||
title: `65th Percentile Paid`,
|
||||
value: 65,
|
||||
},
|
||||
{
|
||||
key: "60p_price_paid",
|
||||
id: "60p-price-paid",
|
||||
name: `60%`,
|
||||
title: `60th Percentile Paid`,
|
||||
value: 60,
|
||||
},
|
||||
{
|
||||
key: "55p_price_paid",
|
||||
id: "55p-price-paid",
|
||||
name: `55%`,
|
||||
title: `55th Percentile Paid`,
|
||||
value: 55,
|
||||
},
|
||||
{
|
||||
key: "45p_price_paid",
|
||||
id: "45p-price-paid",
|
||||
name: `45%`,
|
||||
title: `45th Percentile Paid`,
|
||||
value: 45,
|
||||
},
|
||||
{
|
||||
key: "40p_price_paid",
|
||||
id: "40p-price-paid",
|
||||
name: `40%`,
|
||||
title: `40th Percentile Paid`,
|
||||
value: 40,
|
||||
},
|
||||
{
|
||||
key: "35p_price_paid",
|
||||
id: "35p-price-paid",
|
||||
name: `35%`,
|
||||
title: `35th Percentile Paid`,
|
||||
value: 35,
|
||||
},
|
||||
{
|
||||
key: "30p_price_paid",
|
||||
id: "30p-price-paid",
|
||||
name: `30%`,
|
||||
title: `30th Percentile Paid`,
|
||||
value: 30,
|
||||
},
|
||||
{
|
||||
key: "25p_price_paid",
|
||||
id: "25p-price-paid",
|
||||
name: `25%`,
|
||||
title: `25th Percentile Paid`,
|
||||
value: 25,
|
||||
},
|
||||
{
|
||||
key: "20p_price_paid",
|
||||
id: "20p-price-paid",
|
||||
name: `20%`,
|
||||
title: `20th Percentile Paid`,
|
||||
value: 20,
|
||||
},
|
||||
{
|
||||
key: "15p_price_paid",
|
||||
id: "15p-price-paid",
|
||||
name: `15%`,
|
||||
title: `15th Percentile Paid`,
|
||||
value: 15,
|
||||
},
|
||||
{
|
||||
key: "10p_price_paid",
|
||||
id: "10p-price-paid",
|
||||
name: `10%`,
|
||||
title: `10th Percentile Paid`,
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
key: "05p_price_paid",
|
||||
id: "05p-price-paid",
|
||||
name: `5%`,
|
||||
title: `5th Percentile Paid`,
|
||||
value: 5,
|
||||
|
||||
26
app/src/scripts/datasets/consts/types.d.ts
vendored
26
app/src/scripts/datasets/consts/types.d.ts
vendored
@@ -1,18 +1,24 @@
|
||||
type AgeCohortKey = (typeof import("./age").ageCohorts)[number]["key"];
|
||||
type AgeCohortId = (typeof import("./age").ageCohorts)[number]["id"];
|
||||
|
||||
type AddressCohortKey =
|
||||
type AgeCohortIdSub = Exclude<AgeCohortId, "">;
|
||||
|
||||
type AddressCohortId =
|
||||
(typeof import("./address").addressCohorts)[number]["key"];
|
||||
|
||||
type LiquidityKey = (typeof import("./liquidities").liquidities)[number]["key"];
|
||||
type LiquidityId = (typeof import("./liquidities").liquidities)[number]["id"];
|
||||
|
||||
type AddressCohortKeySplitByLiquidity = `${LiquidityKey}_${AddressCohortKey}`;
|
||||
type AddressCohortIdSplitByLiquidity = `${LiquidityId}-${AddressCohortId}`;
|
||||
|
||||
type AnyCohortKey = AgeCohortKey | AddressCohortKey;
|
||||
type AnyCohortId = AgeCohortId | AddressCohortId;
|
||||
|
||||
type AnyPossibleCohortKey =
|
||||
| AnyCohortKey
|
||||
| AddressCohortKeySplitByLiquidity
|
||||
| LiquidityKey;
|
||||
type AnyPossibleCohortId =
|
||||
| AnyCohortId
|
||||
| AddressCohortIdSplitByLiquidity
|
||||
| LiquidityId;
|
||||
|
||||
type AnyDatasetPrefix =
|
||||
| ""
|
||||
| `${AgeCohortIdSub | AddressCohortId | AddressCohortIdSplitByLiquidity | LiquidityId}-`;
|
||||
|
||||
type AverageName = (typeof import("./averages").averages)[number]["key"];
|
||||
|
||||
@@ -20,3 +26,5 @@ type TotalReturnKey = (typeof import("./returns").totalReturns)[number]["key"];
|
||||
|
||||
type CompoundReturnKey =
|
||||
(typeof import("./returns").compoundReturns)[number]["key"];
|
||||
|
||||
type PercentileId = (typeof import("./percentiles").percentiles)[number]["id"];
|
||||
|
||||
@@ -1,23 +1,49 @@
|
||||
import groupedKeysToURLPath from "/src/../../datasets/grouped_keys_to_url_path.json";
|
||||
|
||||
import { createDateDatasets } from "./date";
|
||||
import { createHeightDatasets } from "./height";
|
||||
import { createResourceDataset } from "./resource";
|
||||
|
||||
export const scales = ["date" as const, "height" as const];
|
||||
|
||||
export const HEIGHT_CHUNK_SIZE = 10_000;
|
||||
|
||||
export function createDatasets() {
|
||||
const date = createDateDatasets({
|
||||
groupedKeysToURLPath: groupedKeysToURLPath.date,
|
||||
});
|
||||
const date = new Map<DateDatasetPath, ResourceDataset<"date">>();
|
||||
const height = new Map<HeightDatasetPath, ResourceDataset<"height">>();
|
||||
|
||||
const height = createHeightDatasets({
|
||||
groupedKeysToURLPath: groupedKeysToURLPath.height,
|
||||
});
|
||||
function getOrImport<Scale extends ResourceScale>(
|
||||
scale: Scale,
|
||||
path: DatasetPath<Scale>,
|
||||
): ResourceDataset<Scale> {
|
||||
if (scale === "date") {
|
||||
const found = date.get(path as any);
|
||||
if (found) return found as ResourceDataset<Scale>;
|
||||
} else {
|
||||
const found = height.get(path as any);
|
||||
if (found) return found as ResourceDataset<Scale>;
|
||||
}
|
||||
|
||||
let dataset: ResourceDataset<Scale, any>;
|
||||
|
||||
if (path === `/${scale}-to-ohlc`) {
|
||||
dataset = createResourceDataset<Scale, OHLC>({
|
||||
scale,
|
||||
path,
|
||||
});
|
||||
} else {
|
||||
dataset = createResourceDataset<Scale>({
|
||||
scale,
|
||||
path,
|
||||
});
|
||||
}
|
||||
|
||||
if (scale === "date") {
|
||||
date.set(path as any, dataset as any);
|
||||
} else {
|
||||
height.set(path as any, dataset as any);
|
||||
}
|
||||
|
||||
return dataset;
|
||||
}
|
||||
|
||||
return {
|
||||
date,
|
||||
height,
|
||||
} satisfies Record<ResourceScale, any>;
|
||||
getOrImport,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -30,224 +30,239 @@ export function createResourceDataset<
|
||||
"https://api-bkp.satonomics.xyz"
|
||||
}${path}`;
|
||||
|
||||
const fetchedJSONs = new Array(
|
||||
(new Date().getFullYear() - new Date("2009-01-01").getFullYear() + 2) *
|
||||
(scale === "date" ? 1 : 6),
|
||||
)
|
||||
.fill(null)
|
||||
.map((): FetchedResult<Scale, Type> => {
|
||||
const json = createRWS<FetchedJSON<Scale, Type, Dataset> | null>(null);
|
||||
return createRoot((dispose) => {
|
||||
const fetchedJSONs = new Array(
|
||||
(new Date().getFullYear() - new Date("2009-01-01").getFullYear() + 2) *
|
||||
(scale === "date" ? 1 : 6),
|
||||
)
|
||||
.fill(null)
|
||||
.map((): FetchedResult<Scale, Type> => {
|
||||
const json = createRWS<FetchedJSON<Scale, Type, Dataset> | null>(null);
|
||||
|
||||
return {
|
||||
at: null,
|
||||
json,
|
||||
loading: false,
|
||||
vec: createMemo(() => {
|
||||
const map = json()?.dataset.map || null;
|
||||
return {
|
||||
at: null,
|
||||
json,
|
||||
loading: false,
|
||||
vec: createMemo(() => {
|
||||
const map = json()?.dataset.map || null;
|
||||
|
||||
if (!map) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const chunkId = json()?.chunk.id!;
|
||||
|
||||
if (Array.isArray(map)) {
|
||||
const values = new Array(map.length);
|
||||
|
||||
for (let i = 0; i < map.length; i++) {
|
||||
const value = map[i];
|
||||
|
||||
values[i] = {
|
||||
time: (chunkId + i) as Time,
|
||||
...(typeof value !== "number" && value !== null
|
||||
? { ...(value as OHLC), value: value.close }
|
||||
: { value: value === null ? NaN : (value as number) }),
|
||||
} as any as Value;
|
||||
if (!map) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return values;
|
||||
} else {
|
||||
return Object.entries(map).map(
|
||||
([date, value]) =>
|
||||
({
|
||||
time: date,
|
||||
const chunkId = json()?.chunk.id!;
|
||||
|
||||
if (Array.isArray(map)) {
|
||||
const values = new Array(map.length);
|
||||
|
||||
for (let i = 0; i < map.length; i++) {
|
||||
const value = map[i];
|
||||
|
||||
values[i] = {
|
||||
time: (chunkId + i) as Time,
|
||||
...(typeof value !== "number" && value !== null
|
||||
? { ...(value as OHLC), value: value.close }
|
||||
: { value: value === null ? NaN : (value as number) }),
|
||||
}) as any as Value,
|
||||
);
|
||||
}
|
||||
}),
|
||||
};
|
||||
}) as FetchedResult<Scale, Type>[];
|
||||
} as any as Value;
|
||||
}
|
||||
|
||||
const _fetch = async (id: number) => {
|
||||
const index = chunkIdToIndex(scale, id);
|
||||
return values;
|
||||
} else {
|
||||
return Object.entries(map).map(
|
||||
([date, value]) =>
|
||||
({
|
||||
time: date,
|
||||
...(typeof value !== "number" && value !== null
|
||||
? { ...(value as OHLC), value: value.close }
|
||||
: { value: value === null ? NaN : (value as number) }),
|
||||
}) as any as Value,
|
||||
);
|
||||
}
|
||||
}),
|
||||
};
|
||||
}) as FetchedResult<Scale, Type>[];
|
||||
|
||||
if (
|
||||
index < 0 ||
|
||||
(scale === "date" && id > new Date().getUTCFullYear()) ||
|
||||
(scale === "height" &&
|
||||
id > 165 * 365 * (new Date().getUTCFullYear() - 2009))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fetched = fetchedJSONs.at(index);
|
||||
|
||||
if (scale === "height" && index > 0) {
|
||||
const length = fetchedJSONs.at(index - 1)?.vec()?.length;
|
||||
|
||||
if (length !== undefined && length < HEIGHT_CHUNK_SIZE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!fetched || fetched.loading) {
|
||||
return;
|
||||
} else if (fetched.at) {
|
||||
const diff = new Date().getTime() - fetched.at.getTime();
|
||||
const _fetch = async (id: number) => {
|
||||
const index = chunkIdToIndex(scale, id);
|
||||
|
||||
if (
|
||||
diff < ONE_MINUTE_IN_MS ||
|
||||
(index < fetchedJSONs.findLastIndex((json) => json.at) &&
|
||||
diff < ONE_HOUR_IN_MS)
|
||||
index < 0 ||
|
||||
(scale === "date" && id > new Date().getUTCFullYear()) ||
|
||||
(scale === "height" &&
|
||||
id > 165 * 365 * (new Date().getUTCFullYear() - 2009))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fetched.loading = true;
|
||||
const fetched = fetchedJSONs.at(index);
|
||||
|
||||
let cache: Cache | undefined;
|
||||
if (scale === "height" && index > 0) {
|
||||
const length = fetchedJSONs.at(index - 1)?.vec()?.length;
|
||||
|
||||
const urlWithQuery = `${baseURL}?chunk=${id}`;
|
||||
const backupUrlWithQuery = `${backupURL}?chunk=${id}`;
|
||||
|
||||
if (!fetched.json()) {
|
||||
try {
|
||||
cache = await caches.open("resources");
|
||||
|
||||
const cachedResponse = await cache.match(urlWithQuery);
|
||||
|
||||
if (cachedResponse) {
|
||||
const json = await convertResponseToJSON<Scale, Type>(cachedResponse);
|
||||
|
||||
if (json) {
|
||||
console.log(`cache: ${path}?chunk=${id}`);
|
||||
|
||||
fetched.json.set(() => json);
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!navigator.onLine) {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let fetchedResponse: Response | undefined;
|
||||
|
||||
try {
|
||||
fetchedResponse = await fetch(urlWithQuery);
|
||||
|
||||
if (!fetchedResponse.ok) {
|
||||
throw Error;
|
||||
}
|
||||
} catch {
|
||||
try {
|
||||
fetchedResponse = await fetch(backupUrlWithQuery);
|
||||
} catch {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fetchedResponse || !fetchedResponse.ok) {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const clonedResponse = fetchedResponse.clone();
|
||||
|
||||
const json = await convertResponseToJSON<Scale, Type>(fetchedResponse);
|
||||
|
||||
if (!json) {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`fetch: ${path}?chunk=${id}`);
|
||||
|
||||
const previousMap = fetched.json()?.dataset.map;
|
||||
const newMap = json.dataset.map;
|
||||
|
||||
const previousLength = Object.keys(previousMap || []).length;
|
||||
const newLength = Object.keys(newMap).length;
|
||||
|
||||
if (!newLength) {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousLength && previousLength === newLength) {
|
||||
const previousLastValue = Object.values(previousMap || []).at(-1);
|
||||
const newLastValue = Object.values(newMap).at(-1);
|
||||
|
||||
if (typeof newLastValue === "number") {
|
||||
if (previousLastValue === newLastValue) {
|
||||
fetched.at = new Date();
|
||||
fetched.loading = false;
|
||||
if (length !== undefined && length < HEIGHT_CHUNK_SIZE) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const previousLastOHLC = previousLastValue as OHLC;
|
||||
const newLastOHLC = newLastValue as OHLC;
|
||||
}
|
||||
|
||||
if (!fetched || fetched.loading) {
|
||||
return;
|
||||
} else if (fetched.at) {
|
||||
const diff = new Date().getTime() - fetched.at.getTime();
|
||||
|
||||
if (
|
||||
previousLastOHLC.open === newLastOHLC.open &&
|
||||
previousLastOHLC.high === newLastOHLC.high &&
|
||||
previousLastOHLC.low === newLastOHLC.low &&
|
||||
previousLastOHLC.close === newLastOHLC.close
|
||||
diff < ONE_MINUTE_IN_MS ||
|
||||
(index < fetchedJSONs.findLastIndex((json) => json.at) &&
|
||||
diff < ONE_HOUR_IN_MS)
|
||||
) {
|
||||
fetched.loading = false;
|
||||
fetched.at = new Date();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetched.json.set(() => json);
|
||||
fetched.loading = true;
|
||||
|
||||
function saveToCache() {
|
||||
cache?.put(urlWithQuery, clonedResponse);
|
||||
}
|
||||
let cache: Cache | undefined;
|
||||
|
||||
if (requestIdleCallbackPossible) {
|
||||
requestIdleCallback(saveToCache);
|
||||
} else {
|
||||
setTimeout(saveToCache, 1);
|
||||
}
|
||||
const urlWithQuery = `${baseURL}?chunk=${id}`;
|
||||
const backupUrlWithQuery = `${backupURL}?chunk=${id}`;
|
||||
|
||||
fetched.at = new Date();
|
||||
fetched.loading = false;
|
||||
};
|
||||
if (!fetched.json()) {
|
||||
try {
|
||||
cache = await caches.open("resources");
|
||||
|
||||
const resource: ResourceDataset<Scale, Type> = {
|
||||
scale,
|
||||
url: baseURL,
|
||||
fetch: _fetch,
|
||||
fetchedJSONs,
|
||||
drop() {
|
||||
fetchedJSONs.forEach((fetched) => {
|
||||
fetched.at = null;
|
||||
fetched.json.set(null);
|
||||
});
|
||||
},
|
||||
};
|
||||
const cachedResponse = await cache.match(urlWithQuery);
|
||||
|
||||
return resource;
|
||||
if (cachedResponse) {
|
||||
const json = await convertResponseToJSON<Scale, Type>(
|
||||
cachedResponse,
|
||||
);
|
||||
|
||||
if (json) {
|
||||
console.log(`cache: ${path}?chunk=${id}`);
|
||||
|
||||
fetched.json.set(() => json);
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
if (!navigator.onLine) {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
let fetchedResponse: Response | undefined;
|
||||
|
||||
const fetchConfig: RequestInit = {
|
||||
signal: AbortSignal.timeout(5000),
|
||||
};
|
||||
|
||||
try {
|
||||
fetchedResponse = await fetch(urlWithQuery, fetchConfig);
|
||||
|
||||
if (!fetchedResponse.ok) {
|
||||
throw Error;
|
||||
}
|
||||
} catch {
|
||||
try {
|
||||
fetchedResponse = await fetch(backupUrlWithQuery, fetchConfig);
|
||||
} catch {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fetchedResponse || !fetchedResponse.ok) {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const clonedResponse = fetchedResponse.clone();
|
||||
|
||||
const json = await convertResponseToJSON<Scale, Type>(fetchedResponse);
|
||||
|
||||
if (!json) {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(`fetch: ${path}?chunk=${id}`);
|
||||
|
||||
const previousMap = fetched.json()?.dataset.map;
|
||||
const newMap = json.dataset.map;
|
||||
|
||||
const previousLength = Object.keys(previousMap || []).length;
|
||||
const newLength = Object.keys(newMap).length;
|
||||
|
||||
if (!newLength) {
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (previousLength && previousLength === newLength) {
|
||||
const previousLastValue = Object.values(previousMap || []).at(-1);
|
||||
const newLastValue = Object.values(newMap).at(-1);
|
||||
|
||||
if (newLastValue === null && previousLastValue === null) {
|
||||
fetched.at = new Date();
|
||||
fetched.loading = false;
|
||||
return;
|
||||
} else if (typeof newLastValue === "number") {
|
||||
if (previousLastValue === newLastValue) {
|
||||
fetched.at = new Date();
|
||||
fetched.loading = false;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
const previousLastOHLC = previousLastValue as OHLC;
|
||||
const newLastOHLC = newLastValue as OHLC;
|
||||
|
||||
if (
|
||||
previousLastOHLC.open === newLastOHLC.open &&
|
||||
previousLastOHLC.high === newLastOHLC.high &&
|
||||
previousLastOHLC.low === newLastOHLC.low &&
|
||||
previousLastOHLC.close === newLastOHLC.close
|
||||
) {
|
||||
fetched.loading = false;
|
||||
fetched.at = new Date();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fetched.json.set(() => json);
|
||||
|
||||
async function saveToCache() {
|
||||
try {
|
||||
await cache?.put(urlWithQuery, clonedResponse);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
if (requestIdleCallbackPossible) {
|
||||
requestIdleCallback(saveToCache);
|
||||
} else {
|
||||
setTimeout(saveToCache, 1);
|
||||
}
|
||||
|
||||
fetched.at = new Date();
|
||||
fetched.loading = false;
|
||||
};
|
||||
|
||||
const resource: ResourceDataset<Scale, Type> = {
|
||||
scale,
|
||||
url: baseURL,
|
||||
fetch: _fetch,
|
||||
fetchedJSONs,
|
||||
drop() {
|
||||
dispose();
|
||||
fetchedJSONs.forEach((fetched) => {
|
||||
fetched.at = null;
|
||||
fetched.json.set(null);
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
return resource;
|
||||
});
|
||||
}
|
||||
|
||||
async function convertResponseToJSON<
|
||||
|
||||
16
app/src/scripts/datasets/types.d.ts
vendored
16
app/src/scripts/datasets/types.d.ts
vendored
@@ -1,9 +1,5 @@
|
||||
type Datasets = ReturnType<typeof import("./index").createDatasets>;
|
||||
|
||||
type DateDatasets = Datasets["date"];
|
||||
type HeightDatasets = Datasets["height"];
|
||||
type AnyDatasets = DateDatasets | HeightDatasets;
|
||||
|
||||
type ResourceScale = (typeof import("./index").scales)[index];
|
||||
|
||||
type DatasetValue<T> = T & Valued;
|
||||
@@ -92,3 +88,15 @@ interface OHLC {
|
||||
|
||||
type GroupedKeysToURLPath =
|
||||
typeof import("/src/../../datasets/grouped_keys_to_url_path.json");
|
||||
|
||||
type DateDatasetPath = import("/src/../../datasets/paths").DatePath;
|
||||
|
||||
type HeightDatasetPath = import("/src/../../datasets/paths").HeightPath;
|
||||
|
||||
type LastDataPath = import("/src/../../datasets/paths").LastPath;
|
||||
|
||||
type DatasetPath<Scale extends ResourceScale> = Scale extends "date"
|
||||
? DateDatasetPath
|
||||
: HeightDatasetPath;
|
||||
|
||||
type AnyDatasetPath = DateDatasetPath | HeightDatasetPath;
|
||||
|
||||
Reference in New Issue
Block a user