Add backtest pipeline, betting_brain filters, score coherence + social v3

betting_brain.py:
- HARD_MIN_SAMPLES=50 floor for calibrator bypass
- ev_edge < 0 + >= 0.20 hard vetoes
- BTTS muted (grid search found no profitable config)
- Per-market optimal envelopes (MS, OU25)
- Score coherence filter: main_pick must agree with score prediction
- HTFT reversal cross-check for MS picks

feature_builder.py / data_loader.py:
- Real home/away_position from data (was hardcoded 10)
- Cup detection wired into UpsetEngine
- _estimate_league_position with 300-day season filter

New scripts:
- diagnostic_backtest.py: per-bet diagnostic backtest with loss patterns
- optimize_filters.py: grid search per-market optimal thresholds
- analyze_backtest_csv.py: root-cause hypothesis testing on CSV
- compare_backtests.py: side-by-side validation with verdict
- test_score_coherence.py: smoke test for coherence filter (20/20 pass)

Reports:
- diagnostic_backtest_20260525_024437 (50-match smoke)
- diagnostic_backtest_20260525_035649 (1000-match in-sample)
- filter_optimization_patch.json (grid search winners per market)

Social poster v3:
- satori + resvg HTML/CSS rendering pipeline
- Twemoji football/basketball + flag SVGs
- caption SEO: 12 curated hashtags per post
- image SEO: descriptive filenames + .json metadata sidecar
- /health, /preview-png, /run-now endpoints

Docs:
- mds/SESSION_HANDOFF.md: full session state for cross-machine continuity
- mds/SOCIAL_POSTER_SETUP.md: API keys + test commands

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-25 20:43:28 +03:00
parent b619c2454a
commit 988ee2f50d
36 changed files with 5268 additions and 46 deletions
+261
View File
@@ -0,0 +1,261 @@
# SESSION HANDOFF — iddaai sistem durumu
**Son güncelleme**: 2026-05-25 ~20:30
**Hedef**: Başka makinede / yeni Claude session'ında bu doc tek başına okunup işin nerede kaldığı anlaşılabilmeli.
---
## 🎯 Üst-seviye hedef
Sistem **maç başı-1 saat** kullanıcı tetiklemesiyle çalışacak. Bahis uzmanı seviyesinde:
- **main_pick + value_pick** (sistemin önerdiği)
- **Tüm market olasılıkları** (MS, HT, OU05-45, BTTS, OE, DC, HTFT, HCAP, Cards, Corners)
- **Net HT + FT skoru** + **Top-5 olası skor dağılımı**
- **Evidence panel**: lineup impact, son 5 maç, h2h, hakem profili, benzer-oran-band geçmişi
Ürün modeli: hem user kendi bahisini oynar, hem sistem para kazanırsa abonelik satılır.
Hedef ROI: **≥%10**. Günde **3-5 kaliteli bahis**.
Detaylı requirements doc: bu dosyanın altında, "Requirements Spec" bölümü.
---
## 🟢 Şu an arka planda KOŞAN işler
### 1. Validation backtest (LOCAL — bu laptop)
- **Script**: `ai-engine/scripts/diagnostic_backtest.py`
- **Komut**: `python scripts/diagnostic_backtest.py --start 2026-05-01 --end 2026-05-14 --max-matches 1500`
- **Log**: `ai-engine/validation_full.log` (OneDrive senkronize)
- **Çıkış**: bittiğinde `ai-engine/reports/diagnostic_backtest_<timestamp>.{csv,json,txt}`
- **Tahmini bitiş**: 2026-05-25 ~22:00 (yaklaşık)
- **Amaç**: Yeni kodla (calibrator + ev_edge veto + envelope + coherence + BTTS mute) **out-of-sample** doğrulama
- **Risk**: Laptop uyursa ölür. Bitmesini beklemen lazım VEYA partial sonuçla devam.
```powershell
# Status check (kendin)
$log='C:\Users\fahri\OneDrive\المستندات\GitHub\iddaai\iddaai-be\ai-engine\validation_full.log'
Select-String $log 'rate=|Outputs:' | Select-Object -Last 3 | ForEach-Object {$_.Line}
```
### 2. Feeder historical scan (REMOTE — Pi server)
- **Konum**: SSH @ haruncan@95.70.252.214:2222 → docker container `iddaai-be` → pm2
- **PM2 process**: `feeder-historical` (id=1)
- **Log rotation**: pm2-logrotate kurulu (max 30MB/dosya, 3 dosya, gzip)
- **Davranış**: 2026-05-03'ten geriye 2023-06-01'e kadar mackolik'ten odds/lineup patch
- **Otomatik restart**: 502 olunca 30 sn delay sonra restart (max 1000 kez)
- **Beklenen süre**: 24-72 saat
```bash
# Status (kendin SSH'la)
sudo docker exec iddaai-be pm2 list
sudo docker exec iddaai-be pm2 logs feeder-historical --lines 30 --nostream
```
---
## 📝 Bu seansta yapılan KOD değişiklikleri
Hepsi local repo'da, OneDrive senkronize edecek, başka makinede pull etmesen de açtığında orada olacak.
### A. Settlement / data layer
| Dosya | Değişiklik |
|---|---|
| `iddaai-be/prisma.config.ts` | `.env` fallback ekledim (`.env.local` üstüne) — `prisma generate` çalışsın diye |
| `iddaai-be/src/tasks/prediction-settlement.market-resolver.ts` | DC parser ayraçsız "1X/X2/12" kabul ediyor + HT_OU05/HT_OU15/HT_OU25 resolver eklendi |
| `iddaai-be/src/tasks/feature-enrichment.task.ts` **(YENİ)** | Cron 08:15 — eksik football_ai_features row insert + odds_movement SQL backfill |
| `iddaai-be/src/tasks/python-enrichment.task.ts` **(YENİ)** | Cron 08:25 — Python `enrich_ai_features.py` subprocess |
| `iddaai-be/src/tasks/tasks.module.ts` | İki yeni task register |
| `iddaai-be/src/scripts/run-feature-enrichment.ts` **(YENİ)** | Manuel one-shot trigger |
### B. AI engine — betting brain
`iddaai-be/ai-engine/services/betting_brain.py` — büyük revizyon:
- **HARD_MIN_SAMPLES = 50** floor (calibrator bypass <50 sample)
- **`ev_edge < 0.0` HARD VETO** (`negative_ev_edge`)
- **`ev_edge >= 0.20` HARD VETO** (`ev_edge_too_high_trap`)
- **`MUTED_MARKETS = {"BTTS"}`** — backtest no profitable config bulduğu için
- **`MARKET_OPTIMAL_FILTERS`** — MS ve OU25 için grid-search'ten gelen optimal envelope
- **`_score_consistent_markets()`** — skor tahminine uymayan picks elimine
- **`judge()` score coherence filter** — main_pick coherent set'ten seçilir
- **HTFT reversal cross-check** — Man City 1/2 senaryosu
### C. AI engine — model & calibration
| Dosya | Değişiklik |
|---|---|
| `ai-engine/models/calibration.py` | HARD_MIN_SAMPLES floor + sample-weighted blend formülü değişti |
| `ai-engine/models/calibration/*.pkl` | **10 calibrator retrain** (ms_home/draw/away, ou15/25/35, btts, ht_home/draw/away) — 4989-5000 sample her biri |
### D. AI engine — orchestrator feature builder
`ai-engine/services/orchestrator/feature_builder.py`:
- Hardcoded `home_position=10, away_position=10` → real `data.home_position` kullanılıyor
- Cup detection upper'a taşındı, `is_cup_match` UpsetEngine'e geçiyor
- Total teams parametresi UpsetEngine'e geçiyor
`ai-engine/services/orchestrator/data_loader.py`:
- `_estimate_league_position` artık **sezon filtresi** (son 300 gün) kullanıyor
### E. AI engine — scripts (yeni)
| Dosya | Ne yapıyor |
|---|---|
| `ai-engine/scripts/diagnostic_backtest.py` | Per-bet diagnostic backtest (CSV+JSON+TXT output) |
| `ai-engine/scripts/analyze_backtest_csv.py` | Backtest CSV üzerinde root-cause hipotez testleri |
| `ai-engine/scripts/optimize_filters.py` | Grid search per-market optimal threshold |
| `ai-engine/scripts/compare_backtests.py` | İki CSV karşılaştırması verdict ile |
| `ai-engine/scripts/test_score_coherence.py` | Coherence filter smoke test (LAFC senaryosu) |
### F. Social poster modülü (NestJS)
| Dosya | Değişiklik |
|---|---|
| `src/modules/social-poster/social-poster.service.ts` | Cron 15→10 dk, window 10-60, MAX_POSTS_PER_RUN, getHealthStatus() |
| `src/modules/social-poster/image-renderer.service.ts` | SEO filename + metadata sidecar (.json) |
| `src/modules/social-poster/caption-generator.service.ts` | SEO hashtag stratejisi (12 küratör tag) |
| `src/modules/social-poster/social-poster.controller.ts` | `/health` public + `/preview-png/:matchId` + `/run-now` endpoints |
| `mds/SOCIAL_POSTER_SETUP.md` **(YENİ)** | Env vars + API key alma adımları + test komutları |
### G. Modern image rendering (deneme)
| Dosya | Açıklama |
|---|---|
| `src/scripts/render-social-card-v3.ts` | satori + resvg-js ile modern HTML→PNG rendering (Twemoji top + bayrak) |
| `src/modules/social-poster/assets/*.svg` | Twemoji futbol/basket/bayrak SVG'leri |
### H. Yapılan DB değişiklikleri (idempotent — tekrar koşturulursa sorun yok)
| İşlem | Etki |
|---|---|
| `football_ai_features` 4008+ satır backfill | Son 60 günün FT maçları için feature row var artık (calculator_ver=feature_enrichment_task_v1) |
| Python enrichment koştu | h2h, referee, possession, league_avg, implied_* hepsi gerçek değerlerle dolu (181,614+ satır enriched) |
| Calibrator dosyaları yazıldı | `ai-engine/models/calibration/*.pkl` overwritten |
---
## 📂 Önemli dosya konumları (OneDrive synced)
```
iddaai-be/
├── mds/
│ ├── SESSION_HANDOFF.md ← BU DOSYA
│ └── SOCIAL_POSTER_SETUP.md ← social poster env+keys
├── ai-engine/
│ ├── reports/ ← BACKTEST CIKTILARI
│ │ ├── diagnostic_backtest_*.csv,json,txt
│ │ └── filter_optimization_patch.json
│ ├── validation_full.log ← validation backtest canlı log
│ ├── diagnostic_backtest_run.log ← önceki backtest log
│ ├── enrichment_run3.log ← enrichment koşma log
│ └── calibration_run.log ← calibrator retrain log
├── public/predictions/ ← render edilmiş social card PNG/JSON
└── src/scripts/ ← tüm yeni script'ler
```
---
## 🔑 Erişim bilgileri
### Pi sunucu (feeder + prod stack)
- **SSH**: `haruncan@95.70.252.214:2222`
- **Şifre**: `M594xH%$iM&4MM`
- **Plink kullan**: `~/plink.exe -ssh -P 2222 -pw '<password>' -hostkey 'SHA256:iq0YVI/4J897sf9dkksI7QzetpLCD0l57ZMX4UissI8' haruncan@95.70.252.214`
- **Docker**: `iddaai-be`, `iddaai-ai-engine`, `iddaai-fe`, `iddaai-postgres`, `iddaai-redis`, `gitea`
### DB (uzak Postgres @ Pi)
- **SSH tunnel function**: `iddaai-db` PowerShell fonksiyonu (yerel makinedeki profile'da kayıtlı)
- **Tunnel: localhost:5432 → Pi:5432**
- **Connection string**: `postgresql://iddaai_user:IddaA1_S4crET!@localhost:5432/iddaai_db?schema=public`
- **MCP**: Claude'un postgres MCP'si bu tunnel üzerinden çalışıyor (restricted mode, read-only)
---
## 📊 BACKTEST sonuçları geçmişi
### Backtest #1 — In-sample grid search (2026-05-11 → 05-24, 1000 maç)
- **CSV**: `ai-engine/reports/diagnostic_backtest_20260525_035649.csv`
- **TXT**: `ai-engine/reports/diagnostic_backtest_20260525_035649.txt`
- **Toplam playable**: 524 bet
- **Hit rate**: %54.77
- **ROI**: **%16.73** (baseline kötü)
- **Grid-search'ten çıkan optimal filtreler (in-sample)**:
- MS: edge [-5%, +15%], V27 AGREE zorunlu → +%8.23 (21 bet)
- OU25: odds ≥ 1.80, edge ≤ +15% → +%28.91 (20 bet)
- BTTS: tüm config'lerde kayıp → MUTE
- **Aggregate optimize**: 95 bet, ROI +%2.16 (in-sample)
### Backtest #2 — Validation (2026-05-01 → 05-14, KOŞUYOR)
- **Bitince konum**: `ai-engine/reports/diagnostic_backtest_<yeni_timestamp>.{csv,json,txt}`
- **Karşılaştırma çalıştır**: `python scripts/compare_backtests.py` (otomatik en yeni 2'yi alır)
- **Beklenen sonuç**: ROI ≥ 0 → out-of-sample doğrulama BAŞARILI; in-sample overfit değil
---
## ❓ Backtest BİTTİĞİNDE yapılacak (yeni session'da bu kısımdan başla)
### 1. Sonucu oku
```powershell
cd C:\Users\fahri\OneDrive\المستندات\GitHub\iddaai\iddaai-be\ai-engine
Get-ChildItem reports\diagnostic_backtest_*.txt | Sort-Object LastWriteTime -Descending | Select-Object -First 1 | Get-Content
```
### 2. Karşılaştır
```powershell
python scripts\compare_backtests.py
```
Bu otomatik en yeni 2 backtest'i karşılaştırır, **VERDICT** verir:
- ✅ "FILTERS WORK" → ROI pozitif AND improved
- 🟡 "PARTIAL" → improved ama hâlâ negatif
- ❌ "OVERFITTING" → validation ROI collapse
### 3. Karara göre 2 yol
**Eğer ROI ≥ +%2 ve overfit yok:**
- `/sc:design` ile UI/API contract → Sprint 1
- Sprint 1: top-5 skor + evidence panel + "why" cümlesi
- Test edip prod'a aç
**Eğer ROI negatif veya overfit:**
- `analyze_backtest_csv.py` ile loss diagnostic
- Hangi market hâlâ kötü → tighten filter veya mute
- Calibrator recalibrate (özellikle BTTS dışındakiler için yeni sample)
- Tekrar backtest
---
## ⚠️ Bilinen açık problemler / sorular
1. **Coherence filter validate edilmedi production-side** — smoke test 20/20 ama gerçek production data ile karşılaştırma yok
2. **Lineup-overlap last-5 hesabı** — yazılmadı, requirements doc'ta F8 var
3. **Skor top-5 distribution** — Poisson zaten hesaplıyor, surface edilmedi (UI tarafı)
4. **"Why" cümlesi main_pick'te** — boş, doldurulması gerek
5. **Cards/Corners/RED CARD model** — yok, "henüz desteklenmiyor" placeholder ile bırak (kullanıcı onayladı: mevcut market'ler sağlamlaşsın)
6. **Orphan match_id 51 satır**`prediction_runs` içinde, `matches`'ta yok. Sample noise, geçiştirilebilir.
7. **opening_value feeder bug**`odds_movement_*` SQL yazıyor ama tüm değerler 0 (opening == closing). Feeder upstream sorun. Düşük öncelik.
---
## 🚦 Yeni Claude session'ında ilk komut
```
Bu projeye yeni bağlandım. Lütfen aşağıdaki dosyayı oku ve bana proje durumunu özet ver:
C:\Users\fahri\OneDrive\المستندات\GitHub\iddaai\iddaai-be\mds\SESSION_HANDOFF.md
Sonra validation backtest'in sonucuna bak:
- C:\Users\fahri\OneDrive\المستندات\GitHub\iddaai\iddaai-be\ai-engine\reports\
içindeki en yeni diagnostic_backtest_*.txt dosyasını oku
- compare_backtests.py script'ini koş, verdict göster
- Verdict'e göre sonraki adımı öner
```
Buradan devam eder. Tüm context bu doc'ta + dosyalarda + DB'de.
---
## 🛠️ Requirements spec (sıkıştırılmış)
**Ürün**: UI-tetikli per-match analiz, bahis uzmanı seviyesi
**Trigger**: User tıklar, on-demand
**Output**: main_pick + value_pick + tüm market olasılıkları + tek HT/FT skoru + top-5 skor dağılımı + evidence panel
**Kapsam**: Mevcut market'ler sağlamlaştırılır, yeni market eklenmez (kullanıcı onayı)
**Quality bar**: Calibration sapması ±2-5pp per market, NaN yok, response <3sn
**Validation**: Out-of-sample backtest (1500 maç, May 1-14) — KOŞUYOR
---
**SON NOT**: Backtest'in TAMAMLANMASINI bekle (~22:00). Laptop'u kapatma. Bittiğinde OneDrive senkronize eder, başka makinede otomatik orada olur. Yeni session'da bu dosyayı oku, sonuçlara bak, devam et.