import { BaseSkill, type SkillInput, type SkillResult, type SkillMetadata } from './base-skill.js'; import type { BaseChatModel } from '@langchain/core/language_models/chat_models'; import type { FastifyBaseLogger } from 'fastify'; import { HumanMessage, SystemMessage } from '@langchain/core/messages'; /** * Market analysis skill implementation * * See market-analysis.skill.md for full documentation */ export class MarketAnalysisSkill extends BaseSkill { constructor(logger: FastifyBaseLogger, model?: BaseChatModel) { super(logger, model); } getMetadata(): SkillMetadata { return { name: 'market-analysis', description: 'Analyze market conditions for a given ticker and timeframe', version: '1.0.0', author: 'Dexorder AI Platform', tags: ['market-data', 'analysis', 'trading'], }; } getParametersSchema(): Record { return { type: 'object', required: ['ticker', 'period'], properties: { ticker: { type: 'string', description: 'Market identifier (e.g., "BINANCE:BTC/USDT")', }, period: { type: 'string', enum: ['1h', '4h', '1d', '1w'], description: 'Analysis period', }, startTime: { type: 'number', description: 'Start timestamp in microseconds', }, endTime: { type: 'number', description: 'End timestamp in microseconds', }, indicators: { type: 'array', items: { type: 'string' }, description: 'Additional indicators to include', }, }, }; } validateInput(parameters: Record): boolean { if (!parameters.ticker || typeof parameters.ticker !== 'string') { return false; } if (!parameters.period || typeof parameters.period !== 'string') { return false; } return true; } async execute(input: SkillInput): Promise { this.logStart(input); if (!this.validateInput(input.parameters)) { return this.error('Invalid parameters: ticker and period are required'); } try { const ticker = input.parameters.ticker as string; const period = input.parameters.period as string; const indicators = (input.parameters.indicators as string[]) || []; // 1. Fetch OHLC data from Iceberg // TODO: Implement Iceberg query // const ohlcData = await this.fetchOHLCData(ticker, period, startTime, endTime); const ohlcData = this.getMockOHLCData(); // Placeholder // 2. Calculate technical indicators const analysis = this.calculateAnalysis(ohlcData, indicators); // 3. Generate natural language analysis using LLM let narrativeAnalysis = ''; if (this.model) { narrativeAnalysis = await this.generateNarrativeAnalysis( ticker, period, analysis ); } const result = this.success({ ticker, period, timeRange: { start: ohlcData.startTime, end: ohlcData.endTime, }, trend: analysis.trend, priceChange: analysis.priceChange, volumeProfile: analysis.volumeProfile, supportLevels: analysis.supportLevels, resistanceLevels: analysis.resistanceLevels, indicators: analysis.indicators, analysis: narrativeAnalysis, }); this.logEnd(result); return result; } catch (error) { const result = this.error(error as Error); this.logEnd(result); return result; } } /** * Calculate technical analysis from OHLC data */ private calculateAnalysis( ohlcData: any, _requestedIndicators: string[] ): any { // TODO: Implement proper technical analysis // This is a simplified placeholder const priceChange = ((ohlcData.close - ohlcData.open) / ohlcData.open) * 100; const trend = priceChange > 1 ? 'bullish' : priceChange < -1 ? 'bearish' : 'neutral'; return { trend, priceChange, volumeProfile: { average: ohlcData.avgVolume, recent: ohlcData.currentVolume, trend: ohlcData.currentVolume > ohlcData.avgVolume ? 'increasing' : 'decreasing', }, supportLevels: [ohlcData.low * 0.98, ohlcData.low * 0.95], resistanceLevels: [ohlcData.high * 1.02, ohlcData.high * 1.05], indicators: {}, }; } /** * Generate natural language analysis using LLM */ private async generateNarrativeAnalysis( ticker: string, period: string, analysis: any ): Promise { if (!this.model) { return 'LLM not available for narrative analysis'; } const systemPrompt = `You are a professional market analyst. Provide concise, actionable market analysis based on technical data. Focus on key insights and avoid jargon.`; const userPrompt = `Analyze the following market data for ${ticker} (${period}): Trend: ${analysis.trend} Price Change: ${analysis.priceChange.toFixed(2)}% Volume: ${analysis.volumeProfile.trend} Support Levels: ${analysis.supportLevels.join(', ')} Resistance Levels: ${analysis.resistanceLevels.join(', ')} Provide a 2-3 sentence analysis suitable for a trading decision.`; const response = await this.model.invoke([ new SystemMessage(systemPrompt), new HumanMessage(userPrompt), ]); return response.content as string; } /** * Mock OHLC data (placeholder until Iceberg integration) */ private getMockOHLCData(): any { return { startTime: Date.now() - 7 * 24 * 60 * 60 * 1000, endTime: Date.now(), open: 50000, high: 52000, low: 49000, close: 51500, avgVolume: 1000000, currentVolume: 1200000, }; } }