Loading market indices...

YONEPSE

Developer documentation for the public JSON datasets generated by the YONEPSE scraper.

Base URL: https://shubhamnpk.github.io/nepse-scaper
Updates: every 30 minutes (Sun-Thu, 11 AM - 3 PM)
17 active endpoints

Quick Start

Get started with the YONEPSE API in seconds

Method
GET
Base URL
https://shubhamnpk.github.io/nepse-scaper
Primary Endpoint
/data/nepse_data.json
OpenAPI Spec
/openapi.yaml
Authentication
None required

AI Quick Copy Pack

Copy complete API documentation context for AI tools. Choose JSON or XML and paste directly into your assistant.

JSON Context Pack

Best for ChatGPT, Claude, Gemini, and most coding assistants.

XML Context Pack

Use when your workflow expects XML-structured context or tags.

curl request
curl -s "https://shubhamnpk.github.io/nepse-scaper/data/nepse_data.json" | jq '.[0]'
JavaScript fetch
async function getStockData() {
  try {
    const response = await fetch('https://shubhamnpk.github.io/nepse-scaper/data/nepse_data.json');
    const data = await response.json();
    console.log('Stock data:', data.slice(0, 5));
    return data;
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}
Python requests
import requests
import json

def get_stock_data():
    url = "https://shubhamnpk.github.io/nepse-scaper/data/nepse_data.json"
    try:
        response = requests.get(url)
        response.raise_for_status()
        data = response.json()
        print(f"Retrieved {len(data)} stocks")
        return data[:5]  # First 5 stocks
    except requests.RequestException as e:
        print(f"Error: {e}")
        return None

if __name__ == "__main__":
    stocks = get_stock_data()
    print(json.dumps(stocks, indent=2))
Sample response
[
  {
    "symbol": "ACLBSL",
    "name": "Aarambha Chautari Laghubitta Bittiya Sanstha Limited",
    "ltp": 970.0,
    "previous_close": 977.0,
    "change": -7.0,
    "percent_change": -0.72,
    "high": 980.0,
    "low": 960.4,
    "volume": 531,
    "turnover": 515567.8,
    "trades": 29,
    "last_updated": "2026-02-26T14:51:14.742578",
    "market_cap": 3561.29
  }
]

Endpoint Index

Endpoint Type Description Updated Size
/data/nepse_data.json GET Live stock prices with OHLCV data (updated during market hours) Every 30 min (Sun-Fri, market hours) ~140KB
/data/market_status.json GET Market open/closed status with last check timestamp Every 30 min (Sun-Fri, market hours) <1KB
/data/indices.json GET Major NEPSE indices (NEPSE, Sensitive, Float) Every 30 min (Sun-Fri, market hours) ~2KB
/data/sector_indices.json GET Sector-wise index performance and metadata Every 30 min (Sun-Fri, market hours) ~5KB
/data/top_stocks.json GET Top gainers, losers, turnover, and volume leaders Every 30 min (Sun-Fri, market hours) ~3KB
/data/market_summary.json GET Key market metrics (turnover, trades, scrips) Every 30 min (Sun-Fri, market hours) ~1KB
/data/market_summary_history.json GET Historical daily market summary data Every 30 min (Sun-Fri, market hours) ~100KB
/data/notices.json GET General, company, and exchange notices Every 30 min (Sun-Fri, market hours) ~20KB
/data/disclosures.json GET Company disclosures and announcements Every 30 min (Sun-Fri, market hours) ~15KB
/data/exchange_messages.json GET Exchange announcements and circulars Every 30 min (Sun-Fri, market hours) ~8KB
/data/brokers.json GET Complete broker directory with contact info Conditional (about every 60 days) ~25KB
/data/all_securities.json GET Master list of all securities with metadata Conditional (about every 60 days) ~30KB
/data/supply_demand.json GET Supply and demand book for all securities Every 30 min (Sun-Fri, market hours) ~10KB
/data/upcoming_ipo.json GET Current and upcoming IPO announcements Daily ~3KB
/data/oldipo.json GET Historical IPO archive Daily ~5KB
/data/proposed_dividend/latest_1y.json GET Latest proposed dividend records (rolling 1-year snapshot) Daily ~105KB
/data/proposed_dividend/history_all_years.json GET Append-only proposed dividend history across all fiscal years Daily ~1.3MB
/data/proposed_dividend/meta.json GET Run metadata: mode, counts, and smoke-check status Daily <1KB
/data/nepse_sector_wise_codes.json GET Sector to security symbol mapping Weekly ~8KB

Expected Formats

Formats below are based on current repository outputs and may include additional fields over time.

GET /data/nepse_data.json array<stock>

Live market data with OHLCV, turnover, and real-time pricing. Updated every 30 minutes during market hours (11AM-3PM NST, Sun-Thu). Contains all active securities with current trading information.

Updated: Every 30 min (market hours)
Size: ~140KB
~300 stocks
Sample response
[
  {
    "symbol": "ACLBSL",
    "name": "Aarambha Chautari Laghubitta Bittiya Sanstha Limited",
    "ltp": 970.0,
    "previous_close": 977.0,
    "change": -7.0,
    "percent_change": -0.72,
    "high": 980.0,
    "low": 960.4,
    "volume": 531,
    "turnover": 515567.8,
    "trades": 29,
    "last_updated": "2026-02-26T14:51:14.742578",
    "market_cap": 3561.29
  }
]
Use Cases:
  • Building stock market dashboards
  • Real-time price monitoring applications
  • Portfolio tracking systems
  • Technical analysis tools
GET /data/market_status.json object

Quick market-state heartbeat for UI chips and guards.

shape
{
  "is_open": false,
  "last_checked": "2026-02-28T04:50:01.120000"
}
GET /data/indices.json array<index>

Main index rows including close/high/low/change fields.

sample item
{
  "index": "Sensitive Index",
  "generatedTime": "2026-02-26T15:27:30.75",
  "close": 454.58,
  "high": 458.6923,
  "low": 454.4399,
  "previousClose": 456.5119,
  "change": 1.93,
  "perChange": 0.42,
  "currentValue": 456.51
}
GET /data/sector_indices.json array<sectorIndex>

Sector-level index metadata and base capitalization fields.

sample keys
{
  "indexCode": "BANK",
  "indexName": "Banking Index",
  "description": "...",
  "activeStatus": "A",
  "baseYearMarketCapitalization": 0
}
GET /data/top_stocks.json object

Grouped rankings: gainers, losers, turnover, trade count, transaction count.

shape
{
  "top_gainer": [
    {
      "symbol": "SABBL",
      "ltp": 584.5,
      "pointChange": 53.1,
      "percentageChange": 9.99
    }
  ],
  "top_loser": [],
  "top_turnover": [],
  "top_trade": [],
  "top_transaction": []
}
GET /data/market_summary.json array<metric>

Summary metrics as label/value pairs.

sample item
{
  "detail": "Total Turnover Rs:",
  "value": 4174630515.28
}
GET /data/market_summary_history.json array<dailySummary>

Historical daily summary for trend tables/charts.

sample item
{
  "businessDate": "2026-02-26",
  "totalTurnover": 4174630515.28,
  "totalTradedShares": 10053145,
  "totalTransactions": 44204,
  "tradedScrips": 335
}
GET /data/notices.json object

Combined notices bundle with separate feeds.

shape
{
  "general": [{ "id": 1223, "noticeHeading": "..." }],
  "company": [{ "id": 44893, "newsHeadline": "..." }],
  "exchange": [{ "id": 208611, "messageTitle": "..." }],
  "last_updated": "2026-02-27T11:04:56.015637"
}
GET /data/disclosures.json array<disclosure>

Company news/disclosures with attachments metadata.

sample item
{
  "id": 44893,
  "newsHeadline": "Appointment of CEO [SIFC]",
  "newsBody": "<p>...</p>",
  "addedDate": "2026-02-27T13:09:10.243",
  "applicationDocumentDetailsList": [
    { "filePath": "...", "encryptedId": "..." }
  ]
}
GET /data/exchange_messages.json array<exchangeMessage>

Exchange-level messages (sometimes with HTML body).

sample item
{
  "id": 208611,
  "messageTitle": "Listing 4.75% Bonus Shares...",
  "messageBody": "<p>...</p>",
  "expiryDate": "2026-02-27",
  "filePath": null
}
GET /data/brokers.json array<broker>

Broker directory with region lists, branch mappings, and TMS link mapping.

sample item
{
  "memberCode": 1,
  "memberName": "Kumari Securities Private Limited",
  "membershipTypeMaster": { "membershipType": "Trading Cum Clearing Member" },
  "provinceList": [{ "description": "Province 3" }],
  "districtList": [{ "districtName": "Kathmandu" }],
  "memberTMSLinkMapping": { "tmsLink": "tms01.nepsetms.com.np" },
  "memberBranchMappings": []
}
GET /data/all_securities.json array<security>

Master list of securities with company/instrument metadata.

sample item
{
  "id": 131,
  "companyName": "Nabil Bank Limited",
  "symbol": "NABIL",
  "securityName": "Nabil Bank Limited",
  "status": "A",
  "sectorName": "Commercial Banks",
  "instrumentType": "Equity"
}
GET /data/supply_demand.json object

Supply and demand book snapshots. Arrays may be empty depending on source availability.

shape
{
  "supplyList": [],
  "demandList": []
}
GET /data/upcoming_ipo.json array<ipo>

Upcoming and active IPO records scraped from public announcements.

sample item
{
  "company": "Beni Hydropower Project Limited",
  "units": "10,40,000.00",
  "date_range": "1st - 15th Chaitra, 2082",
  "announcement_date": "Feb 27, 2026",
  "full_text": "...",
  "url": "https://merolagani.com/AnnouncementDetail.aspx?id=64589",
  "is_reserved_share": false,
  "reserved_for": "",
  "scraped_at": "2026-02-28T04:48:41.131628"
}
GET /data/oldipo.json array (can be empty)

Historical IPO archive. Current repository snapshot may have zero rows.

expected item format
{
  "company": "...",
  "units": "...",
  "date_range": "...",
  "announcement_date": "...",
  "url": "...",
  "reserved_for": "...",
  "scraped_at": "ISO timestamp"
}
GET /data/proposed_dividend/latest_1y.json array<dividend>

Latest proposed dividend data (rolling 1 year). Refreshed in normal scraper runs.

sample item
{
  "id": 432,
  "symbol": "CZBIL",
  "company_name": "Citizen Bank International Limited",
  "company_url": "https://www.sharesansar.com/company/czbil",
  "bonus_share": "8.00",
  "cash_dividend": "4.00",
  "total_dividend": "12.00",
  "announcement_date": "2025-12-24",
  "bookclose_date": "2026-01-01 [Closed]",
  "distribution_date": null,
  "bonus_listing_date": null,
  "fiscal_year": "2081/2082",
  "ltp": "193.30",
  "price_as_of": "2026-03-01",
  "status": 1,
  "scraped_at": "2026-03-02T05:12:00.000000"
}
GET /data/proposed_dividend/history_all_years.json array<dividend>

All-year proposed dividend history. Append-only timeline used for company-level dividend lookups.

shape
[
  {
    "symbol": "NABIL",
    "fiscal_year": "2081/2082",
    "total_dividend": "20.00",
    "announcement_date": "2025-09-15"
  }
]
GET /data/proposed_dividend/meta.json object

Operational metadata for proposed-dividend scraper runs.

sample
{
  "last_run_at": "2026-03-02T05:12:00.000000",
  "mode": "latest",
  "latest_count": 186,
  "history_count": 2394,
  "smoke_passed": true
}
GET /data/nepse_sector_wise_codes.json object<sector,array>

Map of sector name to securities list. Useful for filtering and grouping.

shape
{
  "Commercial Banks": [
    { "symbol": "ADBL", "name": "Agriculture Development Bank Limited" }
  ],
  "Hydro Power": [
    { "symbol": "AHPC", "name": "Arun Valley Hydropower Development Co. Ltd." }
  ]
}

API Testing & Playground

Test endpoints directly from your browser with these interactive tools.

GET Test Market Data Interactive

Click to test the main market data endpoint and see live results.

GET Test Market Status Quick Check

Check if the market is currently open and get the last update time.

Note: These tests make live API calls to your GitHub Pages deployment
CORS: All endpoints support cross-origin requests

Data Schema & Field Reference

Detailed field descriptions and data types for all endpoints.

nepse_data.json Schema
{
  "symbol": "string",           // Stock symbol (e.g., "NABIL")
  "name": "string",             // Full company name
  "ltp": "number",              // Last traded price
  "previous_close": "number",   // Previous closing price
  "change": "number",           // Absolute price change
  "percent_change": "number",   // Percentage change
  "high": "number",             // Day's highest price
  "low": "number",              // Day's lowest price
  "volume": "integer",          // Number of shares traded
  "turnover": "number",         // Total turnover in NPR
  "trades": "integer",          // Number of transactions
  "last_updated": "datetime",   // ISO timestamp of last update
  "market_cap": "number"        // Market capitalization in crores
}

Key Insights

  • ltp: The most recent traded price during market hours
  • turnover: Total value of all trades (volume × average price)
  • market_cap: In crores of NPR (1 crore = 10 million)
  • last_updated: Shows when data was last scraped
market_summary.json Schema
[
  {
    "detail": "string",    // Description of the metric
    "value": "number"      // Metric value
  }
]

Common Metrics

  • "Total Turnover Rs:" - Daily market turnover in NPR
  • "Total Traded Shares:" - Number of shares traded
  • "Total Transactions:" - Number of trades executed
  • "Traded Scrips:" - Number of securities with trades
indices.json Schema
{
  "index": "string",           // Index name (e.g., "NEPSE")
  "generatedTime": "datetime", // When data was generated
  "close": "number",           // Current index value
  "high": "number",            // Day's highest value
  "low": "number",             // Day's lowest value
  "previousClose": "number",   // Previous closing value
  "change": "number",          // Absolute change
  "perChange": "number",       // Percentage change
  "currentValue": "number"     // Current market value
}

Available Indices

  • NEPSE - Main market index
  • Sensitive Index - Large-cap focused index
  • Float Index - Based on publicly traded shares
  • Sensitive Float Index - Combined sensitive & float
notices.json Schema
{
  "general": [
    {
      "id": "integer",
      "noticeHeading": "string",
      "noticeDetail": "string",
      "publishedDate": "datetime"
    }
  ],
  "company": [
    {
      "id": "integer",
      "newsHeadline": "string",
      "newsBody": "string",
      "addedDate": "datetime"
    }
  ],
  "exchange": [
    {
      "id": "integer",
      "messageTitle": "string",
      "messageBody": "string",
      "expiryDate": "date"
    }
  ],
  "last_updated": "datetime"
}

Notice Categories

  • general - NEPSE general announcements
  • company - Company-specific disclosures
  • exchange - Exchange circulars and messages

Error Handling & Best Practices

HTTP Codes Response Handling

Understand HTTP response codes and implement proper error handling in your applications.

HTTP Status Codes
// 200 OK - Request successful
// 404 Not Found - Endpoint doesn't exist or file missing
// 500 Server Error - Temporary server issues

// Example error handling in JavaScript
async function fetchMarketData() {
  try {
    const response = await fetch('https://shubhamnpk.github.io/nepse-scaper/data/nepse_data.json');
    
    if (!response.ok) {
      if (response.status === 404) {
        console.error('Data not available - market may be closed');
        return [];
      }
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    
    const data = await response.json();
    return data;
  } catch (error) {
    console.error('Failed to fetch market data:', error);
    return null;
  }
}
Rate Limiting Best Practices

Implement responsible data fetching to ensure fair usage and reliability.

Rate Limiting Example
// Recommended: Cache data and refresh periodically
class MarketDataCache {
  constructor() {
    this.cache = new Map();
    this.cacheTimeout = 5 * 60 * 1000; // 5 minutes
  }
  
  async getData(endpoint) {
    const cached = this.cache.get(endpoint);
    const now = Date.now();
    
    if (cached && (now - cached.timestamp) < this.cacheTimeout) {
      return cached.data;
    }
    
    try {
      const response = await fetch(endpoint);
      const data = await response.json();
      
      this.cache.set(endpoint, {
        data,
        timestamp: now
      });
      
      return data;
    } catch (error) {
      // Return cached data if available on error
      return cached ? cached.data : null;
    }
  }
}
Tip: Cache responses for 5 minutes to reduce server load
Warning: Always handle 404s for market-hours-only endpoints
Timing: Market hours: 11:00 AM - 3:00 PM NST (Sun-Thu)

Performance & Caching Strategies

Optimize your applications with these performance recommendations and caching patterns.

Caching Performance

Implement smart caching to reduce API calls and improve response times.

Advanced Caching Strategy
class NEPSECacheManager {
  constructor() {
    this.cache = new Map();
    this.cacheTimes = new Map();
    this.marketHoursCache = 5 * 60 * 1000;  // 5 minutes during market hours
    this.offMarketCache = 30 * 60 * 1000;   // 30 minutes off market hours
  }

  async getData(endpoint, forceRefresh = false) {
    const cacheKey = endpoint;
    const now = Date.now();
    const cached = this.cache.get(cacheKey);
    const cacheTime = this.cacheTimes.get(cacheKey);
    
    // Check if cache is valid
    if (!forceRefresh && cached && cacheTime) {
      const age = now - cacheTime;
      const maxAge = await this.getCacheDuration();
      
      if (age < maxAge) {
        console.log(`Cache hit for ${endpoint} (${Math.round(age/1000)}s old)`);
        return cached;
      }
    }
    
    // Fetch fresh data
    try {
      const response = await fetch(`https://shubhamnpk.github.io/nepse-scaper/data/${endpoint}`);
      const data = await response.json();
      
      // Update cache
      this.cache.set(cacheKey, data);
      this.cacheTimes.set(cacheKey, now);
      
      console.log(`Fresh data fetched for ${endpoint}`);
      return data;
    } catch (error) {
      console.error(`Error fetching ${endpoint}:`, error);
      // Return cached data if available on error
      return cached || null;
    }
  }
  
  async getCacheDuration() {
    try {
      const status = await this.getData('market_status.json');
      return status.is_open ? this.marketHoursCache : this.offMarketCache;
    } catch {
      return this.offMarketCache; // Default to longer cache
    }
  }
  
  // Preload common endpoints
  async preloadData() {
    const endpoints = ['nepse_data.json', 'indices.json', 'market_summary.json'];
    await Promise.all(endpoints.map(endpoint => this.getData(endpoint)));
  }
  
  // Clear cache manually
  clearCache(endpoint = null) {
    if (endpoint) {
      this.cache.delete(endpoint);
      this.cacheTimes.delete(endpoint);
    } else {
      this.cache.clear();
      this.cacheTimes.clear();
    }
  }
}
Rate Limiting Best Practices

Implement rate limiting and request batching to be a good API citizen.

Rate Limiting Implementation
class NEPSERateLimiter {
  constructor(maxRequests = 10, windowMs = 60000) { // 10 requests per minute
    this.maxRequests = maxRequests;
    this.windowMs = windowMs;
    this.requests = [];
  }

  async waitForSlot() {
    const now = Date.now();
    
    // Clean old requests
    this.requests = this.requests.filter(time => now - time < this.windowMs);
    
    // Check if we can make a request
    if (this.requests.length < this.maxRequests) {
      this.requests.push(now);
      return;
    }
    
    // Calculate wait time
    const oldestRequest = Math.min(...this.requests);
    const waitTime = this.windowMs - (now - oldestRequest);
    
    if (waitTime > 0) {
      console.log(`Rate limit reached, waiting ${Math.round(waitTime/1000)}s`);
      await new Promise(resolve => setTimeout(resolve, waitTime));
      return this.waitForSlot(); // Retry
    }
  }
}

// Usage with queue for multiple requests
class NEPSEQueue {
  constructor() {
    this.rateLimiter = new NEPSERateLimiter();
    this.queue = [];
    this.processing = false;
  }
  
  async add(endpoint, priority = 0) {
    return new Promise((resolve, reject) => {
      this.queue.push({ endpoint, priority, resolve, reject });
      this.queue.sort((a, b) => b.priority - a.priority);
      this.processQueue();
    });
  }
  
  async processQueue() {
    if (this.processing || this.queue.length === 0) return;
    
    this.processing = true;
    
    while (this.queue.length > 0) {
      const item = this.queue.shift();
      
      try {
        await this.rateLimiter.waitForSlot();
        const response = await fetch(`https://shubhamnpk.github.io/nepse-scaper/data/${item.endpoint}`);
        const data = await response.json();
        item.resolve(data);
      } catch (error) {
        item.reject(error);
      }
    }
    
    this.processing = false;
  }
}
Performance Tip: Cache for 5 minutes during market hours, 30 minutes after hours
Memory: Consider memory usage when caching large datasets
Timing: Schedule updates just after market opens for freshest data

Integration Examples

Complete examples for common integration scenarios.

React Hook for Market Data
import { useState, useEffect } from 'react';

const BASE_URL = 'https://shubhamnpk.github.io/nepse-scaper/data';

export function useMarketData() {
  const [stocks, setStocks] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchMarketData = async () => {
      try {
        setLoading(true);
        const response = await fetch(`${BASE_URL}/nepse_data.json`);
        
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const data = await response.json();
        setStocks(data);
        setError(null);
      } catch (err) {
        setError(err.message);
        setStocks([]);
      } finally {
        setLoading(false);
      }
    };

    fetchMarketData();
    
    // Refresh every 5 minutes during market hours
    const interval = setInterval(fetchMarketData, 5 * 60 * 1000);
    
    return () => clearInterval(interval);
  }, []);

  return { stocks, loading, error };
}

