behemoth-cli
Version:
š BEHEMOTH CLIv3.760.4 - Level 50+ POST-SINGULARITY Intelligence Trading AI
310 lines (307 loc) ⢠12.7 kB
JavaScript
/**
* Chart Command - Interactive ASCII charts for crypto data
*/
import { BaseCommand } from '../base.js';
import InteractiveChartManager, { MultiSymbolDashboard } from '../../ui/components/display/InteractiveChartManager.js';
import { render } from 'ink';
import React from 'react';
export class ChartCommand extends BaseCommand {
command = 'chart';
description = 'Display interactive ASCII charts for crypto analysis';
examples = [
'/chart --symbol=BTCUSDT --type=price',
'/chart --symbol=ETHUSDT --type=all',
'/chart --dashboard',
'/chart --symbol=BTCUSDT --interactive'
];
handler(context) {
// This handler is for the CommandDefinition interface
// The actual chart functionality is in the execute method
console.log('Chart command handler called');
}
async execute(args, agent) {
const { symbol = 'BTCUSDT', type = 'price', timeframe = '1h', interactive = true, dashboard = false } = args;
try {
if (dashboard) {
return this.showDashboard(agent);
}
if (interactive) {
return this.showInteractiveCharts(symbol, type, timeframe, agent);
}
// Static chart fallback
return this.generateStaticChart(symbol, type, timeframe, agent);
}
catch (error) {
return `ā Failed to generate chart: ${error instanceof Error ? error.message : 'Unknown error'}`;
}
}
async showDashboard(agent) {
const popularSymbols = [
'BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'ADAUSDT', 'XRPUSDT',
'SOLUSDT', 'DOTUSDT', 'DOGEUSDT', 'AVAXUSDT', 'MATICUSDT'
];
return new Promise((resolve) => {
const DashboardApp = () => {
return React.createElement(MultiSymbolDashboard, {
symbols: popularSymbols,
onSymbolSelect: async (selectedSymbol) => {
// Close dashboard and show charts for selected symbol
const result = await this.showInteractiveCharts(selectedSymbol, 'all', '1h', agent);
resolve(result);
},
onClose: () => {
resolve('š Chart dashboard closed');
}
});
};
// Render the dashboard
const { unmount } = render(React.createElement(DashboardApp));
// Auto-cleanup after 60 seconds
setTimeout(() => {
unmount();
resolve('š Chart dashboard timed out');
}, 60000);
});
}
async showInteractiveCharts(symbol, type, timeframe, agent) {
// Fetch real data using BEHEMOTH tools
const chartConfigs = await this.generateChartConfigs(symbol, type, timeframe, agent);
return new Promise((resolve) => {
const ChartApp = () => {
return React.createElement(InteractiveChartManager, {
charts: chartConfigs,
onRefresh: async (chartId) => {
// Refresh specific chart data
await this.refreshChartData(chartId, symbol, agent);
},
onClose: () => {
resolve(`š Interactive charts for ${symbol} closed`);
}
});
};
// Render the interactive charts
const { unmount } = render(React.createElement(ChartApp));
// Auto-cleanup after 5 minutes
setTimeout(() => {
unmount();
resolve(`š Interactive charts for ${symbol} timed out`);
}, 300000);
});
}
async generateChartConfigs(symbol, type, timeframe, agent) {
const configs = [];
try {
if (type === 'price' || type === 'all') {
// Get price data
const priceResult = await agent.executeTool('mcp__behemoth__binance_spot_ticker', { symbol });
const klineResult = await agent.executeTool('mcp__behemoth__bitget_klines', {
symbol,
interval: timeframe,
limit: 20
});
if (klineResult?.success && klineResult.data?.length) {
const prices = klineResult.data.map((candle) => parseFloat(candle.close));
const timestamps = klineResult.data.map((candle) => new Date(candle.timestamp).toLocaleTimeString());
configs.push({
id: `price_${symbol}`,
title: `${symbol} Price`,
type: 'price',
symbol,
data: prices,
timestamps,
autoRefresh: true,
refreshInterval: 30
});
}
}
if (type === 'rsi' || type === 'all') {
// Get RSI data
const rsiResult = await agent.executeTool('mcp__behemoth__rsi_analysis', { symbol });
if (rsiResult?.success && rsiResult.data?.rsi_values) {
configs.push({
id: `rsi_${symbol}`,
title: `${symbol} RSI`,
type: 'rsi',
symbol,
data: rsiResult.data.rsi_values,
timestamps: rsiResult.data.timestamps,
autoRefresh: true,
refreshInterval: 30
});
}
}
if (type === 'volume' || type === 'all') {
// Get volume data from klines
const klineResult = await agent.executeTool('mcp__behemoth__bitget_klines', {
symbol,
interval: timeframe,
limit: 20
});
if (klineResult?.success && klineResult.data?.length) {
const volumes = klineResult.data.map((candle) => parseFloat(candle.volume));
const timestamps = klineResult.data.map((candle) => new Date(candle.timestamp).toLocaleTimeString());
configs.push({
id: `volume_${symbol}`,
title: `${symbol} Volume`,
type: 'volume',
symbol,
data: volumes,
timestamps,
autoRefresh: true,
refreshInterval: 30
});
}
}
// If no real data, generate mock data for demo
if (configs.length === 0) {
configs.push(...this.generateMockChartConfigs(symbol, type));
}
}
catch (error) {
console.error('Error generating chart configs:', error);
// Fallback to mock data
configs.push(...this.generateMockChartConfigs(symbol, type));
}
return configs;
}
generateMockChartConfigs(symbol, type) {
const configs = [];
const timestamps = Array.from({ length: 20 }, (_, i) => {
const time = new Date(Date.now() - (19 - i) * 60000);
return time.toLocaleTimeString();
});
if (type === 'price' || type === 'all') {
const basePrice = 45000 + Math.random() * 10000;
const prices = Array.from({ length: 20 }, (_, i) => {
return basePrice + (Math.random() - 0.5) * 2000 + Math.sin(i * 0.5) * 1000;
});
configs.push({
id: `price_${symbol}`,
title: `${symbol} Price (Demo)`,
type: 'price',
symbol,
data: prices,
timestamps,
autoRefresh: true,
refreshInterval: 30
});
}
if (type === 'rsi' || type === 'all') {
const rsiValues = Array.from({ length: 20 }, (_, i) => {
return 30 + Math.random() * 40 + Math.sin(i * 0.3) * 10;
});
configs.push({
id: `rsi_${symbol}`,
title: `${symbol} RSI (Demo)`,
type: 'rsi',
symbol,
data: rsiValues,
timestamps,
autoRefresh: true,
refreshInterval: 30
});
}
if (type === 'volume' || type === 'all') {
const volumes = Array.from({ length: 20 }, (_, i) => {
return 1000000 + Math.random() * 5000000;
});
configs.push({
id: `volume_${symbol}`,
title: `${symbol} Volume (Demo)`,
type: 'volume',
symbol,
data: volumes,
timestamps,
autoRefresh: true,
refreshInterval: 30
});
}
return configs;
}
async refreshChartData(chartId, symbol, agent) {
try {
// Refresh data based on chart type
if (chartId.includes('price')) {
await agent.executeTool('mcp__behemoth__bitget_klines', { symbol, limit: 20 });
}
else if (chartId.includes('rsi')) {
await agent.executeTool('mcp__behemoth__rsi_analysis', { symbol });
}
else if (chartId.includes('volume')) {
await agent.executeTool('mcp__behemoth__bitget_klines', { symbol, limit: 20 });
}
}
catch (error) {
console.error(`Failed to refresh chart ${chartId}:`, error);
}
}
async generateStaticChart(symbol, type, timeframe, agent) {
try {
// Generate a simple text-based chart for non-interactive mode
const result = await agent.executeTool('mcp__behemoth__binance_spot_ticker', { symbol });
if (result?.success) {
const price = parseFloat(result.data.price);
const change = parseFloat(result.data.priceChangePercent);
// Simple sparkline
const sparkline = this.generateSparkline(price, change);
return `š ${symbol} ${type.toUpperCase()} Chart (${timeframe})
Current Price: $${price.toLocaleString()}
24h Change: ${change >= 0 ? '+' : ''}${change.toFixed(2)}%
${sparkline}
š” Use --interactive flag for full interactive charts
Example: /chart --symbol=${symbol} --interactive`;
}
}
catch (error) {
console.error('Error generating static chart:', error);
}
return `š Unable to generate chart for ${symbol}. Try /chart --dashboard for available symbols.`;
}
generateSparkline(price, change) {
// Generate a simple sparkline based on price and change
const chars = ['ā', 'ā', 'ā', 'ā', 'ā
', 'ā', 'ā', 'ā'];
let line = '';
for (let i = 0; i < 20; i++) {
const variation = Math.sin(i * 0.5) * 0.1 + (change / 100);
const normalized = Math.max(0, Math.min(1, 0.5 + variation));
const charIndex = Math.floor(normalized * (chars.length - 1));
line += chars[charIndex];
}
return line;
}
getSchema() {
return {
type: 'object',
properties: {
symbol: {
type: 'string',
description: 'Trading pair symbol (e.g., BTCUSDT)',
default: 'BTCUSDT'
},
type: {
type: 'string',
enum: ['price', 'rsi', 'volume', 'all'],
description: 'Chart type to display',
default: 'price'
},
timeframe: {
type: 'string',
enum: ['1m', '5m', '15m', '1h', '4h', '1d'],
description: 'Chart timeframe',
default: '1h'
},
interactive: {
type: 'boolean',
description: 'Enable interactive chart mode',
default: true
},
dashboard: {
type: 'boolean',
description: 'Show multi-symbol dashboard',
default: false
}
}
};
}
}
//# sourceMappingURL=chart.js.map