feat(trading): store study sizes, reduce candles gap (#4708)
This commit is contained in:
parent
2453d7841a
commit
a77765b1e9
@ -82,6 +82,7 @@ html [data-theme='light'] {
|
|||||||
|
|
||||||
--pennant-color-volume-sell: theme(colors.market.red.DEFAULT);
|
--pennant-color-volume-sell: theme(colors.market.red.DEFAULT);
|
||||||
|
|
||||||
|
/* reduce space between candles */
|
||||||
--pennant-candlestick-inner-padding: 0.1;
|
--pennant-candlestick-inner-padding: 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import { CandlestickChart } from 'pennant';
|
|||||||
import { VegaDataSource } from './data-source';
|
import { VegaDataSource } from './data-source';
|
||||||
import { useApolloClient } from '@apollo/client';
|
import { useApolloClient } from '@apollo/client';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
import debounce from 'lodash/debounce';
|
||||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
import { useVegaWallet } from '@vegaprotocol/wallet';
|
import { useVegaWallet } from '@vegaprotocol/wallet';
|
||||||
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
import { useThemeSwitcher } from '@vegaprotocol/react-helpers';
|
||||||
@ -22,8 +23,25 @@ export const CandlesChartContainer = ({
|
|||||||
const { pubKey } = useVegaWallet();
|
const { pubKey } = useVegaWallet();
|
||||||
const { theme } = useThemeSwitcher();
|
const { theme } = useThemeSwitcher();
|
||||||
|
|
||||||
const { interval, chartType, overlays, studies, merge } =
|
const {
|
||||||
useCandlesChartSettings();
|
interval,
|
||||||
|
chartType,
|
||||||
|
overlays,
|
||||||
|
studies,
|
||||||
|
studySizes,
|
||||||
|
setStudies,
|
||||||
|
setStudySizes,
|
||||||
|
setOverlays,
|
||||||
|
} = useCandlesChartSettings();
|
||||||
|
|
||||||
|
const handlePaneChange = useMemo(
|
||||||
|
() =>
|
||||||
|
debounce((sizes: number[]) => {
|
||||||
|
// first number is main pain, which is greedy so we don't store it
|
||||||
|
setStudySizes(sizes.filter((_, i) => i !== 0));
|
||||||
|
}, 300),
|
||||||
|
[setStudySizes]
|
||||||
|
);
|
||||||
|
|
||||||
const dataSource = useMemo(() => {
|
const dataSource = useMemo(() => {
|
||||||
return new VegaDataSource(client, marketId, pubKey);
|
return new VegaDataSource(client, marketId, pubKey);
|
||||||
@ -45,15 +63,16 @@ export const CandlesChartContainer = ({
|
|||||||
initialNumCandlesToDisplay: Math.floor(
|
initialNumCandlesToDisplay: Math.floor(
|
||||||
width * CANDLES_TO_WIDTH_FACTOR
|
width * CANDLES_TO_WIDTH_FACTOR
|
||||||
),
|
),
|
||||||
|
studySize: 150, // default size
|
||||||
|
studySizes,
|
||||||
}}
|
}}
|
||||||
interval={interval}
|
interval={interval}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
onOptionsChanged={(options) => {
|
onOptionsChanged={(options) => {
|
||||||
merge({
|
setStudies(options.studies);
|
||||||
overlays: options.overlays,
|
setOverlays(options.overlays);
|
||||||
studies: options.studies,
|
|
||||||
});
|
|
||||||
}}
|
}}
|
||||||
|
onPaneChanged={handlePaneChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -5,36 +5,45 @@ import { create } from 'zustand';
|
|||||||
import { persist } from 'zustand/middleware';
|
import { persist } from 'zustand/middleware';
|
||||||
import { immer } from 'zustand/middleware/immer';
|
import { immer } from 'zustand/middleware/immer';
|
||||||
|
|
||||||
|
type StudySizes = { [S in Study]?: number };
|
||||||
|
|
||||||
interface StoredSettings {
|
interface StoredSettings {
|
||||||
interval: Interval;
|
interval: Interval;
|
||||||
type: ChartType;
|
type: ChartType;
|
||||||
overlays: Overlay[];
|
overlays: Overlay[];
|
||||||
studies: Study[];
|
studies: Study[];
|
||||||
|
studySizes: StudySizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const STUDY_SIZE = 100;
|
||||||
|
const STUDY_ORDER: Study[] = [
|
||||||
|
Study.FORCE_INDEX,
|
||||||
|
Study.RELATIVE_STRENGTH_INDEX,
|
||||||
|
Study.ELDAR_RAY,
|
||||||
|
Study.MACD,
|
||||||
|
Study.VOLUME,
|
||||||
|
];
|
||||||
|
|
||||||
const DEFAULT_CHART_SETTINGS = {
|
const DEFAULT_CHART_SETTINGS = {
|
||||||
interval: Interval.I15M,
|
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: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useCandlesChartSettingsStore = create<
|
export const useCandlesChartSettingsStore = create<
|
||||||
StoredSettings & {
|
StoredSettings & {
|
||||||
merge: (settings: Partial<StoredSettings>) => void;
|
|
||||||
setType: (type: ChartType) => void;
|
setType: (type: ChartType) => void;
|
||||||
setInterval: (interval: Interval) => void;
|
setInterval: (interval: Interval) => void;
|
||||||
setOverlays: (overlays: Overlay[]) => void;
|
setOverlays: (overlays?: Overlay[]) => void;
|
||||||
setStudies: (studies: Study[]) => void;
|
setStudies: (studies?: Study[]) => void;
|
||||||
|
setStudySizes: (sizes: number[]) => void;
|
||||||
}
|
}
|
||||||
>()(
|
>()(
|
||||||
persist(
|
persist(
|
||||||
immer((set) => ({
|
immer((set) => ({
|
||||||
...DEFAULT_CHART_SETTINGS,
|
...DEFAULT_CHART_SETTINGS,
|
||||||
merge: (settings: Partial<StoredSettings>) =>
|
|
||||||
set((state) => {
|
|
||||||
Object.assign(state, settings);
|
|
||||||
}),
|
|
||||||
setType: (type) =>
|
setType: (type) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.type = type;
|
state.type = type;
|
||||||
@ -43,14 +52,35 @@ export const useCandlesChartSettingsStore = create<
|
|||||||
set((state) => {
|
set((state) => {
|
||||||
state.interval = interval;
|
state.interval = interval;
|
||||||
}),
|
}),
|
||||||
setOverlays: (overlays) =>
|
setOverlays: (overlays) => {
|
||||||
|
if (!overlays) return;
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.overlays = overlays;
|
state.overlays = overlays;
|
||||||
}),
|
});
|
||||||
setStudies: (studies) =>
|
},
|
||||||
|
setStudies: (studies) => {
|
||||||
|
if (!studies) return;
|
||||||
|
|
||||||
|
// Make sure studies are always returned in the same order
|
||||||
|
studies.sort((a, b) => {
|
||||||
|
return STUDY_ORDER.indexOf(a) - STUDY_ORDER.indexOf(b);
|
||||||
|
});
|
||||||
|
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.studies = studies;
|
state.studies = studies;
|
||||||
}),
|
});
|
||||||
|
},
|
||||||
|
setStudySizes: (sizes) => {
|
||||||
|
set((state) => {
|
||||||
|
// for every study find the corresonding size and update
|
||||||
|
// the size record for that study
|
||||||
|
state.studies.forEach((s, i) => {
|
||||||
|
const size = sizes[i];
|
||||||
|
state.studySizes[s] = size;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
name: 'vega_candles_chart_store',
|
name: 'vega_candles_chart_store',
|
||||||
@ -85,15 +115,22 @@ export const useCandlesChartSettings = () => {
|
|||||||
[Study.VOLUME]
|
[Study.VOLUME]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// find the study size
|
||||||
|
const studySizes = studies.map((s) => {
|
||||||
|
const size = settings.studySizes[s] || STUDY_SIZE;
|
||||||
|
return size;
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
interval,
|
interval,
|
||||||
chartType,
|
chartType,
|
||||||
overlays,
|
overlays,
|
||||||
studies,
|
studies,
|
||||||
|
studySizes,
|
||||||
setInterval: settings.setInterval,
|
setInterval: settings.setInterval,
|
||||||
setType: settings.setType,
|
setType: settings.setType,
|
||||||
setStudies: settings.setStudies,
|
setStudies: settings.setStudies,
|
||||||
setOverlays: settings.setOverlays,
|
setOverlays: settings.setOverlays,
|
||||||
merge: settings.merge,
|
setStudySizes: settings.setStudySizes,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
"jsondiffpatch": "^0.4.1",
|
"jsondiffpatch": "^0.4.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"next": "13.3.0",
|
"next": "13.3.0",
|
||||||
"pennant": "1.11.1",
|
"pennant": "1.12.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-copy-to-clipboard": "^5.0.4",
|
"react-copy-to-clipboard": "^5.0.4",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
@ -20253,10 +20253,10 @@ pend@~1.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||||
integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==
|
integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==
|
||||||
|
|
||||||
pennant@1.11.1:
|
pennant@1.12.0:
|
||||||
version "1.11.1"
|
version "1.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/pennant/-/pennant-1.11.1.tgz#f47bceaade01db215eeba666cd755840d16fe9ed"
|
resolved "https://registry.yarnpkg.com/pennant/-/pennant-1.12.0.tgz#e12707d5f1aac554d81bad060637e608335e0b50"
|
||||||
integrity sha512-U26OxjxETWLJAvCFj20oH0y5gzyBfJ5oD4O3dYg1aWnH4giUYDPWuUDFnzlMJ+yXolyYECccXm6S1BkoVcVzDg==
|
integrity sha512-xosg5erRf+Ke9iORdqyv+SOGcD3uJX1dgf990q1DvHuzz36w2txCZsfnvcXhRO++HYVKS9sU/YLPRLJgolFGtA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime" "^7.13.10"
|
"@babel/runtime" "^7.13.10"
|
||||||
"@d3fc/d3fc-technical-indicator" "^8.0.1"
|
"@d3fc/d3fc-technical-indicator" "^8.0.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user