A resting order at the same price was posted first and has time
priority, so it should count as ahead too (p <= r["price"], not p <).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A driftless-random-walk closed form was tried first and backtested wrong
against 3 years of real exchange history (overstated touch probability
2-4x, confounded by discrete daily-VWAP sampling and real mean-reversion).
Replaced with puga.history.empirical_touch(): a non-parametric estimator
measuring first-passage directly from a ticker's own history, conditioned
on current state (trailing-60d z-score) since mean reversion's effect
depends on where price is now, not just move size. Queue-depth (existing
resting quantity) folds in as a deterministic shift of the hitting time,
not a max, ranking by the resulting hit_factor rather than a point
estimate of median days (which created a false cliff at the 50%-touched
threshold). Optional fixed-horizon right-censoring avoids recency bias
in "never reached" samples.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- puga/network.py + tools/network.py: model a multi-base chain (e.g. mine LST at one base,
ship it, consume it at another). Simulates each base independently, nets a transferred
material's producer-surplus against consumer-need, charges real freight only on what's
moved, cm_free for a founding covered by a Core Module Kit. Worked example in plans/chains/.
- puga/saturation.py: real price-band filtering. FIO's order_book NarrowPriceBandLow/High and
WidePriceBandLow/High match APEX's own displayed Price Band exactly (verified live) - an
order outside it is a stale artifact, not just uncompetitive. Added in_band() and
effective_demand(); effective_supply() gained the same hard band filter alongside its
existing soft vwap-proximity filter (renamed that param mult to free up `band`). Wired into
tools/scan.py stage 2 in place of the raw, unfiltered demand figure. Was flagged as an
unimplemented refinement in saturation-design.md since the original design review.
- tools/sell.py: self-contained tranche split (aggressive tranche capped at a volume quantile,
median normally or 80th pct with --tight when a payment is imminent and stockout risk
outweighs margin; patient tranche priced under the next competitor tier). Instant-bid
comparison moved behind --show-bid (off by default).
- Docs and roadmap updated accordingly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- tools/buy.py: cash-aware shopping list (construction gap vs empire state's built
buildings, plus N days of NET operating stock via simulate() so self-produced
inputs net against consumption), priced at real order-book fill cost, checked
against cash/reserve, flags multi-trip, binary-searches an affordable size when short
- tools/sell.py: where to post an ask vs hitting the bids now, with expected
clear time from 30-day traded-volume percentiles
- docs/library.md: module map and patterns for using puga.* directly instead of
the CLI, plus the "simulate() only knows what the plan lists" gotcha that a
first version of buy.py hit
- tools/simulate.py: fix --no-hq being a no-op; tools/state.py: permits_total_override
for when the in-game HQ screen disagrees with FIO's MaximumPermits
- docs/mechanics.md: HQ display vs PRUNplanner's HQ flag, workforce arrival sources
- CLAUDE.md, docs/roadmap.md updated
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>