Description
Retrieves real-time market prices for specified cryptocurrency symbols. Used to calculate unrealized P&L, display current market values, and update position valuations in real-time.
Array of cryptocurrency trading pair symbols to fetch prices for (e.g., ["BTC-USD", "ETH-USD", "SOL-USD"]). If omitted or empty, returns prices for all available symbols.
TypeScript Type
type CryptoPricesInput = {
symbols ?: string [];
};
Output Schema
Array of cryptocurrency price objects. Show CryptoPrice properties
Cryptocurrency trading pair (e.g., "BTC-USD", "ETH-USD").
Current market price in USD. Returns 0 if price data is unavailable.
Additional information or error message about the price fetch (e.g., "Price temporarily unavailable").
TypeScript Type
type CryptoPricesResponse = {
prices : {
symbol : string ;
price : number ;
message ?: string ;
}[];
};
Example Usage
Basic Query
import { useQuery } from "@tanstack/react-query" ;
import { orpc } from "@/server/orpc/client" ;
function CryptoPrices () {
const { data , isLoading } = useQuery (
orpc . trading . getCryptoPrices . queryOptions ({
input: {
symbols: [ "BTC-USD" , "ETH-USD" , "SOL-USD" ]
}
})
);
if ( isLoading ) return < div > Loading prices ...</ div > ;
return (
< div >
< h3 > Current Prices </ h3 >
< ul >
{ data ?. prices . map (( crypto ) => (
< li key = {crypto. symbol } >
{ crypto . symbol } : $ {crypto.price.toLocaleString( 'en-US' , { minimumFractionDigits : 2 , maximumFractionDigits : 2 })}
{ crypto . message && < span style = {{ color : 'orange' }} > - {crypto. message } </ span > }
</ li >
))}
</ ul >
</ div >
);
}
Real-time Price Ticker
import { useQuery } from "@tanstack/react-query" ;
import { orpc } from "@/server/orpc/client" ;
function PriceTicker () {
// Poll every 2 seconds for real-time updates
const { data } = useQuery ({
... orpc . trading . getCryptoPrices . queryOptions ({
input: {
symbols: [ "BTC-USD" , "ETH-USD" ]
}
}),
refetchInterval: 2000 ,
staleTime: 1000 ,
});
return (
< div style = {{ display : 'flex' , gap : '2rem' , padding : '1rem' , backgroundColor : '#000' }} >
{ data ?. prices . map (( crypto ) => (
< div key = {crypto. symbol } style = {{ color : '#fff' }} >
< div style = {{ fontSize : '0.875rem' , opacity : 0.7 }} > {crypto. symbol } </ div >
< div style = {{ fontSize : '1.5rem' , fontWeight : 'bold' }} >
$ {crypto.price.toLocaleString( 'en-US' , { minimumFractionDigits : 2 , maximumFractionDigits : 2 })}
</ div >
</ div >
))}
</ div >
);
}
Calculate Position Values
import { useQuery } from "@tanstack/react-query" ;
import { orpc } from "@/server/orpc/client" ;
function PositionValuation () {
const positionsQuery = useQuery (
orpc . trading . getPositions . queryOptions ({ input: {} })
);
// Extract unique symbols from positions
const symbols = Array . from (
new Set (
positionsQuery . data ?. positions . flatMap ( account =>
account . positions . map ( pos => pos . symbol )
) ?? []
)
);
const pricesQuery = useQuery (
orpc . trading . getCryptoPrices . queryOptions ({
input: { symbols }
})
);
if ( positionsQuery . isLoading || pricesQuery . isLoading ) {
return < div > Loading ...</ div > ;
}
// Create price lookup map
const priceMap = new Map (
pricesQuery . data ?. prices . map ( p => [ p . symbol , p . price ]) ?? []
);
return (
< div >
< h3 > Position Valuations </ h3 >
{ positionsQuery . data ?. positions . map ( account => (
< div key = {account. modelId } >
< h4 >{account. modelName } </ h4 >
{ account . positions . map (( pos , idx ) => {
const currentPrice = priceMap . get ( pos . symbol ) ?? 0 ;
const value = pos . quantity * currentPrice ;
const pnl = pos . side === 'long'
? (currentPrice - pos.entryPrice) * pos. quantity
: ( pos . entryPrice - currentPrice ) * pos . quantity ;
return (
< div key = { ` ${ pos . symbol } - ${ idx } ` } >
< p >
{pos. symbol }: {pos.quantity.toFixed( 4 ) } × $ {currentPrice.toFixed( 2 ) } =
< strong > $ {value.toFixed( 2 ) } </ strong >
< span style = {{ color : pnl >= 0 ? 'green' : 'red' , marginLeft : '1rem' }} >
({pnl >= 0 ? '+' : '' } $ {pnl.toFixed( 2 ) })
</ span >
</ p >
</ div >
);
})}
</ div >
))}
</ div >
);
}
Price Alert System
import { useQuery } from "@tanstack/react-query" ;
import { orpc } from "@/server/orpc/client" ;
import { useEffect , useState } from "react" ;
type PriceAlert = {
symbol : string ;
threshold : number ;
condition : 'above' | 'below' ;
};
function PriceAlerts () {
const [ alerts , setAlerts ] = useState < PriceAlert []>([
{ symbol: 'BTC-USD' , threshold: 100000 , condition: 'above' },
{ symbol: 'ETH-USD' , threshold: 3000 , condition: 'below' },
]);
const [ triggered , setTriggered ] = useState < string []>([]);
const { data } = useQuery ({
... orpc . trading . getCryptoPrices . queryOptions ({
input: {
symbols: alerts . map ( a => a . symbol )
}
}),
refetchInterval: 5000 ,
});
useEffect (() => {
if ( ! data ?. prices ) return ;
const newTriggered : string [] = [];
alerts . forEach ( alert => {
const price = data . prices . find ( p => p . symbol === alert . symbol );
if ( ! price ) return ;
const isTriggered = alert . condition === 'above'
? price . price > alert . threshold
: price . price < alert . threshold ;
if ( isTriggered ) {
const alertKey = ` ${ alert . symbol } - ${ alert . threshold } - ${ alert . condition } ` ;
if ( ! triggered . includes ( alertKey )) {
newTriggered . push ( alertKey );
// Trigger notification
console . log ( `🚨 ALERT: ${ alert . symbol } is ${ alert . condition } ${ alert . threshold } !` );
}
}
});
if ( newTriggered . length > 0 ) {
setTriggered ( prev => [ ... prev , ... newTriggered ]);
}
}, [ data , alerts , triggered ]);
return (
< div >
< h3 > Price Alerts </ h3 >
{ alerts . map (( alert , idx ) => {
const price = data ?. prices . find ( p => p . symbol === alert . symbol );
return (
< div key = { idx } >
< p >
{ alert . symbol } : $ { price ?. price . toFixed ( 2 ) ?? 'N/A' }
{ alert . condition === 'above' ? ' > ' : ' < ' }
$ { alert . threshold . toFixed ( 2 )}
</ p >
</ div >
);
})}
</ div >
);
}
Fetch All Prices
import { useQuery } from "@tanstack/react-query" ;
import { orpc } from "@/server/orpc/client" ;
function AllCryptoPrices () {
// Omit symbols parameter to fetch all available prices
const { data , isLoading } = useQuery (
orpc . trading . getCryptoPrices . queryOptions ({
input: {}
})
);
if ( isLoading ) return < div > Loading all prices ...</ div > ;
// Sort by price descending
const sortedPrices = [ ... ( data ?. prices ?? [])]. sort (( a , b ) => b . price - a . price );
return (
< div >
< h3 > All Cryptocurrency Prices </ h3 >
< p > Total : { sortedPrices . length } symbols </ p >
< table >
< thead >
< tr >
< th > Symbol </ th >
< th > Price ( USD ) </ th >
</ tr >
</ thead >
< tbody >
{ sortedPrices . map (( crypto ) => (
< tr key = {crypto. symbol } >
< td >{crypto. symbol } </ td >
< td > $ {crypto.price.toLocaleString( 'en-US' , { minimumFractionDigits : 2 , maximumFractionDigits : 2 })} </ td >
</ tr >
))}
</ tbody >
</ table >
</ div >
);
}
Implementation Notes
Normalization : Input symbols are normalized using parseSymbols() before fetching (handles various formats).
Error Handling : Returns empty array (prices: []) on fetch failure instead of throwing an error.
Data Source : Prices are fetched from @/server/features/trading/queries.server.fetchCryptoPrices().
Caching : Recommended to use short staleTime (1-5 seconds) for near real-time updates.