// Usage in component
function MarketDashboard() {
  const { stocks, loading, error } = useMarketData();
  
  if (loading) return 
Loading market data...
; if (error) return
Error: {error}
; return (

NEPSE Market ({stocks.length} stocks)

{stocks.map(stock => (
{stock.symbol}: {stock.ltp} ({stock.percent_change}%)
))}
); }
ue.js Composable
import { ref, onMounted, onUnmounted } from 'vue';

const BASE_URL = 'https://shubhamnpk.github.io/nepse-scaper/data';

export function useMarketData() {
  const stocks = ref([]);
  const loading = ref(true);
  const error = ref(null);
  let interval = null;

  const fetchMarketData = async () => {
    try {
      loading.value = true;
      const response = await fetch(`${BASE_URL}/nepse_data.json`);
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      
      const data = await response.json();
      stocks.value = data;
      error.value = null;
    } catch (err) {
      error.value = err.message;
      stocks.value = [];
    } finally {
      loading.value = false;
    }
  };

  onMounted(() => {
    fetchMarketData();
    interval = setInterval(fetchMarketData, 5 * 60 * 1000);
  });

  onUnmounted(() => {
    if (interval) clearInterval(interval);
  });

  return { stocks, loading, error };
}
Node.js Express API
const express = require('express');
const axios = require('axios');
const NodeCache = require('node-cache');

