Skip to main content
Glama

get_watchlist_report

Analyze multiple assets to get cycle position, risk level, and volume health while detecting state changes since the last check.

Instructions

Analyze multiple assets at once. Returns cycle position, risk level, and volume health for each. Detects state changes since last check. Max 10 assets.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
assetsYesArray of asset names/symbols, e.g. ["btc", "eth", "sol", "avax"]

Implementation Reference

  • The handler function getWatchlistReport which retrieves asset context for a list of assets, compares their current state with the previous snapshot, and generates a report.
    export async function getWatchlistReport(cache: CacheService, assets: string[]): Promise<WatchlistReportOutput | ErrorOutput> {
      if (assets.length === 0) {
        return {
          error: true, error_source: 'get_watchlist_report',
          agent_guidance: 'No assets provided. Pass an array of asset names, e.g. ["btc", "eth", "sol"].',
          last_known_data: null, data_warnings: ['Empty asset list.'],
        };
      }
    
      const limited = assets.slice(0, 10);
    
      try {
        const results = await Promise.allSettled(
          limited.map(a => getAssetContext(cache, a))
        );
    
        const previous = getWatchlistSnapshot(AGENT_ID);
        const prevMap = new Map<string, WatchlistSnapshot>();
        if (previous) {
          for (const s of previous.snapshots) prevMap.set(s.asset.toLowerCase(), s);
        }
    
        const watchlistAssets: WatchlistAsset[] = [];
        const elevatedVolume: string[] = [];
    
        for (const r of results) {
          if (r.status !== 'fulfilled') continue;
          const data = r.value;
          if ('error' in data) continue;
    
          const asset = data as AssetContextOutput;
          const prev = prevMap.get(asset.asset.toLowerCase());
    
          let changed = false;
          let changeDetail = 'No change since last check.';
          if (prev) {
            const changes: string[] = [];
            if (prev.cycle_position !== asset.cycle_position) changes.push(`cycle: ${prev.cycle_position} → ${asset.cycle_position}`);
            if (prev.risk_level !== asset.risk_level) changes.push(`risk: ${prev.risk_level} → ${asset.risk_level}`);
            if (prev.price_trend !== asset.price_trend) changes.push(`trend: ${prev.price_trend} → ${asset.price_trend}`);
            if (changes.length > 0) {
              changed = true;
              changeDetail = changes.join(', ');
            }
          } else {
            changeDetail = 'First check — no prior data.';
          }
    
          if (asset.volume_health === 'elevated' || asset.volume_health === 'extreme') {
            elevatedVolume.push(asset.asset);
          }
    
          watchlistAssets.push({
            asset: asset.asset,
            price_usd: asset.price_usd,
            cycle_position: asset.cycle_position,
            risk_level: asset.risk_level,
            volume_health: asset.volume_health,
            price_trend: asset.price_trend,
            holder_behavior: asset.holder_behavior,
            changed_since_last_check: changed,
            change_detail: changeDetail,
          });
        }
    
        // Save current snapshot for next comparison
        const snapshots: WatchlistSnapshot[] = watchlistAssets.map(a => ({
          asset: a.asset,
          cycle_position: a.cycle_position,
          risk_level: a.risk_level,
          price_trend: a.price_trend,
          volume_health: a.volume_health,
          timestamp: new Date().toISOString(),
        }));
        saveWatchlistSnapshot(AGENT_ID, snapshots);
    
        const stateChanges = watchlistAssets.filter(a => a.changed_since_last_check);
        const sorted = [...watchlistAssets].sort((a, b) => (RISK_ORDER[b.risk_level] ?? 0) - (RISK_ORDER[a.risk_level] ?? 0));
        const highestRisk = sorted[0]?.asset ?? 'none';
        const lowestRisk = sorted[sorted.length - 1]?.asset ?? 'none';
    
        let guidance = `Watchlist: ${watchlistAssets.length} assets analyzed. `;
        if (stateChanges.length > 0) {
          guidance += `STATE CHANGES DETECTED: ${stateChanges.map(s => `${s.asset} (${s.change_detail})`).join('; ')}. Review these positions. `;
        } else {
          guidance += 'No state changes since last check. ';
        }
        if (elevatedVolume.length > 0) {
          guidance += `Elevated volume on: ${elevatedVolume.join(', ')}. `;
        }
        guidance += `Highest risk: ${highestRisk}. Lowest risk: ${lowestRisk}.`;
    
        return {
          assets: watchlistAssets,
          state_changes: stateChanges,
          elevated_volume_assets: elevatedVolume,
          highest_risk_asset: highestRisk,
          lowest_risk_asset: lowestRisk,
          total_assets: watchlistAssets.length,
          agent_guidance: guidance,
        };
      } catch {
        return {
          error: true, error_source: 'get_watchlist_report',
          agent_guidance: 'Watchlist report temporarily unavailable. Retry shortly.',
          last_known_data: null, data_warnings: ['Watchlist service temporarily unavailable.'],
        };
      }
    }
  • Data interfaces defining the schema for the WatchlistReport output.
    export interface WatchlistAsset {
      asset: string;
      price_usd: number;
      cycle_position: string;
      risk_level: string;
      volume_health: string;
      price_trend: string;
      holder_behavior: string;
      changed_since_last_check: boolean;
      change_detail: string;
    }
    
    export interface WatchlistReportOutput {
      assets: WatchlistAsset[];
      state_changes: WatchlistAsset[];
      elevated_volume_assets: string[];
      highest_risk_asset: string;
      lowest_risk_asset: string;
      total_assets: number;
      agent_guidance: string;
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/0xHashy/fathom-fyi'

If you have feedback or need assistance with the MCP directory API, please join our Discord server