Les cours de la Bourse Régionale des Valeurs Mobilières — la bourse commune à huit pays d'Afrique de l'Ouest — collectés chaque jour, archivés depuis 2015, et analysés.
➜ Ouvrir l'application — rien à installer, ça marche dans le navigateur.
Ce n'est pas un conseil en investissement. Cet outil décrit ce qui s'est passé. Il ne dit pas ce qui va se passer, et il est construit pour ne jamais le prétendre.
- C'est quoi, en deux minutes
- Le petit lexique
- Ce que les données disent
- Ce qu'il y a dans le dépôt
- L'application
- La ligne de commande
- D'où viennent les données
- Où sont stockées les données
- Les pièges de brvm.org
- Ce qui reste à faire
- Tests, configuration, licence
La BRVM est la bourse de l'UEMOA : 47 sociétés cotées, réparties sur huit pays (Bénin, Burkina Faso, Côte d'Ivoire, Guinée-Bissau, Mali, Niger, Sénégal, Togo). C'est un marché étroit : peu de sociétés, peu d'échanges certains jours, et des informations dispersées.
Ce projet fait trois choses :
- Il collecte. Chaque soir, un robot lit la cote publiée sur brvm.org et enregistre les cours du jour.
- Il archive. Tout est conservé dans des fichiers texte versionnés dans ce dépôt Git, mis à jour chaque jour de séance — à ce jour 112 913 lignes, 3 000 séances, du 2 janvier 2015 au 31 juillet 2026, plus 309 versements de dividendes sur 41 sociétés.
- Il analyse. Une application web affiche le marché, la fiche de chaque valeur, un classement, et les résultats des tests statistiques.
Et il en tire une conclusion, mesurée sur onze ans et demi de cotation :
Aucune méthode de sélection basée sur les prix ne bat le hasard sur ce marché. Ce qui rapporte, ce sont les dividendes.
Le reste de ce document explique comment on le sait.
Cinq mots reviennent partout. Si vous les connaissez déjà, sautez cette section.
| Mot | Ce que ça veut dire |
|---|---|
| Séance | Une journée de bourse. Il y en a environ 250 par an — ni week-ends, ni jours fériés. |
| Cours de clôture | Le prix de l'action à la fin de la journée. |
| Dividende | La part du bénéfice qu'une société verse à ses actionnaires, en général une fois par an. |
| Détachement | Le jour où le dividende est versé. Le cours baisse mécaniquement du montant versé : ce n'est pas une perte, l'argent est passé de l'action à votre poche. |
| Backtest | Rejouer une stratégie sur le passé pour voir ce qu'elle aurait donné. Utile pour éliminer les mauvaises idées, jamais pour prouver qu'une idée est bonne. |
Deux mots de plus, qui apparaissent dans les résultats :
- IC (information coefficient) — une note entre −1 et +1 qui mesure si un classement prédit vraiment l'avenir. À 0, le classement ne vaut pas mieux qu'un tirage au sort. Sur ce marché, tout ce qui est mesuré reste très proche de 0.
- Liquidité — la facilité à acheter ou revendre. Une action peu liquide peut afficher un beau prix sans que personne ne puisse réellement l'acheter à ce prix.
Ces conclusions sont mesurées sur l'archive, pas supposées. Elles conditionnent la lecture de tout le reste.
Sur les quatre exercices connus, le dividende rapporte 7 à 10 % par an, tous les ans. Le cours, lui, fait n'importe quoi : de −1,6 % à +61,4 % selon l'année.
| Exercice | Cours (médiane) | Dividende | Total |
|---|---|---|---|
| 2022 | +3,6 % | +7,3 % | +10,9 % |
| 2023 | −1,6 % | +8,5 % | +6,9 % |
| 2024 | +15,8 % | +10,0 % | +25,8 % |
| 2025 | +61,4 % | +9,7 % | +71,1 % |
Conséquence : une analyse qui ne regarde que les cours ignore la partie la plus régulière du rendement, et ne garde que la plus bruyante.
On a testé 144 combinaisons — huit méthodes × six segments de marché × trois horizons de temps. Une seule survit une fois corrigée le fait qu'en testant 144 choses, on en trouve forcément quelques-unes « qui marchent » par pur hasard.
Cette unique survivante — le fait qu'une action qui a beaucoup baissé sur un mois a tendance à remonter le mois suivant — rapporte moins que les frais qu'elle coûte. Simulée avec dix lignes et un rééquilibrage mensuel : +7,2 % par an avant frais, −8,3 % après. Les frais valent huit fois le gain.
Momentum, tendance, volatilité, liquidité : indiscernables du bruit sur onze ans et demi.
Et « on ne peut pas conclure » est une réponse différente de « non ».
Le rendement du dividende connu au moment du détachement, confronté à la performance du cours des douze mois suivants, donne un IC de +0,086. Positif sur 6 saisons sur 9 — mais avec seulement neuf saisons, la marge d'erreur est trop large pour trancher. Là où les facteurs de prix ont été réfutés sur 148 périodes, celui-ci n'a simplement pas encore pu être testé, faute d'historique.
L'absence de preuve n'est pas une preuve d'absence.
Sur un marché où toute stratégie qui tourne plus de quelques fois par an est mangée par les frais, la conclusion raisonnable est la détention longue et diversifiée, pas la sélection active. L'application affiche un classement — mais elle affiche aussi, en permanence et avant tout le reste, que ce classement ne prédit rien.
streamlit_app.py l'application web (point d'entrée)
config.exemple.toml configuration commentée, à copier si besoin
pyproject.toml dépendances et métadonnées du paquet
data/ L'ARCHIVE — c'est la base de données du projet
cours.csv 112 913 séances-valeurs depuis 2015
referentiel.csv les 47 sociétés : ticker, nom, secteur
dividendes.csv 309 détachements datés
fondamentaux.csv indicateurs par société
exogenes.csv séries externes (commodités), à charger à la main
referentiel_amorce.csv filet de secours si la collecte du référentiel échoue
src/brvm/
cli.py toutes les commandes
config.py lecture de la configuration
db.py schéma SQLite et accès
features.py calcul des indicateurs
scoring.py le classement
backtest.py rejeu de la stratégie dans le temps
prediction.py modèle appris, et sa validation
recherche.py balayage systématique des prédicteurs
dividende.py logique des détachements
exogene.py séries externes
qualite.py détection des anomalies d'archive
pedagogie.py les textes explicatifs de l'app
ingestion/
brvm_org.py la cote du jour
sikafinance.py l'historique
dividendes.py les calendriers de dividendes
tests/ 237 tests, tous hors ligne
donnees/ captures réelles de pages web, servant de témoins
.github/workflows/
ingestion.yml collecte quotidienne, 16 h UTC en semaine
rapatriement.yml rattrapage d'historique
versement.yml verse les séances collectées, 16 h 45 UTC
veille.yml alerte si l'archive cesse d'avancer
tests.yml les tests à chaque modification
Un fichier n'est pas versionné : data/brvm.db, la base SQLite. Elle
se reconstruit à partir des CSV. Voir
Où sont stockées les données.
Elle tourne sur Streamlit Community Cloud, gratuitement, et se met à jour toute seule à chaque nouvelle donnée versée dans le dépôt.
Cinq onglets, tous cadrés par un même rang de filtres placé au-dessus (secteurs, recherche) — vous n'avez jamais à vous demander quel réglage s'applique où :
| Onglet | Ce qu'on y voit |
|---|---|
| Marché | L'état du jour : qui monte, qui baisse, quels volumes. |
| Valeur | La fiche d'une société : son cours dans le temps, ses dividendes. |
| Classement | Les valeurs ordonnées, et ce que vaut cet ordre. La section « modèle appris » y est incluse. |
| Backtest | Ce qu'aurait donné le classement s'il avait été suivi. |
| Données | La couverture de l'archive et le journal de collecte. |
Le résultat le mieux établi du projet — aucun facteur de prix ne bat le hasard — s'affiche avant les onglets, pas au fond de l'un d'eux : la hiérarchie visuelle doit dire la force de la preuve.
Chaque tableau s'exporte en CSV, et chaque graphique a son jumeau tabulaire. Une infobulle ne doit jamais être le seul accès à un chiffre.
Streamlit rejoue tout le script à chaque clic. Deux conséquences, toutes deux corrigées :
- L'onglet ne se perd plus. Il est retenu d'une relance à l'autre, et
écrit dans l'URL — donc il survit aussi au rechargement de la page, et
?onglet=Backtestse partage tel quel. La société ouverte dans l'onglet Valeur y est écrite de même, ce qui rend chaque fiche partageable par son lien :?onglet=Valeur&valeur=SNTS. Les réglages avancés d'un onglet survivent de leur côté à un aller-retour par un autre. - Seul l'onglet visible se calcule. Les quatre autres étaient entièrement recalculés à chaque interaction : 176 secondes entre deux rendus, pour un affichage qui n'en montre qu'un cinquième. Les résultats sont en outre gardés en mémoire tant que l'archive ne change pas.
Ouvrir l'app demande aujourd'hui 2,7 secondes, et une interaction deux à cinq dixièmes. Seule la première ouverture du classement coûte une dizaine de secondes — c'est la validation glissante du modèle appris, annoncée par son message d'attente et gardée ensuite.
Le mode sombre est une palette choisie, pas un inversement automatique : l'app lit le thème actif et sélectionne le jeu correspondant, chacun validé contre son propre fond.
Hausse et baisse suivent une paire bleu ↔ rouge, pas le vert/rouge boursier habituel — la confusion vert-rouge est le déficit visuel le plus répandu. Et le signe reste toujours écrit dans les tableaux : la couleur ne porte jamais seule une information.
- Sur share.streamlit.io, connectez ce dépôt GitHub.
- Fichier principal :
streamlit_app.py. Branche :main. - Déployez. Les dépendances sont lues dans
requirements.txt.
L'app ne lit que les CSV versionnés. Elle n'écrit rien et ne conserve aucun état — sur un hébergeur gratuit, le conteneur redémarre quand il veut et son disque ne survit pas. Y stocker des données donnerait une app affichant ce que personne ne peut retrouver ailleurs.
Vous n'en avez pas besoin pour utiliser le projet. Elle sert au diagnostic et aux actions automatiques. L'usage courant passe par l'app.
Si vous voulez quand même :
pip install -e ".[dev]" # Python 3.11 minimum
python -m brvm --helpPour lancer l'app en local :
pip install -e ".[web]"
streamlit run streamlit_app.pypython -m brvm verifier # les sélecteurs tiennent-ils ? n'écrit rien
python -m brvm ingerer # enregistre la séance publiée par brvm.org
python -m brvm referentiel # met à jour la liste des sociétés
python -m brvm rapatrier --debut 2015-01-01 --fin 2026-07-31
python -m brvm dividendes # calendriers et historique des dividendesLancez toujours verifier avant de compter sur la collecte automatique.
python -m brvm noter # classe les valeurs
python -m brvm rechercher --valeurs # quel prédicteur marche, et où
python -m brvm predire # probabilité de surperformance à 3 mois
python -m brvm rendement # retour à la moyenne du rendement du dividende
python -m brvm backtester # rejoue le classement dans le tempspython -m brvm exporter # base → CSV versionnés
python -m brvm importer # CSV versionnés → base
python -m brvm etat # ce que contient la base
python -m brvm veille # l'archive s'enrichit-elle encore ?
python -m brvm qualite # séances fantômes et désaccords entre sources
python -m brvm importer-dividendes fichier.csv
python -m brvm importer-fondamentaux fichier.csv
python -m brvm importer-exogenes fichier.csvCes commandes font de vrais appels réseau, pour trancher ce qui ne peut pas l'être hors ligne :
python -m brvm sonder # un appel à l'API sikafinance
python -m brvm sonder-historique # jusqu'où remonte le calendrier
python -m brvm sonder-dividendes # ce que rendent les trois sources
python -m brvm sonder-avis # les avis officiels sont-ils atteignables
python -m brvm texte-avis # vider le texte des avis, pour l'extracteur| Source | Ce qu'elle donne | Lue par |
|---|---|---|
brvm.org /fr/cours-actions/0 |
la cote du jour : clôture, volumes, symboles | ingestion/brvm_org.py |
sikafinance /api/general/GetHistos |
l'historique séance par séance depuis 2015 | ingestion/sikafinance.py |
brvm.org /fr/esv/paiement-de-dividendes |
le calendrier officiel des détachements | ingestion/dividendes.py |
sikafinance /marches/dividendes |
le calendrier et quatre exercices de rendements | ingestion/dividendes.py |
brvm.org fait autorité sur la clôture ; sikafinance apporte la profondeur
et le détail ouverture/haut/bas. La primauté se joue colonne par
colonne — voir db.fusionner_cours.
La page /marches/historiques/SDSC.ci n'est qu'une vitrine ; le tableau
est rempli par un appel que le navigateur fait en arrière-plan :
POST https://www.sikafinance.com/api/general/GetHistos
{"ticker": "SDSC.ci", "datedeb": "2026-01-01",
"datefin": "2026-03-31", "xperiod": "0"}
→ {"lst": [{"Date": "31/03/2026", "Open": …, "Close": …, "Volume": …}, …]}
Ce protocole vient du paquet R BRVM de Koffi Fredy
Sessie (MIT). Aucune ligne de
son code n'est reprise ; ce qui l'est — l'adresse, la forme du corps, le
pas de 89 jours — ce sont des faits sur le service, et le mérite de les
avoir établis lui revient.
Trois choses que la sonde a démenties, et qu'il aurait été naturel de supposer de travers :
Volumecompte des titres, pas des francs. Son ordre de grandeur suggérait le contraire. L'erreur évitée valait un facteur 1 700.- L'API est cohérente là où la page ne l'est pas. Dans le tableau HTML, « plus bas » dépasse la clôture huit fois sur dix ; dans l'API, la relation tient partout.
- Le milieu de
basethautest le prix moyen de la séance. Vérifié au franc près sur dix séances. C'est ce qui permet de reconstituer le volume en francs, que l'API ne fournit pas.
Le dépôt Git est la base de données. Pas de service externe, pas de compte à créer, pas de mot de passe à gérer.
Les fichiers data/*.csv sont versionnés. La base SQLite
(data/brvm.db) ne l'est pas : elle se reconstruit en quelques secondes
par python -m brvm importer. Trois raisons :
- un fichier binaire versionné grossit sans qu'on puisse lire ce qui a changé, et deux collectes simultanées y produisent un conflit irréparable ;
- une nouvelle collecte après correction d'un sélecteur apparaît ligne à ligne dans le diff — c'est exactement ce qu'on veut relire pour valider la correction ;
- Git fournit alors l'historique et la sauvegarde, gratuitement.
Réenregistrer une séance déjà présente la corrige au lieu de la dupliquer.
Six tables, déclarées dans src/brvm/db.py :
| Table | Clé | Contenu |
|---|---|---|
cours |
(date, ticker) | ouverture, haut, bas, clôture, volumes |
referentiel |
ticker | nom, secteur, première et dernière présence |
dividendes |
(ticker, date_detachement) | montant net, exercice |
fondamentaux |
(ticker, date, indicateur) | dividende, rendement, et ce qui viendra |
exogenes |
(date, serie) | commodités, taux — chargés à la main |
journal_ingestion |
— | trace de chaque exécution |
referentiel porte premiere_vue et derniere_vue, et aucune ligne
n'est jamais effacée.
Auparavant, le référentiel était réécrit depuis la photo du jour : une société retirée de la cote y perdait sa ligne, y compris pour les années où elle cotait. Le passé devenait celui des seuls survivants — ce qui fabrique mécaniquement des performances passées trop belles, puisqu'on oublie ceux qui ont échoué.
ingestion.yml et rapatriement.yml sont en lecture seule. Ils
publient un artefact archive-<run_id> contenant data/ et n'écrivent
rien : ce sont des collecteurs.
versement.yml écrit. Il tourne chaque jour ouvré à 16 h 45 UTC, relit
les artefacts des ingestions et des rapatriements récents, contrôle ce
qu'il y trouve, et verse dans data/ — en signant.
Deux façons d'être absente, une seule se verse. Une séance postérieure
à l'archive est un retard, elle se verse. Une ligne antérieure, sur une
date que l'archive connaît déjà, en a été retirée à dessein : la
ressusciter est la panne contre laquelle db.effacer_cours a été écrit,
et le versement la refuse. Entre les deux il y a le trou — une date
entièrement absente, comme le 6 août 2026 dont l'ingestion fut annulée à
mi-course. Celui-là se comble, et c'est à quoi sert rapatriement.yml :
brvm rapatrier --debut … --fin … relit la période, dépose son artefact,
et le versement suivant le reprend. brvm veille liste les trous.
Pourquoi une clé pour un robot. Le versement était d'abord manuel,
au motif qu'un runner ne sait pas signer et qu'un historique à moitié
vérifiable ne vaut guère mieux qu'un historique nu. L'objection portait
sur la signature, pas sur l'écriture : une clé propre au robot la lève.
Chaque versement reste « Verified », et l'auteur — versement automatique — dit qui a agi.
Ce que la contrepartie coûte, dit franchement : une signature ne prouve plus qu'une personne tenait sa clé, seulement que le commit vient de ce dépôt-ci. La distinction reste lisible dans le journal, mais elle change de nature.
Ce que le robot vérifie avant d'écrire, parce que personne ne regardera : en-têtes identiques, aucune ligne déjà présente, aucune séance antérieure à l'archive — ce garde-fou a déjà empêché de ressusciter 38 séances fantômes — tri préservé, aucune clôture nulle ou négative, et aucune séance republiée. Un seul contrôle qui tombe annule le versement.
La séance republiée mérite son nom : le 6 août 2026, rattrapé par
rapatriement, est revenu avec les 47 cours et les 47 volumes du 7 — la
même séance sous une autre date. Versée, elle a mis toutes les variations
de l'onglet Marché à 0 %, et c'est un lecteur qui l'a vu. Le critère
vient de sikafinance.seances_repetees, mesuré sur ce marché : « deux
échanges égaux au franc près n'existent pas, c'est la même transaction
republiée ». Les volumes nuls, eux, se répètent normalement et ne
comptent pas.
Ce qu'il ne refuse pas : la limite de ±7,5 %. La tentation est d'en
faire un invariant dur ; mesurée sur l'archive, elle lève 356 alertes dont
l'immense majorité est légitime — au détachement le prix de référence est
ajusté du dividende, la limite relie deux séances consécutives et non
deux blocs séparés d'un mois, et une division du nominal la franchit par
construction. Bloquer là-dessus arrêterait le versement toute la saison
des détachements, de mai à août. Les dépassements sont donc notés dans le
journal ; brvm qualite les range par cause probable.
Quand il ne verse pas, il retombe sur son ancien comportement : émettre l'incrément dans son journal, compressé et empreinté, à reprendre à la main. Une clé absente, un contrôle en échec ou une poussée refusée font perdre l'automatisme, jamais la donnée.
Une fois, et le versement tourne seul ensuite :
ssh-keygen -t ed25519 -C "versement automatique brvm" -f cle_versement -N ""- Clé publique (
cle_versement.pub) → Settings → SSH and GPG keys → New SSH key, type Signing Key. Pas « Authentication » : une clé d'authentification ne signe rien. - Clé privée (
cle_versement) → Settings → Secrets and variables → Actions → New repository secret, nomCLE_VERSEMENT. - Variable
COURRIEL_VERSEMENT(même écran, onglet Variables) : une adresse vérifiée du compte. L'adresse@users.noreply.github.comconvient. Sans elle, le workflow s'arrête plutôt que de produire un commit non vérifié. - Supprimez
cle_versementde votre disque.
Si le robot s'est arrêté, l'incrément est dans le journal de
versement.yml, avec son empreinte :
# depuis le journal de l'action : la ligne « --- increment base64 gzip --- »
base64 -d increment.b64 | gunzip > increment.csv
sha256sum increment.csv # doit correspondre à l'empreinte annoncéepuis fusionner dans data/cours.csv en respectant le tri, et committer.
L'autre voie reste ouverte : télécharger l'artefact archive-…,
décompresser dans data/, python -m brvm importer.
veille.yml surveille l'ensemble : elle ouvre une issue GitHub quand la
donnée cesse de progresser pendant cinq jours ouvrés, et son message
distingue les deux causes possibles — un versement en panne, ou une
collecte cassée.
veille.yml lance aussi brvm verifier sur la page vivante, une fois
par semaine. La distinction fait tout le dispositif : tests.yml lance le
même diagnostic sur les captures figées du dépôt — il resterait vert
pendant que brvm.org change de mise en page.
Le site a plusieurs comportements qui produisent des données fausses
mais plausibles. Ils sont documentés dans
src/brvm/ingestion/brvm_org.py et verrouillés par des tests ; les
résumer ici évite de les redécouvrir.
- La cote n'est pas paginée.
/fr/cours-actions/{n}n'est pas un numéro de page mais un identifiant de secteur (194 à 200). Les 47 sociétés tiennent sur/0. - Un identifiant inconnu ne renvoie pas d'erreur : le site sert la cote entière. Une lecture sectorielle mal ciblée rangerait donc les 47 sociétés dans un seul secteur, sans que rien ne se déclenche.
- L'URL demandée ne garantit pas le secteur servi. Le 27/07/2026,
/fr/cours-actions/197a rendu « Energie » puis « Industriels » à dix minutes d'intervalle. Le code ne croit donc que l'intitulé affiché par la page elle-même. - La page des sociétés cotées ne publie aucun symbole boursier.
/fr/emetteurs/societes-coteesest une vue en fiches — logo, adresse, téléphone. Le référentiel se lit donc sur la cote, seule page à porter « Symbole » et « Nom ». (/fr/societes-cotees/0, l'URL qu'on croirait bonne, renvoie une 404 habillée du thème complet.) - Les colonnes ne se rafraîchissent pas ensemble. Même séance close,
clôture / veille − 1ne redonne la variation publiée que pour environ la moitié des lignes. Le diagnostic le signale sans bloquer : niveillenivariationne sont enregistrées. - La date de séance vient d'un bloc précis — le « Dernière mise à
jour » posé au-dessus de la cote, cherché dans
section.block-tools— et pas de la bannière du site : deux horodatages différents cohabitent sur la page. Aucun repli sur la date du jour : une séance mal datée fausserait tous les calculs sans être détectable.
python -m brvm qualite cherche une signature étroite : une ligne dont
le cours vaut un multiple entier — ×2, ×5, ×10 — de la séance qui la
précède et de celle qui la suit. Sous une limite de ±7,5 % par
séance, l'aller-retour est deux fois impossible.
Trente-huit lignes portaient cette marque, toutes entre 2015 et 2017. Leur mécanisme se lit à découvert sur ONTBF : cours divisé par deux, quantité doublée, capitaux échangés identiques au franc près à ceux de la veille. Ce ne sont pas des cours mal transcrits, ce sont des échos de la séance précédente rejoués à une autre échelle.
Le préalable est toujours la donnée, jamais le code.
| Ce qui manque | Pourquoi c'est bloquant |
|---|---|
| Une série longue de dividendes | Quatre exercices donnent un ordre de grandeur, pas de quoi mesurer un pouvoir prédictif. C'est la donnée qui débloquerait le plus. |
| Les fondamentaux des émetteurs (PER, ROE, P/B) | Un des quatre facteurs du cadre initial n'a jamais pu être testé. |
| Les cours des commodités et le taux BCEAO | Aucune source n'est joignable depuis ce projet ; le chargement se fait à la main par importer-exogenes. |
Et une question ouverte : le retournement à un mois, seul effet retenu par le balayage, est-il un artefact de détachement ? Un dividende fait chuter le cours mécaniquement, et « baisse puis reprise » est exactement la forme du signal.
Les secteurs de la BRVM n'obéissent pas aux mêmes moteurs, et on pourrait vouloir un modèle par secteur. Le balayage systématique n'a trouvé aucun modèle sectoriel dans les prix : toutes les approches envisageables reposent sur des données d'une autre nature, qu'on n'a pas.
Deux exemples de ce que ça donnerait, et de ce qu'il faudrait :
- Télécoms et services publics (Sonatel, Orange CI, Onatel, CIE,
SODECI) — revenus réguliers, tarifs régulés, logique d'obligation plus
que d'action. Le cours y oscille autour d'un rendement d'équilibre.
python -m brvm rendementestime ce retour à la moyenne. Manque : une série longue de rendements. Cinq valeurs ne font pas un échantillon d'apprentissage — pas de modèle appris ici, et ce n'est pas un manque. - Agro-industrie (SAPH, SOGB, Palmci, Sucrivoire) — c'est là que le pouvoir prédictif serait le meilleur, parce qu'il existe un moteur extérieur au marché : le prix du caoutchouc, de l'huile de palme, du sucre. Manque : ces cours, qu'aucune source joignable ne fournit.
Un détail qui a son importance : le prix du caoutchouc à une date donnée est le même pour les 47 sociétés. Versé tel quel dans un modèle de classement, il ne distingue aucune valeur et l'IC ne bougerait pas — on conclurait à tort que les commodités n'expliquent rien. La variable utile est son produit avec l'appartenance sectorielle.
pytest -q # ou : python tests/test_brvm_org.py237 tests, tous hors ligne. Un test qui dépend du réseau échoue pour des raisons étrangères au code qu'il vérifie.
test_brvm_org.py travaille sur les captures réelles de tests/donnees/,
y compris les pages pathologiques : la 404 habillée du thème complet, la
vue en fiches sans symboles, la vue sectorielle qui se réclame d'un autre
secteur.
Deux fichiers de tests posent une question inhabituelle mais décisive —
le modèle doit aussi savoir ne rien trouver. test_prediction.py et
test_recherche.py lui soumettent du bruit pur : il ne doit rien en
tirer. Un modèle qui bat la référence sur une marche aléatoire a une
fuite, et cette fuite le fera briller en validation avant de perdre de
l'argent.
test_dividendes.py vérifie surtout les refus. Les sources nomment
les sociétés sans les coder, et attribuer le dividende de BANK OF AFRICA
BENIN à la BIIC Bénin ne se verrait jamais. Dès que deux candidats
correspondent, l'appariement refuse et la ligne est signalée plutôt
qu'écrite.
Tout a une valeur par défaut utilisable ; config.toml à la racine est
facultatif. Voir config.exemple.toml. Deux variables
d'environnement priment :
| Variable | Effet |
|---|---|
BRVM_CONFIG |
chemin d'un autre fichier de configuration |
BRVM_BASE |
chemin de la base SQLite |
MIT — voir LICENSE.
- Ce n'est pas un conseil en investissement. Aucun élément affiché ne constitue une recommandation d'achat ou de vente.
- Un backtest ne valide rien. Il sert à éliminer les mauvaises idées. On trouve toujours une règle qui aurait marché sur le passé.
- Les performances passées affichées sont optimistes. Elles reposent sur un univers qui ne contient pas les sociétés radiées.
- Diffusion publique. Publier des recommandations d'achat ou de vente relève du conseil en investissement boursier, encadré par l'AMF-UMOA (ex-CREPMF). Pour un usage personnel, aucun problème. Faites vérifier avant toute commercialisation.
- Collecte. Le délai entre requêtes est configurable ; ne descendez pas sous une seconde.