def simulate_ema_strategy(df, symbol, market="us", reload=False): df = data_loader.load_price_history(symbol, start, now, market="us", reload=reload) directory = f"data/{market}/ema_sim/{start.strftime('%Y-%m-%d')}" if not os.path.exists(directory): os.makedirs(directory) if len(df) == 0: return np.nan smas_min = [3, 5, 8, 10, 12, 15] smas_max = [30, 35, 40, 45, 50, 60] smas_used = smas_min + smas_max len_cols = len(df.columns) for sma in smas_used: df[f"ema_{sma}"] = np.round(df.loc[:, "Adj Close"].rolling(window=sma).mean(), 2) pos = 0 num = 0 percent_change = [] bp = 0 for i in range(len(df)): c_min = np.min(df.iloc[i, len_cols:len_cols + len(smas_min)]) c_max = np.max(df.iloc[i, len_cols + len(smas_min):len_cols + len(smas_min) + len(smas_max)]) close = df["Adj Close"].iloc[i] if c_min > c_max: if pos == 0: bp = close pos = 1 elif c_min < c_max: if pos == 1: pos = 0 sp = close pc = (sp / bp - 1) * 100 percent_change.append(pc) if num >= len(df) and pos == 1: pos = 0 sp = close pc = (sp / bp - 1) * 100 percent_change.append(pc) num += 1 gains = 0 num_gains = 0 losses = 0 num_losses = 0 total_return = 1 for i in percent_change: if i > 0: gains += i num_gains += 1 else: losses += i num_losses += 1 total_return = total_return * ((i / 100) + 1) total_return = round((total_return - 1) * 100, 2) return total_return
def save_charts(df, period_months=24, moving_averages=(20, 50, 100, 200)): if period_months <= 12: chart_type = "candlestick" else: chart_type = "line" width, height = 11.69, 8.27 with PdfPages(f'all_screened_charts_{period_months}_months.pdf') as pdf: first_page = plt.figure(figsize=(width, height)) first_page.clf() txt = f"{len(df)} {chart_type} charts\nLast {period_months} months with {moving_averages} moving averages\n" \ f"{today.strftime('%d %B %Y')}" first_page.text(0.5, 0.5, txt, transform=first_page.transFigure, size=24, ha="center") pdf.savefig() plt.close() for index, row in df.iterrows(): symbol = row["Symbol"] name = row["Security"] div_rate_str = f"{row['dividendRate']}" if div_rate_str == "nan": div_rate_str = f", div. rate = 0" else: div_rate_str = f", div. rate = {row['dividendRate']:.4f}" title = f"\n\n\n{name} ({symbol})\nCurrent close = {row['Current Close']:.2f}\nRSI = {row['RSI']:.2f} " \ f"{div_rate_str}, 50 day MA = {row['50 Day MA']:.2f}" df = data_loader.load_price_history(symbol) fig, ax = mpf.plot( df[df.index >= today - relativedelta(months=period_months)], type=chart_type, mav=moving_averages, volume=True, title=title, returnfig=True, figsize=(width, height)) ax[0].legend(["Adjusted close"] + [f"{m} MA" for m in moving_averages]) pdf.savefig(fig) plt.close(fig)
msg = EmailMessage() start = dt.datetime(2018, 12, 1) now = dt.datetime.now() stock = "QQQ" target_price = 180 msg["Subject"] = f"Alert on {stock}" msg["From"] = email_address msg["To"] = email_address alerted = False df = data_loader.load_price_history(stock, start, now) current_close = df["Adj Close"][-1] condition = current_close > target_price if not alerted and condition: message = f"{stock} has activated the alert price of {target_price:.2f}\nCurrent price: {current_close:.2f}" print(message) msg.set_content(message) files = ["old/all_stocks.xlsx"] for file in files:
def indicator_chart(symbol, directory, start=dt.datetime(2020, 9, 1), smas=(10, 30, 50, 210), sentiment_value=None, frequency_value=None, prefix=None): print(f"Plotting ohlc chart for {symbol}...") try: start = start - dt.timedelta(days=max(smas)) now = dt.datetime.now() df = data_loader.load_price_history(symbol, start, now) if df is None or len(df) == 0: print(f"Dataframe is empty for {symbol}.") return date_delta = df.index[-1] - df.index[0] smas = [sma for sma in smas if sma < date_delta.days / 2] fig, ax = plt.subplots() fig.set_size_inches(18, 9) for sma in smas: df[f"SMA_{sma}"] = df["Adj Close"].rolling(window=sma).mean() # Bollinger bands bb_period = 15 # moving average std_dev = 2 df[f"SMA_{bb_period}"] = df["Adj Close"].rolling( window=bb_period).mean() df["std_dev"] = df["Adj Close"].rolling(window=bb_period).std() df["lower_band"] = df[F"SMA_{bb_period}"] - (std_dev * df["std_dev"] ) # upper Bollinger band df["upper_band"] = df[F"SMA_{bb_period}"] + (std_dev * df["std_dev"] ) # lower Bollinger band df["Date"] = mdates.date2num(df.index) # 10.4.4 stochastic period = 10 K = 4 D = 4 df["rol_high"] = df["High"].rolling( window=period).max() # high of period df["rol_low"] = df["High"].rolling( window=period).min() # low of period df["stok"] = ((df["Adj Close"] - df["rol_low"]) / (df["rol_high"] - df["rol_low"])) * 100 # 10.1 df["K"] = df["stok"].rolling(window=K).mean() # 10.4 df["D"] = df["K"].rolling(window=D).mean() # 10.4.4 df["GD"] = df["K"].rolling(window=D).mean() # green dots ohlc = [] df = df.iloc[max(smas):] green_dot_date = [] green_dot = [] last_K = 0 last_D = 0 last_low = 0 last_close = 0 last_low_bb = 0 # Iterate through price history creating candlesticks and green/blue dots for i in df.index: candlestick = df["Date"][i], df["Open"][i], df["High"][i], df[ "Low"][i], df["Adj Close"][i] ohlc.append(candlestick) # Green dot if df["K"][i] > df["D"][i] and last_K < last_D and last_K < 60: if 30 in smas and df["High"][i] > df["SMA_30"][i]: color = "chartreuse" else: color = "green" plt.plot(df["Date"][i], df["High"][i], marker="o", ms=8, ls="", color=color) plt.annotate(f"{df['High'][i]:.2f}", (df["Date"][i], df["High"][i]), fontsize=10) green_dot_date.append(i) green_dot.append(df["High"][i]) # Lower Bollinger Band Bounce if ((last_low < last_low_bb) or (df["Low"][i] < df["lower_band"][i])) and ( df["Adj Close"][i] > last_close and df["Adj Close"][i] > df["lower_band"][i]) and last_K < 60: plt.plot(df["Date"][i], df["Low"][i], marker="o", ms=8, ls="", color="deepskyblue") # plot blue dot plt.annotate(f"{df['Low'][i]:.2f}", (df["Date"][i], df["Low"][i]), xytext=(-10, 7), fontsize=10) # store values last_K = df["K"][i] last_D = df["D"][i] last_low = df["Low"][i] last_close = df["Adj Close"][i] last_low_bb = df["lower_band"][i] # Plot moving averages and BBands sma_colors = ["cyan", "magenta", "yellow", "orange"] for i, sma in enumerate( smas ): # This for loop calculates the EMAs for te stated periods and appends to dataframe df[f"SMA_{sma}"].plot(label=f"{sma} SMA", color=sma_colors[i]) df["upper_band"].plot(label="Upper Band", color="dimgray", linestyle=":") df["lower_band"].plot(label="Lower Band", color="dimgray", linestyle=":") # plot candlesticks candlestick_ohlc(ax, ohlc, width=0.75, colorup="w", colordown="r", alpha=0.75) ax.xaxis.set_major_formatter( mdates.DateFormatter("%B %d")) # change x axis back to datestamps ax.xaxis.set_major_locator( mticker.MaxNLocator(8)) # add more x axis labels plt.tick_params(axis="x", rotation=45) # rotate dates for readability # Pivot Points pivots = [] # Stores pivot values dates = [] # Stores Dates corresponding to those pivot values counter = 0 # Will keep track of whether a certain value is a pivot lastPivot = 0 # Will store the last Pivot value value_range = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] date_range = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] for i in df.index: current_max = max(value_range, default=0) value = np.round(df["High"][i], 2) value_range = value_range[1:9] date_range = date_range[1:9] value_range.append(value) date_range.append(i) if current_max == max(value_range, default=0): counter += 1 else: counter = 0 if counter == 5: last_pivot = current_max date_loc = value_range.index(last_pivot) last_date = date_range[date_loc] pivots.append(last_pivot) dates.append(last_date) timeD = dt.timedelta(days=30) # Sets length of dotted line on chart for index in range(len(pivots)): # Iterates through pivot array # print(str(pivots[index])+": "+str(dates[index])) #Prints Pivot, Date couple plt.plot_date( [dates[index] - (timeD * .075), dates[index] + timeD ], # Plots horizontal line at pivot value [pivots[index], pivots[index]], linestyle="--", linewidth=2, marker=",", color="chartreuse") plt.annotate(str(pivots[index]), (mdates.date2num(dates[index]), pivots[index]), xytext=(-10, 7), textcoords="offset points", fontsize=14, arrowprops=dict(arrowstyle="simple")) plt.xlabel("Date") # set x axis label plt.ylabel("Price") # set y axis label if sentiment_value is not None and frequency_value is not None: plt.title( f"{sentiment_charts.stock_label(symbol)} - daily indicator chart - " f"sentiment = {sentiment_value:.2f}, frequency = {frequency_value*100:.2f}%" ) else: plt.title( f"{sentiment_charts.stock_label(symbol)} - daily indicator chart" ) plt.ylim(df["Low"].min(), df["High"].max() * 1.05) # add margins # plt.yscale("log") plt.legend(loc="upper left") plt.grid() if prefix is not None: prefix_str = f"{prefix}_" else: prefix_str = "" file_path = f"public_html/finance/res/img/ohlc/{directory}" if not os.path.exists(file_path): os.makedirs(file_path) plt.savefig(f"{file_path}/{prefix_str}{symbol}_ohlc.png", dpi=150) plt.close(fig) plt.clf() except ValueError: print("ValueError for " + symbol) return
def screen_stock(symbol, market="us", reload=False, remove_screened=True): print(symbol) try: df = data_loader.load_price_history(symbol, reload=reload, market=market) if df is None: raise ValueError if not reload and len(df) > 0 and isinstance( df.index[-1], dt.datetime) and not ( (end_date.weekday() >= 5 and df.index[-1] >= end_date - dt.timedelta(days=3)) or (end_date.weekday() < 5 and df.index[-1] >= end_date - dt.timedelta(days=2))): df = data_loader.load_price_history(symbol, reload=True) if df is None or len(df) == 0: raise ValueError except ValueError: print(f"{symbol} not found.") return None smas_used = [50, 150, 200] for sma in smas_used: df[f"SMA_{sma}"] = np.round(df["Adj Close"].rolling(window=sma).mean(), 2) current_close = df["Adj Close"].iloc[-1] moving_average_50 = df["SMA_50"].iloc[-1] moving_average_150 = df["SMA_150"].iloc[-1] moving_average_200 = df["SMA_200"].iloc[-1] try: low_of_52_week = np.min(df["Adj Close"].iloc[-260:]) high_of_52_week = np.max(df["Adj Close"].iloc[-260:]) rs_rating = rsi(df) except IndexError: return None try: moving_average_200_20 = df["SMA_200"].iloc[-20] except IndexError: moving_average_200_20 = 0 # Condition 1: Current Price > 150 SMA and > 200 SMA cond_1 = current_close > moving_average_150 > moving_average_200 # Condition 2: 150 SMA > 200 SMA cond_2 = moving_average_150 > moving_average_200 # Condition 3: 200 SMA trending up for at least 1 month (ideally 4-5 months) cond_3 = moving_average_200 > moving_average_200_20 # Condition 4: 50 SMA > 150 SMA and 150 SMA > 200 SMA cond_4 = moving_average_50 > moving_average_150 > moving_average_200 # Condition 5: Current Price > 50 SMA cond_5 = current_close > moving_average_50 # Condition 6: Current Price is at least 30% above 52 week low (Many of the best are up 100-300% before # coming out of consolidation) cond_6 = current_close >= (1.3 * low_of_52_week) # Condition 7: Current Price is within 25% of 52 week high cond_7 = current_close >= (0.75 * high_of_52_week) # Condition 8: IBD RS rating >70 and the higher the better cond_8 = rs_rating > 70 is_screened = (cond_1 and cond_2 and cond_3 and cond_4 and cond_5 and cond_6 and cond_7 and cond_8) if remove_screened and not is_screened: return None if is_screened: is_screened_str = "PASS" else: is_screened_str = "FAIL" info_dict = data_loader.load_ticker_info(symbol, type_str="info", reload=reload) if info_dict is None: info_dict = {} for key in ["dividendRate", "dividendYield", "payoutRatio"]: if key not in info_dict: info_dict[key] = np.nan elif info_dict[key] is None: info_dict[key] = np.nan elif key == "dividendRate": info_dict[key] = np.round(info_dict[key], 2) else: info_dict[key] = np.round(info_dict[key], 4) for key in ["longName", "sector"]: if key not in info_dict: info_dict[key] = "" elif info_dict[key] is None: info_dict[key] = "" row = { "Security": info_dict["longName"], "Symbol": symbol.upper(), "Sector": info_dict["sector"], "RSI": np.round(rs_rating, 2), "Mark Minervini test": is_screened_str, "Current Close": np.round(current_close, 2), "div. Rate": info_dict["dividendRate"], "div. Yield": info_dict["dividendYield"], "Payout Ratio": info_dict["payoutRatio"], "Simulation % Return": simulator.simulate_ema_strategy(df, symbol, market=market, reload=reload), "50 Day MA": moving_average_50, "150 Day MA": moving_average_150, "200 Day MA": moving_average_200, "52 Week Low": low_of_52_week, "52 Week High": high_of_52_week, } for k, v in info_dict.items(): if k not in cols_to_remove and v is not None: # type(v) # if k == "longBusinessSummary": # row[k] = v.split('.')[0] # else: row[k] = v return row
import datetime as dt import matplotlib.pyplot as plt import numpy as np import data_loader start = dt.datetime(2019, 6, 1) now = dt.datetime.now() df = data_loader.load_price_history("amd", start, now) df["High"].plot(label="High") pivots = [] dates = [] counter = 0 last_pivot = 0 value_range = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] date_range = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] for i in df.index: current_max = max(value_range, default=0) value = np.round(df["High"][i], 2) value_range = value_range[1:9] date_range = date_range[1:9] value_range.append(value)
import datetime as dt import matplotlib.pyplot as plt import mplfinance as mpf import numpy as np import pandas as pd import data_loader as dl now = dt.datetime.today() df = dl.load_price_history("aapl", start_date=dt.datetime(2018, 1, 1)) df.drop(df[df["Volume"] < 1000].index, inplace=True) df_monthly = dl.monthly(df) # GLV: green line value gl_date = 0 last_glv = 0 current_date = None current_glv = 0 counter = 0 glv_list = [] gl_date_list = [] for index, value in df_monthly["High"].items(): if value > current_glv: current_glv = value