Examples¶
🤖 AI Summary
Code examples for common tasks: Match analysis - get KDA, GPM, winner. Player tracking - profile, recent matches, winrate, most played heroes. Meta heroes - filter by pro pick rates, sort by win rate. Player comparison - compare stats between two players. Pro match monitor - poll for new pro matches. Batch collection - paginate through high MMR matches with rate limiting. New in 7.40: Draft analysis, support stats (wards, stacking), laning efficiency, gold/XP timelines, hero variants, comeback detection.
Analyze Match Performance¶
from opendota import OpenDota
async def analyze_match(match_id: int):
async with OpenDota() as client:
match = await client.get_match(match_id)
print(f"Match {match_id} Analysis:")
print(f"Duration: {match.duration // 60}m {match.duration % 60}s")
print(f"Winner: {'Radiant' if match.radiant_win else 'Dire'}")
print(f"Score: {match.radiant_score} - {match.dire_score}")
# Find MVP by KDA
best_kda = max(
match.players,
key=lambda p: (p.kills + p.assists) / max(p.deaths, 1)
)
team = "Radiant" if best_kda.player_slot < 128 else "Dire"
print(f"Best KDA: {best_kda.kills}/{best_kda.deaths}/{best_kda.assists} ({team})")
# Team gold comparison
radiant_gpm = sum(p.gold_per_min for p in match.players if p.player_slot < 128)
dire_gpm = sum(p.gold_per_min for p in match.players if p.player_slot >= 128)
print(f"Avg GPM - Radiant: {radiant_gpm/5:.0f}, Dire: {dire_gpm/5:.0f}")
Track Player Progress¶
from opendota import OpenDota
async def track_player(account_id: int):
async with OpenDota() as client:
# Get player profile
player = await client.get_player(account_id)
print(f"Player: {player.profile.personaname}")
print(f"Rank: {player.rank_tier}")
# Get recent matches
matches = await client.get_player_matches(account_id, limit=20)
wins = sum(1 for m in matches if (m.player_slot < 128) == m.radiant_win)
total = len(matches)
winrate = wins / total * 100
avg_kills = sum(m.kills for m in matches) / total
avg_deaths = sum(m.deaths for m in matches) / total
avg_assists = sum(m.assists for m in matches) / total
print(f"Last {total} matches:")
print(f"Winrate: {winrate:.1f}% ({wins}/{total})")
print(f"Avg KDA: {avg_kills:.1f}/{avg_deaths:.1f}/{avg_assists:.1f}")
# Most played heroes
hero_counts = {}
for match in matches:
hero_counts[match.hero_id] = hero_counts.get(match.hero_id, 0) + 1
heroes = await client.get_heroes()
hero_names = {h.id: h.localized_name for h in heroes}
print("Most played heroes:")
for hero_id, count in sorted(hero_counts.items(), key=lambda x: x[1], reverse=True)[:3]:
print(f" {hero_names.get(hero_id, 'Unknown')}: {count} games")
Find Meta Heroes¶
from opendota import OpenDota
async def find_meta_heroes():
async with OpenDota() as client:
hero_stats = await client.get_hero_stats()
# Filter heroes with significant pick rates
meta_heroes = [h for h in hero_stats if (h.pro_pick or 0) > 50]
# Sort by win rate
meta_heroes.sort(
key=lambda h: (h.pro_win or 0) / max(h.pro_pick or 1, 1),
reverse=True
)
print("Current meta heroes (high pick + win rate):")
for hero in meta_heroes[:10]:
if hero.pro_pick and hero.pro_win:
winrate = hero.pro_win / hero.pro_pick * 100
print(f"{hero.localized_name}: {winrate:.1f}% WR ({hero.pro_pick} picks)")
Compare Two Players¶
from opendota import OpenDota
async def compare_players(player1_id: int, player2_id: int):
async with OpenDota() as client:
p1 = await client.get_player(player1_id)
p2 = await client.get_player(player2_id)
p1_matches = await client.get_player_matches(player1_id, limit=50)
p2_matches = await client.get_player_matches(player2_id, limit=50)
def calc_stats(matches):
wins = sum(1 for m in matches if (m.player_slot < 128) == m.radiant_win)
avg_kda = sum(m.kills + m.assists for m in matches) / max(sum(m.deaths for m in matches), 1)
return {"winrate": wins / len(matches) * 100, "kda": avg_kda}
stats1 = calc_stats(p1_matches)
stats2 = calc_stats(p2_matches)
print(f"Comparison: {p1.profile.personaname} vs {p2.profile.personaname}")
print(f"Winrate: {stats1['winrate']:.1f}% vs {stats2['winrate']:.1f}%")
print(f"Avg KDA: {stats1['kda']:.2f} vs {stats2['kda']:.2f}")
Pro Match Monitor¶
from opendota import OpenDota
import asyncio
async def monitor_pro_matches():
async with OpenDota() as client:
last_match_id = None
while True:
pro_matches = await client.get_pro_matches()
for match in pro_matches:
if last_match_id and match.match_id <= last_match_id:
break
if match.radiant_name and match.dire_name:
winner = match.radiant_name if match.radiant_win else match.dire_name
print(f"[{match.league_name}] {match.radiant_name} vs {match.dire_name}")
print(f" Winner: {winner} ({match.duration // 60}m)")
if pro_matches:
last_match_id = pro_matches[0].match_id
await asyncio.sleep(60) # Check every minute
Batch Data Collection¶
from opendota import OpenDota
import asyncio
async def collect_high_mmr_matches(count: int = 100):
async with OpenDota() as client:
all_matches = []
last_match_id = None
while len(all_matches) < count:
matches = await client.get_public_matches(
mmr_descending=6000,
less_than_match_id=last_match_id
)
if not matches:
break
all_matches.extend(matches)
last_match_id = matches[-1].match_id
# Respect rate limits
await asyncio.sleep(1)
print(f"Collected {len(all_matches)} high MMR matches")
return all_matches[:count]
Analyze Pro Match Draft (New in 7.40)¶
from opendota import OpenDota
async def analyze_draft(match_id: int):
async with OpenDota() as client:
match = await client.get_match(match_id)
if not match.draft_timings:
print("No draft data (not Captains Mode)")
return
# Get hero names
heroes = await client.get_heroes()
hero_names = {h.id: h.localized_name for h in heroes}
print(f"Draft: {match.radiant_name} vs {match.dire_name}")
print(f"Tournament: {match.league.name}\n")
bans = [d for d in match.draft_timings if not d.pick]
picks = [d for d in match.draft_timings if d.pick]
print("Bans:")
for ban in bans:
team = match.radiant_name if ban.active_team == 0 else match.dire_name
hero = hero_names.get(ban.hero_id, "Unknown")
print(f" {team}: {hero}")
print("\nPicks:")
for pick in picks:
team = match.radiant_name if pick.active_team == 0 else match.dire_name
hero = hero_names.get(pick.hero_id, "Unknown")
print(f" {team}: {hero}")
Support Player Analysis (New in 7.40)¶
from opendota import OpenDota
async def analyze_supports(match_id: int):
async with OpenDota() as client:
match = await client.get_match(match_id)
heroes = await client.get_heroes()
hero_names = {h.id: h.localized_name for h in heroes}
print(f"Support Analysis: {match.radiant_name} vs {match.dire_name}\n")
# Find supports by ward placement
supports = sorted(
match.players,
key=lambda p: (p.obs_placed or 0) + (p.sen_placed or 0),
reverse=True
)[:4] # Top 4 ward placers
for player in supports:
team = "Radiant" if player.isRadiant else "Dire"
hero = hero_names.get(player.hero_id, "Unknown")
print(f"[{team}] {player.personaname} - {hero}")
print(f" Wards: {player.obs_placed or 0} obs, {player.sen_placed or 0} sen")
print(f" Camps stacked: {player.camps_stacked or 0}")
print(f" Teamfight: {(player.teamfight_participation or 0) * 100:.0f}%")
print()
Laning Phase Analysis (New in 7.40)¶
from opendota import OpenDota
async def analyze_laning(match_id: int):
async with OpenDota() as client:
match = await client.get_match(match_id)
heroes = await client.get_heroes()
hero_names = {h.id: h.localized_name for h in heroes}
lane_names = {1: "Safelane", 2: "Mid", 3: "Offlane"}
print("Laning Phase Analysis\n")
for team_name, is_radiant in [("Radiant", True), ("Dire", False)]:
print(f"{team_name}:")
team_players = [p for p in match.players if p.isRadiant == is_radiant]
for player in sorted(team_players, key=lambda p: p.lane or 0):
hero = hero_names.get(player.hero_id, "Unknown")
lane = lane_names.get(player.lane, "Unknown")
eff = (player.lane_efficiency or 0) * 100
print(f" {hero} ({lane}): {eff:.0f}% efficiency")
print()
Gold/XP Timeline (New in 7.40)¶
from opendota import OpenDota
async def plot_economy(match_id: int):
async with OpenDota() as client:
match = await client.get_match(match_id)
# Get carry players (highest GPM)
carries = sorted(match.players, key=lambda p: p.gold_per_min, reverse=True)[:2]
for player in carries:
if not player.gold_t:
continue
team = "Radiant" if player.isRadiant else "Dire"
print(f"[{team}] {player.personaname}")
print(f" Final gold: {player.gold_t[-1]:,}")
print(f" 10 min gold: {player.gold_t[10]:,}")
print(f" 20 min gold: {player.gold_t[20]:,}")
# Calculate gold gained per phase
laning = player.gold_t[10] - player.gold_t[0]
mid = player.gold_t[20] - player.gold_t[10]
late = player.gold_t[-1] - player.gold_t[20]
print(f" Laning (0-10): +{laning:,}")
print(f" Mid (10-20): +{mid:,}")
print(f" Late (20+): +{late:,}")
print()
Hero Variant Tracking (New in 7.40)¶
from opendota import OpenDota
async def find_arcana_games(hero_id: int, limit: int = 100):
"""Find recent games where players used hero personas/arcanas."""
async with OpenDota() as client:
heroes = await client.get_heroes()
hero_name = next((h.localized_name for h in heroes if h.id == hero_id), "Unknown")
matches = await client.get_public_matches()
arcana_count = 0
for pub_match in matches[:limit]:
match = await client.get_match(pub_match.match_id)
for player in match.players:
if player.hero_id == hero_id and player.hero_variant and player.hero_variant > 0:
arcana_count += 1
print(f"Match {match.match_id}: {hero_name} variant {player.hero_variant}")
print(f"\nFound {arcana_count} games with {hero_name} arcana/persona")
Match Comeback Detection (New in 7.40)¶
from opendota import OpenDota
async def find_comebacks():
async with OpenDota() as client:
pro_matches = await client.get_pro_matches()
comebacks = []
for pm in pro_matches[:20]:
match = await client.get_match(pm.match_id)
if match.comeback and match.comeback > 1000:
comebacks.append({
"match_id": match.match_id,
"teams": f"{match.radiant_name} vs {match.dire_name}",
"comeback": match.comeback,
"winner": match.radiant_name if match.radiant_win else match.dire_name
})
print("Recent Comeback Games:")
for game in sorted(comebacks, key=lambda x: x["comeback"], reverse=True):
print(f" {game['teams']}")
print(f" Comeback score: {game['comeback']:.0f}")
print(f" Winner: {game['winner']}")
print()