PacktPublishing / Predictive-Analytics-with-TensorFlow

Predictive Analytics with TensorFlow, published by Packt
MIT License
83 stars 71 forks source link

Chapter 11 - Yahoo-Finance no longer working #2

Closed windowshopr closed 5 years ago

windowshopr commented 5 years ago

Wondering if your code will be updated to a new historical data gathering tool as yahoo-finance doesn't work anymore? Maybe iexfinance or Alpha Vantage. And could the predictive model use .csv files instead of .npy? Thanks! Great work!

rezacsedu commented 5 years ago

@windowshopr thanks for filing this issue. I just executed the code once again, which is working fine. I've uploaded the updated codes (mostly tested on TensorFlow 1.8 about 3 months ago, though) as Notebook in each chapter.

But you're right sometimes Yahoo-finance doesn't work. However, I don't have have any workaround here because I'm pretty overloaded at the moment.

Please try running the corresponding Notebook file and let me know it went.

rezacsedu commented 5 years ago

https://github.com/PacktPublishing/Predictive-Analytics-with-TensorFlow/blob/master/Chapter11/StockPricePrediction.ipynb

windowshopr commented 5 years ago

Thanks for the suggestion! This repository was the first one I came across in the Packt Publishing suite haha. I will give the notebook a shot and if there are any issues, I will report back. Maybe this weekend when I get some time, I'll see if I can tweak the existing code to pull the historical data from another source and make a pull request, so that both options could be available.

Thanks!

windowshopr commented 5 years ago

@rezacsedu The notebook worked great. I've made some modifications to convert the .npy to a .csv file and using that for the simulations, but not before running a wavelet transform to denoise the stock data (although probably not super applicable here, it is a feature that I'll want to use in future use). I will also be updating where the historical data is sourced from someday.

I've attached my edited code below here just for reference. One question I did have, could you explain the (avg, std) that gets printed at the end? Is the avg the average ending portfolio size out of all 100 simulations, and what would the std deviation depict? Just a newbie question. Thanks!

import warnings
warnings.filterwarnings("ignore")

from yahoo_finance import Share
from matplotlib import pyplot as plt
import numpy as np
import random
import tensorflow as tf
import random
import pywt
from numpy import genfromtxt

class DecisionPolicy:
    def select_action(self, current_state, step):
        pass

    def update_q(self, state, action, reward, next_state):
        pass

class RandomDecisionPolicy(DecisionPolicy):
    def __init__(self, actions):
        self.actions = actions

    def select_action(self, current_state, step):
        action = self.actions[random.randint(0, len(self.actions) - 1)]
        return action

class QLearningDecisionPolicy(DecisionPolicy):
    def __init__(self, actions, input_dim):
        self.epsilon = 0.5
        self.gamma = 0.001
        self.actions = actions
        output_dim = len(actions)
        h1_dim = 200

        self.x = tf.placeholder(tf.float32, [None, input_dim])
        self.y = tf.placeholder(tf.float32, [output_dim])
        W1 = tf.Variable(tf.random_normal([input_dim, h1_dim]))
        b1 = tf.Variable(tf.constant(0.1, shape=[h1_dim]))
        h1 = tf.nn.relu(tf.matmul(self.x, W1) + b1)
        W2 = tf.Variable(tf.random_normal([h1_dim, output_dim]))
        b2 = tf.Variable(tf.constant(0.1, shape=[output_dim]))
        self.q = tf.nn.relu(tf.matmul(h1, W2) + b2)

        loss = tf.square(self.y - self.q)
        self.train_op = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
        self.sess = tf.Session()
        self.sess.run(tf.initialize_all_variables())

    def select_action(self, current_state, step):
        threshold = min(self.epsilon, step / 1000.)
        if random.random() < threshold:
            # Exploit best option with probability epsilon
            action_q_vals = self.sess.run(self.q, feed_dict={self.x: current_state})
            action_idx = np.argmax(action_q_vals)  # TODO: replace w/ tensorflow's argmax
            action = self.actions[action_idx]
        else:
            # Explore random option with probability 1 - epsilon
            action = self.actions[random.randint(0, len(self.actions) - 1)]
        return action

    def update_q(self, state, action, reward, next_state):
        action_q_vals = self.sess.run(self.q, feed_dict={self.x: state})
        next_action_q_vals = self.sess.run(self.q, feed_dict={self.x: next_state})
        next_action_idx = np.argmax(next_action_q_vals)
        action_q_vals[0, next_action_idx] = reward + self.gamma * next_action_q_vals[0, next_action_idx]
        action_q_vals = np.squeeze(np.asarray(action_q_vals))
        self.sess.run(self.train_op, feed_dict={self.x: state, self.y: action_q_vals})

