peyterho commited on
Commit
f385a4c
Β·
verified Β·
1 Parent(s): 1ac80ae

Rewrite README: plain-language intro, simple vs advanced usage, clear 3-line quickstart

Browse files
Files changed (1) hide show
  1. README.md +146 -197
README.md CHANGED
@@ -1,273 +1,222 @@
1
- # 🏦 Macroeconomic Sentiment Analysis Pipeline
2
 
3
- A multi-head NLP system for scoring macroeconomic text β€” news articles, central bank policy statements, regulatory documents, tweets, and climate/ESG reports.
4
 
5
- ## What's New in v0.2.0
6
 
7
- All three transformer heads have been **fine-tuned on a combined 20K financial sentiment corpus**, dramatically improving accuracy:
8
 
9
- | Head | Base Model | Params | v0.1 (off-the-shelf) | **v0.2 (fine-tuned)** |
10
- |------|-----------|--------|---------------------|-----------------------|
11
- | **FinBERT** | ProsusAI/finbert | 110M | ~0.67 acc | **0.897 acc / 0.881 F1** |
12
- | **RoBERTa-Large** | soleimanian/financial-roberta-large-sentiment | 355M | ~0.67 acc | **0.913 acc / 0.902 F1** |
13
- | **ClimateBERT** | climatebert/distilroberta-base-climate-sentiment | 82M | ~0.67 acc | **0.889 acc / 0.872 F1** |
14
 
15
- Fine-tuned models:
16
- - [`peyterho/finbert-macro-sentiment`](https://huggingface.co/peyterho/finbert-macro-sentiment)
17
- - [`peyterho/financial-roberta-large-macro-sentiment`](https://huggingface.co/peyterho/financial-roberta-large-macro-sentiment)
18
- - [`peyterho/climatebert-macro-sentiment`](https://huggingface.co/peyterho/climatebert-macro-sentiment)
19
 
20
- ## Architecture
 
21
 
22
- ```
23
- Input Text
24
- β”‚
25
- β”œβ”€β–Ί [Keyword Topic Router] ──► Policy/Macro ──► Financial-RoBERTa-Large
26
- β”‚ ──► Climate/ESG ──► ClimateBERT
27
- β”‚ ──► News/Corp ──► FinBERT
28
- β”‚ ──► Social/Tweet ──► FinBERT
29
- β”‚
30
- β”œβ”€β–Ί [Loughran-McDonald (2011)] ──► polarity, subjectivity
31
- β”œβ”€β–Ί [Henry (2008)] ────────────► earnings tone
32
- β”œβ”€β–Ί [Sautner et al. (2023)] ───► climate risk/opportunity density
33
- β”œβ”€β–Ί [Macro Policy Dict] ───────► hawkish/dovish, crisis, uncertainty
34
- β”‚
35
- └─► [Dynamic Combiner] ──► Weighted fusion with crisis-adaptive weights
36
- ──► Final macro sentiment score [-1, +1]
37
  ```
38
 
39
- ## Installation
40
 
41
- ```bash
42
- pip install transformers torch pysentiment2 scikit-learn numpy datasets
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  ```
44
 
45
- Then clone this repo or copy the `macro_sentiment/` package:
 
 
 
 
 
 
46
 
47
  ```bash
48
- # Option 1: Clone the repo
49
- git clone https://huggingface.co/peyterho/macro-sentiment-finbert
50
- cd macro-sentiment-finbert
51
 
52
- # Option 2: Download just the package
53
  pip install huggingface_hub
54
- python -c "from huggingface_hub import snapshot_download; snapshot_download('peyterho/macro-sentiment-finbert', local_dir='.')"
 
55
  ```
56
 
57
- ## Quick Start
58
-
59
- ### Full Pipeline (fine-tuned models, recommended)
60
 
61
  ```python
62
  from macro_sentiment import MacroSentimentPipeline
63
 
64
- # v0.2.0: Automatically uses fine-tuned models by default
65
- pipe = MacroSentimentPipeline(device="cpu")
66
 
67
  result = pipe("The Federal Reserve raised rates by 75bps citing persistent inflation.")
68
  print(result.summary())
69
- # Sentiment: ... | Policy: Very Hawkish (+0.999) | Crisis: Normal | Domain: policy
70
-
71
- # Access individual scores
72
- print(result.macro_sentiment) # [-1, +1] composite score
73
- print(result.policy_stance) # [-1 dovish, +1 hawkish]
74
- print(result.crisis_signal) # [0, 1] crisis intensity
75
- print(result.climate_exposure) # [0, 1] climate topic density
76
- print(result.uncertainty) # [0, 1] uncertainty level
77
  ```
78
 
79
- ### Using Individual Fine-Tuned Models Directly
80
-
81
- Each fine-tuned head can be used standalone via the standard `transformers` pipeline β€” no need for the full macro_sentiment package:
82
 
83
  ```python
84
- from transformers import pipeline
 
 
 
 
 
 
 
85
 
86
- # FinBERT (110M) β€” general financial sentiment
87
- finbert = pipeline("text-classification", model="peyterho/finbert-macro-sentiment")
88
- finbert("Tesla shares surged 15% after beating earnings expectations.")
89
- # [{'label': 'positive', 'score': 0.998}]
90
 
91
- # RoBERTa-Large (355M) β€” best accuracy, policy/formal text
92
- roberta = pipeline("text-classification", model="peyterho/financial-roberta-large-macro-sentiment")
93
- roberta("Markets crashed amid recession fears and massive layoffs.")
94
- # [{'label': 'negative', 'score': 0.997}]
95
 
96
- # ClimateBERT (82M) β€” climate/ESG sentiment
97
- climate = pipeline("text-classification", model="peyterho/climatebert-macro-sentiment")
98
- climate("Renewable energy investments surged as solar costs fell to record lows.")
99
- # [{'label': 'opportunity', 'score': ...}]
100
- ```
101
 
102
- ### Using the Ensemble Directly
 
 
103
 
104
  ```python
105
- from macro_sentiment import TransformerEnsemble
 
 
 
 
106
 
107
- # Fine-tuned models are the default (v0.2.0)
108
- ensemble = TransformerEnsemble(device="cpu")
109
 
110
- # Route to the best head automatically
111
- result = ensemble.score_routed("ECB signals patience on rate cuts.")
112
- print(result["head_used"]) # "policy" (RoBERTa-Large)
113
- print(result["sentiment_score"]) # [-1, +1]
114
 
115
- # Score with all three heads
116
- result = ensemble.score_all("Markets tumbled on trade war fears.")
117
- print(result["ensemble_mean"]) # average of all 3 heads
118
- print(result["finbert_composite_score"])
119
- print(result["policy_composite_score"])
120
- print(result["climate_composite_score"])
121
- ```
 
 
 
122
 
123
- ### Customizing Which Models to Use
124
 
125
  ```python
126
  from macro_sentiment import TransformerEnsemble
127
- from macro_sentiment import ORIGINAL_FINBERT, ORIGINAL_ROBERTA, ORIGINAL_CLIMATEBERT
128
 
129
- # Use original off-the-shelf models (v0.1.0 behavior)
130
- ensemble = TransformerEnsemble(
131
- finbert_model=ORIGINAL_FINBERT, # "ProsusAI/finbert"
132
- roberta_model=ORIGINAL_ROBERTA, # "soleimanian/financial-roberta-large-sentiment"
133
- climatebert_model=ORIGINAL_CLIMATEBERT, # "climatebert/distilroberta-base-climate-sentiment"
134
- )
135
 
136
- # Mix and match: fine-tuned FinBERT + original RoBERTa + fine-tuned ClimateBERT
137
  ensemble = TransformerEnsemble(
138
  finbert_model="peyterho/finbert-macro-sentiment",
139
- roberta_model="soleimanian/financial-roberta-large-sentiment",
140
  climatebert_model="peyterho/climatebert-macro-sentiment",
141
  )
142
 
143
- # Use any custom fine-tuned model
144
- ensemble = TransformerEnsemble(
145
- finbert_model="your-org/your-custom-finbert",
146
- )
147
- ```
148
-
149
- ### Dictionary-Only Mode (no GPU, instant)
150
-
151
- ```python
152
- pipe = MacroSentimentPipeline(load_transformers=False)
153
- result = pipe("Markets crashed amid recession fears.", mode="dict_only")
154
- print(result.policy_stance) # hawkish/dovish from dictionary
155
- print(result.crisis_signal) # crisis intensity from dictionary
156
- ```
157
-
158
- ## Output Fields
159
-
160
- | Field | Range | Description |
161
- |-------|-------|-------------|
162
- | `macro_sentiment` | [-1, +1] | Composite sentiment (weighted transformer + dictionary) |
163
- | `policy_stance` | [-1, +1] | Dovish (-1) to Hawkish (+1) β€” 80% dictionary, 20% transformer |
164
- | `financial_sentiment` | [-1, +1] | Financial sentiment from active transformer head |
165
- | `climate_sentiment` | [-1, +1] | Climate risk (-1) to opportunity (+1) |
166
- | `crisis_signal` | [0, 1] | Crisis intensity (drives dynamic weight adjustment) |
167
- | `uncertainty` | [0, 1] | Macroeconomic uncertainty level |
168
- | `confidence` | [0, 1] | Model confidence (agreement + topic confidence + uncertainty) |
169
- | `detected_domain` | str | `policy` / `climate` / `financial_news` / `social` |
170
- | `topic` | str | Human-readable topic label |
171
- | `head_used` | str | Which transformer head was activated |
172
- | `lm_polarity` | [-1, +1] | Loughran-McDonald polarity |
173
- | `henry_polarity` | [-1, +1] | Henry (2008) earnings tone |
174
- | `climate_exposure` | [0, 1] | Sautner-style climate term density |
175
- | `raw_features` | dict | All 24+ dictionary + transformer features |
176
-
177
- ## Evaluation Results
178
-
179
- ### v0.2.0 β€” Fine-Tuned Transformer Heads (4,333 test samples)
180
-
181
- | Model | Accuracy | F1 Macro | F1 Weighted |
182
- |-------|----------|----------|-------------|
183
- | **RoBERTa-Large (fine-tuned)** | **0.913** | **0.902** | **0.914** |
184
- | FinBERT (fine-tuned) | 0.897 | 0.881 | 0.898 |
185
- | ClimateBERT (fine-tuned) | 0.889 | 0.872 | 0.890 |
186
-
187
- ### Per-Class Performance (Fine-Tuned FinBERT, 4,333 samples)
188
 
 
 
 
189
  ```
190
- precision recall f1-score support
191
 
192
- negative 0.8051 0.8945 0.8474 711
193
- neutral 0.9518 0.8925 0.9212 2613
194
- positive 0.8417 0.9118 0.8754 1009
195
 
196
- accuracy 0.8973 4333
197
- macro avg 0.8662 0.8996 0.8813 4333
198
- weighted avg 0.9021 0.8973 0.8984 4333
 
 
199
  ```
200
 
201
- ### v0.1.0 β€” Off-the-Shelf Baselines
202
-
203
- | Method | Accuracy | F1 Macro | F1 Weighted |
204
- |--------|----------|----------|-------------|
205
- | Dictionary Composite (LM+Henry) | 0.568 | 0.528 | 0.578 |
206
- | Meta-Classifier (Dict features) | 0.669 | 0.578 | 0.650 |
207
-
208
- ### Improvement Summary
209
-
210
- | Metric | v0.1.0 (best) | v0.2.0 (best) | Ξ” |
211
- |--------|---------------|---------------|---|
212
- | Accuracy | 0.669 | **0.913** | +24.4pp |
213
- | F1 Macro | 0.578 | **0.902** | +32.4pp |
214
- | Negative Recall | 0.47 | **0.89** | +42pp |
215
- | Positive Recall | 0.35 | **0.91** | +56pp |
216
 
217
- ## Transformer Models
218
 
219
- | Head | Fine-Tuned Model | Base Model | Params |
220
- |------|-----------------|-----------|--------|
221
- | **FinBERT** | [`peyterho/finbert-macro-sentiment`](https://huggingface.co/peyterho/finbert-macro-sentiment) | ProsusAI/finbert | 110M |
222
- | **RoBERTa-Large** | [`peyterho/financial-roberta-large-macro-sentiment`](https://huggingface.co/peyterho/financial-roberta-large-macro-sentiment) | soleimanian/financial-roberta-large-sentiment | 355M |
223
- | **ClimateBERT** | [`peyterho/climatebert-macro-sentiment`](https://huggingface.co/peyterho/climatebert-macro-sentiment) | climatebert/distilroberta-base-climate-sentiment | 82M |
 
 
 
 
 
 
 
 
 
224
 
225
- ## Dictionaries
226
-
227
- | Dictionary | Paper | Features |
228
- |-----------|-------|----------|
229
- | **Loughran-McDonald** | [LM (2011)](https://doi.org/10.1111/j.1540-6261.2010.01625.x) | 5 features |
230
- | **Henry** | [Henry (2008)](https://doi.org/10.1177/0021943608319388) | 4 features |
231
- | **Climate Exposure** | [Sautner et al. (2023)](https://doi.org/10.1093/rfs/hhad097) style | 8 features |
232
- | **Macro Policy** | Custom | 7 features |
233
-
234
- Total: **24 dictionary features** per text input.
235
 
236
  ## Training Data
237
 
238
- ~20K train / ~4.3K test from 5 financial NLP datasets:
239
-
240
- | Dataset | Train | Test | Domain |
241
- |---------|-------|------|--------|
242
- | [Financial PhraseBank](https://huggingface.co/datasets/nickmuchi/financial-classification) | 4,551 | 506 | News headlines |
243
- | [Twitter Financial News](https://huggingface.co/datasets/zeroshot/twitter-financial-news-sentiment) | 9,543 | 2,388 | Social/tweets |
244
- | [Auditor Sentiment](https://huggingface.co/datasets/FinanceInc/auditor_sentiment) | 3,877 | 969 | Audit reports |
245
- | [FiQA](https://huggingface.co/datasets/pauri32/fiqa-2018) | 1,063 | 150 | Financial Q&A |
246
- | [Climate Sentiment](https://huggingface.co/datasets/climatebert/climate_sentiment) | 1,000 | 320 | Climate/ESG |
247
 
248
- **Label distribution (train):** 15.9% negative, 58.4% neutral, 25.7% positive
 
 
 
 
 
 
249
 
250
  ## File Structure
251
 
252
  ```
253
  macro_sentiment/
254
- β”œβ”€β”€ __init__.py # Package exports (v0.2.0)
255
- β”œβ”€β”€ dictionaries.py # LM, Henry, Climate, Macro dictionary scorers
256
- β”œβ”€β”€ transformers_ensemble.py # FinBERT, RoBERTa, ClimateBERT heads + router
257
- β”œβ”€β”€ pipeline.py # Unified MacroSentimentPipeline
258
- β”œβ”€β”€ data_prep.py # Dataset loading and combination
259
- └── train_meta.py # Meta-classifier training script
260
- eval_results.json # Evaluation metrics
261
- requirements.txt # Dependencies
262
  ```
263
 
264
- ## Literature
265
 
 
266
  - Loughran & McDonald (2011). "When Is a Liability Not a Liability?" *Journal of Finance*
267
  - Henry (2008). "Are Investors Influenced by How Earnings Press Releases Are Written?" *Journal of Business Communication*
268
  - Sautner et al. (2023). "Firm-Level Climate Change Exposure." *Review of Financial Studies*
269
- - Araci (2019). [FinBERT: Financial Sentiment Analysis with Pre-Trained Language Models](https://arxiv.org/abs/1908.10063)
270
- - Huang et al. (2023). [ClimateBERT](https://arxiv.org/abs/2110.12010)
271
 
272
  ## License
273
  Apache 2.0
 
1
+ # 🏦 Macroeconomic Sentiment Analysis
2
 
3
+ **What it does:** Takes any financial or economic text and tells you whether the sentiment is positive, negative, or neutral β€” plus whether the tone is hawkish/dovish, whether it signals a crisis, and how much it relates to climate/ESG.
4
 
5
+ **Who it's for:** Anyone analyzing news articles, central bank statements, earnings reports, financial tweets, or climate/ESG disclosures.
6
 
7
+ ---
8
 
9
+ ## The Simple Way (3 lines of Python)
 
 
 
 
10
 
11
+ If you just want to classify financial text as positive/negative/neutral, use the fine-tuned models directly. No cloning, no extra packages β€” just `pip install transformers torch` and go:
 
 
 
12
 
13
+ ```python
14
+ from transformers import pipeline
15
 
16
+ # Pick one:
17
+ classifier = pipeline("text-classification", model="peyterho/finbert-macro-sentiment") # 110M, fast
18
+ # classifier = pipeline("text-classification", model="peyterho/financial-roberta-large-macro-sentiment") # 355M, most accurate
19
+ # classifier = pipeline("text-classification", model="peyterho/climatebert-macro-sentiment") # 82M, climate-focused
20
+
21
+ # Classify any financial text
22
+ classifier("Tesla shares surged 15% after beating earnings expectations.")
23
+ # β†’ [{'label': 'positive', 'score': 0.998}]
24
+
25
+ classifier("Markets crashed amid recession fears and massive layoffs.")
26
+ # β†’ [{'label': 'negative', 'score': 0.997}]
27
+
28
+ classifier("The company reported quarterly revenue in line with expectations.")
29
+ # β†’ [{'label': 'neutral', 'score': 0.95}]
 
30
  ```
31
 
32
+ That's it. Each model outputs one of three labels: **positive**, **negative**, or **neutral**, with a confidence score.
33
 
34
+ ### Which model should I pick?
35
+
36
+ | Model | Size | Speed | Accuracy | Best for |
37
+ |-------|------|-------|----------|----------|
38
+ | [`peyterho/finbert-macro-sentiment`](https://huggingface.co/peyterho/finbert-macro-sentiment) | 110M | Fast | 89.7% | General financial text β€” good default choice |
39
+ | [`peyterho/financial-roberta-large-macro-sentiment`](https://huggingface.co/peyterho/financial-roberta-large-macro-sentiment) | 355M | Slower | **91.3%** | When accuracy matters most, policy/formal text |
40
+ | [`peyterho/climatebert-macro-sentiment`](https://huggingface.co/peyterho/climatebert-macro-sentiment) | 82M | Fastest | 88.9% | Climate, ESG, and sustainability text |
41
+
42
+ ### Classify a batch of texts
43
+
44
+ ```python
45
+ texts = [
46
+ "Fed raised rates by 75bps citing persistent inflation.",
47
+ "Renewable energy investments hit record highs.",
48
+ "Lehman Brothers filed for bankruptcy.",
49
+ ]
50
+ results = classifier(texts)
51
+ for text, result in zip(texts, results):
52
+ print(f"{result['label']:>8} ({result['score']:.2f}) {text}")
53
+ # β†’ neutral (0.91) Fed raised rates by 75bps citing persistent inflation.
54
+ # positive (0.57) Renewable energy investments hit record highs.
55
+ # negative (0.99) Lehman Brothers filed for bankruptcy.
56
  ```
57
 
58
+ ---
59
+
60
+ ## The Full Pipeline (more signals, more detail)
61
+
62
+ If you need more than just positive/negative/neutral β€” like **hawkish/dovish policy stance**, **crisis detection**, **climate exposure**, and **uncertainty scoring** β€” use the full pipeline. This combines three AI models with four financial dictionaries.
63
+
64
+ ### Setup
65
 
66
  ```bash
67
+ pip install transformers torch pysentiment2 scikit-learn numpy datasets
 
 
68
 
69
+ # Download the pipeline code
70
  pip install huggingface_hub
71
+ python -c "from huggingface_hub import snapshot_download; snapshot_download('peyterho/macro-sentiment-finbert', local_dir='macro-sentiment-finbert')"
72
+ cd macro-sentiment-finbert
73
  ```
74
 
75
+ ### Usage
 
 
76
 
77
  ```python
78
  from macro_sentiment import MacroSentimentPipeline
79
 
80
+ pipe = MacroSentimentPipeline(device="cpu") # use "cuda:0" for GPU
 
81
 
82
  result = pipe("The Federal Reserve raised rates by 75bps citing persistent inflation.")
83
  print(result.summary())
84
+ # β†’ Sentiment: Neutral | Policy: Very Hawkish (+0.999) | Crisis: Normal | Domain: policy
 
 
 
 
 
 
 
85
  ```
86
 
87
+ ### What you get back
 
 
88
 
89
  ```python
90
+ result.macro_sentiment # -1.0 to +1.0 β€” overall sentiment
91
+ result.policy_stance # -1.0 (dovish) to +1.0 (hawkish)
92
+ result.crisis_signal # 0.0 (calm) to 1.0 (crisis)
93
+ result.uncertainty # 0.0 (certain) to 1.0 (uncertain)
94
+ result.climate_exposure # 0.0 (no climate topic) to 1.0 (climate-heavy)
95
+ result.detected_domain # "policy", "climate", "financial_news", or "social"
96
+ result.confidence # 0.0 to 1.0 β€” how confident the model is
97
+ ```
98
 
99
+ ### How it works
 
 
 
100
 
101
+ When you feed in a text, the pipeline:
 
 
 
102
 
103
+ 1. **Routes it** to the right AI model based on keywords (central bank language β†’ RoBERTa, climate terms β†’ ClimateBERT, everything else β†’ FinBERT)
104
+ 2. **Scores it** with four financial dictionaries (Loughran-McDonald, Henry, climate exposure, macro policy)
105
+ 3. **Combines** both signals with crisis-adaptive weighting β€” when crisis terms are detected, dictionary signals get more weight (AI models can struggle with novel crisis patterns)
 
 
106
 
107
+ ### Dictionary-only mode (instant, no GPU)
108
+
109
+ If you don't need AI models β€” just dictionary-based scoring:
110
 
111
  ```python
112
+ pipe = MacroSentimentPipeline(load_transformers=False)
113
+ result = pipe("Markets crashed amid recession fears.", mode="dict_only")
114
+ print(result.crisis_signal) # 0.8 β€” high crisis
115
+ print(result.policy_stance) # -0.5 β€” dovish
116
+ ```
117
 
118
+ ---
 
119
 
120
+ ## Accuracy
 
 
 
121
 
122
+ All models were trained on 20,000 financial texts from 5 datasets (news headlines, tweets, audit reports, financial Q&A, climate reports) and tested on 4,333 held-out samples.
123
+
124
+ | Model | Accuracy | F1 (macro) | Negative recall | Positive recall |
125
+ |-------|----------|------------|-----------------|-----------------|
126
+ | RoBERTa-Large (fine-tuned) | **91.3%** | **0.902** | β€” | β€” |
127
+ | FinBERT (fine-tuned) | 89.7% | 0.881 | 89% | 91% |
128
+ | ClimateBERT (fine-tuned) | 88.9% | 0.872 | β€” | β€” |
129
+ | *Previous version (dict-only meta-classifier)* | *66.9%* | *0.578* | *47%* | *35%* |
130
+
131
+ ---
132
 
133
+ ## Advanced: Customizing the Ensemble
134
 
135
  ```python
136
  from macro_sentiment import TransformerEnsemble
 
137
 
138
+ # Default: uses all three fine-tuned models
139
+ ensemble = TransformerEnsemble(device="cpu")
 
 
 
 
140
 
141
+ # Or pick specific models for each head
142
  ensemble = TransformerEnsemble(
143
  finbert_model="peyterho/finbert-macro-sentiment",
144
+ roberta_model="peyterho/financial-roberta-large-macro-sentiment",
145
  climatebert_model="peyterho/climatebert-macro-sentiment",
146
  )
147
 
148
+ # Route automatically to the best head for the input
149
+ result = ensemble.score_routed("ECB signals patience on rate cuts.")
150
+ print(result["head_used"]) # "policy"
151
+ print(result["sentiment_score"]) # [-1, +1]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
153
+ # Or score with all three heads at once
154
+ result = ensemble.score_all("Markets tumbled on trade war fears.")
155
+ print(result["ensemble_mean"])
156
  ```
 
157
 
158
+ To revert to the original off-the-shelf models:
159
+ ```python
160
+ from macro_sentiment import ORIGINAL_FINBERT, ORIGINAL_ROBERTA, ORIGINAL_CLIMATEBERT
161
 
162
+ ensemble = TransformerEnsemble(
163
+ finbert_model=ORIGINAL_FINBERT,
164
+ roberta_model=ORIGINAL_ROBERTA,
165
+ climatebert_model=ORIGINAL_CLIMATEBERT,
166
+ )
167
  ```
168
 
169
+ ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
+ ## All Output Fields
172
 
173
+ | Field | Range | What it means |
174
+ |-------|-------|---------------|
175
+ | `macro_sentiment` | -1 to +1 | Overall sentiment (negative ← 0 β†’ positive) |
176
+ | `policy_stance` | -1 to +1 | Dovish (rate cuts, easing) ← 0 β†’ Hawkish (rate hikes, tightening) |
177
+ | `financial_sentiment` | -1 to +1 | Raw financial sentiment from whichever AI model was used |
178
+ | `climate_sentiment` | -1 to +1 | Climate risk ← 0 β†’ Climate opportunity |
179
+ | `crisis_signal` | 0 to 1 | 0 = calm, 1 = severe crisis language detected |
180
+ | `uncertainty` | 0 to 1 | 0 = certain, 1 = highly uncertain |
181
+ | `confidence` | 0 to 1 | How confident the pipeline is in its output |
182
+ | `climate_exposure` | 0 to 1 | How much the text relates to climate/ESG topics |
183
+ | `detected_domain` | text | `policy` / `climate` / `financial_news` / `social` |
184
+ | `head_used` | text | Which AI model was activated |
185
+ | `lm_polarity` | -1 to +1 | Loughran-McDonald dictionary score |
186
+ | `henry_polarity` | -1 to +1 | Henry (2008) earnings tone score |
187
 
188
+ ---
 
 
 
 
 
 
 
 
 
189
 
190
  ## Training Data
191
 
192
+ ~20,000 training samples from 5 public datasets:
 
 
 
 
 
 
 
 
193
 
194
+ | Dataset | Samples | What it covers |
195
+ |---------|---------|---------------|
196
+ | [Financial PhraseBank](https://huggingface.co/datasets/nickmuchi/financial-classification) | 5,057 | News headlines about companies |
197
+ | [Twitter Financial News](https://huggingface.co/datasets/zeroshot/twitter-financial-news-sentiment) | 11,931 | Financial tweets with $cashtags |
198
+ | [Auditor Sentiment](https://huggingface.co/datasets/FinanceInc/auditor_sentiment) | 4,846 | Audit and accounting reports |
199
+ | [FiQA](https://huggingface.co/datasets/pauri32/fiqa-2018) | 1,213 | Financial questions and opinions |
200
+ | [Climate Sentiment](https://huggingface.co/datasets/climatebert/climate_sentiment) | 1,320 | Climate and ESG disclosures |
201
 
202
  ## File Structure
203
 
204
  ```
205
  macro_sentiment/
206
+ β”œβ”€β”€ __init__.py # Package entry point
207
+ β”œβ”€β”€ dictionaries.py # Four financial dictionaries
208
+ β”œβ”€β”€ transformers_ensemble.py # Three AI model heads + topic router
209
+ β”œβ”€β”€ pipeline.py # Full pipeline combining everything
210
+ β”œβ”€β”€ data_prep.py # Dataset loading
211
+ └── train_meta.py # Meta-classifier training
 
 
212
  ```
213
 
214
+ ## References
215
 
216
+ - Araci (2019). [FinBERT](https://arxiv.org/abs/1908.10063) β€” Financial Sentiment Analysis with Pre-Trained Language Models
217
  - Loughran & McDonald (2011). "When Is a Liability Not a Liability?" *Journal of Finance*
218
  - Henry (2008). "Are Investors Influenced by How Earnings Press Releases Are Written?" *Journal of Business Communication*
219
  - Sautner et al. (2023). "Firm-Level Climate Change Exposure." *Review of Financial Studies*
 
 
220
 
221
  ## License
222
  Apache 2.0