@sherwoodagent/cli 0.25.3 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/addresses-CQLJSZGN.js +35 -0
- package/dist/agent-QIQABFLV.js +7087 -0
- package/dist/agent-QIQABFLV.js.map +1 -0
- package/dist/{chat-DRKUZCOY.js → chat-N6LSZUSC.js} +45 -12
- package/dist/chat-N6LSZUSC.js.map +1 -0
- package/dist/{chunk-KEUEO4UE.js → chunk-2H6IGGKN.js} +1 -1
- package/dist/chunk-2H6IGGKN.js.map +1 -0
- package/dist/{chunk-H55III3L.js → chunk-3EMDYEAD.js} +7 -5
- package/dist/{chunk-H55III3L.js.map → chunk-3EMDYEAD.js.map} +1 -1
- package/dist/{chunk-6DWQIKGN.js → chunk-I3UVF2GD.js} +7 -5
- package/dist/{chunk-6DWQIKGN.js.map → chunk-I3UVF2GD.js.map} +1 -1
- package/dist/{chunk-4WG64CRK.js → chunk-IIBOFECO.js} +7 -5
- package/dist/{chunk-4WG64CRK.js.map → chunk-IIBOFECO.js.map} +1 -1
- package/dist/{chunk-ICUQY7TY.js → chunk-PQ5ZX6ZT.js} +39 -343
- package/dist/chunk-PQ5ZX6ZT.js.map +1 -0
- package/dist/{chunk-66VFSLPS.js → chunk-QGEIK4H5.js} +2 -2
- package/dist/chunk-T5BRUFWV.js +142 -0
- package/dist/chunk-T5BRUFWV.js.map +1 -0
- package/dist/chunk-WQOTLKVP.js +456 -0
- package/dist/chunk-WQOTLKVP.js.map +1 -0
- package/dist/{chunk-SBVHGUQJ.js → chunk-WRG7GAIA.js} +2 -2
- package/dist/{chunk-Y7LUFGIS.js → chunk-YRYPGJ66.js} +9 -7
- package/dist/{chunk-Y7LUFGIS.js.map → chunk-YRYPGJ66.js.map} +1 -1
- package/dist/{chunk-GWIW6DDG.js → chunk-ZPYN5ZAI.js} +53 -1
- package/dist/chunk-ZPYN5ZAI.js.map +1 -0
- package/dist/{client-CWQFYZ5Z.js → client-HBMSTSKK.js} +3 -3
- package/dist/{eas-652I6ULB.js → eas-D3KSAGWT.js} +6 -5
- package/dist/{governor-CY3GXU44.js → governor-3MYMDBRF.js} +6 -5
- package/dist/index.js +267 -220
- package/dist/index.js.map +1 -1
- package/dist/{ipfs-22YLNQ2C.js → ipfs-IGXLLJCF.js} +2 -2
- package/dist/{network-QEMP3DSP.js → network-X6GM7ROG.js} +6 -2
- package/dist/{price-FOCSYKGJ.js → price-DXNFNTV6.js} +8 -6
- package/dist/{price-FOCSYKGJ.js.map → price-DXNFNTV6.js.map} +1 -1
- package/dist/{research-LJKYDBCL.js → research-H3I4LALI.js} +8 -8
- package/dist/{research-ZX7T2ZIJ.js → research-NCESMYXK.js} +4 -4
- package/dist/research-NCESMYXK.js.map +1 -0
- package/dist/{session-7HKFQ7JZ.js → session-5JUUZYIL.js} +12 -10
- package/dist/{session-7HKFQ7JZ.js.map → session-5JUUZYIL.js.map} +1 -1
- package/dist/{trade-4SOHHD5R.js → trade-XDE6YCNY.js} +16 -14
- package/dist/{trade-4SOHHD5R.js.map → trade-XDE6YCNY.js.map} +1 -1
- package/dist/{xmtp-K555NJPU.js → xmtp-XTJ7HDVG.js} +6 -5
- package/dist/{xmtp-K555NJPU.js.map → xmtp-XTJ7HDVG.js.map} +1 -1
- package/package.json +1 -1
- package/dist/chat-DRKUZCOY.js.map +0 -1
- package/dist/chunk-GWIW6DDG.js.map +0 -1
- package/dist/chunk-ICUQY7TY.js.map +0 -1
- package/dist/chunk-KEUEO4UE.js.map +0 -1
- /package/dist/{client-CWQFYZ5Z.js.map → addresses-CQLJSZGN.js.map} +0 -0
- /package/dist/{chunk-66VFSLPS.js.map → chunk-QGEIK4H5.js.map} +0 -0
- /package/dist/{chunk-SBVHGUQJ.js.map → chunk-WRG7GAIA.js.map} +0 -0
- /package/dist/{eas-652I6ULB.js.map → client-HBMSTSKK.js.map} +0 -0
- /package/dist/{governor-CY3GXU44.js.map → eas-D3KSAGWT.js.map} +0 -0
- /package/dist/{ipfs-22YLNQ2C.js.map → governor-3MYMDBRF.js.map} +0 -0
- /package/dist/{network-QEMP3DSP.js.map → ipfs-IGXLLJCF.js.map} +0 -0
- /package/dist/{research-ZX7T2ZIJ.js.map → network-X6GM7ROG.js.map} +0 -0
- /package/dist/{research-LJKYDBCL.js.map → research-H3I4LALI.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/agent.ts","../src/agent/index.ts","../src/providers/data/defillama.ts","../src/providers/data/coingecko.ts","../src/providers/data/feargreed.ts","../src/providers/data/sentiment.ts","../src/agent/technical.ts","../src/agent/utils.ts","../src/agent/scoring.ts","../src/agent/strategies/smart-money.ts","../src/agent/strategies/token-unlock.ts","../src/agent/strategies/sentiment-contrarian.ts","../src/agent/strategies/breakout-onchain.ts","../src/agent/strategies/tvl-momentum.ts","../src/agent/strategies/funding-rate.ts","../src/providers/data/dexscreener.ts","../src/agent/strategies/dex-flow.ts","../src/agent/strategies/mean-reversion.ts","../src/agent/strategies/twitter-sentiment.ts","../src/agent/strategies/hyperliquid-flow.ts","../src/agent/strategies/multi-timeframe.ts","../src/agent/strategies/index.ts","../src/providers/data/funding-rate.ts","../src/providers/data/token-unlocks.ts","../src/providers/data/twitter.ts","../src/providers/data/hyperliquid.ts","../src/agent/regime.ts","../src/agent/correlation.ts","../src/agent/alerts.ts","../src/agent/token-selector.ts","../src/agent/loop.ts","../src/agent/executor.ts","../src/agent/portfolio.ts","../src/agent/risk.ts","../src/agent/reporter.ts","../src/agent/backtest.ts","../src/agent/alert-formatter.ts","../src/agent/execution-pipeline.ts"],"sourcesContent":["/**\n * CLI commands for the autonomous trading agent.\n * sherwood agent <analyze|signals|start|status|history|config|backtest>\n */\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport ora from \"ora\";\nimport { TradingAgent } from \"../agent/index.js\";\nimport type { AgentConfig, TokenAnalysis, Alert } from \"../agent/index.js\";\nimport { getLatestSignals } from \"../agent/technical.js\";\nimport type { Candle } from \"../agent/technical.js\";\nimport { CoinGeckoProvider } from \"../providers/data/coingecko.js\";\nimport { DynamicTokenSelector } from \"../agent/token-selector.js\";\nimport { SentimentProvider } from \"../providers/data/sentiment.js\";\nimport {\n scoreTechnical,\n scoreSentiment,\n scoreOnChain,\n scoreFundamental,\n scoreEvent,\n} from \"../agent/scoring.js\";\nimport { AgentLoop } from \"../agent/loop.js\";\nimport type { LoopConfig } from \"../agent/loop.js\";\nimport { PortfolioTracker } from \"../agent/portfolio.js\";\nimport { RiskManager, DEFAULT_RISK_CONFIG } from \"../agent/risk.js\";\nimport type { RiskConfig } from \"../agent/risk.js\";\nimport { Reporter } from \"../agent/reporter.js\";\nimport { Backtester } from \"../agent/backtest.js\";\nimport type { BacktestConfig, WalkForwardConfig } from \"../agent/backtest.js\";\nimport { AlertFormatter } from \"../agent/alert-formatter.js\";\nimport { ExecutionPipeline } from \"../agent/execution-pipeline.js\";\n\nconst DEFAULT_TOKENS = [\"ethereum\", \"bitcoin\", \"solana\", \"aave\", \"uniswap\"];\n\nfunction makeConfig(overrides?: Partial<AgentConfig>): AgentConfig {\n return {\n tokens: DEFAULT_TOKENS,\n cycle: \"4h\",\n dryRun: true,\n maxPositionPct: 5,\n maxRiskPct: 20,\n ...overrides,\n };\n}\n\nexport function registerAgentCommands(program: Command): void {\n const agent = program.command(\"agent\").description(\"Autonomous trading agent\");\n\n // ── analyze ──\n agent\n .command(\"analyze\")\n .description(\"Analyze token(s) using multi-signal scoring\")\n .argument(\"[tokens...]\", \"Token IDs to analyze (e.g., ethereum bitcoin)\")\n .option(\"--all\", \"Analyze full watchlist\")\n .option(\"--auto\", \"Use dynamic token selection from Hyperliquid market data\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--x402\", \"Include paid x402 data (Nansen smart-money, Messari fundamentals)\")\n .option(\"--telegram\", \"Output formatted summary for Telegram\")\n .option(\"--proposals\", \"Generate trade proposals for high-confidence opportunities\")\n .action(async (tokens: string[], options: { all?: boolean; auto?: boolean; json?: boolean; x402?: boolean; telegram?: boolean; proposals?: boolean }) => {\n let tokenList: string[];\n let selectionSummary: string | undefined;\n\n if (options.auto) {\n const spinner = ora(\"Fetching dynamic token selection from Hyperliquid...\").start();\n try {\n const selector = new DynamicTokenSelector();\n const selection = await selector.selectTokens();\n tokenList = selection.tokens;\n selectionSummary = selector.formatSelectionSummary(selection);\n spinner.stop();\n\n // Show selection summary\n console.log();\n console.log(selectionSummary);\n console.log();\n } catch (error) {\n spinner.fail(`Dynamic selection failed: ${(error as Error).message}`);\n console.log(\"Falling back to default tokens...\");\n tokenList = DEFAULT_TOKENS;\n }\n } else {\n tokenList = options.all ? DEFAULT_TOKENS : tokens.length > 0 ? tokens : DEFAULT_TOKENS;\n }\n\n const config = makeConfig({ tokens: tokenList, useX402: options.x402 ?? false });\n const tradingAgent = new TradingAgent(config);\n const spinner = ora(\"Analyzing tokens...\").start();\n\n try {\n spinner.text = \"Analyzing tokens and checking for alerts...\";\n const { analyses: results, alerts } = await tradingAgent.analyzeAllWithAlerts();\n spinner.stop();\n\n if (options.telegram) {\n // Output Telegram-formatted summary\n const regime = results[0]?.regime?.regime;\n const summary = AlertFormatter.formatScanSummary(results, alerts, regime);\n console.log(summary);\n return;\n }\n\n if (options.proposals) {\n // Output trade proposals\n const proposals = ExecutionPipeline.generateProposals(results);\n const formatted = ExecutionPipeline.formatProposals(proposals);\n console.log(formatted);\n return;\n }\n\n if (options.json) {\n console.log(JSON.stringify(results.map((r) => ({ token: r.token, decision: r.decision })), null, 2));\n } else {\n console.log(tradingAgent.formatAnalysis(results));\n\n // Show alerts if any\n if (alerts.length > 0) {\n console.log(chalk.bold(\"\\n\" + tradingAgent.formatAlerts(alerts)));\n console.log();\n }\n\n // Detailed signal breakdown\n for (const r of results) {\n console.log(chalk.bold(`\\n ${r.token.toUpperCase()} — Signal Breakdown`));\n console.log(chalk.dim(\" \" + \"─\".repeat(50)));\n\n // Show regime info if available\n if (r.regime) {\n const regimeColor = r.regime.regime === \"trending-up\" ? chalk.green :\n r.regime.regime === \"trending-down\" ? chalk.red :\n r.regime.regime === \"ranging\" ? chalk.yellow :\n r.regime.regime === \"high-volatility\" ? chalk.magenta :\n chalk.cyan;\n console.log(\n ` ${\"Market Regime\".padEnd(22)} ${regimeColor(\"▮\".repeat(10))} ${regimeColor(r.regime.regime.replace('-', ' '))} ${chalk.dim(r.regime.details.slice(0, 60))}`\n );\n }\n\n for (const signal of r.decision.signals) {\n const bar = renderBar(signal.value);\n const color =\n signal.value > 0.1\n ? chalk.green\n : signal.value < -0.1\n ? chalk.red\n : chalk.yellow;\n console.log(\n ` ${signal.source.padEnd(22)} ${bar} ${color(\n (signal.value >= 0 ? \"+\" : \"\") + signal.value.toFixed(3),\n )} ${chalk.dim(signal.details.slice(0, 60))}`,\n );\n }\n }\n console.log();\n }\n } catch (err) {\n spinner.fail(`Analysis failed: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n });\n\n // ── signals ──\n agent\n .command(\"signals\")\n .description(\"Show current signal scores for a token\")\n .argument(\"<token>\", \"Token ID\")\n .action(async (token: string) => {\n const spinner = ora(`Fetching signals for ${token}...`).start();\n\n try {\n const cg = new CoinGeckoProvider();\n const sentimentProvider = new SentimentProvider();\n\n // Fetch OHLC\n spinner.text = \"Fetching OHLC data...\";\n const ohlcRaw = await cg.getOHLC(token, 30);\n const candles: Candle[] = ohlcRaw.map((c: number[]) => ({\n timestamp: c[0]!,\n open: c[1]!,\n high: c[2]!,\n low: c[3]!,\n close: c[4] ?? c[3]!,\n volume: 0,\n }));\n\n // Get volume data\n try {\n spinner.text = \"Fetching volume data...\";\n const marketData = await cg.getMarketData(token, 30);\n if (marketData?.total_volumes) {\n for (const candle of candles) {\n const nearest = marketData.total_volumes.reduce(\n (best: number[], v: number[]) =>\n Math.abs(v[0]! - candle.timestamp) < Math.abs(best[0]! - candle.timestamp)\n ? v\n : best,\n marketData.total_volumes[0]!,\n );\n candle.volume = nearest[1] ?? 0;\n }\n }\n } catch {\n // optional\n }\n\n const techSignals = getLatestSignals(candles);\n\n // Fetch sentiment\n spinner.text = \"Fetching sentiment...\";\n let fgValue = 50;\n let zScore = 0;\n try {\n const fgData = await sentimentProvider.getFearAndGreed();\n if (fgData.length > 0) {\n fgValue = fgData[0]!.value;\n zScore = sentimentProvider.computeSentimentZScore(fgData.map((d) => d.value));\n }\n } catch {\n // default values\n }\n\n spinner.stop();\n\n // Display\n console.log();\n console.log(chalk.bold(` ${token.toUpperCase()} — Detailed Signals`));\n console.log(chalk.dim(\" \" + \"═\".repeat(55)));\n\n // Technical\n console.log(chalk.bold.cyan(\"\\n Technical Indicators\"));\n console.log(` RSI(14): ${formatValue(techSignals.rsi, 30, 70, true)}`);\n console.log(` MACD: ${techSignals.macd.value.toFixed(4)}`);\n console.log(` MACD Signal: ${techSignals.macd.signal.toFixed(4)}`);\n console.log(` MACD Hist: ${formatValue(techSignals.macd.histogram, 0, 0, false)}`);\n console.log(` BB Upper: ${techSignals.bb.upper.toFixed(2)}`);\n console.log(` BB Middle: ${techSignals.bb.middle.toFixed(2)}`);\n console.log(` BB Lower: ${techSignals.bb.lower.toFixed(2)}`);\n console.log(` BB Width: ${techSignals.bb.width.toFixed(4)}`);\n console.log(` BB Squeeze: ${techSignals.bb.squeeze ? chalk.yellow(\"YES\") : \"No\"}`);\n console.log(` EMA(8): ${techSignals.ema.ema8.toFixed(2)}`);\n console.log(` EMA(21): ${techSignals.ema.ema21.toFixed(2)}`);\n console.log(` EMA(50): ${isNaN(techSignals.ema.ema50) ? chalk.dim(\"N/A\") : techSignals.ema.ema50.toFixed(2)}`);\n console.log(` EMA(200): ${isNaN(techSignals.ema.ema200) ? chalk.dim(\"N/A\") : techSignals.ema.ema200.toFixed(2)}`);\n console.log(` ATR(14): ${techSignals.atr.toFixed(2)}`);\n console.log(` VWAP: ${techSignals.vwap.toFixed(2)}`);\n console.log(` Vol Ratio: ${techSignals.volume.ratio.toFixed(2)}x avg`);\n\n // Sentiment\n console.log(chalk.bold.cyan(\"\\n Sentiment\"));\n console.log(` Fear & Greed: ${formatFearGreed(fgValue)}`);\n console.log(` Z-Score: ${zScore.toFixed(2)}`);\n\n // Signal scores\n const techScore = scoreTechnical(techSignals);\n const sentScore = scoreSentiment(fgValue, zScore);\n const onchainScore = scoreOnChain({});\n const fundScore = scoreFundamental({});\n const eventScore = scoreEvent({});\n\n console.log(chalk.bold.cyan(\"\\n Signal Scores\"));\n console.log(` Technical: ${renderBar(techScore.value)} ${colorValue(techScore.value)}`);\n console.log(` Sentiment: ${renderBar(sentScore.value)} ${colorValue(sentScore.value)}`);\n console.log(` On-Chain: ${renderBar(onchainScore.value)} ${colorValue(onchainScore.value)}`);\n console.log(` Fundamental: ${renderBar(fundScore.value)} ${colorValue(fundScore.value)}`);\n console.log(` Event: ${renderBar(eventScore.value)} ${colorValue(eventScore.value)}`);\n console.log();\n } catch (err) {\n spinner.fail(`Failed: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n });\n\n // ── start ──\n agent\n .command(\"start\")\n .description(\"Start autonomous trading loop\")\n .option(\"--cycle <interval>\", \"Cycle interval (15m, 1h, 4h)\", \"4h\")\n .option(\"--dry-run\", \"Paper trading mode\", true)\n .option(\"--tokens <tokens>\", \"Comma-separated token list\")\n .option(\"--auto\", \"Use dynamic token selection from Hyperliquid market data\")\n .option(\"--log <path>\", \"Path to write cycle logs\")\n .option(\"--mode <mode>\", \"Execution mode: dry-run (default), hyperliquid-perp\", \"dry-run\")\n .option(\"--strategy-clone <address>\", \"Strategy clone address on HyperEVM (required for hyperliquid-perp)\")\n .option(\"--chain <chain>\", \"Chain for live execution (hyperevm, hyperevm-testnet)\", \"ethereum\")\n .option(\"--asset-index <n>\", \"HyperCore perp asset index (default: 3 = ETH)\")\n .option(\"--x402\", \"Include paid x402 data (Nansen smart-money, Messari fundamentals)\")\n .action(async (options: { cycle?: string; dryRun?: boolean; tokens?: string; auto?: boolean; log?: string; mode?: string; strategyClone?: string; chain?: string; assetIndex?: string; x402?: boolean }) => {\n let tokenList: string[];\n\n if (options.auto) {\n console.log(chalk.dim(\" Using dynamic token selection from Hyperliquid (refreshes every 30 min)\"));\n // For the loop, we'll create a placeholder list that gets replaced dynamically\n // The actual selection happens in the loop itself to allow periodic refresh\n tokenList = ['bitcoin', 'ethereum']; // Minimal list, will be replaced\n } else {\n tokenList = options.tokens ? options.tokens.split(\",\").map((t) => t.trim()) : DEFAULT_TOKENS;\n }\n\n const cycle = (options.cycle ?? \"4h\") as AgentConfig[\"cycle\"];\n\n // Load persisted risk config from disk (written by `agent config --set`)\n let savedRiskConfig: Partial<RiskConfig> = {};\n try {\n const configPath = join(homedir(), '.sherwood', 'agent', 'config.json');\n const data = await readFile(configPath, 'utf-8');\n const parsed = JSON.parse(data) as Record<string, unknown>;\n // Only pick known risk keys with valid numeric values\n for (const [k, v] of Object.entries(parsed)) {\n if (k in DEFAULT_RISK_CONFIG && typeof v === 'number' && Number.isFinite(v)) {\n (savedRiskConfig as Record<string, number>)[k] = v;\n }\n }\n if (Object.keys(savedRiskConfig).length > 0) {\n console.log(chalk.dim(` Loaded ${Object.keys(savedRiskConfig).length} risk config overrides from ~/.sherwood/agent/config.json`));\n }\n } catch {\n // No saved config — use defaults\n }\n\n const isLive = options.mode === 'hyperliquid-perp';\n if (isLive && !options.strategyClone) {\n console.error(chalk.red(' --strategy-clone is required for hyperliquid-perp mode'));\n process.exitCode = 1;\n return;\n }\n const proposerKey = process.env.SHERWOOD_PROPOSER_KEY as `0x${string}` | undefined;\n if (isLive && !proposerKey) {\n console.error(chalk.red(' SHERWOOD_PROPOSER_KEY env var is required for live execution'));\n process.exitCode = 1;\n return;\n }\n\n const loopConfig: LoopConfig = {\n agent: makeConfig({ tokens: tokenList, cycle, dryRun: !isLive, useX402: options.x402 ?? false }),\n execution: {\n dryRun: !isLive,\n mode: (options.mode ?? 'dry-run') as 'dry-run' | 'hyperliquid-perp',\n mevProtection: false,\n chain: options.chain ?? 'ethereum',\n strategyClone: options.strategyClone as `0x${string}` | undefined,\n proposerPrivateKey: proposerKey,\n assetIndex: options.assetIndex ? (() => {\n const idx = parseInt(options.assetIndex!, 10);\n if (isNaN(idx) || idx < 0) {\n console.error(chalk.red(` Invalid --asset-index: ${options.assetIndex}`));\n process.exit(1);\n }\n return idx;\n })() : undefined,\n },\n riskConfig: savedRiskConfig,\n logPath: options.log,\n autoDynamicSelection: options.auto ?? false,\n };\n\n const loop = new AgentLoop(loopConfig);\n\n // Graceful shutdown\n const shutdown = () => {\n console.log(chalk.yellow(\"\\n Shutting down gracefully...\"));\n loop.stop();\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n await loop.start();\n });\n\n // ── status ──\n agent\n .command(\"status\")\n .description(\"Show current portfolio, open positions, daily PnL\")\n .action(async () => {\n const portfolio = new PortfolioTracker();\n const reporter = new Reporter();\n\n try {\n const state = await portfolio.load();\n\n // Try to update prices for open positions\n if (state.positions.length > 0) {\n try {\n const cg = new CoinGeckoProvider();\n const tokenIds = state.positions.map(p => p.tokenId);\n const priceData = await cg.getPrice(tokenIds, ['usd']);\n const prices: Record<string, number> = {};\n for (const id of tokenIds) {\n const price = priceData?.[id]?.usd;\n if (typeof price === 'number') prices[id] = price;\n }\n if (Object.keys(prices).length > 0) {\n const updated = await portfolio.updatePrices(prices);\n console.log(reporter.formatPortfolioReport(updated));\n return;\n }\n } catch {\n // Fall through to show cached state\n }\n }\n\n console.log(reporter.formatPortfolioReport(state));\n } catch (err) {\n console.error(chalk.red(`Failed to load portfolio: ${(err as Error).message}`));\n process.exitCode = 1;\n }\n });\n\n // ── history ──\n agent\n .command(\"history\")\n .description(\"Show trade history and performance metrics\")\n .option(\"--days <n>\", \"Number of days to look back\", \"30\")\n .action(async (options: { days?: string }) => {\n const portfolio = new PortfolioTracker();\n const reporter = new Reporter();\n const days = Math.max(1, parseInt(options.days ?? \"30\", 10) || 30);\n\n try {\n const trades = await portfolio.getHistory(days);\n const metrics = await portfolio.getMetrics(days);\n\n console.log('');\n console.log(chalk.bold(` Trade History (last ${days} days)`));\n console.log(chalk.dim(' ' + '═'.repeat(70)));\n\n if (trades.length === 0) {\n console.log(chalk.dim(' No trades recorded in this period.'));\n console.log('');\n return;\n }\n\n // Table header\n console.log(chalk.dim(` ${'Symbol'.padEnd(10)} ${'Side'.padEnd(6)} ${'Entry'.padEnd(12)} ${'Exit'.padEnd(12)} ${'PnL $'.padEnd(12)} ${'PnL %'.padEnd(10)} Exit Reason`));\n console.log(chalk.dim(' ' + '─'.repeat(70)));\n\n for (const t of trades) {\n const pnlColor = t.pnlUsd >= 0 ? chalk.green : chalk.red;\n console.log(\n ` ${t.symbol.padEnd(10)} ${t.side.padEnd(6)} $${t.entryPrice.toFixed(2).padEnd(11)} $${t.exitPrice.toFixed(2).padEnd(11)} ${pnlColor(('$' + t.pnlUsd.toFixed(2)).padEnd(12))} ${pnlColor(((t.pnlPercent * 100).toFixed(1) + '%').padEnd(10))} ${t.exitReason.slice(0, 20)}`,\n );\n }\n\n // Performance metrics\n console.log(reporter.formatMetrics(metrics));\n } catch (err) {\n console.error(chalk.red(`Failed to load history: ${(err as Error).message}`));\n process.exitCode = 1;\n }\n });\n\n // ── config ──\n agent\n .command(\"config\")\n .description(\"Show or set risk parameters\")\n .option(\"--set <key=value>\", \"Set a config value (e.g. --set maxSinglePosition=0.15)\")\n .action(async (options: { set?: string }) => {\n const riskConfig = { ...DEFAULT_RISK_CONFIG };\n\n // Bounds for risk config values to prevent disabling guardrails\n const RISK_BOUNDS: Record<string, [number, number]> = {\n maxPortfolioRisk: [0.01, 0.50],\n maxSinglePosition: [0.01, 0.25],\n maxCorrelatedExposure: [0.05, 0.50],\n maxConcurrentTrades: [1, 20],\n hardStopPercent: [0.01, 0.30],\n trailingStopAtr: [0.5, 5.0],\n dailyLossLimit: [0.01, 0.30],\n weeklyLossLimit: [0.01, 0.50],\n monthlyLossLimit: [0.01, 0.60],\n riskPerTrade: [0.005, 0.05],\n };\n\n if (options.set) {\n const [key, value] = options.set.split('=');\n if (key && value && key in riskConfig) {\n if (key === 'maxSlippage') {\n console.log(chalk.red(` maxSlippage must be set per tier (not supported via --set)`));\n console.log('');\n return;\n }\n const numVal = parseFloat(value);\n if (!isNaN(numVal)) {\n // Integer-type fields must not be fractional\n const INTEGER_KEYS = new Set(['maxConcurrentTrades']);\n if (INTEGER_KEYS.has(key) && !Number.isInteger(numVal)) {\n console.log(chalk.red(` ${key} must be a whole number (got ${numVal})`));\n console.log('');\n return;\n }\n const bounds = RISK_BOUNDS[key];\n if (bounds && (numVal < bounds[0] || numVal > bounds[1])) {\n console.log(chalk.red(` Value ${numVal} out of bounds for ${key}: [${bounds[0]}, ${bounds[1]}]`));\n console.log('');\n return;\n }\n (riskConfig as Record<string, unknown>)[key] = numVal;\n console.log(chalk.green(` Set ${key} = ${numVal}`));\n\n // Persist to disk\n const configDir = join(homedir(), '.sherwood', 'agent');\n const configPath = join(configDir, 'config.json');\n let existingConfig: Record<string, unknown> = {};\n try {\n const data = await readFile(configPath, 'utf-8');\n existingConfig = JSON.parse(data);\n } catch {\n // No existing config file\n }\n existingConfig[key] = numVal;\n await mkdir(configDir, { recursive: true });\n await writeFile(configPath, JSON.stringify(existingConfig, null, 2), 'utf-8');\n console.log(chalk.dim(` Saved to ${configPath}`));\n } else {\n console.log(chalk.red(` Invalid value: ${value}`));\n }\n } else {\n console.log(chalk.red(` Unknown config key: ${key}`));\n console.log(chalk.dim(` Available keys: ${Object.keys(riskConfig).join(', ')}`));\n }\n console.log('');\n return;\n }\n\n // Display current config\n console.log('');\n console.log(chalk.bold(' Risk Configuration'));\n console.log(chalk.dim(' ' + '═'.repeat(50)));\n console.log(` Max Portfolio Risk: ${(riskConfig.maxPortfolioRisk * 100).toFixed(0)}%`);\n console.log(` Max Single Position: ${(riskConfig.maxSinglePosition * 100).toFixed(0)}%`);\n console.log(` Max Correlated Exposure: ${(riskConfig.maxCorrelatedExposure * 100).toFixed(0)}%`);\n console.log(` Max Concurrent Trades: ${riskConfig.maxConcurrentTrades}`);\n console.log(` Hard Stop: ${(riskConfig.hardStopPercent * 100).toFixed(0)}%`);\n console.log(` Trailing Stop ATR: ${riskConfig.trailingStopAtr}x`);\n console.log(chalk.dim(' ' + '─'.repeat(50)));\n console.log(` Daily Loss Limit: ${(riskConfig.dailyLossLimit * 100).toFixed(0)}%`);\n console.log(` Weekly Loss Limit: ${(riskConfig.weeklyLossLimit * 100).toFixed(0)}%`);\n console.log(` Monthly Loss Limit: ${(riskConfig.monthlyLossLimit * 100).toFixed(0)}%`);\n console.log(chalk.dim(' ' + '─'.repeat(50)));\n console.log(` Max Slippage (large): ${(riskConfig.maxSlippage.large! * 100).toFixed(1)}%`);\n console.log(` Max Slippage (mid): ${(riskConfig.maxSlippage.mid! * 100).toFixed(1)}%`);\n console.log(` Max Slippage (small): ${(riskConfig.maxSlippage.small! * 100).toFixed(1)}%`);\n console.log('');\n });\n\n // ── backtest ──\n agent\n .command(\"backtest\")\n .description(\"Backtest strategies on historical data\")\n .argument(\"<token>\", \"Token ID (e.g., bitcoin, ethereum)\")\n .option(\"--from <date>\", \"Start date (YYYY-MM-DD)\", \"2024-01-01\")\n .option(\"--to <date>\", \"End date (YYYY-MM-DD)\", \"2024-12-31\")\n .option(\"--strategies <list>\", \"Comma-separated strategy names\", \"\")\n .option(\"--capital <amount>\", \"Initial capital in USD\", \"10000\")\n .option(\"--cycle <interval>\", \"Candle interval (1h, 4h, 1d)\", \"1d\")\n .option(\"--walk-forward\", \"Enable walk-forward optimization\")\n .option(\"--train <days>\", \"Training window in days for walk-forward\", \"90\")\n .option(\"--test <days>\", \"Test window in days for walk-forward\", \"30\")\n .option(\"--verbose\", \"Show detailed decision logs for each candle\")\n .action(async (token: string, options: { from: string; to: string; strategies: string; capital: string; cycle: string; walkForward?: boolean; train: string; test: string; verbose?: boolean }) => {\n const capital = parseFloat(options.capital);\n const strategies = options.strategies ? options.strategies.split(\",\").map((s) => s.trim()) : [];\n\n if (options.walkForward) {\n // Walk-forward optimization mode\n const trainWindow = parseInt(options.train, 10);\n const testWindow = parseInt(options.test, 10);\n const stepSize = Math.min(testWindow, 30); // Default step size to test window or 30 days, whichever is smaller\n const totalDays = trainWindow + (testWindow * 3); // Ensure we have enough data for multiple folds\n\n const walkConfig: WalkForwardConfig = {\n tokenId: token,\n totalDays,\n trainWindow,\n testWindow,\n stepSize,\n capital,\n strategies,\n };\n\n const spinner = ora(`Walk-forward testing ${token} (${trainWindow}d train, ${testWindow}d test)...`).start();\n\n try {\n const backtester = new Backtester({\n tokenId: token,\n startDate: options.from,\n endDate: options.to,\n initialCapital: capital,\n strategies,\n cycle: (options.cycle as BacktestConfig[\"cycle\"]) || \"1d\",\n verbose: options.verbose,\n });\n const result = await backtester.walkForwardTest(walkConfig);\n spinner.stop();\n console.log(backtester.formatWalkForwardResults(result, walkConfig));\n } catch (err) {\n spinner.fail(`Walk-forward test failed: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n } else {\n // Regular backtest mode\n const config: BacktestConfig = {\n tokenId: token,\n startDate: options.from,\n endDate: options.to,\n initialCapital: capital,\n strategies,\n cycle: (options.cycle as BacktestConfig[\"cycle\"]) || \"1d\",\n verbose: options.verbose,\n };\n\n const spinner = ora(`Backtesting ${token} from ${config.startDate} to ${config.endDate}...`).start();\n\n try {\n const backtester = new Backtester(config);\n const result = await backtester.run();\n spinner.stop();\n console.log(backtester.formatResults(result));\n } catch (err) {\n spinner.fail(`Backtest failed: ${(err as Error).message}`);\n process.exitCode = 1;\n }\n }\n });\n\n // ── alerts ──\n const alerts = agent.command(\"alerts\").description(\"Manage trading alerts\");\n\n alerts\n .command(\"list\")\n .alias(\"\")\n .description(\"Show recent alerts\")\n .option(\"--hours <n>\", \"Look back N hours\", \"24\")\n .action(async (options: { hours?: string }) => {\n try {\n const tradingAgent = new TradingAgent(makeConfig());\n const hours = parseInt(options.hours ?? \"24\", 10) || 24;\n const maxAge = hours * 60 * 60 * 1000;\n\n const recentAlerts = await tradingAgent.getRecentAlerts(maxAge);\n\n if (recentAlerts.length === 0) {\n console.log(chalk.dim(\" No alerts in the last \" + hours + \" hours.\"));\n return;\n }\n\n console.log('');\n console.log(chalk.bold(` Recent Alerts (last ${hours} hours)`));\n console.log(chalk.dim(' ' + '═'.repeat(60)));\n\n for (const alert of recentAlerts.slice(0, 20)) {\n const icon = alert.priority === \"critical\" ? \"🔴\" :\n alert.priority === \"high\" ? \"🟡\" :\n alert.priority === \"medium\" ? \"🔵\" : \"⚫\";\n\n const timeStr = new Date(alert.timestamp).toLocaleString();\n const priorityColor = alert.priority === \"critical\" ? chalk.red :\n alert.priority === \"high\" ? chalk.yellow :\n alert.priority === \"medium\" ? chalk.blue : chalk.gray;\n\n console.log(` ${icon} ${priorityColor(alert.priority.toUpperCase())} — ${alert.title}`);\n console.log(chalk.dim(` ${alert.details.slice(0, 80)}${alert.details.length > 80 ? '...' : ''}`));\n console.log(chalk.dim(` Token: ${alert.tokenId}, ${timeStr}`));\n console.log('');\n }\n } catch (err) {\n console.error(chalk.red(`Failed to load alerts: ${(err as Error).message}`));\n process.exitCode = 1;\n }\n });\n\n alerts\n .command(\"clear\")\n .description(\"Clear all alerts\")\n .action(async () => {\n try {\n const tradingAgent = new TradingAgent(makeConfig());\n await tradingAgent.clearAlerts();\n console.log(chalk.green(\" All alerts cleared.\"));\n } catch (err) {\n console.error(chalk.red(`Failed to clear alerts: ${(err as Error).message}`));\n process.exitCode = 1;\n }\n });\n}\n\n// ── Display Helpers ──\n\nfunction renderBar(value: number): string {\n const width = 20;\n const mid = Math.floor(width / 2);\n const bar = new Array(width).fill(\"░\");\n\n const magnitude = Math.min(Math.abs(value), 1.0);\n const filled = Math.round(magnitude * mid);\n\n if (value > 0) {\n for (let i = mid; i < mid + filled; i++) bar[i] = \"█\";\n return chalk.dim(bar.slice(0, mid).join(\"\")) + chalk.green(bar.slice(mid).join(\"\"));\n } else if (value < 0) {\n for (let i = mid - filled; i < mid; i++) bar[i] = \"█\";\n return chalk.red(bar.slice(0, mid).join(\"\")) + chalk.dim(bar.slice(mid).join(\"\"));\n }\n return chalk.dim(bar.join(\"\"));\n}\n\nfunction colorValue(value: number): string {\n const str = (value >= 0 ? \"+\" : \"\") + value.toFixed(3);\n if (value > 0.1) return chalk.green(str);\n if (value < -0.1) return chalk.red(str);\n return chalk.yellow(str);\n}\n\nfunction formatValue(value: number, low: number, high: number, invertColors: boolean): string {\n const str = isNaN(value) ? \"N/A\" : value.toFixed(2);\n if (isNaN(value)) return chalk.dim(str);\n if (invertColors) {\n if (value < low) return chalk.green(str);\n if (value > high) return chalk.red(str);\n } else {\n if (value > high) return chalk.green(str);\n if (value < low) return chalk.red(str);\n }\n return chalk.yellow(str);\n}\n\nfunction formatFearGreed(value: number): string {\n const str = `${value}`;\n if (value < 25) return chalk.green(str + \" (Extreme Fear)\");\n if (value < 40) return chalk.green(str + \" (Fear)\");\n if (value < 60) return chalk.yellow(str + \" (Neutral)\");\n if (value < 75) return chalk.red(str + \" (Greed)\");\n return chalk.red(str + \" (Extreme Greed)\");\n}\n","/**\n * Main trading agent orchestrator.\n * Gathers data from multiple providers, scores signals, produces trade decisions.\n */\n\nimport chalk from \"chalk\";\nimport { DefiLlamaProvider } from \"../providers/data/defillama.js\";\nimport { CoinGeckoProvider } from \"../providers/data/coingecko.js\";\nimport { SentimentProvider } from \"../providers/data/sentiment.js\";\nimport { getResearchProvider } from \"../providers/research/index.js\";\nimport type { Candle, TechnicalSignals } from \"./technical.js\";\nimport { getLatestSignals } from \"./technical.js\";\nimport {\n scoreTechnical,\n scoreSentiment,\n scoreOnChain,\n scoreFundamental,\n scoreEvent,\n computeTradeDecision,\n DEFAULT_WEIGHTS,\n} from \"./scoring.js\";\nimport type { Signal, ScoringWeights, TradeDecision } from \"./scoring.js\";\nimport { runStrategies } from \"./strategies/index.js\";\nimport { DexScreenerProvider } from \"../providers/data/dexscreener.js\";\nimport { FundingRateProvider } from \"../providers/data/funding-rate.js\";\nimport { TokenUnlocksProvider } from \"../providers/data/token-unlocks.js\";\nimport { TwitterSentimentProvider } from \"../providers/data/twitter.js\";\nimport { HyperliquidProvider } from \"../providers/data/hyperliquid.js\";\nimport type { StrategyContext, StrategyConfig } from \"./strategies/index.js\";\nimport { MarketRegimeDetector } from \"./regime.js\";\nimport type { RegimeAnalysis } from \"./regime.js\";\nimport { CorrelationGuard } from \"./correlation.js\";\nimport type { CorrelationCheck } from \"./correlation.js\";\nimport { AlertSystem } from \"./alerts.js\";\nimport type { Alert } from \"./alerts.js\";\n\nexport type { Signal, ScoringWeights, TradeDecision, Alert, TechnicalSignals };\n\nexport interface AgentConfig {\n tokens: string[];\n cycle: \"15m\" | \"1h\" | \"4h\";\n dryRun: boolean;\n maxPositionPct: number;\n maxRiskPct: number;\n weights?: ScoringWeights;\n /** When true, includes paid x402 data (Nansen smart-money, Messari fundamentals) in analysis. */\n useX402?: boolean;\n /** Per-strategy configuration overrides. */\n strategyConfigs?: Record<string, StrategyConfig>;\n}\n\nexport interface TokenAnalysis {\n token: string;\n decision: TradeDecision;\n data: {\n technicalSignals?: TechnicalSignals;\n fearAndGreed?: number;\n tvl?: number;\n };\n regime?: RegimeAnalysis;\n correlation?: CorrelationCheck;\n}\n\nexport class TradingAgent {\n private config: AgentConfig;\n private defillama: DefiLlamaProvider;\n private coingecko: CoinGeckoProvider;\n private sentiment: SentimentProvider;\n private dexscreener: DexScreenerProvider;\n private fundingRate: FundingRateProvider;\n private tokenUnlocks: TokenUnlocksProvider;\n private twitter: TwitterSentimentProvider;\n private hyperliquid: HyperliquidProvider;\n private regimeDetector: MarketRegimeDetector;\n private correlationGuard: CorrelationGuard;\n private alertSystem: AlertSystem;\n\n constructor(config: AgentConfig) {\n this.config = config;\n this.defillama = new DefiLlamaProvider();\n this.coingecko = new CoinGeckoProvider();\n this.sentiment = new SentimentProvider();\n this.dexscreener = new DexScreenerProvider();\n this.fundingRate = new FundingRateProvider();\n this.tokenUnlocks = new TokenUnlocksProvider();\n this.twitter = new TwitterSentimentProvider();\n this.hyperliquid = new HyperliquidProvider();\n this.regimeDetector = new MarketRegimeDetector();\n this.correlationGuard = new CorrelationGuard();\n this.alertSystem = new AlertSystem();\n }\n\n /** Analyze a single token — gather all data and score. */\n async analyzeToken(tokenId: string): Promise<TokenAnalysis> {\n const signals: Signal[] = [];\n let technicalSignals: TechnicalSignals | undefined;\n let fearAndGreedValue: number | undefined;\n let tvl: number | undefined;\n let candles: Candle[] | undefined;\n let sentimentZScore: number | undefined;\n\n // Phase 1: Parallel basic data fetching (OHLC, Fear & Greed, TVL, Hyperliquid)\n const [ohlcResult, fearGreedResult, tvlResult, hyperliquidResult] = await Promise.allSettled([\n // 1. Fetch OHLC data from CoinGecko\n this.coingecko.getOHLC(tokenId, 30).then(async (ohlcRaw) => {\n if (!ohlcRaw || ohlcRaw.length <= 10) return null;\n\n const rawCandles = ohlcRaw.map((c: number[]) => ({\n timestamp: c[0]!,\n open: c[1]!,\n high: c[2]!,\n low: c[3]!,\n close: c[4] ?? c[3]!, // CoinGecko OHLC: [ts, o, h, l, c]\n volume: 0, // OHLC endpoint doesn't include volume\n }));\n\n // Fetch volume data in parallel\n try {\n const marketData = await this.coingecko.getMarketData(tokenId, 30);\n if (marketData?.total_volumes) {\n // Map volumes to nearest candle by timestamp\n for (const candle of rawCandles) {\n const nearest = marketData.total_volumes.reduce(\n (best: number[], v: number[]) =>\n Math.abs(v[0]! - candle.timestamp) < Math.abs(best[0]! - candle.timestamp)\n ? v\n : best,\n marketData.total_volumes[0]!,\n );\n candle.volume = nearest[1] ?? 0;\n }\n }\n } catch {\n // Volume data optional\n }\n\n return rawCandles;\n }),\n\n // 2. Fetch Fear & Greed\n this.sentiment.getFearAndGreed(),\n\n // 3. Fetch TVL data (if DeFi protocol)\n this.defillama.getProtocolTvl(tokenId).then(async (tvlValue) => {\n if (typeof tvlValue === \"number\" && tvlValue > 0) {\n const priceData = await this.coingecko.getPrice([tokenId], [\"usd\"]);\n const mcap = priceData?.[tokenId]?.usd_market_cap;\n return { tvl: tvlValue, mcapToTvl: mcap && tvlValue > 0 ? mcap / tvlValue : undefined };\n }\n return null;\n }),\n\n // 4. Fetch Hyperliquid data (free, exchange-native) — move to Phase 1 for price substitution\n this.hyperliquid.getHyperliquidData(tokenId)\n ]);\n\n // Process OHLC results\n if (ohlcResult.status === 'fulfilled' && ohlcResult.value) {\n candles = ohlcResult.value;\n technicalSignals = getLatestSignals(candles);\n signals.push(scoreTechnical(technicalSignals));\n } else if (ohlcResult.status === 'rejected') {\n console.error(chalk.dim(` Technical analysis failed for ${tokenId}: ${ohlcResult.reason}`));\n }\n\n // Process Fear & Greed results\n if (fearGreedResult.status === 'fulfilled' && fearGreedResult.value?.length > 0) {\n const fgData = fearGreedResult.value;\n fearAndGreedValue = fgData[0]!.value;\n const values = fgData.map((d) => d.value);\n sentimentZScore = this.sentiment.computeSentimentZScore(values);\n signals.push(scoreSentiment(fearAndGreedValue, sentimentZScore));\n } else if (fearGreedResult.status === 'rejected') {\n console.error(chalk.dim(` Sentiment data failed: ${fearGreedResult.reason}`));\n }\n\n // Process Hyperliquid results first to use for price substitution\n let hyperliquidData: any = undefined;\n if (hyperliquidResult.status === 'fulfilled' && hyperliquidResult.value) {\n hyperliquidData = hyperliquidResult.value;\n }\n\n // Process TVL results — use Hyperliquid price if available instead of calling CoinGecko\n if (tvlResult.status === 'fulfilled' && tvlResult.value) {\n const { tvl: tvlValue } = tvlResult.value;\n tvl = tvlValue;\n\n // Calculate mcapToTvl ratio using Hyperliquid price if available\n let mcapToTvl: number | undefined;\n if (hyperliquidData?.markPrice) {\n // Use Hyperliquid mark price instead of CoinGecko\n try {\n const coinDetails = await this.coingecko.getCoinDetails(tokenId);\n const circSupply = coinDetails?.market_data?.circulating_supply;\n if (circSupply) {\n const mcap = hyperliquidData.markPrice * circSupply;\n mcapToTvl = tvlValue > 0 ? mcap / tvlValue : undefined;\n }\n } catch {\n // Fall back to original CoinGecko approach if coin details fail\n const priceData = await this.coingecko.getPrice([tokenId], [\"usd\"]);\n const mcap = priceData?.[tokenId]?.usd_market_cap;\n mcapToTvl = mcap && tvlValue > 0 ? mcap / tvlValue : undefined;\n }\n } else {\n // Fall back to CoinGecko price\n const priceData = await this.coingecko.getPrice([tokenId], [\"usd\"]);\n const mcap = priceData?.[tokenId]?.usd_market_cap;\n mcapToTvl = mcap && tvlValue > 0 ? mcap / tvlValue : undefined;\n }\n\n signals.push(scoreFundamental({ mcapToTvl }));\n } else {\n // Not all tokens have TVL data, that's fine\n signals.push(scoreFundamental({}));\n }\n\n // Shared research data — captured in phase 2, reused in phase 3 strategies\n let nansenData: any = undefined;\n let messariData: any = undefined;\n\n // Phase 2: Parallel research data fetching (Nansen + Messari) if x402 enabled\n if (this.config.useX402) {\n const [nansenResult, messariResult] = await Promise.allSettled([\n // 4. Smart-money & on-chain data (via Nansen x402)\n getResearchProvider(\"nansen\").query({ type: \"smart-money\", target: tokenId }),\n\n // 5. Fundamentals & events (via Messari x402)\n getResearchProvider(\"messari\").query({ type: \"token\", target: tokenId })\n ]);\n\n // Process Nansen results\n if (nansenResult.status === 'fulfilled') {\n const smResult = nansenResult.value;\n nansenData = smResult.data;\n const flows = smResult.data.flows as Array<Record<string, unknown>> | undefined;\n if (flows && flows.length > 0) {\n // Interpret net flow: negative = leaving exchanges = bullish\n const netflow = flows.reduce((sum, f) => sum + (Number(f.netflow ?? f.net_flow ?? 0)), 0);\n signals.push(scoreOnChain({\n exchangeNetFlow: netflow,\n whaleAccumulating: netflow < 0,\n }));\n } else {\n signals.push(scoreOnChain({}));\n }\n console.error(chalk.dim(` x402 Nansen smart-money: cost ${smResult.costUsdc} USDC`));\n } else {\n console.error(chalk.dim(` x402 Nansen smart-money unavailable: ${nansenResult.reason} — using free data only`));\n signals.push(scoreOnChain({}));\n }\n\n // Process Messari results\n if (messariResult.status === 'fulfilled') {\n const tokenResult = messariResult.value;\n messariData = tokenResult.data;\n const d = tokenResult.data as Record<string, unknown>;\n const metrics = d.metrics as Record<string, unknown> | undefined;\n const profile = d.profile as Record<string, unknown> | undefined;\n\n // Extract fundamental metrics from Messari data (replaces TVL-based fundamental if present)\n const mcapToTvl = metrics\n ? Number((metrics as Record<string, unknown>).mcap_to_tvl ?? 0) || undefined\n : undefined;\n\n // Remove any previously-pushed fundamental signal (from phase 1 TVL) to avoid duplicates\n const existingFundIdx = signals.findIndex(s => s.name === \"fundamental\");\n if (existingFundIdx >= 0) signals.splice(existingFundIdx, 1);\n\n if (mcapToTvl || metrics) {\n signals.push(scoreFundamental({ mcapToTvl }));\n } else {\n signals.push(scoreFundamental({}));\n }\n\n // Use profile/category data as an event signal\n const hasPositiveCatalyst = profile\n ? Boolean((profile as Record<string, unknown>).is_verified || (profile as Record<string, unknown>).tag_names)\n : false;\n signals.push(scoreEvent({ positiveEvent: hasPositiveCatalyst || undefined }));\n\n console.error(chalk.dim(` x402 Messari token: cost ${tokenResult.costUsdc} USDC`));\n } else {\n console.error(chalk.dim(` x402 Messari unavailable: ${messariResult.reason} — using free data only`));\n // Fall back: fundamental was already pushed from TVL above only if no TVL\n if (!signals.some(s => s.name === \"fundamental\")) {\n signals.push(scoreFundamental({}));\n }\n signals.push(scoreEvent({}));\n }\n } else {\n // Only push fundamental if not already pushed from TVL data (phase 1)\n if (!signals.some(s => s.name === \"fundamental\")) {\n signals.push(scoreFundamental({}));\n }\n signals.push(scoreEvent({}));\n }\n\n // Phase 3: Parallel strategy data fetching (symbol, funding rate, unlocks)\n let marketData: any = undefined;\n\n try {\n const [symbolResult, fundingRateResult, unlockResult, twitterResult] = await Promise.allSettled([\n // Resolve token symbol + get market data for strategies\n this.coingecko.getCoinDetails(tokenId).then(async (coinDetails) => {\n const symbol = coinDetails?.symbol?.toUpperCase();\n const marketData = await this.coingecko.getMarketData(tokenId, 7);\n return { symbol, marketData };\n }),\n\n // Fetch funding rate data (free, from Binance)\n this.fundingRate.getFundingRate(tokenId),\n\n // Fetch token unlock estimates (free, from DefiLlama FDV)\n this.tokenUnlocks.getUnlocks(tokenId),\n\n // Fetch Twitter sentiment data (free tier with auth)\n this.twitter.getSentiment(tokenId)\n ]);\n\n // Process symbol/market data results\n let tokenSymbol: string | undefined;\n if (symbolResult.status === 'fulfilled' && symbolResult.value) {\n tokenSymbol = symbolResult.value.symbol;\n marketData = symbolResult.value.marketData;\n }\n\n // Process funding rate results\n let fundingRateData: StrategyContext['fundingRateData'] = undefined;\n if (fundingRateResult.status === 'fulfilled' && fundingRateResult.value) {\n const fr = fundingRateResult.value;\n fundingRateData = { rate8h: fr.rate8h, annualizedRate: fr.annualizedRate, exchange: fr.exchange };\n }\n\n // Process unlock results\n let unlockData: StrategyContext['unlockData'] = undefined;\n if (unlockResult.status === 'fulfilled' && unlockResult.value) {\n unlockData = unlockResult.value;\n }\n\n // Process Twitter results\n let twitterData: StrategyContext['twitterData'] = undefined;\n if (twitterResult.status === 'fulfilled' && twitterResult.value) {\n twitterData = twitterResult.value;\n } else if (twitterResult.status === 'rejected') {\n console.error(chalk.dim(` Twitter sentiment failed: ${twitterResult.reason}`));\n }\n\n // Hyperliquid data already processed in Phase 1\n\n const stratCtx: StrategyContext = {\n tokenId,\n candles, // reuse from phase 1\n technicals: technicalSignals,\n fearAndGreed: fearAndGreedValue !== undefined\n ? { value: fearAndGreedValue, classification: fearAndGreedValue < 25 ? 'fear' : fearAndGreedValue > 75 ? 'greed' : 'neutral' }\n : undefined,\n sentimentZScore, // reuse from phase 1\n tvlData: tvl,\n marketData,\n nansenData, // from phase 2\n messariData, // from phase 2\n dexData: undefined, // DexFlowStrategy fetches this internally\n fundingRateData, // from phase 3\n unlockData, // from phase 3\n twitterData, // from phase 3\n hyperliquidData, // from phase 3\n tokenSymbol, // from phase 3\n };\n\n const strategySignals = await runStrategies(stratCtx, this.config.strategyConfigs);\n\n // Merge strategy signals: only add those with meaningful confidence (>0.05)\n for (const sig of strategySignals) {\n if (sig.confidence > 0.05) {\n signals.push(sig);\n }\n }\n } catch (err) {\n console.error(chalk.dim(` Strategy modules failed: ${(err as Error).message}`));\n }\n\n // 6. Market regime detection\n let regimeAnalysis: RegimeAnalysis | undefined;\n try {\n let btcCandles: Candle[] = candles || [];\n\n // If analyzing a non-BTC token, fetch BTC candles for regime analysis\n if (tokenId !== \"bitcoin\" && (!candles || candles.length < 100)) {\n const btcOhlc = await this.coingecko.getOHLC(\"bitcoin\", 200);\n if (btcOhlc && btcOhlc.length > 100) {\n btcCandles = btcOhlc.map((c: number[]) => ({\n timestamp: c[0]!,\n open: c[1]!,\n high: c[2]!,\n low: c[3]!,\n close: c[4] ?? c[3]!,\n volume: 0, // Volume not needed for regime detection\n }));\n }\n }\n\n if (btcCandles.length > 100) {\n regimeAnalysis = await this.regimeDetector.detect(btcCandles);\n }\n } catch (err) {\n console.error(chalk.dim(` Regime detection failed: ${(err as Error).message}`));\n }\n\n // 7. BTC correlation check\n let correlationCheck: CorrelationCheck | undefined;\n try {\n correlationCheck = await this.correlationGuard.checkCorrelation(tokenId);\n } catch (err) {\n console.error(chalk.dim(` Correlation check failed: ${(err as Error).message}`));\n }\n\n // 8. Compute decision with regime adjustments and correlation suppression\n const decision = computeTradeDecision(\n signals,\n this.config.weights ?? DEFAULT_WEIGHTS,\n regimeAnalysis?.strategyAdjustments,\n correlationCheck\n );\n\n return {\n token: tokenId,\n decision,\n data: { technicalSignals, fearAndGreed: fearAndGreedValue, tvl },\n regime: regimeAnalysis,\n correlation: correlationCheck,\n };\n }\n\n /** Update the token watchlist without recreating the agent (preserves caches). */\n updateTokens(tokens: string[]): void {\n this.config.tokens = tokens;\n }\n\n /** Analyze all watchlist tokens. */\n async analyzeAll(): Promise<TokenAnalysis[]> {\n const results: TokenAnalysis[] = [];\n for (const token of this.config.tokens) {\n const result = await this.analyzeToken(token);\n results.push(result);\n }\n return results;\n }\n\n /** Analyze all tokens and generate alerts for state changes. */\n async analyzeAllWithAlerts(): Promise<{ analyses: TokenAnalysis[]; alerts: Alert[] }> {\n const analyses = await this.analyzeAll();\n const alerts = await this.alertSystem.processAnalysis(analyses);\n return { analyses, alerts };\n }\n\n /** Get recent alerts. */\n async getRecentAlerts(maxAge?: number): Promise<Alert[]> {\n return this.alertSystem.getRecentAlerts(maxAge);\n }\n\n /** Clear all alerts. */\n async clearAlerts(): Promise<void> {\n return this.alertSystem.clearAlerts();\n }\n\n /** Get urgent alerts (CRITICAL/HIGH from last 30min) and mark as sent. */\n async getUrgentAlerts(): Promise<Alert[]> {\n return this.alertSystem.getUrgentAlerts();\n }\n\n /** Format alerts for display. */\n formatAlerts(alerts: Alert[], useMarkdown: boolean = false): string {\n return this.alertSystem.formatAlerts(alerts, useMarkdown);\n }\n\n /** Format analysis results for display. */\n formatAnalysis(results: TokenAnalysis[]): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"\");\n lines.push(chalk.bold(\" Sherwood Trading Agent — Analysis Results\"));\n lines.push(chalk.dim(\" \" + \"─\".repeat(60)));\n\n // Market regime display (use the first result's regime if available)\n const regime = results[0]?.regime;\n if (regime) {\n const regimeColor = regime.regime === \"trending-up\" ? chalk.green :\n regime.regime === \"trending-down\" ? chalk.red :\n regime.regime === \"ranging\" ? chalk.yellow :\n regime.regime === \"high-volatility\" ? chalk.magenta :\n chalk.cyan;\n\n const regimeStr = regimeColor(regime.regime.toUpperCase().replace('-', ' '));\n const confidenceStr = `${Math.round(regime.confidence * 100)}%`;\n const trendStr = regime.btcTrend === \"up\" ? chalk.green(\"↑\") :\n regime.btcTrend === \"down\" ? chalk.red(\"↓\") :\n chalk.yellow(\"→\");\n\n lines.push(` Market Regime: ${regimeStr} (${confidenceStr} confidence) | BTC trend: ${trendStr} | Volatility: ${regime.volatilityLevel}`);\n lines.push(chalk.dim(\" \" + \"─\".repeat(60)));\n }\n\n // BTC correlation display (use the first non-BTC result's correlation if available)\n const correlation = results.find(r => r.token !== \"bitcoin\")?.correlation;\n if (correlation) {\n const biasColor = correlation.btcBias === \"bullish\" ? chalk.green :\n correlation.btcBias === \"bearish\" ? chalk.red :\n chalk.yellow;\n\n const biasStr = biasColor(correlation.btcBias.toUpperCase());\n const scoreStr = correlation.btcScore >= 0 ? `+${correlation.btcScore.toFixed(2)}` : correlation.btcScore.toFixed(2);\n\n let suppressionStr = \"\";\n if (correlation.shouldSuppress && correlation.btcBias === \"bearish\") {\n const suppressionPct = Math.round((1 - correlation.suppressionFactor) * 100);\n suppressionStr = ` — alt longs suppressed ${suppressionPct}%`;\n } else if (!correlation.shouldSuppress && correlation.btcBias === \"bullish\") {\n const boostPct = Math.round((correlation.suppressionFactor - 1) * 100);\n if (boostPct > 0) suppressionStr = ` — alt longs boosted ${boostPct}%`;\n }\n\n lines.push(` BTC Correlation: ${biasStr} (${scoreStr})${suppressionStr}`);\n lines.push(chalk.dim(\" \" + \"─\".repeat(60)));\n }\n\n lines.push(\"\");\n\n // Column headers\n const header = ` ${\"Token\".padEnd(14)} ${\"Score\".padEnd(8)} ${\"Action\".padEnd(14)} ${\"Conf\".padEnd(8)} Key Signals`;\n lines.push(chalk.bold(header));\n lines.push(chalk.dim(\" \" + \"─\".repeat(80)));\n\n for (const r of results) {\n const d = r.decision;\n\n // Color the action\n let actionStr: string;\n switch (d.action) {\n case \"STRONG_BUY\":\n actionStr = chalk.bgGreen.black(\" STRONG BUY \");\n break;\n case \"BUY\":\n actionStr = chalk.green(\"BUY\");\n break;\n case \"HOLD\":\n actionStr = chalk.yellow(\"HOLD\");\n break;\n case \"SELL\":\n actionStr = chalk.red(\"SELL\");\n break;\n case \"STRONG_SELL\":\n actionStr = chalk.bgRed.white(\" STRONG SELL \");\n break;\n }\n\n // Score with color\n const scoreColor = d.score > 0.3 ? chalk.green : d.score < -0.3 ? chalk.red : chalk.yellow;\n const scoreStr = scoreColor(d.score.toFixed(3).padStart(7));\n\n // Confidence\n const confStr = `${(d.confidence * 100).toFixed(0)}%`;\n\n // Key signals (first 2)\n const keySignals = d.signals\n .filter((s) => Math.abs(s.value) > 0.1)\n .slice(0, 2)\n .map((s) => {\n const v = s.value;\n const color = v > 0 ? chalk.green : v < 0 ? chalk.red : chalk.yellow;\n return color(`${s.source}: ${v > 0 ? \"+\" : \"\"}${v.toFixed(2)}`);\n })\n .join(\", \");\n\n lines.push(\n ` ${r.token.padEnd(14)} ${scoreStr} ${actionStr.padEnd(14)} ${confStr.padEnd(8)} ${keySignals}`,\n );\n }\n\n lines.push(\"\");\n lines.push(chalk.dim(` Generated at ${new Date().toISOString()}`));\n lines.push(\"\");\n\n return lines.join(\"\\n\");\n }\n}\n","/**\n * DefiLlama free API provider — no API key needed.\n * Provides TVL, protocol, DEX volume, yield, price, and stablecoin data.\n */\n\nimport type { Provider, ProviderInfo } from \"../../types.js\";\n\nexport class DefiLlamaProvider implements Provider {\n info(): ProviderInfo {\n return {\n name: \"DefiLlama\",\n type: \"research\",\n capabilities: [\n \"protocol-tvl\",\n \"protocol-list\",\n \"protocol-details\",\n \"dex-volumes\",\n \"yields\",\n \"token-prices\",\n \"stablecoins\",\n ],\n supportedChains: [],\n };\n }\n\n /** Get current TVL for a protocol (returns a number). */\n async getProtocolTvl(protocol: string): Promise<number> {\n try {\n const res = await fetch(`https://api.llama.fi/tvl/${encodeURIComponent(protocol)}`);\n if (!res.ok) throw new Error(`DefiLlama tvl error: ${res.status} ${res.statusText}`);\n const data = await res.json();\n return data as number;\n } catch (err) {\n throw new Error(`Failed to fetch TVL for ${protocol}: ${(err as Error).message}`);\n }\n }\n\n /** Get all protocols with TVL & chain info. */\n async getProtocols(): Promise<any[]> {\n try {\n const res = await fetch(\"https://api.llama.fi/protocols\");\n if (!res.ok) throw new Error(`DefiLlama protocols error: ${res.status} ${res.statusText}`);\n return (await res.json()) as any[];\n } catch (err) {\n throw new Error(`Failed to fetch protocols: ${(err as Error).message}`);\n }\n }\n\n /** Get detailed protocol info with historical TVL. */\n async getProtocolDetails(protocol: string): Promise<any> {\n try {\n const res = await fetch(`https://api.llama.fi/protocol/${encodeURIComponent(protocol)}`);\n if (!res.ok) throw new Error(`DefiLlama protocol detail error: ${res.status} ${res.statusText}`);\n return await res.json();\n } catch (err) {\n throw new Error(`Failed to fetch protocol details for ${protocol}: ${(err as Error).message}`);\n }\n }\n\n /** Get DEX volumes, optionally filtered by chain. */\n async getDexVolumes(chain?: string): Promise<any> {\n try {\n const url = chain\n ? `https://api.llama.fi/overview/dexs/${encodeURIComponent(chain)}`\n : \"https://api.llama.fi/overview/dexs\";\n const res = await fetch(url);\n if (!res.ok) throw new Error(`DefiLlama dex volumes error: ${res.status} ${res.statusText}`);\n return await res.json();\n } catch (err) {\n throw new Error(`Failed to fetch DEX volumes: ${(err as Error).message}`);\n }\n }\n\n /** Get yield/pool data from DefiLlama yields API. */\n async getYields(): Promise<any> {\n try {\n const res = await fetch(\"https://yields.llama.fi/pools\");\n if (!res.ok) throw new Error(`DefiLlama yields error: ${res.status} ${res.statusText}`);\n return await res.json();\n } catch (err) {\n throw new Error(`Failed to fetch yields: ${(err as Error).message}`);\n }\n }\n\n /**\n * Get current token prices.\n * @param coins Array of \"chain:address\" strings, e.g. [\"ethereum:0x...\"]\n */\n async getTokenPrices(coins: string[]): Promise<any> {\n try {\n const joined = coins.map(encodeURIComponent).join(\",\");\n const res = await fetch(`https://coins.llama.fi/prices/current/${joined}`);\n if (!res.ok) throw new Error(`DefiLlama prices error: ${res.status} ${res.statusText}`);\n return await res.json();\n } catch (err) {\n throw new Error(`Failed to fetch token prices: ${(err as Error).message}`);\n }\n }\n\n /** Get stablecoin data. */\n async getStablecoins(): Promise<any> {\n try {\n const res = await fetch(\"https://stablecoins.llama.fi/stablecoins\");\n if (!res.ok) throw new Error(`DefiLlama stablecoins error: ${res.status} ${res.statusText}`);\n return await res.json();\n } catch (err) {\n throw new Error(`Failed to fetch stablecoins: ${(err as Error).message}`);\n }\n }\n}\n","/**\n * CoinGecko free API provider with aggressive caching and rate-limiting.\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { createHash } from 'node:crypto';\nimport type { Provider, ProviderInfo } from \"../../types.js\";\n\nconst BASE_URL = \"https://api.coingecko.com/api/v3\";\n\n// Shared mutex queue across all instances to prevent 429s.\n// Each request chains onto this promise so only one runs at a time with a 2.5s gap.\nlet requestQueue: Promise<void> = Promise.resolve();\nlet sharedLastCallTime = 0;\nlet MIN_INTERVAL = 2500; // 2.5s between calls (CG free tier: 30/min = 1 every 2s)\n\n// Cache TTLs by endpoint (in milliseconds)\nconst CACHE_TTLS = {\n ohlc: 2 * 60 * 60 * 1000, // 2 hours - historical candles don't change\n market_chart: 60 * 60 * 1000, // 1 hour\n coin_details: 60 * 60 * 1000, // 1 hour\n simple_price: 5 * 60 * 1000, // 5 minutes\n trending: 30 * 60 * 1000, // 30 minutes\n} as const;\n\nexport class CoinGeckoProvider implements Provider {\n private cacheDir: string;\n private apiKey?: string;\n\n constructor() {\n this.cacheDir = join(homedir(), '.sherwood', 'agent', 'cache', 'coingecko');\n // Check for API key from env or config\n this.apiKey = process.env.COINGECKO_API_KEY;\n\n // Adjust throttle for demo key\n if (this.apiKey) {\n MIN_INTERVAL = 1500; // Demo key has better limits\n }\n }\n\n info(): ProviderInfo {\n return {\n name: \"CoinGecko\",\n type: \"research\",\n capabilities: [\"price\", \"market-data\", \"ohlc\", \"coin-details\", \"trending\"],\n supportedChains: [],\n };\n }\n\n /**\n * Generate cache key from endpoint and params.\n */\n private getCacheKey(endpoint: string, params: string): string {\n const hash = createHash('sha1').update(endpoint + params).digest('hex').substring(0, 12);\n return `${hash}.json`;\n }\n\n /**\n * Get cache TTL for an endpoint.\n */\n private getCacheTTL(url: string): number {\n if (url.includes('/ohlc')) return CACHE_TTLS.ohlc;\n if (url.includes('/market_chart')) return CACHE_TTLS.market_chart;\n if (url.includes('/coins/') && !url.includes('/market_chart')) return CACHE_TTLS.coin_details;\n if (url.includes('/simple/price')) return CACHE_TTLS.simple_price;\n if (url.includes('/trending')) return CACHE_TTLS.trending;\n return CACHE_TTLS.simple_price; // Default fallback\n }\n\n /**\n * Read from cache if available and fresh.\n */\n private async readCache(cacheKey: string, ttl: number): Promise<any | null> {\n try {\n const cacheFile = join(this.cacheDir, cacheKey);\n const raw = await readFile(cacheFile, 'utf-8');\n const cached = JSON.parse(raw) as { ts: number; data: any };\n\n if (Date.now() - cached.ts < ttl) {\n return cached.data;\n }\n } catch {\n // Cache miss or invalid cache\n }\n return null;\n }\n\n /**\n * Write to cache with atomic write (tmp file + rename).\n */\n private async writeCache(cacheKey: string, data: any): Promise<void> {\n try {\n await mkdir(this.cacheDir, { recursive: true });\n const cacheFile = join(this.cacheDir, cacheKey);\n const tmpFile = cacheFile + '.tmp';\n\n await writeFile(tmpFile, JSON.stringify({ ts: Date.now(), data }), 'utf-8');\n // Atomic rename (requires fs.rename which we'll use from import)\n await import('node:fs/promises').then(fs => fs.rename(tmpFile, cacheFile));\n } catch {\n // Cache write failure is non-fatal\n }\n }\n\n /**\n * Serialised request method — every CoinGecko call goes through here.\n * Checks cache first, then uses shared promise chain for API calls.\n */\n private async fetchJson(url: string): Promise<any> {\n // Extract cache key from full URL path (includes token ID)\n const urlObj = new URL(url);\n const cacheKey = this.getCacheKey(urlObj.pathname, urlObj.search);\n const ttl = this.getCacheTTL(url);\n\n // Check cache first — if hit, return immediately without touching rate limiter\n const cached = await this.readCache(cacheKey, ttl);\n if (cached) {\n return cached;\n }\n\n // Cache miss — make API call with rate limiting\n const job = requestQueue.then(async () => {\n const now = Date.now();\n const elapsed = now - sharedLastCallTime;\n if (elapsed < MIN_INTERVAL) {\n await new Promise((resolve) => setTimeout(resolve, MIN_INTERVAL - elapsed));\n }\n sharedLastCallTime = Date.now();\n\n // Add API key header if available\n const headers: Record<string, string> = {};\n if (this.apiKey) {\n headers['x-cg-demo-api-key'] = this.apiKey;\n }\n\n const res = await fetch(url, { headers });\n if (res.status === 429) {\n // Rate limited — exponential backoff: 10s, 30s, 60s\n let retryDelay = 10_000;\n for (let attempt = 0; attempt < 3; attempt++) {\n await new Promise((resolve) => setTimeout(resolve, retryDelay));\n sharedLastCallTime = Date.now();\n\n const retry = await fetch(url, { headers });\n if (retry.ok) {\n const data = await retry.json();\n await this.writeCache(cacheKey, data);\n return data;\n }\n\n retryDelay *= 3; // 10s -> 30s -> 90s (but we cap at 60s)\n if (retryDelay > 60_000) retryDelay = 60_000;\n }\n throw new Error(`CoinGecko rate limit exceeded after retries — ${url}`);\n }\n if (!res.ok) throw new Error(`CoinGecko error: ${res.status} ${res.statusText} — ${url}`);\n\n const data = await res.json();\n await this.writeCache(cacheKey, data);\n return data;\n });\n\n // Chain the next request after this one settles (success or failure)\n requestQueue = job.then(() => {}, () => {});\n return job;\n }\n\n /**\n * Get simple prices for multiple tokens.\n * Returns price, 24h vol, 24h change, and market cap per token.\n */\n async getPrice(\n ids: string[],\n vsCurrencies: string[] = [\"usd\"],\n ): Promise<Record<string, any>> {\n const params = new URLSearchParams({\n ids: ids.join(\",\"),\n vs_currencies: vsCurrencies.join(\",\"),\n include_24hr_vol: \"true\",\n include_24hr_change: \"true\",\n include_market_cap: \"true\",\n });\n return this.fetchJson(`${BASE_URL}/simple/price?${params}`);\n }\n\n /**\n * Get market chart data (prices, market_caps, total_volumes) over time.\n * Note: only fetches for a single id at a time.\n */\n async getMarketData(\n id: string,\n days: number = 30,\n ): Promise<{ prices: number[][]; market_caps: number[][]; total_volumes: number[][] }> {\n const params = new URLSearchParams({\n vs_currency: \"usd\",\n days: String(days),\n });\n return this.fetchJson(`${BASE_URL}/coins/${encodeURIComponent(id)}/market_chart?${params}`);\n }\n\n /**\n * Get OHLC candle data.\n * days: 1/7/14/30/90/180/365/max\n * Returns array of [timestamp, open, high, low, close].\n */\n async getOHLC(\n id: string,\n days: number = 30,\n ): Promise<number[][]> {\n const params = new URLSearchParams({\n vs_currency: \"usd\",\n days: String(days),\n });\n return this.fetchJson(`${BASE_URL}/coins/${encodeURIComponent(id)}/ohlc?${params}`);\n }\n\n /** Get detailed coin information. */\n async getCoinDetails(id: string): Promise<any> {\n const params = new URLSearchParams({\n localization: \"false\",\n tickers: \"false\",\n community_data: \"true\",\n developer_data: \"true\",\n });\n return this.fetchJson(`${BASE_URL}/coins/${encodeURIComponent(id)}?${params}`);\n }\n\n /** Get trending coins. */\n async getTrending(): Promise<any> {\n return this.fetchJson(`${BASE_URL}/search/trending`);\n }\n}\n","/**\n * Dedicated Fear & Greed Index provider with history tracking and caching.\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nexport interface FearGreedEntry {\n value: number;\n classification: string;\n timestamp: string;\n}\n\ninterface FearGreedApiResponse {\n name: string;\n data: Array<{\n value: string;\n value_classification: string;\n timestamp: string;\n }>;\n}\n\nconst API_URL = 'https://api.alternative.me/fng/';\n\nexport class FearGreedProvider {\n private cacheDir: string;\n private cacheFile: string;\n private cacheTTL = 30 * 60 * 1000; // 30 minutes\n\n constructor() {\n this.cacheDir = join(homedir(), '.sherwood', 'agent', 'cache');\n this.cacheFile = join(this.cacheDir, 'feargreed.json');\n }\n\n /** Get current Fear & Greed data. */\n async getCurrent(): Promise<FearGreedEntry> {\n const data = await this.fetchWithCache(1);\n if (!data.length) throw new Error('No Fear & Greed data available');\n return data[0]!;\n }\n\n /** Get historical data for the last N days. */\n async getHistory(days: number = 30): Promise<FearGreedEntry[]> {\n return this.fetchWithCache(days);\n }\n\n /**\n * Check if F&G has been in extreme zone for N consecutive days.\n * @param threshold - Value boundary (e.g. 25 for fear, 75 for greed)\n * @param days - Minimum consecutive days in extreme zone\n */\n async isExtreme(\n threshold: number = 25,\n days: number = 3,\n ): Promise<{ extreme: boolean; direction: 'fear' | 'greed' | null; consecutive: number }> {\n const history = await this.getHistory(Math.max(days + 5, 30));\n\n if (history.length === 0) {\n return { extreme: false, direction: null, consecutive: 0 };\n }\n\n // Check consecutive days of extreme fear (below threshold)\n let fearStreak = 0;\n for (const entry of history) {\n if (entry.value <= threshold) {\n fearStreak++;\n } else {\n break;\n }\n }\n\n // Check consecutive days of extreme greed (above 100 - threshold)\n const greedThreshold = 100 - threshold;\n let greedStreak = 0;\n for (const entry of history) {\n if (entry.value >= greedThreshold) {\n greedStreak++;\n } else {\n break;\n }\n }\n\n if (fearStreak >= days) {\n return { extreme: true, direction: 'fear', consecutive: fearStreak };\n }\n if (greedStreak >= days) {\n return { extreme: true, direction: 'greed', consecutive: greedStreak };\n }\n\n return {\n extreme: false,\n direction: null,\n consecutive: Math.max(fearStreak, greedStreak),\n };\n }\n\n /** Fetch data with local file cache. */\n private async fetchWithCache(limit: number): Promise<FearGreedEntry[]> {\n // Try reading cache\n try {\n const raw = await readFile(this.cacheFile, 'utf-8');\n const cached = JSON.parse(raw) as { ts: number; data: FearGreedEntry[] };\n if (Date.now() - cached.ts < this.cacheTTL && cached.data.length >= limit) {\n return cached.data.slice(0, limit);\n }\n } catch {\n // No cache or invalid — fetch fresh\n }\n\n const data = await this.fetchFromApi(Math.max(limit, 30));\n\n // Write cache\n try {\n await mkdir(this.cacheDir, { recursive: true });\n await writeFile(this.cacheFile, JSON.stringify({ ts: Date.now(), data }), 'utf-8');\n } catch {\n // Cache write failure is non-fatal\n }\n\n return data.slice(0, limit);\n }\n\n /** Fetch from the alternative.me API. */\n private async fetchFromApi(limit: number): Promise<FearGreedEntry[]> {\n const url = `${API_URL}?limit=${limit}`;\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`Fear & Greed API error: ${res.status} ${res.statusText}`);\n }\n const json = (await res.json()) as FearGreedApiResponse;\n return json.data.map((d) => ({\n value: Number(d.value),\n classification: d.value_classification,\n timestamp: d.timestamp,\n }));\n }\n}\n","/**\n * Sentiment data provider — delegates to FearGreedProvider for API access,\n * adds z-score utilities and Provider interface compliance.\n */\n\nimport type { Provider, ProviderInfo } from \"../../types.js\";\nimport { FearGreedProvider, type FearGreedEntry } from \"./feargreed.js\";\n\n/** @deprecated Use FearGreedEntry from feargreed.ts instead. */\nexport type FearAndGreedData = FearGreedEntry;\n\nconst fearGreed = new FearGreedProvider();\n\nexport class SentimentProvider implements Provider {\n info(): ProviderInfo {\n return {\n name: \"Sentiment\",\n type: \"research\",\n capabilities: [\"fear-and-greed\", \"sentiment-zscore\"],\n supportedChains: [],\n };\n }\n\n /** Fetch last 30 days of Fear & Greed index data (delegates to FearGreedProvider). */\n async getFearAndGreed(): Promise<FearGreedEntry[]> {\n return fearGreed.getHistory(30);\n }\n\n /** Get just the latest Fear & Greed value (delegates to FearGreedProvider). */\n async getFearAndGreedCurrent(): Promise<FearGreedEntry> {\n return fearGreed.getCurrent();\n }\n\n /**\n * Compute z-score of the latest value compared to the array.\n * z = (latest - mean) / stddev\n */\n computeSentimentZScore(values: number[]): number {\n if (values.length < 2) return 0;\n const latest = values[0]!;\n const mean = values.reduce((a, b) => a + b, 0) / values.length;\n const variance = values.reduce((sum, v) => sum + (v - mean) ** 2, 0) / values.length;\n const stddev = Math.sqrt(variance);\n if (stddev === 0) return 0;\n return (latest - mean) / stddev;\n }\n}\n","/**\n * Technical analysis module — pure calculation functions.\n * All functions use standard financial formulas.\n */\n\nexport interface Candle {\n timestamp: number;\n open: number;\n high: number;\n low: number;\n close: number;\n volume: number;\n}\n\nexport interface TechnicalSignals {\n rsi: number;\n macd: { value: number; signal: number; histogram: number };\n bb: { upper: number; middle: number; lower: number; width: number; squeeze: boolean };\n ema: { ema8: number; ema21: number; ema50: number; ema200: number };\n atr: number;\n vwap: number;\n volume: { current: number; avg20: number; ratio: number };\n}\n\n// ── Simple Moving Average ──\n\nexport function calculateSMA(values: number[], period: number): number[] {\n if (values.length === 0) return [];\n\n const result: number[] = [];\n for (let i = 0; i < values.length; i++) {\n if (i < period - 1) {\n result.push(NaN);\n } else {\n let sum = 0;\n for (let j = i - period + 1; j <= i; j++) {\n sum += values[j]!;\n }\n result.push(sum / period);\n }\n }\n return result;\n}\n\n// ── Exponential Moving Average ──\n\nexport function calculateEMA(values: number[], period: number): number[] {\n if (values.length === 0) return [];\n\n const result: number[] = [];\n const k = 2 / (period + 1);\n\n for (let i = 0; i < values.length; i++) {\n if (i < period - 1) {\n result.push(NaN);\n } else if (i === period - 1) {\n // Seed with SMA of first `period` valid values\n let sum = 0;\n let count = 0;\n for (let j = 0; j < period; j++) {\n if (!isNaN(values[j]!)) {\n sum += values[j]!;\n count++;\n }\n }\n if (count > 0) {\n result.push(sum / count);\n } else {\n result.push(NaN);\n }\n } else {\n const prev = result[i - 1]!;\n const current = values[i]!;\n if (!isNaN(current) && !isNaN(prev)) {\n result.push(current * k + prev * (1 - k));\n } else {\n result.push(NaN);\n }\n }\n }\n return result;\n}\n\n// ── RSI (Relative Strength Index) ──\n\nexport function calculateRSI(candles: Candle[], period: number = 14): number[] {\n if (candles.length < 2) return [];\n\n const closes = candles.map((c) => c.close);\n const result: number[] = [];\n\n // Calculate price changes\n const changes: number[] = [];\n for (let i = 0; i < closes.length; i++) {\n if (i === 0) {\n changes.push(0);\n } else {\n changes.push(closes[i]! - closes[i - 1]!);\n }\n }\n\n let avgGain = 0;\n let avgLoss = 0;\n\n for (let i = 0; i < closes.length; i++) {\n if (i < period) {\n result.push(NaN);\n continue;\n }\n\n if (i === period) {\n // Sum gains and losses for changes[1..period]\n let sumGain = 0;\n let sumLoss = 0;\n for (let j = 1; j <= period; j++) {\n const change = changes[j]!;\n sumGain += Math.max(change, 0);\n sumLoss += Math.max(-change, 0);\n }\n avgGain = sumGain / period;\n avgLoss = sumLoss / period;\n } else {\n // Use Wilder's smoothing (exponential smoothing with alpha = 1/period)\n const change = changes[i]!;\n const alpha = 1 / period;\n avgGain = (1 - alpha) * avgGain + alpha * Math.max(change, 0);\n avgLoss = (1 - alpha) * avgLoss + alpha * Math.max(-change, 0);\n }\n\n if (avgLoss === 0) {\n result.push(100);\n } else {\n const rs = avgGain / avgLoss;\n result.push(100 - 100 / (1 + rs));\n }\n }\n\n return result;\n}\n\n// ── MACD ──\n\nexport function calculateMACD(\n candles: Candle[],\n fast: number = 12,\n slow: number = 26,\n signalPeriod: number = 9,\n): { macd: number[]; signal: number[]; histogram: number[] } {\n const closes = candles.map((c) => c.close);\n const emaFast = calculateEMA(closes, fast);\n const emaSlow = calculateEMA(closes, slow);\n\n const macdLine: number[] = [];\n for (let i = 0; i < closes.length; i++) {\n if (isNaN(emaFast[i]!) || isNaN(emaSlow[i]!)) {\n macdLine.push(NaN);\n } else {\n macdLine.push(emaFast[i]! - emaSlow[i]!);\n }\n }\n\n // Signal line = EMA of MACD line\n // Calculate EMA directly on the MACD line, which will handle NaN values internally\n const signalLine = calculateEMA(macdLine, signalPeriod);\n\n const histogram: number[] = [];\n for (let i = 0; i < macdLine.length; i++) {\n if (isNaN(macdLine[i]!) || isNaN(signalLine[i]!)) {\n histogram.push(NaN);\n } else {\n histogram.push(macdLine[i]! - signalLine[i]!);\n }\n }\n\n return { macd: macdLine, signal: signalLine, histogram };\n}\n\n// ── Bollinger Bands ──\n\nexport function calculateBollingerBands(\n candles: Candle[],\n period: number = 20,\n stdDevMult: number = 2.0,\n): { upper: number[]; middle: number[]; lower: number[]; width: number[] } {\n if (candles.length === 0) {\n return { upper: [], middle: [], lower: [], width: [] };\n }\n\n const closes = candles.map((c) => c.close);\n const middle = calculateSMA(closes, period);\n\n const upper: number[] = [];\n const lower: number[] = [];\n const width: number[] = [];\n\n for (let i = 0; i < closes.length; i++) {\n if (isNaN(middle[i]!)) {\n upper.push(NaN);\n lower.push(NaN);\n width.push(NaN);\n } else {\n let sumSq = 0;\n for (let j = i - period + 1; j <= i; j++) {\n sumSq += (closes[j]! - middle[i]!) ** 2;\n }\n const sd = Math.sqrt(sumSq / period);\n upper.push(middle[i]! + stdDevMult * sd);\n lower.push(middle[i]! - stdDevMult * sd);\n width.push(middle[i]! !== 0 ? (stdDevMult * 2 * sd) / middle[i]! : 0);\n }\n }\n\n return { upper, middle, lower, width };\n}\n\n// ── Average True Range ──\n\nexport function calculateATR(candles: Candle[], period: number = 14): number[] {\n if (candles.length === 0) return [];\n\n const trueRanges: number[] = [];\n for (let i = 0; i < candles.length; i++) {\n const c = candles[i]!;\n if (i === 0) {\n trueRanges.push(c.high - c.low);\n } else {\n const prev = candles[i - 1]!;\n const tr = Math.max(c.high - c.low, Math.abs(c.high - prev.close), Math.abs(c.low - prev.close));\n trueRanges.push(tr);\n }\n }\n\n // ATR = smoothed average of true ranges (Wilder's smoothing)\n const result: number[] = [];\n for (let i = 0; i < trueRanges.length; i++) {\n if (i < period - 1) {\n result.push(NaN);\n } else if (i === period - 1) {\n let sum = 0;\n for (let j = 0; j < period; j++) sum += trueRanges[j]!;\n result.push(sum / period);\n } else {\n result.push((result[i - 1]! * (period - 1) + trueRanges[i]!) / period);\n }\n }\n return result;\n}\n\n// ── VWAP (Volume Weighted Average Price) ──\n\nexport function calculateVWAP(candles: Candle[]): number[] {\n const result: number[] = [];\n let cumulativeTPV = 0;\n let cumulativeVolume = 0;\n\n for (const c of candles) {\n const typicalPrice = (c.high + c.low + c.close) / 3;\n cumulativeTPV += typicalPrice * c.volume;\n cumulativeVolume += c.volume;\n result.push(cumulativeVolume > 0 ? cumulativeTPV / cumulativeVolume : typicalPrice);\n }\n return result;\n}\n\n// ── Bollinger Band Squeeze Detection ──\n\nexport function detectBBSqueeze(candles: Candle[]): boolean {\n const bb = calculateBollingerBands(candles, 20, 2.0);\n const validWidths = bb.width.filter((w) => !isNaN(w));\n if (validWidths.length < 20) return false;\n\n const current = validWidths[validWidths.length - 1]!;\n const recent20 = validWidths.slice(-20);\n const minWidth = Math.min(...recent20);\n return current <= minWidth * 1.01; // within 1% of 20-period low\n}\n\n// ── Get Latest Signals (all indicators at current candle) ──\n\nexport function getLatestSignals(candles: Candle[]): TechnicalSignals {\n if (candles.length < 2) {\n throw new Error(\"Need at least 2 candles for technical analysis\");\n }\n\n const last = (arr: number[]): number => {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (!isNaN(arr[i]!)) return arr[i]!;\n }\n return NaN;\n };\n\n const rsiArr = calculateRSI(candles, 14);\n const macdResult = calculateMACD(candles, 12, 26, 9);\n const bbResult = calculateBollingerBands(candles, 20, 2.0);\n const closes = candles.map((c) => c.close);\n const ema8 = calculateEMA(closes, 8);\n const ema21 = calculateEMA(closes, 21);\n const ema50 = calculateEMA(closes, 50);\n const ema200 = calculateEMA(closes, 200);\n const atrArr = calculateATR(candles, 14);\n const vwapArr = calculateVWAP(candles);\n\n // Volume stats\n const volumes = candles.map((c) => c.volume);\n const currentVol = volumes[volumes.length - 1] ?? 0;\n const recent20Vol = volumes.slice(-20);\n const avg20Vol = recent20Vol.length > 0 ? recent20Vol.reduce((a, b) => a + b, 0) / recent20Vol.length : 0;\n\n return {\n rsi: last(rsiArr),\n macd: {\n value: last(macdResult.macd),\n signal: last(macdResult.signal),\n histogram: last(macdResult.histogram),\n },\n bb: {\n upper: last(bbResult.upper),\n middle: last(bbResult.middle),\n lower: last(bbResult.lower),\n width: last(bbResult.width),\n squeeze: detectBBSqueeze(candles),\n },\n ema: {\n ema8: last(ema8),\n ema21: last(ema21),\n ema50: last(ema50),\n ema200: last(ema200),\n },\n atr: last(atrArr),\n vwap: last(vwapArr),\n volume: {\n current: currentVol,\n avg20: avg20Vol,\n ratio: avg20Vol > 0 ? currentVol / avg20Vol : 0,\n },\n };\n}\n","/** Clamp a number between min and max (default [-1, 1]). */\nexport function clamp(v: number, min: number = -1, max: number = 1): number {\n return Math.min(max, Math.max(min, v));\n}\n","/**\n * Signal scoring engine — converts raw data into trade decisions.\n */\n\nimport type { TechnicalSignals } from \"./technical.js\";\nimport { clamp } from \"./utils.js\";\nimport type { CorrelationCheck } from \"./correlation.js\";\n\nexport interface Signal {\n name: string;\n value: number; // -1.0 to +1.0\n confidence: number; // 0.0 to 1.0\n source: string;\n details: string;\n _weightOverride?: number;\n}\n\nexport interface ScoringWeights {\n smartMoney: number;\n technical: number;\n sentiment: number;\n onchain: number;\n fundamental: number;\n event: number;\n}\n\nexport const DEFAULT_WEIGHTS: ScoringWeights = {\n smartMoney: 0.25,\n technical: 0.20,\n sentiment: 0.20,\n onchain: 0.15,\n fundamental: 0.10,\n event: 0.10,\n};\n\nexport interface TradeDecision {\n action: \"STRONG_BUY\" | \"BUY\" | \"HOLD\" | \"SELL\" | \"STRONG_SELL\";\n score: number;\n signals: Signal[];\n reasoning: string;\n confidence: number;\n timestamp: number;\n}\n\n// ── Score Technical Signals ──\n\nexport function scoreTechnical(signals: TechnicalSignals): Signal {\n let value = 0;\n const details: string[] = [];\n let confidence = 0.5;\n\n // If most indicators are NaN, reduce confidence significantly\n const nanCount = [signals.rsi, signals.macd.histogram, signals.bb.width, signals.ema.ema50].filter(v => isNaN(v)).length;\n if (nanCount >= 3) {\n confidence = 0.15;\n details.push(\"Insufficient data for most indicators\");\n }\n\n // RSI scoring\n const rsi = signals.rsi;\n if (!isNaN(rsi)) {\n if (rsi < 30) {\n const rsiScore = 0.5 + 0.3 * ((30 - rsi) / 30); // 0.5 at RSI=30, 0.8 at RSI=0\n value += rsiScore;\n details.push(`RSI ${rsi.toFixed(1)} oversold (+${rsiScore.toFixed(2)})`);\n confidence += 0.1;\n } else if (rsi > 70) {\n const rsiScore = -(0.5 + 0.3 * ((rsi - 70) / 30)); // -0.5 at RSI=70, -0.8 at RSI=100\n value += rsiScore;\n details.push(`RSI ${rsi.toFixed(1)} overbought (${rsiScore.toFixed(2)})`);\n confidence += 0.1;\n } else {\n // Scale linearly: RSI 50 → 0, RSI 30 → +0.5, RSI 70 → -0.5\n const rsiScore = -((rsi - 50) / 20) * 0.5;\n value += rsiScore;\n details.push(`RSI ${rsi.toFixed(1)} (${rsiScore >= 0 ? \"+\" : \"\"}${rsiScore.toFixed(2)})`);\n }\n }\n\n // MACD histogram scoring\n const hist = signals.macd.histogram;\n if (!isNaN(hist)) {\n if (hist > 0) {\n value += 0.3;\n details.push(`MACD histogram positive (+0.30)`);\n } else if (hist < 0) {\n value -= 0.3;\n details.push(`MACD histogram negative (-0.30)`);\n }\n }\n\n // Bollinger Bands scoring\n if (signals.bb.squeeze) {\n // Squeeze = neutral, wait for breakout\n details.push(\"BB squeeze detected (neutral, awaiting breakout)\");\n } else {\n const lastClose = signals.ema.ema8; // Use ema8 as proxy for current price\n if (!isNaN(signals.bb.lower) && !isNaN(lastClose)) {\n const volSpike = signals.volume.ratio > 1.5;\n if (lastClose < signals.bb.lower && volSpike) {\n value += 0.5;\n details.push(\"Price below lower BB with volume spike (+0.50)\");\n confidence += 0.1;\n } else if (lastClose > signals.bb.upper && volSpike) {\n value -= 0.5;\n details.push(\"Price above upper BB with volume spike (-0.50)\");\n confidence += 0.1;\n }\n }\n }\n\n // EMA alignment scoring\n const { ema8, ema21, ema50, ema200 } = signals.ema;\n if (!isNaN(ema8) && !isNaN(ema21) && !isNaN(ema50) && !isNaN(ema200)) {\n if (ema8 > ema21 && ema21 > ema50 && ema50 > ema200) {\n value += 0.4;\n details.push(\"Bullish EMA alignment (8>21>50>200) (+0.40)\");\n confidence += 0.1;\n } else if (ema8 < ema21 && ema21 < ema50 && ema50 < ema200) {\n value -= 0.4;\n details.push(\"Bearish EMA alignment (8<21<50<200) (-0.40)\");\n confidence += 0.1;\n }\n }\n\n return {\n name: \"technical\",\n value: clamp(value),\n confidence: Math.min(confidence, 1.0),\n source: \"Technical Analysis\",\n details: details.join(\"; \"),\n };\n}\n\n// ── Score Sentiment ──\n\nexport function scoreSentiment(fearAndGreed: number, sentimentZScore?: number): Signal {\n let value = 0;\n const details: string[] = [];\n let confidence = 0.6;\n\n if (fearAndGreed < 15) {\n value = 1.0;\n details.push(`Extreme fear (F&G=${fearAndGreed}) → max contrarian buy`);\n confidence = 0.8;\n } else if (fearAndGreed < 25) {\n // Linear interpolation: F&G 15→+0.8, F&G 25→+0.5\n value = 0.8 - 0.3 * ((fearAndGreed - 15) / 10);\n details.push(`Fear (F&G=${fearAndGreed}) → contrarian buy (+${value.toFixed(2)})`);\n confidence = 0.7;\n } else if (fearAndGreed < 40) {\n // F&G 25→+0.3, F&G 40→+0.1\n value = 0.3 - 0.2 * ((fearAndGreed - 25) / 15);\n details.push(`Mild fear (F&G=${fearAndGreed}) → slight buy (+${value.toFixed(2)})`);\n } else if (fearAndGreed <= 60) {\n value = 0;\n details.push(`Neutral sentiment (F&G=${fearAndGreed})`);\n confidence = 0.4;\n } else if (fearAndGreed <= 75) {\n // F&G 60→-0.1, F&G 75→-0.5\n value = -0.1 - 0.4 * ((fearAndGreed - 60) / 15);\n details.push(`Greed (F&G=${fearAndGreed}) → contrarian sell (${value.toFixed(2)})`);\n } else {\n // F&G 75→-0.5, F&G 100→-1.0\n value = -0.5 - 0.5 * ((fearAndGreed - 75) / 25);\n details.push(`Extreme greed (F&G=${fearAndGreed}) → max contrarian sell (${value.toFixed(2)})`);\n confidence = 0.8;\n }\n\n // Z-score adjustment\n if (sentimentZScore !== undefined) {\n const adjustment = clamp(sentimentZScore * 0.1, -0.2, 0.2);\n value = clamp(value + adjustment);\n if (Math.abs(adjustment) > 0.05) {\n details.push(`Z-score adjustment: ${adjustment >= 0 ? \"+\" : \"\"}${adjustment.toFixed(2)}`);\n }\n }\n\n return {\n name: \"sentiment\",\n value: clamp(value),\n confidence,\n source: \"Market Sentiment\",\n details: details.join(\"; \"),\n };\n}\n\n// ── Score On-Chain ──\n\nexport function scoreOnChain(data: {\n exchangeNetFlow?: number;\n whaleAccumulating?: boolean;\n activeAddressesGrowth?: number;\n}): Signal {\n let value = 0;\n const details: string[] = [];\n let confidence = 0.4;\n\n if (data.exchangeNetFlow !== undefined) {\n if (data.exchangeNetFlow < 0) {\n // Negative net flow = tokens leaving exchanges = bullish\n value += 0.4;\n details.push(\"Negative exchange net flow (bullish)\");\n confidence += 0.1;\n } else if (data.exchangeNetFlow > 0) {\n value -= 0.4;\n details.push(\"Positive exchange net flow (bearish)\");\n confidence += 0.1;\n }\n }\n\n if (data.whaleAccumulating !== undefined) {\n if (data.whaleAccumulating) {\n value += 0.3;\n details.push(\"Whale accumulation detected\");\n confidence += 0.15;\n } else {\n value -= 0.3;\n details.push(\"Whale distribution detected\");\n confidence += 0.15;\n }\n }\n\n if (data.activeAddressesGrowth !== undefined) {\n const growth = data.activeAddressesGrowth;\n if (growth > 0.1) {\n value += 0.2;\n details.push(`Active addresses growing (${(growth * 100).toFixed(1)}%)`);\n } else if (growth < -0.1) {\n value -= 0.2;\n details.push(`Active addresses declining (${(growth * 100).toFixed(1)}%)`);\n }\n }\n\n if (details.length === 0) {\n details.push(\"No on-chain data available\");\n confidence = 0.1;\n }\n\n return {\n name: \"onchain\",\n value: clamp(value),\n confidence: Math.min(confidence, 1.0),\n source: \"On-Chain Analysis\",\n details: details.join(\"; \"),\n };\n}\n\n// ── Score Fundamentals ──\n\nexport function scoreFundamental(data: {\n tvlGrowthWeekly?: number;\n revenueGrowth?: number;\n mcapToTvl?: number;\n}): Signal {\n let value = 0;\n const details: string[] = [];\n let confidence = 0.4;\n\n if (data.tvlGrowthWeekly !== undefined) {\n const g = data.tvlGrowthWeekly;\n if (g > 0.1) {\n value += 0.4;\n details.push(`TVL growing ${(g * 100).toFixed(1)}% weekly`);\n confidence += 0.1;\n } else if (g < -0.1) {\n value -= 0.4;\n details.push(`TVL declining ${(g * 100).toFixed(1)}% weekly`);\n confidence += 0.1;\n }\n }\n\n if (data.revenueGrowth !== undefined) {\n const g = data.revenueGrowth;\n if (g > 0.1) {\n value += 0.3;\n details.push(`Revenue growing ${(g * 100).toFixed(1)}%`);\n } else if (g < -0.1) {\n value -= 0.3;\n details.push(`Revenue declining ${(g * 100).toFixed(1)}%`);\n }\n }\n\n if (data.mcapToTvl !== undefined) {\n const ratio = data.mcapToTvl;\n if (ratio < 1.0) {\n value += 0.3;\n details.push(`Mcap/TVL ratio ${ratio.toFixed(2)} (undervalued)`);\n confidence += 0.1;\n } else if (ratio > 5.0) {\n value -= 0.3;\n details.push(`Mcap/TVL ratio ${ratio.toFixed(2)} (overvalued)`);\n confidence += 0.1;\n }\n }\n\n if (details.length === 0) {\n details.push(\"No fundamental data available\");\n confidence = 0.1;\n }\n\n return {\n name: \"fundamental\",\n value: clamp(value),\n confidence: Math.min(confidence, 1.0),\n source: \"Fundamental Analysis\",\n details: details.join(\"; \"),\n };\n}\n\n// ── Score Events ──\n\nexport function scoreEvent(data: {\n unlockPercent?: number;\n daysUntilUnlock?: number;\n positiveEvent?: boolean;\n}): Signal {\n let value = 0;\n const details: string[] = [];\n let confidence = 0.3;\n\n if (data.unlockPercent !== undefined && data.daysUntilUnlock !== undefined) {\n if (data.unlockPercent > 5 && data.daysUntilUnlock < 30) {\n // Large upcoming unlock = bearish\n const severity = Math.min(data.unlockPercent / 20, 1.0);\n value -= severity * 0.8;\n details.push(\n `Token unlock: ${data.unlockPercent.toFixed(1)}% in ${data.daysUntilUnlock} days (bearish)`,\n );\n confidence = 0.7;\n } else if (data.unlockPercent < 2) {\n details.push(\"Minor unlock, negligible impact\");\n }\n }\n\n if (data.positiveEvent !== undefined) {\n if (data.positiveEvent) {\n value += 0.4;\n details.push(\"Positive catalyst event\");\n confidence += 0.2;\n } else {\n value -= 0.4;\n details.push(\"Negative catalyst event\");\n confidence += 0.2;\n }\n }\n\n if (details.length === 0) {\n details.push(\"No event data available\");\n confidence = 0.1;\n }\n\n return {\n name: \"event\",\n value: clamp(value),\n confidence: Math.min(confidence, 1.0),\n source: \"Event Analysis\",\n details: details.join(\"; \"),\n };\n}\n\n// ── Combine All Signals Into Trade Decision ──\n\nexport function computeTradeDecision(\n signals: Signal[],\n weights?: ScoringWeights,\n regimeAdjustments?: Record<string, number>,\n correlationCheck?: CorrelationCheck,\n): TradeDecision {\n const w = weights ?? DEFAULT_WEIGHTS;\n\n // Map signal names to weight keys\n const weightMap: Record<string, number> = {\n technical: w.technical,\n sentiment: w.sentiment,\n onchain: w.onchain,\n fundamental: w.fundamental,\n event: w.event,\n smartMoney: w.smartMoney,\n\n // Strategy signal mappings to categories\n breakoutOnChain: w.technical,\n meanReversion: w.technical,\n multiTimeframe: w.technical,\n dexFlow: w.onchain,\n fundingRate: w.fundamental,\n tvlMomentum: w.fundamental,\n sentimentContrarian: w.sentiment,\n twitterSentiment: w.sentiment,\n tokenUnlock: w.event,\n hyperliquidFlow: w.onchain,\n };\n\n // Weighted sum\n let totalWeight = 0;\n let weightedSum = 0;\n let weightedConfidence = 0;\n\n for (const signal of signals) {\n const signalWeight = signal._weightOverride ?? weightMap[signal.name] ?? 0.1;\n\n // Apply regime adjustment if available\n let adjustedValue = signal.value;\n let adjustedConfidence = signal.confidence;\n\n if (regimeAdjustments && signal.name in regimeAdjustments) {\n const adjustment = regimeAdjustments[signal.name]!;\n adjustedValue *= adjustment;\n adjustedConfidence *= adjustment;\n }\n\n weightedSum += adjustedValue * signalWeight;\n weightedConfidence += adjustedConfidence * signalWeight;\n totalWeight += signalWeight;\n }\n\n let score = totalWeight > 0 ? weightedSum / totalWeight : 0;\n const confidence = totalWeight > 0 ? weightedConfidence / totalWeight : 0;\n\n // Apply correlation-aware adjustment if provided\n // BTC bearish → suppress longs, boost shorts\n // BTC bullish → boost longs, suppress shorts\n if (correlationCheck) {\n if (correlationCheck.btcBias === \"bearish\" && score > 0) {\n // Suppress long signals when BTC is bearish (factor < 1)\n score *= correlationCheck.suppressionFactor;\n } else if (correlationCheck.btcBias === \"bearish\" && score < 0) {\n // Boost short signals when BTC is bearish\n score *= (1 + Math.abs(correlationCheck.btcScore) * 0.3);\n } else if (correlationCheck.btcBias === \"bullish\" && score > 0) {\n // Boost long signals when BTC is bullish\n score *= (1 + Math.abs(correlationCheck.btcScore) * 0.3);\n } else if (correlationCheck.btcBias === \"bullish\" && score < 0) {\n // Suppress short signals when BTC is bullish (factor < 1)\n score *= correlationCheck.suppressionFactor;\n }\n\n // Clamp the final score\n score = Math.max(-1, Math.min(1, score));\n }\n\n // Determine action\n let action: TradeDecision[\"action\"];\n if (score > 0.6) action = \"STRONG_BUY\";\n else if (score > 0.3) action = \"BUY\";\n else if (score > -0.3) action = \"HOLD\";\n else if (score > -0.6) action = \"SELL\";\n else action = \"STRONG_SELL\";\n\n const reasoning = signals.map((s) => `[${s.source}] ${s.details}`).join(\"\\n\");\n\n return {\n action,\n score,\n signals,\n reasoning,\n confidence,\n timestamp: Date.now(),\n };\n}\n","/**\n * Smart Money Convergence Strategy\n * Analyzes Nansen smart-money netflow data to detect institutional accumulation/distribution.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { clamp } from '../utils.js';\n\nexport class SmartMoneyStrategy implements Strategy {\n name = 'smartMoney';\n description = 'Analyzes Nansen smart-money netflow to detect institutional accumulation or distribution';\n requiredData = ['nansenData'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n const details: string[] = [];\n\n if (!ctx.nansenData) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'Smart Money Convergence',\n details: 'No Nansen smart-money data available',\n };\n }\n\n const data = ctx.nansenData as Record<string, unknown>;\n const flows = data.flows as Array<Record<string, unknown>> | undefined;\n\n if (!flows || flows.length === 0) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'Smart Money Convergence',\n details: 'No smart-money flow data found',\n };\n }\n\n // Calculate net flow across all tracked wallets\n const netflow = flows.reduce(\n (sum, f) => sum + (Number(f.netflow ?? f.net_flow ?? 0)),\n 0,\n );\n\n // Count wallets accumulating vs distributing\n const accumulating = flows.filter(\n f => (Number(f.netflow ?? f.net_flow ?? 0)) < 0, // negative = leaving exchanges = buying\n ).length;\n const distributing = flows.length - accumulating;\n\n // Convergence: multiple wallets moving same direction\n const convergenceRatio = Math.max(accumulating, distributing) / flows.length;\n const isConverging = convergenceRatio > 0.7;\n\n let value = 0;\n let confidence = 0.5;\n\n if (netflow < 0) {\n // Negative net flow = leaving exchanges = smart money buying\n const magnitude = Math.min(Math.abs(netflow) / 1_000_000, 1.0); // normalize\n value = 0.5 + magnitude * 0.5; // +0.5 to +1.0\n details.push(`Smart money buying: net outflow ${Math.abs(netflow).toFixed(0)} tokens`);\n confidence = 0.6;\n } else if (netflow > 0) {\n // Positive net flow = entering exchanges = smart money selling\n const magnitude = Math.min(Math.abs(netflow) / 1_000_000, 1.0);\n value = -(0.5 + magnitude * 0.5); // -0.5 to -1.0\n details.push(`Smart money selling: net inflow ${netflow.toFixed(0)} tokens`);\n confidence = 0.6;\n } else {\n details.push('Smart money neutral: no significant flow');\n }\n\n // Convergence bonus\n if (isConverging && value !== 0) {\n const bonus = value > 0 ? 0.15 : -0.15;\n value = clamp(value + bonus);\n details.push(`${accumulating}/${flows.length} wallets accumulating (convergence signal)`);\n confidence += 0.15;\n } else {\n details.push(`Mixed signals: ${accumulating} accumulating, ${distributing} distributing`);\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(confidence, 1.0),\n source: 'Smart Money Convergence',\n details: details.join('; '),\n };\n }\n}\n","/**\n * Token Unlock Frontrun Strategy\n * Parses Messari data for upcoming token unlocks and signals bearish pressure.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { clamp } from '../utils.js';\n\ninterface UnlockEvent {\n percentOfSupply: number;\n daysUntil: number;\n type: 'team' | 'investor' | 'community' | 'ecosystem' | 'unknown';\n}\n\nfunction parseUnlocks(messariData: Record<string, unknown>): UnlockEvent[] {\n const unlocks: UnlockEvent[] = [];\n\n // Try to extract unlock data from Messari's token profile\n const profile = messariData.profile as Record<string, unknown> | undefined;\n const tokenomics = (profile?.economics ?? profile?.tokenomics ?? messariData.tokenomics) as Record<string, unknown> | undefined;\n const schedule = (tokenomics?.vesting_schedule ?? tokenomics?.unlock_schedule ?? messariData.unlock_schedule) as Array<Record<string, unknown>> | undefined;\n\n if (!schedule || !Array.isArray(schedule)) return unlocks;\n\n const now = Date.now();\n\n for (const entry of schedule) {\n const unlockDate = entry.date ?? entry.unlock_date ?? entry.timestamp;\n if (!unlockDate) continue;\n\n const unlockTime = typeof unlockDate === 'number' ? unlockDate : new Date(String(unlockDate)).getTime();\n const daysUntil = (unlockTime - now) / (1000 * 60 * 60 * 24);\n\n // Only care about future unlocks within 30 days\n if (daysUntil < 0 || daysUntil > 30) continue;\n\n const percentOfSupply = Number(entry.percent ?? entry.percent_of_supply ?? entry.amount_pct ?? 0);\n const typeRaw = String(entry.type ?? entry.category ?? entry.recipient ?? 'unknown').toLowerCase();\n\n let type: UnlockEvent['type'] = 'unknown';\n if (typeRaw.includes('team') || typeRaw.includes('founder')) type = 'team';\n else if (typeRaw.includes('investor') || typeRaw.includes('vc') || typeRaw.includes('seed') || typeRaw.includes('private')) type = 'investor';\n else if (typeRaw.includes('community') || typeRaw.includes('airdrop')) type = 'community';\n else if (typeRaw.includes('ecosystem') || typeRaw.includes('treasury')) type = 'ecosystem';\n\n unlocks.push({ percentOfSupply, daysUntil, type });\n }\n\n return unlocks;\n}\n\nexport class TokenUnlockStrategy implements Strategy {\n name = 'tokenUnlock';\n description = 'Detects upcoming token unlocks and signals potential selling pressure';\n requiredData = ['messariData'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n // Try Messari data first (x402), then fall back to DefiLlama unlock estimates\n if (!ctx.messariData && !ctx.unlockData) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'Token Unlock Frontrun',\n details: 'No unlock data available',\n };\n }\n\n // If we have DefiLlama-based unlock estimates but no Messari data, use those\n if (!ctx.messariData && ctx.unlockData) {\n return this.analyzeFromUnlockData(ctx.unlockData);\n }\n\n const unlocks = parseUnlocks(ctx.messariData as Record<string, unknown>);\n\n if (unlocks.length === 0) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.3,\n source: 'Token Unlock Frontrun',\n details: 'No upcoming token unlocks detected within 30 days',\n };\n }\n\n let value = 0;\n let confidence = 0.5;\n const details: string[] = [];\n\n for (const unlock of unlocks) {\n let signal = 0;\n\n // Large unlock (>5% supply) within 7 days: strong bearish\n if (unlock.percentOfSupply > 5 && unlock.daysUntil <= 7) {\n signal = -(0.6 + Math.min((unlock.percentOfSupply - 5) / 15, 0.4)); // -0.6 to -1.0\n confidence = 0.8;\n }\n // Large unlock (>2% supply) within 14 days: bearish\n else if (unlock.percentOfSupply > 2 && unlock.daysUntil <= 14) {\n signal = -(0.3 + Math.min((unlock.percentOfSupply - 2) / 10, 0.5)); // -0.3 to -0.8\n confidence = Math.max(confidence, 0.6);\n }\n // Smaller unlock: mild bearish\n else if (unlock.percentOfSupply > 1) {\n signal = -0.2;\n }\n\n // VC/team unlock multiplier (more selling pressure expected)\n if (unlock.type === 'team' || unlock.type === 'investor') {\n signal = clamp(signal * 1.5);\n details.push(\n `${unlock.percentOfSupply.toFixed(1)}% supply unlocking in ${Math.ceil(unlock.daysUntil)} days (type: ${unlock.type}) — elevated sell pressure`,\n );\n } else {\n details.push(\n `${unlock.percentOfSupply.toFixed(1)}% supply unlocking in ${Math.ceil(unlock.daysUntil)} days (type: ${unlock.type})`,\n );\n }\n\n // Take the most bearish signal\n if (signal < value) value = signal;\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(confidence, 1.0),\n source: 'Token Unlock Frontrun',\n details: details.join('; '),\n };\n }\n\n /** Analyze from DefiLlama FDV-based unlock estimates (free fallback) */\n private analyzeFromUnlockData(data: NonNullable<StrategyContext['unlockData']>): Signal {\n if (data.upcomingUnlocks.length === 0 || data.totalUpcomingPercent < 0.5) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.2,\n source: 'Token Unlock Frontrun',\n details: 'No significant upcoming unlocks detected',\n };\n }\n\n // Score based on weekly unlock pressure\n let value = 0;\n const pct = data.totalUpcomingPercent;\n if (pct > 5) value = -0.6;\n else if (pct > 2) value = -0.4;\n else if (pct > 1) value = -0.2;\n\n const details = data.upcomingUnlocks.map((u) => u.description).join('; ');\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: 0.4, // lower confidence since these are estimates\n source: 'Token Unlock Frontrun',\n details: details || `~${pct.toFixed(1)}% estimated weekly vesting`,\n };\n }\n}\n","/**\n * Contrarian Sentiment Strategy\n * Uses Fear & Greed index and social sentiment Z-score to trade against the crowd.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { clamp } from '../utils.js';\n\nexport class SentimentContrarianStrategy implements Strategy {\n name = 'sentimentContrarian';\n description = 'Contrarian strategy: buys extreme fear, sells extreme greed, with social Z-score adjustment';\n requiredData = ['fearAndGreed'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n if (!ctx.fearAndGreed) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'Contrarian Sentiment',\n details: 'No Fear & Greed data available',\n };\n }\n\n const fg = ctx.fearAndGreed.value;\n const details: string[] = [];\n let value = 0;\n let confidence = 0.3;\n\n if (fg < 20) {\n // Extreme fear: strong buy\n // Linear: fg=0 → +1.0, fg=20 → +0.6\n value = 1.0 - (fg / 20) * 0.4;\n confidence = 0.9;\n details.push(`Extreme fear (F&G=${fg}): strong contrarian buy signal`);\n } else if (fg < 35) {\n // Fear: buy\n // Linear: fg=20 → +0.5, fg=35 → +0.2\n value = 0.5 - ((fg - 20) / 15) * 0.3;\n confidence = 0.7;\n details.push(`Fear (F&G=${fg}): contrarian buy signal`);\n } else if (fg <= 65) {\n // Neutral: hold\n value = 0.0;\n confidence = 0.3;\n details.push(`Neutral sentiment (F&G=${fg}): no contrarian edge`);\n } else if (fg <= 80) {\n // Greed: sell\n // Linear: fg=65 → -0.2, fg=80 → -0.5\n value = -(0.2 + ((fg - 65) / 15) * 0.3);\n confidence = 0.7;\n details.push(`Greed (F&G=${fg}): contrarian sell signal`);\n } else {\n // Extreme greed: strong sell\n // Linear: fg=80 → -0.6, fg=100 → -1.0\n value = -(0.6 + ((fg - 80) / 20) * 0.4);\n confidence = 0.9;\n details.push(`Extreme greed (F&G=${fg}): strong contrarian sell signal`);\n }\n\n // Z-score adjustment: extreme social sentiment reinforces the signal\n if (ctx.sentimentZScore !== undefined) {\n const z = ctx.sentimentZScore;\n // If Z-score agrees with F&G direction, strengthen; if contradicts, weaken\n let adjustment = 0;\n if (z < -1.5 && value > 0) {\n // Extreme negative social sentiment + fear = stronger buy\n adjustment = 0.2;\n details.push(`Social Z-score ${z.toFixed(2)} reinforces buy (+0.20)`);\n } else if (z > 1.5 && value < 0) {\n // Extreme positive social sentiment + greed = stronger sell\n adjustment = -0.2;\n details.push(`Social Z-score ${z.toFixed(2)} reinforces sell (-0.20)`);\n } else if (Math.abs(z) > 1.0) {\n // Moderate Z-score adjustment\n adjustment = z > 0 ? -0.1 : 0.1;\n if (Math.abs(adjustment) > 0.05) {\n details.push(`Social Z-score ${z.toFixed(2)} adjustment (${adjustment > 0 ? '+' : ''}${adjustment.toFixed(2)})`);\n }\n }\n value = clamp(value + adjustment);\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(confidence, 1.0),\n source: 'Contrarian Sentiment',\n details: details.join('; '),\n };\n }\n}\n","/**\n * Breakout + On-Chain Confirmation Strategy\n * Detects price breakouts confirmed by volume and optionally by smart money flow.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext, Candle } from './types.js';\nimport { clamp } from '../utils.js';\n\nfunction detect20DayBreakout(candles: Candle[]): { direction: 'up' | 'down' | 'none'; volumeConfirmed: boolean } {\n if (candles.length < 21) return { direction: 'none', volumeConfirmed: false };\n\n const lookback = candles.slice(-21, -1); // previous 20 candles (excluding latest)\n const latest = candles[candles.length - 1]!;\n\n const high20 = Math.max(...lookback.map(c => c.high));\n const low20 = Math.min(...lookback.map(c => c.low));\n\n // Volume confirmation: latest volume > 2x 20-period average\n const avgVolume = lookback.reduce((sum, c) => sum + c.volume, 0) / lookback.length;\n const volumeConfirmed = avgVolume > 0 && latest.volume > avgVolume * 2;\n\n if (latest.close > high20) {\n return { direction: 'up', volumeConfirmed };\n } else if (latest.close < low20) {\n return { direction: 'down', volumeConfirmed };\n }\n\n return { direction: 'none', volumeConfirmed: false };\n}\n\nfunction checkEmaAlignment(technicals: { ema: { ema8: number; ema21: number; ema50: number } }): 'bullish' | 'bearish' | 'neutral' {\n const { ema8, ema21, ema50 } = technicals.ema;\n if (isNaN(ema8) || isNaN(ema21) || isNaN(ema50)) return 'neutral';\n\n if (ema8 > ema21 && ema21 > ema50) return 'bullish';\n if (ema8 < ema21 && ema21 < ema50) return 'bearish';\n return 'neutral';\n}\n\nexport class BreakoutOnChainStrategy implements Strategy {\n name = 'breakoutOnChain';\n description = 'Detects 20-day breakouts with volume confirmation and optional smart-money support';\n requiredData = ['candles', 'technicals'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n if (!ctx.candles || ctx.candles.length < 21) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'Breakout + On-Chain',\n details: 'Insufficient candle data for breakout detection (need 21+)',\n };\n }\n\n const details: string[] = [];\n let value = 0;\n let confidence = 0.4;\n\n // Detect breakout\n const breakout = detect20DayBreakout(ctx.candles);\n\n if (breakout.direction === 'none') {\n details.push('No 20-day breakout detected (ranging)');\n\n // Still check EMA alignment for a mild signal\n if (ctx.technicals) {\n const ema = checkEmaAlignment(ctx.technicals);\n if (ema === 'bullish') {\n value = 0.1;\n details.push('EMA alignment bullish (8>21>50)');\n } else if (ema === 'bearish') {\n value = -0.1;\n details.push('EMA alignment bearish (8<21<50)');\n }\n }\n\n return {\n name: this.name,\n value,\n confidence: 0.3,\n source: 'Breakout + On-Chain',\n details: details.join('; '),\n };\n }\n\n // Breakout detected\n if (breakout.direction === 'up') {\n value = breakout.volumeConfirmed ? 0.8 : 0.5;\n confidence = breakout.volumeConfirmed ? 0.7 : 0.5;\n details.push(`Bullish 20-day breakout${breakout.volumeConfirmed ? ' with volume confirmation (>2x avg)' : ' (low volume — caution)'}`);\n } else {\n value = breakout.volumeConfirmed ? -0.8 : -0.5;\n confidence = breakout.volumeConfirmed ? 0.7 : 0.5;\n details.push(`Bearish 20-day breakdown${breakout.volumeConfirmed ? ' with volume confirmation (>2x avg)' : ' (low volume — caution)'}`);\n }\n\n // EMA alignment bonus\n if (ctx.technicals) {\n const ema = checkEmaAlignment(ctx.technicals);\n if ((ema === 'bullish' && value > 0) || (ema === 'bearish' && value < 0)) {\n const bonus = value > 0 ? 0.2 : -0.2;\n value = clamp(value + bonus);\n confidence += 0.1;\n details.push(`EMA alignment confirms direction (+${Math.abs(bonus).toFixed(1)})`);\n } else if ((ema === 'bearish' && value > 0) || (ema === 'bullish' && value < 0)) {\n details.push('EMA alignment contradicts breakout — mixed signal');\n confidence -= 0.1;\n }\n }\n\n // Nansen smart money confirmation (optional)\n if (ctx.nansenData) {\n const data = ctx.nansenData as Record<string, unknown>;\n const flows = data.flows as Array<Record<string, unknown>> | undefined;\n if (flows && flows.length > 0) {\n const netflow = flows.reduce(\n (sum, f) => sum + (Number(f.netflow ?? f.net_flow ?? 0)),\n 0,\n );\n // Negative netflow = buying, positive = selling\n const smartMoneyBuying = netflow < 0;\n const smartMoneySelling = netflow > 0;\n\n if ((smartMoneyBuying && value > 0) || (smartMoneySelling && value < 0)) {\n const bonus = value > 0 ? 0.2 : -0.2;\n value = clamp(value + bonus);\n confidence += 0.1;\n details.push(`Smart money confirms breakout direction (+${Math.abs(bonus).toFixed(1)})`);\n } else if ((smartMoneySelling && value > 0) || (smartMoneyBuying && value < 0)) {\n details.push('Smart money diverges from breakout — caution');\n confidence -= 0.05;\n }\n }\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(Math.max(confidence, 0.1), 1.0),\n source: 'Breakout + On-Chain',\n details: details.join('; '),\n };\n }\n}\n","/**\n * TVL Momentum Strategy\n * Analyzes Total Value Locked growth trends from DefiLlama data.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { clamp } from '../utils.js';\n\nfunction calculateTvlGrowthWoW(tvlData: any): number | null {\n // tvlData may be a historical array or an object with tvl history\n let history: Array<{ date?: number; totalLiquidityUSD?: number; tvl?: number }> | undefined;\n\n if (Array.isArray(tvlData)) {\n history = tvlData;\n } else if (tvlData?.tvl && Array.isArray(tvlData.tvl)) {\n history = tvlData.tvl;\n } else if (tvlData?.chainTvls) {\n // DefiLlama protocol response — try to extract combined TVL\n const combined = Object.values(tvlData.chainTvls as Record<string, any>)\n .find((chain: any) => chain?.tvl && Array.isArray(chain.tvl));\n if (combined) history = (combined as any).tvl;\n }\n\n if (!history || history.length < 8) return null;\n\n // Get current TVL and TVL from ~7 days ago\n const sortedHistory = [...history].sort((a, b) => (a.date ?? 0) - (b.date ?? 0));\n const current = sortedHistory[sortedHistory.length - 1];\n const weekAgo = sortedHistory[Math.max(0, sortedHistory.length - 8)];\n\n const currentTvl = current?.totalLiquidityUSD ?? current?.tvl ?? 0;\n const weekAgoTvl = weekAgo?.totalLiquidityUSD ?? weekAgo?.tvl ?? 0;\n\n if (weekAgoTvl === 0) return null;\n\n return (currentTvl - weekAgoTvl) / weekAgoTvl;\n}\n\nfunction getCurrentTvl(tvlData: any): number | null {\n if (typeof tvlData === 'number') return tvlData;\n if (Array.isArray(tvlData) && tvlData.length > 0) {\n const last = tvlData[tvlData.length - 1];\n return last?.totalLiquidityUSD ?? last?.tvl ?? null;\n }\n if (tvlData?.tvl) {\n if (typeof tvlData.tvl === 'number') return tvlData.tvl;\n if (Array.isArray(tvlData.tvl) && tvlData.tvl.length > 0) {\n const last = tvlData.tvl[tvlData.tvl.length - 1];\n return last?.totalLiquidityUSD ?? last?.tvl ?? null;\n }\n }\n return null;\n}\n\nexport class TvlMomentumStrategy implements Strategy {\n name = 'tvlMomentum';\n description = 'Analyzes TVL growth trends — bullish on rising TVL, bearish on declining';\n requiredData = ['tvlData'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n if (!ctx.tvlData) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'TVL Momentum',\n details: 'No TVL data available (token may not be a DeFi protocol)',\n };\n }\n\n const details: string[] = [];\n let value = 0;\n let confidence = 0.4; // Base low confidence — TVL can be gamed\n\n const growthWoW = calculateTvlGrowthWoW(ctx.tvlData);\n\n if (growthWoW === null) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.15,\n source: 'TVL Momentum',\n details: 'Insufficient TVL history for momentum calculation',\n };\n }\n\n const growthPct = growthWoW * 100;\n\n if (growthWoW > 0.20) {\n // Strong bullish: >20% WoW growth\n value = 0.6 + Math.min((growthWoW - 0.20) / 0.30, 0.2); // 0.6 to 0.8\n confidence = 0.5;\n details.push(`TVL surging +${growthPct.toFixed(1)}% WoW: strong bullish momentum`);\n } else if (growthWoW > 0.10) {\n // Bullish: >10% WoW growth\n value = 0.3 + ((growthWoW - 0.10) / 0.10) * 0.3; // 0.3 to 0.6\n confidence = 0.45;\n details.push(`TVL growing +${growthPct.toFixed(1)}% WoW: bullish momentum`);\n } else if (growthWoW >= -0.02 && growthWoW <= 0.02) {\n // Flat: ±2%\n value = 0.0;\n confidence = 0.3;\n details.push(`TVL flat (${growthPct >= 0 ? '+' : ''}${growthPct.toFixed(1)}% WoW): neutral`);\n } else if (growthWoW > 0.02) {\n // Mild growth: 2-10%\n value = 0.1 + ((growthWoW - 0.02) / 0.08) * 0.2; // 0.1 to 0.3\n details.push(`TVL mildly growing +${growthPct.toFixed(1)}% WoW`);\n } else if (growthWoW >= -0.05) {\n // Mild decline: -2% to -5%\n value = -0.1 - ((Math.abs(growthWoW) - 0.02) / 0.03) * 0.2;\n details.push(`TVL mildly declining ${growthPct.toFixed(1)}% WoW`);\n } else if (growthWoW >= -0.15) {\n // Bearish: -5% to -15%\n value = -(0.3 + ((Math.abs(growthWoW) - 0.05) / 0.10) * 0.3); // -0.3 to -0.6\n confidence = 0.45;\n details.push(`TVL declining ${growthPct.toFixed(1)}% WoW: bearish momentum`);\n } else {\n // Strong bearish: >-15%\n value = -(0.7 + Math.min((Math.abs(growthWoW) - 0.15) / 0.15, 0.2)); // -0.7 to -0.9\n confidence = 0.5;\n details.push(`TVL crashing ${growthPct.toFixed(1)}% WoW: strong bearish momentum`);\n }\n\n // Mcap/TVL ratio consideration\n if (ctx.marketData) {\n const mcap = ctx.marketData.market_cap?.usd ?? ctx.marketData.usd_market_cap;\n const currentTvl = getCurrentTvl(ctx.tvlData);\n if (mcap && currentTvl && currentTvl > 0) {\n const ratio = mcap / currentTvl;\n if (ratio < 1.0) {\n value = clamp(value + 0.15);\n details.push(`Mcap/TVL ratio ${ratio.toFixed(2)} < 1.0 (potentially undervalued)`);\n } else if (ratio > 10) {\n value = clamp(value - 0.1);\n details.push(`Mcap/TVL ratio ${ratio.toFixed(1)} (potentially overvalued)`);\n }\n }\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(confidence, 1.0),\n source: 'TVL Momentum',\n details: details.join('; '),\n };\n }\n}\n","/**\n * Funding Rate Harvester Strategy\n * Looks at perpetual futures funding rates for arbitrage opportunities.\n * Currently a placeholder — requires external funding rate API integration.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { clamp } from '../utils.js';\n\n/**\n * Calculate annualized yield from an 8-hour funding rate.\n * Funding is paid 3x per day (every 8 hours).\n * @param rate8h - The 8-hour funding rate as a decimal (e.g., 0.0005 = 0.05%)\n * @returns Annualized yield as a decimal (e.g., 0.5475 = 54.75%)\n */\nexport function annualizedYieldFromFundingRate(rate8h: number): number {\n // 3 funding periods per day × 365 days = 1095 periods per year\n return rate8h * 3 * 365;\n}\n\n/**\n * Calculate expected return from funding rate arbitrage over a period.\n * @param rate8h - 8-hour funding rate as decimal\n * @param days - Holding period in days\n * @returns Expected return as decimal\n */\nexport function expectedReturnFromFunding(rate8h: number, days: number): number {\n return rate8h * 3 * days;\n}\n\nexport class FundingRateStrategy implements Strategy {\n name = 'fundingRate';\n description = 'Identifies funding rate arbitrage opportunities in perp markets (requires external data source)';\n requiredData = ['fundingRateData'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n // Check if funding rate data is available in the context\n // For now, this is a placeholder — funding rate data isn't provided by current providers\n const fundingData = ctx.fundingRateData;\n\n if (!fundingData) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.0,\n source: 'Funding Rate Harvester',\n details: 'No funding rate data available — requires external data source (Binance, Bybit, etc.)',\n };\n }\n\n const rate = fundingData.rate8h;\n const annualized = annualizedYieldFromFundingRate(rate);\n const ratePct = (rate * 100).toFixed(4);\n const annualizedPct = (annualized * 100).toFixed(1);\n const details: string[] = [];\n let value = 0;\n let confidence = 0.5;\n\n if (rate > 0.0005) {\n // High positive funding: longs pay shorts → market overleveraged long → bearish contrarian\n value = -0.5;\n confidence = 0.6;\n details.push(\n `High positive funding ${ratePct}% (annualized ${annualizedPct}%): overleveraged longs — bearish contrarian on ${fundingData.exchange}`,\n );\n } else if (rate > 0.0002) {\n // Mild positive funding: slightly overleveraged long → mildly bearish\n value = -0.3;\n confidence = 0.4;\n details.push(\n `Mild positive funding ${ratePct}% (annualized ${annualizedPct}%): longs paying shorts — mildly bearish`,\n );\n } else if (rate < -0.0005) {\n // High negative funding: shorts pay longs → market overleveraged short → bullish contrarian\n value = 0.5;\n confidence = 0.6;\n details.push(\n `High negative funding ${ratePct}% (annualized ${annualizedPct}%): overleveraged shorts — bullish contrarian on ${fundingData.exchange}`,\n );\n } else if (rate < -0.0002) {\n // Mild negative funding: slightly overleveraged short → mildly bullish\n value = 0.3;\n confidence = 0.4;\n details.push(\n `Mild negative funding ${ratePct}% (annualized ${annualizedPct}%): shorts paying longs — mildly bullish`,\n );\n } else {\n // Funding between -0.02% and 0.02%: no opportunity\n value = 0.0;\n confidence = 0.3;\n details.push(\n `Funding rate ${ratePct}% near neutral: no directional signal`,\n );\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence,\n source: 'Funding Rate Harvester',\n details: details.join('; '),\n };\n }\n}\n","/**\n * DEXScreener free API provider — real-time DEX data across all chains.\n * Base URL: https://api.dexscreener.com/latest\n * No API key needed. Rate limit: 300 req/min.\n */\n\nconst BASE_URL = 'https://api.dexscreener.com/latest';\n\nexport interface DexPair {\n chainId: string;\n dexId: string;\n pairAddress: string;\n baseToken: { address: string; name: string; symbol: string };\n quoteToken: { address: string; name: string; symbol: string };\n priceUsd: string;\n priceChange: { h1: number; h6: number; h24: number };\n volume: { h1: number; h6: number; h24: number };\n liquidity: { usd: number };\n fdv: number;\n txns: {\n h1: { buys: number; sells: number };\n h24: { buys: number; sells: number };\n };\n}\n\ninterface DexSearchResponse {\n pairs: DexPair[] | null;\n}\n\ninterface DexPairsResponse {\n pairs: DexPair[] | null;\n pair?: DexPair;\n}\n\n// Module-level throttle shared across all instances to enforce rate limit\nlet sharedLastCallTime = 0;\nconst SHARED_MIN_INTERVAL = 200; // 200ms = 300 req/min\n\nexport class DexScreenerProvider {\n private async throttle(): Promise<void> {\n const now = Date.now();\n const elapsed = now - sharedLastCallTime;\n if (elapsed < SHARED_MIN_INTERVAL) {\n await new Promise((resolve) => setTimeout(resolve, SHARED_MIN_INTERVAL - elapsed));\n }\n sharedLastCallTime = Date.now();\n }\n\n private async fetchJson<T>(url: string): Promise<T> {\n await this.throttle();\n const res = await fetch(url);\n if (!res.ok) {\n throw new Error(`DEXScreener API error: ${res.status} ${res.statusText} — ${url}`);\n }\n return res.json() as Promise<T>;\n }\n\n /** Search for token pairs by query string (token name, symbol, or address). */\n async searchPairs(query: string): Promise<DexPair[]> {\n const encoded = encodeURIComponent(query);\n const data = await this.fetchJson<DexSearchResponse>(\n `${BASE_URL}/dex/search/?q=${encoded}`,\n );\n return data.pairs ?? [];\n }\n\n /** Get pair data by chain and pair address. */\n async getPair(chain: string, pairAddress: string): Promise<DexPair> {\n const data = await this.fetchJson<DexPairsResponse>(\n `${BASE_URL}/dex/pairs/${encodeURIComponent(chain)}/${encodeURIComponent(pairAddress)}`,\n );\n if (data.pair) return data.pair;\n if (data.pairs && data.pairs.length > 0) return data.pairs[0]!;\n throw new Error(`No pair found: ${chain}/${pairAddress}`);\n }\n\n /** Get all DEX pairs for a token address (across all chains). */\n async getTokenPairs(tokenAddress: string): Promise<DexPair[]> {\n const data = await this.fetchJson<DexPairsResponse>(\n `${BASE_URL}/dex/tokens/${encodeURIComponent(tokenAddress)}`,\n );\n return data.pairs ?? [];\n }\n\n /** Get trending/top pairs by searching for common tokens. */\n async getTrending(): Promise<DexPair[]> {\n // DEXScreener doesn't have a dedicated trending endpoint in the free API,\n // so we search for well-known tokens and sort by volume\n const results = await this.searchPairs('WETH');\n return results\n .filter((p) => p.volume?.h24 > 0)\n .sort((a, b) => (b.volume?.h24 ?? 0) - (a.volume?.h24 ?? 0))\n .slice(0, 20);\n }\n}\n","/**\n * DEX Flow Analysis Strategy\n * Uses buy/sell transaction ratios from DEXScreener to gauge on-chain momentum.\n *\n * If buy txns significantly > sell txns (ratio > 1.5): bullish +0.3 to +0.6\n * If sell txns > buy txns (ratio > 1.5): bearish -0.3 to -0.6\n * Volume spike (24h volume > 3x liquidity): signal amplified\n * Combines 1h (reactive) and 24h (trend confirmation) data\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { DexScreenerProvider } from '../../providers/data/dexscreener.js';\nimport type { DexPair } from '../../providers/data/dexscreener.js';\nimport { clamp } from '../utils.js';\n\n/** Well-known CoinGecko ID → ticker symbol mapping. */\nconst TOKEN_SYMBOL_MAP: Record<string, string> = {\n ethereum: 'ETH',\n bitcoin: 'BTC',\n solana: 'SOL',\n uniswap: 'UNI',\n chainlink: 'LINK',\n aave: 'AAVE',\n ripple: 'XRP',\n cardano: 'ADA',\n polkadot: 'DOT',\n avalanche: 'AVAX',\n polygon: 'MATIC',\n arbitrum: 'ARB',\n optimism: 'OP',\n litecoin: 'LTC',\n dogecoin: 'DOGE',\n 'shiba-inu': 'SHIB',\n pepe: 'PEPE',\n celestia: 'TIA',\n sui: 'SUI',\n aptos: 'APT',\n sei: 'SEI',\n injective: 'INJ',\n jupiter: 'JUP',\n render: 'RENDER',\n maker: 'MKR',\n compound: 'COMP',\n lido: 'LDO',\n 'wrapped-bitcoin': 'WBTC',\n 'staked-ether': 'STETH',\n};\n\n/** Allowed chains — only EVM mainnet + major L2s. */\nconst ALLOWED_CHAINS = new Set([\n 'ethereum', 'base', 'arbitrum', 'optimism', 'polygon',\n]);\n\nconst MIN_LIQUIDITY_USD = 100_000;\n\n/** Well-known token addresses so we can search by address instead of name. */\nconst KNOWN_TOKENS: Record<string, { address: string; chain: string }> = {\n ETH: { address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', chain: 'ethereum' },\n BTC: { address: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', chain: 'ethereum' },\n WBTC: { address: '0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599', chain: 'ethereum' },\n USDC: { address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', chain: 'ethereum' },\n USDT: { address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', chain: 'ethereum' },\n UNI: { address: '0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984', chain: 'ethereum' },\n AAVE: { address: '0x7Fc66500c84A76Ad7e9c93437bFc5Ac33E2DDaE9', chain: 'ethereum' },\n LINK: { address: '0x514910771AF9Ca656af840dff83E8264EcF986CA', chain: 'ethereum' },\n SOL: { address: '0xD31a59c85aE9D8edEFec411186437e05Ce3a1d82', chain: 'ethereum' },\n MKR: { address: '0x9f8F72aA9304c8B593d555F12eF6589cC3A579A2', chain: 'ethereum' },\n CRV: { address: '0xD533a949740bb3306d119CC777fa900bA034cd52', chain: 'ethereum' },\n LDO: { address: '0x5A98FcBEA516Cf06857215779Fd812CA3beF1B32', chain: 'ethereum' },\n PENDLE: { address: '0x808507121B80c02388fAd14726482e061B8da827', chain: 'ethereum' },\n ARB: { address: '0xB50721BCf8d664c30412Cfbc6cf7a15145234ad1', chain: 'arbitrum' },\n OP: { address: '0x4200000000000000000000000000000000000042', chain: 'optimism' },\n};\n\n/**\n * Resolve a CoinGecko tokenId to a ticker symbol for DEXScreener search.\n */\nfunction resolveSymbol(tokenId: string, ctx: StrategyContext): string {\n if (TOKEN_SYMBOL_MAP[tokenId]) return TOKEN_SYMBOL_MAP[tokenId]!;\n if (ctx.tokenSymbol) return ctx.tokenSymbol.toUpperCase();\n return tokenId.toUpperCase();\n}\n\n/**\n * Filter and rank DEXScreener pairs:\n * 1. ONLY allowed EVM chains\n * 2. Require liquidity >= $100K\n * 3. Sort by liquidity descending\n */\nfunction pickBestPair(pairs: DexPair[]): DexPair | undefined {\n const viable = pairs\n .filter((p) => ALLOWED_CHAINS.has(p.chainId))\n .filter((p) => (p.liquidity?.usd ?? 0) >= MIN_LIQUIDITY_USD)\n .filter((p) => p.volume?.h24 > 0 && p.txns);\n\n if (viable.length === 0) return undefined;\n\n // Sort by liquidity descending\n viable.sort((a, b) => (b.liquidity?.usd ?? 0) - (a.liquidity?.usd ?? 0));\n return viable[0];\n}\n\nexport class DexFlowStrategy implements Strategy {\n name = 'dexFlow';\n description = 'Analyzes DEX buy/sell transaction ratios and volume for on-chain momentum';\n requiredData = ['marketData'];\n\n private dex = new DexScreenerProvider();\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n const details: string[] = [];\n let value = 0;\n let confidence = 0.3;\n\n // Try to find DEX pairs for the token\n let pairs: DexPair[] = [];\n try {\n if (ctx.dexData && Array.isArray(ctx.dexData) && ctx.dexData.length > 0) {\n pairs = ctx.dexData as DexPair[];\n } else {\n const symbol = resolveSymbol(ctx.tokenId, ctx);\n const known = KNOWN_TOKENS[symbol];\n if (known) {\n // Use address-based lookup for known tokens — much more precise\n const allPairs = await this.dex.getTokenPairs(known.address);\n pairs = allPairs.filter((p) => p.chainId === known.chain);\n } else {\n // Fallback: search by symbol\n pairs = await this.dex.searchPairs(symbol);\n }\n }\n } catch (err) {\n return {\n name: this.name,\n value: 0,\n confidence: 0.1,\n source: 'DEX Flow Analysis',\n details: `Failed to fetch DEX data: ${(err as Error).message}`,\n };\n }\n\n if (pairs.length === 0) {\n return {\n name: this.name,\n value: 0,\n confidence: 0.1,\n source: 'DEX Flow Analysis',\n details: `No DEX pairs found for ${ctx.tokenId}`,\n };\n }\n\n // Pick best pair: filter by liquidity, prefer EVM chains, sort by liquidity\n const pair = pickBestPair(pairs);\n\n if (!pair || !pair.txns) {\n return {\n name: this.name,\n value: 0,\n confidence: 0.1,\n source: 'DEX Flow Analysis',\n details: 'No DEX pairs with transaction data',\n };\n }\n\n details.push(`Pair: ${pair.baseToken.symbol}/${pair.quoteToken.symbol} on ${pair.dexId}`);\n\n // 1h transaction ratio analysis (more reactive, weighted higher)\n const h1Buys = pair.txns.h1?.buys ?? 0;\n const h1Sells = pair.txns.h1?.sells ?? 0;\n const h1Total = h1Buys + h1Sells;\n\n let h1Signal = 0;\n if (h1Total > 10) { // need minimum activity\n const h1Ratio = h1Buys / Math.max(h1Sells, 1);\n if (h1Ratio > 1.5) {\n // Bullish: scale from +0.3 (ratio=1.5) to +0.6 (ratio=3.0+)\n h1Signal = 0.3 + Math.min((h1Ratio - 1.5) / 1.5, 1.0) * 0.3;\n details.push(`1h: ${h1Buys} buys / ${h1Sells} sells (ratio ${h1Ratio.toFixed(2)}, bullish)`);\n } else if (h1Ratio < 1 / 1.5) {\n // Bearish: inverse ratio\n const invRatio = h1Sells / Math.max(h1Buys, 1);\n h1Signal = -(0.3 + Math.min((invRatio - 1.5) / 1.5, 1.0) * 0.3);\n details.push(`1h: ${h1Buys} buys / ${h1Sells} sells (ratio ${h1Ratio.toFixed(2)}, bearish)`);\n } else {\n details.push(`1h: ${h1Buys} buys / ${h1Sells} sells (balanced)`);\n }\n confidence += 0.1;\n }\n\n // 24h transaction ratio analysis (trend confirmation)\n const h24Buys = pair.txns.h24?.buys ?? 0;\n const h24Sells = pair.txns.h24?.sells ?? 0;\n const h24Total = h24Buys + h24Sells;\n\n let h24Signal = 0;\n if (h24Total > 50) { // need minimum activity\n const h24Ratio = h24Buys / Math.max(h24Sells, 1);\n if (h24Ratio > 1.5) {\n h24Signal = 0.3 + Math.min((h24Ratio - 1.5) / 1.5, 1.0) * 0.3;\n details.push(`24h: ${h24Buys} buys / ${h24Sells} sells (ratio ${h24Ratio.toFixed(2)}, bullish)`);\n } else if (h24Ratio < 1 / 1.5) {\n const invRatio = h24Sells / Math.max(h24Buys, 1);\n h24Signal = -(0.3 + Math.min((invRatio - 1.5) / 1.5, 1.0) * 0.3);\n details.push(`24h: ${h24Buys} buys / ${h24Sells} sells (ratio ${h24Ratio.toFixed(2)}, bearish)`);\n } else {\n details.push(`24h: ${h24Buys} buys / ${h24Sells} sells (balanced)`);\n }\n confidence += 0.1;\n }\n\n // Combine: 60% weight on 1h (reactive), 40% on 24h (trend)\n value = h1Signal * 0.6 + h24Signal * 0.4;\n\n // Volume spike amplifier: if 24h volume > 3x liquidity, signal is amplified\n const volume24h = pair.volume?.h24 ?? 0;\n const liquidity = pair.liquidity?.usd ?? 0;\n if (liquidity > 0 && volume24h > liquidity * 3) {\n const amplifier = Math.min(volume24h / liquidity / 3, 2.0); // cap at 2x\n value = clamp(value * amplifier);\n confidence += 0.1;\n details.push(`Volume spike: $${(volume24h / 1e6).toFixed(1)}M vol vs $${(liquidity / 1e6).toFixed(1)}M liq (${(volume24h / liquidity).toFixed(1)}x)`);\n }\n\n // Agreement bonus: if 1h and 24h agree in direction, boost confidence\n if ((h1Signal > 0 && h24Signal > 0) || (h1Signal < 0 && h24Signal < 0)) {\n confidence += 0.1;\n details.push('1h and 24h signals agree');\n } else if ((h1Signal > 0 && h24Signal < 0) || (h1Signal < 0 && h24Signal > 0)) {\n confidence -= 0.1;\n details.push('1h and 24h signals diverge');\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(Math.max(confidence, 0.1), 1.0),\n source: 'DEX Flow Analysis',\n details: details.join('; '),\n };\n }\n}\n","/**\n * Mean Reversion Strategy — for range-bound markets.\n *\n * Detect mean-reverting regime: price oscillating around SMA(20)\n * Buy signal: price below lower BB + RSI < 30 + volume spike (capitulation)\n * Sell signal: price above upper BB + RSI > 70 + volume spike (euphoria)\n * Only active when BB width is narrow (not trending) — BB squeeze must NOT be active\n * Filter: skip if EMA(50) > EMA(200) and we'd be shorting (don't fight the trend)\n * Confidence: 0.6 base, +0.1 if volume confirms, -0.2 if trending market\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { clamp } from '../utils.js';\n\nexport class MeanReversionStrategy implements Strategy {\n name = 'meanReversion';\n description = 'Mean reversion strategy for range-bound markets using BB + RSI + volume';\n requiredData = ['candles', 'technicals'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n if (!ctx.candles || !ctx.technicals || ctx.candles.length < 21) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'Mean Reversion',\n details: 'Insufficient data for mean reversion analysis',\n };\n }\n\n const tech = ctx.technicals;\n const details: string[] = [];\n let value = 0;\n let confidence = 0.6;\n\n // Get current price (latest candle close)\n const currentPrice = ctx.candles[ctx.candles.length - 1]!.close;\n\n // Check if BB squeeze is active — if so, this strategy shouldn't fire\n // (squeeze means compression, not a mean-reverting environment)\n if (tech.bb.squeeze) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.2,\n source: 'Mean Reversion',\n details: 'BB squeeze active — awaiting breakout, mean reversion inactive',\n };\n }\n\n // Check BB width — only active in narrow-to-moderate width (not strongly trending)\n // BB width > 0.15 suggests strong trend\n const isTrending = tech.bb.width > 0.15;\n if (isTrending) {\n confidence -= 0.2;\n details.push(`BB width ${tech.bb.width.toFixed(4)} (trending market, reduced confidence)`);\n } else {\n details.push(`BB width ${tech.bb.width.toFixed(4)} (range-bound, favorable)`);\n }\n\n // Detect EMA trend direction\n const ema50 = tech.ema.ema50;\n const ema200 = tech.ema.ema200;\n const bullishTrend = !isNaN(ema50) && !isNaN(ema200) && ema50 > ema200;\n const bearishTrend = !isNaN(ema50) && !isNaN(ema200) && ema50 < ema200;\n\n // Volume spike detection\n const volumeSpike = tech.volume.ratio > 1.5;\n\n // ── Buy Signal: price below lower BB + RSI < 30 (capitulation) ──\n if (currentPrice < tech.bb.lower && tech.rsi < 30) {\n value = 0.6;\n details.push(`Price $${currentPrice.toFixed(2)} below lower BB $${tech.bb.lower.toFixed(2)}`);\n details.push(`RSI ${tech.rsi.toFixed(1)} oversold`);\n\n if (volumeSpike) {\n value += 0.1;\n confidence += 0.1;\n details.push(`Volume spike ${tech.volume.ratio.toFixed(1)}x (capitulation confirmed)`);\n }\n\n // Don't fight bearish trend with buy — but still allow it with reduced confidence\n if (bearishTrend) {\n confidence -= 0.15;\n details.push('Bearish EMA trend — reduced confidence on buy');\n } else if (bullishTrend) {\n confidence += 0.1;\n details.push('Bullish EMA trend supports mean reversion buy');\n }\n }\n // ── Sell Signal: price above upper BB + RSI > 70 (euphoria) ──\n else if (currentPrice > tech.bb.upper && tech.rsi > 70) {\n value = -0.6;\n details.push(`Price $${currentPrice.toFixed(2)} above upper BB $${tech.bb.upper.toFixed(2)}`);\n details.push(`RSI ${tech.rsi.toFixed(1)} overbought`);\n\n if (volumeSpike) {\n value -= 0.1;\n confidence += 0.1;\n details.push(`Volume spike ${tech.volume.ratio.toFixed(1)}x (euphoria confirmed)`);\n }\n\n // Don't fight bullish trend with sell — filter\n if (bullishTrend) {\n confidence -= 0.15;\n details.push('Bullish EMA trend — reduced confidence on sell');\n } else if (bearishTrend) {\n confidence += 0.1;\n details.push('Bearish EMA trend supports mean reversion sell');\n }\n }\n // ── Mild signals when only partially met ──\n else if (currentPrice < tech.bb.lower) {\n value = 0.2;\n details.push(`Price below lower BB but RSI ${tech.rsi.toFixed(1)} not oversold yet`);\n } else if (currentPrice > tech.bb.upper) {\n value = -0.2;\n details.push(`Price above upper BB but RSI ${tech.rsi.toFixed(1)} not overbought yet`);\n } else if (tech.rsi < 30) {\n value = 0.15;\n details.push(`RSI ${tech.rsi.toFixed(1)} oversold but price within BB range`);\n } else if (tech.rsi > 70) {\n value = -0.15;\n details.push(`RSI ${tech.rsi.toFixed(1)} overbought but price within BB range`);\n } else {\n details.push('No mean reversion signal — price within normal range');\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(Math.max(confidence, 0.1), 1.0),\n source: 'Mean Reversion',\n details: details.join('; '),\n };\n }\n}\n","/**\n * Twitter Sentiment Strategy\n * Uses Twitter API data to generate trading signals based on mention volume,\n * sentiment analysis, and engagement patterns.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { clamp } from '../utils.js';\n\nexport class TwitterSentimentStrategy implements Strategy {\n name = 'twitterSentiment';\n description = 'Analyzes Twitter sentiment and mention volume for trading signals';\n requiredData = ['twitterData'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n const twitterData = ctx.twitterData;\n\n if (!twitterData) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.0,\n source: 'Twitter Sentiment',\n details: 'No Twitter sentiment data available — requires Twitter API credentials',\n };\n }\n\n const {\n mentionVolume,\n sentimentScore,\n engagementWeightedSentiment,\n volumeSpike,\n tweetCount,\n llmSentiment,\n llmConfidence,\n llmBullishPercent,\n llmBearishPercent,\n } = twitterData;\n\n let value = 0;\n const details: string[] = [];\n let confidence = this.calculateConfidence(tweetCount, volumeSpike, llmConfidence);\n\n // 1. Volume spike detection (weight 40%)\n const volumeSignal = this.analyzeVolumeSpike(volumeSpike, sentimentScore);\n value += volumeSignal.value * 0.4;\n if (volumeSignal.details) details.push(volumeSignal.details);\n\n // 2. Engagement-weighted sentiment (weight 40%)\n const sentimentSignal = this.analyzeSentiment(engagementWeightedSentiment, llmSentiment, llmBullishPercent, llmBearishPercent);\n value += sentimentSignal.value * 0.4;\n details.push(sentimentSignal.details);\n\n // 3. Contrarian overlay (weight 20%)\n const contrarianSignal = this.analyzeContrarian(sentimentScore, volumeSpike);\n value += contrarianSignal.value * 0.2;\n if (contrarianSignal.details) details.push(contrarianSignal.details);\n\n // Add volume and tweet count context\n details.push(`${tweetCount} tweets analyzed, ${volumeSpike.toFixed(2)}x volume spike`);\n\n return {\n name: this.name,\n value: clamp(value),\n confidence,\n source: 'Twitter Sentiment',\n details: details.join('; '),\n };\n }\n\n /** Analyze volume spike patterns. */\n private analyzeVolumeSpike(volumeSpike: number, sentimentScore: number): { value: number; details?: string } {\n if (volumeSpike > 5) {\n // Extreme attention\n const signal = sentimentScore > 0 ? 0.5 : -0.5;\n return {\n value: signal,\n details: `Extreme attention (${volumeSpike.toFixed(1)}x volume): ${signal > 0 ? 'bullish momentum' : 'bearish momentum'}`,\n };\n } else if (volumeSpike > 3) {\n // High attention\n const signal = sentimentScore > 0 ? 0.3 : -0.3;\n return {\n value: signal,\n details: `High attention (${volumeSpike.toFixed(1)}x volume): ${signal > 0 ? 'positive buzz' : 'negative buzz'}`,\n };\n } else if (volumeSpike > 1.5) {\n // Moderate attention\n const signal = sentimentScore > 0 ? 0.1 : -0.1;\n return {\n value: signal,\n details: `Moderate buzz (${volumeSpike.toFixed(1)}x volume)`,\n };\n }\n\n return { value: 0 }; // No significant volume spike\n }\n\n /** Analyze engagement-weighted sentiment. */\n private analyzeSentiment(\n engagementWeightedSentiment: number,\n llmSentiment?: number,\n llmBullishPercent?: number,\n llmBearishPercent?: number\n ): { value: number; details: string } {\n let finalSentiment: number;\n let analysisMethod: string;\n\n if (llmSentiment !== undefined) {\n // Use LLM sentiment (60%) combined with keyword sentiment (40%)\n finalSentiment = (llmSentiment * 0.6) + (engagementWeightedSentiment * 0.4);\n analysisMethod = '[LLM]';\n } else {\n // Fallback to keyword-only sentiment\n finalSentiment = engagementWeightedSentiment;\n analysisMethod = '';\n }\n\n const sentimentValue = finalSentiment * 0.4; // Scale to max ±0.4\n\n let description: string;\n if (Math.abs(finalSentiment) < 0.1) {\n description = 'neutral sentiment';\n } else if (finalSentiment > 0.7) {\n description = 'very bullish sentiment';\n } else if (finalSentiment > 0.3) {\n description = 'bullish sentiment';\n } else if (finalSentiment < -0.7) {\n description = 'very bearish sentiment';\n } else if (finalSentiment < -0.3) {\n description = 'bearish sentiment';\n } else {\n description = finalSentiment > 0 ? 'mildly bullish' : 'mildly bearish';\n }\n\n let details = `${analysisMethod} Engagement-weighted ${description} (${(finalSentiment > 0 ? '+' : '')}${finalSentiment.toFixed(2)})`;\n\n // Add LLM breakdown if available\n if (llmBullishPercent !== undefined && llmBearishPercent !== undefined) {\n details += ` — ${llmBullishPercent.toFixed(0)}% bullish, ${llmBearishPercent.toFixed(0)}% bearish`;\n }\n\n return {\n value: sentimentValue,\n details,\n };\n }\n\n /** Apply contrarian analysis for extreme sentiment + high volume. */\n private analyzeContrarian(sentimentScore: number, volumeSpike: number): { value: number; details?: string } {\n if (volumeSpike > 3) {\n if (sentimentScore > 0.7) {\n // Extreme bullishness + high volume = potential local top\n return {\n value: -0.2,\n details: 'Contrarian warning: extreme bullishness may indicate local top',\n };\n } else if (sentimentScore < -0.7) {\n // Extreme bearishness + high volume = potential capitulation\n return {\n value: 0.2,\n details: 'Contrarian opportunity: extreme bearishness may indicate capitulation',\n };\n }\n }\n\n return { value: 0 }; // No contrarian signal\n }\n\n /** Calculate confidence based on tweet count and volume spike. */\n private calculateConfidence(tweetCount: number, volumeSpike: number, llmConfidence?: number): number {\n let confidence = 0.3; // Base confidence\n\n if (tweetCount >= 100 && volumeSpike > 2) {\n confidence = 0.8;\n } else if (tweetCount >= 50) {\n confidence = 0.7;\n } else if (tweetCount >= 20) {\n confidence = 0.5;\n }\n\n // Boost confidence if we have high-confidence LLM analysis\n if (llmConfidence !== undefined && llmConfidence > 70) {\n confidence = Math.min(0.9, confidence + 0.2); // Boost by 0.2, cap at 0.9\n }\n\n return confidence;\n }\n}","/**\n * Hyperliquid Flow Strategy\n * Combines exchange-native signals for maximum alpha:\n * - Funding rate arbitrage\n * - OI + price divergence\n * - Order book imbalance\n * - Whale trade flow\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext } from './types.js';\nimport { clamp } from '../utils.js';\n\nexport class HyperliquidFlowStrategy implements Strategy {\n name = 'hyperliquidFlow';\n description = 'Exchange-native flow analysis using Hyperliquid funding, OI, order book, and whale trades';\n requiredData = ['hyperliquidData'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n const hlData = ctx.hyperliquidData;\n\n if (!hlData) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.0,\n source: 'Hyperliquid Flow',\n details: 'No Hyperliquid data available',\n };\n }\n\n const signals = [\n this.analyzeFundingRate(hlData.fundingRate),\n this.analyzeOIPriceDivergence(hlData.oiChangePct, hlData.markPrice, hlData.prevDayPrice),\n this.analyzeOrderBookImbalance(hlData.orderBookImbalance),\n this.analyzeWhaleFlow(hlData.largeTradesBias),\n ];\n\n // Combine signals with weights\n const weights = [0.25, 0.30, 0.25, 0.20]; // funding, OI+price, orderbook, whales\n let totalValue = 0;\n let totalWeight = 0;\n const details: string[] = [];\n\n for (let i = 0; i < signals.length; i++) {\n const signal = signals[i]!;\n const weight = weights[i]!;\n totalValue += signal.value * weight;\n totalWeight += weight;\n if (signal.details) details.push(signal.details);\n }\n\n const value = totalValue / totalWeight;\n\n // Calculate confidence\n let confidence = 0.6; // Base confidence (exchange-native data)\n if (hlData.volume24h > 100_000_000) confidence += 0.1; // High liquidity\n\n // Boost confidence if multiple signals agree\n const positiveSignals = signals.filter(s => s.value > 0.2).length;\n const negativeSignals = signals.filter(s => s.value < -0.2).length;\n if (positiveSignals >= 3 || negativeSignals >= 3) confidence += 0.1;\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(1.0, confidence),\n source: 'Hyperliquid Flow',\n details: details.join(' | '),\n };\n }\n\n /** Analyze funding rate for mean-reversion opportunities. */\n private analyzeFundingRate(rate: number): { value: number; details: string } {\n const ratePct = (rate * 100).toFixed(4);\n\n if (rate > 0.001) {\n // >0.1% funding: strong bearish (overleveraged longs)\n return {\n value: -0.8,\n details: `High positive funding ${ratePct}%: overleveraged longs → bearish`,\n };\n } else if (rate > 0.0003) {\n // >0.03% funding: bearish\n return {\n value: -0.6,\n details: `Elevated positive funding ${ratePct}%: longs paying → bearish`,\n };\n } else if (rate < -0.001) {\n // <-0.1% funding: strong bullish (overleveraged shorts)\n return {\n value: 0.8,\n details: `High negative funding ${ratePct}%: overleveraged shorts → bullish`,\n };\n } else if (rate < -0.0003) {\n // <-0.03% funding: bullish\n return {\n value: 0.6,\n details: `Elevated negative funding ${ratePct}%: shorts paying → bullish`,\n };\n } else {\n // Neutral funding\n return {\n value: 0.0,\n details: `Neutral funding ${ratePct}%: no directional signal`,\n };\n }\n }\n\n /** Analyze OI + price divergence patterns. */\n private analyzeOIPriceDivergence(oiChangePct: number, markPrice: number, prevDayPrice: number): { value: number; details: string } {\n const priceChange = ((markPrice - prevDayPrice) / prevDayPrice) * 100;\n const oiRising = oiChangePct > 1; // >1% OI increase\n const oiFalling = oiChangePct < -1; // >1% OI decrease\n const priceRising = priceChange > 1; // >1% price increase\n const priceFalling = priceChange < -1; // >1% price decrease\n\n if (oiRising && priceRising) {\n return {\n value: 0.6,\n details: `OI+${oiChangePct.toFixed(1)}% Price+${priceChange.toFixed(1)}%: strong trend → bullish`,\n };\n } else if (oiRising && priceFalling) {\n return {\n value: 0.3,\n details: `OI+${oiChangePct.toFixed(1)}% Price${priceChange.toFixed(1)}%: shorts building → potential squeeze`,\n };\n } else if (oiFalling && priceRising) {\n return {\n value: -0.3,\n details: `OI${oiChangePct.toFixed(1)}% Price+${priceChange.toFixed(1)}%: weak rally → potential trap`,\n };\n } else if (oiFalling && priceFalling) {\n return {\n value: 0.2,\n details: `OI${oiChangePct.toFixed(1)}% Price${priceChange.toFixed(1)}%: capitulation → potential bottom`,\n };\n } else {\n return {\n value: 0.0,\n details: `OI${oiChangePct.toFixed(1)}% Price${priceChange.toFixed(1)}%: no clear divergence`,\n };\n }\n }\n\n /** Analyze order book imbalance. */\n private analyzeOrderBookImbalance(imbalance: number): { value: number; details: string } {\n const imbalancePct = (imbalance * 100).toFixed(1);\n\n if (imbalance > 0.5) {\n return {\n value: 0.8,\n details: `Very heavy bids (${imbalancePct}%): strong demand → bullish`,\n };\n } else if (imbalance > 0.3) {\n return {\n value: 0.5,\n details: `Heavy bids (${imbalancePct}%): demand pressure → bullish`,\n };\n } else if (imbalance < -0.5) {\n return {\n value: -0.8,\n details: `Very heavy asks (${imbalancePct}%): strong supply → bearish`,\n };\n } else if (imbalance < -0.3) {\n return {\n value: -0.5,\n details: `Heavy asks (${imbalancePct}%): supply pressure → bearish`,\n };\n } else {\n return {\n value: 0.0,\n details: `Balanced orderbook (${imbalancePct}%): no directional bias`,\n };\n }\n }\n\n /** Analyze whale trade flow direction. */\n private analyzeWhaleFlow(bias: number): { value: number; details: string } {\n const biasPct = (bias * 100).toFixed(1);\n\n if (bias > 0.3) {\n return {\n value: 0.4,\n details: `Whales buying (${biasPct}%): smart money accumulation → bullish`,\n };\n } else if (bias < -0.3) {\n return {\n value: -0.4,\n details: `Whales selling (${biasPct}%): smart money distribution → bearish`,\n };\n } else {\n return {\n value: bias, // Scale linearly for smaller values\n details: `Whale flow (${biasPct}%): moderate directional bias`,\n };\n }\n }\n}","/**\n * Multi-Timeframe Confluence Strategy\n * Analyzes the same token across multiple timeframes for signal confluence.\n * Strong signals occur when multiple timeframes agree on direction.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext, Candle } from './types.js';\nimport { calculateEMA, calculateRSI } from '../technical.js';\nimport { clamp } from '../utils.js';\n\ninterface TimeframeAnalysis {\n timeframe: string;\n trend: number; // +1 bullish, 0 neutral, -1 bearish\n momentum: number; // +1 bullish, 0 neutral, -1 bearish\n structure: number; // +1 bullish, 0 neutral, -1 bearish\n score: number; // combined score\n}\n\nexport class MultiTimeframeStrategy implements Strategy {\n name = 'multiTimeframe';\n description = 'Multi-timeframe confluence analysis using daily, weekly, and short-term data';\n requiredData = ['candles'];\n\n async analyze(ctx: StrategyContext): Promise<Signal> {\n if (!ctx.candles || ctx.candles.length < 30) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'Multi-Timeframe',\n details: 'Insufficient candle data for multi-timeframe analysis (need 30+ daily candles)',\n };\n }\n\n const details: string[] = [];\n let value = 0;\n let confidence = 0.4;\n\n try {\n // Prepare timeframe data\n const dailyCandles = ctx.candles;\n const weeklyCandles = this.aggregateWeeklyCandles(dailyCandles);\n const shortTermCandles = dailyCandles.slice(-10); // Last 10 days as short-term proxy\n\n // Analyze each timeframe with appropriate periods\n const shortTermAnalysis = this.analyzeTimeframe(shortTermCandles, 'Short-term', 5);\n const dailyAnalysis = this.analyzeTimeframe(dailyCandles, 'Daily', 20);\n const weeklyAnalysis = this.analyzeTimeframe(weeklyCandles, 'Weekly', 5); // Reduced from 10\n\n const analyses = [shortTermAnalysis, dailyAnalysis, weeklyAnalysis];\n\n // Calculate confluence score\n const bullishCount = analyses.filter(a => a.score > 0).length;\n const bearishCount = analyses.filter(a => a.score < 0).length;\n const neutralCount = analyses.filter(a => a.score === 0).length;\n\n // Confluence scoring - adjusted for more realistic signals\n if (bullishCount === 3) {\n value = 0.8;\n confidence += 0.2;\n details.push('All timeframes bullish (strong confluence)');\n } else if (bearishCount === 3) {\n value = -0.8;\n confidence += 0.2;\n details.push('All timeframes bearish (strong confluence)');\n } else if (bullishCount === 2) {\n value = 0.4;\n confidence += 0.1;\n details.push('2 of 3 timeframes bullish');\n } else if (bearishCount === 2) {\n value = -0.4;\n confidence += 0.1;\n details.push('2 of 3 timeframes bearish');\n } else if (bullishCount > bearishCount) {\n value = 0.2;\n details.push('Majority bullish (weak confluence)');\n } else if (bearishCount > bullishCount) {\n value = -0.2;\n details.push('Majority bearish (weak confluence)');\n } else {\n value = 0.0;\n details.push('Mixed timeframe signals');\n }\n\n // Add timeframe breakdown details\n for (const analysis of analyses) {\n const score = analysis.score > 0 ? 'bullish' : analysis.score < 0 ? 'bearish' : 'neutral';\n details.push(`${analysis.timeframe}: ${score} (trend:${analysis.trend} momentum:${analysis.momentum} structure:${analysis.structure})`);\n }\n\n // Data quality factor\n const dataQualityFactor = Math.min(dailyCandles.length / 50, 1.0); // Full confidence at 50+ days\n confidence *= dataQualityFactor;\n\n if (dataQualityFactor < 1.0) {\n details.push(`Data quality: ${(dataQualityFactor * 100).toFixed(0)}% (${dailyCandles.length} days)`);\n }\n\n } catch (error) {\n return {\n name: this.name,\n value: 0.0,\n confidence: 0.1,\n source: 'Multi-Timeframe',\n details: `Analysis error: ${(error as Error).message}`,\n };\n }\n\n return {\n name: this.name,\n value: clamp(value),\n confidence: Math.min(Math.max(confidence, 0.1), 1.0),\n source: 'Multi-Timeframe',\n details: details.join('; '),\n };\n }\n\n private aggregateWeeklyCandles(dailyCandles: Candle[]): Candle[] {\n if (dailyCandles.length < 7) return [];\n\n const weeklyCandles: Candle[] = [];\n const sortedCandles = [...dailyCandles].sort((a, b) => a.timestamp - b.timestamp);\n\n // Group by ISO week\n const weekGroups = new Map<string, Candle[]>();\n\n for (const candle of sortedCandles) {\n const date = new Date(candle.timestamp);\n const year = date.getFullYear();\n const week = this.getISOWeek(date);\n const weekKey = `${year}-W${week.toString().padStart(2, '0')}`;\n\n if (!weekGroups.has(weekKey)) {\n weekGroups.set(weekKey, []);\n }\n weekGroups.get(weekKey)!.push(candle);\n }\n\n // Aggregate each week\n for (const [weekKey, candles] of weekGroups) {\n if (candles.length === 0) continue;\n\n const open = candles[0]!.open;\n const close = candles[candles.length - 1]!.close;\n const high = Math.max(...candles.map(c => c.high));\n const low = Math.min(...candles.map(c => c.low));\n const volume = candles.reduce((sum, c) => sum + c.volume, 0);\n const timestamp = candles[0]!.timestamp;\n\n weeklyCandles.push({ timestamp, open, high, low, close, volume });\n }\n\n return weeklyCandles.sort((a, b) => a.timestamp - b.timestamp);\n }\n\n private getISOWeek(date: Date): number {\n const tempDate = new Date(date.valueOf());\n const dayNumber = (date.getDay() + 6) % 7;\n tempDate.setDate(tempDate.getDate() - dayNumber + 3);\n const firstThursday = tempDate.valueOf();\n tempDate.setMonth(0, 1);\n if (tempDate.getDay() !== 4) {\n tempDate.setMonth(0, 1 + ((4 - tempDate.getDay()) + 7) % 7);\n }\n return 1 + Math.ceil((firstThursday - tempDate.valueOf()) / 604800000);\n }\n\n private analyzeTimeframe(candles: Candle[], label: string, emaPeriod: number): TimeframeAnalysis {\n if (candles.length < Math.max(emaPeriod * 0.7, 10)) { // More lenient requirement\n return {\n timeframe: label,\n trend: 0,\n momentum: 0,\n structure: 0,\n score: 0,\n };\n }\n\n // 1. Trend: price vs EMA\n const closes = candles.map(c => c.close);\n const emaValues = calculateEMA(closes, emaPeriod);\n const currentPrice = closes[closes.length - 1]!;\n const currentEMA = emaValues[emaValues.length - 1];\n\n let trend = 0;\n if (!isNaN(currentEMA!)) {\n trend = currentPrice > currentEMA! ? 1 : currentPrice < currentEMA! ? -1 : 0;\n }\n\n // 2. Momentum: RSI zones\n const rsiValues = calculateRSI(candles, 14);\n const currentRSI = rsiValues[rsiValues.length - 1];\n\n let momentum = 0;\n if (!isNaN(currentRSI!)) {\n if (currentRSI! > 60) momentum = 1;\n else if (currentRSI! < 40) momentum = -1;\n else momentum = 0;\n }\n\n // 3. Structure: last 3 candles pattern\n let structure = 0;\n if (candles.length >= 3) {\n const last3 = candles.slice(-3);\n const highs = last3.map(c => c.high);\n const lows = last3.map(c => c.low);\n\n const higherHighs = highs[1] > highs[0] && highs[2] > highs[1];\n const higherLows = lows[1] > lows[0] && lows[2] > lows[1];\n const lowerHighs = highs[1] < highs[0] && highs[2] < highs[1];\n const lowerLows = lows[1] < lows[0] && lows[2] < lows[1];\n\n if (higherHighs && higherLows) structure = 1;\n else if (lowerHighs && lowerLows) structure = -1;\n else structure = 0;\n }\n\n // Combine into score\n const score = trend + momentum + structure;\n\n return {\n timeframe: label,\n trend,\n momentum,\n structure,\n score: Math.sign(score) // Convert to -1, 0, or 1\n };\n }\n}","/**\n * Strategy registry — runs all enabled strategies and collects signals.\n */\n\nimport type { Signal } from '../scoring.js';\nimport type { Strategy, StrategyContext, StrategyConfig } from './types.js';\nimport { SmartMoneyStrategy } from './smart-money.js';\nimport { TokenUnlockStrategy } from './token-unlock.js';\nimport { SentimentContrarianStrategy } from './sentiment-contrarian.js';\nimport { BreakoutOnChainStrategy } from './breakout-onchain.js';\nimport { TvlMomentumStrategy } from './tvl-momentum.js';\nimport { FundingRateStrategy } from './funding-rate.js';\nimport { DexFlowStrategy } from './dex-flow.js';\nimport { MeanReversionStrategy } from './mean-reversion.js';\nimport { TwitterSentimentStrategy } from './twitter-sentiment.js';\nimport { HyperliquidFlowStrategy } from './hyperliquid-flow.js';\nimport { MultiTimeframeStrategy } from './multi-timeframe.js';\n\nexport type { Strategy, StrategyContext, StrategyConfig };\nexport { SmartMoneyStrategy, TokenUnlockStrategy, SentimentContrarianStrategy };\nexport { BreakoutOnChainStrategy, TvlMomentumStrategy, FundingRateStrategy };\nexport { DexFlowStrategy, MeanReversionStrategy, TwitterSentimentStrategy, HyperliquidFlowStrategy };\nexport { MultiTimeframeStrategy };\n\nexport const DEFAULT_STRATEGIES: Strategy[] = [\n new SmartMoneyStrategy(),\n new TokenUnlockStrategy(),\n new SentimentContrarianStrategy(),\n new BreakoutOnChainStrategy(),\n new TvlMomentumStrategy(),\n new FundingRateStrategy(),\n new DexFlowStrategy(),\n new MeanReversionStrategy(),\n new TwitterSentimentStrategy(),\n new HyperliquidFlowStrategy(),\n new MultiTimeframeStrategy(),\n];\n\n/**\n * Run all enabled strategies and collect signals.\n * Each strategy runs independently — one failure doesn't break others.\n */\nexport async function runStrategies(\n ctx: StrategyContext,\n configs?: Record<string, StrategyConfig>,\n): Promise<Signal[]> {\n const signals: Signal[] = [];\n\n const tasks = DEFAULT_STRATEGIES.map(async (strategy) => {\n // Check if strategy is explicitly disabled\n const config = configs?.[strategy.name];\n if (config && !config.enabled) return null;\n\n try {\n const signal = await strategy.analyze(ctx);\n\n // Apply weight override if configured\n if (config?.weight !== undefined) {\n // Weight override is handled at the scoring layer, but we tag it\n (signal as any)._weightOverride = config.weight;\n }\n\n return signal;\n } catch (err) {\n // Strategy failed — return a zero-confidence signal so scoring isn't affected\n console.error(`Strategy ${strategy.name} failed: ${(err as Error).message}`);\n return {\n name: strategy.name,\n value: 0.0,\n confidence: 0.0,\n source: strategy.description,\n details: `Error: ${(err as Error).message}`,\n } satisfies Signal;\n }\n });\n\n const results = await Promise.allSettled(tasks);\n\n for (const result of results) {\n if (result.status === 'fulfilled' && result.value) {\n signals.push(result.value);\n }\n }\n\n return signals;\n}\n","/**\n * Funding rate provider — fetches perpetual futures funding rates from Binance.\n * Free public API, no authentication required.\n * Rate limit: 2400 req/min (generous).\n */\n\nconst BINANCE_BASE = 'https://fapi.binance.com';\n\n// Map CoinGecko token IDs to Binance perp symbols\nconst TOKEN_TO_SYMBOL: Record<string, string> = {\n bitcoin: 'BTCUSDT',\n ethereum: 'ETHUSDT',\n solana: 'SOLUSDT',\n avalanche: 'AVAXUSDT',\n cardano: 'ADAUSDT',\n polkadot: 'DOTUSDT',\n near: 'NEARUSDT',\n cosmos: 'ATOMUSDT',\n sui: 'SUIUSDT',\n aptos: 'APTUSDT',\n uniswap: 'UNIUSDT',\n aave: 'AAVEUSDT',\n maker: 'MKRUSDT',\n chainlink: 'LINKUSDT',\n arbitrum: 'ARBUSDT',\n optimism: 'OPUSDT',\n polygon: 'MATICUSDT',\n dogecoin: 'DOGEUSDT',\n litecoin: 'LTCUSDT',\n filecoin: 'FILUSDT',\n render: 'RENDERUSDT',\n injective: 'INJUSDT',\n jupiter: 'JUPUSDT',\n pendle: 'PENDLEUSDT',\n pepe: 'PEPEUSDT',\n};\n\nexport interface FundingRateData {\n rate8h: number; // Current 8h funding rate (e.g., 0.0001 = 0.01%)\n annualizedRate: number; // Annualized funding rate\n exchange: string;\n symbol: string;\n timestamp: number;\n}\n\nexport class FundingRateProvider {\n /** Get the current funding rate for a token. Returns null if token has no perp market. */\n async getFundingRate(tokenId: string): Promise<FundingRateData | null> {\n const symbol = TOKEN_TO_SYMBOL[tokenId];\n if (!symbol) return null;\n\n try {\n const res = await fetch(`${BINANCE_BASE}/fapi/v1/fundingRate?symbol=${symbol}&limit=1`);\n if (!res.ok) return null;\n\n const data = await res.json() as Array<{ fundingRate: string; fundingTime: number }>;\n if (!data || data.length === 0) return null;\n\n const rate8h = parseFloat(data[0]!.fundingRate);\n // Annualize: 3 funding periods per day × 365 days\n const annualizedRate = rate8h * 3 * 365;\n\n return {\n rate8h,\n annualizedRate,\n exchange: 'binance',\n symbol,\n timestamp: data[0]!.fundingTime,\n };\n } catch {\n return null;\n }\n }\n}\n","/**\n * Token unlock provider — fetches upcoming vesting/unlock events.\n * Uses DefiLlama's free unlocks API (no authentication required).\n * Fallback: CoinGecko status_updates for governance events.\n */\n\nconst DEFILLAMA_UNLOCKS = 'https://api.llama.fi/protocol';\n\n// Map CoinGecko IDs to DefiLlama protocol slugs\nconst TOKEN_TO_PROTOCOL: Record<string, string> = {\n uniswap: 'uniswap',\n aave: 'aave',\n maker: 'makerdao',\n compound: 'compound-finance',\n curve: 'curve-dex',\n lido: 'lido',\n arbitrum: 'arbitrum',\n optimism: 'optimism',\n polygon: 'polygon',\n sushi: 'sushi',\n jupiter: 'jupiter',\n pendle: 'pendle',\n injective: 'injective-protocol',\n render: 'render-network',\n};\n\nexport interface UnlockEvent {\n /** Percentage of circulating supply being unlocked */\n percentOfSupply: number;\n /** Days until the unlock */\n daysUntil: number;\n /** Description of the unlock */\n description: string;\n}\n\nexport interface TokenUnlockData {\n upcomingUnlocks: UnlockEvent[];\n totalUpcomingPercent: number;\n}\n\nexport class TokenUnlocksProvider {\n /** Get upcoming unlock events for a token. Returns null if no data available. */\n async getUnlocks(tokenId: string): Promise<TokenUnlockData | null> {\n const slug = TOKEN_TO_PROTOCOL[tokenId];\n if (!slug) return null;\n\n try {\n const res = await fetch(`${DEFILLAMA_UNLOCKS}/${slug}`);\n if (!res.ok) return null;\n\n const data = await res.json() as any;\n\n // DefiLlama protocol endpoint includes mcap and token info\n // We estimate unlock pressure from token allocation data\n const mcap = data?.mcap;\n const fdv = data?.fdvData;\n\n if (!mcap || !fdv || fdv <= 0) return null;\n\n // Ratio of circulating to fully-diluted gives us how much is still locked\n const circulatingRatio = mcap / fdv;\n const lockedPercent = (1 - circulatingRatio) * 100;\n\n if (lockedPercent < 1) {\n // Fully circulating — no unlock pressure\n return { upcomingUnlocks: [], totalUpcomingPercent: 0 };\n }\n\n // Estimate: assume locked tokens vest linearly over 2 years\n // This is an approximation — real schedules vary\n const monthlyUnlockPercent = lockedPercent / 24;\n const weeklyUnlockPercent = monthlyUnlockPercent / 4;\n\n const unlocks: UnlockEvent[] = [];\n\n if (weeklyUnlockPercent > 0.5) {\n unlocks.push({\n percentOfSupply: weeklyUnlockPercent,\n daysUntil: 7,\n description: `Estimated ~${weeklyUnlockPercent.toFixed(1)}% weekly vesting (${lockedPercent.toFixed(0)}% still locked)`,\n });\n }\n\n if (monthlyUnlockPercent > 1) {\n unlocks.push({\n percentOfSupply: monthlyUnlockPercent,\n daysUntil: 30,\n description: `Estimated ~${monthlyUnlockPercent.toFixed(1)}% monthly vesting`,\n });\n }\n\n return {\n upcomingUnlocks: unlocks,\n totalUpcomingPercent: weeklyUnlockPercent,\n };\n } catch {\n return null;\n }\n }\n}\n","/**\n * Twitter Sentiment Provider — fetches token-specific sentiment data from Twitter API v2.\n * Uses OAuth 1.0a for user-context authentication (higher rate limits than app-only).\n * Rate limit: 10 requests/min, 100 tweets/request (Recent Search free tier).\n */\n\nimport { createHmac, randomBytes } from 'node:crypto';\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nexport interface TwitterSentimentData {\n mentionVolume: number; // Total tweets in last hour vs 24h hourly average\n sentimentScore: number; // Simple keyword-based sentiment (-1 to +1)\n engagementWeightedSentiment: number; // Sentiment weighted by engagement\n volumeSpike: number; // Ratio of last-hour volume to 24h hourly average\n tweetCount: number; // Total tweets analyzed\n llmSentiment?: number; // LLM-analyzed sentiment (-1 to +1)\n llmConfidence?: number; // average LLM confidence\n llmBullishPercent?: number; // % of tweets classified bullish\n llmBearishPercent?: number; // % classified bearish\n}\n\ninterface TwitterTweet {\n id: string;\n text: string;\n created_at: string;\n public_metrics: {\n like_count: number;\n retweet_count: number;\n reply_count: number;\n };\n author_id: string;\n}\n\ninterface TwitterApiResponse {\n data: TwitterTweet[];\n meta: {\n result_count: number;\n next_token?: string;\n };\n}\n\ninterface OpenAISentimentResponse {\n sentiment: 'BULLISH' | 'BEARISH' | 'NEUTRAL';\n confidence: number;\n}\n\ninterface TweetWithEngagement {\n text: string;\n engagement: number;\n}\n\nconst TWITTER_BASE = 'https://api.twitter.com/2';\n\n// Map CoinGecko token IDs to Twitter search queries\nconst TOKEN_TO_SEARCH: Record<string, string> = {\n bitcoin: '$BTC OR #bitcoin',\n ethereum: '$ETH OR #ethereum',\n solana: '$SOL OR #solana',\n arbitrum: '$ARB OR #arbitrum',\n uniswap: '$UNI OR #uniswap',\n aave: '$AAVE OR #aave',\n chainlink: '$LINK OR #chainlink',\n cardano: '$ADA OR #cardano',\n polkadot: '$DOT OR #polkadot',\n avalanche: '$AVAX OR #avalanche',\n near: '$NEAR OR #near',\n cosmos: '$ATOM OR #cosmos',\n sui: '$SUI OR #sui',\n aptos: '$APT OR #aptos',\n maker: '$MKR OR #maker',\n optimism: '$OP OR #optimism',\n polygon: '$MATIC OR #polygon',\n dogecoin: '$DOGE OR #dogecoin',\n litecoin: '$LTC OR #litecoin',\n filecoin: '$FIL OR #filecoin',\n render: '$RENDER OR #render',\n injective: '$INJ OR #injective',\n jupiter: '$JUP OR #jupiter',\n pendle: '$PENDLE OR #pendle',\n pepe: '$PEPE OR #pepe',\n};\n\n// Sentiment keywords\nconst BULLISH_WORDS = [\n 'bullish', 'moon', 'pump', 'buy', 'long', 'breakout', 'ath', 'send it', 'lfg', 'wagmi', 'undervalued',\n 'hodl', 'diamond hands', 'to the moon', 'rocket', 'bull run', 'green', 'gainz', 'surge', 'rally'\n];\n\nconst BEARISH_WORDS = [\n 'bearish', 'dump', 'sell', 'short', 'crash', 'dead', 'rekt', 'ngmi', 'overvalued', 'scam',\n 'paper hands', 'bear market', 'red', 'dip', 'correction', 'bubble', 'rugpull', 'bloodbath'\n];\n\nexport class TwitterSentimentProvider {\n private cacheDir: string;\n private cacheTTL = 5 * 60 * 1000; // 5 minutes\n\n constructor() {\n this.cacheDir = join(homedir(), '.sherwood', 'agent', 'cache');\n }\n\n /** Get Twitter sentiment data for a token. Returns null if no data or API failure. */\n async getSentiment(tokenId: string): Promise<TwitterSentimentData | null> {\n const query = TOKEN_TO_SEARCH[tokenId];\n if (!query) {\n // For unknown tokens, try to use the token symbol if available\n return null;\n }\n\n // Check cache first\n const cached = await this.readCache(tokenId);\n if (cached) return cached;\n\n try {\n // Fetch recent tweets (last 24 hours for volume analysis)\n const tweets = await this.fetchTweets(query, new Date(Date.now() - 24 * 60 * 60 * 1000));\n if (!tweets || tweets.length === 0) return null;\n\n // Calculate metrics\n const data = await this.analyzeTweets(tweets);\n\n // Cache results\n await this.writeCache(tokenId, data);\n\n return data;\n } catch (err) {\n console.error(`Twitter API error for ${tokenId}: ${(err as Error).message}`);\n return null;\n }\n }\n\n /** Fetch tweets using Twitter API v2 Recent Search with OAuth 1.0a. */\n private async fetchTweets(query: string, startTime: Date): Promise<TwitterTweet[] | null> {\n const apiKey = process.env.TWITTER_API_KEY;\n const apiSecret = process.env.TWITTER_API_SECRET;\n const accessToken = process.env.TWITTER_ACCESS_TOKEN;\n const accessTokenSecret = process.env.TWITTER_ACCESS_TOKEN_SECRET;\n\n if (!apiKey || !apiSecret || !accessToken || !accessTokenSecret) {\n throw new Error('Twitter API credentials not found in environment variables');\n }\n\n const url = new URL(`${TWITTER_BASE}/tweets/search/recent`);\n url.searchParams.set('query', query);\n url.searchParams.set('start_time', startTime.toISOString());\n url.searchParams.set('max_results', '100');\n url.searchParams.set('tweet.fields', 'created_at,public_metrics,author_id');\n\n // Generate OAuth 1.0a signature\n const oauthParams: Record<string, string> = {\n oauth_consumer_key: apiKey,\n oauth_token: accessToken,\n oauth_signature_method: 'HMAC-SHA1',\n oauth_timestamp: Math.floor(Date.now() / 1000).toString(),\n oauth_nonce: randomBytes(16).toString('hex'),\n oauth_version: '1.0',\n };\n\n // Create signature base string\n const params = { ...oauthParams, ...Object.fromEntries(url.searchParams) };\n const sortedParams = Object.keys(params)\n .sort()\n .map(key => `${encodeURIComponent(key)}=${encodeURIComponent(params[key])}`)\n .join('&');\n\n const signatureBaseString = `GET&${encodeURIComponent(url.origin + url.pathname)}&${encodeURIComponent(sortedParams)}`;\n\n // Create signing key\n const signingKey = `${encodeURIComponent(apiSecret)}&${encodeURIComponent(accessTokenSecret)}`;\n\n // Generate signature\n const signature = createHmac('sha1', signingKey).update(signatureBaseString).digest('base64');\n\n // Create Authorization header\n const authHeader = 'OAuth ' + Object.entries({ ...oauthParams, oauth_signature: signature })\n .map(([key, value]) => `${encodeURIComponent(key)}=\"${encodeURIComponent(value)}\"`)\n .join(', ');\n\n const response = await fetch(url.toString(), {\n headers: {\n 'Authorization': authHeader,\n 'User-Agent': 'Sherwood-Agent/1.0'\n }\n });\n\n if (!response.ok) {\n if (response.status === 429) {\n // Rate limited\n return null;\n }\n throw new Error(`Twitter API error: ${response.status} ${response.statusText}`);\n }\n\n const data = await response.json() as TwitterApiResponse;\n return data.data || [];\n }\n\n /** Analyze sentiment using OpenAI GPT-4o-mini. */\n private async analyzeSentimentWithLLM(tweets: TwitterTweet[]): Promise<{\n llmSentiment: number;\n llmConfidence: number;\n llmBullishPercent: number;\n llmBearishPercent: number;\n } | null> {\n const openaiKey = process.env.OPENAI_API_KEY;\n if (!openaiKey) {\n return null;\n }\n\n try {\n // Prepare tweets with engagement data\n const tweetsWithEngagement: TweetWithEngagement[] = tweets.map(tweet => ({\n text: tweet.text,\n engagement: tweet.public_metrics.like_count +\n tweet.public_metrics.retweet_count +\n tweet.public_metrics.reply_count,\n }));\n\n // Batch tweets into groups of 20\n const batchSize = 20;\n const batches: TweetWithEngagement[][] = [];\n for (let i = 0; i < tweetsWithEngagement.length; i += batchSize) {\n batches.push(tweetsWithEngagement.slice(i, i + batchSize));\n }\n\n const allResults: (OpenAISentimentResponse & { engagement: number })[] = [];\n\n // Process each batch\n for (const batch of batches) {\n // Sanitize tweet text to prevent prompt injection:\n // 1. Strip dangerous chars first (bidi overrides, zero-width, control chars)\n // 2. Flatten newlines\n // 3. Escape quotes/backslashes\n // 4. Truncate\n const sanitizeTweet = (text: string): string => {\n return text\n .replace(/[\\x00-\\x1f\\x7f]/g, '') // strip control chars\n .replace(/[\\u200B-\\u200D\\u202A-\\u202E\\u2066-\\u2069\\u00AD\\uFEFF]/g, '') // strip bidi overrides + zero-width chars\n .replace(/\\n/g, ' ') // flatten newlines\n .replace(/[\"\\\\]/g, (c) => `\\\\${c}`) // escape quotes/backslashes\n .slice(0, 280); // truncate last (after stripping, not before)\n };\n\n const tweetTexts = batch.map((tweet, idx) => `${idx + 1}. \"${sanitizeTweet(tweet.text)}\"`).join('\\n');\n\n const systemPrompt = `You are a crypto market sentiment analyzer. For each tweet, classify sentiment as BULLISH, BEARISH, or NEUTRAL with confidence 0-100. Consider sarcasm, irony, CT slang. Respond ONLY as a JSON array: [{\"sentiment\": \"BULLISH\", \"confidence\": 85}, ...]`;\n\n const userPrompt = `Analyze these ${batch.length} tweets:\\n${tweetTexts}`;\n\n const response = await fetch('https://api.openai.com/v1/chat/completions', {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${openaiKey}`,\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n model: 'gpt-4o-mini',\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userPrompt },\n ],\n temperature: 0,\n }),\n });\n\n if (!response.ok) {\n console.warn(`OpenAI API error: ${response.status} ${response.statusText}`);\n return null;\n }\n\n const data = await response.json();\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n console.warn('OpenAI API returned no content');\n return null;\n }\n\n // Parse JSON response — strip markdown code blocks if present\n let batchResults: OpenAISentimentResponse[];\n try {\n let jsonStr = content.trim();\n // OpenAI sometimes wraps JSON in ```json ... ``` markdown blocks\n if (jsonStr.startsWith('```')) {\n jsonStr = jsonStr.replace(/^```(?:json)?\\s*\\n?/, '').replace(/\\n?```\\s*$/, '');\n }\n batchResults = JSON.parse(jsonStr);\n if (!Array.isArray(batchResults) || batchResults.length !== batch.length) {\n console.warn('OpenAI response format mismatch');\n return null;\n }\n // Validate each element to prevent NaN propagation from malformed responses\n const VALID_SENTIMENTS = new Set(['BULLISH', 'BEARISH', 'NEUTRAL']);\n for (const r of batchResults) {\n if (!VALID_SENTIMENTS.has(r.sentiment)) r.sentiment = 'NEUTRAL';\n if (typeof r.confidence !== 'number' || !Number.isFinite(r.confidence)) r.confidence = 50;\n r.confidence = Math.max(0, Math.min(100, r.confidence));\n }\n } catch (parseErr) {\n console.warn(`Failed to parse OpenAI response: ${parseErr}`);\n return null;\n }\n\n // Combine with engagement data\n for (let i = 0; i < batchResults.length; i++) {\n allResults.push({\n ...batchResults[i],\n engagement: batch[i].engagement,\n });\n }\n }\n\n // Calculate weighted sentiment metrics\n const bullishTweets = allResults.filter(r => r.sentiment === 'BULLISH');\n const bearishTweets = allResults.filter(r => r.sentiment === 'BEARISH');\n\n const totalTweets = allResults.length;\n const llmBullishPercent = (bullishTweets.length / totalTweets) * 100;\n const llmBearishPercent = (bearishTweets.length / totalTweets) * 100;\n\n // Calculate engagement-weighted sentiment score\n let totalWeightedScore = 0;\n let totalWeight = 0;\n let totalConfidence = 0;\n\n for (const result of allResults) {\n let sentimentMultiplier = 0;\n if (result.sentiment === 'BULLISH') {\n sentimentMultiplier = 1;\n } else if (result.sentiment === 'BEARISH') {\n sentimentMultiplier = -1;\n }\n\n const weight = (result.confidence / 100) * (1 + Math.log10(result.engagement + 1));\n totalWeightedScore += sentimentMultiplier * weight;\n totalWeight += weight;\n totalConfidence += result.confidence;\n }\n\n const llmSentiment = totalWeight > 0 ? Math.max(-1, Math.min(1, totalWeightedScore / totalWeight)) : 0;\n const llmConfidence = totalTweets > 0 ? totalConfidence / totalTweets : 0;\n\n return {\n llmSentiment,\n llmConfidence,\n llmBullishPercent,\n llmBearishPercent,\n };\n\n } catch (error) {\n console.warn(`LLM sentiment analysis failed: ${error}`);\n return null;\n }\n }\n\n /** Analyze tweets to calculate sentiment metrics. */\n private async analyzeTweets(tweets: TwitterTweet[]): Promise<TwitterSentimentData> {\n const now = Date.now();\n const oneHourAgo = now - 60 * 60 * 1000;\n\n // Separate recent (last hour) vs all tweets\n const recentTweets = tweets.filter(t => new Date(t.created_at).getTime() > oneHourAgo);\n const allTweets = tweets;\n\n // Calculate mention volume (recent vs average)\n const recentVolume = recentTweets.length;\n const avgHourlyVolume = allTweets.length / 24; // 24 hours of data\n const volumeSpike = avgHourlyVolume > 0 ? recentVolume / avgHourlyVolume : 1;\n\n // Analyze sentiment for all tweets (keyword-based)\n let bullishCount = 0;\n let bearishCount = 0;\n let totalEngagement = 0;\n let engagementWeightedBullish = 0;\n let engagementWeightedBearish = 0;\n\n for (const tweet of allTweets) {\n const text = tweet.text.toLowerCase();\n const engagement = tweet.public_metrics.like_count +\n tweet.public_metrics.retweet_count +\n tweet.public_metrics.reply_count;\n\n let tweetBullish = 0;\n let tweetBearish = 0;\n\n // Count sentiment words\n for (const word of BULLISH_WORDS) {\n if (text.includes(word)) tweetBullish++;\n }\n for (const word of BEARISH_WORDS) {\n if (text.includes(word)) tweetBearish++;\n }\n\n if (tweetBullish > tweetBearish) {\n bullishCount++;\n engagementWeightedBullish += engagement;\n } else if (tweetBearish > tweetBullish) {\n bearishCount++;\n engagementWeightedBearish += engagement;\n }\n\n totalEngagement += engagement;\n }\n\n // Calculate keyword-based sentiment scores\n const totalAnalyzed = bullishCount + bearishCount;\n const sentimentScore = totalAnalyzed > 0\n ? Math.max(-1, Math.min(1, (bullishCount - bearishCount) / totalAnalyzed))\n : 0;\n\n const engagementWeightedSentiment = totalEngagement > 0\n ? Math.max(-1, Math.min(1, (engagementWeightedBullish - engagementWeightedBearish) / totalEngagement))\n : sentimentScore;\n\n // Try LLM sentiment analysis\n const llmResult = await this.analyzeSentimentWithLLM(allTweets);\n\n const baseData: TwitterSentimentData = {\n mentionVolume: recentVolume,\n sentimentScore,\n engagementWeightedSentiment,\n volumeSpike,\n tweetCount: allTweets.length,\n };\n\n // Add LLM results if available\n if (llmResult) {\n return {\n ...baseData,\n llmSentiment: llmResult.llmSentiment,\n llmConfidence: llmResult.llmConfidence,\n llmBullishPercent: llmResult.llmBullishPercent,\n llmBearishPercent: llmResult.llmBearishPercent,\n };\n }\n\n return baseData;\n }\n\n /** Read cached sentiment data. */\n private async readCache(tokenId: string): Promise<TwitterSentimentData | null> {\n try {\n const cacheFile = join(this.cacheDir, `twitter-${tokenId}.json`);\n const raw = await readFile(cacheFile, 'utf-8');\n const cached = JSON.parse(raw) as { ts: number; data: TwitterSentimentData };\n\n if (Date.now() - cached.ts < this.cacheTTL) {\n return cached.data;\n }\n } catch {\n // No cache or invalid cache\n }\n return null;\n }\n\n /** Write sentiment data to cache. */\n private async writeCache(tokenId: string, data: TwitterSentimentData): Promise<void> {\n try {\n await mkdir(this.cacheDir, { recursive: true });\n const cacheFile = join(this.cacheDir, `twitter-${tokenId}.json`);\n await writeFile(cacheFile, JSON.stringify({ ts: Date.now(), data }), 'utf-8');\n } catch {\n // Cache write failure is non-fatal\n }\n }\n\n /** Get sentiment data with fallback to token symbol for unknown tokens. */\n async getSentimentWithSymbol(tokenId: string, tokenSymbol?: string): Promise<TwitterSentimentData | null> {\n // Try with known token mapping first\n let result = await this.getSentiment(tokenId);\n\n // If no result and we have a symbol, try searching with symbol\n if (!result && tokenSymbol) {\n const symbolQuery = `$${tokenSymbol.toUpperCase()} OR #${tokenSymbol.toLowerCase()}`;\n try {\n const tweets = await this.fetchTweets(symbolQuery, new Date(Date.now() - 24 * 60 * 60 * 1000));\n if (tweets && tweets.length > 0) {\n result = await this.analyzeTweets(tweets);\n await this.writeCache(tokenId, result);\n }\n } catch {\n // Symbol-based search failed\n }\n }\n\n return result;\n }\n}","/**\n * Hyperliquid data provider — fetches native exchange data from Hyperliquid's free REST API.\n * Provides funding rates, open interest, order book, and trade flow data.\n * Base URL: https://api.hyperliquid.xyz/info (POST requests, JSON body)\n * Rate limit: reasonable usage, cached for 2 minutes.\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nconst HYPERLIQUID_BASE = 'https://api.hyperliquid.xyz/info';\n\n// Map CoinGecko token IDs to Hyperliquid coin names\nconst TOKEN_TO_COIN: Record<string, string> = {\n bitcoin: 'BTC',\n ethereum: 'ETH',\n solana: 'SOL',\n arbitrum: 'ARB',\n chainlink: 'LINK',\n aave: 'AAVE',\n uniswap: 'UNI',\n dogecoin: 'DOGE',\n avalanche: 'AVAX',\n near: 'NEAR',\n sui: 'SUI',\n aptos: 'APT',\n injective: 'INJ',\n pendle: 'PENDLE',\n pepe: 'PEPE',\n polygon: 'MATIC',\n optimism: 'OP',\n litecoin: 'LTC',\n cosmos: 'ATOM',\n filecoin: 'FIL',\n maker: 'MKR',\n cardano: 'ADA',\n polkadot: 'DOT',\n render: 'RENDER',\n jupiter: 'JUP',\n};\n\nexport interface HyperliquidData {\n fundingRate: number; // current 8h funding rate\n openInterest: number; // USD value\n oiChangePct: number; // OI change since last fetch (percentage, NOT 24h)\n volume24h: number; // 24h notional volume\n markPrice: number;\n oraclePrice: number;\n prevDayPrice: number;\n orderBookImbalance: number; // (bid_depth - ask_depth) / (bid_depth + ask_depth) for top 10 levels\n largeTradesBias: number; // net direction of trades > $50K in last hour (-1 to +1)\n}\n\ninterface MetaAndAssetCtxs {\n universe: Array<{\n name: string;\n szDecimals: number;\n }>;\n}\n\ninterface AssetCtx {\n funding: string;\n openInterest: string;\n dayNtlVlm: string;\n markPx: string;\n oraclePx: string;\n prevDayPx: string;\n}\n\ninterface L2BookLevel {\n px: string;\n sz: string;\n n: number;\n}\n\ninterface L2Book {\n levels: [L2BookLevel[], L2BookLevel[]]; // [bids, asks]\n}\n\ninterface RecentTrade {\n coin: string;\n side: string;\n px: string;\n sz: string;\n time: number;\n hash: string;\n}\n\nexport class HyperliquidProvider {\n private cacheDir: string;\n private cacheTTL = 2 * 60 * 1000; // 2 minutes\n private oiCache = new Map<string, number>(); // For tracking OI changes\n\n constructor() {\n this.cacheDir = join(homedir(), '.sherwood', 'agent', 'cache');\n }\n\n /** Get comprehensive Hyperliquid data for a token. Returns null if token not supported or API failure. */\n async getHyperliquidData(tokenId: string): Promise<HyperliquidData | null> {\n const coin = TOKEN_TO_COIN[tokenId];\n if (!coin) return null;\n\n // Check cache first\n const cached = await this.readCache(tokenId);\n if (cached) return cached;\n\n try {\n // Fetch all data in parallel\n const [metaResult, bookResult, tradesResult] = await Promise.allSettled([\n this.fetchMetaAndAssetCtxs(),\n this.fetchL2Book(coin),\n this.fetchRecentTrades(coin)\n ]);\n\n // Process meta and asset contexts (funding, OI, volume, prices)\n if (metaResult.status !== 'fulfilled' || !metaResult.value) {\n return null;\n }\n\n const [meta, assetCtxs] = metaResult.value;\n const assetIdx = meta.universe.findIndex(asset => asset.name === coin);\n if (assetIdx === -1 || !assetCtxs[assetIdx]) {\n return null;\n }\n\n const assetData = assetCtxs[assetIdx]!;\n const fundingRate = parseFloat(assetData.funding);\n const openInterest = parseFloat(assetData.openInterest);\n const volume24h = parseFloat(assetData.dayNtlVlm);\n const markPrice = parseFloat(assetData.markPx);\n const oraclePrice = parseFloat(assetData.oraclePx);\n const prevDayPrice = parseFloat(assetData.prevDayPx);\n\n // OI change since last fetch (NOT 24h — in-memory cache resets on restart).\n // For true 24h change, would need historical snapshots on disk.\n const prevOI = this.oiCache.get(coin) ?? openInterest;\n const oiChangePct = prevOI > 0 ? ((openInterest - prevOI) / prevOI) * 100 : 0;\n this.oiCache.set(coin, openInterest);\n\n // Process order book imbalance\n let orderBookImbalance = 0;\n if (bookResult.status === 'fulfilled' && bookResult.value) {\n orderBookImbalance = this.calculateOrderBookImbalance(bookResult.value);\n }\n\n // Process large trades bias\n let largeTradesBias = 0;\n if (tradesResult.status === 'fulfilled' && tradesResult.value) {\n largeTradesBias = this.calculateLargeTradesBias(tradesResult.value);\n }\n\n const data: HyperliquidData = {\n fundingRate,\n openInterest,\n oiChangePct,\n volume24h,\n markPrice,\n oraclePrice,\n prevDayPrice,\n orderBookImbalance,\n largeTradesBias,\n };\n\n // Cache results\n await this.writeCache(tokenId, data);\n\n return data;\n } catch (err) {\n console.error(`Hyperliquid API error for ${tokenId}: ${(err as Error).message}`);\n return null;\n }\n }\n\n /** Fetch metadata and asset contexts (funding, OI, volume, prices). */\n private async fetchMetaAndAssetCtxs(): Promise<[MetaAndAssetCtxs, AssetCtx[]] | null> {\n const response = await fetch(HYPERLIQUID_BASE, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'metaAndAssetCtxs' }),\n });\n\n if (!response.ok) return null;\n const data = await response.json() as [MetaAndAssetCtxs, AssetCtx[]];\n return data;\n }\n\n /** Fetch L2 order book for a coin. */\n private async fetchL2Book(coin: string): Promise<L2Book | null> {\n const response = await fetch(HYPERLIQUID_BASE, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'l2Book', coin }),\n });\n\n if (!response.ok) return null;\n return await response.json() as L2Book;\n }\n\n /** Fetch recent trades for a coin. */\n private async fetchRecentTrades(coin: string): Promise<RecentTrade[] | null> {\n const response = await fetch(HYPERLIQUID_BASE, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'recentTrades', coin }),\n });\n\n if (!response.ok) return null;\n return await response.json() as RecentTrade[];\n }\n\n /** Calculate order book imbalance from L2 book. */\n private calculateOrderBookImbalance(book: L2Book): number {\n const [bids, asks] = book.levels;\n\n // Sum top 10 levels for both sides\n const bidDepth = bids.slice(0, 10).reduce((sum, level) => sum + parseFloat(level.sz), 0);\n const askDepth = asks.slice(0, 10).reduce((sum, level) => sum + parseFloat(level.sz), 0);\n\n const totalDepth = bidDepth + askDepth;\n if (totalDepth === 0) return 0;\n\n return (bidDepth - askDepth) / totalDepth;\n }\n\n /** Calculate large trades bias from recent trades (>$50K in last hour). */\n private calculateLargeTradesBias(trades: RecentTrade[]): number {\n const oneHourAgo = Date.now() - 60 * 60 * 1000;\n const recentTrades = trades.filter(t => t.time > oneHourAgo);\n\n let buyVolume = 0;\n let sellVolume = 0;\n\n for (const trade of recentTrades) {\n const size = parseFloat(trade.sz);\n const price = parseFloat(trade.px);\n const notional = size * price;\n\n // Only count trades >$50K\n if (notional > 50000) {\n if (trade.side === 'B') {\n buyVolume += notional;\n } else if (trade.side === 'A') {\n sellVolume += notional;\n }\n }\n }\n\n const totalVolume = buyVolume + sellVolume;\n if (totalVolume === 0) return 0;\n\n return (buyVolume - sellVolume) / totalVolume;\n }\n\n /** Read cached Hyperliquid data. */\n private async readCache(tokenId: string): Promise<HyperliquidData | null> {\n try {\n const cacheFile = join(this.cacheDir, `hl-${tokenId}.json`);\n const raw = await readFile(cacheFile, 'utf-8');\n const cached = JSON.parse(raw) as { ts: number; data: HyperliquidData };\n\n if (Date.now() - cached.ts < this.cacheTTL) {\n return cached.data;\n }\n } catch {\n // No cache or invalid cache\n }\n return null;\n }\n\n /** Write Hyperliquid data to cache. */\n private async writeCache(tokenId: string, data: HyperliquidData): Promise<void> {\n try {\n await mkdir(this.cacheDir, { recursive: true });\n const cacheFile = join(this.cacheDir, `hl-${tokenId}.json`);\n await writeFile(cacheFile, JSON.stringify({ ts: Date.now(), data }), 'utf-8');\n } catch {\n // Cache write failure is non-fatal\n }\n }\n}","/**\n * Market regime detection module — analyzes BTC to classify market state.\n * Helps adjust strategy confidence based on current macro conditions.\n */\n\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { Candle } from \"./technical.js\";\nimport { calculateEMA, calculateBollingerBands, calculateATR } from \"./technical.js\";\n\nexport type MarketRegime = \"trending-up\" | \"trending-down\" | \"ranging\" | \"high-volatility\" | \"low-volatility\";\n\nexport interface RegimeAnalysis {\n regime: MarketRegime;\n confidence: number; // 0-1 how sure we are about the regime\n btcTrend: \"up\" | \"down\" | \"neutral\";\n volatilityLevel: \"low\" | \"normal\" | \"high\" | \"extreme\";\n details: string;\n strategyAdjustments: Record<string, number>; // multiplier per strategy name (0.0 to 1.5)\n}\n\ninterface RegimeCache {\n timestamp: number;\n analysis: RegimeAnalysis;\n}\n\ninterface BtcDominanceData {\n market_cap_percentage: {\n btc: number;\n };\n}\n\nexport class MarketRegimeDetector {\n private cacheDir: string;\n private cacheFile: string;\n\n constructor() {\n this.cacheDir = join(homedir(), '.sherwood', 'agent', 'cache');\n this.cacheFile = join(this.cacheDir, 'regime.json');\n }\n\n /**\n * Detect current market regime using BTC candles.\n * Returns cached result if less than 15 minutes old.\n */\n async detect(btcCandles: Candle[]): Promise<RegimeAnalysis> {\n // Check cache first\n try {\n const cached = await this.loadCache();\n const now = Date.now();\n const cacheAge = now - cached.timestamp;\n const CACHE_DURATION = 15 * 60 * 1000; // 15 minutes\n\n if (cacheAge < CACHE_DURATION) {\n return cached.analysis;\n }\n } catch {\n // Cache miss or invalid, continue to fresh analysis\n }\n\n const analysis = await this.analyzeBtc(btcCandles);\n\n // Save to cache\n try {\n await this.saveCache(analysis);\n } catch {\n // Non-critical, continue without caching\n }\n\n return analysis;\n }\n\n private async analyzeBtc(candles: Candle[]): Promise<RegimeAnalysis> {\n if (candles.length < 200) {\n return this.fallbackAnalysis(\"Insufficient BTC data for regime analysis\");\n }\n\n const closes = candles.map(c => c.close);\n const currentPrice = closes[closes.length - 1]!;\n\n // Calculate EMAs for trend detection\n const ema50 = calculateEMA(closes, 50);\n const ema200 = calculateEMA(closes, 200);\n const currentEma50 = this.getLastValidValue(ema50);\n const currentEma200 = this.getLastValidValue(ema200);\n\n // Calculate Bollinger Bands for volatility\n const bb = calculateBollingerBands(candles, 20, 2.0);\n const currentBbWidth = this.getLastValidValue(bb.width);\n\n // Calculate ATR for additional volatility measure\n const atr = calculateATR(candles, 14);\n const currentAtr = this.getLastValidValue(atr);\n const atrRatio = currentAtr / currentPrice;\n\n // Calculate ADX for trend strength\n const adx = this.calculateADX(candles, 14);\n const currentAdx = this.getLastValidValue(adx);\n\n // Fetch BTC dominance (async, with fallback)\n let btcDominanceTrend: \"rising\" | \"falling\" | \"neutral\" = \"neutral\";\n try {\n btcDominanceTrend = await this.getBtcDominanceTrend();\n } catch {\n // Use default if fetch fails\n }\n\n // Determine BTC trend\n let btcTrend: RegimeAnalysis[\"btcTrend\"] = \"neutral\";\n if (!isNaN(currentEma50) && !isNaN(currentEma200)) {\n if (currentPrice > currentEma50 && currentEma50 > currentEma200) {\n btcTrend = \"up\";\n } else if (currentPrice < currentEma50 && currentEma50 < currentEma200) {\n btcTrend = \"down\";\n }\n }\n\n // Determine volatility level\n let volatilityLevel: RegimeAnalysis[\"volatilityLevel\"] = \"normal\";\n if (!isNaN(currentBbWidth)) {\n if (currentBbWidth < 0.04) {\n volatilityLevel = \"low\";\n } else if (currentBbWidth > 0.20) {\n volatilityLevel = \"extreme\";\n } else if (currentBbWidth > 0.10) {\n volatilityLevel = \"high\";\n }\n }\n\n // Determine primary regime and confidence\n let regime: MarketRegime;\n let confidence: number;\n let details: string;\n\n // Volatility regimes take precedence if extreme\n if (volatilityLevel === \"extreme\") {\n regime = \"high-volatility\";\n confidence = 0.9;\n details = `Extreme volatility detected (BB width: ${currentBbWidth.toFixed(3)}, ATR: ${atrRatio.toFixed(3)})`;\n } else if (volatilityLevel === \"low\" && currentAdx < 20) {\n regime = \"low-volatility\";\n confidence = 0.8;\n details = `Low volatility detected (BB width: ${currentBbWidth.toFixed(3)}, ADX: ${currentAdx.toFixed(1)})`;\n } else {\n // Trend-based regimes\n if (currentAdx > 25 && btcTrend !== \"neutral\") {\n if (btcTrend === \"up\") {\n regime = \"trending-up\";\n confidence = Math.min(0.9, 0.6 + (currentAdx - 25) * 0.01);\n details = `Strong uptrend (ADX: ${currentAdx.toFixed(1)}, EMAs aligned bullish)`;\n } else {\n regime = \"trending-down\";\n confidence = Math.min(0.9, 0.6 + (currentAdx - 25) * 0.01);\n details = `Strong downtrend (ADX: ${currentAdx.toFixed(1)}, EMAs aligned bearish)`;\n }\n } else {\n regime = \"ranging\";\n confidence = currentAdx < 20 ? 0.7 : 0.5;\n details = `Ranging market (ADX: ${currentAdx.toFixed(1)}, no clear trend)`;\n }\n }\n\n // Add BTC dominance context to details\n if (btcDominanceTrend !== \"neutral\") {\n details += `, BTC dominance ${btcDominanceTrend}`;\n }\n\n // Generate strategy adjustments based on regime\n const strategyAdjustments = this.getStrategyAdjustments(regime);\n\n return {\n regime,\n confidence,\n btcTrend,\n volatilityLevel,\n details,\n strategyAdjustments,\n };\n }\n\n private calculateADX(candles: Candle[], period: number): number[] {\n if (candles.length < period + 1) return [];\n\n // Calculate True Range and Directional Movement\n const trueRanges: number[] = [];\n const dmPlus: number[] = [];\n const dmMinus: number[] = [];\n\n for (let i = 1; i < candles.length; i++) {\n const curr = candles[i]!;\n const prev = candles[i - 1]!;\n\n // True Range\n const tr = Math.max(\n curr.high - curr.low,\n Math.abs(curr.high - prev.close),\n Math.abs(curr.low - prev.close)\n );\n trueRanges.push(tr);\n\n // Directional Movement\n const upMove = curr.high - prev.high;\n const downMove = prev.low - curr.low;\n\n dmPlus.push(upMove > downMove && upMove > 0 ? upMove : 0);\n dmMinus.push(downMove > upMove && downMove > 0 ? downMove : 0);\n }\n\n // Smooth the values using Wilder's smoothing\n const smoothTR = this.wilderSmooth(trueRanges, period);\n const smoothDMPlus = this.wilderSmooth(dmPlus, period);\n const smoothDMMinus = this.wilderSmooth(dmMinus, period);\n\n // Calculate DI+ and DI-\n const diPlus: number[] = [];\n const diMinus: number[] = [];\n const dx: number[] = [];\n\n for (let i = 0; i < smoothTR.length; i++) {\n if (smoothTR[i] > 0) {\n const diP = (smoothDMPlus[i] / smoothTR[i]) * 100;\n const diM = (smoothDMMinus[i] / smoothTR[i]) * 100;\n diPlus.push(diP);\n diMinus.push(diM);\n\n // Calculate DX\n const diSum = diP + diM;\n if (diSum > 0) {\n dx.push((Math.abs(diP - diM) / diSum) * 100);\n } else {\n dx.push(0);\n }\n } else {\n diPlus.push(0);\n diMinus.push(0);\n dx.push(0);\n }\n }\n\n // ADX is the smoothed DX\n return this.wilderSmooth(dx, period);\n }\n\n private wilderSmooth(values: number[], period: number): number[] {\n const result: number[] = [];\n\n for (let i = 0; i < values.length; i++) {\n if (i < period - 1) {\n result.push(NaN);\n } else if (i === period - 1) {\n // Initial smoothed value is simple average\n const sum = values.slice(i - period + 1, i + 1).reduce((a, b) => a + b, 0);\n result.push(sum / period);\n } else {\n // Subsequent values use Wilder's smoothing\n const prev = result[i - 1]!;\n const current = values[i]!;\n result.push((prev * (period - 1) + current) / period);\n }\n }\n\n return result;\n }\n\n private async getBtcDominanceTrend(): Promise<\"rising\" | \"falling\" | \"neutral\"> {\n try {\n const response = await fetch(\"https://api.coingecko.com/api/v3/global\");\n if (!response.ok) throw new Error(\"Failed to fetch global data\");\n\n const data = await response.json() as BtcDominanceData;\n const currentDominance = data.market_cap_percentage.btc;\n\n // This is a simplified trend detection - in production you'd want historical data\n // For now, just use the current value as a neutral baseline\n if (currentDominance > 50) return \"rising\";\n if (currentDominance < 40) return \"falling\";\n return \"neutral\";\n } catch {\n return \"neutral\";\n }\n }\n\n private getStrategyAdjustments(regime: MarketRegime): Record<string, number> {\n const baseMultipliers: Record<MarketRegime, Record<string, number>> = {\n \"trending-up\": {\n breakoutOnChain: 1.3,\n meanReversion: 0.3,\n fundingRate: 1.0,\n dexFlow: 1.2,\n twitterSentiment: 1.0,\n sentimentContrarian: 0.7,\n tvlMomentum: 1.2,\n hyperliquidFlow: 1.2,\n },\n \"trending-down\": {\n breakoutOnChain: 1.3,\n meanReversion: 0.3,\n fundingRate: 1.2,\n dexFlow: 1.2,\n twitterSentiment: 1.0,\n sentimentContrarian: 0.8,\n tvlMomentum: 0.5,\n hyperliquidFlow: 1.3,\n },\n \"ranging\": {\n breakoutOnChain: 0.5,\n meanReversion: 1.5,\n fundingRate: 1.0,\n dexFlow: 0.8,\n twitterSentiment: 0.8,\n sentimentContrarian: 1.3,\n tvlMomentum: 1.0,\n hyperliquidFlow: 1.0,\n },\n \"high-volatility\": {\n breakoutOnChain: 1.0,\n meanReversion: 0.3,\n fundingRate: 1.0,\n dexFlow: 0.7,\n twitterSentiment: 0.7,\n sentimentContrarian: 0.7,\n tvlMomentum: 0.7,\n hyperliquidFlow: 0.7,\n },\n \"low-volatility\": {\n breakoutOnChain: 1.3,\n meanReversion: 1.2,\n fundingRate: 0.8,\n dexFlow: 0.8,\n twitterSentiment: 0.8,\n sentimentContrarian: 0.8,\n tvlMomentum: 0.8,\n hyperliquidFlow: 0.8,\n },\n };\n\n return baseMultipliers[regime];\n }\n\n private getLastValidValue(arr: number[]): number {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (!isNaN(arr[i]!)) return arr[i]!;\n }\n return NaN;\n }\n\n private fallbackAnalysis(reason: string): RegimeAnalysis {\n return {\n regime: \"ranging\",\n confidence: 0.3,\n btcTrend: \"neutral\",\n volatilityLevel: \"normal\",\n details: reason,\n strategyAdjustments: {\n breakoutOnChain: 1.0,\n meanReversion: 1.0,\n fundingRate: 1.0,\n dexFlow: 1.0,\n twitterSentiment: 1.0,\n sentimentContrarian: 1.0,\n tvlMomentum: 1.0,\n hyperliquidFlow: 1.0,\n },\n };\n }\n\n private async loadCache(): Promise<RegimeCache> {\n const data = await readFile(this.cacheFile, 'utf-8');\n return JSON.parse(data) as RegimeCache;\n }\n\n private async saveCache(analysis: RegimeAnalysis): Promise<void> {\n await mkdir(this.cacheDir, { recursive: true });\n const cache: RegimeCache = {\n timestamp: Date.now(),\n analysis,\n };\n await writeFile(this.cacheFile, JSON.stringify(cache, null, 2), 'utf-8');\n }\n}","/**\n * Correlation guard module — prevents going long on alts when BTC is bearish.\n * Uses BTC technicals to assess market structure and suppress/boost alt signals.\n */\n\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport type { Candle } from \"./technical.js\";\nimport { calculateEMA, calculateRSI, calculateMACD } from \"./technical.js\";\nimport { CoinGeckoProvider } from \"../providers/data/coingecko.js\";\n\nexport interface CorrelationCheck {\n btcBias: \"bullish\" | \"bearish\" | \"neutral\";\n btcScore: number; // -1 to +1\n shouldSuppress: boolean; // true if alt long signal should be reduced\n suppressionFactor: number; // 0.0 to 1.0 multiplier on alt signals\n reason: string;\n}\n\ninterface CorrelationCache {\n timestamp: number;\n btcStructure: BtcStructure;\n}\n\ninterface BtcStructure {\n price: number;\n ema50: number;\n ema200: number;\n rsi: number;\n macdDirection: \"bullish\" | \"bearish\" | \"neutral\";\n score: number;\n}\n\nexport class CorrelationGuard {\n private cacheDir: string;\n private cacheFile: string;\n private coingecko: CoinGeckoProvider;\n\n constructor() {\n this.cacheDir = join(homedir(), '.sherwood', 'agent', 'cache');\n this.cacheFile = join(this.cacheDir, 'btc-correlation.json');\n this.coingecko = new CoinGeckoProvider();\n }\n\n /**\n * Check correlation and return suppression factors for a given token.\n * BTC itself is never suppressed. Stablecoins are never suppressed.\n */\n async checkCorrelation(tokenId: string): Promise<CorrelationCheck> {\n // Skip correlation check for BTC and stablecoins\n if (this.shouldSkipCorrelation(tokenId)) {\n return this.neutralCheck(\"BTC or stablecoin - no correlation suppression\");\n }\n\n // Get BTC structure (cached for 10 minutes)\n const btcStructure = await this.getBtcStructure();\n\n // Determine BTC bias and score\n const { bias, score, reason } = this.assessBtcBias(btcStructure);\n\n // Calculate suppression for alt tokens\n const { shouldSuppress, suppressionFactor } = this.calculateSuppression(bias, score);\n\n return {\n btcBias: bias,\n btcScore: score,\n shouldSuppress,\n suppressionFactor,\n reason,\n };\n }\n\n private shouldSkipCorrelation(tokenId: string): boolean {\n // Skip BTC itself\n if (tokenId === \"bitcoin\") return true;\n\n // Skip stablecoins\n const stablecoins = [\n \"tether\", \"usd-coin\", \"binance-usd\", \"dai\", \"frax\",\n \"trueusd\", \"paxos-standard\", \"gemini-dollar\", \"liquity-usd\"\n ];\n\n return stablecoins.includes(tokenId);\n }\n\n private async getBtcStructure(): Promise<BtcStructure> {\n // Check cache first\n try {\n const cached = await this.loadCache();\n const now = Date.now();\n const cacheAge = now - cached.timestamp;\n const CACHE_DURATION = 10 * 60 * 1000; // 10 minutes\n\n if (cacheAge < CACHE_DURATION) {\n return cached.btcStructure;\n }\n } catch {\n // Cache miss or invalid, continue to fresh analysis\n }\n\n // Fetch fresh BTC data\n const btcStructure = await this.analyzeBtcStructure();\n\n // Save to cache\n try {\n await this.saveCache(btcStructure);\n } catch {\n // Non-critical, continue without caching\n }\n\n return btcStructure;\n }\n\n private async analyzeBtcStructure(): Promise<BtcStructure> {\n try {\n // Fetch BTC candles (30 days for EMAs)\n const ohlcData = await this.coingecko.getOHLC(\"bitcoin\", 30);\n\n if (!ohlcData || ohlcData.length < 50) {\n throw new Error(\"Insufficient BTC data\");\n }\n\n const candles: Candle[] = ohlcData.map((c: number[]) => ({\n timestamp: c[0]!,\n open: c[1]!,\n high: c[2]!,\n low: c[3]!,\n close: c[4] ?? c[3]!,\n volume: 0, // Not needed for structure assessment\n }));\n\n const closes = candles.map(c => c.close);\n const currentPrice = closes[closes.length - 1]!;\n\n // Calculate technical indicators\n const ema50Array = calculateEMA(closes, 50);\n const ema200Array = calculateEMA(closes, 200);\n const rsiArray = calculateRSI(candles, 14);\n const macd = calculateMACD(candles, 12, 26, 9);\n\n // Get latest valid values\n const ema50 = this.getLastValidValue(ema50Array);\n const ema200 = this.getLastValidValue(ema200Array);\n const rsi = this.getLastValidValue(rsiArray);\n const macdHistogram = this.getLastValidValue(macd.histogram);\n\n // Determine MACD direction\n let macdDirection: BtcStructure[\"macdDirection\"] = \"neutral\";\n if (!isNaN(macdHistogram)) {\n if (macdHistogram > 0.1) macdDirection = \"bullish\";\n else if (macdHistogram < -0.1) macdDirection = \"bearish\";\n }\n\n // Calculate composite score (-1 to +1)\n let score = 0;\n\n // EMA alignment (40% weight)\n if (!isNaN(ema50) && !isNaN(ema200)) {\n if (currentPrice > ema50 && ema50 > ema200) {\n score += 0.4; // Bullish alignment\n } else if (currentPrice < ema50 && ema50 < ema200) {\n score -= 0.4; // Bearish alignment\n }\n // Neutral if mixed\n }\n\n // RSI (30% weight)\n if (!isNaN(rsi)) {\n if (rsi < 40) {\n score += 0.3; // Oversold = potentially bullish\n } else if (rsi > 60) {\n score -= 0.3; // Overbought = potentially bearish\n }\n // Scale linearly between 40-60\n else {\n const rsiScore = -((rsi - 50) / 10) * 0.15; // Max ±0.15 in neutral range\n score += rsiScore;\n }\n }\n\n // MACD direction (30% weight)\n if (macdDirection === \"bullish\") {\n score += 0.3;\n } else if (macdDirection === \"bearish\") {\n score -= 0.3;\n }\n\n // Clamp score to [-1, 1]\n score = Math.max(-1, Math.min(1, score));\n\n return {\n price: currentPrice,\n ema50: isNaN(ema50) ? 0 : ema50,\n ema200: isNaN(ema200) ? 0 : ema200,\n rsi: isNaN(rsi) ? 50 : rsi,\n macdDirection,\n score,\n };\n\n } catch (error) {\n console.warn(`BTC structure analysis failed: ${(error as Error).message}`);\n\n // Return neutral structure on failure\n return {\n price: 0,\n ema50: 0,\n ema200: 0,\n rsi: 50,\n macdDirection: \"neutral\",\n score: 0,\n };\n }\n }\n\n private assessBtcBias(structure: BtcStructure): { bias: CorrelationCheck[\"btcBias\"], score: number, reason: string } {\n const score = structure.score;\n\n if (score < -0.3) {\n const components = [];\n if (structure.price > 0 && structure.ema50 > 0 && structure.ema200 > 0) {\n if (structure.price < structure.ema50 && structure.ema50 < structure.ema200) {\n components.push(\"below EMAs\");\n }\n }\n if (structure.rsi < 40) components.push(`RSI ${structure.rsi.toFixed(1)}`);\n if (structure.macdDirection === \"bearish\") components.push(\"MACD bearish\");\n\n return {\n bias: \"bearish\",\n score,\n reason: `BTC bearish (${score.toFixed(2)}) — ${components.join(\", \") || \"weak structure\"}`,\n };\n }\n\n if (score > 0.3) {\n const components = [];\n if (structure.price > 0 && structure.ema50 > 0 && structure.ema200 > 0) {\n if (structure.price > structure.ema50 && structure.ema50 > structure.ema200) {\n components.push(\"above EMAs\");\n }\n }\n if (structure.rsi > 60) components.push(`RSI ${structure.rsi.toFixed(1)}`);\n if (structure.macdDirection === \"bullish\") components.push(\"MACD bullish\");\n\n return {\n bias: \"bullish\",\n score,\n reason: `BTC bullish (${score.toFixed(2)}) — ${components.join(\", \") || \"strong structure\"}`,\n };\n }\n\n return {\n bias: \"neutral\",\n score,\n reason: `BTC neutral (${score.toFixed(2)}) — mixed signals`,\n };\n }\n\n private calculateSuppression(bias: CorrelationCheck[\"btcBias\"], score: number): { shouldSuppress: boolean, suppressionFactor: number } {\n if (bias === \"bearish\") {\n // Strong bearish: suppress longs heavily, boost shorts slightly\n const suppressionFactor = 1 + score; // score is negative, so this reduces the factor\n return {\n shouldSuppress: true,\n suppressionFactor: Math.max(0.1, suppressionFactor), // Min 10% of original signal\n };\n }\n\n if (bias === \"bullish\") {\n // Strong bullish: boost longs slightly, suppress shorts\n const boostFactor = 1 + score * 0.2; // Max 20% boost for longs\n return {\n shouldSuppress: false,\n suppressionFactor: Math.min(1.2, boostFactor), // Max 20% boost\n };\n }\n\n // Neutral: no suppression\n return {\n shouldSuppress: false,\n suppressionFactor: 1.0,\n };\n }\n\n private neutralCheck(reason: string): CorrelationCheck {\n return {\n btcBias: \"neutral\",\n btcScore: 0,\n shouldSuppress: false,\n suppressionFactor: 1.0,\n reason,\n };\n }\n\n private getLastValidValue(arr: number[]): number {\n for (let i = arr.length - 1; i >= 0; i--) {\n if (!isNaN(arr[i]!)) return arr[i]!;\n }\n return NaN;\n }\n\n private async loadCache(): Promise<CorrelationCache> {\n const data = await readFile(this.cacheFile, 'utf-8');\n return JSON.parse(data) as CorrelationCache;\n }\n\n private async saveCache(btcStructure: BtcStructure): Promise<void> {\n await mkdir(this.cacheDir, { recursive: true });\n const cache: CorrelationCache = {\n timestamp: Date.now(),\n btcStructure,\n };\n await writeFile(this.cacheFile, JSON.stringify(cache, null, 2), 'utf-8');\n }\n}","/**\n * Smart alert system for regime transitions and signal changes.\n * Detects meaningful state changes and generates prioritized alerts.\n */\n\nimport { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { createHash } from \"node:crypto\";\nimport type { MarketRegime } from \"./regime.js\";\nimport type { TokenAnalysis } from \"./index.js\";\n\nexport type AlertPriority = \"critical\" | \"high\" | \"medium\" | \"low\";\n\nexport interface Alert {\n id: string; // unique hash\n priority: AlertPriority;\n type: string; // e.g. \"regime-transition\", \"signal-divergence\", \"volume-anomaly\"\n title: string; // short headline\n details: string; // full explanation\n tokenId: string;\n timestamp: number;\n acknowledged: boolean;\n sent: boolean; // whether alert was sent via Telegram\n}\n\nexport interface AlertConfig {\n enableRegimeAlerts: boolean;\n enableSignalAlerts: boolean;\n enableVolumeAlerts: boolean;\n minPriority: AlertPriority;\n}\n\ninterface AlertState {\n lastRegime: MarketRegime | null;\n lastRegimeAt: number;\n lastSignals: Record<string, number>;\n alerts: Alert[];\n lastVolumeCheck: Record<string, { twitterVolume: number; hlVolume?: number; timestamp: number }>;\n}\n\nconst DEFAULT_CONFIG: AlertConfig = {\n enableRegimeAlerts: true,\n enableSignalAlerts: true,\n enableVolumeAlerts: true,\n minPriority: \"medium\",\n};\n\nexport class AlertSystem {\n private stateDir: string;\n private stateFile: string;\n private configFile: string;\n private config: AlertConfig;\n\n constructor() {\n this.stateDir = join(homedir(), '.sherwood', 'agent');\n this.stateFile = join(this.stateDir, 'alerts-state.json');\n this.configFile = join(this.stateDir, 'alerts-config.json');\n this.config = DEFAULT_CONFIG;\n }\n\n /**\n * Process analysis results and generate alerts for state changes.\n */\n async processAnalysis(analyses: TokenAnalysis[]): Promise<Alert[]> {\n const state = await this.loadState();\n const newAlerts: Alert[] = [];\n\n // Process regime transitions (using first analysis result with regime data)\n const regimeAnalysis = analyses.find(a => a.regime);\n if (regimeAnalysis?.regime && this.config.enableRegimeAlerts) {\n const regimeAlerts = this.checkRegimeTransition(state, regimeAnalysis.regime.regime);\n newAlerts.push(...regimeAlerts);\n\n state.lastRegime = regimeAnalysis.regime.regime;\n state.lastRegimeAt = Date.now();\n }\n\n // Process signal divergences for each token\n if (this.config.enableSignalAlerts) {\n for (const analysis of analyses) {\n const signalAlerts = this.checkSignalDivergence(state, analysis);\n newAlerts.push(...signalAlerts);\n\n // Update last signal for this token\n state.lastSignals[analysis.token] = analysis.decision.score;\n }\n }\n\n // Process volume anomalies if data is available\n if (this.config.enableVolumeAlerts) {\n for (const analysis of analyses) {\n const volumeAlerts = await this.checkVolumeAnomalies(state, analysis);\n newAlerts.push(...volumeAlerts);\n }\n }\n\n // Add new alerts to state and deduplicate\n for (const alert of newAlerts) {\n if (!this.isAlertDuplicate(state, alert)) {\n state.alerts.push(alert);\n }\n }\n\n // Prune old alerts (keep last 50)\n if (state.alerts.length > 50) {\n state.alerts = state.alerts.slice(-50);\n }\n\n await this.saveState(state);\n return newAlerts.filter(alert => this.shouldShowAlert(alert));\n }\n\n /**\n * Get recent alerts, optionally filtered by priority.\n */\n async getRecentAlerts(maxAge?: number, minPriority?: AlertPriority): Promise<Alert[]> {\n const state = await this.loadState();\n const now = Date.now();\n const ageLimit = maxAge ?? (24 * 60 * 60 * 1000); // Default: 24 hours\n\n return state.alerts\n .filter(alert => (now - alert.timestamp) <= ageLimit)\n .filter(alert => !minPriority || this.priorityValue(alert.priority) >= this.priorityValue(minPriority))\n .sort((a, b) => b.timestamp - a.timestamp);\n }\n\n /**\n * Clear all alerts by marking them as acknowledged.\n */\n async clearAlerts(): Promise<void> {\n const state = await this.loadState();\n for (const alert of state.alerts) {\n alert.acknowledged = true;\n }\n await this.saveState(state);\n }\n\n /**\n * Get unsent CRITICAL/HIGH alerts from last 30min and mark them as sent.\n */\n async getUrgentAlerts(): Promise<Alert[]> {\n const state = await this.loadState();\n const now = Date.now();\n const thirtyMinutes = 30 * 60 * 1000;\n\n // Find unsent critical/high alerts from last 30min\n const urgentAlerts = state.alerts.filter(alert =>\n !alert.sent &&\n !alert.acknowledged &&\n (alert.priority === \"critical\" || alert.priority === \"high\") &&\n (now - alert.timestamp) <= thirtyMinutes\n );\n\n if (urgentAlerts.length === 0) {\n return [];\n }\n\n // Mark alerts as sent\n for (const alert of urgentAlerts) {\n alert.sent = true;\n }\n\n await this.saveState(state);\n return urgentAlerts.sort((a, b) => b.timestamp - a.timestamp);\n }\n\n /**\n * Check for regime transitions and generate alerts.\n */\n private checkRegimeTransition(state: AlertState, currentRegime: MarketRegime): Alert[] {\n const alerts: Alert[] = [];\n\n if (!state.lastRegime || state.lastRegime === currentRegime) {\n return alerts; // No transition\n }\n\n const transition = `${state.lastRegime} → ${currentRegime}`;\n\n // Define transition priorities and messages\n const transitionMap: Record<string, { priority: AlertPriority; title: string; details: string }> = {\n \"ranging → trending-up\": {\n priority: \"high\",\n title: \"Market structure shifted bullish\",\n details: \"Market regime changed from ranging to trending-up. Breakout strategies now activating. Consider increasing position sizes for momentum plays.\"\n },\n \"ranging → trending-down\": {\n priority: \"high\",\n title: \"Market structure shifted bearish\",\n details: \"Market regime changed from ranging to trending-down. Risk-off mode engaged. Consider reducing exposure and defensive positioning.\"\n },\n \"trending-up → ranging\": {\n priority: \"medium\",\n title: \"Uptrend losing momentum\",\n details: \"Market regime changed from trending-up to ranging. Switching to mean reversion strategies. Momentum strategies reduced effectiveness.\"\n },\n \"trending-up → trending-down\": {\n priority: \"critical\",\n title: \"Trend reversal — bull to bear transition\",\n details: \"Major regime shift from trending-up to trending-down. Consider significant risk reduction and potential short positions.\"\n },\n \"trending-down → trending-up\": {\n priority: \"critical\",\n title: \"Trend reversal — bear to bull transition\",\n details: \"Major regime shift from trending-down to trending-up. Consider increasing long exposure and reducing hedges.\"\n },\n \"trending-up → high-volatility\": {\n priority: \"high\",\n title: \"Volatility spike during uptrend\",\n details: \"Market regime changed to high-volatility from trending-up. Reducing position sizes due to increased uncertainty.\"\n },\n \"trending-down → high-volatility\": {\n priority: \"high\",\n title: \"Volatility spike during downtrend\",\n details: \"Market regime changed to high-volatility from trending-down. Extreme caution advised - reducing position sizes.\"\n },\n \"ranging → high-volatility\": {\n priority: \"high\",\n title: \"Volatility breakout from ranging\",\n details: \"Market regime changed to high-volatility from ranging. Preparing for directional moves but reducing sizes due to uncertainty.\"\n },\n \"high-volatility → trending-up\": {\n priority: \"medium\",\n title: \"Volatility normalizing — bullish resolution\",\n details: \"Market regime stabilized from high-volatility to trending-up. Resuming normal position sizing with bullish bias.\"\n },\n \"high-volatility → trending-down\": {\n priority: \"medium\",\n title: \"Volatility normalizing — bearish resolution\",\n details: \"Market regime stabilized from high-volatility to trending-down. Resuming normal position sizing with bearish bias.\"\n },\n \"high-volatility → ranging\": {\n priority: \"medium\",\n title: \"Volatility normalizing — neutral resolution\",\n details: \"Market regime stabilized from high-volatility to ranging. Resuming normal position sizing, mean reversion strategies activated.\"\n }\n };\n\n const transitionData = transitionMap[transition];\n if (transitionData) {\n alerts.push(this.createAlert({\n type: \"regime-transition\",\n priority: transitionData.priority,\n title: transitionData.title,\n details: transitionData.details,\n tokenId: \"bitcoin\", // Regime is based on BTC\n }));\n } else {\n // Generic transition alert for unmapped combinations\n alerts.push(this.createAlert({\n type: \"regime-transition\",\n priority: \"medium\",\n title: `Market regime changed: ${transition}`,\n details: `Market regime transitioned from ${state.lastRegime} to ${currentRegime}. Adjusting strategy weights accordingly.`,\n tokenId: \"bitcoin\",\n }));\n }\n\n return alerts;\n }\n\n /**\n * Check for significant signal changes.\n */\n private checkSignalDivergence(state: AlertState, analysis: TokenAnalysis): Alert[] {\n const alerts: Alert[] = [];\n const currentScore = analysis.decision.score;\n const lastScore = state.lastSignals[analysis.token];\n\n if (lastScore === undefined) {\n return alerts; // First time seeing this token\n }\n\n const scoreChange = currentScore - lastScore;\n const absChange = Math.abs(scoreChange);\n\n // Signal flip (positive to negative or vice versa)\n if ((lastScore > 0 && currentScore < 0) || (lastScore < 0 && currentScore > 0)) {\n alerts.push(this.createAlert({\n type: \"signal-divergence\",\n priority: \"medium\",\n title: `${analysis.token.toUpperCase()} signal flipped ${lastScore > 0 ? 'negative' : 'positive'}`,\n details: `Signal changed from ${lastScore > 0 ? '+' : ''}${lastScore.toFixed(2)} to ${currentScore > 0 ? '+' : ''}${currentScore.toFixed(2)}. Consider reviewing position.`,\n tokenId: analysis.token,\n }));\n }\n // Rapid signal shift (>0.5 change in one scan)\n else if (absChange > 0.5) {\n alerts.push(this.createAlert({\n type: \"signal-divergence\",\n priority: \"high\",\n title: `Rapid signal shift for ${analysis.token.toUpperCase()}`,\n details: `Signal changed by ${scoreChange > 0 ? '+' : ''}${scoreChange.toFixed(2)} in one scan (${lastScore.toFixed(2)} → ${currentScore.toFixed(2)}). Significant momentum detected.`,\n tokenId: analysis.token,\n }));\n }\n\n return alerts;\n }\n\n /**\n * Check for volume anomalies across Twitter and Hyperliquid.\n */\n private async checkVolumeAnomalies(state: AlertState, analysis: TokenAnalysis): Promise<Alert[]> {\n const alerts: Alert[] = [];\n\n // This is a placeholder for volume anomaly detection\n // In a real implementation, you would access Twitter and Hyperliquid volume data\n // from the analysis context and compare against historical averages\n\n const lastVolumeData = state.lastVolumeCheck[analysis.token];\n const now = Date.now();\n\n // Example logic - you would replace this with actual volume data from analysis\n // if (analysis.data.twitterData?.volumeSpike && analysis.data.hyperliquidData?.volumeRatio) {\n // const twitterSpike = analysis.data.twitterData.volumeSpike;\n // const hlVolumeRatio = analysis.data.hyperliquidData.volumeRatio;\n //\n // if (twitterSpike > 5 && hlVolumeRatio > 2) {\n // alerts.push(this.createAlert({\n // type: \"volume-anomaly\",\n // priority: \"high\",\n // title: `Coordinated volume surge for ${analysis.token.toUpperCase()}`,\n // details: `Twitter volume ${twitterSpike.toFixed(1)}x spike with ${hlVolumeRatio.toFixed(1)}x Hyperliquid volume. Monitor for breakout.`,\n // tokenId: analysis.token,\n // }));\n // }\n //\n // // Update volume tracking\n // state.lastVolumeCheck[analysis.token] = {\n // twitterVolume: twitterSpike,\n // hlVolume: hlVolumeRatio,\n // timestamp: now,\n // };\n // }\n\n return alerts;\n }\n\n /**\n * Create an alert with unique ID and timestamp.\n */\n private createAlert(params: Omit<Alert, 'id' | 'timestamp' | 'acknowledged' | 'sent'>): Alert {\n const content = `${params.type}-${params.tokenId}-${params.title}`;\n const id = createHash('sha256').update(content).digest('hex').substring(0, 12);\n\n return {\n id,\n timestamp: Date.now(),\n acknowledged: false,\n sent: false,\n ...params,\n };\n }\n\n /**\n * Check if alert is duplicate within deduplication window.\n */\n private isAlertDuplicate(state: AlertState, newAlert: Alert): boolean {\n const DEDUP_WINDOW = 60 * 60 * 1000; // 1 hour\n const now = Date.now();\n\n return state.alerts.some(existing =>\n existing.type === newAlert.type &&\n existing.tokenId === newAlert.tokenId &&\n existing.title === newAlert.title &&\n (now - existing.timestamp) < DEDUP_WINDOW &&\n !existing.acknowledged\n );\n }\n\n /**\n * Determine if alert should be shown based on config.\n */\n private shouldShowAlert(alert: Alert): boolean {\n return this.priorityValue(alert.priority) >= this.priorityValue(this.config.minPriority);\n }\n\n /**\n * Convert priority to numeric value for comparison.\n */\n private priorityValue(priority: AlertPriority): number {\n const values = { low: 1, medium: 2, high: 3, critical: 4 };\n return values[priority];\n }\n\n /**\n * Load alert state from disk.\n */\n private async loadState(): Promise<AlertState> {\n try {\n const data = await readFile(this.stateFile, 'utf-8');\n return JSON.parse(data) as AlertState;\n } catch {\n return {\n lastRegime: null,\n lastRegimeAt: 0,\n lastSignals: {},\n alerts: [],\n lastVolumeCheck: {},\n };\n }\n }\n\n /**\n * Save alert state to disk.\n */\n private async saveState(state: AlertState): Promise<void> {\n try {\n await mkdir(this.stateDir, { recursive: true });\n await writeFile(this.stateFile, JSON.stringify(state, null, 2), 'utf-8');\n } catch (err) {\n console.error(`Failed to save alert state: ${(err as Error).message}`);\n }\n }\n\n /**\n * Format alerts for CLI display.\n */\n formatAlerts(alerts: Alert[], useMarkdown: boolean = false): string {\n if (alerts.length === 0) {\n return useMarkdown ? \"*No active alerts*\" : \" No active alerts\";\n }\n\n const lines: string[] = [];\n\n if (useMarkdown) {\n lines.push(\"## ALERTS\");\n } else {\n lines.push(\"ALERTS\");\n }\n\n for (const alert of alerts.slice(0, 10)) { // Show max 10\n const ageStr = this.formatAge(Date.now() - alert.timestamp);\n const icon = this.getPriorityIcon(alert.priority);\n\n if (useMarkdown) {\n lines.push(` ${icon} **${alert.priority.toUpperCase()}**: ${alert.title} (${ageStr})`);\n } else {\n lines.push(` ${icon} ${alert.priority.toUpperCase()}: ${alert.title} (${ageStr})`);\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n /**\n * Get emoji icon for alert priority.\n */\n private getPriorityIcon(priority: AlertPriority): string {\n switch (priority) {\n case \"critical\": return \"🔴\";\n case \"high\": return \"🟡\";\n case \"medium\": return \"🔵\";\n case \"low\": return \"⚫\";\n }\n }\n\n /**\n * Format time difference for display.\n */\n private formatAge(ageMs: number): string {\n const minutes = Math.floor(ageMs / (60 * 1000));\n const hours = Math.floor(minutes / 60);\n const days = Math.floor(hours / 24);\n\n if (days > 0) return `${days}d ago`;\n if (hours > 0) return `${hours}h ago`;\n if (minutes > 0) return `${minutes}m ago`;\n return \"just now\";\n }\n}","/**\n * Dynamic token selection from Hyperliquid market data.\n * Selects the most interesting tokens to analyze based on volume, funding rates, and other criteria.\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nconst HYPERLIQUID_BASE = 'https://api.hyperliquid.xyz/info';\n\nexport interface TokenSelection {\n tokens: string[]; // CoinGecko IDs for the agent to analyze\n reason: Record<string, string>; // why each token was selected\n totalMarketsScanned: number;\n timestamp: number;\n}\n\nexport interface SelectionCriteria {\n minVolume24h: number; // minimum 24h volume in USD (default: $5M)\n topByVolume: number; // take top N by volume (default: 10)\n fundingExtremes: number; // take N tokens with most extreme funding (default: 5)\n minFundingRate: number; // absolute funding rate threshold (default: 0.03%)\n}\n\ninterface MetaAndAssetCtxs {\n universe: Array<{\n name: string;\n szDecimals: number;\n }>;\n}\n\ninterface AssetCtx {\n funding: string;\n openInterest: string;\n dayNtlVlm: string;\n markPx: string;\n oraclePx: string;\n prevDayPx: string;\n}\n\ninterface MarketInfo {\n name: string;\n volume24h: number;\n funding: number;\n openInterest: number;\n markPrice: number;\n coingeckoId?: string;\n}\n\n// Comprehensive mapping from Hyperliquid coin names to CoinGecko IDs\nconst HYPERLIQUID_TO_COINGECKO: Record<string, string> = {\n BTC: 'bitcoin',\n ETH: 'ethereum',\n SOL: 'solana',\n HYPE: 'hyperliquid', // May not exist on CG, but try\n XRP: 'ripple',\n DOGE: 'dogecoin',\n AVAX: 'avalanche-2',\n LINK: 'chainlink',\n SUI: 'sui',\n NEAR: 'near',\n AAVE: 'aave',\n ARB: 'arbitrum',\n TAO: 'bittensor',\n TRUMP: 'official-trump',\n ZEC: 'zcash',\n BNB: 'binancecoin',\n OP: 'optimism',\n DOT: 'polkadot',\n ADA: 'cardano',\n ATOM: 'cosmos',\n UNI: 'uniswap',\n MKR: 'maker',\n INJ: 'injective-protocol',\n PENDLE: 'pendle',\n PEPE: 'pepe',\n ENA: 'ethena',\n TIA: 'celestia',\n SEI: 'sei-network',\n APT: 'aptos',\n FIL: 'filecoin',\n RENDER: 'render-token',\n JUP: 'jupiter-exchange-solana',\n STX: 'blockstack',\n WLD: 'worldcoin-wld',\n FET: 'fetch-ai',\n ONDO: 'ondo-finance',\n LDO: 'lido-dao',\n CRV: 'curve-dao-token',\n BLUR: 'blur',\n EIGEN: 'eigenlayer',\n POL: 'polygon-ecosystem-token',\n FARTCOIN: 'fartcoin',\n LTC: 'litecoin',\n MATIC: 'polygon-ecosystem-token', // POL is the new MATIC\n TNSR: 'tensor',\n GRASS: 'grass',\n MOVE: 'move-network',\n GOAT: 'goatseus-maximus',\n PNUT: 'peanut-the-squirrel',\n POPCAT: 'popcat',\n NEIRO: 'neiro',\n WIF: 'dogwifcoin',\n BONK: 'bonk',\n FLOKI: 'floki',\n SHIB: 'shiba-inu',\n MEW: 'cat-in-a-dogs-world',\n MEME: 'memecoin',\n AI16Z: 'ai16z',\n VIRTUAL: 'virtual-protocol',\n AIXBT: 'aixbt-by-virtuals',\n ZEREBRO: 'zerebro',\n arc: 'arc',\n HYPURR: 'hypurr',\n ELIZA: 'eliza',\n GRIFFAIN: 'griffain',\n LUNA: 'ai-analysis-token',\n DEEP: 'deep-worm',\n POLY: 'polyhedra-network',\n VANA: 'vana',\n VELODROME: 'velodrome-finance',\n ACX: 'across-protocol',\n COOKIE: 'cookie-dao',\n USUAL: 'usual',\n PENGU: 'pudgy-penguins',\n ETHFi: 'ether-fi',\n ETHFI: 'ether-fi', // Alternative spelling\n RSR: 'reserve-rights',\n CKB: 'nervos-network',\n RUNE: 'thorchain',\n MANA: 'decentraland',\n SAND: 'the-sandbox',\n ENS: 'ethereum-name-service',\n LRC: 'loopring',\n IMX: 'immutable-x',\n GALA: 'gala',\n CHZ: 'chiliz',\n BAT: 'basic-attention-token',\n ZRX: '0x',\n COMP: 'compound-governance-token',\n SUSHI: 'sushi',\n SNX: 'havven',\n DYDX: 'dydx',\n GMX: 'gmx',\n GRT: 'the-graph',\n FLOW: 'flow',\n KAVA: 'kava',\n ROSE: 'oasis-network',\n ONE: 'harmony',\n ALGO: 'algorand',\n XTZ: 'tezos',\n EGLD: 'elrond-erd-2',\n FTM: 'fantom',\n CAKE: 'pancakeswap-token',\n CVX: 'convex-finance',\n SPELL: 'spell-token',\n ALPHA: 'alpha-finance',\n BADGER: 'badger-dao',\n STKETH: 'lido-staked-ether',\n RETH: 'rocket-pool-eth',\n WSTETH: 'wrapped-steth',\n STETH: 'staked-ether',\n USDC: 'usd-coin',\n USDT: 'tether',\n DAI: 'dai',\n FRAX: 'frax',\n USDD: 'usdd',\n TUSD: 'trueusd',\n LUSD: 'liquity-usd',\n MIM: 'magic-internet-money',\n GUSD: 'gemini-dollar',\n PYUSD: 'paypal-usd',\n USDP: 'paxos-standard',\n};\n\nexport class DynamicTokenSelector {\n private cacheDir: string;\n private cacheTTL = 30 * 60 * 1000; // 30 minutes\n\n constructor() {\n this.cacheDir = join(homedir(), '.sherwood', 'agent', 'cache');\n }\n\n /** Get dynamic token selection based on Hyperliquid market data. */\n async selectTokens(criteria?: Partial<SelectionCriteria>): Promise<TokenSelection> {\n const config: SelectionCriteria = {\n minVolume24h: 5_000_000, // $5M minimum\n topByVolume: 10,\n fundingExtremes: 5,\n minFundingRate: 0.0003, // 0.03%\n ...criteria\n };\n\n // Check cache first\n const cached = await this.readCache();\n if (cached) {\n console.log(`Using cached token selection (${cached.tokens.length} tokens)`);\n return cached;\n }\n\n try {\n // Fetch all Hyperliquid markets\n const marketData = await this.fetchHyperliquidMarkets();\n if (!marketData) {\n console.warn('Failed to fetch Hyperliquid data, using default tokens');\n return this.getDefaultSelection();\n }\n\n // Apply selection algorithm\n const selection = this.applySelectionCriteria(marketData, config);\n\n // Cache the results\n await this.writeCache(selection);\n\n return selection;\n } catch (error) {\n console.error(`Token selection failed: ${(error as Error).message}`);\n return this.getDefaultSelection();\n }\n }\n\n /** Fetch all Hyperliquid market data. */\n private async fetchHyperliquidMarkets(): Promise<MarketInfo[] | null> {\n try {\n const response = await fetch(HYPERLIQUID_BASE, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'metaAndAssetCtxs' }),\n });\n\n if (!response.ok) return null;\n\n const [meta, assetCtxs] = await response.json() as [MetaAndAssetCtxs, AssetCtx[]];\n\n const markets: MarketInfo[] = [];\n\n for (let i = 0; i < meta.universe.length && i < assetCtxs.length; i++) {\n const coin = meta.universe[i]!;\n const ctx = assetCtxs[i]!;\n\n const name = coin.name;\n const volume24h = parseFloat(ctx.dayNtlVlm);\n const funding = parseFloat(ctx.funding);\n const openInterest = parseFloat(ctx.openInterest);\n const markPrice = parseFloat(ctx.markPx);\n const coingeckoId = HYPERLIQUID_TO_COINGECKO[name];\n\n markets.push({\n name,\n volume24h,\n funding,\n openInterest,\n markPrice,\n coingeckoId,\n });\n }\n\n return markets;\n } catch (error) {\n console.error(`Failed to fetch Hyperliquid markets: ${(error as Error).message}`);\n return null;\n }\n }\n\n /** Apply selection criteria to market data. */\n private applySelectionCriteria(markets: MarketInfo[], criteria: SelectionCriteria): TokenSelection {\n const selectedTokens = new Set<string>();\n const reasons: Record<string, string> = {};\n\n // Filter markets that have CoinGecko mappings and minimum volume\n const validMarkets = markets.filter(m =>\n m.coingeckoId &&\n m.volume24h >= 1_000_000 // At least $1M for any consideration\n );\n\n // 1. Always include BTC and ETH (macro indicators)\n const btc = validMarkets.find(m => m.name === 'BTC');\n const eth = validMarkets.find(m => m.name === 'ETH');\n\n if (btc?.coingeckoId) {\n selectedTokens.add(btc.coingeckoId);\n reasons[btc.coingeckoId] = 'Always included: macro indicator';\n }\n\n if (eth?.coingeckoId) {\n selectedTokens.add(eth.coingeckoId);\n reasons[eth.coingeckoId] = 'Always included: macro indicator';\n }\n\n // 2. Top N by volume (meeting minimum threshold)\n const topByVolume = validMarkets\n .filter(m => m.volume24h >= criteria.minVolume24h)\n .sort((a, b) => b.volume24h - a.volume24h)\n .slice(0, criteria.topByVolume);\n\n for (const market of topByVolume) {\n if (market.coingeckoId) {\n selectedTokens.add(market.coingeckoId);\n if (!reasons[market.coingeckoId]) {\n const volumeStr = market.volume24h >= 1_000_000_000\n ? `$${(market.volume24h / 1_000_000_000).toFixed(1)}B`\n : `$${(market.volume24h / 1_000_000).toFixed(0)}M`;\n reasons[market.coingeckoId] = `Top volume: ${volumeStr} 24h`;\n }\n }\n }\n\n // 3. Extreme funding rates\n const extremeFunding = validMarkets\n .filter(m => Math.abs(m.funding) >= criteria.minFundingRate && m.volume24h >= 1_000_000)\n .sort((a, b) => Math.abs(b.funding) - Math.abs(a.funding))\n .slice(0, criteria.fundingExtremes);\n\n for (const market of extremeFunding) {\n if (market.coingeckoId) {\n selectedTokens.add(market.coingeckoId);\n if (!reasons[market.coingeckoId] || reasons[market.coingeckoId]?.startsWith('Always')) {\n const fundingPercent = (market.funding * 100).toFixed(3);\n const direction = market.funding > 0 ? 'longs paying' : 'shorts paying';\n reasons[market.coingeckoId] = `Extreme funding: ${fundingPercent}% (${direction})`;\n }\n }\n }\n\n // Cap at 20 tokens to respect CoinGecko rate limits\n const tokens = Array.from(selectedTokens).slice(0, 20);\n\n return {\n tokens,\n reason: Object.fromEntries(\n tokens.map(token => [token, reasons[token] || 'Selected by criteria'])\n ),\n totalMarketsScanned: markets.length,\n timestamp: Date.now(),\n };\n }\n\n /** Get default token selection when Hyperliquid is unavailable. */\n private getDefaultSelection(): TokenSelection {\n const defaultTokens = ['bitcoin', 'ethereum', 'solana', 'arbitrum', 'chainlink', 'aave', 'uniswap'];\n const reasons = Object.fromEntries(\n defaultTokens.map(token => [token, 'Fallback: Hyperliquid unavailable'])\n );\n\n return {\n tokens: defaultTokens,\n reason: reasons,\n totalMarketsScanned: 0,\n timestamp: Date.now(),\n };\n }\n\n /** Read cached token selection. */\n private async readCache(): Promise<TokenSelection | null> {\n try {\n const cacheFile = join(this.cacheDir, 'token-selection.json');\n const raw = await readFile(cacheFile, 'utf-8');\n const cached = JSON.parse(raw) as TokenSelection;\n\n if (Date.now() - cached.timestamp < this.cacheTTL) {\n return cached;\n }\n } catch {\n // No cache or invalid cache\n }\n return null;\n }\n\n /** Write token selection to cache. */\n private async writeCache(selection: TokenSelection): Promise<void> {\n try {\n await mkdir(this.cacheDir, { recursive: true });\n const cacheFile = join(this.cacheDir, 'token-selection.json');\n await writeFile(cacheFile, JSON.stringify(selection, null, 2), 'utf-8');\n } catch {\n // Cache write failure is non-fatal\n }\n }\n\n /** Format token selection summary for display. */\n formatSelectionSummary(selection: TokenSelection): string {\n const lines: string[] = [];\n\n lines.push(`Dynamic Token Selection (${selection.tokens.length} tokens from ${selection.totalMarketsScanned} HL markets)`);\n lines.push('──────────────────────────────────────────');\n\n // Group tokens by reason type\n const topVolume: string[] = [];\n const fundingPlays: string[] = [];\n const always: string[] = [];\n const other: string[] = [];\n\n for (const token of selection.tokens) {\n const reason = selection.reason[token] || '';\n if (reason.includes('Top volume')) {\n topVolume.push(token.toUpperCase());\n } else if (reason.includes('Extreme funding')) {\n const match = reason.match(/(-?\\d+\\.\\d+)%/);\n const rate = match ? ` (${match[1]}%)` : '';\n fundingPlays.push(`${token.toUpperCase()}${rate}`);\n } else if (reason.includes('Always included')) {\n always.push(token.toUpperCase());\n } else {\n other.push(token.toUpperCase());\n }\n }\n\n if (topVolume.length > 0) {\n lines.push(`Top volume: ${topVolume.join(', ')}`);\n }\n if (fundingPlays.length > 0) {\n lines.push(`Funding plays: ${fundingPlays.join(', ')}`);\n }\n if (always.length > 0) {\n lines.push(`Always: ${always.join(', ')}`);\n }\n if (other.length > 0) {\n lines.push(`Other: ${other.join(', ')}`);\n }\n\n return lines.join('\\n');\n }\n}","/**\n * Autonomous agent loop — runs analysis + execution cycles on a timer.\n */\n\nimport chalk from 'chalk';\nimport { mkdir, appendFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport { TradingAgent } from './index.js';\nimport type { AgentConfig } from './index.js';\nimport { TradeExecutor } from './executor.js';\nimport type { ExecutionConfig } from './executor.js';\nimport { PortfolioTracker, resetPnlCounters } from './portfolio.js';\nimport { RiskManager, DEFAULT_RISK_CONFIG } from './risk.js';\nimport type { RiskConfig } from './risk.js';\nimport { CoinGeckoProvider } from '../providers/data/coingecko.js';\nimport { Reporter } from './reporter.js';\nimport { DynamicTokenSelector } from './token-selector.js';\n\nexport interface LoopConfig {\n agent: AgentConfig;\n execution: ExecutionConfig;\n riskConfig?: Partial<RiskConfig>;\n reportToTelegram?: boolean;\n logPath?: string;\n autoDynamicSelection?: boolean;\n}\n\nexport interface CycleResult {\n cycleNumber: number;\n timestamp: number;\n duration: number;\n tokensAnalyzed: number;\n signals: Array<{ token: string; score: number; action: string }>;\n tradesExecuted: number;\n exitsProcessed: number;\n portfolioValue: number;\n dailyPnl: number;\n errors: string[];\n}\n\nexport class AgentLoop {\n private running = false;\n private cycleCount = 0;\n private config: LoopConfig;\n private agent: TradingAgent;\n private executor: TradeExecutor;\n private portfolio: PortfolioTracker;\n private riskManager: RiskManager;\n private coingecko: CoinGeckoProvider;\n private reporter: Reporter;\n\n constructor(config: LoopConfig) {\n this.config = config;\n this.agent = new TradingAgent(config.agent);\n this.portfolio = new PortfolioTracker();\n this.riskManager = new RiskManager(config.riskConfig);\n this.executor = new TradeExecutor(config.execution, this.riskManager, this.portfolio);\n this.coingecko = new CoinGeckoProvider();\n this.reporter = new Reporter();\n }\n\n /** Start the autonomous loop */\n async start(): Promise<void> {\n this.running = true;\n\n // Ensure state directory exists\n const stateDir = join(homedir(), '.sherwood', 'agent');\n await mkdir(stateDir, { recursive: true });\n\n // Startup banner\n const cfg = this.config.agent;\n console.log('');\n console.log(chalk.bold(' ┌──────────────────────────────────────────────┐'));\n console.log(chalk.bold(' │ Sherwood Trading Agent — Loop │'));\n console.log(chalk.bold(' └──────────────────────────────────────────────┘'));\n console.log(` Mode: ${cfg.dryRun ? chalk.yellow('DRY RUN (paper trading)') : chalk.red('LIVE')}`);\n console.log(` Cycle: ${cfg.cycle}`);\n console.log(` Tokens: ${cfg.tokens.join(', ')}`);\n console.log(` Risk: max ${(this.config.riskConfig?.maxSinglePosition ?? DEFAULT_RISK_CONFIG.maxSinglePosition) * 100}% per position`);\n console.log(` Log: ${this.config.logPath ?? 'console only'}`);\n console.log(chalk.dim('\\n Press Ctrl+C to stop.\\n'));\n\n while (this.running) {\n try {\n await this.runCycle();\n } catch (err) {\n console.error(chalk.red(` Cycle failed: ${(err as Error).message}`));\n }\n\n if (!this.running) break;\n\n const ms = parseCycleInterval(this.config.agent.cycle);\n console.log(chalk.dim(` Next cycle in ${this.config.agent.cycle}. Sleeping...`));\n await this.sleepInterruptible(ms);\n }\n\n console.log(chalk.bold('\\n Agent loop stopped.\\n'));\n }\n\n /** Run a single analysis + execution cycle */\n async runCycle(): Promise<CycleResult> {\n this.cycleCount++;\n const startTime = Date.now();\n const errors: string[] = [];\n let tradesExecuted = 0;\n let exitsProcessed = 0;\n\n // 1. Load portfolio and check drawdown limits\n const state = await this.portfolio.load();\n\n // Reset PnL counters if time boundaries crossed\n const resetState = resetPnlCounters(state);\n if (resetState.dailyPnl !== state.dailyPnl || resetState.weeklyPnl !== state.weeklyPnl || resetState.monthlyPnl !== state.monthlyPnl) {\n await this.portfolio.save(resetState);\n }\n\n this.riskManager.updatePortfolio(resetState);\n const drawdown = this.riskManager.isDrawdownLimitHit();\n if (drawdown.paused) {\n console.log(chalk.red(` ⚠ Trading paused: ${drawdown.message}`));\n const result: CycleResult = {\n cycleNumber: this.cycleCount,\n timestamp: Date.now(),\n duration: Date.now() - startTime,\n tokensAnalyzed: 0,\n signals: [],\n tradesExecuted: 0,\n exitsProcessed: 0,\n portfolioValue: state.totalValue,\n dailyPnl: state.dailyPnl,\n errors: [drawdown.message],\n };\n await this.logCycle(result);\n return result;\n }\n\n // 2. Update prices for existing positions and process exits\n if (state.positions.length > 0) {\n try {\n const tokenIds = state.positions.map(p => p.tokenId);\n const priceData = await this.coingecko.getPrice(tokenIds, ['usd']);\n const currentPrices: Record<string, number> = {};\n\n for (const id of tokenIds) {\n const price = priceData?.[id]?.usd;\n if (typeof price === 'number') {\n currentPrices[id] = price;\n }\n }\n\n if (Object.keys(currentPrices).length > 0) {\n await this.portfolio.updatePrices(currentPrices);\n\n // Process exits (stop losses, take profits)\n const exits = await this.executor.processExits(currentPrices);\n exitsProcessed = exits.length;\n\n for (const exit of exits) {\n const pnlColor = exit.pnl >= 0 ? chalk.green : chalk.red;\n console.log(\n ` ${exit.reason}: ${exit.position.symbol} @ $${exit.exitPrice.toFixed(4)} ${pnlColor(`PnL: $${exit.pnl.toFixed(2)}`)}`,\n );\n }\n }\n } catch (err) {\n errors.push(`Price update failed: ${(err as Error).message}`);\n }\n }\n\n // 3. Update token list if using dynamic selection\n if (this.config.autoDynamicSelection) {\n try {\n const selector = new DynamicTokenSelector();\n const selection = await selector.selectTokens();\n\n // Update token list without recreating the agent (preserves OI cache, provider state)\n this.config.agent.tokens = selection.tokens;\n this.agent.updateTokens(selection.tokens);\n\n if (this.cycleCount % 6 === 1) { // Show selection summary every 6th cycle (~30min for 5min cycles)\n console.log(chalk.dim(` Updated tokens: ${selection.tokens.length} from ${selection.totalMarketsScanned} HL markets`));\n }\n } catch (err) {\n errors.push(`Dynamic selection failed: ${(err as Error).message}`);\n console.log(chalk.yellow(` Warning: Dynamic selection failed, using existing tokens`));\n }\n }\n\n // 4. Analyze all watchlist tokens\n console.log(chalk.dim(` Analyzing ${this.config.agent.tokens.length} tokens...`));\n const results = await this.agent.analyzeAll();\n\n // 5. Collect signals and execute trades for actionable ones\n const signals: CycleResult['signals'] = [];\n\n for (const result of results) {\n const { action, score } = result.decision;\n signals.push({ token: result.token, score, action });\n\n // Only execute on BUY/SELL signals\n if (action === 'STRONG_BUY' || action === 'BUY' || action === 'SELL' || action === 'STRONG_SELL') {\n try {\n // Get current price for the token\n const priceData = await this.coingecko.getPrice([result.token], ['usd']);\n const currentPrice = priceData?.[result.token]?.usd;\n\n if (typeof currentPrice === 'number' && currentPrice > 0) {\n const execResult = await this.executor.execute(result.decision, result.token, currentPrice);\n if (execResult.success) {\n tradesExecuted++;\n console.log(this.executor.formatExecution(execResult));\n } else if (execResult.error && !execResult.error.includes('does not trigger')) {\n errors.push(`${result.token}: ${execResult.error}`);\n }\n } else {\n errors.push(`No price data for ${result.token}`);\n }\n } catch (err) {\n errors.push(`Execution failed for ${result.token}: ${(err as Error).message}`);\n }\n }\n }\n\n // 5. Reload portfolio after trades\n const updatedState = await this.portfolio.load();\n\n // 6. Build cycle result\n const cycleResult: CycleResult = {\n cycleNumber: this.cycleCount,\n timestamp: Date.now(),\n duration: Date.now() - startTime,\n tokensAnalyzed: results.length,\n signals,\n tradesExecuted,\n exitsProcessed,\n portfolioValue: updatedState.totalValue,\n dailyPnl: updatedState.dailyPnl,\n errors,\n };\n\n // 7. Log and report\n await this.logCycle(cycleResult);\n this.reportCycle(cycleResult);\n\n return cycleResult;\n }\n\n /** Stop the loop gracefully */\n stop(): void {\n this.running = false;\n }\n\n /** Whether the loop is currently running */\n get isRunning(): boolean {\n return this.running;\n }\n\n /** Log cycle result to a JSONL file */\n private async logCycle(result: CycleResult): Promise<void> {\n const logPath = this.config.logPath ?? join(homedir(), '.sherwood', 'agent', 'cycles.jsonl');\n try {\n await mkdir(join(homedir(), '.sherwood', 'agent'), { recursive: true });\n await appendFile(logPath, JSON.stringify(result) + '\\n', 'utf-8');\n } catch (err) {\n console.error(chalk.dim(` Failed to write cycle log: ${(err as Error).message}`));\n }\n }\n\n /** Display cycle report to console */\n private reportCycle(result: CycleResult): void {\n console.log(this.reporter.formatCycleReport(result));\n }\n\n /** Sleep that can be interrupted by stop() */\n private sleepInterruptible(ms: number): Promise<void> {\n return new Promise<void>((resolve) => {\n let resolved = false;\n const done = () => {\n if (resolved) return;\n resolved = true;\n clearTimeout(timer);\n clearInterval(check);\n resolve();\n };\n const timer = setTimeout(done, ms);\n const check = setInterval(() => {\n if (!this.running) done();\n }, 1000);\n });\n }\n\n}\n\n/** Parse cycle interval string to milliseconds */\nfunction parseCycleInterval(cycle: string): number {\n const match = cycle.match(/^(\\d+)(m|h)$/);\n if (!match) return 4 * 60 * 60 * 1000; // default 4h\n\n const value = parseInt(match[1]!, 10);\n const unit = match[2];\n\n if (unit === 'm') return value * 60 * 1000;\n if (unit === 'h') return value * 60 * 60 * 1000;\n return 4 * 60 * 60 * 1000;\n}\n","/**\n * Trade execution module — dry-run paper trading + live execution placeholder.\n */\n\nimport chalk from 'chalk';\nimport type { Address, Hex } from 'viem';\nimport { createWalletClient, http, encodeFunctionData, encodeAbiParameters } from 'viem';\nimport { privateKeyToAccount } from 'viem/accounts';\nimport type { TradeDecision } from './scoring.js';\nimport type { Position } from './risk.js';\nimport { RiskManager } from './risk.js';\nimport { PortfolioTracker } from './portfolio.js';\nimport { BASE_STRATEGY_ABI } from '../lib/abis.js';\nimport { hyperevm, hyperevmTestnet } from '../lib/network.js';\n\nexport interface ExecutionConfig {\n dryRun: boolean;\n mevProtection: boolean;\n maxGasPrice?: bigint;\n chain: string;\n /** Execution mode: 'dry-run' (default) or 'hyperliquid-perp' (live on-chain) */\n mode?: 'dry-run' | 'hyperliquid-perp';\n /** Strategy clone address on HyperEVM (required for hyperliquid-perp mode) */\n strategyClone?: Address;\n /** Proposer private key (read from SHERWOOD_PROPOSER_KEY env) */\n proposerPrivateKey?: Hex;\n /** HyperCore perp asset index (default 3 = ETH) */\n assetIndex?: number;\n}\n\nexport interface OrderParams {\n tokenId: string;\n side: 'buy' | 'sell';\n amountUsd: number;\n maxSlippage: number;\n stopLoss: number;\n takeProfit: number;\n}\n\nexport class TradeExecutor {\n private config: ExecutionConfig;\n private riskManager: RiskManager;\n private portfolio: PortfolioTracker;\n\n constructor(config: ExecutionConfig, riskManager: RiskManager, portfolio: PortfolioTracker) {\n this.config = config;\n this.riskManager = riskManager;\n this.portfolio = portfolio;\n }\n\n /** Execute a trade based on a decision */\n async execute(\n decision: TradeDecision,\n tokenId: string,\n currentPrice: number,\n ): Promise<{\n success: boolean;\n position?: Position;\n error?: string;\n dryRun: boolean;\n }> {\n // Handle SELL/STRONG_SELL by closing existing long positions\n if (decision.action === 'SELL' || decision.action === 'STRONG_SELL') {\n const sellState = await this.portfolio.load();\n const existing = sellState.positions.find((p) => p.tokenId === tokenId);\n if (!existing) {\n return {\n success: false,\n error: `No open position in ${tokenId} to sell`,\n dryRun: this.config.dryRun,\n };\n }\n\n try {\n const reason = decision.action === 'STRONG_SELL' ? 'Strong sell signal' : 'Sell signal';\n if (this.config.dryRun) {\n console.error(chalk.cyan(`[DRY RUN] Paper trade: SELL ${existing.quantity.toFixed(6)} ${tokenId} @ $${currentPrice.toFixed(4)}`));\n }\n const closeResult = await this.portfolio.closePosition(tokenId, currentPrice, reason);\n return {\n success: true,\n position: { ...existing, currentPrice, pnlUsd: closeResult.pnl, pnlPercent: closeResult.pnlPercent },\n dryRun: this.config.dryRun,\n };\n } catch (err) {\n return {\n success: false,\n error: `Failed to close position: ${(err as Error).message}`,\n dryRun: this.config.dryRun,\n };\n }\n }\n\n // Only execute buys on BUY or STRONG_BUY; HOLD does nothing\n if (decision.action !== 'BUY' && decision.action !== 'STRONG_BUY') {\n return {\n success: false,\n error: `Action ${decision.action} does not trigger execution`,\n dryRun: this.config.dryRun,\n };\n }\n\n // Load portfolio to get current state\n const state = await this.portfolio.load();\n this.riskManager.updatePortfolio(state);\n\n // Calculate stop loss and take profit from current price\n const stopLossDistance = currentPrice * 0.08; // 8% default stop\n const stopLossPrice = currentPrice - stopLossDistance;\n const takeProfitPrice = currentPrice * (1 + 0.08 * 2.5); // 2.5:1 reward/risk\n\n // Size the position using risk management\n const sizing = this.riskManager.calculatePositionSize(\n currentPrice,\n stopLossPrice,\n state.totalValue,\n );\n\n if (sizing.quantity <= 0 || sizing.sizeUsd <= 0) {\n return {\n success: false,\n error: 'Position sizing returned zero — check portfolio value and stop distance',\n dryRun: this.config.dryRun,\n };\n }\n\n // Check if risk manager allows this trade\n const check = this.riskManager.canOpenPosition(tokenId, sizing.sizeUsd);\n if (!check.allowed) {\n return {\n success: false,\n error: `Risk check failed: ${check.reason}`,\n dryRun: this.config.dryRun,\n };\n }\n\n const order: OrderParams = {\n tokenId,\n side: 'buy',\n amountUsd: sizing.sizeUsd,\n maxSlippage: 0.015,\n stopLoss: stopLossPrice,\n takeProfit: takeProfitPrice,\n };\n\n if (this.config.dryRun) {\n try {\n const position = await this.executeDryRun(order, currentPrice);\n return { success: true, position, dryRun: true };\n } catch (err) {\n return {\n success: false,\n error: `Dry-run failed: ${(err as Error).message}`,\n dryRun: true,\n };\n }\n } else {\n try {\n const result = await this.executeLive(order, currentPrice);\n // If live execution succeeded, also track in portfolio\n const position = await this.portfolio.openPosition({\n tokenId,\n symbol: tokenId.toUpperCase(),\n entryPrice: result.executedPrice,\n currentPrice: result.executedPrice,\n quantity: sizing.quantity,\n entryTimestamp: Date.now(),\n stopLoss: order.stopLoss,\n takeProfit: order.takeProfit,\n strategy: decision.signals[0]?.source ?? 'agent',\n });\n return { success: true, position, dryRun: false };\n } catch (err) {\n return {\n success: false,\n error: `Live execution failed: ${(err as Error).message}`,\n dryRun: false,\n };\n }\n }\n }\n\n /** Process all pending exits (stops, take profits, time stops) */\n async processExits(\n currentPrices: Record<string, number>,\n ): Promise<Array<{ position: Position; exitPrice: number; reason: string; pnl: number }>> {\n const state = await this.portfolio.load();\n this.riskManager.updatePortfolio(state);\n\n const { toClose, reasons } = this.riskManager.checkExits(state.positions, currentPrices);\n const results: Array<{ position: Position; exitPrice: number; reason: string; pnl: number }> = [];\n\n for (const pos of toClose) {\n const exitPrice = currentPrices[pos.tokenId] ?? pos.currentPrice;\n const reason = reasons[pos.tokenId] ?? 'Unknown';\n\n try {\n const closeResult = await this.portfolio.closePosition(pos.tokenId, exitPrice, reason);\n results.push({\n position: pos,\n exitPrice,\n reason,\n pnl: closeResult.pnl,\n });\n } catch (err) {\n console.error(chalk.red(`Failed to close ${pos.symbol}: ${(err as Error).message}`));\n }\n }\n\n return results;\n }\n\n /** Dry-run execution — paper trade */\n private async executeDryRun(order: OrderParams, currentPrice: number): Promise<Position> {\n const quantity = order.amountUsd / currentPrice;\n\n console.error(chalk.cyan(`[DRY RUN] Paper trade: BUY ${quantity.toFixed(6)} ${order.tokenId} @ $${currentPrice.toFixed(4)}`));\n console.error(chalk.cyan(` Size: $${order.amountUsd.toFixed(2)} | SL: $${order.stopLoss.toFixed(4)} | TP: $${order.takeProfit.toFixed(4)}`));\n\n const position = await this.portfolio.openPosition({\n tokenId: order.tokenId,\n symbol: order.tokenId.toUpperCase(),\n entryPrice: currentPrice,\n currentPrice,\n quantity,\n entryTimestamp: Date.now(),\n stopLoss: order.stopLoss,\n takeProfit: order.takeProfit,\n strategy: 'paper',\n });\n\n return position;\n }\n\n /** Live execution — dispatches to the configured mode */\n private async executeLive(order: OrderParams, currentPrice?: number): Promise<{ txHash: string; executedPrice: number }> {\n if (this.config.mode === 'hyperliquid-perp') {\n return this.executeHyperliquidPerp(order, currentPrice);\n }\n throw new Error(\n 'Live execution requires --mode hyperliquid-perp. ' +\n 'Use --dry-run for paper trading.',\n );\n }\n\n /** Execute a trade on HyperEVM via the HyperliquidPerpStrategy contract */\n private async executeHyperliquidPerp(order: OrderParams, currentPrice?: number): Promise<{ txHash: string; executedPrice: number }> {\n if (!this.config.strategyClone) throw new Error('--strategy-clone is required for hyperliquid-perp mode');\n if (!this.config.proposerPrivateKey) throw new Error('SHERWOOD_PROPOSER_KEY env var is required for live execution');\n if (!currentPrice || currentPrice <= 0) throw new Error('currentPrice is required for live execution');\n\n const account = privateKeyToAccount(this.config.proposerPrivateKey);\n const chain = this.config.chain === 'hyperevm-testnet' ? hyperevmTestnet : hyperevm;\n const client = createWalletClient({\n account,\n chain,\n transport: http(),\n });\n\n // limitPx: slightly above market for buy IOC (1% slippage buffer)\n const limitPx = priceToUint64(currentPrice * 1.01);\n // sz: token quantity — fetch asset-specific szDecimals from Hyperliquid meta API\n const quantity = order.amountUsd / currentPrice;\n const assetIndex = this.config.assetIndex ?? 3; // default ETH\n const szDec = await getSzDecimals(assetIndex);\n const sz = sizeToUint64(quantity, szDec);\n const stopLossPx = priceToUint64(order.stopLoss);\n const stopLossSz = sz;\n\n // Encode ACTION_OPEN_LONG (action=1)\n const actionData = encodeAbiParameters(\n [{ type: 'uint8' }, { type: 'uint64' }, { type: 'uint64' }, { type: 'uint64' }, { type: 'uint64' }],\n [1, limitPx, sz, stopLossPx, stopLossSz],\n );\n\n const txData = encodeFunctionData({\n abi: BASE_STRATEGY_ABI,\n functionName: 'updateParams',\n args: [actionData],\n });\n\n const txHash = await client.sendTransaction({\n to: this.config.strategyClone,\n data: txData,\n });\n\n console.error(chalk.green(`[LIVE] Transaction sent: ${txHash}`));\n\n return {\n txHash,\n executedPrice: currentPrice,\n };\n }\n\n /** Format execution result for display */\n formatExecution(result: {\n success: boolean;\n position?: Position;\n error?: string;\n dryRun: boolean;\n }): string {\n const lines: string[] = [];\n const prefix = result.dryRun ? chalk.cyan('[DRY RUN]') : chalk.green('[LIVE]');\n\n if (result.success && result.position) {\n const p = result.position;\n lines.push('');\n lines.push(`${prefix} ${chalk.bold('Trade Executed')}`);\n lines.push(chalk.dim('─'.repeat(40)));\n lines.push(`Token: ${p.symbol}`);\n lines.push(`Entry: $${p.entryPrice.toFixed(4)}`);\n lines.push(`Quantity: ${p.quantity.toFixed(6)}`);\n lines.push(`Size: $${(p.quantity * p.entryPrice).toFixed(2)}`);\n lines.push(`Stop Loss: $${p.stopLoss.toFixed(4)}`);\n lines.push(`Take Profit: $${p.takeProfit.toFixed(4)}`);\n lines.push(`Strategy: ${p.strategy}`);\n lines.push('');\n } else {\n lines.push('');\n lines.push(`${prefix} ${chalk.red('Trade Failed')}`);\n lines.push(`Reason: ${result.error}`);\n lines.push('');\n }\n\n return lines.join('\\n');\n }\n}\n\n// ── HyperCore conversion helpers ──\n\n/** Convert a USD price (e.g. 3000.50) to HyperCore uint64 format (6-decimal fixed point). */\nfunction priceToUint64(priceUsd: number): bigint {\n return BigInt(Math.round(priceUsd * 1e6));\n}\n\n/** Convert a token quantity to HyperCore uint64 format using the asset's szDecimals.\n * HyperCore szDecimals varies per asset — MUST be fetched from the meta API. */\nfunction sizeToUint64(quantity: number, szDecimals: number): bigint {\n return BigInt(Math.round(quantity * 10 ** szDecimals));\n}\n\n/** Fetch szDecimals for an asset index from Hyperliquid's meta API.\n * Caches per session to avoid repeated calls. */\nconst szDecimalsCache = new Map<number, number>();\n\nasync function getSzDecimals(assetIndex: number): Promise<number> {\n if (szDecimalsCache.has(assetIndex)) return szDecimalsCache.get(assetIndex)!;\n\n try {\n const res = await fetch('https://api.hyperliquid.xyz/info', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'meta' }),\n });\n if (!res.ok) throw new Error(`HTTP ${res.status}`);\n const meta = await res.json() as { universe: Array<{ szDecimals: number }> };\n // Cache all assets from the response\n for (let i = 0; i < meta.universe.length; i++) {\n szDecimalsCache.set(i, meta.universe[i]!.szDecimals);\n }\n } catch (err) {\n console.error(`Failed to fetch szDecimals from Hyperliquid meta API: ${err}`);\n }\n\n const dec = szDecimalsCache.get(assetIndex);\n if (dec === undefined) {\n throw new Error(`Unknown asset index ${assetIndex} — cannot determine szDecimals. Check Hyperliquid meta API.`);\n }\n return dec;\n}\n","/**\n * Portfolio tracking with JSON file persistence.\n */\n\nimport { mkdir, readFile, writeFile, rename } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { homedir } from 'node:os';\nimport chalk from 'chalk';\nimport type { Position, PortfolioState } from './risk.js';\n\n/** Check and reset PnL counters based on time boundaries */\nexport function resetPnlCounters(state: PortfolioState): PortfolioState {\n const now = Date.now();\n const updated = { ...state };\n\n // Reset daily PnL at midnight UTC\n const todayMidnight = new Date();\n todayMidnight.setUTCHours(0, 0, 0, 0);\n const todayMs = todayMidnight.getTime();\n if (!updated.lastDailyReset || updated.lastDailyReset < todayMs) {\n updated.dailyPnl = 0;\n updated.lastDailyReset = now;\n }\n\n // Reset weekly PnL on Monday midnight UTC\n const dayOfWeek = new Date(now).getUTCDay(); // 0=Sun, 1=Mon\n const daysSinceMonday = dayOfWeek === 0 ? 6 : dayOfWeek - 1;\n const mondayMidnight = new Date();\n mondayMidnight.setUTCHours(0, 0, 0, 0);\n mondayMidnight.setUTCDate(mondayMidnight.getUTCDate() - daysSinceMonday);\n const mondayMs = mondayMidnight.getTime();\n if (!updated.lastWeeklyReset || updated.lastWeeklyReset < mondayMs) {\n updated.weeklyPnl = 0;\n updated.lastWeeklyReset = now;\n }\n\n // Reset monthly PnL on 1st of month midnight UTC\n const firstOfMonth = new Date();\n firstOfMonth.setUTCHours(0, 0, 0, 0);\n firstOfMonth.setUTCDate(1);\n const firstMs = firstOfMonth.getTime();\n if (!updated.lastMonthlyReset || updated.lastMonthlyReset < firstMs) {\n updated.monthlyPnl = 0;\n updated.lastMonthlyReset = now;\n }\n\n return updated;\n}\n\nexport interface TradeRecord {\n tokenId: string;\n symbol: string;\n side: 'long' | 'short';\n entryPrice: number;\n exitPrice: number;\n quantity: number;\n pnlUsd: number;\n pnlPercent: number;\n entryTimestamp: number;\n exitTimestamp: number;\n duration: number;\n strategy: string;\n exitReason: string;\n}\n\nconst DEFAULT_PORTFOLIO: PortfolioState = {\n totalValue: 10000,\n positions: [],\n cash: 10000,\n dailyPnl: 0,\n weeklyPnl: 0,\n monthlyPnl: 0,\n};\n\nexport class PortfolioTracker {\n private statePath: string;\n private historyPath: string;\n private state: PortfolioState;\n\n constructor() {\n const base = join(homedir(), '.sherwood', 'agent');\n this.statePath = join(base, 'portfolio.json');\n this.historyPath = join(base, 'trades.json');\n this.state = { ...DEFAULT_PORTFOLIO };\n }\n\n /** Load portfolio state from disk with validation */\n async load(): Promise<PortfolioState> {\n try {\n const data = await readFile(this.statePath, 'utf-8');\n const parsed = JSON.parse(data) as PortfolioState;\n\n // Validate critical numeric fields are finite and non-negative\n if (\n !Number.isFinite(parsed.totalValue) || parsed.totalValue < 0\n || !Number.isFinite(parsed.cash) || parsed.cash < 0\n || !Number.isFinite(parsed.dailyPnl)\n || !Number.isFinite(parsed.weeklyPnl)\n || !Number.isFinite(parsed.monthlyPnl)\n || !Array.isArray(parsed.positions)\n ) {\n console.error('Portfolio file has invalid data — resetting to defaults');\n this.state = { ...DEFAULT_PORTFOLIO };\n return this.state;\n }\n\n // Validate each position\n for (const p of parsed.positions) {\n if (\n !Number.isFinite(p.entryPrice) || p.entryPrice <= 0\n || !Number.isFinite(p.quantity) || p.quantity <= 0\n || !Number.isFinite(p.currentPrice) || p.currentPrice <= 0\n || !Number.isFinite(p.stopLoss) || p.stopLoss <= 0\n || !Number.isFinite(p.takeProfit) || p.takeProfit <= 0\n ) {\n console.error(`Invalid position data for ${p.tokenId} — resetting portfolio`);\n this.state = { ...DEFAULT_PORTFOLIO };\n return this.state;\n }\n }\n\n this.state = parsed;\n } catch {\n // File doesn't exist or is invalid — start fresh\n this.state = { ...DEFAULT_PORTFOLIO };\n }\n return this.state;\n }\n\n /** Save portfolio state to disk (atomic write to prevent corruption) */\n async save(state: PortfolioState): Promise<void> {\n this.state = state;\n await mkdir(dirname(this.statePath), { recursive: true });\n const tmpPath = this.statePath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(state, null, 2), 'utf-8');\n await rename(tmpPath, this.statePath);\n }\n\n /** Open a new position */\n async openPosition(position: Omit<Position, 'pnlPercent' | 'pnlUsd'>): Promise<Position> {\n if (position.quantity <= 0) {\n throw new Error(`Invalid position quantity: ${position.quantity}`);\n }\n if (position.entryPrice <= 0) {\n throw new Error(`Invalid entry price: ${position.entryPrice}`);\n }\n await this.load();\n\n const fullPosition: Position = {\n ...position,\n pnlPercent: 0,\n pnlUsd: 0,\n };\n\n this.state.positions.push(fullPosition);\n this.state.cash -= position.quantity * position.entryPrice;\n this.state.totalValue = this.state.cash + this.state.positions.reduce(\n (sum, p) => sum + p.quantity * p.currentPrice,\n 0,\n );\n\n await this.save(this.state);\n return fullPosition;\n }\n\n /** Close a position and record trade */\n async closePosition(\n tokenId: string,\n exitPrice: number,\n reason: string,\n ): Promise<{ pnl: number; pnlPercent: number; duration: number }> {\n await this.load();\n\n const idx = this.state.positions.findIndex((p) => p.tokenId === tokenId);\n if (idx === -1) {\n throw new Error(`No open position for ${tokenId}`);\n }\n\n const pos = this.state.positions[idx]!;\n const pnlUsd = (exitPrice - pos.entryPrice) * pos.quantity;\n const pnlPercent = (exitPrice - pos.entryPrice) / pos.entryPrice;\n const duration = Math.floor((Date.now() - pos.entryTimestamp) / 1000);\n\n // Record the trade\n const record: TradeRecord = {\n tokenId: pos.tokenId,\n symbol: pos.symbol,\n side: 'long',\n entryPrice: pos.entryPrice,\n exitPrice,\n quantity: pos.quantity,\n pnlUsd,\n pnlPercent,\n entryTimestamp: pos.entryTimestamp,\n exitTimestamp: Date.now(),\n duration,\n strategy: pos.strategy,\n exitReason: reason,\n };\n\n await this.appendTradeRecord(record);\n\n // Remove position and update cash\n this.state.positions.splice(idx, 1);\n this.state.cash += pos.quantity * exitPrice;\n this.state.dailyPnl += pnlUsd;\n this.state.weeklyPnl += pnlUsd;\n this.state.monthlyPnl += pnlUsd;\n this.state.totalValue = this.state.cash + this.state.positions.reduce(\n (sum, p) => sum + p.quantity * p.currentPrice,\n 0,\n );\n\n await this.save(this.state);\n\n return { pnl: pnlUsd, pnlPercent, duration };\n }\n\n /** Update current prices for all positions */\n async updatePrices(prices: Record<string, number>): Promise<PortfolioState> {\n await this.load();\n\n for (const pos of this.state.positions) {\n const price = prices[pos.tokenId];\n if (price !== undefined) {\n pos.currentPrice = price;\n pos.pnlUsd = (price - pos.entryPrice) * pos.quantity;\n pos.pnlPercent = (price - pos.entryPrice) / pos.entryPrice;\n }\n }\n\n this.state.totalValue = this.state.cash + this.state.positions.reduce(\n (sum, p) => sum + p.quantity * p.currentPrice,\n 0,\n );\n\n await this.save(this.state);\n return this.state;\n }\n\n /** Get trade history */\n async getHistory(days?: number): Promise<TradeRecord[]> {\n let records: TradeRecord[] = [];\n try {\n const data = await readFile(this.historyPath, 'utf-8');\n records = JSON.parse(data) as TradeRecord[];\n } catch {\n return [];\n }\n\n if (days !== undefined) {\n const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;\n records = records.filter((r) => r.exitTimestamp >= cutoff);\n }\n\n return records;\n }\n\n /** Get performance metrics */\n async getMetrics(days?: number): Promise<{\n totalTrades: number;\n winRate: number;\n avgPnlPercent: number;\n totalPnlUsd: number;\n sharpeRatio: number;\n maxDrawdown: number;\n bestTrade: TradeRecord;\n worstTrade: TradeRecord;\n }> {\n const trades = await this.getHistory(days);\n\n if (trades.length === 0) {\n const empty: TradeRecord = {\n tokenId: '', symbol: '', side: 'long', entryPrice: 0, exitPrice: 0,\n quantity: 0, pnlUsd: 0, pnlPercent: 0, entryTimestamp: 0,\n exitTimestamp: 0, duration: 0, strategy: '', exitReason: '',\n };\n return {\n totalTrades: 0, winRate: 0, avgPnlPercent: 0, totalPnlUsd: 0,\n sharpeRatio: 0, maxDrawdown: 0, bestTrade: empty, worstTrade: empty,\n };\n }\n\n const wins = trades.filter((t) => t.pnlUsd > 0);\n const pnls = trades.map((t) => t.pnlPercent);\n const totalPnlUsd = trades.reduce((s, t) => s + t.pnlUsd, 0);\n const avgPnlPercent = pnls.reduce((s, p) => s + p, 0) / pnls.length;\n\n // Sharpe ratio: annualize returns based on average holding period\n // Standard formula: (mean return - risk-free rate) / stddev of returns\n const avgHoldingDays = trades.length > 0\n ? trades.reduce((sum, t) => sum + t.duration, 0) / trades.length / (24 * 60 * 60)\n : 1;\n const tradesPerYear = Math.max(252 / Math.max(avgHoldingDays, 1), 1);\n\n const riskFreePerTrade = 0.05 / tradesPerYear; // Risk-free rate per trade\n const mean = avgPnlPercent;\n const excessMean = mean - riskFreePerTrade;\n const variance = pnls.length > 1\n ? pnls.reduce((s, p) => s + (p - mean) ** 2, 0) / (pnls.length - 1)\n : 0;\n const stdDev = Math.sqrt(variance);\n const sharpeRatio = stdDev > 0 ? (excessMean / stdDev) * Math.sqrt(tradesPerYear) : 0;\n\n // Max drawdown from cumulative equity curve (peak-to-trough)\n // Start with a reasonable initial portfolio value\n const initialValue = 10000; // Start with default $10k portfolio\n let equityPeak = initialValue;\n let equity = initialValue;\n let maxDrawdown = 0;\n\n for (const t of trades) {\n equity += t.pnlUsd;\n if (equity > equityPeak) {\n equityPeak = equity;\n }\n if (equityPeak > 0 && equity < equityPeak) {\n const drawdown = (equityPeak - equity) / equityPeak;\n if (drawdown > maxDrawdown) {\n maxDrawdown = drawdown;\n }\n }\n }\n\n const sorted = [...trades].sort((a, b) => a.pnlUsd - b.pnlUsd);\n const worstTrade = sorted[0]!;\n const bestTrade = sorted[sorted.length - 1]!;\n\n return {\n totalTrades: trades.length,\n winRate: wins.length / trades.length,\n avgPnlPercent,\n totalPnlUsd,\n sharpeRatio,\n maxDrawdown,\n bestTrade,\n worstTrade,\n };\n }\n\n /** Format portfolio summary for display */\n formatSummary(): string {\n const s = this.state;\n const lines: string[] = [];\n\n lines.push('');\n lines.push(chalk.bold(' Portfolio Summary'));\n lines.push(chalk.dim(' ' + '─'.repeat(50)));\n lines.push(` Total Value: $${s.totalValue.toFixed(2)}`);\n lines.push(` Cash: $${s.cash.toFixed(2)}`);\n lines.push(` Positions: ${s.positions.length}`);\n lines.push('');\n\n if (s.positions.length > 0) {\n lines.push(chalk.bold(' Open Positions:'));\n for (const p of s.positions) {\n const pnlColor = p.pnlUsd >= 0 ? chalk.green : chalk.red;\n const pnlStr = pnlColor(\n `${p.pnlUsd >= 0 ? '+' : ''}$${p.pnlUsd.toFixed(2)} (${(p.pnlPercent * 100).toFixed(1)}%)`,\n );\n lines.push(\n ` ${p.symbol.padEnd(10)} ${p.quantity.toFixed(4)} @ $${p.entryPrice.toFixed(4)} PnL: ${pnlStr} [${p.strategy}]`,\n );\n }\n lines.push('');\n }\n\n const dailyColor = s.dailyPnl >= 0 ? chalk.green : chalk.red;\n lines.push(` Daily PnL: ${dailyColor((s.dailyPnl >= 0 ? '+' : '') + '$' + s.dailyPnl.toFixed(2))}`);\n lines.push(` Weekly PnL: ${s.weeklyPnl >= 0 ? '+' : ''}$${s.weeklyPnl.toFixed(2)}`);\n lines.push(` Monthly PnL: ${s.monthlyPnl >= 0 ? '+' : ''}$${s.monthlyPnl.toFixed(2)}`);\n lines.push('');\n\n return lines.join('\\n');\n }\n\n /** Append a trade record to history file */\n private async appendTradeRecord(record: TradeRecord): Promise<void> {\n let records: TradeRecord[] = [];\n try {\n const data = await readFile(this.historyPath, 'utf-8');\n records = JSON.parse(data) as TradeRecord[];\n } catch {\n // Start fresh\n }\n\n records.push(record);\n await mkdir(dirname(this.historyPath), { recursive: true });\n const tmpPath = this.historyPath + '.tmp';\n await writeFile(tmpPath, JSON.stringify(records, null, 2), 'utf-8');\n await rename(tmpPath, this.historyPath);\n }\n}\n","/**\n * Risk management module — position sizing, drawdown limits, stop-loss management.\n */\n\nimport chalk from 'chalk';\n\nexport interface PortfolioState {\n totalValue: number;\n positions: Position[];\n cash: number;\n dailyPnl: number;\n weeklyPnl: number;\n monthlyPnl: number;\n lastDailyReset?: number;\n lastWeeklyReset?: number;\n lastMonthlyReset?: number;\n}\n\nexport interface Position {\n tokenId: string;\n symbol: string;\n entryPrice: number;\n currentPrice: number;\n quantity: number;\n entryTimestamp: number;\n stopLoss: number;\n takeProfit: number;\n trailingStop?: number;\n strategy: string;\n pnlPercent: number;\n pnlUsd: number;\n}\n\nexport interface RiskConfig {\n maxPortfolioRisk: number;\n maxSinglePosition: number;\n maxCorrelatedExposure: number;\n maxConcurrentTrades: number;\n hardStopPercent: number;\n trailingStopAtr: number;\n dailyLossLimit: number;\n weeklyLossLimit: number;\n monthlyLossLimit: number;\n maxSlippage: Record<string, number>;\n riskPerTrade: number;\n}\n\nexport const DEFAULT_RISK_CONFIG: RiskConfig = {\n maxPortfolioRisk: 0.15,\n maxSinglePosition: 0.10,\n maxCorrelatedExposure: 0.20,\n maxConcurrentTrades: 8,\n hardStopPercent: 0.12,\n trailingStopAtr: 1.5,\n dailyLossLimit: 0.05,\n weeklyLossLimit: 0.10,\n monthlyLossLimit: 0.15,\n maxSlippage: { large: 0.005, mid: 0.015, small: 0.03 },\n riskPerTrade: 0.02,\n};\n\nconst EMPTY_PORTFOLIO: PortfolioState = {\n totalValue: 0,\n positions: [],\n cash: 0,\n dailyPnl: 0,\n weeklyPnl: 0,\n monthlyPnl: 0,\n};\n\nexport class RiskManager {\n private config: RiskConfig;\n private portfolio: PortfolioState;\n\n constructor(config?: Partial<RiskConfig>) {\n this.config = { ...DEFAULT_RISK_CONFIG, ...config };\n this.portfolio = { ...EMPTY_PORTFOLIO };\n }\n\n /** Check if we can open a new position */\n canOpenPosition(token: string, sizeUsd: number): { allowed: boolean; reason?: string } {\n // Check concurrent trades limit\n if (this.portfolio.positions.length >= this.config.maxConcurrentTrades) {\n return { allowed: false, reason: `Max concurrent trades (${this.config.maxConcurrentTrades}) reached` };\n }\n\n // Check single position size limit\n const portfolioValue = this.portfolio.totalValue || this.portfolio.cash;\n if (portfolioValue > 0) {\n const positionPct = sizeUsd / portfolioValue;\n if (positionPct > this.config.maxSinglePosition) {\n return {\n allowed: false,\n reason: `Position size ${(positionPct * 100).toFixed(1)}% exceeds max ${(this.config.maxSinglePosition * 100).toFixed(0)}% per trade`,\n };\n }\n }\n\n // Check total portfolio risk by evaluating potential aggregate loss\n if (portfolioValue > 0) {\n const currentRiskExposure = this.portfolio.positions.reduce(\n (sum, p) => {\n // Estimate max loss per position using stop loss distance\n const maxLossPerPosition = Math.abs(p.entryPrice - p.stopLoss) * p.quantity;\n return sum + maxLossPerPosition;\n },\n 0,\n );\n\n // Estimate new position risk (assuming 8% stop loss)\n const newPositionRisk = sizeUsd * 0.08;\n const totalRiskExposure = currentRiskExposure + newPositionRisk;\n\n if (totalRiskExposure / portfolioValue > this.config.maxPortfolioRisk) {\n return {\n allowed: false,\n reason: `Total portfolio risk ${(totalRiskExposure / portfolioValue * 100).toFixed(1)}% would exceed max ${(this.config.maxPortfolioRisk * 100).toFixed(0)}%`,\n };\n }\n }\n\n // Check if we already have a position in this token\n const existing = this.portfolio.positions.find((p) => p.tokenId === token);\n if (existing) {\n return { allowed: false, reason: `Already have an open position in ${token}` };\n }\n\n // Check cash availability\n if (sizeUsd > this.portfolio.cash) {\n return { allowed: false, reason: `Insufficient cash: need $${sizeUsd.toFixed(2)}, have $${this.portfolio.cash.toFixed(2)}` };\n }\n\n // Check drawdown limits\n const drawdown = this.isDrawdownLimitHit();\n if (drawdown.paused) {\n return { allowed: false, reason: drawdown.message };\n }\n\n // Check correlated exposure by token category\n const TOKEN_CATEGORIES: Record<string, string> = {\n bitcoin: 'L1', ethereum: 'L1', solana: 'L1', avalanche: 'L1', cardano: 'L1',\n polkadot: 'L1', near: 'L1', cosmos: 'L1', sui: 'L1', aptos: 'L1',\n uniswap: 'DeFi', aave: 'DeFi', maker: 'DeFi', compound: 'DeFi', curve: 'DeFi',\n lido: 'DeFi', sushi: 'DeFi', pancakeswap: 'DeFi', jupiter: 'DeFi',\n arbitrum: 'L2', optimism: 'L2', polygon: 'L2', 'starknet': 'L2', base: 'L2',\n 'zksync': 'L2', mantle: 'L2',\n };\n\n const tokenCategory = TOKEN_CATEGORIES[token];\n if (tokenCategory && portfolioValue > 0) {\n const correlatedExposure = this.portfolio.positions\n .filter((p) => TOKEN_CATEGORIES[p.tokenId] === tokenCategory)\n .reduce((sum, p) => sum + p.quantity * p.currentPrice, 0);\n const newExposure = (correlatedExposure + sizeUsd) / portfolioValue;\n if (newExposure > this.config.maxCorrelatedExposure) {\n return {\n allowed: false,\n reason: `Correlated exposure for ${tokenCategory} would be ${(newExposure * 100).toFixed(1)}% (limit: ${(this.config.maxCorrelatedExposure * 100).toFixed(0)}%)`,\n };\n }\n }\n\n return { allowed: true };\n }\n\n /** Calculate position size using classic risk-based formula */\n calculatePositionSize(\n entryPrice: number,\n stopLossPrice: number,\n portfolioValue: number,\n maxRiskPercent?: number,\n ): { quantity: number; sizeUsd: number; riskUsd: number } {\n // Guard against invalid inputs\n if (entryPrice <= 0 || portfolioValue <= 0) {\n return { quantity: 0, sizeUsd: 0, riskUsd: 0 };\n }\n\n const riskPct = maxRiskPercent ?? this.config.riskPerTrade;\n const riskUsd = portfolioValue * riskPct;\n const riskPerUnit = Math.abs(entryPrice - stopLossPrice);\n\n if (riskPerUnit <= 0) {\n return { quantity: 0, sizeUsd: 0, riskUsd: 0 };\n }\n\n // positionSize = (portfolioValue * maxRiskPercent) / (entryPrice - stopLossPrice)\n const quantity = riskUsd / riskPerUnit;\n const sizeUsd = quantity * entryPrice;\n\n // Cap at max single position size\n const maxSizeUsd = portfolioValue * this.config.maxSinglePosition;\n if (sizeUsd > maxSizeUsd) {\n const cappedQuantity = maxSizeUsd / entryPrice;\n return {\n quantity: cappedQuantity,\n sizeUsd: maxSizeUsd,\n riskUsd: cappedQuantity * riskPerUnit,\n };\n }\n\n return { quantity, sizeUsd, riskUsd };\n }\n\n /** Check drawdown limits — returns true if trading should be paused */\n isDrawdownLimitHit(): { paused: boolean; level: 'daily' | 'weekly' | 'monthly' | null; message: string } {\n const portfolioValue = this.portfolio.totalValue || this.portfolio.cash;\n if (portfolioValue <= 0) {\n return { paused: false, level: null, message: 'No portfolio value set' };\n }\n\n const dailyPct = Math.abs(this.portfolio.dailyPnl) / portfolioValue;\n const weeklyPct = Math.abs(this.portfolio.weeklyPnl) / portfolioValue;\n const monthlyPct = Math.abs(this.portfolio.monthlyPnl) / portfolioValue;\n\n if (this.portfolio.dailyPnl < 0 && dailyPct >= this.config.dailyLossLimit) {\n return {\n paused: true,\n level: 'daily',\n message: `Daily loss limit hit: ${(dailyPct * 100).toFixed(1)}% (limit: ${(this.config.dailyLossLimit * 100).toFixed(0)}%)`,\n };\n }\n\n if (this.portfolio.weeklyPnl < 0 && weeklyPct >= this.config.weeklyLossLimit) {\n return {\n paused: true,\n level: 'weekly',\n message: `Weekly loss limit hit: ${(weeklyPct * 100).toFixed(1)}% (limit: ${(this.config.weeklyLossLimit * 100).toFixed(0)}%)`,\n };\n }\n\n if (this.portfolio.monthlyPnl < 0 && monthlyPct >= this.config.monthlyLossLimit) {\n return {\n paused: true,\n level: 'monthly',\n message: `Monthly loss limit hit: ${(monthlyPct * 100).toFixed(1)}% (limit: ${(this.config.monthlyLossLimit * 100).toFixed(0)}%)`,\n };\n }\n\n return { paused: false, level: null, message: 'Within limits' };\n }\n\n /** Update trailing stop losses using ATR values */\n updateStopLosses(positions: Position[], atrValues: Record<string, number>): Position[] {\n return positions.map((pos) => {\n const atr = atrValues[pos.tokenId];\n if (atr === undefined || atr <= 0) return pos;\n\n const trailingDistance = atr * this.config.trailingStopAtr;\n const newTrailingStop = pos.currentPrice - trailingDistance;\n\n // Only move trailing stop up, never down\n const currentTrailing = pos.trailingStop ?? pos.stopLoss;\n if (newTrailingStop > currentTrailing) {\n return {\n ...pos,\n trailingStop: newTrailingStop,\n // Also update hard stop if trailing is higher\n stopLoss: Math.max(pos.stopLoss, newTrailingStop),\n };\n }\n\n return pos;\n });\n }\n\n /** Check if any positions should be closed */\n checkExits(\n positions: Position[],\n currentPrices: Record<string, number>,\n ): { toClose: Position[]; reasons: Record<string, string> } {\n const toClose: Position[] = [];\n const reasons: Record<string, string> = {};\n\n for (const pos of positions) {\n const price = currentPrices[pos.tokenId];\n if (price === undefined) continue;\n\n // Update current price for evaluation\n const updatedPos = { ...pos, currentPrice: price };\n const pnlPercent = (price - pos.entryPrice) / pos.entryPrice;\n\n // Hard stop loss check\n if (pnlPercent <= -this.config.hardStopPercent) {\n toClose.push(updatedPos);\n reasons[pos.tokenId] = `Hard stop hit: ${(pnlPercent * 100).toFixed(1)}% loss (limit: -${(this.config.hardStopPercent * 100).toFixed(0)}%)`;\n continue;\n }\n\n // Stop loss check\n if (price <= pos.stopLoss) {\n toClose.push(updatedPos);\n reasons[pos.tokenId] = `Stop loss hit at $${pos.stopLoss.toFixed(4)} (price: $${price.toFixed(4)})`;\n continue;\n }\n\n // Trailing stop check\n if (pos.trailingStop !== undefined && price <= pos.trailingStop) {\n toClose.push(updatedPos);\n reasons[pos.tokenId] = `Trailing stop hit at $${pos.trailingStop.toFixed(4)} (price: $${price.toFixed(4)})`;\n continue;\n }\n\n // Take profit check\n if (price >= pos.takeProfit) {\n toClose.push(updatedPos);\n reasons[pos.tokenId] = `Take profit hit at $${pos.takeProfit.toFixed(4)} (price: $${price.toFixed(4)})`;\n continue;\n }\n\n // Time-based exit: positions open > 7 days with < 2% profit\n const holdingDays = (Date.now() - pos.entryTimestamp) / (1000 * 60 * 60 * 24);\n if (holdingDays > 7 && pnlPercent < 0.02 && pnlPercent > -0.02) {\n toClose.push(updatedPos);\n reasons[pos.tokenId] = `Time stop: held ${holdingDays.toFixed(0)} days with only ${(pnlPercent * 100).toFixed(1)}% PnL`;\n continue;\n }\n }\n\n return { toClose, reasons };\n }\n\n /** Update portfolio state */\n updatePortfolio(portfolio: Partial<PortfolioState>): void {\n this.portfolio = { ...this.portfolio, ...portfolio };\n }\n\n /** Get current risk exposure summary */\n getRiskSummary(): string {\n const lines: string[] = [];\n const pv = this.portfolio.totalValue || this.portfolio.cash;\n\n lines.push(chalk.bold('Risk Summary'));\n lines.push(chalk.dim('─'.repeat(40)));\n lines.push(`Portfolio Value: $${pv.toFixed(2)}`);\n lines.push(`Cash: $${this.portfolio.cash.toFixed(2)}`);\n lines.push(`Open Positions: ${this.portfolio.positions.length}/${this.config.maxConcurrentTrades}`);\n\n const totalExposure = this.portfolio.positions.reduce(\n (sum, p) => sum + p.quantity * p.currentPrice,\n 0,\n );\n const exposurePct = pv > 0 ? (totalExposure / pv) * 100 : 0;\n lines.push(`Total Exposure: $${totalExposure.toFixed(2)} (${exposurePct.toFixed(1)}%)`);\n\n const totalUnrealizedPnl = this.portfolio.positions.reduce((sum, p) => sum + p.pnlUsd, 0);\n const pnlColor = totalUnrealizedPnl >= 0 ? chalk.green : chalk.red;\n lines.push(`Unrealized PnL: ${pnlColor('$' + totalUnrealizedPnl.toFixed(2))}`);\n\n lines.push(chalk.dim('─'.repeat(40)));\n lines.push(`Daily PnL: ${this.portfolio.dailyPnl >= 0 ? '+' : ''}$${this.portfolio.dailyPnl.toFixed(2)}`);\n lines.push(`Weekly PnL: ${this.portfolio.weeklyPnl >= 0 ? '+' : ''}$${this.portfolio.weeklyPnl.toFixed(2)}`);\n lines.push(`Monthly PnL: ${this.portfolio.monthlyPnl >= 0 ? '+' : ''}$${this.portfolio.monthlyPnl.toFixed(2)}`);\n\n const drawdown = this.isDrawdownLimitHit();\n if (drawdown.paused) {\n lines.push(chalk.red(`TRADING PAUSED: ${drawdown.message}`));\n }\n\n return lines.join('\\n');\n }\n}\n","/**\n * Reporting module — formats cycle results, portfolio summaries, trade alerts, and metrics.\n */\n\nimport chalk from 'chalk';\nimport type { CycleResult } from './loop.js';\nimport type { PortfolioState, Position } from './risk.js';\nimport type { TradeRecord } from './portfolio.js';\n\nexport class Reporter {\n /** Format a cycle result as a nicely-formatted console report */\n formatCycleReport(result: CycleResult): string {\n const lines: string[] = [];\n const ts = new Date(result.timestamp).toLocaleTimeString();\n\n lines.push('');\n lines.push(chalk.bold(` ┌─ Cycle #${result.cycleNumber} ─ ${ts} ─────────────────────────────┐`));\n lines.push(` │ Duration: ${result.duration}ms | Tokens analyzed: ${result.tokensAnalyzed}`);\n lines.push(` │ Trades executed: ${result.tradesExecuted} | Exits processed: ${result.exitsProcessed}`);\n lines.push(chalk.dim(' ├──────────────────────────────────────────────────┤'));\n\n // Signals\n if (result.signals.length > 0) {\n lines.push(chalk.bold(' │ Signals:'));\n for (const sig of result.signals) {\n const color = sig.action.includes('BUY')\n ? chalk.green\n : sig.action.includes('SELL')\n ? chalk.red\n : chalk.yellow;\n const scoreStr = sig.score >= 0 ? `+${sig.score.toFixed(3)}` : sig.score.toFixed(3);\n lines.push(` │ ${sig.token.padEnd(14)} ${color(sig.action.padEnd(12))} ${scoreStr}`);\n }\n } else {\n lines.push(' │ No actionable signals this cycle.');\n }\n\n lines.push(chalk.dim(' ├──────────────────────────────────────────────────┤'));\n\n // Portfolio\n const pvColor = result.dailyPnl >= 0 ? chalk.green : chalk.red;\n const pnlStr = result.dailyPnl >= 0\n ? `+$${result.dailyPnl.toFixed(2)}`\n : `-$${Math.abs(result.dailyPnl).toFixed(2)}`;\n lines.push(` │ Portfolio: $${result.portfolioValue.toFixed(2)} Daily PnL: ${pvColor(pnlStr)}`);\n\n // Errors\n if (result.errors.length > 0) {\n lines.push(chalk.dim(' ├──────────────────────────────────────────────────┤'));\n lines.push(chalk.red(` │ Errors (${result.errors.length}):`));\n for (const err of result.errors.slice(0, 3)) {\n lines.push(chalk.red(` │ ${err.slice(0, 60)}`));\n }\n }\n\n lines.push(chalk.bold(' └──────────────────────────────────────────────────┘'));\n lines.push('');\n\n return lines.join('\\n');\n }\n\n /** Format portfolio state as a detailed summary */\n formatPortfolioReport(state: PortfolioState): string {\n const lines: string[] = [];\n\n lines.push('');\n lines.push(chalk.bold(' Portfolio Summary'));\n lines.push(chalk.dim(' ' + '═'.repeat(60)));\n lines.push(` Total Value: $${state.totalValue.toFixed(2)}`);\n lines.push(` Cash: $${state.cash.toFixed(2)}`);\n lines.push(` Positions: ${state.positions.length}`);\n lines.push('');\n\n if (state.positions.length > 0) {\n lines.push(chalk.bold(' Open Positions:'));\n lines.push(chalk.dim(` ${'Symbol'.padEnd(10)} ${'Qty'.padEnd(12)} ${'Entry'.padEnd(12)} ${'Current'.padEnd(12)} ${'PnL %'.padEnd(10)} PnL $`));\n lines.push(chalk.dim(' ' + '─'.repeat(68)));\n\n for (const p of state.positions) {\n const pnlColor = p.pnlUsd >= 0 ? chalk.green : chalk.red;\n const pctStr = `${(p.pnlPercent * 100).toFixed(1)}%`;\n const usdStr = `${p.pnlUsd >= 0 ? '+' : ''}$${p.pnlUsd.toFixed(2)}`;\n lines.push(\n ` ${p.symbol.padEnd(10)} ${p.quantity.toFixed(4).padEnd(12)} $${p.entryPrice.toFixed(2).padEnd(11)} $${p.currentPrice.toFixed(2).padEnd(11)} ${pnlColor(pctStr.padEnd(10))} ${pnlColor(usdStr)}`,\n );\n }\n lines.push('');\n }\n\n const dailyColor = state.dailyPnl >= 0 ? chalk.green : chalk.red;\n const weeklyColor = state.weeklyPnl >= 0 ? chalk.green : chalk.red;\n const monthlyColor = state.monthlyPnl >= 0 ? chalk.green : chalk.red;\n\n lines.push(` Daily PnL: ${dailyColor((state.dailyPnl >= 0 ? '+' : '') + '$' + state.dailyPnl.toFixed(2))}`);\n lines.push(` Weekly PnL: ${weeklyColor((state.weeklyPnl >= 0 ? '+' : '') + '$' + state.weeklyPnl.toFixed(2))}`);\n lines.push(` Monthly PnL: ${monthlyColor((state.monthlyPnl >= 0 ? '+' : '') + '$' + state.monthlyPnl.toFixed(2))}`);\n lines.push('');\n\n return lines.join('\\n');\n }\n\n /** Format a trade execution alert */\n formatTradeAlert(trade: {\n token: string;\n side: string;\n price: number;\n amount: number;\n strategy: string;\n }): string {\n const emoji = trade.side === 'buy' ? '🟢' : '🔴';\n const sideStr = trade.side.toUpperCase();\n const lines: string[] = [];\n\n lines.push(`${emoji} ${sideStr} ${trade.token.toUpperCase()}`);\n lines.push(` Price: $${trade.price.toFixed(4)}`);\n lines.push(` Amount: $${trade.amount.toFixed(2)}`);\n lines.push(` Strategy: ${trade.strategy}`);\n lines.push(` Time: ${new Date().toISOString()}`);\n\n return lines.join('\\n');\n }\n\n /** Format performance metrics */\n formatMetrics(metrics: {\n totalTrades: number;\n winRate: number;\n avgPnlPercent: number;\n totalPnlUsd: number;\n sharpeRatio: number;\n maxDrawdown: number;\n bestTrade: TradeRecord;\n worstTrade: TradeRecord;\n }): string {\n const lines: string[] = [];\n\n lines.push('');\n lines.push(chalk.bold(' Performance Metrics'));\n lines.push(chalk.dim(' ' + '═'.repeat(50)));\n\n lines.push(` Total Trades: ${metrics.totalTrades}`);\n\n // Win rate with bar\n const winPct = (metrics.winRate * 100).toFixed(1);\n const winBarLen = Math.round(metrics.winRate * 20);\n const winBar = chalk.green('█'.repeat(winBarLen)) + chalk.dim('░'.repeat(20 - winBarLen));\n const winColor = metrics.winRate >= 0.5 ? chalk.green : chalk.red;\n lines.push(` Win Rate: ${winBar} ${winColor(winPct + '%')}`);\n\n // Avg PnL\n const avgColor = metrics.avgPnlPercent >= 0 ? chalk.green : chalk.red;\n lines.push(` Avg PnL: ${avgColor((metrics.avgPnlPercent * 100).toFixed(2) + '%')}`);\n\n // Total PnL\n const totalColor = metrics.totalPnlUsd >= 0 ? chalk.green : chalk.red;\n lines.push(` Total PnL: ${totalColor('$' + metrics.totalPnlUsd.toFixed(2))}`);\n\n // Sharpe\n const sharpeColor = metrics.sharpeRatio >= 1 ? chalk.green : metrics.sharpeRatio >= 0 ? chalk.yellow : chalk.red;\n lines.push(` Sharpe Ratio: ${sharpeColor(metrics.sharpeRatio.toFixed(2))}`);\n\n // Max Drawdown\n const ddBar = chalk.red('█'.repeat(Math.round(Math.min(metrics.maxDrawdown, 1) * 20))) +\n chalk.dim('░'.repeat(20 - Math.round(Math.min(metrics.maxDrawdown, 1) * 20)));\n lines.push(` Max Drawdown: ${ddBar} ${chalk.red((metrics.maxDrawdown * 100).toFixed(1) + '%')}`);\n\n lines.push('');\n\n // Best/worst trade\n if (metrics.bestTrade?.tokenId) {\n const best = metrics.bestTrade;\n lines.push(chalk.green(` Best Trade: ${best.symbol || best.tokenId} ${best.pnlUsd >= 0 ? '+' : ''}$${best.pnlUsd.toFixed(2)} (${(best.pnlPercent * 100).toFixed(1)}%)`));\n }\n if (metrics.worstTrade?.tokenId) {\n const worst = metrics.worstTrade;\n lines.push(chalk.red(` Worst Trade: ${worst.symbol || worst.tokenId} ${worst.pnlUsd >= 0 ? '+' : ''}$${worst.pnlUsd.toFixed(2)} (${(worst.pnlPercent * 100).toFixed(1)}%)`));\n }\n\n lines.push('');\n\n return lines.join('\\n');\n }\n}\n","/**\n * Simple backtesting framework — replays historical data through strategies.\n */\n\nimport chalk from 'chalk';\nimport { CoinGeckoProvider } from '../providers/data/coingecko.js';\nimport { SentimentProvider } from '../providers/data/sentiment.js';\nimport { getLatestSignals } from './technical.js';\nimport type { Candle } from './technical.js';\nimport { runStrategies } from './strategies/index.js';\nimport type { StrategyContext } from './strategies/types.js';\nimport { computeTradeDecision } from './scoring.js';\nimport type { TradeDecision } from './scoring.js';\n\nexport interface BacktestConfig {\n tokenId: string;\n startDate: string; // ISO date\n endDate: string;\n initialCapital: number;\n strategies: string[]; // strategy names to test\n cycle: '1h' | '4h' | '1d';\n verbose?: boolean; // show detailed decision logs\n}\n\nexport interface BacktestTrade {\n entryDate: string;\n exitDate: string;\n entryPrice: number;\n exitPrice: number;\n pnlPercent: number;\n signal: string;\n strategies?: string[]; // Which strategies contributed to this trade\n}\n\nexport interface BacktestResult {\n config: BacktestConfig;\n totalReturn: number;\n totalReturnPercent: number;\n sharpeRatio: number;\n maxDrawdown: number;\n winRate: number;\n totalTrades: number;\n trades: BacktestTrade[];\n equityCurve: Array<{ date: string; value: number }>;\n}\n\nexport interface WalkForwardConfig {\n tokenId: string;\n totalDays: number; // e.g. 180\n trainWindow: number; // e.g. 90 days\n testWindow: number; // e.g. 30 days\n stepSize: number; // e.g. 30 days (how much to advance each fold)\n capital: number;\n strategies: string[];\n}\n\nexport interface WalkForwardResult {\n folds: Array<{\n trainPeriod: { from: Date; to: Date };\n testPeriod: { from: Date; to: Date };\n trainSharpe: number;\n testSharpe: number;\n trainReturn: number;\n testReturn: number;\n testMaxDrawdown: number;\n tradesInTest: number;\n }>;\n aggregateTestSharpe: number;\n aggregateTestReturn: number;\n avgTestMaxDrawdown: number;\n overfit: boolean; // true if train sharpe >> test sharpe\n overfitRatio: number; // train sharpe / test sharpe\n}\n\n// Strategies that can work with candles-only data in backtest mode\nconst CANDLE_BASED_STRATEGIES = [\n 'breakoutOnChain',\n 'meanReversion',\n 'multiTimeframe',\n];\n\nexport class Backtester {\n private config: BacktestConfig;\n private cg: CoinGeckoProvider;\n private sentimentProvider: SentimentProvider;\n\n constructor(config: BacktestConfig) {\n this.config = config;\n this.cg = new CoinGeckoProvider();\n this.sentimentProvider = new SentimentProvider();\n }\n\n /** Run backtest using historical data from CoinGecko. */\n async run(): Promise<BacktestResult> {\n // 1. Fetch historical OHLC data\n const startMs = new Date(this.config.startDate).getTime();\n const endMs = new Date(this.config.endDate).getTime();\n const totalDays = Math.ceil((endMs - startMs) / (24 * 60 * 60 * 1000));\n\n // Use market_chart endpoint (daily prices) — works for any range up to 365 days.\n // OHLC endpoint only returns 12 candles for >30 day ranges on free tier.\n const cgDays = Math.min(Math.max(totalDays, 1), 365);\n const marketData = await this.cg.getMarketData(this.config.tokenId, cgDays);\n\n if (!marketData?.prices?.length) {\n throw new Error(`No price data returned from CoinGecko for ${this.config.tokenId}`);\n }\n\n // Build daily candles from market_chart prices + volumes\n const prices: number[][] = marketData.prices;\n const volumes: number[][] = marketData.total_volumes ?? [];\n\n // Group prices and volumes by day to create OHLCV candles\n const dayMap = new Map<string, { prices: number[]; totalVolume: number; timestamp: number }>();\n\n // Process prices first to establish daily buckets\n for (const [ts, price] of prices) {\n if (ts! < startMs || ts! > endMs) continue;\n const dayKey = new Date(ts!).toISOString().slice(0, 10);\n if (!dayMap.has(dayKey)) {\n dayMap.set(dayKey, { prices: [], totalVolume: 0, timestamp: ts! });\n }\n dayMap.get(dayKey)!.prices.push(price!);\n }\n\n // Sum volumes for each day (instead of averaging)\n for (const [ts, vol] of volumes) {\n if (ts! < startMs || ts! > endMs) continue;\n const dayKey = new Date(ts!).toISOString().slice(0, 10);\n const dayData = dayMap.get(dayKey);\n if (dayData) {\n dayData.totalVolume += vol!;\n }\n }\n\n const allCandles: Candle[] = [...dayMap.entries()]\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([, day]) => {\n const p = day.prices;\n return {\n timestamp: day.timestamp,\n open: p[0]!,\n high: Math.max(...p),\n low: Math.min(...p),\n close: p[p.length - 1]!,\n volume: day.totalVolume, // Use summed volume for the day\n };\n });\n\n if (allCandles.length < 30) {\n throw new Error(`Insufficient data: only ${allCandles.length} candles in date range (need 30+)`);\n }\n\n // 1.5. Fetch Fear & Greed historical data for sentiment-contrarian strategy\n let fearAndGreedData: Record<string, number> = {};\n try {\n const fgData = await this.sentimentProvider.getFearAndGreed();\n for (const entry of fgData) {\n // Convert timestamp to date string and store\n const date = new Date(Number(entry.timestamp) * 1000).toISOString().split('T')[0]!;\n fearAndGreedData[date] = entry.value;\n }\n if (this.config.verbose && Object.keys(fearAndGreedData).length > 0) {\n console.log(chalk.dim(` Loaded ${Object.keys(fearAndGreedData).length} Fear & Greed historical data points`));\n }\n } catch (error) {\n if (this.config.verbose) {\n console.log(chalk.yellow(` Warning: Could not fetch Fear & Greed data: ${(error as Error).message}`));\n }\n }\n\n // 2. Determine step size based on cycle\n const stepSize = this.config.cycle === '1h' ? 1 : this.config.cycle === '4h' ? 4 : 24;\n // CoinGecko OHLC for 90+ days gives daily candles, so step = 1 candle for '1d'\n const step = Math.max(1, Math.floor(stepSize / 24)); // approximate\n\n // 3. Simulate trading\n let capital = this.config.initialCapital;\n let position: { entryPrice: number; entryDate: string; signal: string } | null = null;\n const trades: BacktestTrade[] = [];\n const equityCurve: Array<{ date: string; value: number }> = [];\n const returns: number[] = [];\n\n const windowSize = 30; // min candles needed for indicators\n\n // Show strategy filtering info\n if (this.config.verbose) {\n if (this.config.strategies.length > 0) {\n console.log(chalk.dim(` Using user-specified strategies: ${this.config.strategies.join(', ')}`));\n } else {\n const availableStrategies = [...CANDLE_BASED_STRATEGIES];\n if (Object.keys(fearAndGreedData).length > 0) {\n availableStrategies.push('sentimentContrarian');\n }\n console.log(chalk.dim(` Using candle-based strategies: ${availableStrategies.join(', ')}`));\n console.log(chalk.dim(` Filtered out external data strategies to prevent zero-signal noise`));\n }\n console.log();\n }\n\n for (let i = windowSize; i < allCandles.length; i += step) {\n // Use historical data only (excluding current candle to avoid look-ahead bias)\n const windowCandles = allCandles.slice(Math.max(0, i - 200), i);\n const currentCandle = allCandles[i]!;\n const currentDate = new Date(currentCandle.timestamp).toISOString().split('T')[0]!;\n const currentPrice = currentCandle.close;\n\n // Skip if insufficient data for indicators\n if (windowCandles.length < windowSize) continue;\n\n // Track equity\n const equity = position\n ? capital * (currentPrice / position.entryPrice)\n : capital;\n equityCurve.push({ date: currentDate, value: equity });\n\n // Compute indicators using only historical data\n let decision: TradeDecision;\n try {\n const technicals = getLatestSignals(windowCandles);\n\n // Add Fear & Greed data for the current date if available\n let fearAndGreed: { value: number; classification: string } | undefined;\n const fgValue = fearAndGreedData[currentDate];\n if (fgValue !== undefined) {\n const classification = fgValue < 25 ? 'Extreme Fear' :\n fgValue < 40 ? 'Fear' :\n fgValue < 60 ? 'Neutral' :\n fgValue < 75 ? 'Greed' : 'Extreme Greed';\n fearAndGreed = { value: fgValue, classification };\n }\n\n const ctx: StrategyContext = {\n tokenId: this.config.tokenId,\n candles: windowCandles,\n technicals,\n fearAndGreed,\n };\n\n // Run strategies — filter to candle-based only for backtest\n const signals = await runStrategies(ctx);\n\n // Filter strategies: if user specified strategies, honor their choice\n // Otherwise, filter to candle-based strategies only\n let filtered = signals;\n if (this.config.strategies.length > 0) {\n // User specified strategies — use their selection\n filtered = signals.filter((s) => this.config.strategies.some(\n (name) => s.name.toLowerCase().includes(name.toLowerCase()),\n ));\n } else {\n // No user selection — filter to candle-based strategies only\n filtered = signals.filter((s) => CANDLE_BASED_STRATEGIES.includes(s.name) ||\n (fearAndGreed && s.name === 'sentimentContrarian'));\n }\n\n decision = computeTradeDecision(filtered.length > 0 ? filtered : signals);\n\n // Verbose logging\n if (this.config.verbose) {\n const activeSignals = filtered.filter(s => Math.abs(s.value) > 0.01);\n const signalSummary = activeSignals.map(s =>\n `${s.name}:${s.value >= 0 ? '+' : ''}${s.value.toFixed(2)}`\n ).join(' ');\n console.log(`${currentDate}: score=${decision.score.toFixed(2)} ${decision.action} (${signalSummary || 'no signals'})`);\n }\n } catch {\n continue; // skip candle if analysis fails\n }\n\n // Execute paper trades\n if (!position && (decision.action === 'BUY' || decision.action === 'STRONG_BUY')) {\n // Enter long\n position = {\n entryPrice: currentPrice,\n entryDate: currentDate,\n signal: decision.action,\n };\n } else if (position && (decision.action === 'SELL' || decision.action === 'STRONG_SELL')) {\n // Exit long\n const pnlPercent = (currentPrice - position.entryPrice) / position.entryPrice;\n capital *= (1 + pnlPercent);\n returns.push(pnlPercent);\n\n trades.push({\n entryDate: position.entryDate,\n exitDate: currentDate,\n entryPrice: position.entryPrice,\n exitPrice: currentPrice,\n pnlPercent,\n signal: `${position.signal} → ${decision.action}`,\n });\n\n position = null;\n }\n }\n\n // Close any remaining position at last price\n if (position && allCandles.length > 0) {\n const lastCandle = allCandles[allCandles.length - 1]!;\n const lastPrice = lastCandle.close;\n const lastDate = new Date(lastCandle.timestamp).toISOString().split('T')[0]!;\n const pnlPercent = (lastPrice - position.entryPrice) / position.entryPrice;\n capital *= (1 + pnlPercent);\n returns.push(pnlPercent);\n\n trades.push({\n entryDate: position.entryDate,\n exitDate: lastDate,\n entryPrice: position.entryPrice,\n exitPrice: lastPrice,\n pnlPercent,\n signal: `${position.signal} → CLOSE`,\n });\n }\n\n // 4. Compute metrics\n const totalReturn = capital - this.config.initialCapital;\n const totalReturnPercent = totalReturn / this.config.initialCapital;\n const winRate = returns.length > 0\n ? returns.filter((r) => r > 0).length / returns.length\n : 0;\n\n // Sharpe ratio (annualized from daily equity curve returns, not per-trade returns)\n const dailyReturns: number[] = [];\n for (let i = 1; i < equityCurve.length; i++) {\n const prev = equityCurve[i - 1]!.value;\n if (prev > 0) {\n dailyReturns.push((equityCurve[i]!.value - prev) / prev);\n }\n }\n const meanReturn = dailyReturns.length > 0\n ? dailyReturns.reduce((a, b) => a + b, 0) / dailyReturns.length\n : 0;\n const variance = dailyReturns.length > 1\n ? dailyReturns.reduce((sum, r) => sum + (r - meanReturn) ** 2, 0) / (dailyReturns.length - 1)\n : 0;\n const stdDev = Math.sqrt(variance);\n const riskFreeDaily = 0.05 / 252; // 5% annual risk-free rate\n const sharpeRatio = stdDev > 0 ? ((meanReturn - riskFreeDaily) / stdDev) * Math.sqrt(252) : 0;\n\n // Max drawdown\n let maxDrawdown = 0;\n let peak = this.config.initialCapital;\n for (const point of equityCurve) {\n if (point.value > peak) peak = point.value;\n const drawdown = (peak - point.value) / peak;\n if (drawdown > maxDrawdown) maxDrawdown = drawdown;\n }\n\n return {\n config: this.config,\n totalReturn,\n totalReturnPercent,\n sharpeRatio,\n maxDrawdown,\n winRate,\n totalTrades: trades.length,\n trades,\n equityCurve,\n };\n }\n\n /** Walk-forward optimization to prevent overfitting. */\n async walkForwardTest(config: WalkForwardConfig): Promise<WalkForwardResult> {\n const endDate = new Date();\n endDate.setHours(0, 0, 0, 0); // Start of today\n const startDate = new Date(endDate);\n startDate.setDate(startDate.getDate() - config.totalDays);\n\n const folds: WalkForwardResult['folds'] = [];\n const testReturns: number[] = [];\n const testSharpes: number[] = [];\n const testMaxDrawdowns: number[] = [];\n\n let currentStart = new Date(startDate);\n\n while (currentStart.getTime() + (config.trainWindow + config.testWindow) * 24 * 60 * 60 * 1000 <= endDate.getTime()) {\n // Define train period\n const trainStart = new Date(currentStart);\n const trainEnd = new Date(trainStart);\n trainEnd.setDate(trainEnd.getDate() + config.trainWindow);\n\n // Define test period\n const testStart = new Date(trainEnd);\n const testEnd = new Date(testStart);\n testEnd.setDate(testEnd.getDate() + config.testWindow);\n\n try {\n // Run backtest on training period\n const trainBacktester = new Backtester({\n tokenId: config.tokenId,\n startDate: trainStart.toISOString().slice(0, 10),\n endDate: trainEnd.toISOString().slice(0, 10),\n initialCapital: config.capital,\n strategies: config.strategies,\n cycle: '1d',\n verbose: false, // Don't spam verbose output during walk-forward\n });\n const trainResult = await trainBacktester.run();\n\n // Run backtest on test period\n const testBacktester = new Backtester({\n tokenId: config.tokenId,\n startDate: testStart.toISOString().slice(0, 10),\n endDate: testEnd.toISOString().slice(0, 10),\n initialCapital: config.capital,\n strategies: config.strategies,\n cycle: '1d',\n verbose: false, // Don't spam verbose output during walk-forward\n });\n const testResult = await testBacktester.run();\n\n const fold = {\n trainPeriod: { from: trainStart, to: trainEnd },\n testPeriod: { from: testStart, to: testEnd },\n trainSharpe: trainResult.sharpeRatio,\n testSharpe: testResult.sharpeRatio,\n trainReturn: trainResult.totalReturnPercent,\n testReturn: testResult.totalReturnPercent,\n testMaxDrawdown: testResult.maxDrawdown,\n tradesInTest: testResult.totalTrades,\n };\n\n folds.push(fold);\n testReturns.push(testResult.totalReturnPercent);\n testSharpes.push(testResult.sharpeRatio);\n testMaxDrawdowns.push(testResult.maxDrawdown);\n } catch (error) {\n // Skip fold if data is insufficient\n console.warn(`Skipping fold ${trainStart.toISOString().slice(0, 10)} - ${testEnd.toISOString().slice(0, 10)}: ${error}`);\n }\n\n // Advance to next fold\n currentStart.setDate(currentStart.getDate() + config.stepSize);\n }\n\n if (folds.length === 0) {\n throw new Error('No valid folds could be generated - insufficient data or invalid parameters');\n }\n\n // Calculate aggregate metrics\n const aggregateTestReturn = testReturns.reduce((sum, ret) => sum + ret, 0) / testReturns.length;\n const aggregateTestSharpe = testSharpes.filter(s => !isNaN(s) && isFinite(s)).reduce((sum, s) => sum + s, 0) / testSharpes.filter(s => !isNaN(s) && isFinite(s)).length || 0;\n const avgTestMaxDrawdown = testMaxDrawdowns.reduce((sum, dd) => sum + dd, 0) / testMaxDrawdowns.length;\n\n // Calculate overfitting metrics\n const avgTrainSharpe = folds.map(f => f.trainSharpe).filter(s => !isNaN(s) && isFinite(s)).reduce((sum, s) => sum + s, 0) / folds.filter(f => !isNaN(f.trainSharpe) && isFinite(f.trainSharpe)).length || 0;\n const overfitRatio = avgTrainSharpe > 0 && aggregateTestSharpe > 0 ? avgTrainSharpe / aggregateTestSharpe : 1;\n const overfit = overfitRatio > 2.0; // Flag if train performance is more than 2x better than test\n\n return {\n folds,\n aggregateTestSharpe,\n aggregateTestReturn,\n avgTestMaxDrawdown,\n overfit,\n overfitRatio,\n };\n }\n\n /** Format results for display. */\n formatResults(result: BacktestResult): string {\n const lines: string[] = [];\n\n lines.push('');\n lines.push(chalk.bold(' ┌──────────────────────────────────────────────┐'));\n lines.push(chalk.bold(' │ Backtest Results │'));\n lines.push(chalk.bold(' └──────────────────────────────────────────────┘'));\n lines.push('');\n lines.push(` Token: ${result.config.tokenId}`);\n lines.push(` Period: ${result.config.startDate} → ${result.config.endDate}`);\n lines.push(` Initial: $${result.config.initialCapital.toLocaleString()}`);\n lines.push(` Strategies: ${result.config.strategies.join(', ') || 'all'}`);\n lines.push(` Cycle: ${result.config.cycle}`);\n lines.push('');\n lines.push(chalk.dim(' ' + '═'.repeat(50)));\n\n // Performance metrics\n const retColor = result.totalReturnPercent >= 0 ? chalk.green : chalk.red;\n lines.push(` Total Return: ${retColor('$' + result.totalReturn.toFixed(2))} (${retColor((result.totalReturnPercent * 100).toFixed(2) + '%')})`);\n lines.push(` Final Capital: $${(result.config.initialCapital + result.totalReturn).toFixed(2)}`);\n lines.push(` Sharpe Ratio: ${result.sharpeRatio.toFixed(2)}`);\n lines.push(` Max Drawdown: ${chalk.red((result.maxDrawdown * 100).toFixed(2) + '%')}`);\n lines.push(` Win Rate: ${(result.winRate * 100).toFixed(1)}%`);\n lines.push(` Total Trades: ${result.totalTrades}`);\n\n // Volume quality warning\n const zeroVolumeTrades = result.trades.filter(t => {\n // Check if trades occurred during periods with potentially missing volume data\n return true; // For now, we'll always show this warning since CoinGecko OHLC had volume issues\n }).length;\n const volumeWarning = result.equityCurve.length > 0; // We have equity data, so we can check volume quality\n if (volumeWarning) {\n lines.push('');\n lines.push(chalk.yellow(' ⚠️ Volume Data Quality:'));\n lines.push(chalk.dim(' Volume data sourced from market_chart endpoint and aggregated daily.'));\n lines.push(chalk.dim(' Intraday volume patterns may not be fully captured.'));\n }\n\n // Monthly returns breakdown\n if (result.trades.length > 0) {\n const monthlyReturns = this.calculateMonthlyReturns(result.equityCurve);\n if (Object.keys(monthlyReturns).length > 1) {\n lines.push('');\n lines.push(chalk.bold(' Monthly Returns:'));\n lines.push(chalk.dim(` ${'Month'.padEnd(12)} ${'Return %'.padEnd(10)} Performance`));\n lines.push(chalk.dim(' ' + '─'.repeat(35)));\n\n for (const [month, returnPct] of Object.entries(monthlyReturns).slice(-12)) { // Show last 12 months\n const returnColor = returnPct >= 0 ? chalk.green : chalk.red;\n const bar = this.renderMiniBar(returnPct / 100, 10);\n lines.push(\n ` ${month.padEnd(12)} ${returnColor((returnPct > 0 ? '+' : '') + returnPct.toFixed(1) + '%').padEnd(18)} ${bar}`,\n );\n }\n }\n }\n\n // Strategy performance breakdown (simplified version)\n if (result.trades.length > 0 && result.config.strategies.length > 0) {\n lines.push('');\n lines.push(chalk.bold(' Strategy Performance:'));\n lines.push(chalk.dim(` ${'Strategy'.padEnd(20)} ${'Trades'.padEnd(8)} Win Rate`));\n lines.push(chalk.dim(' ' + '─'.repeat(40)));\n\n // For now, show overall win rate per configured strategy filter\n // In a future enhancement, we could track which specific strategies triggered each trade\n for (const strategy of result.config.strategies.slice(0, 5)) { // Top 5 strategies\n const strategyTrades = Math.floor(result.totalTrades / result.config.strategies.length); // Approximate distribution\n const winRate = result.winRate; // Use overall win rate as approximation\n const winRateColor = winRate >= 0.6 ? chalk.green : winRate >= 0.4 ? chalk.yellow : chalk.red;\n lines.push(\n ` ${strategy.slice(0, 19).padEnd(20)} ${strategyTrades.toString().padEnd(8)} ${winRateColor((winRate * 100).toFixed(1) + '%')}`,\n );\n }\n if (result.config.strategies.length === 0) {\n lines.push(chalk.dim(' All strategies combined'));\n }\n }\n\n // Trade list\n if (result.trades.length > 0) {\n lines.push('');\n lines.push(chalk.bold(' Trades:'));\n lines.push(chalk.dim(` ${'Entry'.padEnd(12)} ${'Exit'.padEnd(12)} ${'Entry$'.padEnd(10)} ${'Exit$'.padEnd(10)} ${'PnL%'.padEnd(10)} Signal`));\n lines.push(chalk.dim(' ' + '─'.repeat(65)));\n\n for (const t of result.trades.slice(-20)) { // show last 20\n const pnlColor = t.pnlPercent >= 0 ? chalk.green : chalk.red;\n lines.push(\n ` ${t.entryDate.padEnd(12)} ${t.exitDate.padEnd(12)} $${t.entryPrice.toFixed(2).padEnd(9)} $${t.exitPrice.toFixed(2).padEnd(9)} ${pnlColor((t.pnlPercent * 100).toFixed(2).padStart(7) + '%')} ${t.signal}`,\n );\n }\n if (result.trades.length > 20) {\n lines.push(chalk.dim(` ... and ${result.trades.length - 20} more trades`));\n }\n }\n\n // Equity curve ASCII art\n if (result.equityCurve.length > 2) {\n lines.push('');\n lines.push(chalk.bold(' Equity Curve:'));\n lines.push(this.renderEquityCurve(result.equityCurve, result.config.initialCapital));\n }\n\n lines.push('');\n return lines.join('\\n');\n }\n\n /** Format walk-forward results for display. */\n formatWalkForwardResults(result: WalkForwardResult, config: WalkForwardConfig): string {\n const lines: string[] = [];\n\n lines.push('');\n lines.push(chalk.bold(' ┌──────────────────────────────────────────────┐'));\n lines.push(chalk.bold(' │ Walk-Forward Optimization Results │'));\n lines.push(chalk.bold(' └──────────────────────────────────────────────┘'));\n lines.push('');\n lines.push(` Token: ${config.tokenId}`);\n lines.push(` Train Window: ${config.trainWindow} days`);\n lines.push(` Test Window: ${config.testWindow} days`);\n lines.push(` Step Size: ${config.stepSize} days`);\n lines.push(` Total Folds: ${result.folds.length}`);\n lines.push(` Strategies: ${config.strategies.join(', ') || 'all'}`);\n lines.push('');\n lines.push(chalk.dim(' ' + '═'.repeat(50)));\n\n // Aggregate performance\n const retColor = result.aggregateTestReturn >= 0 ? chalk.green : chalk.red;\n const overfitColor = result.overfit ? chalk.red : chalk.green;\n lines.push(` Aggregate Test Return: ${retColor((result.aggregateTestReturn * 100).toFixed(2) + '%')}`);\n lines.push(` Aggregate Test Sharpe: ${result.aggregateTestSharpe.toFixed(2)}`);\n lines.push(` Avg Test Max Drawdown: ${chalk.red((result.avgTestMaxDrawdown * 100).toFixed(2) + '%')}`);\n lines.push(` Overfitting Ratio: ${overfitColor(result.overfitRatio.toFixed(2) + (result.overfit ? ' ⚠️ OVERFIT' : ' ✓'))}`);\n\n // Fold-by-fold breakdown\n if (result.folds.length > 0) {\n lines.push('');\n lines.push(chalk.bold(' Fold-by-Fold Results:'));\n lines.push(chalk.dim(` ${'Train Period'.padEnd(23)} ${'Test Period'.padEnd(23)} ${'Train'.padEnd(8)} ${'Test'.padEnd(8)} ${'Test DD%'.padEnd(9)} Trades`));\n lines.push(chalk.dim(' ' + '─'.repeat(90)));\n\n for (const fold of result.folds) {\n const trainPeriodStr = `${fold.trainPeriod.from.toISOString().slice(0, 10)} to ${fold.trainPeriod.to.toISOString().slice(0, 10)}`;\n const testPeriodStr = `${fold.testPeriod.from.toISOString().slice(0, 10)} to ${fold.testPeriod.to.toISOString().slice(0, 10)}`;\n const trainSharpeStr = isFinite(fold.trainSharpe) ? fold.trainSharpe.toFixed(2) : 'N/A';\n const testSharpeStr = isFinite(fold.testSharpe) ? fold.testSharpe.toFixed(2) : 'N/A';\n const testReturnColor = fold.testReturn >= 0 ? chalk.green : chalk.red;\n const testDdStr = (fold.testMaxDrawdown * 100).toFixed(1) + '%';\n\n lines.push(\n ` ${trainPeriodStr.padEnd(23)} ${testPeriodStr.padEnd(23)} ${trainSharpeStr.padEnd(8)} ${testReturnColor(testSharpeStr.padEnd(8))} ${chalk.red(testDdStr.padEnd(9))} ${fold.tradesInTest}`,\n );\n }\n\n // Summary stats\n const winningFolds = result.folds.filter(f => f.testReturn > 0).length;\n const winRate = result.folds.length > 0 ? (winningFolds / result.folds.length * 100).toFixed(1) : '0.0';\n\n lines.push('');\n lines.push(chalk.dim(' ' + '─'.repeat(50)));\n lines.push(` Winning Folds: ${winningFolds}/${result.folds.length} (${winRate}%)`);\n\n if (result.overfit) {\n lines.push('');\n lines.push(chalk.red(' ⚠️ WARNING: Strategy shows signs of overfitting!'));\n lines.push(chalk.red(' Train performance significantly exceeds test performance.'));\n lines.push(chalk.red(' Consider simplifying the strategy or using longer test periods.'));\n }\n }\n\n lines.push('');\n return lines.join('\\n');\n }\n\n /** Calculate monthly returns from equity curve. */\n private calculateMonthlyReturns(equityCurve: Array<{ date: string; value: number }>): Record<string, number> {\n const monthlyReturns: Record<string, number> = {};\n\n if (equityCurve.length === 0) return monthlyReturns;\n\n let currentMonth = '';\n let monthStartValue = equityCurve[0]!.value;\n let monthEndValue = equityCurve[0]!.value;\n\n for (const point of equityCurve) {\n const pointMonth = point.date.slice(0, 7); // YYYY-MM format\n\n if (currentMonth === '') {\n currentMonth = pointMonth;\n monthStartValue = point.value;\n } else if (pointMonth !== currentMonth) {\n // Month changed, calculate return for previous month\n if (monthStartValue > 0) {\n const returnPct = ((monthEndValue - monthStartValue) / monthStartValue) * 100;\n monthlyReturns[currentMonth] = returnPct;\n }\n\n // Start new month\n currentMonth = pointMonth;\n monthStartValue = point.value;\n }\n\n monthEndValue = point.value;\n }\n\n // Don't forget the last month\n if (currentMonth && monthStartValue > 0) {\n const returnPct = ((monthEndValue - monthStartValue) / monthStartValue) * 100;\n monthlyReturns[currentMonth] = returnPct;\n }\n\n return monthlyReturns;\n }\n\n /** Render a mini bar chart for monthly returns. */\n private renderMiniBar(value: number, width: number): string {\n const magnitude = Math.min(Math.abs(value), 0.3); // Cap at 30% for display\n const filled = Math.round(magnitude * width / 0.3);\n\n if (value > 0) {\n return chalk.green('█'.repeat(filled)) + chalk.dim('░'.repeat(width - filled));\n } else if (value < 0) {\n return chalk.red('█'.repeat(filled)) + chalk.dim('░'.repeat(width - filled));\n }\n return chalk.dim('░'.repeat(width));\n }\n\n /** Render a simple ASCII equity curve using box-drawing chars. */\n private renderEquityCurve(\n curve: Array<{ date: string; value: number }>,\n initialCapital: number,\n ): string {\n const width = 60;\n const height = 15;\n\n // Sample curve to fit width\n const sampled: number[] = [];\n const step = Math.max(1, Math.floor(curve.length / width));\n for (let i = 0; i < curve.length; i += step) {\n sampled.push(curve[i]!.value);\n }\n if (sampled.length > width) sampled.length = width;\n\n const minVal = Math.min(...sampled);\n const maxVal = Math.max(...sampled);\n const range = maxVal - minVal || 1;\n\n // Build grid\n const grid: string[][] = [];\n for (let row = 0; row < height; row++) {\n grid.push(new Array(sampled.length).fill(' '));\n }\n\n // Plot points\n for (let col = 0; col < sampled.length; col++) {\n const normalized = (sampled[col]! - minVal) / range;\n const row = height - 1 - Math.round(normalized * (height - 1));\n grid[row]![col] = sampled[col]! >= initialCapital ? '█' : '▓';\n }\n\n // Render with Y-axis labels\n const lines: string[] = [];\n for (let row = 0; row < height; row++) {\n const yVal = maxVal - (row / (height - 1)) * range;\n const label = `$${yVal.toFixed(0)}`.padStart(8);\n const lineStr = grid[row]!.join('');\n const rowColor = yVal >= initialCapital ? chalk.green : chalk.red;\n lines.push(` ${chalk.dim(label)} │${rowColor(lineStr)}`);\n }\n lines.push(` ${''.padStart(8)} └${'─'.repeat(sampled.length)}`);\n\n // X-axis labels\n const firstDate = curve[0]?.date ?? '';\n const lastDate = curve[curve.length - 1]?.date ?? '';\n const axisLabel = ` ${''.padStart(9)}${firstDate}${''.padStart(Math.max(0, sampled.length - firstDate.length - lastDate.length))}${lastDate}`;\n lines.push(chalk.dim(axisLabel));\n\n return lines.join('\\n');\n }\n}\n","/**\n * Telegram-optimized alert formatting for trading notifications.\n * Formats scan results, regime changes, and alerts with emoji indicators.\n */\n\nimport type { Alert, TokenAnalysis } from \"./index.js\";\nimport type { MarketRegime } from \"./regime.js\";\n\nexport class AlertFormatter {\n\n /**\n * Format alerts for Telegram with priority grouping and emoji indicators.\n * Returns null if no alerts to display.\n */\n static formatForTelegram(alerts: Alert[]): string | null {\n if (alerts.length === 0) return null;\n\n // Group by priority\n const grouped: Record<string, Alert[]> = {\n critical: [],\n high: [],\n medium: [],\n low: []\n };\n\n for (const alert of alerts) {\n grouped[alert.priority].push(alert);\n }\n\n const lines: string[] = [];\n lines.push(\"🚨 *TRADING ALERTS*\");\n\n // Critical alerts\n if (grouped.critical.length > 0) {\n lines.push(\"\\n🔴 *CRITICAL*\");\n for (const alert of grouped.critical.slice(0, 3)) {\n lines.push(`• ${alert.title}`);\n if (alert.tokenId !== 'bitcoin') {\n lines.push(` _${alert.tokenId.toUpperCase()}_`);\n }\n }\n }\n\n // High priority alerts\n if (grouped.high.length > 0) {\n lines.push(\"\\n🟡 *HIGH*\");\n for (const alert of grouped.high.slice(0, 3)) {\n lines.push(`• ${alert.title}`);\n if (alert.tokenId !== 'bitcoin') {\n lines.push(` _${alert.tokenId.toUpperCase()}_`);\n }\n }\n }\n\n // Medium priority alerts\n if (grouped.medium.length > 0) {\n lines.push(\"\\n🔵 *MEDIUM*\");\n for (const alert of grouped.medium.slice(0, 2)) {\n lines.push(`• ${alert.title}`);\n }\n }\n\n // Low priority alerts (only show count)\n if (grouped.low.length > 0) {\n lines.push(`\\n⚫ ${grouped.low.length} low priority alerts`);\n }\n\n const result = lines.join(\"\\n\");\n\n // Telegram message limit is 4096 chars\n if (result.length > 4000) {\n return result.substring(0, 3900) + \"\\n\\n_...truncated_\";\n }\n\n return result;\n }\n\n /**\n * Format comprehensive scan summary with opportunities, top movers, and alerts.\n */\n static formatScanSummary(\n results: TokenAnalysis[],\n alerts: Alert[],\n regime?: MarketRegime\n ): string {\n const lines: string[] = [];\n\n // Header with timestamp\n lines.push(\"📊 *MARKET SCAN SUMMARY*\");\n lines.push(`_${new Date().toLocaleTimeString()}_`);\n\n // Market regime\n if (regime) {\n const regimeEmoji = regime === \"trending-up\" ? \"📈\" :\n regime === \"trending-down\" ? \"📉\" :\n regime === \"ranging\" ? \"↔️\" :\n regime === \"high-volatility\" ? \"🌋\" : \"🔄\";\n lines.push(`\\n${regimeEmoji} *Regime:* ${regime.toUpperCase().replace('-', ' ')}`);\n }\n\n // Check if all signals are HOLD (brief mode)\n const allHold = results.every(r => r.decision.action === \"HOLD\");\n\n if (allHold) {\n // Brief format for all HOLD scenario\n const strongest = results.reduce((max, r) =>\n r.decision.score > max.decision.score ? r : max\n );\n const weakest = results.reduce((min, r) =>\n r.decision.score < min.decision.score ? r : min\n );\n\n const fearGreed = results[0]?.data.fearAndGreed;\n const fgText = fearGreed ?\n (fearGreed < 25 ? \"Extreme Fear\" :\n fearGreed < 40 ? \"Fear\" :\n fearGreed < 60 ? \"Neutral\" :\n fearGreed < 75 ? \"Greed\" : \"Extreme Greed\") : \"Unknown\";\n\n lines.push(`\\n🔄 *All positions HOLD*`);\n lines.push(`💪 Strongest: ${strongest.token.toUpperCase()} (+${strongest.decision.score.toFixed(2)})`);\n lines.push(`💤 Weakest: ${weakest.token.toUpperCase()} (${weakest.decision.score.toFixed(2)})`);\n if (fearGreed) {\n lines.push(`😱 F&G: ${fearGreed} (${fgText})`);\n }\n } else {\n // Full format with opportunities and movers\n\n // Opportunities (score > 0.3)\n const opportunities = results.filter(r =>\n r.decision.score > 0.3 && (r.decision.action === \"BUY\" || r.decision.action === \"STRONG_BUY\")\n ).sort((a, b) => b.decision.score - a.decision.score);\n\n if (opportunities.length > 0) {\n lines.push(\"\\n💡 *OPPORTUNITIES*\");\n for (const opp of opportunities.slice(0, 3)) {\n const action = opp.decision.action === \"STRONG_BUY\" ? \"🚀 STRONG BUY\" : \"📈 BUY\";\n lines.push(`${action} ${opp.token.toUpperCase()} (${opp.decision.score.toFixed(2)})`);\n\n // Top signal\n const topSignal = opp.decision.signals\n .filter(s => Math.abs(s.value) > 0.1)\n .sort((a, b) => Math.abs(b.value) - Math.abs(a.value))[0];\n\n if (topSignal) {\n const signalEmoji = topSignal.value > 0 ? \"⬆️\" : \"⬇️\";\n lines.push(` ${signalEmoji} ${topSignal.source}: ${topSignal.value > 0 ? \"+\" : \"\"}${topSignal.value.toFixed(2)}`);\n }\n }\n }\n\n // Top movers (biggest absolute score changes)\n const topMovers = results\n .filter(r => Math.abs(r.decision.score) > 0.2)\n .sort((a, b) => Math.abs(b.decision.score) - Math.abs(a.decision.score))\n .slice(0, 3);\n\n if (topMovers.length > 0) {\n lines.push(\"\\n🎯 *TOP MOVERS*\");\n for (const mover of topMovers) {\n const scoreEmoji = mover.decision.score > 0 ? \"📈\" : \"📉\";\n lines.push(`${scoreEmoji} ${mover.token.toUpperCase()}: ${mover.decision.score > 0 ? \"+\" : \"\"}${mover.decision.score.toFixed(2)}`);\n }\n }\n }\n\n // Alerts section\n const alertText = this.formatForTelegram(alerts);\n if (alertText) {\n lines.push(`\\n${alertText}`);\n }\n\n const result = lines.join(\"\\n\");\n\n // Respect Telegram limit\n if (result.length > 4000) {\n return result.substring(0, 3900) + \"\\n\\n_...truncated_\";\n }\n\n return result;\n }\n}","/**\n * Execution pipeline - bridges scanner results to actionable trade proposals.\n * Converts high-confidence analysis into sized position recommendations.\n */\n\nimport type { TokenAnalysis } from \"./index.js\";\nimport type { TechnicalSignals } from \"./technical.js\";\nimport type { Candle } from \"./technical.js\";\nimport { calculateATR } from \"./technical.js\";\n\nexport type TradeAction = \"LONG\" | \"SHORT\";\n\nexport interface TradeProposal {\n tokenId: string;\n symbol: string;\n action: TradeAction;\n entryPrice: number;\n stopLoss: number;\n takeProfit: number;\n positionSizeUsd: number;\n leverage: number;\n confidence: number;\n signals: string[]; // Top 3 signal names\n regime: string;\n timestamp: number;\n}\n\nexport class ExecutionPipeline {\n\n /**\n * Generate trade proposals from analysis results.\n * Only creates proposals for high-confidence opportunities (score > 0.4, confidence > 50%).\n */\n static generateProposals(\n analyses: TokenAnalysis[],\n portfolioValueUsd: number = 10000\n ): TradeProposal[] {\n const proposals: TradeProposal[] = [];\n\n for (const analysis of analyses) {\n const { decision, token, data } = analysis;\n\n // Filter criteria: score > 0.4 and confidence > 50%\n if (Math.abs(decision.score) <= 0.4 || decision.confidence <= 0.5) {\n continue;\n }\n\n // Skip HOLD signals\n if (decision.action === \"HOLD\") {\n continue;\n }\n\n // Determine trade direction\n const isLong = decision.score > 0;\n const action: TradeAction = isLong ? \"LONG\" : \"SHORT\";\n\n // Get current price (use entry price from technical data or mock)\n const entryPrice = this.getEntryPrice(data.technicalSignals);\n if (!entryPrice) continue;\n\n // Calculate ATR for stop loss\n const atr = this.getATR(data.technicalSignals);\n if (!atr) continue;\n\n // Calculate stop loss (entry +/- 2*ATR)\n const stopLoss = isLong\n ? entryPrice - (2 * atr)\n : entryPrice + (2 * atr);\n\n // Calculate take profit (2.5:1 R:R)\n const riskAmount = Math.abs(entryPrice - stopLoss);\n const takeProfit = isLong\n ? entryPrice + (2.5 * riskAmount)\n : entryPrice - (2.5 * riskAmount);\n\n // Position sizing (2% portfolio risk)\n const riskPercentage = 0.02;\n const positionSizeUsd = (portfolioValueUsd * riskPercentage) / (Math.abs(entryPrice - stopLoss) / entryPrice);\n\n // Calculate leverage (size / max 10% portfolio allocation, capped at 5x)\n const maxAllocation = portfolioValueUsd * 0.10;\n const leverage = Math.min(5.0, positionSizeUsd / maxAllocation);\n\n // Get top 3 signals\n const topSignals = decision.signals\n .filter(s => Math.abs(s.value) > 0.05)\n .sort((a, b) => Math.abs(b.value) - Math.abs(a.value))\n .slice(0, 3)\n .map(s => s.source);\n\n // Get regime\n const regime = analysis.regime?.regime || \"unknown\";\n\n // Resolve token symbol (fallback to tokenId if not available)\n const symbol = this.resolveSymbol(token);\n\n const proposal: TradeProposal = {\n tokenId: token,\n symbol,\n action,\n entryPrice,\n stopLoss,\n takeProfit,\n positionSizeUsd,\n leverage,\n confidence: decision.confidence,\n signals: topSignals,\n regime,\n timestamp: Date.now(),\n };\n\n proposals.push(proposal);\n }\n\n return proposals.sort((a, b) => b.confidence - a.confidence);\n }\n\n /**\n * Format trade proposals for human review.\n */\n static formatProposals(proposals: TradeProposal[]): string {\n if (proposals.length === 0) {\n return \"📝 *TRADE PROPOSALS*\\n\\n_No actionable opportunities found._\\n_Criteria: Score > 0.4, Confidence > 50%_\";\n }\n\n const lines: string[] = [];\n lines.push(\"📝 *TRADE PROPOSALS*\");\n lines.push(\"_⚠️ For review only - NO auto-execution_\");\n\n for (const proposal of proposals.slice(0, 5)) {\n const directionEmoji = proposal.action === \"LONG\" ? \"🟢\" : \"🔴\";\n const confidenceBar = \"█\".repeat(Math.floor(proposal.confidence * 10));\n\n lines.push(`\\n${directionEmoji} *${proposal.action} ${proposal.symbol}*`);\n lines.push(`📈 Entry: $${proposal.entryPrice.toFixed(4)}`);\n lines.push(`🛑 Stop: $${proposal.stopLoss.toFixed(4)} (${this.calculatePctChange(proposal.entryPrice, proposal.stopLoss)}%)`);\n lines.push(`🎯 Target: $${proposal.takeProfit.toFixed(4)} (${this.calculatePctChange(proposal.entryPrice, proposal.takeProfit)}%)`);\n lines.push(`💰 Size: $${proposal.positionSizeUsd.toFixed(0)} (${proposal.leverage.toFixed(1)}x leverage)`);\n lines.push(`✅ Confidence: ${(proposal.confidence * 100).toFixed(0)}% ${confidenceBar}`);\n\n // Top signals\n if (proposal.signals.length > 0) {\n lines.push(`🔍 Signals: ${proposal.signals.slice(0, 2).join(\", \")}`);\n }\n\n // Market regime\n const regimeEmoji = proposal.regime === \"trending-up\" ? \"📈\" :\n proposal.regime === \"trending-down\" ? \"📉\" :\n proposal.regime === \"ranging\" ? \"↔️\" :\n proposal.regime === \"high-volatility\" ? \"🌋\" : \"🔄\";\n lines.push(`${regimeEmoji} Regime: ${proposal.regime}`);\n }\n\n if (proposals.length > 5) {\n lines.push(`\\n_...${proposals.length - 5} more proposals available_`);\n }\n\n lines.push(`\\n_Generated: ${new Date().toLocaleTimeString()}_`);\n\n const result = lines.join(\"\\n\");\n\n // Respect character limits\n if (result.length > 4000) {\n return result.substring(0, 3900) + \"\\n\\n_...truncated_\";\n }\n\n return result;\n }\n\n /**\n * Extract entry price from technical signals or use fallback.\n */\n private static getEntryPrice(technicalSignals?: TechnicalSignals): number | null {\n if (!technicalSignals) return null;\n\n // Use VWAP as entry price if available, fallback to EMA8\n if (technicalSignals.vwap > 0) {\n return technicalSignals.vwap;\n }\n\n if (technicalSignals.ema.ema8 > 0) {\n return technicalSignals.ema.ema8;\n }\n\n return null;\n }\n\n /**\n * Extract ATR from technical signals.\n */\n private static getATR(technicalSignals?: TechnicalSignals): number | null {\n if (!technicalSignals) return null;\n return technicalSignals.atr > 0 ? technicalSignals.atr : null;\n }\n\n /**\n * Resolve token symbol from token ID.\n */\n private static resolveSymbol(tokenId: string): string {\n const symbolMap: Record<string, string> = {\n \"bitcoin\": \"BTC\",\n \"ethereum\": \"ETH\",\n \"solana\": \"SOL\",\n \"aave\": \"AAVE\",\n \"uniswap\": \"UNI\",\n \"chainlink\": \"LINK\",\n \"polygon\": \"MATIC\",\n \"avalanche-2\": \"AVAX\",\n \"cardano\": \"ADA\",\n \"polkadot\": \"DOT\",\n };\n\n return symbolMap[tokenId] || tokenId.toUpperCase().slice(0, 6);\n }\n\n /**\n * Calculate percentage change between two prices.\n */\n private static calculatePctChange(from: number, to: number): string {\n const change = ((to - from) / from) * 100;\n return change >= 0 ? `+${change.toFixed(1)}` : change.toFixed(1);\n }\n}"],"mappings":"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","names":["chalk","readFile","writeFile","mkdir","join","homedir","data","mkdir","readFile","writeFile","join","homedir","BASE_URL","sharedLastCallTime","mkdir","readFile","writeFile","join","homedir","mkdir","readFile","writeFile","join","homedir","readFile","writeFile","mkdir","join","homedir","join","homedir","readFile","mkdir","writeFile","readFile","writeFile","mkdir","join","homedir","join","homedir","readFile","mkdir","writeFile","readFile","writeFile","mkdir","join","homedir","createHash","marketData","mkdir","readFile","writeFile","join","homedir","HYPERLIQUID_BASE","chalk","mkdir","join","homedir","chalk","chalk","mkdir","readFile","writeFile","join","homedir","chalk","chalk","chalk","join","homedir","mkdir","chalk","chalk","chalk","fearGreed","spinner","alerts","chalk","join","homedir","readFile","mkdir","writeFile"]}
|