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


diff --git a/package-lock.json b/package-lock.json
index d5702bd461cbc3d3cdb5e9c9eca9dc8af4fdc1ed..9957620897d235428a3934816d2f61e32cd9855f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11917,7 +11917,7 @@
       "version": "1.11.6",
       "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/@swc/core/-/core-1.11.6.tgz",
       "integrity": "sha1-EcYPZy8plHwFLjkg4USzrRxkXkk=",
-      "devOptional": true,
+      "dev": true,
       "dependencies": {
         "@swc/counter": "^0.1.3",
         "@swc/types": "^0.1.25"
@@ -11949,6 +11949,7 @@
       "version": "1.15.1",
       "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.1.tgz",
       "integrity": "sha1-Ao/bHkGda8HUIvsn6Vko0LnXt4I=",
+      "dev": true,
       "optional": true,
       "engines": {
         "node": ">=10"
@@ -11958,13 +11959,13 @@
       "version": "0.1.3",
       "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/@swc/counter/-/counter-0.1.3.tgz",
       "integrity": "sha1-zHRjvQKUlhHGMpWW/M0rDseCsOk=",
-      "devOptional": true
+      "dev": true
     },
     "node_modules/@swc/helpers": {
       "version": "0.5.13",
       "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/@swc/helpers/-/helpers-0.5.13.tgz",
       "integrity": "sha1-M+Y/880MreVXZyvXiIo5zn0RWow=",
-      "devOptional": true,
+      "dev": true,
       "license": "Apache-2.0",
       "peer": true,
       "dependencies": {
@@ -11975,7 +11976,7 @@
       "version": "0.1.25",
       "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/@swc/types/-/types-0.1.25.tgz",
       "integrity": "sha1-tReypg/rN92TPlQtkwk3GeTPEHg=",
-      "devOptional": true,
+      "dev": true,
       "dependencies": {
         "@swc/counter": "^0.1.3"
       }
diff --git a/src/components/ChartTooltip/index.tsx b/src/components/ChartTooltip/index.tsx
index 3024f9ca7bebdec851927b73162eb042b615d353..0d386f8a9d4cbba1290b3a11ba51b4bbb30fb0c7 100644
--- a/src/components/ChartTooltip/index.tsx
+++ b/src/components/ChartTooltip/index.tsx
@@ -1,9 +1,11 @@
 import { Divider } from 'exchange-elements/v2';
-import { UTCTimestamp } from 'lightweight-charts';
+import { Time, UTCTimestamp } from 'lightweight-charts';
 import { FC, useLayoutEffect, useRef, useState } from 'react';
 
 import { Observable } from 'rxjs';
 
+import { Ohlc } from '@core/Legend';
+
 import { TooltipVM } from '@core/Tooltip';
 
 import { getThemeStore } from '@src/theme';
@@ -22,7 +24,6 @@ export interface TooltipProps {
   ohlcConfig: OHLCConfig;
 }
 
-// const isNum = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v);
 const TOOLTIP_MARGIN = 15;
 
 export const ChartTooltip: FC<TooltipProps> = ({
@@ -41,7 +42,7 @@ export const ChartTooltip: FC<TooltipProps> = ({
 
   const { colors } = getThemeStore();
 
-  const { visible, position, ohlc, viewport } = viewModel ?? {};
+  const { visible, position, viewport, vm: vmLegend } = viewModel ?? {};
   const showTime = timeframe ? shouldShowTime(timeframe) : true;
 
   useLayoutEffect(() => {
@@ -53,7 +54,7 @@ export const ChartTooltip: FC<TooltipProps> = ({
     setTooltipSize({ width, height });
   }, [visible]);
 
-  if (!visible || !ohlc || !position || !viewport) {
+  if (!visible || !position || !viewport) {
     return null;
   }
   const coords = calcTooltipPosition({
@@ -84,58 +85,89 @@ export const ChartTooltip: FC<TooltipProps> = ({
       style={style}
       ref={refTooltip}
     >
-      {tooltipConfig.time?.visible &&
-        ohlc.time &&
-        renderRow(
-          tooltipConfig.time.label,
-          formatDate(
-            ohlc.time as UTCTimestamp,
-            format?.dateFormat ?? Defaults.dateFormat,
-            format?.timeFormat ?? Defaults.timeFormat,
-            showTime,
-          ),
-        )}
-
-      {(tooltipConfig.close?.visible || tooltipConfig.open?.visible) && (!!ohlc.close || !!ohlc.open) && (
-        <Divider
-          direction="horizontal"
-          pt={{ divider: { className: styles.divider } }}
-        />
-      )}
-
-      {tooltipConfig.close?.visible &&
-        ohlc.close &&
-        renderRow(tooltipConfig.close.label, formatPrice(ohlc.close, precision))}
-      {/* {tooltipConfig.value?.visible &&
-        ohlc.value &&
-        renderRow(tooltipConfig.value.label, formatPrice(ohlc.value, precision))} */}
-      {tooltipConfig.open?.visible &&
-        ohlc.open &&
-        renderRow(tooltipConfig.open.label, formatPrice(ohlc.open, precision))}
-
-      {(tooltipConfig.high?.visible || tooltipConfig.low?.visible) && (!!ohlc.high || !!ohlc.low) && (
-        <Divider
-          direction="horizontal"
-          pt={{ divider: { className: styles.divider } }}
-        />
-      )}
-
-      {tooltipConfig.high?.visible &&
-        ohlc.high &&
-        renderRow(tooltipConfig.high.label, formatPrice(ohlc.high, precision))}
-      {tooltipConfig.low?.visible && ohlc.low && renderRow(tooltipConfig.low.label, formatPrice(ohlc.low, precision))}
-      {/* {tooltipConfig.change?.visible && (isNum(ohlc.absoluteChange) || isNum(ohlc.percentageChange)) && (
-        <div className={styles.row}>
-          <span className={styles.label}>{tooltipConfig.change.label}:</span>
-          <span
-            className={styles.value}
-            style={{ color: priceColor }}
-          >
-            {`${formatPrice(ohlc.absoluteChange)} (${formatPrice(ohlc.percentageChange)}%)`}
-          </span>
-        </div>
-      )} */}
-      {/* {tooltipConfig.volume?.visible && volume && renderRow(tooltipConfig.volume.label, volume)} */}
+      {vmLegend?.map((indicator) => {
+        if (indicator.isIndicator) {
+          const entries = Array.from(
+            indicator.values as Map<keyof Ohlc, { value: number | string | Time; color: string; name: string }>,
+          );
+
+          return (
+            <>
+              {entries.map((x) => {
+                const [key, entry] = x as [keyof Ohlc, { value: number | string | Time; color: string; name: string }];
+
+                return renderRow(key as string, entry.value as string);
+              })}
+            </>
+          );
+        }
+
+        const entries: Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>> =
+          Object.fromEntries(indicator.values as any);
+
+        return (
+          <>
+            {tooltipConfig.time?.visible &&
+              entries.time?.value &&
+              renderRow(
+                tooltipConfig.time.label,
+                formatDate(
+                  entries.time.value as UTCTimestamp,
+                  format?.dateFormat ?? Defaults.dateFormat,
+                  format?.timeFormat ?? Defaults.timeFormat,
+                  showTime,
+                ),
+              )}
+
+            {((tooltipConfig.close?.visible && !!entries.close?.value) ||
+              (tooltipConfig.open?.visible && !!entries.open?.value) ||
+              (tooltipConfig.value?.visible && !!entries.value?.value)) && (
+              <Divider
+                direction="horizontal"
+                pt={{ divider: { className: styles.divider } }}
+              />
+            )}
+
+            {tooltipConfig.close?.visible &&
+              entries.close?.value &&
+              renderRow(tooltipConfig.close.label, formatPrice(entries.close?.value as string, precision))}
+
+            {tooltipConfig.value?.visible &&
+              entries.value?.value &&
+              renderRow(tooltipConfig.value.label, formatPrice(entries.value.value as string, precision))}
+
+            {tooltipConfig.open?.visible &&
+              entries.open?.value &&
+              renderRow(tooltipConfig.open.label, formatPrice(entries.open.value as string, precision))}
+
+            {((tooltipConfig.high?.visible && !!entries.high?.value) ||
+              (tooltipConfig.low?.visible && !!entries.low?.value) ||
+              (tooltipConfig.change?.visible && !!entries.absoluteChange?.value) ||
+              (tooltipConfig.change?.visible && !!entries.percentageChange?.value)) && (
+              <Divider
+                direction="horizontal"
+                pt={{ divider: { className: styles.divider } }}
+              />
+            )}
+
+            {tooltipConfig.high?.visible &&
+              entries.high?.value &&
+              renderRow(tooltipConfig.high.label, formatPrice(entries.high.value as string, precision))}
+
+            {tooltipConfig.low?.visible &&
+              entries.low?.value &&
+              renderRow(tooltipConfig.low.label, formatPrice(entries.low.value as string, precision))}
+
+            {tooltipConfig.change?.visible &&
+              entries.absoluteChange?.value &&
+              renderRow('Абсолютное изменение', entries.absoluteChange.value as string)}
+
+            {tooltipConfig.change?.visible &&
+              entries.percentageChange?.value &&
+              renderRow('Относительное изменение', entries.percentageChange.value as string)}
+          </>
+        );
+      })}
     </div>
   );
 };
diff --git a/src/components/Legend/index.module.scss b/src/components/Legend/index.module.scss
index 63292a4fcdfda0ab3c7a1d640b3ffa6efc946138..edbd0605f1fe3f6a693673d2320d616e28061965 100644
--- a/src/components/Legend/index.module.scss
+++ b/src/components/Legend/index.module.scss
@@ -1,3 +1,5 @@
+@use '../../theme/mixins' as m;
+
 .legend {
   display: flex;
   width: 100%;
@@ -8,13 +10,13 @@
   .row {
     display: flex;
     justify-content: start;
-    align-items: center;
+    align-items: baseline;
     flex-wrap: wrap;
     gap: var(--space-0500);
   }
 
   .item {
-    display: flex;
+    display: inline-flex;
     gap: var(--space-0250);
   }
 
@@ -24,4 +26,14 @@
     line-height: var(--space-1000);
     font-weight: var(--font-medium);
   }
+
+  & .button {
+    @include m.buttonBase;
+
+    &Content {
+      display: flex;
+      align-items: flex-start;
+      justify-content: flex-start;
+    }
+  }
 }
diff --git a/src/components/Legend/index.tsx b/src/components/Legend/index.tsx
index f6c7ca6842750b31410c5605dedd53f5935c8dee..d1755cdac931d2273783ed66fbed4d1ad81a1b08 100644
--- a/src/components/Legend/index.tsx
+++ b/src/components/Legend/index.tsx
@@ -1,70 +1,75 @@
+import { Button } from 'exchange-elements/v2';
+import { Time } from 'lightweight-charts';
 import React from 'react';
 
 import { Observable } from 'rxjs';
 
-import { LegendVM } from '@core/Legend';
+import { TrashIcon } from '@components/Icon';
 
-import { CompareLegendRow } from '@src/components/CompareLegendRow';
+import { LegendModel, Ohlc, ohlcValuesToShowForMainSerie } from '@core/Legend';
 
-import { CompareMode, OHLCConfig } from '../../types';
-import { formatPrice, formatVolume, getPriceColor, useObservable } from '../../utils';
+import { OHLCConfig } from '../../types';
+import { useObservable } from '../../utils';
 
 import styles from './index.module.scss';
 
 export interface LegendProps {
   ohlcConfig?: OHLCConfig;
-  viewModel: Observable<LegendVM>;
-  onCompareRemove?: (symbol: string, mode: CompareMode) => void;
+  viewModel: Observable<LegendModel>;
 }
 
-export const LegendComponent: React.FC<LegendProps> = ({ ohlcConfig, viewModel: vm, onCompareRemove }) => {
-  const viewModel = useObservable(vm);
-  const ohlc = viewModel?.ohlc ?? null;
-  const symbol = viewModel?.symbol ?? null;
-  const volume = viewModel?.volume ?? undefined;
-  const compareItems = viewModel?.compareItems ?? [];
-
-  const showVolume = ohlcConfig?.showVolume;
+export const LegendComponent: React.FC<LegendProps> = ({ ohlcConfig, viewModel }) => {
+  const model = useObservable(viewModel);
   const showOhlc = ohlcConfig?.show;
 
-  const priceColor = getPriceColor(ohlc);
-
-  const renderLegendItem = (label: string, value?: string | number, show = true) => {
-    if (!show || !value) return null;
-
-    return (
-      <div className={styles.item}>
-        {label} <span style={{ color: priceColor }}>{value}</span>
-      </div>
-    );
-  };
-
   return (
     <section className={styles.legend}>
-      <div className={styles.row}>
-        {symbol && <div className={styles.symbol}>{symbol}</div>}
-        {showOhlc && (
-          <>
-            {renderLegendItem('Отк.', formatPrice(ohlc?.open), !!ohlc?.open)}
-            {renderLegendItem('Макс.', formatPrice(ohlc?.high), !!ohlc?.high)}
-            {renderLegendItem('Мин.', formatPrice(ohlc?.low), !!ohlc?.low)}
-            {renderLegendItem('Закр.', formatPrice(ohlc?.close), !!ohlc?.close)}
-            {renderLegendItem(
-              'Изм.',
-              `${formatPrice(ohlc?.percentageChange)}%`,
-              !!ohlc?.absoluteChange && !!ohlc?.percentageChange,
-            )}
-          </>
-        )}
-      </div>
-      <div className={styles.row}>{renderLegendItem('Объем.', formatVolume(volume), showVolume)}</div>
-      {compareItems.map((item) => (
-        <CompareLegendRow
-          key={`${item.symbol}|${item.mode}`}
-          item={item}
-          onRemove={onCompareRemove}
-        />
-      ))}
+      {model?.map((indicator) => {
+        const inds = Array.from(
+          indicator.values as Map<keyof Ohlc, { value: number | string | Time; color: string; name: string }>,
+        );
+        return (
+          <div
+            key={`indicator-${indicator.name}`}
+            className={styles.row}
+          >
+            {indicator.name}
+            {showOhlc &&
+              inds?.map((x, index) => {
+                const [key, serie] = x as [keyof Ohlc, { value: number | string | Time; color: string; name: string }];
+                if (!indicator.isIndicator) {
+                  if (!ohlcValuesToShowForMainSerie.includes(key)) {
+                    return null;
+                  }
+
+                  return (
+                    <div
+                      key={serie.name === '' ? `${indicator.name}${index}` : serie.name}
+                      className={styles.item}
+                    >
+                      {serie.name} <span style={{ color: serie.color }}>{serie.value as string}</span>
+                    </div>
+                  );
+                }
+
+                return (
+                  <div
+                    key={serie.name === '' ? `${indicator.name}${index}` : serie.name}
+                    className={styles.item}
+                  >
+                    {serie.name} <span style={{ color: serie.color }}>{serie.value as string}</span>
+                  </div>
+                );
+              })}
+            <Button
+              size="sm"
+              className={styles.button}
+              onClick={() => indicator.remove()}
+              label={<TrashIcon />}
+            />
+          </div>
+        );
+      })}
     </section>
   );
 };
diff --git a/src/core/Chart.ts b/src/core/Chart.ts
index d4bf4632e89a129faa2627fac050de03be44cf73..ca7441b218f9d89443d421961880e16f69712085 100644
--- a/src/core/Chart.ts
+++ b/src/core/Chart.ts
@@ -23,11 +23,20 @@ import { DrawingsManager } from '@core/DrawingsManager';
 import { EventManager } from '@core/EventManager';
 import { IndicatorManager } from '@core/IndicatorManager';
 import { ModalRenderer } from '@core/ModalRenderer';
+import { PaneManager } from '@core/PaneManager';
 import { CompareManager } from '@src/core/CompareManager';
 import { SeriesFactory, SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
 import { getThemeStore } from '@src/theme/store';
 import { ThemeKey, ThemeMode } from '@src/theme/types';
-import { Candle, ChartOptionsModel, ChartSeriesType, ChartTypeOptions, Direction } from '@src/types';
+import {
+  Candle,
+  ChartOptionsModel,
+  ChartSeriesType,
+  ChartTypeOptions,
+  Direction,
+  OHLCConfig,
+  TooltipConfig,
+} from '@src/types';
 import { Defaults } from '@src/types/defaults';
 import { DayjsOffset, Intervals, intervalsToDayjs } from '@src/types/intervals';
 import { ensureDefined } from '@src/utils';
@@ -54,6 +63,8 @@ interface ChartParams extends ChartConfig {
   dataSource: DataSource;
   eventManager: EventManager;
   modalRenderer: ModalRenderer;
+  ohlcConfig: OHLCConfig;
+  tooltipConfig: TooltipConfig;
 }
 
 /**
@@ -63,9 +74,9 @@ export class Chart {
   private lwcChart!: IChartApi;
   private container: HTMLElement;
   private eventManager: EventManager;
+  private paneManager!: PaneManager;
   private compareManager: CompareManager;
   private mouseEvents: ChartMouseEvents;
-  private drawingsManager: DrawingsManager;
   private indicatorManager: IndicatorManager;
   private optionsSubscription: Subscription;
   private dataSource: DataSource;
@@ -84,7 +95,7 @@ export class Chart {
 
   private historyBatchRunning = false;
 
-  constructor({ eventManager, dataSource, modalRenderer, ...lwcConfig }: ChartParams) {
+  constructor({ eventManager, dataSource, modalRenderer, ohlcConfig, tooltipConfig, ...lwcConfig }: ChartParams) {
     this.eventManager = eventManager;
     this.dataSource = dataSource;
     this.container = lwcConfig.container;
@@ -107,22 +118,6 @@ export class Chart {
 
     this.subscriptions.add(this.optionsSubscription);
 
-    this.subscriptions.add(
-      this.eventManager.subscribeSeriesSelected((nextSeries) => {
-        this.mainSeries.value?.destroy();
-
-        const next = ensureDefined(SeriesFactory.create(nextSeries))({
-          lwcChart: this.lwcChart,
-          dataSource,
-          mainSymbol$: this.eventManager.getSymbol(),
-          mainSerie$: this.mainSeries,
-          chartOptions: lwcConfig.chartOptions,
-        });
-
-        this.mainSeries.next(next);
-      }),
-    );
-
     this.mouseEvents = new ChartMouseEvents({ lwcChart: this.lwcChart, container: this.container });
 
     this.mouseEvents.subscribe('wheel', this.onWheel);
@@ -133,21 +128,24 @@ export class Chart {
 
     this.DOM = new DOMModel({ modalRenderer });
 
-    this.indicatorManager = new IndicatorManager({
-      eventManager,
-      DOM: this.DOM,
-      mainSerie$: this.mainSeries,
-      dataSource: this.dataSource,
+    this.paneManager = new PaneManager({
+      eventManager: this.eventManager,
       lwcChart: this.lwcChart,
-      chartOptions: lwcConfig.chartOptions,
+      dataSource,
+      DOM: this.DOM,
+      ohlcConfig,
+      subscribeChartEvent: this.subscribeChartEvent,
+      chartContainer: this.container,
+      tooltipConfig,
     });
 
-    this.drawingsManager = new DrawingsManager({
+    this.indicatorManager = new IndicatorManager({
       eventManager,
       DOM: this.DOM,
-      mainSeries$: this.mainSeries.asObservable(),
+      mainSerie$: this.mainSeries,
+      dataSource: this.dataSource,
       lwcChart: this.lwcChart,
-      container: this.container,
+      paneManager: this.paneManager,
       chartOptions: lwcConfig.chartOptions,
     });
 
@@ -156,102 +154,10 @@ export class Chart {
       eventManager: this.eventManager,
       dataSource: this.dataSource,
       indicatorManager: this.indicatorManager,
+      paneManager: this.paneManager,
     });
 
-    const getWarmupFrom = (): number => {
-      if (this.currentInterval && this.currentInterval !== Intervals.All) {
-        return getIntervalRange(this.currentInterval).from;
-      }
-
-      const range = this.lwcChart.timeScale().getVisibleRange();
-      if (!range) return 0;
-
-      const { from } = range as IRange<number>;
-      return from as number;
-    };
-
-    const warmupSymbols = (symbols: string[]) => {
-      if (!symbols.length) return;
-
-      const from = getWarmupFrom();
-      if (!from) return;
-
-      Promise.all(symbols.map((symbol) => this.dataSource.loadTill(symbol, from))).catch((error) => {
-        console.error('[Chart] Ошибка при прогреве символов:', error);
-      });
-    };
-
-    const symbols$ = combineLatest([this.eventManager.symbol(), this.compareManager.itemsObs()]).pipe(
-      map(([main, items]) => Array.from(new Set([main, ...items.map((i) => i.symbol)]))),
-    );
-
-    this.subscriptions.add(
-      symbols$.subscribe((symbols) => {
-        const prevSymbols = this.activeSymbols;
-        this.activeSymbols = symbols;
-
-        this.dataSource.setSymbols(symbols);
-
-        const prevSet = new Set(prevSymbols);
-        const added: string[] = [];
-
-        for (let i = 0; i < symbols.length; i += 1) {
-          const s = symbols[i];
-          if (!s) continue;
-          if (prevSet.has(s)) continue;
-          added.push(s);
-        }
-
-        if (added.length) {
-          warmupSymbols(added);
-        }
-      }),
-    );
-
-    this.subscriptions.add(
-      this.eventManager
-        .getInterval()
-        .pipe(withLatestFrom(symbols$))
-        .subscribe(([interval, symbols]) => {
-          this.currentInterval = interval;
-
-          if (!interval) return;
-
-          if (interval === Intervals.All) {
-            Promise.all(symbols.map((s) => this.dataSource.loadAllHistory(s)))
-              .then(() => {
-                requestAnimationFrame(() => this.lwcChart.timeScale().fitContent());
-              })
-              .catch((error) => console.error('[Chart] Ошибка при загрузке всей истории:', error));
-
-            return;
-          }
-
-          const { from, to } = getIntervalRange(interval);
-
-          Promise.all(symbols.map((s) => this.dataSource.loadTill(s, from)))
-            .then(() => {
-              this.lwcChart.timeScale().setVisibleRange({ from: from as Time, to: to as Time });
-            })
-            .catch((error) => {
-              console.error('[Chart] Ошибка при применении интервала:', error);
-            });
-        }),
-    );
-
-    this.subscriptions.add(
-      combineLatest([
-        this.eventManager.symbol(),
-        this.compareManager.itemsObs(),
-        this.mainSeries.asObservable(),
-      ]).subscribe(([main, items, serie]) => {
-        if (!serie) return;
-
-        const title = items.length ? main : '';
-        serie.getLwcSeries().applyOptions({ title });
-      }),
-    );
-
+    this.setupDataSourceSubs();
     this.setupHistoricalDataLoading();
   }
 
@@ -266,7 +172,7 @@ export class Chart {
   }
 
   public getDrawingsManager = (): DrawingsManager => {
-    return this.drawingsManager;
+    return this.paneManager.getDrawingsManager();
   };
 
   public getIndicatorManager = (): IndicatorManager => {
@@ -387,6 +293,101 @@ export class Chart {
     });
   };
 
+  private setupDataSourceSubs() {
+    const getWarmupFrom = (): number => {
+      if (this.currentInterval && this.currentInterval !== Intervals.All) {
+        return getIntervalRange(this.currentInterval).from;
+      }
+
+      const range = this.lwcChart.timeScale().getVisibleRange();
+      if (!range) return 0;
+
+      const { from } = range as IRange<number>;
+      return from as number;
+    };
+
+    const warmupSymbols = (symbols: string[]) => {
+      if (!symbols.length) return;
+
+      const from = getWarmupFrom();
+      if (!from) return;
+
+      Promise.all(symbols.map((symbol) => this.dataSource.loadTill(symbol, from))).catch((error) => {
+        console.error('[Chart] Ошибка при прогреве символов:', error);
+      });
+    };
+    const symbols$ = combineLatest([this.eventManager.symbol(), this.compareManager.itemsObs()]).pipe(
+      map(([main, items]) => Array.from(new Set([main, ...items.map((i) => i.symbol)]))),
+    );
+
+    this.subscriptions.add(
+      this.eventManager
+        .getInterval()
+        .pipe(withLatestFrom(symbols$))
+        .subscribe(([interval, symbols]) => {
+          this.currentInterval = interval;
+
+          if (!interval) return;
+
+          if (interval === Intervals.All) {
+            Promise.all(symbols.map((s) => this.dataSource.loadAllHistory(s)))
+              .then(() => {
+                requestAnimationFrame(() => this.lwcChart.timeScale().fitContent());
+              })
+              .catch((error) => console.error('[Chart] Ошибка при загрузке всей истории:', error));
+
+            return;
+          }
+
+          const { from, to } = getIntervalRange(interval);
+
+          Promise.all(symbols.map((s) => this.dataSource.loadTill(s, from)))
+            .then(() => {
+              this.lwcChart.timeScale().setVisibleRange({ from: from as Time, to: to as Time });
+            })
+            .catch((error) => {
+              console.error('[Chart] Ошибка при применении интервала:', error);
+            });
+        }),
+    );
+
+    this.subscriptions.add(
+      symbols$.subscribe((symbols) => {
+        const prevSymbols = this.activeSymbols;
+        this.activeSymbols = symbols;
+
+        this.dataSource.setSymbols(symbols);
+
+        const prevSet = new Set(prevSymbols);
+        const added: string[] = [];
+
+        for (let i = 0; i < symbols.length; i += 1) {
+          const s = symbols[i];
+          if (!s) continue;
+          if (prevSet.has(s)) continue;
+          added.push(s);
+        }
+
+        if (added.length) {
+          warmupSymbols(added);
+        }
+      }),
+    );
+
+    this.subscriptions.add(
+      combineLatest([
+        this.eventManager.symbol(),
+        this.compareManager.itemsObs(),
+        this.mainSeries.asObservable(),
+      ]).subscribe(([main, items, serie]) => {
+        if (!serie) return;
+
+        const title = items.length ? main : '';
+        serie.getLwcSeries().applyOptions({ title });
+      }),
+    );
+  }
+
   private setupHistoricalDataLoading(): void {
     // todo (не)вызвать loadMoreHistory после проверки на необходимость дозагрузки после смены таймфрейма
     this.mouseEvents.subscribe('visibleLogicalRangeChange', (logicalRange: LogicalRange | null) => {
diff --git a/src/core/CompareIndicator.ts b/src/core/CompareIndicator.ts
deleted file mode 100644
index d605ae7e1ed6f6f0dc84742f27512888719c6443..0000000000000000000000000000000000000000
--- a/src/core/CompareIndicator.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { IChartApi, SeriesPartialOptionsMap, SeriesType } from 'lightweight-charts';
-import { BehaviorSubject } from 'rxjs';
-
-import { DataSource } from '@core/DataSource';
-import { DOMObjectParams } from '@core/DOMObject';
-
-import { SeriesObject } from '@src/core/SeriesObject';
-import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
-import { ChartTypeOptions } from '@src/types';
-
-interface CompareIndicatorParams extends DOMObjectParams {
-  lwcChart: IChartApi;
-  dataSource: DataSource;
-  mainSerie$: BehaviorSubject<SeriesStrategies | null>;
-  symbol$: BehaviorSubject<string>;
-  seriesType: SeriesType;
-  seriesOptions?: SeriesPartialOptionsMap[SeriesType];
-  showSymbolLabel?: boolean;
-  paneIndex?: number;
-}
-
-export class CompareIndicator extends SeriesObject {
-  constructor(params: CompareIndicatorParams) {
-    super({
-      ...params,
-    });
-  }
-}
diff --git a/src/core/CompareManager.ts b/src/core/CompareManager.ts
index b0bafa4b7ac32fd2da377a163c9cca00640f89c0..3c1522eac2426eb28bfdf227c795c676b68b874a 100644
--- a/src/core/CompareManager.ts
+++ b/src/core/CompareManager.ts
@@ -3,11 +3,16 @@ import { BehaviorSubject, distinctUntilChanged, map, Observable } from 'rxjs';
 
 import { DataSource } from '@core/DataSource';
 import { EventManager } from '@core/EventManager';
+import { Indicator } from '@core/Indicator';
 import { IndicatorManager } from '@core/IndicatorManager';
+import { IndicatorConfig, IndicatorDataFormatter } from '@core/Indicators';
+import { emaIndicator } from '@core/Indicators/ema';
+import { PaneManager } from '@core/PaneManager';
 
 import { MAIN_PANE_INDEX } from '@src/constants';
-import { CompareIndicator } from '@src/core/CompareIndicator';
+// import { CompareIndicator } from '@src/core/CompareIndicator';
 import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
+import { getThemeStore } from '@src/theme';
 import { CompareItem, CompareMode, Direction } from '@src/types';
 import { normalizeSymbol } from '@src/utils';
 
@@ -17,35 +22,52 @@ interface CompareEntry {
   mode: CompareMode;
   paneIndex: number;
   symbol$: BehaviorSubject<string>;
-  entity: CompareIndicator;
+  entity: Indicator;
 }
 
 function makeKey(symbol: string, mode: CompareMode): string {
   return `${symbol}|${mode}`;
 }
 
+interface CompareManagerParams {
+  chart: IChartApi;
+  eventManager: EventManager;
+  dataSource: DataSource;
+  indicatorManager: IndicatorManager;
+  paneManager: PaneManager;
+}
+
+const defaultCompareIndicator: IndicatorConfig = {
+  newPane: true,
+  series: [
+    {
+      name: 'Line', // todo: change with enum
+      id: `compare-${Math.random()}`,
+      seriesOptions: {
+        visible: true,
+        color: getThemeStore().colors.chartPriceLineText,
+      },
+    },
+  ],
+};
+
 export class CompareManager {
   private readonly chart: IChartApi;
   private readonly eventManager: EventManager;
   private readonly dataSource: DataSource;
   private readonly indicatorManager: IndicatorManager;
+  private readonly paneManager: PaneManager;
 
   private readonly entries = new Map<string, CompareEntry>();
   private readonly itemsSubject = new BehaviorSubject<CompareItem[]>([]);
-  private readonly entitiesSubject = new BehaviorSubject<CompareIndicator[]>([]);
+  private readonly entitiesSubject = new BehaviorSubject<Indicator[]>([]);
 
-  private nextPaneIndex = MAIN_PANE_INDEX + 1;
-
-  constructor(params: {
-    chart: IChartApi;
-    eventManager: EventManager;
-    dataSource: DataSource;
-    indicatorManager: IndicatorManager;
-  }) {
-    this.chart = params.chart;
-    this.eventManager = params.eventManager;
-    this.dataSource = params.dataSource;
-    this.indicatorManager = params.indicatorManager;
+  constructor({ chart, eventManager, dataSource, indicatorManager, paneManager }: CompareManagerParams) {
+    this.chart = chart;
+    this.eventManager = eventManager;
+    this.dataSource = dataSource;
+    this.indicatorManager = indicatorManager;
+    this.paneManager = paneManager;
 
     this.eventManager.timeframe().subscribe(() => {
       this.applyPolicy();
@@ -56,7 +78,7 @@ export class CompareManager {
     return this.itemsSubject.asObservable();
   }
 
-  public entitiesObs(): Observable<CompareIndicator[]> {
+  public entitiesObs(): Observable<Indicator[]> {
     return this.entitiesSubject.asObservable();
   }
 
@@ -87,30 +109,34 @@ export class CompareManager {
     const { paneIndex, priceScaleId } = this.getPlacement(mode);
     const symbol$ = new BehaviorSubject(symbol);
 
-    const entity = this.indicatorManager.addEntity<CompareIndicator>(
+    const entity = this.indicatorManager.addEntity<Indicator>(
       (zIndex, moveUp, moveDown) =>
-        new CompareIndicator({
+        new Indicator({
           id: key,
+          lwcChart: this.chart,
+          mainSymbol$: new BehaviorSubject<string>(symbol),
+          dataSource: this.dataSource,
           zIndex,
+          onDelete: () => this.removeByKey(key),
           moveUp,
           moveDown,
-          onDelete: () => this.removeByKey(key),
-          lwcChart: this.chart,
-          dataSource: this.dataSource,
-          mainSerie$: new BehaviorSubject<SeriesStrategies | null>(null),
-          symbol$,
-          seriesType,
-          paneIndex,
-          seriesOptions: {
-            priceScaleId,
+          paneManager: this.paneManager,
+          config: {
+            ...defaultCompareIndicator,
+            series: [
+              {
+                ...defaultCompareIndicator.series[0],
+                seriesOptions: {
+                  ...defaultCompareIndicator.series[0]?.seriesOptions,
+                  priceScaleId,
+                },
+              },
+            ],
+            newPane: mode === CompareMode.NewPane,
           },
         }),
     );
 
-    if (mode === CompareMode.NewPane) {
-      entity.getStrategy().getLwcSeries().moveToPane(paneIndex);
-    }
-
     this.entries.set(key, { key, symbol, mode, paneIndex, symbol$, entity });
 
     this.applyPolicy();
@@ -173,7 +199,6 @@ export class CompareManager {
 
     this.entries.delete(key);
 
-    this.indicatorManager.removeEntity(entry.entity);
     entry.entity.destroy();
     entry.symbol$.complete();
 
@@ -185,7 +210,7 @@ export class CompareManager {
     const values = Array.from(this.entries.values());
 
     const items: CompareItem[] = [];
-    const entities: CompareIndicator[] = [];
+    const entities: Indicator[] = [];
 
     for (let i = 0; i < values.length; i += 1) {
       items.push({ symbol: values[i].symbol, mode: values[i].mode });
@@ -209,8 +234,8 @@ export class CompareManager {
 
     let hasMainNewScale = false;
     for (let i = 0; i < list.length; i += 1) {
-      const series = list[i].entity.getStrategy().getLwcSeries();
-      const paneIndex = series.getPane().paneIndex();
+      // [0 - в индикаторах compare сущности может быть только одна серия] [1 - entry]
+      const paneIndex = Array.from(list[i].entity.getSeriesMap())[0][1].getPane().paneIndex();
       if (paneIndex === MAIN_PANE_INDEX && list[i].mode === CompareMode.NewScale) {
         hasMainNewScale = true;
         break;
@@ -219,7 +244,9 @@ export class CompareManager {
 
     const paneSet = new Set<number>();
     for (let i = 0; i < list.length; i += 1) {
-      const paneIndex = list[i].entity.getStrategy().getLwcSeries().getPane().paneIndex();
+      // [0 - в индикаторах compare сущности может быть только одна серия] [1 - entry]
+      const paneIndex = Array.from(list[i].entity.getSeriesMap())[0][1].getPane().paneIndex();
+
       if (paneIndex !== MAIN_PANE_INDEX) paneSet.add(paneIndex);
     }
 
@@ -258,15 +285,17 @@ export class CompareManager {
 
     for (let i = 0; i < list.length; i += 1) {
       const entry = list[i];
-      const series = entry.entity.getStrategy().getLwcSeries();
-      const paneIndex = series.getPane().paneIndex();
+
+      // [0 - в индикаторах compare сущности может быть только одна серия] [1 - entry]
+      const serie = Array.from(entry.entity.getSeriesMap())[0][1];
+      const paneIndex = serie.getPane().paneIndex();
 
       if (paneIndex !== MAIN_PANE_INDEX) {
-        series.applyOptions({ priceScaleId: Direction.Right });
+        serie.applyOptions({ priceScaleId: Direction.Right });
         continue;
       }
 
-      series.applyOptions({
+      serie.applyOptions({
         priceScaleId: entry.mode === CompareMode.NewScale ? Direction.Left : Direction.Right,
       });
     }
@@ -274,7 +303,7 @@ export class CompareManager {
 
   private getPlacement(mode: CompareMode): { paneIndex: number; priceScaleId: Direction } {
     const priceScaleId = mode === CompareMode.NewScale ? Direction.Left : Direction.Right;
-    const paneIndex = mode === CompareMode.NewPane ? this.nextPaneIndex++ : MAIN_PANE_INDEX;
+    const paneIndex = mode === CompareMode.NewPane ? this.paneManager.getPanes().size - 1 : MAIN_PANE_INDEX;
     return { paneIndex, priceScaleId };
   }
 }
diff --git a/src/core/ContainerManager.ts b/src/core/ContainerManager.ts
index 609b714da5867acda0133dafee0859ab6c7c36c1..6c9b1de15bff24365fea2616156786026c4d4aec 100644
--- a/src/core/ContainerManager.ts
+++ b/src/core/ContainerManager.ts
@@ -81,20 +81,6 @@ export class ContainerManager {
     toolBarContainer.style.minHeight = '0';
     toolBarContainer.style.overflow = 'hidden';
 
-    const legendContainer = document.createElement('div');
-    legendContainer.style.width = '100%';
-    legendContainer.style.position = 'absolute';
-    legendContainer.style.top = '0';
-    legendContainer.style.left = '0';
-    legendContainer.style.zIndex = ZIndex.Base;
-
-    const overlayContainer = document.createElement('div');
-    overlayContainer.className = 'moex-chart-overlay-container';
-    overlayContainer.style.position = 'absolute';
-    overlayContainer.style.inset = '0';
-    overlayContainer.style.zIndex = ZIndex.Base;
-    overlayContainer.style.pointerEvents = 'none';
-
     const controlBarContainer = document.createElement('div');
     controlBarContainer.style.width = '250px';
     controlBarContainer.style.position = 'absolute';
@@ -111,7 +97,7 @@ export class ContainerManager {
     modalContainer.style.zIndex = ZIndex.Modal;
     modalContainer.style.pointerEvents = 'none';
 
-    chartAreaContainer.append(overlayContainer, controlBarContainer, modalContainer);
+    chartAreaContainer.append(controlBarContainer, modalContainer);
 
     chartContainer.style.gridTemplateColumns = 'minmax(0, 1fr)';
     chartContainer.append(chartAreaContainer);
@@ -151,9 +137,7 @@ export class ContainerManager {
       chartAreaContainer,
       toolBarContainer,
 
-      legendContainer,
       modalContainer,
-      overlayContainer,
       controlBarContainer,
 
       toggleToolbar,
@@ -166,4 +150,25 @@ export class ContainerManager {
   static clearContainers(parentContainer: HTMLElement): void {
     parentContainer.innerHTML = '';
   }
+
+  static createPaneContainers() {
+    const legendContainer = document.createElement('div');
+    legendContainer.style.width = '100%';
+    legendContainer.style.position = 'absolute';
+    legendContainer.style.top = '0';
+    legendContainer.style.left = '0';
+    legendContainer.style.zIndex = ZIndex.Base;
+
+    const paneOverlayContainer = document.createElement('div');
+    paneOverlayContainer.className = 'moex-chart-pane-overlay-container';
+    paneOverlayContainer.style.position = 'absolute';
+    paneOverlayContainer.style.inset = '0';
+    paneOverlayContainer.style.zIndex = ZIndex.Base;
+    paneOverlayContainer.style.pointerEvents = 'none';
+
+    return {
+      legendContainer,
+      paneOverlayContainer,
+    };
+  }
 }
diff --git a/src/core/DrawingsManager.ts b/src/core/DrawingsManager.ts
index 57dfc8829896a927cd7f083c3b36ff5d6fbccab5..21b5fb35c683337509a1ae48977e11e5edddfa7c 100644
--- a/src/core/DrawingsManager.ts
+++ b/src/core/DrawingsManager.ts
@@ -24,7 +24,7 @@ interface DrawingsManagerParams {
   eventManager: EventManager;
   mainSeries$: Observable<SeriesStrategies | null>;
   lwcChart: IChartApi;
-  chartOptions?: ChartTypeOptions;
+  // chartOptions?: ChartTypeOptions;
   DOM: DOMModel;
   container: HTMLElement;
 }
@@ -166,7 +166,7 @@ export const drawingsMap: Record<DrawingsNames, DrawingConfig> = {
 export class DrawingsManager {
   private eventManager: EventManager;
   private lwcChart: IChartApi;
-  private chartOptions?: ChartTypeOptions;
+  // private chartOptions?: ChartTypeOptions;
   private drawingsQty = 0; // todo: replace with hash
   private DOM: DOMModel;
   private container: HTMLElement;
@@ -175,11 +175,11 @@ export class DrawingsManager {
   private subscriptions = new Subscription();
   private drawings$: BehaviorSubject<Drawing[]> = new BehaviorSubject<Drawing[]>([]);
 
-  constructor({ eventManager, mainSeries$, lwcChart, chartOptions, DOM, container }: DrawingsManagerParams) {
+  constructor({ eventManager, mainSeries$, lwcChart, DOM, container }: DrawingsManagerParams) {
     this.DOM = DOM;
     this.eventManager = eventManager;
     this.lwcChart = lwcChart;
-    this.chartOptions = chartOptions;
+    // this.chartOptions = chartOptions;
     this.container = container;
 
     this.subscriptions.add(
diff --git a/src/core/HoverController.ts b/src/core/HoverController.ts
deleted file mode 100644
index 0dddcb1149a50e8f3c72ecce5ca13fbe7f582237..0000000000000000000000000000000000000000
--- a/src/core/HoverController.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-import { BarData, CustomData, HistogramData, LineData, MouseEventParams } from 'lightweight-charts';
-import { Observable, Subscription } from 'rxjs';
-
-import { CompareLegendItem, Legend } from '@core/Legend';
-
-import { TooltipService } from '@core/Tooltip';
-
-import { CompareManager } from '@src/core/CompareManager';
-import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
-
-import { CompareMode } from '@src/types';
-import { formatPrice, getPriceColor } from '@src/utils';
-
-import { ChartMouseEvents } from './ChartMouseEvents';
-
-interface HoverControllerParams {
-  legend: Legend;
-  tooltip?: TooltipService;
-  chartEventSub: ChartMouseEvents['subscribe'];
-  chartEventUnsub: ChartMouseEvents['unsubscribe'];
-  mainSeriesObs: Observable<SeriesStrategies | null>;
-  compareManager: CompareManager;
-}
-
-// todo: первый кандидат на рефактор
-// todo: не нужно тянуть сюда tooltip и legend. Hover нужно наоборот прокидывать в них
-export class HoverController {
-  private unsubChartHover: () => void = () => {};
-  private unsubSeries: () => void = () => {};
-  private mainSeriesSubscription: Subscription;
-  private isChartHovered = false;
-  private tooltip: TooltipService | undefined;
-  private legend: Legend;
-  private compareManager: CompareManager;
-
-  constructor({
-    legend,
-    tooltip,
-    chartEventSub,
-    chartEventUnsub,
-    mainSeriesObs,
-    compareManager,
-  }: HoverControllerParams) {
-    this.tooltip = tooltip;
-    this.legend = legend;
-    this.compareManager = compareManager;
-
-    this.mainSeriesSubscription = mainSeriesObs.subscribe((nextSeries: SeriesStrategies | null) => {
-      if (!nextSeries) return;
-
-      this.unsubChartHover();
-      this.unsubSeries();
-
-      const onCrosshairMove = (param: MouseEventParams) => {
-        this.handleCrosshairMove(nextSeries, param);
-      };
-
-      chartEventSub('crosshairMove', onCrosshairMove);
-      this.unsubChartHover = () => chartEventUnsub('crosshairMove', onCrosshairMove);
-
-      const onDataChanged = () => this.updateWithLastCandle(nextSeries);
-      nextSeries.subscribeDataChanged(onDataChanged);
-      this.unsubSeries = () => nextSeries.unsubscribeDataChanged(onDataChanged);
-    });
-  }
-
-  public destroy(): void {
-    this.unsubChartHover();
-    this.unsubSeries();
-    this.mainSeriesSubscription.unsubscribe();
-  }
-
-  private handleCrosshairMove(mainSeries: SeriesStrategies, param: MouseEventParams) {
-    if (param.point === undefined || !param.time || param.point.x < 0 || param.point.y < 0) {
-      this.tooltip?.setVisible(false);
-      this.isChartHovered = false;
-      this.updateWithLastCandle(mainSeries);
-      return;
-    }
-
-    this.isChartHovered = true;
-
-    const { prevSeriesData, currentSeriesData } = this.processChartHover(param, mainSeries);
-    const compareItems = this.getCompareItems(param.logical!);
-
-    this.legend.updateLegendView(prevSeriesData, currentSeriesData, compareItems);
-
-    this.tooltip?.setVisible(true);
-    this.tooltip?.setPosition(param.point);
-  }
-
-  private getCompareItems(logical: number): CompareLegendItem[] {
-    const entities = this.compareManager.getAllEntities();
-
-    return entities.map(({ symbol, entity, mode }) => {
-      const strategy = entity.getStrategy();
-      const data = strategy.dataByIndex(logical);
-
-      return this.formatCompareItem(symbol, mode, data);
-    });
-  }
-
-  private getCompareItemsLast(): CompareLegendItem[] {
-    const entities = this.compareManager.getAllEntities();
-
-    return entities.map(({ symbol, entity, mode }) => {
-      const strategy = entity.getStrategy();
-      const allData = strategy.data();
-      const lastData = allData[allData.length - 1];
-
-      return this.formatCompareItem(symbol, mode, lastData);
-    });
-  }
-
-  private formatCompareItem(symbol: string, mode: CompareMode, data: any): CompareLegendItem {
-    let valueStr = '-';
-    const priceColor = getPriceColor(data);
-
-    if (data) {
-      const value = data.close ?? data.value;
-
-      if (value) {
-        valueStr = formatPrice(value) as string;
-      }
-    }
-
-    return {
-      symbol,
-      mode,
-      value: valueStr,
-      color: priceColor,
-    };
-  }
-
-  private processChartHover(
-    param: MouseEventParams,
-    mainSeries: SeriesStrategies,
-  ): {
-    prevSeriesData: BarData | LineData | HistogramData | CustomData | null;
-    currentSeriesData: BarData | LineData | HistogramData | CustomData | null;
-  } {
-    const currentSeriesData = param.seriesData.get(mainSeries.getLwcSeries()) ?? null;
-    const prevSeriesData = mainSeries.dataByIndex(param.logical! - 1) ?? null;
-
-    return { prevSeriesData, currentSeriesData };
-  }
-
-  private updateWithLastCandle(series: SeriesStrategies): void {
-    if (this.isChartHovered) return;
-
-    const seriesData = series.data();
-    if (seriesData.length < 1) return;
-
-    const currentSeriesData = seriesData[seriesData.length - 1];
-    const prevSeriesData = seriesData.length > 1 ? seriesData[seriesData.length - 2] : null;
-
-    const compareItems = this.getCompareItemsLast();
-
-    this.legend.updateLegendView(prevSeriesData, currentSeriesData, compareItems);
-  }
-}
diff --git a/src/core/Indicator.ts b/src/core/Indicator.ts
index 793ca19f9f0bcf4cedd80be6d970354ffbd08a85..e08834d1465c147798a21034cedc3063ad8de412 100644
--- a/src/core/Indicator.ts
+++ b/src/core/Indicator.ts
@@ -1,9 +1,11 @@
 import { IChartApi } from 'lightweight-charts';
-import { BehaviorSubject, Observable } from 'rxjs';
+import { BehaviorSubject, Observable, throttleTime } from 'rxjs';
 
 import { DataSource } from '@core/DataSource';
 import { DOMObject, DOMObjectParams } from '@core/DOMObject';
-import { IndicatorsIds, indicatorsMap } from '@core/Indicators';
+import { IndicatorConfig, IndicatorsIds, indicatorsMap } from '@core/Indicators';
+import { Pane } from '@core/Pane';
+import { PaneManager } from '@core/PaneManager';
 
 import { SeriesFactory, SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
 import { ChartTypeOptions } from '@src/types';
@@ -11,35 +13,41 @@ import { ensureDefined } from '@src/utils';
 
 type IIndicator = DOMObject;
 
-interface IndicatorParams extends DOMObjectParams {
+export interface IndicatorParams extends DOMObjectParams {
   mainSymbol$: Observable<string>;
-  mainSerie$: BehaviorSubject<SeriesStrategies | null>;
   lwcChart: IChartApi;
   dataSource: DataSource;
+  paneManager: PaneManager;
   chartOptions?: ChartTypeOptions;
+  config?: IndicatorConfig;
 }
 
 export class Indicator extends DOMObject implements IIndicator {
   private series: SeriesStrategies[] = [];
   private seriesMap: Map<string, SeriesStrategies> = new Map();
+  private lwcChart: IChartApi;
+  private associatedPane: Pane;
 
   constructor({
     id,
     lwcChart,
     dataSource,
-    chartOptions,
     zIndex,
     onDelete,
     moveUp,
     moveDown,
-    mainSerie$,
     mainSymbol$,
+    paneManager,
+    config,
   }: IndicatorParams) {
     super({ id: id as string, zIndex, onDelete, moveUp, moveDown });
+    this.lwcChart = lwcChart;
 
-    const indicatorConfig = indicatorsMap[id as IndicatorsIds];
+    const indicatorConfig = indicatorsMap[id as IndicatorsIds] ?? config;
 
-    const { series, paneIndex } = ensureDefined(indicatorConfig);
+    const { series, newPane } = ensureDefined(indicatorConfig);
+
+    this.associatedPane = newPane ? paneManager.addPane() : paneManager.getMainPane();
 
     series.forEach(({ name, id: serieId, dataFormatter, seriesOptions, priceScaleOptions }) => {
       const serie = SeriesFactory.create(name!)({
@@ -47,12 +55,11 @@ export class Indicator extends DOMObject implements IIndicator {
         dataSource,
         customFormatter: dataFormatter,
         seriesOptions,
-        chartOptions,
         priceScaleOptions,
         mainSymbol$,
-        mainSerie$,
+        mainSerie$: this.associatedPane.getMainSerie(),
         showSymbolLabel: false,
-        paneIndex,
+        paneIndex: this.associatedPane.getId(),
         indicatorReference: this,
       });
 
@@ -60,14 +67,32 @@ export class Indicator extends DOMObject implements IIndicator {
 
       this.series.push(serie);
     });
+
+    this.associatedPane.setIndicator(id as IndicatorsIds, this);
   }
 
-  public getSeriesMap() {
+  public subscribeDataChange(handler: () => void): void {
+    // todo: возможно нужно переписать завязавшись гна this.associatedPane.getMainSerie()
+    const firer = new BehaviorSubject<number>(0);
+    this.series.forEach((serie) => {
+      serie.subscribeDataChanged(() => {
+        firer.next(firer.value + 1);
+      });
+    });
+
+    firer.pipe(throttleTime(500)).subscribe(() => {
+      handler();
+    });
+  }
+
+  public getSeriesMap(): Map<string, SeriesStrategies> {
     return this.seriesMap;
   }
 
   public delete() {
     super.delete();
+
+    this.associatedPane.removeIndicator(this.id as IndicatorsIds);
   }
 
   public show() {
diff --git a/src/core/IndicatorManager.ts b/src/core/IndicatorManager.ts
index 1fca145ef84e3dd780cc91c0b18195287791c0eb..183b8b21f1a06eeb8d040d8be600c9223b9ba28c 100644
--- a/src/core/IndicatorManager.ts
+++ b/src/core/IndicatorManager.ts
@@ -6,6 +6,7 @@ import { DOMModel } from '@core/DOMModel';
 import { EventManager } from '@core/EventManager';
 import { Indicator } from '@core/Indicator';
 import { IndicatorsIds } from '@core/Indicators';
+import { PaneManager } from '@core/PaneManager';
 import { DOMObject } from '@src/core/DOMObject';
 import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
 import { ChartTypeOptions } from '@src/types';
@@ -15,6 +16,7 @@ interface SeriesParams {
   dataSource: DataSource;
   mainSerie$: BehaviorSubject<SeriesStrategies | null>;
   lwcChart: IChartApi;
+  paneManager: PaneManager;
   DOM: DOMModel;
   chartOptions?: ChartTypeOptions;
 }
@@ -28,7 +30,7 @@ export class IndicatorManager {
   private indicatorSeriesMap$: BehaviorSubject<Map<IndicatorsIds, Indicator>> = new BehaviorSubject(new Map());
   private DOM: DOMModel;
 
-  constructor({ eventManager, dataSource, lwcChart, DOM, chartOptions, mainSerie$ }: SeriesParams) {
+  constructor({ eventManager, dataSource, lwcChart, DOM, chartOptions, mainSerie$, paneManager }: SeriesParams) {
     this.eventManager = eventManager;
     this.lwcChart = lwcChart;
     this.chartOptions = chartOptions;
@@ -45,13 +47,13 @@ export class IndicatorManager {
                 id,
                 lwcChart,
                 mainSymbol$: this.eventManager.getSymbol(),
-                mainSerie$,
                 dataSource,
                 chartOptions,
                 zIndex,
                 onDelete: this.deleteIndicator,
                 moveUp,
                 moveDown,
+                paneManager,
               }),
           );
 
@@ -80,7 +82,7 @@ export class IndicatorManager {
     });
   }
 
-  public addEntity<T extends DOMObject>(
+  public addEntity<T extends Indicator>(
     factory: (zIndex: number, moveUp: (id: string) => void, moveDown: (id: string) => void) => T,
   ): T {
     return this.DOM.setEntity(factory);
diff --git a/src/core/Indicators/index.tsx b/src/core/Indicators/index.tsx
index 3b2b10fc58b2901017d6d7bd002a1cb4294037b2..85542e5fa4f1b0e8e72247c083599b731d66046b 100644
--- a/src/core/Indicators/index.tsx
+++ b/src/core/Indicators/index.tsx
@@ -26,9 +26,9 @@ export interface IndicatorConfig {
     seriesOptions?: SeriesPartialOptionsMap[ChartSeriesType];
     priceScaleOptions?: DeepPartial<PriceScaleOptions>;
     priceScaleId?: string;
-    dataFormatter<T extends SeriesType>(params: IndicatorDataFormatter<T>): SeriesDataItemTypeMap<Time>[T][];
+    dataFormatter?<T extends SeriesType>(params: IndicatorDataFormatter<T>): SeriesDataItemTypeMap<Time>[T][];
   }[];
-  paneIndex?: number;
+  newPane?: boolean;
 }
 
 export enum IndicatorsIds {
@@ -101,7 +101,7 @@ export const indicatorsMap: Partial<Record<IndicatorsIds, IndicatorConfig>> = {
     ],
   },
   [IndicatorsIds.macd]: {
-    paneIndex: 1, // todo: временное решение , пока нет поддержки пейнов
+    newPane: true,
     series: [
       {
         name: 'Line', // todo: change with enum
diff --git a/src/core/Legend.ts b/src/core/Legend.ts
index f3eeaf0c4682be6f9768e92e2c6b6615c5837887..29d3d77725714f7154ff9938ff0eb94ce5a8d4e7 100644
--- a/src/core/Legend.ts
+++ b/src/core/Legend.ts
@@ -1,17 +1,23 @@
-import { BarData, CustomData, HistogramData, LineData, Time } from 'lightweight-charts';
+import { MouseEventParams, Point, Time } from 'lightweight-charts';
 
-import { BehaviorSubject, combineLatest, map, Observable } from 'rxjs';
+import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
 
-import { DataSource } from '@core/DataSource';
+import { ChartMouseEvents } from '@core/ChartMouseEvents';
 
 import { EventManager } from '@core/EventManager';
+import { Indicator } from '@core/Indicator';
+import { IndicatorsIds } from '@core/Indicators';
+import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
 import { CompareMode, OHLCConfig } from '@src/types';
-import { isBarData, isLineData } from '@src/utils';
+import { ensureDefined } from '@src/utils';
 
 export interface LegendParams {
   config: OHLCConfig;
   eventManager: EventManager;
-  dataSource: DataSource;
+  indicators: BehaviorSubject<Map<IndicatorsIds, Indicator>>;
+  subscribeChartEvent: ChartMouseEvents['subscribe'];
+  mainSeries: BehaviorSubject<SeriesStrategies | null> | null;
+  paneId: number;
 }
 
 export interface Ohlc {
@@ -33,99 +39,235 @@ export interface CompareLegendItem {
 }
 
 export interface LegendVM {
-  ohlc: Ohlc | null;
-  symbol: string;
-  volume: number | null;
-  compareItems: CompareLegendItem[];
+  vm: LegendModel;
 }
 
-// todo: принести в легенду данные из indicatorManager
+export type LegendModel = {
+  name: IndicatorsIds | string;
+  isIndicator: boolean;
+  values: Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>>;
+  remove: () => void;
+}[];
+
+export const ohlcValuesToShowForMainSerie = [
+  // 'time',
+  'open',
+  'high',
+  'low',
+  'close',
+  'value',
+  // 'absoluteChange',
+  'percentageChange',
+];
+
+export const ohlcValuesToShowForIndicators = [
+  // 'time',
+  'open',
+  // 'high',
+  // 'low',
+  // 'close',
+  'value',
+  // 'absoluteChange',
+  // 'percentageChange'
+];
+
 export class Legend {
   private eventManager: EventManager;
-  private dataSource: DataSource;
-  private ohlc$ = new BehaviorSubject<Ohlc | null>(null);
-  private volume$ = new BehaviorSubject<number | null>(null); // fixme should be map
-  private compareItems$ = new BehaviorSubject<CompareLegendItem[]>([]);
+  private indicators: Map<IndicatorsIds, Indicator> = new Map();
   private config: OHLCConfig;
 
-  constructor({ config, eventManager, dataSource }: LegendParams) {
+  private mainSeries!: SeriesStrategies;
+  private isChartHovered = false;
+  private model$ = new BehaviorSubject<LegendModel>([]);
+  private tooltipVisability = new BehaviorSubject<boolean>(false);
+  private tooltipPos = new BehaviorSubject<null | Point>(null);
+  private paneId: number;
+
+  constructor({ config, eventManager, indicators, subscribeChartEvent, mainSeries, paneId }: LegendParams) {
     this.config = config;
     this.eventManager = eventManager;
-    this.dataSource = dataSource;
+    this.paneId = paneId;
+
+    if (!mainSeries) {
+      indicators.subscribe((value: Map<IndicatorsIds, Indicator>) => {
+        this.indicators = value;
+        this.handleIndicatorSeriesDataChange();
+      });
+    } else {
+      combineLatest([mainSeries, indicators]).subscribe(([mainSerie, inds]) => {
+        if (!mainSerie) {
+          return;
+        }
+        this.mainSeries = mainSerie;
+        this.indicators = inds;
+        this.handleMainSeriesDataChange();
+      });
+    }
+    subscribeChartEvent('crosshairMove', this.handleCrosshairMove);
   }
 
-  public getConfig(): OHLCConfig {
-    return this.config;
+  public subscribeCursorPosition(cb: (point: Point | null) => void) {
+    this.tooltipPos.subscribe(cb);
   }
 
-  public getLegendViewModel(): Observable<LegendVM> {
-    return combineLatest([this.ohlc$, this.eventManager.getSymbol(), this.volume$, this.compareItems$]).pipe(
-      map(([ohlc, symbol, volume, compareItems]): LegendVM => <LegendVM>{ ohlc, symbol, volume, compareItems }),
-    );
+  public subscribeCursorVisability(cb: (isVisible: boolean) => void) {
+    this.tooltipVisability.subscribe(cb);
   }
 
-  public updateLegendView(
-    prev: BarData | LineData | HistogramData | CustomData | null,
-    current: BarData | LineData | HistogramData | CustomData | null,
-    compareItems: CompareLegendItem[] = [],
-  ): void {
-    const preparedData = calcCandleChange(prev, current);
-    if (!preparedData) return;
+  private handleIndicatorSeriesDataChange = () => {
+    for (const [_, indicator] of this.indicators) {
+      indicator?.subscribeDataChange(this.updateWithLastCandle);
+    }
+  };
 
-    const { customValues, ...ohlc } = preparedData;
+  private handleMainSeriesDataChange = () => {
+    this.mainSeries?.subscribeDataChanged(() => {
+      this.updateWithLastCandle();
+    });
+  };
 
-    this.ohlc$.next(ohlc as Ohlc);
+  private updateWithLastCandle = () => {
+    if (this.isChartHovered) return;
 
-    if (!customValues) return;
-    this.volume$.next(customValues.volume ?? null);
+    const model: LegendModel = [];
 
-    this.compareItems$.next(compareItems);
-  }
+    if (this.mainSeries) {
+      const series = new Map();
 
-  public destroy() {
-    this.volume$.complete();
-    this.ohlc$.complete();
-    this.compareItems$.complete();
-  }
-}
+      const serieData = this.mainSeries.getLegendData();
 
-function calcCandleChange(
-  prev: BarData | LineData | HistogramData | CustomData | null,
-  current: BarData | LineData | HistogramData | CustomData | null,
-): (Ohlc & { customValues?: Record<string, any> }) | null {
-  if (!current) {
-    return null;
-  }
+      Object.entries(serieData).forEach(([key, sd]) => {
+        series.set(`${key}`, {
+          ...sd,
+        });
+      });
 
-  if (!prev) {
-    return current;
-  }
+      model.push({
+        name: this.mainSeries.options().title,
+        values: series as Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>>,
+        isIndicator: false,
+        remove: () => {
+          // serieData.remove() // todo: запретить удалять главную серию на главном пейне
+        },
+      });
+    }
+
+    if (!this.indicators) {
+      return;
+    }
+
+    for (const [indicatorName, indicator] of this.indicators) {
+      const indicatorSeries = new Map();
+
+      for (const [serieName, serie] of indicator.getSeriesMap()) {
+        if (!serie.isVisible()) {
+          continue;
+        }
+
+        const serieData = serie.getLegendData();
+
+        const value = serieData.value ?? serieData.close;
+
+        indicatorSeries.set(serieName, { ...value });
+      }
 
-  if (isBarData(prev) && isBarData(current)) {
-    const absoluteChange = current.close - prev.close;
-    const percentageChange = ((current.close - prev.close) / prev.close) * 100;
+      model.push({
+        name: indicatorName,
+        values: indicatorSeries as Partial<
+          Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>
+        >,
+        isIndicator: true,
+        remove: () => indicator.delete(),
+      });
+    }
 
-    return {
-      ...current,
-      absoluteChange,
-      percentageChange,
-    };
+    this.model$.next(model);
+  };
+
+  private handleCrosshairMove = (param: MouseEventParams) => {
+    // todo: есть одинаковый код с updateWithLastCandle
+    if (param.point === undefined || !param.time || param.point.x < 0 || param.point.y < 0) {
+      this.tooltipVisability.next(false);
+
+      this.isChartHovered = false;
+      this.updateWithLastCandle();
+      return;
+    }
+
+    if (this.paneId === param.paneIndex) {
+      this.tooltipVisability.next(true);
+    } else {
+      this.tooltipVisability.next(false);
+    }
+
+    this.isChartHovered = true;
+
+    const model: LegendModel = [];
+
+    if (this.mainSeries) {
+      const series = new Map();
+      const serieData = this.mainSeries.getLegendData(param);
+
+      Object.entries(serieData).forEach(([key, sd]) => {
+        series.set(`${key}`, {
+          ...sd,
+        });
+      });
+
+      model.push({
+        name: this.mainSeries.options().title,
+        values: series as Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>>,
+        isIndicator: false,
+        remove: () => {
+          // serieData.remove() // todo: запретить удалять главную серию на главном пейне
+        },
+      });
+    }
+
+    if (!this.indicators) {
+      return;
+    }
+
+    for (const [indicatorName, indicator] of this.indicators) {
+      const indicatorSeries = new Map();
+
+      for (const [serieName, serie] of indicator.getSeriesMap()) {
+        if (!serie.isVisible()) {
+          continue;
+        }
+
+        const serieData = serie.getLegendData(param);
+
+        const value = ensureDefined(serieData.value ?? serieData.close);
+
+        indicatorSeries.set(serieName, value);
+      }
+
+      model.push({
+        name: indicatorName,
+        values: indicatorSeries as Partial<
+          Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>
+        >,
+        isIndicator: true,
+        remove: () => indicator.delete(),
+      });
+    }
+
+    this.model$.next(model);
+    this.tooltipPos.next(param.point);
+  };
+
+  public getConfig(): OHLCConfig {
+    return this.config;
   }
 
-  if (isLineData(prev) && isLineData(current)) {
-    const absoluteChange = current.value - prev.value;
-    const percentageChange = ((current.value - prev.value) / prev.value) * 100;
-
-    return {
-      time: current.time,
-      value: current.value,
-      high: current.customValues?.high as number,
-      low: current.customValues?.low as number,
-      absoluteChange,
-      percentageChange,
-      customValues: current.customValues,
-    };
+  public getLegendViewModel(): Observable<LegendModel> {
+    return this.model$;
   }
 
-  return null;
+  public destroy = () => {
+    this.model$.complete();
+    this.tooltipVisability.complete();
+    this.tooltipPos.complete();
+  };
 }
diff --git a/src/core/MoexChart.tsx b/src/core/MoexChart.tsx
index 98d38d2391a724d34529e0ae37bf32b078937e32..efea78409cd9f167355002fe08310b4502431fdd 100644
--- a/src/core/MoexChart.tsx
+++ b/src/core/MoexChart.tsx
@@ -4,18 +4,12 @@ import { ControlBar } from '@components/ControlBar';
 import { Footer } from '@components/Footer';
 
 import { Header } from '@components/Header';
-import { LegendComponent } from '@components/Legend';
 import { DataSource, DataSourceParams } from '@core/DataSource';
-import { Legend } from '@core/Legend';
 import { ModalRenderer } from '@core/ModalRenderer';
-import { TooltipService } from '@core/Tooltip';
-
-import { ChartTooltip } from '@src/components/ChartTooltip';
 import { SettingsModal } from '@src/components/SettingsModal';
 
 import Toolbar from '@src/components/Toolbar';
 import { CompareManager } from '@src/core/CompareManager';
-import { DrawingsNames } from '@src/core/DrawingsManager';
 import { FullscreenController } from '@src/core/Fullscreen';
 
 import { IndicatorsIds } from '@src/core/Indicators';
@@ -30,7 +24,6 @@ import { Chart } from './Chart';
 import { ChartSettings, ChartSettingsSource } from './ChartSettings';
 import { ContainerManager } from './ContainerManager';
 import { EventManager } from './EventManager';
-import { HoverController } from './HoverController';
 import { ReactRenderer } from './ReactRenderer';
 import { TimeScaleHoverController } from './TimescaleHoverController';
 import { UIRenderer } from './UIRenderer';
@@ -94,23 +87,18 @@ export class MoexChart {
   private chart: Chart;
   private resizeObserver?: ResizeObserver;
   private eventManager: EventManager;
-  private legend: Legend;
   private rootContainer: HTMLElement;
 
   private headerRenderer: UIRenderer;
-  private legendRenderer: UIRenderer;
   private modalRenderer: ModalRenderer;
-  private tooltipRenderer: UIRenderer | undefined;
   private toolbarRenderer: UIRenderer | undefined;
   private controlBarRenderer?: UIRenderer;
   private footerRenderer?: UIRenderer;
 
-  private hoverController: HoverController;
   private timeScaleHoverController: TimeScaleHoverController;
   private dataSource: DataSource;
 
   private subscriptions = new Subscription();
-  private tooltip: TooltipService | undefined;
 
   private fullscreen: FullscreenController;
 
@@ -138,16 +126,6 @@ export class MoexChart {
       eventManager: this.eventManager,
     });
 
-    this.legend = new Legend({
-      config: config.ohlc,
-      dataSource: this.dataSource,
-      eventManager: this.eventManager,
-    });
-
-    if (config.tooltipConfig) {
-      this.tooltip = new TooltipService({ config: config.tooltipConfig, legend: this.legend });
-    }
-
     this.rootContainer = config.container;
 
     this.fullscreen = new FullscreenController(this.rootContainer);
@@ -158,9 +136,7 @@ export class MoexChart {
       chartAreaContainer,
       toolBarContainer,
       headerContainer,
-      legendContainer,
       modalContainer,
-      overlayContainer,
       controlBarContainer,
       footerContainer,
       toggleToolbar, // todo: move this function to toolbarRenderer
@@ -181,47 +157,20 @@ export class MoexChart {
       seriesTypes: config.supportedChartSeriesTypes,
       dataSource: this.dataSource,
       chartOptions: config.chartOptions, // todo: remove, use only model from eventManager
-    });
-
-    /*
-      Внутри lightweight-chart DOM построен как таблица из 3 td
-      [0] left priceScale, [1] center chart, [2] right priceScale
-      Кладём легенду в td[1] и тогда легенда сама будет адаптироваться при изменении ширины шкал
-    */
-    requestAnimationFrame(() => {
-      const root = chartAreaContainer.querySelector('.tv-lightweight-charts');
-      const table = root?.querySelector('table');
-      const centerId = table?.getElementsByTagName('td')?.[1];
-
-      if (centerId && legendContainer && legendContainer.parentElement !== centerId) {
-        centerId.appendChild(legendContainer);
-      }
+      ohlcConfig: config.ohlc, // todo: omptimize
+      tooltipConfig: config.tooltipConfig ?? {},
     });
 
     this.subscriptions.add(
-      combineLatest([store.theme$, store.mode$]).subscribe(([t, m]) => {
-        this.chart.updateTheme(t, m);
+      combineLatest([store.theme$, store.mode$]).subscribe(([theme, mode]) => {
+        this.chart.updateTheme(theme, mode);
 
-        document.documentElement.dataset.theme = t;
-        document.documentElement.dataset.mode = m;
+        document.documentElement.dataset.theme = theme;
+        document.documentElement.dataset.mode = mode;
       }),
     );
 
-    this.subscriptions.add(
-      this.chart
-        .getDrawingsManager()
-        .entities()
-        .subscribe((drawings) => {
-          const hasRuler = drawings.some((drawing) => drawing.id.startsWith(DrawingsNames.ruler));
-          legendContainer.style.display = hasRuler ? 'none' : '';
-        }),
-    );
-
     this.headerRenderer = new ReactRenderer(headerContainer);
-    this.legendRenderer = new ReactRenderer(legendContainer);
-    if (this.tooltip) {
-      this.tooltipRenderer = new ReactRenderer(overlayContainer);
-    }
     this.toolbarRenderer = new ReactRenderer(toolBarContainer);
 
     if (config.showControlBar) {
@@ -232,13 +181,6 @@ export class MoexChart {
       this.footerRenderer = new ReactRenderer(footerContainer);
     }
 
-    if (this.tooltip) {
-      this.tooltip.setViewport({
-        width: this.rootContainer.clientWidth,
-        height: this.rootContainer.clientHeight,
-      });
-    }
-
     this.headerRenderer.renderComponent(
       <Header
         timeframes={config.supportedTimeframes}
@@ -279,46 +221,18 @@ export class MoexChart {
       />,
     );
 
-    this.hoverController = new HoverController({
-      legend: this.legend,
-      tooltip: this.tooltip,
-      chartEventSub: this.chart.subscribeChartEvent,
-      chartEventUnsub: this.chart.unsubscribeChartEvent,
-      mainSeriesObs: this.chart.getMainSeries(),
-      compareManager: this.chart.getCompareManager(),
-    });
-
     this.timeScaleHoverController = new TimeScaleHoverController({
       eventManager: this.eventManager,
       controlBarContainer,
       chartContainer: chartAreaContainer,
     });
 
-    this.legendRenderer.renderComponent(
-      <LegendComponent
-        ohlcConfig={this.legend.getConfig()}
-        viewModel={this.legend.getLegendViewModel()}
-        onCompareRemove={(symbol, mode) => this.chart.getCompareManager().removeSymbolMode(symbol, mode)}
-      />,
-    );
-
-    if (this.tooltipRenderer && this.tooltip) {
-      this.tooltipRenderer.renderComponent(
-        <ChartTooltip
-          formatObs={this.eventManager.getChartOptionsModel()}
-          timeframeObs={this.eventManager.getTimeframeObs()}
-          viewModel={this.tooltip.getTooltipViewModel()}
-          ohlcConfig={this.legend.getConfig()}
-          tooltipConfig={this.tooltip.getConfig()}
-        />,
-      );
-    }
-
     if (config.showMenuButton) {
       this.toolbarRenderer.renderComponent(
         <Toolbar
           toggleDOM={this.chart.getDom().toggleDOM}
           addDrawing={(name) => {
+            // todo: deal with new panes logic
             this.chart.getDrawingsManager().addDrawing(name);
           }}
         />,
@@ -345,10 +259,6 @@ export class MoexChart {
         />,
       );
     }
-
-    if (!config.size) {
-      this.setupAutoResize(chartAreaContainer);
-    }
   }
 
   public setSettings(settings: ChartSettingsSource): void {
@@ -363,23 +273,6 @@ export class MoexChart {
     return this.chart.getRealtimeApi();
   }
 
-  /**
-   * Настройка автоматического изменения размера
-   */
-  private setupAutoResize(chartAreaContainer: HTMLDivElement): void {
-    if (typeof ResizeObserver !== 'undefined') {
-      this.resizeObserver = new ResizeObserver(() => {
-        const { width, height } = chartAreaContainer.getBoundingClientRect();
-
-        this.tooltip?.setViewport({
-          width: Math.floor(width),
-          height: Math.floor(height),
-        });
-      });
-      this.resizeObserver.observe(chartAreaContainer);
-    }
-  }
-
   // todo: описать в доке
   public getCompareManager(): CompareManager {
     return this.chart.getCompareManager();
@@ -396,11 +289,7 @@ export class MoexChart {
    * @returns void
    */
   destroy(): void {
-    this.tooltip?.destroy();
-    this.legend.destroy();
     this.headerRenderer.destroy();
-    this.legendRenderer.destroy();
-    this.hoverController.destroy();
     this.subscriptions.unsubscribe();
     this.timeScaleHoverController.destroy();
 
diff --git a/src/core/Pane.tsx b/src/core/Pane.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..ef094f89d7fb5bcc63ae85b8f80e060c17a4499a
--- /dev/null
+++ b/src/core/Pane.tsx
@@ -0,0 +1,274 @@
+import { IChartApi, IPaneApi, Time } from 'lightweight-charts';
+
+import { BehaviorSubject, Subscription } from 'rxjs';
+
+import { ChartTooltip } from '@components/ChartTooltip';
+import { LegendComponent } from '@components/Legend';
+import { ChartMouseEvents } from '@core/ChartMouseEvents';
+import { ContainerManager } from '@core/ContainerManager';
+import { DataSource } from '@core/DataSource';
+import { DOMModel } from '@core/DOMModel';
+import { DrawingsManager, DrawingsNames } from '@core/DrawingsManager';
+import { EventManager } from '@core/EventManager';
+import { Indicator } from '@core/Indicator';
+import { IndicatorsIds } from '@core/Indicators';
+import { Legend } from '@core/Legend';
+import { ReactRenderer } from '@core/ReactRenderer';
+import { TooltipService } from '@core/Tooltip';
+import { UIRenderer } from '@core/UIRenderer';
+import { SeriesFactory, SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
+import { OHLCConfig, TooltipConfig } from '@src/types';
+import { ensureDefined } from '@src/utils';
+
+export interface PaneParams {
+  id: number;
+  lwcChart: IChartApi;
+  eventManager: EventManager;
+  DOM: DOMModel;
+  isMainPane: boolean;
+  ohlcConfig: OHLCConfig;
+  dataSource: DataSource | null; // todo: deal with dataSource. На каких то пейнах он нужен, на каких то нет
+  basedOn?: Pane; // Pane на котором находится главная серия, или серия, по которой строятся серии на текущем пейне
+  subscribeChartEvent: ChartMouseEvents['subscribe'];
+  tooltipConfig: TooltipConfig;
+  onDelete: () => void;
+  chartContainer: HTMLElement;
+}
+
+// todo: Pane, ему должна принадлежать mainSerie, а также IndicatorManager и drawingsManager, mouseEvents. Также перекинуть соответствующие/необходимые свойства из чарта, и из чарта удалить
+// todo: Учитывать, что есть линейка, которая рисуется одна для всех пейнов
+// todo: в CompareManage, при создании нового пейна для сравнения - инициализируем новый dataSource, принадлежащий только конкретному пейну. Убираем возможность добавлять индикаторы на такие пейны
+// todo: на каждый символ свой DataSource (учитывать что есть MainPane и "главный" DataSource, который инициализиурется во время старта moexChart)
+// todo: сделать два разных представления для compare, в зависимости от отображения на главном пейне или на второстепенном
+
+export class Pane {
+  private id: number;
+  private isMain: boolean;
+  private mainSeries: BehaviorSubject<SeriesStrategies | null> = new BehaviorSubject<SeriesStrategies | null>(null); // Main Series. Exists in a single copy
+  private legend!: Legend;
+  private tooltip: TooltipService | undefined;
+
+  private indicatorsMap: BehaviorSubject<Map<IndicatorsIds, Indicator>> = new BehaviorSubject<
+    Map<IndicatorsIds, Indicator>
+  >(new Map());
+
+  private lwcPane: IPaneApi<Time>;
+  private lwcChart: IChartApi;
+
+  private eventManager: EventManager;
+  private drawingsManager: DrawingsManager;
+
+  private legendContainer!: HTMLElement;
+  private paneOverlayContainer!: HTMLElement;
+  private legendRenderer!: UIRenderer;
+  private tooltipRenderer: UIRenderer | undefined;
+
+  private mainSerieSub!: Subscription;
+  private subscribeChartEvent: ChartMouseEvents['subscribe'];
+  private onDelete: () => void;
+  private subscriptions = new Subscription();
+
+  constructor({
+    lwcChart,
+    eventManager,
+    dataSource,
+    DOM,
+    isMainPane,
+    ohlcConfig,
+    id,
+    basedOn,
+    subscribeChartEvent,
+    tooltipConfig,
+    onDelete,
+    chartContainer,
+  }: PaneParams) {
+    this.onDelete = onDelete;
+    this.eventManager = eventManager;
+    this.lwcChart = lwcChart;
+    this.subscribeChartEvent = subscribeChartEvent;
+    this.isMain = isMainPane ?? false;
+    this.id = id;
+
+    this.initializeLegend({ ohlcConfig });
+
+    if (isMainPane) {
+      this.lwcPane = this.lwcChart.panes()[this.id];
+    } else {
+      this.lwcPane = this.lwcChart.addPane(true);
+    }
+
+    this.tooltip = new TooltipService({
+      config: tooltipConfig,
+      legend: this.legend,
+      paneOverlayContainer: this.paneOverlayContainer,
+    });
+
+    this.tooltipRenderer = new ReactRenderer(this.paneOverlayContainer);
+
+    this.tooltipRenderer.renderComponent(
+      <ChartTooltip
+        formatObs={this.eventManager.getChartOptionsModel()}
+        timeframeObs={this.eventManager.getTimeframeObs()}
+        viewModel={this.tooltip.getTooltipViewModel()}
+        // ohlcConfig={this.legend.getConfig()}
+        ohlcConfig={ohlcConfig}
+        tooltipConfig={this.tooltip.getConfig()}
+      />,
+    );
+
+    if (dataSource) {
+      this.initializeMainSerie({ lwcChart, dataSource });
+    } else if (basedOn) {
+      this.mainSeries = basedOn?.getMainSerie();
+    } else {
+      console.error('[Pane]: There is no any mainSerie for new pane');
+    }
+
+    this.drawingsManager = new DrawingsManager({
+      // todo: менеджер дровингов должен быть один на чарт, не на пейн
+      eventManager,
+      DOM,
+      mainSeries$: this.mainSeries.asObservable(),
+      lwcChart,
+      container: chartContainer,
+    });
+
+    this.subscriptions.add(
+      // todo: переедет в пейн
+      this.drawingsManager.entities().subscribe((drawings) => {
+        const hasRuler = drawings.some((drawing) => drawing.id.startsWith(DrawingsNames.ruler));
+        this.legendContainer.style.display = hasRuler ? 'none' : '';
+      }),
+    );
+  }
+
+  public getMainSerie = () => {
+    return this.mainSeries;
+  };
+
+  public getId = () => {
+    return this.id;
+  };
+
+  public setIndicator(indicatorName: IndicatorsIds, indicator: Indicator): void {
+    const map = this.indicatorsMap.value;
+
+    map.set(indicatorName, indicator);
+
+    this.indicatorsMap.next(map);
+  }
+
+  public removeIndicator(indicatorName: IndicatorsIds): void {
+    const map = this.indicatorsMap.value;
+
+    map.delete(indicatorName);
+
+    this.indicatorsMap.next(map);
+
+    if (map.size === 0 && !this.isMain) {
+      this.destroy();
+    }
+  }
+
+  public getDrawingManager(): DrawingsManager {
+    return this.drawingsManager;
+  }
+
+  private initializeLegend({ ohlcConfig }: { ohlcConfig: OHLCConfig }) {
+    const { legendContainer, paneOverlayContainer } = ContainerManager.createPaneContainers();
+    this.legendContainer = legendContainer;
+    this.paneOverlayContainer = paneOverlayContainer;
+    this.legendRenderer = new ReactRenderer(legendContainer);
+
+    requestAnimationFrame(() => {
+      setTimeout(() => {
+        const lwcPaneElement = this.lwcPane.getHTMLElement();
+        if (!lwcPaneElement) return;
+        lwcPaneElement.style.position = 'relative';
+        lwcPaneElement.appendChild(legendContainer);
+        lwcPaneElement.appendChild(paneOverlayContainer);
+      }, 0);
+    });
+
+    // todo: переписать код ниже под логику пейнов
+    // /*
+    //   Внутри lightweight-chart DOM построен как таблица из 3 td
+    //   [0] left priceScale, [1] center chart, [2] right priceScale
+    //   Кладём легенду в td[1] и тогда легенда сама будет адаптироваться при изменении ширины шкал
+    // */
+    // requestAnimationFrame(() => {
+    //   const root = chartAreaContainer.querySelector('.tv-lightweight-charts');
+    //   console.log(root)
+    //   const table = root?.querySelector('table');
+    //   console.log(table)
+    //
+    //   const htmlCollectionOfPanes = table?.getElementsByTagName('td')
+    //   console.log(htmlCollectionOfPanes)
+    //
+    //   const centerId = htmlCollectionOfPanes?.[1];
+    //   console.log(centerId)
+    //
+    //   if (centerId && legendContainer && legendContainer.parentElement !== centerId) {
+    //     centerId.appendChild(legendContainer);
+    //   }
+    // });
+    // /*
+    //   Внутри lightweight-chart DOM построен как таблица из 3 td
+    //   [0] left priceScale, [1] center chart, [2] right priceScale
+    //   Кладём легенду в td[1] и тогда легенда сама будет адаптироваться при изменении ширины шкал
+    // */
+    // requestAnimationFrame(() => {
+    //   const root = chartAreaContainer.querySelector('.tv-lightweight-charts');
+    //   const table = root?.querySelector('table');
+    //   const centerId = table?.getElementsByTagName('td')?.[1];
+    //
+    //   if (centerId && legendContainer && legendContainer.parentElement !== centerId) {
+    //     centerId.appendChild(legendContainer);
+    //   }
+    // });
+
+    this.legend = new Legend({
+      config: ohlcConfig,
+      indicators: this.indicatorsMap,
+      eventManager: this.eventManager,
+      subscribeChartEvent: this.subscribeChartEvent,
+      mainSeries: this.isMain ? this.mainSeries : null,
+      paneId: this.id,
+      // todo: throw isMainPane
+    });
+
+    this.legendRenderer.renderComponent(
+      <LegendComponent
+        ohlcConfig={this.legend.getConfig()}
+        viewModel={this.legend.getLegendViewModel()}
+      />,
+    );
+  }
+
+  private initializeMainSerie({ lwcChart, dataSource }: { lwcChart: IChartApi; dataSource: DataSource }) {
+    this.mainSerieSub = this.eventManager.subscribeSeriesSelected((nextSeries) => {
+      this.mainSeries.value?.destroy();
+
+      const next = ensureDefined(SeriesFactory.create(nextSeries))({
+        lwcChart,
+        dataSource,
+        mainSymbol$: this.eventManager.getSymbol(),
+        mainSerie$: this.mainSeries,
+      });
+
+      this.mainSeries.next(next);
+    });
+  }
+
+  public destroy() {
+    this.subscriptions.unsubscribe();
+    this.tooltip?.destroy();
+    this.legend.destroy();
+    this.legendRenderer.destroy();
+
+    this.mainSerieSub?.unsubscribe();
+    this.lwcChart.removePane(this.id);
+
+    this.onDelete();
+  }
+}
diff --git a/src/core/PaneManager.ts b/src/core/PaneManager.ts
new file mode 100644
index 0000000000000000000000000000000000000000..1721a6bdddeed149c420d5bf623d4b0849762d2a
--- /dev/null
+++ b/src/core/PaneManager.ts
@@ -0,0 +1,56 @@
+import { DataSource } from '@core/DataSource';
+import { DrawingsManager } from '@core/DrawingsManager';
+import { Pane, PaneParams } from '@core/Pane';
+
+type PaneManagerParams = Omit<PaneParams, 'isMainPane' | 'id' | 'basedOn' | 'onDelete'>;
+
+// todo: PaneManager, регулирует порядок пейнов. Знает про MainPane.
+// todo: Также перекинуть соответствующие/необходимые свойства из чарта, и из чарта удалить
+// todo: в CompareManage, при создании нового пейна для сравнения - инициализируем новый dataSource, принадлежащий только конкретному пейну. Убираем возможность добавлять индикаторы на такие пейны
+// todo: на каждый символ свой DataSource (учитывать что есть MainPane и "главный" DataSource, который инициализиурется во время старта moexChart)
+// todo: сделать два разных представления для compare, в зависимости от отображения на главном пейне или на второстепенном
+
+export class PaneManager {
+  private mainPane: Pane;
+  private paneChartInheritedParams: PaneManagerParams & { isMainPane: boolean };
+  private panesMap: Map<number, Pane> = new Map<number, Pane>();
+
+  constructor(params: PaneManagerParams) {
+    this.paneChartInheritedParams = { ...params, isMainPane: false };
+
+    this.mainPane = new Pane({ ...params, isMainPane: true, id: 0, onDelete: () => {} });
+
+    this.panesMap.set(0, this.mainPane);
+  }
+
+  public getPanes() {
+    return this.panesMap;
+  }
+
+  public getMainPane: () => Pane = () => {
+    return this.mainPane;
+  };
+
+  public addPane(dataSource?: DataSource): Pane {
+    const panesOverallCount = this.panesMap.size;
+
+    const pane = new Pane({
+      ...this.paneChartInheritedParams,
+      id: panesOverallCount,
+      dataSource: dataSource ?? null,
+      basedOn: dataSource ? undefined : this.mainPane,
+      onDelete: () => {
+        this.panesMap.delete(panesOverallCount);
+      },
+    });
+
+    this.panesMap.set(panesOverallCount, pane);
+
+    return pane;
+  }
+
+  public getDrawingsManager(): DrawingsManager {
+    // todo: temp
+    return this.mainPane.getDrawingManager();
+  }
+}
diff --git a/src/core/Series/BarSeriesStrategy.ts b/src/core/Series/BarSeriesStrategy.ts
index 1bba182c8158f7a746624594a78fbc3746f24685..a86f493fb44ec4e519912744e23dd8f506038f75 100644
--- a/src/core/Series/BarSeriesStrategy.ts
+++ b/src/core/Series/BarSeriesStrategy.ts
@@ -1,9 +1,22 @@
-import { BarSeries, SeriesDataItemTypeMap, SeriesDefinition, SeriesPartialOptionsMap, Time } from 'lightweight-charts';
+import {
+  BarData,
+  BarSeries,
+  CustomData,
+  HistogramData,
+  LineData,
+  SeriesDataItemTypeMap,
+  SeriesDefinition,
+  SeriesPartialOptionsMap,
+  Time,
+} from 'lightweight-charts';
 
-import { BaseSeries, BaseSeriesParams } from '@src/core/Series/BaseSeries';
+import { Ohlc } from '@core/Legend';
+
+import { BaseSeries, BaseSeriesParams, calcCandleChange } from '@src/core/Series/BaseSeries';
 import { ISeries } from '@src/modules/series-strategies';
 import { getThemeStore } from '@src/theme';
 import { Candle, LineCandle } from '@src/types';
+import { ensureDefined, formatPrice, isBarData } from '@src/utils';
 
 export class BarSeriesStrategy extends BaseSeries<'Bar'> implements ISeries<'Bar'> {
   constructor(params: BaseSeriesParams<'Bar'>) {
@@ -72,4 +85,55 @@ export class BarSeriesStrategy extends BaseSeries<'Bar'> implements ISeries<'Bar
       customValues: point as unknown as Record<string, unknown>,
     }));
   }
+
+  protected formatLegendValues(
+    currentBar: null | BarData | LineData | HistogramData | CustomData,
+    prevBar: null | BarData | LineData | HistogramData | CustomData,
+  ): Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>> {
+    if (!currentBar || !isBarData(currentBar)) {
+      return {};
+    }
+
+    const color = currentBar.close < currentBar.open ? 'red' : 'green';
+
+    const { absoluteChange, percentageChange, time } = ensureDefined(calcCandleChange(prevBar, currentBar));
+
+    return {
+      open: {
+        value: formatPrice(currentBar.open) ?? '',
+        name: 'Откр.',
+        color,
+      },
+      high: {
+        value: formatPrice(currentBar.high) ?? '',
+        name: 'Макс.',
+        color,
+      },
+      low: {
+        value: formatPrice(currentBar.low) ?? '',
+        name: 'Мин.',
+        color,
+      },
+      close: {
+        value: formatPrice(currentBar.close) ?? '',
+        name: 'Закр.',
+        color,
+      },
+      absoluteChange: {
+        value: `${formatPrice(absoluteChange)}%`,
+        name: 'Изм.',
+        color,
+      },
+      percentageChange: {
+        value: `${formatPrice(percentageChange)}%`,
+        name: 'Изм.',
+        color,
+      },
+      time: {
+        value: time,
+        name: 'Время',
+        color,
+      },
+    };
+  }
 }
diff --git a/src/core/Series/BaseSeries.ts b/src/core/Series/BaseSeries.ts
index 13dd5331aba35ad48c398ef042f8e2f6971204de..5d7b10ae7ffb6eb57cabd539a110ebd4d54cc6af 100644
--- a/src/core/Series/BaseSeries.ts
+++ b/src/core/Series/BaseSeries.ts
@@ -1,10 +1,13 @@
 import {
+  BarData,
   BarPrice,
   BarsInfo,
   Coordinate,
   CreatePriceLineOptions,
+  CustomData,
   DataChangedHandler,
   DeepPartial,
+  HistogramData,
   IChartApi,
   IPaneApi,
   IPriceFormatter,
@@ -13,7 +16,9 @@ import {
   IRange,
   ISeriesApi,
   ISeriesPrimitive,
+  LineData,
   MismatchDirection,
+  MouseEventParams,
   PriceScaleOptions,
   SeriesDataItemTypeMap,
   SeriesDefinition,
@@ -28,11 +33,12 @@ import { BehaviorSubject, distinctUntilChanged, Observable, Subscription } from
 import { DataSource } from '@core/DataSource';
 import { Indicator } from '@core/Indicator';
 import { ChartTypeToCandleData, IndicatorDataFormatter } from '@core/Indicators';
+import { Ohlc } from '@core/Legend';
 import { MAIN_PANE_INDEX } from '@src/constants';
 
 import { SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
-import { Candle, ChartTypeOptions, Direction } from '@src/types';
-import { formatPrice, getPricePrecisionStep, normalizeSeriesData } from '@src/utils';
+import { Candle, Direction } from '@src/types';
+import { formatPrice, getPricePrecisionStep, isBarData, isLineData, normalizeSeriesData } from '@src/utils';
 
 export interface SerieData {
   time: Time;
@@ -48,6 +54,9 @@ export interface CreateSeriesParams<TSeries extends SeriesType> {
 
 export interface IBaseSeries<TSeries extends SeriesType> extends ISeriesApi<TSeries> {
   getLwcSeries: () => ISeriesApi<TSeries>;
+  getLegendData: (
+    param?: MouseEventParams,
+  ) => Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>>;
 }
 
 export interface BaseSeriesParams<TSeries extends SeriesType = SeriesType> {
@@ -56,7 +65,6 @@ export interface BaseSeriesParams<TSeries extends SeriesType = SeriesType> {
   mainSymbol$: Observable<string>;
   mainSerie$: BehaviorSubject<SeriesStrategies | null>;
   customFormatter?: (params: IndicatorDataFormatter<TSeries>) => SeriesDataItemTypeMap<Time>[TSeries][];
-  chartOptions?: ChartTypeOptions;
   seriesOptions?: SeriesPartialOptionsMap[TSeries];
   priceScaleOptions?: DeepPartial<PriceScaleOptions>;
   showSymbolLabel?: boolean;
@@ -100,7 +108,6 @@ export abstract class BaseSeries<TSeries extends SeriesType> implements IBaseSer
     mainSerie$,
     customFormatter,
     seriesOptions,
-    chartOptions,
     priceScaleOptions,
     showSymbolLabel = true,
     paneIndex,
@@ -108,7 +115,7 @@ export abstract class BaseSeries<TSeries extends SeriesType> implements IBaseSer
   }: BaseSeriesParams<TSeries>) {
     this.lwcSeries = this.createSeries({
       chart: lwcChart,
-      seriesOptions: { ...chartOptions, ...seriesOptions } as SeriesPartialOptionsMap[TSeries],
+      seriesOptions,
       paneIndex,
       priceScaleOptions,
     });
@@ -120,6 +127,24 @@ export abstract class BaseSeries<TSeries extends SeriesType> implements IBaseSer
     this.indicatorReference = indicatorReference ?? null;
   }
 
+  public getLegendData = (
+    param?: MouseEventParams,
+  ): Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>> => {
+    if (!param) {
+      const seriesData = this.data();
+      if (seriesData.length < 1) return {};
+
+      const dataToFormat = seriesData[seriesData.length - 1];
+      const prevBarData = seriesData.length > 1 ? seriesData[seriesData.length - 2] : null;
+      return this.formatLegendValues(dataToFormat, prevBarData);
+    }
+
+    const dataToFormat = param?.seriesData.get(this.getLwcSeries()) ?? null;
+    const prevBarData = this.dataByIndex(param.logical! - 1) ?? null;
+
+    return this.formatLegendValues(dataToFormat, prevBarData);
+  };
+
   public show(): void {
     this.lwcSeries.applyOptions({ ...this.lwcSeries.options(), visible: true });
   }
@@ -128,6 +153,10 @@ export abstract class BaseSeries<TSeries extends SeriesType> implements IBaseSer
     this.lwcSeries.applyOptions({ ...this.lwcSeries.options(), visible: false });
   }
 
+  public isVisible(): boolean {
+    return this.lwcSeries.options().visible;
+  }
+
   public destroy(): void {
     this.dataSub?.unsubscribe();
     this.realtimeSub?.unsubscribe();
@@ -275,6 +304,10 @@ export abstract class BaseSeries<TSeries extends SeriesType> implements IBaseSer
   protected abstract dataSourceRealtimeSubscription(next: Candle): void;
   protected abstract getDefaultOptions(): SeriesPartialOptionsMap[TSeries];
   protected abstract formatMainSerie(inputData: Candle[]): SeriesDataItemTypeMap<Time>[TSeries][];
+  protected abstract formatLegendValues(
+    currentBar: null | BarData | LineData | HistogramData | CustomData,
+    prevBar: null | BarData | LineData | HistogramData | CustomData,
+  ): Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>>;
 
   protected applyTimezone(data: Candle[]): Candle[] {
     return applyMoscowTimezone(data);
@@ -336,3 +369,44 @@ export abstract class BaseSeries<TSeries extends SeriesType> implements IBaseSer
     );
   };
 }
+
+export function calcCandleChange(
+  prev: BarData | LineData | HistogramData | CustomData | null,
+  current: BarData | LineData | HistogramData | CustomData | null,
+): (Ohlc & { customValues?: Record<string, any> }) | null {
+  if (!current) {
+    return null;
+  }
+
+  if (!prev) {
+    return current;
+  }
+
+  if (isBarData(prev) && isBarData(current)) {
+    const absoluteChange = current.close - prev.close;
+    const percentageChange = ((current.close - prev.close) / prev.close) * 100;
+
+    return {
+      ...current,
+      absoluteChange,
+      percentageChange,
+    };
+  }
+
+  if (isLineData(prev) && isLineData(current)) {
+    const absoluteChange = current.value - prev.value;
+    const percentageChange = ((current.value - prev.value) / prev.value) * 100;
+
+    return {
+      time: current.time,
+      value: current.value,
+      high: current.customValues?.high as number,
+      low: current.customValues?.low as number,
+      absoluteChange,
+      percentageChange,
+      customValues: current.customValues,
+    };
+  }
+
+  return null;
+}
diff --git a/src/core/Series/CandlestickSeriesStrategy.ts b/src/core/Series/CandlestickSeriesStrategy.ts
index eb3e36e1dfb5c0d6281498c4cd1de59e4320c28f..6e102ce7761c94c10e63af76fb8546185b2544d6 100644
--- a/src/core/Series/CandlestickSeriesStrategy.ts
+++ b/src/core/Series/CandlestickSeriesStrategy.ts
@@ -1,17 +1,24 @@
 import {
+  BarData,
   CandlestickSeries,
+  CustomData,
+  HistogramData,
+  LineData,
   SeriesDataItemTypeMap,
   SeriesDefinition,
   SeriesPartialOptionsMap,
   Time,
 } from 'lightweight-charts';
 
-import { BaseSeries, BaseSeriesParams } from '@core/Series/BaseSeries';
+import { Ohlc } from '@core/Legend';
+
+import { BaseSeries, BaseSeriesParams, calcCandleChange } from '@core/Series/BaseSeries';
 
 import { ISeries } from '@src/modules/series-strategies';
 
 import { getThemeStore } from '@src/theme/store';
 import { Candle, LineCandle } from '@src/types';
+import { ensureDefined, formatPrice, isBarData } from '@src/utils';
 
 export class CandlestickSeriesStrategy extends BaseSeries<'Candlestick'> implements ISeries<'Candlestick'> {
   constructor(params: BaseSeriesParams<'Candlestick'>) {
@@ -92,4 +99,55 @@ export class CandlestickSeriesStrategy extends BaseSeries<'Candlestick'> impleme
       customValues: point as unknown as Record<string, unknown>,
     }));
   }
+
+  protected formatLegendValues(
+    currentBar: null | BarData | LineData | HistogramData | CustomData,
+    prevBar: null | BarData | LineData | HistogramData | CustomData,
+  ): Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>> {
+    if (!currentBar || !isBarData(currentBar)) {
+      return {};
+    }
+
+    const color = currentBar.close < currentBar.open ? 'red' : 'green';
+
+    const { absoluteChange, percentageChange, time } = ensureDefined(calcCandleChange(prevBar, currentBar));
+
+    return {
+      open: {
+        value: formatPrice(currentBar.open) ?? '',
+        name: 'Откр.',
+        color,
+      },
+      high: {
+        value: formatPrice(currentBar.high) ?? '',
+        name: 'Макс.',
+        color,
+      },
+      low: {
+        value: formatPrice(currentBar.low) ?? '',
+        name: 'Мин.',
+        color,
+      },
+      close: {
+        value: formatPrice(currentBar.close) ?? '',
+        name: 'Закр.',
+        color,
+      },
+      absoluteChange: {
+        value: `${formatPrice(absoluteChange)}%`,
+        name: 'Изм.',
+        color,
+      },
+      percentageChange: {
+        value: `${formatPrice(percentageChange)}%`,
+        name: 'Изм.',
+        color,
+      },
+      time: {
+        value: time,
+        name: 'Время',
+        color,
+      },
+    };
+  }
 }
diff --git a/src/core/Series/HistogramSeriesStrategy.ts b/src/core/Series/HistogramSeriesStrategy.ts
index 601407b900a37dc6fd3cb2958394fd9af23a5e05..cec33581edce7c6312923dd0988909b2e6d465d3 100644
--- a/src/core/Series/HistogramSeriesStrategy.ts
+++ b/src/core/Series/HistogramSeriesStrategy.ts
@@ -1,15 +1,22 @@
 import {
+  BarData,
+  CustomData,
+  HistogramData,
   HistogramSeries,
+  LineData,
   SeriesDataItemTypeMap,
   SeriesDefinition,
   SeriesPartialOptionsMap,
   Time,
 } from 'lightweight-charts';
 
-import { BaseSeries, BaseSeriesParams } from '@core/Series/BaseSeries';
+import { Ohlc } from '@core/Legend';
+
+import { BaseSeries, BaseSeriesParams, calcCandleChange } from '@core/Series/BaseSeries';
 
 import { ISeries } from '@src/modules/series-strategies';
 import { Candle, LineCandle } from '@src/types';
+import { ensureDefined, formatPrice, isHistogramData } from '@src/utils';
 
 export class HistogramSeriesStrategy extends BaseSeries<'Histogram'> implements ISeries<'Histogram'> {
   constructor(params: BaseSeriesParams<'Histogram'>) {
@@ -65,4 +72,38 @@ export class HistogramSeriesStrategy extends BaseSeries<'Histogram'> implements
       customValues: point as unknown as Record<string, unknown>,
     }));
   }
+
+  protected formatLegendValues(
+    currentBar: null | BarData | LineData | HistogramData | CustomData,
+    prevBar: null | BarData | LineData | HistogramData | CustomData,
+  ): Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>> {
+    if (!currentBar || !isHistogramData(currentBar)) {
+      return {};
+    }
+
+    const { absoluteChange, percentageChange, time } = ensureDefined(calcCandleChange(prevBar, currentBar));
+
+    return {
+      value: {
+        value: formatPrice(currentBar.value) ?? '',
+        name: '',
+        color: currentBar.color?.slice(0, -2) ?? this.options().color,
+      },
+      absoluteChange: {
+        value: `${formatPrice(absoluteChange)}%`,
+        name: 'Изм.',
+        color: currentBar.color?.slice(0, -2) ?? this.options().color,
+      },
+      percentageChange: {
+        value: `${formatPrice(percentageChange)}%`,
+        name: 'Изм.',
+        color: currentBar.color?.slice(0, -2) ?? this.options().color,
+      },
+      time: {
+        value: time,
+        name: 'Время',
+        color: currentBar.color?.slice(0, -2) ?? this.options().color,
+      },
+    };
+  }
 }
diff --git a/src/core/Series/LineSeriesStrategy.ts b/src/core/Series/LineSeriesStrategy.ts
index 7596d25e21e5cfb74573426b887af5feefbf4c1b..c512e4c60a8e6c01da5aef1f235a395fb1c1fdb7 100644
--- a/src/core/Series/LineSeriesStrategy.ts
+++ b/src/core/Series/LineSeriesStrategy.ts
@@ -1,4 +1,8 @@
 import {
+  BarData,
+  CustomData,
+  HistogramData,
+  LineData,
   LineSeries,
   LineStyle,
   SeriesDataItemTypeMap,
@@ -7,12 +11,15 @@ import {
   Time,
 } from 'lightweight-charts';
 
-import { BaseSeries, BaseSeriesParams } from '@core/Series/BaseSeries';
+import { Ohlc } from '@core/Legend';
+
+import { BaseSeries, BaseSeriesParams, calcCandleChange } from '@core/Series/BaseSeries';
 
 import { ISeries } from '@src/modules/series-strategies';
 
 import { getThemeStore } from '@src/theme/store';
 import { Candle, LineCandle } from '@src/types';
+import { ensureDefined, formatPrice, isLineData } from '@src/utils';
 
 export class LineSeriesStrategy extends BaseSeries<'Line'> implements ISeries<'Line'> {
   constructor(params: BaseSeriesParams<'Line'>) {
@@ -74,4 +81,38 @@ export class LineSeriesStrategy extends BaseSeries<'Line'> implements ISeries<'L
       customValues: point as unknown as Record<string, unknown>,
     }));
   }
+
+  protected formatLegendValues(
+    currentBar: null | BarData | LineData | HistogramData | CustomData,
+    prevBar: null | BarData | LineData | HistogramData | CustomData,
+  ): Partial<Record<keyof Ohlc, { value: number | string | Time; color: string; name: string }>> {
+    if (!currentBar || !isLineData(currentBar)) {
+      return {};
+    }
+
+    const { absoluteChange, percentageChange, time } = ensureDefined(calcCandleChange(prevBar, currentBar));
+
+    return {
+      value: {
+        value: formatPrice(currentBar.value) ?? '',
+        name: '',
+        color: currentBar.color?.slice(0, -2) ?? this.options().color,
+      },
+      absoluteChange: {
+        value: `${formatPrice(absoluteChange)}%`,
+        name: 'Изм.',
+        color: currentBar.color?.slice(0, -2) ?? this.options().color,
+      },
+      percentageChange: {
+        value: `${formatPrice(percentageChange)}%`,
+        name: 'Изм.',
+        color: currentBar.color?.slice(0, -2) ?? this.options().color,
+      },
+      time: {
+        value: time,
+        name: 'Время',
+        color: currentBar.color?.slice(0, -2) ?? this.options().color,
+      },
+    };
+  }
 }
diff --git a/src/core/SeriesObject.ts b/src/core/SeriesObject.ts
deleted file mode 100644
index 99f9aef479585e7c378e4083cd7b0b60379436c4..0000000000000000000000000000000000000000
--- a/src/core/SeriesObject.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { IChartApi, SeriesPartialOptionsMap, SeriesType } from 'lightweight-charts';
-import { BehaviorSubject, Observable } from 'rxjs';
-
-import { DataSource } from '@core/DataSource';
-import { DOMObject, DOMObjectParams } from '@core/DOMObject';
-
-import { SeriesFactory, SeriesStrategies } from '@src/modules/series-strategies/SeriesFactory';
-
-interface SeriesObjectParams extends DOMObjectParams {
-  lwcChart: IChartApi;
-  dataSource: DataSource;
-  symbol$: Observable<string>;
-  mainSerie$: BehaviorSubject<SeriesStrategies | null>;
-  seriesType: SeriesType;
-  seriesOptions?: SeriesPartialOptionsMap[SeriesType];
-  customFormatter?: any;
-  showSymbolLabel?: boolean;
-  paneIndex?: number;
-}
-
-export class SeriesObject extends DOMObject {
-  protected strategy: SeriesStrategies;
-
-  constructor({
-    id,
-    zIndex,
-    onDelete,
-    moveUp,
-    moveDown,
-    lwcChart,
-    dataSource,
-    symbol$,
-    mainSerie$,
-    seriesType,
-    seriesOptions,
-    customFormatter,
-    showSymbolLabel,
-    paneIndex,
-  }: SeriesObjectParams) {
-    super({ id, zIndex, onDelete, moveUp, moveDown });
-
-    this.strategy = SeriesFactory.create(seriesType)({
-      lwcChart,
-      dataSource,
-      mainSymbol$: symbol$,
-      mainSerie$,
-      customFormatter,
-      seriesOptions,
-      showSymbolLabel,
-      paneIndex,
-    });
-  }
-
-  public getStrategy(): SeriesStrategies {
-    return this.strategy;
-  }
-
-  public show(): void {
-    this.strategy.show();
-    super.show();
-  }
-
-  public hide(): void {
-    this.strategy.hide();
-    super.hide();
-  }
-
-  public destroy(): void {
-    this.strategy.destroy();
-  }
-}
diff --git a/src/core/Tooltip.ts b/src/core/Tooltip.ts
index 3278667b1eccf31162ca11b889e52ae7596e5473..abe917b95cc6d243b78f274f9d6708f707bd76d2 100644
--- a/src/core/Tooltip.ts
+++ b/src/core/Tooltip.ts
@@ -10,6 +10,7 @@ import { Point, Size } from '@src/utils';
 interface TooltipServiceParams {
   config: TooltipConfig | undefined;
   legend: Legend;
+  paneOverlayContainer: HTMLElement;
 }
 
 export interface TooltipVM extends LegendVM {
@@ -34,9 +35,25 @@ export class TooltipService {
 
   private config: TooltipConfig;
 
-  constructor({ config, legend }: TooltipServiceParams) {
+  private resizeObserver?: ResizeObserver;
+
+  constructor({ config, legend, paneOverlayContainer }: TooltipServiceParams) {
     this.legend = legend;
+
+    this.setViewport({
+      width: paneOverlayContainer.clientWidth,
+      height: paneOverlayContainer.clientHeight,
+    });
+
+    this.legend.subscribeCursorPosition((point) => {
+      this.setPosition(point ?? { x: 0, y: 0 });
+    });
+    this.legend.subscribeCursorVisability((isVisible) => {
+      this.setVisible(isVisible);
+    });
     this.config = merge(DEFAULT_TOOLTIPS_CONFIG, config);
+
+    this.setupAutoResize(paneOverlayContainer);
   }
 
   public getConfig(): TooltipConfig {
@@ -50,12 +67,14 @@ export class TooltipService {
       this.getViewport(),
       this.legend.getLegendViewModel(),
     ]).pipe(
-      map(([hoverVisible, position, viewport, legendVM]) => ({
-        ...legendVM,
-        visible: Boolean(this.config.showTooltip) && hoverVisible,
-        position,
-        viewport,
-      })),
+      map(([hoverVisible, position, viewport, legendVM]) => {
+        return {
+          vm: legendVM,
+          visible: Boolean(this.config.showTooltip) && hoverVisible,
+          position,
+          viewport,
+        };
+      }),
     );
   }
 
@@ -63,11 +82,25 @@ export class TooltipService {
     this.visible$.next(value);
   }
 
-  public setPosition(pos: { x: number; y: number }): void {
+  private setPosition(pos: { x: number; y: number }): void {
     this.position$.next(pos);
   }
 
-  public setViewport(viewport: { width: number; height: number }): void {
+  private setupAutoResize(paneContainer: HTMLElement): void {
+    if (typeof ResizeObserver !== 'undefined') {
+      this.resizeObserver = new ResizeObserver(() => {
+        const { width, height } = paneContainer.getBoundingClientRect();
+
+        this.setViewport({
+          width: Math.floor(width),
+          height: Math.floor(height),
+        });
+      });
+      this.resizeObserver.observe(paneContainer);
+    }
+  }
+
+  private setViewport(viewport: { width: number; height: number }): void {
     this.viewport$.next(viewport);
   }
 
@@ -87,5 +120,10 @@ export class TooltipService {
     this.visible$.complete();
     this.position$.complete();
     this.viewport$.complete();
+
+    if (this.resizeObserver) {
+      this.resizeObserver.disconnect();
+      this.resizeObserver = undefined;
+    }
   }
 }
diff --git a/src/modules/series-strategies/ISeries.ts b/src/modules/series-strategies/ISeries.ts
index 564b4e1f6866278fbabec814c289cad2f6fad800..cf559ca1a4b3a6a808b279bf8941ba35897f14f7 100644
--- a/src/modules/series-strategies/ISeries.ts
+++ b/src/modules/series-strategies/ISeries.ts
@@ -7,6 +7,8 @@ import { Candle, Destroyable, LineCandle } from '../../types/chart';
 export interface ISeries<TSeries extends SeriesType> extends IBaseSeries<TSeries>, Destroyable {
   show(): void;
 
+  isVisible(): boolean;
+
   hide(): void;
 
   validateData(data: (Partial<Candle> & Partial<LineCandle>)[]): boolean;
diff --git a/src/utils/typeGuards.ts b/src/utils/typeGuards.ts
index 7c205eea0d202bdbfb443d3357d114f2b1cf81be..a95c4ea082fece10d33c16d507c9c1deecc0e9fd 100644
--- a/src/utils/typeGuards.ts
+++ b/src/utils/typeGuards.ts
@@ -1,9 +1,18 @@
 import { BarData, CustomData, HistogramData, LineData } from 'lightweight-charts';
 
 export function isBarData(value: BarData | LineData | HistogramData | CustomData): value is BarData {
-  return (value as BarData).close !== undefined;
+  return (
+    (value as BarData).open !== undefined &&
+    (value as BarData).high !== undefined &&
+    (value as BarData).low !== undefined &&
+    (value as BarData).close !== undefined
+  );
 }
 
-export function isLineData(value: BarData | LineData | HistogramData | CustomData): value is LineData | HistogramData {
+export function isLineData(value: BarData | LineData | HistogramData | CustomData): value is LineData {
+  return (value as LineData | HistogramData).value !== undefined;
+}
+
+export function isHistogramData(value: BarData | LineData | HistogramData | CustomData): value is HistogramData {
   return (value as LineData | HistogramData).value !== undefined;
 }
diff --git a/stories/MXT/MXT.stories.tsx b/stories/MXT/MXT.stories.tsx
index d8e153216b5ab1377638b83e570b8b396bccf1d3..65d5688ec88b4228d78ce0d3c6bcd3556cfb65d0 100644
--- a/stories/MXT/MXT.stories.tsx
+++ b/stories/MXT/MXT.stories.tsx
@@ -89,7 +89,7 @@ const args: MXTProps = {
   getDataSource: dataSourceProvider.generateCandles.bind(dataSourceProvider),
   theme: 'mxt',
   ohlc: {
-    show: true,
+    show: false,
     showVolume: true,
     precision: 6,
   },
diff --git a/stories/TradeRadar/TradeRadar.stories.tsx b/stories/TradeRadar/TradeRadar.stories.tsx
index a8c1fb8b64226338ab15c4fe9fcace52067c8711..c40b902e84a0c1ac7d1d5b4b354cb5affdc510ae 100644
--- a/stories/TradeRadar/TradeRadar.stories.tsx
+++ b/stories/TradeRadar/TradeRadar.stories.tsx
@@ -128,7 +128,7 @@ const args: TRProps = {
   showSettingsButton: true,
   showControlBar: true,
   tooltipConfig: {
-    showTooltip: false,
+    showTooltip: true,
     time: { visible: true, label: 'Время' },
     close: { visible: true, label: 'Закр.' },
     change: { visible: true, label: 'Изм.' },