Refactor code to allow daily vs intraday data

This commit is contained in:
didier
2020-12-26 16:38:00 +00:00
parent 41a7221bd5
commit 7c9663b313
3 changed files with 133 additions and 107 deletions

View File

@@ -11,6 +11,14 @@
Finviz for data
Check AlphaVantage for TA as well.
Add s_ylabel and s_legend to plot_ta or plot_stock_ta
Daily Stock vs Intraday 5min Stock
Only show menu that allow daily TA or intraday TA,
i.e. if daily Stock don't show VWAP bc doesn't make sense!
Fix the 'help' params
"""
from alpha_vantage.timeseries import TimeSeries
@@ -27,7 +35,7 @@ import stock_market_technical_analysis as smta
import stock_market_fundamental_analysis as smfa
# -----------------------------------------------------------------------------------------------------------------------
def print_help(s_ticker, s_start, b_is_market_open):
def print_help(s_ticker, s_start, s_interval, b_is_market_open):
""" Print help
"""
print("What do you want to do?")
@@ -40,10 +48,12 @@ def print_help(s_ticker, s_start, b_is_market_open):
print(" help help to see this menu again")
print(" quit to abandon the program")
s_intraday = (f'Intraday {s_interval}', 'Daily')[s_interval == "1440min"]
if s_ticker and s_start:
print(f"\nStock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
print(f"\n{s_intraday} Stock: {s_ticker} (from {s_start.strftime('%Y-%m-%d')})")
elif s_ticker:
print(f"\nStock: {s_ticker}")
print(f"\n{s_intraday} Stock: {s_ticker}")
else:
print("\nStock: ?")
@@ -55,7 +65,8 @@ def print_help(s_ticker, s_start, b_is_market_open):
print(" sma simple moving average [daily]")
print(" ema exponential moving average [daily]")
print(" macd moving average convergence/divergence [daily]")
print(" vwap volume weighted average price [intraday]")
if s_interval != "1440min":
print(" vwap volume weighted average price [intraday]")
print(" stoch stochastic oscillator [daily]")
print(" rsi relative strength index [daily]")
@@ -86,6 +97,8 @@ def main():
s_ticker = ""
s_start = ""
df_stock = pd.DataFrame()
b_intraday = False
s_interval = "1440min"
# Set stock by default to speed up testing
s_ticker = "TSLA"
@@ -104,7 +117,7 @@ def main():
# Print first welcome message and help
print("\nWelcome to Didier's Stock Market Bot\n")
print_help(s_ticker, s_start, b_is_stock_market_open())
print_help(s_ticker, s_start, s_interval, b_is_stock_market_open())
print("\n")
# Loop forever and ever
@@ -136,17 +149,17 @@ def main():
# ---------------------------------------------------- LOAD ----------------------------------------------------
elif ns_known_args.cmd == 'load':
[s_ticker, s_start, df_stock] = smm.load(l_args, s_ticker, s_start, df_stock)
[s_ticker, s_start, s_interval, df_stock] = smm.load(l_args, s_ticker, s_start, s_interval, df_stock)
continue
# ---------------------------------------------------- VIEW ----------------------------------------------------
elif ns_known_args.cmd == 'view':
smm.view(l_args, s_ticker, s_start, df_stock)
smm.view(l_args, s_ticker, s_start, s_interval, df_stock)
continue
# ---------------------------------------------------- HELP ----------------------------------------------------
elif ns_known_args.cmd == 'help':
print_help(s_ticker, s_start, b_is_stock_market_open())
print_help(s_ticker, s_start, s_interval, b_is_stock_market_open())
# ----------------------------------------------------- QUIT ----------------------------------------------------
elif ns_known_args.cmd == 'quit':
@@ -170,32 +183,32 @@ def main():
# ---------------------------------------------------- SMA ----------------------------------------------------
elif ns_known_args.cmd == 'sma':
smta.sma(l_args, s_ticker, df_stock)
smta.sma(l_args, s_ticker, s_interval, df_stock)
continue
# ---------------------------------------------------- EMA ----------------------------------------------------
elif ns_known_args.cmd == 'ema':
smta.ema(l_args, s_ticker, df_stock)
smta.ema(l_args, s_ticker, s_interval, df_stock)
continue
# ---------------------------------------------------- MACD ----------------------------------------------------
elif ns_known_args.cmd == 'macd':
smta.macd(l_args, s_ticker, df_stock)
smta.macd(l_args, s_ticker, s_interval, df_stock)
continue
# ---------------------------------------------------- VWAP ----------------------------------------------------
elif ns_known_args.cmd == 'vwap':
smta.vwap(l_args, s_ticker, s_start)
smta.vwap(l_args, s_ticker, s_interval, df_stock)
continue
# ---------------------------------------------------- STOCH ----------------------------------------------------
elif ns_known_args.cmd == 'stoch':
smta.stoch(l_args, s_ticker, df_stock)
smta.stoch(l_args, s_ticker, s_interval, df_stock)
continue
# ---------------------------------------------------- RSI ----------------------------------------------------
elif ns_known_args.cmd == 'rsi':
smta.rsi(l_args, s_ticker, df_stock)
smta.rsi(l_args, s_ticker, s_interval, df_stock)
continue
# --------------------------------------------------------------------------------------------------------------

View File

@@ -1,5 +1,6 @@
import argparse
from alpha_vantage.timeseries import TimeSeries
import re
import config_bot as cfg
import pandas as pd
from stock_market_helper_funcs import *
@@ -26,67 +27,62 @@ def gainers(l_args):
print("")
# ----------------------------------------------------- LOAD -----------------------------------------------------
def load(l_args, s_ticker, s_start, df_stock):
parser = argparse.ArgumentParser(prog='load',
description=""" Given a stock market ticker, and an optional starting time,
load a stock in order to perform analysis""")
parser.add_argument('-t', "--ticker", action="store", dest="s_ticker", required=True, help='Stock ticker')
parser.add_argument('-s', "--start", type=valid_date, dest="s_start_date",
help="The starting date (format YYYY-MM-DD) of the stock")
def load(l_args, s_ticker, s_start, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='load', description=""" Load a stock in order to perform analysis""")
parser.add_argument('-t', "--ticker", action="store", dest="s_ticker", required=True, help="Stock ticker")
parser.add_argument('-s', "--start", type=valid_date, dest="s_start_date", help="The starting date (format YYYY-MM-DD) of the stock")
parser.add_argument('-i', "--interval", action="store", dest="n_interval", type=int, default=1440, choices=[1,5,15,30,60], help="Intraday stock minutes")
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
except SystemExit:
print("")
return [s_ticker, s_start, df_stock]
return [s_ticker, s_start, s_interval, df_stock]
if l_unknown_args:
print(f"The following args couldn't be interpreted: {l_unknown_args}")
# Update values:
s_ticker = ns_parser.s_ticker
s_start = ns_parser.s_start_date
s_interval = str(ns_parser.n_interval)+'min'
try:
# Currently only supports daily stocks
ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format='pandas')
df_stock, d_stock_metadata = ts.get_daily_adjusted(symbol=ns_parser.s_ticker, outputsize='full')
# Daily
if s_interval == "1440min":
df_stock, d_stock_metadata = ts.get_daily_adjusted(symbol=ns_parser.s_ticker, outputsize='full')
# Intraday
else:
df_stock, d_stock_metadata = ts.get_intraday(symbol=ns_parser.s_ticker, outputsize='full', interval=s_interval)
except:
print("Either the ticker or the API_KEY are invalids. Try again!")
return [s_ticker, s_start, df_stock]
return [s_ticker, s_start, s_interval, df_stock]
s_ticker = ns_parser.s_ticker
if ns_parser.s_start_date:
s_start = ns_parser.s_start_date
# Slice dataframe from the starting date YYYY-MM-DD selected
if ns_parser.s_start_date:
df_stock = df_stock[ns_parser.s_start_date:]
s_intraday = (f'Intraday {s_interval}', 'Daily')[s_interval == "1440min"]
if s_start:
print(f"Loading {s_ticker} stock with starting period {s_start.strftime('%Y-%m-%d')} for analysis.\n")
# Slice dataframe from the starting date YYYY-MM-DD selected
df_stock = df_stock[ns_parser.s_start_date:]
print(f"Loading {s_intraday} {s_ticker} stock with starting period {s_start.strftime('%Y-%m-%d')} for analysis.\n")
else:
print(f"Loading {s_ticker} stock for analysis.\n")
print(f"Loading {s_intraday} {s_ticker} stock for analysis.\n")
return [s_ticker, s_start, df_stock]
return [s_ticker, s_start, s_interval, df_stock]
# ----------------------------------------------------- VIEW -----------------------------------------------------
def view(l_args, s_ticker, s_start, df_stock):
parser = argparse.ArgumentParser(prog='view',
description='Given a stock market ticker, allows to see historical data of \
the corresponding stock. Note that the alpha_vantage key is necessary \
for this to work!')
def view(l_args, s_ticker, s_start, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='view', description='Visualise historical data of a stock. An alpha_vantage key is necessary.')
if s_ticker:
parser.add_argument('-t', "--ticker", action="store", dest="s_ticker", default=s_ticker, help='Stock ticker')
else:
parser.add_argument('-t', "--ticker", action="store", dest="s_ticker", required=True, help='Stock ticker')
parser.add_argument('-i', "--intraday", action="store_true", dest="b_intraday", default=False, help='Stock ticker')
parser.add_argument("--interval", action="store", dest="n_interval", type=int, default=15, choices=[1,5,15,30,60], help='Stock ticker')
parser.add_argument('-s', "--start", type=valid_date, dest="s_start_date",
help="The starting date (format YYYY-MM-DD) of the stock")
parser.add_argument('-s', "--start", type=valid_date, dest="s_start_date", help="The starting date (format YYYY-MM-DD) of the stock")
parser.add_argument('-i', "--interval", action="store", dest="n_interval", type=int, default=0, choices=[1,5,15,30,60], help="Intraday stock minutes")
parser.add_argument("--type", action="store", dest="n_type", type=check_positive, default=5, # in case it's daily
help='12345 corresponds to types: 1. open; 2. high; 3.low; 4. close; \
while 14 corresponds to types: 1.open; 4. close')
help='1234 corresponds to types: 1. open; 2. high; 3.low; 4. close; while 14 corresponds to types: 1.open; 4. close')
try:
(ns_parser, l_unknown_args) = parser.parse_known_args(l_args)
@@ -97,41 +93,34 @@ def view(l_args, s_ticker, s_start, df_stock):
if l_unknown_args:
print(f"The following args couldn't be interpreted: {l_unknown_args}")
# Update values:
s_ticker = ns_parser.s_ticker
if ns_parser.s_start_date:
s_start = ns_parser.s_start_date
# A new interval intraday period was given
if ns_parser.n_interval != 0:
s_interval = str(ns_parser.n_interval)+'min'
try:
# We want to view a different stock than the one we loaded
if ns_parser.s_ticker != s_ticker:
ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format='pandas')
df_stock, d_stock_metadata = ts.get_daily_adjusted(symbol=ns_parser.s_ticker, outputsize='full')
# We want to see intraday data about this stock
elif ns_parser.b_intraday:
ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format='pandas')
s_interval = str(ns_parser.n_interval)+'min'
df_stock, d_stock_metadata = ts.get_intraday(symbol=ns_parser.s_ticker, outputsize='full', interval=s_interval)
ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format='pandas')
# Daily
if s_interval == "1440min":
df_stock, d_stock_metadata = ts.get_daily_adjusted(symbol=s_ticker, outputsize='full')
# Intraday
else:
df_stock, d_stock_metadata = ts.get_intraday(symbol=s_ticker, outputsize='full', interval=s_interval)
except:
print("Either the ticker or the API_KEY are invalids. Try again!")
return
# Slice dataframe from the starting date YYYY-MM-DD selected
if ns_parser.s_start_date:
df_stock = df_stock[ns_parser.s_start_date:]
df_stock = df_stock[s_start:]
# Intraday data
if ns_parser.b_intraday:
# The default doesn't exist for intradaily data
if ns_parser.n_type == 5:
ln_col_idx = [3]
else:
ln_col_idx = [int(x)-1 for x in list(str(ns_parser.n_type))]
# Check that the types given are not bigger than 3, as there are only 4 types (0-3)
if len([i for i in ln_col_idx if i > 3]) > 0:
print("An index bigger than 3 was given, which is wrong. Try again")
return
# Append last column of df to be filtered which corresponds to: 5. Volume
ln_col_idx.append(4)
# Daily data
else:
# The default doesn't exist for intradaily data
# Daily
if s_interval == "1440min":
# The default doesn't exist for intradaily data
ln_col_idx = [int(x)-1 for x in list(str(ns_parser.n_type))]
if 4 not in ln_col_idx:
ln_col_idx.append(4)
@@ -141,5 +130,19 @@ def view(l_args, s_ticker, s_start, df_stock):
return
# Append last column of df to be filtered which corresponds to: 6. Volume
ln_col_idx.append(5)
# Intraday
else:
# The default doesn't exist for intradaily data
if ns_parser.n_type == 5:
ln_col_idx = [3]
else:
ln_col_idx = [int(x)-1 for x in list(str(ns_parser.n_type))]
# Check that the types given are not bigger than 3, as there are only 4 types (0-3)
if len([i for i in ln_col_idx if i > 3]) > 0:
print("An index bigger than 3 was given, which is wrong. Try again")
return
# Append last column of df to be filtered which corresponds to: 5. Volume
ln_col_idx.append(4)
# Plot view of the stock
plot_view_stock(df_stock.iloc[:, ln_col_idx], ns_parser.s_ticker)

View File

@@ -6,7 +6,7 @@ import config_bot as cfg
from stock_market_helper_funcs import *
# ----------------------------------------------------- SMA -----------------------------------------------------
def sma(l_args, s_ticker, df_stock):
def sma(l_args, s_ticker, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='sma',
description=""" Moving Averages are used to smooth the data in an array to
help eliminate noise and identify trends. The Simple Moving Average is literally
@@ -28,15 +28,21 @@ def sma(l_args, s_ticker, df_stock):
print(f"The following args couldn't be interpreted: {l_unknown_args}")
try:
df_ta = ta.sma(df_stock['5. adjusted close'], timeperiod=ns_parser.n_time_period).dropna()
plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, f"{ns_parser.n_time_period} SMA")
# Daily
if s_interval == "1440min":
df_ta = ta.sma(df_stock['5. adjusted close'], timeperiod=ns_parser.n_time_period).dropna()
plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, f"{ns_parser.n_time_period} SMA")
# Intraday
else:
df_ta = ta.sma(df_stock['4. close'], timeperiod=ns_parser.n_time_period).dropna()
plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, f"{ns_parser.n_time_period} SMA")
except:
print("")
return
# ----------------------------------------------------- EMA -----------------------------------------------------
def ema(l_args, s_ticker, df_stock):
def ema(l_args, s_ticker, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='ema',
description=""" The Exponential Moving Average is a staple of technical
analysis and is used in countless technical indicators. In a Simple Moving
@@ -59,15 +65,21 @@ def ema(l_args, s_ticker, df_stock):
print(f"The following args couldn't be interpreted: {l_unknown_args}")
try:
df_ta = ta.ema(df_stock['5. adjusted close'], timeperiod=ns_parser.n_time_period).dropna()
plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, f"{ns_parser.n_time_period} EMA")
# Daily
if s_interval == "1440min":
df_ta = ta.ema(df_stock['5. adjusted close'], timeperiod=ns_parser.n_time_period).dropna()
plot_stock_ta(df_stock['5. adjusted close'], s_ticker, df_ta, f"{ns_parser.n_time_period} EMA")
# Intraday
else:
df_ta = ta.ema(df_stock['4. close'], timeperiod=ns_parser.n_time_period).dropna()
plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, f"{ns_parser.n_time_period} EMA")
except:
print("")
return
# ----------------------------------------------------- MACD -----------------------------------------------------
def macd(l_args, s_ticker, df_stock):
def macd(l_args, s_ticker, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='macd',
description=""" The Moving Average Convergence Divergence (MACD) is the difference
between two Exponential Moving Averages. The Signal line is an Exponential Moving
@@ -98,12 +110,17 @@ def macd(l_args, s_ticker, df_stock):
print(f"The following args couldn't be interpreted: {l_unknown_args}")
try:
df_ta = ta.macd(df_stock['5. adjusted close'],
fast=ns_parser.n_fast,
slow=ns_parser.n_slow,
signal=ns_parser.n_signal,
offset=ns_parser.n_offset).dropna()
# Daily
if s_interval == "1440min":
df_ta = ta.macd(df_stock['5. adjusted close'],
fast=ns_parser.n_fast, slow=ns_parser.n_slow,
signal=ns_parser.n_signal, offset=ns_parser.n_offset).dropna()
# Intraday
else:
df_ta = ta.macd(df_stock['4. close'],
fast=ns_parser.n_fast, slow=ns_parser.n_slow,
signal=ns_parser.n_signal, offset=ns_parser.n_offset).dropna()
plot_ta(s_ticker, df_ta, f"{ns_parser.n_fast}-{ns_parser.n_slow}-{ns_parser.n_signal}-{ns_parser.n_offset} MACD")
except:
print("")
@@ -111,7 +128,7 @@ def macd(l_args, s_ticker, df_stock):
# ----------------------------------------------------- VWAP -----------------------------------------------------
def vwap(l_args, s_ticker, s_start):
def vwap(l_args, s_ticker, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='vwap',
description=""" The Volume Weighted Average Price that measures the average typical price
by volume. It is typically used with intraday charts to identify general
@@ -129,27 +146,15 @@ def vwap(l_args, s_ticker, s_start):
print(f"The following args couldn't be interpreted: {l_unknown_args}")
try:
ts = TimeSeries(key=cfg.API_KEY_ALPHAVANTAGE, output_format='pandas')
s_interval = str(ns_parser.n_interval)+'min'
df_stock, d_stock_metadata = ts.get_intraday(symbol=s_ticker, outputsize='full', interval=s_interval)
if s_start:
df_stock = df_stock[s_start:]
df_ta = ta.vwap(high=df_stock['2. high'], low=df_stock['3. low'], close=df_stock['4. close'], volume=df_stock['5. volume'], interval=s_interval)
plot_stock_ta(df_stock['4. close'], s_ticker, df_ta, f"{s_interval} VWAP")
# ti = TechIndicators(cfg.API_KEY_FINANCIALMODELINGPREP, output_format='pandas')
# df_ta, d_ta_metadata = ti.get_vwap(symbol=s_ticker, interval=s_interval)
# plot_ta(s_ticker, df_ta, f"{s_interval} VWAP")
except:
print("")
return
# ----------------------------------------------------- STOCH -----------------------------------------------------
def stoch(l_args, s_ticker, df_stock):
def stoch(l_args, s_ticker, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='stoch',
description=""" The Stochastic Oscillator measures where the close is in relation
to the recent trading range. The values range from zero to 100. %D values over 75
@@ -193,7 +198,7 @@ def stoch(l_args, s_ticker, df_stock):
# ----------------------------------------------------- RSI -----------------------------------------------------
def rsi(l_args, s_ticker, df_stock):
def rsi(l_args, s_ticker, s_interval, df_stock):
parser = argparse.ArgumentParser(prog='rsi',
description=""" The Relative Strength Index (RSI) calculates a ratio of the
recent upward price movements to the absolute price movement. The RSI ranges
@@ -214,8 +219,13 @@ def rsi(l_args, s_ticker, df_stock):
print(f"The following args couldn't be interpreted: {l_unknown_args}")
try:
df_ta = ta.rsi(df_stock['5. adjusted close'], time_period=ns_parser.n_timeperiod).dropna()
# Daily
if s_interval == "1440min":
df_ta = ta.rsi(df_stock['5. adjusted close'], time_period=ns_parser.n_timeperiod).dropna()
# Intraday
else:
df_ta = ta.rsi(df_stock['4. close'], time_period=ns_parser.n_timeperiod).dropna()
plot_ta(s_ticker, df_ta, f"{ns_parser.n_timeperiod} RSI")
except:
print("")