kibo: part 4

This commit is contained in:
nym21
2025-03-31 10:02:59 +02:00
parent 50ad5f681b
commit 1c72362c6b
13 changed files with 664 additions and 437 deletions

View File

@@ -217,7 +217,7 @@
--white: oklch(99% 0.01 44);
--light-gray: oklch(90% 0.01 44);
--gray: oklch(60% 0.01 44);
--dark-gray: oklch(25% 0.01 44);
--dark-gray: oklch(30% 0.01 44);
--black: oklch(17.5% 0.005 44);
--red: oklch(0.607 0.241 26.328);
--orange: oklch(67.64% 0.191 44.41);
@@ -236,8 +236,8 @@
--purple: oklch(0.5925 0.2765 303.1105);
--fuchsia: oklch(0.629 0.294 322.523);
--pink: oklch(0.624 0.245 357.444);
--rose: oklch(0.6155 0.2495 17.012)
--background-color: light-dark(var(--white), var(--black));
--rose: oklch(0.6155 0.2495 17.012);
--background-color: light-dark(var(--white), var(--black));
--color: light-dark(var(--black), var(--white));
--off-color: var(--gray);
--border-color: light-dark(var(--light-gray), var(--dark-gray));
@@ -256,6 +256,8 @@
--line-height-xl: calc(1.75 / 1.25);
--font-size-2xl: 1.5rem;
--line-height-2xl: calc(2 / 1.5);
--font-size-3xl: 1.75rem;
--line-height-3xl: calc(2.25 / 1.75);
--main-padding: 2rem;
@@ -265,7 +267,7 @@
--negative-main-padding: calc(-1 * var(--main-padding));
--font-weight-base: 450;
--font-weight-base: 400;
--font-weight-bold: 700;
--transform-scale-active: scaleY(0.9);
@@ -446,16 +448,11 @@
}
}
field,
h1 {
text-transform: capitalize;
}
h1,
h2 {
font-size: var(--font-size-2xl);
line-height: var(--line-height-2xl);
font-weight: 400;
font-size: var(--font-size-3xl);
line-height: var(--line-height-3xl);
font-weight: 300;
}
h3 {
@@ -889,7 +886,7 @@
transparent,
var(--background-color)
);
height: var(--main-padding);
height: calc(var(--main-padding) * 10);
bottom: 0;
left: 0;
right: 0;
@@ -936,6 +933,7 @@
}
> div.field {
text-transform: lowercase;
display: flex;
align-items: center;
/* font-size: var(--font-size-xs);
@@ -948,17 +946,17 @@
}
> hr {
min-width: 1rem;
min-width: 2rem;
}
label {
padding: 0.5rem;
/* margin: -0.5rem; */
margin: -0.5rem;
}
> div {
display: flex;
gap: 0.5rem;
gap: 1.5rem;
}
}
}
@@ -968,6 +966,7 @@
flex-direction: column;
min-height: 0;
z-index: 20;
margin-bottom: 2rem;
> legend {
display: flex;

View File

@@ -1,5 +1,7 @@
// @ts-check
/** @import {SeriesDefinition} from './v5.0.5/types' */
export default import("./v5.0.5/script.js").then((lc) => {
/**
* @param {Object} args
@@ -23,26 +25,18 @@ export default import("./v5.0.5/script.js").then((lc) => {
autoSize: true,
layout: {
fontFamily: "Satoshi",
fontSize: 13.5,
fontSize: 14,
background: { color: "transparent" },
attributionLogo: false,
colorSpace: "display-p3",
colorParsers: [oklchToRGBA],
panes: {},
},
grid: {
vertLines: { visible: false },
horzLines: { visible: false },
},
timeScale: {
minBarSpacing: 0.1,
shiftVisibleRangeOnNewBar: false,
allowShiftVisibleRangeOnWhitespaceReplacement: false,
},
handleScale: {
axisDoubleClickReset: {
time: false,
},
minBarSpacing: 2.1,
},
localization: {
priceFormatter: utils.locale.numberToShortUSFormat,
@@ -51,6 +45,7 @@ export default import("./v5.0.5/script.js").then((lc) => {
..._options,
};
/** @type {IChartApi} */
const chart = lc.createChart(element, options);
chart.priceScale("right").applyOptions({
@@ -65,13 +60,22 @@ export default import("./v5.0.5/script.js").then((lc) => {
() => ({
defaultColor: colors.default(),
offColor: colors.off(),
borderColor: colors.border(),
}),
({ defaultColor, offColor }) => {
console.log(defaultColor, offColor);
({ defaultColor, offColor, borderColor }) => {
console.log(
defaultColor,
offColor,
borderColor,
`rgba(${oklchToRGBA(borderColor).join(", ")})`,
);
chart.applyOptions({
layout: {
textColor: offColor,
panes: {
separatorColor: borderColor,
},
},
rightPriceScale: {
borderVisible: false,
@@ -82,13 +86,14 @@ export default import("./v5.0.5/script.js").then((lc) => {
},
crosshair: {
horzLine: {
color: defaultColor,
color: offColor,
labelBackgroundColor: defaultColor,
},
vertLine: {
color: defaultColor,
color: offColor,
labelBackgroundColor: defaultColor,
},
mode: 3,
},
});
},
@@ -103,9 +108,9 @@ export default import("./v5.0.5/script.js").then((lc) => {
const defaultSeriesOptions = {
// @ts-ignore
lineWidth: 1.5,
priceLineVisible: false,
baseLineVisible: false,
baseLineColor: "",
// priceLineVisible: false,
// baseLineVisible: false,
// baseLineColor: "",
};
/**
@@ -116,15 +121,16 @@ export default import("./v5.0.5/script.js").then((lc) => {
* @param {Colors} args.colors
* @param {"static" | "scrollable"} args.kind
* @param {Utilities} args.utils
* @param {VecsResources} args.vecsResources
* @param {Owner | null} [args.owner]
*/
function createChartElement({
parent,
signals,
colors,
id: chartId,
kind,
utils,
vecsResources,
owner: _owner,
}) {
let owner = _owner || signals.getOwner();
@@ -133,14 +139,16 @@ export default import("./v5.0.5/script.js").then((lc) => {
div.classList.add("chart");
parent.append(div);
const legendElement = window.document.createElement("legend");
div.append(legendElement);
const legend = createLegend({
parent: div,
});
const chartDiv = window.document.createElement("div");
chartDiv.classList.add("lightweight-chart");
div.append(chartDiv);
let ichart = /** @type {IChartApi | null} */ (null);
let timeScaleSet = false;
if (kind === "static") {
new ResizeObserver(() => ichart?.timeScale().fitContent()).observe(
@@ -148,17 +156,82 @@ export default import("./v5.0.5/script.js").then((lc) => {
);
}
/** @type {Index} */
let index = 0;
let timeResource = /** @type {VecResource| null} */ (null);
/**
* @param {ISeriesApi<any>} series
* @param {VecResource} valuesResource
*/
function createSetDataEffect(series, valuesResource) {
signals.createEffect(
() => [timeResource?.fetched(), valuesResource.fetched()],
([indexes, _ohlcs]) => {
if (!ichart) throw Error("IChart should be initialized");
if (!indexes || !_ohlcs) return;
const ohlcs = /** @type {OHLCTuple[]} */ (_ohlcs);
let length = Math.min(indexes.length, ohlcs.length);
const data = new Array(length);
let prevTime = null;
let offset = 0;
for (let i = 0; i < length; i++) {
const time = indexes[i];
if (prevTime && prevTime === time) {
offset += 1;
}
const v = ohlcs[i];
if (typeof v === "number") {
data[i - offset] = {
time,
value: v,
};
} else {
data[i - offset] = {
time,
open: v[0],
high: v[1],
low: v[2],
close: v[3],
};
}
prevTime = time;
}
data.length -= offset;
series.setData(data);
if (
!timeScaleSet &&
(index === /** @satisfies {Yearindex} */ (15) ||
index === /** @satisfies {Decadeindex} */ (16))
) {
ichart
.timeScale()
.setVisibleLogicalRange({ from: -1, to: data.length });
}
timeScaleSet = true;
},
);
}
return {
chart() {
return ichart;
},
/**
* @param {Index} index
* @param {Index} _index
*/
createChart(index) {
create(_index) {
index = _index;
if (ichart) throw Error("IChart shouldn't be initialized");
createLightweightChart({
timeResource = vecsResources.getOrCreate(
index,
index === /** @satisfies {Height} */ (2)
? "fixed-timestamp"
: "timestamp",
);
timeResource.fetch();
ichart = createLightweightChart({
index,
element: chartDiv,
signals,
@@ -166,6 +239,56 @@ export default import("./v5.0.5/script.js").then((lc) => {
utils,
});
},
/**
* @param {VecId} id
* @param {number} [paneNumber]
*/
addCandlestickSeries(id, paneNumber) {
if (!ichart || !timeResource) throw Error("Chart not fully set");
const valuesResource = vecsResources.getOrCreate(index, id);
valuesResource.fetch();
const green = colors.green();
const red = colors.red();
const series = ichart.addSeries(
/** @type {SeriesDefinition<'Candlestick'>} */ (lc.CandlestickSeries),
{
upColor: green,
downColor: red,
wickUpColor: green,
wickDownColor: red,
borderVisible: false,
},
paneNumber,
);
createSetDataEffect(series, valuesResource);
return series;
},
/**
* @param {VecId} id
* @param {number} [paneNumber]
*/
addLineSeries(id, paneNumber) {
if (!ichart || !timeResource) throw Error("Chart not fully set");
const valuesResource = vecsResources.getOrCreate(index, id);
valuesResource.fetch();
const series = ichart.addSeries(
/** @type {SeriesDefinition<'Line'>} */ (lc.LineSeries),
{
lineWidth: /** @type {any} */ (1.5),
},
paneNumber,
);
createSetDataEffect(series, valuesResource);
return series;
},
/**
*
* @param {Object} args
@@ -173,21 +296,35 @@ export default import("./v5.0.5/script.js").then((lc) => {
*/
reset({ owner: _owner }) {
owner = _owner;
if (ichart !== null) {
ichart.remove();
} else {
throw Error("IChart should be initialized");
}
legendElement.innerHTML = "";
ichart?.remove();
ichart = null;
timeScaleSet = false;
legend.reset();
},
};
}
return {
inner: lc,
createChartElement,
};
});
/**
* @param {Object} args
* @param {Element} args.parent
*/
function createLegend({ parent }) {
const legendElement = window.document.createElement("legend");
parent.append(legendElement);
return {
reset() {
legendElement.innerHTML = "";
},
};
}
const oklchToRGBA = (() => {
{
/**

View File

@@ -10,6 +10,7 @@
* @param {WebSockets} args.webSockets
* @param {Elements} args.elements
* @param {VecsResources} args.vecsResources
* @param {VecIdToIndexes} args.vecIdToIndexes
*/
export function init({
colors,
@@ -20,6 +21,7 @@ export function init({
utils,
webSockets,
vecsResources,
vecIdToIndexes,
}) {
console.log("init chart state");
@@ -28,56 +30,61 @@ export function init({
const { headerElement, titleElement } = utils.dom.createHeader({});
elements.charts.append(headerElement);
signals.createEffect(selected, (option) => {
titleElement.innerHTML = option.title;
});
const chartElement = lightweightCharts.createChartElement({
const chart = lightweightCharts.createChartElement({
parent: elements.charts,
signals,
colors,
id: "chart",
kind: "scrollable",
utils,
vecsResources,
});
const indexes = utils.dom.createHorizontalChoiceField({
title: "Index",
selected: "date",
choices: [
"Timestamp",
"Date",
"Week",
"Difficulty Epoch",
"Month",
"Year",
"Halving Epoch",
"Decade",
],
id: "index",
signals,
const index = createIndexSelector({ elements, signals, utils });
// const vecs = signals.createSignal(
// /** @type {Set<VecResource>} */ (new Set()),
// {
// equals: false,
// },
// );
signals.createEffect(selected, (option) => {
titleElement.innerHTML = option.title;
signals.createEffect(index, (index) => {
chart.reset({ owner: signals.getOwner() });
chart.create(index);
const candles = chart.addCandlestickSeries("ohlc");
signals.createEffect(webSockets.kraken1dCandle.latest, (latest) => {
if (!latest) return;
const last = /** @type { CandlestickData | undefined} */ (
candles.data().at(-1)
);
if (!last) return;
candles?.update({ ...last, close: latest.close });
});
[
{ blueprints: option.top, paneIndex: 0 },
{ blueprints: option.bottom, paneIndex: 1 },
].forEach(({ blueprints, paneIndex }) => {
blueprints?.forEach((blueprint) => {
if (vecIdToIndexes[blueprint.key].includes(index)) {
const series = chart.addLineSeries(blueprint.key, paneIndex);
series.applyOptions({
visible: blueprint.defaultActive !== false,
color: blueprint.color?.(),
});
}
});
});
});
});
const fieldset = window.document.createElement("fieldset");
fieldset.append(indexes);
elements.charts.append(fieldset);
const vecs = signals.createSignal(
/** @type {Set<VecResource<any>>} */ (new Set()),
{
equals: false,
},
);
const index = /** @satisfies {Dateindex} */ (1);
chartElement.createChart(index);
const ohlc = vecsResources.getOrCreate(index, "ohlc");
const date = vecsResources.getOrCreate(index, "date");
date.fetch(-10_000);
// function createFetchChunksOfVisibleDatasetsEffect() {
// signals.createEffect(
// () => ({
@@ -185,3 +192,65 @@ export function init({
// }
// createApplyChartOptionEffect();
}
/**
* @param {Object} args
* @param {Elements} args.elements
* @param {Signals} args.signals
* @param {Utilities} args.utils
*/
function createIndexSelector({ elements, signals, utils }) {
const indexLSKey = "chart-index";
const indexChoices = /**@type {const} */ ([
"timestamp",
"date",
"week",
// "difficulty epoch",
"month",
"year",
// "halving epoch",
"decade",
]);
/** @typedef {(typeof indexChoices)[number]} SerializedIndex */
const serializedIndex = signals.createSignal(
/** @type {SerializedIndex} */ (localStorage.getItem(indexLSKey) || "date"),
);
const indexesField = utils.dom.createHorizontalChoiceField({
title: "Index",
selected: serializedIndex(),
choices: indexChoices,
id: "index",
signals,
});
indexesField.addEventListener("change", (event) => {
// @ts-ignore
const value = event.target.value;
localStorage.setItem(indexLSKey, value);
serializedIndex.set(value);
});
const fieldset = window.document.createElement("fieldset");
fieldset.append(indexesField);
elements.charts.append(fieldset);
const index = signals.createMemo(
/** @returns {Index} */ () => {
switch (serializedIndex()) {
case "timestamp":
return /** @satisfies {Height} */ (2);
case "date":
return /** @satisfies {Dateindex} */ (1);
case "week":
return /** @satisfies {Weekindex} */ (13);
case "month":
return /** @satisfies {Monthindex} */ (14);
case "year":
return /** @satisfies {Yearindex} */ (15);
case "decade":
return /** @satisfies {Decadeindex} */ (16);
}
},
);
return index;
}

View File

@@ -1,7 +1,7 @@
// @ts-check
/**
* @import { Option, TimeRange, Weighted, OHLC, Color, DatasetCandlestickData, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, VecResource, Valued, FetchedVecRange, SingleValueData, CandlestickData, ChartData } from "./types/self"
* @import { Option, Weighted, Color, DatasetCandlestickData, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, SimulationOption, Valued, SingleValueData, CandlestickData, ChartData, OHLCTuple } from "./types/self"
* @import { Marker, CreatePaneParameters, HoveredLegend, ChartPane, SplitSeries, SingleSeries, CreateSplitSeriesParameters, LineSeriesBlueprint, CandlestickSeriesBlueprint, BaselineSeriesBlueprint, CreateBaseSeriesParameters, BaseSeries, RemoveSeriesBlueprintFluff, SplitSeriesBlueprint, AnySeries, PriceSeriesType } from "../packages/lightweight-charts/types";
* @import * as _ from "../packages/ufuzzy/v1.0.14/types"
* @import { createChart as CreateClassicChart, createChartEx as CreateCustomChart, LineStyleOptions, DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, ISeriesApi, Time, LineData, LogicalRange, SeriesMarker, SeriesType, BaselineStyleOptions, SeriesOptionsCommon } from "../packages/lightweight-charts/v5.0.5/types"
@@ -9,7 +9,7 @@
* @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/2024-11-02/types/core/owner"
* @import { createSignal as CreateSignal, createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo, createRoot as CreateRoot, runWithOwner as RunWithOwner } from "../packages/solid-signals/2024-11-02/types/signals";
* @import {Signal, Signals} from "../packages/solid-signals/types";
* @import {Addressindex, Dateindex, Decadeindex, Difficultyepoch, Index, Halvingepoch, Height, Monthindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, VecId, Weekindex, Yearindex} from "./vecid-to-indexes"
* @import {Addressindex, Dateindex, Decadeindex, Difficultyepoch, Index, Halvingepoch, Height, Monthindex, P2PK33index, P2PK65index, P2PKHindex, P2SHindex, P2TRindex, P2WPKHindex, P2WSHindex, Txindex, Txinindex, Txoutindex, VecId, Weekindex, Yearindex, VecIdToIndexes} from "./vecid-to-indexes"
*/
function initPackages() {
@@ -301,14 +301,6 @@ function createUtils() {
a.click();
a.remove();
},
/**
* @param {string} text
*/
createItalic(text) {
const italic = window.document.createElement("i");
italic.innerHTML = text;
return italic;
},
/**
* @param {string} href
*/
@@ -375,12 +367,6 @@ function createUtils() {
return field;
},
createUlElement() {
return window.document.createElement("ul");
},
createLiElement() {
return window.document.createElement("li");
},
/**
* @param {Object} args
* @param {string} args.id
@@ -1204,7 +1190,7 @@ function createUtils() {
return `/api${genPath(index, vecId)}`;
},
/**
* @template {number | OHLC} [T=number]
* @template {number | OHLCTuple} [T=number]
* @param {(v: T[]) => void} callback
* @param {Index} index
* @param {VecId} vecId
@@ -1215,7 +1201,7 @@ function createUtils() {
return fetchApi(callback, genPath(index, vecId, from, to));
},
/**
* @template {number | OHLC} [T=number]
* @template {number | OHLCTuple} [T=number]
* @param {(v: T) => void} callback
* @param {Index} index
* @param {VecId} vecId
@@ -1252,14 +1238,10 @@ function createUtils() {
* @param {Utilities} utils
*/
function createVecsResources(signals, utils) {
/** @type {Map<string, VecResource>} */
const map = new Map();
const owner = signals.getOwner();
const STEP = 1000;
/**
* @template {number | OHLC} [T=number]
* @template {number | OHLCTuple} [T=number]
* @param {Index} index
* @param {VecId} id
*/
@@ -1267,134 +1249,45 @@ function createVecsResources(signals, utils) {
return signals.runWithOwner(owner, () => {
/** @typedef {T extends number ? SingleValueData : CandlestickData} Value */
// interface VecResource<Type extends OHLC | number = number> {
// url: string;
// fetch: (from: number, to: number) => Promise<Type[] | null>;
// ranges: Map<number, FetchedVecRange<Type>>;
// }
const vec = {
const fetched = signals.createSignal(/** @type {T[] | null} */ (null));
let loading = false;
let at = /** @type {Date | null} */ (null);
return {
url: utils.api.genUrl(index, id),
/**
*
* @param {number} [from]
* @param {number} [to]
* @returns
*/
async fetch(from, to) {
const range = getOrCreate(from);
if (range.loading) return range.fetched();
if (range.at) {
fetched,
async fetch() {
if (loading) return fetched();
if (at) {
const diff = new Date().getTime() - at.getTime();
const ONE_MINUTE_IN_MS = 60_000;
const ONE_HOUR_IN_MS = 3_600_000;
const diff = new Date().getTime() - range.at.getTime();
if (diff < ONE_MINUTE_IN_MS) return range.fetched();
/** @type {number | null} */
let lastFrom = null;
for (const key of vec.ranges.keys()) {
lastFrom = key;
}
if (lastFrom && from < lastFrom && diff < ONE_HOUR_IN_MS) {
return range.fetched();
}
if (diff < ONE_MINUTE_IN_MS) return fetched();
}
range.loading = true;
loading = true;
const res = /** @type {T[] | null} */ (
await utils.api.fetchVec(
(values) => {
range.fetched.set(/** @type {T[]} */ (values));
fetched.set(/** @type {T[]} */ (values));
},
index,
id,
from,
to,
-10_000,
)
);
range.at = new Date();
range.loading = false;
at = new Date();
loading = false;
return res;
},
ranges: new Map(),
};
/**
* @param {number} from
*/
function getOrCreate(from) {
const found = vec.ranges.get(from);
if (found) return found;
const fetched = signals.createSignal(/** @type {T[] | null} */ (null));
/**
* @param {number} i
*/
function computeTime(i) {
switch (index) {
case /** @satisfies {Dateindex} */ (1): {
const index = from + i;
if (index === 0) {
return new Date(Date.UTC(2009, 1, 3));
} else {
let d = new Date(Date.UTC(2009, 1, 9));
d.setUTCDate(d.getUTCDate() + index - 1);
return d;
}
}
case /** @satisfies {Height} */ (2): {
// vecs.getOrCreate(/** @satisfies {Height} */ (2), "timestamp");
}
default: {
throw Error("todo!");
}
}
}
/** @type {FetchedVecRange<T>} */
const range = {
at: null,
fetched,
transformed: signals.createMemo(() => {
const vec = fetched();
if (!vec) return null;
const values = /** @type {Value[]} */ (new Array(vec.length));
for (let i = 0; i < vec.length; i++) {
const v = vec[i];
const time = /** @type {Time} */ (computeTime(i).valueOf());
/** @satisfies {SingleValueData} */
const value = {
time,
index: from + i,
...(Array.isArray(v) && v !== null
? {
open: v[0],
high: v[1],
low: v[2],
close: v[3],
value: v[3],
}
: {
value: v === null ? NaN : /** @type {number} */ (v),
}),
};
values[i] = /** @type {Value} */ (value);
}
return values;
}),
loading: false,
};
vec.ranges.set(from, range);
return range;
}
return vec;
});
}
/** @type {Map<string, NonNullable<ReturnType<typeof createVecResource>>>} */
const map = new Map();
const vecs = {
STEP,
/**
* @template {number | OHLCTuple} [T=number]
* @param {Index} index
* @param {VecId} id
*/
@@ -1406,9 +1299,10 @@ function createVecsResources(signals, utils) {
return found;
}
console.log("not found");
const vec = createVecResource(index, id);
if (!vec) throw Error("vec is undefined");
map.set(key, vec);
map.set(key, /** @type {any} */ (vec));
return vec;
},
};
@@ -1416,6 +1310,7 @@ function createVecsResources(signals, utils) {
return vecs;
}
/** @typedef {ReturnType<typeof createVecsResources>} VecsResources */
/** @typedef {ReturnType<VecsResources["getOrCreate"]>} VecResource */
function initEnv() {
const standalone =
@@ -1487,7 +1382,6 @@ function createColors(dark, elements) {
*/
function getColor(color) {
return elements.style.getPropertyValue(`--${color}`);
// return utils.color.oklch2hex(elements.style.getPropertyValue(`--${color}`));
}
function red() {
return getColor("red");
@@ -1559,10 +1453,14 @@ function createColors(dark, elements) {
function textColor() {
return getLightDarkValue("--color");
}
function borderColor() {
return getLightDarkValue("--border-color");
}
return {
default: textColor,
off,
border: borderColor,
lightBitcoin: yellow,
bitcoin: orange,
offBitcoin: red,
@@ -1834,8 +1732,8 @@ function initWebSockets(signals, utils) {
/** @typedef {ReturnType<typeof initWebSockets>} WebSockets */
function main() {
const options = import("./options.js");
const vecidToIndexes = import("./vecid-to-indexes.js");
const optionsPromise = import("./options.js");
const vecidToIndexesPromise = import("./vecid-to-indexes.js");
const packages = initPackages();
const env = initEnv();
const utils = createUtils();
@@ -1948,8 +1846,10 @@ function main() {
createKeyDownEventListener();
packages.signals().then((signals) =>
vecidToIndexes.then(({ VecIdToIndexes }) =>
options.then(async ({ initOptions }) => {
vecidToIndexesPromise.then(({ createVecIdToIndexes }) =>
optionsPromise.then(async ({ initOptions }) => {
const vecIdToIndexes = createVecIdToIndexes();
function initDark() {
const preferredColorSchemeMatchMedia = window.matchMedia(
"(prefers-color-scheme: dark)",
@@ -2071,6 +1971,7 @@ function main() {
utils,
webSockets,
vecsResources,
vecIdToIndexes: vecIdToIndexes,
}),
),
),

View File

@@ -4926,7 +4926,8 @@ function createPartialOptions(colors) {
// name: "Market",
// tree: [
{
name: "Dollars Per Bitcoin",
name: "Price",
title: "Bitcoin Price in US Dollars",
},
{
name: "Blocks",
@@ -4948,11 +4949,13 @@ function createPartialOptions(colors) {
key: "block-interval-max",
title: "Max",
color: colors.pink,
defaultActive: false,
},
{
key: "block-interval-min",
title: "Min",
color: colors.green,
defaultActive: false,
},
{
key: "block-interval-90p",

View File

@@ -17,19 +17,6 @@ import {
BaselineData,
} from "../../packages/lightweight-charts/v5.0.5/types";
import { AnyPossibleCohortId, Groups } from "../options";
import { Signal } from "../../packages/solid-signals/types";
// type TimeScale = "date" | "height";
type TimeRange = IRange<Time | number>;
// type DatasetPath<Scale extends TimeScale> = Scale extends "date"
// ? DatePath
// : HeightPath;
// type AnyDatasetPath = import("./paths").DatePath | import("./paths").HeightPath;
// type AnyPath = AnyDatasetPath | LastPath;
type Color = () => string;
type ColorName = keyof Colors;
@@ -118,24 +105,7 @@ interface OptionsGroup extends PartialOptionsGroup {
tree: OptionsTree;
}
interface OHLC {
open: number;
high: number;
low: number;
close: number;
}
interface FetchedVecRange<
Value extends number | OHLC,
Data extends SingleValueData | CandlestickData = Value extends number
? SingleValueData
: CandlestickData,
> {
at: Date | null;
fetched: Signal<Value[] | null>;
transformed: Accessor<Data[] | null>;
loading: boolean;
}
type OHLCTuple = [number, number, number, number];
interface Valued {
value: number;

View File

@@ -1,134 +1,138 @@
const Addressindex = 0;
/** @typedef {typeof Addressindex} Addressindex */
const Dateindex = 1;
/** @typedef {typeof Dateindex} Dateindex */
const Height = 2;
/** @typedef {typeof Height} Height */
const P2PK33index = 3;
/** @typedef {typeof P2PK33index} P2PK33index */
const P2PK65index = 4;
/** @typedef {typeof P2PK65index} P2PK65index */
const P2PKHindex = 5;
/** @typedef {typeof P2PKHindex} P2PKHindex */
const P2SHindex = 6;
/** @typedef {typeof P2SHindex} P2SHindex */
const P2TRindex = 7;
/** @typedef {typeof P2TRindex} P2TRindex */
const P2WPKHindex = 8;
/** @typedef {typeof P2WPKHindex} P2WPKHindex */
const P2WSHindex = 9;
/** @typedef {typeof P2WSHindex} P2WSHindex */
const Txindex = 10;
/** @typedef {typeof Txindex} Txindex */
const Txinindex = 11;
/** @typedef {typeof Txinindex} Txinindex */
const Txoutindex = 12;
/** @typedef {typeof Txoutindex} Txoutindex */
const Weekindex = 13;
/** @typedef {typeof Weekindex} Weekindex */
const Monthindex = 14;
/** @typedef {typeof Monthindex} Monthindex */
const Yearindex = 15;
/** @typedef {typeof Yearindex} Yearindex */
const Decadeindex = 16;
/** @typedef {typeof Decadeindex} Decadeindex */
const Difficultyepoch = 17;
/** @typedef {typeof Difficultyepoch} Difficultyepoch */
const Halvingepoch = 18;
/** @typedef {typeof Halvingepoch} Halvingepoch */
/** @typedef {0} Addressindex */
/** @typedef {1} Dateindex */
/** @typedef {2} Height */
/** @typedef {3} P2PK33index */
/** @typedef {4} P2PK65index */
/** @typedef {5} P2PKHindex */
/** @typedef {6} P2SHindex */
/** @typedef {7} P2TRindex */
/** @typedef {8} P2WPKHindex */
/** @typedef {9} P2WSHindex */
/** @typedef {10} Txindex */
/** @typedef {11} Txinindex */
/** @typedef {12} Txoutindex */
/** @typedef {13} Weekindex */
/** @typedef {14} Monthindex */
/** @typedef {15} Yearindex */
/** @typedef {16} Decadeindex */
/** @typedef {17} Difficultyepoch */
/** @typedef {18} Halvingepoch */
/** @typedef {Addressindex | Dateindex | Height | P2PK33index | P2PK65index | P2PKHindex | P2SHindex | P2TRindex | P2WPKHindex | P2WSHindex | Txindex | Txinindex | Txoutindex | Weekindex | Monthindex | Yearindex | Decadeindex | Difficultyepoch | Halvingepoch} Index */
export const VecIdToIndexes = {
addressindex: [Txoutindex],
addresstype: [Addressindex],
addresstypeindex: [Addressindex],
"base-size": [Txindex],
"block-count": [Dateindex],
"block-interval": [Height],
"block-interval-10p": [Dateindex],
"block-interval-25p": [Dateindex],
"block-interval-75p": [Dateindex],
"block-interval-90p": [Dateindex],
"block-interval-average": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"block-interval-max": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"block-interval-median": [Dateindex],
"block-interval-min": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
blockhash: [Height],
close: [Dateindex, Height, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"close-in-cents": [Dateindex, Height],
date: [Dateindex],
dateindex: [Dateindex, Height],
decadeindex: [Yearindex, Decadeindex],
difficulty: [Height],
difficultyepoch: [Height, Difficultyepoch],
"first-addressindex": [Height],
"first-dateindex": [Weekindex, Monthindex],
"first-emptyindex": [Height],
"first-height": [Dateindex, Difficultyepoch, Halvingepoch],
"first-monthindex": [Yearindex],
"first-multisigindex": [Height],
"first-open": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"first-opreturnindex": [Height],
"first-p2pk33index": [Height],
"first-p2pk65index": [Height],
"first-p2pkhindex": [Height],
"first-p2shindex": [Height],
"first-p2trindex": [Height],
"first-p2wpkhindex": [Height],
"first-p2wshindex": [Height],
"first-pushonlyindex": [Height],
"first-txindex": [Height],
"first-txinindex": [Height, Txindex],
"first-txoutindex": [Height, Txindex],
"first-unkownindex": [Height],
"first-yearindex": [Decadeindex],
"fixed-date": [Height],
halvingepoch: [Height, Halvingepoch],
height: [Addressindex, Height, Txindex],
high: [Dateindex, Height],
"high-in-cents": [Dateindex, Height],
"high-max": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"inputs-count": [Txindex],
"is-coinbase": [Txindex],
"is-explicitly-rbf": [Txindex],
"last-dateindex": [Weekindex, Monthindex],
"last-height": [Dateindex, Difficultyepoch, Halvingepoch],
"last-monthindex": [Yearindex],
"last-txindex": [Height],
"last-txinindex": [Txindex],
"last-txoutindex": [Txindex],
"last-yearindex": [Decadeindex],
locktime: [Txindex],
low: [Dateindex, Height],
"low-in-cents": [Dateindex, Height],
"low-min": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
monthindex: [Dateindex, Monthindex],
ohlc: [Dateindex, Height, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"ohlc-in-cents": [Dateindex, Height],
open: [Dateindex, Height],
"open-in-cents": [Dateindex, Height],
"outputs-count": [Txindex],
p2pk33addressbytes: [P2PK33index],
p2pk65addressbytes: [P2PK65index],
p2pkhaddressbytes: [P2PKHindex],
p2shaddressbytes: [P2SHindex],
p2traddressbytes: [P2TRindex],
p2wpkhaddressbytes: [P2WPKHindex],
p2wshaddressbytes: [P2WSHindex],
"real-date": [Height],
"sats-per-dollar": [Dateindex, Height],
size: [Height],
timestamp: [Height],
"total-block-count": [Dateindex],
"total-size": [Txindex],
txid: [Txindex],
txoutindex: [Txinindex],
txversion: [Txindex],
value: [Txoutindex],
weekindex: [Dateindex, Weekindex],
weight: [Height],
yearindex: [Monthindex, Yearindex],
export function createVecIdToIndexes() {
const Addressindex = /** @satisfies {Addressindex} */ (0);
const Dateindex = /** @satisfies {Dateindex} */ (1);
const Height = /** @satisfies {Height} */ (2);
const P2PK33index = /** @satisfies {P2PK33index} */ (3);
const P2PK65index = /** @satisfies {P2PK65index} */ (4);
const P2PKHindex = /** @satisfies {P2PKHindex} */ (5);
const P2SHindex = /** @satisfies {P2SHindex} */ (6);
const P2TRindex = /** @satisfies {P2TRindex} */ (7);
const P2WPKHindex = /** @satisfies {P2WPKHindex} */ (8);
const P2WSHindex = /** @satisfies {P2WSHindex} */ (9);
const Txindex = /** @satisfies {Txindex} */ (10);
const Txinindex = /** @satisfies {Txinindex} */ (11);
const Txoutindex = /** @satisfies {Txoutindex} */ (12);
const Weekindex = /** @satisfies {Weekindex} */ (13);
const Monthindex = /** @satisfies {Monthindex} */ (14);
const Yearindex = /** @satisfies {Yearindex} */ (15);
const Decadeindex = /** @satisfies {Decadeindex} */ (16);
const Difficultyepoch = /** @satisfies {Difficultyepoch} */ (17);
const Halvingepoch = /** @satisfies {Halvingepoch} */ (18);
return {
addressindex: [Txoutindex],
addresstype: [Addressindex],
addresstypeindex: [Addressindex],
"base-size": [Txindex],
"block-count": [Dateindex],
"block-interval": [Height],
"block-interval-10p": [Dateindex],
"block-interval-25p": [Dateindex],
"block-interval-75p": [Dateindex],
"block-interval-90p": [Dateindex],
"block-interval-average": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"block-interval-max": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"block-interval-median": [Dateindex],
"block-interval-min": [Dateindex, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
blockhash: [Height],
close: [Dateindex, Height, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"close-in-cents": [Dateindex, Height],
date: [Dateindex],
dateindex: [Dateindex, Height],
decadeindex: [Yearindex, Decadeindex],
difficulty: [Height],
difficultyepoch: [Height, Difficultyepoch],
"first-addressindex": [Height],
"first-dateindex": [Weekindex, Monthindex],
"first-emptyindex": [Height],
"first-height": [Dateindex, Difficultyepoch, Halvingepoch],
"first-monthindex": [Yearindex],
"first-multisigindex": [Height],
"first-open": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"first-opreturnindex": [Height],
"first-p2pk33index": [Height],
"first-p2pk65index": [Height],
"first-p2pkhindex": [Height],
"first-p2shindex": [Height],
"first-p2trindex": [Height],
"first-p2wpkhindex": [Height],
"first-p2wshindex": [Height],
"first-pushonlyindex": [Height],
"first-txindex": [Height],
"first-txinindex": [Height, Txindex],
"first-txoutindex": [Height, Txindex],
"first-unkownindex": [Height],
"first-yearindex": [Decadeindex],
"fixed-date": [Height],
"fixed-timestamp": [Height],
halvingepoch: [Height, Halvingepoch],
height: [Addressindex, Height, Txindex],
high: [Dateindex, Height],
"high-in-cents": [Dateindex, Height],
"high-max": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"inputs-count": [Txindex],
"is-coinbase": [Txindex],
"is-explicitly-rbf": [Txindex],
"last-dateindex": [Weekindex, Monthindex],
"last-height": [Dateindex, Difficultyepoch, Halvingepoch],
"last-monthindex": [Yearindex],
"last-txindex": [Height],
"last-txinindex": [Txindex],
"last-txoutindex": [Txindex],
"last-yearindex": [Decadeindex],
locktime: [Txindex],
low: [Dateindex, Height],
"low-in-cents": [Dateindex, Height],
"low-min": [Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
monthindex: [Dateindex, Monthindex],
ohlc: [Dateindex, Height, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch],
"ohlc-in-cents": [Dateindex, Height],
open: [Dateindex, Height],
"open-in-cents": [Dateindex, Height],
"outputs-count": [Txindex],
p2pk33addressbytes: [P2PK33index],
p2pk65addressbytes: [P2PK65index],
p2pkhaddressbytes: [P2PKHindex],
p2shaddressbytes: [P2SHindex],
p2traddressbytes: [P2TRindex],
p2wpkhaddressbytes: [P2WPKHindex],
p2wshaddressbytes: [P2WSHindex],
"real-date": [Height],
"sats-per-dollar": [Dateindex, Height],
size: [Height],
timestamp: [Dateindex, Height, Weekindex, Monthindex, Yearindex, Decadeindex, Difficultyepoch, Halvingepoch],
"total-block-count": [Dateindex],
"total-size": [Txindex],
txid: [Txindex],
txoutindex: [Txinindex],
txversion: [Txindex],
value: [Txoutindex],
weekindex: [Dateindex, Weekindex],
weight: [Height],
yearindex: [Monthindex, Yearindex],
}
}
/** @typedef {typeof VecIdToIndexes} VecIdToIndexes */
/** @typedef {ReturnType<typeof createVecIdToIndexes>} VecIdToIndexes */
/** @typedef {keyof VecIdToIndexes} VecId */