Skip to main content
This section documents the dual news systems that track regulatory filings and media coverage with sentiment scoring.

Recent Announcements (Regulatory)

Recent Announcements
array
Top 5 recent regulatory filings from company disclosure platforms.Format: Array of announcement objectsDefault: [] (empty array if no announcements)Source: Company filings from NSE/BSE disclosure platformsMax Items: 5 (most recent)Data Sources:
  1. company_filings/*_filings.json - Historical regulatory filings
  2. all_company_announcements.json - Live announcements feed
Extraction:
news_map = {}

# 1. From company_filings
filing_files = glob.glob(os.path.join(filings_dir, "*_filings.json"))
for ff in filing_files:
    sym = os.path.basename(ff).replace("_filings.json", "")
    with open(ff, "r") as f:
        f_data = json.load(f)
        items = f_data.get("data", [])
        
        news_map[sym] = []
        for item in items[:5]:
            headline = (item.get("caption") or item.get("descriptor") or item.get("news_body") or "N/A")
            headline = " ".join(headline.split())
            news_map[sym].append({
                "Date": item.get("news_date", "N/A"),
                "Headline": headline,
                "URL": item.get("file_url") or "N/A"
            })

# 2. Merge from all_company_announcements.json
with open(ann_file, "r") as f:
    ann_data = json.load(f)
    for ann in ann_data:
        sym = ann.get("Symbol")
        event_text = ann.get("Event") or ""
        date_str = ann.get("Date", "")
        
        if sym:
            if sym not in news_map:
                news_map[sym] = []
            
            # Check if headline already exists
            exists = False
            for existing in news_map[sym]:
                if event_text.lower() in existing["Headline"].lower():
                    exists = True
                    break
            
            if not exists:
                news_map[sym].insert(0, {
                    "Date": date_str,
                    "Headline": event_text,
                    "URL": "N/A"
                })
                news_map[sym] = news_map[sym][:5]  # Keep only top 5

# Update master JSON
stock["Recent Announcements"] = news_map.get(sym, [])[:5]
Location: add_corporate_events.py:121-212, 251-252

Announcement Object Schema

Date
string
Date and time of the regulatory announcement.Format: YYYY-MM-DD HH:MM:SS or YYYY-MM-DDExample: "2024-03-15 18:30:00" or "2024-03-15"Source: news_date field from filing or announcement API
Headline
string
Title or description of the regulatory filing.Example: "Outcome of Board Meeting - Approval of Quarterly Results"Source Priority:
  1. caption (preferred)
  2. descriptor (fallback)
  3. news_body (last resort)
Processing: Whitespace normalized via " ".join(headline.split())Default: "N/A" if all fields empty
URL
string
Direct link to the PDF/document of the regulatory filing.Example: "https://nsearchives.nseindia.com/corporate/RELIANCE_15032024_result.pdf"Source: file_url field from filing dataDefault: "N/A" if URL not available (common for live announcements)Note: Some announcements from all_company_announcements.json may not have PDF links

News Feed (Media)

News Feed
array
Top 5 recent media news articles with AI-powered sentiment analysis.Format: Array of news objectsDefault: [] (empty array if no news)Source: Aggregated market news from media sourcesMax Items: 5 (most recent)Source Directory: market_news/*_news.jsonExtraction:
news_feed_map = {}

if os.path.exists(market_news_dir):
    news_files = glob.glob(os.path.join(market_news_dir, "*_news.json"))
    for nf in news_files:
        with open(nf, "r") as f:
            n_data = json.load(f)
            sym = n_data.get("Symbol")
            news_list = n_data.get("News", [])
            
            if sym and news_list:
                formatted_news = []
                for item in news_list[:5]:
                    formatted_news.append({
                        "Title": item.get("Title"),
                        "Sentiment": item.get("Sentiment"),
                        "Date": item.get("PublishDate")
                    })
                news_feed_map[sym] = formatted_news

# Update master JSON
stock["News Feed"] = news_feed_map.get(sym, [])
Location: add_corporate_events.py:215-240, 254-255

News Object Schema

Title
string
Headline of the news article.Example: "Reliance Industries to invest $10B in green energy expansion"Source: Title field from news API
Sentiment
string
AI-analyzed sentiment classification of the news article.Possible Values:
  • "positive" - Bullish news (growth, expansion, positive earnings, deals)
  • "neutral" - Factual reporting without directional bias
  • "negative" - Bearish news (losses, layoffs, investigations, downgrades)
Example: "positive"Source: Sentiment field from news API (likely NLP/LLM-powered)Use Cases:
  • Sentiment aggregation (count positive vs negative news)
  • News-based momentum signals
  • Risk assessment (cluster of negative news = caution)
Date
string
Publication timestamp of the news article.Format: ISO 8601 timestamp or date stringExample: "2024-03-15T14:30:00Z" or "2024-03-15"Source: PublishDate field from news APINote: Raw timestamp preserved (not normalized)

Data Sources Comparison

FeatureRecent AnnouncementsNews Feed
NatureRegulatory filings (mandatory disclosures)Media articles (journalistic coverage)
SourceNSE/BSE/Company secretaryNews aggregators, financial media
TimelinessOfficial, may have filing delaysReal-time to near real-time
AccuracyAuthoritative (from company)Subject to media interpretation
PDF LinksUsually availableNot applicable
SentimentNot analyzedAI-classified
Use CaseCompliance tracking, event verificationMarket sentiment, momentum signals

Combined Analysis Strategies

1. Event Confirmation

Cross-reference News Feed sentiment with Recent Announcements:
  • Positive news + Results announcement = Potential earnings beat
  • Negative sentiment + No announcement = Market rumor (investigate)

2. Sentiment Aggregation

Count sentiment distribution in last 5 news items:
sentiments = [item["Sentiment"] for item in stock["News Feed"]]
positive_count = sentiments.count("positive")
negative_count = sentiments.count("negative")

if positive_count >= 4:
    # Strong positive media coverage
    pass
elif negative_count >= 3:
    # Bearish media narrative
    pass

3. Announcement Type Detection

Parse Recent Announcements headlines for key events:
for ann in stock["Recent Announcements"]:
    headline = ann["Headline"].lower()
    if "quarterly results" in headline or "financial results" in headline:
        # Results announcement detected
        pass
    elif "board meeting" in headline:
        # Upcoming decision/announcement
        pass
    elif "acquisition" in headline or "merger" in headline:
        # M&A activity
        pass

Pipeline Integration

Both news systems are populated by add_corporate_events.py, which runs after the main fundamental analysis pipeline:
if __name__ == "__main__":
    map_refined_events()
This script:
  1. Loads all_stocks_fundamental_analysis.json
  2. Scans multiple data sources (filings, announcements, news)
  3. Populates Event Markers, Recent Announcements, and News Feed
  4. Writes updated JSON back to disk

Missing Data Handling

  • No filings found: Recent Announcements = []
  • No news coverage: News Feed = []
  • Symbol not in news sources: Empty arrays (not "N/A" string)

Source Code Reference

  • Announcement processing: add_corporate_events.py:120-212
  • News feed processing: add_corporate_events.py:215-240
  • Field updates: add_corporate_events.py:251-255
  • Output schema: all_stocks_fundamental_analysis.json

Build docs developers (and LLMs) love