95 lines
1.9 KiB
Go
95 lines
1.9 KiB
Go
package news
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/pheinrich/aitrade/pkg/model"
|
|
)
|
|
|
|
// Simple keyword-based sentiment analyzer
|
|
type Analyzer struct {
|
|
positiveKeywords map[string]int
|
|
negativeKeywords map[string]int
|
|
}
|
|
|
|
func NewAnalyzer() *Analyzer {
|
|
return &Analyzer{
|
|
positiveKeywords: map[string]int{
|
|
"profit": 2,
|
|
"gain": 2,
|
|
"growth": 2,
|
|
"surge": 2,
|
|
"rally": 2,
|
|
"bullish": 3,
|
|
"upgrade": 2,
|
|
"beat": 2,
|
|
"record": 1,
|
|
"strong": 1,
|
|
"positive": 1,
|
|
"success": 1,
|
|
"win": 1,
|
|
"jump": 2,
|
|
"soar": 3,
|
|
"outperform": 2,
|
|
},
|
|
negativeKeywords: map[string]int{
|
|
"loss": 2,
|
|
"decline": 2,
|
|
"fall": 2,
|
|
"drop": 2,
|
|
"crash": 3,
|
|
"bearish": 3,
|
|
"downgrade": 2,
|
|
"miss": 2,
|
|
"weak": 1,
|
|
"negative": 1,
|
|
"fail": 2,
|
|
"plunge": 3,
|
|
"slump": 2,
|
|
"underperform": 2,
|
|
"risk": 1,
|
|
"concern": 1,
|
|
},
|
|
}
|
|
}
|
|
|
|
func (a *Analyzer) Analyze(article *model.NewsArticle) {
|
|
text := strings.ToLower(article.Title + " " + article.Content)
|
|
words := strings.Fields(text)
|
|
|
|
positiveScore := 0
|
|
negativeScore := 0
|
|
|
|
for _, word := range words {
|
|
word = strings.Trim(word, ".,!?;:\"'()")
|
|
|
|
if score, ok := a.positiveKeywords[word]; ok {
|
|
positiveScore += score
|
|
}
|
|
if score, ok := a.negativeKeywords[word]; ok {
|
|
negativeScore += score
|
|
}
|
|
}
|
|
|
|
// Calculate sentiment score from -1.0 to 1.0
|
|
totalScore := positiveScore + negativeScore
|
|
if totalScore == 0 {
|
|
score := 0.0
|
|
article.SentimentScore = &score
|
|
article.SentimentLabel = "neutral"
|
|
return
|
|
}
|
|
|
|
sentimentScore := float64(positiveScore-negativeScore) / float64(totalScore)
|
|
article.SentimentScore = &sentimentScore
|
|
|
|
// Label the sentiment
|
|
if sentimentScore > 0.3 {
|
|
article.SentimentLabel = "positive"
|
|
} else if sentimentScore < -0.3 {
|
|
article.SentimentLabel = "negative"
|
|
} else {
|
|
article.SentimentLabel = "neutral"
|
|
}
|
|
}
|