<div align="center">
# ๐ finvader
### Finance-aware sentiment analysis for Rust
**VADER, re-tuned for the market** โ financial lexicon, phrase rules, and
catalyst detection for news headlines and market text instead of tweets.
[](https://crates.io/crates/finvader)
[](https://docs.rs/finvader)
[](https://github.com/albyte-ai/finvader/actions)
[](https://github.com/albyte-ai/finvader/blob/main/LICENSE)
[-brightgreen?style=flat-square)](#-accuracy)
[-red?style=flat-square)](#-accuracy)
[](#-performance)
[](https://github.com/albyte-ai/finvader/blob/main/Cargo.toml)
[](https://github.com/albyte-ai/finvader/blob/main/Cargo.toml)
</div>
---
## ๐ฏ Why finvader?
Generic [VADER](https://github.com/cjhutto/vaderSentiment) was calibrated for
social media. On financial text it misfires in **two directions**:
| **Misses finance sentiment** | *"beats expectations"*, *"cuts guidance"*, *"going concern"* โ score โ 0 | ๐ Financial lexicon + phrase rules |
| **Misfires on neutral finance words** | *"**gross** margin"*, *"**cancer** drug"*, *"**debt** refinancing"* โ scored negative | ๐ญ Neutral-override masking |
And it adds something VADER never had: **๐จ catalyst detection** โ single
events (FDA approval, buyout offer, index inclusion, bankruptcy) that
permanently re-rate a stock and deserve to be surfaced on their own.
## ๐ Accuracy
On a hand-labeled set of 60 financial headlines:
| generic VADER | 31 / 60 | 51.7% | ๐ฅ๐ฅ๐ฅ๐ฅ๐ฅโฌโฌโฌโฌโฌ |
| **finvader** | **60 / 60** | **100%** | ๐ฉ๐ฉ๐ฉ๐ฉ๐ฉ๐ฉ๐ฉ๐ฉ๐ฉ๐ฉ |
## ๐ Quick start
```toml
[dependencies]
finvader = "0.1"
```
```rust
use finvader::{FinVader, Signal};
let fv = FinVader::new();
let s = fv.analyze("Acme beats Q3 expectations and raises full-year guidance");
assert!(s.compound > 0.5);
assert_eq!(s.signal, Signal::StronglyBullish);
// Which terms drove the score:
for t in &s.triggers {
println!("{:<20} {:+.3}", t.term, t.valence);
}
```
> ๐ก Construct one `FinVader` and reuse it across calls โ it loads the
> lexicons once and is `Send + Sync`.
## โ๏ธ How it works
Each input runs two parallel passes โ a masked base-VADER pass and a
financial layer (phrases, gap-phrases, single words) โ then the two are
blended, nudged by any catalyst, and clamped:
<p align="center">
<img src="https://raw.githubusercontent.com/albyte-ai/finvader/main/docs/pipeline.svg" alt="finvader analysis pipeline" width="620">
</p>
| ๐ก **normalize** | Lowercase, strip punctuation, keep market-text characters (`-`, `%`, `$`, `'`) |
| ๐ญ **mask_for_base** | Replace finance-neutral words (`gross`, `cancer`, `debt`, `crude`, `vice`, `share`โฆ) with a placeholder *before* base VADER, so everyday valences never pollute the score |
| ๐งฉ **phrase / gap / word passes** | Match multi-word phrases (`beats expectations`), gap-tolerant pairs (`beats โฆ expectations`, up to 2 tokens apart), and single words โ consumed so nothing double-counts. `up 45%` / `down 30%` become magnitude-scaled moves |
| ๐ **negation & boosters** | `failed to beat expectations` **flips** ยท `sharply missed` **amplifies** ยท `slightly missed` **softens** ยท `beat by 40%` **scales on magnitude** |
| โ๏ธ **blend** | With financial terms present: `0.35 ร base + 0.65 ร financial`; otherwise base VADER passes through untouched |
| ๐จ **catalyst bonus** | A detected event shifts the compound by ยฑ0.25 |
### ๐ Signals
`compound` maps to a discrete `Signal`:
| `>= 0.5` | `StronglyBullish` | ๐ข๐ข |
| `>= 0.15` | `Bullish` | ๐ข |
| `-0.15 .. 0.15` | `Neutral` | โช |
| `<= -0.15` | `Bearish` | ๐ด |
| `<= -0.5` | `StronglyBearish` | ๐ด๐ด |
### ๐จ Catalyst detection
Beyond the smooth sentiment score, finvader flags **episodic-pivot events**
and returns them as `Option<Catalyst>`:
| FDA approval / clearance | FDA rejection |
| Breakthrough therapy | Missed / failed endpoint |
| Met primary endpoint | Chapter 11 / Chapter 7 |
| Buyout / takeover / merger | Going concern |
| S&P 500 inclusion | SEC charges |
| Contract awards | Accounting fraud |
| Record quarter, beat-and-raise | Auditor resignation |
## ๐ Where it fits
finvader is the scoring core of a news-driven momentum alert pipeline:
<p align="center">
<img src="https://raw.githubusercontent.com/albyte-ai/finvader/main/docs/system.svg" alt="finvader in an alert pipeline" width="820">
</p>
## โก Performance
Single-threaded, release build, `cargo run --release --example bench`
(Apple Silicon):
| generic VADER | 1.8 ยตs | ~570,000 / sec |
| **finvader** | 22.3 ยตs | **~45,000 / sec** |
finvader does more work per call (masking + three match passes + catalyst
detection) and still clears tens of thousands of headlines per second per
core.
## ๐ Lexicon
Single-word and phrase valences are calibrated for market news, informed by
the [Loughran-McDonald](https://sraf.nd.edu/loughranmcdonald-master-dictionary/)
financial sentiment research. Valences are on VADER's `-4.0 ..= 4.0` scale.
## ๐งช Examples
```sh
cargo run --example demo # side-by-side finvader vs generic VADER
cargo run --release --example bench # throughput benchmark
```
## ๐ License
MIT ยฉ [albyte-ai](https://github.com/albyte-ai)