Spaces:
Sleeping
Sleeping
took out fetch_data from technical analysis to its own module
Browse files- app.py +3 -1
- src/fetch_data.py +64 -0
- src/stock_analysis_agent.py +3 -1
- src/technical_analysis.py +12 -56
app.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
import dotenv
|
| 2 |
import gradio as gr
|
| 3 |
|
|
|
|
| 4 |
from src.fetch_forecast import FetchForecast
|
| 5 |
from src.stock_analysis_agent import StockAnalyst
|
| 6 |
from src.technical_analysis import TechnicalAnalysis
|
|
@@ -48,11 +49,12 @@ def plot_stock(agent_instance, ticker):
|
|
| 48 |
if ticker_exists:
|
| 49 |
# fetch the forecasts
|
| 50 |
dotenv.load_dotenv(dotenv.find_dotenv())
|
|
|
|
| 51 |
df_past, df_fcst = FetchForecast(ticker).run()
|
| 52 |
# run the technical analysis
|
| 53 |
_, fig = TechnicalAnalysis(
|
| 54 |
ticker=ticker,
|
| 55 |
-
|
| 56 |
df_past=df_past,
|
| 57 |
df_fcst=df_fcst,
|
| 58 |
plot_ta=True,
|
|
|
|
| 1 |
import dotenv
|
| 2 |
import gradio as gr
|
| 3 |
|
| 4 |
+
from src.fetch_data import FetchData
|
| 5 |
from src.fetch_forecast import FetchForecast
|
| 6 |
from src.stock_analysis_agent import StockAnalyst
|
| 7 |
from src.technical_analysis import TechnicalAnalysis
|
|
|
|
| 49 |
if ticker_exists:
|
| 50 |
# fetch the forecasts
|
| 51 |
dotenv.load_dotenv(dotenv.find_dotenv())
|
| 52 |
+
df_hist = FetchData(ticker, fetchperiodinweeks=12).run()
|
| 53 |
df_past, df_fcst = FetchForecast(ticker).run()
|
| 54 |
# run the technical analysis
|
| 55 |
_, fig = TechnicalAnalysis(
|
| 56 |
ticker=ticker,
|
| 57 |
+
df_hist=df_hist,
|
| 58 |
df_past=df_past,
|
| 59 |
df_fcst=df_fcst,
|
| 60 |
plot_ta=True,
|
src/fetch_data.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import datetime as dt
|
| 3 |
+
import logging
|
| 4 |
+
import os
|
| 5 |
+
|
| 6 |
+
import pandas as pd
|
| 7 |
+
import yfinance as yf
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
class FetchData:
|
| 11 |
+
def __init__(self, ticker: str, fetchperiodinweeks: int = 12, debug=False):
|
| 12 |
+
# set up logging
|
| 13 |
+
if debug:
|
| 14 |
+
self.logger_level = logging.DEBUG
|
| 15 |
+
else:
|
| 16 |
+
self.logger_level = logging.INFO
|
| 17 |
+
self.logger = logging.getLogger(__name__)
|
| 18 |
+
logging.basicConfig(level=self.logger_level) # filename='TechnicalAnalysis.log',
|
| 19 |
+
|
| 20 |
+
self.ticker = ticker
|
| 21 |
+
self.fetchperiodinweeks = fetchperiodinweeks
|
| 22 |
+
|
| 23 |
+
def run(
|
| 24 |
+
self
|
| 25 |
+
) -> pd.DataFrame:
|
| 26 |
+
"""
|
| 27 |
+
Fetches historical stock price data from Yahoo Finance.
|
| 28 |
+
This method downloads historical stock price data for the specified
|
| 29 |
+
ticker over a given period of weeks. The data is fetched on a daily
|
| 30 |
+
interval and stored in a pandas DataFrame. If the download is successful,
|
| 31 |
+
redundant ticker columns are removed, and logging information is
|
| 32 |
+
recorded. In case of failure, an empty DataFrame is returned and an
|
| 33 |
+
exception is raised.
|
| 34 |
+
Returns:
|
| 35 |
+
pd.DataFrame
|
| 36 |
+
A DataFrame containing the historical stock price data with columns
|
| 37 |
+
for open, high, low, close, volume, and adjusted close prices.
|
| 38 |
+
Raises:
|
| 39 |
+
Exception
|
| 40 |
+
If the data fetching fails, an exception is raised with an error
|
| 41 |
+
message.
|
| 42 |
+
"""
|
| 43 |
+
|
| 44 |
+
period_start = dt.datetime.now() - dt.timedelta(weeks=self.fetchperiodinweeks)
|
| 45 |
+
self.logger.info(f'Fetching price data for {self.ticker}')
|
| 46 |
+
try:
|
| 47 |
+
df = yf.download(
|
| 48 |
+
self.ticker,
|
| 49 |
+
start=period_start,
|
| 50 |
+
end=dt.datetime.now(),
|
| 51 |
+
interval='1d'
|
| 52 |
+
)
|
| 53 |
+
except Exception as e:
|
| 54 |
+
self.logger.error(f'{e}')
|
| 55 |
+
# create empty df
|
| 56 |
+
df = pd.DataFrame()
|
| 57 |
+
|
| 58 |
+
if df.shape[0] > 0:
|
| 59 |
+
# get rid of the redundant ticker column
|
| 60 |
+
df.columns = df.columns.droplevel('Ticker')
|
| 61 |
+
self.logger.debug(df.head(10))
|
| 62 |
+
self.logger.info(f'Fetched {df.shape[0]} rows for {self.ticker}')
|
| 63 |
+
|
| 64 |
+
return df
|
src/stock_analysis_agent.py
CHANGED
|
@@ -12,6 +12,7 @@ from langgraph.graph.message import add_messages
|
|
| 12 |
import logging
|
| 13 |
from pydantic import BaseModel, Field
|
| 14 |
|
|
|
|
| 15 |
from src.fetch_forecast import FetchForecast
|
| 16 |
from src.technical_analysis import TechnicalAnalysis
|
| 17 |
from src.fundamental_analysis import FundamentalAnalysis
|
|
@@ -27,10 +28,11 @@ def get_stock_prices(
|
|
| 27 |
ticker: str
|
| 28 |
The stock ticker symbol to fetch data for.
|
| 29 |
"""
|
|
|
|
| 30 |
df_past, df_fcst = FetchForecast(ticker).run()
|
| 31 |
df, _ = TechnicalAnalysis(
|
| 32 |
ticker=ticker,
|
| 33 |
-
|
| 34 |
df_past=df_past,
|
| 35 |
df_fcst=df_fcst,
|
| 36 |
plot_ta=False,
|
|
|
|
| 12 |
import logging
|
| 13 |
from pydantic import BaseModel, Field
|
| 14 |
|
| 15 |
+
from src.fetch_data import FetchData
|
| 16 |
from src.fetch_forecast import FetchForecast
|
| 17 |
from src.technical_analysis import TechnicalAnalysis
|
| 18 |
from src.fundamental_analysis import FundamentalAnalysis
|
|
|
|
| 28 |
ticker: str
|
| 29 |
The stock ticker symbol to fetch data for.
|
| 30 |
"""
|
| 31 |
+
df_hist = FetchData(ticker, fetchperiodinweeks=12).run()
|
| 32 |
df_past, df_fcst = FetchForecast(ticker).run()
|
| 33 |
df, _ = TechnicalAnalysis(
|
| 34 |
ticker=ticker,
|
| 35 |
+
df_hist=df_hist,
|
| 36 |
df_past=df_past,
|
| 37 |
df_fcst=df_fcst,
|
| 38 |
plot_ta=False,
|
src/technical_analysis.py
CHANGED
|
@@ -1,25 +1,22 @@
|
|
| 1 |
-
import datetime as dt
|
| 2 |
import logging
|
|
|
|
| 3 |
|
| 4 |
import dotenv
|
| 5 |
import matplotlib.pyplot as plt
|
| 6 |
import matplotlib.dates as mdates
|
| 7 |
from matplotlib.axes import Axes
|
| 8 |
import numpy as np
|
| 9 |
-
import os
|
| 10 |
import pandas as pd
|
| 11 |
from ta.volume import volume_weighted_average_price
|
| 12 |
from ta.momentum import RSIIndicator, StochasticOscillator
|
| 13 |
from ta.trend import MACD
|
| 14 |
-
import yfinance as yf
|
| 15 |
|
| 16 |
-
from src.fetch_forecast import FetchForecast
|
| 17 |
|
| 18 |
class TechnicalAnalysis():
|
| 19 |
def __init__(
|
| 20 |
self,
|
| 21 |
-
ticker:str,
|
| 22 |
-
|
| 23 |
df_past=None,
|
| 24 |
df_fcst=None,
|
| 25 |
plot_ta:bool=True,
|
|
@@ -31,8 +28,8 @@ class TechnicalAnalysis():
|
|
| 31 |
Args:
|
| 32 |
ticker : str
|
| 33 |
stock ticker to analyze
|
| 34 |
-
|
| 35 |
-
|
| 36 |
df_past: pd.DataFrame, optional, default: None
|
| 37 |
Closeing price of the ticker for the past few days
|
| 38 |
df_fcst: pd.DataFrame, optional, default: None
|
|
@@ -52,7 +49,7 @@ class TechnicalAnalysis():
|
|
| 52 |
|
| 53 |
# input arguments
|
| 54 |
self.ticker = ticker
|
| 55 |
-
self.
|
| 56 |
self.df_past = df_past
|
| 57 |
self.df_fcst = df_fcst
|
| 58 |
self.plot_ta = plot_ta
|
|
@@ -66,12 +63,10 @@ class TechnicalAnalysis():
|
|
| 66 |
"""
|
| 67 |
Main entry point for the TechnicalAnalysis object.
|
| 68 |
This method:
|
| 69 |
-
- fetches historical data from YahooFinance,
|
| 70 |
- computes the technical analysis metrics
|
| 71 |
- plots the price and TA metrics.
|
| 72 |
"""
|
| 73 |
-
|
| 74 |
-
df = self.fetch_data()
|
| 75 |
# add the features based on technical analysis
|
| 76 |
if df.shape[0] > 0:
|
| 77 |
df = self.tech_analysis(df)
|
|
@@ -100,48 +95,6 @@ class TechnicalAnalysis():
|
|
| 100 |
|
| 101 |
return df, fig
|
| 102 |
|
| 103 |
-
def fetch_data(
|
| 104 |
-
self
|
| 105 |
-
) -> pd.DataFrame:
|
| 106 |
-
"""
|
| 107 |
-
Fetches historical stock price data from Yahoo Finance.
|
| 108 |
-
This method downloads historical stock price data for the specified
|
| 109 |
-
ticker over a given period of weeks. The data is fetched on a daily
|
| 110 |
-
interval and stored in a pandas DataFrame. If the download is successful,
|
| 111 |
-
redundant ticker columns are removed, and logging information is
|
| 112 |
-
recorded. In case of failure, an empty DataFrame is returned and an
|
| 113 |
-
exception is raised.
|
| 114 |
-
Returns:
|
| 115 |
-
pd.DataFrame
|
| 116 |
-
A DataFrame containing the historical stock price data with columns
|
| 117 |
-
for open, high, low, close, volume, and adjusted close prices.
|
| 118 |
-
Raises:
|
| 119 |
-
Exception
|
| 120 |
-
If the data fetching fails, an exception is raised with an error
|
| 121 |
-
message.
|
| 122 |
-
"""
|
| 123 |
-
|
| 124 |
-
period_start = dt.datetime.now() - dt.timedelta(weeks=self.fetchperiodinweeks)
|
| 125 |
-
self.logger.info(f'Fetching price data for {self.ticker}')
|
| 126 |
-
try:
|
| 127 |
-
df = yf.download(
|
| 128 |
-
self.ticker,
|
| 129 |
-
start=period_start,
|
| 130 |
-
end=dt.datetime.now(),
|
| 131 |
-
interval='1d'
|
| 132 |
-
)
|
| 133 |
-
except Exception as e:
|
| 134 |
-
self.logger.error(f'{e}')
|
| 135 |
-
# create empty df
|
| 136 |
-
df = pd.DataFrame()
|
| 137 |
-
|
| 138 |
-
if df.shape[0] > 0:
|
| 139 |
-
# get rid of the redundant ticker column
|
| 140 |
-
df.columns = df.columns.droplevel('Ticker')
|
| 141 |
-
self.logger.debug(df.head(10))
|
| 142 |
-
self.logger.info(f'Fetched {df.shape[0]} rows for {self.ticker}')
|
| 143 |
-
|
| 144 |
-
return df
|
| 145 |
|
| 146 |
def tech_analysis(
|
| 147 |
self,
|
|
@@ -390,10 +343,13 @@ class TechnicalAnalysis():
|
|
| 390 |
|
| 391 |
if __name__ == '__main__':
|
| 392 |
ticker = 'AAPL'
|
| 393 |
-
#
|
|
|
|
|
|
|
| 394 |
dotenv.load_dotenv(dotenv.find_dotenv())
|
|
|
|
| 395 |
df_past, df_fcst = FetchForecast(ticker).run()
|
| 396 |
-
df, fig = TechnicalAnalysis(ticker, df_past=df_past, df_fcst=df_fcst, plot_ta=True, savefig=True, debug=False).run()
|
| 397 |
# print(f'columns: {df.columns}')
|
| 398 |
|
| 399 |
|
|
|
|
|
|
|
| 1 |
import logging
|
| 2 |
+
import os
|
| 3 |
|
| 4 |
import dotenv
|
| 5 |
import matplotlib.pyplot as plt
|
| 6 |
import matplotlib.dates as mdates
|
| 7 |
from matplotlib.axes import Axes
|
| 8 |
import numpy as np
|
|
|
|
| 9 |
import pandas as pd
|
| 10 |
from ta.volume import volume_weighted_average_price
|
| 11 |
from ta.momentum import RSIIndicator, StochasticOscillator
|
| 12 |
from ta.trend import MACD
|
|
|
|
| 13 |
|
|
|
|
| 14 |
|
| 15 |
class TechnicalAnalysis():
|
| 16 |
def __init__(
|
| 17 |
self,
|
| 18 |
+
ticker: str,
|
| 19 |
+
df_hist: pd.DataFrame,
|
| 20 |
df_past=None,
|
| 21 |
df_fcst=None,
|
| 22 |
plot_ta:bool=True,
|
|
|
|
| 28 |
Args:
|
| 29 |
ticker : str
|
| 30 |
stock ticker to analyze
|
| 31 |
+
df_hist: pd.DataFrame
|
| 32 |
+
historical price data for ticker
|
| 33 |
df_past: pd.DataFrame, optional, default: None
|
| 34 |
Closeing price of the ticker for the past few days
|
| 35 |
df_fcst: pd.DataFrame, optional, default: None
|
|
|
|
| 49 |
|
| 50 |
# input arguments
|
| 51 |
self.ticker = ticker
|
| 52 |
+
self.df_hist = df_hist
|
| 53 |
self.df_past = df_past
|
| 54 |
self.df_fcst = df_fcst
|
| 55 |
self.plot_ta = plot_ta
|
|
|
|
| 63 |
"""
|
| 64 |
Main entry point for the TechnicalAnalysis object.
|
| 65 |
This method:
|
|
|
|
| 66 |
- computes the technical analysis metrics
|
| 67 |
- plots the price and TA metrics.
|
| 68 |
"""
|
| 69 |
+
df = self.df_hist
|
|
|
|
| 70 |
# add the features based on technical analysis
|
| 71 |
if df.shape[0] > 0:
|
| 72 |
df = self.tech_analysis(df)
|
|
|
|
| 95 |
|
| 96 |
return df, fig
|
| 97 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 98 |
|
| 99 |
def tech_analysis(
|
| 100 |
self,
|
|
|
|
| 343 |
|
| 344 |
if __name__ == '__main__':
|
| 345 |
ticker = 'AAPL'
|
| 346 |
+
# testing
|
| 347 |
+
from src.fetch_forecast import FetchForecast
|
| 348 |
+
from src.fetch_data import FetchData
|
| 349 |
dotenv.load_dotenv(dotenv.find_dotenv())
|
| 350 |
+
df_hist = FetchData(ticker, fetchperiodinweeks=12).run()
|
| 351 |
df_past, df_fcst = FetchForecast(ticker).run()
|
| 352 |
+
df, fig = TechnicalAnalysis(ticker, df_hist=df_hist, df_past=df_past, df_fcst=df_fcst, plot_ta=True, savefig=True, debug=False).run()
|
| 353 |
# print(f'columns: {df.columns}')
|
| 354 |
|
| 355 |
|