Update dashboard
This commit is contained in:
@@ -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;
|
||||||
@@ -13,3 +13,4 @@ export { default as GridTile } from './GridTile/GridTile'
|
|||||||
export { default as SelectColumnFilter } from './Table/SelectColumnFilter'
|
export { default as SelectColumnFilter } from './Table/SelectColumnFilter'
|
||||||
export { default as Card } from './Card/Card'
|
export { default as Card } from './Card/Card'
|
||||||
export { default as ConfigDisplayModal } from './ConfigDisplayModal/ConfigDisplayModal'
|
export { default as ConfigDisplayModal } from './ConfigDisplayModal/ConfigDisplayModal'
|
||||||
|
export { default as IndicatorsDisplay } from './IndicatorsDisplay/IndicatorsDisplay'
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ import React, {useEffect, useState} from 'react'
|
|||||||
|
|
||||||
import {Hub} from '../../../app/providers/Hubs'
|
import {Hub} from '../../../app/providers/Hubs'
|
||||||
import useApiUrlStore from '../../../app/store/apiStore'
|
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 {AccountClient, BotClient, TradeDirection, TradeStatus,} from '../../../generated/ManagingApi'
|
||||||
import {SelectColumnFilter, Table} from '../../mollecules'
|
import {IndicatorsDisplay, SelectColumnFilter, Table} from '../../mollecules'
|
||||||
import StatusBadge from '../StatusBadge/StatusBadge'
|
import StatusBadge from '../StatusBadge/StatusBadge'
|
||||||
import Summary from '../Trading/Summary'
|
import Summary from '../Trading/Summary'
|
||||||
import BotRowDetails from './botRowDetails'
|
import BotRowDetails from './botRowDetails'
|
||||||
|
|
||||||
export default function ActiveBots() {
|
export default function ActiveBots() {
|
||||||
const [bots, setBots] = useState<TradingBot[]>([])
|
const [bots, setBots] = useState<TradingBotResponse[]>([])
|
||||||
const [accounts, setAccounts] = useState<Account[]>([])
|
const [accounts, setAccounts] = useState<Account[]>([])
|
||||||
const { apiUrl } = useApiUrlStore()
|
const { apiUrl } = useApiUrlStore()
|
||||||
|
|
||||||
@@ -64,23 +64,31 @@ export default function ActiveBots() {
|
|||||||
{
|
{
|
||||||
Filter: SelectColumnFilter,
|
Filter: SelectColumnFilter,
|
||||||
Header: 'Ticker',
|
Header: 'Ticker',
|
||||||
accessor: 'ticker',
|
accessor: 'config.ticker',
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Account',
|
Header: 'Name',
|
||||||
accessor: 'accountName',
|
accessor: 'config.name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Filter: SelectColumnFilter,
|
Filter: SelectColumnFilter,
|
||||||
Header: 'Timeframe',
|
Header: 'Timeframe',
|
||||||
accessor: 'timeframe',
|
accessor: 'config.timeframe',
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Filter: SelectColumnFilter,
|
Header: 'Indicators',
|
||||||
Header: 'Scenario',
|
accessor: 'config.scenario.indicators',
|
||||||
accessor: 'scenario',
|
Cell: ({cell}: any) => {
|
||||||
|
const bot = cell.row.original as TradingBotResponse;
|
||||||
|
const indicators = bot.config?.scenario?.indicators || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IndicatorsDisplay indicators={indicators} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
disableFilters: true,
|
||||||
disableSortBy: true,
|
disableSortBy: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -161,12 +169,12 @@ export default function ActiveBots() {
|
|||||||
const setupHubConnection = async () => {
|
const setupHubConnection = async () => {
|
||||||
const hub = new Hub('bothub', apiUrl).hub
|
const hub = new Hub('bothub', apiUrl).hub
|
||||||
|
|
||||||
hub.on('BotsSubscription', (data: TradingBot[]) => {
|
hub.on('BotsSubscription', (data: TradingBotResponse[]) => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(
|
console.log(
|
||||||
'bot List',
|
'bot List',
|
||||||
bots.map((bot: TradingBot) => {
|
bots.map((bot: TradingBotResponse) => {
|
||||||
return bot.name
|
return bot.config.name
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
setBots(data)
|
setBots(data)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { TradeChart, CardPositionItem } from '..'
|
import {CardPositionItem, TradeChart} from '..'
|
||||||
import { Backtest, MoneyManagement, TradingBot } from '../../../generated/ManagingApi'
|
import {TradingBotResponse} from '../../../generated/ManagingApi'
|
||||||
import { CardPosition, CardText } from '../../mollecules'
|
import {CardPosition, CardText} from '../../mollecules'
|
||||||
|
|
||||||
interface IBotRowDetailsProps {
|
interface IBotRowDetailsProps {
|
||||||
bot: TradingBot;
|
bot: TradingBotResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BotRowDetails: React.FC<IBotRowDetailsProps> = ({
|
const BotRowDetails: React.FC<IBotRowDetailsProps> = ({
|
||||||
@@ -18,7 +18,8 @@ const BotRowDetails: React.FC<IBotRowDetailsProps> = ({
|
|||||||
candles,
|
candles,
|
||||||
positions,
|
positions,
|
||||||
signals,
|
signals,
|
||||||
moneyManagement
|
config,
|
||||||
|
agentName
|
||||||
} = bot;
|
} = bot;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -43,8 +44,8 @@ const BotRowDetails: React.FC<IBotRowDetailsProps> = ({
|
|||||||
<CardText
|
<CardText
|
||||||
title="Money Management"
|
title="Money Management"
|
||||||
content={
|
content={
|
||||||
"SL: " +(moneyManagement?.stopLoss * 100).toFixed(2) + "% TP: " +
|
"SL: " +(config.moneyManagement?.stopLoss * 100).toFixed(2) + "% TP: " +
|
||||||
(moneyManagement?.takeProfit * 100).toFixed(2) + "%"
|
(config.moneyManagement?.takeProfit * 100).toFixed(2) + "%"
|
||||||
}
|
}
|
||||||
></CardText>
|
></CardText>
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import React, {useEffect, useState} from 'react'
|
|||||||
|
|
||||||
import useApiUrlStore from '../../../app/store/apiStore'
|
import useApiUrlStore from '../../../app/store/apiStore'
|
||||||
import useBacktestStore from '../../../app/store/backtestStore'
|
import useBacktestStore from '../../../app/store/backtestStore'
|
||||||
import type {Backtest, Indicator, IndicatorType} from '../../../generated/ManagingApi'
|
import type {Backtest} from '../../../generated/ManagingApi'
|
||||||
import {BacktestClient, SignalType} from '../../../generated/ManagingApi'
|
import {BacktestClient} from '../../../generated/ManagingApi'
|
||||||
import {CardText, ConfigDisplayModal, SelectColumnFilter, Table} from '../../mollecules'
|
import {CardText, ConfigDisplayModal, IndicatorsDisplay, SelectColumnFilter, Table} from '../../mollecules'
|
||||||
import {UnifiedTradingModal} from '../index'
|
import {UnifiedTradingModal} from '../index'
|
||||||
import Toast from '../../mollecules/Toast/Toast'
|
import Toast from '../../mollecules/Toast/Toast'
|
||||||
|
|
||||||
@@ -16,49 +16,7 @@ interface BacktestTableProps {
|
|||||||
isFetching?: boolean
|
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 BacktestTable: React.FC<BacktestTableProps> = ({list, isFetching}) => {
|
||||||
const [rows, setRows] = useState<Backtest[]>([])
|
const [rows, setRows] = useState<Backtest[]>([])
|
||||||
@@ -207,34 +165,10 @@ const BacktestTable: React.FC<BacktestTableProps> = ({list, isFetching}) => {
|
|||||||
accessor: 'config.scenario.indicators',
|
accessor: 'config.scenario.indicators',
|
||||||
Cell: ({cell}: any) => {
|
Cell: ({cell}: any) => {
|
||||||
const backtest = cell.row.original as Backtest;
|
const backtest = cell.row.original as Backtest;
|
||||||
const indicators = getScenarioIndicators(backtest);
|
const indicators = backtest.config?.scenario?.indicators || [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-wrap gap-1">
|
<IndicatorsDisplay indicators={indicators} />
|
||||||
{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>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
disableFilters: true,
|
disableFilters: true,
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
|||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
{/* Bot Name - Always on its own line */}
|
{/* Bot Name - Always on its own line */}
|
||||||
<h2 className="card-title text-sm mb-3">
|
<h2 className="card-title text-sm mb-3">
|
||||||
{bot.config.ticker}
|
{bot.config.name}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
{/* Badge Container - Responsive */}
|
{/* Badge Container - Responsive */}
|
||||||
@@ -282,6 +282,10 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
|||||||
<div className="columns-2">
|
<div className="columns-2">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
<CardText
|
||||||
|
title="Ticker"
|
||||||
|
content={bot.config.ticker}
|
||||||
|
></CardText>
|
||||||
<CardText
|
<CardText
|
||||||
title="Scenario"
|
title="Scenario"
|
||||||
content={bot.config.scenarioName ?? bot.config.scenario?.name}
|
content={bot.config.scenarioName ?? bot.config.scenario?.name}
|
||||||
@@ -290,8 +294,11 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="columns-2">
|
<div className="columns-2">
|
||||||
|
<CardText
|
||||||
|
title="Agent"
|
||||||
|
content={bot.agentName}
|
||||||
|
></CardText>
|
||||||
<CardSignal signals={bot.signals}></CardSignal>
|
<CardSignal signals={bot.signals}></CardSignal>
|
||||||
<CardText title="Type" content={bot.config.flipPosition ? 'Flipping' : 'Simple'}></CardText>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="columns-2">
|
<div className="columns-2">
|
||||||
<CardPosition
|
<CardPosition
|
||||||
|
|||||||
Reference in New Issue
Block a user