[object Object]

← back to Bertha

chore(alshi-dash): update 1 file (.js) [+256/-1]

fd178e43cbafc6bb0f04f95c72d93763a240fa2f · 2026-02-15 16:43:30 +0000 · DW Commit Agent

Files touched

Diff

commit fd178e43cbafc6bb0f04f95c72d93763a240fa2f
Author: DW Commit Agent <commit-agent@dw-agents.com>
Date:   Sun Feb 15 16:43:30 2026 +0000

    chore(alshi-dash): update 1 file (.js) [+256/-1]
---
 kalshi-dash/server.js | 257 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 256 insertions(+), 1 deletion(-)

diff --git a/kalshi-dash/server.js b/kalshi-dash/server.js
index b4c1cd9..2d123ad 100644
--- a/kalshi-dash/server.js
+++ b/kalshi-dash/server.js
@@ -1900,6 +1900,167 @@ async function scrapeMetaculus() {
   }
 }
 
+// ── PredictIt API (another prediction market for cross-reference) ──
+async function scrapePredictIt() {
+  try {
+    const controller = new AbortController();
+    setTimeout(() => controller.abort(), 8000);
+    const res = await fetch('https://www.predictit.org/api/marketdata/all/', {
+      signal: controller.signal,
+      headers: { 'User-Agent': 'Ken-Bot/1.0' }
+    });
+    if (!res.ok) return [];
+    const data = await res.json();
+    return (data.markets || []).slice(0, 100).map(m => ({
+      title: m.name,
+      url: m.url || `https://www.predictit.org/markets/detail/${m.id}`,
+      score: Math.round((m.contracts?.[0]?.lastTradePrice || 0) * 100),
+      num_comments: m.contracts?.length || 0,
+      source: 'predictit',
+      extra: JSON.stringify({
+        contracts: (m.contracts || []).slice(0, 5).map(c => ({
+          name: c.name, lastPrice: c.lastTradePrice, bestBuy: c.bestBuyYesCost, bestSell: c.bestSellYesCost
+        }))
+      })
+    }));
+  } catch (e) {
+    console.log(`[Ken] PredictIt scrape failed: ${e.message}`);
+    return [];
+  }
+}
+
+// ── FRED Economic Data API (real economic indicators — no key needed for some endpoints) ──
+async function scrapeFredIndicators() {
+  const indicators = [
+    { series: 'CPIAUCSL', name: 'CPI Inflation' },
+    { series: 'UNRATE', name: 'Unemployment Rate' },
+    { series: 'GDP', name: 'GDP Growth' },
+    { series: 'FEDFUNDS', name: 'Federal Funds Rate' },
+    { series: 'T10Y2Y', name: '10Y-2Y Treasury Spread' },
+    { series: 'VIXCLS', name: 'VIX Volatility Index' },
+    { series: 'DGS10', name: '10-Year Treasury Yield' },
+    { series: 'DCOILWTICO', name: 'WTI Crude Oil Price' },
+  ];
+  const results = [];
+  for (const ind of indicators) {
+    try {
+      const controller = new AbortController();
+      setTimeout(() => controller.abort(), 5000);
+      const res = await fetch(`https://fred.stlouisfed.org/graph/fredgraph.csv?id=${ind.series}&cosd=${new Date(Date.now() - 90*86400000).toISOString().split('T')[0]}`, {
+        signal: controller.signal,
+        headers: { 'User-Agent': 'Ken-Bot/1.0' }
+      });
+      if (!res.ok) continue;
+      const csv = await res.text();
+      const lines = csv.trim().split('\n');
+      if (lines.length < 2) continue;
+      const lastLine = lines[lines.length - 1];
+      const [date, value] = lastLine.split(',');
+      if (value && value !== '.') {
+        results.push({
+          title: `${ind.name}: ${value} (${date})`,
+          url: `https://fred.stlouisfed.org/series/${ind.series}`,
+          score: Math.round(parseFloat(value) * 100) || 0,
+          source: 'fred_economic',
+          keyword: ind.series,
+        });
+      }
+    } catch {}
+  }
+  return results;
+}
+
+// ── NWS Active Weather Alerts (real severe weather data for weather markets) ──
+async function scrapeNWSAlerts() {
+  try {
+    const controller = new AbortController();
+    setTimeout(() => controller.abort(), 8000);
+    const res = await fetch('https://api.weather.gov/alerts/active?status=actual&message_type=alert&limit=50', {
+      signal: controller.signal,
+      headers: { 'User-Agent': 'Ken-Bot/1.0 (ken@designerwallcoverings.com)', 'Accept': 'application/geo+json' }
+    });
+    if (!res.ok) return [];
+    const data = await res.json();
+    return (data.features || []).map(f => ({
+      title: `${f.properties.event}: ${f.properties.headline || f.properties.description?.substring(0, 200) || ''}`.substring(0, 500),
+      url: f.properties['@id'] || 'https://alerts.weather.gov',
+      score: f.properties.severity === 'Extreme' ? 100 : f.properties.severity === 'Severe' ? 75 : f.properties.severity === 'Moderate' ? 50 : 25,
+      num_comments: 0,
+      source: 'nws_alerts',
+      keyword: f.properties.event || 'weather',
+    }));
+  } catch (e) {
+    console.log(`[Ken] NWS Alerts failed: ${e.message}`);
+    return [];
+  }
+}
+
+// ── Congressional/Government Activity (GovTrack API) ──
+async function scrapeGovTrack() {
+  try {
+    const controller = new AbortController();
+    setTimeout(() => controller.abort(), 8000);
+    const res = await fetch('https://www.govtrack.us/api/v2/vote?order_by=-created&limit=20', {
+      signal: controller.signal,
+      headers: { 'User-Agent': 'Ken-Bot/1.0' }
+    });
+    if (!res.ok) return [];
+    const data = await res.json();
+    return (data.objects || []).map(v => ({
+      title: `${v.chamber === 'senate' ? 'Senate' : 'House'} Vote: ${v.question || v.result || 'Unknown'}`.substring(0, 500),
+      url: `https://www.govtrack.us${v.link || ''}`,
+      score: v.total_plus || 0,
+      num_comments: v.total_minus || 0,
+      source: 'govtrack',
+      keyword: v.category || 'legislation',
+    }));
+  } catch (e) {
+    console.log(`[Ken] GovTrack failed: ${e.message}`);
+    return [];
+  }
+}
+
+// ── X/Twitter via Nitter instances (public, no auth needed) ──
+async function scrapeNitterTrending() {
+  const nitterInstances = [
+    'https://nitter.poast.org',
+    'https://nitter.privacydev.net',
+    'https://nitter.cz',
+  ];
+  const searchTerms = ['kalshi', 'polymarket', 'prediction market', 'fed rate decision', 'hurricane season'];
+  const results = [];
+  for (const term of searchTerms) {
+    for (const instance of nitterInstances) {
+      try {
+        const controller = new AbortController();
+        setTimeout(() => controller.abort(), 6000);
+        const url = `${instance}/search?f=tweets&q=${encodeURIComponent(term)}&since=`;
+        const res = await fetch(url, { signal: controller.signal, headers: { 'User-Agent': 'Mozilla/5.0' } });
+        if (!res.ok) continue;
+        const html = await res.text();
+        // Extract tweet text from Nitter HTML
+        const tweetMatches = html.match(/<div class="tweet-content[^"]*"[^>]*>([\s\S]*?)<\/div>/g) || [];
+        for (const match of tweetMatches.slice(0, 5)) {
+          const text = match.replace(/<[^>]+>/g, '').trim().substring(0, 500);
+          if (text.length > 10) {
+            results.push({
+              title: text,
+              url: `${instance}/search?q=${encodeURIComponent(term)}`,
+              score: 0,
+              num_comments: 0,
+              source: 'twitter_nitter',
+              keyword: term,
+            });
+          }
+        }
+        break; // One working instance per term is enough
+      } catch {} // Nitter instances are unreliable, fail silently
+    }
+    await new Promise(r => setTimeout(r, 2000));
+  }
+  return results;
+}
+
 // ── Discord Bot Intelligence (reads messages from joined servers) ──
 const DISCORD_BOT_TOKEN = 'MTQ3MjYyNDg2OTk3NDg2ODA2Mg.GifeyF.C5l9KqQUia-Ex54Ldg23fuxislxwf2QtmkXYII';
 const DISCORD_API = 'https://discord.com/api/v10';
