Update dashboard

This commit is contained in:
2025-07-08 13:36:48 +07:00
parent 2551dddc23
commit 7a74c44739
6 changed files with 124 additions and 93 deletions

View File

@@ -0,0 +1,80 @@
import React from 'react'
import type {Indicator, IndicatorType} from '../../../generated/ManagingApi'
import {SignalType} from '../../../generated/ManagingApi'
interface IndicatorsDisplayProps {
indicators: Indicator[]
className?: string
}
// Helper function to get indicator parameters from scenario indicators
const getIndicatorParameters = (indicator: Indicator) => {
if (!indicator) return null;
return {
name: indicator.name || 'Unnamed Indicator',
type: indicator.type,
signalType: indicator.signalType,
period: indicator.period,
fastPeriods: indicator.fastPeriods,
slowPeriods: indicator.slowPeriods,
signalPeriods: indicator.signalPeriods,
multiplier: indicator.multiplier,
smoothPeriods: indicator.smoothPeriods,
stochPeriods: indicator.stochPeriods,
cyclePeriods: indicator.cyclePeriods
};
};
// Helper function to get badge color based on signal type
const getBadgeColor = (signalType: SignalType) => {
switch (signalType) {
case SignalType.Signal:
return 'badge-primary';
case SignalType.Trend:
return 'badge-secondary';
case SignalType.Context:
return 'badge-accent';
default:
return 'badge-neutral';
}
};
// Helper function to format indicator type for display
const formatIndicatorType = (type: IndicatorType) => {
return type.replace(/([A-Z])/g, ' $1').trim();
};
const IndicatorsDisplay: React.FC<IndicatorsDisplayProps> = ({ indicators, className = "" }) => {
const processedIndicators = indicators.map(getIndicatorParameters).filter(Boolean);
return (
<div className={`flex flex-wrap gap-1 ${className}`}>
{processedIndicators.map((indicator: any, index: number) => {
if (!indicator) return null;
// Build tooltip content with indicator parameters
const tooltipContent = `
${indicator.period ? `Period: ${indicator.period}` : ''}
${indicator.fastPeriods ? `Fast: ${indicator.fastPeriods}` : ''}
${indicator.slowPeriods ? `Slow: ${indicator.slowPeriods}` : ''}
${indicator.signalPeriods ? `Signal: ${indicator.signalPeriods}` : ''}
${indicator.multiplier ? `Multiplier: ${indicator.multiplier}` : ''}
${indicator.smoothPeriods ? `Smooth: ${indicator.smoothPeriods}` : ''}
${indicator.stochPeriods ? `Stoch: ${indicator.stochPeriods}` : ''}
${indicator.cyclePeriods ? `Cycle: ${indicator.cyclePeriods}` : ''}
`.trim().replace(/\n\s+/g, '\n');
return (
<div key={index} className="tooltip" data-tip={tooltipContent}>
<div className={`badge ${getBadgeColor(indicator.signalType)} badge-sm`}>
{formatIndicatorType(indicator.type)}
</div>
</div>
);
})}
</div>
);
};
export default IndicatorsDisplay;

View File

@@ -13,3 +13,4 @@ export { default as GridTile } from './GridTile/GridTile'
export { default as SelectColumnFilter } from './Table/SelectColumnFilter'
export { default as Card } from './Card/Card'
export { default as ConfigDisplayModal } from './ConfigDisplayModal/ConfigDisplayModal'
export { default as IndicatorsDisplay } from './IndicatorsDisplay/IndicatorsDisplay'

View File

