From 719ce96e116cf653cb6caf379b5314bbfaf869a6 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Tue, 7 Oct 2025 02:00:39 +0700 Subject: [PATCH] Fix lastStartTime update --- .../Bots/Grains/LiveTradingBotGrain.cs | 18 +++--- .../src/generated/ManagingApi.ts | 57 +++++++++++++++++++ .../src/generated/ManagingApiTypes.ts | 2 + .../src/pages/botsPage/bots.tsx | 12 ++-- .../src/pages/dashboardPage/agentSearch.tsx | 1 - 5 files changed, 76 insertions(+), 14 deletions(-) diff --git a/src/Managing.Application/Bots/Grains/LiveTradingBotGrain.cs b/src/Managing.Application/Bots/Grains/LiveTradingBotGrain.cs index 28bb2222..16f18390 100644 --- a/src/Managing.Application/Bots/Grains/LiveTradingBotGrain.cs +++ b/src/Managing.Application/Bots/Grains/LiveTradingBotGrain.cs @@ -174,10 +174,11 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable _state.State.StartupTime = DateTime.UtcNow; } - // Track runtime: set LastStartTime when bot starts and clear LastStopTime - _state.State.LastStartTime = DateTime.UtcNow; - _state.State.LastStopTime = null; - + if (previousStatus != BotStatus.Running) + { + _state.State.LastStartTime = DateTime.UtcNow; + } + await _state.WriteStateAsync(); // Start the in-memory timer and persistent reminder @@ -217,6 +218,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable await _state.WriteStateAsync(); await SaveBotAsync(BotStatus.Running); } + _logger.LogInformation("LiveTradingBotGrain {GrainId} is already running", this.GetPrimaryKey()); return; } @@ -304,8 +306,9 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable _state.State.AccumulatedRunTimeSeconds += currentSessionSeconds; _state.State.LastStopTime = DateTime.UtcNow; _state.State.LastStartTime = null; // Clear since bot is no longer running - - _logger.LogInformation("Bot {GrainId} accumulated {Seconds} seconds of runtime. Total: {TotalSeconds} seconds", + + _logger.LogInformation( + "Bot {GrainId} accumulated {Seconds} seconds of runtime. Total: {TotalSeconds} seconds", this.GetPrimaryKey(), currentSessionSeconds, _state.State.AccumulatedRunTimeSeconds); } @@ -781,7 +784,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable } catch (Exception ex) { - _logger.LogWarning(ex, "Unable to load user for bot {BotId} while saving stats", _state.State.Identifier); + _logger.LogWarning(ex, "Unable to load user for bot {BotId} while saving stats", + _state.State.Identifier); } } diff --git a/src/Managing.WebApp/src/generated/ManagingApi.ts b/src/Managing.WebApp/src/generated/ManagingApi.ts index 3ede22e2..86c3eec0 100644 --- a/src/Managing.WebApp/src/generated/ManagingApi.ts +++ b/src/Managing.WebApp/src/generated/ManagingApi.ts @@ -2215,6 +2215,61 @@ export class DataClient extends AuthorizedApiBase { } return Promise.resolve(null as any); } + + data_GetStrategiesPaginated(pageNumber: number | undefined, pageSize: number | undefined, name: string | null | undefined, ticker: string | null | undefined, agentName: string | null | undefined, sortBy: BotSortableColumn | undefined, sortDirection: string | null | undefined): Promise { + let url_ = this.baseUrl + "/Data/GetStrategiesPaginated?"; + if (pageNumber === null) + throw new Error("The parameter 'pageNumber' cannot be null."); + else if (pageNumber !== undefined) + url_ += "pageNumber=" + encodeURIComponent("" + pageNumber) + "&"; + if (pageSize === null) + throw new Error("The parameter 'pageSize' cannot be null."); + else if (pageSize !== undefined) + url_ += "pageSize=" + encodeURIComponent("" + pageSize) + "&"; + if (name !== undefined && name !== null) + url_ += "name=" + encodeURIComponent("" + name) + "&"; + if (ticker !== undefined && ticker !== null) + url_ += "ticker=" + encodeURIComponent("" + ticker) + "&"; + if (agentName !== undefined && agentName !== null) + url_ += "agentName=" + encodeURIComponent("" + agentName) + "&"; + if (sortBy === null) + throw new Error("The parameter 'sortBy' cannot be null."); + else if (sortBy !== undefined) + url_ += "sortBy=" + encodeURIComponent("" + sortBy) + "&"; + if (sortDirection !== undefined && sortDirection !== null) + url_ += "sortDirection=" + encodeURIComponent("" + sortDirection) + "&"; + url_ = url_.replace(/[?&]$/, ""); + + let options_: RequestInit = { + method: "GET", + headers: { + "Accept": "application/json" + } + }; + + return this.transformOptions(options_).then(transformedOptions_ => { + return this.http.fetch(url_, transformedOptions_); + }).then((_response: Response) => { + return this.processData_GetStrategiesPaginated(_response); + }); + } + + protected processData_GetStrategiesPaginated(response: Response): Promise { + const status = response.status; + let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; + if (status === 200) { + return response.text().then((_responseText) => { + let result200: any = null; + result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as PaginatedResponseOfTradingBotResponse; + return result200; + }); + } else if (status !== 200 && status !== 204) { + return response.text().then((_responseText) => { + return throwException("An unexpected server error occurred.", status, _responseText, _headers); + }); + } + return Promise.resolve(null as any); + } } export class MoneyManagementClient extends AuthorizedApiBase { @@ -4223,6 +4278,7 @@ export interface TradingBotResponse { candles: Candle[]; winRate: number; profitAndLoss: number; + roi: number; identifier: string; agentName: string; createDate: Date; @@ -4247,6 +4303,7 @@ export enum BotSortableColumn { Ticker = "Ticker", Status = "Status", StartupTime = "StartupTime", + Roi = "Roi", Pnl = "Pnl", WinRate = "WinRate", AgentName = "AgentName", diff --git a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts index 87c23a15..14ea3e1e 100644 --- a/src/Managing.WebApp/src/generated/ManagingApiTypes.ts +++ b/src/Managing.WebApp/src/generated/ManagingApiTypes.ts @@ -753,6 +753,7 @@ export interface TradingBotResponse { candles: Candle[]; winRate: number; profitAndLoss: number; + roi: number; identifier: string; agentName: string; createDate: Date; @@ -777,6 +778,7 @@ export enum BotSortableColumn { Ticker = "Ticker", Status = "Status", StartupTime = "StartupTime", + Roi = "Roi", Pnl = "Pnl", WinRate = "WinRate", AgentName = "AgentName", diff --git a/src/Managing.WebApp/src/pages/botsPage/bots.tsx b/src/Managing.WebApp/src/pages/botsPage/bots.tsx index 7337b844..f41e9fb8 100644 --- a/src/Managing.WebApp/src/pages/botsPage/bots.tsx +++ b/src/Managing.WebApp/src/pages/botsPage/bots.tsx @@ -3,7 +3,7 @@ import React, {useState} from 'react' import 'react-toastify/dist/ReactToastify.css' import useApiUrlStore from '../../app/store/apiStore' import {UnifiedTradingModal} from '../../components/organism' -import {BotClient, BotStatus, UserClient} from '../../generated/ManagingApi' +import {BotClient, BotSortableColumn, BotStatus, UserClient} from '../../generated/ManagingApi' import BotList from './botList' import {useQuery} from '@tanstack/react-query' @@ -33,15 +33,15 @@ const Bots: React.FC = () => { queryFn: () => { switch (activeTab) { case 0: // All Active Bots - return botClient.bot_GetBotsPaginated(pageNumber, pageSize, BotStatus.Running, undefined, undefined, undefined, 'CreatedAt', 'Desc') + return botClient.bot_GetBotsPaginated(pageNumber, pageSize, BotStatus.Running, undefined, undefined, undefined, BotSortableColumn.Roi, 'Desc') case 1: // My Active Bots - return botClient.bot_GetBotsPaginated(pageNumber, pageSize, BotStatus.Running, undefined, undefined, currentUser?.agentName, 'CreatedAt', 'Desc') + return botClient.bot_GetBotsPaginated(pageNumber, pageSize, BotStatus.Running, undefined, undefined, currentUser?.agentName, BotSortableColumn.Roi, 'Desc') case 2: // My Down Bots - return botClient.bot_GetBotsPaginated(pageNumber, pageSize, BotStatus.Stopped, undefined, undefined, currentUser?.agentName, 'CreatedAt', 'Desc') + return botClient.bot_GetBotsPaginated(pageNumber, pageSize, BotStatus.Stopped, undefined, undefined, currentUser?.agentName, BotSortableColumn.Roi, 'Desc') case 3: // Saved Bots - return botClient.bot_GetBotsPaginated(pageNumber, pageSize, BotStatus.Saved, undefined, undefined, currentUser?.agentName, 'CreatedAt', 'Desc') + return botClient.bot_GetBotsPaginated(pageNumber, pageSize, BotStatus.Saved, undefined, undefined, currentUser?.agentName, BotSortableColumn.Roi, 'Desc') default: - return botClient.bot_GetBotsPaginated(pageNumber, pageSize, undefined, undefined, undefined, undefined, 'CreatedAt', 'Desc') + return botClient.bot_GetBotsPaginated(pageNumber, pageSize, undefined, undefined, undefined, undefined, BotSortableColumn.Roi, 'Desc') } }, queryKey: ['paginatedBots', activeTab, pageNumber, pageSize, currentUser?.agentName], diff --git a/src/Managing.WebApp/src/pages/dashboardPage/agentSearch.tsx b/src/Managing.WebApp/src/pages/dashboardPage/agentSearch.tsx index b90beff1..4f5eb08a 100644 --- a/src/Managing.WebApp/src/pages/dashboardPage/agentSearch.tsx +++ b/src/Managing.WebApp/src/pages/dashboardPage/agentSearch.tsx @@ -161,7 +161,6 @@ function AgentSearch({ index }: { index: number }) { const chartData = prepareChartData() const theme = useTheme().themeProperty() const openPositions = (agentData?.positions || []).filter(p => [ - PositionStatus.New, PositionStatus.Updating, PositionStatus.Filled, PositionStatus.Flipped