Merge pull request #85 from blockworks-foundation/stable-price-tv-line
add stable price line to tv chart
This commit is contained in:
commit
d713692dc6
|
@ -6,6 +6,7 @@ import {
|
|||
IChartingLibraryWidget,
|
||||
ResolutionString,
|
||||
IOrderLineAdapter,
|
||||
EntityId,
|
||||
} from '@public/charting_library'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useViewport } from 'hooks/useViewport'
|
||||
|
@ -13,6 +14,7 @@ import {
|
|||
CHART_DATA_FEED,
|
||||
DEFAULT_MARKET_NAME,
|
||||
SHOW_ORDER_LINES_KEY,
|
||||
SHOW_STABLE_PRICE_KEY,
|
||||
} from 'utils/constants'
|
||||
import { breakpoints } from 'utils/theme'
|
||||
import { COLORS } from 'styles/colors'
|
||||
|
@ -34,6 +36,7 @@ import { formatNumericValue, getDecimalCount } from 'utils/numbers'
|
|||
import { BN } from '@project-serum/anchor'
|
||||
import SpotDatafeed from 'apis/birdeye/datafeed'
|
||||
import PerpDatafeed from 'apis/mngo/datafeed'
|
||||
import useStablePrice from 'hooks/useStablePrice'
|
||||
|
||||
export interface ChartContainerProps {
|
||||
container: ChartingLibraryWidgetOptions['container']
|
||||
|
@ -72,6 +75,14 @@ const TradingViewChart = () => {
|
|||
const [showOrderLines, toggleShowOrderLines] = useState(
|
||||
showOrderLinesLocalStorage
|
||||
)
|
||||
|
||||
const [showStablePriceLocalStorage, toggleShowStablePriceLocalStorage] =
|
||||
useLocalStorageState(SHOW_STABLE_PRICE_KEY, false)
|
||||
const [showStablePrice, toggleShowStablePrice] = useState(
|
||||
showStablePriceLocalStorage
|
||||
)
|
||||
const stablePrice = useStablePrice()
|
||||
const stablePriceLine = mangoStore((s) => s.tradingView.stablePriceLine)
|
||||
const selectedMarketName = mangoStore((s) => s.selectedMarket.current?.name)
|
||||
const isMobile = width ? width < breakpoints.sm : false
|
||||
|
||||
|
@ -233,17 +244,115 @@ const TradingViewChart = () => {
|
|||
|
||||
tvWidgetRef.current.onChartReady(function () {
|
||||
createOLButton()
|
||||
createStablePriceButton()
|
||||
if (showOrderLines) {
|
||||
const openOrders = mangoStore.getState().mangoAccount.openOrders
|
||||
deleteLines()
|
||||
drawLinesForMarket(openOrders)
|
||||
}
|
||||
if (showStablePrice && stablePrice) {
|
||||
const set = mangoStore.getState().set
|
||||
set((s) => {
|
||||
s.tradingView.stablePriceLine = drawStablePriceLine(stablePrice)
|
||||
})
|
||||
}
|
||||
setChartReady(true)
|
||||
})
|
||||
//eslint-disable-next-line
|
||||
}
|
||||
}, [theme, isMobile, defaultProps, spotOrPerp])
|
||||
|
||||
const createStablePriceButton = () => {
|
||||
const button = tvWidgetRef?.current?.createButton()
|
||||
if (!button) {
|
||||
return
|
||||
}
|
||||
button.textContent = 'SP'
|
||||
if (showStablePriceLocalStorage) {
|
||||
button.style.color = COLORS.ACTIVE[theme]
|
||||
} else {
|
||||
button.style.color = COLORS.FGD4[theme]
|
||||
}
|
||||
button.setAttribute('title', t('tv-chart:toggle-stable-price'))
|
||||
button.addEventListener('click', toggleStablePrice)
|
||||
}
|
||||
|
||||
function toggleStablePrice(this: HTMLElement) {
|
||||
toggleShowStablePrice((prevState: boolean) => !prevState)
|
||||
if (this.style.color === hexToRgb(COLORS.ACTIVE[theme])) {
|
||||
this.style.color = COLORS.FGD4[theme]
|
||||
} else {
|
||||
this.style.color = COLORS.ACTIVE[theme]
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (showStablePrice !== showStablePriceLocalStorage) {
|
||||
toggleShowStablePriceLocalStorage(showStablePrice)
|
||||
}
|
||||
}, [showStablePrice])
|
||||
|
||||
useEffect(() => {
|
||||
if (tvWidgetRef.current && chartReady) {
|
||||
if (stablePriceLine) {
|
||||
removeStablePrice(stablePriceLine)
|
||||
}
|
||||
if (showStablePrice && stablePrice) {
|
||||
const set = mangoStore.getState().set
|
||||
set((s) => {
|
||||
s.tradingView.stablePriceLine = drawStablePriceLine(stablePrice)
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [stablePrice, showStablePrice, chartReady, tvWidgetRef])
|
||||
|
||||
function drawStablePriceLine(price: number) {
|
||||
if (!tvWidgetRef?.current?.chart()) return
|
||||
const newStablePrice: Map<string, EntityId> = new Map()
|
||||
const now = Date.now() / 1000
|
||||
try {
|
||||
const id = tvWidgetRef.current.chart().createShape(
|
||||
{ time: now, price: price },
|
||||
{
|
||||
shape: 'horizontal_line',
|
||||
overrides: {
|
||||
linecolor: COLORS.FGD4[theme],
|
||||
linestyle: 1,
|
||||
linewidth: 1,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (id) {
|
||||
try {
|
||||
newStablePrice.set(`${now}${price}`, id)
|
||||
} catch (error) {
|
||||
console.log('failed to set stable price line')
|
||||
}
|
||||
} else {
|
||||
console.log('failed to create stable price line')
|
||||
}
|
||||
} catch {
|
||||
console.log('failed to create stable price line')
|
||||
}
|
||||
return newStablePrice
|
||||
}
|
||||
|
||||
const removeStablePrice = (stablePrice: Map<string, EntityId>) => {
|
||||
if (!tvWidgetRef?.current?.chart()) return
|
||||
const set = mangoStore.getState().set
|
||||
for (const val of stablePrice.values()) {
|
||||
try {
|
||||
tvWidgetRef.current.chart().removeEntity(val)
|
||||
} catch (error) {
|
||||
console.log('stable price could not be removed')
|
||||
}
|
||||
}
|
||||
set((s) => {
|
||||
s.tradingView.stablePriceLine = new Map()
|
||||
})
|
||||
}
|
||||
|
||||
const createOLButton = () => {
|
||||
const button = tvWidgetRef?.current?.createButton()
|
||||
if (!button) {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import { I80F48, PerpMarket } from '@blockworks-foundation/mango-v4'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import { useMemo } from 'react'
|
||||
import useMangoGroup from './useMangoGroup'
|
||||
import useSelectedMarket from './useSelectedMarket'
|
||||
|
||||
const useStablePrice = () => {
|
||||
const { selectedMarket } = useSelectedMarket()
|
||||
const perpMarkets = mangoStore((s) => s.perpMarkets)
|
||||
const { group } = useMangoGroup()
|
||||
|
||||
const banks = useMemo(() => {
|
||||
if (!group) return []
|
||||
return Array.from(group.banksMapByMint)
|
||||
.map(([mintAddress, banks]) => banks)
|
||||
.map((b) => b[0])
|
||||
}, [group])
|
||||
|
||||
const stablePrice = useMemo(() => {
|
||||
if (!group || !selectedMarket || !banks.length) return 0
|
||||
let stablePrice
|
||||
if (selectedMarket instanceof PerpMarket) {
|
||||
stablePrice = selectedMarket.stablePriceModel.stablePrice || 0
|
||||
} else {
|
||||
const baseBank = banks.find(
|
||||
(b) => b.tokenIndex === selectedMarket.baseTokenIndex
|
||||
)
|
||||
const quoteBank = banks.find(
|
||||
(b) => b.tokenIndex === selectedMarket.quoteTokenIndex
|
||||
)
|
||||
|
||||
const baseStablePrice = group.toUiPrice(
|
||||
I80F48.fromNumber(baseBank!.stablePriceModel.stablePrice),
|
||||
baseBank!.mintDecimals
|
||||
)
|
||||
const quoteStablePrice = group.toUiPrice(
|
||||
I80F48.fromNumber(quoteBank!.stablePriceModel.stablePrice),
|
||||
quoteBank!.mintDecimals
|
||||
)
|
||||
stablePrice = baseStablePrice / quoteStablePrice
|
||||
}
|
||||
return stablePrice
|
||||
}, [banks, group, perpMarkets, selectedMarket])
|
||||
|
||||
return stablePrice
|
||||
}
|
||||
|
||||
export default useStablePrice
|
|
@ -7,6 +7,7 @@
|
|||
"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",
|
||||
"toggle-stable-price": "Toggle stable price line",
|
||||
"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",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"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",
|
||||
"toggle-stable-price": "Toggle stable price line",
|
||||
"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",
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
"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",
|
||||
"toggle-stable-price": "Toggle stable price line",
|
||||
"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",
|
||||
|
|
|
@ -10,5 +10,6 @@
|
|||
"slippage-accept": "若您接受潜在的下滑请使用交易表格进行。",
|
||||
"slippage-warning": "您的订单价格({{updatedOrderPrice}})多余5%{{aboveBelow}}市场价格({{selectedMarketPrice}})表是您也许遭受可观的下滑。",
|
||||
"toggle-order-line": "切换订单线可见性",
|
||||
"toggle-stable-price": "Toggle stable price line",
|
||||
"toggle-trade-executions": "Toggle trade execution visibility"
|
||||
}
|
|
@ -10,5 +10,6 @@
|
|||
"slippage-accept": "若您接受潛在的下滑請使用交易表格進行。",
|
||||
"slippage-warning": "您的訂單價格({{updatedOrderPrice}})多餘5%{{aboveBelow}}市場價格({{selectedMarketPrice}})表是您也許遭受可觀的下滑。",
|
||||
"toggle-order-line": "切換訂單線可見性",
|
||||
"toggle-stable-price": "Toggle stable price line",
|
||||
"toggle-trade-executions": "Toggle trade execution visibility"
|
||||
}
|
|
@ -49,7 +49,10 @@ 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'
|
||||
import {
|
||||
EntityId,
|
||||
IOrderLineAdapter,
|
||||
} from '@public/charting_library/charting_library'
|
||||
|
||||
const GROUP = new PublicKey('78b8f4cGCwmZ9ysPFMWLaLTkkaYnUjwMJYStWe5RTSSX')
|
||||
|
||||
|
@ -333,6 +336,7 @@ export type MangoStore = {
|
|||
}
|
||||
tradeForm: TradeForm
|
||||
tradingView: {
|
||||
stablePriceLine: Map<string, EntityId> | undefined
|
||||
orderLines: Map<string | BN, IOrderLineAdapter>
|
||||
}
|
||||
wallet: {
|
||||
|
@ -480,6 +484,7 @@ const mangoStore = create<MangoStore>()(
|
|||
},
|
||||
tradeForm: DEFAULT_TRADE_FORM,
|
||||
tradingView: {
|
||||
stablePriceLine: new Map(),
|
||||
orderLines: new Map(),
|
||||
},
|
||||
wallet: {
|
||||
|
|
|
@ -45,6 +45,8 @@ export const RPC_PROVIDER_KEY = 'rpcProviderKey-0.4'
|
|||
|
||||
export const PRIORITY_FEE_KEY = 'priorityFeeKey-0.1'
|
||||
|
||||
export const SHOW_STABLE_PRICE_KEY = 'showStablePriceKey-0.1'
|
||||
|
||||
export const SHOW_ORDER_LINES_KEY = 'showOrderLines-0.1'
|
||||
|
||||
// Unused
|
||||
|
|
Loading…
Reference in New Issue