Разработка системы оценки тональности публикаций о токенах
Система оценки тональности для конкретного токена — это таргетированный инструмент: не рыночный sentiment в целом, а направленный анализ того, что пишут именно об этом активе. Для проектов меньше BTC и ETH, где информационное давление особенно велико, это может быть ключевым преимуществом.
Token-specific NLP challenges
Ambiguity: «ETH» в контексте может быть Ethereum, аббревиатурой Zurich (ETH Zurich), или финансовым инструментом. Контекстная disambiguation обязательна.
Token aliases: Ethereum = ETH = Ether = $ETH. Uniswap = UNI. Нужна полная база синонимов.
Cross-lingual: крипто-сообщество глобально. Корейские, китайские, русские публикации о токенах требуют мультиязычных моделей.
Token mention extraction
import re
from typing import Optional
# База синонимов токенов
TOKEN_ALIASES = {
'BTC': ['bitcoin', 'btc', '$btc', '#bitcoin', '#btc', 'satoshi'],
'ETH': ['ethereum', 'eth', '$eth', '#ethereum', 'ether', 'vitalik coin'],
'SOL': ['solana', 'sol', '$sol', '#solana'],
'UNI': ['uniswap', 'uni', '$uni', 'uniswap protocol'],
# ... и т.д.
}
def extract_token_mentions(text: str) -> list[str]:
"""Находим все упомянутые токены в тексте"""
text_lower = text.lower()
mentioned = set()
for token, aliases in TOKEN_ALIASES.items():
for alias in aliases:
# Точное совпадение с word boundary
pattern = r'\b' + re.escape(alias) + r'\b'
if re.search(pattern, text_lower):
mentioned.add(token)
break
# Cashtags (e.g., $BTC, $ETH)
cashtags = re.findall(r'\$([A-Z]{2,10})\b', text.upper())
mentioned.update(cashtags)
return list(mentioned)
def is_about_token(text: str, token: str) -> tuple[bool, float]:
"""Степень релевантности текста к конкретному токену"""
mentions = extract_token_mentions(text)
if token not in mentions:
return False, 0.0
# Подсчёт частоты упоминания
all_token_mentions = sum(text.lower().count(alias.lower())
for alias in TOKEN_ALIASES.get(token, [token]))
other_token_mentions = sum(
text.lower().count(alias.lower())
for other_token in mentions if other_token != token
for alias in TOKEN_ALIASES.get(other_token, [other_token])
)
# Если о токене говорится значительно больше чем о других — это про него
relevance = all_token_mentions / max(all_token_mentions + other_token_mentions, 1)
return True, relevance
Aspect-based sentiment analysis (ABSA)
Продвинутый подход: sentiment не общий для текста, а по конкретным аспектам токена:
- Technology: обновления протокола, bugs, security
- Team: founders, advisors, departures
- Market: price action, trading volume, listings
- Community: ecosystem growth, developer activity
- Regulation: legal status, government actions
from transformers import pipeline
class AspectBasedSentimentAnalyzer:
def __init__(self):
# QA-based ABSA: задаём вопросы о конкретных аспектах
self.qa_pipeline = pipeline('question-answering',
model='deepset/roberta-large-squad2')
self.sentiment = pipeline('sentiment-analysis',
model='ProsusAI/finbert')
ASPECT_QUESTIONS = {
'technology': 'What do they say about the technology or protocol?',
'team': 'What do they say about the team or founders?',
'price': 'What is the sentiment about the price or market performance?',
'community': 'What do they say about the community or adoption?'
}
def analyze_aspects(self, text, token):
results = {}
for aspect, question in self.ASPECT_QUESTIONS.items():
try:
answer = self.qa_pipeline(
question=f"Regarding {token}: {question}",
context=text
)
if answer['score'] > 0.3:
sentiment_result = self.sentiment(answer['answer'])[0]
results[aspect] = {
'excerpt': answer['answer'],
'sentiment': sentiment_result['label'],
'confidence': sentiment_result['score']
}
except:
continue
return results
Scoring модель
Итоговый token sentiment score для каждого временного интервала:
class TokenSentimentScorer:
def __init__(self, token):
self.token = token
self.publications = []
def add_publication(self, text, source, engagement=1, timestamp=None):
# Проверяем релевантность
is_relevant, relevance = is_about_token(text, self.token)
if not is_relevant or relevance < 0.3:
return
# Анализируем sentiment
sentiment = analyze_sentiment(text)
self.publications.append({
'text': text[:200],
'source': source,
'engagement': engagement,
'relevance': relevance,
'sentiment_score': sentiment['score'],
'timestamp': timestamp
})
def compute_score(self, window_hours=24, decay_factor=0.9):
"""Score с экспоненциальным decay по времени"""
now = datetime.utcnow()
total_weight = 0
weighted_score = 0
source_weights = {'news': 2.0, 'twitter': 1.5, 'reddit': 1.8, 'telegram': 1.3}
for pub in self.publications:
age_hours = (now - pub['timestamp']).total_seconds() / 3600
time_decay = decay_factor ** age_hours
weight = (
pub['engagement'] *
pub['relevance'] *
source_weights.get(pub['source'], 1.0) *
time_decay
)
weighted_score += pub['sentiment_score'] * weight
total_weight += weight
return weighted_score / max(total_weight, 1e-8)
Token Sentiment Timeline
Ключевая визуализация: sentiment score токена наложенный на ценовой график. На исторических данных хорошо виден leading indicator эффект — sentiment начинает расти/падать за 4–24 часа до ценового движения.
Alert система
Sentiment spike alert: если sentiment токена изменился > 0.4 за последний час → alert.
Divergence alert: цена растёт, но sentiment резко падает (или наоборот) → осторожность.
Anomalous volume of publications: количество публикаций о токене превысило N × обычный уровень → что-то происходит.
Разрабатываем систему token-specific sentiment scoring с ABSA, relevance filtering, engagement weighting, temporal decay и realtime alerts.







