Fix Runtime

This commit is contained in:
2025-10-06 00:55:18 +07:00
parent 6cbfff38d0
commit dab4807334
8 changed files with 172 additions and 9 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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>
)
}