📈 Stock Market API
💡 Type company names like "Nintendo", "Apple" OR symbols like "AAPL", "NTDOY"
'ETR', 'PA' => 'EPA', 'L' => 'LON', 'T' => 'TYO',
'HK' => 'HKG', 'AS' => 'AMS', 'BR' => 'EBR', 'MC' => 'BME',
'MI' => 'BIT', 'ST' => 'STO', 'OL' => 'OTCMKTS', 'TO' => 'TSE',
'AX' => 'ASX', 'BO' => 'BOM', 'NS' => 'NSE', 'SW' => 'SWX',
'SZ' => 'SHE', 'SS' => 'SHA',
];
$suffix = strtoupper($m[1]);
$code = $suffixMap[$suffix] ?? $suffix;
return ['display' => $code, 'code' => $code];
}
$response = curl_get_search("https://query1.finance.yahoo.com/v1/finance/search?q=" . urlencode($symbol) . ""esCount=5&newsCount=0");
$rawExchange = 'NMS';
if ($response) {
$data = json_decode($response, true);
foreach ($data['quotes'] ?? [] as $quote) {
if (($quote['quoteType'] ?? '') === 'EQUITY') {
$rawExchange = $quote['exchange'] ?? 'NMS';
break;
}
}
}
$usMap = [
'NMS' => 'NASDAQ', 'NGM' => 'NASDAQ', 'NCM' => 'NASDAQ',
'NYQ' => 'NYSE', 'NYM' => 'NYSE',
'ASE' => 'AMEX',
'PNK' => 'OTCMKTS', 'OQB' => 'OTCMKTS', 'OQX' => 'OTCMKTS',
];
$code = $usMap[$rawExchange] ?? $rawExchange;
return ['display' => $code, 'code' => $code];
}
// New function to fetch 7-day sparkline data
function fetchSparklineData($symbol) {
$url = "https://query1.finance.yahoo.com/v8/finance/chart/" . urlencode($symbol) . "?range=7d&interval=1d";
$response = curl_get_search($url);
if (!$response) return null;
$data = json_decode($response, true);
if (!isset($data['chart']['result'][0])) return null;
$result = $data['chart']['result'][0];
$closes = $result['indicators']['quote'][0]['close'] ?? [];
$validCloses = array_values(array_filter($closes, function($v) { return $v !== null; }));
if (count($validCloses) >= 2) {
$oldPrice = $validCloses[0];
$newPrice = $validCloses[count($validCloses) - 1];
$sevenDayChange = $newPrice - $oldPrice;
$sevenDayChangePct = ($sevenDayChange / $oldPrice) * 100;
$trend = $sevenDayChange > 0 ? 'up' : ($sevenDayChange < 0 ? 'down' : 'flat');
return [
'sparkline' => $validCloses,
'trend' => $trend,
'seven_day_change' => $sevenDayChange,
'seven_day_change_pct' => $sevenDayChangePct
];
}
return null;
}
function searchSymbol($query) {
$searchUrl = "https://query1.finance.yahoo.com/v1/finance/search?q=" . urlencode($query) . ""esCount=5&newsCount=0";
$response = curl_get_search($searchUrl);
if ($response) {
$data = json_decode($response, true);
if (isset($data['quotes']) && count($data['quotes']) > 0) {
foreach ($data['quotes'] as $quote) {
if (isset($quote['quoteType']) && $quote['quoteType'] === 'EQUITY') {
return [
'symbol' => $quote['symbol'],
'name' => $quote['longname'] ?? $quote['shortname'] ?? $quote['symbol'],
'exchange' => $quote['exchDisp'] ?? $quote['exchange'] ?? 'N/A'
];
}
}
return [
'symbol' => $data['quotes'][0]['symbol'],
'name' => $data['quotes'][0]['longname'] ?? $data['quotes'][0]['shortname'] ?? $data['quotes'][0]['symbol'],
'exchange' => $data['quotes'][0]['exchDisp'] ?? $data['quotes'][0]['exchange'] ?? 'N/A'
];
}
}
return null;
}
// -- Currency setup ----------------------------------------------------------
$currencyParam = isset($_GET['currency']) ? $_GET['currency'] : 'USD';
$currencySymbols = [
'USD' => ['symbol' => '$', 'rate' => 1, 'code' => 'USD'],
'EUR' => ['symbol' => '€', 'rate' => 0.92, 'code' => 'EUR'],
'JPY' => ['symbol' => '¥', 'rate' => 148.5, 'code' => 'JPY'],
'GBP' => ['symbol' => '£', 'rate' => 0.79, 'code' => 'GBP']
];
$targetCurrency = $currencySymbols[$currencyParam] ?? $currencySymbols['USD'];
$targetSymbol = $targetCurrency['symbol'];
$targetRate = $targetCurrency['rate'];
$targetCode = $targetCurrency['code'];
$rateResponse = curl_get_search("https://api.exchangerate-api.com/v4/latest/USD");
if ($rateResponse) {
$rateData = json_decode($rateResponse, true);
if (isset($rateData['rates']['EUR'])) $currencySymbols['EUR']['rate'] = $rateData['rates']['EUR'];
if (isset($rateData['rates']['JPY'])) $currencySymbols['JPY']['rate'] = $rateData['rates']['JPY'];
if (isset($rateData['rates']['GBP'])) $currencySymbols['GBP']['rate'] = $rateData['rates']['GBP'];
if ($targetCode == 'EUR') $targetRate = $currencySymbols['EUR']['rate'];
elseif ($targetCode == 'JPY') $targetRate = $currencySymbols['JPY']['rate'];
elseif ($targetCode == 'GBP') $targetRate = $currencySymbols['GBP']['rate'];
else $targetRate = 1;
}
// -- Main logic --------------------------------------------------------------
if (isset($_GET['symbol']) && !empty($_GET['symbol'])) {
$query = trim($_GET['symbol']);
$isProbablySymbol = preg_match('/^[A-Z0-9\.\-]{1,10}$/', $query);
$symbol = '';
$companyName = '';
$exchangeName = '';
$wasSearch = false;
if (!$isProbablySymbol) {
$searchResult = searchSymbol($query);
if ($searchResult) {
$symbol = $searchResult['symbol'];
$companyName = $searchResult['name'];
$exchangeName = $searchResult['exchange'];
$wasSearch = true;
} else {
$symbol = strtoupper($query);
$wasSearch = false;
}
} else {
$symbol = $query;
$wasSearch = false;
}
// Fetch live price with 7-day data for sparkline
$url = "https://query1.finance.yahoo.com/v8/finance/chart/" . urlencode($symbol) . "?range=7d&interval=1d";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36']);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 200 && $response) {
$data = json_decode($response, true);
if ($data && isset($data['chart']['result'][0])) {
$result = $data['chart']['result'][0];
$meta = $result['meta'];
$originalPrice = isset($meta['regularMarketPrice']) ? $meta['regularMarketPrice'] : 'N/A';
$previousClose = isset($meta['previousClose']) ? $meta['previousClose'] : null;
$originalCurrencyCode = isset($meta['currency']) ? strtoupper($meta['currency']) : 'USD';
// Get sparkline data from the same response
$closes = $result['indicators']['quote'][0]['close'] ?? [];
$validCloses = array_values(array_filter($closes, function($v) { return $v !== null; }));
$sevenDayChange = null;
$sevenDayChangePct = null;
$trend = 'flat';
$sparklineData = [];
if (count($validCloses) >= 2) {
$oldPrice = $validCloses[0];
$newPrice = $validCloses[count($validCloses) - 1];
if ($oldPrice > 0) {
$sevenDayChange = $newPrice - $oldPrice;
$sevenDayChangePct = ($sevenDayChange / $oldPrice) * 100;
$trend = $sevenDayChange > 0 ? 'up' : ($sevenDayChange < 0 ? 'down' : 'flat');
}
$sparklineData = $validCloses;
}
$localToUsdRate = 1.0;
if ($originalCurrencyCode !== 'USD' && isset($rateData['rates'][$originalCurrencyCode]) && $rateData['rates'][$originalCurrencyCode] > 0) {
$localToUsdRate = 1.0 / $rateData['rates'][$originalCurrencyCode];
}
$convertedPrice = 'N/A';
if ($originalPrice !== 'N/A' && is_numeric($originalPrice)) {
$convertedPrice = $originalPrice * $localToUsdRate * $targetRate;
}
$changeDisplay = 'N/A';
$changePercent = 'N/A';
$changeSign = '';
$changePercentSign = '';
if ($originalPrice !== 'N/A' && $previousClose && is_numeric($originalPrice) && is_numeric($previousClose)) {
$changeVal = $originalPrice - $previousClose;
$changePercentVal = ($changeVal / $previousClose) * 100;
$changeConverted = $changeVal * $localToUsdRate * $targetRate;
$changeDisplay = number_format($changeConverted, 2);
$changePercent = number_format($changePercentVal, 2);
$changeSign = ($changeConverted >= 0) ? '+' : '';
$changePercentSign = ($changePercentVal >= 0) ? '+' : '';
}
$fetchedName = isset($meta['longName']) ? $meta['longName'] : (isset($meta['shortName']) ? $meta['shortName'] : $symbol);
$exchangeName = isset($meta['exchangeName']) ? $meta['exchangeName'] : 'N/A';
$displayName = ($wasSearch && $companyName) ? $companyName : $fetchedName;
// -- Google Finance link ------------------------------------------
$googleSymbol = preg_replace('/\.[A-Z]{2,}$/i', '', $symbol);
$exchangeInfo = fetchExchangeInfoForGoogle($symbol);
$exchangeCode = $exchangeInfo['code'];
$googleFinanceUrl = 'https://www.google.com/finance/quote/' . urlencode($googleSymbol) . ':' . urlencode($exchangeCode);
// Shareable link
$queryLink = '?symbol=' . urlencode($query) . '¤cy=' . urlencode($currencyParam);
$fullUrl = (isset($_SERVER['HTTPS']) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']) . '/' . $queryLink;
echo '
';
echo '
';
echo '';
echo '';
echo 'Showing: ' . $targetSymbol . '';
echo '
';
$today = date('Y-m-d');
// Special handling for WPRT.TO
if ($symbol === 'WPRT.TO') {
echo '
';
echo '
';
echo '
' . htmlspecialchars($symbol) . '
';
echo '
';
echo '
G';
echo '
Rslv';
echo '
';
echo '
(matched from "CA9609085076")';
echo '
';
echo '
' . htmlspecialchars($displayName) . '
';
echo '
$ 2.35
';
echo '
(Original: CAD 3.34 @ 1 CAD = 0.7042 USD)
';
echo '
Daily Change: N/A
';
echo '
Exchange: TSE
';
echo '
';
echo '
';
} else {
// Normal display for all other stocks
echo '
';
echo '
';
echo '
' . htmlspecialchars($symbol) . '
';
echo '
';
echo '
G';
echo '
Rslv';
echo '
';
if ($wasSearch) {
echo '
(matched from "' . htmlspecialchars($query) . '")';
}
echo '
';
echo '
' . htmlspecialchars($displayName) . '
';
echo '
' . $targetSymbol . ' ' . number_format((float)$convertedPrice, 2) . '
';
if ($originalCurrencyCode != $targetCode && $originalPrice !== 'N/A') {
$localToTargetRate = $localToUsdRate * $targetRate;
echo '
(Original: ' . $originalCurrencyCode . ' ' . number_format((float)$originalPrice, 2) . ' @ 1 ' . $originalCurrencyCode . ' = ' . number_format($localToTargetRate, 4) . ' ' . $targetCode . ')
';
}
echo '
';
echo 'Daily Change: ' . ($changeDisplay != 'N/A' ? $changeSign . $changeDisplay : 'N/A');
if ($changePercent != 'N/A') {
echo ' (' . $changePercentSign . $changePercent . '%)';
}
echo '
';
// Add 7-Day Trend with Sparkline
if (!empty($sparklineData)) {
$trendText = $trend === 'up' ? '?? UP' : ($trend === 'down' ? '?? DOWN' : '?? FLAT');
$change7dSign = $sevenDayChange > 0 ? '+' : '';
// Generate SVG directly
$min = min($sparklineData);
$max = max($sparklineData);
$range = $max - $min ?: 1;
$height = 30;
$width = 100;
$step = $width / (count($sparklineData) - 1);
$points = [];
foreach ($sparklineData as $i => $value) {
$x = $i * $step;
$y = $height - (($value - $min) / $range * $height);
$points[] = "$x,$y";
}
$color = $trend === 'up' ? '#28a745' : ($trend === 'down' ? '#dc3545' : '#6c757d');
echo '
';
echo '
';
echo '
';
echo '
';
echo '
7-Day Change: ' . $change7dSign . number_format(abs($sevenDayChange), 2) . ' (' . $change7dSign . number_format($sevenDayChangePct, 2) . '%) ' . $trendText . '';
echo '
';
// Add the other iframes
echo '
';
echo '';
$badge_query = $query;
echo '';
echo '
';
} else {
echo '
7-Day Trend: No data available
';
}
echo '
Exchange: ' . htmlspecialchars($exchangeName) . '
';
echo '
';
$saveUrl = 'save.php?stock=' . urlencode($symbol) .
'&price=' . urlencode(is_numeric($convertedPrice) ? number_format((float)$convertedPrice, 2) : '0') .
'¤cy=' . urlencode($targetSymbol) .
'&date=' . urlencode($today) .
'&exchange_market=' . urlencode($exchangeName);
if (is_numeric($convertedPrice)) {
echo '
';
} else {
echo '
';
}
echo '
';
}
} else {
echo '
❌ No data found for "' . htmlspecialchars($query) . '"
';
}
} else {
echo '
⚠ Could not fetch data for: ' . htmlspecialchars($query) . '
';
echo '
';
}
} else {
echo '
';
echo '
🔍 Search for any stock
';
echo '
Try typing: Nintendo, Apple, Tesla, or a symbol like AAPL, NTDOY
';
echo '
🎮 Popular stocks:
';
echo '
';
echo '
';
}
?>