Advertisement
davidparks21

item_quality_api.py

Jun 23rd, 2025
407
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.47 KB | Gaming | 0 0
  1. import argparse
  2. import requests
  3. import os
  4. import sys
  5. import csv
  6. import time
  7.  
  8. def format_price(price):
  9.     return "$" + f"{price:,}" if isinstance(price, int) else price
  10.  
  11. def query_market(item_id, api_key):
  12.     all_listings = []
  13.     offset = 0
  14.     page_size = 100  # Torn usually returns ~100 listings per page
  15.     global_seen_uids = set()
  16.  
  17.     print(f"Querying Torn API v2 for item ID {item_id}...")
  18.  
  19.     while True:
  20.         url = f"https://api.torn.com/v2/market?selections=itemMarket&id={item_id}&offset={offset}&key={api_key}"
  21.  
  22.         try:
  23.             response = requests.get(url, timeout=10)
  24.         except Exception as e:
  25.             print(f"ERROR: Failed to query API: {e}")
  26.             sys.exit(1)
  27.  
  28.         if response.status_code != 200:
  29.             print(f"ERROR: API returned status code {response.status_code}")
  30.             print(response.text)
  31.             sys.exit(1)
  32.  
  33.         data = response.json()
  34.  
  35.         if "error" in data:
  36.             print(f"Torn API ERROR: {data['error']}")
  37.             sys.exit(1)
  38.  
  39.         item_info = data.get("itemmarket", {}).get("item", {})
  40.         listings = data.get("itemmarket", {}).get("listings", [])
  41.  
  42.         if offset == 0:
  43.             print(f"\nItem: {item_info.get('name', 'Unknown')} (ID: {item_info.get('id', item_id)})")
  44.  
  45.         if not listings:
  46.             print("No more listings found.")
  47.             break
  48.  
  49.         for listing in listings:
  50.             price = listing.get("price", "-")
  51.             item_id = item_info.get("id", "-")
  52.             stats = listing.get("item_details", {}).get("stats", {})
  53.             quality = stats.get("quality", None)
  54.  
  55.             uid = listing.get("item_details", {}).get("uid", None)
  56.             if uid and uid not in global_seen_uids:
  57.                 all_listings.append({
  58.                     "ItemID": item_id,
  59.                     "UID": uid,
  60.                     "Price": price,
  61.                     "Quality": quality
  62.                 })
  63.                 global_seen_uids.add(uid)
  64.  
  65.         if len(listings) < page_size:
  66.             print("Last page reached.")
  67.             break
  68.  
  69.         offset += page_size
  70.         time.sleep(0.5)
  71.  
  72.     return all_listings
  73.  
  74. def compute_higher_quality_min_prices(listings, percent):
  75.     listings_sorted = sorted(listings, key=lambda x: x["Quality"] if isinstance(x["Quality"], (int, float)) else 0.0, reverse=True)
  76.     min_price_above = None
  77.     results = []
  78.  
  79.     for i, listing in enumerate(listings_sorted):
  80.         result = listing.copy()
  81.  
  82.         if min_price_above is None:
  83.             result[">Quality Min Price"] = "-"
  84.             result["PctChange"] = ""
  85.         else:
  86.             result[">Quality Min Price"] = format_price(min_price_above)
  87.             current_price = listing["Price"]
  88.             if isinstance(current_price, int) and current_price < min_price_above:
  89.                 pct_increase = ((min_price_above - current_price) / current_price) * 100
  90.  
  91.                 this_quality = listing["Quality"] if isinstance(listing["Quality"], (int, float)) else 0.0
  92.                 min_quality_allowed = this_quality - percent
  93.                 lowest_price_in_window = None
  94.  
  95.                 for candidate in listings_sorted:
  96.                     candidate_quality = candidate["Quality"] if isinstance(candidate["Quality"], (int, float)) else 0.0
  97.                     if candidate_quality < min_quality_allowed:
  98.                         continue
  99.                     candidate_price = candidate["Price"]
  100.                     if candidate["UID"] != listing["UID"] and isinstance(candidate_price, int):
  101.                         if lowest_price_in_window is None or candidate_price < lowest_price_in_window:
  102.                             lowest_price_in_window = candidate_price
  103.  
  104.                 if lowest_price_in_window is not None and lowest_price_in_window != current_price:
  105.                     price_diff = current_price - lowest_price_in_window
  106.                     price_diff_prefix = "+" if price_diff >= 0 else "-"
  107.                     result["PctChange"] = f"(+{pct_increase:.1f}%|{price_diff_prefix}{format_price(abs(price_diff))})"
  108.                 else:
  109.                     result["PctChange"] = f"(+{pct_increase:.1f}%)"
  110.             else:
  111.                 result["PctChange"] = ""
  112.  
  113.         price = listing["Price"]
  114.         if isinstance(price, int):
  115.             if (min_price_above is None) or (price < min_price_above):
  116.                 min_price_above = price
  117.  
  118.         results.append(result)
  119.  
  120.     return results
  121.  
  122. def print_listings(listings):
  123.     print("\n{:<12} {:>15} {:>10} {:>20} {:>25}".format(
  124.         "Item ID", "Price", "Quality", ">Quality Min Price", "PctChange"
  125.     ))
  126.     print("-" * 90)
  127.  
  128.     for listing in listings:
  129.         quality_display = f"{listing['Quality']:.2f}" if isinstance(listing["Quality"], (float, int)) else "0.00"
  130.         min_price_display = listing[">Quality Min Price"]
  131.         pct_change_display = listing["PctChange"]
  132.  
  133.         print("{:<12} {:>15} {:>10} {:>20} {:>25}".format(
  134.             listing["ItemID"],
  135.             format_price(listing["Price"]),
  136.             quality_display,
  137.             min_price_display,
  138.             pct_change_display
  139.         ))
  140.  
  141. def main():
  142.     parser = argparse.ArgumentParser(description="Query Torn v2 market listings for an item (with paging, quality sort, higher quality min price).")
  143.     parser.add_argument("--id", type=int, required=True, help="Item ID to query.")
  144.     parser.add_argument("--csv", type=str, help="Optional CSV output filename.")
  145.     parser.add_argument("--percent", type=float, default=10.0, help="Fixed quality delta to compare lower quality prices (default 10.0 quality points).")
  146.     args = parser.parse_args()
  147.  
  148.     api_key = os.environ.get("TORN_API_KEY")
  149.     if not api_key:
  150.         print("ERROR: Environment variable TORN_API_KEY is not set.")
  151.         sys.exit(1)
  152.  
  153.     all_listings = query_market(args.id, api_key)
  154.  
  155.     if not all_listings:
  156.         print("No listings found.")
  157.         sys.exit(0)
  158.  
  159.     enriched_listings = compute_higher_quality_min_prices(all_listings, args.percent)
  160.  
  161.     print_listings(enriched_listings)
  162.  
  163.     if args.csv:
  164.         fieldnames = ["ItemID", "Price", "Quality", ">Quality Min Price", "PctChange"]
  165.         with open(args.csv, mode="w", newline="") as csvfile:
  166.             writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
  167.             writer.writeheader()
  168.             writer.writerows(enriched_listings)
  169.         print(f"\nCSV written to {args.csv}")
  170.  
  171. if __name__ == "__main__":
  172.     main()
  173.  
Tags: torn
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement