Skip to content

Commit

Permalink
Updated to python 3.13 and implementated code formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmad-masud committed Feb 17, 2025
1 parent 5bfeaca commit e28d019
Show file tree
Hide file tree
Showing 17 changed files with 121 additions and 78 deletions.
66 changes: 38 additions & 28 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"TSLA": "Tesla, Inc.",
}

print('''
print(
r"""
/$$$$$$ /$$ /$$ /$$$$$$$
/$$__ $$| $$$ /$$$| $$__ $$
| $$ \ $$| $$$$ /$$$$| $$ \ $$
Expand All @@ -24,62 +25,71 @@
| $$$$$$/| $$ \/ | $$| $$
\____ $$$|__/ |__/|__/
\__/
''')

"""
)


# Display the list of popular ticker symbols to the user.
print('Popular Ticker Symbols:\n')
print("Popular Ticker Symbols:\n")
for symbol, company in popular_ticker_symbols.items():
# Iterate through the dictionary of ticker symbols and print each one with its corresponding company name.
print(f"{symbol} - {company}")

# Prompt to guide users where they can find more ticker symbols.
print('\nFind more ticker symbols at https://stockanalysis.com/stocks/\n')
print("\nFind more ticker symbols at https://stockanalysis.com/stocks/\n")

while (True):
while True:
# Request user input for the ticker symbol they're interested in.
ticker_symbol = input('Enter the ticker symbol: ')
if yf.Ticker(ticker_symbol).history(period='20y').empty: # Check if the ticker symbol is invalid
ticker_symbol = input("Enter the ticker symbol: ").strip().upper()
if not ticker_symbol:
print("Ticker symbol cannot be empty. Please try again.")
continue

# Request user input for the period in years for which they want the data, with a constraint between 1 and 20 years.
period = input('How far back do you want data from, choose a period in years from 1 to 20: ')
if yf.Ticker(ticker_symbol).history(period="20y").empty:
print(f"Invalid ticker symbol: {ticker_symbol}. Please try again.")
continue

# Validate the period input to ensure it's a digit, and within the allowed range (1 to 20 years).
if (period.isdigit() == False) or (int(period) < 1) or (int(period) > 20):
# Request user input for the period in years for which they want the data, with a constraint between 1 and 20 years.
while True:
# Validate the period input to ensure it's a digit, and within the allowed range (1 to 20 years).
period = input("How far back do you want data from (1 to 20 years)? ")
if period.isdigit() and 1 <= int(period) <= 20:
period = int(period)
break
# If the input is invalid, notify the user and terminate the program.
print('Invalid period')
continue
print("Invalid input. Please enter a number between 1 and 20.")

while (True):
while True:
# Present the user with options for the functionality they wish to use.
print('1. Predict the future stock price')
print('2. Measure Stock Risk in Volatility')
print('3. Plot the historical stock data')
print('4. Change Ticker Symbol and/or Period')
print('5. Exit')
print("1. Predict the future stock price")
print("2. Measure Stock Risk in Volatility")
print("3. Plot the historical stock data")
print("4. Change Ticker Symbol and/or Period")
print("5. Exit")

# Capture the user's choice.
option = input('Choose an option: ')
option = input("Choose an option: ")

# Based on the user's choice, either predict future stock prices or plot historical data.
if option == '1':
if option == "1":
# If option 1, request the number of days into the future for which the prediction is desired.
x_days = int(input('Enter the number of days into the future for the prediction: '))
x_days = int(
input("Enter the number of days into the future for the prediction: ")
)
# Call the function to predict future price based on the inputs.
predict_future_price(ticker_symbol, x_days, period)
elif option == '2':
elif option == "2":
# If option 2, call the function to measure stock risk based on the ticker symbol and period.
risk_score(ticker_symbol, period)
elif option == '3':
elif option == "3":
# If option 2, call the function to plot historical data based on the ticker symbol and period.
plot_data(ticker_symbol, period)
elif option == '4':
elif option == "4":
# If option 3, break out of the current loop and prompt the user for a new ticker symbol and period.
break
elif option == '5':
elif option == "5":
# If option 4, terminate the program.
exit()
else:
# If the user enters an invalid option, notify them.
print('Invalid option')
print("Invalid option")
10 changes: 5 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
numpy==1.24.4
pandas==2.0.3
scikit-learn==1.3.2
yfinance==0.2.36
matplotlib==3.7.4
numpy>=1.24.4
pandas>=2.0.3
scikit-learn>=1.3.2
yfinance>=0.2.36
matplotlib>=3.7.4
2 changes: 1 addition & 1 deletion scripts/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .predict_future_price import predict_future_price
from .risk_score import risk_score
from .plot_data import plot_data
from .plot_data import plot_data
Binary file added scripts/__pycache__/__init__.cpython-313.pyc
Binary file not shown.
Binary file added scripts/__pycache__/plot_data.cpython-313.pyc
Binary file not shown.
Binary file not shown.
Binary file added scripts/__pycache__/risk_score.cpython-313.pyc
Binary file not shown.
24 changes: 16 additions & 8 deletions scripts/plot_data.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,40 @@
import yfinance as yf
import matplotlib.pyplot as plt


def plot_data(ticker_symbol, period) -> bool:
"""
Plots the historical stock data for a given stock based on its ticker symbol and the period in years.
:param ticker_symbol: The stock's ticker symbol as a string.
:param period: The period over which to calculate the risk score ('1mo', '3mo', '6mo', '1y', '2y', etc.).
:return: True if the plot is successful, False otherwise.
"""
# Fetch historical stock data
ticker = yf.Ticker(ticker_symbol)
ticker_data = ticker.history(period=f'{period}y')
ticker_data = ticker.history(period=f"{period}y")

# Calculate Average
ticker_data['Average'] = (ticker_data['High'] + ticker_data['Low']) / 2
ticker_data["Average"] = (ticker_data["High"] + ticker_data["Low"]) / 2

# Plot the historical stock data
plt.figure(figsize=(14, 7))
plt.plot(ticker_data.index, ticker_data['Average'], label='Daily Average Price', linewidth=1)
plt.plot(
ticker_data.index,
ticker_data["Average"],
label="Daily Average Price",
linewidth=1,
)

plt.title(f'Daily Average Price of {ticker.info["longName"]} Stock Over the Last {period} Years')
plt.xlabel('Date')
plt.ylabel('Average Price (USD)')
plt.title(
f'Daily Average Price of {ticker.info["longName"]} Stock Over the Last {period} Years'
)
plt.xlabel("Date")
plt.ylabel("Average Price (USD)")
plt.legend()
plt.grid(True)
plt.tight_layout()

plt.show()

return True;
return True
26 changes: 16 additions & 10 deletions scripts/predict_future_price.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,30 @@
def predict_future_price(ticker_symbol, x_days, period) -> float:
"""
Predicts the future stock price for a given stock based on its ticker symbol and the number of days into the future.
:param ticker_symbol: The stock's ticker symbol as a string.
:param x_days: The number of days into the future for the prediction as an integer.
:param period: The period over which to calculate the risk score ('1mo', '3mo', '6mo', '1y', '2y', etc.).
:return: The predicted future stock price as a float.
"""
# Fetch historical stock data
ticker = yf.Ticker(ticker_symbol)
ticker_data = ticker.history(period=f'{period}y')
ticker_data = ticker.history(period=f"{period}y")

# Preparing the data
ticker_data['Target'] = ticker_data['Close'].shift(-x_days)
ticker_data = ticker_data.dropna() # Dropping NA values to avoid issues in model training
ticker_data["Target"] = ticker_data["Close"].shift(-x_days)
ticker_data = (
ticker_data.dropna()
) # Dropping NA values to avoid issues in model training

# Features and Labels
X = ticker_data[['Close']]
y = ticker_data['Target']
X = ticker_data[["Close"]]
y = ticker_data["Target"]

# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)

# Linear Regression Model
model = LinearRegression()
Expand All @@ -38,16 +42,18 @@ def predict_future_price(ticker_symbol, x_days, period) -> float:

# MSE
mse = mean_squared_error(y_test, predictions)
print(f'Mean Squared Error: {mse}')
print(f"Mean Squared Error: {mse}")

# Predicting the future price based on the latest price
# Ensure the input for prediction matches the training data format
latest_price_df = pd.DataFrame({'Close': [ticker_data['Close'].iloc[-1]]})
latest_price_df = pd.DataFrame({"Close": [ticker_data["Close"].iloc[-1]]})

# Predicting a single future price using DataFrame to match training format
future_price = model.predict(latest_price_df)

# Print the predicted future price
print(f'Predicted stock price for {ticker.info["longName"]} {x_days} days into the future: {future_price[0]:.2f}')
print(
f'Predicted stock price for {ticker.info["longName"]} {x_days} days into the future: {future_price[0]:.2f}'
)

return round(future_price[0], 2)
15 changes: 8 additions & 7 deletions scripts/risk_score.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import yfinance as yf
import numpy as np


def risk_score(ticker_symbol, period) -> float:
"""
Calculates a risk score for a given stock based on its ticker symbol and history period.
:param ticker_symbol: The stock's ticker symbol as a string.
:param history_period: The period over which to calculate the risk score ('1mo', '3mo', '6mo', '1y', '2y', etc.).
:return: The risk score as a float.
"""
# Fetch historical stock data
ticker = yf.Ticker(ticker_symbol)
ticker_data = ticker.history(period=f'{period}y')
ticker_data = ticker.history(period=f"{period}y")

# Calculate daily returns
daily_returns = ticker_data['Close'].pct_change().dropna()
daily_returns = ticker_data["Close"].pct_change().dropna()

# Calculate the standard deviation of daily returns (volatility)
volatility = daily_returns.std()

# Annualize the volatility to get the risk score
# Assuming 252 trading days in a year
risk_score = volatility * np.sqrt(252)
Expand All @@ -41,6 +42,6 @@ def risk_score(ticker_symbol, period) -> float:
print("Risk Level: Very High Risk")
elif 0.6 < risk_score:
print("Risk Level: Extreme Risk")

# Return the risk score
return round(risk_score, 4)
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from setuptools import setup, find_packages

setup(
name='Quant-Market-Predictor',
version='0.1',
name="Quant-Market-Predictor",
version="0.1",
packages=find_packages(),
install_requires=[],
)
Binary file added tests/__pycache__/test_plot_data.cpython-313.pyc
Binary file not shown.
Binary file not shown.
Binary file added tests/__pycache__/test_risk_score.cpython-313.pyc
Binary file not shown.
13 changes: 8 additions & 5 deletions tests/test_plot_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@

from scripts import plot_data


class test_plot_data(unittest.TestCase):
def test_plot_data(self):
self.assertTrue(plot_data('aapl', 10))
self.assertTrue(plot_data('msft', 5))
self.assertTrue(plot_data('amzn', 17))
def test_plot_data_runs(self):
"""Ensure plot_data runs without errors and returns True."""
self.assertTrue(plot_data("aapl", 10))
self.assertTrue(plot_data("msft", 5))
self.assertTrue(plot_data("amzn", 17))


if __name__ == '__main__':
if __name__ == "__main__":
unittest.main()
19 changes: 13 additions & 6 deletions tests/test_predict_future_price.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,18 @@

from scripts import predict_future_price


class test_predict_future_price(unittest.TestCase):
def test_predict_future_price(self):
self.assertIsNotNone(predict_future_price('aapl', 50, 10))
self.assertIsNotNone(predict_future_price('msft', 75, 5))
self.assertIsNotNone(predict_future_price('amzn', 300, 17))
def test_prediction_returns_float(self):
"""Ensure predict_future_price returns a float."""
prediction = predict_future_price("AAPL", 30, 5)
self.assertIsInstance(prediction, float)

def test_prediction_is_positive(self):
"""Ensure predicted stock price is greater than zero."""
prediction = predict_future_price("MSFT", 30, 5)
self.assertGreater(prediction, 0)


if __name__ == '__main__':
unittest.main()
if __name__ == "__main__":
unittest.main()
20 changes: 14 additions & 6 deletions tests/test_risk_score.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@

from scripts import risk_score


class test_risk_score(unittest.TestCase):
def test_risk_score(self):
self.assertIsNotNone(risk_score('aapl', 10))
self.assertIsNotNone(risk_score('msft', 5))
self.assertIsNotNone(risk_score('amzn', 17))
def test_risk_score_returns_float(self):
"""Ensure risk_score returns a float."""
risk = risk_score("AAPL", 5)
self.assertIsInstance(risk, float)

def test_risk_score_is_within_range(self):
"""Ensure risk score is within reasonable bounds (0-2)."""
risk = risk_score("MSFT", 5)
self.assertGreaterEqual(risk, 0)
self.assertLessEqual(risk, 2)


if __name__ == '__main__':
unittest.main()
if __name__ == "__main__":
unittest.main()

0 comments on commit e28d019

Please sign in to comment.