├── images
├── boxplot1.png
├── boxplot2.png
├── prices.png
├── 1_dataframe.png
├── 2_coinmarket.png
├── data_limpio.png
└── data_original.png
├── .gitignore
├── __pycache__
└── functions.cpython-39.pyc
├── global_data.py
├── main.py
├── functions.py
└── README.md
/images/boxplot1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloing93/Trading-Robot/HEAD/images/boxplot1.png
--------------------------------------------------------------------------------
/images/boxplot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloing93/Trading-Robot/HEAD/images/boxplot2.png
--------------------------------------------------------------------------------
/images/prices.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloing93/Trading-Robot/HEAD/images/prices.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #Ingnoring local folder
2 | .ipynb_checkpoints/
3 | __pycache__/
4 | my_tests.py
5 | alquiler.csv
--------------------------------------------------------------------------------
/images/1_dataframe.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloing93/Trading-Robot/HEAD/images/1_dataframe.png
--------------------------------------------------------------------------------
/images/2_coinmarket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloing93/Trading-Robot/HEAD/images/2_coinmarket.png
--------------------------------------------------------------------------------
/images/data_limpio.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloing93/Trading-Robot/HEAD/images/data_limpio.png
--------------------------------------------------------------------------------
/images/data_original.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloing93/Trading-Robot/HEAD/images/data_original.png
--------------------------------------------------------------------------------
/__pycache__/functions.cpython-39.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pabloing93/Trading-Robot/HEAD/__pycache__/functions.cpython-39.pyc
--------------------------------------------------------------------------------
/global_data.py:
--------------------------------------------------------------------------------
1 | user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36"
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from functions import *
2 | from IPython.display import clear_output
3 | import time
4 |
5 | while(True):
6 | clear_output()
7 | df_bitcoin = importar_base_bitcoin()
8 | precio, tendencia = extraer_tendencias("BTC")
9 | media_bitcoin = limpieza_datos(df_bitcoin)
10 | decision = tomar_desiciones(precio, media_bitcoin, tendencia)
11 | visualizacion(df_bitcoin, precio, media_bitcoin, decision)
12 | time.sleep(300)
--------------------------------------------------------------------------------
/functions.py:
--------------------------------------------------------------------------------
1 | import yfinance
2 | from bs4 import BeautifulSoup
3 | import requests
4 | from global_data import user_agent
5 | import pandas
6 | import matplotlib.pyplot as plt
7 |
8 | #Getting Yahoo! Finance Bitcoin History Data
9 | def importar_base_bitcoin():
10 | bitcoin = yfinance.Ticker("BTC-USD")
11 | df_bitcoin = bitcoin.history(period="7d", interval="5m")
12 | return df_bitcoin
13 |
14 | #Getting tendencies from CoinMarket
15 | def extraer_tendencias(simbol: str) -> tuple:
16 |
17 | def get_tendencie(row: str) -> str:
18 | alta_icon = "icon-Caret-up"
19 | baja_icon = "icon-Caret-down"
20 | if(alta_icon in row):
21 | return "alta"
22 | else:
23 | return "baja"
24 |
25 | def str_to_float(price: str) -> float:
26 | return float(price.replace("$", "").replace(",", ""))
27 |
28 | def get_column_position(a_table: BeautifulSoup, column_name: str) -> int:
29 | for index, columna in enumerate(list(a_table.thead.tr.find_all("th"))):
30 | if(columna.find('p')):
31 | texto_p = columna.p.text.strip()
32 | if column_name == texto_p:
33 | return index
34 |
35 | def get_simbol_row(a_table: BeautifulSoup, a_simbol: str) -> list:
36 | for tr in a_table.tbody:
37 | p_tags = tr.find_all("p")
38 | for p in p_tags:
39 | if(p.string == a_simbol):
40 | return list(tr)
41 |
42 | #1) Obtengo el html de la web
43 | headers = { "User-Agent": user_agent }
44 | url = "https://coinmarketcap.com/"
45 | request = requests.get(url, headers)
46 | web_content = BeautifulSoup(request.content, features="lxml")
47 | html_table = web_content.find("table", class_="cmc-table")
48 |
49 | #2) obtengo la posicion de las columnas que me interesan
50 | tendencie_column_position = get_column_position(html_table, "1h %")
51 | price_column_position = get_column_position(html_table, "Price")
52 |
53 | #3) obtengo la fila de la moneda que me interesa
54 | simbol_row = get_simbol_row(html_table, simbol)
55 |
56 | #4) Accedo al contenido especifico que busco
57 | price_string = str(simbol_row[price_column_position].span.text)
58 | price = str_to_float(price_string) #limpio el dato
59 | tendencie_string = str(simbol_row[tendencie_column_position])
60 | tendencie = get_tendencie(tendencie_string) #limpio el dato
61 |
62 | return ( price, tendencie )
63 |
64 | def limpieza_datos(df_bitcoins: pandas.DataFrame) -> tuple:
65 | def draw_boxplot(title: str, dataframe: pandas):
66 | plt.figure(figsize=(8, 6))
67 | plt.title(title)
68 | plt.boxplot(dataframe['Close'], vert=False)
69 | plt.show()
70 | # Hago una copia del dataframe original
71 | dataframe = df_bitcoins.copy()
72 | # Eliminar duplicados en el índice
73 | dataframe = dataframe[~dataframe.index.duplicated(keep='first')]
74 | # Buscar valores nulos en la columna "Close" y eliminarlos
75 | dataframe.dropna(subset=['Close'], inplace=True)
76 | # Verificar que todos los registros tengan un Volume de transacción mayor a 0
77 | dataframe = dataframe[dataframe['Volume'] > 0]
78 | # Identificar y eliminar outliers en la columna "Close" usando un boxplot
79 | #Obtengo los valores de Close que se encuentren entre Q1 y Q3
80 | Q1 = dataframe['Close'].quantile(0.25)
81 | Q3 = dataframe['Close'].quantile(0.75)
82 | dataframe = dataframe[(dataframe['Close'] >= Q1) & (dataframe['Close'] <= Q3)]
83 | # Calcular el precio promedio (Close) de esta selección
84 | media_bitcoin = dataframe['Close'].mean()
85 | return media_bitcoin
86 |
87 | def tomar_desiciones(current_price: int, mean_price: int, tendencie: str) -> str:
88 | #Defino los casos de decisiones
89 | case_1 = (current_price >= mean_price) & (tendencie == 'baja')
90 | case_2 = (current_price < mean_price) & (tendencie == 'alta')
91 | if (case_1):
92 | decision = 'Vender'
93 | elif (case_2):
94 | decision = 'Comprar'
95 | else:
96 | decision = 'Esperar'
97 | return decision
98 |
99 | def visualizacion(df_bitcoin: pandas.DataFrame, current_price: float, mean: float, decision: str):
100 | #Hago una copia del DF original
101 | dataframe = df_bitcoin.copy()
102 | #Creo una columna nueva y cargo el valor de la media
103 | dataframe['Promedio'] = mean
104 | #Configuro el tamaño del gráfico en 16x5
105 | plt.rc('figure', figsize = (16,5))
106 | #Dibujo el gráfico (Volumen,Datetime)
107 | graph = dataframe['Close'].plot()
108 | #Dibujo la linea del promedio
109 | graph = dataframe['Promedio'].plot()
110 | #Seteo títulos al gráfico
111 | graph.set_title('Bitcoin BTC YFinance', {'fontsize': 22})
112 | graph.set_ylabel('Precio de Cierre')
113 | graph.set_xlabel('Fecha')
114 | #Mostrar la decision con el metodo annotate()
115 | current_date = dataframe.index[-1]
116 | if (decision == 'Comprar'):
117 | plt.annotate(
118 | text = decision,
119 | horizontalalignment = 'center',
120 | xy=(current_date, current_price),
121 | arrowprops={'facecolor': 'green'},
122 | xytext=(current_date, current_price+100)
123 | )
124 | elif (decision == 'Vender'):
125 | plt.annotate(
126 | text = decision,
127 | horizontalalignment = 'center',
128 | xy=(current_date, current_price),
129 | arrowprops={'facecolor': 'red'},
130 | xytext=(current_date, current_price+500)
131 | )
132 | graph.legend(
133 | [f'Bitcoin Price: {round(current_price, 2)}', f'Mean: {round(mean, 2)}'],
134 | loc='upper left',
135 | title=f'Recomendacion: {decision}')
136 | plt.show()
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Trading Robot 🤖
2 |
3 | ## Tecnologías utilizadas 📊
4 |
5 | ### Pandas
6 | Pandas es una biblioteca esencial para el análisis y manipulación de datos en Python. Muy utilizada en proyectos de Ciencia de Datos.
7 |
8 | ### BeautifulSoup (bs4)
9 | BeautifulSoup es una biblioteca utilizada para técnicas de webscraping. La utilizamos en nuestro proyecto para obtener datos de Coinmarket.
10 |
11 | ### Matplotlib Pyplot
12 | Una biblioteca de visualización de datos en Python. Nos facilita la creación de gráficos y mejor comprensión de la distribución de los datos a través de visualizaciones.
13 |
14 | ### Yfinance
15 | Yfinance es una herramienta open source que nos proporciona una API para acceder a datos financieros y del mercado en tiempo real.
16 |
17 |
18 | ## Etapas del algoritmo
19 |
20 | ## Configuración del ambiente
21 | > [!IMPORTANT]
22 | > Se requiere instalar las tecnologías necesarias para poder ejecutar el proyecto de manera local
23 | > ```
24 | > pip install pandas, matplotlib, yfinance, beautifulsoup4
25 | > ```
26 |
27 | ## Obtencion de datos 📁
28 |
29 | La función importar_base_bitcoin() utiliza la API de yfinance para obtener datos históricos de Bitcoin durante los últimos 7 días con intervalos de 5 minutos.
30 | Llamamos a la función y almacenamos su valor en una variable como se muestra a continuación:
31 |
32 | 
33 |
34 |
35 |
36 | [
code link
][KBD]
37 |
38 | [KBD]: f221f39a64f4846224f8496a8a094dc92aecfdac/functions.py#L9
39 |
40 | La función extraer_tendencias() recibe como parámetro "BTC" que es el símbolo de la moneda de la cuál extraeremos la información del precio y la tendencia.
41 | Llamamos a la función y almacenamos su valor en una variable como se muestra a continuación:
42 |
43 | 
44 | 
45 |
46 | [
code link
][KBD]
47 |
48 | [KBD]: f221f39a64f4846224f8496a8a094dc92aecfdac/functions.py#L15
49 |
50 | Procedimiento:
51 | Utilizando el símbolo de la moneda aplicamos webscraping a la página web https://coinmarketcap.com/
52 | Obtenemos el precio y la tendencia en 1h %
53 |
54 |
55 |
56 | ## Depuración de los datos 🧹
57 |
58 | La depuración de los datos se realiza a través de la función limpieza_datos()
59 |
60 | 
61 |
62 | Que se encuentra definida de la siguiente forma
63 | 
64 |
65 | [
code link
][KBD]
66 |
67 | [KBD]: f221f39a64f4846224f8496a8a094dc92aecfdac/functions.py#L64
68 |
69 | 1. Hacemos una copia de ```df_bitcoin```
70 | 2. Eliminamos los registros duplicados de la columna ```Datetime```.
71 | 3. Eliminamos los registros cuyo valor en la columna ```Close``` sea nulo o 0.
72 | 4. Nos quedamos con los registros cuyo valor en columna ```Volume``` sea mayor a 0.
73 | 5. Identifica y eliminanos los "outliers" del precio de cierre de Bitcoin.
74 |
75 |
76 |
77 | 6. Agrupamos los datos que se encuentren entre el primer y el tercer Quartil ```Q3 > Close > Q1```
78 | 7. Obtenemos el valor de la media desde los datos depurados
79 |
80 |
81 |
82 | En resumen, este código se encarga de asegurarse de que los datos relacionados con el precio de Bitcoin sean precisos y útiles para futuros análisis. Esto implica eliminar datos duplicados, nulos e inusuales, y calcular el precio promedio después de realizar estas limpiezas.
83 |
84 | ## Toma de decisiones 🚀
85 |
86 | 
87 |
88 | 
89 |
90 | [
code link
][KBD]
91 |
92 | [KBD]: f221f39a64f4846224f8496a8a094dc92aecfdac/functions.py#L87
93 |
94 | El algoritmo de toma de decisiones consiste en analizar el precio actual de la moneda, el precio promedio y la tendencia.
95 | - Caso 1: Si el precio actual es mayor o igual al precio promedio y la tendencia es "baja", entonces se recomienda "Vender".
96 | - Caso 2: Si el precio actual es menor que el precio promedio y la tendencia es "alta", entonces recomienda "Comprar".
97 | - Si ninguno de estos casos se cumple, se recomienda "Esperar".
98 |
99 | Finalmente, la función devuelve una decisión, que puede ser "Vender", "Comprar" o "Esperar" en función de los valores de entrada.
100 |
101 | ## Visualizacion 📈
102 | En éste procedimiento del algoritmo mostramos los resultados en un gráfico para facilitar su comprensión de los datos resultados y dar apoyo en la toma de decisiones.
103 |
104 | 
105 | 
106 | [
code link
][KBD]
107 |
108 | [KBD]: f221f39a64f4846224f8496a8a094dc92aecfdac/functions.py#L99
109 |
110 |
111 |
112 | ## Automatizacion 🧠
113 |
114 | Este proceso automatizado permite a los usuarios rastrear el precio de Bitcoin y tomar decisiones rápidas basadas en datos actualizados en tiempo real.
115 |
116 | 
117 |
118 |
--------------------------------------------------------------------------------