Maitrîser l'utilisation des dates en Python

"Le temps, c'est de l'argent", dit un vieux dicton. Dans le monde effréné de la finance, cela n'a jamais été aussi vrai. Les dates et les séquences temporelles sont le pouls des marchés financiers, influençant chaque décision, chaque analyse, chaque transaction. Que vous traquiez la performance d'un stock sur une décennie ou analysiez les fluctuations du marché minute par minute, une maîtrise précise des dates est absolument cruciale.

Dans cet épisode, nous dévoilerons les mystères de la manipulation des dates en Python, en vous offrant les clés pour naviguer avec aisance dans le temps.

Introduction aux dates en Python

Le module datetime

En Python, la gestion des dates est assurée principalement par le module datetime. Il propose des classes pour manipuler aussi bien des dates (année, mois, jour) que des instants précis (ajoutant heures, minutes, secondes).

Voici comment créer vos premiers objets date et datetime en Python:

import datetime

# Créer une date simple
d = datetime.date(2023, 8, 21)
print(d)  # Affiche "2023-08-21"

# Créer un instant précis (timestamp)
dt = datetime.datetime(2023, 8, 21, 14, 30)
print(dt)  # Affiche "2023-08-21 14:30:00"

Pour obtenir la date courante ou le moment précis actuel :

today = datetime.date.today()
print(today)  # Affiche la date d'aujourd'hui

now = datetime.datetime.now()
print(now)  # Affiche le moment précis actuel

2. Formats courants de dates

2.1 String

Les dates sont souvent représentées sous forme de chaînes de caractères, en particulier lorsqu'elles sont lues depuis des fichiers ou des bases de données.

date_string = "2023-08-21"

# Convertir un string en objet datetime
date_object = datetime.datetime.strptime(date_string, "%Y-%m-%d")
print(date_object)

# Un autre exemple avec jour/mois/année et heures:minutes
date_string2 = "21/08/2023 14:30"
date_object2 = datetime.datetime.strptime(date_string2, "%d/%m/%Y %H:%M")
print(date_object2)

2.2 Timestamp Unix

Le timestamp Unix représente le nombre de secondes (ou millisecondes) écoulées depuis le 1er janvier 1970, appelé "epoch". C'est un format compact et universel largement utilisé en finance.

import time

# Obtenir le timestamp actuel
timestamp = time.time()
print(timestamp)

# Conversion d'un timestamp vers datetime
date_from_timestamp = datetime.fromtimestamp(timestamp)
print(date_from_timestamp)

# Exemple avec millisecondes
timestamp_millis = timestamp * 1000
date_from_millis = datetime.fromtimestamp(timestamp_millis / 1000)
print(date_from_millis)

2.3 Résumé des types de date

Si nous souhaitons résumer, il existe majoritairement 4 formats pour stocker une date :

  • Le format chaîne de caractère exemple “2023-08-28” qui est de type string.
  • Le format timestamp par exemple 1693233091.2038012 qui est de type float et qui représente le nombre de secondes depuis 1970 (ou millisecondes).
  • Le format datetime qui est le format utilisé majoritairement utiliser par python pour stocker des dates avec les heures et secondes, exemple datetime.datetime(2023, 8, 21, 14, 30), cet objet est de type datetime.datetime.
  • Le format date qui est le format utilisé majoritairement utiliser par python pour stocker des dates sans heures ou secondes, exemple datetime.date(2023, 8, 21), cet objet est de type datetime.date.

3. Conversion entre les formats de dates

Naviguer entre les différents formats est un besoin courant.

# De datetime vers string
formatted_date = date_object.strftime("%Y-%m-%d")
print(formatted_date)  # "2023-08-21"

# Un autre format
formatted_date2 = date_object.strftime("%d %B %Y")
print(formatted_date2)  # "21 August 2023"

# De datetime vers timestamp (secondes depuis l'epoch)
timestamp_from_date = date_object.timestamp()
print(timestamp_from_date)

# Et en millisecondes
timestamp_millis_from_date = timestamp_from_date * 1000
print(timestamp_millis_from_date)

Vous avez ci-dessus plusieurs exemples de conversion d’un format de date à un autre. Ces exemples ne sont pas exhaustifs et il faudra vous renseigner en fonction de vos besoins.

4. Utilisation des dates avec Pandas

Après avoir exploré les bases de la manipulation des dates en Python, il est temps de passer à la vitesse supérieure en intégrant ces connaissances avec Pandas. Si vous êtes dans le monde de la finance, Pandas sera votre outil de prédilection pour une multitude de tâches, notamment le traitement des séries temporelles financières. Dans cet épisode, nous allons voir comment Pandas peut nous aider à manipuler des dates pour des cas très spécifiques liés à la finance, comme les séries temporelles des prix du Bitcoin (BTC).

4.1 Création du DataFrame et conversion du format de date

Pour ces exemples, nous allons charger notre DataFrame à parti d’un fichier csv déjà présenté lors de la formation précédente https://github.com/CryptoRobotFr/python-pour-la-finance/blob/main/BTC-USDT.csv. Ce csv représente l’évolution du prix du Bitcoin heure par heure sous le format OHLCV (Open, High, Low, Close, Volume).