@@ -3,15 +3,15 @@ import React, {useEffect, useState} from 'react'
import {Hub} from '../../../app/providers/Hubs'
import useApiUrlStore from '../../../app/store/apiStore'
import type {Account, TradingBot} from '../../../generated/ManagingApi'
import type {Account, TradingBotResponse} from '../../../generated/ManagingApi'
import {AccountClient, BotClient, TradeDirection, TradeStatus,} from '../../../generated/ManagingApi'
import {SelectColumnFilter, Table} from '../../mollecules'
import {IndicatorsDisplay, SelectColumnFilter, Table} from '../../mollecules'
import StatusBadge from '../StatusBadge/StatusBadge'
import Summary from '../Trading/Summary'
import BotRowDetails from './botRowDetails'
export default function ActiveBots() {
const [bots, setBots] = useState<TradingBot[]>([])
const [bots, setBots] = useState<TradingBotResponse[]>([])
const [accounts, setAccounts] = useState<Account[]>([])
const { apiUrl } = useApiUrlStore()
@@ -64,23 +64,31 @@ export default function ActiveBots() {
{
Filter: SelectColumnFilter,
Header: 'Ticker',
accessor: 'ticker',
accessor: 'config.ticker',
disableSortBy: true,
},
{
Header: 'Account',
accessor: 'accountName',
Header: 'Name',
accessor: 'config.name',
},
{
Filter: SelectColumnFilter,
Header: 'Timeframe',
accessor: 'timeframe',
accessor: 'config.timeframe',
disableSortBy: true,
},
{
Filter: SelectColumnFilter,
Header: 'Scenario',
accessor: 'scenario',
Header: 'Indicators',
accessor: 'config.scenario.indicators',
Cell: ({cell}: any) => {
const bot = cell.row.original as TradingBotResponse;
const indicators = bot.config?.scenario?.indicators || [];
return (
<IndicatorsDisplay indicators={indicators} />
);
},
disableFilters: true,
disableSortBy: true,
},
{
@@ -161,12 +169,12 @@ export default function ActiveBots() {
const setupHubConnection = async () => {
const hub = new Hub('bothub', apiUrl).hub
hub.on('BotsSubscription', (data: TradingBot[]) => {
hub.on('BotsSubscription', (data: TradingBotResponse[]) => {
// eslint-disable-next-line no-console
console.log(
'bot List',
bots.map((bot: TradingBot) => {
return bot.name
bots.map((bot: TradingBotResponse) => {
return bot.config.name
})
)
setBots(data)

View File

@@ -1,9 +1,9 @@
import { TradeChart, CardPositionItem } from '..'
import { Backtest, MoneyManagement, TradingBot } from '../../../generated/ManagingApi'
import {CardPositionItem, TradeChart} from '..'
import {TradingBotResponse} from '../../../generated/ManagingApi'
import {CardPosition, CardText} from '../../mollecules'
interface IBotRowDetailsProps {
bot: TradingBot;
bot: TradingBotResponse;
}
const BotRowDetails: React.FC<IBotRowDetailsProps> = ({
@@ -18,7 +18,8 @@ const BotRowDetails: React.FC<IBotRowDetailsProps> = ({
candles,
positions,
signals,
moneyManagement
config,
agentName
} = bot;
return (
@@ -43,8 +44,8 @@ const BotRowDetails: React.FC<IBotRowDetailsProps> = ({
<CardText
title="Money Management"
content={
"SL: " +(moneyManagement?.stopLoss * 100).toFixed(2) + "% TP: " +
(moneyManagement?.takeProfit * 100).toFixed(2) + "%"
"SL: " +(config.moneyManagement?.stopLoss * 100).toFixed(2) + "% TP: " +
(config.moneyManagement?.takeProfit * 100).toFixed(2) + "%"
}
></CardText>

View File

@@ -3,9 +3,9 @@ import React, {useEffect, useState} from 'react'
import useApiUrlStore from '../../../app/store/apiStore'
import useBacktestStore from '../../../app/store/backtestStore'
import type {Backtest, Indicator, IndicatorType} from '../../../generated/ManagingApi'
import {BacktestClient, SignalType} from '../../../generated/ManagingApi'
import {CardText, ConfigDisplayModal, SelectColumnFilter, Table} from '../../mollecules'
import type {Backtest} from '../../../generated/ManagingApi'
import {BacktestClient} from '../../../generated/ManagingApi'
import {CardText, ConfigDisplayModal, IndicatorsDisplay, SelectColumnFilter, Table} from '../../mollecules'
import {UnifiedTradingModal} from '../index'
import Toast from '../../mollecules/Toast/Toast'
@@ -16,49 +16,7 @@ interface BacktestTableProps {
isFetching?: boolean
}
// Helper function to get indicator parameters from scenario indicators
const getIndicatorParameters = (indicator: Indicator) => {
if (!indicator) return null;
return {
name: indicator.name || 'Unnamed Indicator',
type: indicator.type,
signalType: indicator.signalType,
period: indicator.period,
fastPeriods: indicator.fastPeriods,
slowPeriods: indicator.slowPeriods,
signalPeriods: indicator.signalPeriods,
multiplier: indicator.multiplier,
smoothPeriods: indicator.smoothPeriods,
stochPeriods: indicator.stochPeriods,
cyclePeriods: indicator.cyclePeriods
};
};
// Helper function to get indicators from scenario
const getScenarioIndicators = (backtest: Backtest) => {
if (!backtest.config?.scenario?.indicators) return [];
return backtest.config.scenario.indicators.map(getIndicatorParameters).filter(Boolean);
};
// Helper function to get badge color based on signal type
const getBadgeColor = (signalType: SignalType) => {
switch (signalType) {
case SignalType.Signal:
return 'badge-primary';
case SignalType.Trend:
return 'badge-secondary';
case SignalType.Context:
return 'badge-accent';
default:
return 'badge-neutral';
}
};
// Helper function to format indicator type for display
const formatIndicatorType = (type: IndicatorType) => {
return type.replace(/([A-Z])/g, ' $1').trim();
};
const BacktestTable: React.FC<BacktestTableProps> = ({list, isFetching}) => {
const [rows, setRows] = useState<Backtest[]>([])
@@ -207,34 +165,10 @@ const BacktestTable: React.FC<BacktestTableProps> = ({list, isFetching}) => {
accessor: 'config.scenario.indicators',
Cell: ({cell}: any) => {
const backtest = cell.row.original as Backtest;
const indicators = getScenarioIndicators(backtest);
const indicators = backtest.config?.scenario?.indicators || [];
return (
<div className="flex flex-wrap gap-1">
{indicators.map((indicator: any, index: number) => {
if (!indicator) return null;
// Build tooltip content with indicator parameters
const tooltipContent = `
${indicator.period ? `Period: ${indicator.period}` : ''}
${indicator.fastPeriods ? `Fast: ${indicator.fastPeriods}` : ''}
${indicator.slowPeriods ? `Slow: ${indicator.slowPeriods}` : ''}
${indicator.signalPeriods ? `Signal: ${indicator.signalPeriods}` : ''}
${indicator.multiplier ? `Multiplier: ${indicator.multiplier}` : ''}
${indicator.smoothPeriods ? `Smooth: ${indicator.smoothPeriods}` : ''}
${indicator.stochPeriods ? `Stoch: ${indicator.stochPeriods}` : ''}
${indicator.cyclePeriods ? `Cycle: ${indicator.cyclePeriods}` : ''}
`.trim().replace(/\n\s+/g, '\n');
return (
<div key={index} className="tooltip" data-tip={tooltipContent}>
<div className={`badge ${getBadgeColor(indicator.signalType)} badge-sm`}>
{formatIndicatorType(indicator.type)}
</div>
</div>
);
})}
</div>
<IndicatorsDisplay indicators={indicators} />
);
},
disableFilters: true,

View File

@@ -258,7 +258,7 @@ const BotList: React.FC<IBotList> = ({ list }) => {
<div className="mb-4">
{/* Bot Name - Always on its own line */}
<h2 className="card-title text-sm mb-3">
{bot.config.ticker}
{bot.config.name}
</h2>
{/* Badge Container - Responsive */}
@@ -282,6 +282,10 @@ const BotList: React.FC<IBotList> = ({ list }) => {
<div className="columns-2">
<div>
<div>
<CardText
title="Ticker"
content={bot.config.ticker}
></CardText>
<CardText
title="Scenario"
content={bot.config.scenarioName ?? bot.config.scenario?.name}
@@ -290,8 +294,11 @@ const BotList: React.FC<IBotList> = ({ list }) => {
</div>
</div>
<div className="columns-2">
<CardText
title="Agent"
content={bot.agentName}
></CardText>
<CardSignal signals={bot.signals}></CardSignal>
<CardText title="Type" content={bot.config.flipPosition ? 'Flipping' : 'Simple'}></CardText>
</div>
<div className="columns-2">
<CardPosition