Skip to main content
This guide shows how to build a price alert system — poll the NGN Market API on an interval, compare prices against user-defined thresholds, and fire a notification (webhook, email, or push) when a condition is met. Endpoint used:
  • GET /companies/:symbol (Starter plan) — single stock quote with current price

Alert types

You can model any of these conditions:
TypeExample
Price rises above targetNotify when DANGCEM > ₦320
Price falls below targetNotify when GTCO < ₦55
Price moves up by %Notify when MTNN gains 5% today
Price moves down by %Notify when ZENITHBANK drops 3% today

Step 1: Define your alerts

JavaScript
const alerts = [
  { id: 1, symbol: 'DANGCEM',    condition: 'above', target: 320.00  },
  { id: 2, symbol: 'GTCO',       condition: 'below', target: 55.00   },
  { id: 3, symbol: 'MTNN',       condition: 'change_above', target: 5  }, // +5% today
  { id: 4, symbol: 'ZENITHBANK', condition: 'change_below', target: -3 }, // -3% today
];
Python
alerts = [
    {'id': 1, 'symbol': 'DANGCEM',    'condition': 'above',        'target': 320.00},
    {'id': 2, 'symbol': 'GTCO',       'condition': 'below',        'target': 55.00 },
    {'id': 3, 'symbol': 'MTNN',       'condition': 'change_above', 'target': 5     },
    {'id': 4, 'symbol': 'ZENITHBANK', 'condition': 'change_below', 'target': -3    },
]

Step 2: Fetch a quote

const API_KEY = 'ngm_live_YOUR_KEY';

async function getQuote(symbol) {
  const res = await fetch(
    `https://api.ngnmarket.com/v1/companies/${symbol}`,
    { headers: { Authorization: `Bearer ${API_KEY}` } }
  );
  const { data } = await res.json();
  return data; // current_price, price_change_percent, last_updated, etc.
}

Sample quote response (trimmed)

{
  "symbol": "DANGCEM",
  "company_name": "Dangote Cement Plc",
  "current_price": 322.50,
  "price_change": 20.00,
  "price_change_percent": 6.61,
  "last_updated": "2026-04-21T11:40:00.000Z"
}

Step 3: Evaluate alert conditions

function isTriggered(alert, quote) {
  const { condition, target } = alert;
  const { current_price, price_change_percent } = quote;

  switch (condition) {
    case 'above':        return current_price >= target;
    case 'below':        return current_price <= target;
    case 'change_above': return price_change_percent >= target;
    case 'change_below': return price_change_percent <= target;
    default:             return false;
  }
}

Step 4: Send a notification

Replace notify() with whatever delivery mechanism you use — webhook, email, SMS, or push.
async function notify(alert, quote) {
  const message = buildMessage(alert, quote);

  // Option A: webhook
  await fetch(process.env.WEBHOOK_URL, {
    method:  'POST',
    headers: { 'Content-Type': 'application/json' },
    body:    JSON.stringify({ text: message, alert, quote }),
  });

  // Option B: log to console (replace with your email/SMS/push SDK)
  console.log(`[ALERT] ${message}`);
}

function buildMessage({ condition, target, symbol }, { current_price, price_change_percent }) {
  if (condition === 'above')        return `${symbol} hit ₦${current_price} — above your ₦${target} target`;
  if (condition === 'below')        return `${symbol} dropped to ₦${current_price} — below your ₦${target} target`;
  if (condition === 'change_above') return `${symbol} is up ${price_change_percent.toFixed(2)}% today (target: +${target}%)`;
  if (condition === 'change_below') return `${symbol} is down ${price_change_percent.toFixed(2)}% today (target: ${target}%)`;
}

Step 5: Run the checker on an interval

const triggered = new Set(); // prevent repeat notifications per session

async function checkAlerts() {
  for (const alert of alerts) {
    // Skip already-triggered alerts
    if (triggered.has(alert.id)) continue;

    const quote = await getQuote(alert.symbol);
    if (isTriggered(alert, quote)) {
      await notify(alert, quote);
      triggered.add(alert.id); // fire once per session
    }
  }
}

// Check every 5 minutes during market hours
const INTERVAL = 5 * 60 * 1000;
checkAlerts();
const timer = setInterval(checkAlerts, INTERVAL);

Persistent alerts with a database

For a production system where alert state survives restarts, store alerts and their triggered status in a database:
JavaScript
// Pseudocode — adapt to your ORM/database
async function checkAlerts() {
  const activeAlerts = await db.alerts.findAll({ where: { triggered: false } });

  for (const alert of activeAlerts) {
    const quote = await getQuote(alert.symbol);
    if (isTriggered(alert, quote)) {
      await notify(alert, quote);
      await db.alerts.update(
        { triggered: true, triggered_at: new Date(), triggered_price: quote.current_price },
        { where: { id: alert.id } }
      );
    }
  }
}

Tips

Debounce noisy conditions. A stock can briefly cross a threshold and come back. Consider requiring the condition to hold for two consecutive checks before firing. Reset daily alerts at midnight WAT. change_above / change_below alerts are based on price_change_percent, which resets each session. Clear those triggered flags at the start of each trading day. Only check during trading hours. Prices don’t move outside NGX hours (Mon–Fri, 09:00–16:00 WAT), so skip checks then to save quota.
JavaScript
function isMarketOpen() {
  const now     = new Date();
  const day     = now.getUTCDay();
  if (day === 0 || day === 6) return false;
  const watTime = (now.getUTCHours() + 1) * 100 + now.getUTCMinutes();
  return watTime >= 900 && watTime < 1600; // 09:00–16:00
}

Company detail reference

All fields returned by GET /companies/:symbol

Live price ticker guide

How to keep prices updating automatically