diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..4b680f3 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,54 @@ +# Changelog + +Todas as mudanças notáveis deste projeto são documentadas aqui. +Formato baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/); +o projeto segue versionamento pragmático (paper-trading-first, ver ADR-001). + +> **Nota sobre histórico:** o histórico detalhado por sprint vive nos +> `docs/roadmap_v1..v6.md` e nas auditorias datadas (`docs/auditoria-*.md`) — +> esses arquivos são **registros históricos** e preservam os números da época +> (ex.: contagens de testes por sprint). A contagem de testes **canônica atual** +> está no README e no TESTING.md. + +## [Não lançado] + +### Onda 2 — Higiene estrutural (backend + frontend + docs) +- **R5 (Kelly):** fórmula central do Kelly extraída para + `src/risk/position_sizing.full_kelly_fraction`, agora **fonte única** consumida + pelo endpoint `GET /v1/risk/kelly` (que antes reimplementava inline) e por + `KellyCriterion`. `src/risk/` deixa de ser código morto. Contrato da API + inalterado. *Plugar Kelly no sizing real (`SquadOrchestrator._position_quantity`) + permanece como cauda do R5 — ver ADR-006.* +- **R2 (colisões de nome):** classes duplicadas renomeadas por propósito — + `protocols.SquadOrchestrator`→`A2ASquad`, `adaptive_replanner.AdaptivePlanner`→ + `AdaptiveReplanner`, `continuous_evaluator.ContinuousEvaluator`→ + `AgentPerformanceEvaluator`, `intelligent_forgetting.MemoryStore`→ + `RelevanceMemoryStore`. +- **market_data unificado:** o backtest (`engine._build_market_data`) agora computa + um `TechnicalIndicators` real + regime (guarda de warmup), em vez de placeholders + — estratégias dirigidas por indicadores (Grid, MeanReversion) exercitam o mesmo + caminho do live. +- **Frontend (R8, fatia):** utilitário `.kpi-row` (auto-reflow via `auto-fit`) + aplicado às linhas de KPI das telas; **sidebar responsiva** < 960px (lacuna do + briefing). Rollout completo de responsividade/a11y permanece aberto. +- **Docs:** ADR-006 (política de sizing Kelly); `mapeamento-dados.md` §8/§9 e + `arquitetura.md` §12 sincronizados; `CHANGELOG.md`/`CONTRIBUTING.md`/`SECURITY.md` + adicionados; `plano-melhorias.md` atualizado. + +### Onda 1 — Correções seguras (mergeada, PR #68) +- **Backend:** `ab_tests.jsonl` agora é JSON válido (`json.dumps`); + `mean_reversion` roteável no regime `sideways`; remoção de dados mortos + (`RiskAgent.max_daily_loss_pct`, `UnifiedOrchestrator.sandbox`/`chain_manager`, + `AgentMemorySystem.short_term`); log em vez de `except: pass` silencioso. +- **Frontend:** erros de mutação → toast (HITL/journal/settings/backtest); + confirmação em 2 etapas ao aprovar/rejeitar ordem; fim da colisão + `STATUS_VARIANT`/`STATUS_LABEL`; limpeza de arquivos/CSS mortos. +- **Docs:** contagem de testes reconciliada (**416 coletados / 408 passam / + 8 pulados** sem `DATABASE_URL`); ADR-004 documentado + índice corrigido; + `docs/documentação/` → `docs/data/`; `docs/plano-melhorias.md` criado como fonte + única do backlog. + +## Histórico anterior (v1–v6) +Ver `docs/roadmap_v1.md` … `docs/roadmap_v6.md` (correção & verdade → produção +Docker → observabilidade → métricas de domínio → Grafana → backend PostgreSQL +opcional) e `docs/auditoria-criptotrade-2026-06.md` (remediação P0–P3 + Fase 5b). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..46cda5a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,59 @@ +# Contribuindo com o Criptotrade + +Obrigado por contribuir! Este guia resume o fluxo de desenvolvimento. Para a +arquitetura, ver `docs/architecture/arquitetura.md` (C4) e +`docs/uml/arquitetura-uml.md` (classes); para o backlog priorizado, ver +`docs/plano-melhorias.md`. + +## Princípios inegociáveis + +Toda mudança **deve preservar** os invariantes centrais: + +1. **Paper-trading-first** — `EXCHANGE_DRY_RUN` é obrigatório; o único caminho + para a exchange roda offline por padrão (ADR-001). Nunca introduza um caminho + de ordem real que rode sem override explícito de ambiente. +2. **HITL fail-closed** — ordens acima do limiar de autonomia exigem aprovação + humana; em produção a API sobe fail-closed sem `API_KEYS`. +3. **Tudo auditável** — decisões e execuções vão para o ledger append-only / event + log XES. Não remova trilha de auditoria. + +## Setup + +```bash +python -m venv .venv && source .venv/bin/activate +pip install -r requirements.txt +pytest -q # suíte completa (ver contagem no README/TESTING.md) +``` + +Console React (opcional): `cd docs/design/pages && npm install && npm run build`. + +## Fluxo + +1. **Branch** a partir de `master`. +2. **Commits** em [Conventional Commits](https://www.conventionalcommits.org/) + (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `build:`, `chore:`). +3. **Testes**: adicione/estenda testes em `tests/`. O gate de cobertura da CI é + **72%** (`pyproject.toml`); não o reduza. +4. **Lint**: `ruff check src` (regras E4/E7/E9/F). +5. **CI verde** antes do merge — jobs `test`, `console-build`, `console-e2e`, + `docker-build`, `validate-phases`, `secret-scan`. +6. **PR** contra `master`. Decisões arquiteturais entram como **ADR** em + `docs/adr/` (use `ADR-Template.md`; próximo número livre indicado no + `docs/adr/README.md`). + +## Convenções + +- **Sem segredos no repo.** `.env` é gitignored; use `.env.example` como + referência. A CI roda `secret-scan` e `scripts/validate_deploy_config.py`. +- **Nomes de classe únicos por propósito** (ver R2 em `arquitetura.md §12`): + evite reintroduzir colisões como dois `SquadOrchestrator`. +- **Reuse antes de criar**: cheque utilitários existentes em `src/core`, + `src/utils` e (no front) `components.jsx` antes de escrever novos. +- **Documentação viva vs. histórica**: atualize os docs de estado atual + (`README`, `TESTING.md`, `mapeamento-dados.md`, `arquitetura.md`, + `plano-melhorias.md`, `CHANGELOG.md`). **Não** reescreva registros datados + (roadmaps por sprint, auditorias) — eles são snapshots históricos. + +## Reportando vulnerabilidades + +Ver `SECURITY.md`. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..a4004a6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,48 @@ +# Política de Segurança + +O Criptotrade é um sistema financeiro (trading de cripto). Levamos segurança a +sério — mesmo em modo paper-trading, uma configuração insegura pode expor a API, +segredos ou, no futuro com trading real, capital. + +## Versões suportadas + +O projeto está em estágio **paper-trading / alpha**. Apenas o `master` recebe +correções de segurança. + +## Reportando uma vulnerabilidade + +**Não** abra uma issue pública para vulnerabilidades. Em vez disso: + +- Envie um relatório privado por **[GitHub Security Advisories]** + (`Security` → `Report a vulnerability` no repositório), ou +- contate o mantenedor do repositório diretamente. + +Inclua: descrição, passos de reprodução, impacto potencial e, se possível, uma +sugestão de correção. Faremos o possível para responder rapidamente e coordenar +uma divulgação responsável após a correção. + +[GitHub Security Advisories]: https://docs.github.com/pt/code-security/security-advisories + +## Superfície e controles atuais + +Controles já implementados (ver `docs/architecture/arquitetura.md §11` e a +auditoria `docs/auditoria-criptotrade-2026-06.md`): + +- **Autenticação** por `X-API-Key` (`API_KEYS`), timing-safe + (`secrets.compare_digest`), **fail-closed em produção** (a API recusa subir sem + `API_KEYS` quando `APP_ENV=production`). +- **CORS** travável por `CORS_ORIGINS` (sem `*` em produção — validado na CI por + `scripts/validate_deploy_config.py`). +- **Rate limiting** (`RateLimitMiddleware`, Redis opcional). +- **Headers de segurança** (CSP, HSTS, X-Frame-Options, etc.) via middleware + nginx. +- **Confirmação explícita** (`confirm: true`) para mutações de alto impacto. +- **Sem segredos no repo**: `.env` gitignored; CI roda `secret-scan`. +- **Paper-trading-first**: `EXCHANGE_DRY_RUN` obrigatório; zero rede de corretora + por padrão. + +## Boas práticas para operadores + +- Gere um `API_KEYS` forte (`openssl rand -hex 32`) e nunca o commite. +- Só vire `EXCHANGE_DRY_RUN=false` como decisão deliberada, após validar a stack + (ver `docs/acaoPendenteDono.md`). +- Mantenha `CORS_ORIGINS` restrito à origem real do console. diff --git a/docs/adr/006-kelly-sizing-policy.md b/docs/adr/006-kelly-sizing-policy.md new file mode 100644 index 0000000..461b5d3 --- /dev/null +++ b/docs/adr/006-kelly-sizing-policy.md @@ -0,0 +1,57 @@ +# ADR-006: Política de sizing por Kelly (fonte única + cauda de integração) + +## Status +🟡 Aceita parcialmente (2026-07-15) — fonte única entregue; sizing ao vivo diferido. + +## Contexto +O módulo `src/risk/` (`KellyCriterion`, `PositionSizer`, `CapitalProtections`) +existia **completo e testado, mas morto**: nenhum código de aplicação o +importava. Pior, o endpoint `GET /v1/risk/kelly` **reimplementava o Kelly inline** +(`src/api/routes/risk.py`), com constantes e fórmulas divergentes da biblioteca — +dando a falsa impressão de que o sistema dimensionava posições por Kelly quando, na +verdade, o pipeline de trading (`SquadOrchestrator._position_quantity`) usa +`position_size_pct` fixo. Isto está registrado como **R5** em +`docs/architecture/arquitetura.md §12` e no §8 de `docs/data/mapeamento-dados.md`. + +Havia três caminhos possíveis: (a) **deletar** o módulo morto; (b) **unificar** +tornando a biblioteca a fonte única e o endpoint um consumidor; (c) **plugar** o +Kelly no sizing real das ordens. + +## Decisão +Adotar (b) agora, de forma **preservadora de contrato**, e diferir (c): + +1. A fórmula central do Kelly foi extraída para + `src/risk/position_sizing.full_kelly_fraction(win_rate, avg_win_pct, + avg_loss_pct)` — **fonte única de verdade**. É algebricamente idêntica à forma + anterior (`(p·b − q)/b ≡ p − (1−p)/b`), então **nenhum número da API muda**. +2. `GET /v1/risk/kelly` passa a **delegar** a essa função (removendo a + reimplementação inline). `KellyCriterion.full_kelly()` também a consome. Assim + `src/risk/` deixa de ser código morto. +3. A apresentação do endpoint (Kelly fracionado × 0.25, risco de ruína, limiar de + 10 trades para `data_quality:"insufficient"`) é **mantida como está** — é um + endpoint **consultivo** (display), não de execução. + +## Diferido (cauda do R5) +- **Plugar `PositionSizer`/`KellyCriterion` no sizing real** de ordens + (`SquadOrchestrator._position_quantity`) muda **o que é negociado** — é uma + mudança de comportamento que exige validação dedicada (backtest comparativo, + revisão de risco) e **não** entra junto de higiene de código. +- **Unificar a apresentação fracionada/ruína** entre endpoint e biblioteca (hoje o + endpoint usa fração crua não-clampada; a lib usa percentual clampado [0.5, 5.0] e + a fórmula clássica de ruína). Decisão de produto sobre qual semântica é canônica. +- **`CapitalProtections`** (limites diário/semanal/mensal com `size_multiplier`) + permanece disponível, ainda não alimentado por P&L do período. + +## Consequências +- **Positivas:** remove a duplicação e a falsa impressão; `src/risk/` passa a ser + exercitado pela API; caminho claro para o sizing por Kelly quando houver + validação. Zero mudança observável de contrato/comportamento. +- **Negativas:** o sistema **ainda não dimensiona por Kelly** — o valor pleno do + R5 (sizing dinâmico por edge) fica para a etapa (c). O módulo continua + parcialmente subutilizado (`PositionSizer`/`CapitalProtections`). + +## Referências +- `docs/architecture/arquitetura.md §12` (R5), `docs/data/mapeamento-dados.md §8`. +- `src/risk/position_sizing.py`, `src/api/routes/risk.py`, + `src/orchestration/squad_orchestrator.py` (`_position_quantity`). +- `docs/plano-melhorias.md` (R5 — backlog estrutural). diff --git a/docs/adr/README.md b/docs/adr/README.md index a5ae47b..86e93b9 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -12,6 +12,7 @@ o boilerplate de metodologia que não descrevia o sistema. | [003](003-persistence-sqlite-wal.md) | Persistência — JSONL (ledger/XES) + SQLite WAL (estado cross-process) | Aceito | | [004](004-reserved.md) | *Número reservado — não utilizado* (a sequência salta de 003 para 005) | Vago | | [005](005-scaling-path.md) | Caminho de Escalabilidade — single-host → horizontal (Redis/Postgres opt-in) | Aceita | +| [006](006-kelly-sizing-policy.md) | Política de sizing por Kelly — fonte única (`src/risk`) + endpoint delega; sizing ao vivo diferido | Aceita parcial | Novos ADRs: copie [`ADR-Template.md`](ADR-Template.md), use o próximo número -sequencial livre (**006** em diante — ver ADR-004) e adicione a linha na tabela acima. +sequencial livre (**007** em diante) e adicione a linha na tabela acima. diff --git a/docs/architecture/arquitetura.md b/docs/architecture/arquitetura.md index ba16233..2607506 100644 --- a/docs/architecture/arquitetura.md +++ b/docs/architecture/arquitetura.md @@ -598,11 +598,11 @@ graph TB | # | Severidade | Achado | Recomendação | |---|---|---|---| | R1 | 🔴 Alta | **Cluster "BuildToValue" paralelo** (`UnifiedOrchestrator` + planning/routing/consensus/chains/parallel + agentes de engenharia) **não exercitado pelo trading** | Extrair para pacote opcional `src/experimental/` ou remover; medir cobertura real. Reduz superfície e confusão. | -| R2 | 🔴 Alta | **Colisões de nome** (`SquadOrchestrator`×2, `AdaptivePlanner`×2, `ContinuousEvaluator`×2, `MemoryStore`×2, `Guardrail`×2) | Renomear por propósito (ex.: `TradingSquad` vs `A2ASquad`). Evita imports errados. | +| R2 | 🟡 Parcial | **Colisões de nome** (`SquadOrchestrator`×2, `AdaptivePlanner`×2, `ContinuousEvaluator`×2, `MemoryStore`×2, `Guardrail`×2) | 🟢 **Feito (Onda 2):** duplicatas renomeadas por propósito — `A2ASquad`, `AdaptiveReplanner`, `AgentPerformanceEvaluator`, `RelevanceMemoryStore`. **Resta** `Guardrail`×2 (ver R2b/R3). | | R2b | 🟠 Média | **Duas fundações de agente** (`BaseAgent` async vs `SafeAgentBase` sync) sem ponte | Escolher uma base única ou documentar explicitamente os dois papéis. | | R3 | 🟠 Média | **Duas políticas de validação de ordem** e **dois modelos de autonomia** (US$ threshold vs trust-score) | Eleger fonte única de política de risco/autonomia. | | R4 | 🟠 Média | **HITL por polling de SQLite** acopla loop↔API ao arquivo; loop single-instance | Migrar coordenação para **Postgres `LISTEN/NOTIFY`** ou Redis pub/sub → menor latência + caminho para multi-loop. | -| R5 | 🟡 Baixa | **Kelly/proteções prontos mas não plugados** no sizing do pipeline | Ligar `PositionSizer`/`KellyCriterion`/`CapitalProtections` no `SquadOrchestrator._position_quantity`. | +| R5 | 🟡 Parcial | **Kelly/proteções prontos mas não plugados** no sizing do pipeline | 🟢 **Feito (Onda 2, ADR-006):** fórmula central do Kelly virou fonte única (`src/risk.full_kelly_fraction`), consumida pelo endpoint `/v1/risk/kelly` — `src/risk/` não é mais morto. **Resta** plugar no `SquadOrchestrator._position_quantity` (muda o trading — validação dedicada). | | R6 | 🟡 Baixa | **Namespace `/v1/agents/...` servido por dois routers** (`agents` e `config`) | Consolidar num router único. | | R7 | 🟡 Baixa | **XES/alerts ainda em JSONL** (ADR-003 deferido) | Concluir migração para SQLite/Postgres quando o volume justificar. | | R8 | 🟡 Baixa | **Frontend "classic scripts" com globals `window.*`** | Migrar para ES modules + bundler quando o console crescer. | @@ -653,10 +653,10 @@ graph TB ``` **Roteiro incremental (sem big-bang):** -1. **Higiene** (R1, R2): isolar/remover o cluster genérico e renomear colisões — baixo risco, alto ganho de clareza. -2. **Consolidação de política** (R3, R5, R6): uma fonte de risco/autonomia; plugar Kelly; unificar rotas de agentes. +1. **Higiene** (R1, R2): 🟡 **R2 renomeações feitas (Onda 2)**; R1 (isolar cluster genérico) ainda aberto. +2. **Consolidação de política** (R3, R5, R6): 🟡 **R5 fonte única do Kelly feita (Onda 2, ADR-006)**; resta plugar no sizing, unificar política de risco/autonomia (R3) e rotas de agentes (R6). 3. **Coordenação** (R4, R7): trocar polling SQLite por `LISTEN/NOTIFY` no Postgres (já suportado pela abstração de DB) e unificar o event store — habilita multi-loop com leader-election. -4. **Frontend** (R8): migrar para ES modules/bundler. +4. **Frontend** (R8): 🟡 **fatia feita (Onda 2)** — `.kpi-row` responsivo + sidebar colapsável < 960px; migração para ES modules/bundler ainda aberta. Cada passo é independente e preserva o invariante central: **paper-trading-first, HITL fail-closed, tudo auditável no ledger/XES**. diff --git a/docs/auditoria-criptotrade-2026-06.md b/docs/auditoria-criptotrade-2026-06.md index 045db76..fe30e94 100644 --- a/docs/auditoria-criptotrade-2026-06.md +++ b/docs/auditoria-criptotrade-2026-06.md @@ -509,6 +509,40 @@ Revisão do código após Fase 5b. **4 achados corrigidos em `remediacao/audit-f | A-03 | `scripts/migrate_ledger.py:43` | `json.loads()` sem `try/except` abortava migração em linha corrompida, deixando histórico parcialmente importado sem aviso | Baixo | Adicionado `try/except JSONDecodeError` com skip+warn por linha | | A-04 | `README.md` | Contagem de testes desatualizada (273 → 324, duas ocorrências) | Doc | Atualizado | +### 7.7 Análise & Melhorias — Ondas 1–2 (2026-07-15) + +Análise profunda partindo da documentação de mapeamento (`docs/data/mapeamento-dados.md`), +que catalogou anomalias §9 e dados mortos §8 **sem corrigir**. As 9 anomalias foram +verificadas (todas verdadeiras) e uma primeira leva foi corrigida. Fonte única do +backlog: `docs/plano-melhorias.md`. + +**Onda 1** (PR #68, baixo risco): + +| # | Arquivo | Correção | Sev. | +|---|---------|----------|------| +| O1-1 | `evaluation/ab_testing.py` | `ab_tests.jsonl` gravado como JSON válido (`json.dumps`, não `repr`) | Baixo | +| O1-2 | `analysis/regime_detector.py` | `mean_reversion` roteável no regime `sideways` (era registrada mas nunca emitida) + teste de consistência | Médio | +| O1-3 | `agents/risk_agent.py`, `orchestration/unified_orchestrator.py`, `memory/agent_memory.py` | Remoção de dados mortos (§8): `max_daily_loss_pct`, `sandbox`/`chain_manager`, `short_term`; log em vez de `except: pass` | Baixo | +| O1-4 | `docs/design/pages/*.jsx` | Erros de mutação → toast; confirmação em aprovar/rejeitar; fim da colisão `STATUS_*`; limpeza morta | Médio | +| O1-5 | README/TESTING + ADR-004 + `docs/documentação`→`docs/data` | Contagem de testes reconciliada (**416/408/8**); índice ADR corrigido | Doc | + +**Onda 2** (higiene estrutural): + +| # | Arquivo | Correção | Sev. | +|---|---------|----------|------| +| O2-1 | `risk/position_sizing.py`, `api/routes/risk.py` | **R5**: fórmula central do Kelly vira fonte única (`full_kelly_fraction`); endpoint delega; `src/risk/` deixa de ser morto (contrato inalterado — ADR-006) | Médio | +| O2-2 | `protocols/`, `planning/`, `evaluation/`, `memory/` | **R2**: colisões de nome renomeadas (`A2ASquad`, `AdaptiveReplanner`, `AgentPerformanceEvaluator`, `RelevanceMemoryStore`) | Baixo | +| O2-3 | `backtest/engine.py` | `market_data` unificado: backtest computa `TechnicalIndicators` real + regime (guarda de warmup) — Grid/MeanReversion não ficam mais inertes | Médio | +| O2-4 | `docs/design/pages/styles.css` + `screen_*.jsx` | **R8 (fatia)**: `.kpi-row` auto-reflow + sidebar responsiva < 960px | Baixo | +| O2-5 | `CHANGELOG.md`, `CONTRIBUTING.md`, `SECURITY.md`, ADR-006, sync de `mapeamento`/`arquitetura`/`uml` | Docs de projeto ausentes criadas; docs vivas sincronizadas | Doc | + +**Verificação:** `408 passed / 8 skipped` (cobertura ≥ gate 72%); console `npm run build` OK; +`scripts/validate_deploy_config.py` OK. Invariante central preservado. + +**Aberto (backlog em `plano-melhorias.md`):** R1 (isolar cluster BuildToValue), +cauda do R5 (plugar Kelly no sizing real), R3 (unificar política de risco/autonomia), +R6 (rotas de agentes), R8 completo (ES modules + a11y), CandleOut `lo`→`l`. + --- ## 8. Anexos diff --git a/docs/data/mapeamento-dados.md b/docs/data/mapeamento-dados.md index 00adcc2..8c2aee3 100644 --- a/docs/data/mapeamento-dados.md +++ b/docs/data/mapeamento-dados.md @@ -170,9 +170,9 @@ Estes são os **dicts que fluem entre módulos** — o dado "vivo" do sistema. C ### 3.3 `signal` (StrategyAgent._generate_signal → strategy_agent.py:218) — **o dado central do sistema** `action`(BUY\|SELL\|HOLD)`, entry_price, stop_loss, take_profit, position_size_pct`(default 2.0)`, strategy, regime, market_context:{atr,bb_middle,volume_ratio}|None`. `symbol` é adicionado depois pelo orquestrador via `setdefault` (`:214`); `reason` só existe nos caminhos HOLD. -### 3.4 `market_data` — **DOIS formatos distintos** -- **Nested** (Grid/MeanReversion) — `_build_market_data` (`strategy_agent.py:383`): `symbol, current_price, trend, regime, rsi, macd_histogram, at_bollinger_lower, ma_20, ma_50, volume_24h, avg_volume, indicators:TechnicalIndicators, support_resistance, volume_profile, _raw_ohlcv` -- **Flat** (DCA e backtest) — `engine.py:234`: `current_price, rsi(=50), macd_histogram(=0), at_bollinger_lower(=False), ma_20, ma_50, volume_24h, avg_volume(=1), _raw_ohlcv` (sem `indicators`) +### 3.4 `market_data` — formato unificado (ver nota) +- **Nested** (StrategyAgent e backtest) — `_build_market_data` (`strategy_agent.py:383`): `symbol, current_price, trend, regime, rsi, macd_histogram, at_bollinger_lower, ma_20, ma_50, volume_24h, avg_volume, indicators:TechnicalIndicators, support_resistance, volume_profile, _raw_ohlcv` +- **Backtest** — `engine._build_market_data`: 🟢 **desde Onda 2** computa `indicators:TechnicalIndicators` real + `regime` (guarda de warmup `WARMUP_CANDLES=50`), mantendo os campos flat (`rsi/ma_20/ma_50/...`) que DCA lê. Fallback a placeholders só se os indicadores não puderem ser computados (janela curta / numpy ausente em CI mínima). Antes emitia flat com `rsi=50`/`indicators` ausente — o que deixava Grid/MeanReversion inertes no backtest. ### 3.5 Resultados dos agentes - **strategy_result** (`strategy_agent.py:89`): `success, agent, signal, confidence, analysis, llm_used, llm_thesis, stub_used` @@ -264,7 +264,7 @@ Estes são os **dicts que fluem entre módulos** — o dado "vivo" do sistema. C - **BacktestTrade** `{candle_index,action,entry_price,exit_price,position_size_pct,pnl_usdt,pnl_pct,stop_loss,take_profit,exit_reason}`. - **BacktestResult** `{total_trades,win_rate,total_pnl_usdt,total_pnl_pct,max_drawdown_pct,sharpe_ratio,profit_factor,avg_win_pct,avg_loss_pct,trades:[BacktestTrade]}` + prop `expectancy`. Constantes commission 0.001, slippage 5bps, warmup 50. - **WindowResult**/`WalkForwardResult` (validação walk-forward; MAX_SHARPE_DEVIATION=0.30). **MonteCarloResult** `{n_simulations,median/p5/p95_pnl_pct,max_simulated_drawdown,pct_profitable,rejected}`. -- `_build_market_data` emite o formato **flat** (§3.4) → só DCA o consome plenamente. +- `_build_market_data` (desde Onda 2) computa `indicators` real + `regime` (§3.4) → estratégias dirigidas por indicadores (Grid/MeanReversion) exercitam o mesmo caminho que o live, não só DCA. ### 4.6 `src/risk/` - **KellyCriterion** `{win_rate,avg_win_pct,avg_loss_pct,capital=10000,n_trades}` → `full_kelly()|None` (min 30 trades), `fractional_kelly(0.25)` clamp [0.5,5.0], `ruin_risk()`. Constantes KELLY_FRACTION=0.25, MIN/MAX_POSITION_PCT=0.5/5.0, MIN_SAMPLE_FOR_KELLY=30. @@ -413,36 +413,43 @@ Em paralelo: cada ciclo emite XES `agent_cycle_started/completed/failed` → `GE ## 8. Dados "perdidos na classe" / declarados-mas-não-usados -Dados atribuídos e **nunca lidos depois** (marca **X**), conforme pedido: +Dados atribuídos e **nunca lidos depois** (marca **X**), conforme pedido. +> **Estado (atualizado após Ondas 1–2, PR #68 + seguinte):** vários itens foram +> resolvidos — marcados ✅ abaixo. Ver `docs/plano-melhorias.md` e `CHANGELOG.md`. | Dado | Local | Observação | |---|---|---| -| `RiskAgent.max_daily_loss_pct` | `risk_agent.py:22` | lido do env, nunca referenciado na classe | -| `UnifiedOrchestrator.sandbox` | `unified_orchestrator.py:38` | instanciado, nunca usado | -| `UnifiedOrchestrator.chain_manager` | `unified_orchestrator.py:39` | instanciado, nunca usado | -| `AgentMemorySystem.short_term` | `agent_memory.py:21` | dict criado, nunca escrito | -| `SecureToolSandbox.memory_limit_mb` | `secure_executor.py:26` | declarado, não aplicado na execução | -| `SecureToolSandbox.cpu_quota` | `secure_executor.py:27` | declarado, não aplicado | -| `ContinuousEvaluator.baseline` (continuous_eval) | `continuous_eval.py:11` | atribuído None, nunca usado | -| metrics `user_satisfaction`,`error_rate`,`response_time_p95` | `continuous_evaluator.py:12` | chaves declaradas, nunca alimentadas | -| `signal["market_context"]` | `strategy_agent.py:232` | construído mas o pipeline nunca lê (RiskAgent passa o signal inteiro) | -| `analysis["fibonacci_levels"]` | `strategy_agent.py:126` | computado, só carregado/sanitizado, nunca consumido a jusante | -| `strategy_result.{analysis,llm_used,llm_thesis,reasoning}` | `strategy_agent.py:89` | retornados; orquestrador só lê signal/confidence/stub_used | -| `OrchestratorLoop.order_store` | `orchestrator_loop.py:220` | exposto "para inspeção/futuro" | - -Dados **carregados mas subutilizados**: `KellyCriterion`/`PositionSizer`/`CapitalProtections` existem completos mas o pipeline dimensiona por `position_size_pct` simples (o Kelly só aparece em `GET /v1/risk/kelly`). +| ~~`RiskAgent.max_daily_loss_pct`~~ | `risk_agent.py` | ✅ **REMOVIDO (Onda 1)** — a perda-diária vive no `CircuitBreaker`, que tem o P&L; atributo era morto/enganoso | +| ~~`UnifiedOrchestrator.sandbox`~~ | `unified_orchestrator.py` | ✅ **REMOVIDO (Onda 1)** | +| ~~`UnifiedOrchestrator.chain_manager`~~ | `unified_orchestrator.py` | ✅ **REMOVIDO (Onda 1)** | +| ~~`AgentMemorySystem.short_term`~~ | `agent_memory.py` | ✅ **REMOVIDO (Onda 1)** | +| `SecureToolSandbox.memory_limit_mb` | `secure_executor.py:26` | declarado, não aplicado na execução (aberto) | +| `SecureToolSandbox.cpu_quota` | `secure_executor.py:27` | declarado, não aplicado (aberto) | +| `ContinuousEvaluator.baseline` (continuous_eval) | `continuous_eval.py:11` | atribuído None, nunca usado (aberto) | +| metrics `user_satisfaction`,`error_rate`,`response_time_p95` | `continuous_evaluator.py` (`AgentPerformanceEvaluator`) | chaves declaradas, nunca alimentadas (aberto) | +| `signal["market_context"]` | `strategy_agent.py:232` | construído mas o pipeline nunca lê (RiskAgent passa o signal inteiro) (aberto) | +| `analysis["fibonacci_levels"]` | `strategy_agent.py:126` | computado, só carregado/sanitizado, nunca consumido a jusante (aberto) | +| `strategy_result.{analysis,llm_used,llm_thesis,reasoning}` | `strategy_agent.py:89` | retornados; orquestrador só lê signal/confidence/stub_used (aberto) | +| `OrchestratorLoop.order_store` | `orchestrator_loop.py:220` | exposto "para inspeção/futuro" (aberto) | + +Dados **carregados mas subutilizados**: `KellyCriterion`/`PositionSizer`/`CapitalProtections`. +🟡 **Parcial (Onda 2, ADR-006):** a fórmula central do Kelly virou fonte única +(`src/risk/position_sizing.full_kelly_fraction`) e o endpoint `GET /v1/risk/kelly` +agora a consome — `src/risk/` não é mais código morto. **Resta:** o pipeline ainda +dimensiona por `position_size_pct` simples (plugar Kelly/proteções no sizing é a +cauda do R5). --- ## 9. Anomalias e inconsistências de dados -Achados relevantes para refatoramento (não alteram código — apenas documentados): +Achados relevantes para refatoramento. **Estado atualizado após Ondas 1–2** (✅ = resolvido): -1. **Dois formatos de `market_data`** (§3.4): `_build_market_data` do backtest emite o formato **flat** sem `indicators`; se Grid/MeanReversion forem usadas no backtest, `indicators=None` — só DCA consome o flat plenamente (`engine.py:234` vs `strategy_agent.py:383`). -2. **Ponte de nome `entry`→`entry_price`**: estratégias emitem `entry` (`mean_reversion.py:68`), mas guardrails/Order esperam `entry_price` — o `StrategyAgent._generate_signal` faz a normalização; um consumo direto do output da estratégia quebraria a validação. -3. **Mismatch de chave no registry de estratégias**: `STRATEGY_REGISTRY` tem `"mean_reversion"` (`__init__.py:23`) mas `_REGIME_STRATEGY_MAP` só emite `"dca"`/`"grid"` — **mean_reversion nunca é selecionada** por regime. -4. **`ab_tests.jsonl` não é JSON válido**: gravado via `str(payload)` (repr Python), não `json.dumps` (`ab_testing.py:60`). -5. **Colisões de nome de tipo** (mesmos dados, classes distintas): `ContinuousEvaluator`×2, `AdaptivePlanner`×2, `MemoryStore`×2, `SquadOrchestrator`×2, `Guardrail`×2. +1. ✅ **Dois formatos de `market_data`** (§3.4) — **RESOLVIDO (Onda 2)**: `engine._build_market_data` agora computa um `TechnicalIndicators` real + `regime` (guarda de warmup), exercitando o mesmo caminho que o live; Grid/MeanReversion não ficam mais inertes no backtest. +2. **Ponte de nome `entry`→`entry_price`** (aberto): estratégias emitem `entry` (`mean_reversion.py:68`), mas guardrails/Order esperam `entry_price` — o `StrategyAgent._generate_signal` faz a normalização; um consumo direto do output da estratégia quebraria a validação. +3. ✅ **Mismatch de chave no registry de estratégias** — **RESOLVIDO (Onda 1)**: `mean_reversion` agora é emitida no regime `sideways` por `_REGIME_STRATEGY_MAP`; teste de consistência registry↔roteamento adicionado. +4. ✅ **`ab_tests.jsonl` não é JSON válido** — **RESOLVIDO (Onda 1)**: gravado via `json.dumps` (`ab_testing.py`). +5. 🟡 **Colisões de nome de tipo** — **PARCIAL (Onda 2, R2)**: renomeados por propósito — `SquadOrchestrator`(protocols)→`A2ASquad`, `AdaptivePlanner`(replanner)→`AdaptiveReplanner`, `ContinuousEvaluator`(evaluator)→`AgentPerformanceEvaluator`, `MemoryStore`(forgetting)→`RelevanceMemoryStore`. **Resta** `Guardrail`×2 (ligado a R2b/R3 — duas fundações de agente/política). 6. **Duas políticas de validação de ordem** com campos diferentes: `GuardrailSystem` lê `market_context/action/entry_price`; `SecurityConfig.validate_order` lê `notes/exchange/position_size_pct`. 7. **`CandleOut` usa `lo`** (não `l`) para low (`schemas.py:216`) — divergência de convenção vs OHLCV interno `[o,h,l,c]`. 8. **Namespace `/v1/agents/{id}/config`** servido por dois routers (`agents` GET, `config` PATCH). diff --git a/docs/design/pages/screen_agents.jsx b/docs/design/pages/screen_agents.jsx index 0fdd677..c0ebd10 100644 --- a/docs/design/pages/screen_agents.jsx +++ b/docs/design/pages/screen_agents.jsx @@ -190,13 +190,13 @@ function ScreenAgents() { -