-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #14 from jk1mm/dev
Merge dev to release
- Loading branch information
Showing
7 changed files
with
192 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
## Stock Analysis | ||
|
||
|
||
The **stock_profit** function within the analysis directory contains net profit | ||
view for a particular stock of interest. The following features are shown in the | ||
code snippet below. | ||
|
||
```python | ||
# Python | ||
|
||
# Import module | ||
from stock_market.analysis.stocks import stock_profit | ||
|
||
# Get the supposed net profit if 100 AAPL stocks were purchased | ||
# at market open on January 7 2021 and sold one week after before market close | ||
print( | ||
stock_profit(ticker="AAPL", | ||
quantity=100, | ||
purchase_date="2021-01-07", | ||
sell_date="2021-01-14", | ||
purchase_time="Open", | ||
sell_time="Close") | ||
) | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
pandas >= 1.1.5 | ||
numpy >= 1.19.4 | ||
pandas-datareader >= 0.9.0 | ||
pandas-datareader == 0.9.0 | ||
bs4 >= 0.0.1 | ||
requests >= 2.25.1 | ||
plotly >= 4.14.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
from stock_market.data import get_ticker | ||
from typing import Optional | ||
import pandas as pd | ||
import warnings | ||
|
||
|
||
MARKET_TIME = [ | ||
"open", # at market open | ||
"close", # at market close | ||
"high", # at day high price | ||
"low", # at day low price | ||
] | ||
|
||
|
||
def stock_profit( | ||
ticker: str, | ||
quantity: int, | ||
purchase_date: str, | ||
sell_date: str = None, | ||
purchase_time: str = "open", | ||
sell_time: str = "close", | ||
) -> Optional[float]: | ||
""" | ||
Stock calculator, to understand the net profit from buying and selling n number of stocks on a | ||
certain period of time. | ||
Parameters | ||
---------- | ||
ticker: str | ||
Stock ticker symbol. | ||
quantity: int | ||
Number of stocks purchased/sold. | ||
purchase_date: str | ||
Date of stock purchase. | ||
sell_date: str, default None | ||
Date of stock sell. If None, use current date. | ||
purchase_time: str, default "open" | ||
Time of purchase. | ||
sell_time: str, default "close" | ||
Time of sell. | ||
Returns | ||
------- | ||
net_profit: Optional[float] | ||
Net profit, in the respective exchange currency. | ||
""" | ||
# Check if purchase or sell time is valid | ||
purchase_time = purchase_time.lower() | ||
sell_time = sell_time.lower() | ||
if purchase_time not in MARKET_TIME or sell_time not in MARKET_TIME: | ||
raise Exception(f"Populate valid time metrics: {MARKET_TIME}") | ||
|
||
# TODO: Think of a more efficient way to do this | ||
|
||
# Call the ticker data | ||
ticker_history = get_ticker( | ||
ticker=ticker, start_date=purchase_date, end_date=sell_date, new_metrics=False | ||
) | ||
|
||
# If no data is returned (from invalid date range) | ||
if ticker_history is None: | ||
print("No stock history for requested date range.") | ||
return None | ||
|
||
# Checking validity of the requested days | ||
|
||
# For buy date, shift to next nearest day if invalid | ||
if pd.to_datetime(purchase_date) != ticker_history.index[0]: | ||
warnings.warn("Purchase date has been shifted to the next stock in market day.") | ||
|
||
# For sell date, shift to previous nearest day | ||
if pd.to_datetime(sell_date) != ticker_history.index[-1]: | ||
warnings.warn( | ||
"Sell date has been shifted back to the previous stock in market day." | ||
) | ||
|
||
# Re-format column names for standardization | ||
ticker_history.columns = ["high", "low", "open", "close", "volume", "adj close"] | ||
|
||
# Calculation | ||
|
||
# Edge case: for length == 1, raise warning for potential inaccurate results | ||
if len(ticker_history) == 1: | ||
warnings.warn( | ||
"Result may be inaccurate since buying and selling happens on the same day." | ||
) | ||
|
||
# Calculate | ||
net_profit = (ticker_history.loc[:, sell_time][-1] * quantity) - ( | ||
ticker_history.loc[:, purchase_time][0] * quantity | ||
) | ||
|
||
return net_profit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import pytest | ||
|
||
from stock_market.analysis.stocks import stock_profit | ||
|
||
|
||
def test_stock_profit(): | ||
# TODO: Add edge case of potential start and end date convergence | ||
|
||
# Invalid market time raises exception | ||
with pytest.raises(Exception): | ||
stock_profit( | ||
ticker="AAPL", | ||
quantity=100, | ||
purchase_date="2020-12-10", | ||
purchase_time="Invalid time", | ||
) | ||
|
||
# Invalid date range | ||
assert ( | ||
stock_profit( | ||
ticker="AAPL", | ||
quantity=100, | ||
purchase_date="2100-01-01", | ||
sell_date="2100-01-08", | ||
) | ||
is None | ||
) | ||
|
||
# Raise warning for non market date specification | ||
with pytest.warns(UserWarning): | ||
stock_profit( | ||
ticker="AAPL", | ||
quantity=100, | ||
purchase_date="2021-01-02", | ||
sell_date="2021-01-09", | ||
) | ||
|
||
# Raise warning for one day ticker history | ||
with pytest.warns(UserWarning): | ||
stock_profit( | ||
ticker="AAPL", | ||
quantity=100, | ||
purchase_date="2021-01-07", | ||
sell_date="2021-01-07", | ||
) | ||
|
||
# Check Value calculation results | ||
assert ( | ||
stock_profit(ticker="aapl", quantity=1, purchase_date="2021-01-14") | ||
== -1.8899993896484375 | ||
) |