albion-market-ia
by cesarscf
README.md
# Albion Market IA — Detector de Lucro em Compra → Transporte → Refino
[](https://github.com/cesarscf/albion-market-ia/actions/workflows/ci.yml)
**[Baixar](https://github.com/cesarscf/albion-market-ia/releases/latest)** — Windows, macOS e Linux.
> Documento de concepção. Pesquisa validada em 08/09/2026 com chamadas reais à API do AODP
> e extração direta do `items.json` do `ao-bin-dumps`.
---
## 1. Problema
Descobrir, **agora**, quais itens do Albion Online dão mais lucro no ciclo:
```
comprar raw (cidade A) → transportar (cidade B) → refinar → vender (cidade C)
```
O gargalo não é o cálculo — é ter **preço real e fresco** por cidade, e modelar corretamente
tudo que a API *não* entrega (return rate, taxas de estação, impostos, peso, risco de rota).
---
## Como rodar
Requer Node 22.5+ (usa o `node:sqlite` embutido, sem dependência nativa) e pnpm.
```bash
pnpm install
pnpm sync:catalog # baixa receitas e pesos do ao-bin-dumps
pnpm dev # API + app web em http://localhost:5183
```
O servidor mantém os preços atualizados sozinho: um poller REST a cada 5 minutos
e o feed NATS ao vivo do AODP. `ALBION_POLL=off` e `ALBION_NATS=off` desligam.
Também dá para usar só pelo terminal:
```bash
pnpm poll # uma coleta manual
pnpm opps "Fort Sterling" 2000000 # ranqueia rotas para essa cidade e capital
```
Estado fica em `~/.albion-market/market.sqlite` (mude com `ALBION_HOME`).
Servidor padrão é o `west`; troque com `ALBION_SERVER=east|europe`.
```bash
pnpm -r test # 31 testes
pnpm -r typecheck
```
### App desktop
Pronto para instalar em [Releases](https://github.com/cesarscf/albion-market-ia/releases/latest),
ou para rodar do código:
```bash
pnpm dev:desktop # abre a janela do Electron
pnpm dist:desktop # gera o instalador da plataforma atual
```
Windows, macOS e Linux, sem dependência nativa. Detalhes em
[docs/user/desktop.md](./docs/user/desktop.md).
### Usar dentro da sua IA
```bash
pnpm mcp # servidor MCP no stdio
```
Registre em Claude Code, Codex, Cursor ou OpenCode e pergunte
*"o que compensa refinar agora estando em Lymhurst com 2M?"* usando a assinatura
que você já tem. Passo a passo em [docs/user/mcp.md](./docs/user/mcp.md).
---
> **Arquitetura técnica:** ver [ARCHITECTURE.md](./ARCHITECTURE.md) — stack, estrutura de pastas,
> contrato, tema e o mecanismo de "use qualquer IA", inspirados no [t3code](https://github.com/pingdotgg/t3code).
---
## 2. De onde vêm os dados
**Não existe API oficial de mercado da Sandbox Interactive.** O `gameinfo.albiononline.com`
só expõe PvP/guildas/players. Todo app de preço (AlbionOnline2D, Albion Free Market,
AlbionCodex, calculadoras diversas) consome a **mesma fonte**: o
**Albion Online Data Project (AODP)**.
### Como o AODP funciona
1. O jogador roda um **data client** (`albiondata-client` oficial, ou o **AFM Data Client**,
que tem versão Android).
2. O client escuta pacotes UDP do jogo via libpcap. **Não modifica o cliente do jogo** —
por isso é tolerado pela SBI.
3. Quando o jogador abre a aba de Mercado / Casa de Leilões numa cidade, o client parseia
as ordens e publica num servidor **NATS** central.
4. O NATS deduplica (janela de 10 min) e alimenta o banco que expõe a **API REST pública**.
> **Consequência crítica:** o preço só existe se algum jogador abriu aquela aba recentemente.
> Não é um feed do servidor do jogo. Frescor é função do tráfego de jogadores.
---
## 3. As três fontes obrigatórias
### 3.1. API REST do AODP — preço atual e histórico
| Servidor | Base URL |
|---|---|
| Americas (West) | `https://west.albion-online-data.com` |
| Asia (East) | `https://east.albion-online-data.com` |
| Europe | `https://europe.albion-online-data.com` |
```
/api/v2/stats/prices/{ids}.json?locations=Caerleon,Martlock&qualities=1
/api/v2/stats/history/{ids}.json?date=...&end_date=...&locations=...&time-scale=24
/api/v2/stats/charts/{ids}.json?...&time-scale=6
/api/v2/stats/gold.json?count=24
```
- `time-scale`: `1` horário · `6` 6h · `24` diário
- `qualities`: 1 Normal · 2 Bom · 3 Excepcional · 4 Excelente · 5 Obra-prima
- **Rate limit: 180 req/min e 300 req/5min**
- **URL máx 4096 chars** → empacote ~100 item IDs por chamada. Use gzip.
Resposta real (T4_PLANKS, servidor West, 08/09/2026):
```json
{"item_id":"T4_PLANKS","city":"Fort Sterling","quality":1,
"sell_price_min":295,"sell_price_min_date":"2026-09-08T17:25:00",
"sell_price_max":328,"sell_price_max_date":"2026-09-08T17:25:00",
"buy_price_min":2,"buy_price_min_date":"2026-09-08T17:25:00",
"buy_price_max":253,"buy_price_max_date":"2026-09-08T17:25:00"}
```
**O campo que separa app amador de app bom é o `*_date`.** Na mesma chamada:
- Martlock veio com timestamp de **ontem**
- Caerleon veio com `sell_price_min: 580` e `sell_price_max: 13292` — outlier puro
- `T6_PLANKS` na Black Market e em Brecilien voltou **tudo zero** (sem dado)
Semântica dos campos:
- `sell_price_min` → menor **sell order** = preço de **compra instantânea**
- `buy_price_max` → maior **buy order** = preço de **venda instantânea**
### 3.2. Stream NATS — tempo real (push, sem polling)
```
nats://public:thenewalbiondata@nats.albion-online-data.com:4222
```
Tópicos: `marketorders.deduped` · `markethistories.deduped` · `goldprices.deduped`
Mesmo dado da API REST, porém push: você recebe a ordem no instante em que qualquer
jogador do mundo abre aquele mercado.
### 3.3. `ao-bin-dumps` — metadados do jogo (fonte autoritativa)
Repo `ao-data/ao-bin-dumps`, arquivo `items.json` (~17 MB). Contém receitas, pesos,
`itemvalue` e custo de foco. Extraído diretamente:
```json
"T6_PLANKS": {
"@itemvalue": "64", "@weight": "1.14", "@fasttravelfactor": "8",
"craftingrequirements": [{
"@craftingfocus": "164", "@amountcrafted": "1",
"craftresource": [ {"T6_WOOD": 4}, {"T5_PLANKS": 1} ]
}]
}
```
**Receitas de refino** (confirmadas no dump):
| Tier | Raw | Refinado (T-1) |
|---|---|---|
| T4 | 2 | 1 |
| T5 | 3 | 1 |
| T6 | 4 | 1 |
| T7 | 5 | 1 |
| T8 | 5 | 1 |
Detalhe que quase nenhum calculador considera: existe uma **receita alternativa com
Faction Token** que troca 1 raw por 1 token de facção.
---
## 4. O que a API NÃO dá — a matemática do lucro
### 4.1. Resource Return Rate (RRR)
```
RRR = b / (1 + b) // b = soma ADITIVA dos bônus
```
| Situação | b | RRR |
|---|---|---|
| Cidade sem bônus | 0,18 | **15,3%** |
| Cidade com bônus de refino (+40%) | 0,58 | **36,7%** |
| Cidade com bônus + foco (+59%) | 1,17 | **53,9%** |
| Cidade com bônus + foco + dia de ouro (+20%) | 1,37 | **57,8%** |
Consumo real de material = `nominal × (1 − RRR)`.
Com 53,9% de RRR você consome só ~46% dos materiais nominais.
> **Especialização não aumenta RRR** — ela reduz o custo de foco (Focus Cost Efficiency).
### 4.2. Cidades de bônus de refino
| Raw | Refinado | Cidade |
|---|---|---|
| Minério (Ore) | Barra (Metal Bar) | **Thetford** |
| Couro cru (Hide) | Couro (Leather) | **Martlock** |
| Fibra (Fiber) | Tecido (Cloth) | **Lymhurst** |
| Madeira (Wood) | Tábua (Plank) | **Fort Sterling** |
| Pedra (Stone) | Bloco (Stone Block) | **Bridgewatch** |
### 4.3. Taxa da estação de refino
```
taxa_por_unidade = itemvalue × 0,1125 × (taxa_por_100_nutricao / 100)
```
Ex.: T6_PLANKS (`itemvalue` 64) numa estação a 300 → `64 × 0,1125 × 3 = 21,6` prata/unidade.
`itemvalue` dobra por tier: T4=16 · T5=32 · T6=64 · T7=128 · T8=256.
### 4.4. Taxas de mercado
| Ação | Custo |
|---|---|
| Criar/atualizar ordem (setup fee) | **2,5%** — perdido mesmo se não vender |
| Imposto na venda (sem Premium) | **8%** |
| Imposto na venda (com Premium) | **4%** |
Venda instantânea (bater na buy order) não paga setup fee, só o imposto.
### 4.5. Transporte
- `@weight` do dump × capacidade da montaria → quantos ciclos de viagem
- `@fasttravelfactor` → custo de fast travel
- Rota para Caerleon atravessa red zone → o modelo precisa de **fator de risco**
---
## 5. Arquitetura proposta
> **Regra de ouro: o LLM não calcula.** Ele erra aritmética e alucina preço.
> A IA é camada de *interface e interpretação*, nunca de cálculo.
```
┌─────────────────────────────────────────────────────────────┐
│ CAMADA 1 — INGESTÃO │
│ • Data client próprio (AFM/oficial) rodando local │
│ • Subscriber NATS (marketorders.deduped) │
│ • Poller REST em batch (~100 ids/req) p/ cidades não visit.│
│ • Sync periódico do ao-bin-dumps/items.json │
│ ↓ Postgres + TimescaleDB │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ CAMADA 2 — MOTOR DETERMINÍSTICO │
│ Input: cidade_atual, capital, capacidade_peso, │
│ tem_premium, tem_foco, tolerancia_risco │
│ Loop: família × tier × cidade_compra × cidade_refino × │
│ cidade_venda │
│ Aplica: RRR · receita · taxa estação · impostos · peso │
│ Output: ranking com margem abs, margem %, capital travado, │
│ idade_do_dado_min, liquidez estimada │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ CAMADA 3 — LLM (tool / function calling) │
│ Recebe o top-N já calculado. Faz o que ele faz bem: │
│ • interpretar intenção em linguagem natural │
│ • filtrar por contexto que não cabe em SQL │
│ • explicar trade-off risco × retorno │
│ • comparar com histórico e sinalizar dado suspeito │
└─────────────────────────────────────────────────────────────┘
```
### Ganho de rodar data client próprio
1. Dado **mais fresco** que a API pública para as cidades onde você joga
2. Não fica refém do rate limit
3. Vantagem informacional real sobre quem só consome a API
### Assinatura da tool exposta ao LLM
```
buscar_oportunidades(
cidade_atual: str,
capital_disponivel: int,
capacidade_peso: float,
tem_premium: bool,
tem_foco: bool,
tolerancia_risco: "baixa" | "media" | "alta",
max_idade_dado_min: int = 120
) -> list[Oportunidade]
```
---
## 6. Regras de sanidade obrigatórias
Sem isso o sistema gera "oportunidades" fantasma:
- [ ] Descartar preço com `*_date` mais velho que ~2h — **crítico para buy orders**, elas somem rápido
- [ ] Descartar `price == 0` e `date == "0001-01-01T00:00:00"`
- [ ] Cruzar com `/history` (média móvel 7d): spread > 3σ = outlier, não oportunidade
- [ ] Nunca assumir liquidez — usar `item_count` do `/history` para saber se o mercado absorve o volume
- [ ] `buy_price_max` é só o topo da fila — você vende *aquela* quantidade nesse preço, não o estoque todo
- [ ] Sempre exibir a **idade do dado** junto da margem, na UI e na resposta da IA
---
## 7. Roadmap sugerido
| Fase | Entrega |
|---|---|
| 1 | Poller REST + Postgres + sync do `items.json` |
| 2 | Motor determinístico (RRR + receitas + taxas + impostos) |
| 3 | Regras de sanidade e cruzamento com histórico |
| 4 | Data client próprio + subscriber NATS |
| 5 | Camada LLM com function calling |
| 6 | Sinais proativos (alertas quando margem > X e dado < Y min) |
---
## 8. Referências
- [The Albion Online Data Project](https://www.albion-online-data.com/)
- [AODP API reference](https://www.albion-online-data.com/api/)
- [albiondata-client (GitHub)](https://github.com/ao-data/albiondata-client)
- [ao-bin-dumps (GitHub)](https://github.com/ao-data/ao-bin-dumps)
- [AFM Data Client](https://albionfreemarket.com/data-client)
- [Return Rate Explained — Albion Codex](https://www.albioncodex.com/guides/albion-online-return-rate-explained)
- [Albion Online Refining Guide — Heaven Guardian](https://heaven-guardian.com/albion-online-refining-guide/)
- [Marketplace — Albion Online Wiki](https://wiki.albiononline.com/wiki/Marketplace)
- [Explaining Crafting Tax — Albion Online Forum](https://forum.albiononline.com/index.php/Thread/167434-Explaining-Crafting-Tax-and-more/)
- [How to Use Albion Market Data (AODP Guide) — Albion Codex](https://www.albioncodex.com/guides/how-to-use-albion-market-data)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues