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


diff --git a/package-lock.json b/package-lock.json
index ad067c16b..36d60d8a2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -39,7 +39,7 @@
         "markdown-it-link-attributes": "^4.0.1",
         "markdown-it-underline": "^1.0.1",
         "meow": "^8.1.2",
-        "moex-chart": "^0.1.12",
+        "moex-chart": "^0.1.13",
         "rc-virtual-list": "^3.14.5",
         "react": "^18.2.0",
         "react-chartjs-2": "^5.2.0",
@@ -28809,9 +28809,9 @@
       }
     },
     "node_modules/moex-chart": {
-      "version": "0.1.12",
-      "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/moex-chart/-/moex-chart-0.1.12.tgz",
-      "integrity": "sha1-0uaftIpE4fqxiyRu7ZNEseyXAcM=",
+      "version": "0.1.13",
+      "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/moex-chart/-/moex-chart-0.1.13.tgz",
+      "integrity": "sha1-DjDtaVo3SKtpu/1x9+XKb5gMJuY=",
       "dependencies": {
         "@dnd-kit/core": "^6.1.0",
         "@dnd-kit/modifiers": "^7.0.0",
@@ -60585,9 +60585,9 @@
       "dev": true
     },
     "moex-chart": {
-      "version": "0.1.12",
-      "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/moex-chart/-/moex-chart-0.1.12.tgz",
-      "integrity": "sha1-0uaftIpE4fqxiyRu7ZNEseyXAcM=",
+      "version": "0.1.13",
+      "resolved": "https://nexus-dev.tech.moex.com/repository/trade-radar-npm-private-group/moex-chart/-/moex-chart-0.1.13.tgz",
+      "integrity": "sha1-DjDtaVo3SKtpu/1x9+XKb5gMJuY=",
       "requires": {
         "@dnd-kit/core": "^6.1.0",
         "@dnd-kit/modifiers": "^7.0.0",
diff --git a/package.json b/package.json
index df913f9be..707f844d8 100644
--- a/package.json
+++ b/package.json
@@ -146,7 +146,7 @@
     "markdown-it-link-attributes": "^4.0.1",
     "markdown-it-underline": "^1.0.1",
     "meow": "^8.1.2",
-    "moex-chart": "^0.1.12",
+    "moex-chart": "^0.1.13",
     "rc-virtual-list": "^3.14.5",
     "react": "^18.2.0",
     "react-chartjs-2": "^5.2.0",
diff --git a/src/components/InstrumentSearch/components/Actions/MoexChartActions.tsx b/src/components/InstrumentSearch/components/Actions/MoexChartActions.tsx
index 4fad0da7a..63170eaae 100644
--- a/src/components/InstrumentSearch/components/Actions/MoexChartActions.tsx
+++ b/src/components/InstrumentSearch/components/Actions/MoexChartActions.tsx
@@ -6,12 +6,12 @@ import { Button } from '@uikit/Button';
 import styles from './styles.module.scss';
 
 type TMoexChartActionsProps = {
-  selectedInstrumentRows: [] | Contract[];
+  selectedInstrumentRows: Contract[];
   isNewScaleDisabled?: boolean;
   customActionsFooterHandlers: {
-    handlePercent: (symbol: string) => void;
-    handleNewScale: (symbol: string) => void;
-    handleNewPanel: (symbol: string) => void;
+    handlePercent: (instrument: Contract) => void;
+    handleNewScale: (instrument: Contract) => void;
+    handleNewPanel: (instrument: Contract) => void;
   };
 };
 
@@ -22,16 +22,16 @@ export const MoexChartActions = ({
 }: TMoexChartActionsProps) => {
   const { handlePercent, handleNewScale, handleNewPanel } = customActionsFooterHandlers;
 
-  const selectedSymbol = selectedInstrumentRows[0]?.issKey;
-  const isButtonDisabled = !selectedSymbol;
+  const selectedInstrument = selectedInstrumentRows[0];
+  const isButtonDisabled = !selectedInstrument?.issKey;
 
   return (
     <div className={styles.actionWrapper}>
       <Button
         text="%"
         onClick={() => {
-          if (selectedSymbol) {
-            handlePercent(selectedSymbol);
+          if (selectedInstrument?.issKey) {
+            handlePercent(selectedInstrument);
           }
         }}
         disabled={isButtonDisabled}
@@ -40,8 +40,8 @@ export const MoexChartActions = ({
       <Button
         text="Новая шкала"
         onClick={() => {
-          if (selectedSymbol) {
-            handleNewScale(selectedSymbol);
+          if (selectedInstrument?.issKey) {
+            handleNewScale(selectedInstrument);
           }
         }}
         disabled={isButtonDisabled || isNewScaleDisabled}
@@ -50,8 +50,8 @@ export const MoexChartActions = ({
       <Button
         text="Новая панель"
         onClick={() => {
-          if (selectedSymbol) {
-            handleNewPanel(selectedSymbol);
+          if (selectedInstrument?.issKey) {
+            handleNewPanel(selectedInstrument);
           }
         }}
         disabled={isButtonDisabled}
diff --git a/src/components/InstrumentSearch/components/Actions/__tests__/MoexChartActions.test.tsx b/src/components/InstrumentSearch/components/Actions/__tests__/MoexChartActions.test.tsx
index 64e65a890..05e49ded0 100644
--- a/src/components/InstrumentSearch/components/Actions/__tests__/MoexChartActions.test.tsx
+++ b/src/components/InstrumentSearch/components/Actions/__tests__/MoexChartActions.test.tsx
@@ -1,8 +1,8 @@
 import { render, screen } from '@testing-library/react';
 import React from 'react';
 
-import '@testing-library/jest-dom';
 import { Contract } from '@modules/contracts';
+import '@testing-library/jest-dom';
 
 import { MoexChartActions } from '../MoexChartActions';
 
@@ -22,6 +22,7 @@ describe('MoexChartActions', () => {
   });
 
   it('should render correctly with no selected instruments', () => {
+    // Arrange & Act
     render(
       <MoexChartActions
         selectedInstrumentRows={[]}
@@ -29,14 +30,17 @@ describe('MoexChartActions', () => {
       />,
     );
 
+    // Assert
     expect(screen.getByText('%')).toBeInTheDocument();
     expect(screen.getByText('Новая шкала')).toBeInTheDocument();
     expect(screen.getByText('Новая панель')).toBeInTheDocument();
   });
 
   it('should render correctly with selected instruments', () => {
+    // Arrange
     const selectedInstruments = [mockContract];
 
+    // Act
     render(
       <MoexChartActions
         selectedInstrumentRows={selectedInstruments as Contract[]}
@@ -44,6 +48,7 @@ describe('MoexChartActions', () => {
       />,
     );
 
+    // Assert
     expect(screen.getByText('%')).toBeInTheDocument();
     expect(screen.getByText('Новая шкала')).toBeInTheDocument();
     expect(screen.getByText('Новая панель')).toBeInTheDocument();
@@ -59,6 +64,7 @@ describe('MoexChartActions', () => {
   });
 
   it('should call handlePercent when percent button is clicked and instrument is selected', () => {
+    // Arrange
     const selectedInstruments = [mockContract];
 
     render(
@@ -69,13 +75,18 @@ describe('MoexChartActions', () => {
     );
 
     const percentButton = screen.getByText('%');
+
     expect(percentButton).not.toBeDisabled();
 
+    // Act
     percentButton.click();
-    expect(mockHandlers.handlePercent).toHaveBeenCalledWith('RU000A0JQ0Y0');
+
+    // Assert
+    expect(mockHandlers.handlePercent).toHaveBeenCalledWith(mockContract);
   });
 
   it('should call handleNewScale when new scale button is clicked and instrument is selected', () => {
+    // Arrange
     const selectedInstruments = [mockContract];
 
     render(
@@ -86,13 +97,18 @@ describe('MoexChartActions', () => {
     );
 
     const newScaleButton = screen.getByText('Новая шкала');
+
     expect(newScaleButton).not.toBeDisabled();
 
+    // Act
     newScaleButton.click();
-    expect(mockHandlers.handleNewScale).toHaveBeenCalledWith('RU000A0JQ0Y0');
+
+    // Assert
+    expect(mockHandlers.handleNewScale).toHaveBeenCalledWith(mockContract);
   });
 
   it('should call handleNewPanel when new panel button is clicked and instrument is selected', () => {
+    // Arrange
     const selectedInstruments = [mockContract];
 
     render(
@@ -103,14 +119,26 @@ describe('MoexChartActions', () => {
     );
 
     const newPanelButton = screen.getByText('Новая панель');
+
     expect(newPanelButton).not.toBeDisabled();
 
+    // Act
     newPanelButton.click();
-    expect(mockHandlers.handleNewPanel).toHaveBeenCalledWith('RU000A0JQ0Y0');
+
+    // Assert
+    expect(mockHandlers.handleNewPanel).toHaveBeenCalledWith(mockContract);
   });
 
   it('should handle multiple selected instruments (only first is used)', () => {
-    const multipleContracts = [{ issKey: 'RU000A0JQ0Y0' }, { issKey: 'RU000A0JQ0Y1' }];
+    // Arrange
+    const multipleContracts = [
+      {
+        issKey: 'RU000A0JQ0Y0',
+      },
+      {
+        issKey: 'RU000A0JQ0Y1',
+      },
+    ];
 
     render(
       <MoexChartActions
@@ -127,14 +155,15 @@ describe('MoexChartActions', () => {
     expect(newScaleButton).not.toBeDisabled();
     expect(newPanelButton).not.toBeDisabled();
 
-    // Click buttons and verify they call handler with first instrument's issKey
+    // Act
     percentButton.click();
-    expect(mockHandlers.handlePercent).toHaveBeenCalledWith('RU000A0JQ0Y0');
-
     newScaleButton.click();
-    expect(mockHandlers.handleNewScale).toHaveBeenCalledWith('RU000A0JQ0Y0');
-
     newPanelButton.click();
-    expect(mockHandlers.handleNewPanel).toHaveBeenCalledWith('RU000A0JQ0Y0');
+
+    // Assert
+    // Verify that handlers are called with the first selected instrument
+    expect(mockHandlers.handlePercent).toHaveBeenCalledWith(multipleContracts[0]);
+    expect(mockHandlers.handleNewScale).toHaveBeenCalledWith(multipleContracts[0]);
+    expect(mockHandlers.handleNewPanel).toHaveBeenCalledWith(multipleContracts[0]);
   });
 });
diff --git a/src/components/InstrumentSearch/types/hooks.ts b/src/components/InstrumentSearch/types/hooks.ts
index a623c5b80..d82fa0da3 100644
--- a/src/components/InstrumentSearch/types/hooks.ts
+++ b/src/components/InstrumentSearch/types/hooks.ts
@@ -74,9 +74,9 @@ export type InstrumentSearchType = {
    * TODO: убрать, когда разработаем свою модалку для moex_chart
    */
   customActionsFooterHandlers?: {
-    handlePercent: (symbol: string) => void;
-    handleNewScale: (symbol: string) => void;
-    handleNewPanel: (symbol: string) => void;
+    handlePercent: (instrument: Contract) => void;
+    handleNewScale: (instrument: Contract) => void;
+    handleNewPanel: (instrument: Contract) => void;
   };
   isNewScaleDisabled?: boolean;
 };
diff --git a/src/widgets/Chart/__tests__/CompareModal.test.tsx b/src/widgets/Chart/__tests__/CompareModal.test.tsx
new file mode 100644
index 000000000..893eb8c5d
--- /dev/null
+++ b/src/widgets/Chart/__tests__/CompareModal.test.tsx
@@ -0,0 +1,255 @@
+import { act, render } from '@testing-library/react';
+
+import { CompareMode } from 'moex-chart';
+import React from 'react';
+
+import { InstrumentSearch } from '@components/InstrumentSearch';
+
+import { CompareModal } from '../components/MoexChart/components/CompareModal';
+
+import type { Contract } from '@modules/contracts';
+import type { __CompareManager__ } from 'moex-chart';
+import type { MutableRefObject } from 'react';
+
+jest.mock('moex-chart', () => ({
+  __esModule: true,
+  CompareMode: {
+    Percentage: 'PCT',
+    NewScale: 'SCALE',
+    NewPane: 'PANE',
+  },
+}));
+
+jest.mock('@components/InstrumentSearch', () => ({
+  InstrumentSearch: jest.fn(() => null),
+}));
+
+interface CompareActions {
+  handlePercent: (instrument: Contract) => void;
+  handleNewScale: (instrument: Contract) => void;
+  handleNewPanel: (instrument: Contract) => void;
+}
+
+interface InstrumentSearchMockProps {
+  widgetId: number;
+  variant: string;
+  isOpen: boolean;
+  setOpen: (isOpen: boolean) => void;
+  isNewScaleDisabled: boolean;
+  customActionsFooterHandlers: CompareActions;
+}
+
+describe('CompareModal', () => {
+  const mockInstrumentSearch = InstrumentSearch as jest.Mock;
+
+  const mockSetOpen = jest.fn();
+  const mockSetSymbolMode = jest.fn();
+  const mockIsNewScaleDisabled = jest.fn();
+  const mockIsNewScaleDisabledObservable = jest.fn();
+  const mockSubscribe = jest.fn();
+  const mockUnsubscribe = jest.fn();
+
+  let newScaleDisabledListener: ((disabled: boolean) => void) | null;
+  let compareManager: __CompareManager__;
+  let compareManagerRef: MutableRefObject<__CompareManager__ | null>;
+
+  const getInstrumentSearchProps = (): InstrumentSearchMockProps => {
+    const lastCall = mockInstrumentSearch.mock.calls[mockInstrumentSearch.mock.calls.length - 1];
+
+    return lastCall?.[0] as InstrumentSearchMockProps;
+  };
+
+  const renderComponent = (isOpen = true) =>
+    render(
+      <CompareModal
+        widgetId={42}
+        compareManager={compareManagerRef}
+        isOpen={isOpen}
+        setOpen={mockSetOpen}
+      />,
+    );
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+
+    newScaleDisabledListener = null;
+
+    mockIsNewScaleDisabled.mockReturnValue(false);
+    mockSetSymbolMode.mockResolvedValue(undefined);
+
+    mockSubscribe.mockImplementation((listener: (disabled: boolean) => void) => {
+      newScaleDisabledListener = listener;
+
+      return {
+        unsubscribe: mockUnsubscribe,
+      };
+    });
+
+    mockIsNewScaleDisabledObservable.mockReturnValue({
+      subscribe: mockSubscribe,
+    });
+
+    compareManager = {
+      setSymbolMode: mockSetSymbolMode,
+      isNewScaleDisabled: mockIsNewScaleDisabled,
+      isNewScaleDisabledObservable: mockIsNewScaleDisabledObservable,
+    } as unknown as __CompareManager__;
+
+    compareManagerRef = {
+      current: compareManager,
+    };
+  });
+
+  it('should pass modal properties and current scale state to instrument search', () => {
+    // Arrange
+    mockIsNewScaleDisabled.mockReturnValue(true);
+
+    // Act
+    renderComponent();
+
+    const instrumentSearchProps = getInstrumentSearchProps();
+
+    // Assert
+    expect(instrumentSearchProps.widgetId).toBe(42);
+    expect(instrumentSearchProps.variant).toBe('single');
+    expect(instrumentSearchProps.isOpen).toBe(true);
+    expect(instrumentSearchProps.setOpen).toBe(mockSetOpen);
+    expect(instrumentSearchProps.isNewScaleDisabled).toBe(true);
+    expect(instrumentSearchProps.customActionsFooterHandlers).toEqual({
+      handlePercent: expect.any(Function),
+      handleNewScale: expect.any(Function),
+      handleNewPanel: expect.any(Function),
+    });
+  });
+
+  it('should subscribe to new scale disabled state', () => {
+    // Arrange & Act
+    renderComponent();
+
+    // Assert
+    expect(mockIsNewScaleDisabled).toHaveBeenCalledTimes(1);
+    expect(mockIsNewScaleDisabledObservable).toHaveBeenCalledTimes(1);
+    expect(mockSubscribe).toHaveBeenCalledTimes(1);
+  });
+
+  it('should update new scale disabled state from manager observable', () => {
+    // Arrange
+    renderComponent();
+
+    // Act
+    act(() => {
+      newScaleDisabledListener?.(true);
+    });
+
+    // Assert
+    expect(getInstrumentSearchProps().isNewScaleDisabled).toBe(true);
+  });
+
+  it('should unsubscribe from manager observable on unmount', () => {
+    // Arrange
+    const { unmount } = renderComponent();
+
+    // Act
+    unmount();
+
+    // Assert
+    expect(mockUnsubscribe).toHaveBeenCalledTimes(1);
+  });
+
+  it('should not subscribe when modal is closed', () => {
+    // Arrange & Act
+    renderComponent(false);
+
+    // Assert
+    expect(mockIsNewScaleDisabled).not.toHaveBeenCalled();
+    expect(mockIsNewScaleDisabledObservable).not.toHaveBeenCalled();
+    expect(getInstrumentSearchProps().isNewScaleDisabled).toBe(false);
+  });
+
+  it('should not subscribe when compare manager is unavailable', () => {
+    // Arrange
+    compareManagerRef.current = null;
+
+    // Act
+    renderComponent();
+
+    // Assert
+    expect(mockIsNewScaleDisabled).not.toHaveBeenCalled();
+    expect(mockIsNewScaleDisabledObservable).not.toHaveBeenCalled();
+    expect(getInstrumentSearchProps().isNewScaleDisabled).toBe(false);
+  });
+
+  it.each([
+    ['handlePercent', CompareMode.Percentage],
+    ['handleNewScale', CompareMode.NewScale],
+    ['handleNewPanel', CompareMode.NewPane],
+  ] as const)('should add compare instrument using %s action', (handlerName, mode) => {
+    // Arrange
+    renderComponent();
+
+    const instrument = {
+      issKey: 'MXSE:TQBR:SBER',
+      displayName: 'Сбербанк',
+      symbol: 'SBER',
+    } as Contract;
+
+    const handlers = getInstrumentSearchProps().customActionsFooterHandlers;
+
+    // Act
+    handlers[handlerName](instrument);
+
+    // Assert
+    expect(mockSetSymbolMode).toHaveBeenCalledTimes(1);
+    expect(mockSetSymbolMode).toHaveBeenCalledWith(
+      'Line',
+      {
+        symbolId: 'MXSE:TQBR:SBER',
+        symbol: 'SBER',
+        symbolName: 'Сбербанк',
+      },
+      mode,
+    );
+  });
+
+  it('should delegate missing symbol metadata fallback to moex chart', () => {
+    // Arrange
+    renderComponent();
+
+    const instrument = {
+      issKey: 'MXSE:TQBR:SBER',
+      displayName: '',
+      symbol: '',
+    } as Contract;
+
+    // Act
+    getInstrumentSearchProps().customActionsFooterHandlers.handlePercent(instrument);
+
+    // Assert
+    expect(mockSetSymbolMode).toHaveBeenCalledWith(
+      'Line',
+      {
+        symbolId: 'MXSE:TQBR:SBER',
+        symbol: '',
+        symbolName: '',
+      },
+      CompareMode.Percentage,
+    );
+  });
+
+  it('should not add compare instrument without issKey', () => {
+    // Arrange
+    renderComponent();
+
+    const instrument = {
+      issKey: '',
+      displayName: 'Сбербанк',
+      symbol: 'SBER',
+    } as Contract;
+
+    // Act
+    getInstrumentSearchProps().customActionsFooterHandlers.handlePercent(instrument);
+
+    // Assert
+    expect(mockSetSymbolMode).not.toHaveBeenCalled();
+  });
+});
diff --git a/src/widgets/Chart/__tests__/MoexChart.test.tsx b/src/widgets/Chart/__tests__/MoexChart.test.tsx
new file mode 100644
index 000000000..3350dc9b8
--- /dev/null
+++ b/src/widgets/Chart/__tests__/MoexChart.test.tsx
@@ -0,0 +1,205 @@
+import { act, render } from '@testing-library/react';
+
+import React from 'react';
+
+import { CompareModal } from '../components/MoexChart/components/CompareModal';
+import { SymbolSearchModal } from '../components/MoexChart/components/SymbolSearchModal';
+import { useMoexChart } from '../components/MoexChart/hooks';
+import MoexChartComponent from '../components/MoexChart/MoexChart';
+
+import type { SelectedInstrument } from '../types';
+
+import type { __CompareManager__, SymbolInfoInput } from 'moex-chart';
+import type { MutableRefObject } from 'react';
+
+jest.mock('../components/MoexChart/hooks', () => ({
+  useMoexChart: jest.fn(),
+}));
+
+jest.mock('../components/MoexChart/components/CompareModal', () => ({
+  CompareModal: jest.fn(() => null),
+}));
+
+jest.mock('../components/MoexChart/components/SymbolSearchModal', () => ({
+  SymbolSearchModal: jest.fn(() => null),
+}));
+
+interface CompareModalMockProps {
+  widgetId: number;
+  isOpen: boolean;
+  setOpen: (isOpen: boolean) => void;
+  compareManager: MutableRefObject<__CompareManager__ | null>;
+}
+
+interface SymbolSearchModalMockProps {
+  widgetId: number;
+  isOpen: boolean;
+  setOpen: (isOpen: boolean) => void;
+  onSymbolChange: (instrument: SelectedInstrument) => void;
+}
+
+describe('MoexChart', () => {
+  const mockUseMoexChart = useMoexChart as jest.Mock;
+  const mockCompareModal = CompareModal as jest.Mock;
+  const mockSymbolSearchModal = SymbolSearchModal as jest.Mock;
+
+  const mockSetIsCompareOpen = jest.fn();
+  const mockSetIsSymbolSearchOpen = jest.fn();
+  const mockAddInstrumentFromModal = jest.fn();
+
+  const symbolInfo: SymbolInfoInput = {
+    symbolId: 'MXSE:TQBR:SBER',
+    symbol: 'SBER',
+    symbolName: 'Сбербанк',
+  };
+
+  let containerRef: MutableRefObject<HTMLDivElement | null>;
+  let compareManagerRef: MutableRefObject<__CompareManager__ | null>;
+
+  const renderComponent = () =>
+    render(
+      <MoexChartComponent
+        symbolInfo={symbolInfo}
+        widgetId={42}
+        addInstrumentFromModal={mockAddInstrumentFromModal}
+      />,
+    );
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+
+    containerRef = {
+      current: null,
+    };
+
+    compareManagerRef = {
+      current: null,
+    };
+
+    mockUseMoexChart.mockReturnValue({
+      containerRef,
+      isCompareOpen: false,
+      isSymbolSearchOpen: false,
+      compareManagerRef,
+      setIsCompareOpen: mockSetIsCompareOpen,
+      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
+      saveSnapshot: jest.fn(),
+      applySnapshot: jest.fn(),
+      hasSavedSnapshot: false,
+    });
+  });
+
+  it('should initialize chart hook with symbol info', () => {
+    // Arrange & Act
+    renderComponent();
+
+    // Assert
+    expect(mockUseMoexChart).toHaveBeenCalledTimes(1);
+    expect(mockUseMoexChart).toHaveBeenCalledWith({
+      symbolInfo,
+      indicativeData: undefined,
+    });
+  });
+
+  it('should attach chart container ref', () => {
+    // Arrange & Act
+    renderComponent();
+
+    // Assert
+    expect(containerRef.current).toBeInstanceOf(HTMLDivElement);
+  });
+
+  it('should not render modals when they are closed', () => {
+    // Arrange & Act
+    renderComponent();
+
+    // Assert
+    expect(mockCompareModal).not.toHaveBeenCalled();
+    expect(mockSymbolSearchModal).not.toHaveBeenCalled();
+  });
+
+  it('should render compare modal with chart manager', () => {
+    // Arrange
+    mockUseMoexChart.mockReturnValue({
+      containerRef,
+      isCompareOpen: true,
+      isSymbolSearchOpen: false,
+      compareManagerRef,
+      setIsCompareOpen: mockSetIsCompareOpen,
+      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
+      saveSnapshot: jest.fn(),
+      applySnapshot: jest.fn(),
+      hasSavedSnapshot: false,
+    });
+
+    // Act
+    renderComponent();
+
+    const compareModalProps = mockCompareModal.mock.calls[0]?.[0] as CompareModalMockProps;
+
+    // Assert
+    expect(compareModalProps.widgetId).toBe(42);
+    expect(compareModalProps.isOpen).toBe(true);
+    expect(compareModalProps.setOpen).toBe(mockSetIsCompareOpen);
+    expect(compareModalProps.compareManager).toBe(compareManagerRef);
+  });
+
+  it('should render symbol search modal', () => {
+    // Arrange
+    mockUseMoexChart.mockReturnValue({
+      containerRef,
+      isCompareOpen: false,
+      isSymbolSearchOpen: true,
+      compareManagerRef,
+      setIsCompareOpen: mockSetIsCompareOpen,
+      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
+      saveSnapshot: jest.fn(),
+      applySnapshot: jest.fn(),
+      hasSavedSnapshot: false,
+    });
+
+    // Act
+    renderComponent();
+
+    const symbolSearchModalProps = mockSymbolSearchModal.mock.calls[0]?.[0] as SymbolSearchModalMockProps;
+
+    // Assert
+    expect(symbolSearchModalProps.widgetId).toBe(42);
+    expect(symbolSearchModalProps.isOpen).toBe(true);
+    expect(symbolSearchModalProps.setOpen).toBe(mockSetIsSymbolSearchOpen);
+  });
+
+  it('should pass selected instrument from symbol search modal', () => {
+    // Arrange
+    mockUseMoexChart.mockReturnValue({
+      containerRef,
+      isCompareOpen: false,
+      isSymbolSearchOpen: true,
+      compareManagerRef,
+      setIsCompareOpen: mockSetIsCompareOpen,
+      setIsSymbolSearchOpen: mockSetIsSymbolSearchOpen,
+      saveSnapshot: jest.fn(),
+      applySnapshot: jest.fn(),
+      hasSavedSnapshot: false,
+    });
+
+    renderComponent();
+
+    const symbolSearchModalProps = mockSymbolSearchModal.mock.calls[0]?.[0] as SymbolSearchModalMockProps;
+
+    const instrument: SelectedInstrument = {
+      issKey: 'MXSE:TQBR:GAZP',
+      displayName: 'Газпром',
+      symbol: 'GAZP',
+    };
+
+    // Act
+    act(() => {
+      symbolSearchModalProps.onSymbolChange(instrument);
+    });
+
+    // Assert
+    expect(mockAddInstrumentFromModal).toHaveBeenCalledTimes(1);
+    expect(mockAddInstrumentFromModal).toHaveBeenCalledWith([instrument]);
+  });
+});
diff --git a/src/widgets/Chart/__tests__/SymbolSearchModal.test.tsx b/src/widgets/Chart/__tests__/SymbolSearchModal.test.tsx
index b61b7fc18..e8d2587f0 100644
--- a/src/widgets/Chart/__tests__/SymbolSearchModal.test.tsx
+++ b/src/widgets/Chart/__tests__/SymbolSearchModal.test.tsx
@@ -1,4 +1,5 @@
 import { render } from '@testing-library/react';
+
 import React from 'react';
 
 import { InstrumentSearch } from '@components/InstrumentSearch';
@@ -54,12 +55,14 @@ describe('SymbolSearchModal', () => {
     expect(instrumentSearchProps.addInstruments).toEqual(expect.any(Function));
   });
 
-  it('should change symbol after instrument selection', () => {
+  it('should pass selected instrument after instrument selection', () => {
     // Arrange
     const instrumentSearchProps = renderComponent();
 
     const instrument = {
-      issKey: 'MOEX:SBER',
+      issKey: 'MXSE:TQBR:SBER',
+      displayName: 'Сбербанк',
+      symbol: 'SBER',
     } as Contract;
 
     // Act
@@ -67,7 +70,30 @@ describe('SymbolSearchModal', () => {
 
     // Assert
     expect(mockOnSymbolChange).toHaveBeenCalledTimes(1);
-    expect(mockOnSymbolChange).toHaveBeenCalledWith('MOEX:SBER');
+    expect(mockOnSymbolChange).toHaveBeenCalledWith(instrument);
+  });
+
+  it('should pass all required symbol metadata after instrument selection', () => {
+    // Arrange
+    const instrumentSearchProps = renderComponent();
+
+    const instrument = {
+      issKey: 'MXSE:TQBR:GAZP',
+      displayName: 'Газпром',
+      symbol: 'GAZP',
+    } as Contract;
+
+    // Act
+    instrumentSearchProps.addInstruments([instrument]);
+
+    // Assert
+    expect(mockOnSymbolChange).toHaveBeenCalledWith(
+      expect.objectContaining({
+        issKey: 'MXSE:TQBR:GAZP',
+        displayName: 'Газпром',
+        symbol: 'GAZP',
+      }),
+    );
   });
 
   it('should close modal after instrument selection', () => {
@@ -75,7 +101,9 @@ describe('SymbolSearchModal', () => {
     const instrumentSearchProps = renderComponent();
 
     const instrument = {
-      issKey: 'MOEX:SBER',
+      issKey: 'MXSE:TQBR:SBER',
+      displayName: 'Сбербанк',
+      symbol: 'SBER',
     } as Contract;
 
     // Act
@@ -102,8 +130,13 @@ describe('SymbolSearchModal', () => {
     // Arrange
     const instrumentSearchProps = renderComponent();
 
+    const instrument = {
+      displayName: 'Сбербанк',
+      symbol: 'SBER',
+    } as Contract;
+
     // Act
-    instrumentSearchProps.addInstruments([{} as Contract]);
+    instrumentSearchProps.addInstruments([instrument]);
 
     // Assert
     expect(mockOnSymbolChange).not.toHaveBeenCalled();
@@ -116,6 +149,8 @@ describe('SymbolSearchModal', () => {
 
     const instrument = {
       issKey: '',
+      displayName: 'Сбербанк',
+      symbol: 'SBER',
     } as Contract;
 
     // Act
@@ -125,4 +160,23 @@ describe('SymbolSearchModal', () => {
     expect(mockOnSymbolChange).not.toHaveBeenCalled();
     expect(mockSetOpen).not.toHaveBeenCalled();
   });
+
+  it('should pass instrument with empty optional display metadata', () => {
+    // Arrange
+    const instrumentSearchProps = renderComponent();
+
+    const instrument = {
+      issKey: 'MXSE:TQBR:SBER',
+      displayName: '',
+      symbol: '',
+    } as Contract;
+
+    // Act
+    instrumentSearchProps.addInstruments([instrument]);
+
+    // Assert
+    expect(mockOnSymbolChange).toHaveBeenCalledTimes(1);
+    expect(mockOnSymbolChange).toHaveBeenCalledWith(instrument);
+    expect(mockSetOpen).toHaveBeenCalledWith(false);
+  });
 });
diff --git a/src/widgets/Chart/__tests__/dataSourceProvide.test.ts b/src/widgets/Chart/__tests__/dataSourceProvide.test.ts
index 68529685a..1082c242d 100644
--- a/src/widgets/Chart/__tests__/dataSourceProvide.test.ts
+++ b/src/widgets/Chart/__tests__/dataSourceProvide.test.ts
@@ -1,3 +1,5 @@
+import { DEFAULT_SYMBOL } from '@widgets/Chart/const';
+
 import type { Timeframes as TimeframesType } from 'moex-chart';
 
 type DataSourceProvideModule = typeof import('@widgets/Chart/components/MoexChart/dataSourceProvide');
@@ -120,7 +122,6 @@ describe('DataSourceProvider', () => {
     // Arrange
     const mockTimeframeCallback = jest.fn();
 
-    // mockMoexChartTimeConverter.mockReturnValue('1');
     mockRequestBars.mockResolvedValue([mockBar]);
 
     const provider = new DataSourceProvider();
@@ -148,6 +149,36 @@ describe('DataSourceProvider', () => {
     expect(result).toEqual([mockBar]);
   });
 
+  it('should not request chart history data for default symbol', async () => {
+    // Arrange
+    const mockTimeframeCallback = jest.fn();
+
+    const provider = new DataSourceProvider();
+
+    const dataSource = provider.getDataSource(undefined, mockTimeframeCallback);
+
+    // Act
+    const result = await dataSource(Timeframes['1m'], DEFAULT_SYMBOL);
+
+    // Assert
+    expect(result).toBeNull();
+    expect(mockRequestBars).not.toHaveBeenCalled();
+  });
+
+  it('should not request chart history data for empty symbol', async () => {
+    // Arrange
+    const provider = new DataSourceProvider();
+
+    const dataSource = provider.getDataSource();
+
+    // Act
+    const result = await dataSource(Timeframes['1m'], '   ');
+
+    // Assert
+    expect(result).toBeNull();
+    expect(mockRequestBars).not.toHaveBeenCalled();
+  });
+
   it('should request chart history data with indicative data', async () => {
     // Arrange
     const indicativeData = {
@@ -160,7 +191,6 @@ describe('DataSourceProvider', () => {
       key: 'SBER_TBQR',
     };
 
-    // mockMoexChartTimeConverter.mockReturnValue('1');
     mockRequestBars.mockResolvedValue([mockBar]);
 
     const provider = new DataSourceProvider();
@@ -204,7 +234,6 @@ describe('DataSourceProvider', () => {
 
   it('should return null when history data is empty', async () => {
     // Arrange
-    // mockMoexChartTimeConverter.mockReturnValue('1');
     mockRequestBars.mockResolvedValue([]);
 
     const provider = new DataSourceProvider();
@@ -223,7 +252,6 @@ describe('DataSourceProvider', () => {
     const provider = new DataSourceProvider();
     const mockUpdate = jest.fn();
 
-    // mockMoexChartTimeConverter.mockReturnValue('1');
     const localMockedBar = {
       time: 1640995200,
       open: 100,
@@ -232,6 +260,7 @@ describe('DataSourceProvider', () => {
       low: 90,
       volume: Math.floor(Math.random() * 1000),
     };
+
     mockRequestRealtimeBars.mockImplementation(() => localMockedBar);
 
     provider.startRealtime({
@@ -247,18 +276,65 @@ describe('DataSourceProvider', () => {
 
     // Assert
     expect(mockRequestRealtimeBars).toHaveBeenCalledWith({
-      currencyPair: 'MOEX.SBER',
+      currencyPair: 'moex.sber',
       interval: '1',
-      ticker: 'MOEX:SBER',
+      ticker: 'moex:sber',
       indicativeData: undefined,
     });
-    expect(mockUpdate).toHaveBeenCalledWith('MOEX:SBER', localMockedBar);
+    expect(mockUpdate).toHaveBeenCalledWith('moex:sber', localMockedBar);
+  });
+
+  it('should not request realtime data for default symbol', async () => {
+    // Arrange
+    const provider = new DataSourceProvider();
+    const mockUpdate = jest.fn();
+
+    const unsubscribe = provider.startRealtime({
+      getSymbols: () => [DEFAULT_SYMBOL],
+      getTimeframe: () => Timeframes['1m'],
+      update: mockUpdate,
+      periodMs: 1000,
+    });
+
+    // Act
+    jest.advanceTimersByTime(1000);
+    await flushPromises();
+
+    unsubscribe();
+
+    // Assert
+    expect(mockRequestRealtimeBars).not.toHaveBeenCalled();
+    expect(mockUpdate).not.toHaveBeenCalled();
+  });
+
+  it('should not request realtime data for default symbol with surrounding spaces', async () => {
+    // Arrange
+    const provider = new DataSourceProvider();
+    const mockUpdate = jest.fn();
+
+    const unsubscribe = provider.startRealtime({
+      getSymbols: () => [`  ${DEFAULT_SYMBOL}  `],
+      getTimeframe: () => Timeframes['1m'],
+      update: mockUpdate,
+      periodMs: 1000,
+    });
+
+    // Act
+    jest.advanceTimersByTime(1000);
+    await flushPromises();
+
+    unsubscribe();
+
+    // Assert
+    expect(mockRequestRealtimeBars).not.toHaveBeenCalled();
+    expect(mockUpdate).not.toHaveBeenCalled();
   });
 
   it('should request realtime data with indicative data', async () => {
     // Arrange
     const provider = new DataSourceProvider();
     const mockUpdate = jest.fn();
+
     const indicativeData = {
       id: 1,
       title: 'Test instrument',
@@ -269,7 +345,6 @@ describe('DataSourceProvider', () => {
       key: 'SBER_TBQR',
     };
 
-    // mockMoexChartTimeConverter.mockReturnValue('1');
     mockRequestRealtimeBars.mockResolvedValue(mockBar);
 
     provider.startRealtime({
@@ -297,7 +372,6 @@ describe('DataSourceProvider', () => {
     const provider = new DataSourceProvider();
     const mockUpdate = jest.fn();
 
-    // mockMoexChartTimeConverter.mockReturnValue('1');
     mockRequestRealtimeBars.mockResolvedValue(undefined);
 
     provider.startRealtime({
@@ -319,7 +393,6 @@ describe('DataSourceProvider', () => {
     // Arrange
     const provider = new DataSourceProvider();
 
-    // mockMoexChartTimeConverter.mockReturnValue('1');
     mockRequestRealtimeBars.mockResolvedValue(mockBar);
 
     provider.startRealtime({
@@ -341,7 +414,6 @@ describe('DataSourceProvider', () => {
     // Arrange
     const provider = new DataSourceProvider();
 
-    // mockMoexChartTimeConverter.mockReturnValue('1');
     mockRequestRealtimeBars.mockResolvedValue(mockBar);
 
     const unsubscribe = provider.startRealtime({
@@ -353,6 +425,7 @@ describe('DataSourceProvider', () => {
 
     // Act
     unsubscribe();
+
     jest.advanceTimersByTime(1000);
     await flushPromises();
 
@@ -369,6 +442,7 @@ describe('DataSourceProvider', () => {
     mockRequestBars.mockResolvedValue(historyData);
 
     const provider = new DataSourceProvider();
+
     const dataSource = provider.getDataSource();
 
     // Act
@@ -396,6 +470,7 @@ describe('DataSourceProvider', () => {
     mockRequestBars.mockResolvedValue(historyData);
 
     const provider = new DataSourceProvider();
+
     const dataSource = provider.getDataSource();
 
     // Act
@@ -432,6 +507,7 @@ describe('DataSourceProvider', () => {
     mockRequestBars.mockResolvedValue(historyData);
 
     const provider = new DataSourceProvider();
+
     const dataSource = provider.getDataSource();
 
     // Act
@@ -458,6 +534,7 @@ describe('DataSourceProvider', () => {
     mockRequestBars.mockResolvedValue([createBar(0), createBar(1)]);
 
     const provider = new DataSourceProvider();
+
     const dataSource = provider.getDataSource();
 
     // Act
diff --git a/src/widgets/Chart/__tests__/useChartComponentFacade.test.tsx b/src/widgets/Chart/__tests__/useChartComponentFacade.test.tsx
new file mode 100644
index 000000000..b6341a06b
--- /dev/null
+++ b/src/widgets/Chart/__tests__/useChartComponentFacade.test.tsx
@@ -0,0 +1,393 @@
+import { act, renderHook } from '@testing-library/react';
+
+import { useDispatch } from 'react-redux';
+
+import { communicator } from '@core/comm';
+import { useAppSelect } from '@hooks/useAppSelector';
+import { CORPACTIONS_OPEN_EXESTED_WIDGET_EVENT, HIGHLIGHT_WIDGET_EVENT } from '@modules/widgets/shared';
+import { addContentPropsToWidget, unbindWidgets } from '@store/slices/widgets';
+import { getState } from '@store/store';
+import { useWidgetsBind } from '@utils/hooks/useWidgetsBind';
+
+import useChartComponentFacade from '../hooks/useChartComponentFacade';
+import { useChartPublicContext } from '../hooks/useChartPublicContext';
+
+import type { WidgetProperties } from '../properties/types';
+import type { ChartContainerProps } from '../types';
+
+import type { SymbolInfoInput } from 'moex-chart';
+
+jest.mock('@store/store', () => ({
+  getState: jest.fn(),
+}));
+
+jest.mock('@store/slices/widgets', () => ({
+  addContentPropsToWidget: jest.fn(),
+  unbindWidgets: jest.fn(),
+}));
+
+jest.mock('react-redux', () => ({
+  useDispatch: jest.fn(),
+}));
+
+jest.mock('@core/comm', () => ({
+  communicator: {
+    listen: jest.fn(),
+  },
+}));
+
+jest.mock('@hooks/useAppSelector', () => ({
+  useAppSelect: jest.fn(),
+}));
+
+jest.mock('@utils/hooks/useWidgetsBind', () => ({
+  useWidgetsBind: jest.fn(),
+}));
+
+jest.mock('../hooks/useChartPublicContext', () => ({
+  useChartPublicContext: jest.fn(),
+}));
+
+interface PublicContextMockParams {
+  setCurrInstrument: (symbolInfo: SymbolInfoInput) => void;
+}
+
+describe('useChartComponentFacade', () => {
+  const mockUseDispatch = useDispatch as jest.Mock;
+  const mockUseAppSelect = useAppSelect as jest.Mock;
+  const mockAddContentPropsToWidget = addContentPropsToWidget as unknown as jest.Mock;
+  const mockUnbindWidgets = unbindWidgets as unknown as jest.Mock;
+  const mockGetState = getState as jest.Mock;
+  const mockUseWidgetsBind = useWidgetsBind as jest.Mock;
+  const mockUseChartPublicContext = useChartPublicContext as jest.Mock;
+  const mockCommunicatorListen = communicator.listen as jest.Mock;
+
+  const mockDispatch = jest.fn();
+  const mockTriggerRelatedWidgetsToUpdate = jest.fn();
+  const mockGetMasterInstrumentFromPublicContext = jest.fn();
+
+  const mockUnsubscribeCorpActions = jest.fn();
+  const mockUnsubscribeHighlighter = jest.fn();
+
+  const widgetProperties = {
+    chartState: {
+      savedInstrument: 'MOEX:SBER',
+      savedSymbol: 'SBER',
+      savedSymbolName: 'Сбербанк',
+      interval: '1m',
+    },
+    indicativeData: {
+      id: 1,
+      key: 'INDICATIVE',
+      secId: 'INAV',
+      instrumentName: 'Индикатив',
+      settlement: 'Расчётный',
+      firmName: 'Тестовая фирма',
+    },
+  } as WidgetProperties;
+
+  const renderFacade = () =>
+    renderHook(() =>
+      useChartComponentFacade({
+        widgetId: 42,
+      } as ChartContainerProps),
+    );
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+
+    mockUseDispatch.mockReturnValue(mockDispatch);
+    mockUseAppSelect.mockReturnValue(widgetProperties);
+
+    mockGetState.mockReturnValue({
+      widgets: {
+        widgets: [
+          {
+            id: 42,
+            widgetContentProps: widgetProperties,
+          },
+        ],
+      },
+    });
+
+    mockUseWidgetsBind.mockReturnValue({
+      triggerRelatedWidgetsToUpdate: mockTriggerRelatedWidgetsToUpdate,
+      getMasterInstrumentFromPublicContext: mockGetMasterInstrumentFromPublicContext,
+    });
+
+    mockUseChartPublicContext.mockReturnValue({
+      issKey: undefined,
+    });
+
+    mockAddContentPropsToWidget.mockImplementation((payload) => ({
+      type: 'widgets/addContentPropsToWidget',
+      payload,
+    }));
+
+    mockUnbindWidgets.mockImplementation((payload) => ({
+      type: 'widgets/unbindWidgets',
+      payload,
+    }));
+
+    mockCommunicatorListen.mockImplementation(({ messageType }) => {
+      if (messageType === CORPACTIONS_OPEN_EXESTED_WIDGET_EVENT) {
+        return mockUnsubscribeCorpActions;
+      }
+
+      if (messageType === HIGHLIGHT_WIDGET_EVENT) {
+        return mockUnsubscribeHighlighter;
+      }
+
+      return jest.fn();
+    });
+  });
+
+  it('should initialize symbol info from widget properties', () => {
+    // Arrange & Act
+    const { result } = renderFacade();
+
+    // Assert
+    expect(result.current.currentSymbolInfo).toEqual({
+      symbolId: 'MOEX:SBER',
+      symbol: 'SBER',
+      symbolName: 'Сбербанк',
+    });
+  });
+
+  it('should update and save instrument selected from modal', () => {
+    // Arrange
+    const { result } = renderFacade();
+
+    jest.clearAllMocks();
+
+    // Act
+    act(() => {
+      result.current.addInstrumentFromModal([
+        {
+          issKey: 'MOEX:GAZP',
+          displayName: 'Газпром',
+          symbol: 'GAZP',
+        },
+      ]);
+    });
+
+    // Assert
+    expect(result.current.currentSymbolInfo).toEqual({
+      symbolId: 'MOEX:GAZP',
+      symbol: 'GAZP',
+      symbolName: 'Газпром',
+    });
+
+    expect(mockUnbindWidgets).toHaveBeenCalledWith({
+      widgetId: 42,
+    });
+
+    expect(mockAddContentPropsToWidget).toHaveBeenCalledWith({
+      id: 42,
+      withoutSend: true,
+      widgetContentProps: {
+        chartState: {
+          ...widgetProperties.chartState,
+          savedInstrument: 'MOEX:GAZP',
+          savedSymbol: 'GAZP',
+          savedSymbolName: 'Газпром',
+        },
+        indicativeData: undefined,
+      },
+    });
+
+    expect(mockTriggerRelatedWidgetsToUpdate).toHaveBeenCalledWith('MOEX:GAZP');
+  });
+
+  it('should update symbol metadata without unbinding when symbol id is unchanged', () => {
+    // Arrange
+    const { result } = renderFacade();
+
+    jest.clearAllMocks();
+
+    // Act
+    act(() => {
+      result.current.addInstrumentFromModal([
+        {
+          issKey: 'MOEX:SBER',
+          displayName: 'Сбербанк ПАО',
+          symbol: 'SBERP',
+        },
+      ]);
+    });
+
+    // Assert
+    expect(result.current.currentSymbolInfo).toEqual({
+      symbolId: 'MOEX:SBER',
+      symbol: 'SBERP',
+      symbolName: 'Сбербанк ПАО',
+    });
+
+    expect(mockUnbindWidgets).not.toHaveBeenCalled();
+    expect(mockTriggerRelatedWidgetsToUpdate).not.toHaveBeenCalled();
+
+    expect(mockAddContentPropsToWidget).toHaveBeenCalledWith({
+      id: 42,
+      withoutSend: true,
+      widgetContentProps: {
+        chartState: {
+          ...widgetProperties.chartState,
+          savedInstrument: 'MOEX:SBER',
+          savedSymbol: 'SBERP',
+          savedSymbolName: 'Сбербанк ПАО',
+        },
+        indicativeData: widgetProperties.indicativeData,
+      },
+    });
+  });
+
+  it('should send dropped instrument update immediately', () => {
+    // Arrange
+    const { result } = renderFacade();
+
+    jest.clearAllMocks();
+
+    // Act
+    act(() => {
+      result.current.onDropInstrument('MOEX:LKOH', true);
+    });
+
+    // Assert
+    expect(result.current.currentSymbolInfo).toEqual({
+      symbolId: 'MOEX:LKOH',
+      symbol: undefined,
+      symbolName: undefined,
+    });
+
+    expect(mockAddContentPropsToWidget).toHaveBeenCalledWith(
+      expect.objectContaining({
+        id: 42,
+        withoutSend: false,
+        widgetContentProps: expect.objectContaining({
+          chartState: expect.objectContaining({
+            savedInstrument: 'MOEX:LKOH',
+            savedSymbol: undefined,
+            savedSymbolName: undefined,
+          }),
+        }),
+      }),
+    );
+  });
+
+  it('should update instrument from public context without unbinding widget', () => {
+    // Arrange
+    renderFacade();
+
+    const publicContextParams = mockUseChartPublicContext.mock.calls[0]?.[0] as PublicContextMockParams;
+
+    jest.clearAllMocks();
+
+    // Act
+    act(() => {
+      publicContextParams.setCurrInstrument({
+        symbolId: 'MOEX:ROSN',
+        symbol: 'ROSN',
+        symbolName: 'Роснефть',
+      });
+    });
+
+    // Assert
+    expect(mockUnbindWidgets).not.toHaveBeenCalled();
+
+    expect(mockAddContentPropsToWidget).toHaveBeenCalledWith(
+      expect.objectContaining({
+        withoutSend: false,
+        widgetContentProps: expect.objectContaining({
+          chartState: expect.objectContaining({
+            savedInstrument: 'MOEX:ROSN',
+            savedSymbol: 'ROSN',
+            savedSymbolName: 'Роснефть',
+          }),
+        }),
+      }),
+    );
+  });
+
+  it('should delegate missing symbol metadata fallback to moex chart', () => {
+    // Arrange
+    const { result } = renderFacade();
+
+    const corpActionsListener = mockCommunicatorListen.mock.calls.find(
+      ([options]) => options.messageType === CORPACTIONS_OPEN_EXESTED_WIDGET_EVENT,
+    )?.[1] as (message: Record<number, string>) => void;
+
+    // Act
+    act(() => {
+      corpActionsListener({
+        42: 'MOEX:UNKNOWN',
+      });
+    });
+
+    // Assert
+    expect(result.current.currentSymbolInfo).toEqual({
+      symbolId: 'MOEX:UNKNOWN',
+      symbol: undefined,
+      symbolName: undefined,
+    });
+
+    expect(mockAddContentPropsToWidget).toHaveBeenCalledWith(
+      expect.objectContaining({
+        widgetContentProps: expect.objectContaining({
+          chartState: expect.objectContaining({
+            savedInstrument: 'MOEX:UNKNOWN',
+            savedSymbol: undefined,
+            savedSymbolName: undefined,
+          }),
+        }),
+      }),
+    );
+  });
+
+  it('should not update instrument when modal selection is empty', () => {
+    // Arrange
+    const { result } = renderFacade();
+
+    jest.clearAllMocks();
+
+    // Act
+    act(() => {
+      result.current.addInstrumentFromModal([]);
+    });
+
+    // Assert
+    expect(mockAddContentPropsToWidget).not.toHaveBeenCalled();
+    expect(mockUnbindWidgets).not.toHaveBeenCalled();
+    expect(mockTriggerRelatedWidgetsToUpdate).not.toHaveBeenCalled();
+  });
+
+  it('should update widget highlight state', () => {
+    // Arrange
+    const { result } = renderFacade();
+
+    const highlighterListener = mockCommunicatorListen.mock.calls.find(
+      ([options]) => options.messageType === HIGHLIGHT_WIDGET_EVENT,
+    )?.[1] as (message: Record<number, boolean>) => void;
+
+    // Act
+    act(() => {
+      highlighterListener({
+        42: true,
+      });
+    });
+
+    // Assert
+    expect(result.current.isOver).toBe(true);
+  });
+
+  it('should unsubscribe communicator listeners on unmount', () => {
+    // Arrange
+    const { unmount } = renderFacade();
+
+    // Act
+    unmount();
+
+    // Assert
+    expect(mockUnsubscribeCorpActions).toHaveBeenCalledTimes(1);
+    expect(mockUnsubscribeHighlighter).toHaveBeenCalledTimes(1);
+  });
+});
diff --git a/src/widgets/Chart/__tests__/useChartPublicContext.test.tsx b/src/widgets/Chart/__tests__/useChartPublicContext.test.tsx
index 666aa3073..0b0f20572 100644
--- a/src/widgets/Chart/__tests__/useChartPublicContext.test.tsx
+++ b/src/widgets/Chart/__tests__/useChartPublicContext.test.tsx
@@ -7,7 +7,8 @@ import { DEFAULT_SYMBOL } from '@widgets/Chart/const';
 
 import { useChartPublicContext } from '../hooks/useChartPublicContext';
 
-// Mock the dependencies
+import type { Contract } from '@modules/contracts';
+
 jest.mock('@hooks/useAppSelector');
 jest.mock('@modules/contracts');
 jest.mock('@utils/filterByUniqIssKey');
@@ -24,6 +25,7 @@ jest.mock('@api/index', () => ({
     update: jest.fn(),
   },
 }));
+
 jest.mock('@api/controllers/workspace', () => ({
   workspaceController: {
     update: jest.fn(),
@@ -36,32 +38,43 @@ describe('useChartPublicContext', () => {
   const mockFilterByUniqIssKey = filterByUniqIssKey as jest.Mock;
 
   const mockContracts = [
+    {
+      issKey: DEFAULT_SYMBOL,
+      displayName: 'Инструмент по умолчанию',
+      symbol: 'DEFAULT',
+      // ... other contract properties
+    },
     {
       issKey: 'MOEX:TEST1',
-      instrName: 'Test Instrument 1',
+      displayName: 'Test Instrument 1',
       symbol: 'TEST1',
       // ... other contract properties
     },
     {
       issKey: 'MOEX:TEST2',
-      instrName: 'Test Instrument 2',
+      displayName: 'Test Instrument 2',
       symbol: 'TEST2',
       // ... other contract properties
     },
     {
       issKey: 'MOEX:TEST3',
-      instrName: 'Test Instrument 3',
+      displayName: 'Test Instrument 3',
       symbol: 'TEST3',
       // ... other contract properties
     },
-  ];
+  ] as Contract[];
 
   const mockWidget = {
     id: 1,
     name: 'Test Widget',
     type: 'graphic',
     master: 123,
-    externalProperties: [{ key: 'instrument', value: 'MOEX:TEST1' }],
+    externalProperties: [
+      {
+        key: 'instrument',
+        value: 'MOEX:TEST1',
+      },
+    ],
     // ... other widget properties
   };
 
@@ -77,9 +90,11 @@ describe('useChartPublicContext', () => {
       if (selector.toString().includes('publicContext')) {
         return mockPublicContext;
       }
+
       if (selector.toString().includes('widgets')) {
         return mockWidget;
       }
+
       return {};
     });
 
@@ -89,7 +104,7 @@ describe('useChartPublicContext', () => {
     });
 
     // Mock filterByUniqIssKey to return the same contracts
-    mockFilterByUniqIssKey.mockImplementation((contracts, keys) => contracts);
+    mockFilterByUniqIssKey.mockImplementation((contracts: Contract[]) => contracts);
   });
 
   it('should return the correct issKey when a matching instrument is found', () => {
@@ -110,13 +125,13 @@ describe('useChartPublicContext', () => {
     expect(result.current.issKey).toBe('MOEX:TEST1');
   });
 
-  it('should return undefined when no matching instrument is found', () => {
+  it('should pass symbol info when a matching instrument is found', () => {
     // Arrange
     const mockSetCurrInstrument = jest.fn();
-    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue('MOEX:NONEXISTENT');
+    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue('MOEX:TEST2');
 
     // Act
-    const { result } = renderHook(() =>
+    renderHook(() =>
       useChartPublicContext({
         widgetId: 1,
         setCurrInstrument: mockSetCurrInstrument,
@@ -125,13 +140,18 @@ describe('useChartPublicContext', () => {
     );
 
     // Assert
-    expect(result.current.issKey).toBeUndefined();
+    expect(mockSetCurrInstrument).toHaveBeenCalledTimes(1);
+    expect(mockSetCurrInstrument).toHaveBeenCalledWith({
+      symbolId: 'MOEX:TEST2',
+      symbol: 'TEST2',
+      symbolName: 'Test Instrument 2',
+    });
   });
 
-  it('should return undefined when getMasterInstrumentFromPublicContext returns null', () => {
+  it('should return undefined when no matching instrument is found', () => {
     // Arrange
     const mockSetCurrInstrument = jest.fn();
-    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue(null);
+    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue('MOEX:NONEXISTENT');
 
     // Act
     const { result } = renderHook(() =>
@@ -144,12 +164,13 @@ describe('useChartPublicContext', () => {
 
     // Assert
     expect(result.current.issKey).toBeUndefined();
+    expect(mockSetCurrInstrument).not.toHaveBeenCalled();
   });
 
-  it('should return undefined when getMasterInstrumentFromPublicContext returns undefined', () => {
+  it('should return undefined when getMasterInstrumentFromPublicContext returns null', () => {
     // Arrange
     const mockSetCurrInstrument = jest.fn();
-    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue(undefined);
+    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue(null);
 
     // Act
     const { result } = renderHook(() =>
@@ -164,13 +185,13 @@ describe('useChartPublicContext', () => {
     expect(result.current.issKey).toBeUndefined();
   });
 
-  it('should set current instrument to DEFAULT_SYMBOL when no field value and widget has master', () => {
+  it('should return undefined when getMasterInstrumentFromPublicContext returns undefined', () => {
     // Arrange
     const mockSetCurrInstrument = jest.fn();
-    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue(null);
+    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue(undefined);
 
     // Act
-    renderHook(() =>
+    const { result } = renderHook(() =>
       useChartPublicContext({
         widgetId: 1,
         setCurrInstrument: mockSetCurrInstrument,
@@ -179,13 +200,13 @@ describe('useChartPublicContext', () => {
     );
 
     // Assert
-    expect(mockSetCurrInstrument).toHaveBeenCalledWith(DEFAULT_SYMBOL);
+    expect(result.current.issKey).toBeUndefined();
   });
 
-  it('should set current instrument to the found issKey when a matching instrument exists', () => {
+  it('should set default symbol info when context value is empty', () => {
     // Arrange
     const mockSetCurrInstrument = jest.fn();
-    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue('MOEX:TEST2');
+    const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue(null);
 
     // Act
     renderHook(() =>
@@ -197,29 +218,35 @@ describe('useChartPublicContext', () => {
     );
 
     // Assert
-    expect(mockSetCurrInstrument).toHaveBeenCalledWith('MOEX:TEST2');
+    expect(mockSetCurrInstrument).toHaveBeenCalledTimes(1);
+    expect(mockSetCurrInstrument).toHaveBeenCalledWith({
+      symbolId: DEFAULT_SYMBOL,
+      symbol: 'DEFAULT',
+      symbolName: 'Инструмент по умолчанию',
+    });
   });
 
-  it('should handle case when widget is not found in widgets array', () => {
+  it('should resolve instrument when widget is not found', () => {
     // Arrange
     const mockSetCurrInstrument = jest.fn();
     const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue('MOEX:TEST1');
 
-    // Mock useAppSelect to return null for widget (widget not found)
     mockUseAppSelect.mockImplementation((selector) => {
       if (selector.toString().includes('publicContext')) {
         return mockPublicContext;
       }
+
       if (selector.toString().includes('widgets')) {
-        return null; // Widget not found
+        return null;
       }
+
       return {};
     });
 
     // Act
     const { result } = renderHook(() =>
       useChartPublicContext({
-        widgetId: 999, // Non-existent widget ID
+        widgetId: 999,
         setCurrInstrument: mockSetCurrInstrument,
         getMasterInstrumentFromPublicContext: mockGetMasterInstrumentFromPublicContext,
       }),
@@ -227,14 +254,18 @@ describe('useChartPublicContext', () => {
 
     // Assert
     expect(result.current.issKey).toBe('MOEX:TEST1');
+    expect(mockSetCurrInstrument).toHaveBeenCalledWith({
+      symbolId: 'MOEX:TEST1',
+      symbol: 'TEST1',
+      symbolName: 'Test Instrument 1',
+    });
   });
 
-  it('should handle case when contracts array is empty', () => {
+  it('should not set instrument when contracts array is empty', () => {
     // Arrange
     const mockSetCurrInstrument = jest.fn();
     const mockGetMasterInstrumentFromPublicContext = jest.fn().mockReturnValue('MOEX:TEST1');
 
-    // Mock useContracts to return empty contracts
     mockUseContracts.mockReturnValue({
       contracts: [],
     });
@@ -250,5 +281,6 @@ describe('useChartPublicContext', () => {
 
     // Assert
     expect(result.current.issKey).toBeUndefined();
+    expect(mockSetCurrInstrument).not.toHaveBeenCalled();
   });
 });
diff --git a/src/widgets/Chart/__tests__/useMoexchart.test.tsx b/src/widgets/Chart/__tests__/useMoexchart.test.tsx
index 2396e0910..f60feb2d8 100644
--- a/src/widgets/Chart/__tests__/useMoexchart.test.tsx
+++ b/src/widgets/Chart/__tests__/useMoexchart.test.tsx
@@ -4,11 +4,12 @@ import { MoexChart, Timeframes } from 'moex-chart';
 import React from 'react';
 
 import { useChangeProperties, useSelectProperties } from '@modules/widgetProperties';
-import { ChartIndicativeData } from '@widgets/Chart/types';
 
 import { useMoexChart } from '../components/MoexChart/hooks';
 
-// Mock the dependencies
+import type { ChartIndicativeData } from '@widgets/Chart/types';
+import type { SymbolInfoInput } from 'moex-chart';
+
 jest.mock('@modules/widgetProperties');
 
 jest.mock('../components/MoexChart/dataSourceProvide', () => ({
@@ -59,13 +60,37 @@ const mockedDataSourceProvide = jest.requireMock('../components/MoexChart/dataSo
 
 type TimeframeValue = (typeof Timeframes)[keyof typeof Timeframes];
 
+interface MockCompareSeries {
+  name: string;
+  seriesOptions?: {
+    priceScaleId?: string;
+    color?: string;
+  };
+}
+
+interface MockIndicatorConfig {
+  symbolInfo?: SymbolInfoInput;
+  label?: string;
+  newPane?: boolean;
+  series: MockCompareSeries[];
+}
+
+interface MockIndicatorSnapshot {
+  id?: string;
+  indicatorType?: string;
+  dataSource?: unknown;
+  config?: MockIndicatorConfig;
+}
+
 interface MockPaneSnapshot {
-  indicators: unknown[];
+  indicators: MockIndicatorSnapshot[];
 }
 
 interface MockChartSnapshot {
   charts: {
+    symbolId: string;
     symbol: string;
+    symbolName: string;
     timeframe: TimeframeValue;
     chartSeriesType: string;
     panes: MockPaneSnapshot[];
@@ -88,7 +113,8 @@ interface MockMoexChartConfig {
 }
 
 interface MockMoexChartState {
-  tf?: TimeframeValue;
+  timeframe: TimeframeValue;
+  initialInterval?: string;
   savedData?: string;
 }
 
@@ -101,13 +127,20 @@ type UpdatePropertiesCallback = (state: MockPropertiesState) => void;
 type TimeframeChangeCallback = (timeframe: TimeframeValue) => void;
 
 interface TestComponentProps {
-  symbol?: string;
+  symbolInfo?: SymbolInfoInput;
+  indicativeData?: ChartIndicativeData;
 }
 
+const defaultSymbolInfo: SymbolInfoInput = {
+  symbolId: 'MOEX:SBER',
+  symbol: 'SBER',
+  symbolName: 'Сбербанк',
+};
+
 describe('useMoexChart', () => {
   const mockUseSelectProperties = useSelectProperties as jest.Mock;
   const mockUseChangeProperties = useChangeProperties as jest.Mock;
-  const mockMoexChart = MoexChart as jest.Mock;
+  const mockMoexChart = MoexChart as unknown as jest.Mock;
   const mockDataSourceProvider = mockedDataSourceProvide.DataSourceProvider;
 
   const mockUpdateProperties = jest.fn();
@@ -117,6 +150,7 @@ describe('useMoexChart', () => {
   const mockSetSnapshot = jest.fn();
   const mockSetSymbol = jest.fn();
   const mockGetCompareManager = jest.fn();
+  const mockSetSettings = jest.fn();
 
   const mockDataSource = jest.fn();
   const mockStartRealtime = jest.fn();
@@ -130,7 +164,9 @@ describe('useMoexChart', () => {
   const mockSnapshot: MockChartSnapshot = {
     charts: [
       {
-        symbol: 'OLD:SYMBOL',
+        symbolId: 'OLD:SYMBOL',
+        symbol: 'OLD',
+        symbolName: 'Old instrument',
         timeframe: Timeframes['5m'],
         chartSeriesType: 'Candlestick',
         panes: [
@@ -146,10 +182,13 @@ describe('useMoexChart', () => {
   let lastMoexChartConfig: MockMoexChartConfig | null = null;
   let mockMoexChartState: MockMoexChartState | undefined;
 
-  const TestComponent = ({ symbol = 'MOEX:SBER' }: TestComponentProps): React.ReactElement => {
+  const TestComponent = ({
+    symbolInfo = defaultSymbolInfo,
+    indicativeData,
+  }: TestComponentProps): React.ReactElement => {
     hookResult = useMoexChart({
-      symbol,
-      indicativeData: undefined,
+      symbolInfo,
+      indicativeData,
     });
 
     return <div ref={hookResult.containerRef} />;
@@ -157,12 +196,13 @@ describe('useMoexChart', () => {
 
   beforeEach(() => {
     jest.clearAllMocks();
+    jest.useFakeTimers();
 
     hookResult = null;
     lastMoexChartConfig = null;
 
     mockMoexChartState = {
-      tf: Timeframes['1m'],
+      timeframe: Timeframes['1m'],
       savedData: undefined,
     };
 
@@ -177,8 +217,8 @@ describe('useMoexChart', () => {
     });
 
     mockGetDataSource.mockImplementation(
-      (_indicativeData?: ChartIndicativeData, callback?: (timeframe: Timeframes) => void) =>
-        (timeframe: Timeframes) => {
+      (_indicativeData?: ChartIndicativeData, callback?: (timeframe: TimeframeValue) => void) =>
+        (timeframe: TimeframeValue) => {
           callback?.(timeframe);
 
           return mockDataSource();
@@ -203,46 +243,70 @@ describe('useMoexChart', () => {
         getSnapshot: mockGetSnapshot,
         setSnapshot: mockSetSnapshot,
         setSymbol: mockSetSymbol,
+        setSettings: mockSetSettings,
         getCompareManager: mockGetCompareManager,
       };
     });
   });
 
-  it('should create moex chart with current symbol and timeframe', () => {
+  afterEach(() => {
+    jest.clearAllTimers();
+    jest.useRealTimers();
+  });
+
+  it('should create moex chart with current symbol info and timeframe', () => {
     // Arrange & Act
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     // Assert
     expect(mockMoexChart).toHaveBeenCalledTimes(1);
     expect(mockDataSourceProvider).toHaveBeenCalledTimes(1);
-
     expect(lastMoexChartConfig?.container).toBeInstanceOf(HTMLDivElement);
-    expect(lastMoexChartConfig?.snapshot.charts[0]?.symbol).toBe('MOEX:SBER');
-    expect(lastMoexChartConfig?.snapshot.charts[0]?.timeframe).toBe(Timeframes['1m']);
-
+    expect(lastMoexChartConfig?.snapshot.charts[0]).toEqual(
+      expect.objectContaining({
+        symbolId: 'MOEX:SBER',
+        symbol: 'SBER',
+        symbolName: 'Сбербанк',
+        timeframe: Timeframes['1m'],
+      }),
+    );
     expect(hookResult?.compareManagerRef.current).toBe(mockCompareManager);
+    expect(hookResult?.hasSavedSnapshot).toBe(false);
   });
 
-  it('should create chart with saved snapshot when saved data exists', () => {
+  it('should create chart with saved snapshot and current symbol info', () => {
     // Arrange
     mockMoexChartState = {
-      tf: Timeframes['5m'],
+      timeframe: Timeframes['5m'],
       savedData: JSON.stringify(mockSnapshot),
     };
 
     // Act
-    render(<TestComponent symbol="MOEX:GAZP" />);
+    render(
+      <TestComponent
+        symbolInfo={{
+          symbolId: 'MOEX:GAZP',
+          symbol: 'GAZP',
+          symbolName: 'Газпром',
+        }}
+      />,
+    );
 
     // Assert
-    expect(lastMoexChartConfig?.snapshot.charts[0]?.symbol).toBe('MOEX:GAZP');
-    expect(lastMoexChartConfig?.snapshot.charts[0]?.timeframe).toBe(Timeframes['5m']);
-
+    expect(lastMoexChartConfig?.snapshot.charts[0]).toEqual(
+      expect.objectContaining({
+        symbolId: 'MOEX:GAZP',
+        symbol: 'GAZP',
+        symbolName: 'Газпром',
+        timeframe: Timeframes['5m'],
+      }),
+    );
     expect(hookResult?.hasSavedSnapshot).toBe(true);
   });
 
   it('should save chart snapshot to widget properties', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     // Act
     act(() => {
@@ -257,23 +321,138 @@ describe('useMoexChart', () => {
 
     const mockState: MockPropertiesState = {
       moexChartState: {
-        tf: Timeframes['1m'],
+        timeframe: Timeframes['1m'],
       },
     };
 
     updateCallback(mockState);
 
     expect(mockState.moexChartState).toEqual({
-      tf: Timeframes['1m'],
+      timeframe: Timeframes['1m'],
       savedData: JSON.stringify(mockSnapshot),
     });
   });
 
+  it('should serialize compare symbol info in snapshot', () => {
+    // Arrange
+    const snapshotWithIndicators: MockChartSnapshot = {
+      charts: [
+        {
+          symbolId: 'MOEX:SBER',
+          symbol: 'SBER',
+          symbolName: 'Сбербанк',
+          timeframe: Timeframes['1m'],
+          chartSeriesType: 'Candlestick',
+          panes: [
+            {
+              indicators: [
+                {
+                  id: 'compare-gazp',
+                  indicatorType: undefined,
+                  dataSource: {
+                    subscription: {},
+                  },
+                  config: {
+                    symbolInfo: {
+                      symbolId: 'MOEX:GAZP',
+                      symbol: 'GAZP',
+                      symbolName: 'Газпром',
+                    },
+                    label: 'Газпром',
+                    newPane: false,
+                    series: [
+                      {
+                        name: 'Line',
+                        seriesOptions: {
+                          priceScaleId: 'left',
+                          color: '#FFFFFF',
+                        },
+                      },
+                    ],
+                  },
+                },
+                {
+                  id: 'rsi',
+                  indicatorType: 'RSI',
+                  dataSource: {
+                    subscription: {},
+                  },
+                  config: {
+                    label: 'RSI',
+                    newPane: true,
+                    series: [
+                      {
+                        name: 'Line',
+                        seriesOptions: {
+                          priceScaleId: 'right',
+                        },
+                      },
+                    ],
+                  },
+                },
+              ],
+            },
+          ],
+        },
+      ],
+    };
+
+    mockGetSnapshot.mockReturnValue(snapshotWithIndicators);
+
+    render(<TestComponent />);
+
+    // Act
+    act(() => {
+      hookResult?.saveSnapshot();
+    });
+
+    const updateCallback = mockUpdateProperties.mock.calls[0]?.[0] as UpdatePropertiesCallback;
+
+    const mockState: MockPropertiesState = {
+      moexChartState: {
+        timeframe: Timeframes['1m'],
+      },
+    };
+
+    updateCallback(mockState);
+
+    const savedSnapshot = JSON.parse(mockState.moexChartState?.savedData ?? '{}') as MockChartSnapshot;
+
+    const [compareIndicator, regularIndicator] = savedSnapshot.charts[0]?.panes[0]?.indicators ?? [];
+
+    // Assert
+    expect(compareIndicator).toEqual({
+      id: 'compare-gazp',
+      config: {
+        symbolInfo: {
+          symbolId: 'MOEX:GAZP',
+          symbol: 'GAZP',
+          symbolName: 'Газпром',
+        },
+        label: 'Газпром',
+        newPane: false,
+        series: [
+          {
+            name: 'Line',
+            seriesOptions: {
+              priceScaleId: 'left',
+            },
+          },
+        ],
+      },
+    });
+
+    expect(regularIndicator).toEqual({
+      id: 'rsi',
+      indicatorType: 'RSI',
+    });
+  });
+
   it('should not save snapshot when chart does not return snapshot', () => {
     // Arrange
     mockGetSnapshot.mockReturnValue(undefined);
 
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     // Act
     act(() => {
@@ -285,14 +464,14 @@ describe('useMoexChart', () => {
     expect(mockUpdateProperties).not.toHaveBeenCalled();
   });
 
-  it('should apply saved snapshot with current symbol and timeframe', () => {
+  it('should apply saved snapshot with current symbol info and timeframe', () => {
     // Arrange
     mockMoexChartState = {
-      tf: Timeframes['5m'],
+      timeframe: Timeframes['5m'],
       savedData: JSON.stringify(mockSnapshot),
     };
 
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     // Act
     act(() => {
@@ -305,18 +484,19 @@ describe('useMoexChart', () => {
       charts: [
         {
           ...mockSnapshot.charts[0],
-          symbol: 'MOEX:SBER',
+          symbolId: 'MOEX:SBER',
+          symbol: 'SBER',
+          symbolName: 'Сбербанк',
           timeframe: Timeframes['5m'],
         },
       ],
     });
-
     expect(hookResult?.compareManagerRef.current).toBe(mockCompareManager);
   });
 
   it('should update compare modal state', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     // Act
     act(() => {
@@ -329,7 +509,7 @@ describe('useMoexChart', () => {
 
   it('should open compare modal from chart preset callback', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     // Act
     act(() => {
@@ -342,7 +522,7 @@ describe('useMoexChart', () => {
 
   it('should update symbol search modal state', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     // Act
     act(() => {
@@ -355,7 +535,7 @@ describe('useMoexChart', () => {
 
   it('should open symbol search modal from chart preset callback', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     // Act
     act(() => {
@@ -366,82 +546,172 @@ describe('useMoexChart', () => {
     expect(hookResult?.isSymbolSearchOpen).toBe(true);
   });
 
-  it('should normalize and change main symbol', () => {
+  it('should update chart when external symbol info changes', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    const { rerender } = render(<TestComponent />);
 
     // Act
-    act(() => {
-      hookResult?.setMainSymbol('  MOEX:GAZP  ');
-    });
+    rerender(
+      <TestComponent
+        symbolInfo={{
+          symbolId: 'MOEX:GAZP',
+          symbol: 'GAZP',
+          symbolName: 'Газпром',
+        }}
+      />,
+    );
 
     // Assert
     expect(mockSetSymbol).toHaveBeenCalledTimes(1);
-    expect(mockSetSymbol).toHaveBeenCalledWith('MOEX:GAZP');
+    expect(mockSetSymbol).toHaveBeenCalledWith({
+      symbolId: 'MOEX:GAZP',
+      symbol: 'GAZP',
+      symbolName: 'Газпром',
+    });
   });
 
-  it('should not change main symbol when value is empty', () => {
+  it('should update chart when only symbol name changes', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    const { rerender } = render(<TestComponent />);
 
     // Act
-    act(() => {
-      hookResult?.setMainSymbol('');
-      hookResult?.setMainSymbol('   ');
-    });
+    rerender(
+      <TestComponent
+        symbolInfo={{
+          symbolId: 'MOEX:SBER',
+          symbol: 'SBER',
+          symbolName: 'Сбербанк ПАО',
+        }}
+      />,
+    );
 
     // Assert
-    expect(mockSetSymbol).not.toHaveBeenCalled();
+    expect(mockSetSymbol).toHaveBeenCalledTimes(1);
+    expect(mockSetSymbol).toHaveBeenCalledWith({
+      symbolId: 'MOEX:SBER',
+      symbol: 'SBER',
+      symbolName: 'Сбербанк ПАО',
+    });
   });
 
-  it('should not change main symbol when it is already selected', () => {
+  it('should update chart when only symbol changes', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    const { rerender } = render(<TestComponent />);
 
     // Act
-    act(() => {
-      hookResult?.setMainSymbol('MOEX:SBER');
+    rerender(
+      <TestComponent
+        symbolInfo={{
+          symbolId: 'MOEX:SBER',
+          symbol: 'SBERP',
+          symbolName: 'Сбербанк',
+        }}
+      />,
+    );
+
+    // Assert
+    expect(mockSetSymbol).toHaveBeenCalledTimes(1);
+    expect(mockSetSymbol).toHaveBeenCalledWith({
+      symbolId: 'MOEX:SBER',
+      symbol: 'SBERP',
+      symbolName: 'Сбербанк',
     });
+  });
+
+  it('should delegate missing symbol name fallback to moex chart', () => {
+    // Arrange
+    const { rerender } = render(<TestComponent />);
+
+    // Act
+    rerender(
+      <TestComponent
+        symbolInfo={{
+          symbolId: 'MOEX:SBER',
+          symbol: 'SBER',
+        }}
+      />,
+    );
 
     // Assert
-    expect(mockSetSymbol).not.toHaveBeenCalled();
+    expect(mockSetSymbol).toHaveBeenCalledTimes(1);
+    expect(mockSetSymbol).toHaveBeenCalledWith({
+      symbolId: 'MOEX:SBER',
+      symbol: 'SBER',
+      symbolName: undefined,
+    });
   });
 
-  it('should update chart when external symbol changes', () => {
+  it('should delegate missing symbol fallback to moex chart', () => {
     // Arrange
-    const { rerender } = render(<TestComponent symbol="MOEX:SBER" />);
+    const { rerender } = render(<TestComponent />);
 
     // Act
-    rerender(<TestComponent symbol="MOEX:GAZP" />);
+    rerender(
+      <TestComponent
+        symbolInfo={{
+          symbolId: 'MOEX:SBER',
+          symbolName: 'Сбербанк',
+        }}
+      />,
+    );
 
     // Assert
     expect(mockSetSymbol).toHaveBeenCalledTimes(1);
-    expect(mockSetSymbol).toHaveBeenCalledWith('MOEX:GAZP');
+    expect(mockSetSymbol).toHaveBeenCalledWith({
+      symbolId: 'MOEX:SBER',
+      symbol: undefined,
+      symbolName: 'Сбербанк',
+    });
+  });
+
+  it('should not update chart when symbol info is unchanged', () => {
+    // Arrange
+    const { rerender } = render(<TestComponent />);
+
+    // Act
+    rerender(<TestComponent />);
+
+    // Assert
+    expect(mockSetSymbol).not.toHaveBeenCalled();
   });
 
   it('should not recreate chart when external symbol changes', () => {
     // Arrange
-    const { rerender } = render(<TestComponent symbol="MOEX:SBER" />);
+    const { rerender } = render(<TestComponent />);
 
     // Act
-    rerender(<TestComponent symbol="MOEX:GAZP" />);
+    rerender(
+      <TestComponent
+        symbolInfo={{
+          symbolId: 'MOEX:GAZP',
+          symbol: 'GAZP',
+          symbolName: 'Газпром',
+        }}
+      />,
+    );
 
     // Assert
     expect(mockMoexChart).toHaveBeenCalledTimes(1);
   });
 
-  it('should apply saved snapshot with symbol selected from search modal', () => {
+  it('should apply saved snapshot with externally selected symbol', () => {
     // Arrange
     mockMoexChartState = {
-      tf: Timeframes['5m'],
+      timeframe: Timeframes['5m'],
       savedData: JSON.stringify(mockSnapshot),
     };
 
-    render(<TestComponent symbol="MOEX:SBER" />);
+    const { rerender } = render(<TestComponent />);
 
-    act(() => {
-      hookResult?.setMainSymbol('MOEX:GAZP');
-    });
+    rerender(
+      <TestComponent
+        symbolInfo={{
+          symbolId: 'MOEX:GAZP',
+          symbol: 'GAZP',
+          symbolName: 'Газпром',
+        }}
+      />,
+    );
 
     // Act
     act(() => {
@@ -454,16 +724,53 @@ describe('useMoexChart', () => {
       charts: [
         {
           ...mockSnapshot.charts[0],
-          symbol: 'MOEX:GAZP',
+          symbolId: 'MOEX:GAZP',
+          symbol: 'GAZP',
+          symbolName: 'Газпром',
           timeframe: Timeframes['5m'],
         },
       ],
     });
   });
 
+  it('should initialize indicative instrument with symbol info', () => {
+    // Arrange
+    const indicativeData: ChartIndicativeData = {
+      id: 1,
+      title: 'Indicative instrument',
+      secId: 'INAV',
+      instrumentName: 'Индикатив',
+      settlement: 'Расчётный',
+      firmName: 'Тестовая фирма',
+      key: '2xOFZ:INAV',
+    };
+
+    // Act
+    render(
+      <TestComponent
+        symbolInfo={{
+          symbolId: '2xOFZ:INAV',
+          symbol: 'INAV',
+          symbolName: 'Индикатив Расчётный',
+        }}
+        indicativeData={indicativeData}
+      />,
+    );
+
+    // Assert
+    expect(mockGetDataSource).toHaveBeenCalledWith(indicativeData, expect.any(Function));
+    expect(lastMoexChartConfig?.snapshot.charts[0]).toEqual(
+      expect.objectContaining({
+        symbolId: '2xOFZ:INAV',
+        symbol: 'INAV',
+        symbolName: 'Индикатив Расчётный',
+      }),
+    );
+  });
+
   it('should pass realtime params to data source provider', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     const getSymbols = jest.fn(() => ['MOEX:SBER']);
     const getTimeframe = jest.fn(() => Timeframes['1m']);
@@ -478,13 +785,12 @@ describe('useMoexChart', () => {
       getTimeframe,
       update,
     });
-
     expect(unsubscribe).toBe(mockRealtimeUnsubscribe);
   });
 
   it('should update timeframe from data source callback', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     const timeframeChangeCallback = mockGetDataSource.mock.calls[0]?.[1] as TimeframeChangeCallback;
 
@@ -500,18 +806,18 @@ describe('useMoexChart', () => {
 
     const mockState: MockPropertiesState = {
       moexChartState: {
-        tf: Timeframes['1m'],
+        timeframe: Timeframes['1m'],
       },
     };
 
     updateCallback(mockState);
 
-    expect(mockState.moexChartState?.tf).toBe(Timeframes['5m']);
+    expect(mockState.moexChartState?.timeframe).toBe(Timeframes['5m']);
   });
 
   it('should not update timeframe when it is the same as current timeframe', () => {
     // Arrange
-    render(<TestComponent symbol="MOEX:SBER" />);
+    render(<TestComponent />);
 
     const timeframeChangeCallback = mockGetDataSource.mock.calls[0]?.[1] as TimeframeChangeCallback;
 
@@ -526,7 +832,7 @@ describe('useMoexChart', () => {
 
   it('should destroy chart on unmount', () => {
     // Arrange
-    const { unmount } = render(<TestComponent symbol="MOEX:SBER" />);
+    const { unmount } = render(<TestComponent />);
 
     // Act
     unmount();
diff --git a/src/widgets/Chart/components/MoexChart/MoexChart.tsx b/src/widgets/Chart/components/MoexChart/MoexChart.tsx
index 86e7bb981..a1dc9291d 100644
--- a/src/widgets/Chart/components/MoexChart/MoexChart.tsx
+++ b/src/widgets/Chart/components/MoexChart/MoexChart.tsx
@@ -1,23 +1,24 @@
 import React from 'react';
 
-import { Contract } from '@modules/contracts';
 import { SymbolSearchModal } from '@widgets/Chart/components/MoexChart/components/SymbolSearchModal';
 
-import { ChartIndicativeData } from '../../types';
-
 import { CompareModal } from './components/CompareModal';
 import { useMoexChart } from './hooks';
 
+import type { ChartIndicativeData, SelectedInstrument } from '../../types';
+
+import type { SymbolInfoInput } from 'moex-chart';
+
 import 'moex-chart/dist/styles.css';
 
-type TRProps = {
-  fullName: string;
-  indicativeData?: ChartIndicativeData | undefined;
+interface TRProps {
+  symbolInfo: SymbolInfoInput;
+  indicativeData?: ChartIndicativeData;
   widgetId: number;
-  addInstrumentFromModal: (instruments: Pick<Contract, 'issKey'>[]) => void;
-};
+  addInstrumentFromModal: (instruments: SelectedInstrument[]) => void;
+}
 
-export default React.memo(({ fullName, indicativeData, widgetId, addInstrumentFromModal }: TRProps) => {
+function MoexChart({ symbolInfo, indicativeData, widgetId, addInstrumentFromModal }: TRProps) {
   const {
     containerRef,
     isCompareOpen,
@@ -25,15 +26,13 @@ export default React.memo(({ fullName, indicativeData, widgetId, addInstrumentFr
     compareManagerRef,
     setIsCompareOpen,
     setIsSymbolSearchOpen,
-    setMainSymbol,
   } = useMoexChart({
+    symbolInfo,
     indicativeData,
-    symbol: fullName,
   });
 
-  const handleSymbolChange = (symbol: string): void => {
-    addInstrumentFromModal([{ issKey: symbol }]);
-    setMainSymbol(symbol);
+  const handleSymbolChange = (instrument: SelectedInstrument): void => {
+    addInstrumentFromModal([instrument]);
   };
 
   return (
@@ -48,7 +47,6 @@ export default React.memo(({ fullName, indicativeData, widgetId, addInstrumentFr
 
       {isCompareOpen && (
         <CompareModal
-          onClose={() => setIsCompareOpen(false)}
           compareManager={compareManagerRef}
           widgetId={widgetId}
           isOpen={isCompareOpen}
@@ -66,4 +64,6 @@ export default React.memo(({ fullName, indicativeData, widgetId, addInstrumentFr
       )}
     </div>
   );
-});
+}
+
+export default React.memo(MoexChart);
diff --git a/src/widgets/Chart/components/MoexChart/components/CompareModal.tsx b/src/widgets/Chart/components/MoexChart/components/CompareModal.tsx
index 092f6df1a..2ffba9e87 100644
--- a/src/widgets/Chart/components/MoexChart/components/CompareModal.tsx
+++ b/src/widgets/Chart/components/MoexChart/components/CompareModal.tsx
@@ -1,21 +1,20 @@
-import { __CompareManager__, CompareMode } from 'moex-chart';
-import React, { MutableRefObject, useEffect, useState } from 'react';
+import { CompareMode } from 'moex-chart';
+import React, { useEffect, useState } from 'react';
 
 import { InstrumentSearch } from '@components/InstrumentSearch';
+import { Contract } from '@modules/contracts';
 
-export const CompareModal = ({
-  compareManager,
-  widgetId,
-  isOpen,
-  setOpen,
-}: {
-  onClose: () => void;
+import type { __CompareManager__ } from 'moex-chart';
+import type { MutableRefObject } from 'react';
+
+interface CompareModalProps {
   widgetId: number;
   compareManager: MutableRefObject<__CompareManager__ | null>;
-
   isOpen: boolean;
   setOpen: (isOpen: boolean) => void;
-}) => {
+}
+
+export const CompareModal = ({ compareManager, widgetId, isOpen, setOpen }: CompareModalProps): React.ReactElement => {
   const [isNewScaleDisabled, setIsNewScaleDisabled] = useState(false);
 
   useEffect(() => {
@@ -33,16 +32,32 @@ export const CompareModal = ({
     return () => subscription.unsubscribe();
   }, [compareManager, isOpen]);
 
-  const handlePercent = (symbol: string) => {
-    compareManager?.current?.setSymbolMode('Line', symbol, CompareMode.Percentage);
+  const setCompareMode = (instrument: Contract, mode: CompareMode): void => {
+    if (!instrument.issKey) {
+      return;
+    }
+
+    compareManager.current?.setSymbolMode(
+      'Line',
+      {
+        symbolId: instrument.issKey,
+        symbol: instrument.symbol,
+        symbolName: instrument.displayName,
+      },
+      mode,
+    );
+  };
+
+  const handlePercent = (instrument: Contract): void => {
+    setCompareMode(instrument, CompareMode.Percentage);
   };
 
-  const handleNewScale = (symbol: string) => {
-    compareManager?.current?.setSymbolMode('Line', symbol, CompareMode.NewScale);
+  const handleNewScale = (instrument: Contract): void => {
+    setCompareMode(instrument, CompareMode.NewScale);
   };
 
-  const handleNewPanel = (symbol: string) => {
-    compareManager?.current?.setSymbolMode('Line', symbol, CompareMode.NewPane);
+  const handleNewPanel = (instrument: Contract): void => {
+    setCompareMode(instrument, CompareMode.NewPane);
   };
 
   return (
diff --git a/src/widgets/Chart/components/MoexChart/components/SymbolSearchModal.tsx b/src/widgets/Chart/components/MoexChart/components/SymbolSearchModal.tsx
index efb08af16..bed8d94db 100644
--- a/src/widgets/Chart/components/MoexChart/components/SymbolSearchModal.tsx
+++ b/src/widgets/Chart/components/MoexChart/components/SymbolSearchModal.tsx
@@ -3,23 +3,29 @@ import React from 'react';
 import { InstrumentSearch } from '@components/InstrumentSearch';
 
 import type { Contract } from '@modules/contracts';
+import type { SelectedInstrument } from '@widgets/Chart/types';
 
 interface SymbolSearchModalProps {
   widgetId: number;
   isOpen: boolean;
   setOpen: (isOpen: boolean) => void;
-  onSymbolChange: (symbol: string) => void;
+  onSymbolChange: (instrument: SelectedInstrument) => void;
 }
 
 export const SymbolSearchModal = ({ widgetId, isOpen, setOpen, onSymbolChange }: SymbolSearchModalProps) => {
-  const handleAddInstruments = (instruments: Contract[]) => {
-    const symbol = instruments[0]?.issKey;
+  const handleAddInstruments = (instruments: Contract[]): void => {
+    const selectedInstrument = instruments[0];
 
-    if (!symbol) {
+    if (!selectedInstrument?.issKey) {
       return;
     }
 
-    onSymbolChange(symbol);
+    onSymbolChange({
+      issKey: selectedInstrument.issKey,
+      symbol: selectedInstrument.symbol,
+      displayName: selectedInstrument.displayName,
+    });
+
     setOpen(false);
   };
 
diff --git a/src/widgets/Chart/components/MoexChart/constants.ts b/src/widgets/Chart/components/MoexChart/constants.ts
index 288036c50..24a0dcab9 100644
--- a/src/widgets/Chart/components/MoexChart/constants.ts
+++ b/src/widgets/Chart/components/MoexChart/constants.ts
@@ -1,11 +1,11 @@
 import { DateFormat, IndicatorsIds, Locale, Timeframes } from 'moex-chart';
 
-import type { ChartCollectionPreset, IMoexChart, MoexChartSnapshot } from 'moex-chart';
+import type { ChartCollectionPreset, IMoexChart, MoexChartSnapshotInput } from 'moex-chart';
 
 type ChartCollectionPresetConfig = Omit<ChartCollectionPreset, 'getDataSource' | 'startRealtime'>;
-type ChartSnapshotItemConfig = Omit<MoexChartSnapshot['charts'][number], 'symbol'>;
-type MoexChartSnapshotConfig = Omit<MoexChartSnapshot, 'charts'> & {
-  charts: ChartSnapshotItemConfig[];
+type ChartSnapshotConfig = Omit<MoexChartSnapshotInput['charts'][number], 'symbolId'>;
+type MoexChartSnapshotConfig = Omit<MoexChartSnapshotInput, 'charts'> & {
+  charts: ChartSnapshotConfig[];
 };
 
 type MoexChartConfig = Omit<IMoexChart, 'container' | 'chartCollectionPreset' | 'snapshot'> & {
diff --git a/src/widgets/Chart/components/MoexChart/dataSourceProvide.ts b/src/widgets/Chart/components/MoexChart/dataSourceProvide.ts
index 2bc6851d5..929f2b851 100644
--- a/src/widgets/Chart/components/MoexChart/dataSourceProvide.ts
+++ b/src/widgets/Chart/components/MoexChart/dataSourceProvide.ts
@@ -8,6 +8,7 @@ import {
   moexChartTimeConverter,
   moexChartToIssTimeframe,
 } from '@utils/chartToReqTimeConverter';
+import { DEFAULT_SYMBOL } from '@widgets/Chart/const';
 
 import { requestBars, requestRealtimeBars } from '../../requestBars';
 import { ChartIndicativeData } from '../../types';
@@ -17,9 +18,14 @@ import type { Candle, Timeframes } from 'moex-chart';
 
 dayjs.extend(duration);
 
-function normalizeSymbol(symbolRaw?: string): string {
-  return String(symbolRaw ?? '')
-    .trim();
+function getRequestSymbol(symbolRaw?: string): string | undefined {
+  const symbol = String(symbolRaw ?? '').trim();
+
+  if (!symbol || symbol === DEFAULT_SYMBOL) {
+    return undefined;
+  }
+
+  return symbol;
 }
 
 const collectCandleGroup = ({
@@ -181,7 +187,13 @@ class DataSourceProvider {
 
   public getDataSource =
     (indicativeData?: ChartIndicativeData, cb?: (timeframe: Timeframes) => void) =>
-    async (timeframe: Timeframes, symbol: string, until?: Candle) => {
+    async (timeframe: Timeframes, symbolId: string, until?: Candle) => {
+      const symbol = getRequestSymbol(symbolId);
+
+      if (!symbol) {
+        return null;
+      }
+
       cb?.(timeframe);
 
       const interval = moexChartTimeConverter(timeframe);
@@ -226,7 +238,7 @@ class DataSourceProvider {
   }: {
     getSymbols: () => string[];
     getTimeframe: () => Timeframes;
-    update: (symbol: string, candle: Candle) => void;
+    update: (symbolId: string, candle: Candle) => void;
     periodMs?: number;
     indicativeData?: ChartIndicativeData;
   }): () => void {
@@ -236,11 +248,11 @@ class DataSourceProvider {
 
     this.realtimeTimer = setInterval(() => {
       const timeframe = getTimeframe();
-      const symbols = getSymbols();
+      const symbolIds = getSymbols();
 
       Promise.all(
-        symbols.map(async (value) => {
-          const symbol = normalizeSymbol(value);
+        symbolIds.map(async (symbolId) => {
+          const symbol = getRequestSymbol(symbolId);
 
           if (!symbol) {
             return;
diff --git a/src/widgets/Chart/components/MoexChart/hooks/useMoexchart.ts b/src/widgets/Chart/components/MoexChart/hooks/useMoexchart.ts
index 58c504900..37641688f 100644
--- a/src/widgets/Chart/components/MoexChart/hooks/useMoexchart.ts
+++ b/src/widgets/Chart/components/MoexChart/hooks/useMoexchart.ts
@@ -1,24 +1,25 @@
 import { MoexChart, Timeframes } from 'moex-chart';
 
-import { useEffect, useRef, useState } from 'react';
+import { useCallback, useEffect, useRef, useState } from 'react';
 
 import { useChangeProperties, useSelectProperties } from '@modules/widgetProperties';
+import { WidgetProperties } from '@widgets/Chart/properties/types';
 import { ChartIndicativeData } from '@widgets/Chart/types';
 
-import { WidgetProperties } from '../../../properties/types';
-
 import { MOEX_CHART_CONFIG } from '../constants';
 import { DataSourceProvider } from '../dataSourceProvide';
 
-import type { __CompareManager__, IMoexChart } from 'moex-chart';
+import type { __CompareManager__, IMoexChart, SymbolInfoInput } from 'moex-chart';
 
 interface TUseMoexChartProps {
-  symbol: string;
+  symbolInfo: SymbolInfoInput;
   indicativeData?: ChartIndicativeData;
 }
 
-export const useMoexChart = ({ symbol, indicativeData }: TUseMoexChartProps) => {
-  const moexChartState = useSelectProperties((wProps: Partial<WidgetProperties>) => wProps.moexChartState);
+export const useMoexChart = ({ symbolInfo, indicativeData }: TUseMoexChartProps) => {
+  const moexChartState = useSelectProperties(
+    (widgetProperties: Partial<WidgetProperties>) => widgetProperties.moexChartState,
+  );
 
   const { updateProperties } = useChangeProperties<WidgetProperties>();
 
@@ -27,32 +28,23 @@ export const useMoexChart = ({ symbol, indicativeData }: TUseMoexChartProps) =>
 
   const containerRef = useRef<HTMLDivElement | null>(null);
   const chartRef = useRef<MoexChart | null>(null);
-  const compareManagerRef = useRef<null | __CompareManager__>(null);
-  const currentSymbolRef = useRef(symbol);
+  const compareManagerRef = useRef<__CompareManager__ | null>(null);
+  const currentSymbolInfoRef = useRef<SymbolInfoInput>(symbolInfo);
 
   const timeframeRef = useRef<Timeframes | undefined>(moexChartState?.timeframe);
   const savedDataRef = useRef<string | undefined>(moexChartState?.savedData);
-  const updateTimeframeRef = useRef<((tf: Timeframes) => void) | null>(null);
+  const updateTimeframeRef = useRef<((timeframe: Timeframes) => void) | null>(null);
 
   useEffect(() => {
-    if (!symbol || currentSymbolRef.current === symbol) {
-      return;
-    }
-
-    currentSymbolRef.current = symbol;
-    chartRef.current?.setSymbol(symbol);
-  }, [symbol]);
-
-  const setMainSymbol = (nextSymbol: string) => {
-    const normalizedSymbol = nextSymbol.trim();
+    const nextSymbolInfo: SymbolInfoInput = {
+      symbolId: symbolInfo.symbolId,
+      symbol: symbolInfo.symbol,
+      symbolName: symbolInfo.symbolName,
+    };
 
-    if (!normalizedSymbol || currentSymbolRef.current === normalizedSymbol) {
-      return;
-    }
-
-    currentSymbolRef.current = normalizedSymbol;
-    chartRef.current?.setSymbol(normalizedSymbol);
-  };
+    currentSymbolInfoRef.current = nextSymbolInfo;
+    chartRef.current?.setSymbol(nextSymbolInfo);
+  }, [symbolInfo.symbolId, symbolInfo.symbol, symbolInfo.symbolName]);
 
   useEffect(() => {
     timeframeRef.current = moexChartState?.timeframe;
@@ -74,7 +66,7 @@ export const useMoexChart = ({ symbol, indicativeData }: TUseMoexChartProps) =>
     });
   };
 
-  const saveSnapshot = () => {
+  const saveSnapshot = useCallback((): void => {
     const snapshot = chartRef.current?.getSnapshot();
 
     if (!snapshot) {
@@ -89,13 +81,15 @@ export const useMoexChart = ({ symbol, indicativeData }: TUseMoexChartProps) =>
           ...pane,
           indicators: pane.indicators.map((indicator) => {
             const compareSeries = indicator.config?.series[0];
+            const compareSymbolInfo = indicator.config?.symbolInfo;
 
             return {
               ...indicator,
               dataSource: undefined, // dataSource пока не среиализуем
               config:
-                indicator.indicatorType === undefined && indicator.config?.label && compareSeries
+                indicator.indicatorType === undefined && compareSymbolInfo && indicator.config?.label && compareSeries
                   ? {
+                      symbolInfo: compareSymbolInfo,
                       label: indicator.config.label,
                       newPane: indicator.config.newPane,
                       series: [
@@ -123,9 +117,21 @@ export const useMoexChart = ({ symbol, indicativeData }: TUseMoexChartProps) =>
         savedData,
       };
     });
-  };
-
-  const applySnapshot = () => {
+  }, [updateProperties]);
+
+  const getSnapshotWithCurrentSymbol = (
+    snapshot: typeof MOEX_CHART_CONFIG.snapshot | IMoexChart['snapshot'],
+    timeframe: Timeframes,
+  ): IMoexChart['snapshot'] => ({
+    ...snapshot,
+    charts: snapshot.charts.map((chartSnapshot) => ({
+      ...chartSnapshot,
+      ...currentSymbolInfoRef.current,
+      timeframe,
+    })),
+  });
+
+  const applySnapshot = (): void => {
     if (!savedDataRef.current || !chartRef.current) {
       return;
     }
@@ -133,14 +139,7 @@ export const useMoexChart = ({ symbol, indicativeData }: TUseMoexChartProps) =>
     const savedSnapshot = JSON.parse(savedDataRef.current) as IMoexChart['snapshot'];
     const timeframe = timeframeRef.current || Timeframes['1m'];
 
-    chartRef.current.setSnapshot({
-      ...savedSnapshot,
-      charts: savedSnapshot.charts.map((chartSnapshot) => ({
-        ...chartSnapshot,
-        symbol: currentSymbolRef.current,
-        timeframe,
-      })),
-    });
+    chartRef.current.setSnapshot(getSnapshotWithCurrentSymbol(savedSnapshot, timeframe));
 
     compareManagerRef.current = chartRef.current.getCompareManager();
   };
@@ -161,20 +160,13 @@ export const useMoexChart = ({ symbol, indicativeData }: TUseMoexChartProps) =>
     const chart = new MoexChart({
       ...MOEX_CHART_CONFIG,
       container,
-      snapshot: {
-        ...savedSnapshot,
-        charts: savedSnapshot.charts.map((chartSnapshot) => ({
-          ...chartSnapshot,
-          symbol: currentSymbolRef.current,
-          timeframe,
-        })),
-      },
+      snapshot: getSnapshotWithCurrentSymbol(savedSnapshot, timeframe),
       chartCollectionPreset: {
         ...MOEX_CHART_CONFIG.chartCollectionPreset,
         openCompareModal: () => setIsCompareOpen(true),
         openSymbolSearchModal: () => setIsSymbolSearchOpen(true),
-        getDataSource: dataProvider.getDataSource(indicativeData, (tf) => {
-          updateTimeframeRef.current?.(tf);
+        getDataSource: dataProvider.getDataSource(indicativeData, (nextTimeframe) => {
+          updateTimeframeRef.current?.(nextTimeframe);
         }),
         startRealtime: (getSymbols, getTimeframe, update) =>
           dataProvider.startRealtime({
@@ -208,7 +200,6 @@ export const useMoexChart = ({ symbol, indicativeData }: TUseMoexChartProps) =>
     compareManagerRef,
     setIsCompareOpen,
     setIsSymbolSearchOpen,
-    setMainSymbol,
     saveSnapshot,
     applySnapshot,
     hasSavedSnapshot: Boolean(moexChartState?.savedData),
diff --git a/src/widgets/Chart/hooks/useChartComponentFacade.tsx b/src/widgets/Chart/hooks/useChartComponentFacade.tsx
index ece1436b8..4892f3aa7 100644
--- a/src/widgets/Chart/hooks/useChartComponentFacade.tsx
+++ b/src/widgets/Chart/hooks/useChartComponentFacade.tsx
@@ -13,20 +13,20 @@ import { DEFAULT_SYMBOL } from '../const';
 import { useChartPublicContext } from './useChartPublicContext';
 
 import type { WidgetProperties } from '../properties/types';
-import type { ChartContainerProps } from '../types';
+import type { ChartContainerProps, SelectedInstrument } from '../types';
 
-import type { Contract } from '@modules/contracts';
+import type { SymbolInfoInput } from 'moex-chart';
 import type { Dispatch, SetStateAction } from 'react';
 import type { Widget } from 'types/Widgets';
 
 interface UseChartComponentFacadeReturn {
   dropDownOpen: boolean;
   setDropdownOpen: Dispatch<SetStateAction<boolean>>;
-  currentInstrument: string;
+  currentSymbolInfo: SymbolInfoInput;
   isWidgetHeaderContextMenuOpen: boolean;
   setIsWidgetHeaderContextMenuOpen: Dispatch<SetStateAction<boolean>>;
-  onDropInstruments: (val: string, withUpdate?: boolean) => void;
-  addInstrumentFromModal: (instruments: Pick<Contract, 'issKey'>[]) => void;
+  onDropInstrument: (symbolId: string, withUpdate?: boolean) => void;
+  addInstrumentFromModal: (instruments: SelectedInstrument[]) => void;
   isOver: boolean;
 }
 
@@ -48,12 +48,13 @@ export default function useChartComponentFacade(props: ChartContainerProps): Use
     (state) => state.widgets.widgets.find(({ id }) => id === widgetId)?.widgetContentProps,
   ) as WidgetProperties | undefined;
 
-  const initialInstrument = widgetProperties?.chartState?.savedInstrument ?? DEFAULT_SYMBOL;
+  const currentSymbolInfoRef = useRef<SymbolInfoInput>({
+    symbolId: widgetProperties?.chartState?.savedInstrument ?? DEFAULT_SYMBOL,
+    symbol: widgetProperties?.chartState?.savedSymbol,
+    symbolName: widgetProperties?.chartState?.savedSymbolName,
+  });
 
-  // TODO временно реф из-за непредсказуемого изменения если используется useState,
-  // нужен рефакторинг и вернуть обратно useState
-  const currentInstrumentRef = useRef(initialInstrument);
-  const [currentInstrument, setCurrentInstrument] = useState(initialInstrument);
+  const [currentSymbolInfo, setCurrentSymbolInfo] = useState<SymbolInfoInput>(currentSymbolInfoRef.current);
 
   const { triggerRelatedWidgetsToUpdate, getMasterInstrumentFromPublicContext } = useWidgetsBind({
     widgetId,
@@ -66,8 +67,8 @@ export default function useChartComponentFacade(props: ChartContainerProps): Use
   }, [triggerRelatedWidgetsToUpdate]);
 
   const saveContentProps = useCallback(
-    (val: SaveContentPropsOptions): void => {
-      const { withUpdate, cleanIndicativeData, ...chartStateVal } = val;
+    (value: SaveContentPropsOptions): void => {
+      const { withUpdate, cleanIndicativeData, ...chartStateValue } = value;
 
       const oldProps = (getState().widgets.widgets.find(({ id }) => id === widgetId) as Widget | undefined)
         ?.widgetContentProps;
@@ -83,7 +84,7 @@ export default function useChartComponentFacade(props: ChartContainerProps): Use
           widgetContentProps: {
             chartState: {
               ...oldProps.chartState,
-              ...chartStateVal,
+              ...chartStateValue,
             },
             // при смене инструмента очищаем индикативные данные, переданные из виджета Индикативные котировки
             indicativeData: cleanIndicativeData ? undefined : oldProps.indicativeData,
@@ -95,60 +96,85 @@ export default function useChartComponentFacade(props: ChartContainerProps): Use
   );
 
   const onInstrumentChange = useCallback(
-    (newVal: string, withUpdate?: boolean, unbind = true): void => {
-      if (!newVal) {
+    (symbolInfo: SymbolInfoInput, withUpdate?: boolean, unbind = true): void => {
+      const symbolId = symbolInfo.symbolId.trim();
+
+      if (!symbolId) {
         return;
       }
 
       setIsWidgetHeaderContextMenuOpen(false);
 
-      if (currentInstrumentRef.current === newVal) {
+      const currentValue = currentSymbolInfoRef.current;
+      const symbolIdChanged = currentValue.symbolId !== symbolId;
+
+      const symbol = symbolInfo.symbol?.trim() || (symbolIdChanged ? undefined : currentValue.symbol);
+      const symbolName = symbolInfo.symbolName?.trim() || (symbolIdChanged ? undefined : currentValue.symbolName);
+
+      const nextSymbolInfo: SymbolInfoInput = {
+        symbolId,
+        symbol,
+        symbolName,
+      };
+
+      const symbolChanged = currentValue.symbol !== symbol;
+      const symbolNameChanged = currentValue.symbolName !== symbolName;
+
+      if (!symbolIdChanged && !symbolChanged && !symbolNameChanged) {
         return;
       }
 
-      currentInstrumentRef.current = newVal;
-      setCurrentInstrument(newVal);
+      currentSymbolInfoRef.current = nextSymbolInfo;
+      setCurrentSymbolInfo(nextSymbolInfo);
 
-      if (unbind) {
+      if (symbolIdChanged && unbind) {
         dispatch(unbindWidgets({ widgetId }));
       }
 
       // при смене инструмента очищаем индикативные данные виджета график
       // т.к. логика для графика индикатива построена на наличии в widgetContentProps данных indicativeData
       saveContentProps({
-        savedInstrument: newVal,
+        savedInstrument: symbolId,
+        savedSymbol: symbol,
+        savedSymbolName: symbolName,
         withUpdate,
-        cleanIndicativeData: true,
+        cleanIndicativeData: symbolIdChanged,
       });
 
-      triggerRelatedWidgetsToUpdateRef.current(newVal);
+      if (symbolIdChanged) {
+        triggerRelatedWidgetsToUpdateRef.current(symbolId);
+      }
     },
     [dispatch, saveContentProps, widgetId],
   );
 
   const addInstrumentFromModal = useCallback(
-    (instruments: Pick<Contract, 'issKey'>[]) => {
-      const issKey = instruments[0]?.issKey;
+    (instruments: SelectedInstrument[]): void => {
+      const instrument = instruments[0];
 
-      if (!issKey) {
+      if (!instrument?.issKey) {
         return;
       }
 
-      onInstrumentChange(issKey);
+      onInstrumentChange({
+        symbolId: instrument.issKey,
+        symbol: instrument.symbol,
+        symbolName: instrument.displayName,
+      });
     },
     [onInstrumentChange],
   );
 
   const onInstrumentChangeFromBind = useCallback(
-    (instrumentId: string) => {
-      onInstrumentChange(instrumentId, true, false);
+    (symbolInfo: SymbolInfoInput): void => {
+      onInstrumentChange(symbolInfo, true, false);
     },
     [onInstrumentChange],
   );
 
-  const onDropInstruments = useCallback(
-    (val: string, withUpdate?: boolean): void => {
-      onInstrumentChange(val, withUpdate);
+  const onDropInstrument = useCallback(
+    (symbolId: string, withUpdate?: boolean): void => {
+      onInstrumentChange({ symbolId }, withUpdate);
     },
     [onInstrumentChange],
   );
@@ -160,7 +186,7 @@ export default function useChartComponentFacade(props: ChartContainerProps): Use
   });
 
   useEffect(() => {
-    triggerRelatedWidgetsToUpdateRef.current(currentInstrumentRef.current);
+    triggerRelatedWidgetsToUpdateRef.current(currentSymbolInfoRef.current.symbolId);
   }, []);
 
   useEffect(() => {
@@ -169,10 +195,10 @@ export default function useChartComponentFacade(props: ChartContainerProps): Use
         messageType: CORPACTIONS_OPEN_EXESTED_WIDGET_EVENT,
       },
       (message) => {
-        const issKey = (message as Record<number, string>)[widgetId];
+        const symbolId = (message as Record<number, string>)[widgetId];
 
-        if (issKey) {
-          addInstrumentFromModal([{ issKey }]);
+        if (symbolId) {
+          onInstrumentChange({ symbolId });
         }
       },
     );
@@ -194,15 +220,15 @@ export default function useChartComponentFacade(props: ChartContainerProps): Use
       unsubscribe();
       unsubscribeHighlighter();
     };
-  }, [addInstrumentFromModal, widgetId]);
+  }, [onInstrumentChange, widgetId]);
 
   return {
     dropDownOpen,
     setDropdownOpen,
-    currentInstrument,
+    currentSymbolInfo,
     isWidgetHeaderContextMenuOpen,
     setIsWidgetHeaderContextMenuOpen,
-    onDropInstruments,
+    onDropInstrument,
     addInstrumentFromModal,
     isOver,
   };
diff --git a/src/widgets/Chart/hooks/useChartPublicContext.ts b/src/widgets/Chart/hooks/useChartPublicContext.ts
index 0edfadcae..fe6184965 100644
--- a/src/widgets/Chart/hooks/useChartPublicContext.ts
+++ b/src/widgets/Chart/hooks/useChartPublicContext.ts
@@ -7,8 +7,10 @@ import { filterByUniqIssKey } from '@utils/filterByUniqIssKey';
 import { DEFAULT_SYMBOL } from '@widgets/Chart/const';
 import { Widget } from 'types/Widgets';
 
+import type { SymbolInfoInput } from 'moex-chart';
+
 interface UseChartPublicContextArg {
-  setCurrInstrument: (instrumentId: string) => void;
+  setCurrInstrument: (symbolInfo: SymbolInfoInput) => void;
   widgetId: Widget['id'];
   getMasterInstrumentFromPublicContext: () => string | number | null | undefined;
 }
@@ -27,29 +29,45 @@ export function useChartPublicContext({
 
   const { contracts } = useContracts();
 
-  const instruments = useMemo(() => [...(contracts && filterByUniqIssKey(contracts, ['issKey']))], [contracts]);
+  const instruments = useMemo(() => (contracts ? filterByUniqIssKey(contracts, ['issKey']) : []), [contracts]);
 
   const issKey = useMemo(() => {
     const fieldValue = getMasterInstrumentFromPublicContext();
-    const instrKey = instruments.find((item) => item.issKey === fieldValue)?.issKey;
-    return instrKey;
+
+    return instruments.find((instrument) => instrument.issKey === fieldValue)?.issKey;
     // eslint-disable-next-line react-hooks/exhaustive-deps -- Посмотреть этот момент.
   }, [publicContext, instruments]);
 
   useEffect(() => {
     const fieldValue = getMasterInstrumentFromPublicContext();
+
     if (!fieldValue && widget?.master) {
-      setCurrInstrument(DEFAULT_SYMBOL);
+      const defaultInstrument = instruments.find((instrument) => instrument.issKey === DEFAULT_SYMBOL);
+
+      setCurrInstrument({
+        symbolId: DEFAULT_SYMBOL,
+        symbol: defaultInstrument?.symbol ?? undefined,
+        symbolName: defaultInstrument?.displayName ?? undefined,
+      });
+
       return;
     }
-    const instrKey = instruments.find((item) => item.issKey === fieldValue)?.issKey;
-    if (instrKey) {
-      setCurrInstrument(instrKey);
+
+    const instrument = instruments.find((item) => item.issKey === fieldValue);
+
+    if (!instrument?.issKey) {
+      return;
     }
+
+    setCurrInstrument({
+      symbolId: instrument.issKey,
+      symbol: instrument.symbol ?? undefined,
+      symbolName: instrument.displayName ?? undefined,
+    });
     // eslint-disable-next-line react-hooks/exhaustive-deps -- Посмотреть этот момент.
   }, [publicContext, instruments, widget?.externalProperties, setCurrInstrument]);
 
   return {
-    issKey: issKey ?? undefined,
+    issKey,
   };
 }
diff --git a/src/widgets/Chart/index.tsx b/src/widgets/Chart/index.tsx
index e38b1552a..7121ad997 100644
--- a/src/widgets/Chart/index.tsx
+++ b/src/widgets/Chart/index.tsx
@@ -21,10 +21,10 @@ export const Chart: FC<ChartContainerProps> = function (props): JSX.Element {
   const {
     dropDownOpen,
     setDropdownOpen,
-    currentInstrument,
+    currentSymbolInfo,
     setIsWidgetHeaderContextMenuOpen,
     isWidgetHeaderContextMenuOpen,
-    onDropInstruments,
+    onDropInstrument,
     addInstrumentFromModal,
     isOver,
   } = useChartComponentFacade(props);
@@ -33,7 +33,7 @@ export const Chart: FC<ChartContainerProps> = function (props): JSX.Element {
     и делаем апдейт на бэк, чтобы сохранить изменения
     при обновлении страницы */
   const { dropRef } = useDropInstrument((dragData) => {
-    onDropInstruments(dragData.properties.issKey, true);
+    onDropInstrument(dragData.properties.issKey, true);
   });
 
   const [isOpenEmptyAction, setIsOpenEmptyAction] = useState<boolean>(false);
@@ -45,11 +45,17 @@ export const Chart: FC<ChartContainerProps> = function (props): JSX.Element {
 
   // TODO: Зависит от сеток
   const { isDraggedOver } = useContext(WidgetEnvContext);
-  const contractsInstrumentName = useWidgetHeaderName(currentInstrument);
+  const contractsInstrumentName = useWidgetHeaderName(currentSymbolInfo.symbolId);
 
-  const instrumentName = indicativeData
-    ? `${indicativeData.instrumentName} ${indicativeData.settlement} - ${indicativeData.firmName}`
-    : contractsInstrumentName;
+  const symbolInfo = indicativeData
+    ? {
+        symbolId: indicativeData.key,
+        symbol: indicativeData.secId,
+        symbolName: `${indicativeData.instrumentName} ${indicativeData.settlement} - ${indicativeData.firmName}`,
+      }
+    : currentSymbolInfo;
+
+  const instrumentName = symbolInfo.symbolName || contractsInstrumentName || symbolInfo.symbol || symbolInfo.symbolId;
 
   return (
     <DNDWrapper
@@ -78,7 +84,7 @@ export const Chart: FC<ChartContainerProps> = function (props): JSX.Element {
           }}
         >
           <MoexChart
-            fullName={currentInstrument}
+            symbolInfo={symbolInfo}
             indicativeData={indicativeData}
             widgetId={props.widgetId}
             addInstrumentFromModal={addInstrumentFromModal}
diff --git a/src/widgets/Chart/properties/types.ts b/src/widgets/Chart/properties/types.ts
index afdbdf473..720bcec6f 100644
--- a/src/widgets/Chart/properties/types.ts
+++ b/src/widgets/Chart/properties/types.ts
@@ -1,12 +1,15 @@
-import { Contract } from '@modules/contracts/types';
+import type { ChartIndicativeData } from '../types';
 
-import { ChartIndicativeData } from '../types';
+import type { Contract } from '@modules/contracts/types';
 
+import type { WidgetProperties as BaseWidgetProperties } from '@modules/widgetProperties/types';
 import type { Timeframes } from 'moex-chart';
 
-export type WidgetProperties = {
+export interface WidgetProperties extends BaseWidgetProperties {
   chartState: {
     savedInstrument: Contract['issKey'] | null;
+    savedSymbol?: Contract['symbol'];
+    savedSymbolName?: Contract['displayName'];
     interval: string;
     savedData?: string;
   };
@@ -15,4 +18,4 @@ export type WidgetProperties = {
     timeframe: Timeframes;
     savedData?: string;
   };
-};
+}
diff --git a/src/widgets/Chart/types.ts b/src/widgets/Chart/types.ts
index bbc0155d5..2a4a5aae3 100644
--- a/src/widgets/Chart/types.ts
+++ b/src/widgets/Chart/types.ts
@@ -1,12 +1,22 @@
-import type { WidgetContentBasicProps } from 'types/Widgets';
 import type { WidgetProperties } from './properties/types';
 
-export type ChartIndicativeData = {
+import type { Contract } from '@modules/contracts';
+
+import type { WidgetProperties as BaseWidgetProperties } from '@modules/widgetProperties/types';
+import type { WidgetContentBasicProps } from 'types/Widgets';
+
+export interface ChartIndicativeData extends BaseWidgetProperties {
   secId: string;
   instrumentName: string;
   settlement: string;
   firmName: string;
   key: string;
-};
+}
+
+export interface SelectedInstrument {
+  issKey: Contract['issKey'];
+  displayName: Contract['displayName'];
+  symbol: Contract['symbol'];
+}
 
 export type ChartContainerProps = WidgetContentBasicProps<WidgetProperties>;