chore(trading): store all chart state (#5627)
Co-authored-by: bwallacee <ben@vega.xyz>
This commit is contained in:
parent
f22a3bc2d2
commit
0660eda334
@ -25,12 +25,12 @@ export const ChartContainer = ({ marketId }: { marketId: string }) => {
|
|||||||
overlays,
|
overlays,
|
||||||
studies,
|
studies,
|
||||||
studySizes,
|
studySizes,
|
||||||
tradingViewStudies,
|
|
||||||
setInterval,
|
setInterval,
|
||||||
setStudies,
|
setStudies,
|
||||||
setStudySizes,
|
setStudySizes,
|
||||||
setOverlays,
|
setOverlays,
|
||||||
setTradingViewStudies,
|
state,
|
||||||
|
setState,
|
||||||
} = useChartSettings();
|
} = useChartSettings();
|
||||||
|
|
||||||
const pennantChart = (
|
const pennantChart = (
|
||||||
@ -64,13 +64,13 @@ export const ChartContainer = ({ marketId }: { marketId: string }) => {
|
|||||||
libraryHash={CHARTING_LIBRARY_HASH}
|
libraryHash={CHARTING_LIBRARY_HASH}
|
||||||
marketId={marketId}
|
marketId={marketId}
|
||||||
interval={toTradingViewResolution(interval)}
|
interval={toTradingViewResolution(interval)}
|
||||||
studies={tradingViewStudies}
|
|
||||||
onIntervalChange={(newInterval) => {
|
onIntervalChange={(newInterval) => {
|
||||||
setInterval(fromTradingViewResolution(newInterval));
|
setInterval(fromTradingViewResolution(newInterval));
|
||||||
}}
|
}}
|
||||||
onAutoSaveNeeded={(data: { studies: string[] }) => {
|
onAutoSaveNeeded={(data) => {
|
||||||
setTradingViewStudies(data.studies);
|
setState(data);
|
||||||
}}
|
}}
|
||||||
|
state={state}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -27,11 +27,11 @@ describe('ChartMenu', () => {
|
|||||||
|
|
||||||
render(<ChartMenu />);
|
render(<ChartMenu />);
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'Vega chart' }));
|
await userEvent.click(screen.getByTestId('chartlib-toggle-button'));
|
||||||
expect(useChartSettingsStore.getState().chartlib).toEqual('pennant');
|
|
||||||
|
|
||||||
await userEvent.click(screen.getByRole('button', { name: 'TradingView' }));
|
|
||||||
expect(useChartSettingsStore.getState().chartlib).toEqual('tradingview');
|
expect(useChartSettingsStore.getState().chartlib).toEqual('tradingview');
|
||||||
|
|
||||||
|
await userEvent.click(screen.getByTestId('chartlib-toggle-button'));
|
||||||
|
expect(useChartSettingsStore.getState().chartlib).toEqual('pennant');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('tradingview', () => {
|
describe('tradingview', () => {
|
||||||
|
@ -68,6 +68,7 @@ export const ChartMenu = () => {
|
|||||||
setChartlib(isPennant ? 'tradingview' : 'pennant');
|
setChartlib(isPennant ? 'tradingview' : 'pennant');
|
||||||
}}
|
}}
|
||||||
size="extra-small"
|
size="extra-small"
|
||||||
|
testId="chartlib-toggle-button"
|
||||||
>
|
>
|
||||||
{isPennant ? 'TradingView' : t('Vega chart')}
|
{isPennant ? 'TradingView' : t('Vega chart')}
|
||||||
</TradingButton>
|
</TradingButton>
|
||||||
|
@ -9,6 +9,7 @@ type StudySizes = { [S in Study]?: number };
|
|||||||
export type Chartlib = 'pennant' | 'tradingview';
|
export type Chartlib = 'pennant' | 'tradingview';
|
||||||
|
|
||||||
interface StoredSettings {
|
interface StoredSettings {
|
||||||
|
state: object | undefined; // Don't see a better type provided from TradingView type definitions
|
||||||
chartlib: Chartlib;
|
chartlib: Chartlib;
|
||||||
// For interval we use the enum from @vegaprotocol/types, this is to make mapping between different
|
// For interval we use the enum from @vegaprotocol/types, this is to make mapping between different
|
||||||
// chart types easier and more consistent
|
// chart types easier and more consistent
|
||||||
@ -17,7 +18,6 @@ interface StoredSettings {
|
|||||||
overlays: Overlay[];
|
overlays: Overlay[];
|
||||||
studies: Study[];
|
studies: Study[];
|
||||||
studySizes: StudySizes;
|
studySizes: StudySizes;
|
||||||
tradingViewStudies: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const STUDY_SIZE = 90;
|
export const STUDY_SIZE = 90;
|
||||||
@ -30,13 +30,13 @@ const STUDY_ORDER: Study[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export const DEFAULT_CHART_SETTINGS = {
|
export const DEFAULT_CHART_SETTINGS = {
|
||||||
chartlib: 'tradingview' as const,
|
state: undefined,
|
||||||
|
chartlib: 'pennant' as const,
|
||||||
interval: Interval.INTERVAL_I15M,
|
interval: Interval.INTERVAL_I15M,
|
||||||
type: ChartType.CANDLE,
|
type: ChartType.CANDLE,
|
||||||
overlays: [Overlay.MOVING_AVERAGE],
|
overlays: [Overlay.MOVING_AVERAGE],
|
||||||
studies: [Study.MACD, Study.VOLUME],
|
studies: [Study.MACD, Study.VOLUME],
|
||||||
studySizes: {},
|
studySizes: {},
|
||||||
tradingViewStudies: ['Volume'],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useChartSettingsStore = create<
|
export const useChartSettingsStore = create<
|
||||||
@ -47,7 +47,7 @@ export const useChartSettingsStore = create<
|
|||||||
setStudies: (studies?: Study[]) => void;
|
setStudies: (studies?: Study[]) => void;
|
||||||
setStudySizes: (sizes: number[]) => void;
|
setStudySizes: (sizes: number[]) => void;
|
||||||
setChartlib: (lib: Chartlib) => void;
|
setChartlib: (lib: Chartlib) => void;
|
||||||
setTradingViewStudies: (studies: string[]) => void;
|
setState: (state: object) => void;
|
||||||
}
|
}
|
||||||
>()(
|
>()(
|
||||||
persist(
|
persist(
|
||||||
@ -95,10 +95,8 @@ export const useChartSettingsStore = create<
|
|||||||
state.chartlib = lib;
|
state.chartlib = lib;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setTradingViewStudies: (studies: string[]) => {
|
setState: (state) => {
|
||||||
set((state) => {
|
set({ state });
|
||||||
state.tradingViewStudies = studies;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
@ -147,13 +145,13 @@ export const useChartSettings = () => {
|
|||||||
overlays,
|
overlays,
|
||||||
studies,
|
studies,
|
||||||
studySizes,
|
studySizes,
|
||||||
tradingViewStudies: settings.tradingViewStudies,
|
|
||||||
setInterval: settings.setInterval,
|
setInterval: settings.setInterval,
|
||||||
setType: settings.setType,
|
setType: settings.setType,
|
||||||
setStudies: settings.setStudies,
|
setStudies: settings.setStudies,
|
||||||
setOverlays: settings.setOverlays,
|
setOverlays: settings.setOverlays,
|
||||||
setStudySizes: settings.setStudySizes,
|
setStudySizes: settings.setStudySizes,
|
||||||
setChartlib: settings.setChartlib,
|
setChartlib: settings.setChartlib,
|
||||||
setTradingViewStudies: settings.setTradingViewStudies,
|
state: settings.state,
|
||||||
|
setState: settings.setState,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
"extends": ["plugin:@nx/react", "../../.eslintrc.json"],
|
||||||
"ignorePatterns": ["!**/*", "__generated__"],
|
"ignorePatterns": ["!**/*", "__generated__", "charting-library.d.ts"],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||||
|
19258
libs/trading-view/src/charting-library.d.ts
vendored
Normal file
19258
libs/trading-view/src/charting-library.d.ts
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -9,17 +9,17 @@ export const TradingViewContainer = ({
|
|||||||
libraryHash,
|
libraryHash,
|
||||||
marketId,
|
marketId,
|
||||||
interval,
|
interval,
|
||||||
studies,
|
|
||||||
onIntervalChange,
|
onIntervalChange,
|
||||||
onAutoSaveNeeded,
|
onAutoSaveNeeded,
|
||||||
|
state,
|
||||||
}: {
|
}: {
|
||||||
libraryPath: string;
|
libraryPath: string;
|
||||||
libraryHash: string;
|
libraryHash: string;
|
||||||
marketId: string;
|
marketId: string;
|
||||||
interval: ResolutionString;
|
interval: ResolutionString;
|
||||||
studies: string[];
|
|
||||||
onIntervalChange: (interval: string) => void;
|
onIntervalChange: (interval: string) => void;
|
||||||
onAutoSaveNeeded: OnAutoSaveNeededCallback;
|
onAutoSaveNeeded: OnAutoSaveNeededCallback;
|
||||||
|
state: object | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
const t = useT();
|
const t = useT();
|
||||||
const scriptState = useScript(
|
const scriptState = useScript(
|
||||||
@ -48,9 +48,9 @@ export const TradingViewContainer = ({
|
|||||||
libraryPath={libraryPath}
|
libraryPath={libraryPath}
|
||||||
marketId={marketId}
|
marketId={marketId}
|
||||||
interval={interval}
|
interval={interval}
|
||||||
studies={studies}
|
|
||||||
onIntervalChange={onIntervalChange}
|
onIntervalChange={onIntervalChange}
|
||||||
onAutoSaveNeeded={onAutoSaveNeeded}
|
onAutoSaveNeeded={onAutoSaveNeeded}
|
||||||
|
state={state}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,127 +1,167 @@
|
|||||||
import { useEffect, useRef } from 'react';
|
import { useEffect, useRef } from 'react';
|
||||||
import {
|
import {
|
||||||
|
usePrevious,
|
||||||
useScreenDimensions,
|
useScreenDimensions,
|
||||||
useThemeSwitcher,
|
useThemeSwitcher,
|
||||||
} from '@vegaprotocol/react-helpers';
|
} from '@vegaprotocol/react-helpers';
|
||||||
import { useLanguage } from './use-t';
|
import { useLanguage } from './use-t';
|
||||||
import { useDatafeed } from './use-datafeed';
|
import { useDatafeed } from './use-datafeed';
|
||||||
import { type ResolutionString } from './constants';
|
import { type ResolutionString } from './constants';
|
||||||
|
import {
|
||||||
|
type ChartingLibraryFeatureset,
|
||||||
|
type LanguageCode,
|
||||||
|
type ChartingLibraryWidgetOptions,
|
||||||
|
type IChartingLibraryWidget,
|
||||||
|
type ChartPropertiesOverrides,
|
||||||
|
type ResolutionString as TVResolutionString,
|
||||||
|
} from '../charting-library';
|
||||||
|
|
||||||
export type OnAutoSaveNeededCallback = (data: { studies: string[] }) => void;
|
const noop = () => {};
|
||||||
|
|
||||||
|
export type OnAutoSaveNeededCallback = (data: object) => void;
|
||||||
|
|
||||||
export const TradingView = ({
|
export const TradingView = ({
|
||||||
marketId,
|
marketId,
|
||||||
libraryPath,
|
libraryPath,
|
||||||
interval,
|
interval,
|
||||||
studies,
|
|
||||||
onIntervalChange,
|
onIntervalChange,
|
||||||
onAutoSaveNeeded,
|
onAutoSaveNeeded,
|
||||||
|
state,
|
||||||
}: {
|
}: {
|
||||||
marketId: string;
|
marketId: string;
|
||||||
libraryPath: string;
|
libraryPath: string;
|
||||||
interval: ResolutionString;
|
interval: ResolutionString;
|
||||||
studies: string[];
|
|
||||||
onIntervalChange: (interval: string) => void;
|
onIntervalChange: (interval: string) => void;
|
||||||
onAutoSaveNeeded: OnAutoSaveNeededCallback;
|
onAutoSaveNeeded: OnAutoSaveNeededCallback;
|
||||||
|
state: object | undefined;
|
||||||
}) => {
|
}) => {
|
||||||
const { isMobile } = useScreenDimensions();
|
const { isMobile } = useScreenDimensions();
|
||||||
const { theme } = useThemeSwitcher();
|
const { theme } = useThemeSwitcher();
|
||||||
const language = useLanguage();
|
const language = useLanguage();
|
||||||
const chartContainerRef =
|
const chartContainerRef = useRef<HTMLDivElement>(null);
|
||||||
useRef<HTMLDivElement>() as React.MutableRefObject<HTMLInputElement>;
|
const widgetRef = useRef<IChartingLibraryWidget>();
|
||||||
// Cant get types as charting_library is externally loaded
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
const widgetRef = useRef<any>();
|
|
||||||
|
|
||||||
const datafeed = useDatafeed();
|
const datafeed = useDatafeed();
|
||||||
|
|
||||||
useEffect(
|
const prevMarketId = usePrevious(marketId);
|
||||||
() => {
|
const prevTheme = usePrevious(theme);
|
||||||
const disableOnSmallScreens = isMobile ? ['left_toolbar'] : [];
|
|
||||||
|
|
||||||
const overrides = getOverrides(theme);
|
|
||||||
|
|
||||||
const widgetOptions = {
|
|
||||||
symbol: marketId,
|
|
||||||
datafeed,
|
|
||||||
interval: interval,
|
|
||||||
container: chartContainerRef.current,
|
|
||||||
library_path: libraryPath,
|
|
||||||
custom_css_url: 'vega_styles.css',
|
|
||||||
// Trading view accepts just 'en' rather than 'en-US' which is what react-i18next provides
|
|
||||||
// https://www.tradingview.com/charting-library-docs/latest/core_concepts/Localization?_highlight=language#supported-languages
|
|
||||||
locale: language.split('-')[0],
|
|
||||||
enabled_features: ['tick_resolution'],
|
|
||||||
disabled_features: [
|
|
||||||
'header_symbol_search',
|
|
||||||
'header_compare',
|
|
||||||
'show_object_tree',
|
|
||||||
'timeframes_toolbar',
|
|
||||||
...disableOnSmallScreens,
|
|
||||||
],
|
|
||||||
fullscreen: false,
|
|
||||||
autosize: true,
|
|
||||||
theme,
|
|
||||||
overrides,
|
|
||||||
loading_screen: {
|
|
||||||
backgroundColor: overrides['paneProperties.background'],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// @ts-ignore parent component loads TradingView onto window obj
|
|
||||||
widgetRef.current = new window.TradingView.widget(widgetOptions);
|
|
||||||
|
|
||||||
widgetRef.current.onChartReady(() => {
|
|
||||||
widgetRef.current.applyOverrides(getOverrides(theme));
|
|
||||||
|
|
||||||
widgetRef.current.subscribe('onAutoSaveNeeded', () => {
|
|
||||||
const studies = widgetRef.current
|
|
||||||
.activeChart()
|
|
||||||
.getAllStudies()
|
|
||||||
.map((s: { id: string; name: string }) => s.name);
|
|
||||||
onAutoSaveNeeded({ studies });
|
|
||||||
});
|
|
||||||
|
|
||||||
const activeChart = widgetRef.current.activeChart();
|
|
||||||
|
|
||||||
// Show volume study by default, second bool arg adds it as a overlay on top of the chart
|
|
||||||
studies.forEach((study) => {
|
|
||||||
activeChart.createStudy(study);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Subscribe to interval changes so it can be persisted in chart settings
|
|
||||||
activeChart.onIntervalChanged().subscribe(null, onIntervalChange);
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
if (!widgetRef.current) return;
|
|
||||||
widgetRef.current.remove();
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
// No theme in deps to avoid full chart reload when the theme changes
|
|
||||||
// Instead the theme is changed programmatically in a separate useEffect
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
[datafeed, marketId, language, libraryPath, isMobile]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Update the trading view theme every time the app theme updates, done separately
|
|
||||||
// to avoid full chart reload
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!widgetRef.current || !widgetRef.current._ready) return;
|
// Widget already created
|
||||||
|
if (widgetRef.current !== undefined) {
|
||||||
|
// Update the symbol if changed
|
||||||
|
if (marketId !== prevMarketId) {
|
||||||
|
widgetRef.current.setSymbol(
|
||||||
|
marketId,
|
||||||
|
(interval ? interval : '15') as TVResolutionString,
|
||||||
|
noop
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Calling changeTheme will reset the default dark/light background to the TV default
|
// Update theme theme if changed
|
||||||
// so we need to re-apply the pane bg override. A promise is also required
|
if (theme !== prevTheme) {
|
||||||
// https://github.com/tradingview/charting_library/issues/6546#issuecomment-1139517908
|
widgetRef.current.changeTheme(theme).then(() => {
|
||||||
widgetRef.current.changeTheme(theme).then(() => {
|
if (!widgetRef.current) return;
|
||||||
widgetRef.current.applyOverrides(getOverrides(theme));
|
widgetRef.current.applyOverrides(getOverrides(theme));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!chartContainerRef.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create widget
|
||||||
|
const overrides = getOverrides(theme);
|
||||||
|
|
||||||
|
const disabledOnSmallScreens: ChartingLibraryFeatureset[] = isMobile
|
||||||
|
? ['left_toolbar']
|
||||||
|
: [];
|
||||||
|
const disabledFeatures: ChartingLibraryFeatureset[] = [
|
||||||
|
'header_symbol_search',
|
||||||
|
'header_compare',
|
||||||
|
'show_object_tree',
|
||||||
|
'timeframes_toolbar',
|
||||||
|
...disabledOnSmallScreens,
|
||||||
|
];
|
||||||
|
|
||||||
|
const widgetOptions: ChartingLibraryWidgetOptions = {
|
||||||
|
symbol: marketId,
|
||||||
|
datafeed,
|
||||||
|
interval: interval as TVResolutionString,
|
||||||
|
container: chartContainerRef.current,
|
||||||
|
library_path: libraryPath,
|
||||||
|
custom_css_url: 'vega_styles.css',
|
||||||
|
// Trading view accepts just 'en' rather than 'en-US' which is what react-i18next provides
|
||||||
|
// https://www.tradingview.com/charting-library-docs/latest/core_concepts/Localization?_highlight=language#supported-languages
|
||||||
|
locale: language.split('-')[0] as LanguageCode,
|
||||||
|
enabled_features: ['tick_resolution'],
|
||||||
|
disabled_features: disabledFeatures,
|
||||||
|
fullscreen: false,
|
||||||
|
autosize: true,
|
||||||
|
theme,
|
||||||
|
overrides,
|
||||||
|
loading_screen: {
|
||||||
|
backgroundColor: overrides['paneProperties.background'],
|
||||||
|
},
|
||||||
|
auto_save_delay: 1,
|
||||||
|
saved_data: state,
|
||||||
|
};
|
||||||
|
|
||||||
|
widgetRef.current = new window.TradingView.widget(widgetOptions);
|
||||||
|
|
||||||
|
widgetRef.current.onChartReady(() => {
|
||||||
|
if (!widgetRef.current) return;
|
||||||
|
|
||||||
|
const activeChart = widgetRef.current.activeChart();
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
// If chart has loaded with no state, create a volume study
|
||||||
|
activeChart.createStudy('Volume');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe to interval changes so it can be persisted in chart settings
|
||||||
|
activeChart.onIntervalChanged().subscribe(null, onIntervalChange);
|
||||||
});
|
});
|
||||||
}, [theme]);
|
|
||||||
|
widgetRef.current.subscribe('onAutoSaveNeeded', () => {
|
||||||
|
if (!widgetRef.current) return;
|
||||||
|
|
||||||
|
widgetRef.current.save((newState) => {
|
||||||
|
onAutoSaveNeeded(newState);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, [
|
||||||
|
state,
|
||||||
|
datafeed,
|
||||||
|
interval,
|
||||||
|
prevTheme,
|
||||||
|
prevMarketId,
|
||||||
|
marketId,
|
||||||
|
theme,
|
||||||
|
language,
|
||||||
|
libraryPath,
|
||||||
|
isMobile,
|
||||||
|
onAutoSaveNeeded,
|
||||||
|
onIntervalChange,
|
||||||
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (!widgetRef.current) return;
|
||||||
|
widgetRef.current.remove();
|
||||||
|
widgetRef.current = undefined;
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return <div ref={chartContainerRef} className="w-full h-full" />;
|
return <div ref={chartContainerRef} className="w-full h-full" />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getOverrides = (theme: 'dark' | 'light') => {
|
const getOverrides = (
|
||||||
|
theme: 'dark' | 'light'
|
||||||
|
): Partial<ChartPropertiesOverrides> => {
|
||||||
return {
|
return {
|
||||||
// colors set here, trading view lets the user set a color
|
// colors set here, trading view lets the user set a color
|
||||||
'paneProperties.background': theme === 'dark' ? '#05060C' : '#fff',
|
'paneProperties.background': theme === 'dark' ? '#05060C' : '#fff',
|
||||||
|
@ -2,15 +2,6 @@ import { useEffect, useMemo, useRef } from 'react';
|
|||||||
import compact from 'lodash/compact';
|
import compact from 'lodash/compact';
|
||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
import { type Subscription } from 'zen-observable-ts';
|
import { type Subscription } from 'zen-observable-ts';
|
||||||
/*
|
|
||||||
* TODO: figure out how we can get the chart types
|
|
||||||
import {
|
|
||||||
type LibrarySymbolInfo,
|
|
||||||
type IBasicDataFeed,
|
|
||||||
type ResolutionString,
|
|
||||||
type SeriesFormat,
|
|
||||||
} from '../charting_library/charting_library';
|
|
||||||
*/
|
|
||||||
import {
|
import {
|
||||||
GetBarsDocument,
|
GetBarsDocument,
|
||||||
LastBarDocument,
|
LastBarDocument,
|
||||||
@ -27,6 +18,12 @@ import {
|
|||||||
type SymbolQueryVariables,
|
type SymbolQueryVariables,
|
||||||
} from './__generated__/Symbol';
|
} from './__generated__/Symbol';
|
||||||
import { getMarketExpiryDate, toBigNum } from '@vegaprotocol/utils';
|
import { getMarketExpiryDate, toBigNum } from '@vegaprotocol/utils';
|
||||||
|
import {
|
||||||
|
type IBasicDataFeed,
|
||||||
|
type DatafeedConfiguration,
|
||||||
|
type LibrarySymbolInfo,
|
||||||
|
type ResolutionString,
|
||||||
|
} from '../charting-library';
|
||||||
|
|
||||||
const EXCHANGE = 'VEGA';
|
const EXCHANGE = 'VEGA';
|
||||||
|
|
||||||
@ -42,12 +39,8 @@ const resolutionMap: Record<string, Interval> = {
|
|||||||
|
|
||||||
const supportedResolutions = Object.keys(resolutionMap);
|
const supportedResolutions = Object.keys(resolutionMap);
|
||||||
|
|
||||||
const configurationData = {
|
const configurationData: DatafeedConfiguration = {
|
||||||
// only showing Vega ofc
|
|
||||||
exchanges: [EXCHANGE],
|
|
||||||
|
|
||||||
// Represents the resolutions for bars supported by your datafeed
|
// Represents the resolutions for bars supported by your datafeed
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
supported_resolutions: supportedResolutions as ResolutionString[],
|
supported_resolutions: supportedResolutions as ResolutionString[],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@ -57,9 +50,7 @@ export const useDatafeed = () => {
|
|||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
|
|
||||||
const datafeed = useMemo(() => {
|
const datafeed = useMemo(() => {
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
const feed: IBasicDataFeed = {
|
const feed: IBasicDataFeed = {
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
onReady: (callback) => {
|
onReady: (callback) => {
|
||||||
setTimeout(() => callback(configurationData));
|
setTimeout(() => callback(configurationData));
|
||||||
},
|
},
|
||||||
@ -69,11 +60,8 @@ export const useDatafeed = () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
resolveSymbol: async (
|
resolveSymbol: async (
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
marketId,
|
marketId,
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
onSymbolResolvedCallback,
|
onSymbolResolvedCallback,
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
onResolveErrorCallback
|
onResolveErrorCallback
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
@ -110,9 +98,8 @@ export const useDatafeed = () => {
|
|||||||
const expirationDate = getMarketExpiryDate(instrument.metadata.tags);
|
const expirationDate = getMarketExpiryDate(instrument.metadata.tags);
|
||||||
const expirationTimestamp = expirationDate
|
const expirationTimestamp = expirationDate
|
||||||
? Math.floor(expirationDate.getTime() / 1000)
|
? Math.floor(expirationDate.getTime() / 1000)
|
||||||
: null;
|
: undefined;
|
||||||
|
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
const symbolInfo: LibrarySymbolInfo = {
|
const symbolInfo: LibrarySymbolInfo = {
|
||||||
ticker: market.id, // use ticker as our unique identifier so that code/name can be used for name/description
|
ticker: market.id, // use ticker as our unique identifier so that code/name can be used for name/description
|
||||||
name: instrument.code,
|
name: instrument.code,
|
||||||
@ -120,10 +107,9 @@ export const useDatafeed = () => {
|
|||||||
description: instrument.name,
|
description: instrument.name,
|
||||||
listed_exchange: EXCHANGE,
|
listed_exchange: EXCHANGE,
|
||||||
expired: productType === 'Perpetual' ? false : true,
|
expired: productType === 'Perpetual' ? false : true,
|
||||||
expirationDate: expirationTimestamp,
|
expiration_date: expirationTimestamp,
|
||||||
|
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
format: 'price',
|
||||||
format: 'price' as SeriesFormat,
|
|
||||||
type,
|
type,
|
||||||
session: '24x7',
|
session: '24x7',
|
||||||
timezone: 'Etc/UTC',
|
timezone: 'Etc/UTC',
|
||||||
@ -151,15 +137,10 @@ export const useDatafeed = () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getBars: async (
|
getBars: async (
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
symbolInfo,
|
symbolInfo,
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
resolution,
|
resolution,
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
periodParams,
|
periodParams,
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
onHistoryCallback,
|
onHistoryCallback,
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
onErrorCallback
|
onErrorCallback
|
||||||
) => {
|
) => {
|
||||||
if (!symbolInfo.ticker) {
|
if (!symbolInfo.ticker) {
|
||||||
@ -211,13 +192,9 @@ export const useDatafeed = () => {
|
|||||||
},
|
},
|
||||||
|
|
||||||
subscribeBars: (
|
subscribeBars: (
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
symbolInfo,
|
symbolInfo,
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
resolution,
|
resolution,
|
||||||
// @ts-ignore cant import types as chartin_library is external
|
|
||||||
onTick
|
onTick
|
||||||
|
|
||||||
// subscriberUID, // chart will subscribe and unsbuscribe when the parent market of the page changes so we don't need to use subscriberUID as of now
|
// subscriberUID, // chart will subscribe and unsbuscribe when the parent market of the page changes so we don't need to use subscriberUID as of now
|
||||||
) => {
|
) => {
|
||||||
if (!symbolInfo.ticker) {
|
if (!symbolInfo.ticker) {
|
||||||
|
@ -16,6 +16,7 @@ type TradingButtonProps = {
|
|||||||
subLabel?: ReactNode;
|
subLabel?: ReactNode;
|
||||||
fill?: boolean;
|
fill?: boolean;
|
||||||
minimal?: boolean;
|
minimal?: boolean;
|
||||||
|
testId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getClassName = (
|
const getClassName = (
|
||||||
@ -120,6 +121,7 @@ export const TradingButton = forwardRef<
|
|||||||
className,
|
className,
|
||||||
subLabel,
|
subLabel,
|
||||||
fill,
|
fill,
|
||||||
|
testId,
|
||||||
...props
|
...props
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
@ -132,6 +134,7 @@ export const TradingButton = forwardRef<
|
|||||||
{ size, subLabel, intent, fill, minimal },
|
{ size, subLabel, intent, fill, minimal },
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
data-testid={testId}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<Content icon={icon} subLabel={subLabel} children={children} />
|
<Content icon={icon} subLabel={subLabel} children={children} />
|
||||||
|
Loading…
Reference in New Issue
Block a user