df = pd.read_csv("BTC-USDT.csv")

date-formation-python0

Comme vous pouvez le remarquer, la colonne date est illisible. Cependant, si vous avez bien suivi la formation, le début de l’épisode, ce format devrait vous faire penser à quelque chose. Vous l’avez peut-être reconnu, mais ces dates sont des timestamp. Ce sont le nombre de millisecondes écoulées depuis 1970 (on peut reconnaître le fait que ce sont des millisecondes grâce au nombre de 0 à la fin).

Voici comment convertir les timestamp en datetime (plus lisible et surtout plus manipulable)

df = pd.read_csv("BTC-USDT.csv")
print(df["date"].dtype)
df["date"] = pd.to_datetime(df["date"], unit="ms")
print(df["date"].dtype)

date-formation-python1

Les dates sont tout de suite plus lisibles. Dans le code, nous avons également rajouté deux lignes de code permettant d’afficher le type de la colonne avant et après la transformation. Nous remarquons qu’avant la transformation la colonne était de type int et maintenant, elle est de type datetime.

Nous pouvons commencer à réaliser des manipulations sur les dates.

4.2 Extraction du Jour de la Semaine

Pandas rend facile l'extraction du jour de la semaine grâce à son attribut dayofweek.

df["weekday"] = df["date"].dt.weekday

date-formation-python2

Les jours de la semaine sont affichés de 0 à 6 avec 0 représentants le lundi et le 6 représentants le dimanche.

Si vous souhaitez les voir sous forme de string comme “Monday” il faudra faire ce que l’on appelle un mapping (faire correspondre une valeur à une autre) cela se fait à l’aide d’un dictionnaire et de la fonction pandas .map().

day_name_map = {
    0: 'Monday',
    1: 'Tuesday',
    2: 'Wednesday',
    3: 'Thursday',
    4: 'Friday',
    5: 'Saturday',
    6: 'Sunday'
}

df['weekday'] = df['weekday'].map(day_name_map)

4.3 Soustraction entre Deux Dates

Essayons désormais de vérifier que nous avons bien une heure entre chacune de données. Pour cela, nous pouvons pour chaque donnée vérifier l’écart entre la date de la valeur et de la valeur précédente.

df["date_diff"] = df["date"] - df["date"].shift(1)
print(df["date_diff"].value_counts())

Nous faisons ici simplement la différence entre la valeur de la colonne date avec la valeur de la colonne date de la valeur précédente grâce à shift(1). Nous affichons ensuite toutes les valeurs uniques et leur nombre d’occurrences associées.

date-formation-python3

On remarque que dans l’immense majorité des cas, nous avons bien une heure entre nos deux valeurs. Cependant, nous avons quelque cas particulier :

  • 26 cas sans aucun écart (peut être des doublons)
  • Plus ou moins 30 cas avec, au minimum deux heures de différences jusqu’à un maximum de plus d’un jour. Il peut être intéressant d’essayer de se renseigner sur la cause.

4.4 Regroupement par date

À partir de nos données, il serait intéressant de savoir si le volume d’échange moyen de bitcoin, varie en fonction du jour de la semaine.

Pour faire cela, nous pouvons essayer de regrouper nos données en fonction du jour de la semaine. Nous allons ici utiliser la fonction group_by() qui va nous permettre de regrouper nos données par jour de la semaine, puis la fonction agg() qui permet d’agréger nos données par rapport à la colonne groupée.

Cela se fait en une petite ligne de code :

df.groupby('weekday').agg({"volume": "mean"})

date-formation-python4

Comme on aurait pu l’attendre, le volume les jours de week-end (Samedi et Dimanche) sont bien inférieurs aux jours de la semaine. Près de 50% de volume en moins. Cela montre en partie que le majeur parti des échanges de Bitcoin sont réalisés par des professionnels qui ne traient que très peu pendant le week-end.

Mise en pratique

Pour mettre en pratique les concepts abordés dans cette partie, essayons de répondre à une question. Est-ce qu’il existe, comme on l’a vu avec le volume en fonction des jours de la semaine, des différences dans le comportement du Bitcoin en fonction des marchés financiers ouverts.

Nous pouvons par exemple prendre la bourse Européenne (Euronext), la bourse de New York (NYSE) et la bourse de Tokyo. La bourse Européenne est ouverte entre 9h et 17h sur le fuseau horaire de Paris. Nous vous laissons vous renseigner sur les horaires d’ouverture des autres bourses.

La première étape sera de créer une colonne par place boursière et d’afficher True si pour la ligne en question la place boursière est ouverte, False si ce n’est pas le cas.

Une fois que cela est fait, vous pouvez comparer le volume moyen en fonction de si la place boursière est ouverte ou non. Vous pouvez également comparer la variation moyenne d’une bougie en comparant par exemple la différence entre le high et le low de chaque bougie en pourcentage. Nous vous encourageons vraiment à faire vos propres analyses.

Un exemple de correction se trouve ici: https://github.com/RobotTraders/Python_For_Finance/blob/main/exercise_correction_chapter_8.ipynb