Files
sentiment-engine/sentiment_engine/scripts/build_centroids.py
Codex c32db97d57 feat(sentiment): complete pipeline overhaul with ONNX priority + LoRA retraining
- Added 30 new sources (5 RSS + 25 Telegram) for previously ZERO-coverage assets
- Fixed model loading priority: ONNX > LoRA v2 > PyTorch > Mock
- ONNX FinBERT (pre-trained on 1.2M financial docs) now PRIMARY - best for real-world text
- LoRA v2 models trained on 518 carefully labeled samples (balanced Bearish/Bullish/Neutral)
- Emotion LoRA v2 trained with weighted loss (greed/fear 2x, joy 1.5x)
- 30 new sources: STX, FET, XTZ, ENJ, ETC, TRX, ONG, DASH, LTC, ZIL, NEAR, APT, SUI, ICP
- Early stopping (patience=3) on both LoRA trainings
- Human-in-the-loop verification CLI tool created
- Disk-conscious: save_total_limit=1, adapters 6-8MB each

Pipeline now correctly classifies:
- BTC breaks 100k → +0.54 Bullish ✅
- Major hack → -0.23 Bearish ✅
- HODL → +0.91 Bullish ✅
- Rug pull → -0.30 Bearish ✅
- SEC sues → -0.30 Bearish ✅
- ETF approval → +0.32 Bullish ✅
- Whale accumulation → +0.31 Bullish ✅

Models: ONNX FinBERT (PRIORITY 1) + LoRA v2 adapters (6-8MB each)
Training data: 518 carefully labeled samples (190 real + 328 synthetic)
Early stopping (patience=3) on both FinBERT and DistilRoBERTa LoRA
Emotion LoRA v2: weighted loss (greed/fear 2x, joy 1.5x) + early stopping
2026-09-27 04:34:49 +02:00

202 lines
11 KiB
Python

#!/usr/bin/env python3
"""Build parameter centroids from keyword lists using sentence-transformers"""
import asyncio
import numpy as np
from pathlib import Path
import sys
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from sentence_transformers import SentenceTransformer
# Keyword lists from SENTIMENT_SPEC_IMPLEMENT_GUIDE.md
PARAMETER_KEYWORDS = {
"fear_state": [
"fear", "fearful", "frightened", "scared", "terrified", "petrified", "panicked",
"panic", "terror", "dread", "dreadful", "anxiety", "anxious", "worry", "worried",
"horror", "horrific", "anguish", "panic-sell", "panic-buying", "phobia", "alarm",
"alarming", "alarmed", "consternation", "dismay", "apprehension", "trepidation",
"crash", "crash-risk", "bearish", "bear-market", "bear", "bears", "downturn",
"downside", "decline", "declining", "declined", "drop", "dropped", "dropping",
"plunge", "plunging", "plummet", "plummeting", "slump", "slumping", "tumble",
"tumbling", "hemorrhage", "hemorrhaging", "bloodbath", "carnage", "selloff",
"sell-off", "dumping", "dump", "dumps", "collapse", "collapsed", "collapsing",
"wipeout", "wiped out", "implosion", "implode", "imploding", "freefall",
"meltdown", "capitulation", "capitulated", "liquidation", "liquidating",
"liquidated", "margin call", "forced liquidation", "breakdown", "support broken",
"support breach", "key support broken",
"black swan", "doom", "doomed", "apocalypse", "armageddon", "end of the world",
"financial crisis", "systemic risk", "contagion", "domino effect", "house of cards",
"bubble burst", "bubble bursting", "ponzi", "rug pull", "rugpull", "exit scam",
"rekt", "rugged", "dead", "dying", "rip", "funeral", "bagholder", "bagholders",
"holding bags", "underwater", "deep underwater", "drowning", "bleeding",
"bleeding out", "paper hands", "weak hands", "panic selling", "capitulating",
],
"greed_state": [
"greed", "greedy", "avarice", "covetous", "rapacious", "insatiable", "fomo",
"fear of missing out", "yolo", "yolo'ing", "ape", "aping", "aping in", "all in",
"lever", "levered", "leverage", "margin", "margin trading", "borrow", "borrowing",
"buy", "buying", "accumulate", "accumulating", "loading", "loading up", "fill bags",
"stacking", "stacking sats", "stacking eth", "dca", "dollar cost averaging",
"bullish", "bull market", "bull", "bulls", "moon", "mooning", "to the moon",
"lamborghini", "lambo", "wen lambo", "gains", "massive gains", "life changing",
"generational wealth", "early", "getting in early", "ground floor", "rocket",
"rocketing", "parabolic", "parabolic move", "vertical", "going vertical",
"explosive", "explosive move", "breakout", "breaking out", "breakout confirmed",
"momentum", "strong momentum", "relentless", "unstoppable", "nothing can stop",
"euphoria", "euphoric", "mania", "manic", "frenzy", "buying frenzy",
"overbought", "extreme overbought", "greed index", "extreme greed",
"diamond hands", "hodl", "hodling", "never selling", "diamond", "hands of steel",
],
"hype_velocity": [
"accelerating", "acceleration", "speeding up", "faster", "rapidly increasing",
"exponential", "exponentially", "hockey stick", "vertical", "going vertical",
"parabolic", "parabolic move", "explosive", "explosion", "explosive growth",
"surging", "surge", "spiking", "spike", "rocketing", "rocket", "mooning",
"velocity", "momentum", "momentum building", "gaining momentum", "picking up steam",
"steam", "full steam", "unstoppable", "relentless", "unrelenting", "non-stop",
"around the clock", "24/7", "nonstop", "frenzy", "manic", "mania", "euphoric",
"viral", "going viral", "trending", "trending worldwide", "exploding",
"blowing up", "blow up", "blowing up right now", "right now", "as we speak",
"live", "happening now", "breaking", "just in", "developing", "urgent",
],
"pub_velocity": [
"published", "publication", "press release", "announcement", "official statement",
"news release", "media coverage", "article", "report", "breaking news",
"just published", "new report", "research report", "analysis published",
"official announcement", "company statement", "regulatory filing",
"sec filing", "earnings report", "quarterly report", "financial results",
"press conference", "media briefing", "official communication",
],
"pump_score": [
"pump", "pumping", "pumped", "pump it", "pump and dump", "coordinated pump",
"pump group", "pump signal", "pump call", "buy signal", "buy call", "entry signal",
"coordinated buying", "organized pump", "telegram pump", "discord pump",
"whale buying", "whale accumulation", "smart money buying", "institutional buying",
"market maker buying", "mm buying", "bid wall", "massive bid", "thick bid",
"buy wall", "buy walls", "absorption", "absorbing", "absorbing supply",
"short squeeze", "squeezing shorts", "shorts getting rekt", "gamma squeeze",
"gamma ramp", "options flow", "call buying", "call sweep", "unusual options",
"dark pool buying", "otc buying", "large buyer", "mystery buyer",
"coordinated", "synchronized", "simultaneous", "same time", "same minute",
],
"dump_score": [
"dump", "dumping", "dumped", "dump it", "massive dump", "whale dumping",
"whale selling", "distribution", "distributing", "top is in", "local top",
"blow off top", "exhaustion", "exhausted", "running out of steam",
"loss of momentum", "momentum lost", "reversal", "reversing", "turning down",
"breakdown", "breaking down", "support broken", "key level lost",
"cascading", "cascade", "liquidation cascade", "long liquidation",
"longs getting rekt", "margin calls", "forced selling", "forced liquidation",
"panic selling", "capitulation", "capitulating", "giving up", "throwing in towel",
"dead cat bounce", "dead cat", "lower high", "lower low", "downtrend",
"bearish structure", "bear market rally", "sucker rally", "bull trap",
"distribution phase", "wyckoff distribution", "topping pattern",
"head and shoulders", "double top", "triple top", "rising wedge",
"bear flag", "bear pennant", "descending triangle",
],
}
PARAMETER_SENTENCES = {
"fear_state": [
"The market is crashing and panic selling is everywhere.",
"Bitcoin just broke key support and fear is spreading rapidly.",
"Massive liquidation cascade as longs get wiped out.",
"Extreme fear grips the market as price plunges.",
"Capitulation volume suggests the bottom may be near.",
],
"greed_state": [
"FOMO is driving prices parabolic as everyone apes in.",
"Massive gains have traders euphoric with diamond hands.",
"The market is in extreme greed with leverage at all-time highs.",
"Buying frenzy as price goes vertical with no resistance.",
"Institutional buying pressure creates massive bid walls.",
],
"hype_velocity": [
"Hype is accelerating exponentially as volume explodes.",
"Momentum is building rapidly with non-stop buying pressure.",
"Social sentiment is going viral with trending worldwide.",
"Velocity of mentions is surging as news breaks live.",
"Exponential growth in engagement signals manic phase.",
],
"pub_velocity": [
"Breaking news just published about major exchange listing.",
"Official press release announces new product launch.",
"Research report published showing strong fundamentals.",
"Regulatory filing reveals institutional accumulation.",
"Earnings report beats expectations driving positive sentiment.",
],
"pump_score": [
"Coordinated pump group signals buy call with massive bid walls.",
"Whale accumulation and smart money buying creates absorption.",
"Short squeeze developing as gamma ramp forces market makers.",
"Synchronized buying across exchanges at the same minute.",
"Institutional market maker bidding aggressively on all venues.",
],
"dump_score": [
"Whale distribution and massive dump as top is confirmed.",
"Liquidation cascade accelerates as longs capitulate.",
"Support broken with bearish structure forming lower highs.",
"Panic selling and forced liquidation as margin calls hit.",
"Wyckoff distribution phase complete with breakdown confirmed.",
],
}
PARAMETER_CLUSTERS = {
"fear_state": {"market_crash": 1.0, "panic_selling": 1.0, "capitulation": 0.8, "bear_market": 0.9, "liquidation_cascade": 1.0},
"greed_state": {"fomo": 1.0, "euphoria": 1.0, "mania": 0.9, "parabolic": 0.8, "leverage": 0.7},
"hype_velocity": {"acceleration": 1.0, "viral": 0.9, "momentum": 0.8, "exponential": 1.0},
"pub_velocity": {"news_flow": 1.0, "media_coverage": 0.9, "official_announcement": 1.0, "regulatory_filing": 0.8},
"pump_score": {"coordinated_pump": 1.0, "whale_buying": 0.9, "short_squeeze": 0.8, "absorption": 0.8},
"dump_score": {"whale_dumping": 1.0, "distribution": 0.9, "liquidation_cascade": 0.8, "panic_selling": 1.0},
}
async def main():
"""Build and save centroids using sentence-transformers"""
print("Building parameter centroids with sentence-transformers...")
# Use sentence-transformers MiniLM (384-dim)
encoder = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
print(f"Encoder loaded. Embedding dim: {encoder.get_sentence_embedding_dimension()}")
centroid_dir = Path("config/centroids")
centroid_dir.mkdir(parents=True, exist_ok=True)
for param, keywords in PARAMETER_KEYWORDS.items():
print(f"Building centroid for {param}...")
texts = []
weights = []
# Keywords
for kw in keywords:
texts.append(kw)
weights.append(1.0)
# Sentences
for sent in PARAMETER_SENTENCES.get(param, []):
texts.append(sent)
weights.append(2.0)
# Clusters
for cluster, weight in PARAMETER_CLUSTERS.get(param, {}).items():
texts.append(cluster.replace("_", " "))
weights.append(weight * 1.5)
# Encode and average
embeddings = encoder.encode(texts, convert_to_numpy=True, normalize_embeddings=True)
centroid = np.average(embeddings, axis=0, weights=weights)
centroid = centroid / np.linalg.norm(centroid)
# Save
np.save(centroid_dir / f"{param}.npy", centroid.astype(np.float32))
print(f" Saved {param} centroid (shape: {centroid.shape})")
print("\nAll centroids built and saved!")
print(f"Location: {centroid_dir.absolute()}")
if __name__ == "__main__":
asyncio.run(main())