agent / algorithme_readme.md
Echodelta06's picture
Update: algorithme recherche comps et valuation
e9297d9
|
Raw History Blame Contribute Delete
5.35 kB
# Algorithme de Matching & Valorisation (Dual-Track)
Ce document decrit le moteur implemente dans `backend/database.py` apres refonte en **double entonnoir**:
- Track A: **Market Intel / affichage** (`list_display`)
- Track B: **Valuation / extraction de multiples** (`list_valuation`)
## 1) Vue d'ensemble du pipeline
1. Embedding de la cible (Mistral).
2. Retrieval des candidats (RPC pgvector, fallback Python si erreur).
3. Scoring de chaque transaction:
- `vector_score`
- `size_score`
- `naf_score`
- `weighted_final_score`
4. Construction de 2 listes:
- `list_display` (pertinence marche/metier pour l'affichage)
- `list_valuation` (coherence financiere pour la valorisation)
5. Relaxation elastique si quota insuffisant:
- `list_display`: baisse `semantic` uniquement, par pas de `0.05` (plancher `0.20`)
- `list_valuation`: hausse `size` d'abord (+10%), puis baisse `semantic`
6. Calcul des multiples:
- priorite a `list_display`
- complement via `list_valuation` si < 3 valeurs
7. Generation d'un CSV d'audit dans `debug_logs/`.
## 2) Parametres configurables (`backend/config.py`)
### Phase 1 - Identification (List Display)
- `MIN_SEMANTIC_MATCH = 0.80`
- contrainte de taille **retiree** sur ce track (focus metier)
- score d'affichage dedie:
- `display_score = (0.95 * vector_score) + (0.05 * size_score)` (si taille connue)
- sinon `display_score = vector_score`
- relaxation si `< 3` resultats:
- baisse `MIN_SEMANTIC_MATCH` par pas de `0.05` jusqu'a `0.20`
### Phase 2 - Extraction Multiples (List Valuation)
- `VALUATION_MIN_SEMANTIC = 0.45`
- `VALUATION_MIN_COUNT = 3`
- `MAX_CA_MULTIPLE_VALUATION = 20`
- `MAX_EBITDA_MULTIPLE_VALUATION = 70`
- contrainte de taille stricte au depart: `size_delta_percent <= 1.00` (±100%)
- filtres secondaires:
- `naf_score` (si NAF cible disponible)
- `semantic_score`
- relaxation elastique:
1) on relache d'abord la taille (`+0.10` par pas)
2) puis la semantique (pas `0.05`)
### Relaxation elastique (quota force)
- `semantic_step = 0.05` (jusqu'a `0.20`)
- `size_step = 0.10`
- `list_display`: relaxe semantique uniquement
- `list_valuation`: relaxe taille puis semantique
## 3) Formules de score
### 3.1 Delta de taille
`size_delta_percent = |CA_transaction - CA_cible| / CA_cible`
si la taille n'est pas connue: `size_delta_percent = null`.
### 3.2 Score final (taille connue + NAF disponible)
`ScoreFinal = (0.40 * ScoreTaille) + (0.40 * ScoreVectoriel) + (0.20 * ScoreNAF)`
### 3.3 Score final (taille inconnue + NAF disponible)
`ScoreFinal = ((0.40 * ScoreVectoriel) + (0.20 * ScoreNAF)) / (0.40 + 0.20)`
### 3.4 Score final (taille inconnue + NAF indisponible)
`ScoreFinal = ScoreVectoriel`
## 4) Regles hard-stop par track
### Track A (`list_display`)
- reject si `vector_score < MIN_SEMANTIC_MATCH`
- pas de hard-stop taille (l'objectif est la coherence metier pour l'affichage)
- priorisation par `display_score` (95% semantique, 5% taille)
### Track B (`list_valuation`)
Une transaction entre dans `list_valuation` si:
- `vector_score >= VALUATION_MIN_SEMANTIC`
- ET `multiple_ca` ou `multiple_ebitda` est present et positif
- ET respecte la contrainte de taille stricte initiale (±100%) quand taille connue
- ET passe le filtre `naf_score` si NAF cible disponible
- si quota insuffisant: relaxation elastique (taille puis semantique)
## 5) Logique de calcul des multiples
Pour chaque axe (CA, EBITDA):
1. on prend les multiples valides de `list_display`
2. si le count est `< VALUATION_MIN_COUNT`, on complete avec les meilleurs de `list_valuation` (tri `weighted_final_score`)
3. si count final `< VALUATION_MIN_COUNT`:
- `is_calculable = false`
- `reason = "Données insuffisantes même après élargissement"`
4. toute transaction ajoutee via paliers elastiques est taggee:
- `quality_label = "Match Élargi (Quota Forcé)"`
Sinon, calcul mediane/moyenne.
## 6) Contrat de sortie (zero-null)
Dans `results.multiples`:
- montants toujours numeriques (`0` par defaut)
- objet normalise:
- `valuation_ca = { value, is_calculable, reason }`
- `valuation_ebitda = { value, is_calculable, reason }`
- scope de valorisation:
- `valuation_scope = "listing stricte"` ou `"listing élargie"`
## 7) Audit CSV
Pour chaque execution:
- fichier: `debug_logs/audit_matching_[timestamp].csv`
- toutes les transactions scannees (retenues + rejetees)
- colonnes de provenance:
- `in_display_track`
- `in_valuation_track`
- `list_origin` (`display`, `valuation`, `display+valuation`, `rejected`)
- statuts typiques:
- `RETAINED_DISPLAY`
- `RETAINED_VALUATION_POOL`
- `RETAINED_DISPLAY+VALUATION_POOL`
- `REJECTED`
## Rajout ed06 (a améliorer):
Actuellement, la formule ressemble probablement à ceci :
Score Final = (Poids_Sémantique * Similarité) + (Poids_CA * Proximité_CA)
Si la métallurgie a un score CA de 1.0 (CA identique) et un score sémantique de 0.6 (faible mais passe le seuil), elle peut battre une boutique de vêtements qui aurait un score sémantique de 0.9 mais un score CA de 0.4 (boutique plus petite). C'est ce qu'on appelle un faux positif financier.
Si la métallurgie sort dans le top 3 d'une boutique de vêtements, c'est que ton algorithme actuel est additif (on additionne les scores) au lieu d'être éliminatoire (on filtre d'abord, on score ensuite).