/** * @file Node definitions for trading analytics dashboard */ import * as React from "react"; import { createNodeDefinition, asNodeDefinition, type NodeDefinition, type NodeRendererProps, } from "../../../../../types/NodeDefinition"; import { NodeResizer } from "../../../../../components/node/resize/NodeResizer"; import { renderTradingConnection, renderTradingPort } from "./tradingRenderers"; import classes from "./TradingAnalyticsDashboard.module.css"; // Strategy/Signal card data types type StrategyCardData = { title: string; trader: string; signals: number; winRate: number; status: "active" | "testing" | "paused" | "deployed"; }; // Trading metric data types type MetricPeriodValue = { value: number | string; change: number | null; }; type TradingMetricData = { title: string; metricType: string; past1day: MetricPeriodValue; past1week: MetricPeriodValue; past1month: MetricPeriodValue; trendDirection: "up" | "down"; symbol?: string; }; type PerformanceMetricData = { title: string; metricType: string; past1day: MetricPeriodValue; past1week: MetricPeriodValue; past1month: MetricPeriodValue; target?: { value: number; label: string }; variance?: number; }; type PortfolioMetricData = { title: string; metricType: string; past1day: MetricPeriodValue; past1week: MetricPeriodValue; past1month: MetricPeriodValue; symbol?: string; }; // Helper to format values const formatValue = (value: number | string): string => { if (typeof value === "string") { return value; } return value.toLocaleString(); }; // Helper to format percentage const formatPercentage = (change: number | null): string => { if (change === null) { return "No change"; } const sign = change >= 0 ? "+" : ""; return `${sign}${change.toFixed(2)}%`; }; // Strategy Card Renderer const StrategyCardRenderer = ({ node }: NodeRendererProps) => { const statusColors = { active: "#10b981", testing: "#f59e0b", paused: "#6366f1", deployed: "#8b5cf6", }; return ( {({ width, height }) => (

{node.data.title}

{node.data.trader}
{node.data.signals} signals • {node.data.winRate}% win rate
{node.data.status === "paused" && "Paused"} {node.data.status === "active" && "Active"} {node.data.status === "testing" && "Testing"} {node.data.status === "deployed" && "Deployed"}
)} ); }; // Trading Metric Renderer const TradingMetricRenderer = ({ node }: NodeRendererProps) => { return ( {({ width, height }) => (

{node.data.title}

📊 {node.data.metricType}
Past 24h
{node.data.symbol} {formatValue(node.data.past1day.value)}
= 0} > {formatPercentage(node.data.past1day.change)} ↑
Past 1 week
{node.data.symbol} {formatValue(node.data.past1week.value)}
= 0} > {formatPercentage(node.data.past1week.change)} ↑
Past 1 month
{node.data.symbol} {formatValue(node.data.past1month.value)}
= 0} > {formatPercentage(node.data.past1month.change)} ↑
)}
); }; // Performance Metric Renderer (with target) const PerformanceMetricRenderer = ({ node }: NodeRendererProps) => { return ( {({ width, height }) => (

{node.data.title}

🎯 {node.data.metricType}
{node.data.target && (
Target: {node.data.target.value.toLocaleString()} {node.data.target.label}
)}
24h
{formatValue(node.data.past1day.value)}
= 0} > {formatPercentage(node.data.past1day.change)}
1 week
{formatValue(node.data.past1week.value)}
= 0} > {formatPercentage(node.data.past1week.change)}
1 month
{formatValue(node.data.past1month.value)}
= 0} > {formatPercentage(node.data.past1month.change)}
{node.data.variance !== undefined && (
{node.data.variance.toFixed(3)}
)}
)}
); }; // Portfolio Metric Renderer const PortfolioMetricRenderer = ({ node }: NodeRendererProps) => { return ( {({ width, height }) => (

{node.data.title}

