Fetching Real-Time Precious Metals Prices from Shanghai Gold Exchange via API
The Shanghai Gold Exchange (SGE) price data is served dynamically through a JSONP endpoint that returns structured market quotes. The API accepts a comma-separated list of instrument codes and appends a timestamp to prevent caching.
Instrument identifiers include:
JO_9753,JO_92226,JO_9754,JO_71,JO_70,JO_73,JO_72,JO_75,JO_9751,JO_9752,
JO_92224,JO_92225,JO_92276,JO_76,JO_74,JO_92277,JO_92278
The corresponding endpoint is:
https://api.jijinhao.com/quoteCenter/realTime.htm?codes=JO_9753,...,JO_92278
Response format contains a global quote_json object where each key maps to an instrument code, and values are objects with fields like q1 (open), q2 (close), q3 (high), q4 (low), q5 (bid), q6 (ask), q63 (last), q70 (change), q80 (change percent), time (Unix timestamp in milliseconds), digits (decimal precision), showCode (symbol name), and unit.
Below is a clean Python implemantation that fetches, parses, and normalizes this data with out HTML formatting or UI logic:
import requests
import json
from datetime import datetime
from typing import Dict, Any, Optional
# Mapping from internal code to human-readable name
INSTRUMENT_NAMES = {
"Au(T+D)": "Gold T+D",
"mAu(T+D)": "Mini Gold T+D",
"Ag(T+D)": "Silver T+D",
"Au9999": "Gold 99.99%",
"Au9995": "Gold 99.95%",
"Au100g": "100g Gold Bar",
"Au50g": "50g Gold Bar",
"Ag999": "Silver 99.9%",
"AuT+N1": "Gold T+N1",
"AuT+N2": "Gold T+N2",
"SGiAu100g": "Gi 100g Gold",
"SGiAu9999i": "Gi Gold 99.99%",
"SGiAu995i": "Gi Gold 99.95%",
"Ag9999": "Silver 99.99%",
"PT9995": "Platinum 99.95%",
"NYAuTN06": "NYMEX Gold TN06",
"NYAuTN12": "NYMEX Gold TN12"
}
# Correspondence between JO_* codes and symbols
CODE_TO_SYMBOL = {
"JO_9753": "Au(T+D)",
"JO_92226": "mAu(T+D)",
"JO_9754": "Ag(T+D)",
"JO_71": "Au9999",
"JO_70": "Au9995",
"JO_73": "Au100g",
"JO_72": "Au50g",
"JO_75": "Ag999",
"JO_9751": "AuT+N1",
"JO_9752": "AuT+N2",
"JO_92224": "SGiAu100g",
"JO_92225": "SGiAu9999i",
"JO_92276": "SGiAu995i",
"JO_76": "Ag9999",
"JO_74": "PT9995",
"JO_92277": "NYAuTN06",
"JO_92278": "NYAuTN12"
}
def fetch_sge_quotes() -> Dict[str, Dict[str, Any]]:
base_url = "https://api.jijinhao.com/quoteCenter/realTime.htm"
codes = ",".join(CODE_TO_SYMBOL.keys())
url = f"{base_url}?codes={codes}"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
try:
response = requests.get(url, headers=headers, timeout=10)
response.raise_for_status()
# Extract JSONP callback: look for 'quote_json = {...};'
content = response.text.strip()
start = content.find('{')
end = content.rfind('}') + 1
if start == -1 or end == 0:
raise ValueError("Invalid JSONP response: missing JSON object")
json_str = content[start:end]
raw_data = json.loads(json_str)
result = {}
for jo_code, quote in raw_data.items():
if not isinstance(quote, dict):
continue
symbol = CODE_TO_SYMBOL.get(jo_code)
if not symbol:
continue
digits = int(quote.get("digits", 2))
def safe_round(val) -> Optional[float]:
try:
return round(float(val), digits) if val not in (None, "", "----") else None
except (ValueError, TypeError):
return None
def safe_datetime(ts_ms) -> Optional[str]:
try:
if isinstance(ts_ms, (int, float)) and ts_ms > 1e9:
return datetime.fromtimestamp(ts_ms / 1000).strftime("%Y-%m-%d %H:%M:%S")
except (OSError, ValueError):
pass
return None
result[symbol] = {
"name": INSTRUMENT_NAMES.get(symbol, symbol),
"last": safe_round(quote.get("q63")),
"change_value": safe_round(quote.get("q70")),
"change_percent": safe_round(quote.get("q80")),
"open": safe_round(quote.get("q1")),
"close": safe_round(quote.get("q2")),
"high": safe_round(quote.get("q3")),
"low": safe_round(quote.get("q4")),
"bid": safe_round(quote.get("q5")),
"ask": safe_round(quote.get("q6")),
"timestamp": safe_datetime(quote.get("time")),
"unit": quote.get("unit", "").strip() or None
}
return result
except Exception as e:
print(f"Failed to fetch SGE quotes: {e}")
return {}
# Example usage
if __name__ == "__main__":
quotes = fetch_sge_quotes()
for symbol, data in quotes.items():
if data["last"] is not None:
print(f"{data['name']} ({symbol}): {data['last']} {data['unit'] or ''} @ {data['timestamp']}")
This script handles malformed responses, missing fields, and type coercion gracefully. It discards presentation logic (e.g., color classes or HTML wrappers), converts timestamps to ISO-style strings, replaces placeholder values (----) with None, and maps internal codes to standardized instrument names and units.