Загрузка данных


import { Locale } from '@lib';
import { Ohlc } from '@src/core/Legend';

import { getThemeStore } from '@src/theme/store';
import { getLocale } from '@src/translations';

import {
  getPercentPrecision,
  getPricePrecision,
} from '@src/utils/precision';

import { isBarData } from './typeGuards';

export function formatCompactNumber(
  value: number,
  locale: Locale = getLocale(),
  maxFractionDigits: number = getPricePrecision(),
): string {
  const unitList: {
    divisor: number;
    suffix: string;
  }[] = [
    { divisor: 1, suffix: '' },
    { divisor: 1_000, suffix: 'k' },
    { divisor: 1_000_000, suffix: 'm' },
    { divisor: 1_000_000_000, suffix: 'b' },
    {
      divisor: 1_000_000_000_000,
      suffix: 't',
    },
  ];

  let selectedUnit = unitList[0];

  for (
    let index = unitList.length - 1;
    index >= 0;
    index -= 1
  ) {
    if (
      Math.abs(value) >=
      unitList[index].divisor
    ) {
      selectedUnit = unitList[index];

      break;
    }
  }

  const divided =
    value / selectedUnit.divisor;

  const formatter = new Intl.NumberFormat(
    locale,
    {
      maximumFractionDigits:
        maxFractionDigits,
      minimumFractionDigits: 0,
      useGrouping: false,
    },
  );

  return (
    formatter.format(divided) +
    selectedUnit.suffix
  );
}

export const formatPrice = (
  price?: number | string,
  precision = getPricePrecision(),
  locale: Locale = getLocale(),
): string | undefined => {
  if (price === undefined) {
    return undefined;
  }

  const value = Number(price);

  if (!Number.isFinite(value)) {
    return undefined;
  }

  return new Intl.NumberFormat(locale, {
    maximumFractionDigits: precision,
    minimumFractionDigits: 0,
    useGrouping: false,
  }).format(value);
};

export const formatPercent = (
  value: number,
  precision = getPercentPrecision(),
  locale: Locale = getLocale(),
): string => {
  if (!Number.isFinite(value)) {
    return '0%';
  }

  const formattedValue =
    new Intl.NumberFormat(locale, {
      maximumFractionDigits: precision,
      minimumFractionDigits: 0,
      useGrouping: false,
    }).format(value);

  return `${formattedValue}%`;
};

export const formatSignedNumber = (
  value: number,
): string => {
  if (!Number.isFinite(value)) {
    return '0';
  }

  const formatted =
    formatPrice(Math.abs(value)) ?? '0';

  return value < 0
    ? `-${formatted}`
    : formatted;
};

export const formatVolume = (
  volume?: number,
): string => {
  if (!volume) return '';

  if (volume >= 1_000_000) {
    return `${(volume / 1_000_000)
      .toFixed(1)
      .replace(/\.0$/, '')}M`;
  }

  if (volume >= 1_000) {
    return `${(volume / 1_000)
      .toFixed(1)
      .replace(/\.0$/, '')}K`;
  }

  return volume.toString();
};

export function getPriceColor(
  ohlc: Ohlc | null,
  upColor?: string,
  downColor?: string,
): string {
  if (!ohlc) return '';

  const { colors } = getThemeStore();

  const positiveColor =
    upColor ?? colors.chartCandleUp;

  const negativeColor =
    downColor ?? colors.chartCandleDown;

  if (
    ohlc.open &&
    ohlc.close &&
    isBarData(ohlc)
  ) {
    return ohlc.close >= ohlc.open
      ? positiveColor
      : negativeColor;
  }

  if (
    typeof ohlc.absoluteChange ===
    'number'
  ) {
    return ohlc.absoluteChange >= 0
      ? positiveColor
      : negativeColor;
  }

  return '';
}