Overview
The Market News API retrieves the latest market news articles with sentiment analysis for individual stocks. This endpoint provides up to 100 news items per stock with overall sentiment classification (positive, negative, neutral).
Source File: fetch_market_news.py
Endpoint Details
https://news-live.dhan.co/v2/news/getLiveNews
{
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "application/json, text/plain, */*"
}
Request Payload
News categories filter. Use ["ALL"] for all categories.
Page number (0-indexed). Use 0 for first page.
Number of news items to fetch. Maximum tested: 100.
Timestamp of first news item (for pagination). Use 0 for initial request.
Timestamp of last news item (for pagination). Use 0 for initial request.
Feed type - use “live” for latest news.
Array of ISINs. Single ISIN per request for stock-specific news.
Entity identifier. Leave empty for stock news.
Example Payload
{
"categories": ["ALL"],
"page_no": 0,
"limit": 50,
"first_news_timeStamp": 0,
"last_news_timeStamp": 0,
"news_feed_type": "live",
"stock_list": ["INE002A01018"],
"entity_id": ""
}
Example Request
curl -X POST https://news-live.dhan.co/v2/news/getLiveNews \
-H "Content-Type: application/json" \
-H "User-Agent: Mozilla/5.0" \
-d '{
"categories": ["ALL"],
"page_no": 0,
"limit": 50,
"first_news_timeStamp": 0,
"last_news_timeStamp": 0,
"news_feed_type": "live",
"stock_list": ["INE002A01018"],
"entity_id": ""
}'
Response Structure
Array of news item objects
News Item Fields
news_object.overall_sentiment
Sentiment classification: “positive”, “negative”, or “neutral”
Publish timestamp (Unix epoch in milliseconds)
Example Response
{
"data": {
"latest_news": [
{
"news_object": {
"title": "Reliance Industries Reports Strong Q3 Results",
"text": "Reliance Industries posted consolidated net profit of Rs 18,500 crore for Q3 FY24, up 12% YoY...",
"overall_sentiment": "positive"
},
"publish_date": 1705320000000,
"category": "Business News"
},
{
"news_object": {
"title": "RIL to Invest $10B in Green Energy",
"text": "Reliance announces major investment in renewable energy sector...",
"overall_sentiment": "positive"
},
"publish_date": 1705233600000,
"category": "Market News"
}
]
}
}
Implementation Details
Configuration
Concurrent threads for parallel processing (conservative for news API)
Request timeout in seconds
News items per stock (max tested: 100)
market_news/{SYMBOL}_news.json
Processing Flow
- Load Master Map: Read ISINs from master_isin_map.json
- Parallel Fetch: Use ThreadPoolExecutor with 15 workers
- Extract News: Parse news_object for title, text, sentiment
- Structure Data: Create clean news objects with metadata
- Save Per Stock: Write individual files per symbol
- Track Progress: Log success/empty/error counts
Code Implementation
import requests
import json
from concurrent.futures import ThreadPoolExecutor, as_completed
url = "https://news-live.dhan.co/v2/news/getLiveNews"
NEWS_LIMIT = 50
def fetch_market_news(item):
symbol = item.get("Symbol")
isin = item.get("ISIN")
output_path = f"market_news/{symbol}_news.json"
payload = {
"categories": ["ALL"],
"page_no": 0,
"limit": NEWS_LIMIT,
"first_news_timeStamp": 0,
"last_news_timeStamp": 0,
"news_feed_type": "live",
"stock_list": [isin],
"entity_id": ""
}
try:
response = requests.post(url, json=payload, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
news_items = data.get("data", {}).get("latest_news", [])
if news_items:
processed_news = []
for news in news_items:
news_obj = news.get("news_object", {})
processed_news.append({
"Title": news_obj.get("title", ""),
"Summary": news_obj.get("text", ""),
"Sentiment": news_obj.get("overall_sentiment", "neutral"),
"PublishDate": news.get("publish_date", 0),
"Source": news.get("category", "")
})
final_output = {
"Symbol": symbol,
"ISIN": isin,
"News": processed_news
}
with open(output_path, "w") as f:
json.dump(final_output, f, indent=4)
return "success"
else:
return "empty"
elif response.status_code == 429:
time.sleep(2) # Rate limit backoff
return "rate_limit"
else:
return f"http_{response.status_code}"
except:
return "error"
# Load master list
with open("master_isin_map.json", "r") as f:
stock_list = json.load(f)
# Parallel processing
with ThreadPoolExecutor(max_workers=15) as executor:
future_to_stock = {executor.submit(fetch_market_news, item): item["Symbol"]
for item in stock_list}
for future in as_completed(future_to_stock):
result = future.result()
# Track success/empty/error counts
Output Structure
Each stock gets its own JSON file:
market_news/
├── RELIANCE_news.json
├── TCS_news.json
└── HDFCBANK_news.json
File format:
{
"Symbol": "RELIANCE",
"ISIN": "INE002A01018",
"News": [
{
"Title": "Reliance Industries Reports Strong Q3 Results",
"Summary": "Reliance Industries posted consolidated net profit...",
"Sentiment": "positive",
"PublishDate": 1705320000000,
"Source": "Business News"
}
]
}
- Total Stocks: ~2,775
- Threads: 15 concurrent requests
- Time per Stock: ~2-3 seconds
- Total Time: ~6-8 minutes for full market
- Avg News per Stock: 10-30 (varies significantly)
- Success Rate: ~85% (some stocks have no news)
- Empty Response Rate: ~15%
Progress Tracking
[50/2775] | Success: 42 | Empty: 7 | Errors: 1 | Elapsed: 85.3s
[100/2775] | Success: 83 | Empty: 15 | Errors: 2 | Elapsed: 165.1s
...
News Found: 2350 stocks | No News: 420 | Errors: 5
For stocks with >100 news items, use pagination:
def fetch_all_news(isin):
all_news = []
page_no = 0
limit = 100
while True:
payload = {
"categories": ["ALL"],
"page_no": page_no,
"limit": limit,
"news_feed_type": "live",
"stock_list": [isin]
}
response = requests.post(url, json=payload, headers=headers)
news_items = response.json().get("data", {}).get("latest_news", [])
if not news_items:
break
all_news.extend(news_items)
page_no += 1
return all_news
Sentiment Analysis
Bullish news - earnings beats, new contracts, positive outlook
Bearish news - earnings misses, regulatory issues, downgrades
Informational news - general updates, announcements
Sentiment Distribution Examples
# Analyze sentiment distribution
with open("market_news/RELIANCE_news.json", "r") as f:
data = json.load(f)
sentiments = [item["Sentiment"] for item in data["News"]]
positive = sentiments.count("positive")
negative = sentiments.count("negative")
neutral = sentiments.count("neutral")
print(f"Positive: {positive}, Negative: {negative}, Neutral: {neutral}")
Rate Limiting
The API implements rate limiting:
- 429 Response: Too many requests
- Backoff Strategy: Sleep 2 seconds on 429
- Thread Limit: 15 concurrent (conservative)
- Retry Logic: Automatic retry on rate limit
if response.status_code == 429:
time.sleep(2) # Backoff
return "rate_limit"
Use Cases
- News Aggregation: Build comprehensive news database per stock
- Sentiment Analysis: Track sentiment trends over time
- Event Detection: Identify major news events impacting stocks
- Portfolio Monitoring: Get news alerts for portfolio holdings
- Earnings Coverage: Track quarterly result announcements
- Market Research: Analyze news flow for stock screening
Filtering Examples
Recent News Only
from datetime import datetime, timedelta
# Last 7 days
seven_days_ago = (datetime.now() - timedelta(days=7)).timestamp() * 1000
recent_news = [
item for item in news_list
if item["PublishDate"] >= seven_days_ago
]
Positive Sentiment Only
positive_news = [
item for item in news_list
if item["Sentiment"] == "positive"
]
By Source
business_news = [
item for item in news_list
if item["Source"] == "Business News"
]
Notes
- News availability varies by stock (large caps have more coverage)
- Small/micro caps may have limited or no news
- Sentiment is auto-generated using NLP algorithms
- News sources include major business publications and wire services
- The API updates in real-time as news is published
- Historical news depth: typically 30-90 days
- Limit=100 is maximum tested; higher values may not work
- Use per-stock files for efficient incremental updates