Deep Optimal Portfolios

In the sequel we shall construct optimal portfolios.

The code is based on great work of my master student Michael Giegrich, whose work is based on the paper Deep Hedging by Hans Bühler, Lukas Gonon, Josef Teichmann and Ben Wood.

We use the fundamental concept of expect utility. Let $ u $ be a concave utility function (always assumed $C^2$, strictly concave and strictly increasing on its domain: typical examples are $ \log(x) $, $ 1 - \exp(-\gamma x) $ for $ \gamma > 0 $ or $ \frac{x^{1 - \eta}-1}{1-\eta} $ for real $ \eta > 0 $).

Economic decision making is based on preferences and optimal decisions in their presence. This often leads to convex optimization for which existence and algorithmic construction of solutions can be easily described.

General duality theory yields in a setting with finitely many scenarios that the following problem is well posed in absence of arbitrage for every initial captial $ x $ and has a unique solution: $$ \sup_{H \text{ predictable strategy}} E_P[u(x + (H \bullet S))] \, . $$ Here it is also possible to account for transaction costs since the intial capital $ x $ is fixed.

The idea is simple: 'large' portfolios create large negative values due to the absence of arbitrage. Analogue arguments hold in the presence of transaction costs:

  1. Assume the existence of an optimal portfolio $ H^* $, then at $ H^* $ we have $$ E_P[u'((x + H^* \bullet S)) (S_t - S_s)] = 0 $$ for all $ t \geq s $ by the first order condition, i.e. the derivative of the utility function (a positive quantity) is a multiple of a martingale measure at the optimal portfolio. Whence no arbitrage.
  2. Assume no arbitrage, then 'large' portfolios lead to small gains in utility but large losses, whence the existence of a finite optimizer.

Economically speaking this describes a general way of pricing claims with many reasonable properties. We denote transaction costs by $ c(H) $ and a claim by $ F $. The indifference price $ p $ for $ F $ given transaction costs and an initial capital $ x$ is defined by $$ \sup_{H \text{ predictable strategy}} E_P[u(x + (H \bullet S))] = \sup_{H \text{ predictable strategy}} E_P[u(x + p + (H \bullet S)) - F] \, . $$

Such prices can be relatively easily calculated by machine learning techniques.

In [1]:
import os
import time
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'
import tensorflow as tf
import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
import scipy.stats as ss

# Set Parameters
np.random.seed(2)
tf.set_random_seed(2)
global_step = tf.Variable(0, trainable=False)
t0 = time.time()
class parameters():
    def __init__(self):
        self.NUM_EPOCHS = 40
        self.TIME_STEPS = 52
        self.NUM_ASSETS = 1#50
        self.NUM_RELAVENT = 1 
        self.NUM_SAMPLES = 100000
        self.BATCH_SIZE = 258
        self.NUM_BATCHES = self.NUM_SAMPLES // self.BATCH_SIZE
        self.hidden_dim1 = 2*self.NUM_ASSETS
        self.hidden_dim2 = 2*self.NUM_ASSETS
        self.LEARNING_RATE = 0.0005
        self.NUM_TEST = 10000
        self.training = 1
        self.decay = 0.999
        self.minimal_loss = 100.0 #Determines if model is saved
        self.NUM_VALIDATION = 10000
        self.L1_LAMBDA = 0.001 #Parameter for L1-Penalty
        self.correlated = True
        self.corr = 1
        self.initialcapital = 1
        self.epsilon = 0.01
/usr/lib64/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
In [2]:
#############################################
# Generates Model Hedge And Price For Calls #
#############################################
def delta_BS(S, sigma = 0.2, K = 100., r = 0.1, T =52./52.):
    delta_hedge = []
    time_steps = int(T*52)
    for i in range(time_steps-1):
        i_ratio = float(i)/52.
        delta = (ss.norm.cdf((np.log(S[:,i]/K) +(r+sigma**2/2)*(T-i_ratio))/(sigma*np.sqrt(T-i_ratio))))
        delta_hedge.append(delta)
    delta_hedge = np.stack(delta_hedge, axis=1)
    return delta_hedge
def d1(S0, K, r, sigma, T):
    return (np.log(S0/K) + (r + sigma**2 / 2) * T)/(sigma * np.sqrt(T)) 
def d2(S0, K, r, sigma, T):
    return (np.log(S0 / K) + (r -sigma**2 / 2) * T) / (sigma * np.sqrt(T)) 
def BlackScholes(S0, sigma = 0.2, K = 100., r = 0., T =52./52.):
    return (S0 * ss.norm.cdf(d1(S0, K, r, sigma, T)) - K * np.exp(-r * T)* ss.norm.cdf(d2(S0, K, r, sigma, T)))
In [3]:
import math as m

####################
# Generate Samples #
####################
def SampleGenerator(NumOfAssets ,corr, NumOfRelevant = 5,InitPrice =  1, rf_rate = 0.1, dt = 1./52.,TimeSteps = 52, sigma = 0.2, K = 100.):
    S0 = np.ones(NumOfAssets)*InitPrice
    features = np.zeros((TimeSteps, NumOfAssets))
    L = np.linalg.cholesky(corr)
    features[0, 0:NumOfAssets] = S0
    for i in range(1, TimeSteps):
        W = m.sqrt(dt)*np.dot(L,np.random.randn(NumOfAssets))
        features[i, 0:NumOfAssets] =(features[i-1, 0:NumOfAssets]*np.exp((rf_rate*np.ones(NumOfAssets)-0.5*sigma*sigma)*dt+sigma*W)) 
    FinalPrices = features[TimeSteps-1, 0:NumOfRelevant]
    value = np.maximum(FinalPrices - K, 0)  
    value = np.sum(value)
    return features, value

###############################
# Generate Correlation Matrix #
###############################
def corr(NumOfAssets):
    dim = NumOfAssets
    A = np.random.normal(3, 8,size=(dim,dim))
    cov = np.dot(A,np.transpose(A))
    D = np.identity(dim)/np.sqrt(np.diag(cov))
    corr = np.dot(D,np.dot(cov,D))
    return corr 

#################
# Generate Data #
#################
def DataGenerator(NumOfSamples, TimeSteps = 52,NumOfAssets = 50, corr = 1, correlated = False,NumOfRelevant = 5):
    if not(correlated): 
        corr = np.eye(NumOfAssets)
    features = np.zeros((NumOfSamples, TimeSteps, NumOfAssets))
    labels = np.zeros((NumOfSamples))
    for i in range(1, NumOfSamples+1):
        features[i-1, :, :], labels[i-1] = SampleGenerator(
        NumOfAssets, TimeSteps=TimeSteps, corr=corr, 
        NumOfRelevant = NumOfRelevant)
    labels = labels.reshape((NumOfSamples, 1))
    return features, labels
In [4]:
##########################
# Generate Price Tensors #
##########################
def price(FLAGS):
    price = FLAGS.initialcapital*np.ones((FLAGS.BATCH_SIZE))
    q = tf.constant(price, dtype = tf.float32)
    return q
def price_test(FLAGS):
    price = FLAGS.initialcapital*np.ones((FLAGS.NUM_TEST))
    q = tf.constant(price, dtype = tf.float32)
    return q
def price_valid(FLAGS):
    price = FLAGS.initialcapital*np.ones((FLAGS.NUM_VALIDATION))
    q = tf.constant(price, dtype = tf.float32)
    return q

###############################
# Functions for Data-Pipeline #
###############################
def generate_data(FLAGS):
    X, Y = DataGenerator(FLAGS.NUM_SAMPLES,TimeSteps = FLAGS.TIME_STEPS, corr = FLAGS.corr,correlated = FLAGS.correlated, NumOfAssets = FLAGS.NUM_ASSETS,NumOfRelevant = FLAGS.NUM_RELAVENT)
    return X, Y
def generate_test_data(FLAGS):
    X, Y = DataGenerator(FLAGS.NUM_TEST,TimeSteps = FLAGS.TIME_STEPS, corr = FLAGS.corr,correlated = FLAGS.correlated, NumOfAssets = FLAGS.NUM_ASSETS,NumOfRelevant = FLAGS.NUM_RELAVENT)
    return X, Y
def generate_validation_data(FLAGS):
    X, Y = DataGenerator(FLAGS.NUM_VALIDATION,TimeSteps = FLAGS.TIME_STEPS, corr = FLAGS.corr,correlated = FLAGS.correlated, NumOfAssets = FLAGS.NUM_ASSETS,NumOfRelevant = FLAGS.NUM_RELAVENT)
    return X, Y  
def generate_batch(FLAGS, raw_data):
    raw_X, raw_y = raw_data
    # Create Batches from Raw Data
    num_batches = FLAGS.NUM_SAMPLES // FLAGS.BATCH_SIZE 
    data_X = np.zeros([FLAGS.BATCH_SIZE, FLAGS.NUM_ASSETS,FLAGS.TIME_STEPS], dtype=np.float32)
    data_y = np.zeros([FLAGS.BATCH_SIZE], dtype=np.float32)
    for i in range(num_batches):
        data_X = (raw_X[FLAGS.BATCH_SIZE * i:FLAGS.BATCH_SIZE * (i+1), :, :])
        data_y = raw_y[FLAGS.BATCH_SIZE * i:FLAGS.BATCH_SIZE * (i+1)]
        yield (data_X, data_y)
def generate_epochs(FLAGS):
    for i in range(FLAGS.NUM_EPOCHS):
        yield generate_batch(FLAGS, FLAGS.data)

#######################
# Batch Normalization #
#######################
def batch_norm(FLAGS, x, name):
    with tf.variable_scope(name, reuse=tf.AUTO_REUSE):
        if FLAGS.training==2:
            FLAGS.decay = 0
        elif FLAGS.training==3:
            FLAGS.decay = FLAGS.NUM_SAMPLES/(FLAGS.NUM_SAMPLES
                                             +FLAGS.NUM_TEST)
        param_shape = [x.get_shape()[-1]]
        batch_mean, batch_var = tf.nn.moments(x, [0], name='moments')
        pop_mean = tf.get_variable('moving_mean', param_shape,tf.float32, initializer=tf.constant_initializer(0.0),trainable=False)
        pop_var = tf.get_variable('moving_variance', param_shape,tf.float32, initializer=tf.constant_initializer(1.0),trainable=False)
        train_mean_op = tf.assign(pop_mean, pop_mean * FLAGS.decay + batch_mean * (1 - FLAGS.decay))
        train_var_op = tf.assign(pop_var, pop_var * FLAGS.decay + batch_var * (1 - FLAGS.decay))
        if FLAGS.training==1:
            with tf.control_dependencies([train_mean_op, train_var_op]):
                return tf.nn.batch_normalization(x, batch_mean, batch_var, 0, 1, 1e-3)
        elif FLAGS.training==2:
            with tf.control_dependencies([train_mean_op, train_var_op]):
                return tf.nn.batch_normalization(x, batch_mean, batch_var, 0, 1, 1e-3)
        elif FLAGS.training==3:
            with tf.control_dependencies([train_mean_op, train_var_op]):
                return tf.nn.batch_normalization(x, pop_mean,pop_var, 0, 1, 1e-3)

###################
# Define RNN Cell #
###################
def rnn_cell(FLAGS, rnn_input, state, name):
    with tf.variable_scope('rnn_cell'+ str(name), reuse=True):
      input_ = tf.concat( [rnn_input, state], axis = 1)
      W1 = tf.get_variable('W1',[FLAGS.NUM_ASSETS*2, FLAGS.hidden_dim1],initializer=tf.random_normal_initializer(stddev=0.1))
      b1 = tf.get_variable('b1', [FLAGS.hidden_dim1],initializer=tf.constant_initializer(0.0))
      W2 = tf.get_variable('W2',[FLAGS.hidden_dim1, FLAGS.hidden_dim2],initializer=tf.random_normal_initializer(stddev=0.1))
      b2 = tf.get_variable('b2', [FLAGS.hidden_dim2],initializer=tf.constant_initializer(0.0))
      W3 = tf.get_variable('W3',[FLAGS.hidden_dim2, FLAGS.NUM_ASSETS], initializer=tf.random_normal_initializer(stddev=0.1))
      b3 = tf.get_variable('b3', [FLAGS.NUM_ASSETS],initializer=tf.constant_initializer(0.0))
      input_ = batch_norm(FLAGS, input_, 'Layer_0')
      out1 = tf.matmul(input_, W1) + b1
      hidden_out1 = tf.nn.relu(out1)
      out2 = batch_norm(FLAGS, hidden_out1, 'Layer_1')
      out2 = tf.matmul(out2, W2) + b2
      hidden_out2 = tf.nn.relu(out2)
      output =tf.matmul(hidden_out2, W3) + b3
      return output, W3, b3, W2, b2, W1, b1

#########################
# Define Loss Functions #
#########################
def UtilityRegularized(FLAGS, outputs,W3, b3,
 W2, b2, W1, b1, y, X, q):
    PriceChanges = X[:, 1:, :] - X[:, :-1, :]
    PortfolioValue = tf.reduce_sum(tf.reduce_sum(tf.multiply(PriceChanges, outputs), axis=1),axis=1)
    one = tf.ones(tf.squeeze(y).shape, dtype = tf.float32)
    penalization = (tf.reduce_sum(tf.abs(W3), [0,1,2])+tf.reduce_sum(tf.abs(b3),[0,1])+tf.reduce_sum(tf.abs(W2),[0,1,2])+tf.reduce_sum(tf.abs(b2),[0,1])+tf.reduce_sum(tf.abs(W1),[0,1,2])+tf.reduce_sum(tf.abs(b1),[0,1]))
    utility = tf.reduce_mean(tf.exp(-(PortfolioValue + q*one))) + FLAGS.L1_LAMBDA*penalization
    return utility
def Utility(FLAGS, outputs, y, X, q):
    PriceChanges = X[:, 1:, :] - X[:, :-1, :]
    Prices = X[:,:,:]
    StrategyChangeshelper = outputs[:,1:,:]-outputs[:,:-1,:]
    helper0=outputs[:,0:1,:]
    helper1=outputs[:,FLAGS.TIME_STEPS-2:FLAGS.TIME_STEPS-1,:]
    StrategyChanges=tf.concat([helper0,StrategyChangeshelper,helper1],axis=1)
    PortfolioValue = tf.reduce_sum(
        tf.reduce_sum(tf.multiply(PriceChanges,outputs),axis=1),axis=1)
    TransactionCost = tf.reduce_sum(
        tf.reduce_sum(tf.multiply(tf.abs(Prices),tf.abs(StrategyChanges)),axis=1),axis=1)
    one = tf.ones(tf.squeeze(y).shape, dtype = tf.float32)
    utility = tf.reduce_mean(tf.exp(-(PortfolioValue - FLAGS.epsilon*TransactionCost + q*one)))
    return utility
# Calculate Portfolio Losses
def UtilityNP(outputs, y, X, p):
    PriceChanges = X[:, 1:, :] - X[:, :-1, :]
    Prices = X[:,:,:]
    StrategyChangeshelper = outputs[:,1:,:]-outputs[:,:-1,:]
    helper0=outputs[:,0:1,:]
    helper1=outputs[:,FLAGS.TIME_STEPS-2:FLAGS.TIME_STEPS-1,:]
    StrategyChanges=np.concatenate([helper0,StrategyChangeshelper,helper1],axis=1)
    TransactionCost = np.sum(np.sum(np.abs(Prices)*np.abs(StrategyChanges),axis=1),axis=1)
    PortfolioValue = np.sum(np.sum(PriceChanges*outputs,axis=1),axis=1)
    one = np.ones(np.squeeze(y).shape, dtype = np.float32)
    wealth = PortfolioValue + p*one -FLAGS.epsilon*TransactionCost
    return wealth 

def UtilityNPcum(outputs, y, X, p):
    PriceChanges = X[:, 1:, :] - X[:, :-1, :]
    Prices = X[:,:,:]
    StrategyChangeshelper = outputs[:,1:,:]-outputs[:,:-1,:]
    helper0=outputs[:,0:1,:]
    helper1=outputs[:,FLAGS.TIME_STEPS-2:FLAGS.TIME_STEPS-1,:]
    StrategyChanges=np.concatenate([helper0,StrategyChangeshelper,helper1],axis=1)
    TransactionCost = np.cumsum(np.sum(np.abs(Prices)*np.abs(StrategyChanges),axis=2),axis=1)
    TransactionCost = TransactionCost[:,1:]
    PortfolioValue = np.cumsum(np.sum(PriceChanges*outputs,axis=2),axis=1)
    one = np.ones(np.squeeze(PortfolioValue.shape), dtype = np.float32)
    wealth = PortfolioValue + p*one - FLAGS.epsilon*TransactionCost
    return wealth 

######################
# Define Model Class #
######################
class model(object):
    def __init__(self, FLAGS):
        #Placeholder for Data
        self.X = tf.placeholder(tf.float32, 
            [FLAGS.BATCH_SIZE, FLAGS.TIME_STEPS, FLAGS.NUM_ASSETS],
            name='input_placeholder')
        self.y = tf.placeholder(tf.float32, [FLAGS.BATCH_SIZE],
            name='labels_placeholder')
        self.X_train = tf.placeholder(tf.float32, 
            [FLAGS.NUM_SAMPLES, FLAGS.TIME_STEPS, FLAGS.NUM_ASSETS],
            name='input_train_placeholder')
        self.X_valid = tf.placeholder(tf.float32, 
            [FLAGS.NUM_VALIDATION, FLAGS.TIME_STEPS, FLAGS.NUM_ASSETS],
            name='valid_input_placeholder')
        self.y_valid = tf.placeholder(tf.float32,[FLAGS.NUM_VALIDATION], name='valid_labels_placeholder')
        self.X_test = tf.placeholder(tf.float32, 
            [FLAGS.NUM_TEST, FLAGS.TIME_STEPS, FLAGS.NUM_ASSETS],
            name='test_input_placeholder')
        self.y_test = tf.placeholder(tf.float32, [FLAGS.NUM_TEST],
            name='test_labels_placeholder')
        # Define RNN Cell
        self.initial_state = tf.zeros([FLAGS.BATCH_SIZE,FLAGS.NUM_ASSETS])
        for i in range(0, FLAGS.TIME_STEPS-1):
            with tf.variable_scope('rnn_cell'+ str(i)):
                W1 = tf.get_variable('W1',
                    [FLAGS.NUM_ASSETS*2, FLAGS.hidden_dim1])
                b1 = tf.get_variable('b1', [FLAGS.hidden_dim1],
                    initializer=tf.constant_initializer(0.0))
                W2 = tf.get_variable('W2',
                    [FLAGS.hidden_dim1, FLAGS.hidden_dim2])
                b2 = tf.get_variable('b2', [FLAGS.hidden_dim2],
                    initializer=tf.constant_initializer(0.0))
                W3 = tf.get_variable('W3',
                    [FLAGS.hidden_dim2, FLAGS.NUM_ASSETS])
                b3 = tf.get_variable('b3', [FLAGS.NUM_ASSETS],
                    initializer=tf.constant_initializer(0.0))

        # Build Network Graph
        state = self.initial_state
        weights3 = []
        bias3 = []
        weights2 = []
        bias2 = []
        weights1 = []
        bias1 = []
        rnn_outputs = []
        for i in range(0, FLAGS.TIME_STEPS-1):
            FLAGS.counter = i
            state, weight_matrix3, bias_vector3,  weight_matrix2, bias_vector2, weight_matrix1, bias_vector1 = rnn_cell(FLAGS, self.X[:, i, :], state, name=i)
            rnn_outputs.append(state)
            weights3.append(weight_matrix3)
            bias3.append(bias_vector3)
            weights2.append(weight_matrix2)
            bias2.append(bias_vector2)
            weights1.append(weight_matrix1)
            bias1.append(bias_vector1)
        rnn_outputs = tf.stack(rnn_outputs, axis=1)
        weights3 = tf.stack(weights3, axis=1)
        bias3 = tf.stack(bias3, axis=1)
        weights2 = tf.stack(weights2, axis=1)
        bias2 = tf.stack(bias2, axis=1)
        weights1 = tf.stack(weights1, axis=1)
        bias1 = tf.stack(bias1, axis=1)        
        self.hedging_weights = rnn_outputs
        self.test = rnn_outputs

    #Build Loss Graph and Optimization Step
        self.q =  price(FLAGS)             
        self.total_loss = Utility(FLAGS,self.hedging_weights, self.y, self.X, self.q)#UtilityRegularized(FLAGS, self.hedging_weights, weights3, bias3, weights2, bias2,weights1, bias1, self.y, self.X, self.q)
        optimizer = tf.train.AdamOptimizer(FLAGS.LEARNING_RATE)
        self.quad_loss = Utility(FLAGS,self.hedging_weights, self.y, self.X, self.q)
        self.train_step = optimizer.minimize(self.total_loss,global_step = global_step)
        
    def step(self, sess, batch_X, batch_y):
        input_feed = {self.X: batch_X,
                      self.y: np.squeeze(batch_y)}
        output_feed = [self.hedging_weights,
                       self.total_loss,
                       self.quad_loss,
                       self.train_step,
                       self.q
                       ]
        outputs = sess.run(output_feed, input_feed)
        return (outputs[0], outputs[1], outputs[2],outputs[3], outputs[4])

    # Graphs for Sampling
    def sample_train(self, FLAGS):
        initial_state = tf.zeros(
            [FLAGS.NUM_SAMPLES, FLAGS.NUM_ASSETS])
        hedging_weights = []
        state = initial_state
        for i in range(0, FLAGS.TIME_STEPS-1):
                FLAGS.counter = i
                state,_,_,_,_,_,_ = rnn_cell(FLAGS,self.X_train[:, i, :], state, name = i)
                hedging_weights.append(state)
        hedging_weights = tf.stack(hedging_weights, axis = 1)
        return hedging_weights

    def sample(self, FLAGS):
        initial_state = tf.zeros([FLAGS.NUM_TEST, FLAGS.NUM_ASSETS])
        hedging_weights = []
        state = initial_state
        for i in range(0, FLAGS.TIME_STEPS-1):
                FLAGS.counter = i
                state,_,_,_,_,_,_ = rnn_cell(FLAGS,self.X_test[:, i, :], state, name = i)
                hedging_weights.append(state)
        hedging_weights = tf.stack(hedging_weights, axis = 1)
        return hedging_weights

    def sample_validate(self, FLAGS):
        initial_state = tf.zeros(
            [FLAGS.NUM_VALIDATION, FLAGS.NUM_ASSETS])
        hedging_weights = []
        state = initial_state
        for i in range(0, FLAGS.TIME_STEPS-1):
                FLAGS.counter = i
                state,_,_,_,_,_,_ = rnn_cell(FLAGS, 
                    self.X_valid[:, i, :], state, name = i)
                hedging_weights.append(state)
        hedging_weights = tf.stack(hedging_weights, axis = 1)
        return hedging_weights

# Intializes Model
def create_model(sess, FLAGS):
    char_model = model(FLAGS)
    sess.run(tf.global_variables_initializer())
    return char_model
In [5]:
#if __name__ == '__main__':
FLAGS = parameters()
#Generate Correlation Matrix
if FLAGS.correlated:
    FLAGS.corr = corr(FLAGS.NUM_ASSETS)
#Generate Data
train_data = generate_data(FLAGS)
FLAGS.data = train_data
X_valid, y_valid = generate_validation_data(FLAGS)
X_test, y_test = generate_test_data(FLAGS)
EarlyTrainLoss =np.zeros(FLAGS.NUM_EPOCHS)
EarlyValidateLoss =np.zeros(FLAGS.NUM_EPOCHS)

with tf.Session() as sess:
    model = create_model(sess, FLAGS)
    saver = tf.train.Saver()
        
#########################
# Train Hedging Network #
#########################
    for idx, epoch in enumerate(generate_epochs(FLAGS)):
        training_losses = []
        quad_losses = []
        for step, (input_X, input_y) in enumerate(epoch):
            predictions, total_loss, quad_loss, after_loss, q = model.step(sess, input_X, input_y)
            training_losses.append(total_loss)
            quad_losses.append(quad_loss)
        #model_weights = delta_BS(input_X,T = float(FLAGS.TIME_STEPS)/365.)
        #model_weights = np.concatenate([model_weights[:,:,0:FLAGS.NUM_RELAVENT],np.zeros([FLAGS.BATCH_SIZE,FLAGS.TIME_STEPS-1,FLAGS.NUM_ASSETS-FLAGS.NUM_RELAVENT])], axis = 2)
        #model_hedge_loss = UtilityNP(model_weights, input_y, input_X, q)
        deep_portfolio = UtilityNP(predictions, input_y, input_X, q)
        #plt.hist(model_hedge_loss,range=(np.min(deep_hedge_loss),np.max(deep_hedge_loss)),color='green')
        #plt.show()
        plt.hist(deep_portfolio)
        plt.show()
        print(np.mean(deep_portfolio))
        i = np.random.randint(0,257,1)[0]
        #model_hedge_loss_tra = UtilityNPcum(model_weights[i:i+1,:,:], input_y[i:i+1,:], input_X[i:i+1,:,:], q[i:i+1])
        deep_portfolio_tra = UtilityNPcum(predictions[i:i+1,:,:], input_y[i:i+1,:], input_X[i:i+1,:,:], q[i:i+1])
        #plt.plot(model_hedge_loss_tra[0,:],color='green')
        #plt.show()
        plt.plot(deep_portfolio_tra[0,:])
        plt.show()
        print("Initial Capital: ", q[i:i+1])
        #print("Deep Hedge price:", deep_hedge_loss_tra[0,0])
        print("Epoch %i, negative utility: %.3f" % (idx,np.mean(training_losses)))
        #print("Unregularized Loss: %.3f" % (np.mean(quad_losses)))
        FLAGS.training = 2
        train_batch = model.sample_train(FLAGS)
        X_train, y_train = train_data
        test_weights = sess.run([train_batch],{model.X_train: X_train})
        FLAGS.training = 3
        p = price_valid(FLAGS)
        validate_graph = model.sample_validate(FLAGS)
        loss = Utility(FLAGS, validate_graph,model.y_valid, model.X_valid, p)
        validate_loss,test_weights,certain_equivalent=sess.run([loss, validate_graph, model.q],{model.X_valid: X_valid,model.y_valid:np.squeeze(y_valid)})
        print("Validate negative utility: %.3f" % (validate_loss))
        FLAGS.training = 1

        #Save Model for Early Stopping
        if validate_loss < FLAGS.minimal_loss:
            FLAGS.minimal_loss = validate_loss
            save_path = saver.save(sess, './model/my-test-model')
            
        EarlyTrainLoss[idx] = np.mean(training_losses)
        EarlyValidateLoss[idx] = validate_loss

    # Generate Batch Normalization Parameters for Testing
    FLAGS.training = 2
    train_batch = model.sample_train(FLAGS)
    X_train, y_train = train_data
    test_weights = sess.run([train_batch], {model.X_train: X_train})

    # Generate Predictions
    FLAGS.training = 3
    p = price_test(FLAGS)
    test_graph = model.sample(FLAGS)
    loss = Utility(FLAGS, test_graph,model.y_test, model.X_test, p)
    test_loss, test_weights, certain_equivalent = sess.run([loss, test_graph, model.q],{model.X_test: X_test,model.y_test: np.squeeze(y_test)})
    print("Utility on Test Data (unstopped): %.3f" % (test_loss))
    p_np = (FLAGS.initialcapital)

#######################################
# Evaluate Network for Early Stopping #
#######################################
new_saver = tf.train.import_meta_graph('./model/my-test-model.meta', clear_devices=True)
with tf.Session() as sess1:
    # Generate Batch Normalization Parameters for Testing
    new_saver.restore(sess1,tf.train.latest_checkpoint('./model/'))
    FLAGS.training = 2
    train_batch = model.sample_train(FLAGS)
    X_train, y_train = train_data
    test_weights = sess1.run([train_batch],{model.X_train: X_train})
    
    # Generate Predictions
    FLAGS.training = 3
    p = price_test(FLAGS)
    test_graph = model.sample(FLAGS)
    loss = Utility(FLAGS, test_graph,model.y_test, model.X_test, p)
    test_loss, test_weights, certain_equivalent = sess1.run([loss, test_graph, model.q],{model.X_test: X_test, model.y_test: np.squeeze(y_test)})
    print("Utility on Test Data (stopped): %.3f" % (test_loss))

# Print Runtime 
t1 = time.time()
total_time=t1-t0
print("Runtime (in sec): %.3f" % (total_time))
0.8286487713317018
Initial Capital:  [1.]
Epoch 0, negative utility: 0.495
Validate negative utility: 0.446
0.889954184166572
Initial Capital:  [1.]
Epoch 1, negative utility: 0.425
Validate negative utility: 0.412
0.9261064701214056
Initial Capital:  [1.]
Epoch 2, negative utility: 0.404
Validate negative utility: 0.398
0.9467030903326066
Initial Capital:  [1.]
Epoch 3, negative utility: 0.393
Validate negative utility: 0.389
0.9598712514690526
Initial Capital:  [1.]
Epoch 4, negative utility: 0.386
Validate negative utility: 0.382
0.9721058880084821
Initial Capital:  [1.]
Epoch 5, negative utility: 0.380
Validate negative utility: 0.378
0.9809570300433815
Initial Capital:  [1.]
Epoch 6, negative utility: 0.377
Validate negative utility: 0.374
0.9881826557277773
Initial Capital:  [1.]
Epoch 7, negative utility: 0.374
Validate negative utility: 0.373
0.994506354860198
Initial Capital:  [1.]
Epoch 8, negative utility: 0.372
Validate negative utility: 0.370
0.9999390755413611
Initial Capital:  [1.]
Epoch 9, negative utility: 0.370
Validate negative utility: 0.368
1.0060550452663974
Initial Capital:  [1.]
Epoch 10, negative utility: 0.368
Validate negative utility: 0.366
1.0093070342049342
Initial Capital:  [1.]
Epoch 11, negative utility: 0.366
Validate negative utility: 0.365
1.0123043926008968
Initial Capital:  [1.]
Epoch 12, negative utility: 0.365
Validate negative utility: 0.364
1.0172543202109272
Initial Capital:  [1.]
Epoch 13, negative utility: 0.364
Validate negative utility: 0.363
1.0211170332061186
Initial Capital:  [1.]
Epoch 14, negative utility: 0.363
Validate negative utility: 0.362
1.0245764779580935
Initial Capital:  [1.]
Epoch 15, negative utility: 0.362
Validate negative utility: 0.360
1.027614766926462
Initial Capital:  [1.]
Epoch 16, negative utility: 0.361
Validate negative utility: 0.360
1.0275659951803873
Initial Capital:  [1.]
Epoch 17, negative utility: 0.360
Validate negative utility: 0.359
1.031932097575862
Initial Capital:  [1.]
Epoch 18, negative utility: 0.360
Validate negative utility: 0.358
1.0342618260220315
Initial Capital:  [1.]
Epoch 19, negative utility: 0.359
Validate negative utility: 0.358
1.038159992517722
Initial Capital:  [1.]
Epoch 20, negative utility: 0.358
Validate negative utility: 0.357
1.0412787137330177
Initial Capital:  [1.]
Epoch 21, negative utility: 0.358
Validate negative utility: 0.356
1.043539037797786
Initial Capital:  [1.]
Epoch 22, negative utility: 0.357
Validate negative utility: 0.355
1.046061454219849
Initial Capital:  [1.]
Epoch 23, negative utility: 0.356
Validate negative utility: 0.355
1.0484091213873077
Initial Capital:  [1.]
Epoch 24, negative utility: 0.356
Validate negative utility: 0.354
1.050777550901151
Initial Capital:  [1.]
Epoch 25, negative utility: 0.355
Validate negative utility: 0.353
1.0539475348118854
Initial Capital:  [1.]
Epoch 26, negative utility: 0.354
Validate negative utility: 0.353
1.056979574984834
Initial Capital:  [1.]
Epoch 27, negative utility: 0.354
Validate negative utility: 0.352
1.0603897543776724
Initial Capital:  [1.]
Epoch 28, negative utility: 0.353
Validate negative utility: 0.351
1.0622333904209618
Initial Capital:  [1.]
Epoch 29, negative utility: 0.352
Validate negative utility: 0.351
1.0656001028271824
Initial Capital:  [1.]
Epoch 30, negative utility: 0.352
Validate negative utility: 0.350
1.067908116656114
Initial Capital:  [1.]
Epoch 31, negative utility: 0.351
Validate negative utility: 0.349
1.070499739037848
Initial Capital:  [1.]
Epoch 32, negative utility: 0.350
Validate negative utility: 0.348
1.0731810404490585
Initial Capital:  [1.]
Epoch 33, negative utility: 0.350
Validate negative utility: 0.348
1.0750197087596565
Initial Capital:  [1.]
Epoch 34, negative utility: 0.349
Validate negative utility: 0.347
1.0777369750098618
Initial Capital:  [1.]
Epoch 35, negative utility: 0.349
Validate negative utility: 0.347
1.0795441950761353
Initial Capital:  [1.]
Epoch 36, negative utility: 0.348
Validate negative utility: 0.346
1.0815038786240476
Initial Capital:  [1.]
Epoch 37, negative utility: 0.347
Validate negative utility: 0.345
1.0829798408040907
Initial Capital:  [1.]
Epoch 38, negative utility: 0.347
Validate negative utility: 0.345
1.0849844757572016
Initial Capital:  [1.]
Epoch 39, negative utility: 0.347
Validate negative utility: 0.344
Utility on Test Data (unstopped): 0.346
INFO:tensorflow:Restoring parameters from ./model/my-test-model
Utility on Test Data (stopped): 0.346
Runtime (in sec): 1687.529
In [6]:
################
# Save Results #
################

np.save('deep_weights', test_weights)
deep_portfolio = UtilityNP(test_weights, y_test, X_test, p_np)
deep_portfolio_tra = UtilityNPcum(test_weights, y_test, X_test, p_np)
np.save('stock_prices', X_test)
df = pd.DataFrame(deep_portfolio)
df.to_csv('deep_portfolio.csv')
df = pd.DataFrame(deep_portfolio_tra)
df.to_csv('deep_portfolio_tra.csv')
In [7]:
stock_prices=np.load('stock_prices.npy')
#model_hedge_loss = pd.read_csv('model_hedge_loss.csv')
deep_portfolio = pd.read_csv('deep_portfolio.csv')
deep_portfolio_tra = pd.read_csv('deep_portfolio_tra.csv')
In [8]:
for i in range(10):
   plt.plot(stock_prices[i,1:,:])
plt.show()
In [9]:
deep_portfolio_tra = deep_portfolio_tra.transpose()
In [10]:
#deep_portfolio_tra
In [11]:
deep_portfolio_traSel = deep_portfolio_tra.iloc[1:,1:20]
deep_portfolio_traSel.plot()
plt.show()
In [12]:
#model_hedge_loss.hist(column='0',color='green')
deep_portfolio.hist(column='0')
Out[12]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7f037f364898>]],
      dtype=object)
In [13]:
plt.show()
In [14]:
weights=np.load('deep_weights.npy')
In [15]:
plt.plot(weights[1,:])
plt.show()