def run_simulation(policy, initial_budget, initial_num_stocks, my_data, hist, debug=False):
    budget = initial_budget
    num_stocks = initial_num_stocks
    share_value = 0
    transitions = list()
    for i in range(len(my_data) - hist - 1):
        if i % 100 == 0:
            print('progress {:.2f}%'.format(float(100*i) / (len(my_data) - hist - 1)))
        current_state = np.asmatrix(np.hstack((my_data[i:i+hist], budget, num_stocks)))
        current_portfolio = budget + num_stocks * share_value
        action = policy.select_action(current_state, i)
        share_value = float(my_data[i + hist + 1])
        if action == 'Buy' and budget >= share_value:
            budget -= share_value
            num_stocks += 1
        elif action == 'Sell' and num_stocks > 0:
            budget += share_value
            num_stocks -= 1
        else:
            action = 'Hold'
        new_portfolio = budget + num_stocks * share_value
        reward = new_portfolio - current_portfolio
        next_state = np.asmatrix(np.hstack((my_data[i+1:i+hist+1], budget, num_stocks)))
        transitions.append((current_state, action, reward, next_state))
        policy.update_q(current_state, action, reward, next_state)

    portfolio = budget + num_stocks * share_value
    if debug:
        print('${}\t{} shares'.format(budget, num_stocks))
    return portfolio

def run_simulations(policy, budget, num_stocks, my_data, hist):
    num_tries = 100
    final_portfolios = list()
    for i in range(num_tries):
        final_portfolio = run_simulation(policy, budget, num_stocks, my_data, hist)
        final_portfolios.append(final_portfolio)
    avg, std = np.mean(final_portfolios), np.std(final_portfolios)
    return avg, std

def get_prices(share_symbol, start_date, end_date, cache_filename):
    try:
        stock_prices = np.load(cache_filename)
    except IOError:
        share = Share(share_symbol)
        stock_hist = share.get_historical(start_date, end_date)
        stock_prices = [stock_price['Open'] for stock_price in stock_hist]
        np.save(cache_filename, stock_prices)

    return stock_prices

def plot_prices(my_data):
    plt.title('Opening stock prices')
    plt.xlabel('day')
    plt.ylabel('price ($)')
    plt.plot(my_data)
    plt.savefig('my_data.png')

if __name__ == '__main__':
    prices = get_prices('MSFT', '2000-07-01', '2017-07-01', r'C:\Users\windowshopr\Desktop\Python Scripts\Stock Market Prediction\Predictive Analytics with TensorFlow\Chapter11\resource\stock_prices.npy')

    # Perform wavelet transform to preprocess stock data 
    x = np.array(prices)                
    (ca, cd) = pywt.dwt(x, "haar")                
    cat = pywt.threshold(ca, np.std(ca), mode="soft")                
    cdt = pywt.threshold(cd, np.std(cd), mode="soft")                
    tx = pywt.idwt(cat, cdt, "haar")

    # Save data as .csv file to use for simulation
    np.savetxt('stock_prices.csv', tx, delimiter=",", fmt="%s") 

    my_data = genfromtxt('stock_prices.csv', delimiter=',')
    plot_prices(my_data)

    actions = ['Buy', 'Sell', 'Hold']
    hist = 200
    policy = RandomDecisionPolicy(actions)

    budget = 1000.0
    num_stocks = 0
    avg, std = run_simulations(policy, budget, num_stocks, my_data, hist)
    print(avg, std)