Skip to content

Instantly share code, notes, and snippets.

@jweinst1
Last active May 2, 2026 08:21
Show Gist options
  • Select an option

  • Save jweinst1/b103abc706fb5090a0e51de4f1ebb03e to your computer and use it in GitHub Desktop.

Select an option

Save jweinst1/b103abc706fb5090a0e51de4f1ebb03e to your computer and use it in GitHub Desktop.
get russell 2000 tickers in python
import requests
import csv
import io
def get_russell_2000_tickers() -> list[str]:
"""
Fetches current Russell 2000 constituents from iShares IWM ETF holdings CSV.
Pure Python + built-in csv module. No pandas. Handles the messy header + huge disclaimer.
Returns clean tickers ready for yfinance (BRK.B → BRK-B).
"""
url = "https://www.ishares.com/us/products/239710/ishares-russell-2000-etf/1467271812596.ajax?fileType=csv&fileName=IWM"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"Accept": "text/csv"
}
resp = requests.get(url, headers=headers, timeout=20)
resp.raise_for_status()
text = resp.text
lines = [line.strip() for line in text.splitlines() if line.strip()]
# Find the start of the real data (header row that contains "Ticker")
start_idx = 0
for i, line in enumerate(lines):
if line.startswith('"Ticker"') or ('Ticker' in line and 'Name' in line):
start_idx = i
break
else:
# Fallback: first line with many commas
for i, line in enumerate(lines):
if line.count(',') > 8:
start_idx = i
break
# Parse only the data section with csv module
data_section = '\n'.join(lines[start_idx:])
csv_file = io.StringIO(data_section)
reader = csv.reader(csv_file)
tickers = []
header = next(reader, None) # skip header row
if header:
# Find Ticker column index (handles slight column name variations)
ticker_col = next((i for i, col in enumerate(header) if col and ('Ticker' in col or 'Symbol' in col)), 0)
for row in reader:
if not row or len(row) <= ticker_col:
continue
ticker = row[ticker_col].strip()
# Stop when we hit the legal disclaimer text
if (ticker.startswith('The content contained herein') or
ticker.startswith('©') or
ticker.startswith('Holdings subject to change') or
'BlackRock' in ticker):
break
# Skip junk rows
if (not ticker or
ticker == '-' or
ticker.startswith('RTYM') or # futures
len(ticker) < 2):
continue
# Clean for yfinance
ticker = ticker.replace('.', '-')
tickers.append(ticker)
clean_tickers = sorted(set(tickers))
print(f"✅ Successfully parsed {len(clean_tickers)} Russell 2000 tickers")
return clean_tickers
print(get_russell_2000_tickers())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment