Merge pull request #34 from blockworks-foundation/feature/kline-charts-spot
Feature/kline chart
This commit is contained in:
commit
d135f5e22c
|
@ -103,8 +103,10 @@ export default {
|
|||
time_to: to,
|
||||
}
|
||||
const query = Object.keys(urlParameters)
|
||||
//@ts-ignore
|
||||
.map((name: any) => `${name}=${encodeURIComponent(urlParameters[name])}`)
|
||||
.map(
|
||||
(name: any) =>
|
||||
`${name}=${encodeURIComponent((urlParameters as any)[name])}`
|
||||
)
|
||||
.join('&')
|
||||
try {
|
||||
const data = await makeApiRequest(`defi/ohlcv/pair?${query}`)
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
const BE_API_KEY =
|
||||
export const BE_API_KEY =
|
||||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE2Njc1NTI4MzV9.FpbBT3M6GN_TKSJ8CarGeOMU5U7ZUvgZOIy8789m1bk'
|
||||
|
||||
export const API_URL = 'https://public-api.birdeye.so/'
|
||||
|
||||
// Make requests to CryptoCompare API
|
||||
export async function makeApiRequest(path: string) {
|
||||
try {
|
||||
const response = await fetch(`https://public-api.birdeye.so/${path}`, {
|
||||
const response = await fetch(`${API_URL}${path}`, {
|
||||
headers: {
|
||||
'X-API-KEY': BE_API_KEY,
|
||||
},
|
||||
|
|
|
@ -6,7 +6,11 @@ import { useTranslation } from 'next-i18next'
|
|||
import { useTheme } from 'next-themes'
|
||||
// import { useRouter } from 'next/router'
|
||||
// import { useCallback } from 'react'
|
||||
import { NOTIFICATION_POSITION_KEY, SIZE_INPUT_UI_KEY } from 'utils/constants'
|
||||
import {
|
||||
NOTIFICATION_POSITION_KEY,
|
||||
SIZE_INPUT_UI_KEY,
|
||||
TRADE_CHART_UI_KEY,
|
||||
} from 'utils/constants'
|
||||
|
||||
const NOTIFICATION_POSITIONS = [
|
||||
'bottom-left',
|
||||
|
@ -54,6 +58,10 @@ const DisplaySettings = () => {
|
|||
SIZE_INPUT_UI_KEY,
|
||||
'Slider'
|
||||
)
|
||||
const [tradeChartUi, setTradeChartUi] = useLocalStorageState(
|
||||
TRADE_CHART_UI_KEY,
|
||||
'Trading'
|
||||
)
|
||||
|
||||
// const handleLangChange = useCallback(
|
||||
// (l: string) => {
|
||||
|
@ -117,6 +125,16 @@ const DisplaySettings = () => {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col border-t border-th-bkg-3 py-4 md:flex-row md:items-center md:justify-between md:px-4">
|
||||
<p className="mb-2 lg:mb-0">{t('settings:trading-chart')}</p>
|
||||
<div className="w-full min-w-[160px] md:w-auto">
|
||||
<ButtonGroup
|
||||
activeValue={tradeChartUi}
|
||||
onChange={(v) => setTradeChartUi(v)}
|
||||
values={[t('settings:original'), t('settings:trading')]}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import { useMemo } from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import ReactGridLayout, { Responsive, WidthProvider } from 'react-grid-layout'
|
||||
|
||||
import mangoStore from '@store/mangoStore'
|
||||
// import { IS_ONBOARDED_KEY } from 'utils/constants'
|
||||
// import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
|
@ -16,7 +15,7 @@ import OrderbookAndTrades from './OrderbookAndTrades'
|
|||
// import TradeOnboardingTour from '@components/tours/TradeOnboardingTour'
|
||||
import FavoriteMarketsBar from './FavoriteMarketsBar'
|
||||
|
||||
const TradingViewChart = dynamic(() => import('./TradingViewChart'), {
|
||||
const TradingChartContainer = dynamic(() => import('./TradingChartContainer'), {
|
||||
ssr: false,
|
||||
})
|
||||
|
||||
|
@ -178,7 +177,7 @@ const TradeAdvancedPage = () => {
|
|||
className="h-full border border-x-0 border-th-bkg-3"
|
||||
>
|
||||
<div className={`relative h-full overflow-auto`}>
|
||||
<TradingViewChart />
|
||||
<TradingChartContainer />
|
||||
</div>
|
||||
</div>
|
||||
<div key="balances">
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
import useLocalStorageState from 'hooks/useLocalStorageState'
|
||||
import dynamic from 'next/dynamic'
|
||||
import { TRADE_CHART_UI_KEY } from 'utils/constants'
|
||||
|
||||
const TradingViewChart = dynamic(() => import('./TradingViewChart'), {
|
||||
ssr: false,
|
||||
})
|
||||
|
||||
const TradingViewChartKlineContainer = dynamic(
|
||||
() => import('./TradingViewChartKlineContainer'),
|
||||
{
|
||||
ssr: false,
|
||||
}
|
||||
)
|
||||
|
||||
const TradingChartContainer = () => {
|
||||
const [tradingChart] = useLocalStorageState(TRADE_CHART_UI_KEY)
|
||||
const isTradingChart = tradingChart === 'Original'
|
||||
return !isTradingChart ? (
|
||||
<TradingViewChart></TradingViewChart>
|
||||
) : (
|
||||
<TradingViewChartKlineContainer></TradingViewChartKlineContainer>
|
||||
)
|
||||
}
|
||||
|
||||
export default TradingChartContainer
|
|
@ -0,0 +1,359 @@
|
|||
import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react'
|
||||
import mangoStore from '@store/mangoStore'
|
||||
import klinecharts, { init, dispose } from 'klinecharts'
|
||||
import axios from 'axios'
|
||||
import { useViewport } from 'hooks/useViewport'
|
||||
import usePrevious from '@components/shared/usePrevious'
|
||||
import Modal from '@components/shared/Modal'
|
||||
import Switch from '@components/forms/Switch'
|
||||
import {
|
||||
BASE_CHART_QUERY,
|
||||
CHART_QUERY,
|
||||
DEFAULT_MAIN_INDICATORS,
|
||||
DEFAULT_SUB_INDICATOR,
|
||||
HISTORY,
|
||||
mainTechnicalIndicatorTypes,
|
||||
MAIN_INDICATOR_CLASS,
|
||||
ONE_DAY_SECONDS,
|
||||
RES_NAME_TO_RES_VAL,
|
||||
subTechnicalIndicatorTypes,
|
||||
} from 'utils/kLineChart'
|
||||
import { ArrowsPointingOutIcon } from '@heroicons/react/24/outline'
|
||||
import Loading from '@components/shared/Loading'
|
||||
import clsx from 'clsx'
|
||||
import { API_URL, BE_API_KEY } from 'apis/birdeye/helpers'
|
||||
|
||||
const UPDATE_INTERVAL = 10000
|
||||
|
||||
type Props = {
|
||||
setIsFullView?: Dispatch<SetStateAction<boolean>>
|
||||
isFullView?: boolean
|
||||
}
|
||||
|
||||
const TradingViewChartKline = ({ setIsFullView, isFullView }: Props) => {
|
||||
const { width } = useViewport()
|
||||
const prevWidth = usePrevious(width)
|
||||
const selectedMarket = mangoStore((s) => s.selectedMarket.current)
|
||||
const selectedMarketName = selectedMarket?.name
|
||||
const [isTechnicalModalOpen, setIsTechnicalModalOpen] = useState(false)
|
||||
const [mainTechnicalIndicators, setMainTechnicalIndicators] = useState<
|
||||
string[]
|
||||
>([])
|
||||
const [subTechnicalIndicators, setSubTechnicalIndicators] = useState<{
|
||||
//indicatorName: class
|
||||
[indicatorName: string]: string
|
||||
}>({})
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [resolution, setResolution] = useState(RES_NAME_TO_RES_VAL['1H'])
|
||||
const [chart, setChart] = useState<klinecharts.Chart | null>(null)
|
||||
const previousChart = usePrevious(chart)
|
||||
const [baseChartQuery, setQuery] = useState<BASE_CHART_QUERY | null>(null)
|
||||
const clearTimerRef = useRef<NodeJS.Timeout | null>(null)
|
||||
const fetchData = async (baseQuery: BASE_CHART_QUERY, from: number) => {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
const query: CHART_QUERY = {
|
||||
...baseQuery,
|
||||
time_from: from,
|
||||
}
|
||||
const response = await axios.get(`${API_URL}defi/ohlcv/pair`, {
|
||||
params: query,
|
||||
headers: {
|
||||
'X-API-KEY': BE_API_KEY,
|
||||
},
|
||||
})
|
||||
const newData = response.data.data.items as HISTORY[]
|
||||
const dataSize = newData.length
|
||||
const dataList = []
|
||||
for (let i = 0; i < dataSize; i++) {
|
||||
const row = newData[i]
|
||||
const kLineModel = {
|
||||
open: row.o,
|
||||
low: row.l,
|
||||
high: row.h,
|
||||
close: row.c,
|
||||
volume: row.v,
|
||||
timestamp: row.unixTime * 1000,
|
||||
}
|
||||
dataList.push(kLineModel)
|
||||
}
|
||||
setIsLoading(false)
|
||||
return dataList
|
||||
} catch (e) {
|
||||
setIsLoading(false)
|
||||
console.log(e)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
//update data every 10 secs
|
||||
function updateData(
|
||||
kLineChart: klinecharts.Chart,
|
||||
baseQuery: BASE_CHART_QUERY
|
||||
) {
|
||||
if (clearTimerRef.current) {
|
||||
clearInterval(clearTimerRef.current)
|
||||
}
|
||||
clearTimerRef.current = setTimeout(async () => {
|
||||
if (kLineChart) {
|
||||
const from = baseQuery.time_to - resolution.seconds
|
||||
const newData = (await fetchData(baseQuery!, from))[0]
|
||||
if (newData) {
|
||||
newData.timestamp += UPDATE_INTERVAL
|
||||
kLineChart.updateData(newData)
|
||||
updateData(kLineChart, baseQuery)
|
||||
}
|
||||
}
|
||||
}, UPDATE_INTERVAL)
|
||||
}
|
||||
const fetchFreshData = async (daysToSubtractFromToday: number) => {
|
||||
const from =
|
||||
Math.floor(Date.now() / 1000) - ONE_DAY_SECONDS * daysToSubtractFromToday
|
||||
const data = await fetchData(baseChartQuery!, from)
|
||||
if (chart) {
|
||||
chart.applyNewData(data)
|
||||
//after we fetch fresh data start to update data every x seconds
|
||||
updateData(chart, baseChartQuery!)
|
||||
}
|
||||
}
|
||||
|
||||
//size change
|
||||
useEffect(() => {
|
||||
if (width !== prevWidth && chart) {
|
||||
//wait for event que to be empty
|
||||
//to have current width
|
||||
setTimeout(() => {
|
||||
chart?.resize()
|
||||
}, 0)
|
||||
}
|
||||
}, [width])
|
||||
|
||||
//when base query change we refetch with fresh data
|
||||
useEffect(() => {
|
||||
if (chart && baseChartQuery) {
|
||||
fetchFreshData(14)
|
||||
//add callback to fetch more data when zoom out
|
||||
chart.loadMore(() => {
|
||||
try {
|
||||
fetchFreshData(365)
|
||||
} catch (e) {
|
||||
console.log('Error fetching new data')
|
||||
}
|
||||
chart.loadMore(() => null)
|
||||
})
|
||||
}
|
||||
}, [baseChartQuery])
|
||||
|
||||
//change query based on market and resolution
|
||||
useEffect(() => {
|
||||
if (selectedMarketName && resolution) {
|
||||
setQuery({
|
||||
type: resolution.val,
|
||||
address: '8BnEgHoWFysVcuFFX7QztDmzuH8r5ZFvyP3sYwn1XTh6',
|
||||
time_to: Math.floor(Date.now() / 1000),
|
||||
})
|
||||
}
|
||||
}, [selectedMarketName, resolution])
|
||||
|
||||
//init default technical indicators after init of chart
|
||||
useEffect(() => {
|
||||
if (chart !== null && previousChart === null) {
|
||||
if (DEFAULT_SUB_INDICATOR) {
|
||||
const subId = chart.createTechnicalIndicator(
|
||||
DEFAULT_SUB_INDICATOR,
|
||||
true
|
||||
)
|
||||
setSubTechnicalIndicators({ [DEFAULT_SUB_INDICATOR]: subId })
|
||||
}
|
||||
if (DEFAULT_MAIN_INDICATORS?.length) {
|
||||
for (const type of DEFAULT_MAIN_INDICATORS) {
|
||||
chart?.createTechnicalIndicator(type, true, {
|
||||
id: MAIN_INDICATOR_CLASS,
|
||||
})
|
||||
}
|
||||
setMainTechnicalIndicators(DEFAULT_MAIN_INDICATORS)
|
||||
}
|
||||
}
|
||||
}, [chart !== null])
|
||||
|
||||
//init chart without data
|
||||
useEffect(() => {
|
||||
const initKline = async () => {
|
||||
const style = getComputedStyle(document.body)
|
||||
const gridColor = style.getPropertyValue('--bkg-3')
|
||||
const kLineChart = init('update-k-line')
|
||||
kLineChart.setStyleOptions({
|
||||
grid: {
|
||||
show: true,
|
||||
horizontal: {
|
||||
style: 'solid',
|
||||
color: gridColor,
|
||||
},
|
||||
vertical: {
|
||||
style: 'solid',
|
||||
color: gridColor,
|
||||
},
|
||||
},
|
||||
candle: {
|
||||
tooltip: {
|
||||
labels: ['T: ', 'O: ', 'C: ', 'H: ', 'L: ', 'V: '],
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
axisLine: {
|
||||
show: true,
|
||||
color: gridColor,
|
||||
size: 1,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
axisLine: {
|
||||
show: true,
|
||||
color: gridColor,
|
||||
size: 1,
|
||||
},
|
||||
},
|
||||
separator: {
|
||||
size: 2,
|
||||
color: gridColor,
|
||||
},
|
||||
})
|
||||
setChart(kLineChart)
|
||||
}
|
||||
initKline()
|
||||
return () => {
|
||||
dispose('update-k-line')
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'fixed h-full w-full',
|
||||
isFullView &&
|
||||
'left-[64px] top-0 right-0 bottom-0 bg-th-bkg-1 text-th-fgd-1'
|
||||
)}
|
||||
>
|
||||
<div className="flex w-full">
|
||||
{Object.keys(RES_NAME_TO_RES_VAL).map((key) => (
|
||||
<div
|
||||
className={clsx(
|
||||
'cursor-pointer py-1 px-2',
|
||||
resolution === RES_NAME_TO_RES_VAL[key] && 'text-th-active'
|
||||
)}
|
||||
key={key}
|
||||
onClick={() => setResolution(RES_NAME_TO_RES_VAL[key])}
|
||||
>
|
||||
{key}
|
||||
</div>
|
||||
))}
|
||||
<div
|
||||
className="cursor-pointer py-1 px-2 "
|
||||
onClick={() => setIsTechnicalModalOpen(true)}
|
||||
>
|
||||
Indicator
|
||||
</div>
|
||||
{setIsFullView && (
|
||||
<div className="cursor-pointer py-1 px-2">
|
||||
<ArrowsPointingOutIcon
|
||||
onClick={() => setIsFullView(!isFullView)}
|
||||
className="w-5"
|
||||
></ArrowsPointingOutIcon>
|
||||
</div>
|
||||
)}
|
||||
<div className="py-1 px-2">
|
||||
{isLoading && <Loading className="w-4"></Loading>}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
style={{ height: 'calc(100% - 30px)', width: '100%' }}
|
||||
id="update-k-line"
|
||||
className="k-line-chart"
|
||||
/>
|
||||
<Modal
|
||||
isOpen={isTechnicalModalOpen}
|
||||
onClose={() => setIsTechnicalModalOpen(false)}
|
||||
>
|
||||
<div className="flex max-h-96 flex-col overflow-auto text-left">
|
||||
<h2 className="py-4">Main Indicator</h2>
|
||||
{mainTechnicalIndicatorTypes.map((type) => {
|
||||
return (
|
||||
<IndicatorSwitch
|
||||
key={type}
|
||||
type={type}
|
||||
checked={!!mainTechnicalIndicators.find((x) => x === type)}
|
||||
onChange={(check) => {
|
||||
if (check) {
|
||||
chart?.createTechnicalIndicator(type, true, {
|
||||
id: MAIN_INDICATOR_CLASS,
|
||||
})
|
||||
setMainTechnicalIndicators([
|
||||
...mainTechnicalIndicators,
|
||||
type,
|
||||
])
|
||||
} else {
|
||||
chart?.removeTechnicalIndicator(MAIN_INDICATOR_CLASS, type)
|
||||
setMainTechnicalIndicators([
|
||||
...mainTechnicalIndicators.filter((x) => x !== type),
|
||||
])
|
||||
}
|
||||
}}
|
||||
></IndicatorSwitch>
|
||||
)
|
||||
})}
|
||||
<h2 className="py-4">Sub Indicator</h2>
|
||||
{subTechnicalIndicatorTypes.map((type) => {
|
||||
return (
|
||||
<IndicatorSwitch
|
||||
key={type}
|
||||
type={type}
|
||||
checked={
|
||||
!!Object.keys(subTechnicalIndicators).find((x) => x === type)
|
||||
}
|
||||
onChange={(check) => {
|
||||
if (check) {
|
||||
const subId = chart?.createTechnicalIndicator(type, true)
|
||||
setSubTechnicalIndicators({
|
||||
...subTechnicalIndicators,
|
||||
[type]: subId!,
|
||||
})
|
||||
} else {
|
||||
chart?.removeTechnicalIndicator(
|
||||
subTechnicalIndicators[type],
|
||||
type
|
||||
)
|
||||
const newItems = { ...subTechnicalIndicators }
|
||||
delete newItems[type] // or whichever key you want
|
||||
setSubTechnicalIndicators(newItems)
|
||||
}
|
||||
}}
|
||||
></IndicatorSwitch>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const IndicatorSwitch = ({
|
||||
type,
|
||||
onChange,
|
||||
checked,
|
||||
}: {
|
||||
type: string
|
||||
onChange: (checked: boolean) => void
|
||||
checked: boolean
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className="flex justify-between border-t border-th-bkg-3 p-4 text-th-fgd-4"
|
||||
key={type}
|
||||
>
|
||||
{type}
|
||||
<Switch checked={checked} onChange={onChange} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TradingViewChartKline
|
|
@ -0,0 +1,31 @@
|
|||
import dynamic from 'next/dynamic'
|
||||
import { useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
|
||||
const TradingViewChartKline = dynamic(() => import('./TradingViewChartKline'), {
|
||||
ssr: false,
|
||||
})
|
||||
|
||||
const TradingViewChartKlineContainer = () => {
|
||||
const [isFullView, setIsFullView] = useState<boolean>(false)
|
||||
return (
|
||||
<>
|
||||
{isFullView ? (
|
||||
createPortal(
|
||||
<TradingViewChartKline
|
||||
setIsFullView={setIsFullView}
|
||||
isFullView={isFullView}
|
||||
></TradingViewChartKline>,
|
||||
document.body
|
||||
)
|
||||
) : (
|
||||
<TradingViewChartKline
|
||||
setIsFullView={setIsFullView}
|
||||
isFullView={isFullView}
|
||||
></TradingViewChartKline>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default TradingViewChartKlineContainer
|
|
@ -25,13 +25,16 @@
|
|||
"@types/howler": "^2.2.7",
|
||||
"@types/lodash": "^4.14.185",
|
||||
"assert": "^2.0.0",
|
||||
"axios": "^1.2.0",
|
||||
"big.js": "^6.2.1",
|
||||
"clsx": "^1.2.1",
|
||||
"date-fns": "^2.29.3",
|
||||
"dayjs": "^1.11.3",
|
||||
"decimal.js": "^10.4.0",
|
||||
"howler": "^2.2.3",
|
||||
"html-react-parser": "^3.0.4",
|
||||
"immer": "^9.0.12",
|
||||
"klinecharts": "^8.6.3",
|
||||
"lodash": "^4.17.21",
|
||||
"next": "^13.0.0",
|
||||
"next-i18next": "^11.1.1",
|
||||
|
|
|
@ -38,5 +38,8 @@
|
|||
"top-left": "Top-Left",
|
||||
"top-right": "Top-Right",
|
||||
"transaction-fail": "Transaction Fail",
|
||||
"transaction-success": "Transaction Success"
|
||||
"transaction-success": "Transaction Success",
|
||||
"original": "Original",
|
||||
"trading": "Trading",
|
||||
"trading-chart": "Trading Chart"
|
||||
}
|
|
@ -38,5 +38,8 @@
|
|||
"top-left": "Top-Left",
|
||||
"top-right": "Top-Right",
|
||||
"transaction-fail": "Transaction Fail",
|
||||
"transaction-success": "Transaction Success"
|
||||
"transaction-success": "Transaction Success",
|
||||
"original": "Original",
|
||||
"trading": "Trading",
|
||||
"trading-chart": "Trading Chart"
|
||||
}
|
|
@ -38,5 +38,8 @@
|
|||
"top-left": "Top-Left",
|
||||
"top-right": "Top-Right",
|
||||
"transaction-fail": "Transaction Fail",
|
||||
"transaction-success": "Transaction Success"
|
||||
"transaction-success": "Transaction Success",
|
||||
"original": "Original",
|
||||
"trading": "Trading",
|
||||
"trading-chart": "Trading Chart"
|
||||
}
|
|
@ -38,5 +38,8 @@
|
|||
"top-left": "Top-Left",
|
||||
"top-right": "Top-Right",
|
||||
"transaction-fail": "Transaction Fail",
|
||||
"transaction-success": "Transaction Success"
|
||||
"transaction-success": "Transaction Success",
|
||||
"original": "Original",
|
||||
"trading": "Trading",
|
||||
"trading-chart": "Trading Chart"
|
||||
}
|
|
@ -38,5 +38,8 @@
|
|||
"top-left": "Top-Left",
|
||||
"top-right": "Top-Right",
|
||||
"transaction-fail": "Transaction Fail",
|
||||
"transaction-success": "Transaction Success"
|
||||
"transaction-success": "Transaction Success",
|
||||
"original": "Original",
|
||||
"trading": "Trading",
|
||||
"trading-chart": "Trading Chart"
|
||||
}
|
|
@ -33,6 +33,7 @@ export const GRID_LAYOUT_KEY = 'savedLayouts-0.2'
|
|||
|
||||
export const NOTIFICATION_POSITION_KEY = 'notificationPosition-0.1'
|
||||
|
||||
export const TRADE_CHART_UI_KEY = 'tradeChart'
|
||||
export const FAVORITE_MARKETS_KEY = 'favoriteMarkets-0.2'
|
||||
|
||||
export const THEME_KEY = 'theme-0.1'
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
export const ONE_HOUR_MINS = 60
|
||||
export const ONE_MINUTE_SECONDS = 60
|
||||
export const ONE_HOUR_SECONDS = ONE_HOUR_MINS * ONE_MINUTE_SECONDS
|
||||
export const ONE_DAY_SECONDS = ONE_HOUR_SECONDS * 24
|
||||
export type BASE_CHART_QUERY = {
|
||||
address: string
|
||||
type: string
|
||||
time_to: number
|
||||
}
|
||||
export type CHART_QUERY = BASE_CHART_QUERY & {
|
||||
time_from: number
|
||||
}
|
||||
export type HISTORY = {
|
||||
c: number
|
||||
h: number
|
||||
l: number
|
||||
o: number
|
||||
unixTime: number
|
||||
v: number
|
||||
}
|
||||
//Translate values that api accepts to chart seconds
|
||||
export const RES_NAME_TO_RES_VAL: {
|
||||
[key: string]: {
|
||||
val: string
|
||||
seconds: number
|
||||
}
|
||||
} = {
|
||||
'1m': { val: '1M', seconds: ONE_MINUTE_SECONDS },
|
||||
'5m': { val: '5M', seconds: 5 * ONE_MINUTE_SECONDS },
|
||||
'30m': {
|
||||
val: `30M`,
|
||||
seconds: (ONE_HOUR_MINS / 2) * ONE_MINUTE_SECONDS,
|
||||
},
|
||||
'1H': { val: `1H`, seconds: ONE_HOUR_SECONDS },
|
||||
'2H': { val: `2H`, seconds: ONE_HOUR_SECONDS * 2 },
|
||||
'4H': { val: `4H`, seconds: ONE_HOUR_SECONDS * 4 },
|
||||
'1D': { val: '1D', seconds: 24 * ONE_HOUR_SECONDS },
|
||||
}
|
||||
export const mainTechnicalIndicatorTypes = [
|
||||
'MA',
|
||||
'EMA',
|
||||
'SAR',
|
||||
'BOLL',
|
||||
'SMA',
|
||||
'BBI',
|
||||
'TRIX',
|
||||
]
|
||||
export const subTechnicalIndicatorTypes = [
|
||||
'VOL',
|
||||
'MACD',
|
||||
'RSI',
|
||||
'KDJ',
|
||||
'OBV',
|
||||
'CCI',
|
||||
'WR',
|
||||
'DMI',
|
||||
'MTM',
|
||||
'EMV',
|
||||
]
|
||||
export const DEFAULT_SUB_INDICATOR = 'VOL'
|
||||
export const DEFAULT_MAIN_INDICATORS = ['EMA']
|
||||
export const MAIN_INDICATOR_CLASS = 'candle_pane'
|
61
yarn.lock
61
yarn.lock
|
@ -2177,6 +2177,11 @@ async-mutex@^0.3.2:
|
|||
dependencies:
|
||||
tslib "^2.3.1"
|
||||
|
||||
asynckit@^0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||
|
||||
atomic-sleep@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b"
|
||||
|
@ -2218,6 +2223,15 @@ axios@^0.25.0:
|
|||
dependencies:
|
||||
follow-redirects "^1.14.7"
|
||||
|
||||
axios@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.2.1.tgz#44cf04a3c9f0c2252ebd85975361c026cb9f864a"
|
||||
integrity sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==
|
||||
dependencies:
|
||||
follow-redirects "^1.15.0"
|
||||
form-data "^4.0.0"
|
||||
proxy-from-env "^1.1.0"
|
||||
|
||||
axobject-query@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
|
||||
|
@ -2635,7 +2649,7 @@ cliui@^5.0.0:
|
|||
strip-ansi "^5.2.0"
|
||||
wrap-ansi "^5.1.0"
|
||||
|
||||
clsx@^1.1.1:
|
||||
clsx@^1.1.1, clsx@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
|
||||
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
|
||||
|
@ -2664,6 +2678,13 @@ color-name@^1.1.4, color-name@~1.1.4:
|
|||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
combined-stream@^1.0.8:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@^2.20.3:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
|
@ -2932,6 +2953,11 @@ delay@^5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d"
|
||||
integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==
|
||||
|
||||
delayed-stream@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
|
||||
|
||||
des.js@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843"
|
||||
|
@ -3723,7 +3749,7 @@ flatted@^3.1.0:
|
|||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3"
|
||||
integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==
|
||||
|
||||
follow-redirects@^1.14.0, follow-redirects@^1.14.7:
|
||||
follow-redirects@^1.14.0, follow-redirects@^1.14.7, follow-redirects@^1.15.0:
|
||||
version "1.15.2"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
|
||||
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
|
||||
|
@ -3733,6 +3759,15 @@ foreach@^2.0.5:
|
|||
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
|
||||
integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
fraction.js@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950"
|
||||
|
@ -4400,6 +4435,11 @@ keyvaluestorage-interface@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz#13ebdf71f5284ad54be94bd1ad9ed79adad515ff"
|
||||
integrity sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==
|
||||
|
||||
klinecharts@^8.6.3:
|
||||
version "8.6.3"
|
||||
resolved "https://registry.yarnpkg.com/klinecharts/-/klinecharts-8.6.3.tgz#9ff2c40e31d86ca0600abc5fb8bf546c61daf130"
|
||||
integrity sha512-hGDtWiMNywEDneZFmt+vZ6tOYutCDWV5FPBcXcn7L8kGwe73Q5yJayk8UzP9pIQSBWyxswWIySKh/BVFA6GhuQ==
|
||||
|
||||
language-subtag-registry@~0.3.2:
|
||||
version "0.3.21"
|
||||
resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a"
|
||||
|
@ -4559,6 +4599,18 @@ miller-rabin@^4.0.0:
|
|||
bn.js "^4.0.0"
|
||||
brorand "^1.0.1"
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
mime-types@^2.1.12:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mimic-fn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
|
@ -5135,6 +5187,11 @@ prop-types@15.x, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, pro
|
|||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
proxy-from-env@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||
|
||||
ps-tree@1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/ps-tree/-/ps-tree-1.2.0.tgz#5e7425b89508736cdd4f2224d028f7bb3f722ebd"
|
||||
|
|
Loading…
Reference in New Issue