td.mono { white-space: nowrap; }
D'où viennent les cours et les données économiques, ce que l'IA regarde chaque jour, comment on calcule ce qu'elle aurait gagné, pourquoi on la juge sur une période qu'elle n'a jamais vue, si l'économie ou les bougies l'aident vraiment à prévoir, et comment fonctionnent le temps réel et l'effet de levier.
Simulation pédagogique avec de l'argent fictif, pas un conseil en investissement. Le code est volontairement simple ; les limites sont listées en fin de page.
Les cours viennent de Yahoo Finance : le contrat à terme sur l'or du COMEX (symbole GC=F), en dollars l'once. Il y a deux types de données : les clôtures quotidiennes depuis 2000 (6 550 séances) pour l'entraînement, et le cours minute par minute de la séance pour le temps réel.
Un navigateur n'a pas le droit d'interroger Yahoo directement : les sites refusent les requêtes venant d'une autre page (règle CORS). Un petit relais sur rdv-app.fr, serveur/or-serveur.js, fait la requête à sa place et garde la réponse en mémoire, 6 heures pour l'historique et 30 secondes pour le cours en direct. Si Yahoo ne répond pas, il renvoie la dernière valeur connue ; si le relais lui-même est indisponible, la page se rabat sur un fichier statique, or.json.
// Attention : avec range=max, Yahoo renvoie des points mensuels. On demande donc explicitement les dates.
const r = await yahoo(`period1=946684800&period2=${Math.floor(Date.now() / 1000)}&interval=1d`);
Ce commentaire vient d'un vrai piège rencontré : la première version recevait 269 points mensuels au lieu de 6 550 points quotidiens, sans aucune erreur.
Chaque jour, l'IA reçoit au minimum 13 nombres (jusqu'à 33 avec les options « forme des bougies » et « économie », présentées plus bas). Les 10 premiers sont des indicateurs classiques de l'analyse technique, calculés uniquement avec les cours jusqu'à ce jour-là. Utiliser par erreur un cours du lendemain donnerait une IA miraculeuse sur le papier et inutile en vrai.
| Entrée | Ce qu'elle mesure | Divisée par |
|---|---|---|
| 1 à 4 | Variation du cours sur 1, 5, 20 et 60 jours (en logarithme) | 1,5 % · 3,5 % · 7 % · 12 % |
| 5 à 7 | Écart entre le cours et sa moyenne sur 20, 50 et 200 jours | 4 % · 6 % · 12 % |
| 8 | Volatilité : ampleur moyenne des variations quotidiennes sur 20 jours | 1,2 % |
| 9 | RSI 14 jours : le cours a-t-il surtout monté ou baissé récemment ? (de 0 à 100, centré sur 50) | 25 |
| 10 | Recul depuis le plus haut des 252 derniers jours (un an de séances) | 15 % |
| 11 à 13 | Position actuelle de l'IA : vendeuse, neutre ou acheteuse (une seule vaut 1) | – |
Chaque indicateur est divisé par une valeur typique, puis borné entre −3 et 3 : le réseau reçoit des nombres de même ordre de grandeur, et un jour de krach ne fait pas « exploser » ses calculs. Les 200 premières séances servent seulement à amorcer les moyennes : l'IA commence à trader en 2001.
const borne = (v) => Math.max(-3, Math.min(3, v));
f[o] = borne(lr(i, 1) / 0.015); // variation sur 1 jour
f[o + 4] = borne((c[i] / moy(20) - 1) / 0.04); // écart à la moyenne 20 jours
f[o + 8] = borne((rsi - 50) / 25); // RSI centré
f[o + 9] = borne((c[i] / haut - 1) / 0.15); // recul depuis le plus haut d'un an
Le réseau a 3 sorties : vendre, rester neutre, acheter. La plus forte l'emporte. Si la vente à découvert n'est pas autorisée, la sortie « vendre » est simplement ignorée. Donner la position actuelle en entrée permet au réseau d'apprendre à ne pas changer d'avis pour un rien, puisque chaque changement coûte des frais.
const e = Array.from(f.subarray(i * NF, i * NF + NF));
e.push(pos === -1 ? 1 : 0, pos === 0 ? 1 : 0, pos === 1 ? 1 : 0);
const o = activer(e);
let k = 1; // neutre par défaut
if (o[2] > o[k]) k = 2; // acheter
if (vente && o[0] > o[k]) k = 0; // vendre, seulement si autorisé
return k - 1; // -1, 0 ou 1
La règle est simple et prudente : l'IA décide à la clôture du jour i, avec les cours connus ce jour-là, et sa position s'applique jusqu'à la clôture du lendemain. Elle ne profite donc jamais d'un mouvement qu'elle n'aurait pas pu anticiper.
À chaque changement de position, on prélève les frais (0,1 % par défaut, le double pour passer directement d'acheteur à vendeur). Le portefeuille suit ensuite le cours : multiplié par la variation de l'or si l'IA est acheteuse, divisé si elle est vendeuse, inchangé si elle est neutre. On note au passage la pire chute depuis un sommet.
for (let i = a; i < b; i++) {
const p = decider(activer, f, i, pos, vente);
if (p !== pos) { eq *= 1 - frais * Math.abs(p - pos); trades++; pos = p; }
eq *= Math.exp(pos * Math.log(c[i + 1] / c[i])); // la position joue jusqu'à la clôture suivante
if (eq > haut) haut = eq;
dd = Math.max(dd, 1 - eq / haut); // pire chute depuis un sommet
}
Les rendements sont ramenés à une moyenne annuelle (252 séances par an) pour pouvoir comparer des périodes de longueurs différentes.
La note d'une IA est le logarithme de ce qu'elle a multiplié son capital pendant l'entraînement, moins la moitié de sa pire chute :
const r = simuler(reseau(versCerveau(g)), C, F, A, S, FRAIS, VENTE); // A → S : entraînement seulement
g.fitness = Math.log(r.eq) - 0.5 * r.dd;
Le logarithme met les gains et les pertes à égalité (doubler puis diviser par deux ramène à zéro). La pénalité de chute écarte les IA qui gagnent beaucoup en prenant des risques énormes : à rendement égal, celle qui a moins chuté en cours de route est préférée.
Le reste est le même NEAT que dans les autres jeux, exécuté dans un Web Worker : réseaux qui grandissent par mutation, espèces, élitisme, relance de diversité après 40 générations sans progrès. Une génération de 60 IA prend environ une demi-seconde.
La sélection n'utilise que la période d'entraînement (de A à S). Après chaque génération, le Worker rejoue la meilleure IA sur la période de test (de S à aujourd'hui), en partant d'une position neutre, et envoie ce résultat à la page sans jamais s'en servir pour choisir. C'est la condition pour que le test soit un vrai examen.
pop.forEach(evaluer); // notes sur l'entraînement uniquement
const best = [...pop].sort((a, b) => b.fitness - a.fitness)[0];
const test = simuler(reseau(versCerveau(best)), C, F, S, B, FRAIS, VENTE); // examen, pour information
Résultat mesuré avec un entraînement de 2001 à 2018 (100 IA, 150 générations) : la meilleure IA passe de 9 % à 21 % par an sur l'entraînement, mais ne fait que 7 à 14 % par an sur 2019-2026, alors qu'acheter et garder rapportait 16,4 %. La courbe par génération de la page montre ce décrochage : c'est le surapprentissage, expliqué en détail sur la page elle-même.
Si l'on déplace la fin de l'entraînement après coup, les IA déjà entraînées sont effacées : leurs chiffres auraient été calculés avec une autre coupure et ne seraient plus comparables.
En option, l'IA reçoit aussi le contexte économique américain et géopolitique. Le script scripts/maj_marche.py rassemble tout dans un seul fichier, or-macro.json, aligné jour par jour sur les séances de l'or. Le relais le reconstruit toutes les 12 heures et le sert à la page (/or-api/macro).
| Donnée | Source | Rythme |
|---|---|---|
| Taux à 10 ans, bon du Trésor à 3 mois (suit le taux de la Fed), dollar, VIX, pétrole, S&P 500 | Yahoo Finance | quotidien |
| Inflation (indice des prix CPI-U, sur un an) et taux de chômage | BLS, l'office statistique américain | mensuel |
| Créations d'emplois américaines (emploi salarié non agricole) | BLS | mensuel |
| Argent métal | Yahoo Finance (SI=F) | quotidien |
| Risque géopolitique mondial, avec les grands événements datés | Caldara et Iacoviello (Réserve fédérale), indice calculé à partir de la presse | quotidien |
| Tensions par région : Moyen-Orient (Israël, Arabie saoudite, Égypte, Turquie), Russie-Ukraine, Chine-Taïwan | Caldara et Iacoviello, indices par pays (part des articles qui évoquent des tensions impliquant chaque pays) | mensuel |
La difficulté est de ne jamais donner à l'IA une information qu'elle n'aurait pas eue à l'époque. L'inflation de mars, par exemple, n'est publiée que vers le 15 avril : utiliser ce chiffre fin mars reviendrait à tricher. Chaque valeur n'est donc rendue disponible qu'à partir de sa date de publication.
def publication(annee, mois):
#Les chiffres du mois M sont publiés vers le 15 du mois suivant
a, m = (annee + 1, 1) if mois == 12 else (annee, mois + 1)
return datetime.date(a, m, 15).isoformat()
def aligner(dates, serie, decalage_jours=1):
#Valeur connue à chaque date : la dernière observation antérieure d'au moins `decalage_jours`
...
| Donnée | Utilisée à partir du |
|---|---|
| Cours de marché, risque géopolitique quotidien | lendemain |
| Inflation et chômage du mois M | 15 du mois M+1 |
| Créations d'emplois du mois M (publiées le premier vendredi) | 8 du mois M+1 |
| Tensions par région du mois M | 5 du mois M+1 |
Exemple vérifié : le 20 mars 2020, en pleine panique du Covid, le chômage vu par l'IA est encore 3,5 % (le chiffre de février). L'envolée à près de 15 % n'apparaît qu'à sa publication, en mai.
Trois pièges rencontrés :
scripts/cache/ : une mise à jour ne redemande que les deux dernières années, et si le BLS refuse, les chiffres précédents sont conservés.Avec l'option « économie », l'IA reçoit 15 critères de plus, en plus des indicateurs du cours et de sa position. Comme pour le cours, chaque critère est ramené à une échelle comparable et borné entre −3 et 3.
| Critère | Calcul | Effet habituel sur l'or |
|---|---|---|
| Taux à 10 ans | évolution sur un mois | des taux qui montent pèsent sur l'or |
| Taux réel | taux à 10 ans moins l'inflation (approximation) | l'or ne rapporte rien : il attire moins quand le taux réel est élevé |
| Taux de la Fed | évolution du taux à 3 mois sur 3 mois | les hausses de la Fed pèsent souvent sur l'or |
| Dollar | évolution sur un mois | dollar fort, or souvent en baisse |
| Peur des marchés (VIX) | niveau (20 = normal) | valeur refuge lors des crises |
| Inflation | niveau sur un an | protection contre l'inflation |
| Chômage | évolution sur six mois | annonce souvent des baisses de taux |
| Risque géopolitique | niveau (100 = moyenne 1985-2019) | guerres et tensions poussent vers les refuges |
| Pétrole, actions américaines | évolution sur un mois | inflation, appétit pour le risque |
| Créations d'emplois | dernier mois publié (0 si pas encore connu) | un marché du travail faible fait espérer des baisses de taux |
| Tensions Moyen-Orient, Russie-Ukraine, Chine-Taïwan | niveau mensuel par région | refuge ; achats d'or des banques centrales après 2022 |
| Argent métal | évolution sur un mois | les deux métaux évoluent souvent ensemble |
f[o + 11] = b((v("taux10", i) - v("inflation", i) - 1) / 1.5); // taux réel : taux moins inflation
f[o + 13] = b(lrm("dollar", 20) / 0.02); // le dollar se renforce-t-il ?
f[o + 17] = b((v("geopolitique", i) - 100) / 60); // risque géopolitique
Un bug instructif rencontré en écrivant ce code : dans la boucle, une variable de comptage portait le même nom (m) que les séries économiques, et les masquait. Le paramètre s'appelle désormais macro.
Quatre entraînements par cas (60 IA, 120 générations), comparés sur la période de test jamais vue (mesure faite avec les 10 premiers critères) :
| Période de test | Cours seul | Cours + économie | Acheter et garder |
|---|---|---|---|
| 2019-2026 | 14,9 %/an (14,1 à 16,1) | 12,1 %/an (8,2 à 17,2) | 16,4 %/an |
| 2013-2026 | 5,7 %/an (5,0 à 6,7) | 3,8 %/an (2,5 à 7,2) | 6,8 %/an |
Avec l'économie, l'IA réussit mieux sur l'entraînement (15,7 % au lieu de 14,0 % par an pour la première coupure), mais moins bien sur le test, et de façon plus irrégulière. Plus d'informations, c'est aussi plus de façons d'apprendre le passé par cœur : le surapprentissage augmente.
Le panneau de contexte de la page mesure le « lien observé » : la corrélation entre les variations sur 21 séances de chaque indicateur et celles de l'or, de 2001 à aujourd'hui. Seuls l'argent métal (+0,70) et le dollar (−0,45) ont un lien net et régulier ; le taux de la Fed suit de loin (−0,18). L'inflation, le VIX, le pétrole, le chômage et les tensions géopolitiques, régionales comprises, n'en ont presque pas mois par mois : leur effet existe lors de certaines crises, pas de façon régulière. Et un lien n'est pas une prévision : l'argent et le dollar bougent en même temps que l'or, pas avant.
Un réseau de neurones ne dit pas pourquoi il décide. On peut l'interroger de l'extérieur : sur chaque jour de la période de test, on « neutralise » un critère à la fois (on le remet à sa valeur moyenne, 0) et on regarde si la décision change. La part des jours où elle change mesure l'importance du critère.
const base = choix(act(e), evo.vente);
for (let k = 0; k < nf; k++) {
const e2 = e.slice(); e2[k] = 0; // critère neutralisé
if (choix(act(e2), evo.vente) !== base) changes[k]++; // la décision change-t-elle ?
}
L'avis du jour utilise la même idée sur la dernière séance : l'IA donne sa décision (acheter, rester à l'écart, vendre), et les critères dont le retrait réduit le plus l'avance de cette décision sur les autres sont présentés avec les vrais chiffres du jour (« or 12 % sous son plus haut d'un an », « taux de la Fed 4,02 % »…). C'est un avis appris sur le passé, accompagné de son résultat sur la période de test, pas un conseil.
Une bougie résume une période avec quatre prix : ouverture, plus haut, plus bas, clôture. Le script récupère ces quatre valeurs pour chaque séance ; quand Yahoo ne les a pas (752 séances anciennes, surtout avant 2010), la bougie se réduit à un trait au cours de clôture.
Pour afficher des bougies par semaine ou par mois, on regroupe les séances : la première ouverture, le plus haut des plus hauts, le plus bas des plus bas, la dernière clôture. La semaine est repérée par son lundi.
const k = cle(H.dates[i]), b = bougies[bougies.length - 1];
if (b && b.k === k) { b.i1 = i; b.h = Math.max(b.h, HAU[i]); b.l = Math.min(b.l, BAS[i]); b.c = C[i]; }
else bougies.push({ k, i0: i, i1: i, o: OUV[i], h: HAU[i], l: BAS[i], c: C[i] });
Le cours en direct complète la bougie du jour : toutes les 30 secondes, les cours minute par minute de la séance donnent l'ouverture, le plus haut et le plus bas, et le dernier cours sert de clôture provisoire. Si la séance n'est pas encore dans l'historique (reconstruit toutes les 12 heures), la bougie est ajoutée au bout du graphique, entourée en or et marquée « en direct ». En simulation, les cours minute par minute sont aussi regroupés en bougies de 5 minutes.
Deux façons de poser la question, avec deux réponses différentes.
L'analyse technique donne des noms à certaines formes de bougies : le marteau (longue mèche basse, censé annoncer une hausse), l'étoile filante (longue mèche haute, censée annoncer une baisse), l'avalement (une bougie qui « englobe » la précédente), le doji (ouverture et clôture presque égales)… La page les détecte sur chaque séance, puis compare ce que fait l'or le lendemain avec un jour ordinaire, sur 2010-2018 puis sur 2019-2026.
["Marteau", "hausse", (i) => Math.abs(corps(i)) > 0 && mb(i) >= 2 * Math.abs(corps(i)) && mh(i) <= 0.3 * Math.abs(corps(i))],
// … pour chaque figure et chaque période : nombre de cas, variation moyenne le lendemain, part de hausses,
// et écart avec un jour ordinaire rapporté à sa marge d'erreur (« t »).
const stable = Math.sign(p1.t) === Math.sign(p2.t) && Math.abs(p1.t) > 2 && Math.abs(p2.t) > 2;
| Figure | Censée annoncer | Lendemain 2010-2018 | Lendemain 2019-2026 |
|---|---|---|---|
| Marteau | hausse | −0,47 % (67 cas) | +0,55 % (19 cas) |
| Avalement baissier | baisse | −0,24 % (84 cas) | +0,19 % (103 cas) |
| Étoile filante | baisse | +0,34 % (64 cas) | +0,56 % (16 cas) |
| Doji, avalement haussier, 3 vertes, 3 rouges… | – | comme un jour ordinaire | |
Aucune figure ne tient sur les deux périodes : le marteau et l'avalement baissier changent de sens, l'étoile filante fait l'inverse de ce qu'elle annonce, sur peu de cas. Avec une quarantaine de mesures, quelques écarts « remarquables » apparaissent de toute façon par hasard. La carte « Les bougies prédisent-elles l'avenir ? » de la page refait ce calcul en direct sur les données à jour.
Plutôt que des figures toutes faites, l'option « forme des bougies » donne à l'IA cinq mesures brutes de la bougie du jour, et la laisse les combiner avec le reste :
| Critère | Calcul |
|---|---|
| Corps | (clôture − ouverture) / amplitude : de −1 (toute rouge) à +1 (toute verte) |
| Mèche haute, mèche basse | taille de chaque mèche, en part de l'amplitude |
| Écart à l'ouverture | ouverture du jour comparée à la clôture de la veille (le « gap ») |
| Amplitude du jour | (plus haut − plus bas) / cours, comparée à la volatilité habituelle |
const O = bg.ouverture[i], Hh = bg.haut[i], L = bg.bas[i], amp = Hh - L;
if (amp > 0) { // bougie sans ouverture/haut/bas connus : zéros
f[q] = borne((c[i] - O) / amp); // corps
f[q + 1] = borne(((Hh - Math.max(O, c[i])) / amp) * 2 - 1); // mèche haute
f[q + 2] = borne(((Math.min(O, c[i]) - L) / amp) * 2 - 1); // mèche basse
f[q + 4] = borne((amp / c[i]) / (vol || 0.01) - 1.5); // amplitude du jour
}
if (i > 0) f[q + 3] = borne((O / c[i - 1] - 1) / 0.005); // écart à l'ouverture
Résultat sur 48 entraînements (60 IA, 120 générations), quatre coupures différentes, rendement par an sur la période de test jamais vue :
| Période de test | Cours seul | Cours + forme des bougies | Acheter et garder |
|---|---|---|---|
| 2013-2026 (8 essais par cas) | 5,4 % | 6,2 % | 6,8 % |
| 2016-2026 (4 essais) | 11,2 % | 12,5 % | 13,4 % |
| 2019-2026 (8 essais) | 13,5 % | 16,7 % | 16,4 % |
| 2021-2026 (4 essais) | 12,6 % | 15,8 % | 14,1 % |
La forme des bougies améliore le résultat sur la période de test pour les quatre coupures : l'écart moyen avec acheter et garder passe de −1,7 à −0,4 point par an. Et ce n'est pas du surapprentissage : le résultat sur l'entraînement, lui, ne monte pas (il baisse même légèrement). L'information sert donc pour l'avenir, pas seulement pour le passé.
Mais restons mesurés : une troisième série de 16 essais donne un écart de −1,6 point par an au lieu de −0,4. L'apport des bougies est réel mais modeste, et une partie de l'écart vient du hasard des entraînements. En moyenne, l'IA ne bat toujours pas acheter et garder : elle s'en approche, certains essais le battent, d'autres non.
Dernière question : en donnant à l'IA à la fois la forme des bougies et les 15 critères économiques, prédit-elle mieux ? Seize essais par cas :
| Période de test | Bougies seules | Bougies + économie | Acheter et garder |
|---|---|---|---|
| 2013-2026 | 5,5 % | 4,0 % | 6,8 % |
| 2016-2026 | 10,6 % | 3,9 % | 13,4 % |
| 2019-2026 | 13,9 % | 10,2 % | 16,4 % |
| 2021-2026 | 14,2 % | 4,8 % | 14,1 % |
| Écart moyen avec le marché | −1,6 point/an | −7,0 points/an |
Avec l'économie en plus, le résultat sur l'entraînement monte (15,7 % au lieu de 14,6 % par an), mais il s'effondre sur la période de test : aucun des 16 essais ne bat le marché. Avec 33 entrées pour quelques milliers de séances, l'IA trouve dans le passé des coïncidences entre l'or et l'économie qui ne se reproduisent pas. Plus d'informations n'est pas toujours mieux : c'est la leçon centrale de cette page. D'où les réglages par défaut : forme des bougies cochée, économie décochée.
NEAT fait évoluer une population de réseaux et ne leur donne qu'une note : le rendement sur toute la période d'entraînement. PPO (Proximal Policy Optimization, apprentissage par renforcement) fait apprendre un seul réseau par gradient, et juge chaque décision : la récompense du jour est ce que la position a rapporté jusqu'au lendemain, moins les frais. « Proximale » : à chaque mise à jour, la politique ne change que légèrement, ce qui rend l'apprentissage stable.
Le script scripts/ppo_or.py (PyTorch) reprend exactement les conditions de la page : mêmes 15 indicateurs (cours + forme des bougies, recopiés à l'identique de JavaScript — vérifié : écart nul sur les 6 550 séances), même position en entrée, mêmes frais, mêmes coupures. Il s'entraîne sur des fenêtres d'un an tirées au hasard dans la période d'entraînement, 16 à la fois.
p = positions[act[t, e]]
r = -FRAIS * abs(p - pos[e]) + p * math.log(c[jour[e] + 1] / c[jour[e]]) # ce que la position a rapporté
rec[t, e] = r * 100 # en %, pour le gradient
Résultat sur la période de test jamais vue, 4 essais par coupure (400 000 décisions d'entraînement chacun, environ 30 secondes) :
| Période de test | Acheter et garder | NEAT (moyenne) | PPO (moyenne) | PPO bat le marché |
|---|---|---|---|---|
| 2013-2026 | 6,8 % | 5,9 % | 7,0 % | 3/4 |
| 2016-2026 | 13,5 % | 11,6 % | 14,7 % | 3/4 |
| 2019-2026 | 16,5 % | 15,8 % | 15,8 % | 2/4 |
| 2021-2026 | 14,3 % | 15,0 % | 16,9 % | 4/4 |
| Écart moyen avec le marché | −0,7 point/an | +0,8 point/an | 12/16 |
PPO fait mieux que NEAT sur trois coupures sur quatre, et un peu mieux que le marché en moyenne. Son comportement explique pourquoi : il reste à l'achat 90 à 98 % du temps et ne sort du marché que quelques jours par an. Il a surtout appris qu'acheter et garder l'or fonctionne, avec quelques sorties. Il surapprend aussi moins : sur l'entraînement, il fait moins que NEAT (par exemple 22-23 % par an contre 25 % pour la coupure 2012), mais mieux sur la suite.
Avec la vente à découvert autorisée, l'écart moyen monte à +1,4 point par an, mais devient très irrégulier (de 3,9 % à 27,7 % par an pour la même coupure) : parier sur la baisse de l'or a rarement payé sur 25 ans.
La page refait les calculs du réseau PPO en JavaScript à partir de ses poids exportés (or-ppo.json) : on peut afficher chacune des 16 IA PPO sur les graphiques, lire son avis du jour et la faire jouer en temps réel. Vérifié : ses décisions dans le navigateur sont identiques à celles de Python sur les 6 349 séances.
La page interroge le relais toutes les 30 secondes. Pour décider, l'IA a besoin de ses 10 indicateurs « du jour » : on prend l'historique et on remplace la clôture d'aujourd'hui par le cours en direct, comme si la séance se terminait maintenant.
const cours = Array.from(C);
if (H.dates[N - 1] === auj) cours[N - 1] = prix; else cours.push(prix); // clôture provisoire
const f = Or.indicateurs(cours.slice(-300));
return Or.decider(Or.reseau(directEtat.cerveau), f, Math.min(cours.length, 300) - 1, directEtat.ia.pos, directEtat.vente);
Par défaut, l'IA décide une fois par jour, à la première mise à jour d'une nouvelle séance, comme pendant son entraînement. L'option « à chaque mise à jour » la fait réagir toutes les 30 secondes : plus spectaculaire, mais elle n'a jamais été entraînée à ce rythme et risque de payer beaucoup de frais.
L'état de la simulation (positions, gains, journal, courbe) est gardé dans votre navigateur : la simulation reprend à chaque visite. Pendant que la page est fermée, rien ne tourne ; au retour, les portefeuilles rattrapent d'un coup la variation du cours.
En temps réel, on ne raisonne plus en « capital multiplié » mais en euros gagnés ou perdus sur une exposition fixe, comme chez un courtier. Avec 1 000 000 € d'exposition et un levier ×20, le courtier bloque 50 000 € de marge ; à ×100, seulement 10 000 €. Le gain ou la perte, lui, dépend uniquement de l'exposition :
p.pnl += directEtat.expo * p.pos * (prix / p.prix - 1); // gain ou perte depuis la dernière mise à jour
if (p.pnl <= -directEtat.expo / directEtat.levier) { // les pertes ont mangé toute la marge
p.liquide = true; p.pos = 0; // appel de marge : position fermée
}
| Exposition 1 000 000 € | Marge | Mouvement de l'or qui efface la marge |
|---|---|---|
| Levier ×5 | 200 000 € | 20 % |
| Levier ×20 | 50 000 € | 5 % |
| Levier ×100 | 10 000 € | 1 % |
Le gain ou la perte de chaque journée se calcule en retenant le résultat cumulé au premier cours de chaque nouvelle séance : la différence avec la séance suivante (ou avec maintenant) donne la journée. Sur l'historique, la page fait le même calcul pour chaque jour de la période de test et affiche la pire et la meilleure journée. Avec 1 000 000 € exposés, la pire journée récente dépasse −100 000 € : plus que la marge entière à ×20.
| Simplification | Dans la réalité |
|---|---|
| Ordres exécutés exactement au cours de clôture | Le prix obtenu s'écarte un peu (glissement), surtout les jours agités. |
| Un seul frais fixe par changement de position | Écart achat-vente variable, commissions, et frais de financement chaque nuit sur les positions à levier. |
| Contrat à terme continu (GC=F) | Les contrats expirent et sont « roulés » sur le suivant, ce qui crée de petits sauts de prix. |
| Montants en euros sans taux de change | L'or est coté en dollars : un investisseur en euros subit aussi les variations de l'euro-dollar. |
| Cours différé de quelques minutes | Les courtiers donnent le cours en temps réel. |
| Taux réel calculé comme taux à 10 ans moins l'inflation passée | Les professionnels utilisent le rendement des obligations indexées sur l'inflation (TIPS). |
| Des dates de publication fixes (le 5, le 8, le 15 du mois suivant) | Les dates réelles varient de quelques jours. |
| Chiffres économiques dans leur version actuelle | Inflation et surtout créations d'emplois sont révisées après coup : le chiffre connu à l'époque différait parfois de celui utilisé ici. |
| Figures de bougies définies par des seuils simples | Les manuels d'analyse technique en donnent des définitions variables, souvent avec le contexte (tendance précédente). |
| Une seule période de test | Un résultat sérieux se vérifie sur plusieurs découpages et plusieurs entraînements, pas un seul. |
| Fichier | Contenu |
|---|---|
web/trading-or.html | La page : indicateurs, réseau, simulation, NEAT (Web Worker), graphiques, temps réel et levier |
serveur/or-serveur.js | Relais Yahoo Finance avec cache, et données économiques (/or-api/macro) (service pm2 or-temps-reel, port 3078, route nginx /or-api/) |
scripts/maj_marche.py | Construit web/or-macro.json (or en bougies, économie, emplois, géopolitique par région, argent métal) et web/or.json ; lancé par le relais toutes les 12 h |
scripts/ppo_or.py | Entraînement PPO (PyTorch, environnement .venv-shinobi) et export des 16 IA dans web/or-ppo.json |
scripts/cache/ | Séries du BLS déjà téléchargées (limite de 25 requêtes par jour) |
scripts/maj_or.py | Ancienne version, cours de l'or seul |
pm2 restart or-temps-reel # relancer le relais après une modification
.venv/bin/python scripts/maj_marche.py # reconstruire les données (or, économie, géopolitique)
./deploy.sh # publier les pages sur rdv-app.fr