Feature/kline perp stats (#88)

* kline perp wip

* fix

* make data more common with trading view

* datafeeds

* fixes

* fixes

* fix

* fix error

* better logging
This commit is contained in:
Adrian Brzeziński 2023-02-15 23:17:58 +01:00 committed by GitHub
parent 2c8da6f1a7
commit d9fc7f11ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 385 additions and 322 deletions

View File

@ -1,5 +1,10 @@
import { makeApiRequest, parseResolution } from './helpers' import { makeApiRequest, parseResolution } from './helpers'
import { subscribeOnStream, unsubscribeFromStream } from './streaming' import {
closeSocket,
isOpen,
subscribeOnStream,
unsubscribeFromStream,
} from './streaming'
import mangoStore from '@store/mangoStore' import mangoStore from '@store/mangoStore'
import { import {
DatafeedConfiguration, DatafeedConfiguration,
@ -194,6 +199,7 @@ export default {
resolution as any, resolution as any,
periodParams periodParams
) )
if (!bars || bars.length === 0) { if (!bars || bars.length === 0) {
// "noData" should be set if there is no data in the requested period. // "noData" should be set if there is no data in the requested period.
onHistoryCallback([], { onHistoryCallback([], {
@ -210,6 +216,7 @@ export default {
onHistoryCallback(bars, { onHistoryCallback(bars, {
noData: false, noData: false,
}) })
return bars
} catch (error) { } catch (error) {
console.warn('[getBars]: Get error', error) console.warn('[getBars]: Get error', error)
onErrorCallback(error) onErrorCallback(error)
@ -234,7 +241,11 @@ export default {
}, },
unsubscribeBars: () => { unsubscribeBars: () => {
console.warn('[unsubscribeBars]')
unsubscribeFromStream() unsubscribeFromStream()
}, },
closeSocket: () => {
closeSocket()
},
name: 'birdeye',
isSocketOpen: isOpen,
} }

View File

@ -7,7 +7,7 @@ const socket = new WebSocket(socketUrl, 'echo-protocol')
// Connection opened // Connection opened
socket.addEventListener('open', (_event) => { socket.addEventListener('open', (_event) => {
console.log('[socket] Connected') console.log('[socket] Connected birdeye')
}) })
// Listen for messages // Listen for messages
@ -21,7 +21,6 @@ socket.addEventListener('message', (msg) => {
const nextBarTime = getNextBarTime(lastBar, resolution) const nextBarTime = getNextBarTime(lastBar, resolution)
let bar let bar
if (currTime >= nextBarTime) { if (currTime >= nextBarTime) {
bar = { bar = {
time: nextBarTime, time: nextBarTime,
@ -67,6 +66,11 @@ export function subscribeOnStream(
currency: symbolInfo.type || 'usd', currency: symbolInfo.type || 'usd',
}, },
} }
if (!isOpen(socket)) {
console.warn('Socket Closed')
return
}
console.warn('[subscribeBars birdeye]')
socket.send(JSON.stringify(msg)) socket.send(JSON.stringify(msg))
} }
@ -75,5 +79,24 @@ export function unsubscribeFromStream() {
type: 'UNSUBSCRIBE_PRICE', type: 'UNSUBSCRIBE_PRICE',
} }
if (!isOpen(socket)) {
console.warn('Socket Closed')
return
}
console.warn('[unsubscribeBars birdeye]')
socket.send(JSON.stringify(msg)) socket.send(JSON.stringify(msg))
} }
export function closeSocket() {
if (!isOpen(socket)) {
console.warn('Socket Closed birdeye')
return
}
console.warn('[closeSocket birdeye]')
socket.close()
}
export function isOpen(ws?: WebSocket) {
const sock = ws || socket
return sock.readyState === sock.OPEN
}

View File

@ -1,5 +1,10 @@
import { makeApiRequest, parseResolution } from './helpers' import { makeApiRequest, parseResolution } from './helpers'
import { subscribeOnStream, unsubscribeFromStream } from './streaming' import {
subscribeOnStream,
unsubscribeFromStream,
closeSocket,
isOpen,
} from './streaming'
import mangoStore from '@store/mangoStore' import mangoStore from '@store/mangoStore'
import { import {
DatafeedConfiguration, DatafeedConfiguration,
@ -216,6 +221,7 @@ export default {
onHistoryCallback(bars, { onHistoryCallback(bars, {
noData: false, noData: false,
}) })
return bars
} catch (error) { } catch (error) {
console.warn('[getBars]: Get error', error) console.warn('[getBars]: Get error', error)
onErrorCallback(error) onErrorCallback(error)
@ -240,7 +246,11 @@ export default {
}, },
unsubscribeBars: () => { unsubscribeBars: () => {
console.warn('[unsubscribeBars]')
unsubscribeFromStream() unsubscribeFromStream()
}, },
closeSocket: () => {
closeSocket()
},
name: 'mngo',
isSocketOpen: isOpen,
} }

View File

@ -1,4 +1,4 @@
import { parseResolution, getNextBarTime } from './helpers' import { getNextBarTime } from './helpers'
let subscriptionItem: any = {} let subscriptionItem: any = {}
@ -7,7 +7,7 @@ const socket = new WebSocket(`wss://api.mngo.cloud/fills/v1/`)
// Connection opened // Connection opened
socket.addEventListener('open', (_event) => { socket.addEventListener('open', (_event) => {
console.log('[socket] Connected') console.log('[socket] Connected mngo')
}) })
// Listen for messages // Listen for messages
@ -16,7 +16,6 @@ socket.addEventListener('message', (msg) => {
if (!data.event) return console.warn(data) if (!data.event) return console.warn(data)
if (data.event.maker) return if (data.event.maker) return
const currTime = new Date(data.event.timestamp).getTime() const currTime = new Date(data.event.timestamp).getTime()
const lastBar = subscriptionItem.lastBar const lastBar = subscriptionItem.lastBar
const resolution = subscriptionItem.resolution const resolution = subscriptionItem.resolution
@ -66,7 +65,11 @@ export function subscribeOnStream(
command: 'subscribe', command: 'subscribe',
marketId: 'HwhVGkfsSQ9JSQeQYu2CbkRCLvsh3qRZxG6m4oMVwZpN', marketId: 'HwhVGkfsSQ9JSQeQYu2CbkRCLvsh3qRZxG6m4oMVwZpN',
} }
if (!isOpen(socket)) {
console.warn('Socket Closed')
return
}
console.warn('[subscribeBars mngo]')
socket.send(JSON.stringify(msg)) socket.send(JSON.stringify(msg))
} }
@ -75,6 +78,24 @@ export function unsubscribeFromStream() {
command: 'unsubscribe', command: 'unsubscribe',
marketId: 'HwhVGkfsSQ9JSQeQYu2CbkRCLvsh3qRZxG6m4oMVwZpN', marketId: 'HwhVGkfsSQ9JSQeQYu2CbkRCLvsh3qRZxG6m4oMVwZpN',
} }
if (!isOpen(socket)) {
console.warn('Socket Closed')
return
}
console.warn('[unsubscribeBars mngo]')
socket.send(JSON.stringify(msg)) socket.send(JSON.stringify(msg))
} }
export function closeSocket() {
if (!isOpen(socket)) {
console.warn('Socket Closed mngo')
return
}
console.warn('[closeSocket mngo]')
socket.close()
}
export function isOpen(ws?: WebSocket) {
const sock = ws || socket
return sock.readyState === sock.OPEN
}

View File

@ -1,6 +1,6 @@
import { Dispatch, SetStateAction, useEffect, useState } from 'react' import { Dispatch, SetStateAction, useEffect, useState } from 'react'
import mangoStore from '@store/mangoStore' import mangoStore from '@store/mangoStore'
import klinecharts, { init, dispose, KLineData } from 'klinecharts' import klinecharts, { init, dispose } from 'klinecharts'
import { useViewport } from 'hooks/useViewport' import { useViewport } from 'hooks/useViewport'
import usePrevious from '@components/shared/usePrevious' import usePrevious from '@components/shared/usePrevious'
import Modal from '@components/shared/Modal' import Modal from '@components/shared/Modal'
@ -18,16 +18,12 @@ import {
} from 'utils/kLineChart' } from 'utils/kLineChart'
import Loading from '@components/shared/Loading' import Loading from '@components/shared/Loading'
import clsx from 'clsx' import clsx from 'clsx'
import { useTheme } from 'next-themes'
import { COLORS } from 'styles/colors'
import { IconButton } from '@components/shared/Button' import { IconButton } from '@components/shared/Button'
import { ArrowsPointingOutIcon, XMarkIcon } from '@heroicons/react/20/solid' import { ArrowsPointingOutIcon, XMarkIcon } from '@heroicons/react/20/solid'
import { queryBars } from 'apis/birdeye/datafeed' import spotDataFeed from 'apis/birdeye/datafeed'
import { import perpDataFeed from 'apis/mngo/datafeed'
getNextBarTime, import { sleep } from 'utils'
parseResolution, import { useKlineChart } from 'hooks/useKlineChart'
socketUrl,
} from 'apis/birdeye/helpers'
type Props = { type Props = {
setIsFullView?: Dispatch<SetStateAction<boolean>> setIsFullView?: Dispatch<SetStateAction<boolean>>
@ -35,233 +31,12 @@ type Props = {
} }
const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => { const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => {
const { theme } = useTheme() const { styles } = useKlineChart()
const styles = {
grid: {
show: false,
},
candle: {
bar: {
upColor: COLORS.UP[theme],
downColor: COLORS.DOWN[theme],
},
tooltip: {
labels: ['', 'O:', 'C:', 'H:', 'L:', 'V:'],
text: {
size: 12,
family: 'TT Mono',
weight: 'normal',
color: COLORS.FGD4[theme],
marginLeft: 8,
marginTop: 6,
marginRight: 8,
marginBottom: 0,
},
},
priceMark: {
show: true,
high: {
show: true,
color: COLORS.FGD4[theme],
textMargin: 5,
textSize: 10,
textFamily: 'TT Mono',
textWeight: 'normal',
},
low: {
show: true,
color: COLORS.FGD4[theme],
textMargin: 5,
textSize: 10,
textFamily: 'TT Mono',
textWeight: 'normal',
},
last: {
show: true,
upColor: COLORS.BKG4[theme],
downColor: COLORS.BKG4[theme],
noChangeColor: COLORS.BKG4[theme],
line: {
show: true,
// 'solid'|'dash'
style: 'dash',
dashValue: [4, 4],
size: 1,
},
text: {
show: true,
size: 10,
paddingLeft: 2,
paddingTop: 2,
paddingRight: 2,
paddingBottom: 2,
color: '#FFFFFF',
family: 'TT Mono',
weight: 'normal',
borderRadius: 2,
},
},
},
},
xAxis: {
axisLine: {
show: true,
color: COLORS.BKG4[theme],
size: 1,
},
tickLine: {
show: true,
size: 1,
length: 3,
color: COLORS.BKG4[theme],
},
tickText: {
show: true,
color: COLORS.FGD4[theme],
family: 'TT Mono',
weight: 'normal',
size: 10,
},
},
yAxis: {
axisLine: {
show: true,
color: COLORS.BKG4[theme],
size: 1,
},
tickLine: {
show: true,
size: 1,
length: 3,
color: COLORS.BKG4[theme],
},
tickText: {
show: true,
color: COLORS.FGD4[theme],
family: 'TT Mono',
weight: 'normal',
size: 10,
},
},
crosshair: {
show: true,
horizontal: {
show: true,
line: {
show: true,
style: 'dash',
dashValue: [4, 2],
size: 1,
color: COLORS.FGD4[theme],
},
text: {
show: true,
color: '#FFFFFF',
size: 10,
family: 'TT Mono',
weight: 'normal',
paddingLeft: 2,
paddingRight: 2,
paddingTop: 2,
paddingBottom: 2,
borderSize: 1,
borderColor: COLORS.FGD4[theme],
borderRadius: 2,
backgroundColor: COLORS.FGD4[theme],
},
},
vertical: {
show: true,
line: {
show: true,
style: 'dash',
dashValue: [4, 2],
size: 1,
color: COLORS.FGD4[theme],
},
text: {
show: true,
color: '#FFFFFF',
size: 10,
family: 'TT Mono',
weight: 'normal',
paddingLeft: 2,
paddingRight: 2,
paddingTop: 2,
paddingBottom: 2,
borderSize: 1,
borderColor: COLORS.FGD4[theme],
borderRadius: 2,
backgroundColor: COLORS.FGD4[theme],
},
},
},
technicalIndicator: {
margin: {
top: 0.2,
bottom: 0.1,
},
bar: {
upColor: COLORS.UP[theme],
downColor: COLORS.DOWN[theme],
noChangeColor: '#888888',
},
line: {
size: 1,
colors: ['#FF9600', '#9D65C9', '#2196F3', '#E11D74', '#01C5C4'],
},
circle: {
upColor: '#26A69A',
downColor: '#EF5350',
noChangeColor: '#888888',
},
lastValueMark: {
show: false,
text: {
show: false,
color: '#ffffff',
size: 12,
family: 'Helvetica Neue',
weight: 'normal',
paddingLeft: 3,
paddingTop: 2,
paddingRight: 3,
paddingBottom: 2,
borderRadius: 2,
},
},
tooltip: {
// 'always' | 'follow_cross' | 'none'
showRule: 'always',
// 'standard' | 'rect'
showType: 'standard',
showName: true,
showParams: true,
defaultValue: 'n/a',
text: {
size: 12,
family: 'TT Mono',
weight: 'normal',
color: COLORS.FGD4[theme],
marginTop: 6,
marginRight: 8,
marginBottom: 0,
marginLeft: 8,
},
},
},
separator: {
size: 2,
color: COLORS.BKG4[theme],
},
}
const socket = new WebSocket(socketUrl, 'echo-protocol')
const unsub_msg = {
type: 'UNSUBSCRIBE_PRICE',
}
const { width } = useViewport() const { width } = useViewport()
const prevWidth = usePrevious(width)
const selectedMarket = mangoStore((s) => s.selectedMarket.current) const selectedMarket = mangoStore((s) => s.selectedMarket.current)
const prevWidth = usePrevious(width)
const [currentDataFeed, setCurrentDataFeed] = useState(spotDataFeed)
const previousDataFeed = usePrevious(currentDataFeed)
const [socketConnected, setSocketConnected] = useState(false) const [socketConnected, setSocketConnected] = useState(false)
const selectedMarketName = selectedMarket?.name const selectedMarketName = selectedMarket?.name
const [isTechnicalModalOpen, setIsTechnicalModalOpen] = useState(false) const [isTechnicalModalOpen, setIsTechnicalModalOpen] = useState(false)
@ -277,10 +52,12 @@ const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => {
const [chart, setChart] = useState<klinecharts.Chart | null>(null) const [chart, setChart] = useState<klinecharts.Chart | null>(null)
const previousChart = usePrevious(chart) const previousChart = usePrevious(chart)
const [baseChartQuery, setQuery] = useState<BASE_CHART_QUERY | null>(null) const [baseChartQuery, setQuery] = useState<BASE_CHART_QUERY | null>(null)
const fetchData = async ( const fetchData = async (
baseQuery: BASE_CHART_QUERY, baseQuery: BASE_CHART_QUERY,
from: number, from: number,
to?: number to?: number,
firstDataRequest?: boolean
) => { ) => {
try { try {
setIsLoading(true) setIsLoading(true)
@ -289,15 +66,31 @@ const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => {
time_from: from, time_from: from,
time_to: to ? to : baseQuery.time_to, time_to: to ? to : baseQuery.time_to,
} }
const response = await queryBars(query.address, query.type, { let symbolInfo: any
firstDataRequest: false, currentDataFeed.resolveSymbol(baseQuery.address, (sInfo) => {
symbolInfo = sInfo
})
const response = await currentDataFeed.getBars(
symbolInfo,
query.type as any,
{
firstDataRequest: !!firstDataRequest,
from: query.time_from, from: query.time_from,
to: query.time_to, to: query.time_to,
}) countBack: 0,
const dataSize = response.length },
() => {
return null
},
(e) => {
console.log(e)
return null
}
)
const dataSize = response?.length || 0
const dataList = [] const dataList = []
for (let i = 0; i < dataSize; i++) { for (let i = 0; i < dataSize; i++) {
const row = response[i] const row = response![i]
const kLineModel = { const kLineModel = {
...row, ...row,
} }
@ -312,74 +105,35 @@ const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => {
} }
} }
//update data every 10 secs async function setupSocket(
function setupSocket(
kLineChart: klinecharts.Chart, kLineChart: klinecharts.Chart,
baseQuery: BASE_CHART_QUERY baseQuery: BASE_CHART_QUERY
) { ) {
// Connection opened await sleep(1500)
socket.addEventListener('open', (_event) => {
console.log('[socket] Kline Connected')
})
socket.addEventListener('message', (msg) => {
const data = JSON.parse(msg.data)
if (data.type === 'WELLCOME') {
setSocketConnected(true) setSocketConnected(true)
socket.send(JSON.stringify(unsub_msg)) let symbolInfo: any = undefined
const msg = { currentDataFeed.resolveSymbol(baseQuery.address, (symbolInf) => {
type: 'SUBSCRIBE_PRICE', symbolInfo = symbolInf
data: {
chartType: parseResolution(baseQuery.type),
address: baseQuery.address,
currency: 'pair',
},
}
socket.send(JSON.stringify(msg))
}
if (data.type === 'PRICE_DATA') {
const dataList = kLineChart.getDataList()
const lastItem = dataList[dataList.length - 1]
const currTime = data.data.unixTime * 1000
if (!dataList.length) {
return
}
const lastBar: KLineData & { time: number } = {
...lastItem,
time: lastItem.timestamp,
}
const resolution = parseResolution(baseQuery.type)
const nextBarTime = getNextBarTime(lastBar, resolution)
let bar: KLineData
if (currTime >= nextBarTime) {
bar = {
timestamp: nextBarTime,
open: data.data.o,
high: data.data.h,
low: data.data.l,
close: data.data.c,
volume: data.data.v,
}
} else {
bar = {
...lastBar,
high: Math.max(lastBar.high, data.data.h),
low: Math.min(lastBar.low, data.data.l),
close: data.data.c,
volume: data.data.v,
}
}
kLineChart.updateData(bar)
}
}) })
previousDataFeed.unsubscribeBars()
currentDataFeed.subscribeBars(
symbolInfo,
baseQuery.type,
(bar) => {
kLineChart.updateData(bar)
},
'',
() => {
return null
}
)
} }
const fetchFreshData = async (daysToSubtractFromToday: number) => { const fetchFreshData = async (daysToSubtractFromToday: number) => {
const from = const from =
Math.floor(Date.now() / 1000) - ONE_DAY_SECONDS * daysToSubtractFromToday Math.floor(Date.now() / 1000) - ONE_DAY_SECONDS * daysToSubtractFromToday
const data = await fetchData(baseChartQuery!, from) const data = await fetchData(baseChartQuery!, from, undefined, true)
if (chart) { if (chart) {
chart.applyNewData(data) chart.applyNewData(data)
//after we fetch fresh data start to update data every x seconds
setupSocket(chart, baseChartQuery!) setupSocket(chart, baseChartQuery!)
} }
} }
@ -398,7 +152,7 @@ const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => {
//when base query change we refetch with fresh data //when base query change we refetch with fresh data
useEffect(() => { useEffect(() => {
if (chart && baseChartQuery) { if (chart && baseChartQuery) {
//becuase bird eye send onlu 1k records at one time //because bird eye send only 1k records at one time
//we query for lower amounts of days at the start //we query for lower amounts of days at the start
const halfDayThreshold = ['1', '3'] const halfDayThreshold = ['1', '3']
const twoDaysThreshold = ['5', '15', '30'] const twoDaysThreshold = ['5', '15', '30']
@ -414,23 +168,40 @@ const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => {
const unixTime = timestamp / 1000 const unixTime = timestamp / 1000
const from = unixTime - ONE_DAY_SECONDS * daysToSub const from = unixTime - ONE_DAY_SECONDS * daysToSub
const data = await fetchData(baseChartQuery!, from, unixTime) const data = await fetchData(baseChartQuery!, from, unixTime)
if (!data.length) {
chart.loadMore(() => null)
}
chart.applyMoreData(data) chart.applyMoreData(data)
} catch (e) { } catch (e) {
console.error('Error fetching new data') console.error('Error fetching new data')
} }
}) })
} }
}, [baseChartQuery]) }, [baseChartQuery, currentDataFeed.name])
//change query based on market and resolution //change query based on market and resolution
useEffect(() => { useEffect(() => {
if (selectedMarketName && resolution) { let dataFeed = spotDataFeed
const group = mangoStore.getState().group
let address = '8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6'
if (!selectedMarketName?.toLowerCase().includes('perp') && group) {
address = group!
.getSerum3MarketByName(selectedMarketName!)
.serumMarketExternal.toString()
} else if (group) {
dataFeed = perpDataFeed
address = group!
.getPerpMarketByName(selectedMarketName!)
.publicKey.toString()
}
setCurrentDataFeed(dataFeed)
setQuery({ setQuery({
type: resolution.val, type: resolution.val,
address: '8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6', address: address,
time_to: Math.floor(Date.now() / 1000), time_to: Math.floor(Date.now() / 1000),
}) })
}
}, [selectedMarketName, resolution]) }, [selectedMarketName, resolution])
// init default technical indicators after init of chart // init default technical indicators after init of chart
@ -466,9 +237,8 @@ const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => {
return () => { return () => {
dispose('update-k-line') dispose('update-k-line')
if (socketConnected) { if (socketConnected) {
console.log('[socket] kline disconnected') currentDataFeed.unsubscribeBars()
socket.send(JSON.stringify(unsub_msg)) currentDataFeed.closeSocket()
socket.close()
} }
} }
}, []) }, [])

