Covers data/api.py, data/cache.py, data/read_flipping_utils.py, and data/update_prices.py.
Thin wrapper around the OSRS Wiki real-time prices API.
Rate-limited to 1 request per second. User-Agent is set from config.USER_AGENT.
Description: HTTP session for the OSRS Wiki prices API with automatic rate limiting.
Example:
from data.api import WikiClient
client = WikiClient()
mapping = client.get_mapping()
latest = client.get_latest()Description: Fetch item metadata for every tradeable item.
Arguments: None.
Returns: pd.DataFrame indexed by item ID (int) with columns name, members, limit, highalch, lowalch, value.
Example:
mapping = client.get_mapping()
print(mapping.loc[11832, "name"]) # "Bandos chestplate"
print(mapping.loc[11832, "limit"]) # 8Description: Fetch the most recent insta-buy and insta-sell price for every item.
Arguments: None.
Returns: pd.DataFrame indexed by item ID with columns high, highTime, low, lowTime.
high is the last insta-buy (ask); low is the last insta-sell (bid). Times are Unix seconds.
Example:
latest = client.get_latest()
print(latest.loc[11832, "high"]) # e.g. 27_500_000Description: Fetch aggregated OHLC-like data for all items over the last time window.
Arguments:
timestep(str):"1h"or"6h".
Returns: pd.DataFrame indexed by item ID with columns avgHighPrice, avgLowPrice, highPriceVolume, lowPriceVolume.
Example:
agg = client.get_aggregate("1h")
print(agg.loc[2, "avgHighPrice"]) # Cannonball average ask over last 1hDescription: Fetch historical bar data for a single item.
Arguments:
item_id(int): OSRS item ID.timestep(str):"5m","1h", or"6h". Default"1h".
Returns: pd.DataFrame indexed by UTC datetime with columns avgHighPrice, avgLowPrice, highPriceVolume, lowPriceVolume. Empty DataFrame if the item has no history.
Example:
ts = client.get_timeseries(2, "1h") # Cannonball, 1h bars
print(ts.tail(3))Description: Fetch timeseries for multiple items sequentially, respecting the rate limit.
Arguments:
item_ids(list[int]): Item IDs to fetch.timestep(str):"5m","1h", or"6h". Default"1h".
Returns: dict[int, pd.DataFrame] — only items with non-empty results are included.
Example:
data = client.get_timeseries_bulk([2, 11832, 27277], "1h")
print(data.keys()) # {2, 11832, 27277}File-based cache for API responses. DataFrames are stored as Parquet files in cache/.
A JSON manifest (cache/manifest.json) tracks every entry with its save timestamp and TTL (Time To Live) class.
All manifest reads and writes are guarded by a threading.Lock.
Description: Load from cache if fresh; otherwise call fetch_fn(), save the result, and return it.
Arguments:
key(str): Cache key, used as the Parquet filename.ttl_key(str): One of the keys inconfig.CACHE_TTL("mapping","latest","1h","6h","timeseries").fetch_fn(Callable[[], pd.DataFrame]): Zero-argument function that fetches fresh data.force_refresh(bool): Bypass cache and always fetch. DefaultFalse.
Returns: pd.DataFrame. Returns stale cached data if the fetch fails. Returns an empty DataFrame if there is no cache and the fetch fails.
Example:
from data.cache import get_or_fetch
from data.api import WikiClient
client = WikiClient()
mapping = get_or_fetch("mapping", "mapping", client.get_mapping)Description: Return a cached DataFrame if it exists and is within TTL, else None.
Arguments:
key(str): Cache key.ttl_key(str): TTL class key fromconfig.CACHE_TTL.
Returns: pd.DataFrame | None.
Description: Save a DataFrame to cache and update the manifest.
Arguments:
key(str): Cache key.df(pd.DataFrame): Data to save.ttl_key(str): TTL class. Default"timeseries".
Returns: Nothing.
Description: Mark a cache key as stale so the next read triggers a fetch.
Arguments:
key(str): Cache key to invalidate.
Returns: Nothing.
Description: Print a Rich table showing all cached entries with age, TTL, freshness, row count, and file size.
Arguments: None.
Returns: Nothing (side effect: prints to terminal).
Example:
from data.cache import print_cache_status
print_cache_status()Description: Return all cache keys for timeseries entries that are past their TTL.
Arguments: None.
Returns: list[str] of stale cache keys.
Reads ~/.runelite/flipping/<character>.json written by the Flipping Utilities RuneLite plugin.
Auto-selects the most recently modified character file if character is None.
Description: Return all active GE (Grand Exchange) offers from the most recent Flipping Utilities (FU) file.
Arguments:
character(str | None): Character name (filename stem). Auto-selects ifNone.
Returns: list[dict], one entry per occupied slot, sorted by slot index. Each dict has:
| Key | Type | Description |
|---|---|---|
slot |
int |
GE slot index (0–7) |
item_id |
int |
OSRS item ID |
item_name |
str |
Item name from trade history |
is_buy |
bool |
True = buy offer |
status |
str |
BUYING / SELLING / BOUGHT / SOLD |
price |
int |
Offer price per unit |
qty_filled |
int |
Units filled so far |
qty_total |
int |
Total units in offer |
pct_filled |
float |
qty_filled / qty_total |
updated_at |
float |
Last update (Unix seconds) |
started_at |
float |
Offer placed (Unix seconds) |
fill_seconds |
float |
Seconds to fill (or time so far) |
Example:
from data.read_flipping_utils import current_offers
for offer in current_offers():
print(offer["slot"], offer["item_name"], offer["status"])Description: Return the number of GE slots not currently occupied.
Arguments:
character(str | None): Character name. Auto-selects ifNone.
Returns: int (0–8).
Description: Return all individual offers from the Flipping Utilities trade history (buys and sells).
Arguments:
character(str | None): Character name. Auto-selects ifNone.
Returns: list[dict], one entry per completed or cancelled offer. Each dict has:
item_id, item_name, is_buy, status, price, qty, total_gp, started_at, completed_at, fill_seconds.
Description: Return the most recently observed buy and sell price per item, derived from your trade history.
Arguments:
character(str | None): Character name. Auto-selects ifNone.
Returns: dict[int, dict] keyed by item ID. Each value has:
| Key | Type | Description |
|---|---|---|
item_name |
str |
|
last_buy |
int | None |
Most recent BOUGHT price |
last_sell |
int | None |
Most recent SOLD price |
last_buy_at |
float | None |
Unix seconds |
last_sell_at |
float | None |
Unix seconds |
avg_buy |
float | None |
GP (gold pieces) weighted average buy price |
avg_sell |
float | None |
GP-weighted average sell price |
margin |
int | None |
last_sell − last_buy (gross, pre-tax) |
n_buys |
int |
|
n_sells |
int |
Description: Return average fill time per item, split by buy and sell side.
Arguments:
character(str | None): Character name. Auto-selects ifNone.
Returns: dict[int, dict] keyed by item ID. Each value has:
item_name, avg_buy_fill (float | None), avg_sell_fill (float | None).
CLI script that fetches live prices for all items listed in data/prices.csv and writes
updated prices back to that file. Run this manually to refresh data/prices.csv.
python data/update_prices.pyDescription: Fetch /mapping and /latest prices for items in data/prices.csv and write
the updated prices back to data/prices.csv. Does not touch the timeseries cache.
Arguments: None (reads from sys.argv when run as a script).
Returns: Nothing.