Fix Runtime by adding TotalRuntimeInSeconds
This commit is contained in:
@@ -498,7 +498,8 @@ public class DataController : ControllerBase
|
|||||||
PnL = strategy.Pnl,
|
PnL = strategy.Pnl,
|
||||||
NetPnL = strategy.NetPnL,
|
NetPnL = strategy.NetPnL,
|
||||||
ROIPercentage = strategy.Roi,
|
ROIPercentage = strategy.Roi,
|
||||||
Runtime = strategy.StartupTime,
|
Runtime = strategy.Status == BotStatus.Running ? strategy.LastStartTime : null,
|
||||||
|
TotalRuntimeSeconds = strategy.GetTotalRuntimeSeconds(),
|
||||||
WinRate = winRate,
|
WinRate = winRate,
|
||||||
TotalVolumeTraded = totalVolume,
|
TotalVolumeTraded = totalVolume,
|
||||||
VolumeLast24H = volumeLast24h,
|
VolumeLast24H = volumeLast24h,
|
||||||
|
|||||||
@@ -33,9 +33,14 @@ namespace Managing.Api.Models.Responses
|
|||||||
public decimal ROIPercentage { get; set; }
|
public decimal ROIPercentage { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Date and time when the strategy was started
|
/// Date and time when the strategy was started (only present when running, for live ticker)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DateTime Runtime { get; set; }
|
public DateTime? Runtime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total accumulated runtime in seconds (including current session if running)
|
||||||
|
/// </summary>
|
||||||
|
public long TotalRuntimeSeconds { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Average percentage of successful trades
|
/// Average percentage of successful trades
|
||||||
|
|||||||
@@ -170,6 +170,10 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
|
|
||||||
// Set startup time when bot actually starts running
|
// Set startup time when bot actually starts running
|
||||||
_state.State.StartupTime = DateTime.UtcNow;
|
_state.State.StartupTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// Track runtime: set LastStartTime when bot starts
|
||||||
|
_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
|
||||||
@@ -281,6 +285,18 @@ public class LiveTradingBotGrain : Grain, ILiveTradingBotGrain, IRemindable
|
|||||||
StopAndDisposeTimer();
|
StopAndDisposeTimer();
|
||||||
await UnregisterReminder();
|
await UnregisterReminder();
|
||||||
|
|
||||||
|
// Track runtime: accumulate current session runtime when stopping
|
||||||
|
if (_state.State.LastStartTime.HasValue)
|
||||||
|
{
|
||||||
|
var currentSessionSeconds = (long)(DateTime.UtcNow - _state.State.LastStartTime.Value).TotalSeconds;
|
||||||
|
_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",
|
||||||
|
this.GetPrimaryKey(), currentSessionSeconds, _state.State.AccumulatedRunTimeSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
// Sync state from the volatile TradingBotBase before destroying it
|
// Sync state from the volatile TradingBotBase before destroying it
|
||||||
SyncStateFromBase();
|
SyncStateFromBase();
|
||||||
await _state.WriteStateAsync();
|
await _state.WriteStateAsync();
|
||||||
|
|||||||
@@ -121,4 +121,22 @@ public class TradingBotGrainState
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Id(18)]
|
[Id(18)]
|
||||||
public Candle? LastCandle { get; set; }
|
public Candle? LastCandle { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The last time the bot was started (for runtime tracking)
|
||||||
|
/// </summary>
|
||||||
|
[Id(19)]
|
||||||
|
public DateTime? LastStartTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The last time the bot was stopped (for runtime tracking)
|
||||||
|
/// </summary>
|
||||||
|
[Id(20)]
|
||||||
|
public DateTime? LastStopTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Total accumulated runtime in seconds (excluding current session if running)
|
||||||
|
/// </summary>
|
||||||
|
[Id(21)]
|
||||||
|
public long AccumulatedRunTimeSeconds { get; set; }
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,11 @@ namespace Managing.Domain.Bots
|
|||||||
public DateTime StartupTime { get; set; }
|
public DateTime StartupTime { get; set; }
|
||||||
public DateTime CreateDate { get; set; }
|
public DateTime CreateDate { get; set; }
|
||||||
|
|
||||||
|
// Runtime tracking fields
|
||||||
|
public DateTime? LastStartTime { get; set; }
|
||||||
|
public DateTime? LastStopTime { get; set; }
|
||||||
|
public long AccumulatedRunTimeSeconds { get; set; }
|
||||||
|
|
||||||
public int TradeWins { get; set; }
|
public int TradeWins { get; set; }
|
||||||
public int TradeLosses { get; set; }
|
public int TradeLosses { get; set; }
|
||||||
public decimal Pnl { get; set; }
|
public decimal Pnl { get; set; }
|
||||||
@@ -23,5 +28,21 @@ namespace Managing.Domain.Bots
|
|||||||
public int LongPositionCount { get; set; }
|
public int LongPositionCount { get; set; }
|
||||||
public int ShortPositionCount { get; set; }
|
public int ShortPositionCount { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the total runtime in seconds, including the current session if the bot is running
|
||||||
|
/// </summary>
|
||||||
|
public long GetTotalRuntimeSeconds()
|
||||||
|
{
|
||||||
|
var totalSeconds = AccumulatedRunTimeSeconds;
|
||||||
|
|
||||||
|
// If bot is currently running, add current session time
|
||||||
|
if (Status == BotStatus.Running && LastStartTime.HasValue)
|
||||||
|
{
|
||||||
|
var currentSessionSeconds = (long)(DateTime.UtcNow - LastStartTime.Value).TotalSeconds;
|
||||||
|
totalSeconds += currentSessionSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return totalSeconds;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
1467
src/Managing.Infrastructure.Database/Migrations/20251005132435_AddBotRuntimeTracking.Designer.cs
generated
Normal file
1467
src/Managing.Infrastructure.Database/Migrations/20251005132435_AddBotRuntimeTracking.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Managing.Infrastructure.Databases.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddBotRuntimeTracking : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<long>(
|
||||||
|
name: "AccumulatedRunTimeSeconds",
|
||||||
|
table: "Bots",
|
||||||
|
type: "bigint",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0L);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "LastStartTime",
|
||||||
|
table: "Bots",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "LastStopTime",
|
||||||
|
table: "Bots",
|
||||||
|
type: "timestamp with time zone",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AccumulatedRunTimeSeconds",
|
||||||
|
table: "Bots");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastStartTime",
|
||||||
|
table: "Bots");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "LastStopTime",
|
||||||
|
table: "Bots");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1467
src/Managing.Infrastructure.Database/Migrations/20251005133552_ConfigureBotRuntimeFields.Designer.cs
generated
Normal file
1467
src/Managing.Infrastructure.Database/Migrations/20251005133552_ConfigureBotRuntimeFields.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,22 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Managing.Infrastructure.Databases.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class ConfigureBotRuntimeFields : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -244,6 +244,9 @@ namespace Managing.Infrastructure.Databases.Migrations
|
|||||||
.HasMaxLength(255)
|
.HasMaxLength(255)
|
||||||
.HasColumnType("uuid");
|
.HasColumnType("uuid");
|
||||||
|
|
||||||
|
b.Property<long>("AccumulatedRunTimeSeconds")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
b.Property<DateTime>("CreateDate")
|
b.Property<DateTime>("CreateDate")
|
||||||
.HasColumnType("timestamp with time zone");
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
@@ -251,6 +254,12 @@ namespace Managing.Infrastructure.Databases.Migrations
|
|||||||
.HasPrecision(18, 8)
|
.HasPrecision(18, 8)
|
||||||
.HasColumnType("numeric(18,8)");
|
.HasColumnType("numeric(18,8)");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastStartTime")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("LastStopTime")
|
||||||
|
.HasColumnType("timestamp with time zone");
|
||||||
|
|
||||||
b.Property<int>("LongPositionCount")
|
b.Property<int>("LongPositionCount")
|
||||||
.HasColumnType("integer");
|
.HasColumnType("integer");
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,12 @@ public class BotEntity
|
|||||||
public DateTime CreateDate { get; set; }
|
public DateTime CreateDate { get; set; }
|
||||||
public DateTime UpdatedAt { get; set; }
|
public DateTime UpdatedAt { get; set; }
|
||||||
public DateTime StartupTime { get; set; }
|
public DateTime StartupTime { get; set; }
|
||||||
|
|
||||||
|
// Runtime tracking fields
|
||||||
|
public DateTime? LastStartTime { get; set; }
|
||||||
|
public DateTime? LastStopTime { get; set; }
|
||||||
|
public long AccumulatedRunTimeSeconds { get; set; }
|
||||||
|
|
||||||
public int TradeWins { get; set; }
|
public int TradeWins { get; set; }
|
||||||
public int TradeLosses { get; set; }
|
public int TradeLosses { get; set; }
|
||||||
public decimal Pnl { get; set; }
|
public decimal Pnl { get; set; }
|
||||||
|
|||||||
@@ -445,6 +445,10 @@ public class ManagingDbContext : DbContext
|
|||||||
entity.Property(e => e.Status).IsRequired().HasConversion<string>();
|
entity.Property(e => e.Status).IsRequired().HasConversion<string>();
|
||||||
entity.Property(e => e.CreateDate).IsRequired();
|
entity.Property(e => e.CreateDate).IsRequired();
|
||||||
entity.Property(e => e.StartupTime).IsRequired();
|
entity.Property(e => e.StartupTime).IsRequired();
|
||||||
|
// Runtime tracking fields
|
||||||
|
entity.Property(e => e.LastStartTime);
|
||||||
|
entity.Property(e => e.LastStopTime);
|
||||||
|
entity.Property(e => e.AccumulatedRunTimeSeconds);
|
||||||
entity.Property(e => e.TradeWins).IsRequired();
|
entity.Property(e => e.TradeWins).IsRequired();
|
||||||
entity.Property(e => e.TradeLosses).IsRequired();
|
entity.Property(e => e.TradeLosses).IsRequired();
|
||||||
entity.Property(e => e.Pnl).HasPrecision(18, 8);
|
entity.Property(e => e.Pnl).HasPrecision(18, 8);
|
||||||
|
|||||||
@@ -692,6 +692,9 @@ public static class PostgreSqlMappers
|
|||||||
Name = entity.Name,
|
Name = entity.Name,
|
||||||
Ticker = entity.Ticker,
|
Ticker = entity.Ticker,
|
||||||
StartupTime = entity.StartupTime,
|
StartupTime = entity.StartupTime,
|
||||||
|
LastStartTime = entity.LastStartTime,
|
||||||
|
LastStopTime = entity.LastStopTime,
|
||||||
|
AccumulatedRunTimeSeconds = entity.AccumulatedRunTimeSeconds,
|
||||||
TradeWins = entity.TradeWins,
|
TradeWins = entity.TradeWins,
|
||||||
TradeLosses = entity.TradeLosses,
|
TradeLosses = entity.TradeLosses,
|
||||||
Pnl = entity.Pnl,
|
Pnl = entity.Pnl,
|
||||||
@@ -719,6 +722,9 @@ public static class PostgreSqlMappers
|
|||||||
Name = bot.Name,
|
Name = bot.Name,
|
||||||
Ticker = bot.Ticker,
|
Ticker = bot.Ticker,
|
||||||
StartupTime = bot.StartupTime,
|
StartupTime = bot.StartupTime,
|
||||||
|
LastStartTime = bot.LastStartTime,
|
||||||
|
LastStopTime = bot.LastStopTime,
|
||||||
|
AccumulatedRunTimeSeconds = bot.AccumulatedRunTimeSeconds,
|
||||||
TradeWins = bot.TradeWins,
|
TradeWins = bot.TradeWins,
|
||||||
TradeLosses = bot.TradeLosses,
|
TradeLosses = bot.TradeLosses,
|
||||||
Pnl = bot.Pnl,
|
Pnl = bot.Pnl,
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ const LogIn = () => {
|
|||||||
<label
|
<label
|
||||||
htmlFor="name"
|
htmlFor="name"
|
||||||
className="dark:text-white block mb-2 text-sm font-medium text-gray-900"
|
className="dark:text-white block mb-2 text-sm font-medium text-gray-900"
|
||||||
|
hidden={true}
|
||||||
>
|
>
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -4491,7 +4491,8 @@ export interface UserStrategyDetailsViewModel {
|
|||||||
pnL?: number;
|
pnL?: number;
|
||||||
netPnL?: number;
|
netPnL?: number;
|
||||||
roiPercentage?: number;
|
roiPercentage?: number;
|
||||||
runtime?: Date;
|
runtime?: Date | null;
|
||||||
|
totalRuntimeSeconds?: number;
|
||||||
winRate?: number;
|
winRate?: number;
|
||||||
totalVolumeTraded?: number;
|
totalVolumeTraded?: number;
|
||||||
volumeLast24H?: number;
|
volumeLast24H?: number;
|
||||||
|
|||||||
@@ -974,7 +974,8 @@ export interface UserStrategyDetailsViewModel {
|
|||||||
pnL?: number;
|
pnL?: number;
|
||||||
netPnL?: number;
|
netPnL?: number;
|
||||||
roiPercentage?: number;
|
roiPercentage?: number;
|
||||||
runtime?: Date;
|
runtime?: Date | null;
|
||||||
|
totalRuntimeSeconds?: number;
|
||||||
winRate?: number;
|
winRate?: number;
|
||||||
totalVolumeTraded?: number;
|
totalVolumeTraded?: number;
|
||||||
volumeLast24H?: number;
|
volumeLast24H?: number;
|
||||||
|
|||||||
@@ -48,14 +48,10 @@ function AgentSearch({ index }: { index: number }) {
|
|||||||
)
|
)
|
||||||
])
|
])
|
||||||
|
|
||||||
// Extract open positions from all strategies
|
// Extract positions from all strategies (status not available in generated PositionViewModel)
|
||||||
const allPositions = strategies.flatMap(strategy => strategy.positions || [])
|
const allPositions = strategies.flatMap(strategy => strategy.positions || [])
|
||||||
const openPositions = allPositions.filter(position =>
|
|
||||||
position.status !== 'Finished' &&
|
|
||||||
position.status !== 'Canceled'
|
|
||||||
)
|
|
||||||
|
|
||||||
setAgentData({ strategies, balances, positions: openPositions })
|
setAgentData({ strategies, balances, positions: allPositions })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError('Failed to fetch agent data. Please check the agent name and try again.')
|
setError('Failed to fetch agent data. Please check the agent name and try again.')
|
||||||
console.error('Error fetching agent data:', err)
|
console.error('Error fetching agent data:', err)
|
||||||
@@ -461,13 +457,20 @@ function AgentSearch({ index }: { index: number }) {
|
|||||||
{strategy.roiPercentage && strategy.roiPercentage >= 0 ? '+' : ''}{(strategy.roiPercentage || 0).toFixed(2)}%
|
{strategy.roiPercentage && strategy.roiPercentage >= 0 ? '+' : ''}{(strategy.roiPercentage || 0).toFixed(2)}%
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
{strategy.runtime ? (() => {
|
{strategy.totalRuntimeSeconds > 0 ? (() => {
|
||||||
const runtime = new Date(strategy.runtime)
|
const totalSeconds = strategy.totalRuntimeSeconds
|
||||||
const now = new Date()
|
const days = Math.floor(totalSeconds / 86400)
|
||||||
const diffHours = Math.floor((now.getTime() - runtime.getTime()) / (1000 * 60 * 60))
|
const hours = Math.floor((totalSeconds % 86400) / 3600)
|
||||||
const diffDays = Math.floor(diffHours / 24)
|
const minutes = Math.floor((totalSeconds % 3600) / 60)
|
||||||
return diffDays > 0 ? `${diffDays}d ${diffHours % 24}h` : `${diffHours}h`
|
if (days > 0) {
|
||||||
|
return `${days}d ${hours}h`
|
||||||
|
} else if (hours > 0) {
|
||||||
|
return `${hours}h ${minutes}m`
|
||||||
|
} else {
|
||||||
|
return `${minutes}m`
|
||||||
|
}
|
||||||
})() : '-'}
|
})() : '-'}
|
||||||
|
{strategy.state === BotStatus.Running && <span className="ml-1 text-green-500">●</span>}
|
||||||
</span>
|
</span>
|
||||||
<span>{(strategy.winRate || 0).toFixed(0)}%</span>
|
<span>{(strategy.winRate || 0).toFixed(0)}%</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import React, {useEffect, useState} from 'react'
|
import React, {useEffect, useState} from 'react'
|
||||||
import {PlayIcon, StopIcon} from '@heroicons/react/solid'
|
import {PlayIcon, StopIcon} from '@heroicons/react/solid'
|
||||||
import moment from 'moment'
|
|
||||||
import {
|
import {
|
||||||
BotClient,
|
BotClient,
|
||||||
BotStatus,
|
BotStatus,
|
||||||
DataClient,
|
DataClient,
|
||||||
Position,
|
PositionViewModel,
|
||||||
TradeDirection,
|
TradeDirection,
|
||||||
UserStrategyDetailsViewModel
|
UserStrategyDetailsViewModel
|
||||||
} from '../../generated/ManagingApi'
|
} from '../../generated/ManagingApi'
|
||||||
@@ -62,16 +61,12 @@ const AgentStrategy: React.FC<AgentStrategyProps> = ({ index }) => {
|
|||||||
return `${value >= 0 ? '+' : ''}${value.toFixed(2)}%`
|
return `${value >= 0 ? '+' : ''}${value.toFixed(2)}%`
|
||||||
}
|
}
|
||||||
|
|
||||||
const formatDuration = (runtime?: Date | null) => {
|
const formatDuration = (totalRuntimeSeconds?: number | null) => {
|
||||||
if (!runtime) return '0h'
|
if (!totalRuntimeSeconds || totalRuntimeSeconds === 0) return '0h'
|
||||||
|
|
||||||
const start = moment(runtime)
|
const days = Math.floor(totalRuntimeSeconds / 86400)
|
||||||
const now = moment()
|
const hours = Math.floor((totalRuntimeSeconds % 86400) / 3600)
|
||||||
const duration = moment.duration(now.diff(start))
|
const minutes = Math.floor((totalRuntimeSeconds % 3600) / 60)
|
||||||
|
|
||||||
const days = Math.floor(duration.asDays())
|
|
||||||
const hours = duration.hours()
|
|
||||||
const minutes = duration.minutes()
|
|
||||||
|
|
||||||
if (days > 0) {
|
if (days > 0) {
|
||||||
return `${days}d ${hours}h ${minutes}m`
|
return `${days}d ${hours}h ${minutes}m`
|
||||||
@@ -82,22 +77,22 @@ const AgentStrategy: React.FC<AgentStrategyProps> = ({ index }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getStatusBadge = (state: string | null | undefined) => {
|
const getStatusBadge = (state: BotStatus | null | undefined) => {
|
||||||
const badgeClass = state === 'Up'
|
const badgeClass = state === BotStatus.Running
|
||||||
? 'badge badge-success'
|
? 'badge badge-success'
|
||||||
: state === 'Down'
|
: state === BotStatus.Stopped
|
||||||
? 'badge badge-error'
|
? 'badge badge-warning'
|
||||||
: 'badge badge-neutral'
|
: 'badge badge-neutral'
|
||||||
|
|
||||||
return <span className={badgeClass}>{state}</span>
|
return <span className={badgeClass}>{state}</span>
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggleStrategyStatus = (status: string | null | undefined, identifier: string) => {
|
const toggleStrategyStatus = (status: BotStatus | null | undefined, identifier: string) => {
|
||||||
const isUp = status === 'Up'
|
const isRunning = status === BotStatus.Running
|
||||||
const t = new Toast(isUp ? 'Stopping strategy' : 'Starting strategy')
|
const t = new Toast(isRunning ? 'Stopping strategy' : 'Starting strategy')
|
||||||
|
|
||||||
console.log('toggleStrategyStatus', status, identifier)
|
console.log('toggleStrategyStatus', status, identifier)
|
||||||
if (status === 'Up') {
|
if (status === BotStatus.Running) {
|
||||||
botClient
|
botClient
|
||||||
.bot_Stop(identifier)
|
.bot_Stop(identifier)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -108,7 +103,7 @@ const AgentStrategy: React.FC<AgentStrategyProps> = ({ index }) => {
|
|||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
t.update('error', err)
|
t.update('error', err)
|
||||||
})
|
})
|
||||||
} else if (status === 'Down' || status === 'None') {
|
} else {
|
||||||
botClient
|
botClient
|
||||||
.bot_Restart(identifier)
|
.bot_Restart(identifier)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@@ -212,7 +207,7 @@ const AgentStrategy: React.FC<AgentStrategyProps> = ({ index }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="stat bg-base-200 rounded-lg">
|
<div className="stat bg-base-200 rounded-lg">
|
||||||
<div className="stat-title">Runtime</div>
|
<div className="stat-title">Runtime</div>
|
||||||
<div className="stat-value text-sm">{formatDuration(strategyData.runtime)}</div>
|
<div className="stat-value text-sm">{formatDuration(strategyData.totalRuntimeSeconds)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -292,7 +287,7 @@ const AgentStrategy: React.FC<AgentStrategyProps> = ({ index }) => {
|
|||||||
<div className="card bg-base-200">
|
<div className="card bg-base-200">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h3 className="card-title">Total Runtime</h3>
|
<h3 className="card-title">Total Runtime</h3>
|
||||||
<div className="text-2xl font-bold">{formatDuration(strategyData.runtime)}</div>
|
<div className="text-2xl font-bold">{formatDuration(strategyData.totalRuntimeSeconds)}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -302,7 +297,7 @@ const AgentStrategy: React.FC<AgentStrategyProps> = ({ index }) => {
|
|||||||
<div className="card bg-base-200">
|
<div className="card bg-base-200">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h3 className="card-title">Trade History</h3>
|
<h3 className="card-title">Trade History</h3>
|
||||||
{strategyData.positions && Object.keys(strategyData.positions).length > 0 ? (
|
{strategyData.positions && strategyData.positions.length > 0 ? (
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
<table className="table table-zebra">
|
<table className="table table-zebra">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -317,8 +312,7 @@ const AgentStrategy: React.FC<AgentStrategyProps> = ({ index }) => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{Object.values(strategyData.positions).map((position: Position, index: number) => (
|
{(strategyData.positions || []).map((position: PositionViewModel, index: number) => (
|
||||||
console.log(position),
|
|
||||||
<tr key={index}>
|
<tr key={index}>
|
||||||
<td>{new Date(position.Open.date || '').toLocaleDateString()}</td>
|
<td>{new Date(position.Open.date || '').toLocaleDateString()}</td>
|
||||||
<td>{position.ticker}</td>
|
<td>{position.ticker}</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user