const app = express();
const cache = new NodeCache({ stdTTL: 300 }); // 5 minutes cache
const BASE_URL = 'https://shubhamnpk.github.io/nepse-scaper/data';

app.get('/api/stocks', async (req, res) => {
  try {
    const cachedData = cache.get('market-data');
    
    if (cachedData) {
      return res.json({
        data: cachedData,
        cached: true,
        timestamp: new Date().toISOString()
      });
    }

    const response = await axios.get(`${BASE_URL}/nepse_data.json`);
    const data = response.data;
    
    cache.set('market-data', data);
    
    res.json({
      data,
      cached: false,
      timestamp: new Date().toISOString(),
      count: data.length
    });
  } catch (error) {
    console.error('Error fetching market data:', error);
    res.status(500).json({
      error: 'Failed to fetch market data',
      message: error.message
    });
  }
});

app.get('/api/stocks/:symbol', async (req, res) => {
  try {
    const cachedData = cache.get('market-data');
    let data = cachedData;
    
    if (!data) {
      const response = await axios.get(`${BASE_URL}/nepse_data.json`);
      data = response.data;
      cache.set('market-data', data);
    }
    
    const stock = data.find(s => s.symbol === req.params.symbol.toUpperCase());
    
    if (!stock) {
      return res.status(404).json({
        error: 'Stock not found',
        symbol: req.params.symbol
      });
    }
    
    res.json(stock);
  } catch (error) {
    res.status(500).json({
      error: 'Failed to fetch stock data',
      message: error.message
    });
  }
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`NEPSE API proxy running on port ${PORT}`);
});
Python Data Pipeline
import requests
import pandas as pd
import sqlite3
from datetime import datetime, timedelta
import time
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

