wire up trade history
This commit is contained in:
parent
9e67c147bf
commit
56c0372a7f
|
@ -65,37 +65,37 @@ const BalancesTable = () => {
|
|||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Coin
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Deposits
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Borrows
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
In Orders
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Unsettled
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Net
|
||||
</th>
|
||||
|
@ -110,32 +110,32 @@ const BalancesTable = () => {
|
|||
`}
|
||||
>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{balance.coin}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{balance.marginDeposits}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{balance.borrows}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{balance.orders}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{balance.unsettled}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{balance.net}
|
||||
</td>
|
||||
|
@ -146,7 +146,7 @@ const BalancesTable = () => {
|
|||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={`w-full text-center py-6 text-base bg-th-bkg-1 font-light text-th-fgd-4 rounded-md`}
|
||||
className={`w-full text-center py-6 text-base bg-th-bkg-1 font-light text-th-fgd-2 rounded-md`}
|
||||
>
|
||||
No balances
|
||||
</div>
|
||||
|
|
|
@ -49,11 +49,11 @@ const FeeDiscountsTable = () => {
|
|||
</div>
|
||||
<div className="mt-6">
|
||||
{connected ? (
|
||||
<div className="bg-th-bkg-2 p-6">
|
||||
<div className="text-th-fgd-4 text-center">
|
||||
<div className="bg-th-bkg-2 p-6 rounded">
|
||||
<div className="text-th-fgd-4 text-center text-lg">
|
||||
Your contributed SRM: {contributedSrm}
|
||||
</div>
|
||||
<div className="flex space-x-4 mt-8">
|
||||
<div className="flex space-x-4 mt-4">
|
||||
<Button onClick={() => setShowDeposit(true)}>Deposit</Button>
|
||||
<Button onClick={() => setShowWithdraw(true)}>Withdraw</Button>
|
||||
</div>
|
||||
|
|
|
@ -61,25 +61,25 @@ const OpenOrdersTable = () => {
|
|||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Market
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Side
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Size
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-4 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Price
|
||||
</th>
|
||||
|
@ -97,12 +97,12 @@ const OpenOrdersTable = () => {
|
|||
`}
|
||||
>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{order.marketName}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
<div
|
||||
className={`rounded inline-block bg-mango-green px-2 py-1 text-mango-dark font-bold`}
|
||||
|
@ -111,12 +111,12 @@ const OpenOrdersTable = () => {
|
|||
</div>
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{order.size}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-4 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{order.price}
|
||||
</td>
|
||||
|
@ -142,7 +142,7 @@ const OpenOrdersTable = () => {
|
|||
</div>
|
||||
) : (
|
||||
<div
|
||||
className={`w-full text-center py-6 text-base bg-th-bkg-1 font-light text-th-fgd-4 rounded-md`}
|
||||
className={`w-full text-center py-6 text-base bg-th-bkg-1 font-light text-th-fgd-2 rounded-md`}
|
||||
>
|
||||
No open orders
|
||||
</div>
|
||||
|
|
|
@ -1,113 +1,103 @@
|
|||
import { useOpenOrders } from '../hooks/useOpenOrders'
|
||||
import useTradeHistory from '../hooks/useTradeHistory'
|
||||
|
||||
const TradeHistoryTable = () => {
|
||||
const openOrders = useOpenOrders()
|
||||
const { tradeHistory } = useTradeHistory()
|
||||
|
||||
return (
|
||||
<div className={`flex flex-col py-6`}>
|
||||
<div className={`-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8`}>
|
||||
<div className={`align-middle inline-block min-w-full sm:px-6 lg:px-8`}>
|
||||
{openOrders ? (
|
||||
{tradeHistory ? (
|
||||
<div
|
||||
className={`shadow overflow-hidden border-b border-mango-dark-light sm:rounded-md`}
|
||||
className={`shadow overflow-hidden border-b border-th-bkg-2 sm:rounded-md`}
|
||||
>
|
||||
<table className={`min-w-full divide-y divide-mango-dark-light`}>
|
||||
<table className={`min-w-full divide-y divide-th-bkg-2`}>
|
||||
<thead>
|
||||
<tr>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-gray-300 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Coin
|
||||
Market
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-gray-300 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Wallet Balance
|
||||
Side
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-gray-300 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Deposits
|
||||
Size
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-gray-300 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Borrows
|
||||
Price
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-gray-300 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
In Orders
|
||||
Liquidity
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-gray-300 tracking-wider`}
|
||||
className={`px-6 py-3 text-left text-base font-medium text-th-fgd-2 tracking-wider`}
|
||||
>
|
||||
Unsettled
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
className={`px-6 py-3 text-left text-base font-medium text-gray-300 tracking-wider`}
|
||||
>
|
||||
Net
|
||||
Fees
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{openOrders.map((order, index) => (
|
||||
{tradeHistory.map((trade, index) => (
|
||||
<tr
|
||||
key={`${order.orderId}${order.side}`}
|
||||
key={`${trade.orderId}${trade.side}`}
|
||||
className={`
|
||||
${
|
||||
index % 2 === 0
|
||||
? `bg-mango-dark-light`
|
||||
: `bg-mango-dark-lighter`
|
||||
}
|
||||
${index % 2 === 0 ? `bg-th-bkg-2` : `bg-th-bkg-3`}
|
||||
`}
|
||||
>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-gray-300 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{order.marketName}
|
||||
{trade.marketName}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-gray-300 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
<div
|
||||
className={`rounded inline-block bg-mango-green px-2 py-1 text-mango-dark font-bold`}
|
||||
className={`rounded inline-block ${
|
||||
trade.side === 'buy'
|
||||
? 'bg-th-green text-th-bkg-1'
|
||||
: 'bg-th-red text-white'
|
||||
}
|
||||
px-2 py-1 font-bold`}
|
||||
>
|
||||
{order.side.toUpperCase()}
|
||||
{trade.side.toUpperCase()}
|
||||
</div>
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-gray-300 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{order.size}
|
||||
{trade.size}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-gray-300 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{order.price}
|
||||
{trade.price}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-gray-300 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{order.price}
|
||||
{trade.liquidity}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-gray-300 font-light`}
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-th-fgd-2 font-light`}
|
||||
>
|
||||
{order.price}
|
||||
</td>
|
||||
<td
|
||||
className={`px-6 py-4 whitespace-nowrap text-sm text-gray-300 font-light`}
|
||||
>
|
||||
{order.price}
|
||||
{trade.feeCost}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
|
|
|
@ -3,14 +3,19 @@ import { Market } from '@project-serum/serum'
|
|||
import { PublicKey, AccountInfo } from '@solana/web3.js'
|
||||
import useConnection from './useConnection'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import useSerumStore from '../stores/useSerumStore'
|
||||
import useMarketList from './useMarketList'
|
||||
import { notify } from '../utils/notifications'
|
||||
import useInterval from './useInterval'
|
||||
|
||||
const _SLOW_REFRESH_INTERVAL = 5 * 1000
|
||||
|
||||
const marketAddressSelector = (s) => s.selectedMarket.address
|
||||
const mangoGroupMarketsSelector = (s) => s.selectedMangoGroup.markets
|
||||
|
||||
const useHydrateStore = () => {
|
||||
const setMangoStore = useMangoStore((s) => s.set)
|
||||
const setSerumStore = useSerumStore((s) => s.set)
|
||||
const selectedMarketAddress = useMangoStore(marketAddressSelector)
|
||||
const marketsForSelectedMangoGroup = useMangoStore(mangoGroupMarketsSelector)
|
||||
const { connection, dexProgramId } = useConnection()
|
||||
|
@ -128,6 +133,22 @@ const useHydrateStore = () => {
|
|||
}
|
||||
}
|
||||
}, [marketsForSelectedMangoGroup])
|
||||
|
||||
useInterval(() => {
|
||||
async function fetchFills() {
|
||||
const market = useMangoStore.getState().market.current
|
||||
if (!market || !connection) {
|
||||
return null
|
||||
}
|
||||
const loadedFills = await market.loadFills(connection, 10000)
|
||||
|
||||
setSerumStore((state) => {
|
||||
state.fills = loadedFills
|
||||
})
|
||||
}
|
||||
|
||||
fetchFills()
|
||||
}, _SLOW_REFRESH_INTERVAL)
|
||||
}
|
||||
|
||||
export default useHydrateStore
|
||||
|
|
|
@ -1,36 +1,7 @@
|
|||
import { useEffect } from 'react'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import useInterval from './useInterval'
|
||||
import useSerumStore from '../stores/useSerumStore'
|
||||
import useOrderbook from './useOrderbook'
|
||||
import useConnection from './useConnection'
|
||||
|
||||
// const _FAST_REFRESH_INTERVAL = 1000;
|
||||
const _SLOW_REFRESH_INTERVAL = 5 * 1000
|
||||
// const _VERY_SLOW_REFRESH_INTERVAL = 5000 * 1000;
|
||||
|
||||
export function _useUnfilteredTrades(limit = 10000) {
|
||||
console.log('fetching unfiltered trades')
|
||||
|
||||
const market = useMangoStore((state) => state.market.current)
|
||||
const { connection } = useConnection()
|
||||
const setSerumStore = useSerumStore((state) => state.set)
|
||||
|
||||
useInterval(() => {
|
||||
async function fetchFills() {
|
||||
if (!market || !connection) {
|
||||
return null
|
||||
}
|
||||
const loadedFills = await market.loadFills(connection, limit)
|
||||
|
||||
setSerumStore((state) => {
|
||||
state.fills = loadedFills
|
||||
})
|
||||
}
|
||||
|
||||
fetchFills()
|
||||
}, _SLOW_REFRESH_INTERVAL)
|
||||
}
|
||||
|
||||
export function useTrades() {
|
||||
const trades = useSerumStore((state) => state.fills)
|
||||
|
@ -64,10 +35,11 @@ export default function useMarkPrice() {
|
|||
? [bb, ba, last].sort((a, b) => a - b)[1]
|
||||
: (bb + ba) / 2
|
||||
: null
|
||||
|
||||
setMangoStore((state) => {
|
||||
state.market.markPrice = newMarkPrice
|
||||
})
|
||||
if (newMarkPrice !== markPrice) {
|
||||
setMangoStore((state) => {
|
||||
state.market.markPrice = newMarkPrice
|
||||
})
|
||||
}
|
||||
}, [orderbook, trades])
|
||||
|
||||
return markPrice
|
||||
|
|
|
@ -2,6 +2,8 @@ import { useCallback, useState, useEffect, useRef } from 'react'
|
|||
import { isDefined } from '../utils'
|
||||
import useMangoStore from '../stores/useMangoStore'
|
||||
import useSerumStore from '../stores/useSerumStore'
|
||||
import useMarket from './useMarket'
|
||||
import useInterval from './useInterval'
|
||||
|
||||
const byTimestamp = (a, b) => {
|
||||
return (
|
||||
|
@ -35,13 +37,30 @@ export const usePrevious = (value) => {
|
|||
return ref.current
|
||||
}
|
||||
|
||||
const useFills = () => {
|
||||
const fills = useSerumStore((s) => s.fills)
|
||||
const { market, marketName } = useMarket()
|
||||
const marginAccount = useMangoStore((s) => s.selectedMarginAccount.current)
|
||||
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
|
||||
|
||||
if (!marginAccount || !selectedMangoGroup) return null
|
||||
|
||||
const marketIndex = selectedMangoGroup.getMarketIndex(market)
|
||||
const openOrdersAccount = marginAccount.openOrdersAccounts[marketIndex]
|
||||
return fills
|
||||
.filter((fill) => fill.openOrders.equals(openOrdersAccount.publicKey))
|
||||
.map((fill) => ({ ...fill, marketName }))
|
||||
}
|
||||
|
||||
export const useTradeHistory = () => {
|
||||
const eventQueueFills = useSerumStore((s) => s.fills)
|
||||
const eventQueueFills = useFills()
|
||||
const [tradeHistory, setTradeHistory] = useState<any[]>([])
|
||||
const [allTrades, setAllTrades] = useState<any[]>([])
|
||||
const marginAccount = useMangoStore((s) => s.selectedMarginAccount.current)
|
||||
|
||||
const fetchTradeHistory = useCallback(async () => {
|
||||
console.log('fetching history')
|
||||
|
||||
if (!marginAccount) return
|
||||
if (marginAccount.openOrdersAccounts.length === 0) return
|
||||
|
||||
|
@ -59,16 +78,18 @@ export const useTradeHistory = () => {
|
|||
return parsedResponse?.data ? parsedResponse.data : []
|
||||
})
|
||||
)
|
||||
console.log('results', results)
|
||||
|
||||
setTradeHistory(formatTradeHistory(results))
|
||||
setAllTrades(formatTradeHistory(results))
|
||||
}, [marginAccount, eventQueueFills])
|
||||
}, [marginAccount])
|
||||
|
||||
useEffect(() => {
|
||||
useInterval(() => {
|
||||
console.log('interval', allTrades, tradeHistory)
|
||||
if (marginAccount && tradeHistory.length === 0) {
|
||||
fetchTradeHistory()
|
||||
}
|
||||
}, [marginAccount])
|
||||
}, 10000)
|
||||
|
||||
useEffect(() => {
|
||||
if (eventQueueFills && eventQueueFills.length > 0) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect, useState } from 'react'
|
||||
import styled from '@emotion/styled'
|
||||
import { Button, Select } from 'antd'
|
||||
import { Select } from 'antd'
|
||||
import { LineChart, Line, ReferenceLine, XAxis, YAxis, Tooltip } from 'recharts'
|
||||
import useDimensions from 'react-cool-dimensions'
|
||||
import { IDS, MangoClient } from '@blockworks-foundation/mango-client'
|
||||
|
@ -197,7 +197,7 @@ export default function StatsPage() {
|
|||
return (
|
||||
<Wrapper>
|
||||
<TopBar />
|
||||
<div className="px-48">
|
||||
<div className="w-2/3 mx-auto">
|
||||
<FloatingElement>
|
||||
<>
|
||||
<div className="text-center">
|
||||
|
|
Loading…
Reference in New Issue