Changer la fréquence
Les données arrivent rarement à la fréquence voulue. Les ticks arrivent à la milliseconde, un modèle veut des barres quotidiennes, un rapport veut des mois. Le rééchantillonnage regroupe une série temporelle en nouvelles périodes. Passer du fin au grossier (jours vers mois) est un sous-échantillonnage : chaque nouvelle période contient plusieurs anciennes observations, il faut donc dire comment les combiner. Passer du grossier au fin (semaines vers jours) est un sur-échantillonnage : il y a de nouvelles périodes sans données, il faut donc dire quoi y mettre.
import pandas as pd
daily = pd.Series(
[100.0, 101, 103, 102, 104, 105, 103, 106],
index=pd.bdate_range("2026-02-25", periods=8), # Wed 25 Feb ... Fri 6 Mar
name="close",
)
print(daily.resample("ME").last()) # the last price of each month ("ME" = month end)
# 2026-02-28 103.0
# 2026-03-31 106.0
# Freq: ME, Name: close, dtype: float64
print(daily.resample("W-FRI").last()) # the last price of each week, weeks ending on Friday
# 2026-02-27 103.0
# 2026-03-06 106.0
# Freq: W-FRI, Name: close, dtype: float64Choisir l'agrégation
series.resample("ME") seul ne fait rien : il décrit seulement les périodes. L'agrégation qui suit décide de la valeur et doit correspondre à la signification des données. Un prix est un instantané, donc un mois est représenté par sa valeur last (ou first). Un volume est une quantité échangée, donc un mois est la sum. Une amplitude utilise max et min. Les étiquettes suivent la règle : "ME" étiquette un mois par son dernier jour calendaire, même si c'est un samedi, et "W-FRI" étiquette une semaine par son vendredi.
volume = pd.Series([10, 20, 30, 40, 50, 60, 70, 80], index=daily.index)
print(volume.resample("ME").sum().to_dict())
# {Timestamp('2026-02-28 00:00:00'): 60, Timestamp('2026-03-31 00:00:00'): 300}
# Several summaries at once
print(daily.resample("ME").agg(["first", "last", "max"]))
# first last max
# 2026-02-28 100.0 103.0 103.0
# 2026-03-31 102.0 106.0 106.0Barres à partir de ticks, et sur-échantillonnage
Les graphiques et les modèles utilisent des barres OHLC : l'ouverture (premier prix), le plus haut, le plus bas et la clôture (dernier prix) de chaque période. resample("D").ohlc() les construit à partir de prix intrajournaliers en un appel. Les jours calendaires sans aucune transaction, comme les week-ends, apparaissent quand même en lignes de NaN : terminez par dropna() si vous ne voulez que les jours négociés. Le sur-échantillonnage va dans l'autre sens : resample("D").ffill() répète la dernière valeur connue les jours sans données, ce que signifie vraiment un prix coté chaque semaine. N'utilisez jamais bfill pour des prix : il recopie une valeur future vers le passé et fait fuiter l'information de demain dans aujourd'hui.
times = ["2026-03-05 09:30", "2026-03-05 11:00", "2026-03-05 15:59",
"2026-03-09 09:30", "2026-03-09 12:00", "2026-03-09 15:59"]
ticks = pd.Series([100.0, 101.5, 99.8, 100.7, 102.0, 101.0], index=pd.to_datetime(times))
bars = ticks.resample("D").ohlc()
print(bars)
# open high low close
# 2026-03-05 100.0 101.5 99.8 99.8
# 2026-03-06 NaN NaN NaN NaN
# 2026-03-07 NaN NaN NaN NaN
# 2026-03-08 NaN NaN NaN NaN
# 2026-03-09 100.7 102.0 100.7 101.0
print(bars.dropna().index.strftime("%d %b").tolist()) # ['05 Mar', '09 Mar'] only the days that traded# Upsampling: observations on the 2nd, 6th and 10th, spread over every day with ffill
weekly = pd.Series([100.0, 103.0, 101.0], index=pd.to_datetime(["2026-03-02", "2026-03-06", "2026-03-10"]))
print(weekly.resample("D").ffill().tolist())
# [100.0, 100.0, 100.0, 100.0, 103.0, 103.0, 103.0, 103.0, 101.0]
print(int(weekly.resample("D").mean().isna().sum())) # 6 without a fill rule the new days are empty"ME", utilisez ffill (jamais bfill) pour le sur-échantillonnage, et décalez un signal mensuel avant de l'utiliser sur des données quotidiennes.series.resample(règle)décrit les périodes ("D","W-FRI","ME","h") ; l'agrégation qui suit calcule les valeurs.- Prix :
lastouohlc(); volumes :sum; les périodes vides apparaissent enNaN, quedropna()retire. - Le sur-échantillonnage demande une règle de remplissage :
ffill()répète la dernière valeur connue ; jamaisbfill()pour des prix, il fait fuiter le futur.
À suivre : les fenêtres glissantes, des statistiques comme les moyennes mobiles, calculées sur une fenêtre glissante des périodes récentes.
Lab : ce qui est noté
- Prendre le dernier prix de chaque mois avec
month_end_close25 pts - Totaliser le volume de chaque semaine avec
weekly_volume25 pts - Construire des barres quotidiennes à partir de prix intrajournaliers avec
daily_ohlc25 pts - Étaler des observations irrégulières sur chaque jour avec
fill_to_daily25 pts