diff --git a/apps/trading/client-pages/market/trade-grid.tsx b/apps/trading/client-pages/market/trade-grid.tsx
index c10b4831b..cf96266f8 100644
--- a/apps/trading/client-pages/market/trade-grid.tsx
+++ b/apps/trading/client-pages/market/trade-grid.tsx
@@ -192,7 +192,7 @@ const MainGrid = memo(
);
- }
+ },
);
MainGrid.displayName = 'MainGrid';
@@ -200,7 +200,7 @@ export const TradeGrid = ({ market, pinnedAsset }: TradeGridProps) => {
const featureFlags = useFeatureFlags((state) => state.flags);
const wrapperClasses = classNames(
'h-full grid',
- 'grid-rows-[min-content_1fr]'
+ 'grid-rows-[min-content_1fr]',
);
return (
diff --git a/apps/trading/client-pages/market/trade-views.tsx b/apps/trading/client-pages/market/trade-views.tsx
index 959e2797f..33e537270 100644
--- a/apps/trading/client-pages/market/trade-views.tsx
+++ b/apps/trading/client-pages/market/trade-views.tsx
@@ -1,8 +1,4 @@
import { DepthChartContainer } from '@vegaprotocol/market-depth';
-import {
- CandlesChartContainer,
- CandlesMenu,
-} from '@vegaprotocol/candles-chart';
import { Filter, OpenOrdersMenu } from '@vegaprotocol/orders';
import { TradesContainer } from '../../components/trades-container';
import { OrderbookContainer } from '../../components/orderbook-container';
@@ -16,13 +12,14 @@ import { OrdersContainer } from '../../components/orders-container';
import { StopOrdersContainer } from '../../components/stop-orders-container';
import { AccountsMenu } from '../../components/accounts-menu';
import { PositionsMenu } from '../../components/positions-menu';
+import { ChartContainer, ChartMenu } from '../../components/chart-container';
export type TradingView = keyof typeof TradingViews;
export const TradingViews = {
candles: {
- component: CandlesChartContainer,
- menu: CandlesMenu,
+ component: ChartContainer,
+ menu: ChartMenu,
},
depth: {
component: DepthChartContainer,
diff --git a/libs/candles-chart/src/lib/candles-menu.spec.tsx b/apps/trading/components/chart-container/chart-container.spec.tsx
similarity index 88%
rename from libs/candles-chart/src/lib/candles-menu.spec.tsx
rename to apps/trading/components/chart-container/chart-container.spec.tsx
index a2964685a..3bbfafb4d 100644
--- a/libs/candles-chart/src/lib/candles-menu.spec.tsx
+++ b/apps/trading/components/chart-container/chart-container.spec.tsx
@@ -1,18 +1,18 @@
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { CandlesMenu } from './candles-menu';
+import { ChartMenu } from './chart-container';
import {
useCandlesChartSettingsStore,
DEFAULT_CHART_SETTINGS,
} from './use-candles-chart-settings';
import { Overlay, Study, overlayLabels, studyLabels } from 'pennant';
-describe('CandlesMenu', () => {
+describe('ChartMenu', () => {
const openDropdown = async () => {
await userEvent.click(
screen.getByRole('button', {
name: 'Indicators',
- })
+ }),
);
};
@@ -22,7 +22,7 @@ describe('CandlesMenu', () => {
});
it.each(Object.values(Overlay))('can set %s overlay', async (overlay) => {
- render();
+ render();
await openDropdown();
@@ -35,12 +35,12 @@ describe('CandlesMenu', () => {
expect(screen.getByText(overlayLabels[overlay as Overlay])).toHaveAttribute(
'data-state',
- 'checked'
+ 'checked',
);
});
it.each(Object.values(Study))('can set %s study', async (study) => {
- render();
+ render();
await openDropdown();
@@ -53,33 +53,33 @@ describe('CandlesMenu', () => {
expect(screen.getByText(studyLabels[study as Study])).toHaveAttribute(
'data-state',
- 'checked'
+ 'checked',
);
});
it('should render with the correct default studies and overlays', async () => {
useCandlesChartSettingsStore.setState(DEFAULT_CHART_SETTINGS);
- render();
+ render();
await userEvent.click(
screen.getByRole('button', {
name: 'Indicators',
- })
+ }),
);
const menu = within(await screen.findByRole('menu'));
expect(menu.getByText(studyLabels.volume)).toHaveAttribute(
'data-state',
- 'checked'
+ 'checked',
);
expect(menu.getByText(studyLabels.macd)).toHaveAttribute(
'data-state',
- 'checked'
+ 'checked',
);
expect(menu.getByText(overlayLabels.movingAverage)).toHaveAttribute(
'data-state',
- 'checked'
+ 'checked',
);
});
});
diff --git a/apps/trading/components/chart-container/chart-container.tsx b/apps/trading/components/chart-container/chart-container.tsx
new file mode 100644
index 000000000..b6528dae7
--- /dev/null
+++ b/apps/trading/components/chart-container/chart-container.tsx
@@ -0,0 +1,254 @@
+import { CandlesChartContainer } from '@vegaprotocol/candles-chart';
+import {
+ ChartType,
+ Interval,
+ Overlay,
+ Study,
+ chartTypeLabels,
+ intervalLabels,
+ overlayLabels,
+ studyLabels,
+} from 'pennant';
+import {
+ TradingButton,
+ TradingDropdown,
+ TradingDropdownCheckboxItem,
+ TradingDropdownContent,
+ TradingDropdownItemIndicator,
+ TradingDropdownRadioGroup,
+ TradingDropdownRadioItem,
+ TradingDropdownTrigger,
+ Icon,
+} from '@vegaprotocol/ui-toolkit';
+import { type IconName } from '@blueprintjs/icons';
+import { IconNames } from '@blueprintjs/icons';
+import { useT } from '../../lib/use-t';
+
+import {
+ useCandlesChartSettings,
+ STUDY_SIZE,
+} from './use-candles-chart-settings';
+import { TradingViewContainer } from '../../components/trading-view-container';
+
+const chartTypeIcon = new Map([
+ [ChartType.AREA, IconNames.TIMELINE_AREA_CHART],
+ [ChartType.CANDLE, IconNames.WATERFALL_CHART],
+ [ChartType.LINE, IconNames.TIMELINE_LINE_CHART],
+ [ChartType.OHLC, IconNames.WATERFALL_CHART],
+]);
+
+/**
+ * Renders either the pennant chart or the tradingview chart
+ */
+export const ChartContainer = ({ marketId }: { marketId: string }) => {
+ const {
+ chartlib,
+ interval,
+ chartType,
+ overlays,
+ studies,
+ studySizes,
+ setStudies,
+ setStudySizes,
+ setOverlays,
+ } = useCandlesChartSettings();
+
+ switch (chartlib) {
+ case 'tradingview': {
+ return ;
+ }
+ case 'pennant': {
+ return (
+
+ );
+ }
+ default: {
+ throw new Error('invalid chart lib');
+ }
+ }
+};
+
+export const ChartMenu = () => {
+ const {
+ chartlib,
+ interval,
+ chartType,
+ studies,
+ overlays,
+ setChartlib,
+ setInterval,
+ setType,
+ setStudies,
+ setOverlays,
+ } = useCandlesChartSettings();
+ const t = useT();
+
+ const contentAlign = 'end';
+ const triggerClasses = 'text-xs';
+ const triggerButtonProps = { size: 'extra-small' } as const;
+
+ const chartlibDropdown = (
+
+ {chartlib}
+
+ }
+ >
+
+ {
+ // @ts-ignore need to cast to Chartlib
+ setChartlib(value);
+ }}
+ >
+
+ Tradingview
+
+
+
+
+ Pennant
+
+
+
+
+
+ );
+
+ switch (chartlib) {
+ case 'tradingview': {
+ return <>{chartlibDropdown}>;
+ }
+ case 'pennant': {
+ return (
+ <>
+ {chartlibDropdown}
+
+
+ {t('Interval: {{interval}}', {
+ interval: intervalLabels[interval],
+ })}
+
+
+ }
+ >
+
+ {
+ setInterval(value as Interval);
+ }}
+ >
+ {Object.values(Interval).map((timeInterval) => (
+
+ {intervalLabels[timeInterval]}
+
+
+ ))}
+
+
+
+
+
+
+
+
+ }
+ >
+
+ {
+ setType(value as ChartType);
+ }}
+ >
+ {Object.values(ChartType).map((type) => (
+
+ {chartTypeLabels[type]}
+
+
+ ))}
+
+
+
+
+
+ {t('Indicators')}
+
+
+ }
+ >
+
+ {Object.values(Overlay).map((overlay) => (
+ {
+ const newOverlays = [...overlays];
+ const index = overlays.findIndex(
+ (item) => item === overlay,
+ );
+
+ index !== -1
+ ? newOverlays.splice(index, 1)
+ : newOverlays.push(overlay);
+
+ setOverlays(newOverlays);
+ }}
+ >
+ {overlayLabels[overlay]}
+
+
+ ))}
+ {Object.values(Study).map((study) => (
+ {
+ const newStudies = [...studies];
+ const index = studies.findIndex((item) => item === study);
+
+ index !== -1
+ ? newStudies.splice(index, 1)
+ : newStudies.push(study);
+
+ setStudies(newStudies);
+ }}
+ >
+ {studyLabels[study]}
+
+
+ ))}
+
+
+ >
+ );
+ }
+ default: {
+ throw new Error('invalid chart lib');
+ }
+ }
+};
diff --git a/apps/trading/components/chart-container/index.ts b/apps/trading/components/chart-container/index.ts
new file mode 100644
index 000000000..e01a5c388
--- /dev/null
+++ b/apps/trading/components/chart-container/index.ts
@@ -0,0 +1 @@
+export { ChartContainer, ChartMenu } from './chart-container';
diff --git a/libs/candles-chart/src/lib/use-candles-chart-settings.ts b/apps/trading/components/chart-container/use-candles-chart-settings.ts
similarity index 88%
rename from libs/candles-chart/src/lib/use-candles-chart-settings.ts
rename to apps/trading/components/chart-container/use-candles-chart-settings.ts
index 4e22c3e7c..3fc9ae68d 100644
--- a/libs/candles-chart/src/lib/use-candles-chart-settings.ts
+++ b/apps/trading/components/chart-container/use-candles-chart-settings.ts
@@ -6,8 +6,10 @@ import { persist } from 'zustand/middleware';
import { immer } from 'zustand/middleware/immer';
type StudySizes = { [S in Study]?: number };
+type Chartlib = 'pennant' | 'tradingview';
interface StoredSettings {
+ chartlib: Chartlib;
interval: Interval;
type: ChartType;
overlays: Overlay[];
@@ -25,6 +27,7 @@ const STUDY_ORDER: Study[] = [
];
export const DEFAULT_CHART_SETTINGS = {
+ chartlib: 'tradingview' as const,
interval: Interval.I15M,
type: ChartType.CANDLE,
overlays: [Overlay.MOVING_AVERAGE],
@@ -39,6 +42,7 @@ export const useCandlesChartSettingsStore = create<
setOverlays: (overlays?: Overlay[]) => void;
setStudies: (studies?: Study[]) => void;
setStudySizes: (sizes: number[]) => void;
+ setChartlib: (lib: Chartlib) => void;
}
>()(
persist(
@@ -81,11 +85,16 @@ export const useCandlesChartSettingsStore = create<
});
});
},
+ setChartlib: (lib) => {
+ set((state) => {
+ state.chartlib = lib;
+ });
+ },
})),
{
name: 'vega_candles_chart_store',
- }
- )
+ },
+ ),
);
export const useCandlesChartSettings = () => {
@@ -94,25 +103,25 @@ export const useCandlesChartSettings = () => {
const interval: Interval = getValidItem(
settings.interval,
Object.values(Interval),
- Interval.I15M
+ Interval.I15M,
);
const chartType: ChartType = getValidItem(
settings.type,
Object.values(ChartType),
- ChartType.CANDLE
+ ChartType.CANDLE,
);
const overlays: Overlay[] = getValidSubset(
settings.overlays,
Object.values(Overlay),
- []
+ [],
);
const studies: Study[] = getValidSubset(
settings.studies,
Object.values(Study),
- [Study.VOLUME]
+ [Study.VOLUME],
);
// find the study size
@@ -122,6 +131,7 @@ export const useCandlesChartSettings = () => {
});
return {
+ chartlib: settings.chartlib,
interval,
chartType,
overlays,
@@ -132,5 +142,6 @@ export const useCandlesChartSettings = () => {
setStudies: settings.setStudies,
setOverlays: settings.setOverlays,
setStudySizes: settings.setStudySizes,
+ setChartlib: settings.setChartlib,
};
};
diff --git a/apps/trading/components/trading-view-container/index.ts b/apps/trading/components/trading-view-container/index.ts
new file mode 100644
index 000000000..97f6bf9f5
--- /dev/null
+++ b/apps/trading/components/trading-view-container/index.ts
@@ -0,0 +1 @@
+export { TradingViewContainer } from './trading-view-container';
diff --git a/apps/trading/components/trading-view-container/trading-view-container.tsx b/apps/trading/components/trading-view-container/trading-view-container.tsx
new file mode 100644
index 000000000..eb2f4f1ba
--- /dev/null
+++ b/apps/trading/components/trading-view-container/trading-view-container.tsx
@@ -0,0 +1,5 @@
+import { TradingView } from '@vegaprotocol/trading-view';
+
+export const TradingViewContainer = ({ marketId }: { marketId: string }) => {
+ return ;
+};
diff --git a/apps/trading/pages/index.page.tsx b/apps/trading/pages/index.page.tsx
index 3278d530b..2a4476b7c 100644
--- a/apps/trading/pages/index.page.tsx
+++ b/apps/trading/pages/index.page.tsx
@@ -1,5 +1,7 @@
import Head from 'next/head';
import { ClientRouter } from './client-router';
+import Script from 'next/script';
+import { useState } from 'react';
/**
* Next only handles this single index page, react-router takes over after the page
@@ -7,6 +9,7 @@ import { ClientRouter } from './client-router';
* have to serve a static site via next export
*/
export default function Index() {
+ const [isScriptReady, setIsScriptReady] = useState(false);
return (
<>
@@ -27,7 +30,14 @@ export default function Index() {
-
+