Created
October 5, 2025 07:14
-
-
Save anthonywong/7a6ad76275b1cc2cbde2a115022a448c to your computer and use it in GitHub Desktop.
Retrieve latest CBBC price for Hong Kong market
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * 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