From f9cab5f68461637911e70441e92837289d7ef082 Mon Sep 17 00:00:00 2001 From: lgeorgiev Date: Tue, 17 Sep 2024 18:58:44 -0400 Subject: [PATCH] adding first draft of the func --- build/lib/stocksim/__init__.py | 0 build/lib/stocksim/__main__.py | 4 +++ build/lib/stocksim/cli.py | 50 ++++++++++++++++++++++++++ pyproject.toml | 7 ++-- stocksim/cli.py | 64 +++++++++++++++++++++++++++------- 5 files changed, 110 insertions(+), 15 deletions(-) create mode 100644 build/lib/stocksim/__init__.py create mode 100644 build/lib/stocksim/__main__.py create mode 100644 build/lib/stocksim/cli.py diff --git a/build/lib/stocksim/__init__.py b/build/lib/stocksim/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/build/lib/stocksim/__main__.py b/build/lib/stocksim/__main__.py new file mode 100644 index 0000000..98dcca0 --- /dev/null +++ b/build/lib/stocksim/__main__.py @@ -0,0 +1,4 @@ +from .cli import cli + +if __name__ == "__main__": + cli() diff --git a/build/lib/stocksim/cli.py b/build/lib/stocksim/cli.py new file mode 100644 index 0000000..5a6a0e4 --- /dev/null +++ b/build/lib/stocksim/cli.py @@ -0,0 +1,50 @@ +import click +import yfinance as yf +import numpy as np +import pandas as pd +from datetime import datetime, timedelta + +@click.command() +@click.option('--ticker', required=True, help='Stock ticker symbol') +@click.option('--days', default=30, help='Number of days for simulation') +@click.option('--target-price', required=True, type=float, help='Target price for probability calculation') +@click.option('--simulations', default=1000, help='Number of Monte Carlo simulations') +def monte_carlo_simulation(ticker, days, target_price, simulations): + # Download historical data + end_date = datetime.now() + start_date = end_date - timedelta(days=5*365) # 5 years ago + data = yf.download(ticker, start=start_date, end=end_date) + + # Calculate daily returns + returns = data['Close'].pct_change().dropna() + + # Calculate mean and variance of daily returns + mu = returns.mean() + var = returns.var() + + # Simulate future stock prices + last_price = data['Close'].iloc[-1] + simulation_df = pd.DataFrame() + + for i in range(simulations): + prices = [last_price] + for _ in range(days): + price = prices[-1] * (1 + np.random.normal(mu, var**0.5)) + prices.append(price) + simulation_df[i] = prices + + # Calculate probability of exceeding target price + final_prices = simulation_df.iloc[-1] + prob_above_target = (final_prices > target_price).mean() + + # Output results + click.echo(f"Monte Carlo simulation results for {ticker}:") + click.echo(f"Number of simulations: {simulations}") + click.echo(f"Number of days: {days}") + click.echo(f"Target price: ${target_price:.2f}") + click.echo(f"Probability of price above target: {prob_above_target:.2%}") + click.echo(f"Current price: ${last_price:.2f}") + click.echo(f"Simulated price range: ${final_prices.min():.2f} - ${final_prices.max():.2f}") + +if __name__ == '__main__': + monte_carlo_simulation() diff --git a/pyproject.toml b/pyproject.toml index 2ff2365..aea4cb4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,12 +5,15 @@ description = "Simulate stock price over a future period" readme = "README.md" authors = [{name = "Lyubomir Georgiev"}] license = {text = "Apache-2.0"} -requires-python = ">=3.8" +requires-python = ">=3.10" classifiers = [ "License :: OSI Approved :: Apache Software License" ] dependencies = [ - "click" + "click", + "pandas", + "numpy", + "yfinance" ] [project.urls] diff --git a/stocksim/cli.py b/stocksim/cli.py index 53a6010..4c4649c 100644 --- a/stocksim/cli.py +++ b/stocksim/cli.py @@ -1,21 +1,59 @@ import click - +import yfinance as yf +import numpy as np +import pandas as pd +from datetime import datetime, timedelta @click.group() @click.version_option() def cli(): "Simulate stock price over a future period" +@click.command() +@click.option('--ticker', required=True, help='Stock ticker symbol') +@click.option('--days', default=30, help='Number of days for simulation') +@click.option('--target-price', required=True, type=float, help='Target price for probability calculation') +@click.option('--simulations', default=1000, help='Number of Monte Carlo simulations') +def cli(ticker, days, target_price, simulations): + # Download historical data + end_date = datetime.now() + start_date = end_date - timedelta(days=5*365) # 5 years ago + data = yf.download(ticker, start=start_date, end=end_date) + + # Calculate daily returns + returns = data['Close'].pct_change().dropna() + + # Calculate mean and variance of daily returns + mu = returns.mean() + var = returns.var() + + # Simulate future stock prices + last_price = data['Close'].iloc[-1] + + # Create a matrix of random returns + random_returns = np.random.normal(mu, var**0.5, size=(days, simulations)) + + # Calculate price paths + price_paths = last_price * np.exp(np.cumsum(random_returns, axis=0)) + + # Insert the initial price at the beginning of each path + price_paths = np.insert(price_paths, 0, last_price, axis=0) + + # Convert to DataFrame + simulation_df = pd.DataFrame(price_paths, columns=[f'Sim_{i}' for i in range(simulations)]) + + # Calculate probability of exceeding target price + final_prices = simulation_df.iloc[-1] + prob_above_target = (final_prices > target_price).mean() + + # Output results + click.echo(f"Monte Carlo simulation results for {ticker}:") + click.echo(f"Number of simulations: {simulations}") + click.echo(f"Number of days: {days}") + click.echo(f"Target price: ${target_price:.2f}") + click.echo(f"Probability of price above target: {prob_above_target:.2%}") + click.echo(f"Current price: ${last_price:.2f}") + click.echo(f"Simulated price range: ${final_prices.min():.2f} - ${final_prices.max():.2f}") -@cli.command(name="command") -@click.argument( - "example" -) -@click.option( - "-o", - "--option", - help="An example option", -) -def first_command(example, option): - "Command description goes here" - click.echo("Here is some output") +if __name__ == '__main__': + cli()