EVE Online has one of the most complex player-driven economies in gaming. Billions of ISK change hands every day through player-controlled markets across hundreds of star systems. If you've ever wanted to write a trading bot that finds profitable routes — this guide walks you through it using real, live market data.
We'll use the EVE Online Market Tool API on RapidAPI, which wraps the EVE ESI (EVE Swagger Interface) and does the heavy lifting of scanning thousands of market orders so you don't have to.
What We're Building
A Python script that:
- Fetches current trading opportunities from the EVE market
- Finds arbitrage routes between stations
- Scores each opportunity by profit potential and volume
- Prints a ranked list of trades to execute
Prerequisites
- Python 3.8+
- A free RapidAPI account (the API has a free tier)
- Basic Python knowledge
Step 1: Get Your API Key
- Go to RapidAPI and create a free account
- Search for "EVE Online Market Tool"
- Subscribe to the free BASIC plan
- Copy your
X-RapidAPI-Keyfrom the API console
Step 2: Install Dependencies
pip install requests tabulate colorama
Step 3: The Trading Bot
import requests
import json
from tabulate import tabulate
from colorama import Fore, Style, init
init(autoreset=True)
RAPIDAPI_KEY = "YOUR_RAPIDAPI_KEY_HERE"
RAPIDAPI_HOST = "eve-online-market-tool.p.rapidapi.com"
BASE_URL = f"https://{RAPIDAPI_HOST}"
HEADERS = {
"X-RapidAPI-Key": RAPIDAPI_KEY,
"X-RapidAPI-Host": RAPIDAPI_HOST
}
def get_trading_opportunities():
"""Fetch station trading opportunities (buy low, sell high same station)."""
response = requests.get(f"{BASE_URL}/scan/trading", headers=HEADERS)
response.raise_for_status()
return response.json()
def get_arbitrage_routes():
"""Fetch cross-region arbitrage routes (buy in one region, sell in another)."""
response = requests.get(f"{BASE_URL}/scan/arbitrage", headers=HEADERS)
response.raise_for_status()
return response.json()
def get_npc_arbitrage():
"""Fetch NPC seeded items with player market arbitrage potential."""
response = requests.get(f"{BASE_URL}/scan/npc-arbitrage", headers=HEADERS)
response.raise_for_status()
return response.json()
def analyze_item(item_name):
"""Get deep analysis for a specific item."""
response = requests.get(
f"{BASE_URL}/analyze/{item_name}",
headers=HEADERS
)
response.raise_for_status()
return response.json()
def format_isk(value):
"""Format ISK values with M/B suffixes."""
if value >= 1_000_000_000:
return f"{value/1_000_000_000:.1f}B"
elif value >= 1_000_000:
return f"{value/1_000_000:.1f}M"
elif value >= 1_000:
return f"{value/1_000:.1f}K"
return f"{value:.0f}"
def display_trading_opportunities(data, top_n=10):
"""Display top station trading opportunities."""
print(f"\n{Fore.CYAN}=== STATION TRADING OPPORTUNITIES ==={Style.RESET_ALL}")
print("Buy and sell at the same station for guaranteed margin\n")
if not data or "opportunities" not in data:
print("No data available")
return
opportunities = sorted(
data["opportunities"],
key=lambda x: x.get("profit_margin_pct", 0),
reverse=True
)[:top_n]
rows = []
for opp in opportunities:
margin = opp.get("profit_margin_pct", 0)
color = Fore.GREEN if margin > 20 else Fore.YELLOW if margin > 10 else Fore.WHITE
rows.append([
color + opp.get("item_name", "Unknown") + Style.RESET_ALL,
format_isk(opp.get("buy_price", 0)),
format_isk(opp.get("sell_price", 0)),
f"{margin:.1f}%",
format_isk(opp.get("profit_per_unit", 0)),
opp.get("volume_available", 0),
opp.get("station_name", "Unknown")[:30]
])
headers = ["Item", "Buy", "Sell", "Margin", "Profit/Unit", "Volume", "Station"]
print(tabulate(rows, headers=headers, tablefmt="rounded_outline"))
def display_arbitrage_routes(data, top_n=10):
"""Display top arbitrage routes."""
print(f"\n{Fore.CYAN}=== ARBITRAGE ROUTES ==={Style.RESET_ALL}")
print("Buy in one region, haul to another for profit\n")
if not data or "routes" not in data:
print("No data available")
return
routes = sorted(
data["routes"],
key=lambda x: x.get("profit_total", 0),
reverse=True
)[:top_n]
rows = []
for route in routes:
profit = route.get("profit_total", 0)
color = Fore.GREEN if profit > 50_000_000 else Fore.YELLOW if profit > 10_000_000 else Fore.WHITE
rows.append([
color + route.get("item_name", "Unknown") + Style.RESET_ALL,
route.get("buy_region", "?")[:20],
route.get("sell_region", "?")[:20],
format_isk(route.get("buy_price", 0)),
format_isk(route.get("sell_price", 0)),
format_isk(profit),
route.get("quantity", 0)
])
headers = ["Item", "Buy Region", "Sell Region", "Buy Price", "Sell Price", "Total Profit", "Qty"]
print(tabulate(rows, headers=headers, tablefmt="rounded_outline"))
def main():
print(f"{Fore.MAGENTA}╔══════════════════════════════════╗")
print(f"║ EVE ONLINE MARKET TRADING BOT ║")
print(f"╚══════════════════════════════════╝{Style.RESET_ALL}")
print("\nScanning markets...\n")
try:
# Fetch all data
trading_data = get_trading_opportunities()
arbitrage_data = get_arbitrage_routes()
# Display results
display_trading_opportunities(trading_data)
display_arbitrage_routes(arbitrage_data)
# Quick item analysis example
print(f"\n{Fore.CYAN}=== ITEM DEEP DIVE: Tritanium ==={Style.RESET_ALL}")
trit_data = analyze_item("Tritanium")
if trit_data:
print(json.dumps(trit_data, indent=2))
except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
print(f"{Fore.RED}Invalid API key. Check your RapidAPI key.{Style.RESET_ALL}")
elif e.response.status_code == 429:
print(f"{Fore.RED}Rate limit hit. Upgrade to PRO for higher limits.{Style.RESET_ALL}")
else:
print(f"{Fore.RED}API Error: {e}{Style.RESET_ALL}")
if __name__ == "__main__":
main()
Sample Output
╔══════════════════════════════════╗
║ EVE ONLINE MARKET TRADING BOT ║
╚══════════════════════════════════╝
Scanning markets...
=== STATION TRADING OPPORTUNITIES ===
Buy and sell at the same station for guaranteed margin
╭─────────────────────┬──────────┬──────────┬────────┬────────────┬─────────┬────────────────────────────────╮
│ Item │ Buy │ Sell │ Margin │ Profit/Unit│ Volume │ Station │
├─────────────────────┼──────────┼──────────┼────────┼────────────┼─────────┼────────────────────────────────┤
│ PLEX │ 4.1M │ 5.3M │ 29.3% │ 1.2M │ 847 │ Jita IV - Moon 4 - Caldari N..│
│ Skill Injector │ 812M │ 960M │ 18.2% │ 148M │ 12 │ Jita IV - Moon 4 - Caldari N..│
│ Brutix Navy Issue │ 218M │ 255M │ 17.0% │ 37M │ 3 │ Amarr VIII - Oris - Emperor F.│
╰─────────────────────┴──────────┴──────────┴────────┴────────────┴─────────┴────────────────────────────────╯
Strategy Notes
Station Trading (Best for Beginners)
- Works in Jita (the main trade hub) and Amarr
- Set buy orders slightly above lowest buyer, sell orders slightly below lowest seller
- Target items with 15%+ margins and high daily volume
- Ideal starting capital: 500M ISK+
Arbitrage (Intermediate)
- Buy underpriced items in low-traffic regions, haul to Jita
- Risk: price can move during haul time (minimize with fast ships)
- Caldari Shuttle for scanning, Iteron for hauling
- Use the
/scan/npc-arbitrageendpoint for NPC station seeded items — these replenish automatically
Risk Management
- Never invest more than 20% of capital in a single trade
- Check the
/analyze/{item}endpoint for price history trends before big positions - Avoid items with fewer than 5 sellers (illiquid, spread can disappear)
Going Further
The API also supports:
# Get NPC arbitrage (guaranteed replenish sources)
npc_data = get_npc_arbitrage()
# Analyze specific items for trend data
analysis = analyze_item("Caldari Navy Raven")
PRO tier unlocks higher rate limits (1000 req/month vs 100 on free) — useful if you're running this on a schedule via cron.
Automating the Bot
Run it every hour with cron (Linux/Mac):
# crontab -e
0 * * * * /usr/bin/python3 /path/to/eve_bot.py >> /var/log/eve_bot.log 2>&1
Or Windows Task Scheduler for a daily market report to your inbox.
The full API is available on RapidAPI — search "EVE Online Market Tool" by Circle of Wizards. Free tier includes 100 requests/month, plenty for personal use or small bots.
Happy trading, Capsuleer. o7
Top comments (0)