- Published on
Réaliser un bot télégram de finance pour les néophytes
- Authors
- Name
- Léo Delpon
Faire un bot télégram pour la finance
Depuis que je suis en 4ème, j'ai toujours été bercé par le monde de la finance et de l'entreprenariat. Malheureusement le carry
c’était mon père. ll a géré pour moi mon argent jusqu’à ce que je puisse être assez mature pour le gérer tout seul. Maintenant j’ai 25 ans, je vais bientôt être diplômé de mon école, cela fait maintenant 3 ans que je suis en freelance
et je ne sais toujours pas gérer mon argent...
J’ai donc commencé par rattraper tout le retard que j’avais eu en demandant à la source (le bon vieux daron). C’est là que j'ai commencé à créer des petits outils pour monitorer mon argent car étant un peu tête en l’air, j’ai parfois du mal à m’informer sur les actualités économiques et financières. Voilà pour j’écris ce petit article, c’est pour vous montrer que coder des outils simples c’est très rapide à faire et ça peut parfois aider un peu ! (petite pensée à mon ami Lectra, sniff
)
Dans cet article je vais vous apprendre à coder un bot qui permettra de retracer le cours de bourse de vos actions facilement. Nous calculerons le taux de croissance :
- Par rapport à la
veille
- Par rapport à une
semaine
- Par rapport à
un mois
- Par rapport à
six mois
- Par rapport à
un an
Bon j'avoue, je ne me suis pas ultra foulé mais c'est pour vous montrer qu'on peut faire des choses rapidement !
Trouver une API qui soit assez performante pour voir à moyen termes
Après quelques recherches, je suis tombé sur une API qui avait l’air très intéressante, celle de Yahoo Finance
. Si vous êtes novice dans le domaine de la finance et que vous ne souhaitez pas consacrer de nombreuses heures à l'étude de documents techniques, l'API Yahoo Finance représente un choix judicieux.
Non seulement elle est entièrement gratuite (quoique des offres payantes sont disponibles pour les utilisateurs exigeants dans d’autres plateformes), mais elle offre également un large éventail de données sur les marchés, dont certaines ne sont pas disponibles sur d'autres plateformes. De plus, l'installation de l'API est extrêmement aisée et rapide. Vous pouvez ainsi obtenir des clés API personnelles en quelques clics et même automatiser les tâches les plus répétitives grâce aux fonctions pré-construites dans les modules.
L'API Yahoo Finance représente une véritable porte d'entrée pour les débutants dans le monde de la finance, leur permettant de prendre leurs premiers pas en toute sérénité. Pour tout les plus curieux, je vous invite à lire cet article !
Il est temps de coder le module simple en python
On commence d’abord par importer les modules dont on a besoin :
from datetime import datetime
import yfinance as yf
Vous pouvez remarquer que cette librairie yfinance
permet d’utiliser l’API de Yahoo Finance. Néanmoins, il faut savoir que ce dernier n’est pas maintenu par Yahoo personnellement mais est un module open-source. Je vous recommande d’aller lire les termes d’utilisations pour un usage plus particulier.
Si vous ne possédez pas cette librairie, je vous propose de l’installer
A présent, commençons par tester cette dernière :
element = yf.Ticker("CS.PA")
print(element.info)
print(element.history(period="1y"))
Si on analyse le résultat ci-dessous, on remarque deux choses, les informations fournies sont assez complètes mais surtout en analysant l’historique, on peut apercevoir l’intervalle de temps de l’historique qui est entre hier
et il y a un an
. Cette période peut évoluer en indiquant une période différente. (voir la documentation de yfinance 🙃)
$ py finance.py
{'address1': '25, avenue Matignon', 'city': 'Paris', 'zip': '75008', 'country': 'France', 'phone': '33 1 40 75 57 00', 'website': 'https://www.axa.com', 'industry': 'Insurance—Diversified', 'sector': 'Financial Services', 'longBusinessSummary': "AXA SA, through its subsidiaries, provides insurance, asset management, and banking services worldwide. The company operates through six segments: France, Europe, Asia, AXA XL, International, and Transversal & Central Holdings. It offers life and savings insurance products, such as savings and retirement, other health, and personal protection products. The company also provides property and casualty insurance products, including car, home, and personal or professional liability to individual and business clients; international insurance for large corporate clients in Europe; and marine and aviation insurance services, as well as property and casualty reinsurance products. In addition, it offers asset management services in the areas of various asset classes, including equities, bonds, hedge funds, private equity, and real estate for the group's insurance companies and their clients, and retail and institutional clients. Further, the company provides health, term life, whole life, universal life, endowment, and other investment-based products for personal/individual and commercial/ group customers. AXA SA was founded in 1852 and is headquartered in Paris, France.", 'fullTimeEmployees': 92695, 'companyOfficers': [{'maxAge': 1, 'name': 'Dr. Thomas Buberl', 'age': 49, 'title': 'CEO & Director', 'yearBorn': 1973, 'fiscalYear': 2022, 'totalPay': 2871631, 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Ms. Helen Browne', 'age': 60, 'title': 'Group Gen. Counsel & Employee Representative Director', 'yearBorn': 1962, 'fiscalYear': 2022, 'totalPay': 93794, 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Mr. Alban de Mailly Nesle', 'age': 52, 'title': 'Group CFO and Chief Risk & Investment Officer', 'yearBorn': 1970, 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Dr. Alexander Vollert', 'age': 53, 'title': 'Group Chief Operating Officer', 'yearBorn': 1969, 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Gregoire de Montchalin', 'title': 'Chief Accounting & Reporting Officer', 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Mr. Nicolas Leclercq', 'title': 'Head of Group Corp. Fin. & Treasury', 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Mr. Marc Blottière', 'title': 'Group Chief Information Officer', 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Ms. Anu Venkataraman', 'title': 'Head of Investor Relations', 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Mr. Andrew Wallace-Barnett', 'title': 'Group Chief Compliance Officer', 'exercisedValue': 0, 'unexercisedValue': 0}, {'maxAge': 1, 'name': 'Ms. Ulrike Decoene', 'title': 'Group Chief Communication, Brand & Sustainability Officer', 'exercisedValue': 0, 'unexercisedValue': 0}], 'auditRisk': 5, 'boardRisk': 8, 'compensationRisk': 5, 'shareHolderRightsRisk': 1, 'overallRisk': 4, 'governanceEpochDate': 1680307200, 'compensationAsOfEpochDate': 1672444800, 'maxAge': 86400, 'priceHint': 2, 'previousClose': 29.455, 'open': 29.64, 'dayLow': 29.095, 'dayHigh': 29.68, 'regularMarketPreviousClose': 29.455, 'regularMarketOpen': 29.64, 'regularMarketDayLow': 29.095, 'regularMarketDayHigh': 29.68, 'dividendRate': 1.7, 'dividendYield': 0.0581, 'exDividendDate': 1683504000, 'payoutRatio': 0.5442, 'beta': 1.337786, 'trailingPE': 10.333334, 'forwardPE': 8.068493, 'volume': 916383, 'regularMarketVolume': 916383, 'averageVolume': 5203177, 'averageVolume10days': 3967380, 'averageDailyVolume10Day': 3967380, 'bid': 0.0, 'ask': 0.0, 'bidSize': 0, 'askSize': 0, 'marketCap': 66690703360, 'fiftyTwoWeekLow': 20.335, 'fiftyTwoWeekHigh': 30.34, 'priceToSalesTrailing12Months': 0.6431119, 'fiftyDayAverage': 28.4945, 'twoHundredDayAverage': 26.24995, 'trailingAnnualDividendRate': 1.7, 'trailingAnnualDividendYield': 0.05771516, 'currency': 'EUR', 'enterpriseValue': 113347788800, 'profitMargins': 0.06437, 'floatShares': 1819891043, 'sharesOutstanding': 2264539904, 'heldPercentInsiders': 0.20195, 'heldPercentInstitutions': 0.42022, 'impliedSharesOutstanding': 0, 'bookValue': 20.028, 'priceToBook': 1.4704415, 'lastFiscalYearEnd': 1672444800, 'nextFiscalYearEnd': 1703980800, 'mostRecentQuarter': 1672444800, 'earningsQuarterlyGrowth': -0.222, 'netIncomeToCommon': 6493000192, 'trailingEps': 2.85, 'forwardEps': 3.65, 'pegRatio': 1.04, 'lastSplitFactor': '4:1', 'lastSplitDate': 989971200, 'enterpriseToRevenue': 1.093, 'enterpriseToEbitda': 11.104, '52WeekChange': 0.1569128, 'SandP52WeekChange': 0.0008276701, 'lastDividendValue': 1.7, 'lastDividendDate': 1683504000, 'exchange': 'PAR', 'quoteType': 'EQUITY', 'symbol': 'CS.PA', 'underlyingSymbol': 'CS.PA', 'shortName': 'AXA', 'longName': 'AXA SA', 'firstTradeDateEpochUtc': 651481200, 'timeZoneFullName': 'Europe/Paris', 'timeZoneShortName': 'CEST', 'uuid': '8d6b474a-15eb-38c4-9e9e-2bff261dcf4c', 'messageBoardId': 'finmb_121238', 'gmtOffSetMilliseconds': 7200000, 'currentPrice': 29.45, 'targetHighPrice': 36.0, 'targetLowPrice': 28.0, 'targetMeanPrice': 33.1, 'targetMedianPrice': 33.3, 'recommendationMean': 1.8, 'recommendationKey': 'buy', 'numberOfAnalystOpinions': 19, 'totalCash': 26168999936, 'totalCashPerShare': 11.556, 'ebitda': 10208000000, 'totalDebt': 63393001472, 'quickRatio': 0.27, 'currentRatio': 0.595, 'totalRevenue': 103699996672, 'debtToEquity': 115.733, 'revenuePerShare': 45.284, 'returnOnAssets': 0.007929999, 'returnOnEquity': 0.099530004, 'grossProfits': 19490000000, 'freeCashflow': 2330125056, 'operatingCashflow': 7880999936, 'earningsGrowth': -0.186, 'revenueGrowth': -0.066, 'grossMargins': 0.18794, 'ebitdaMargins': 0.09844, 'operatingMargins': 0.090050004, 'financialCurrency': 'EUR', 'trailingPegRatio': None}
Open High Low Close Volume Dividends Stock Splits
Date
2022-04-28 00:00:00+02:00 24.396057 24.597639 23.875695 24.086653 5465441 0.0 0.0
2022-04-29 00:00:00+02:00 24.199162 24.283546 23.791312 23.871006 5931332 0.0 0.0
2022-05-02 00:00:00+02:00 23.645984 23.716304 23.350645 23.613169 5229984 0.0 0.0
2022-05-03 00:00:00+02:00 23.660049 23.936638 23.556914 23.899134 5564054 0.0 0.0
2022-05-04 00:00:00+02:00 23.978829 24.025708 23.552227 23.589729 4929845 0.0 0.0
... ... ... ... ... ... ... ...
2023-04-24 00:00:00+02:00 29.200001 29.400000 29.150000 29.320000 3202571 0.0 0.0
2023-04-25 00:00:00+02:00 29.200001 29.309999 28.924999 29.285000 3450686 0.0 0.0
2023-04-26 00:00:00+02:00 29.240000 29.410000 28.875000 29.270000 3886950 0.0 0.0
2023-04-27 00:00:00+02:00 29.315001 29.610001 29.135000 29.455000 2878200 0.0 0.0
2023-04-28 00:00:00+02:00 29.639999 29.680000 29.094999 29.450001 916383 0.0 0.0
[259 rows x 7 columns]
On note quelque chose d’intéressant, c’est que la disposition de l’historique est sous forme de DataFrame
, nous allons donc pouvoir faire une selection assez simplement (normal, c'est le but de python d'être simple). Créons une fonction pour obtenir tout les cours de bourses de aujourd’hui à partir de différents symboles que l'on appelle aussi Ticker
:
# On utilise les symboles boursiers pour récupérer les informations
pea_stock_options = [
"CS.PA",
"BNP.PA",
"LSS.PA",
"MC.PA",
"PAEJ.PA",
"PASI.PA",
"EWLD.PA",
"PUST.PA",
"PSP5.PA",
"PWG.PA",
"TTE.PA"
]
def get_current_stock_value():
result = []
print("[+] Getting stocks values")
now = datetime.now()
t_string = now.strftime("%d/%m/%Y %H:%M:%S")
for symbol in pea_stock_options:
element = yf.Ticker(symbol)
hist = element.history(period="1y")
result.append(f"[{t_string}] {hist.iloc[-1]['Close']}")
message = "\n".join(result)
del result[:]
print(message)
return message
Et voici le résultat :
delpo@LAPTOP-M0MPIPJ6 MINGW64 ~/Documents/tools/test_scrapper
$ py finance.py
[+] Getting stocks values
[28/04/2023 15:22:43] 29.469999313354492
[28/04/2023 15:22:43] 58.09000015258789
[28/04/2023 15:22:43] 28.950000762939453
[28/04/2023 15:22:43] 867.9000244140625
[28/04/2023 15:22:43] 15.680000305175781
[28/04/2023 15:22:43] 9.08899974822998
[28/04/2023 15:22:43] 24.00200080871582
[28/04/2023 15:22:43] 47.70000076293945
[28/04/2023 15:22:43] 31.8799991607666
[28/04/2023 15:22:43] 2.2100000381469727
[28/04/2023 15:22:43] 57.040000915527344
Plutôt cool n’est-ce pas ? Bien, à présent, passons aux choses sérieuses ! On va créer les différents taux de croissances. Commençons par créer la fonction qui va calculer la croissance
def evolution_rate(value_start, value_end):
return ((value_end - value_start) / value_start)*100
Maintenant, passons au calculs pour toutes nos métriques temporelles
def rate_overall(hist):
rates = dict()
rates["last_annual_rate"] = round(evolution_rate(float(hist.iloc[0]['Close']), float(hist.iloc[-1]['Close'])), 2)
rates["last_six_month_rate"] = round(evolution_rate(float(hist.iloc[-132]['Close']), float(hist.iloc[-1]['Close'])), 2)
rates["last_month_rate"] = round(evolution_rate(float(hist.iloc[-22]['Close']), float(hist.iloc[-1]['Close'])), 2)
rates["last_week_rate"] = round(evolution_rate(float(hist.iloc[-5]['Close']), float(hist.iloc[-1]['Close'])), 2)
rates["last_rate"] = round(evolution_rate(float(hist.iloc[-2]['Close']), float(hist.iloc[-1]['Close'])), 2)
return rates
On a donc nos deux petits outils, voici la version finale de get_current_stock_value():
def get_current_stock_value():
result = []
print("[+] Getting stocks values")
now = datetime.now()
t_string = now.strftime("%d/%m/%Y %H:%M:%S")
for symbol in pea_stock_options:
element = yf.Ticker(symbol)
hist = element.history(period="1y")
rates = rate_overall(hist)
result.append(f"[{t_string}] {element.info['longName']} ({element.info['symbol']}) : \n{round(float(hist.iloc[-1]['Close']), 2)} € [1A:{rates['last_annual_rate']} ] [6M:{rates['last_six_month_rate']} %] [1M:{rates['last_month_rate']} %] ([1W:{rates['last_week_rate']} %] [Y:{rates['last_rate']} %]")
message = "\n\n".join(result)
del result[:]
print(message)
return message
et voici le resultat :
$ py finance.py
[+] Getting stocks values
[28/04/2023 15:31:41] AXA SA (CS.PA) :
29.48 € [1A:22.37 ] [6M:18.68 %] [1M:8.5 %] ([1W:0.53 %] [Y:0.07 %]
[28/04/2023 15:31:41] BNP Paribas SA (BNP.PA) :
58.08 € [1A:26.04 ] [6M:23.67 %] [1M:11.76 %] ([1W:-1.79 %] [Y:-1.12 %]
[28/04/2023 15:31:41] Lectra SA (LSS.PA) :
29.25 € [1A:-26.37 ] [6M:-2.82 %] [1M:-16.55 %] ([1W:-14.97 %] [Y:-11.36 %]
[28/04/2023 15:31:41] Lyxor PEA Nasdaq-100 UCITS ETF (PUST.PA) :
47.7 € [1A:-4.12 ] [6M:4.57 %] [1M:3.09 %] ([1W:2.11 %] [Y:0.89 %]
[28/04/2023 15:31:41] Lyxor PEA S&P 500 UCITS ETF (PSP5.PA) :
31.87 € [1A:-5.41 ] [6M:-1.2 %] [1M:2.33 %] ([1W:0.21 %] [Y:0.73 %]
[28/04/2023 15:31:41] Prodways Group SA (PWG.PA) :
2.21 € [1A:-15.65 ] [6M:-39.45 %] [1M:-5.56 %] ([1W:-2.21 %] [Y:-1.12 %]
[28/04/2023 15:31:41] TotalEnergies SE (TTE.PA) :
57.14 € [1A:30.87 ] [6M:11.34 %] [1M:6.78 %] ([1W:-1.84 %] [Y:0.47 %]
Ca commence à avoir un peu plus de panache ! On peut passer à la partie du bot télégram.
Réalisation du bot et envoi des données à un interval de temps régulier
Pour créer un bot, je ne vais pas réinventer la roue, je vous propose d’aller plutôt voir mon article sur comment faire un bot télégram. On va donc utiliser notre fichier .env
afin d’être capable d’importer notre clé d’API de télégram.
import telebot
import os.path
from dotenv import load_dotenv
load_dotenv()
bot = telebot.TeleBot(os.getenv('TELEGRAM_API_KEY_STOCK'))
On crée ensuite notre fonction d’envoi de message de télégram
@bot.message_handler(commands=['start'])
def get_cup_data(message):
text = "Hi, welcome back to stock bot register !"
bot.send_message(message.chat.id, text, parse_mode="Markdown")
while True:
response = get_current_stock_value()
bot.send_message(message.chat.id, response)
time.sleep(120)
bot.infinity_polling()
Si nous lançons notre bot :
Et voici les résultats à partir de notre liste de symbole boursier. J’ai mis le tout dans une boucle infinie
avec une intervalle de 120 secondes
. Nous recevrons donc nos informations toute les deux minutes. (bah ouais, faut pas non plus SPAM comme un en**ulé)
Voilà, j’espère que cela vous aura plu car j’ai pris beaucoup de plaisir à coder ce petit bot. Le prochain article qui aura comme thématique la finance sera dans pas trop longtemps et je parlerai d’une plateforme qui est très intéressante qui est : TradingView. Je vous apprendrai à coder une dashboard totalement modulable de finance.
Allez PEACE mes chers nakamas.