investing: more data + charts

This commit is contained in:
nym21
2026-01-26 10:28:26 +01:00
parent 5c824e50b8
commit 371fb2cb17
30 changed files with 1922 additions and 1010 deletions

View File

@@ -85,7 +85,7 @@ export function createPriceWithRatioOptions(
return [
{
name: "price",
name: "Price",
title,
top: [line({ metric: priceMetric, name: legend, color, unit: Unit.usd })],
},
@@ -100,6 +100,9 @@ export function createPriceWithRatioOptions(
];
}
/** Common period IDs to show at top level */
const COMMON_PERIODS = ["1w", "1m", "200d", "1y", "200w", "4y"];
/**
* @param {PartialContext} ctx
* @param {MarketMovingAverage} movingAverage
@@ -113,35 +116,54 @@ export function createAveragesSection(ctx, movingAverage) {
* @param {string} label
* @param {ReturnType<typeof buildSmaAverages> | ReturnType<typeof buildEmaAverages>} averages
*/
const createSubSection = (label, averages) => ({
name: label,
tree: [
{
name: "Compare",
title: `Price ${label}s`,
top: averages.map(({ id, color, ratio }) =>
line({
metric: ratio.price,
name: id,
const createSubSection = (label, averages) => {
const commonAverages = averages.filter(({ id }) => COMMON_PERIODS.includes(id));
const moreAverages = averages.filter(({ id }) => !COMMON_PERIODS.includes(id));
return {
name: label,
tree: [
{
name: "Compare",
title: `Price ${label}s`,
top: averages.map(({ id, color, ratio }) =>
line({
metric: ratio.price,
name: id,
color,
unit: Unit.usd,
}),
),
},
// Common periods at top level
...commonAverages.map(({ name, color, ratio }) => ({
name,
tree: createPriceWithRatioOptions(ctx, {
ratio,
title: `${name} ${label}`,
legend: "average",
color,
unit: Unit.usd,
}),
),
},
...averages.map(({ name, color, ratio }) => ({
name,
tree: createPriceWithRatioOptions(ctx, {
ratio,
title: `${name} ${label}`,
legend: "average",
color,
}),
})),
],
});
})),
// Less common periods in "More..." folder
{
name: "More...",
tree: moreAverages.map(({ name, color, ratio }) => ({
name,
tree: createPriceWithRatioOptions(ctx, {
ratio,
title: `${name} ${label}`,
legend: "average",
color,
}),
})),
},
],
};
};
return {
name: "Averages",
name: "Moving Averages",
tree: [
createSubSection("SMA", smaAverages),
createSubSection("EMA", emaAverages),

View File

@@ -1,7 +1,7 @@
/** Bands indicators (MinMax, Mayer Multiple) */
import { Unit } from "../../../utils/units.js";
import { line } from "../../series.js";
import { Unit } from "../../utils/units.js";
import { line } from "../series.js";
/**
* Create Bands section

View File

@@ -4,9 +4,12 @@ import { localhost } from "../../utils/env.js";
import { Unit } from "../../utils/units.js";
import { candlestick, line } from "../series.js";
import { createAveragesSection } from "./averages.js";
import { createPerformanceSection } from "./performance.js";
import { createIndicatorsSection } from "./indicators/index.js";
import { createInvestingSection } from "./investing.js";
import { createReturnsSection } from "./performance.js";
import { createMomentumSection } from "./momentum.js";
import { createVolatilitySection } from "./volatility.js";
import { createBandsSection } from "./bands.js";
import { createValuationSection } from "./onchain.js";
import { createDcaVsLumpSumSection, createDcaByYearSection } from "./investing.js";
/**
* Create Market section
@@ -161,22 +164,29 @@ export function createMarketSection(ctx) {
],
},
// Averages
// Moving Averages
createAveragesSection(ctx, movingAverage),
// Performance
createPerformanceSection(ctx, returns),
// Returns
createReturnsSection(ctx, returns),
// Indicators
createIndicatorsSection(ctx, {
volatility,
range,
movingAverage,
indicators,
}),
// Volatility
createVolatilitySection(ctx, { volatility, range }),
// Investing
createInvestingSection(ctx, { dca, lookback, returns }),
// Momentum
createMomentumSection(ctx, indicators),
// Bands
createBandsSection(ctx, { range, movingAverage }),
// Valuation
createValuationSection(ctx, { indicators, movingAverage }),
// DCA vs Lump Sum
createDcaVsLumpSumSection(ctx, { dca, lookback, returns }),
// DCA by Year
createDcaByYearSection(ctx, { dca }),
],
};
}

View File

@@ -1,27 +0,0 @@
/** Indicators section - Main entry point */
import { createMomentumSection } from "./momentum.js";
import { createVolatilitySection } from "./volatility.js";
import { createBandsSection } from "./bands.js";
import { createOnchainSection } from "./onchain.js";
/**
* Create Indicators section
* @param {PartialContext} ctx
* @param {Object} args
* @param {Market["volatility"]} args.volatility
* @param {Market["range"]} args.range
* @param {Market["movingAverage"]} args.movingAverage
* @param {Market["indicators"]} args.indicators
*/
export function createIndicatorsSection(ctx, { volatility, range, movingAverage, indicators }) {
return {
name: "Indicators",
tree: [
createMomentumSection(ctx, indicators),
createVolatilitySection(ctx, { volatility, range }),
createBandsSection(ctx, { range, movingAverage }),
createOnchainSection(ctx, { indicators, movingAverage }),
],
};
}

View File

@@ -32,20 +32,115 @@ export function buildDcaClasses(colors, dca) {
costBasis: dca.classAveragePrice[`_${year}`],
returns: dca.classReturns[`_${year}`],
stack: dca.classStack[`_${year}`],
daysInProfit: dca.classDaysInProfit[`_${year}`],
daysInLoss: dca.classDaysInLoss[`_${year}`],
maxDrawdown: dca.classMaxDrawdown[`_${year}`],
maxReturn: dca.classMaxReturn[`_${year}`],
}));
}
/**
* Create Investing section
* Create DCA vs Lump Sum section
* @param {PartialContext} ctx
* @param {Object} args
* @param {Market["dca"]} args.dca
* @param {Market["lookback"]} args.lookback
* @param {Market["returns"]} args.returns
*/
export function createInvestingSection(ctx, { dca, lookback, returns }) {
export function createDcaVsLumpSumSection(ctx, { dca, lookback, returns }) {
const { colors } = ctx;
const dcaClasses = buildDcaClasses(colors, dca);
/**
* @param {string} name
* @param {ShortPeriodKey | LongPeriodKey} key
*/
const costBasisChart = (name, key) => ({
name: "Cost Basis",
title: `${name} Cost Basis`,
top: [
line({
metric: dca.periodAveragePrice[key],
name: "DCA",
color: colors.green,
unit: Unit.usd,
}),
line({
metric: lookback[key],
name: "Lump sum",
color: colors.orange,
unit: Unit.usd,
}),
],
});
/** @param {string} name @param {ShortPeriodKey | LongPeriodKey} key */
const daysInProfitChart = (name, key) => ({
name: "Days in Profit",
title: `${name} Days in Profit`,
top: [
line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }),
line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }),
],
bottom: [
line({ metric: dca.periodDaysInProfit[key], name: "DCA", color: colors.green, unit: Unit.days }),
line({ metric: dca.periodLumpSumDaysInProfit[key], name: "Lump sum", color: colors.orange, unit: Unit.days }),
],
});
/** @param {string} name @param {ShortPeriodKey | LongPeriodKey} key */
const daysInLossChart = (name, key) => ({
name: "Days in Loss",
title: `${name} Days in Loss`,
top: [
line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }),
line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }),
],
bottom: [
line({ metric: dca.periodDaysInLoss[key], name: "DCA", color: colors.red, unit: Unit.days }),
line({ metric: dca.periodLumpSumDaysInLoss[key], name: "Lump sum", color: colors.orange, unit: Unit.days }),
],
});
/** @param {string} name @param {ShortPeriodKey | LongPeriodKey} key */
const maxDrawdownChart = (name, key) => ({
name: "Max Drawdown",
title: `${name} Max Drawdown`,
top: [
line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }),
line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }),
],
bottom: [
line({ metric: dca.periodMaxDrawdown[key], name: "DCA", color: colors.green, unit: Unit.percentage }),
line({ metric: dca.periodLumpSumMaxDrawdown[key], name: "Lump sum", color: colors.orange, unit: Unit.percentage }),
],
});
/** @param {string} name @param {ShortPeriodKey | LongPeriodKey} key */
const maxReturnChart = (name, key) => ({
name: "Max Return",
title: `${name} Max Return`,
top: [
line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }),
line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }),
],
bottom: [
line({ metric: dca.periodMaxReturn[key], name: "DCA", color: colors.green, unit: Unit.percentage }),
line({ metric: dca.periodLumpSumMaxReturn[key], name: "Lump sum", color: colors.orange, unit: Unit.percentage }),
],
});
/**
* @param {string} name
* @param {ShortPeriodKey | LongPeriodKey} key
*/
const stackChart = (name, key) => ({
name: "Stack",
title: `${name} Stack`,
bottom: [
...satsBtcUsd(dca.periodStack[key], "DCA", colors.green),
...satsBtcUsd(dca.periodLumpSumStack[key], "Lump sum", colors.orange),
],
});
/**
* @param {string} id
@@ -56,31 +151,34 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
return {
name,
tree: [
{
name: "Cost basis",
title: `${name} Cost Basis`,
top: [
line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }),
line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }),
],
},
costBasisChart(name, key),
{
name: "Returns",
title: `${name} Returns`,
bottom: [
baseline({ metric: dca.periodReturns[key], name: "DCA", unit: Unit.percentage }),
baseline({ metric: returns.priceReturns[key], name: "Lump sum", color: [colors.cyan, colors.orange], unit: Unit.percentage }),
priceLine({ ctx, unit: Unit.percentage }),
baseline({
metric: dca.periodReturns[key],
name: "DCA",
unit: Unit.percentage,
}),
baseline({
metric: dca.periodLumpSumReturns[key],
name: "Lump sum",
color: [colors.cyan, colors.orange],
unit: Unit.percentage,
}),
],
},
{
name: "Stack",
title: `${name} Stack`,
bottom: [
...satsBtcUsd(dca.periodStack[key], "DCA", colors.green),
...satsBtcUsd(dca.periodLumpSumStack[key], "Lump sum", colors.orange),
name: "Profitability",
tree: [
daysInProfitChart(name, key),
daysInLossChart(name, key),
maxDrawdownChart(name, key),
maxReturnChart(name, key),
],
},
stackChart(name, key),
],
};
};
@@ -94,142 +192,226 @@ export function createInvestingSection(ctx, { dca, lookback, returns }) {
return {
name,
tree: [
{
name: "Cost basis",
title: `${name} Cost Basis`,
top: [
line({ metric: dca.periodAveragePrice[key], name: "DCA", color: colors.green, unit: Unit.usd }),
line({ metric: lookback[key], name: "Lump sum", color: colors.orange, unit: Unit.usd }),
],
},
costBasisChart(name, key),
{
name: "Returns",
title: `${name} Returns`,
bottom: [
baseline({ metric: dca.periodReturns[key], name: "DCA", unit: Unit.percentage }),
baseline({ metric: returns.priceReturns[key], name: "Lump sum", color: [colors.cyan, colors.orange], unit: Unit.percentage }),
line({ metric: dca.periodCagr[key], name: "DCA CAGR", color: colors.purple, unit: Unit.percentage, defaultActive: false }),
line({ metric: returns.cagr[key], name: "Lump sum CAGR", color: colors.indigo, unit: Unit.percentage, defaultActive: false }),
baseline({
metric: dca.periodReturns[key],
name: "DCA",
unit: Unit.percentage,
}),
baseline({
metric: dca.periodLumpSumReturns[key],
name: "Lump sum",
color: [colors.cyan, colors.orange],
unit: Unit.percentage,
}),
line({
metric: dca.periodCagr[key],
name: "DCA CAGR",
color: colors.purple,
unit: Unit.percentage,
defaultActive: false,
}),
line({
metric: returns.cagr[key],
name: "Lump sum CAGR",
color: colors.indigo,
unit: Unit.percentage,
defaultActive: false,
}),
priceLine({ ctx, unit: Unit.percentage }),
],
},
{
name: "Stack",
title: `${name} Stack`,
bottom: [
...satsBtcUsd(dca.periodStack[key], "DCA", colors.green),
...satsBtcUsd(dca.periodLumpSumStack[key], "Lump sum", colors.orange),
name: "Profitability",
tree: [
daysInProfitChart(name, key),
daysInLossChart(name, key),
maxDrawdownChart(name, key),
maxReturnChart(name, key),
],
},
stackChart(name, key),
],
};
};
return {
name: "Investing",
name: "DCA vs Lump Sum",
tree: [
// DCA vs Lump sum
{
name: "DCA vs Lump sum",
tree: [
createPeriodTree("1w", "_1w"),
createPeriodTree("1m", "_1m"),
createPeriodTree("3m", "_3m"),
createPeriodTree("6m", "_6m"),
createPeriodTree("1y", "_1y"),
createPeriodTreeWithCagr("2y", "_2y"),
createPeriodTreeWithCagr("3y", "_3y"),
createPeriodTreeWithCagr("4y", "_4y"),
createPeriodTreeWithCagr("5y", "_5y"),
createPeriodTreeWithCagr("6y", "_6y"),
createPeriodTreeWithCagr("8y", "_8y"),
createPeriodTreeWithCagr("10y", "_10y"),
],
},
// DCA classes
{
name: "DCA classes",
tree: [
// Comparison charts (all years overlaid)
{
name: "Compare",
tree: [
{
name: "Cost basis",
title: "DCA Cost Basis",
top: dcaClasses.map(
({ year, color, defaultActive, costBasis }) =>
line({
metric: costBasis,
name: `${year}`,
color,
defaultActive,
unit: Unit.usd,
}),
),
},
{
name: "Returns",
title: "DCA Returns",
bottom: dcaClasses.map(
({ year, color, defaultActive, returns }) =>
baseline({
metric: returns,
name: `${year}`,
color,
defaultActive,
unit: Unit.percentage,
}),
),
},
{
name: "Stack",
title: "DCA Stack",
bottom: dcaClasses.flatMap(
({ year, color, defaultActive, stack }) =>
satsBtcUsd(stack, `${year}`, color, { defaultActive }),
),
},
],
},
// Individual year charts
...dcaClasses.map(({ year, color, costBasis, returns, stack }) => ({
name: `${year}`,
tree: [
{
name: "Cost basis",
title: `${year} Cost Basis`,
top: [
line({
metric: costBasis,
name: "Cost basis",
color,
unit: Unit.usd,
}),
],
},
{
name: "Returns",
title: `${year} Returns`,
bottom: [
baseline({
metric: returns,
name: "Returns",
color,
unit: Unit.percentage,
}),
],
},
{
name: "Stack",
title: `${year} Stack`,
bottom: satsBtcUsd(stack, "Stack", color),
},
],
})),
],
},
createPeriodTree("1w", "_1w"),
createPeriodTree("1m", "_1m"),
createPeriodTree("3m", "_3m"),
createPeriodTree("6m", "_6m"),
createPeriodTree("1y", "_1y"),
createPeriodTreeWithCagr("2y", "_2y"),
createPeriodTreeWithCagr("3y", "_3y"),
createPeriodTreeWithCagr("4y", "_4y"),
createPeriodTreeWithCagr("5y", "_5y"),
createPeriodTreeWithCagr("6y", "_6y"),
createPeriodTreeWithCagr("8y", "_8y"),
createPeriodTreeWithCagr("10y", "_10y"),
],
};
}
/**
* Create DCA by Year section
* @param {PartialContext} ctx
* @param {Object} args
* @param {Market["dca"]} args.dca
*/
export function createDcaByYearSection(ctx, { dca }) {
const { colors } = ctx;
const dcaClasses = buildDcaClasses(colors, dca);
return {
name: "DCA by Year",
tree: [
// Comparison charts (all years overlaid)
{
name: "Compare",
tree: [
{
name: "Cost basis",
title: "DCA Cost Basis",
top: dcaClasses.map(({ year, color, defaultActive, costBasis }) =>
line({
metric: costBasis,
name: `${year}`,
color,
defaultActive,
unit: Unit.usd,
}),
),
},
{
name: "Returns",
title: "DCA Returns",
bottom: dcaClasses.map(({ year, defaultActive, returns }) =>
baseline({
metric: returns,
name: `${year}`,
defaultActive,
unit: Unit.percentage,
}),
),
},
{
name: "Profitability",
title: "DCA Profitability",
bottom: [
...dcaClasses.map(({ year, color, defaultActive, daysInProfit }) =>
line({
metric: daysInProfit,
name: `${year} Days in Profit`,
color,
defaultActive,
unit: Unit.days,
}),
),
...dcaClasses.map(({ year, color, daysInLoss }) =>
line({
metric: daysInLoss,
name: `${year} Days in Loss`,
color,
defaultActive: false,
unit: Unit.days,
}),
),
],
},
{
name: "Stack",
title: "DCA Stack",
bottom: dcaClasses.flatMap(
({ year, color, defaultActive, stack }) =>
satsBtcUsd(stack, `${year}`, color, { defaultActive }),
),
},
],
},
// Individual year charts
...dcaClasses.map(
({
year,
color,
costBasis,
returns,
stack,
daysInProfit,
daysInLoss,
maxDrawdown,
maxReturn,
}) => ({
name: `${year}`,
tree: [
{
name: "Cost Basis",
title: `${year} Cost Basis`,
top: [
line({
metric: costBasis,
name: "Cost Basis",
color,
unit: Unit.usd,
}),
],
},
{
name: "Returns",
title: `${year} Returns`,
bottom: [
baseline({
metric: returns,
name: "Returns",
unit: Unit.percentage,
}),
],
},
{
name: "Profitability",
title: `${year} Profitability`,
bottom: [
line({
metric: daysInProfit,
name: "Days in Profit",
color: colors.green,
unit: Unit.days,
}),
line({
metric: daysInLoss,
name: "Days in Loss",
color: colors.red,
unit: Unit.days,
}),
line({
metric: maxDrawdown,
name: "Max Drawdown",
color: colors.purple,
unit: Unit.percentage,
defaultActive: false,
}),
line({
metric: maxReturn,
name: "Max Return",
color: colors.cyan,
unit: Unit.percentage,
defaultActive: false,
}),
],
},
{
name: "Stack",
title: `${year} Stack`,
bottom: satsBtcUsd(stack, "Stack", color),
},
],
}),
),
],
};
}

