> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ngnmarket.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Display a Live Price Ticker

> Poll the NGN Market API on an interval to keep stock prices current in your UI.

This guide shows how to build a price ticker that stays current throughout the NGX trading day. Because equity prices refresh every 20 minutes on our end, polling every 5 minutes gives you fresh data without wasting quota.

**Endpoints used:**

* `GET /companies` (Free plan) — fetch prices for all or filtered stocks
* `GET /companies/:symbol` (Starter plan) — fetch a single stock's full quote

## How it works

1. Fetch current prices on page load
2. Re-fetch on a fixed interval (5 minutes recommended)
3. Display the updated values — highlight the change direction if you like
4. Stop polling when the user leaves or the page unmounts

The `last_updated` field in every response tells you exactly when the price was last written, so you can show users how fresh the data is.

## Fetch prices for a watchlist

Use `GET /companies` with a `search` or `sector` filter, or just fetch the full list and filter client-side.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const API_KEY = 'ngm_live_YOUR_KEY';

  async function fetchPrices(symbols) {
    // Fetch all companies, then filter to your watchlist
    const res = await fetch(
      'https://api.ngnmarket.com/v1/companies?limit=200',
      { headers: { Authorization: `Bearer ${API_KEY}` } }
    );
    const { data } = await res.json();
    return data.companies.filter(c => symbols.includes(c.symbol));
  }

  const watchlist = ['DANGCEM', 'GTCO', 'AIRTELAFRI', 'MTNN', 'ZENITHBANK'];
  const prices = await fetchPrices(watchlist);
  ```

  ```python Python theme={null}
  import requests

  API_KEY = 'ngm_live_YOUR_KEY'
  WATCHLIST = ['DANGCEM', 'GTCO', 'AIRTELAFRI', 'MTNN', 'ZENITHBANK']

  def fetch_prices():
      res = requests.get(
          'https://api.ngnmarket.com/v1/companies',
          params={'limit': 200},
          headers={'Authorization': f'Bearer {API_KEY}'},
      )
      companies = res.json()['data']['companies']
      return [c for c in companies if c['symbol'] in WATCHLIST]

  prices = fetch_prices()
  ```
</CodeGroup>

### Sample response (trimmed)

```json theme={null}
{
  "success": true,
  "data": {
    "companies": [
      {
        "symbol": "DANGCEM",
        "company_name": "Dangote Cement Plc",
        "sector": "Industrial Goods",
        "current_price": 302.50,
        "price_change": 4.00,
        "price_change_percent": 1.34,
        "volume": 812400,
        "market_cap": 5150820750000,
        "last_updated": "2026-04-21T11:40:00.000Z"
      },
      {
        "symbol": "GTCO",
        "company_name": "Guaranty Trust Holding Co",
        "sector": "Financial Services",
        "current_price": 62.10,
        "price_change": -0.40,
        "price_change_percent": -0.64,
        "volume": 3201000,
        "market_cap": 1831545000000,
        "last_updated": "2026-04-21T11:40:00.000Z"
      }
    ]
  }
}
```

## Poll on an interval (vanilla JavaScript)

```javascript JavaScript theme={null}
const API_KEY  = 'ngm_live_YOUR_KEY';
const SYMBOLS  = ['DANGCEM', 'GTCO', 'AIRTELAFRI', 'MTNN', 'ZENITHBANK'];
const INTERVAL = 5 * 60 * 1000; // 5 minutes in ms

