Skip to content

Commit

Permalink
[ECO-2372] Fix candlestick chart issues (#330)
Browse files Browse the repository at this point in the history
Run format

Fix lints
  • Loading branch information
xbtmatt committed Nov 7, 2024
1 parent 475d02b commit 1a1a1c6
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 11 deletions.
1 change: 0 additions & 1 deletion src/typescript/frontend/src/app/market/[market]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ const EmojicoinPage = async (params: EmojicoinPageProps) => {
});
const state = await fetchMarketState({ searchEmojis: emojis });


if (state) {
const { marketID } = state.market;
const marketAddress = deriveEmojicoinPublisherAddress({ emojis });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export async function getPoolData(
searchEmojis?: string[],
provider?: string
) {
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
let ret: any;
if (provider) {
ret = fetchUserLiquidityPools({
Expand Down
31 changes: 24 additions & 7 deletions src/typescript/frontend/src/components/charts/PrivateChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
type Timezone,
widget,
} from "@static/charting_library";
import { getClientTimezone } from "lib/chart-utils";
import { getClientTimezone, hasTradingActivity } from "lib/chart-utils";
import { type ChartContainerProps } from "./types";
import { useRouter } from "next/navigation";
import { ROUTES } from "router/routes";
Expand Down Expand Up @@ -188,12 +188,13 @@ export const Chart = (props: ChartContainerProps) => {
// Convert the market view data to `latestBar[]` and set the latest bars in our EventStore to those values.
const latestBars = marketToLatestBars(marketResource);
const marketEmojiData = toMarketEmojiData(marketResource.metadata.emojiBytes);
const symbolEmojis = marketEmojiData.emojis.map((e) => e.emoji);
const marketMetadata: MarketMetadataModel = {
marketID: marketResource.metadata.marketID,
time: 0n,
marketNonce: marketResource.sequenceInfo.nonce,
trigger: Trigger.PackagePublication, // Make up some bunk trigger, since it should be clear it's made up.
symbolEmojis: marketEmojiData.emojis.map((e) => e.emoji),
symbolEmojis,
marketAddress: marketResource.metadata.marketAddress,
...marketEmojiData,
};
Expand All @@ -218,9 +219,11 @@ export const Chart = (props: ChartContainerProps) => {
// some visual inconsistencies in the chart.
const bars: Bar[] = data.reduce((acc: Bar[], event) => {
const bar = toBar(event);
if (bar.time >= from * 1000 && bar.time <= to * 1000) {
if (acc.at(-1)) {
bar.open = acc.at(-1)!.close;
const inTimeRange = bar.time >= from * 1000 && bar.time <= to * 1000;
if (inTimeRange && hasTradingActivity(bar)) {
const prev = acc.at(-1);
if (prev) {
bar.open = prev.close;
}
acc.push(bar);
}
Expand All @@ -229,9 +232,23 @@ export const Chart = (props: ChartContainerProps) => {

// Push the latest bar to the bars array if it exists and update its `open` value to be the previous bar's
// `close` if it's not the first/only bar.
// This logic mirrors what we use in `createBarFrom[Swap|PeriodicState]` but we need it here because we
// update the latest bar based on the market view every time we fetch with `getBars`, not just when a new
// event comes in.
if (latestBar) {
if (bars.at(-1)) {
latestBar.open = bars.at(-1)!.close;
const secondLatestBar = bars.at(-1);
if (secondLatestBar) {
// If the latest bar has no trading activity, set all of its fields to the previous bar's close.
if (!hasTradingActivity(latestBar)) {
latestBar.high = secondLatestBar.close;
latestBar.low = secondLatestBar.close;
latestBar.close = secondLatestBar.close;
}
if (secondLatestBar.close !== 0) {
latestBar.open = secondLatestBar.close;
} else {
latestBar.open = latestBar.close;
}
}
bars.push(latestBar);
}
Expand Down
6 changes: 6 additions & 0 deletions src/typescript/frontend/src/lib/chart-utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// cspell:word Kolkata
// cspell:word Fakaofo

import { type Bar } from "@static/charting_library/datafeed-api";

/**
* Retrieves the client's timezone based on the current system time offset.
*
Expand Down Expand Up @@ -70,3 +73,6 @@ export function getClientTimezone() {
}
return "Etc/UTC";
}

export const hasTradingActivity = (bar: Bar) =>
[bar.open, bar.high, bar.low, bar.close].some((price) => price !== 0);
10 changes: 7 additions & 3 deletions src/typescript/frontend/src/lib/store/event/candlestick-bars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const toBar = (event: PeriodicStateEventModel): Bar => ({
high: q64ToBig(event.periodicState.highPriceQ64).toNumber(),
low: q64ToBig(event.periodicState.lowPriceQ64).toNumber(),
close: q64ToBig(event.periodicState.closePriceQ64).toNumber(),
volume: Number(event.periodicState.volumeQuote),
volume: Number(event.periodicState.volumeBase),
});

export const toBars = (events: PeriodicStateEventModel | PeriodicStateEventModel[]) =>
Expand All @@ -75,7 +75,9 @@ export const createBarFromSwap = (
const periodStartTime = getPeriodStartTimeFromTime(market.time, period);
return {
time: Number(periodStartTime / 1000n),
open: previousClose ?? price,
// Only use previousClose if it's a truthy value, otherwise, new bars that follow bars with no
// trading activity will appear as a huge green candlestick because their open price is `0`.
open: previousClose ? previousClose : price,
high: price,
low: price,
close: price,
Expand All @@ -94,7 +96,9 @@ export const createBarFromPeriodicState = (
const price = q64ToBig(periodicState.closePriceQ64).toNumber();
return {
time: periodEnumToRawDuration(period) / 1000,
open: previousClose ?? price,
// Only use previousClose if it's a truthy value, otherwise, new bars that follow bars with no
// trading activity will appear as a huge green candlestick because their open price is `0`.
open: previousClose ? previousClose : price,
high: price,
low: price,
close: price,
Expand Down
10 changes: 10 additions & 0 deletions src/typescript/frontend/src/lib/store/event/event-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ export const createEventStore = () => {
const market = state.markets.get(symbol)!;
latestBars.forEach((bar) => {
const period = bar.period;
// A bar's open should never be zero, so use the previous bar if it exists and isn't 0,
// otherwise, use the existing current bar's close.
if (bar.open === 0) {
const prevLatestBarClose = market[period].latestBar?.close;
if (prevLatestBarClose) {
bar.open = prevLatestBarClose;
} else {
bar.open = bar.close;
}
}
market[period].latestBar = bar;
});
});
Expand Down

0 comments on commit 1a1a1c6

Please sign in to comment.