- puga/contd.py, tools/contd.py: price open CONTD contract offers against real buy-fresh cost, flagging conditions that can't be priced from the API alone. - tools/buyat.py: cheapest bid price likely to fill by a hard deadline (stockout risk), using the empirical first-passage model from history.py. - puga/actpkg.py, tools/actpkg.py: Refined PrUn XIT ACT buy-list JSON packages. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
70 lines
3.2 KiB
Python
70 lines
3.2 KiB
Python
"""Player-to-player CONTD contracts (FIO /contract/allcontracts/{user}) - the NPC logistics-officer
|
|
offers shown in APEX's CONTD panel, not the public Local Market hauling ads in puga/contracts.py.
|
|
Only OPEN contracts are real choices - exactly one of the pool of (usually 3) offers can be accepted;
|
|
CANCELLED/REJECTED/FULFILLED/PARTIALLY_FULFILLED are history or already-committed work.
|
|
|
|
Condition vocabulary seen in this account's full history (2026-10-16): PAYMENT, REPUTATION,
|
|
PROVISION_SHIPMENT and COMEX_PURCHASE_PICKUP (a material+qty+address you must supply - these are the
|
|
only ones with a real market buy-fresh cost), PICKUP_SHIPMENT/DELIVERY_SHIPMENT (logistics legs, no
|
|
separate cost beyond the material), and open-ended ones this module deliberately does NOT price
|
|
because their real cost depends on context this API can't see (a ship already flying that route, a
|
|
planet you were about to survey anyway, a ship already damaged): EXPLORATION (Address = planet to
|
|
survey), REPAIR_SHIP, HEADQUARTERS_UPGRADE, BASE_CONSTRUCTION, CONTRIBUTION, WAIT,
|
|
INCREASE_SATISFACTION. Judging whether one of those is actually cheap right now is the caller's job.
|
|
"""
|
|
from . import fio, market
|
|
|
|
MATERIAL_TYPES = {"PROVISION_SHIPMENT", "COMEX_PURCHASE_PICKUP"}
|
|
|
|
|
|
def open_contracts():
|
|
me = fio.me()
|
|
data = fio.own(f"/contract/allcontracts/{me}", ttl=60)
|
|
return [c for c in data if c["Status"] == "OPEN"]
|
|
|
|
|
|
def evaluate(contract: dict, cx: str) -> dict:
|
|
"""Payment, priced material requirements (buy-fresh cost at `cx` - assumes none already in free
|
|
stock, check storage for materials you may already hold), and any unpriced/contextual conditions
|
|
flagged separately for the caller to judge."""
|
|
payment = 0.0
|
|
reputation = False
|
|
requirements = [] # (ticker, qty, address)
|
|
flags = [] # (type, address) for conditions this module won't price
|
|
deadline_days = 0.0
|
|
for cond in contract["Conditions"]:
|
|
t = cond["Type"]
|
|
if t == "PAYMENT" and cond.get("Amount"):
|
|
payment += cond["Amount"]
|
|
elif t == "REPUTATION":
|
|
reputation = True
|
|
elif t in MATERIAL_TYPES and cond.get("MaterialTicker"):
|
|
requirements.append((cond["MaterialTicker"], cond["MaterialAmount"], cond.get("Address")))
|
|
elif t not in MATERIAL_TYPES | {"PAYMENT", "REPUTATION", "PICKUP_SHIPMENT", "DELIVERY_SHIPMENT"}:
|
|
flags.append((t, cond.get("Address")))
|
|
dl = cond.get("DeadlineDurationMs")
|
|
if dl:
|
|
deadline_days = max(deadline_days, dl / 86400000)
|
|
|
|
material_cost = 0.0
|
|
short = False
|
|
priced = []
|
|
for tick, qty, addr in requirements:
|
|
r = market.walk(tick, cx, qty, "buy")
|
|
priced.append({"ticker": tick, "qty": qty, "address": addr, "cost": r["total"], "short": r["short"]})
|
|
material_cost += r["total"]
|
|
short = short or r["short"]
|
|
|
|
return {
|
|
"id": contract["ContractLocalId"],
|
|
"partner": contract.get("PartnerName"),
|
|
"payment": payment,
|
|
"reputation": reputation,
|
|
"deadline_days": deadline_days,
|
|
"requirements": priced,
|
|
"material_cost": material_cost,
|
|
"net": payment - material_cost,
|
|
"short": short,
|
|
"flags": flags,
|
|
}
|