class NEPSEDataPipeline:
    def __init__(self, db_path='nepse_data.db'):
        self.base_url = 'https://shubhamnpk.github.io/nepse-scaper/data'
        self.db_path = db_path
        self.session = requests.Session()
        self.init_database()
    
    def init_database(self):
        """Initialize SQLite database with required tables"""
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        cursor.execute('''
            CREATE TABLE IF NOT EXISTS stock_prices (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                symbol TEXT,
                name TEXT,
                ltp REAL,
                previous_close REAL,
                change REAL,
                percent_change REAL,
                high REAL,
                low REAL,
                volume INTEGER,
                turnover REAL,
                trades INTEGER,
                last_updated TEXT,
                created_at TEXT DEFAULT CURRENT_TIMESTAMP
            )
        ''')
        
        conn.commit()
        conn.close()
    
    def fetch_market_data(self):
        """Fetch latest market data"""
        try:
            response = self.session.get(f'{self.base_url}/nepse_data.json')
            response.raise_for_status()
            return response.json()
        except requests.RequestException as e:
            logger.error(f"Error fetching market data: {e}")
            return None
    
    def store_data(self, data):
        """Store market data in database"""
        if not data:
            return False
        
        conn = sqlite3.connect(self.db_path)
        cursor = conn.cursor()
        
        for stock in data:
            cursor.execute('''
                INSERT INTO stock_prices 
                (symbol, name, ltp, previous_close, change, percent_change, 
                 high, low, volume, turnover, trades, last_updated)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            ''', (
                stock.get('symbol'),
                stock.get('name'),
                stock.get('ltp'),
                stock.get('previous_close'),
                stock.get('change'),
                stock.get('percent_change'),
                stock.get('high'),
                stock.get('low'),
                stock.get('volume'),
                stock.get('turnover'),
                stock.get('trades'),
                stock.get('last_updated')
            ))
        
        conn.commit()
        conn.close()
        logger.info(f"Stored {len(data)} stock records")
        return True
    
    def get_top_gainers(self, limit=10):
        """Get top gainers from latest data"""
        conn = sqlite3.connect(self.db_path)
        df = pd.read_sql_query('''
            SELECT symbol, name, ltp, percent_change, last_updated
            FROM stock_prices 
            WHERE created_at = (
                SELECT MAX(created_at) FROM stock_prices
            )
            ORDER BY percent_change DESC
            LIMIT ?
        ''', conn, params=(limit,))
        conn.close()
        return df
    
    def run_pipeline(self):
        """Run the complete data pipeline"""
        logger.info("Starting NEPSE data pipeline...")
        
        # Fetch data
        data = self.fetch_market_data()
        if not data:
            logger.error("Failed to fetch data")
            return
        
        # Store data
        success = self.store_data(data)
        if success:
            logger.info("Pipeline completed successfully")
        else:
            logger.error("Failed to store data")

# Usage
if __name__ == "__main__":
    pipeline = NEPSEDataPipeline()
    
    # Run immediately
    pipeline.run_pipeline()
    
    # Schedule to run every 5 minutes during market hours
    while True:
        now = datetime.now()
        if now.hour >= 11 and now.hour < 15 and now.weekday() < 5:
            pipeline.run_pipeline()
        
        time.sleep(300)  # Sleep 5 minutes