Peru Stock API Guide: Fetch BVL Real-Time & Historical Data with Python

Introduction
Amid the accelerating trend toward global multi-asset allocation, Latin American capital markets — particularly Peru — have emerged as an increasingly relevant frontier for institutional and systematic investors. The Bolsa de Valores de Lima (BVL) hosts a concentrated universe of high-quality issuers, predominantly in the mining, financial services, and consumer sectors. However, reliable, low-latency, and programmatically accessible data coverage for the Peruvian market remains limited.
This guide demonstrates how to leverage the iTick Financial Data Platform to seamlessly obtain real-time Level 1 quotes, historical bar (K-line) series, and related market metrics from the BVL via clean, RESTful endpoints — enabling robust quantitative research, systematic strategy development, backtesting, and live execution workflows.
Why iTick for Peruvian Market Access?
iTick is a professional-grade market data vendor delivering unified API access across multiple asset classes and geographies. Key advantages relevant to emerging market equities include:
- Broad geographic coverage — including major LatAm venues (Mexico, Brazil, Peru, Argentina, Chile) alongside developed markets (US, Hong Kong, A-shares, etc.)
- Dual delivery protocols — REST for on-demand polling and historical retrieval; WebSocket for streaming real-time tick and market-by-order updates
- Developer-first design — consistent request/response schema, comprehensive SDK examples, OpenAPI-compatible documentation
- Institutional-grade customization — bespoke symbol universes, SLA-backed latency, and premium data entitlements available for enterprise clients
Prerequisites: Authentication & Environment Setup
All authenticated requests require an API Token obtained after registration on the iTick platform.
API_TOKEN = "your_api_token_here" # ← replace with your actual token
BASE_URL = "https://api.itick.org"
REST API Protocol Overview
iTick REST endpoints follow HTTPS GET conventions with JSON payloads. Authentication is performed via HTTP header:
headers = {
"Accept": "application/json",
"Token": API_TOKEN
}
Successful responses follow the envelope pattern:
{
"code": 0,
"msg": "ok",
"data": { … }
}
Non-zero code values indicate business-level errors (rate limit, invalid symbol, subscription entitlement, etc.).
Use Case 1 – Real-Time Level 1 Quote
Retrieve current inside market, last trade, session statistics, and basic reference data for a single instrument.
EndpointGET /stock/quote
Required Query Parameters
region— ISO country/market code ("PE"for Peru)code— local ticker symbol (e.g.,"SCCO"– Southern Copper Corporation)
Example Implementation
import requests
def fetch_realtime_quote(region: str, symbol: str) -> dict | None:
"""Retrieve Level 1 real-time quote for a Peruvian equity."""
url = f"{BASE_URL}/stock/quote"
params = {"region": region, "code": symbol}
try:
r = requests.get(url, headers=headers, params=params, timeout=5)
r.raise_for_status()
payload = r.json()
if payload.get("code") != 0:
print(f"API error: {payload.get('msg')}")
return None
quote = payload["data"]
print(f"Ticker: {quote.get('s')}")
print(f"Last: {quote.get('ld')}")
print(f"Open: {quote.get('o')}")
print(f"High: {quote.get('h')}")
print(f"Low: {quote.get('l')}")
print(f"Change: {quote.get('ch')} ({quote.get('chp')}%)")
print(f"Volume: {quote.get('v'):,}")
return quote
except Exception as e:
print(f"Request failed: {e}")
return None
# Example: Southern Copper (SCCO.PE)
fetch_realtime_quote("PE", "SCCO")
Field reference (indicative; refer to latest docs):ld = Last traded pricech / chp = Absolute / percentage change from previous closev = Session accumulated volume
Use Case 2 – Historical OHLCV Candlestick Series
Fetch time-barred aggregated data suitable for backtesting, technical analysis, and risk modeling.
EndpointGET /stock/kline
Key Parameters
region—"PE"code— symbolkType— bar aggregation:
1 = 1-min, 2 = 5-min, 3 = 15-min, 4 = 30-min, 5 = 60-min,
6/8 = Daily, 7/9 = Weekly, 8/10 = Monthly (exact mapping may vary)limit— number of bars to return (most recent first)et— optional end timestamp (Unix ms) for anchoring the window
Example – Pandas Integration
import requests
import pandas as pd
def fetch_ohlcv(region: str, symbol: str, ktype: int, limit: int = 200, end_ts: int = None) -> pd.DataFrame | None:
url = f"{BASE_URL}/stock/kline"
params = {"region": region, "code": symbol, "kType": ktype, "limit": limit}
if end_ts:
params["et"] = end_ts
try:
r = requests.get(url, headers=headers, params=params)
r.raise_for_status()
payload = r.json()
if payload.get("code") != 0:
print(f"API error: {payload.get('msg')}")
return None
bars = payload.get("data", [])
if not bars:
return None
df = pd.DataFrame(bars)
df.rename(columns={
"t": "timestamp_ms",
"o": "open",
"h": "high",
"l": "low",
"c": "close",
"v": "volume"
}, inplace=True)
df["datetime"] = pd.to_datetime(df["timestamp_ms"], unit="ms", utc=True)
df.sort_values("timestamp_ms", inplace=True)
df.set_index("datetime", inplace=True)
print(f"Retrieved {len(df)} bars | Range: {df.index.min()} → {df.index.max()}")
return df[["open", "high", "low", "close", "volume"]]
except Exception as e:
print(f"Request failed: {e}")
return None
# Example: Last 30 daily bars
df_daily = fetch_ohlcv("PE", "SCCO", ktype=8, limit=30)
if df_daily is not None:
print(df_daily.tail())
print("\nSummary statistics:")
print(df_daily["close"].describe())
Use Case 3 – Batch Multi-Symbol Real-Time Quotes
Efficiently monitor a watchlist of Peruvian names in a single call.
EndpointGET /stock/quotes
Parameter
codes— comma-separated list of symbols
Implementation Snippet
def fetch_batch_quotes(region: str, symbols: list[str]) -> dict | None:
url = f"{BASE_URL}/stock/quotes"
params = {"region": region, "codes": ",".join(symbols)}
try:
r = requests.get(url, headers=headers, params=params)
r.raise_for_status()
payload = r.json()
if payload.get("code") != 0:
return None
return payload["data"] # {symbol: quote_dict, ...}
except Exception as e:
print(e)
return None
# Example watchlist
batch = fetch_batch_quotes("PE", ["SCCO", "BVN", "VOLCABC1"])
Important Considerations & Best Practices
- Symbol Format & Coverage
Peruvian tickers may require specific suffix or exchange prefix. Always validate the exact symbology via iTick’s/symbol/listendpoint or contact support (Telegram: @iticksupport | WhatsApp: +852 59046663). - Rate Limits & Quotas
Free tier imposes strict call-per-minute restrictions. Production deployments typically require a paid subscription tier. - Latency & Data Sourcing
REST polling introduces additional latency; high-frequency or execution-oriented strategies should migrate to WebSocket streaming. Historical data fidelity should be cross-validated when possible. - Error Handling & Resilience
Implement exponential backoff, circuit breakers, and comprehensive logging around network, HTTP 4xx/5xx, and business-level (code ≠ 0) failures.
Conclusion
The Peruvian equity market offers attractive exposure to commodity super-cycles, prudent fiscal policy, and under-researched alpha opportunities. With iTick’s unified REST + WebSocket APIs, quantitative practitioners and fintech developers can efficiently incorporate BVL data into global multi-market models without building custom exchange integrations.
Start by registering at https://itick.org, obtain your token, and test the code samples above against live Peruvian symbols.
Further Reading
- Argentina BCBA (BYMA) Market Data Integration Guide
- Toronto Stock Exchange (TSX/TSXV) Real-Time & Historical API Tutorial
- Combining Quantitative Chanlun Indicators with Real-Time Quote Streams
- Global Equities Real-Time Data Infrastructure for Systematic Trading
- Official API Reference
- https://github.com/itick-org