Fix Runtime
This commit is contained in:
@@ -4493,6 +4493,9 @@ export interface UserStrategyDetailsViewModel {
|
||||
roiPercentage?: number;
|
||||
runtime?: Date | null;
|
||||
totalRuntimeSeconds?: number;
|
||||
lastStartTime?: Date | null;
|
||||
lastStopTime?: Date | null;
|
||||
accumulatedRunTimeSeconds?: number;
|
||||
winRate?: number;
|
||||
totalVolumeTraded?: number;
|
||||
volumeLast24H?: number;
|
||||
|
||||
@@ -976,6 +976,9 @@ export interface UserStrategyDetailsViewModel {
|
||||
roiPercentage?: number;
|
||||
runtime?: Date | null;
|
||||
totalRuntimeSeconds?: number;
|
||||
lastStartTime?: Date | null;
|
||||
lastStopTime?: Date | null;
|
||||
accumulatedRunTimeSeconds?: number;
|
||||
winRate?: number;
|
||||
totalVolumeTraded?: number;
|
||||
volumeLast24H?: number;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, {useState} from 'react'
|
||||
import {Card, FormInput, GridTile} from '../../components/mollecules'
|
||||
import {Card, FormInput, GridTile, Table} from '../../components/mollecules'
|
||||
import useApiUrlStore from '../../app/store/apiStore'
|
||||
import Plot from 'react-plotly.js'
|
||||
import useTheme from '../../hooks/useTheme'
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type AgentBalanceHistory,
|
||||
BotStatus,
|
||||
DataClient,
|
||||
PositionStatus,
|
||||
type PositionViewModel,
|
||||
TradeDirection,
|
||||
type UserStrategyDetailsViewModel
|
||||
@@ -93,6 +94,7 @@ function AgentSearch({ index }: { index: number }) {
|
||||
const totalVolume = agentData.strategies.reduce((sum, strategy) => sum + (strategy.totalVolumeTraded || 0), 0)
|
||||
const totalWins = agentData.strategies.reduce((sum, strategy) => sum + (strategy.wins || 0), 0)
|
||||
const totalLosses = agentData.strategies.reduce((sum, strategy) => sum + (strategy.losses || 0), 0)
|
||||
const totalRuntimeSeconds = agentData.strategies.reduce((sum, strategy) => sum + (strategy.totalRuntimeSeconds || 0), 0)
|
||||
const avgWinRate = agentData.strategies.length > 0
|
||||
? agentData.strategies.reduce((sum, strategy) => sum + (strategy.winRate || 0), 0) / agentData.strategies.length
|
||||
: 0
|
||||
@@ -104,6 +106,7 @@ function AgentSearch({ index }: { index: number }) {
|
||||
totalWins,
|
||||
totalLosses,
|
||||
avgWinRate,
|
||||
totalRuntimeSeconds,
|
||||
activeStrategies: agentData.strategies.filter(s => s.state === BotStatus.Running).length,
|
||||
totalStrategies: agentData.strategies.length
|
||||
}
|
||||
@@ -157,6 +160,70 @@ function AgentSearch({ index }: { index: number }) {
|
||||
const currentBalance = getCurrentBalance()
|
||||
const chartData = prepareChartData()
|
||||
const theme = useTheme().themeProperty()
|
||||
const openPositions = (agentData?.positions || []).filter(p => [
|
||||
PositionStatus.New,
|
||||
PositionStatus.Updating,
|
||||
PositionStatus.Filled,
|
||||
PositionStatus.Flipped
|
||||
].includes(p.status))
|
||||
const allPositions = agentData?.positions || []
|
||||
|
||||
const positionTableColumns = React.useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Date',
|
||||
accessor: (row: PositionViewModel) => new Date(row.date).toLocaleString(),
|
||||
},
|
||||
{
|
||||
Header: 'Ticker',
|
||||
accessor: (row: PositionViewModel) => `${row.ticker}/USDC`,
|
||||
},
|
||||
{
|
||||
Header: 'Direction',
|
||||
accessor: (row: PositionViewModel) => row.originDirection,
|
||||
},
|
||||
{
|
||||
Header: 'Leverage',
|
||||
accessor: (row: PositionViewModel) => `${row.Open?.leverage ?? 0}x`,
|
||||
},
|
||||
{
|
||||
Header: 'Quantity',
|
||||
accessor: (row: PositionViewModel) => row.Open?.quantity ?? 0,
|
||||
},
|
||||
{
|
||||
Header: 'Entry Price',
|
||||
accessor: (row: PositionViewModel) => row.Open?.price ?? 0,
|
||||
},
|
||||
{
|
||||
Header: 'Status',
|
||||
accessor: (row: PositionViewModel) => row.status,
|
||||
},
|
||||
{
|
||||
Header: 'Realized PnL ($)',
|
||||
accessor: (row: PositionViewModel) => row.ProfitAndLoss?.realized ?? 0,
|
||||
Cell: ({ value }: { value: number }) => (
|
||||
<span className={value >= 0 ? 'text-green-500' : 'text-red-500'}>
|
||||
{value >= 0 ? '+' : ''}{value.toFixed(2)}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
Header: 'ROI %',
|
||||
accessor: (row: PositionViewModel) => {
|
||||
const costBasis = (row.Open?.price ?? 0) * (row.Open?.quantity ?? 0)
|
||||
if (!costBasis) return 0
|
||||
const realized = row.ProfitAndLoss?.realized ?? 0
|
||||
return (realized / costBasis) * 100
|
||||
},
|
||||
Cell: ({ value }: { value: number }) => (
|
||||
<span className={value >= 0 ? 'text-green-500' : 'text-red-500'}>
|
||||
{value >= 0 ? '+' : ''}{value.toFixed(2)}%
|
||||
</span>
|
||||
)
|
||||
},
|
||||
],
|
||||
[]
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="container mx-auto pt-6 space-y-6">
|
||||
@@ -202,10 +269,10 @@ function AgentSearch({ index }: { index: number }) {
|
||||
</GridTile>
|
||||
|
||||
{/* Open Positions Section */}
|
||||
{agentData?.positions && agentData.positions.length > 0 && (
|
||||
{openPositions.length > 0 && (
|
||||
<GridTile title="Open Positions">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{agentData.positions.map((position, index) => (
|
||||
{openPositions.map((position, index) => (
|
||||
<div key={index} className="bg-base-200 p-4 rounded-lg border border-base-300">
|
||||
<div className="flex justify-between items-start mb-3">
|
||||
<div>
|
||||
@@ -426,6 +493,28 @@ function AgentSearch({ index }: { index: number }) {
|
||||
<div className="stat-desc text-xs">Fees paid across all strategies</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card name="Total Runtime">
|
||||
<div className="stat">
|
||||
<div className="stat-title text-xs">Total Runtime</div>
|
||||
<div className="stat-value text-lg">
|
||||
{(() => {
|
||||
const totalSeconds = summary.totalRuntimeSeconds || 0
|
||||
const days = Math.floor(totalSeconds / 86400)
|
||||
const hours = Math.floor((totalSeconds % 86400) / 3600)
|
||||
const minutes = Math.floor((totalSeconds % 3600) / 60)
|
||||
if (days > 0) {
|
||||
return `${days}d ${hours}h`
|
||||
} else if (hours > 0) {
|
||||
return `${hours}h ${minutes}m`
|
||||
} else {
|
||||
return `${minutes}m`
|
||||
}
|
||||
})()}
|
||||
</div>
|
||||
<div className="stat-desc text-xs">Across all strategies</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</GridTile>
|
||||
)}
|
||||
@@ -457,7 +546,7 @@ function AgentSearch({ index }: { index: number }) {
|
||||
{strategy.roiPercentage && strategy.roiPercentage >= 0 ? '+' : ''}{(strategy.roiPercentage || 0).toFixed(2)}%
|
||||
</span>
|
||||
<span>
|
||||
{strategy.totalRuntimeSeconds > 0 ? (() => {
|
||||
{strategy.totalRuntimeSeconds && strategy.totalRuntimeSeconds > 0 ? (() => {
|
||||
const totalSeconds = strategy.totalRuntimeSeconds
|
||||
const days = Math.floor(totalSeconds / 86400)
|
||||
const hours = Math.floor((totalSeconds % 86400) / 3600)
|
||||
@@ -486,6 +575,16 @@ function AgentSearch({ index }: { index: number }) {
|
||||
</div>
|
||||
</GridTile>
|
||||
)}
|
||||
|
||||
{allPositions.length > 0 && (
|
||||
<GridTile title="All Positions">
|
||||
<Table
|
||||
columns={positionTableColumns}
|
||||
data={allPositions}
|
||||
showPagination={true}
|
||||
/>
|
||||
</GridTile>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user