Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
"execution_count": 1,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:21.060809Z",
"iopub.status.busy": "2026-10-22T13:17:21.060554Z",
"iopub.status.idle": "2026-10-22T13:17:23.247097Z",
"shell.execute_reply": "2026-10-22T13:17:23.245577Z"
"iopub.execute_input": "2026-10-24T04:12:33.553664Z",
"iopub.status.busy": "2026-10-24T04:12:33.553380Z",
"iopub.status.idle": "2026-10-24T04:12:35.229230Z",
"shell.execute_reply": "2026-10-24T04:12:35.228121Z"
}
},
"outputs": [
Expand Down Expand Up @@ -76,10 +76,10 @@
"execution_count": 2,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:23.287006Z",
"iopub.status.busy": "2026-10-22T13:17:23.286708Z",
"iopub.status.idle": "2026-10-22T13:17:23.627537Z",
"shell.execute_reply": "2026-10-22T13:17:23.623427Z"
"iopub.execute_input": "2026-10-24T04:12:35.265950Z",
"iopub.status.busy": "2026-10-24T04:12:35.265681Z",
"iopub.status.idle": "2026-10-24T04:12:35.404440Z",
"shell.execute_reply": "2026-10-24T04:12:35.402989Z"
}
},
"outputs": [
Expand Down Expand Up @@ -114,10 +114,10 @@
"execution_count": 3,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:23.631912Z",
"iopub.status.busy": "2026-10-22T13:17:23.631578Z",
"iopub.status.idle": "2026-10-22T13:17:24.549406Z",
"shell.execute_reply": "2026-10-22T13:17:24.547933Z"
"iopub.execute_input": "2026-10-24T04:12:35.407252Z",
"iopub.status.busy": "2026-10-24T04:12:35.406810Z",
"iopub.status.idle": "2026-10-24T04:12:35.847696Z",
"shell.execute_reply": "2026-10-24T04:12:35.846442Z"
}
},
"outputs": [
Expand Down Expand Up @@ -269,10 +269,10 @@
"execution_count": 4,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:24.552907Z",
"iopub.status.busy": "2026-10-22T13:17:24.552474Z",
"iopub.status.idle": "2026-10-22T13:17:24.584673Z",
"shell.execute_reply": "2026-10-22T13:17:24.583560Z"
"iopub.execute_input": "2026-10-24T04:12:35.850233Z",
"iopub.status.busy": "2026-10-24T04:12:35.849932Z",
"iopub.status.idle": "2026-10-24T04:12:35.863796Z",
"shell.execute_reply": "2026-10-24T04:12:35.862272Z"
}
},
"outputs": [
Expand Down Expand Up @@ -363,10 +363,10 @@
"execution_count": 5,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:24.588722Z",
"iopub.status.busy": "2026-10-22T13:17:24.588454Z",
"iopub.status.idle": "2026-10-22T13:17:24.597880Z",
"shell.execute_reply": "2026-10-22T13:17:24.596186Z"
"iopub.execute_input": "2026-10-24T04:12:35.866402Z",
"iopub.status.busy": "2026-10-24T04:12:35.866192Z",
"iopub.status.idle": "2026-10-24T04:12:35.874005Z",
"shell.execute_reply": "2026-10-24T04:12:35.872359Z"
}
},
"outputs": [
Expand Down Expand Up @@ -427,10 +427,10 @@
"execution_count": 6,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:24.601591Z",
"iopub.status.busy": "2026-10-22T13:17:24.601274Z",
"iopub.status.idle": "2026-10-22T13:17:24.649139Z",
"shell.execute_reply": "2026-10-22T13:17:24.635384Z"
"iopub.execute_input": "2026-10-24T04:12:35.876820Z",
"iopub.status.busy": "2026-10-24T04:12:35.876515Z",
"iopub.status.idle": "2026-10-24T04:12:35.901072Z",
"shell.execute_reply": "2026-10-24T04:12:35.899848Z"
}
},
"outputs": [
Expand Down Expand Up @@ -501,10 +501,10 @@
"execution_count": 7,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:24.656229Z",
"iopub.status.busy": "2026-10-22T13:17:24.655979Z",
"iopub.status.idle": "2026-10-22T13:17:28.045972Z",
"shell.execute_reply": "2026-10-22T13:17:28.044232Z"
"iopub.execute_input": "2026-10-24T04:12:35.903767Z",
"iopub.status.busy": "2026-10-24T04:12:35.903533Z",
"iopub.status.idle": "2026-10-24T04:12:37.514787Z",
"shell.execute_reply": "2026-10-24T04:12:37.513118Z"
}
},
"outputs": [
Expand Down Expand Up @@ -577,10 +577,10 @@
"execution_count": 8,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:28.049888Z",
"iopub.status.busy": "2026-10-22T13:17:28.049619Z",
"iopub.status.idle": "2026-10-22T13:17:30.168995Z",
"shell.execute_reply": "2026-10-22T13:17:30.167141Z"
"iopub.execute_input": "2026-10-24T04:12:37.517748Z",
"iopub.status.busy": "2026-10-24T04:12:37.517531Z",
"iopub.status.idle": "2026-10-24T04:12:39.073017Z",
"shell.execute_reply": "2026-10-24T04:12:39.071557Z"
}
},
"outputs": [
Expand Down Expand Up @@ -629,10 +629,10 @@
"execution_count": 9,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:30.179388Z",
"iopub.status.busy": "2026-10-22T13:17:30.178912Z",
"iopub.status.idle": "2026-10-22T13:17:30.216234Z",
"shell.execute_reply": "2026-10-22T13:17:30.207410Z"
"iopub.execute_input": "2026-10-24T04:12:39.076003Z",
"iopub.status.busy": "2026-10-24T04:12:39.075535Z",
"iopub.status.idle": "2026-10-24T04:12:39.099475Z",
"shell.execute_reply": "2026-10-24T04:12:39.098012Z"
}
},
"outputs": [
Expand Down Expand Up @@ -684,10 +684,10 @@
"execution_count": 10,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:30.219641Z",
"iopub.status.busy": "2026-10-22T13:17:30.219308Z",
"iopub.status.idle": "2026-10-22T13:17:34.907964Z",
"shell.execute_reply": "2026-10-22T13:17:34.906856Z"
"iopub.execute_input": "2026-10-24T04:12:39.102496Z",
"iopub.status.busy": "2026-10-24T04:12:39.102278Z",
"iopub.status.idle": "2026-10-24T04:12:42.844931Z",
"shell.execute_reply": "2026-10-24T04:12:42.842380Z"
}
},
"outputs": [
Expand Down Expand Up @@ -735,10 +735,10 @@
"execution_count": 11,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:34.922090Z",
"iopub.status.busy": "2026-10-22T13:17:34.921668Z",
"iopub.status.idle": "2026-10-22T13:17:35.011262Z",
"shell.execute_reply": "2026-10-22T13:17:35.010467Z"
"iopub.execute_input": "2026-10-24T04:12:42.860161Z",
"iopub.status.busy": "2026-10-24T04:12:42.858975Z",
"iopub.status.idle": "2026-10-24T04:12:42.928299Z",
"shell.execute_reply": "2026-10-24T04:12:42.923480Z"
}
},
"outputs": [
Expand Down Expand Up @@ -774,10 +774,10 @@
"execution_count": 12,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:35.068968Z",
"iopub.status.busy": "2026-10-22T13:17:35.068435Z",
"iopub.status.idle": "2026-10-22T13:17:58.591408Z",
"shell.execute_reply": "2026-10-22T13:17:58.577776Z"
"iopub.execute_input": "2026-10-24T04:12:42.932960Z",
"iopub.status.busy": "2026-10-24T04:12:42.932619Z",
"iopub.status.idle": "2026-10-24T04:12:58.660250Z",
"shell.execute_reply": "2026-10-24T04:12:58.648033Z"
}
},
"outputs": [
Expand Down Expand Up @@ -831,7 +831,7 @@
"\n",
"La validation croisée temporelle (5 découpes entraînées sur le passé, évaluées sur le futur immédiat) confirme la tendance : Naive Bayes 50,78 % en moyenne (47,43 % à 54,73 % selon la découpe), régression logistique 52,57 % (50,08 % à 57,71 %) — autour du hasard, jamais nettement au-dessus de la classe dominante.\n",
"\n",
"Cette lecture est **cohérente avec le backtest de la section 9** : la stratégie retire **77,19 %** sur la fenêtre, mais le buy & hold équipondéré du même univers en retire **111,67 %** (écart **-34,48 %**). Le rendement positif vient du panier tech 2017-2019 (le beta du panier), pas du signal — le signal, lui, reste sous la baseline. C'est l'attente d'un pipeline où les « news » sont fabriquées depuis les prix passés (section 2) : le classifieur ré-apprend la transformation prix → texte → prix, une circularité sans bord prédictif. Notons enfin que le backtest balaye toute la fenêtre, période d'entraînement comprise : il illustre le pipeline, il n'évalue pas le classifieur hors échantillon.\n",
"Cette lecture est **cohérente avec le backtest de la section 9** : la stratégie retire **77,19 %** sur la fenêtre, mais le buy & hold équipondéré du même univers et de la même fenêtre — ancré sur la première barre où la stratégie peut trader, du 2017-06-30 au 2019-12-31 — en retire **86,08 %**, soit un écart de **-8,89 %**. Le rendement positif vient du panier tech 2017-2019 (le beta du panier), pas du signal — le signal, lui, reste sous la baseline. C'est l'attente d'un pipeline où les « news » sont fabriquées depuis les prix passés (section 2) : le classifieur ré-apprend la transformation prix → texte → prix, une circularité sans bord prédictif. Notons enfin que le backtest balaye toute la fenêtre, période d'entraînement comprise : il illustre le pipeline, il n'évalue pas le classifieur hors échantillon.\n",
"\n",
"Trois leçons à retenir :\n",
"1. **Sur données temporelles, le split aléatoire surestime l'accuracy** : il met des jours voisins (fortement autocorrélés) des deux côtés de la coupure et mesure un effet de voisinage, pas une prédiction.\n",
Expand All @@ -851,10 +851,10 @@
"execution_count": 13,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:58.599277Z",
"iopub.status.busy": "2026-10-22T13:17:58.598930Z",
"iopub.status.idle": "2026-10-22T13:17:58.736341Z",
"shell.execute_reply": "2026-10-22T13:17:58.734878Z"
"iopub.execute_input": "2026-10-24T04:12:58.703593Z",
"iopub.status.busy": "2026-10-24T04:12:58.703292Z",
"iopub.status.idle": "2026-10-24T04:12:58.832520Z",
"shell.execute_reply": "2026-10-24T04:12:58.830997Z"
}
},
"outputs": [
Expand Down Expand Up @@ -919,10 +919,10 @@
"execution_count": 14,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:58.739173Z",
"iopub.status.busy": "2026-10-22T13:17:58.738930Z",
"iopub.status.idle": "2026-10-22T13:17:58.778426Z",
"shell.execute_reply": "2026-10-22T13:17:58.776680Z"
"iopub.execute_input": "2026-10-24T04:12:58.835620Z",
"iopub.status.busy": "2026-10-24T04:12:58.835323Z",
"iopub.status.idle": "2026-10-24T04:12:58.889045Z",
"shell.execute_reply": "2026-10-24T04:12:58.886922Z"
}
},
"outputs": [
Expand Down Expand Up @@ -1020,10 +1020,10 @@
"execution_count": 15,
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-22T13:17:58.781608Z",
"iopub.status.busy": "2026-10-22T13:17:58.781300Z",
"iopub.status.idle": "2026-10-22T13:18:02.290030Z",
"shell.execute_reply": "2026-10-22T13:18:02.288565Z"
"iopub.execute_input": "2026-10-24T04:12:58.894756Z",
"iopub.status.busy": "2026-10-24T04:12:58.894429Z",
"iopub.status.idle": "2026-10-24T04:12:46.494682Z",
"shell.execute_reply": "2026-10-24T04:12:46.493210Z"
}
},
"outputs": [
Expand All @@ -1037,8 +1037,9 @@
"Valeur finale: $177,190.59\n",
"Return total: 77.19%\n",
"Nombre de trades: 404\n",
"Buy & hold (équipondéré, même univers/fenêtre) : 111.67%\n",
"Écart stratégie - buy&hold : -34.48%\n"
"Fenêtre de la stratégie : 2017-06-30 au 2019-12-31\n",
"Buy & hold (équipondéré, même univers et même fenêtre) : 86.08%\n",
"Écart stratégie - buy&hold : -8.89%\n"
]
}
],
Expand Down Expand Up @@ -1130,13 +1131,22 @@
"print(f\"Valeur finale: ${backtest_results['final_value']:,.2f}\")\n",
"print(f\"Return total: {backtest_results['return']:.2%}\")\n",
"print(f\"Nombre de trades: {len(backtest_results['trades'])}\")\n",
"# Baseline buy-and-hold équipondéré sur la même fenêtre / le même univers\n",
"# (recette ai-01 c.45, #8777 CHANGES_REQUESTED) : sans ce comparateur, le +77% isolé\n",
"# laisse croire que le classifieur de sentiment \"marche\", alors que l'accuracy est\n",
"# ~52% (≈ hasard). Le rendement vient de la direction cumulative + du beta du panier\n",
"# tech sur la fenêtre, pas du signal de sentiment.\n",
"bh = (closes.ffill().iloc[-1] / closes.ffill().iloc[0] - 1).mean()\n",
"print(f\"Buy & hold (équipondéré, même univers/fenêtre) : {bh:.2%}\")\n",
"# Baseline buy-and-hold équipondéré sur le même univers ET la même fenêtre que la\n",
"# stratégie (recette ai-01 c.45, #8777 CHANGES_REQUESTED) : sans ce comparateur, le\n",
"# +77% isolé laisse croire que le classifieur de sentiment \"marche\", alors que\n",
"# l'accuracy est ~52% (≈ hasard). Le rendement vient de la direction cumulative + du\n",
"# beta du panier tech sur la fenêtre, pas du signal de sentiment.\n",
"#\n",
"# Ancre = première barre où la stratégie peut trader (start_idx = 100), jamais\n",
"# l'indice 0 : ancré à 0, le buy & hold couvre 100 barres de plus que la stratégie et\n",
"# l'écart mélange écart de performance et écart de période (réserve mesurée par la\n",
"# revue Hermes du head 5e039ed1, corrigée ici).\n",
"bh_start_idx = 100\n",
"bh_entry = closes.ffill().iloc[bh_start_idx]\n",
"bh_exit = closes.ffill().iloc[-1]\n",
"bh = (bh_exit / bh_entry - 1).mean()\n",
"print(f\"Fenêtre de la stratégie : {closes.index[bh_start_idx].date()} au {closes.index[-1].date()}\")\n",
"print(f\"Buy & hold (équipondéré, même univers et même fenêtre) : {bh:.2%}\")\n",
"print(f\"Écart stratégie - buy&hold : {backtest_results['return'] - bh:+.2%}\")"
]
},
Expand All @@ -1148,6 +1158,11 @@
"\n",
"**Rappel d'objectif** : ce carnet ne teste pas le chemin « vraies news ». Les extensions ci-dessous changent la source des textes autant que le modèle — aucune n'est validée par les mesures précédentes, qui portent exclusivement sur des titres simulés depuis les prix.\n",
"\n",
"### Protocole d'évaluation\n",
"- **Flux de titres réel** : remplacer `simulate_news_headlines` par une API de news — tant que le texte dérive du prix, aucun modèle ne peut battre le hasard\n",
"- **Validation purgée** : blocs croissants avec purge autour de la coupure, pour couper l'autocorrélation résiduelle des fenêtres glissantes\n",
"- **Référence passive systématique** : tout backtest se lit contre un buy & hold équipondéré du même univers et de la même fenêtre\n",
"\n",
"### NLP Avancé\n",
"- **TF-IDF**: Pondération par importance des mots\n",
"- **Word Embeddings**: Word2Vec, GloVe pour capturer le contexte\n",
Expand Down
Loading