From 21896ca2c3ae63f84f5a7fa6bc45728e0a83f4f8 Mon Sep 17 00:00:00 2001 From: saml33 Date: Wed, 8 Feb 2023 20:58:03 +1100 Subject: [PATCH 1/2] add order lines to tv chart --- components/trade/TradingViewChart.tsx | 490 ++++++++++++++++++++++++-- pages/trade.tsx | 1 + public/locales/en/tv-chart.json | 17 +- public/locales/es/tv-chart.json | 17 +- public/locales/ru/tv-chart.json | 23 +- public/locales/zh/tv-chart.json | 3 +- public/locales/zh_tw/tv-chart.json | 3 +- store/mangoStore.ts | 9 +- utils/constants.ts | 2 + 9 files changed, 511 insertions(+), 54 deletions(-) diff --git a/components/trade/TradingViewChart.tsx b/components/trade/TradingViewChart.tsx index fea260c3..fd1e8680 100644 --- a/components/trade/TradingViewChart.tsx +++ b/components/trade/TradingViewChart.tsx @@ -1,17 +1,38 @@ -import { useEffect, useRef, useMemo, useState } from 'react' +import { useEffect, useRef, useMemo, useState, useCallback } from 'react' import { useTheme } from 'next-themes' import { widget, ChartingLibraryWidgetOptions, IChartingLibraryWidget, ResolutionString, + IOrderLineAdapter, } from '@public/charting_library' import mangoStore from '@store/mangoStore' import { useViewport } from 'hooks/useViewport' -import { CHART_DATA_FEED, DEFAULT_MARKET_NAME } from 'utils/constants' +import { + CHART_DATA_FEED, + DEFAULT_MARKET_NAME, + SHOW_ORDER_LINES_KEY, +} from 'utils/constants' import { breakpoints } from 'utils/theme' import { COLORS } from 'styles/colors' import Datafeed from 'apis/birdeye/datafeed' +import { useTranslation } from 'next-i18next' +import { notify } from 'utils/notifications' +import { + PerpMarket, + PerpOrder, + PerpOrderType, + Serum3Market, + Serum3OrderType, + Serum3SelfTradeBehavior, + Serum3Side, +} from '@blockworks-foundation/mango-v4' +import { Order } from '@project-serum/serum/lib/market' +import { PublicKey } from '@solana/web3.js' +import useLocalStorageState from 'hooks/useLocalStorageState' +import { formatNumericValue, getDecimalCount } from 'utils/numbers' +import { BN } from '@project-serum/anchor' export interface ChartContainerProps { container: ChartingLibraryWidgetOptions['container'] @@ -29,12 +50,27 @@ export interface ChartContainerProps { theme: string } +function hexToRgb(hex: string) { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) + return result + ? `rgb(${parseInt(result[1], 16)}, ${parseInt(result[2], 16)}, ${parseInt( + result[3], + 16 + )})` + : null +} + const TradingViewChart = () => { + const { t } = useTranslation('tv-chart') const { theme } = useTheme() const { width } = useViewport() - const [chartReady, setChartReady] = useState(false) const [spotOrPerp, setSpotOrPerp] = useState('spot') + const [showOrderLinesLocalStorage, toggleShowOrderLinesLocalStorage] = + useLocalStorageState(SHOW_ORDER_LINES_KEY, true) + const [showOrderLines, toggleShowOrderLines] = useState( + showOrderLinesLocalStorage + ) const selectedMarketName = mangoStore((s) => s.selectedMarket.current?.name) const isMobile = width ? width < breakpoints.sm : false @@ -116,7 +152,7 @@ const TradingViewChart = () => { console.warn('Trading View change symbol error: ', e) } } - }, [selectedMarketName, chartReady]) + }, [selectedMarketName, chartReady, tvWidgetRef]) useEffect(() => { if ( @@ -186,26 +222,7 @@ const TradingViewChart = () => { : 'Dark', custom_css_url: '/styles/tradingview.css', loading_screen: { - backgroundColor: - theme === 'Dark' - ? COLORS.BKG1.Dark - : theme === 'Light' - ? COLORS.BKG1.Light - : theme === 'Mango Classic' - ? COLORS.BKG1['Mango Classic'] - : theme === 'Medium' - ? COLORS.BKG1.Medium - : theme === 'Avocado' - ? COLORS.BKG1.Avocado - : theme === 'Blueberry' - ? COLORS.BKG1.Blueberry - : theme === 'Banana' - ? COLORS.BKG1.Banana - : theme === 'Lychee' - ? COLORS.BKG1.Lychee - : theme === 'Olive' - ? COLORS.BKG1.Olive - : COLORS.BKG1['High Contrast'], + backgroundColor: COLORS.BKG1[theme], }, overrides: { timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, @@ -218,12 +235,437 @@ const TradingViewChart = () => { tvWidgetRef.current = tvWidget tvWidgetRef.current.onChartReady(function () { + createOLButton() + if (showOrderLines) { + const openOrders = mangoStore.getState().mangoAccount.openOrders + deleteLines() + drawLinesForMarket(openOrders) + } setChartReady(true) }) //eslint-disable-next-line } }, [theme, isMobile, defaultProps, spotOrPerp]) + const createOLButton = () => { + const button = tvWidgetRef?.current?.createButton() + if (!button) { + return + } + button.textContent = 'OL' + if (showOrderLinesLocalStorage) { + button.style.color = COLORS.ACTIVE[theme] + } else { + button.style.color = COLORS.FGD4[theme] + } + button.setAttribute('title', t('tv-chart:toggle-order-line')) + button.addEventListener('click', toggleOrderLines) + } + + function toggleOrderLines(this: HTMLElement) { + toggleShowOrderLines((prevState: boolean) => !prevState) + if (this.style.color === hexToRgb(COLORS.ACTIVE[theme])) { + deleteLines() + this.style.color = COLORS.FGD4[theme] + } else { + const openOrders = mangoStore.getState().mangoAccount.openOrders + drawLinesForMarket(openOrders) + this.style.color = COLORS.ACTIVE[theme] + } + } + + useEffect(() => { + if (showOrderLines !== showOrderLinesLocalStorage) { + toggleShowOrderLinesLocalStorage(showOrderLines) + } + }, [showOrderLines]) + + // updated order lines if a user's open orders change + useEffect(() => { + let subscription + if (chartReady && tvWidgetRef?.current) { + subscription = mangoStore.subscribe( + (state) => state.mangoAccount.openOrders, + (openOrders) => { + const orderLines = mangoStore.getState().tradingView.orderLines + tvWidgetRef.current?.onChartReady(() => { + let matchingOrderLines = 0 + let openOrdersForMarket = 0 + + const oOrders = Object.entries(openOrders).map( + ([marketPk, orders]) => ({ + orders, + marketPk, + }) + ) + + for (const [key] of orderLines) { + oOrders?.forEach(({ orders }) => { + for (const order of orders) { + if (order.orderId == key) { + matchingOrderLines += 1 + } + } + }) + } + const selectedMarket = mangoStore.getState().selectedMarket.current + const selectedMarketPk = + selectedMarket instanceof Serum3Market + ? selectedMarket?.serumMarketExternal.toString() + : selectedMarket?.publicKey.toString() + + oOrders?.forEach(({ marketPk }) => { + if (marketPk === selectedMarketPk) { + openOrdersForMarket += 1 + } + }) + + tvWidgetRef.current?.activeChart().dataReady(() => { + if ( + (showOrderLines && + matchingOrderLines !== openOrdersForMarket) || + orderLines?.size != matchingOrderLines + ) { + deleteLines() + drawLinesForMarket(openOrders) + } + }) + }) + } + ) + } + return subscription + }, [chartReady, showOrderLines]) + + const drawLinesForMarket = ( + openOrders: Record + ) => { + const set = mangoStore.getState().set + const newOrderLines = new Map() + const oOrders = Object.entries(openOrders).map(([marketPk, orders]) => ({ + orders, + marketPk, + })) + if (oOrders?.length) { + const selectedMarket = mangoStore.getState().selectedMarket.current + const selectedMarketPk = + selectedMarket instanceof Serum3Market + ? selectedMarket?.serumMarketExternal.toString() + : selectedMarket?.publicKey.toString() + for (const { orders, marketPk } of oOrders) { + if (marketPk === selectedMarketPk) { + for (const order of orders) { + newOrderLines.set(order.orderId.toString(), drawLine(order)) + } + } + } + } + set((state) => { + state.tradingView.orderLines = newOrderLines + }) + } + + const deleteLines = () => { + const set = mangoStore.getState().set + const orderLines = mangoStore.getState().tradingView.orderLines + if (orderLines.size > 0) { + orderLines?.forEach((value: IOrderLineAdapter, key: string | BN) => { + orderLines.get(key)?.remove() + }) + + set((state) => { + state.tradingView.orderLines = new Map() + }) + } + } + + function getOrderDecimals() { + const selectedMarket = mangoStore.getState().selectedMarket.current + let minOrderDecimals = 4 + let tickSizeDecimals = 2 + if (!selectedMarket) return [minOrderDecimals, tickSizeDecimals] + if (selectedMarket instanceof PerpMarket) { + minOrderDecimals = getDecimalCount(selectedMarket.minOrderSize) + tickSizeDecimals = getDecimalCount(selectedMarket.tickSize) + } else { + const group = mangoStore.getState().group + const market = group?.getSerum3ExternalMarket( + selectedMarket.serumMarketExternal + ) + if (market) { + minOrderDecimals = getDecimalCount(market.minOrderSize) + tickSizeDecimals = getDecimalCount(market.tickSize) + } + } + return [minOrderDecimals, tickSizeDecimals] + } + + function drawLine(order: Order | PerpOrder) { + const side = + typeof order.side === 'string' + ? t(order.side) + : 'bid' in order.side + ? t('trade:long') + : t('trade:short') + const isLong = side === 'buy' || side === 'long' + const isShort = side === 'sell' || side === 'short' + const [minOrderDecimals, tickSizeDecimals] = getOrderDecimals() + const orderSizeUi: string = formatNumericValue(order.size, minOrderDecimals) + if (!tvWidgetRef?.current?.chart()) return + return ( + tvWidgetRef.current + .chart() + .createOrderLine({ disableUndo: false }) + .onMove(function (this: IOrderLineAdapter) { + const currentOrderPrice = order.price + const updatedOrderPrice = this.getPrice() + const selectedMarketPrice = + mangoStore.getState().selectedMarket.markPrice + if ( + (isLong && updatedOrderPrice > 1.05 * selectedMarketPrice) || + (isShort && updatedOrderPrice < 0.95 * selectedMarketPrice) + ) { + tvWidgetRef.current?.showNoticeDialog({ + title: t('tv-chart:outside-range'), + body: + t('tv-chart:slippage-warning', { + updatedOrderPrice: updatedOrderPrice, + aboveBelow: + side == 'buy' || side === 'long' ? t('above') : t('below'), + selectedMarketPrice: selectedMarketPrice, + }) + + '

' + + t('tv-chart:slippage-accept'), + callback: () => { + this.setPrice(currentOrderPrice) + }, + }) + } else { + tvWidgetRef.current?.showConfirmDialog({ + title: t('tv-chart:modify-order'), + body: t('tv-chart:modify-order-details', { + marketName: selectedMarketName, + orderSize: orderSizeUi, + orderSide: side.toUpperCase(), + currentOrderPrice: formatNumericValue( + currentOrderPrice, + tickSizeDecimals + ), + updatedOrderPrice: formatNumericValue( + updatedOrderPrice, + tickSizeDecimals + ), + }), + callback: (res) => { + if (res) { + modifyOrder(order, updatedOrderPrice) + } else { + this.setPrice(currentOrderPrice) + } + }, + }) + } + }) + .onCancel(function () { + tvWidgetRef.current?.showConfirmDialog({ + title: t('tv-chart:cancel-order'), + body: t('tv-chart:cancel-order-details', { + marketName: selectedMarketName, + orderSize: orderSizeUi, + orderSide: side.toUpperCase(), + orderPrice: formatNumericValue(order.price, tickSizeDecimals), + }), + callback: (res) => { + if (res) { + if (order instanceof PerpOrder) { + cancelPerpOrder(order) + } else { + cancelSpotOrder(order) + } + } + }, + }) + }) + .setPrice(order.price) + .setQuantity(orderSizeUi) + .setText(side.toUpperCase()) + // .setTooltip( + // order.perpTrigger?.clientOrderId + // ? `${order.orderType} Order #: ${order.orderId}` + // : `Order #: ${order.orderId}` + // ) + .setBodyTextColor(isLong ? COLORS.UP[theme] : COLORS.DOWN[theme]) + .setQuantityTextColor(isLong ? COLORS.UP[theme] : COLORS.DOWN[theme]) + .setCancelButtonIconColor(COLORS.FGD4[theme]) + .setBodyBorderColor(isLong ? COLORS.UP[theme] : COLORS.DOWN[theme]) + .setQuantityBorderColor(isLong ? COLORS.UP[theme] : COLORS.DOWN[theme]) + .setCancelButtonBorderColor( + isLong ? COLORS.UP[theme] : COLORS.DOWN[theme] + ) + .setBodyBackgroundColor(COLORS.BKG1[theme]) + .setQuantityBackgroundColor(COLORS.BKG1[theme]) + .setCancelButtonBackgroundColor(COLORS.BKG1[theme]) + .setLineColor(isLong ? COLORS.UP[theme] : COLORS.DOWN[theme]) + .setLineLength(3) + .setLineWidth(1) + .setLineStyle(1) + ) + } + + const modifyOrder = useCallback( + async (o: PerpOrder | Order, price: number) => { + const client = mangoStore.getState().client + const group = mangoStore.getState().group + const mangoAccount = mangoStore.getState().mangoAccount.current + const actions = mangoStore.getState().actions + const baseSize = o.size + if (!group || !mangoAccount) return + try { + let tx = '' + if (o instanceof PerpOrder) { + tx = await client.modifyPerpOrder( + group, + mangoAccount, + o.perpMarketIndex, + o.orderId, + o.side, + price, + Math.abs(baseSize), + undefined, // maxQuoteQuantity + Date.now(), + PerpOrderType.limit, + undefined, + undefined + ) + } else { + const marketPk = findSerum3MarketPkInOpenOrders(o) + if (!marketPk) return + const market = group.getSerum3MarketByExternalMarket( + new PublicKey(marketPk) + ) + tx = await client.modifySerum3Order( + group, + o.orderId, + mangoAccount, + market.serumMarketExternal, + o.side === 'buy' ? Serum3Side.bid : Serum3Side.ask, + price, + baseSize, + Serum3SelfTradeBehavior.decrementTake, + Serum3OrderType.limit, + Date.now(), + 10 + ) + } + actions.fetchOpenOrders() + notify({ + type: 'success', + title: 'Transaction successful', + txid: tx, + }) + } catch (e: any) { + console.error('Error canceling', e) + notify({ + title: 'Unable to modify order', + description: e.message, + txid: e.txid, + type: 'error', + }) + } + }, + [t] + ) + + const cancelSpotOrder = useCallback( + async (o: Order) => { + const client = mangoStore.getState().client + const group = mangoStore.getState().group + const mangoAccount = mangoStore.getState().mangoAccount.current + const actions = mangoStore.getState().actions + if (!group || !mangoAccount) return + const marketPk = findSerum3MarketPkInOpenOrders(o) + if (!marketPk) return + const market = group.getSerum3MarketByExternalMarket( + new PublicKey(marketPk) + ) + try { + const tx = await client.serum3CancelOrder( + group, + mangoAccount, + market!.serumMarketExternal, + o.side === 'buy' ? Serum3Side.bid : Serum3Side.ask, + o.orderId + ) + + actions.fetchOpenOrders() + notify({ + type: 'success', + title: 'Transaction successful', + txid: tx, + }) + } catch (e: any) { + console.error('Error canceling', e) + notify({ + title: t('trade:cancel-order-error'), + description: e.message, + txid: e.txid, + type: 'error', + }) + } + }, + [t] + ) + + const cancelPerpOrder = useCallback( + async (o: PerpOrder) => { + const client = mangoStore.getState().client + const group = mangoStore.getState().group + const mangoAccount = mangoStore.getState().mangoAccount.current + const actions = mangoStore.getState().actions + if (!group || !mangoAccount) return + try { + const tx = await client.perpCancelOrder( + group, + mangoAccount, + o.perpMarketIndex, + o.orderId + ) + actions.fetchOpenOrders() + notify({ + type: 'success', + title: 'Transaction successful', + txid: tx, + }) + } catch (e: any) { + console.error('Error canceling', e) + notify({ + title: t('trade:cancel-order-error'), + description: e.message, + txid: e.txid, + type: 'error', + }) + } + }, + [t] + ) + + const findSerum3MarketPkInOpenOrders = (o: Order): string | undefined => { + const openOrders = mangoStore.getState().mangoAccount.openOrders + let foundedMarketPk: string | undefined = undefined + for (const [marketPk, orders] of Object.entries(openOrders)) { + for (const order of orders) { + if (order.orderId.eq(o.orderId)) { + foundedMarketPk = marketPk + break + } + } + if (foundedMarketPk) { + break + } + } + return foundedMarketPk + } + return (

) diff --git a/pages/trade.tsx b/pages/trade.tsx index 3496af2e..c3382cbf 100644 --- a/pages/trade.tsx +++ b/pages/trade.tsx @@ -23,6 +23,7 @@ export async function getStaticProps({ locale }: { locale: string }) { 'settings', 'trade', 'close-account', + 'tv-chart', ])), }, } diff --git a/public/locales/en/tv-chart.json b/public/locales/en/tv-chart.json index a3953bfe..e08575d1 100644 --- a/public/locales/en/tv-chart.json +++ b/public/locales/en/tv-chart.json @@ -1,13 +1,14 @@ { "advanced-order": "Advanced Order Type", - "advanced-order-details": "Advanced order types in the chart window may only be cancelled. If new conditions are required, please cancel this order and use the Advanced Trade Form.", - "cancel-order": "Cancel Your Order?", - "cancel-order-details": "Would you like to cancel your order for {{orderSize}} {{baseSymbol}} {{orderSide}} at ${{orderPrice}}?", - "modify-order": "Modify Your Order?", - "modify-order-details": "Would you like to change your order from a {{orderSize}} {{baseSymbol}} {{orderSide}} at ${{currentOrderPrice}} to a {{orderSize}} {{baseSymbol}} LIMIT {{orderSide}} at ${{updatedOrderPrice}}?", + "advanced-order-details": "Advanced order types in the chart window may only be cancelled. If new conditions are required, cancel this order and use the trade order form.", + "cancel-order": "Cancel Order", + "cancel-order-details": "Cancel your order for {{orderSide}} {{orderSize}} {{marketName}} at {{orderPrice}}", + "modify-order": "Modify Order", + "modify-order-details": "Edit your {{marketName}} order from {{orderSide}} {{orderSize}} at {{currentOrderPrice}} to {{orderSide}} {{orderSize}} at {{updatedOrderPrice}}", "order-details": " ({{orderType}} {{orderSide}}) if price is {{triggerCondition}} {{triggerPrice}}", "outside-range": "Order Price Outside Range", - "slippage-accept": "Please use the trade input form if you wish to accept the potential slippage.", - "slippage-warning": "Your order price ({{updatedOrderPrice}}) is greater than 5% {{aboveBelow}} the current market price ({{selectedMarketPrice}}) indicating you might incur significant slippage.", - "toggle-order-line": "Toggle order line visibility" + "slippage-accept": "Use the trade order form if you wish to accept the potential slippage.", + "slippage-warning": "{{updatedOrderPrice}} is greater than 5% {{aboveBelow}} the current market price of {{selectedMarketPrice}}. Executing this trade could incur significant slippage.", + "toggle-order-line": "Toggle order line visibility", + "toggle-trade-executions": "Toggle trade execution visibility" } \ No newline at end of file diff --git a/public/locales/es/tv-chart.json b/public/locales/es/tv-chart.json index a3953bfe..e08575d1 100644 --- a/public/locales/es/tv-chart.json +++ b/public/locales/es/tv-chart.json @@ -1,13 +1,14 @@ { "advanced-order": "Advanced Order Type", - "advanced-order-details": "Advanced order types in the chart window may only be cancelled. If new conditions are required, please cancel this order and use the Advanced Trade Form.", - "cancel-order": "Cancel Your Order?", - "cancel-order-details": "Would you like to cancel your order for {{orderSize}} {{baseSymbol}} {{orderSide}} at ${{orderPrice}}?", - "modify-order": "Modify Your Order?", - "modify-order-details": "Would you like to change your order from a {{orderSize}} {{baseSymbol}} {{orderSide}} at ${{currentOrderPrice}} to a {{orderSize}} {{baseSymbol}} LIMIT {{orderSide}} at ${{updatedOrderPrice}}?", + "advanced-order-details": "Advanced order types in the chart window may only be cancelled. If new conditions are required, cancel this order and use the trade order form.", + "cancel-order": "Cancel Order", + "cancel-order-details": "Cancel your order for {{orderSide}} {{orderSize}} {{marketName}} at {{orderPrice}}", + "modify-order": "Modify Order", + "modify-order-details": "Edit your {{marketName}} order from {{orderSide}} {{orderSize}} at {{currentOrderPrice}} to {{orderSide}} {{orderSize}} at {{updatedOrderPrice}}", "order-details": " ({{orderType}} {{orderSide}}) if price is {{triggerCondition}} {{triggerPrice}}", "outside-range": "Order Price Outside Range", - "slippage-accept": "Please use the trade input form if you wish to accept the potential slippage.", - "slippage-warning": "Your order price ({{updatedOrderPrice}}) is greater than 5% {{aboveBelow}} the current market price ({{selectedMarketPrice}}) indicating you might incur significant slippage.", - "toggle-order-line": "Toggle order line visibility" + "slippage-accept": "Use the trade order form if you wish to accept the potential slippage.", + "slippage-warning": "{{updatedOrderPrice}} is greater than 5% {{aboveBelow}} the current market price of {{selectedMarketPrice}}. Executing this trade could incur significant slippage.", + "toggle-order-line": "Toggle order line visibility", + "toggle-trade-executions": "Toggle trade execution visibility" } \ No newline at end of file diff --git a/public/locales/ru/tv-chart.json b/public/locales/ru/tv-chart.json index a7e6488c..e08575d1 100644 --- a/public/locales/ru/tv-chart.json +++ b/public/locales/ru/tv-chart.json @@ -1,13 +1,14 @@ { - "advanced-order": "高級訂單類型", - "advanced-order-details": "在圖表窗口中高級訂單類型只能取消。如果需要新條件,請取消此訂單並使用高級交易表格進行。", - "cancel-order": "取消訂單嗎?", - "cancel-order-details": "您確定要取消{{orderSize}} {{baseSymbol}} {{orderSide}} 價格${{orderPrice}}的掛單嗎?", - "modify-order": "改您的訂單嗎?", - "modify-order-details": "您確定要把{{orderSize}} {{baseSymbol}}{{orderSide}} 價格${{currentOrderPrice}}的掛單改成{{orderSize}} {{baseSymbol}}限價{{orderSide}} 價格${{updatedOrderPrice}}嗎?", - "order-details": "({{orderType}}{{orderSide}})若價格{{triggerCondition}}{{triggerPrice}}", - "outside-range": "訂單價格在範圍之外", - "slippage-accept": "若您接受潛在的下滑請使用交易表格進行。", - "slippage-warning": "您的訂單價格({{updatedOrderPrice}})多餘5%{{aboveBelow}}市場價格({{selectedMarketPrice}})表是您也許遭受可觀的下滑。", - "toggle-order-line": "切換訂單線可見性" + "advanced-order": "Advanced Order Type", + "advanced-order-details": "Advanced order types in the chart window may only be cancelled. If new conditions are required, cancel this order and use the trade order form.", + "cancel-order": "Cancel Order", + "cancel-order-details": "Cancel your order for {{orderSide}} {{orderSize}} {{marketName}} at {{orderPrice}}", + "modify-order": "Modify Order", + "modify-order-details": "Edit your {{marketName}} order from {{orderSide}} {{orderSize}} at {{currentOrderPrice}} to {{orderSide}} {{orderSize}} at {{updatedOrderPrice}}", + "order-details": " ({{orderType}} {{orderSide}}) if price is {{triggerCondition}} {{triggerPrice}}", + "outside-range": "Order Price Outside Range", + "slippage-accept": "Use the trade order form if you wish to accept the potential slippage.", + "slippage-warning": "{{updatedOrderPrice}} is greater than 5% {{aboveBelow}} the current market price of {{selectedMarketPrice}}. Executing this trade could incur significant slippage.", + "toggle-order-line": "Toggle order line visibility", + "toggle-trade-executions": "Toggle trade execution visibility" } \ No newline at end of file diff --git a/public/locales/zh/tv-chart.json b/public/locales/zh/tv-chart.json index c865ddf6..7e425928 100644 --- a/public/locales/zh/tv-chart.json +++ b/public/locales/zh/tv-chart.json @@ -9,5 +9,6 @@ "outside-range": "订单价格在范围之外", "slippage-accept": "若您接受潜在的下滑请使用交易表格进行。", "slippage-warning": "您的订单价格({{updatedOrderPrice}})多余5%{{aboveBelow}}市场价格({{selectedMarketPrice}})表是您也许遭受可观的下滑。", - "toggle-order-line": "切换订单线可见性" + "toggle-order-line": "切换订单线可见性", + "toggle-trade-executions": "Toggle trade execution visibility" } \ No newline at end of file diff --git a/public/locales/zh_tw/tv-chart.json b/public/locales/zh_tw/tv-chart.json index a7e6488c..617ccac1 100644 --- a/public/locales/zh_tw/tv-chart.json +++ b/public/locales/zh_tw/tv-chart.json @@ -9,5 +9,6 @@ "outside-range": "訂單價格在範圍之外", "slippage-accept": "若您接受潛在的下滑請使用交易表格進行。", "slippage-warning": "您的訂單價格({{updatedOrderPrice}})多餘5%{{aboveBelow}}市場價格({{selectedMarketPrice}})表是您也許遭受可觀的下滑。", - "toggle-order-line": "切換訂單線可見性" + "toggle-order-line": "切換訂單線可見性", + "toggle-trade-executions": "Toggle trade execution visibility" } \ No newline at end of file diff --git a/store/mangoStore.ts b/store/mangoStore.ts index 7cc5a00e..368f7c42 100644 --- a/store/mangoStore.ts +++ b/store/mangoStore.ts @@ -2,7 +2,7 @@ import dayjs from 'dayjs' import produce from 'immer' import create from 'zustand' import { subscribeWithSelector } from 'zustand/middleware' -import { AnchorProvider, Wallet, web3 } from '@project-serum/anchor' +import { AnchorProvider, BN, Wallet, web3 } from '@project-serum/anchor' import { Connection, Keypair, PublicKey } from '@solana/web3.js' import { OpenOrders, Order } from '@project-serum/serum/lib/market' import { Orderbook } from '@project-serum/serum' @@ -49,6 +49,7 @@ import spotBalancesUpdater from './spotBalancesUpdater' import { PerpMarket } from '@blockworks-foundation/mango-v4/' import perpPositionsUpdater from './perpPositionsUpdater' import { DEFAULT_PRIORITY_FEE } from '@components/settings/RpcSettings' +import { IOrderLineAdapter } from '@public/charting_library/charting_library' const GROUP = new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX') @@ -317,6 +318,9 @@ export type MangoStore = { data: TokenStatsItem[] | null } tradeForm: TradeForm + tradingView: { + orderLines: Map + } wallet: { tokens: TokenAccount[] nfts: { @@ -461,6 +465,9 @@ const mangoStore = create()( data: [], }, tradeForm: DEFAULT_TRADE_FORM, + tradingView: { + orderLines: new Map(), + }, wallet: { tokens: [], nfts: { diff --git a/utils/constants.ts b/utils/constants.ts index 43d45ba5..6c7d8456 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -45,6 +45,8 @@ export const RPC_PROVIDER_KEY = 'rpcProviderKey-0.4' export const PRIORITY_FEE_KEY = 'priorityFeeKey-0.1' +export const SHOW_ORDER_LINES_KEY = 'showOrderLines-0.1' + // Unused export const PROFILE_CATEGORIES = [ 'borrower', From fdd0c97fcd8f5dfb945e60e3cf67b6760def19f0 Mon Sep 17 00:00:00 2001 From: saml33 Date: Wed, 8 Feb 2023 21:04:20 +1100 Subject: [PATCH 2/2] add missing translation keys --- components/trade/TradingViewChart.tsx | 4 ++-- public/locales/en/trade.json | 2 ++ public/locales/es/trade.json | 2 ++ public/locales/ru/trade.json | 2 ++ public/locales/zh/trade.json | 2 ++ public/locales/zh_tw/trade.json | 2 ++ 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/components/trade/TradingViewChart.tsx b/components/trade/TradingViewChart.tsx index fd1e8680..76066b99 100644 --- a/components/trade/TradingViewChart.tsx +++ b/components/trade/TradingViewChart.tsx @@ -61,7 +61,7 @@ function hexToRgb(hex: string) { } const TradingViewChart = () => { - const { t } = useTranslation('tv-chart') + const { t } = useTranslation(['tv-chart', 'trade']) const { theme } = useTheme() const { width } = useViewport() const [chartReady, setChartReady] = useState(false) @@ -280,7 +280,7 @@ const TradingViewChart = () => { } }, [showOrderLines]) - // updated order lines if a user's open orders change + // update order lines if a user's open orders change useEffect(() => { let subscription if (chartReady && tvWidgetRef?.current) { diff --git a/public/locales/en/trade.json b/public/locales/en/trade.json index 6a1e53a6..a6ea0671 100644 --- a/public/locales/en/trade.json +++ b/public/locales/en/trade.json @@ -20,6 +20,7 @@ "in-orders": "In Orders", "instantaneous-funding": "Instantaneous Funding", "limit-price": "Limit Price", + "long": "Long", "margin": "Margin", "no-balances": "No balances", "no-orders": "No open orders", @@ -41,6 +42,7 @@ "sells": "Sells", "settle-funds": "Settle Funds", "settle-funds-error": "Failed to settle funds", + "short": "Short", "show-asks": "Show Asks", "show-bids": "Show Bids", "side": "Side", diff --git a/public/locales/es/trade.json b/public/locales/es/trade.json index 6a1e53a6..a6ea0671 100644 --- a/public/locales/es/trade.json +++ b/public/locales/es/trade.json @@ -20,6 +20,7 @@ "in-orders": "In Orders", "instantaneous-funding": "Instantaneous Funding", "limit-price": "Limit Price", + "long": "Long", "margin": "Margin", "no-balances": "No balances", "no-orders": "No open orders", @@ -41,6 +42,7 @@ "sells": "Sells", "settle-funds": "Settle Funds", "settle-funds-error": "Failed to settle funds", + "short": "Short", "show-asks": "Show Asks", "show-bids": "Show Bids", "side": "Side", diff --git a/public/locales/ru/trade.json b/public/locales/ru/trade.json index 6a1e53a6..a6ea0671 100644 --- a/public/locales/ru/trade.json +++ b/public/locales/ru/trade.json @@ -20,6 +20,7 @@ "in-orders": "In Orders", "instantaneous-funding": "Instantaneous Funding", "limit-price": "Limit Price", + "long": "Long", "margin": "Margin", "no-balances": "No balances", "no-orders": "No open orders", @@ -41,6 +42,7 @@ "sells": "Sells", "settle-funds": "Settle Funds", "settle-funds-error": "Failed to settle funds", + "short": "Short", "show-asks": "Show Asks", "show-bids": "Show Bids", "side": "Side", diff --git a/public/locales/zh/trade.json b/public/locales/zh/trade.json index 6a1e53a6..a6ea0671 100644 --- a/public/locales/zh/trade.json +++ b/public/locales/zh/trade.json @@ -20,6 +20,7 @@ "in-orders": "In Orders", "instantaneous-funding": "Instantaneous Funding", "limit-price": "Limit Price", + "long": "Long", "margin": "Margin", "no-balances": "No balances", "no-orders": "No open orders", @@ -41,6 +42,7 @@ "sells": "Sells", "settle-funds": "Settle Funds", "settle-funds-error": "Failed to settle funds", + "short": "Short", "show-asks": "Show Asks", "show-bids": "Show Bids", "side": "Side", diff --git a/public/locales/zh_tw/trade.json b/public/locales/zh_tw/trade.json index 6a1e53a6..a6ea0671 100644 --- a/public/locales/zh_tw/trade.json +++ b/public/locales/zh_tw/trade.json @@ -20,6 +20,7 @@ "in-orders": "In Orders", "instantaneous-funding": "Instantaneous Funding", "limit-price": "Limit Price", + "long": "Long", "margin": "Margin", "no-balances": "No balances", "no-orders": "No open orders", @@ -41,6 +42,7 @@ "sells": "Sells", "settle-funds": "Settle Funds", "settle-funds-error": "Failed to settle funds", + "short": "Short", "show-asks": "Show Asks", "show-bids": "Show Bids", "side": "Side",