Fix lastStartTime update
This commit is contained in:
@@ -174,10 +174,11 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
_state.State.StartupTime = DateTime.UtcNow;
|
_state.State.StartupTime = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track runtime: set LastStartTime when bot starts and clear LastStopTime
|
if (previousStatus != BotStatus.Running)
|
||||||
_state.State.LastStartTime = DateTime.UtcNow;
|
{
|
||||||
_state.State.LastStopTime = null;
|
_state.State.LastStartTime = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
|
|
||||||
// Start the in-memory timer and persistent reminder
|
// Start the in-memory timer and persistent reminder
|
||||||
@@ -217,6 +218,7 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
await SaveBotAsync(BotStatus.Running);
|
await SaveBotAsync(BotStatus.Running);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("LiveTradingBotGrain {GrainId} is already running", this.GetPrimaryKey());
|
_logger.LogInformation("LiveTradingBotGrain {GrainId} is already running", this.GetPrimaryKey());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -304,8 +306,9 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
_state.State.AccumulatedRunTimeSeconds += currentSessionSeconds;
|
_state.State.AccumulatedRunTimeSeconds += currentSessionSeconds;
|
||||||
_state.State.LastStopTime = DateTime.UtcNow;
|
_state.State.LastStopTime = DateTime.UtcNow;
|
||||||
_state.State.LastStartTime = null; // Clear since bot is no longer running
|
_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);
|
this.GetPrimaryKey(), currentSessionSeconds, _state.State.AccumulatedRunTimeSeconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,7 +784,8 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2215,6 +2215,61 @@ export class DataClient extends AuthorizedApiBase {
|
|||||||
}
|
}
|
||||||
return Promise.resolve<string[]>(null as any);
|
return Promise.resolve<string[]>(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<PaginatedResponseOfTradingBotResponse> {
|
||||||
|
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<PaginatedResponseOfTradingBotResponse> {
|
||||||
|
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<PaginatedResponseOfTradingBotResponse>(null as any);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MoneyManagementClient extends AuthorizedApiBase {
|
export class MoneyManagementClient extends AuthorizedApiBase {
|
||||||
@@ -4223,6 +4278,7 @@ export interface TradingBotResponse {
|
|||||||
candles: Candle[];
|
candles: Candle[];
|
||||||
winRate: number;
|
winRate: number;
|
||||||
profitAndLoss: number;
|
profitAndLoss: number;
|
||||||
|
roi: number;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
agentName: string;
|
agentName: string;
|
||||||
createDate: Date;
|
createDate: Date;
|
||||||
@@ -4247,6 +4303,7 @@ export enum BotSortableColumn {
|
|||||||
Ticker = "Ticker",
|
Ticker = "Ticker",
|
||||||
Status = "Status",
|
Status = "Status",
|
||||||
StartupTime = "StartupTime",
|
StartupTime = "StartupTime",
|
||||||
|
Roi = "Roi",
|
||||||
Pnl = "Pnl",
|
Pnl = "Pnl",
|
||||||
WinRate = "WinRate",
|
WinRate = "WinRate",
|
||||||
AgentName = "AgentName",
|
AgentName = "AgentName",
|
||||||
|
|||||||
@@ -753,6 +753,7 @@ export interface TradingBotResponse {
|
|||||||
candles: Candle[];
|
candles: Candle[];
|
||||||
winRate: number;
|
winRate: number;
|
||||||
profitAndLoss: number;
|
profitAndLoss: number;
|
||||||
|
roi: number;
|
||||||
identifier: string;
|
identifier: string;
|
||||||
agentName: string;
|
agentName: string;
|
||||||
createDate: Date;
|
createDate: Date;
|
||||||
@@ -777,6 +778,7 @@ export enum BotSortableColumn {
|
|||||||
Ticker = "Ticker",
|
Ticker = "Ticker",
|
||||||
Status = "Status",
|
Status = "Status",
|
||||||
StartupTime = "StartupTime",
|
StartupTime = "StartupTime",
|
||||||
|
Roi = "Roi",
|
||||||
Pnl = "Pnl",
|
Pnl = "Pnl",
|
||||||
WinRate = "WinRate",
|
WinRate = "WinRate",
|
||||||
AgentName = "AgentName",
|
AgentName = "AgentName",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import React, {useState} from 'react'
|
|||||||
import 'react-toastify/dist/ReactToastify.css'
|
import 'react-toastify/dist/ReactToastify.css'
|
||||||
import useApiUrlStore from '../../app/store/apiStore'
|
import useApiUrlStore from '../../app/store/apiStore'
|
||||||
import {UnifiedTradingModal} from '../../components/organism'
|
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 BotList from './botList'
|
||||||
import {useQuery} from '@tanstack/react-query'
|
import {useQuery} from '@tanstack/react-query'
|
||||||
@@ -33,15 +33,15 @@ const Bots: React.FC = () => {
|
|||||||
queryFn: () => {
|
queryFn: () => {
|
||||||
switch (activeTab) {
|
switch (activeTab) {
|
||||||
case 0: // All Active Bots
|
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
|
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
|
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
|
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:
|
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],
|
queryKey: ['paginatedBots', activeTab, pageNumber, pageSize, currentUser?.agentName],
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ function AgentSearch({ index }: { index: number }) {
|
|||||||
const chartData = prepareChartData()
|
const chartData = prepareChartData()
|
||||||
const theme = useTheme().themeProperty()
|
const theme = useTheme().themeProperty()
|
||||||
const openPositions = (agentData?.positions || []).filter(p => [
|
const openPositions = (agentData?.positions || []).filter(p => [
|
||||||
PositionStatus.New,
|
|
||||||
PositionStatus.Updating,
|
PositionStatus.Updating,
|
||||||
PositionStatus.Filled,
|
PositionStatus.Filled,
|
||||||
PositionStatus.Flipped
|
PositionStatus.Flipped
|
||||||
|
|||||||
Reference in New Issue
Block a user