<filename>indicator.py
import requests
import yfinance as yf
import pandas as pd
import time, datetime
import numpy as np
import csv
import data_access as dao


def ema(f_name, period, freq, signal=None):
    ''' 
    Calculate the Exponential Moving Average 
    EMA = (Current Close * (Smoothing/1+Days)) + Previous EMA * (1-(Smoothing/1+Days)))
        @params:
            period(int): The period over which the EMA is taken
        @return:
            Returns the full list of EMA values, incuding unused values as NaN
    '''

    # Read from file and create new df
    df = dao.read_data(f_name)
    df_size = len(df)-1

    # Find the data range based off the freq
    if (freq == '1d'):
        data_range = period
        signal_start = 26
    elif (freq == '15m'):
        data_range = period*26  # multiply by 26 15-minute periods within a trading day
        signal_start = 676 # 26 15-min periods in a trading day times 26 days
    else:
        data_range = 1
        print('ERROR: Unsupported Range')

    # Set the initial EMA to the average of first n elements; obtain index of the position
    total = 0
    count = 0
    if (signal == None):
        for i in range(data_range):
            total += df.iloc[i]['Close']
            count+=1
    else:
        for i in range(signal_start, data_range):
            total += df.iloc[i]['MACD']
            count+=1
    average = round(total/count, 4)
    ema_prev = average

    # Initialize elements before starting pos to NaN
    empty_list = np.empty(data_range-1)
    empty_list[:] = np.nan
    # from position period+1, calculate the EMA
    ema_list = [ema_prev]

    for i in range(data_range-1, df_size):
        close = df.iloc[i]['Close'] if (signal==None) else df.iloc[i]['MACD']
        factor = (2/(period+1))
        value = (close*factor) + (ema_prev*(1-factor))
        ema_prev = round(value, 4)
        ema_list.append(ema_prev)

    # Concatenate the emtpy list and list of values to create a new column
    full_list = [*empty_list, *ema_list]
    return full_list


def macd(f_name, freq):
    ''' 
    Calculate the MACD 
    MACD = 12-Period EMA - 26-Period EMA
    Adds new columns to dataframe and writes to a new file
    '''

    df = dao.read_data(f_name)
    df_size = len(df)
    # Calculate the 12-day and 26-day ema
    ema_12 = ema(f_name=f_name, period=12, freq=freq)
    ema_26 = ema(f_name=f_name, period=26, freq=freq)

    # Calculate the macd
    macd = []
    for i in range(df_size):
        if(ema_12[i] != np.nan and ema_26[i] != np.nan):
            macd.append(ema_12[i] - ema_26[i])

    # Add new columns to the df
    df['EMA_12'] = ema_12
    df['EMA_26'] = ema_26
    df['MACD'] = macd
    # Write to file so that macd can be read
    df.to_csv(f_name, index=False)

    # Calculate the macd signal (9-day ema of macd)
    signal = ema(f_name=f_name, period=34, freq=freq, signal=1)
    df['MACD_Signal'] = signal

    # Calculate histogram (macd - signal)
    hist = []
    for i in range(df_size):
        if(macd[i] != np.nan and signal[i] != np.nan):
            hist.append(macd[i]-signal[i])
    df['Hist'] = hist
    
    # Write data to file
    df.to_csv(f_name, index=False)
 

<filename>indicator.py
import requests
import yfinance as yf
import pandas as pd
import time, datetime
import numpy as np
import csv
import data_access as dao


def ema(f_name, period, freq, signal=None):
    ''' 
    Calculate the Exponential Moving Average 
    EMA = (Current Close * (Smoothing/1+Days)) + Previous EMA * (1-(Smoothing/1+Days)))
        @params:
            period(int): The period over which the EMA is taken
        @return:
            Returns the full list of EMA values, incuding unused values as NaN
    '''

    # Read from file and create new df
    df = dao.read_data(f_name)
    df_size = len(df)-1

    # Find the data range based off the freq
    if (freq == '1d'):
        data_range = period
        signal_start = 26
    elif (freq == '15m'):
        data_range = period*26  # multiply by 26 15-minute periods within a trading day
        signal_start = 676 # 26 15-min periods in a trading day times 26 days
    else:
        data_range = 1
        print('ERROR: Unsupported Range')

    # Set the initial EMA to the average of first n elements; obtain index of the position
    total = 0
    count = 0
    if (signal == None):
        for i in range(data_range):
            total += df.iloc[i]['Close']
            count+=1
    else:
        for i in range(signal_start, data_range):
            total += df.iloc[i]['MACD']
            count+=1
    average = round(total/count, 4)
    ema_prev = average

    # Initialize elements before starting pos to NaN
    empty_list = np.empty(data_range-1)
    empty_list[:] = np.nan
    # from position period+1, calculate the EMA
    ema_list = [ema_prev]

    for i in range(data_range-1, df_size):
        close = df.iloc[i]['Close'] if (signal==None) else df.iloc[i]['MACD']
        factor = (2/(period+1))
        value = (close*factor) + (ema_prev*(1-factor))
        ema_prev = round(value, 4)
        ema_list.append(ema_prev)

    # Concatenate the emtpy list and list of values to create a new column
    full_list = [*empty_list, *ema_list]
    return full_list


def macd(f_name, freq):
    ''' 
    Calculate the MACD 
    MACD = 12-Period EMA - 26-Period EMA
    Adds new columns to dataframe and writes to a new file
    '''

    df = dao.read_data(f_name)
    df_size = len(df)
    # Calculate the 12-day and 26-day ema
    ema_12 = ema(f_name=f_name, period=12, freq=freq)
    ema_26 = ema(f_name=f_name, period=26, freq=freq)

    # Calculate the macd
    macd = []
    for i in range(df_size):
        if(ema_12[i] != np.nan and ema_26[i] != np.nan):
            macd.append(ema_12[i] - ema_26[i])

    # Add new columns to the df
    df['EMA_12'] = ema_12
    df['EMA_26'] = ema_26
    df['MACD'] = macd
    # Write to file so that macd can be read
    df.to_csv(f_name, index=False)

    # Calculate the macd signal (9-day ema of macd)
    signal = ema(f_name=f_name, period=34, freq=freq, signal=1)
    df['MACD_Signal'] = signal

    # Calculate histogram (macd - signal)
    hist = []
    for i in range(df_size):
        if(macd[i] != np.nan and signal[i] != np.nan):
            hist.append(macd[i]-signal[i])
    df['Hist'] = hist
    
    # Write data to file
    df.to_csv(f_name, index=False)
 

Calculate the Exponential Moving Average      EMA = (Current Close * (Smoothing/1+Days)) + Previous EMA * (1-(Smoothing/1+Days)))         @params:             period(int): The period over which the EMA is taken         @return:             Returns the full list of EMA values, incuding unused values as NaN # Read from file and create new df # Find the data range based off the freq # multiply by 26 15-minute periods within a trading day # 26 15-min periods in a trading day times 26 days # Set the initial EMA to the average of first n elements; obtain index of the position # Initialize elements before starting pos to NaN # from position period+1, calculate the EMA # Concatenate the emtpy list and list of values to create a new column Calculate the MACD      MACD = 12-Period EMA - 26-Period EMA     Adds new columns to dataframe and writes to a new file # Calculate the 12-day and 26-day ema # Calculate the macd # Add new columns to the df # Write to file so that macd can be read # Calculate the macd signal (9-day ema of macd) # Calculate histogram (macd - signal) # Write data to file