mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-08 06:01:57 -07:00
website: update
This commit is contained in:
@@ -54,3 +54,6 @@ docker/kibo
|
||||
|
||||
# Types
|
||||
website/scripts/types/paths.d.ts
|
||||
|
||||
# Misc
|
||||
OPENSATS.md
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
## Description
|
||||
|
||||
[**kibō**](https://kibo.money) (_hope_ in japanese) is primarily an open source Bitcoin Core data extractor and visualizer (similar to [Glassnode](https://glassnode.com)). The goal is to empower people with information that is often hard to come by and/or very pricey.
|
||||
[**kibō**](https://kibo.money) (_hope_ in japanese) is primarily an open source Bitcoin Core data extractor and visualizer (similar to [Glassnode](https://glassnode.com)) which goal is to empower anybody with data about Bitcoin for free.
|
||||
|
||||
The project is split in 3 parts:
|
||||
|
||||
|
||||
+27
-26
@@ -253,6 +253,10 @@
|
||||
--pink: oklch(0.624 0.245 357.444);
|
||||
--rose: oklch(0.6155 0.2495 17.012);
|
||||
--dollar: var(--green);
|
||||
--background-color: light-dark(var(--white), var(--black));
|
||||
--color: light-dark(var(--black), var(--white));
|
||||
--off-color: light-dark(var(--light-gray), var(--dark-gray));
|
||||
--border-color: light-dark(var(--lighter-gray), var(--darker-gray));
|
||||
|
||||
--font-size-2xs: 0.625rem;
|
||||
--line-height-2xs: 1rem;
|
||||
@@ -282,11 +286,6 @@
|
||||
|
||||
--default-main-width: 25rem;
|
||||
|
||||
--background-color: light-dark(var(--white), var(--black));
|
||||
--color: light-dark(var(--black), var(--white));
|
||||
--off-color: light-dark(var(--light-gray), var(--dark-gray));
|
||||
--border-color: light-dark(var(--lighter-gray), var(--darker-gray));
|
||||
|
||||
--emoji-filter: grayscale(1) contrast(5) invert(1);
|
||||
@media (prefers-color-scheme: dark) {
|
||||
--emoji-filter: grayscale(1) contrast(5);
|
||||
@@ -388,14 +387,16 @@
|
||||
aside {
|
||||
min-width: 0px;
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
margin-bottom: calc(var(--main-padding) + 1.5rem);
|
||||
|
||||
@media (max-width: 767px) {
|
||||
padding-bottom: calc(var(--main-padding) + 1.5rem);
|
||||
|
||||
html[data-display="standalone"] & {
|
||||
margin-bottom: calc(var(--main-padding) + 2rem);
|
||||
padding-bottom: calc(var(--main-padding) + 2rem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,7 +602,7 @@
|
||||
display: flex;
|
||||
margin: var(--main-padding);
|
||||
margin-bottom: var(--main-padding);
|
||||
z-index: 20;
|
||||
z-index: 100;
|
||||
pointer-events: none;
|
||||
justify-content: center;
|
||||
|
||||
@@ -649,9 +650,16 @@
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
section {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
select {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none;
|
||||
background: url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M7 10l5 5 5-5z" fill="gray"/><path d="M0 0h24v24H0z" fill="none"/></svg>')
|
||||
100% 50% no-repeat transparent;
|
||||
|
||||
&:focus-visible {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
nav,
|
||||
@@ -811,10 +819,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
#selected-frame {
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
|
||||
aside {
|
||||
> header {
|
||||
button {
|
||||
margin: -0.5rem 0;
|
||||
@@ -975,8 +980,6 @@
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: var(--main-padding);
|
||||
padding-right: var(--main-padding);
|
||||
font-size: var(--font-size-xs);
|
||||
line-height: var(--line-height-xs);
|
||||
gap: 0.5rem;
|
||||
@@ -986,7 +989,7 @@
|
||||
align-items: center;
|
||||
font-size: var(--font-size-xs);
|
||||
line-height: var(--line-height-xs);
|
||||
gap: 1rem;
|
||||
gap: 0.5rem;
|
||||
|
||||
> legend,
|
||||
> div {
|
||||
@@ -1010,8 +1013,8 @@
|
||||
}
|
||||
|
||||
> .chart-div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin-right: calc(var(--negative-main-padding) - 0.5rem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1528,12 +1531,10 @@
|
||||
</footer>
|
||||
</main>
|
||||
<aside id="aside">
|
||||
<section id="selected-frame">
|
||||
<div id="charts" hidden></div>
|
||||
<div id="simulation" hidden></div>
|
||||
<div id="live-price" hidden></div>
|
||||
<div id="moscow-time" hidden></div>
|
||||
</section>
|
||||
<div id="charts" hidden></div>
|
||||
<div id="simulation" hidden></div>
|
||||
<div id="live-price" hidden></div>
|
||||
<div id="moscow-time" hidden></div>
|
||||
</aside>
|
||||
<div id="share-div" hidden>
|
||||
<div id="share-content-div">
|
||||
|
||||
+28
-105
@@ -34,7 +34,7 @@ export function init({
|
||||
}) {
|
||||
console.log("init chart state");
|
||||
|
||||
/** @type {Array<(IChartApi & {whitespace: ISeriesApi<"Line">})>} */
|
||||
/** @type {ChartPane[]} */
|
||||
let charts = [];
|
||||
|
||||
const scale = signals.createMemo(() => selected().scale);
|
||||
@@ -53,15 +53,26 @@ export function init({
|
||||
descriptionElement.innerHTML = option.serializedPath;
|
||||
});
|
||||
|
||||
const div = window.document.createElement("div");
|
||||
elements.charts.append(div);
|
||||
// const div = window.document.createElement("div");
|
||||
// elements.charts.append(div);
|
||||
|
||||
const legendElement = window.document.createElement("legend");
|
||||
div.append(legendElement);
|
||||
// const legendElement = window.document.createElement("legend");
|
||||
// div.append(legendElement);
|
||||
|
||||
const chartListElement = window.document.createElement("div");
|
||||
chartListElement.classList.add("chart-list");
|
||||
div.append(chartListElement);
|
||||
// const chartListElement = window.document.createElement("div");
|
||||
// chartListElement.classList.add("chart-list");
|
||||
// div.append(chartListElement);
|
||||
//
|
||||
const {
|
||||
chartListElement,
|
||||
legendElement,
|
||||
createPane: addChart,
|
||||
} = lightweightCharts.createChart({
|
||||
parent: elements.charts,
|
||||
signals,
|
||||
colors,
|
||||
id: "chart",
|
||||
});
|
||||
|
||||
/**
|
||||
* @returns {TimeRange}
|
||||
@@ -248,59 +259,6 @@ export function init({
|
||||
}
|
||||
createFetchChunksOfVisibleDatasetsEffect();
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} parent
|
||||
* @param {number} chartIndex
|
||||
*/
|
||||
function createChartDiv(parent, chartIndex) {
|
||||
const chartWrapper = window.document.createElement("div");
|
||||
chartWrapper.classList.add("chart-wrapper");
|
||||
parent.append(chartWrapper);
|
||||
|
||||
const chartDiv = window.document.createElement("div");
|
||||
chartDiv.classList.add("chart-div");
|
||||
chartWrapper.append(chartDiv);
|
||||
|
||||
function createUnitAndModeElements() {
|
||||
const fieldset = window.document.createElement("fieldset");
|
||||
fieldset.dataset.size = "sm";
|
||||
chartWrapper.append(fieldset);
|
||||
|
||||
const unitName = signals.createSignal("");
|
||||
|
||||
const id = `chart-${chartIndex}-mode`;
|
||||
|
||||
const chartModes = /** @type {const} */ (["Linear", "Log"]);
|
||||
const chartMode = signals.createSignal(
|
||||
/** @type {Lowercase<typeof chartModes[number]>} */ (
|
||||
localStorage.getItem(id) ||
|
||||
chartModes[chartIndex ? 0 : 1].toLowerCase()
|
||||
),
|
||||
);
|
||||
|
||||
const field = utils.dom.createHorizontalChoiceField({
|
||||
choices: chartModes,
|
||||
selected: chartMode(),
|
||||
id,
|
||||
title: unitName,
|
||||
signals,
|
||||
});
|
||||
fieldset.append(field);
|
||||
|
||||
field.addEventListener("change", (event) => {
|
||||
// @ts-ignore
|
||||
const value = event.target.value;
|
||||
localStorage.setItem(id, value);
|
||||
chartMode.set(value);
|
||||
});
|
||||
|
||||
return { unitName, chartMode };
|
||||
}
|
||||
const { unitName, chartMode } = createUnitAndModeElements();
|
||||
|
||||
return { chartDiv, unitName, chartMode };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {IChartApi} chart
|
||||
*/
|
||||
@@ -526,7 +484,7 @@ export function init({
|
||||
* @param {ResourceDataset<S>} args.dataset
|
||||
* @param {SeriesBlueprint} args.seriesBlueprint
|
||||
* @param {Option} args.option
|
||||
* @param {IChartApi} args.chart
|
||||
* @param {ChartPane} args.chart
|
||||
* @param {number} args.index
|
||||
* @param {Series[]} args.chartSeries
|
||||
* @param {Accessor<number | undefined>} args.lastVisibleDatasetIndex
|
||||
@@ -630,42 +588,26 @@ export function init({
|
||||
if (!s) {
|
||||
switch (type) {
|
||||
case "Baseline": {
|
||||
s = lightweightCharts.createBaseLineSeries({
|
||||
chart,
|
||||
s = chart.createBaseLineSeries({
|
||||
color,
|
||||
options: seriesOptions,
|
||||
owner,
|
||||
signals,
|
||||
colors,
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "Candlestick": {
|
||||
s = lightweightCharts.createCandlesticksSeries({
|
||||
chart,
|
||||
s = chart.createCandlesticksSeries({
|
||||
options: seriesOptions,
|
||||
owner,
|
||||
signals,
|
||||
colors,
|
||||
});
|
||||
break;
|
||||
}
|
||||
// case "Histogram": {
|
||||
// s = createHistogramSeries({
|
||||
// chart,
|
||||
// options,
|
||||
// });
|
||||
// break;
|
||||
// }
|
||||
default:
|
||||
case "Line": {
|
||||
s = lightweightCharts.createLineSeries({
|
||||
chart,
|
||||
s = chart.createLineSeries({
|
||||
color,
|
||||
options: seriesOptions,
|
||||
owner,
|
||||
signals,
|
||||
colors,
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -766,7 +708,7 @@ export function init({
|
||||
* @param {PriceSeriesType} args.type
|
||||
* @param {VoidFunction} args.setMinMaxMarkersWhenIdle
|
||||
* @param {Option} args.option
|
||||
* @param {IChartApi} args.chart
|
||||
* @param {ChartPane} args.chart
|
||||
* @param {Series[]} args.chartSeries
|
||||
* @param {Accessor<number | undefined>} args.lastVisibleDatasetIndex
|
||||
*/
|
||||
@@ -864,16 +806,11 @@ export function init({
|
||||
const allSeries = [];
|
||||
|
||||
charts = chartsBlueprints.map((seriesBlueprints, chartIndex) => {
|
||||
const { chartDiv, unitName, chartMode } = createChartDiv(
|
||||
chartListElement,
|
||||
const chart = addChart({
|
||||
chartIndex,
|
||||
);
|
||||
|
||||
const chart = lightweightCharts.createChartWithWhitespace({
|
||||
scale,
|
||||
element: chartDiv,
|
||||
signals,
|
||||
colors,
|
||||
unit: option.unit || "US Dollars",
|
||||
whitespace: true,
|
||||
});
|
||||
|
||||
setInitialVisibleTimeRange(chart);
|
||||
@@ -1063,12 +1000,6 @@ export function init({
|
||||
});
|
||||
}
|
||||
createLinkPriceSeriesEffect();
|
||||
|
||||
/** @type {Unit} */
|
||||
const unit = "US Dollars";
|
||||
unitName.set(unit);
|
||||
} else {
|
||||
unitName.set(option.unit);
|
||||
}
|
||||
|
||||
[...seriesBlueprints].reverse().forEach((seriesBlueprint, index) => {
|
||||
@@ -1110,9 +1041,7 @@ export function init({
|
||||
|
||||
function createChartVisibilityEffect() {
|
||||
signals.createEffect(chartVisible, (chartVisible) => {
|
||||
const chartWrapper = chartDiv.parentElement;
|
||||
if (!chartWrapper) throw "Should exist";
|
||||
chartWrapper.hidden = !chartVisible;
|
||||
chart.setHidden(!chartVisible);
|
||||
});
|
||||
}
|
||||
createChartVisibilityEffect();
|
||||
@@ -1134,12 +1063,6 @@ export function init({
|
||||
}
|
||||
createTimeScaleVisibilityEffect();
|
||||
|
||||
signals.createEffect(chartMode, (chartMode) =>
|
||||
chart.priceScale("right").applyOptions({
|
||||
mode: chartMode === "linear" ? 0 : 1,
|
||||
}),
|
||||
);
|
||||
|
||||
chart.timeScale().subscribeVisibleLogicalRangeChange((logicalRange) => {
|
||||
if (!logicalRange) return;
|
||||
|
||||
|
||||
+280
-148
@@ -1,7 +1,7 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @import { Option, ResourceDataset, TimeScale, TimeRange, Unit, Marker, Weighted, DatasetPath, OHLC, FetchedJSON, DatasetValue, FetchedResult, AnyDatasetPath, SeriesBlueprint, BaselineSpecificSeriesBlueprint, CandlestickSpecificSeriesBlueprint, LineSpecificSeriesBlueprint, SpecificSeriesBlueprintWithChart, Signal, Color, DatasetCandlestickData, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, AnyPath, SimulationOption, Frequency } from "./types/self"
|
||||
* @import { Option, ResourceDataset, TimeScale, TimeRange, Unit, Marker, Weighted, DatasetPath, OHLC, FetchedJSON, DatasetValue, FetchedResult, AnyDatasetPath, SeriesBlueprint, BaselineSpecificSeriesBlueprint, CandlestickSpecificSeriesBlueprint, LineSpecificSeriesBlueprint, SpecificSeriesBlueprintWithChart, Signal, Color, DatasetCandlestickData, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, AnyPath, SimulationOption, Frequency, CreatePaneParameters, CreateBaselineSeriesParams, CreateCandlestickSeriesParams, CreateLineSeriesParams } from "./types/self"
|
||||
* @import {createChart as CreateClassicChart, createChartEx as CreateCustomChart, LineStyleOptions} from "../packages/lightweight-charts/v4.2.0/types";
|
||||
* @import * as _ from "../packages/ufuzzy/v1.0.14/types"
|
||||
* @import { DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, SingleValueData, ISeriesApi, Time, LineData, LogicalRange, SeriesMarker, CandlestickData, SeriesType, BaselineStyleOptions, SeriesOptionsCommon } from "../packages/lightweight-charts/v4.2.0/types"
|
||||
@@ -252,7 +252,7 @@ function initPackages() {
|
||||
* @param {Colors} args.colors
|
||||
* @param {DeepPartial<ChartOptions>} [args.options]
|
||||
*/
|
||||
function createChart({
|
||||
function createLightweightChart({
|
||||
scale,
|
||||
element,
|
||||
signals,
|
||||
@@ -282,9 +282,6 @@ function initPackages() {
|
||||
time: false,
|
||||
},
|
||||
},
|
||||
crosshair: {
|
||||
mode: 0,
|
||||
},
|
||||
localization: {
|
||||
priceFormatter: utils.locale.numberToShortUSFormat,
|
||||
locale: "en-us",
|
||||
@@ -360,127 +357,6 @@ function initPackages() {
|
||||
baseLineColor: "",
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {SpecificSeriesBlueprintWithChart<BaselineSpecificSeriesBlueprint> & {colors: Colors, signals: Signals}} args
|
||||
*/
|
||||
function createBaseLineSeries({
|
||||
chart,
|
||||
color,
|
||||
options,
|
||||
owner,
|
||||
colors,
|
||||
signals,
|
||||
}) {
|
||||
const topLineColor = color || colors.profit;
|
||||
const bottomLineColor = color || colors.loss;
|
||||
|
||||
function computeColors() {
|
||||
return {
|
||||
topLineColor: topLineColor(),
|
||||
bottomLineColor: bottomLineColor(),
|
||||
};
|
||||
}
|
||||
|
||||
const transparent = "transparent";
|
||||
|
||||
/** @type {DeepPartial<BaselineStyleOptions & SeriesOptionsCommon>} */
|
||||
const seriesOptions = {
|
||||
priceScaleId: "right",
|
||||
...defaultSeriesOptions,
|
||||
...options,
|
||||
topFillColor1: transparent,
|
||||
topFillColor2: transparent,
|
||||
bottomFillColor1: transparent,
|
||||
bottomFillColor2: transparent,
|
||||
...computeColors(),
|
||||
};
|
||||
|
||||
const series = chart.addBaselineSeries(seriesOptions);
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(computeColors, (computeColors) => {
|
||||
series.applyOptions(computeColors);
|
||||
});
|
||||
});
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SpecificSeriesBlueprintWithChart<CandlestickSpecificSeriesBlueprint> & {colors: Colors, signals: Signals}} args
|
||||
*/
|
||||
function createCandlesticksSeries({
|
||||
chart,
|
||||
options,
|
||||
owner,
|
||||
signals,
|
||||
colors,
|
||||
}) {
|
||||
function computeColors() {
|
||||
const upColor = colors.profit();
|
||||
const downColor = colors.loss();
|
||||
|
||||
return {
|
||||
upColor,
|
||||
wickUpColor: upColor,
|
||||
downColor,
|
||||
wickDownColor: downColor,
|
||||
};
|
||||
}
|
||||
|
||||
const candlestickSeries = chart.addCandlestickSeries({
|
||||
baseLineVisible: false,
|
||||
borderVisible: false,
|
||||
priceLineVisible: false,
|
||||
baseLineColor: "",
|
||||
borderColor: "",
|
||||
borderDownColor: "",
|
||||
borderUpColor: "",
|
||||
...options,
|
||||
...computeColors(),
|
||||
});
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(computeColors, (computeColors) => {
|
||||
candlestickSeries.applyOptions(computeColors);
|
||||
});
|
||||
});
|
||||
|
||||
return candlestickSeries;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {SpecificSeriesBlueprintWithChart<LineSpecificSeriesBlueprint> & {colors: Colors, signals: Signals}} args
|
||||
*/
|
||||
function createLineSeries({
|
||||
chart,
|
||||
color,
|
||||
options,
|
||||
owner,
|
||||
signals,
|
||||
colors,
|
||||
}) {
|
||||
function computeColors() {
|
||||
return {
|
||||
color: color(),
|
||||
};
|
||||
}
|
||||
|
||||
const series = chart.addLineSeries({
|
||||
...defaultSeriesOptions,
|
||||
...options,
|
||||
...computeColors(),
|
||||
});
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(computeColors, (computeColors) => {
|
||||
series.applyOptions(computeColors);
|
||||
});
|
||||
});
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
function initWhitespace() {
|
||||
const whitespaceStartDate = new Date("1970-01-01");
|
||||
const whitespaceStartDateYear =
|
||||
@@ -576,34 +452,285 @@ function initPackages() {
|
||||
const { setWhitespace } = initWhitespace();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Parameters<typeof createChart>[0]} args
|
||||
* @typeof {Object} PaneParameters
|
||||
* @property {Unit} param.unit
|
||||
* @param {TimeScale} param.scale
|
||||
* @param {number} [param.chartIndex]
|
||||
* @param {true} [param.whitespace]
|
||||
* @param {DeepPartial<ChartOptions>} [param.options]
|
||||
*/
|
||||
function createChartWithWhitespace({
|
||||
element,
|
||||
scale,
|
||||
colors,
|
||||
|
||||
/**
|
||||
* @param {Object} param0
|
||||
* @param {string} param0.id
|
||||
* @param {HTMLElement} param0.parent
|
||||
* @param {Signals} param0.signals
|
||||
* @param {Colors} param0.colors
|
||||
* @param {"static" | "dynamic"} [param0.kind]
|
||||
* @param {CreatePaneParameters[]} [param0.config]
|
||||
*/
|
||||
function createChart({
|
||||
parent,
|
||||
signals,
|
||||
colors,
|
||||
id: chartId,
|
||||
kind,
|
||||
config,
|
||||
}) {
|
||||
const chart =
|
||||
/** @type {IChartApi & {whitespace: ISeriesApi<"Line">}} */ (
|
||||
createChart({
|
||||
colors,
|
||||
element,
|
||||
scale,
|
||||
const div = window.document.createElement("div");
|
||||
div.classList.add("charts");
|
||||
parent.append(div);
|
||||
|
||||
const legendElement = window.document.createElement("legend");
|
||||
div.append(legendElement);
|
||||
|
||||
const chartListElement = window.document.createElement("div");
|
||||
chartListElement.classList.add("chart-list");
|
||||
div.append(chartListElement);
|
||||
|
||||
/**
|
||||
* @param {CreatePaneParameters} param
|
||||
*/
|
||||
function createPane({
|
||||
chartIndex,
|
||||
whitespace,
|
||||
scale,
|
||||
unit,
|
||||
options,
|
||||
config,
|
||||
}) {
|
||||
const chartWrapper = window.document.createElement("div");
|
||||
chartWrapper.classList.add("chart-wrapper");
|
||||
chartListElement.append(chartWrapper);
|
||||
|
||||
const chartDiv = window.document.createElement("div");
|
||||
chartDiv.classList.add("chart-div");
|
||||
chartWrapper.append(chartDiv);
|
||||
|
||||
options = { ...options };
|
||||
if (kind === "static") {
|
||||
options.handleScale = false;
|
||||
options.handleScroll = false;
|
||||
} else {
|
||||
options.crosshair = {
|
||||
...options.crosshair,
|
||||
mode: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const _chart = createLightweightChart({
|
||||
scale,
|
||||
element: chartDiv,
|
||||
signals,
|
||||
colors,
|
||||
options,
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {CreateBaselineSeriesParams} args
|
||||
*/
|
||||
function createBaseLineSeries({ color, options, owner, data }) {
|
||||
const topLineColor = color || colors.profit;
|
||||
const bottomLineColor = color || colors.loss;
|
||||
|
||||
function computeColors() {
|
||||
return {
|
||||
topLineColor: topLineColor(),
|
||||
bottomLineColor: bottomLineColor(),
|
||||
};
|
||||
}
|
||||
|
||||
const transparent = "transparent";
|
||||
|
||||
/** @type {DeepPartial<BaselineStyleOptions & SeriesOptionsCommon>} */
|
||||
const seriesOptions = {
|
||||
priceScaleId: "right",
|
||||
...defaultSeriesOptions,
|
||||
...options,
|
||||
topFillColor1: transparent,
|
||||
topFillColor2: transparent,
|
||||
bottomFillColor1: transparent,
|
||||
bottomFillColor2: transparent,
|
||||
...computeColors(),
|
||||
};
|
||||
|
||||
const series = _chart.addBaselineSeries(seriesOptions);
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(computeColors, (computeColors) => {
|
||||
series.applyOptions(computeColors);
|
||||
});
|
||||
});
|
||||
|
||||
if (data) {
|
||||
series.setData(data);
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CreateCandlestickSeriesParams} args
|
||||
*/
|
||||
function createCandlestickSeries({ options, owner, data }) {
|
||||
function computeColors() {
|
||||
const upColor = colors.profit();
|
||||
const downColor = colors.loss();
|
||||
|
||||
return {
|
||||
upColor,
|
||||
wickUpColor: upColor,
|
||||
downColor,
|
||||
wickDownColor: downColor,
|
||||
};
|
||||
}
|
||||
|
||||
const series = _chart.addCandlestickSeries({
|
||||
baseLineVisible: false,
|
||||
borderVisible: false,
|
||||
priceLineVisible: false,
|
||||
baseLineColor: "",
|
||||
borderColor: "",
|
||||
borderDownColor: "",
|
||||
borderUpColor: "",
|
||||
...options,
|
||||
...computeColors(),
|
||||
});
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(computeColors, (computeColors) => {
|
||||
series.applyOptions(computeColors);
|
||||
});
|
||||
});
|
||||
|
||||
if (data) {
|
||||
series.setData(data);
|
||||
}
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {CreateLineSeriesParams} args
|
||||
*/
|
||||
function createLineSeries({ color, options, owner, data }) {
|
||||
function computeColors() {
|
||||
return {
|
||||
color: color(),
|
||||
};
|
||||
}
|
||||
|
||||
const series = _chart.addLineSeries({
|
||||
...defaultSeriesOptions,
|
||||
...options,
|
||||
...computeColors(),
|
||||
});
|
||||
|
||||
if (data) {
|
||||
series.setData(data);
|
||||
}
|
||||
|
||||
signals.runWithOwner(owner, () => {
|
||||
signals.createEffect(computeColors, (computeColors) => {
|
||||
series.applyOptions(computeColors);
|
||||
});
|
||||
});
|
||||
|
||||
return series;
|
||||
}
|
||||
|
||||
const chart =
|
||||
/** @type {IChartApi & { whitespace: ISeriesApi<"Line">, createBaseLineSeries: typeof createBaseLineSeries, createCandlesticksSeries: typeof createCandlestickSeries, createLineSeries: typeof createLineSeries; setHidden: (b: boolean) => void }} */ (
|
||||
_chart
|
||||
);
|
||||
|
||||
if (whitespace) {
|
||||
chart.whitespace = setWhitespace(_chart, scale);
|
||||
}
|
||||
|
||||
chart.createBaseLineSeries = createBaseLineSeries;
|
||||
chart.createCandlesticksSeries = createCandlestickSeries;
|
||||
chart.createLineSeries = createLineSeries;
|
||||
chart.setHidden = (b) => {
|
||||
chartWrapper.hidden = b;
|
||||
};
|
||||
|
||||
function createUnitAndModeElements() {
|
||||
const fieldset = window.document.createElement("fieldset");
|
||||
fieldset.dataset.size = "sm";
|
||||
chartWrapper.append(fieldset);
|
||||
|
||||
const id = `chart-${chartId}-${chartIndex}-mode`;
|
||||
|
||||
const chartModes = /** @type {const} */ (["Linear", "Log"]);
|
||||
const chartMode = signals.createSignal(
|
||||
/** @type {Lowercase<typeof chartModes[number]>} */ (
|
||||
localStorage.getItem(id) ||
|
||||
chartModes[chartIndex ? 0 : 1].toLowerCase()
|
||||
),
|
||||
);
|
||||
|
||||
const field = utils.dom.createHorizontalChoiceField({
|
||||
choices: chartModes,
|
||||
selected: chartMode(),
|
||||
id,
|
||||
title: unit,
|
||||
signals,
|
||||
})
|
||||
);
|
||||
chart.whitespace = setWhitespace(chart, scale);
|
||||
return chart;
|
||||
});
|
||||
fieldset.append(field);
|
||||
|
||||
field.addEventListener("change", (event) => {
|
||||
// @ts-ignore
|
||||
const value = event.target.value;
|
||||
localStorage.setItem(id, value);
|
||||
chartMode.set(value);
|
||||
});
|
||||
|
||||
signals.createEffect(chartMode, (chartMode) =>
|
||||
_chart.priceScale("right").applyOptions({
|
||||
mode: chartMode === "linear" ? 0 : 1,
|
||||
}),
|
||||
);
|
||||
}
|
||||
createUnitAndModeElements();
|
||||
|
||||
config?.forEach((params) => {
|
||||
switch (params.kind) {
|
||||
case "line": {
|
||||
chart.createLineSeries(params);
|
||||
break;
|
||||
}
|
||||
case "candle": {
|
||||
chart.createCandlesticksSeries(params);
|
||||
break;
|
||||
}
|
||||
case "baseline": {
|
||||
chart.createBaseLineSeries(params);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (kind === "static") {
|
||||
chart.timeScale().fitContent();
|
||||
}
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
config?.forEach((params) => {
|
||||
createPane(params);
|
||||
});
|
||||
|
||||
return {
|
||||
legendElement,
|
||||
chartListElement,
|
||||
createPane,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createChart,
|
||||
createChartWithWhitespace,
|
||||
createBaseLineSeries,
|
||||
createCandlesticksSeries,
|
||||
createLineSeries,
|
||||
};
|
||||
},
|
||||
),
|
||||
@@ -654,6 +781,7 @@ const packages = initPackages();
|
||||
/**
|
||||
* @typedef {Awaited<ReturnType<typeof packages.signals>>} Signals
|
||||
* @typedef {Awaited<ReturnType<typeof packages.lightweightCharts>>} LightweightCharts
|
||||
* @typedef {ReturnType<ReturnType<Awaited<ReturnType<typeof packages.lightweightCharts>>['createChart']>['createPane']>} ChartPane
|
||||
*/
|
||||
|
||||
const options = import("./options.js");
|
||||
@@ -1700,7 +1828,6 @@ const elements = {
|
||||
search: utils.dom.getElementById("search"),
|
||||
nav: utils.dom.getElementById("nav"),
|
||||
navHeader: utils.dom.getElementById("nav-header"),
|
||||
selectedFrame: utils.dom.getElementById("selected-frame"),
|
||||
searchInput: /** @type {HTMLInputElement} */ (
|
||||
utils.dom.getElementById("search-input")
|
||||
),
|
||||
@@ -1914,8 +2041,13 @@ function createColors(dark) {
|
||||
offDollars: emerald,
|
||||
|
||||
yellow,
|
||||
lime,
|
||||
orange,
|
||||
red,
|
||||
sky,
|
||||
blue,
|
||||
rose,
|
||||
pink,
|
||||
|
||||
_1d: pink,
|
||||
_1w: red,
|
||||
@@ -2813,7 +2945,7 @@ packages.signals().then((signals) =>
|
||||
}
|
||||
createMobileSwitchEffect();
|
||||
|
||||
utils.dom.onFirstIntersection(elements.selectedFrame, initSelectedFrame);
|
||||
utils.dom.onFirstIntersection(elements.aside, initSelectedFrame);
|
||||
}
|
||||
initSelected();
|
||||
|
||||
|
||||
+237
-191
@@ -292,14 +292,8 @@ export function init({
|
||||
);
|
||||
|
||||
const firstParagraph = window.document.createElement("p");
|
||||
resultsElement.append(firstParagraph);
|
||||
|
||||
const secondParagraph = window.document.createElement("p");
|
||||
resultsElement.append(secondParagraph);
|
||||
|
||||
const parent = window.document.createElement("div");
|
||||
parent.classList.add("chart-list");
|
||||
resultsElement.append(parent);
|
||||
|
||||
const owner = signals.getOwner();
|
||||
|
||||
@@ -330,24 +324,27 @@ export function init({
|
||||
fees,
|
||||
}) => {
|
||||
console.log({ start, end });
|
||||
parent.innerHTML = "";
|
||||
|
||||
resultsElement.innerHTML = "";
|
||||
resultsElement.append(firstParagraph);
|
||||
resultsElement.append(secondParagraph);
|
||||
|
||||
if (!start || !end || start > end) return;
|
||||
|
||||
const range = utils.date.getRange(start, end);
|
||||
|
||||
/** @type {LineData<Time>[]} */
|
||||
const investedData = [];
|
||||
const totalInvestedAmountData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const returnData = [];
|
||||
const bitcoinValueData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const bitcoinData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const resultData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const dollarsData = [];
|
||||
const dollarsLeftData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const totalData = [];
|
||||
const totalValueData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const investmentData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
@@ -357,17 +354,26 @@ export function init({
|
||||
/** @type {LineData<Time>[]} */
|
||||
const bitcoinPriceData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const investmentsData = [];
|
||||
const buyCountData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const totalFeesPaidData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const daysCountData = [];
|
||||
/** @type {LineData<Time>[]} */
|
||||
const profitableDaysRatioData = [];
|
||||
|
||||
let bitcoin = 0;
|
||||
let dollars = initialDollarAmount;
|
||||
let investedAmount = 0;
|
||||
let investmentsCount = 0;
|
||||
let buyCount = 0;
|
||||
let averagePricePaid = 0;
|
||||
let _return = 0;
|
||||
let bitcoinValue = 0;
|
||||
let roi = 0;
|
||||
|
||||
let feesPaid = 0;
|
||||
let totalValue = 0;
|
||||
let totalFeesPaid = 0;
|
||||
let daysCount = range.length;
|
||||
let profitableDays = 0;
|
||||
let unprofitableDays = 0;
|
||||
|
||||
range.forEach((date, index) => {
|
||||
const year = date.getUTCFullYear();
|
||||
@@ -383,13 +389,13 @@ export function init({
|
||||
|
||||
if (!close) return;
|
||||
|
||||
let investmentPreFees = 0;
|
||||
let dailyInvestment = 0;
|
||||
/** @param {number} value */
|
||||
function invest(value) {
|
||||
value = Math.min(dollars, value);
|
||||
investmentPreFees += value;
|
||||
dailyInvestment += value;
|
||||
dollars -= value;
|
||||
investmentsCount += 1;
|
||||
buyCount += 1;
|
||||
}
|
||||
if (!index) {
|
||||
invest(initialSwap);
|
||||
@@ -398,19 +404,31 @@ export function init({
|
||||
invest(recurrentSwap);
|
||||
}
|
||||
|
||||
let investment = investmentPreFees * (1 - (fees || 0) / 100);
|
||||
feesPaid += investmentPreFees - investment;
|
||||
let dailyInvestmentPostFees =
|
||||
dailyInvestment * (1 - (fees || 0) / 100);
|
||||
|
||||
const bitcoinAdded = investment / close;
|
||||
totalFeesPaid += dailyInvestment - dailyInvestmentPostFees;
|
||||
|
||||
const bitcoinAdded = dailyInvestmentPostFees / close;
|
||||
bitcoin += bitcoinAdded;
|
||||
|
||||
investedAmount += investment;
|
||||
investedAmount += dailyInvestmentPostFees;
|
||||
|
||||
_return = close * bitcoin;
|
||||
bitcoinValue = close * bitcoin;
|
||||
|
||||
totalValue = dollars + bitcoinValue;
|
||||
|
||||
averagePricePaid = investedAmount / bitcoin;
|
||||
|
||||
roi = (_return / investedAmount - 1) * 100;
|
||||
roi = (bitcoinValue / investedAmount - 1) * 100;
|
||||
|
||||
const daysCount = index + 1;
|
||||
|
||||
if (roi >= 0) {
|
||||
profitableDays += 1;
|
||||
} else {
|
||||
unprofitableDays += 1;
|
||||
}
|
||||
|
||||
bitcoinPriceData.push({
|
||||
time,
|
||||
@@ -422,14 +440,14 @@ export function init({
|
||||
value: bitcoin,
|
||||
});
|
||||
|
||||
investedData.push({
|
||||
totalInvestedAmountData.push({
|
||||
time,
|
||||
value: investedAmount,
|
||||
});
|
||||
|
||||
returnData.push({
|
||||
bitcoinValueData.push({
|
||||
time,
|
||||
value: _return,
|
||||
value: bitcoinValue,
|
||||
});
|
||||
|
||||
resultData.push({
|
||||
@@ -437,19 +455,19 @@ export function init({
|
||||
value: roi,
|
||||
});
|
||||
|
||||
dollarsData.push({
|
||||
dollarsLeftData.push({
|
||||
time,
|
||||
value: dollars,
|
||||
});
|
||||
|
||||
totalData.push({
|
||||
totalValueData.push({
|
||||
time,
|
||||
value: dollars + _return,
|
||||
value: totalValue,
|
||||
});
|
||||
|
||||
investmentData.push({
|
||||
time,
|
||||
value: investment,
|
||||
value: dailyInvestment,
|
||||
});
|
||||
|
||||
bitcoinAddedData.push({
|
||||
@@ -462,19 +480,27 @@ export function init({
|
||||
value: averagePricePaid,
|
||||
});
|
||||
|
||||
investmentsData.push({
|
||||
buyCountData.push({
|
||||
time,
|
||||
value: investmentsCount,
|
||||
value: buyCount,
|
||||
});
|
||||
|
||||
totalFeesPaidData.push({
|
||||
time,
|
||||
value: totalFeesPaid,
|
||||
});
|
||||
|
||||
daysCountData.push({
|
||||
time,
|
||||
value: daysCount,
|
||||
});
|
||||
|
||||
profitableDaysRatioData.push({
|
||||
time,
|
||||
value: profitableDays / daysCount,
|
||||
});
|
||||
});
|
||||
|
||||
// const { headerElement } = utils.dom.createHeader({
|
||||
// title: "TItle",
|
||||
// description: "Description",
|
||||
// });
|
||||
|
||||
// parent.append(headerElement);
|
||||
|
||||
const f = utils.locale.numberToUSFormat;
|
||||
/**
|
||||
* @param {string} c
|
||||
@@ -482,168 +508,188 @@ export function init({
|
||||
*/
|
||||
const c = (c, t) => createColoredSpan({ color: c, text: t });
|
||||
|
||||
firstParagraph.innerHTML = `After exchanging ${c("dollar", `$${f(investedAmount)}`)} in the span of ${c("sky", f(range.length))} days, you would've accumulated ${c("orange", f(bitcoin))} Bitcoin worth ${c("dollar", `$${f(_return)}`)} at an average price of ${c("dollar", `$${f(averagePricePaid)}`)} per Bitcoin with a return of investment of ${c("yellow", `${f(roi)}%`)}.`;
|
||||
firstParagraph.innerHTML = `After exchanging ${c("dollar", `$${f(investedAmount)}`)} in the span of ${c("sky", f(daysCount))} days, you would've accumulated ${c("orange", f(bitcoin))} Bitcoin worth ${c("dollar", `$${f(bitcoinValue)}`)} at an average price of ${c("dollar", `$${f(averagePricePaid)}`)} per Bitcoin with a return of investment of ${c("yellow", `${f(roi)}%`)}.`;
|
||||
|
||||
secondParagraph.innerHTML = `After exchanging ${c("dollar", `$${f(investedAmount)}`)} in the span of ${c("sky", f(range.length))} days, you would've accumulated ${c("orange", f(bitcoin))} Bitcoin worth ${c("dollar", `$${f(_return)}`)} at an average price of ${c("dollar", `$${f(averagePricePaid)}`)} per Bitcoin with a return of investment of ${c("yellow", `${f(roi)}%`)}.`;
|
||||
secondParagraph.innerHTML = `Work in progress`;
|
||||
|
||||
(() => {
|
||||
const chartWrapper = window.document.createElement("div");
|
||||
chartWrapper.classList.add("chart-wrapper");
|
||||
parent.append(chartWrapper);
|
||||
|
||||
const chartDiv = window.document.createElement("div");
|
||||
chartDiv.classList.add("chart-div");
|
||||
chartWrapper.append(chartDiv);
|
||||
|
||||
const chart = lightweightCharts.createChart({
|
||||
scale: "date",
|
||||
element: chartDiv,
|
||||
signals,
|
||||
colors,
|
||||
options: {
|
||||
handleScale: false,
|
||||
handleScroll: false,
|
||||
lightweightCharts.createChart({
|
||||
parent: resultsElement,
|
||||
signals,
|
||||
colors,
|
||||
id: `simulation-0`,
|
||||
kind: "static",
|
||||
config: [
|
||||
{
|
||||
unit: "US Dollars",
|
||||
scale: "date",
|
||||
config: [
|
||||
{
|
||||
kind: "line",
|
||||
color: colors.dollars,
|
||||
owner,
|
||||
data: totalInvestedAmountData,
|
||||
},
|
||||
{
|
||||
kind: "line",
|
||||
color: colors.bitcoin,
|
||||
owner,
|
||||
data: bitcoinValueData,
|
||||
},
|
||||
{
|
||||
kind: "line",
|
||||
color: colors.lime,
|
||||
owner,
|
||||
data: dollarsLeftData,
|
||||
},
|
||||
{
|
||||
kind: "line",
|
||||
color: colors.default,
|
||||
owner,
|
||||
data: totalValueData,
|
||||
},
|
||||
{
|
||||
kind: "line",
|
||||
color: colors.yellow,
|
||||
owner,
|
||||
data: investmentData,
|
||||
},
|
||||
{
|
||||
kind: "line",
|
||||
color: colors.red,
|
||||
owner,
|
||||
data: totalFeesPaidData,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
],
|
||||
});
|
||||
|
||||
const line = chart.addLineSeries();
|
||||
|
||||
line.setData(investedData);
|
||||
|
||||
const line2 = chart.addLineSeries();
|
||||
|
||||
line2.setData(returnData);
|
||||
|
||||
const line3 = chart.addLineSeries();
|
||||
|
||||
line3.setData(dollarsData);
|
||||
|
||||
const line4 = chart.addLineSeries();
|
||||
|
||||
line4.setData(totalData);
|
||||
|
||||
const line5 = chart.addLineSeries();
|
||||
|
||||
line5.setData(investmentData);
|
||||
|
||||
chart.timeScale().fitContent();
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const chartWrapper = window.document.createElement("div");
|
||||
chartWrapper.classList.add("chart-wrapper");
|
||||
parent.append(chartWrapper);
|
||||
|
||||
const chartDiv = window.document.createElement("div");
|
||||
chartDiv.classList.add("chart-div");
|
||||
chartWrapper.append(chartDiv);
|
||||
|
||||
const chart = lightweightCharts.createChart({
|
||||
scale: "date",
|
||||
element: chartDiv,
|
||||
signals,
|
||||
colors,
|
||||
options: {
|
||||
handleScale: false,
|
||||
handleScroll: false,
|
||||
lightweightCharts.createChart({
|
||||
parent: resultsElement,
|
||||
signals,
|
||||
colors,
|
||||
id: `simulation-1`,
|
||||
kind: "static",
|
||||
config: [
|
||||
{
|
||||
unit: "US Dollars",
|
||||
scale: "date",
|
||||
config: [
|
||||
{
|
||||
kind: "line",
|
||||
color: colors.bitcoin,
|
||||
owner,
|
||||
data: bitcoinData,
|
||||
},
|
||||
{
|
||||
kind: "line",
|
||||
color: colors.lightBitcoin,
|
||||
owner,
|
||||
data: bitcoinAddedData,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
],
|
||||
});
|
||||
|
||||
const line = chart.addLineSeries();
|
||||
|
||||
line.setData(bitcoinData);
|
||||
|
||||
const line2 = chart.addLineSeries();
|
||||
|
||||
line2.setData(bitcoinAddedData);
|
||||
|
||||
chart.timeScale().fitContent();
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const chartWrapper = window.document.createElement("div");
|
||||
chartWrapper.classList.add("chart-wrapper");
|
||||
parent.append(chartWrapper);
|
||||
|
||||
const chartDiv = window.document.createElement("div");
|
||||
chartDiv.classList.add("chart-div");
|
||||
chartWrapper.append(chartDiv);
|
||||
|
||||
const chart = lightweightCharts.createChart({
|
||||
scale: "date",
|
||||
element: chartDiv,
|
||||
signals,
|
||||
colors,
|
||||
options: {
|
||||
handleScale: false,
|
||||
handleScroll: false,
|
||||
lightweightCharts.createChart({
|
||||
parent: resultsElement,
|
||||
signals,
|
||||
colors,
|
||||
id: `simulation-2`,
|
||||
kind: "static",
|
||||
config: [
|
||||
{
|
||||
unit: "US Dollars",
|
||||
scale: "date",
|
||||
config: [
|
||||
{
|
||||
kind: "baseline",
|
||||
owner,
|
||||
data: resultData,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
],
|
||||
});
|
||||
|
||||
const line = chart.addLineSeries();
|
||||
|
||||
line.setData(resultData);
|
||||
|
||||
chart.timeScale().fitContent();
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const chartWrapper = window.document.createElement("div");
|
||||
chartWrapper.classList.add("chart-wrapper");
|
||||
parent.append(chartWrapper);
|
||||
|
||||
const chartDiv = window.document.createElement("div");
|
||||
chartDiv.classList.add("chart-div");
|
||||
chartWrapper.append(chartDiv);
|
||||
|
||||
const chart = lightweightCharts.createChart({
|
||||
scale: "date",
|
||||
element: chartDiv,
|
||||
signals,
|
||||
colors,
|
||||
options: {
|
||||
handleScale: false,
|
||||
handleScroll: false,
|
||||
lightweightCharts.createChart({
|
||||
parent: resultsElement,
|
||||
signals,
|
||||
colors,
|
||||
id: `simulation-3`,
|
||||
kind: "static",
|
||||
config: [
|
||||
{
|
||||
unit: "US Dollars",
|
||||
scale: "date",
|
||||
config: [
|
||||
{
|
||||
kind: "line",
|
||||
owner,
|
||||
color: colors.bitcoin,
|
||||
data: bitcoinPriceData,
|
||||
},
|
||||
{
|
||||
kind: "line",
|
||||
owner,
|
||||
color: colors.default,
|
||||
data: averagePricePaidData,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
],
|
||||
});
|
||||
|
||||
const line = chart.addLineSeries();
|
||||
|
||||
line.setData(bitcoinPriceData);
|
||||
|
||||
const line2 = chart.addLineSeries();
|
||||
|
||||
line2.setData(averagePricePaidData);
|
||||
|
||||
chart.timeScale().fitContent();
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const chartWrapper = window.document.createElement("div");
|
||||
chartWrapper.classList.add("chart-wrapper");
|
||||
parent.append(chartWrapper);
|
||||
|
||||
const chartDiv = window.document.createElement("div");
|
||||
chartDiv.classList.add("chart-div");
|
||||
chartWrapper.append(chartDiv);
|
||||
|
||||
const chart = lightweightCharts.createChart({
|
||||
scale: "date",
|
||||
element: chartDiv,
|
||||
signals,
|
||||
colors,
|
||||
options: {
|
||||
handleScale: false,
|
||||
handleScroll: false,
|
||||
lightweightCharts.createChart({
|
||||
parent: resultsElement,
|
||||
signals,
|
||||
colors,
|
||||
id: `simulation-4`,
|
||||
kind: "static",
|
||||
config: [
|
||||
{
|
||||
unit: "US Dollars",
|
||||
scale: "date",
|
||||
config: [
|
||||
{
|
||||
kind: "line",
|
||||
owner,
|
||||
color: colors.blue,
|
||||
data: buyCountData,
|
||||
},
|
||||
{
|
||||
kind: "line",
|
||||
owner,
|
||||
color: colors.sky,
|
||||
data: daysCountData,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
],
|
||||
});
|
||||
|
||||
const line = chart.addLineSeries();
|
||||
|
||||
line.setData(investmentsData);
|
||||
|
||||
chart.timeScale().fitContent();
|
||||
})();
|
||||
lightweightCharts.createChart({
|
||||
parent: resultsElement,
|
||||
signals,
|
||||
colors,
|
||||
id: `simulation-5`,
|
||||
kind: "static",
|
||||
config: [
|
||||
{
|
||||
unit: "Percentage",
|
||||
scale: "date",
|
||||
config: [
|
||||
{
|
||||
kind: "line",
|
||||
owner,
|
||||
color: colors.pink,
|
||||
data: profitableDaysRatioData,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
Vendored
+27
-4
@@ -15,6 +15,7 @@ import {
|
||||
SeriesType,
|
||||
IChartApi,
|
||||
ISeriesApi,
|
||||
BaselineData,
|
||||
} from "../../packages/lightweight-charts/v4.2.0/types";
|
||||
import { DatePath, HeightPath, LastPath } from "./paths";
|
||||
import { Owner } from "../../packages/solid-signals/2024-11-02/types/core/owner";
|
||||
@@ -46,18 +47,21 @@ interface BaselineSpecificSeriesBlueprint {
|
||||
type: "Baseline";
|
||||
color?: Color;
|
||||
options?: DeepPartial<BaselineStyleOptions & SeriesOptionsCommon>;
|
||||
data?: BaselineData<Time>[];
|
||||
}
|
||||
|
||||
interface CandlestickSpecificSeriesBlueprint {
|
||||
type: "Candlestick";
|
||||
color?: Color;
|
||||
options?: DeepPartial<CandlestickStyleOptions & SeriesOptionsCommon>;
|
||||
data?: CandlestickData<Time>[];
|
||||
}
|
||||
|
||||
interface LineSpecificSeriesBlueprint {
|
||||
type?: "Line";
|
||||
color: Color;
|
||||
options?: DeepPartial<LineStyleOptions & SeriesOptionsCommon>;
|
||||
data?: LineData<Time>[];
|
||||
}
|
||||
|
||||
type AnySpecificSeriesBlueprint =
|
||||
@@ -66,10 +70,16 @@ type AnySpecificSeriesBlueprint =
|
||||
| LineSpecificSeriesBlueprint;
|
||||
|
||||
type SpecificSeriesBlueprintWithChart<A extends AnySpecificSeriesBlueprint> = {
|
||||
chart: IChartApi;
|
||||
owner: Owner | null;
|
||||
} & Omit<A, "type">;
|
||||
|
||||
type CreateBaselineSeriesParams =
|
||||
SpecificSeriesBlueprintWithChart<BaselineSpecificSeriesBlueprint>;
|
||||
type CreateLineSeriesParams =
|
||||
SpecificSeriesBlueprintWithChart<LineSpecificSeriesBlueprint>;
|
||||
type CreateCandlestickSeriesParams =
|
||||
SpecificSeriesBlueprintWithChart<CandlestickSpecificSeriesBlueprint>;
|
||||
|
||||
type SeriesBlueprint = {
|
||||
datasetPath: AnyDatasetPath;
|
||||
title: string;
|
||||
@@ -224,7 +234,7 @@ interface OHLC {
|
||||
|
||||
interface ResourceDataset<
|
||||
Scale extends TimeScale,
|
||||
Type extends OHLC | number = number
|
||||
Type extends OHLC | number = number,
|
||||
> {
|
||||
scale: Scale;
|
||||
url: string;
|
||||
@@ -243,7 +253,7 @@ interface FetchedResult<
|
||||
SingleValueData | ValuedCandlestickData
|
||||
> = DatasetValue<
|
||||
Type extends number ? SingleValueData : ValuedCandlestickData
|
||||
>
|
||||
>,
|
||||
> {
|
||||
at: Date | null;
|
||||
json: Signal<FetchedJSON<Scale, Type> | null>;
|
||||
@@ -273,7 +283,7 @@ interface FetchedChunk {
|
||||
|
||||
type FetchedDataset<
|
||||
Scale extends TimeScale,
|
||||
Type extends number | OHLC
|
||||
Type extends number | OHLC,
|
||||
> = Scale extends "date"
|
||||
? FetchedDateDataset<Type>
|
||||
: FetchedHeightDataset<Type>;
|
||||
@@ -376,3 +386,16 @@ interface Frequency {
|
||||
value: string;
|
||||
isTriggerDay: (date: Date) => boolean;
|
||||
}
|
||||
|
||||
interface CreatePaneParameters {
|
||||
unit: Unit;
|
||||
scale: TimeScale;
|
||||
chartIndex?: number;
|
||||
whitespace?: true;
|
||||
options?: DeepPartial<ChartOptions>;
|
||||
config?: (
|
||||
| ({ kind: "line" } & CreateLineSeriesParams)
|
||||
| ({ kind: "candle" } & CreateCandlestickSeriesParams)
|
||||
| ({ kind: "baseline" } & CreateBaselineSeriesParams)
|
||||
)[];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
#charts {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-height: 0;
|
||||
padding: var(--main-padding);
|
||||
|
||||
@@ -23,11 +24,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
.charts {
|
||||
flex: 1;
|
||||
margin-top: 2rem;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 2rem;
|
||||
min-height: 0;
|
||||
|
||||
> legend {
|
||||
@@ -80,9 +82,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
.chart-list {
|
||||
.chart-div {
|
||||
margin-left: var(--negative-main-padding);
|
||||
margin-right: calc(var(--negative-main-padding) - 0.5rem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,8 @@
|
||||
#simulation {
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
header {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
> div:first-child {
|
||||
max-width: var(--default-main-width);
|
||||
border-right: 1px;
|
||||
padding-bottom: var(--bottom-area);
|
||||
}
|
||||
|
||||
> div:last-child {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1rem;
|
||||
|
||||
p {
|
||||
font-size: var(--font-size-lg);
|
||||
text-wrap: pretty;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
> span {
|
||||
display: block;
|
||||
}
|
||||
small {
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
}
|
||||
|
||||
> div {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
@@ -60,8 +26,62 @@
|
||||
}
|
||||
}
|
||||
|
||||
.chart-list {
|
||||
max-height: 2000px;
|
||||
margin-right: calc(var(--negative-main-padding) - 0.5rem);
|
||||
@media (max-width: 767px) {
|
||||
overflow-y: auto;
|
||||
|
||||
> div:first-child {
|
||||
border-bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
flex-direction: row;
|
||||
|
||||
> div {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding-bottom: var(--bottom-area);
|
||||
}
|
||||
|
||||
> div:first-child {
|
||||
max-width: var(--default-main-width);
|
||||
border-right: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
header {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
> div:last-child {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
overflow-x: hidden;
|
||||
|
||||
p {
|
||||
text-wrap: pretty;
|
||||
}
|
||||
}
|
||||
|
||||
label {
|
||||
> span {
|
||||
display: block;
|
||||
}
|
||||
small {
|
||||
font-size: var(--font-size-base);
|
||||
}
|
||||
}
|
||||
|
||||
.charts {
|
||||
flex-shrink: 0;
|
||||
height: 400px;
|
||||
|
||||
.chart-div {
|
||||
margin-left: calc(var(--negative-main-padding) / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user