@@ -2384,6 +2545,100 @@ async function redditIntelligenceLoop() {
     totalPosts += tvTotal + lemmyTotal + lobstersTotal + tildesTotal + bskyTotal;
     totalPosts += manifoldTotal + predMarketRedditTotal;
 
+    // ── PredictIt (cross-reference prediction market) ──
+    let predictItTotal = 0;
+    try {
+      const piMarkets = await scrapePredictIt();
+      for (const m of piMarkets) {
+        const sentiment = scoreSentiment(m.title);
+        await kenQ(`
+          INSERT INTO ken_sentiment (source, subreddit, keyword, post_title, post_url, score, num_comments, sentiment_score, raw_text)
+          VALUES ('predictit', 'predictit', 'market', $1, $2, $3, $4, $5, $6)
+          ON CONFLICT DO NOTHING
+        `, [m.title, m.url, m.score, m.num_comments || 0, sentiment, m.extra || '']);
+        predictItTotal++;
+      }
+      totalPosts += predictItTotal;
+      console.log(`[Ken] PredictIt: ${predictItTotal} markets`);
+    } catch (e) {
+      console.log(`[Ken] PredictIt failed: ${e.message}`);
+    }
+
+    // ── FRED Economic Indicators (real data for economic markets) ──
+    let fredTotal = 0;
+    try {
+      const fredData = await scrapeFredIndicators();
+      for (const ind of fredData) {
+        await kenQ(`
+          INSERT INTO ken_sentiment (source, subreddit, keyword, post_title, post_url, score, sentiment_score, raw_text)
+          VALUES ('fred_economic', 'fred', $1, $2, $3, $4, 0, '')
+          ON CONFLICT DO NOTHING
+        `, [ind.keyword, ind.title, ind.url, ind.score]);
+        fredTotal++;
+      }
+      totalPosts += fredTotal;
+      console.log(`[Ken] FRED Economic: ${fredTotal} indicators`);
+    } catch (e) {
+      console.log(`[Ken] FRED failed: ${e.message}`);
+    }
+
+    // ── NWS Active Weather Alerts (severe weather data for weather markets) ──
+    let nwsAlertTotal = 0;
+    try {
+      const alerts = await scrapeNWSAlerts();
+      for (const alert of alerts) {
+        const sentiment = scoreSentiment(alert.title);
+        await kenQ(`
+          INSERT INTO ken_sentiment (source, subreddit, keyword, post_title, post_url, score, num_comments, sentiment_score, raw_text)
+          VALUES ('nws_alerts', 'weather', $1, $2, $3, $4, 0, $5, '')
+          ON CONFLICT DO NOTHING
+        `, [alert.keyword, alert.title, alert.url, alert.score, sentiment]);
+        nwsAlertTotal++;
+      }
+      totalPosts += nwsAlertTotal;
+      console.log(`[Ken] NWS Alerts: ${nwsAlertTotal} active alerts`);
+    } catch (e) {
+      console.log(`[Ken] NWS Alerts failed: ${e.message}`);
+    }
+
+    // ── GovTrack Congressional Votes (legislation for political markets) ──
+    let govTrackTotal = 0;
+    try {
+      const votes = await scrapeGovTrack();
+      for (const v of votes) {
+        const sentiment = scoreSentiment(v.title);
+        await kenQ(`
+          INSERT INTO ken_sentiment (source, subreddit, keyword, post_title, post_url, score, num_comments, sentiment_score, raw_text)
+          VALUES ('govtrack', 'congress', $1, $2, $3, $4, $5, $6, '')
+          ON CONFLICT DO NOTHING
+        `, [v.keyword, v.title, v.url, v.score, v.num_comments || 0, sentiment]);
+        govTrackTotal++;
+      }
+      totalPosts += govTrackTotal;
+      console.log(`[Ken] GovTrack: ${govTrackTotal} congressional votes`);
+    } catch (e) {
+      console.log(`[Ken] GovTrack failed: ${e.message}`);
+    }
+
+    // ── Twitter/X via Nitter (public sentiment, no auth needed) ──
+    let nitterTotal = 0;
+    try {
+      const tweets = await scrapeNitterTrending();
+      for (const t of tweets) {
+        const sentiment = scoreSentiment(t.title);
+        await kenQ(`
+          INSERT INTO ken_sentiment (source, subreddit, keyword, post_title, post_url, score, num_comments, sentiment_score, raw_text)
+          VALUES ('twitter_nitter', 'twitter', $1, $2, $3, 0, 0, $4, '')
+          ON CONFLICT DO NOTHING
+        `, [t.keyword, t.title, t.url, sentiment]);
+        nitterTotal++;
+      }
+      totalPosts += nitterTotal;
+      console.log(`[Ken] Twitter/Nitter: ${nitterTotal} tweets`);
+    } catch (e) {
+      console.log(`[Ken] Twitter/Nitter failed: ${e.message}`);
+    }
+
     // ── Discord (Kalshi, Polymarket, Prediction Markets servers) ──
     let discordTotal = 0;
     try {
@@ -2408,7 +2663,7 @@ async function redditIntelligenceLoop() {
     }
     if (global.gc) global.gc();
 
-    console.log(`[Ken] ═══ FULL SWEEP: ${totalPosts} items (Reddit, HN, ${NEWS_FEEDS.length} feeds, TV, YT, Manifold, r/Kalshi, r/Polymarket, Lemmy, Lobsters, Tildes, Bluesky, Mastodon, Metaculus, Discord) ═══`);
+    console.log(`[Ken] ═══ FULL SWEEP: ${totalPosts} items (Reddit, HN, ${NEWS_FEEDS.length} feeds, TV, YT, Manifold, r/Kalshi, r/Polymarket, Lemmy, Lobsters, Tildes, Bluesky, Mastodon, Metaculus, PredictIt, FRED, NWS Alerts, GovTrack, Twitter, Discord) ═══`);
     return totalPosts;
   } catch (e) {
     console.error('[Ken] Intelligence sweep error:', e.message);

← 1d7b7c1 chore(alshi-dash): update 1 file (.js) [+218/-20]  ·  back to Bertha  ·  chore(alshi-dash,kalshi-dash): update 2 files (.html) [+563/ 1124be9 →