Skip to content

Instantly share code, notes, and snippets.

@anthonywong
Created October 5, 2025 07:14
Show Gist options
  • Select an option

  • Save anthonywong/7a6ad76275b1cc2cbde2a115022a448c to your computer and use it in GitHub Desktop.

Select an option

Save anthonywong/7a6ad76275b1cc2cbde2a115022a448c to your computer and use it in GitHub Desktop.
Retrieve latest CBBC price for Hong Kong market
/**
* Get (delayed) last price from AASTOCKS Whatshot table.
* Usage in Google Sheets: =AASTOCKS_PRICE("55288")
*
* @param {string|number} symbol HK code (e.g., 5, 00005, 700, 55288)
* @return {number} Last price
* @customfunction
*/
function AASTOCKS_PRICE(symbol) {
// symbol='55288';
if (symbol == null || symbol === "") {
throw new Error('Provide a stock code, e.g. =AASTOCKS_PRICE("55288").');
}
// Keep digits only; AASTOCKS Whatshot accepts both equities (4 digits) and
// structured products (usually 5 digits)
var digits = String(symbol).trim().replace(/\D/g, "");
if (!digits) throw new Error("Symbol must contain digits.");
// Whatshot quote page (server-rendered HTML that contains tblStockPrice)
var url = "https://www.aastocks.com/pkages/web/bcomsec/eng/whatshot/quote_v2.asp?symbol=" + encodeURIComponent(digits);
var res = UrlFetchApp.fetch(url, {
followRedirects: true,
muteHttpExceptions: true,
headers: {
"User-Agent": "Mozilla/5.0 (AppsScript)",
"Accept": "text/html,application/xhtml+xml",
"Accept-Language": "en-US,en;q=0.9",
"Referer": "https://www.aastocks.com/"
}
});
var code = res.getResponseCode();
if (code < 200 || code >= 400) {
throw new Error("AASTOCKS request failed (HTTP " + code + ").");
}
var html = res.getContentText();
// 1) Narrow to the tblStockPrice block
var tableMatch = /<table[^>]*class="[^"]*\btblStockPrice\b[^"]*"[^>]*>[\s\S]*?<\/table>/i.exec(html);
if (!tableMatch) {
throw new Error("tblStockPrice block not found for symbol " + digits + ".");
}
var scope = tableMatch[0];
// 2) Inside that block, capture the number inside the large price cell:
// <td class="f24w"><strong>0.072</strong></td>
// (works for integers, decimals, and comma groups)
var priceMatch = /<td[^>]*class="[^"]*\bf24w\b[^"]*"[^>]*>\s*<strong>\s*([0-9]{1,3}(?:,[0-9]{3})*(?:\.\d+)?|\d+(?:\.\d+)?)\s*<\/strong>/i.exec(scope);
if (!priceMatch) {
// Fallback: sometimes the class ordering varies; grab the FIRST strong number within the table
priceMatch = /<strong>\s*([0-9]{1,3}(?:,[0-9]{3})*(?:\.\d+)?|\d+(?:\.\d+)?)\s*<\/strong>/i.exec(scope);
}
if (!priceMatch) {
throw new Error("Could not locate price in tblStockPrice for symbol " + digits + ".");
}
var price = parseFloat(priceMatch[1].replace(/,/g, ""));
if (isNaN(price)) {
throw new Error("Parsed price is NaN for symbol " + digits + ".");
}
//console.log(price);
return price;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment