From 5be4bae07bcd1323885a50784547310e4a76b1fb Mon Sep 17 00:00:00 2001 From: Raidas Grisk <30408368+RaidasGrisk@users.noreply.github.com> Date: Mon, 8 Jan 2018 01:43:03 +0200 Subject: [PATCH] Add files via upload --- main.py | 66 +++++++++++---- models.py | 121 ++++++++++++++++++--------- train_cnn_v1.py | 142 ++++++++++++++++++++++++++++++++ train_cnn_v2.py | 140 +++++++++++++++++++++++++++++++ train_logistic_regression_v1.py | 133 ++++++++++++++++-------------- train_logistic_regression_v2.py | 68 +++++++++------ train_lstm_v1.py | 139 ++++++++++++++++++++----------- train_lstm_v2.py | 75 ++++++++++------- 8 files changed, 661 insertions(+), 223 deletions(-) create mode 100644 train_cnn_v1.py create mode 100644 train_cnn_v2.py diff --git a/main.py b/main.py index bb91d1f..36e76f3 100644 --- a/main.py +++ b/main.py @@ -9,16 +9,24 @@ from helpers.get_historical_data import get_latest_oanda_data import tensorflow as tf import numpy as np +import pandas as pd import datetime from apscheduler.schedulers.blocking import BlockingScheduler +# TODO: trading params like position size kelly criterion +position_size = 10000 +close_current_positions = True +start_on_spot = False + # oanda access keys -accountID = '' -access_token = '' -model_name = 'lr-v2-avg_score0.204-64000' +accountID = '101-004-3943081-001' +access_token = 'fb12d7edd860927ce27467d8ec4aee94-1cb7ffc0e40d649b736315872a10c545' +model_name = 'lr-v1-avg_score1.454-2000' # init trading session trading_sess = TradingSession(accountID=accountID, access_token=access_token) +if close_current_positions: + trading_sess.close_all_open_positions() # init tf model config = tf.ConfigProto(device_count={'GPU': 0}) @@ -26,51 +34,73 @@ saver = tf.train.import_meta_graph('saved_models/' + model_name + '.meta') saver.restore(sess, tf.train.latest_checkpoint('saved_models/')) graph = tf.get_default_graph() -x = graph.get_tensor_by_name("Placeholder:0") -tf_op_to_restore = graph.get_tensor_by_name("Softmax:0") +x = graph.get_tensor_by_name('Placeholder:0') +drop_out = graph.get_tensor_by_name('strided_slice_1:0') +y_ = graph.get_tensor_by_name('Softmax:0') -# Do stuff every period -scheduler = BlockingScheduler() +# global variables +log = pd.DataFrame() +start_time = str(datetime.datetime.now())[:-7].replace(':', '-') -@scheduler.scheduled_job(trigger='cron', day_of_week='0-6', hour='0-23', minute='0', second='5') def do_stuff_every_period(): - # retrieve data and return signal + global log + global start_time + current_time = str(datetime.datetime.now())[:-7] + + # gather data and return signal oanda_data = get_latest_oanda_data('EUR_USD', 'H1', 64) input_data_raw, input_data_dummy = get_features(oanda_data) input_data, input_data_dummy = remove_nan_rows([input_data_raw, input_data_dummy]) input_data_scaled_no_dummies = (input_data - min_max_scaling[1, :]) / ( min_max_scaling[0, :] - min_max_scaling[1, :]) input_data_scaled = np.concatenate([input_data_scaled_no_dummies, input_data_dummy], axis=1) - y_ = sess.run(tf_op_to_restore, feed_dict={x: input_data_scaled}) - order_signal = y_.argmax() # 0 stands for buy, 1 for sell, 2 for hold - print('{} | signal: buy: {:.2f}, sell: {:.2f}, nothing: {:.2f}'.format( - str(datetime.datetime.now())[:-4], y_[0][0], y_[0][1], y_[0][2])) + # estimate signal + y_pred = sess.run(y_, feed_dict={x: input_data_scaled, drop_out: 1}) + order_signal = y_pred.argmax() # 0 stands for buy, 1 for sell, 2 for hold + + print('{} | price: {:.5f} | signal: buy: {:.2f}, sell: {:.2f}, nothing: {:.2f}' + .format(current_time, oanda_data[-1]['closeMid'], y_pred[0][0], y_pred[0][1], y_pred[0][2])) # if signal long if order_signal == 0: if trading_sess.order_book['EUR_USD']['order_type'] == -1: trading_sess.close_order('EUR_USD') - trading_sess.open_order('EUR_USD', 1) + trading_sess.open_order('EUR_USD', position_size) # if signal short elif order_signal == 1: if trading_sess.order_book['EUR_USD']['order_type'] == 1: trading_sess.close_order('EUR_USD') - trading_sess.open_order('EUR_USD', -1) + trading_sess.open_order('EUR_USD', -position_size) # else (uncharted waters) else: print('Do nothing') + # log + new_log = pd.DataFrame([[current_time, oanda_data[-1]['closeMid'], y_pred]], + columns=['Datetime', 'Last input Price', 'y_pred']) + log = log.append(new_log) + log.to_csv('logs/log {}.csv'.format(start_time)) + -# start -do_stuff_every_period() +# Scheduler +scheduler = BlockingScheduler() +scheduler.add_job(do_stuff_every_period, + trigger='cron', + day_of_week='0-4', + hour='0-23', + minute='0', + second='5') + +if start_on_spot: + do_stuff_every_period() scheduler.start() -# close_order_manually(accountID, access_token, 1579) +# close_order_manually(accountID, access_token, 1603) # trading_sess.check_open_positions() # trading_sess.check_account_summary() # trading_sess.order_book diff --git a/models.py b/models.py index 9e1eabc..178adae 100644 --- a/models.py +++ b/models.py @@ -6,24 +6,102 @@ import numpy as np -def logistic_regression(input_dim, output_dim, drop_keep_prob): +def logistic_regression(input_dim, output_dim): """Simple logistic regression Returns x and y placeholders, logits and y_ (y hat)""" tf.reset_default_graph() x = tf.placeholder(tf.float32, [None, input_dim]) y = tf.placeholder(tf.float32, [None, output_dim]) + learning_r = tf.placeholder(tf.float32, 1)[0] + drop_out = tf.placeholder(tf.float32, 1)[0] w_init = tf.contrib.layers.xavier_initializer() b_init = tf.initializers.truncated_normal(mean=0.1, stddev=0.025) - weights = {0: tf.get_variable('weights1', shape=[input_dim, output_dim], initializer=w_init)} - biases = {0: tf.get_variable('bias1', shape=[output_dim], initializer=b_init)} + w = tf.get_variable('weights1', shape=[input_dim, output_dim], initializer=w_init) + b = tf.get_variable('bias1', shape=[output_dim], initializer=b_init) - logits = tf.nn.dropout(tf.matmul(x, weights[0]) + biases[0], keep_prob=drop_keep_prob) + logits = tf.matmul(tf.nn.dropout(x, keep_prob=drop_out), w) + b y_ = tf.nn.softmax(logits) [print(var) for var in tf.trainable_variables()] - return x, y, logits, y_ + return x, y, logits, y_, learning_r, drop_out + + +def lstm_nn(input_dim, output_dim, time_steps, n_hidden): + """LSTM net returns x and y placeholders, logits and y_ (y hat)""" + + tf.reset_default_graph() + + x = tf.placeholder(tf.float32, [None, time_steps, input_dim]) + y = tf.placeholder(tf.float32, [None, output_dim]) + learning_r = tf.placeholder(tf.float32, 1)[0] + drop_out = tf.placeholder(tf.float32, 1)[0] + + w_init = tf.contrib.layers.xavier_initializer() + b_init = tf.initializers.truncated_normal(mean=0.1, stddev=0.025) + w = tf.get_variable('last_weights', shape=[n_hidden[-1], output_dim], initializer=w_init) + # b = tf.get_variable('bias1', shape=[output_dim], initializer=b_init) + + x_split = tf.unstack(x, time_steps, 1) + + # stack lstm cells, a cell per hidden layer + stacked_lstm_cells = [] # a list of lstm cells to be inputted into MultiRNNCell + for layer_size in n_hidden: + stacked_lstm_cells.append(tf.contrib.rnn.BasicLSTMCell(layer_size, activation=tf.nn.relu)) + + # create the net and add dropout + lstm_cell = tf.contrib.rnn.MultiRNNCell(stacked_lstm_cells) + lstm_cell_with_dropout = tf.contrib.rnn.DropoutWrapper(lstm_cell, output_keep_prob=drop_out) + + # forward propagate + outputs, state = tf.contrib.rnn.static_rnn(lstm_cell_with_dropout, x_split, dtype=tf.float32) + logits = tf.matmul(outputs[-1], w) # + b # logits are used for cross entropy + y_ = tf.nn.softmax(logits) + + [print(var) for var in tf.trainable_variables()] + print([print(i) for i in outputs]) + print(y_) + return x, y, logits, y_, learning_r, drop_out + + +def cnn(input_dim, output_dim, time_steps, filter): + """CNN returns x and y placeholders, logits and y_ (y hat)""" + + tf.reset_default_graph() + + x = tf.placeholder(tf.float32, [None, input_dim, time_steps, 1]) + y = tf.placeholder(tf.float32, [None, output_dim]) + learning_r = tf.placeholder(tf.float32, 1)[0] + drop_out = tf.placeholder(tf.float32, 1)[0] + + conv1 = tf.layers.conv2d(inputs=x, + filters=filter[0], + kernel_size=(input_dim, 1), + kernel_initializer=tf.truncated_normal_initializer(stddev=0.1, dtype=tf.float32), + strides=1, + padding='valid', + activation=tf.nn.relu) + conv1_dropout = tf.layers.dropout(inputs=conv1, rate=drop_out) + conv2 = tf.layers.conv2d(inputs=conv1_dropout, + filters=filter[1], + kernel_size=(1, time_steps), + kernel_initializer=tf.truncated_normal_initializer(stddev=0.1, dtype=tf.float32), + strides=1, + padding='valid', + activation=tf.nn.relu) + logits_dense = tf.layers.dense(inputs=conv2, + units=output_dim, + kernel_initializer=tf.truncated_normal_initializer(stddev=0.1, dtype=tf.float32), + activation=None, + use_bias=False) + + logits = tf.reshape(logits_dense, (-1, output_dim)) + y_ = tf.nn.softmax(tf.reshape(logits_dense, (-1, output_dim))) + + [print(var) for var in tf.trainable_variables()] + print(y_) + return x, y, logits, y_, learning_r, drop_out def vanilla_nn(input_dim, output_dim, architecture, drop_layer=0, drop_keep_prob=0.9): @@ -60,36 +138,3 @@ def vanilla_nn(input_dim, output_dim, architecture, drop_layer=0, drop_keep_prob print(y_) return x, y, layer_values[len(layer_values)-1], y_ - -def lstm_nn(input_dim, output_dim, time_steps, n_hidden, drop_keep_prob=0.9): - """LSTM net returns x and y placeholders, logits and y_ (y hat)""" - - tf.reset_default_graph() - - x = tf.placeholder(tf.float32, [None, time_steps, input_dim]) - y = tf.placeholder(tf.float32, [None, output_dim]) - - w_init = tf.contrib.layers.xavier_initializer() - w = tf.get_variable('last_weights', shape=[n_hidden[-1], output_dim], initializer=w_init) - - x_split = tf.unstack(x, time_steps, 1) - - # stack lstm cells, a cell per hidden layer - stacked_lstm_cells = [] # a list of lstm cells to be inputed into MultiRNNCell - for layer_size in n_hidden: - stacked_lstm_cells.append(tf.contrib.rnn.BasicLSTMCell(layer_size, activation=tf.nn.tanh)) - - # create the net and add dropout - lstm_cell = tf.contrib.rnn.MultiRNNCell(stacked_lstm_cells) - lstm_cell_with_dropout = tf.contrib.rnn.DropoutWrapper(lstm_cell, output_keep_prob=drop_keep_prob) - - # forwawrd propagate - outputs, state = tf.contrib.rnn.static_rnn(lstm_cell_with_dropout, x_split, dtype=tf.float32) - logits = tf.matmul(outputs[-1], w) # logits are used for cross entropy - y_ = tf.nn.softmax(logits) - - [print(var) for var in tf.trainable_variables()] - print([print(i) for i in outputs]) - print(y_) - return x, y, logits, y_ - diff --git a/train_cnn_v1.py b/train_cnn_v1.py new file mode 100644 index 0000000..6756939 --- /dev/null +++ b/train_cnn_v1.py @@ -0,0 +1,142 @@ +""" +Training cnn model + +Dropout and lr to placeholders +random batches +""" + +import numpy as np +import pylab as pl +import tensorflow as tf +from helpers.utils import price_to_binary_target, extract_timeseries_from_oanda_data, train_test_validation_split +from helpers.utils import remove_nan_rows, get_signal, get_data_batch, get_cnn_input_output +from models import cnn +from helpers.get_features import get_features, min_max_scaling + + +# other-params +np.set_printoptions(linewidth=75*3+5, edgeitems=6) +pl.rcParams.update({'font.size': 6}) + +# hyper-params +batch_size = 1024 +learning_rate = 0.002 +drop_keep_prob = 0.8 +value_moving_average = 50 +split = (0.5, 0.3, 0.2) +plotting = False +saving = False +time_steps = 4 + +# load data +oanda_data = np.load('data\\EUR_USD_H1.npy') # [-50000:] +output_data_raw = price_to_binary_target(oanda_data, delta=0.00027) +price_data_raw = extract_timeseries_from_oanda_data(oanda_data, ['closeMid']) +input_data_raw, input_data_dummy_raw = get_features(oanda_data) +price_data_raw = np.concatenate([[[0]], + (price_data_raw[1:] - price_data_raw[:-1]) / (price_data_raw[1:] + 1e-10)], axis=0) + +# prepare data +input_data, output_data, input_data_dummy, price_data = \ + remove_nan_rows([input_data_raw, output_data_raw, input_data_dummy_raw, price_data_raw]) +input_data_scaled_no_dummies = (input_data - min_max_scaling[1, :]) / (min_max_scaling[0, :] - min_max_scaling[1, :]) +input_data = np.concatenate([input_data_scaled_no_dummies, input_data_dummy], axis=1) +input_data, output_data = get_cnn_input_output(input_data, output_data, time_steps=time_steps) +price_data = price_data[-len(input_data):] + +# split to train, test and cross validation +input_train, input_test, input_cv, output_train, output_test, output_cv, price_train, price_test, price_cv = \ + train_test_validation_split([input_data, output_data, price_data], split=split) + +# get dims +_, input_dim, _, _ = np.shape(input_data) +_, output_dim = np.shape(output_data) + +# forward-propagation +x, y, logits, y_, learning_r, drop_out = cnn(input_dim, output_dim, time_steps=time_steps, filter=[3, 6]) + +# tf cost and optimizer +cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y)) +train_step = tf.train.AdamOptimizer(learning_r).minimize(cost) + +# init session +cost_hist_train, cost_hist_test, value_hist_train, value_hist_test, value_hist_cv, value_hist_train_ma, \ + value_hist_test_ma, value_hist_cv_ma, step, step_hist, saving_score = [], [], [], [], [], [], [], [], 0, [], 0.05 +saver = tf.train.Saver() +init = tf.global_variables_initializer() +sess = tf.Session() +sess.run(init) + +# train +while True: + + if step == 30000: + break + + # train model + x_train, y_train = get_data_batch([input_train, output_train], batch_size, sequential=False) + _, cost_train = sess.run([train_step, cost], + feed_dict={x: x_train, y: y_train, learning_r: learning_rate, drop_out: drop_keep_prob}) + + # keep track of stuff + step += 1 + if step % 100 == 0 or step == 1: + + # get y_ predictions + y_train_pred = sess.run(y_, feed_dict={x: input_train, drop_out: drop_keep_prob}) + cost_test, y_test_pred = sess.run([cost, y_], feed_dict={x: input_test, y: output_test, drop_out: drop_keep_prob}) + y_cv_pred = sess.run(y_, feed_dict={x: input_cv, drop_out: drop_keep_prob}) + + # get portfolio value + signal_train, signal_test, signal_cv = get_signal(y_train_pred), get_signal(y_test_pred), get_signal(y_cv_pred) + value_train = 1 + np.cumsum(np.sum(signal_train[:-1] * price_train[1:], axis=1)) + value_test = 1 + np.cumsum(np.sum(signal_test[:-1] * price_test[1:], axis=1)) + value_cv = 1 + np.cumsum(np.sum(signal_cv[:-1] * price_cv[1:], axis=1)) + + # save history + step_hist.append(step) + cost_hist_train.append(cost_train) + cost_hist_test.append(cost_test) + value_hist_train.append(value_train[-1]) + value_hist_test.append(value_test[-1]) + value_hist_cv.append(value_cv[-1]) + value_hist_train_ma.append(np.mean(value_hist_train[-value_moving_average:])) + value_hist_test_ma.append(np.mean(value_hist_test[-value_moving_average:])) + value_hist_cv_ma.append(np.mean(value_hist_cv[-value_moving_average:])) + + print('Step {}: train {:.4f}, test {:.4f}'.format(step, cost_train, cost_test)) + + if plotting: + + pl.figure(1, figsize=(3, 7), dpi=80, facecolor='w', edgecolor='k') + + pl.subplot(211) + pl.title('cost function') + pl.plot(step_hist, cost_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, cost_hist_test, color='dodgerblue', linewidth=0.3) + + pl.subplot(212) + pl.title('Portfolio value') + pl.plot(step_hist, value_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, value_hist_test, color='dodgerblue', linewidth=0.3) + pl.plot(step_hist, value_hist_cv, color='magenta', linewidth=1) + pl.plot(step_hist, value_hist_train_ma, color='tomato', linewidth=1.5) + pl.plot(step_hist, value_hist_test_ma, color='royalblue', linewidth=1.5) + pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=1.5) + pl.pause(1e-10) + + # save if some complicated rules + if saving: + current_score = 0 if value_test[-1] < 0.01 or value_cv[-1] < 0.01 \ + else np.average([value_test[-1], value_cv[-1]]) + saving_score = current_score if saving_score < current_score else saving_score + if saving_score == current_score and saving_score > 0.05: + saver.save(sess, 'saved_models/cnn-v1-avg_score{:.3f}'.format(current_score), global_step=step) + print('Model saved. Average score: {:.2f}'.format(current_score)) + + pl.figure(2) + pl.plot(value_test, linewidth=0.2) + pl.plot(value_cv, linewidth=2) + pl.pause(1e-10) + + diff --git a/train_cnn_v2.py b/train_cnn_v2.py new file mode 100644 index 0000000..2ddb7cb --- /dev/null +++ b/train_cnn_v2.py @@ -0,0 +1,140 @@ +""" +Training lstm v2: +using model to allocate funds, i.e. maximizing return without target labels. + +""" + +import numpy as np +import pylab as pl +import tensorflow as tf +from helpers.utils import extract_timeseries_from_oanda_data, train_test_validation_split +from helpers.utils import remove_nan_rows, get_data_batch, get_cnn_input_output +from models import cnn +from helpers.get_features import get_features, min_max_scaling + + +# other-params +np.set_printoptions(linewidth=75*3+5, edgeitems=6) +pl.rcParams.update({'font.size': 6}) + +# hyper-params +batch_size = 1024 +learning_rate = 0.002 +drop_keep_prob = 0.2 +value_moving_average = 50 +split = (0.5, 0.3, 0.2) +plotting = False +saving = False +time_steps = 4 + +# load data +oanda_data = np.load('data\\EUR_USD_H1.npy') # [-50000:] +price_data_raw = extract_timeseries_from_oanda_data(oanda_data, ['closeMid']) +input_data_raw, input_data_dummy = get_features(oanda_data) +price_data_raw = np.concatenate([[[0]], + (price_data_raw[1:] - price_data_raw[:-1]) / (price_data_raw[1:] + 1e-10)], axis=0) + +# prepare data +input_data, price_data, input_data_dummy = remove_nan_rows([input_data_raw, price_data_raw, input_data_dummy]) +input_data_scaled_no_dummies = (input_data - min_max_scaling[1, :]) / (min_max_scaling[0, :] - min_max_scaling[1, :]) +input_data_scaled = np.concatenate([input_data_scaled_no_dummies, input_data_dummy], axis=1) +input_data, _ = get_cnn_input_output(input_data, np.zeros_like(input_data), time_steps=time_steps) +price_data = price_data[-len(input_data):] + +# split to train,test and cross validation +input_train, input_test, input_cv, price_train, price_test, price_cv = \ + train_test_validation_split([input_data, price_data], split=split) + +# get dims +_, input_dim, _, _ = np.shape(input_train) + +# forward-propagation +x, y, logits, y_, learning_r, drop_out = cnn(input_dim, 3, time_steps=time_steps, filter=[1, 1]) + +# tf cost and optimizer +price_h = tf.placeholder(tf.float32, [None, 1]) +signals = tf.constant([[1., -1., 0.]]) +cost = (tf.reduce_mean(y_ * signals * price_h * 100)) # profit function +train_step = tf.train.AdamOptimizer(learning_r).minimize(-cost) + +# init session +cost_hist_train, cost_hist_test, value_hist_train, value_hist_test, value_hist_cv, value_hist_train_ma, \ + value_hist_test_ma, value_hist_cv_ma, step, step_hist, saving_score = [], [], [], [], [], [], [], [], 0, [], 0.05 +saver = tf.train.Saver() +init = tf.global_variables_initializer() +sess = tf.Session() +sess.run(init) + +# train +while True: + + if step == 30000: + break + + # train model + x_train, price_batch = get_data_batch([input_train[:-1], price_train[1:]], batch_size, sequential=False) + _, cost_train = sess.run([train_step, cost], + feed_dict={x: x_train, price_h: price_batch, + learning_r: learning_rate, drop_out: drop_keep_prob}) + + # keep track of stuff + step += 1 + if step % 100 == 0 or step == 1: + + # get y_ predictions + y_train_pred = sess.run(y_, feed_dict={x: input_train, drop_out: drop_keep_prob}) + y_test_pred, cost_test = sess.run([y_, cost], feed_dict={x: input_test[:-1], price_h: price_test[1:], drop_out: drop_keep_prob}) + y_cv_pred = sess.run(y_, feed_dict={x: input_cv, drop_out: drop_keep_prob}) + + # get portfolio value + value_train = 1 + np.cumsum(np.sum(y_train_pred[:-1] * [1., -1., 0.] * price_train[1:], axis=1)) + value_test = 1 + np.cumsum(np.sum(y_test_pred * [1., -1., 0.] * price_test[1:], axis=1)) + value_cv = 1 + np.cumsum(np.sum(y_cv_pred[:-1] * [1., -1., 0.] * price_cv[1:], axis=1)) + + # save history + step_hist.append(step) + cost_hist_train.append(cost_train) + cost_hist_test.append(cost_test) + value_hist_train.append(value_train[-1]) + value_hist_test.append(value_test[-1]) + value_hist_cv.append(value_cv[-1]) + value_hist_train_ma.append(np.mean(value_hist_train[-value_moving_average:])) + value_hist_test_ma.append(np.mean(value_hist_test[-value_moving_average:])) + value_hist_cv_ma.append(np.mean(value_hist_cv[-value_moving_average:])) + + print('Step {}: train {:.4f}, test {:.4f}'.format(step, cost_train, cost_test)) + + if plotting: + + pl.figure(1, figsize=(3, 7), dpi=80, facecolor='w', edgecolor='k') + + pl.subplot(211) + pl.title('Objective function') + pl.plot(step_hist, cost_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, cost_hist_test, color='dodgerblue', linewidth=0.3) + + pl.subplot(212) + pl.title('Portfolio value') + pl.plot(step_hist, value_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, value_hist_test, color='dodgerblue', linewidth=0.3) + pl.plot(step_hist, value_hist_cv, color='magenta', linewidth=1) + pl.plot(step_hist, value_hist_train_ma, color='tomato', linewidth=1.5) + pl.plot(step_hist, value_hist_test_ma, color='royalblue', linewidth=1.5) + pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=1.5) + pl.pause(1e-10) + + # save if some complicated rules + if saving: + current_score = 0 if value_test[-1] < 0.01 or value_cv[-1] < 0.01 \ + else np.average([value_test[-1], value_cv[-1]]) + saving_score = current_score if saving_score < current_score else saving_score + if saving_score == current_score and saving_score > 0.05: + saver.save(sess, 'saved_models/lstm-v2-avg_score{:.3f}'.format(current_score), global_step=step) + print('Model saved. Average score: {:.2f}'.format(current_score)) + + pl.figure(2) + pl.plot(value_train, linewidth=1) + pl.plot(value_test, linewidth=1) + pl.plot(value_cv, linewidth=1) + pl.pause(1e-10) + diff --git a/train_logistic_regression_v1.py b/train_logistic_regression_v1.py index 8e6576f..b67b43b 100644 --- a/train_logistic_regression_v1.py +++ b/train_logistic_regression_v1.py @@ -6,47 +6,60 @@ import numpy as np import pylab as pl import tensorflow as tf -from sklearn.preprocessing import minmax_scale from helpers.utils import price_to_binary_target, extract_timeseries_from_oanda_data, train_test_validation_split -from helpers.utils import remove_nan_rows, get_signal, portfolio_value, get_data_batch +from helpers.utils import remove_nan_rows, get_signal, get_data_batch from models import logistic_regression -from helpers.get_features import get_features +from helpers.get_features import get_features, min_max_scaling + + +# other-params +np.set_printoptions(linewidth=75*3+5, edgeitems=6) +pl.rcParams.update({'font.size': 6}) +np.random.seed(0) +tf.set_random_seed(0) # hyper-params batch_size = 1024 +learning_rate = 0.002 +drop_keep_prob = 1 +value_moving_average = 50 +split = (0.5, 0.3, 0.2) plotting = False -value_cv_moving_average = 100 +saving = False # load data -oanda_data = np.load('data\\EUR_GBP_H1.npy')[-60000:] -input_data_raw, input_data_dummies = get_features(oanda_data) +oanda_data = np.load('data\\EUR_USD_H1.npy')[-50000:] output_data_raw = price_to_binary_target(oanda_data, delta=0.0001) price_data_raw = extract_timeseries_from_oanda_data(oanda_data, ['closeMid']) +input_data_raw, input_data_dummy_raw = get_features(oanda_data) +price_data_raw = np.concatenate([[[0]], + (price_data_raw[1:] - price_data_raw[:-1]) / (price_data_raw[1:] + 1e-10)], axis=0) # prepare data -input_data, output_data, input_data_dummies, price_data = \ - remove_nan_rows([input_data_raw, output_data_raw, input_data_dummies, price_data_raw]) -input_data_norm = np.concatenate([minmax_scale(input_data, axis=0), input_data_dummies], axis=1) +input_data, output_data, input_data_dummy, price_data = \ + remove_nan_rows([input_data_raw, output_data_raw, input_data_dummy_raw, price_data_raw]) +input_data_scaled_no_dummies = (input_data - min_max_scaling[1, :]) / (min_max_scaling[0, :] - min_max_scaling[1, :]) +input_data_scaled = np.concatenate([input_data_scaled_no_dummies, input_data_dummy], axis=1) -# split to train,test and cross validation +# split to train, test and cross validation input_train, input_test, input_cv, output_train, output_test, output_cv, price_train, price_test, price_cv = \ - train_test_validation_split([input_data_norm, output_data, price_data], split=(0.5, 0.3, 0.2)) + train_test_validation_split([input_data_scaled, output_data, price_data], split=split) # get dims _, input_dim = np.shape(input_train) _, output_dim = np.shape(output_train) # forward-propagation -x, y, logits, y_ = logistic_regression(input_dim, output_dim, drop_keep_prob=0.8) +x, y, logits, y_, learning_r, drop_out = logistic_regression(input_dim, output_dim) # tf cost and optimizer -# TODO: maximize return or sharpe or something, but not cross-entropy cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y)) -train_step = tf.train.AdamOptimizer(0.01).minimize(cost) +train_step = tf.train.AdamOptimizer(learning_r).minimize(cost) # init session -step, cost_hist_train, cost_hist_test, value_hist_train, value_hist_test, value_hist_cv, value_hist_cv_ma = \ - 0, [], [], [], [], [], [] +cost_hist_train, cost_hist_test, value_hist_train, value_hist_test, value_hist_cv, value_hist_train_ma, \ + value_hist_test_ma, value_hist_cv_ma, step, step_hist, saving_score = [], [], [], [], [], [], [], [], 0, [], 0.05 +saver = tf.train.Saver() init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) @@ -54,75 +67,73 @@ # main loop while True: - if step == 100000: + if step == 2000: break # train model - x_train, y_train = get_data_batch([input_train, output_train], batch_size) - _, cost_train = sess.run([train_step, cost], feed_dict={x: x_train, y: y_train}) + x_train, y_train = get_data_batch([input_train, output_train], batch_size, sequential=False) + _, cost_train = sess.run([train_step, cost], + feed_dict={x: x_train, y: y_train, learning_r: learning_rate, drop_out: drop_keep_prob}) # keep track of stuff step += 1 - if step % 100 == 0 or step == 1: + if step % 1 == 0 or step == 1: # get y_ predictions - y_train = sess.run([y_], feed_dict={x: input_train, y: output_train}) - cost_test, y_test = sess.run([cost, y_], feed_dict={x: input_test, y: output_test}) - y_cv = sess.run([y_], feed_dict={x: input_cv, y: output_cv}) + y_train_pred = sess.run(y_, feed_dict={x: input_train, drop_out: drop_keep_prob}) + y_test_pred, cost_test = sess.run([y_, cost], feed_dict={x: input_test, y: output_test, drop_out: drop_keep_prob}) + y_cv_pred = sess.run(y_, feed_dict={x: input_cv, drop_out: drop_keep_prob}) # get portfolio value - signal_test, signal_train, signal_cv = get_signal(y_test), get_signal(y_train[0]), get_signal(y_cv[0]) - value_test = portfolio_value(price_test[1:], signal_test[:-1], trans_costs=0) - value_train = portfolio_value(price_train[1:], signal_train[:-1], trans_costs=0) - value_cv = portfolio_value(price_cv[1:], signal_cv[:-1], trans_costs=0) + signal_train, signal_test, signal_cv = get_signal(y_train_pred), get_signal(y_test_pred), get_signal(y_cv_pred) + value_train = 1 + np.cumsum(np.sum(signal_train[:-1] * price_train[1:], axis=1)) + value_test = 1 + np.cumsum(np.sum(signal_test[:-1] * price_test[1:], axis=1)) + value_cv = 1 + np.cumsum(np.sum(signal_cv[:-1] * price_cv[1:], axis=1)) # save history - cost_hist_train.append(cost_train / batch_size) - cost_hist_test.append(cost_test / batch_size) + step_hist.append(step) + cost_hist_train.append(cost_train) + cost_hist_test.append(cost_test) value_hist_train.append(value_train[-1]) value_hist_test.append(value_test[-1]) value_hist_cv.append(value_cv[-1]) - value_hist_cv_ma.append(np.mean(value_hist_cv[-value_cv_moving_average:])) + value_hist_train_ma.append(np.mean(value_hist_train[-value_moving_average:])) + value_hist_test_ma.append(np.mean(value_hist_test[-value_moving_average:])) + value_hist_cv_ma.append(np.mean(value_hist_cv[-value_moving_average:])) print('Step {}: train {:.4f}, test {:.4f}'.format(step, cost_train, cost_test)) if plotting: - length = 1000 - - pl.figure(1) + pl.figure(1, figsize=(3, 7), dpi=80, facecolor='w', edgecolor='k') pl.subplot(211) - pl.title('Cost') - pl.plot(cost_hist_train, color='darkorange') - pl.plot(cost_hist_test, color='dodgerblue') - # pl.legend(loc='upper right') + pl.title('cost function') + pl.plot(step_hist, cost_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, cost_hist_test, color='dodgerblue', linewidth=0.3) pl.subplot(212) pl.title('Portfolio value') - pl.plot(value_hist_train, color='darkorange', linewidth=0.2) - pl.plot(value_hist_test, color='dodgerblue', linewidth=0.2) - pl.plot(value_hist_cv, color='magenta', linewidth=2) - pl.plot(value_hist_cv_ma, color='black', linewidth=0.5) - + pl.plot(step_hist, value_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, value_hist_test, color='dodgerblue', linewidth=0.3) + pl.plot(step_hist, value_hist_cv, color='magenta', linewidth=1) + pl.plot(step_hist, value_hist_train_ma, color='tomato', linewidth=1.5) + pl.plot(step_hist, value_hist_test_ma, color='royalblue', linewidth=1.5) + pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=1.5) pl.pause(1e-10) -# -# pl.figure(3) -# pl.plot(value_hist_cv_ma) -# -# pl.figure(4) -# pl.plot(value_train) -# pl.plot(value_test) -# pl.plot(value_cv) -# -# a = [] -# b = [] -# c = [] -# for i in range(len(value_hist_train)): -# if value_hist_train[i] > 1 and value_hist_test[i] > 1 and value_hist_cv[i] > 1: -# a.append(value_hist_train[i]) -# b.append(value_hist_test[i]) -# c.append(value_hist_cv[i]) -# -# pl.scatter(b, c) \ No newline at end of file + # save if some complicated rules + if saving: + current_score = 0 if value_test[-1] < 0.01 or value_cv[-1] < 0.01 \ + else np.average([value_test[-1], value_cv[-1]]) + saving_score = current_score if saving_score < current_score else saving_score + if saving_score == current_score and saving_score > 0.05: + saver.save(sess, 'saved_models/lr-v1-avg_score{:.3f}'.format(current_score), global_step=step) + print('Model saved. Average score: {:.2f}'.format(current_score)) + + pl.figure(2) + pl.plot(value_train, linewidth=1) + pl.plot(value_test, linewidth=1) + pl.plot(value_cv, linewidth=1) + pl.pause(1e-10) + diff --git a/train_logistic_regression_v2.py b/train_logistic_regression_v2.py index f09b79e..e98604d 100644 --- a/train_logistic_regression_v2.py +++ b/train_logistic_regression_v2.py @@ -21,15 +21,20 @@ from helpers.get_features import get_features, min_max_scaling +# other-params +np.set_printoptions(linewidth=75*3+5, edgeitems=6) +pl.rcParams.update({'font.size': 6}) + # hyper-params batch_size = 1024 -plotting = False -saving = True -value_cv_moving_average = 50 +learning_rate = 0.002 +drop_keep_prob = 0.3 +value_moving_average = 50 split = (0.5, 0.3, 0.2) +plotting = False +saving = False # load data -# TODO oanda_data = np.load('data\\EUR_USD_H1.npy')[-50000:] price_data_raw = extract_timeseries_from_oanda_data(oanda_data, ['closeMid']) input_data_raw, input_data_dummy = get_features(oanda_data) @@ -41,7 +46,7 @@ input_data_scaled_no_dummies = (input_data - min_max_scaling[1, :]) / (min_max_scaling[0, :] - min_max_scaling[1, :]) input_data_scaled = np.concatenate([input_data_scaled_no_dummies, input_data_dummy], axis=1) -# split to train,test and cross validation +# split to train, test and cross validation input_train, input_test, input_cv, price_train, price_test, price_cv = \ train_test_validation_split([input_data_scaled, price_data], split=split) @@ -49,54 +54,60 @@ _, input_dim = np.shape(input_data_scaled) # forward-propagation -x, _, logits, y_ = logistic_regression(input_dim, 3, drop_keep_prob=0.7) +x, y, logits, y_, learning_r, drop_out = logistic_regression(input_dim, 3) # tf cost and optimizer price_h = tf.placeholder(tf.float32, [None, 1]) signals = tf.constant([[1., -1., 0.]]) -objective = (tf.reduce_mean(y_[:-1] * signals * price_h[1:] * 100)) # profit function -train_step = tf.train.AdamOptimizer(0.001).minimize(-objective) +cost = tf.reduce_mean(y_ * signals * price_h * 100) # * 24 * 251 # objective fun: annualized average hourly return +train_step = tf.train.AdamOptimizer(learning_r).minimize(-cost) # init session -step, step_hist, objective_hist_train, objective_hist_test, value_hist_train, value_hist_test, \ - value_hist_cv, value_hist_cv_ma, saving_score = 0, [], [], [], [], [], [], [], 0.05 +cost_hist_train, cost_hist_test, value_hist_train, value_hist_test, value_hist_cv, value_hist_train_ma, \ + value_hist_test_ma, value_hist_cv_ma, step, step_hist, saving_score = [], [], [], [], [], [], [], [], 0, [], 0.05 saver = tf.train.Saver() init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) - # main loop while True: + if step ==30000: + break + # train model - x_train, price_batch = get_data_batch([input_train, price_train], batch_size) - _, objective_train, sig = sess.run([train_step, objective, y_], feed_dict={x: x_train, price_h: price_batch}) + x_train, price_batch = get_data_batch([input_train[:-1], price_train[1:]], batch_size, sequential=False) + _, cost_train = sess.run([train_step, cost], + feed_dict={x: x_train, price_h: price_batch, + learning_r: learning_rate, drop_out: drop_keep_prob}) # keep track of stuff step += 1 if step % 100 == 0 or step == 1: # get y_ predictions - y_train_pred = sess.run(y_, feed_dict={x: input_train}) - y_test_pred, objective_test = sess.run([y_, objective], feed_dict={x: input_test, price_h: price_test}) - y_cv_pred = sess.run(y_, feed_dict={x: input_cv}) + y_train_pred = sess.run(y_, feed_dict={x: input_train, drop_out: drop_keep_prob}) + y_test_pred, cost_test = sess.run([y_, cost], feed_dict={x: input_test[:-1], price_h: price_test[1:], drop_out: drop_keep_prob}) + y_cv_pred = sess.run(y_, feed_dict={x: input_cv, drop_out: drop_keep_prob}) # get portfolio value value_train = 1 + np.cumsum(np.sum(y_train_pred[:-1] * [1., -1., 0.] * price_train[1:], axis=1)) - value_test = 1 + np.cumsum(np.sum(y_test_pred[:-1] * [1., -1., 0.] * price_test[1:], axis=1)) + value_test = 1 + np.cumsum(np.sum(y_test_pred * [1., -1., 0.] * price_test[1:], axis=1)) value_cv = 1 + np.cumsum(np.sum(y_cv_pred[:-1] * [1., -1., 0.] * price_cv[1:], axis=1)) # save history step_hist.append(step) - objective_hist_train.append(objective_train) - objective_hist_test.append(objective_test) + cost_hist_train.append(cost_train) + cost_hist_test.append(cost_test) value_hist_train.append(value_train[-1]) value_hist_test.append(value_test[-1]) value_hist_cv.append(value_cv[-1]) - value_hist_cv_ma.append(np.mean(value_hist_cv[-value_cv_moving_average:])) + value_hist_train_ma.append(np.mean(value_hist_train[-value_moving_average:])) + value_hist_test_ma.append(np.mean(value_hist_test[-value_moving_average:])) + value_hist_cv_ma.append(np.mean(value_hist_cv[-value_moving_average:])) - print('Step {}: train {:.4f}, test {:.4f}'.format(step, objective_train, objective_test)) + print('Step {}: train {:.4f}, test {:.4f}'.format(step, cost_train, cost_test)) if plotting: @@ -104,18 +115,20 @@ pl.subplot(211) pl.title('Objective function') - pl.plot(step_hist, objective_hist_train, color='darkorange', linewidth=0.3) - pl.plot(step_hist, objective_hist_test, color='dodgerblue', linewidth=0.3) + pl.plot(step_hist, cost_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, cost_hist_test, color='dodgerblue', linewidth=0.3) pl.subplot(212) pl.title('Portfolio value') pl.plot(step_hist, value_hist_train, color='darkorange', linewidth=0.3) pl.plot(step_hist, value_hist_test, color='dodgerblue', linewidth=0.3) pl.plot(step_hist, value_hist_cv, color='magenta', linewidth=1) - pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=0.5) + pl.plot(step_hist, value_hist_train_ma, color='tomato', linewidth=1.5) + pl.plot(step_hist, value_hist_test_ma, color='royalblue', linewidth=1.5) + pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=1.5) pl.pause(1e-10) - # save if some complicated rules + # save if some complicated rules if saving: current_score = 0 if value_test[-1] < 0.01 or value_cv[-1] < 0.01 \ else np.average([value_test[-1], value_cv[-1]]) @@ -125,7 +138,8 @@ print('Model saved. Average score: {:.2f}'.format(current_score)) pl.figure(2) - pl.plot(value_test, linewidth=0.2) - pl.plot(value_cv, linewidth=2) + pl.plot(value_train, linewidth=1) + pl.plot(value_test, linewidth=1) + pl.plot(value_cv, linewidth=1) pl.pause(1e-10) diff --git a/train_lstm_v1.py b/train_lstm_v1.py index b629d53..b63adce 100644 --- a/train_lstm_v1.py +++ b/train_lstm_v1.py @@ -1,5 +1,5 @@ """ -Training lstm model +Training lstm model v1 """ import numpy as np @@ -9,25 +9,36 @@ from helpers.utils import price_to_binary_target, extract_timeseries_from_oanda_data, train_test_validation_split from helpers.utils import remove_nan_rows, get_signal, portfolio_value, get_data_batch, get_lstm_input_output from models import lstm_nn -from helpers.get_features import get_features +from helpers.get_features import get_features, min_max_scaling + + +# other-params +np.set_printoptions(linewidth=75*3+5, edgeitems=6) +pl.rcParams.update({'font.size': 6}) # hyper-params batch_size = 1024 -time_steps = 12 +learning_rate = 0.001 +drop_keep_prob = 0.6 +value_moving_average = 50 +split = (0.7, 0.2, 0.1) plotting = False -value_cv_moving_average = 100 -split = (0.5, 0.3, 0.2) +saving = False +time_steps = 5 # load data -oanda_data = np.load('data\\EUR_GBP_H1.npy')[-50000:] -input_data_raw, input_data_dummies = get_features(oanda_data) -output_data_raw = price_to_binary_target(oanda_data, delta=0.00037) +oanda_data = np.load('data\\EUR_USD_H1.npy') # [-50000:] +output_data_raw = price_to_binary_target(oanda_data, delta=0.00027) price_data_raw = extract_timeseries_from_oanda_data(oanda_data, ['closeMid']) +input_data_raw, input_data_dummy_raw = get_features(oanda_data) +price_data_raw = np.concatenate([[[0]], + (price_data_raw[1:] - price_data_raw[:-1]) / (price_data_raw[1:] + 1e-10)], axis=0) # prepare data -input_data, output_data, input_data_dummies, price_data = \ - remove_nan_rows([input_data_raw, output_data_raw, input_data_dummies, price_data_raw]) -input_data = np.concatenate([minmax_scale(input_data, axis=1), input_data_dummies], axis=1) +input_data, output_data, input_data_dummy, price_data = \ + remove_nan_rows([input_data_raw, output_data_raw, input_data_dummy_raw, price_data_raw]) +input_data_scaled_no_dummies = (input_data - min_max_scaling[1, :]) / (min_max_scaling[0, :] - min_max_scaling[1, :]) +input_data = np.concatenate([input_data_scaled_no_dummies, input_data_dummy], axis=1) input_data, output_data = get_lstm_input_output(input_data, output_data, time_steps=time_steps) price_data = price_data[-len(input_data):] @@ -40,16 +51,16 @@ _, output_dim = np.shape(output_data) # forward-propagation -x, y, logits, y_ = lstm_nn(input_dim, output_dim, time_steps=time_steps, n_hidden=[16], drop_keep_prob=0.3) +x, y, logits, y_, learning_r, drop_out = lstm_nn(input_dim, output_dim, time_steps=time_steps, n_hidden=[8]) # tf cost and optimizer -# TODO: maximize return or sharpe or something, but not cross-entropy cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=y)) -train_step = tf.train.AdamOptimizer(0.01).minimize(cost) +train_step = tf.train.AdamOptimizer(learning_r).minimize(cost) # init session -step, cost_hist_train, cost_hist_test, value_hist_train, value_hist_test, value_hist_cv, value_hist_cv_ma = \ - 0, [], [], [], [], [], [] +cost_hist_train, cost_hist_test, value_hist_train, value_hist_test, value_hist_cv, value_hist_train_ma, \ + value_hist_test_ma, value_hist_cv_ma, step, step_hist, saving_score = [], [], [], [], [], [], [], [], 0, [], 0.05 +saver = tf.train.Saver() init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) @@ -57,63 +68,95 @@ # train while True: - if step == 100000: + if step == 30000: break # train model - x_train, y_train = get_data_batch([input_train, output_train], batch_size) - _, cost_train = sess.run([train_step, cost], feed_dict={x: x_train, y: y_train}) + x_train, y_train = get_data_batch([input_train, output_train], batch_size, sequential=False) + _, cost_train = sess.run([train_step, cost], + feed_dict={x: x_train, y: y_train, learning_r: learning_rate, drop_out: drop_keep_prob}) # keep track of stuff step += 1 if step % 100 == 0 or step == 1: # get y_ predictions - y_train = sess.run([y_], feed_dict={x: input_train, y: output_train}) - cost_test, y_test = sess.run([cost, y_], feed_dict={x: input_test, y: output_test}) - y_cv = sess.run([y_], feed_dict={x: input_cv, y: output_cv}) + y_train_pred = sess.run(y_, feed_dict={x: input_train, drop_out: drop_keep_prob}) + cost_test, y_test_pred = sess.run([cost, y_], feed_dict={x: input_test, y: output_test, drop_out: drop_keep_prob}) + y_cv_pred = sess.run(y_, feed_dict={x: input_cv, y: output_cv, drop_out: drop_keep_prob}) # get portfolio value - signal_test, signal_train, signal_cv = get_signal(y_test), get_signal(y_train[0]), get_signal(y_cv[0]) - value_test = portfolio_value(price_test, signal_test, trans_costs=0) - value_train = portfolio_value(price_train, signal_train, trans_costs=0) - value_cv = portfolio_value(price_cv, signal_cv, trans_costs=0) + signal_train, signal_test, signal_cv = get_signal(y_train_pred), get_signal(y_test_pred), get_signal(y_cv_pred) + value_train = 1 + np.cumsum(np.sum(signal_train[:-1] * price_train[1:], axis=1)) + value_test = 1 + np.cumsum(np.sum(signal_test[:-1] * price_test[1:], axis=1)) + value_cv = 1 + np.cumsum(np.sum(signal_cv[:-1] * price_cv[1:], axis=1)) # save history - cost_hist_train.append(cost_train / batch_size) - cost_hist_test.append(cost_test / batch_size) + step_hist.append(step) + cost_hist_train.append(cost_train) + cost_hist_test.append(cost_test) value_hist_train.append(value_train[-1]) value_hist_test.append(value_test[-1]) value_hist_cv.append(value_cv[-1]) - value_hist_cv_ma.append(np.mean(value_hist_cv[-value_cv_moving_average:])) + value_hist_train_ma.append(np.mean(value_hist_train[-value_moving_average:])) + value_hist_test_ma.append(np.mean(value_hist_test[-value_moving_average:])) + value_hist_cv_ma.append(np.mean(value_hist_cv[-value_moving_average:])) print('Step {}: train {:.4f}, test {:.4f}'.format(step, cost_train, cost_test)) if plotting: - pl.figure(1) + pl.figure(1, figsize=(3, 7), dpi=80, facecolor='w', edgecolor='k') pl.subplot(211) - pl.title('Cost') - pl.plot(cost_hist_train, color='darkorange') - pl.plot(cost_hist_test, color='dodgerblue') + pl.title('cost function') + pl.plot(step_hist, cost_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, cost_hist_test, color='dodgerblue', linewidth=0.3) pl.subplot(212) pl.title('Portfolio value') - pl.plot(value_hist_train, color='darkorange', linewidth=0.2) - pl.plot(value_hist_test, color='dodgerblue', linewidth=0.2) - pl.plot(value_hist_cv, color='magenta', linewidth=2) - pl.plot(value_hist_cv_ma, color='black', linewidth=0.5) - + pl.plot(step_hist, value_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, value_hist_test, color='dodgerblue', linewidth=0.3) + pl.plot(step_hist, value_hist_cv, color='magenta', linewidth=1) + pl.plot(step_hist, value_hist_train_ma, color='tomato', linewidth=1.5) + pl.plot(step_hist, value_hist_test_ma, color='royalblue', linewidth=1.5) + pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=1.5) pl.pause(1e-10) -pl.figure(3) -pl.plot(value_train) -pl.plot(value_test) -pl.plot(value_cv) - -threshold = 1.12 - -for i in range(len(value_hist_cv)): - if value_hist_cv[i] > threshold and value_hist_train[i] > threshold and value_hist_test[i] > threshold: - print(value_hist_cv[i], value_hist_train[i], value_hist_test[i]) + # save if some complicated rules + if saving: + current_score = 0 if value_test[-1] < 0.01 or value_cv[-1] < 0.01 \ + else np.average([value_test[-1], value_cv[-1]]) + saving_score = current_score if saving_score < current_score else saving_score + if saving_score == current_score and saving_score > 0.05: + saver.save(sess, 'saved_models/lstm-v1-avg_score{:.3f}'.format(current_score), global_step=step) + print('Model saved. Average score: {:.2f}'.format(current_score)) + + pl.figure(2) + pl.plot(value_test, linewidth=0.2) + pl.plot(value_cv, linewidth=2) + pl.pause(1e-10) + + +def save_plot(): + pl.figure(1, figsize=(3, 7), dpi=80, facecolor='w', edgecolor='k') + + pl.subplot(211) + pl.title('cost function') + pl.plot(step_hist, cost_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, cost_hist_test, color='dodgerblue', linewidth=0.3) + + pl.subplot(212) + pl.title('Portfolio value') + pl.plot(step_hist, value_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, value_hist_test, color='dodgerblue', linewidth=0.3) + pl.plot(step_hist, value_hist_cv, color='magenta', linewidth=1) + pl.plot(step_hist, value_hist_train_ma, color='tomato', linewidth=1.5) + pl.plot(step_hist, value_hist_test_ma, color='royalblue', linewidth=1.5) + pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=1.5) + pl.pause(1e-10) + + pl.savefig('lstm_v1_{:.3f}_{:.3f}.png'.format(learning_rate, value_cv[-1])) + pl.close() + +save_plot() diff --git a/train_lstm_v2.py b/train_lstm_v2.py index 48af442..1f89ff5 100644 --- a/train_lstm_v2.py +++ b/train_lstm_v2.py @@ -1,10 +1,7 @@ """ Training lstm v2: -using model to allocate funds, i.e. maximizing return without correct labels. +using model to allocate funds, i.e. maximizing return without target labels. -Other options to set: -np.set_printoptions(linewidth=75*3+5, edgeitems=6) -pl.rcParams.update({'font.size': 6}) """ import numpy as np @@ -15,16 +12,23 @@ from models import lstm_nn from helpers.get_features import get_features, min_max_scaling + +# other-params +np.set_printoptions(linewidth=75*3+5, edgeitems=6) +pl.rcParams.update({'font.size': 6}) + # hyper-params -batch_size = 256 -time_steps = 12 +batch_size = 10024 +learning_rate = 0.05 +drop_keep_prob = 0.7 +value_moving_average = 50 +split = (0.7, 0.2, 0.1) plotting = False saving = False -value_cv_moving_average = 50 -split = (0.6, 0.2, 0.1) +time_steps = 6 # load data -oanda_data = np.load('data\\EUR_USD_M10.npy') # [-50000:] +oanda_data = np.load('data\\EUR_USD_H1.npy') # [-50000:] price_data_raw = extract_timeseries_from_oanda_data(oanda_data, ['closeMid']) input_data_raw, input_data_dummy = get_features(oanda_data) price_data_raw = np.concatenate([[[0]], @@ -45,18 +49,17 @@ _, _, input_dim = np.shape(input_train) # forward-propagation -x, y, logits, y_ = lstm_nn(input_dim, 3, time_steps=time_steps, n_hidden=[3], drop_keep_prob=0.6) +x, y, logits, y_, learning_r, drop_out = lstm_nn(input_dim, 3, time_steps=time_steps, n_hidden=[3]) # tf cost and optimizer price_h = tf.placeholder(tf.float32, [None, 1]) -signals = tf.constant([[1., -1., 0.]]) -objective = (tf.reduce_mean(y_[:-1] * signals * price_h[1:] * 100)) # profit function -train_step = tf.train.AdamOptimizer(0.001).minimize(-objective) - +signals = tf.constant([[1., -1., -1e-10]]) +cost = (tf.reduce_mean(y_ * signals * price_h * 100)) # profit function +train_step = tf.train.AdamOptimizer(learning_r).minimize(-cost) # init session -step, step_hist, objective_hist_train, objective_hist_test, value_hist_train, value_hist_test, \ - value_hist_cv, value_hist_cv_ma, saving_score = 0, [], [], [], [], [], [], [], 0.05 +cost_hist_train, cost_hist_test, value_hist_train, value_hist_test, value_hist_cv, value_hist_train_ma, \ + value_hist_test_ma, value_hist_cv_ma, step, step_hist, saving_score = [], [], [], [], [], [], [], [], 0, [], 0.05 saver = tf.train.Saver() init = tf.global_variables_initializer() sess = tf.Session() @@ -65,34 +68,41 @@ # train while True: + if step == 30000: + break + # train model - x_train, price_batch = get_data_batch([input_train, price_train], batch_size) - _, objective_train, sig = sess.run([train_step, objective, y_], feed_dict={x: x_train, price_h: price_batch}) + x_train, price_batch = get_data_batch([input_train[:-1], price_train[1:]], batch_size, sequential=False) + _, cost_train = sess.run([train_step, cost], + feed_dict={x: x_train, price_h: price_batch, + learning_r: learning_rate, drop_out: drop_keep_prob}) # keep track of stuff step += 1 if step % 100 == 0 or step == 1: # get y_ predictions - y_train_pred = sess.run(y_, feed_dict={x: input_train}) - y_test_pred, objective_test = sess.run([y_, objective], feed_dict={x: input_test, price_h: price_test}) - y_cv_pred = sess.run(y_, feed_dict={x: input_cv}) + y_train_pred = sess.run(y_, feed_dict={x: input_train, drop_out: drop_keep_prob}) + y_test_pred, cost_test = sess.run([y_, cost], feed_dict={x: input_test[:-1], price_h: price_test[1:], drop_out: drop_keep_prob}) + y_cv_pred = sess.run(y_, feed_dict={x: input_cv, drop_out: drop_keep_prob}) # get portfolio value value_train = 1 + np.cumsum(np.sum(y_train_pred[:-1] * [1., -1., 0.] * price_train[1:], axis=1)) - value_test = 1 + np.cumsum(np.sum(y_test_pred[:-1] * [1., -1., 0.] * price_test[1:], axis=1)) + value_test = 1 + np.cumsum(np.sum(y_test_pred * [1., -1., 0.] * price_test[1:], axis=1)) value_cv = 1 + np.cumsum(np.sum(y_cv_pred[:-1] * [1., -1., 0.] * price_cv[1:], axis=1)) # save history step_hist.append(step) - objective_hist_train.append(objective_train) - objective_hist_test.append(objective_test) + cost_hist_train.append(cost_train) + cost_hist_test.append(cost_test) value_hist_train.append(value_train[-1]) value_hist_test.append(value_test[-1]) value_hist_cv.append(value_cv[-1]) - value_hist_cv_ma.append(np.mean(value_hist_cv[-value_cv_moving_average:])) + value_hist_train_ma.append(np.mean(value_hist_train[-value_moving_average:])) + value_hist_test_ma.append(np.mean(value_hist_test[-value_moving_average:])) + value_hist_cv_ma.append(np.mean(value_hist_cv[-value_moving_average:])) - print('Step {}: train {:.4f}, test {:.4f}'.format(step, objective_train, objective_test)) + print('Step {}: train {:.4f}, test {:.4f}'.format(step, cost_train, cost_test)) if plotting: @@ -100,15 +110,17 @@ pl.subplot(211) pl.title('Objective function') - pl.plot(step_hist, objective_hist_train, color='darkorange', linewidth=0.3) - pl.plot(step_hist, objective_hist_test, color='dodgerblue', linewidth=0.3) + pl.plot(step_hist, cost_hist_train, color='darkorange', linewidth=0.3) + pl.plot(step_hist, cost_hist_test, color='dodgerblue', linewidth=0.3) pl.subplot(212) pl.title('Portfolio value') pl.plot(step_hist, value_hist_train, color='darkorange', linewidth=0.3) pl.plot(step_hist, value_hist_test, color='dodgerblue', linewidth=0.3) pl.plot(step_hist, value_hist_cv, color='magenta', linewidth=1) - pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=0.5) + pl.plot(step_hist, value_hist_train_ma, color='tomato', linewidth=1.5) + pl.plot(step_hist, value_hist_test_ma, color='royalblue', linewidth=1.5) + pl.plot(step_hist, value_hist_cv_ma, color='black', linewidth=1.5) pl.pause(1e-10) # save if some complicated rules @@ -121,7 +133,8 @@ print('Model saved. Average score: {:.2f}'.format(current_score)) pl.figure(2) - pl.plot(value_test, linewidth=0.2) - pl.plot(value_cv, linewidth=2) + pl.plot(value_train, linewidth=1) + pl.plot(value_test, linewidth=1) + pl.plot(value_cv, linewidth=1) pl.pause(1e-10)