Every stronghold craft ranked by net gold — per craft, per hour, ROI. Priced at a robust 14-day average (not the live spot) so a bought-out market can't distort it. Method & setup in the dropdown at the bottom.
General stacks onto the category-specific column. Edits apply instantly.
General
Battle
Cooking
Special (fusion)
Market prices & live-sync
Prices are per bundle (gathered mats = per 100, crafted = per 1). Edit any cell to override.
Gathered materials (per 100)
Crafted items & outputs (per 1)
Live-sync proxy (optional)
Best craft right now
All crafts — ranked
ShowColumnsClick a row for the full material breakdown.
Price watch — recent movers
Split into craftable outputs (you sell) and materials (you buy) — items above ~50g whose yesterday's average or live spot sits ≥15% off the fair (robust) price. The deal column judges the spot from your side of the trade (pricey = good to sell, cheap = good to buy) and shows where spot falls in the 14-day range. History runs today → oldest (today's live value dimmed, excluded from fair).
Method & setup
Your browser recomputes every number from the reductions above and current market prices. The engine mirrors loa-buddy.pages.dev exactly (verified against its code), so results match the tool you already trust.
adjustedGold = floor( craftingCost x (1 - (general.cost + category.cost)/100) )
adjustedTime = craftingTime x (1 - (general.time + category.time)/100)
GSC (great success chance) = enabled ? 5 x (1 + (general.GS + category.GS)/100) : 0
EY (expected yield) = baseQuantity x (1 + GSC/100)
materialCost = SUM qty x (marketPrice / bundleSize) (cheapest gathering path is auto-picked)
totalCost = materialCost + adjustedGold
tax = sellPrice <= 1 ? 0 : ceil(sellPrice x 0.05) (5%, rounded UP to nearest gold)
NET PROFIT / craft = EY x (sellPrice - tax) - totalCost
NET / hour = netProfit / (adjustedTime / 60)
ROI % = netProfit / totalCost
Great Success doubles a craft's output, and happens GSC% of the time — that's why expected yield is qty x (1 + GSC/100). The "x2" badge in-game refers to this doubling. Toggle it off to see worst-case.
Cheapest path — click to switch: fusion materials can be made from several gathering types (Fishing / Hunting / Mining...). The tool prices each path and uses the cheapest by default; the chosen one shows in the Path column. Click the Path cell to cycle paths, or click a row in a recipe's “Gathering paths” breakdown to force one — handy for matching another tool's selected path. Your choice persists; “reset to cheapest” clears it.
Robust vs spot pricing. Each item carries a current spot (lowest listing) and 14 days of daily average prices. The default robust price excludes the current (live, in-progress) day entirely, then drops the highest & lowest few of the completed days and takes a recency-weighted mean of the rest (newest completed day ×1, each older ×decay) — so it tracks genuine moves but the live spike (or a lowball) can never enter. Tune drop hi/lo and decay live above; the breakdown flags any item whose spot is ≥15% off its robust price (⚠). Toggle Pricing → Spot for the live lowest price, or Pricing → Yesterday to value everything at the most recent completed day’s average — more accurate than the robust mean when a market has fallen for many days in a row (the 14-day average then lags above where prices actually are).
Mats are valued at market price (true opportunity cost). If you farm a mat yourself, edit its price toward 0 to see your effective profit.
Two added meals (Virtuoso's Striploin, Specialist's Beef Tenderloin) aren't in loa-buddy. Their recipes come from in-game. Their craft times are assumed (75 / 60 min) — confirm them in-game; this only affects the per-hour column, not per-craft.
Prices come from the same market feed loa-buddy uses, baked in as a snapshot and auto-refreshed every 6 hours by a GitHub Action (both spot & median). In-browser "Sync live prices" (needs a proxy worker) refreshes spot only; the median comes from the scheduled refresh.
Enable one-click live sync (optional). The market API only answers loa-buddy's own domain (CORS), so this page can't call it directly. Deploy this ~20-line Cloudflare Worker (free), then paste its URL into the Proxy field above:
// worker.js -- deploy at dash.cloudflare.com > Workers > Create
export default {
async fetch(req) {
const cors = { "Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "POST,OPTIONS",
"Access-Control-Allow-Headers": "Content-Type" };
if (req.method === "OPTIONS") return new Response(null, { headers: cors });
const body = await req.text();
const r = await fetch("https://marketdata-api.yrzhao1068589.workers.dev/v1/prices/latest",
{ method: "POST", headers: { "Content-Type": "application/json" }, body });
return new Response(await r.text(),
{ headers: { ...cors, "Content-Type": "application/json" } });
}
};