228
hooks/useKlineChart.ts Normal file
View File

@ -0,0 +1,228 @@
import { useTheme } from 'next-themes'
import { COLORS } from 'styles/colors'
export function useKlineChart() {
const { theme } = useTheme()
const styles = {
grid: {
show: false,
},
candle: {
bar: {
upColor: COLORS.UP[theme],
downColor: COLORS.DOWN[theme],
},
tooltip: {
labels: ['', 'O:', 'C:', 'H:', 'L:', 'V:'],
text: {
size: 12,
family: 'TT Mono',
weight: 'normal',
color: COLORS.FGD4[theme],
marginLeft: 8,
marginTop: 6,
marginRight: 8,
marginBottom: 0,
},
},
priceMark: {
show: true,
high: {
show: true,
color: COLORS.FGD4[theme],
textMargin: 5,
textSize: 10,
textFamily: 'TT Mono',
textWeight: 'normal',
},
low: {
show: true,
color: COLORS.FGD4[theme],
textMargin: 5,
textSize: 10,
textFamily: 'TT Mono',
textWeight: 'normal',
},
last: {
show: true,
upColor: COLORS.BKG4[theme],
downColor: COLORS.BKG4[theme],
noChangeColor: COLORS.BKG4[theme],
line: {
show: true,
// 'solid'|'dash'
style: 'dash',
dashValue: [4, 4],
size: 1,
},
text: {
show: true,
size: 10,
paddingLeft: 2,
paddingTop: 2,
paddingRight: 2,
paddingBottom: 2,
color: '#FFFFFF',
family: 'TT Mono',
weight: 'normal',
borderRadius: 2,
},
},
},
},
xAxis: {
axisLine: {
show: true,
color: COLORS.BKG4[theme],
size: 1,
},
tickLine: {
show: true,
size: 1,
length: 3,
color: COLORS.BKG4[theme],
},
tickText: {
show: true,
color: COLORS.FGD4[theme],
family: 'TT Mono',
weight: 'normal',
size: 10,
},
},
yAxis: {
axisLine: {
show: true,
color: COLORS.BKG4[theme],
size: 1,
},
tickLine: {
show: true,
size: 1,
length: 3,
color: COLORS.BKG4[theme],
},
tickText: {
show: true,
color: COLORS.FGD4[theme],
family: 'TT Mono',
weight: 'normal',
size: 10,
},
},
crosshair: {
show: true,
horizontal: {
show: true,
line: {
show: true,
style: 'dash',
dashValue: [4, 2],
size: 1,
color: COLORS.FGD4[theme],
},
text: {
show: true,
color: '#FFFFFF',
size: 10,
family: 'TT Mono',
weight: 'normal',
paddingLeft: 2,
paddingRight: 2,
paddingTop: 2,
paddingBottom: 2,
borderSize: 1,
borderColor: COLORS.FGD4[theme],
borderRadius: 2,
backgroundColor: COLORS.FGD4[theme],
},
},
vertical: {
show: true,
line: {
show: true,
style: 'dash',
dashValue: [4, 2],
size: 1,
color: COLORS.FGD4[theme],
},
text: {
show: true,
color: '#FFFFFF',
size: 10,
family: 'TT Mono',
weight: 'normal',
paddingLeft: 2,
paddingRight: 2,
paddingTop: 2,
paddingBottom: 2,
borderSize: 1,
borderColor: COLORS.FGD4[theme],
borderRadius: 2,
backgroundColor: COLORS.FGD4[theme],
},
},
},
technicalIndicator: {
margin: {
top: 0.2,
bottom: 0.1,
},
bar: {
upColor: COLORS.UP[theme],
downColor: COLORS.DOWN[theme],
noChangeColor: '#888888',
},
line: {
size: 1,
colors: ['#FF9600', '#9D65C9', '#2196F3', '#E11D74', '#01C5C4'],
},
circle: {
upColor: '#26A69A',
downColor: '#EF5350',
noChangeColor: '#888888',
},
lastValueMark: {
show: false,
text: {
show: false,
color: '#ffffff',
size: 12,
family: 'Helvetica Neue',
weight: 'normal',
paddingLeft: 3,
paddingTop: 2,
paddingRight: 3,
paddingBottom: 2,
borderRadius: 2,
},
},
tooltip: {
// 'always' | 'follow_cross' | 'none'
showRule: 'always',
// 'standard' | 'rect'
showType: 'standard',
showName: true,
showParams: true,
defaultValue: 'n/a',
text: {
size: 12,
family: 'TT Mono',
weight: 'normal',
color: COLORS.FGD4[theme],
marginTop: 6,
marginRight: 8,
marginBottom: 0,
marginLeft: 8,
},
},
},
separator: {
size: 2,
color: COLORS.BKG4[theme],
},
}
return {
styles,
}
}

View File

@ -1,4 +1,4 @@
import { SUPPORTED_RESOLUTIONS } from 'apis/birdeye/datafeed' import { SUPPORTED_RESOLUTIONS as SUPPORTED_SPOT_RESOLUTIONS } from 'apis/birdeye/datafeed'
export const ONE_HOUR_MINS = 60 export const ONE_HOUR_MINS = 60
export const ONE_MINUTE_SECONDS = 60 export const ONE_MINUTE_SECONDS = 60
@ -6,7 +6,7 @@ export const ONE_HOUR_SECONDS = ONE_HOUR_MINS * ONE_MINUTE_SECONDS
export const ONE_DAY_SECONDS = ONE_HOUR_SECONDS * 24 export const ONE_DAY_SECONDS = ONE_HOUR_SECONDS * 24
export type BASE_CHART_QUERY = { export type BASE_CHART_QUERY = {
address: string address: string
type: typeof SUPPORTED_RESOLUTIONS[number] type: typeof SUPPORTED_SPOT_RESOLUTIONS[number]
time_to: number time_to: number
} }
export type CHART_QUERY = BASE_CHART_QUERY & { export type CHART_QUERY = BASE_CHART_QUERY & {
@ -16,7 +16,7 @@ export type CHART_QUERY = BASE_CHART_QUERY & {
//Translate values that api accepts to chart seconds //Translate values that api accepts to chart seconds
export const RES_NAME_TO_RES_VAL: { export const RES_NAME_TO_RES_VAL: {
[key: string]: { [key: string]: {
val: typeof SUPPORTED_RESOLUTIONS[number] val: typeof SUPPORTED_SPOT_RESOLUTIONS[number]
seconds: number seconds: number
} }
} = { } = {