View File

@@ -1,8 +1,8 @@
/** Momentum indicators (RSI, StochRSI, Stochastic, MACD) */
import { Unit } from "../../../utils/units.js";
import { priceLine, priceLines } from "../../constants.js";
import { line, histogram } from "../../series.js";
import { Unit } from "../../utils/units.js";
import { priceLine, priceLines } from "../constants.js";
import { line, histogram } from "../series.js";
/**
* Create Momentum section

View File

@@ -1,20 +1,20 @@
/** On-chain indicators (Pi Cycle, Puell, NVT, Gini) */
import { Unit } from "../../../utils/units.js";
import { baseline, line } from "../../series.js";
import { Unit } from "../../utils/units.js";
import { baseline, line } from "../series.js";
/**
* Create On-chain section
* Create Valuation section
* @param {PartialContext} ctx
* @param {Object} args
* @param {Market["indicators"]} args.indicators
* @param {Market["movingAverage"]} args.movingAverage
*/
export function createOnchainSection(ctx, { indicators, movingAverage }) {
export function createValuationSection(ctx, { indicators, movingAverage }) {
const { colors } = ctx;
return {
name: "On-chain",
name: "Valuation",
tree: [
{
name: "Pi Cycle",

View File

@@ -6,55 +6,100 @@ import { baseline } from "../series.js";
import { periodIdToName } from "./utils.js";
/**
* Create Performance section
* Create Returns section
* @param {PartialContext} ctx
* @param {Market["returns"]} returns
*/
export function createPerformanceSection(ctx, returns) {
export function createReturnsSection(ctx, returns) {
const { colors } = ctx;
const shortTermPeriods = /** @type {const} */ ([
["1d", "_1d", undefined],
["1w", "_1w", undefined],
["1m", "_1m", undefined],
]);
const mediumTermPeriods = /** @type {const} */ ([
["3m", "_3m", undefined],
["6m", "_6m", undefined],
["1y", "_1y", undefined],
]);
const longTermPeriods = /** @type {const} */ ([
["2y", "_2y", "_2y"],
["3y", "_3y", "_3y"],
["4y", "_4y", "_4y"],
["5y", "_5y", "_5y"],
["6y", "_6y", "_6y"],
["8y", "_8y", "_8y"],
["10y", "_10y", "_10y"],
]);
/**
* @template {keyof typeof returns.priceReturns} K
* @param {readonly [string, K, K | undefined]} period
*/
const createPeriodChart = ([id, returnKey, cagrKey]) => {
const priceReturns = returns.priceReturns[/** @type {K} */ (returnKey)];
const cagr = cagrKey ? returns.cagr[/** @type {keyof typeof returns.cagr} */ (cagrKey)] : undefined;
const name = periodIdToName(id, true);
return {
name,
title: `${name} Returns`,
bottom: [
baseline({
metric: priceReturns,
name: "Total",
unit: Unit.percentage,
}),
...(cagr
? [
baseline({
metric: cagr,
name: "CAGR",
color: [colors.cyan, colors.orange],
unit: Unit.percentage,
}),
]
: []),
priceLine({ ctx, unit: Unit.percentage }),
],
};
};
return {
name: "Performance",
tree: /** @type {const} */ ([
["1d", "_1d", undefined],
["1w", "_1w", undefined],
["1m", "_1m", undefined],
["3m", "_3m", undefined],
["6m", "_6m", undefined],
["1y", "_1y", undefined],
["2y", "_2y", "_2y"],
["3y", "_3y", "_3y"],
["4y", "_4y", "_4y"],
["5y", "_5y", "_5y"],
["6y", "_6y", "_6y"],
["8y", "_8y", "_8y"],
["10y", "_10y", "_10y"],
]).map(([id, returnKey, cagrKey]) => {
const priceReturns = returns.priceReturns[returnKey];
const cagr = cagrKey ? returns.cagr[cagrKey] : undefined;
const name = periodIdToName(id, true);
return {
name,
title: `${name} Returns`,
name: "Returns",
tree: [
// Compare all periods
{
name: "Compare",
title: "Returns Comparison",
bottom: [
baseline({
metric: priceReturns,
name: "Total",
unit: Unit.percentage,
}),
...(cagr
? [
baseline({
metric: cagr,
name: "CAGR",
color: [colors.cyan, colors.orange],
unit: Unit.percentage,
}),
]
: []),
baseline({ metric: returns.priceReturns._1d, name: "1d", color: colors.red, unit: Unit.percentage }),
baseline({ metric: returns.priceReturns._1w, name: "1w", color: colors.orange, unit: Unit.percentage }),
baseline({ metric: returns.priceReturns._1m, name: "1m", color: colors.yellow, unit: Unit.percentage }),
baseline({ metric: returns.priceReturns._3m, name: "3m", color: colors.lime, unit: Unit.percentage, defaultActive: false }),
baseline({ metric: returns.priceReturns._6m, name: "6m", color: colors.green, unit: Unit.percentage, defaultActive: false }),
baseline({ metric: returns.priceReturns._1y, name: "1y", color: colors.teal, unit: Unit.percentage }),
baseline({ metric: returns.priceReturns._4y, name: "4y", color: colors.blue, unit: Unit.percentage }),
priceLine({ ctx, unit: Unit.percentage }),
],
};
}),
},
// Short-term (1d, 1w, 1m)
{
name: "Short-term",
tree: shortTermPeriods.map(createPeriodChart),
},
// Medium-term (3m, 6m, 1y)
{
name: "Medium-term",
tree: mediumTermPeriods.map(createPeriodChart),
},
// Long-term (2y+)
{
name: "Long-term",
tree: longTermPeriods.map(createPeriodChart),
},
],
};
}

View File

@@ -1,8 +1,8 @@
/** Volatility indicators (Index, True Range, Choppiness, Sharpe, Sortino) */
import { Unit } from "../../../utils/units.js";
import { priceLine, priceLines } from "../../constants.js";
import { line } from "../../series.js";
import { Unit } from "../../utils/units.js";
import { priceLine, priceLines } from "../constants.js";
import { line } from "../series.js";
/**
* Create Volatility section