async function fetchPrices() {
  const res = await fetch(
    'https://api.ngnmarket.com/v1/companies?limit=200',
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  const { data } = await res.json();
  return data.companies.filter(c => SYMBOLS.includes(c.symbol));
}

function renderTicker(prices) {
  prices.forEach(({ symbol, current_price, price_change_percent, last_updated }) => {
    const el = document.getElementById(`ticker-${symbol}`);
    if (!el) return;
    el.querySelector('.price').textContent = `₦${current_price.toFixed(2)}`;
    el.querySelector('.change').textContent =
      `${price_change_percent >= 0 ? '+' : ''}${price_change_percent.toFixed(2)}%`;
    el.querySelector('.change').className =
      `change ${price_change_percent >= 0 ? 'up' : 'down'}`;
    el.querySelector('.updated').textContent =
      `Updated ${new Date(last_updated).toLocaleTimeString('en-NG')}`;
  });
}

// Initial load
fetchPrices().then(renderTicker);

// Refresh every 5 minutes
const timer = setInterval(() => fetchPrices().then(renderTicker), INTERVAL);

// Clean up when the page is closed
window.addEventListener('beforeunload', () => clearInterval(timer));
```

## React component

```tsx React theme={null}
import { useEffect, useState, useRef } from 'react';

const API_KEY  = 'ngm_live_YOUR_KEY';
const SYMBOLS  = ['DANGCEM', 'GTCO', 'AIRTELAFRI', 'MTNN', 'ZENITHBANK'];
const INTERVAL = 5 * 60 * 1000; // 5 minutes

async function fetchPrices() {
  const res = await fetch(
    'https://api.ngnmarket.com/v1/companies?limit=200',
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  const { data } = await res.json();
  return data.companies.filter(c => SYMBOLS.includes(c.symbol));
}

export function PriceTicker() {
  const [prices, setPrices]   = useState([]);
  const [loading, setLoading] = useState(true);
  const timerRef              = useRef(null);

  useEffect(() => {
    // Load on mount
    fetchPrices().then(p => { setPrices(p); setLoading(false); });

    // Poll every 5 minutes
    timerRef.current = setInterval(
      () => fetchPrices().then(setPrices),
      INTERVAL
    );

    return () => clearInterval(timerRef.current); // clean up on unmount
  }, []);

  if (loading) return <p>Loading prices…</p>;

  return (
    <table>
      <thead>
        <tr>
          <th>Symbol</th>
          <th>Price (₦)</th>
          <th>Change</th>
          <th>Last updated</th>
        </tr>
      </thead>
      <tbody>
        {prices.map(({ symbol, current_price, price_change_percent, last_updated }) => (
          <tr key={symbol}>
            <td>{symbol}</td>
            <td>{current_price.toFixed(2)}</td>
            <td style={{ color: price_change_percent >= 0 ? 'green' : 'red' }}>
              {price_change_percent >= 0 ? '+' : ''}{price_change_percent.toFixed(2)}%
            </td>
            <td>{new Date(last_updated).toLocaleTimeString('en-NG')}</td>
          </tr>
        ))}
      </tbody>
    </table>
  );
}
```

## Tips

**Choose the right polling interval.** Data refreshes every 20 minutes during trading hours, so polling more frequently than every 5 minutes won't give you fresher prices — it just uses quota. Outside trading hours you can stop polling entirely.

**Check `last_updated` before re-rendering.** If the timestamp hasn't changed since your last poll, the price hasn't moved and you can skip the DOM/state update.

**Only poll during trading hours.** NGX trades Monday–Friday, 09:00–16:00 WAT. You can detect this client-side and pause the interval outside those windows:

```javascript JavaScript theme={null}
function isMarketOpen() {
  const now = new Date();
  const day = now.getUTCDay(); // 0 = Sun, 6 = Sat
  if (day === 0 || day === 6) return false;

  // WAT = UTC+1
  const watHour   = now.getUTCHours() + 1;
  const watMinute = now.getUTCMinutes();
  const watTime   = watHour * 100 + watMinute;

  return watTime >= 900 && watTime < 1600; // 09:00–16:00
}

// Only start polling if the market is open
if (isMarketOpen()) {
  fetchPrices().then(renderTicker);
  const timer = setInterval(() => {
    if (!isMarketOpen()) { clearInterval(timer); return; }
    fetchPrices().then(renderTicker);
  }, INTERVAL);
}
```

<CardGroup cols={2}>
  <Card title="Companies list reference" icon="book" href="/api-reference/companies/list">
    All parameters for `GET /companies`
  </Card>

  <Card title="Company detail reference" icon="book" href="/api-reference/companies/detail">
    Full quote fields from `GET /companies/:symbol`
  </Card>
</CardGroup>
