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


import { SymbolInfo } from '@src/types/symbol';

export enum CompareMode {
  Absolute = 'ABS',
  Percentage = 'PCT',
  NewScale = 'SCALE',
  NewPane = 'PANE',
}

export interface CompareItem extends SymbolInfo {
  mode: CompareMode;
}

import { MenuList, type MenuOption } from '@src/components/Menu/MenuList';

import { t } from '@src/translations';

import type { ChartView } from '@src/core/Seasonality/types';

interface ChartViewMenuProps {
  selectedView: ChartView;
  onClick: (view: ChartView) => void;
}

export function ChartViewMenu({ selectedView, onClick }: ChartViewMenuProps) {
  const options: MenuOption<ChartView>[] = [
    { value: 'chart', label: t('Chart') },
    { value: 'seasonality', label: t('Seasonality') },
  ];

  return (
    <MenuList
      mode="single"
      value={selectedView}
      options={options}
      onClick={onClick}
    />
  );
}

















import { MenuList, type MenuOption } from '@src/components/Menu/MenuList';

import { t } from '@src/translations';

import type { SeasonalityScale } from '@src/core/Seasonality/types';

interface SeasonalityScaleMenuProps {
  selectedScale: SeasonalityScale;
  onClick: (scale: SeasonalityScale) => void;
}

export function SeasonalityScaleMenu({ selectedScale, onClick }: SeasonalityScaleMenuProps) {
  const options: MenuOption<SeasonalityScale>[] = [
    { value: 'absolute', label: t('Price') },
    { value: 'percentage', label: t('Percent') },
  ];

  return (
    <MenuList
      mode="single"
      value={selectedScale}
      options={options}
      onClick={onClick}
    />
  );
}

















import { Dropdown } from '@src/components/Dropdown';
import { RangeField } from '@src/components/FormFields';
import { SeasonalityScaleMenu } from '@src/components/Menu/SeasonalityScaleMenu';
import { t } from '@src/translations';
import { useObservable } from '@src/utils';

import styles from './index.module.scss';

import type { SeasonalityRange, SeasonalityScale, SeasonalityState } from '@src/core/Seasonality/types';
import type { Observable } from 'rxjs';

interface SeasonalityControlsProps {
  stateObs: Observable<SeasonalityState>;
  setScale: (scale: SeasonalityScale) => void;
  setRange: (range: SeasonalityRange) => void;
}

export function SeasonalityControls({ stateObs, setScale, setRange }: SeasonalityControlsProps) {
  const state = useObservable(stateObs);

  if (!state || state.view !== 'seasonality') {
    return null;
  }

  const handleRangeChange = ([fromYear, toYear]: [number, number]) => {
    setRange({ fromYear, toYear });
  };

  return (
    <div className={styles.controls}>
      <div className={styles.controls_header}>
        <Dropdown selectedValue={state.scale === 'absolute' ? t('Price') : t('Percent')}>
          <SeasonalityScaleMenu
            selectedScale={state.scale}
            onClick={setScale}
          />
        </Dropdown>
      </div>

      <div className={styles.controls_range}>
        <RangeField
          mode="range"
          value={[state.fromYear, state.toYear]}
          min={state.minYear}
          max={state.maxYear}
          step={1}
          suffix=""
          size="sm"
          disabled={state.status === 'loading' || state.status === 'error'}
          onRangeChange={handleRangeChange}
        />
      </div>
    </div>
  );
}


import type { Candle } from '@src/types';
import type { Timeframes } from '@src/types/timeframes';

export type ChartView = 'chart' | 'seasonality';
export type SeasonalityScale = 'absolute' | 'percentage';

export interface SeasonalityRange {
  fromYear: number;
  toYear: number;
}

export interface SeasonalityState extends SeasonalityRange {
  view: ChartView;
  status: 'idle' | 'loading' | 'ready' | 'empty' | 'error';
  scale: SeasonalityScale;
  symbolId: string;
  minYear: number;
  maxYear: number;
  error: string | null;
}

export function createInitialSeasonalityState(): SeasonalityState {
  const year = new Date().getUTCFullYear();
  return {
    view: 'chart',
    status: 'idle',
    scale: 'absolute',
    symbolId: '',
    error: null,
    minYear: year - 4,
    maxYear: year,
    fromYear: year - 4,
    toYear: year,
  };
}

export interface SeasonalityPoint {
  date: string;
  chartDate: string;
  price: number;
  percentage: number | null;
}

export interface SeasonalityYear {
  year: number;
  baselineDate: string;
  baselinePrice: number;
  points: SeasonalityPoint[];
}

export interface DailyClose {
  date: string;
  close: number;
}

export type SeasonalityGetData = (timeframe: Timeframes, symbolId: string, until?: Candle) => Promise<Candle[] | null>;


import { SeriesType, Time } from 'lightweight-charts';

import { DateFormat } from '@src/utils/formatter';

import { TimeFormat } from './timeScale';
/**
 * Типы графиков, поддерживаемые библиотекой
 */
export type ChartSeriesType = SeriesType;

/**
 * Универсальный формат данных для всех типов графиков
 */
export interface ChartDataPoint {
  time?: Time;
  value?: number;
  open?: number;
  high?: number;
  low?: number;
  close?: number;
  volume?: number;
}

interface CandlestickChartOptions {
  upColor?: string;
  downColor?: string;
  wickUpColor?: string;
  wickDownColor?: string;
  borderVisible?: boolean;
}

interface LineChartOptions {
  lineStyle?: 'solid' | 'dotted' | 'dashed';
}

interface AreaChartOptions {
  topColor?: string;
  bottomColor?: string;
}

interface BaselineChartOptions {
  baseValue?: number;
  topLineColor?: string;
  bottomLineColor?: string;
  topFillColor1?: string;
  topFillColor2?: string;
  bottomFillColor1?: string;
  bottomFillColor2?: string;
}

interface TimescaleOptions {
  timeVisible?: boolean;
  secondsVisible?: boolean;
  timeFormat?: TimeFormat;
  dateFormat?: DateFormat;
}

interface CrosshairOptions {
  crosshairLineXColor?: string;
  crosshairLineYColor?: string;
  crosshairLabelXBgColor?: string;
  crosshairLabelYBgColor?: string;
}

interface HistogramOptions {
  scaleMargins?: {
    top: number;
    bottom: number;
  };
}

/**
 * @deprecated
 * Опции для разных типов графиков
 */
export interface ChartTypeOptions // todo: неверный интерфейс
  extends HistogramOptions,
    CrosshairOptions,
    TimescaleOptions,
    BaselineChartOptions,
    AreaChartOptions,
    LineChartOptions,
    CandlestickChartOptions {
  // Общие опции
  color?: string;
  lineWidth?: number;
}

export interface LineCandle {
  time: number;
  value: number;
  volume?: number;
}

export interface Candle {
  time: number;
  open: number;
  high: number;
  low: number;
  close: number;
  volume?: number; // todo: volume & future metaData to customFields
}

export type Destroyable = {
  destroy(): void;
};

export enum Direction {
  Top = 'top',
  Bottom = 'bottom',
  Left = 'left',
  Right = 'right',
}

// Настройки графика, которые могут изменяться в рантайме
export interface ChartOptionsModel {
  dateFormat: DateFormat;
  timeFormat: TimeFormat;
  showTime: boolean;
}