python-pour-finance/10-Plateforme-Quantopian/02-Bases-Méthodes-Algorith...

360 lines
16 KiB
Plaintext
Raw Permalink Normal View History

2023-08-21 15:12:19 +00:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Méthodes Algorithmiques de Base\n",
"\n",
"Testons notre stratégie de portefeuille technologique optimisé avec Quantopian !\n",
"\n",
"#### CE CODE NE FONCTIONNE QUE SUR L'IDE QUANTOPIAN. CHAQUE CELLULE CORRESPOND À UNE PARTIE DE LA VIDÉOCO. N'OUBLIEZ PAS DE REGARDER LES VIDÉOS POUR PLUS DE CLARTÉ SUR CE POINT !"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**initialize()**\n",
"\n",
"initialize() est appelé exactement une fois lorsque notre algorithme démarre et nécessite context en entrée.\n",
"\n",
"contaxt est un dictionnaire Python augmenté utilisé pour maintenir l'état pendant notre backtest ou durant notre trading en direct, et peut être référencé dans différentes parties de notre algorithme. context doit être utilisé à la place des variables globales dans l'algorithme. Les propriétés sont accessibles en utilisant la notation par points (context.some_property)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"** handle_data() **\n",
"\n",
"handle_data() est appelé une fois à la fin de chaque minute et nécessite le contexte et les données en entrée. Le contexte est une référence au même dictionnaire dans initialize() et les données sont un objet qui stocke plusieurs fonctions API."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Notre portefeuille optimisé d'actions technologiques\n",
"\n",
"Utilisons le portefeuille d'actions technologiques que nous avons calculé plus tôt. Gardez à l'esprit que handle_data() réajuste notre portefeuille chaque minute ! Cela peut être déraisonnable pour certains algorithmes, mais pour cet exemple, nous allons simplement continuer avec ces fonctions de base."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"def initialize(context):\n",
" # référence aux Actions Tech\n",
" context.aapl = sid(24)\n",
" context.csco = sid(1900)\n",
" context.amzn = sid(16841)\n",
"\n",
"def handle_data(context, data):\n",
" # Positions de notre optimisation de portefeuille !\n",
" order_target_percent(context.aapl, .27)\n",
" order_target_percent(context.csco, .20)\n",
" order_target_percent(context.amzn, .53)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Saisir les données actuelles"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### data.current()\n",
"data.current() peut être utilisé pour récupérer la valeur la plus récente d'un ou de plusieurs champs pour un ou plusieurs actifs donnés. data.current() nécessite deux arguments : l'actif ou la liste d'actifs, et le champ ou la liste de champs considérés. Les champs possibles sont 'price', 'open', 'high', 'low', 'close' et 'volume'. Le type de sortie dépendra des types d'entrée."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def initialize(context):\n",
" # Référence aux Actions Tech\n",
" context.techies = [sid(16841),sid(24),sid(1900)]\n",
"\n",
"def handle_data(context, data):\n",
" # Positions de notre optimisation de portefeuille! \n",
" tech_close = data.current(context.techies,'close')\n",
" print(type(tech_close)) # Pandas Series\n",
" print(tech_close) # Prix à la Clôture"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### A noter ! Vous pouvez utiliser data.is_stale(sid(#)) pour vérifier si les résultats de data.current() ont été générés à la barre courante (la période) ou s'ils ont été complétés à partir d'une période antérieure."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Vérification pour trading"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### data.can_trade()\n",
"\n",
"data.can_trade() est utilisé pour déterminer si un ou plusieurs actifs sont actuellement cotés sur une place de marché et peuvent être négociés. Si data.can_trade() renvoie True pour un actif particulier dans une période de minutes donnée, nous sommes en mesure de passer un ordre pour cet actif dans cette minute. Il s'agit d'un élément important à intégrer dans notre algorithme si nous sélectionnons à la main les titres que nous voulons négocier. Il ne nécessite qu'un seul argument : un actif ou une liste d'actifs."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def initialize(context):\n",
" # Référence à Amazon\n",
" context.amzn = sid(16841)\n",
" \n",
"def handle_data(context, data):\n",
" # Cela nous permet de ne pas lever une exception !\n",
" if data.can_trade(sid(16841)):\n",
" order_target_percent(context.amzn, 1.0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Vérification des données historiques\n",
"\n",
"Lorsque votre algorithme appelle data.history sur les actions, les données renvoyées sont ajustées en fonction des scissions, fusions et dividendes à la date de simulation actuelle. En d'autres termes, lorsque votre algorithme demande une fenêtre historique des prix, et qu'il y a une scission au milieu de cette fenêtre, la première partie de cette fenêtre sera ajustée pour la scission. Cet ajustement est effectué pour que votre algorithme puisse effectuer des calculs significatifs en utilisant les valeurs de la fenêtre.\n",
"\n",
"Ce code interroge les 20 derniers jours de l'historique des prix pour obtenir un ensemble statique de titres. Plus précisément, il retourne le prix de clôture quotidien des 20 derniers jours, y compris le prix actuel pour la journée en cours. Dans la simulation, les prix des actions sont ajustés en fonction de la division et du dividende à la date du jour :"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"\n",
"def initialize(context):\n",
" # AAPL, CSCO et AMZN\n",
" context.assets = [sid(24), sid(1900), sid(16841)]\n",
"\n",
"def before_trading_start(context,data):\n",
" price_history = data.history(context.assets,fields=\"price\", bar_count=5, frequency=\"1d\")\n",
" \n",
" print(price_history)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"L'argument bar_count indique le nombre de jours ou de minutes à inclure dans la DataFrame pandas renvoyée par la fonction history. Ce paramètre n'accepte que des valeurs entières.\n",
"\n",
"L'argument frequency spécifie la fréquence d'échantillonnage des données : quotidienne ou par minute. Les entrées acceptables sont \"1d\" ou \"1m\". Pour les autres fréquences, utilisez la fonction de rééchantillonnage de pandas."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Exemples\n",
"Vous trouverez ci-dessous des exemples de codes ainsi que des explications sur les données renvoyées.\n",
"\n",
"### Daily History\n",
"\n",
"Utilisez \"1d\" pour la fréquence. Le DataFrame retourné est toujours construit en \"barres\" quotidiennes. Les barres ne couvrent jamais plus d'un jour de trading. Pour les actions américaines, une barre quotidienne saisit l'activité de négociation pendant les heures de marché (généralement de 9h30 à 16h00 ET). Pour les contrats à terme américains, une barre quotidienne saisit l'activité commerciale de 18 h à 18 h (heure de l'Est) (24 heures). Par exemple, la barre quotidienne du lundi saisit l'activité de 18 heures la veille (dimanche) à 18 heures le lundi. Le mardi, la barre quotidienne s'étend de 18 heures la veille (lundi) à 18 heures le mardi, etc. Pour l'une ou l'autre des classes d'actifs, la dernière barre, si elle est partielle, est construite en utilisant les minutes de la journée en cours.\n",
"\n",
"### Exemples (en considérant que context.assets existe):\n",
"\n",
"* data.history(context.assets, \"price\", 1, \"1d\") retourne le prix actuel.\n",
"* data.history(context.assets, \"volume\", 1, \"1d\") retourne le volume depuis l'ouverture de la journée en cours, même s'il est partiel.\n",
"* data.history(context.assets, \"price\", 2, \"1d\") retourne le prix de clôture d'hier et le prix actuel.\n",
"* data.history(context.assets, \"price\", 6, \"1d\") retourne les prix des 5 jours précédents et le prix actuel.\n",
"\n",
"\n",
"### Minute History\n",
"\n",
"Utilisez \"1m\" pour la dréquence.\n",
"\n",
"Exemples (en considérant que context.assets existe):\n",
"\n",
"* data.history(context.assets, \"price\", 1, \"1m\") retourne le prix actuel.\n",
"* data.history(context.assets, \"price\", 2, \"1m\") retourne le prix de clôture de la minute précédente et le prix actuel.\n",
"* data.history(context.assets, \"volume\", 60, \"1m\") retourne le volume des 60 minutes précédentes."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Planification\n",
"\n",
"Utilisez la fonction schedule_function pour indiquer quand vous souhaitez que d'autres fonctions soient exécutées. Les fonctions transmises doivent prendre comme paramètres le contexte et les données (context et data)."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def initialize(context):\n",
" context.appl = sid(49051)\n",
"\n",
" # Au début de la semaine de trading\n",
" # A l'ouverture du marché, fixer 10% du portefeuille à Apple\n",
" schedule_function(open_positions, date_rules.week_start(), time_rules.market_open())\n",
" \n",
" # A la fin de la semaine de trading\n",
" # 30 min avant la fermeture du marché, liquider toutes les actions Apple.\n",
" schedule_function(close_positions, date_rules.week_end(), time_rules.market_close(minutes=30))\n",
"\n",
"def open_positions(context, data):\n",
" order_target_percent(context.appl, 0.10)\n",
"\n",
"def close_positions(context, data):\n",
" order_target_percent(context.appl, 0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Information Portefeuille\n",
"\n",
"Vous pouvez obtenir des informations sur le portefeuille et les enregistrer !"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def initialize(context):\n",
" context.amzn = sid(16841)\n",
" context.ibm = sid(3766)\n",
"\n",
" schedule_function(rebalance, date_rules.every_day(), time_rules.market_open())\n",
" schedule_function(record_vars, date_rules.every_day(), time_rules.market_close())\n",
"\n",
"def rebalance(context, data):\n",
" # La moitié de notre portefeuille est sur une position longue d'amazon\n",
" order_target_percent(context.amzn, 0.50)\n",
" # L'autre moitié est en position courte d'IBM\n",
" order_target_percent(context.ibm, -0.50)\n",
"\n",
"def record_vars(context, data):\n",
"\n",
" # Tracé des prix à la clôture\n",
" record(amzn_close=data.current(context.amzn,'close'))\n",
" record(ibm_close=data.current(context.ibm,'close'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Slippage et Commision \n",
"\n",
"### Slippage\n",
"En finance le slippage (en français glissement) est l'écart de cours qui peut avoir lieu entre le moment de passage d'un ordre de trading et son exécution effective.\n",
"Lorsqu'un ordre est passé pour une transaction, le marché est affecté. Les ordres d'achat font monter les prix, et les ordres de vente les font baisser ; c'est ce qu'on appelle généralement l'impact d'une transaction sur les prix. En outre, les ordres de transaction ne sont pas nécessairement exécutés instantanément. Les taux d'exécution dépendent de la taille de l'ordre et du volume actuel des transactions sur le titre négocié. Le paramètre volume_limite détermine la fraction du volume d'échange d'un titre qui peut être utilisée par votre algorithme.\n",
"\n",
"Dans le cadre du backtesting et du trading papier sans courtage (trading papier quantopian), un modèle de slippage (glissement) peut être spécifié dans initialize() à l'aide de set_slippage(). Il existe différents modèles de slippage intégrés qui peuvent être utilisés, ainsi que la possibilité de définir un modèle personnalisé. Par défaut (si un modèle de slippage n'est pas spécifié), le modèle de slippage de la part de volume suivant est utilisé :"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"# valeurs par défaut de la fonction set_slippage dans quantopian, à ajouter dans la fonction initialize()\n",
"# set_slippage(slippage.VolumeShareSlippage(volume_limit=0.025, price_impact=0.1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"En utilisant le modèle par défaut, si un ordre de 60 actions est placé pour une action donnée, que 1000 actions de cette action se négocient dans chacune des prochaines minutes et que la limite de volume est de 0,025, alors notre ordre de négociation sera divisé en trois ordres (25 actions, 25 actions et 10 actions) qui s'exécuteront dans les 3 prochaines minutes.\n",
"\n",
"À la fin de chaque journée, tous les ordres ouverts sont annulés, de sorte que la négociation d'actions liquides est généralement une bonne idée. En outre, les ordres placés exactement à la clôture du marché n'auront pas le temps d'être exécutés et seront annulés."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Commision\n",
"\n",
"Pour définir le coût des transactions, nous pouvons spécifier un modèle de commission dans initialize() en utilisant set_commission(). Par défaut (si un modèle de commission n'est pas spécifié), le modèle de commission suivant est utilisé :"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"# set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Le modèle de commission par défaut est de 0,0075 dollar par action, avec un coût commercial minimum de 1 dollar.\n",
"\n",
"Les modèles de glissement et de commission peuvent avoir un impact sur la performance d'un backtest. Les modèles par défaut utilisés par Quantopian sont assez réalistes. Il est donc fortement recommandé de les utiliser."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Bon Travail !\n",
"\n",
"Ce sont toutes les bases du tutoriel sur les Quantopians ! Avec ces fonctions clés, vous en savez en fait assez pour commencer à faire du trading ! "
]
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python 3.5",
"language": "python",
"name": "py35"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.5"
}
},
"nbformat": 4,
"nbformat_minor": 1
}