💼 {node.data.metricType}
Past 24h
{node.data.symbol} {formatValue(node.data.past1day.value)}
= 0} > {formatPercentage(node.data.past1day.change)} ↑
Past 1 week
{node.data.symbol} {formatValue(node.data.past1week.value)}
= 0} > {formatPercentage(node.data.past1week.change)} ↑
Past 1 month
{node.data.symbol} {formatValue(node.data.past1month.value)}
= 0} > {formatPercentage(node.data.past1month.change)} ↑
)}
); }; // Node Definitions const AlgoTradingStrategyDefinition = createNodeDefinition({ type: "algo-strategy", displayName: "Algorithm Trading Strategy", category: "Trading", defaultData: { title: "New Strategy", trader: "Trader", signals: 0, winRate: 0, status: "paused", }, defaultSize: { width: 220, height: 140 }, renderNode: StrategyCardRenderer, ports: [ { id: "output", type: "output", label: "", position: "right", renderPort: renderTradingPort, renderConnection: renderTradingConnection, }, ], }); const SignalSourceDefinition = createNodeDefinition({ type: "signal-source", displayName: "Signal Source", category: "Trading", defaultData: { title: "New Signal", trader: "Source", signals: 0, winRate: 0, status: "paused", }, defaultSize: { width: 220, height: 120 }, renderNode: StrategyCardRenderer, ports: [ { id: "output", type: "output", label: "", position: "right", renderPort: renderTradingPort, renderConnection: renderTradingConnection, }, ], }); const TradingVolumeDefinition = createNodeDefinition({ type: "trading-volume", displayName: "Trading Volume", category: "Metrics", defaultData: { title: "Trading Volume", metricType: "Volume", past1day: { value: 0, change: 0 }, past1week: { value: 0, change: 0 }, past1month: { value: 0, change: 0 }, trendDirection: "up", }, defaultSize: { width: 320, height: 180 }, renderNode: TradingMetricRenderer, ports: [ { id: "input", type: "input", label: "", position: "left", renderPort: renderTradingPort, renderConnection: renderTradingConnection, }, { id: "output", type: "output", label: "", position: "right", renderPort: renderTradingPort, renderConnection: renderTradingConnection, }, ], }); const PerformanceMetricDefinition = createNodeDefinition({ type: "performance-metric", displayName: "Performance Metric", category: "Metrics", defaultData: { title: "Performance", metricType: "Performance", past1day: { value: 0, change: 0 }, past1week: { value: 0, change: 0 }, past1month: { value: 0, change: 0 }, }, defaultSize: { width: 320, height: 240 }, renderNode: PerformanceMetricRenderer, ports: [ { id: "input", type: "input", label: "", position: "left", renderPort: renderTradingPort, renderConnection: renderTradingConnection, }, { id: "output", type: "output", label: "", position: "right", renderPort: renderTradingPort, renderConnection: renderTradingConnection, }, ], }); const PortfolioMetricDefinition = createNodeDefinition({ type: "portfolio-metric", displayName: "Portfolio Metric", category: "Portfolio", defaultData: { title: "Portfolio Value", metricType: "Portfolio", past1day: { value: 0, change: 0 }, past1week: { value: 0, change: 0 }, past1month: { value: 0, change: 0 }, }, defaultSize: { width: 280, height: 160 }, renderNode: PortfolioMetricRenderer, ports: [ { id: "input", type: "input", label: "", position: "left", renderPort: renderTradingPort, renderConnection: renderTradingConnection, }, { id: "output", type: "output", label: "", position: "right", renderPort: renderTradingPort, renderConnection: renderTradingConnection, }, ], }); export const createTradingNodeDefinitions = (): NodeDefinition[] => [ asNodeDefinition(AlgoTradingStrategyDefinition), asNodeDefinition(SignalSourceDefinition), asNodeDefinition(TradingVolumeDefinition), asNodeDefinition(PerformanceMetricDefinition), asNodeDefinition(PortfolioMetricDefinition), ];