#!/usr/bin/env python3 """Scan live Local Market hauling ads (real player-posted freight jobs, FIO /localmarket/shipping/*) and rank by margin after real fuel cost (puga.shipping). One-way cost only (margin assumes you pick up the next job near the destination, not an empty flight home). tools/lmscan.py ANT # ads picking up at Antares Station tools/lmscan.py ANT --direction destination # ads dropping off at Antares Station tools/lmscan.py ZV-759c --min-margin 0 # only profitable ones, from Deimos """ import argparse, sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from puga import config, contracts, market def main(): ap = argparse.ArgumentParser() ap.add_argument("planet", help="station/planet natural id to scan ads at, e.g. ANT, ZV-759c") ap.add_argument("--direction", choices=["source", "destination"], default="source", help="source = ads picking up here (default); destination = ads dropping off here") ap.add_argument("--v0", type=float, default=1.0) ap.add_argument("--v1", type=float, default=1.0) ap.add_argument("--min-margin", type=float, help="only show ads with at least this AIC margin") ap.add_argument("--cx", default=config.DEFAULT_CX) a = ap.parse_args() snap = market.snapshot() sf_px = (snap.get(("SF", a.cx)) or market.Quote("SF", a.cx)).ask or 0 ff_px = (snap.get(("FF", a.cx)) or market.Quote("FF", a.cx)).ask or 0 rows = contracts.scan(a.planet, a.direction, sf_px, ff_px, a.v0, a.v1) priced = [r for r in rows if r["margin_aic"] is not None] unpriceable = [r for r in rows if r["margin_aic"] is None] priced.sort(key=lambda r: r["margin_aic"], reverse=True) if a.min_margin is not None: priced = [r for r in priced if r["margin_aic"] >= a.min_margin] print(f"{len(rows)} ads ({a.direction} = {a.planet}), {len(priced)} priceable at v0={a.v0} v1={a.v1}\n") print(f"{'route':16} {'jump':4} {'t':>6} {'m3':>6} {'payout':>9} {'fuel/fee':>9} {'margin':>9} {'margin/day':>11}") for r in priced: print(f"{r['OriginPlanetNaturalId']}->{r['DestinationPlanetNaturalId']:11} {r['JumpDistance']:4} " f"{r['CargoWeight']:6.0f} {r['CargoVolume']:6.0f} {r['PayoutPrice']:9,.0f} " f"{r['cost']['aic']:9,.0f} {r['margin_aic']:9,.0f} {r['margin_per_day']:11,.0f}") if unpriceable: print(f"\n{len(unpriceable)} ad(s) not priced (over-capacity cargo, non-AIC payout, or an unmeasured gateway route):") for r in unpriceable: reason = "cargo exceeds 500t/500m3 (needs multiple trips, not modelled)" if r["over_capacity"] else \ ("non-AIC payout" if r["PayoutCurrency"] != "AIC" else "no known route (unmeasured gateway?)") print(f" {r['OriginPlanetNaturalId']}->{r['DestinationPlanetNaturalId']} {r['PayoutPrice']:,.0f} {r['PayoutCurrency']} [{reason}]") print("\nCAVEATS: one-way cost only, assumes a return cargo lined up at the destination (no empty flight home " "priced in) - see puga/contracts.py. margin/day divides by the ad's DeliveryTime DEADLINE, not real " "transit time (we don't model trip duration, only fuel) - treat it as a floor, not the real rate. " "Fuel model itself is scoped to this account's one hull/reactor; see puga/shipping.py for open gaps.") if __name__ == "__main__": main()