The Python Quantiacs toolbox allows you to use machine learning methods for coding trading algorithms. We describe an example based on keras and use a Long Short-Term Memory (LSTM) model for time series forecasting.
All Quantiacs system files should contain a definition of the settings:
def mySettings():
settings = {}
settings['markets'] = ['F_ES']
settings['slippage'] = 0.05
settings['budget'] = 1000000
settings['lookback'] = 504
settings['beginInSample'] = '20140101'
settings['endInSample'] = '20170101'
return settings
These settings define one asset to be traded, the E-Mini S&P 500 Index Futures, set slippage to be 5% of the daily range of the asset, fix initial capital to 1 M USD, define a lookback period of 504 days and set the initial and final days of the simulation.
In addition, we define an auxiliary function which creates and trains the LSTM network. First of all, we import the required modules:
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
import tensorflow as tf
Next, we define the function:
def createAndTrain(DATE, CLOSE, settings):
lst_dates = DATE.tolist()
lst_dates = lst_dates[1:]Quantiacs
price_data = CLOSE[1:, :]
average = np.average(price_data)
std_dev = np.std(price_data)
price_data = (price_data - average) / std_dev
return_data = (CLOSE[1:, :] - CLOSE[:- 1, :]) / CLOSE[:- 1, :]
# define training set and target:
trainX = np.reshape(price_data, (price_data.shape[0], 1, price_data.shape[1]))
trainY = return_data
# create and fit the LSTM network:
model = Sequential()
model.add(LSTM(4, input_dim=1))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=100, batch_size=1, verbose=0)
settings['mean'] = average
settings['std'] = std_dev
settings['model'] = model
return
The function performs supervised learning by defining a training set where the features are the normalized CLOSE prices of the assets. Normalization takes place by subtracting from the CLOSE the mean and dividing by the standard deviation. The target variable is represented by the relative returns of the assets.
Next, it creates a LSTM network and fits it with the training set. The function expands the settings for the trading system by defining three new objects:
settings['mean'] = average
settings['std'] = std_dev
settings['model'] = model
which are used by the trading system.
The trading logic is defined in the trading system function:
def myTradingSystem(DATE, CLOSE, exposure, equity, settings):
lookBack = settings['lookback']
if 'model' not in settings:
createAndTrain(DATE[:lookBack - 2], CLOSE[:lookBack - 2], settings)
model = settings['model']
average = settings['mean']
std_dev = settings['std']
testX = (CLOSE[lookBack-1:] - average) / std_dev
testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1]))
testY = model.predict(testX)
newDelta = testY[0]
nMarkets = CLOSE.shape[1]
pos = np.ones((1, nMarkets))
if newDelta >= 0:
pos[0] = 1
else:
pos[0] = -1
return pos, settings
The trading system calls the auxiliary function which builds the model using a slice of the data and later applies the model for predicting the relative returns. If the predicted return is positive the system goes long, otherwise it goes short.
The main function call is:
if __name__ == '__main__':
from quantiacsToolbox import runts
inter_op_parallelism_threads = 1
tf.random.set_seed(1)
results = runts(__file__)
The same logic of defining an auxiliary function for performing intermediate operations can be used for simpler methods, like performing a linear regression.
If you are interested in statistics and machine learning, and want to test your ideas on global financial markets, submit your code before end of 2020 and take part to the Q14 contest on Quantiacs!
The Full Strategy
import numpy as np
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
import tensorflow as tf
def createAndTrain(DATE, CLOSE, settings):
lst_dates = DATE.tolist()
lst_dates = lst_dates[1:]
price_data = CLOSE[1:, :]
average = np.average(price_data)
std_dev = np.std(price_data)
price_data = (price_data - average) / std_dev
return_data = (CLOSE[1:, :] - CLOSE[:- 1, :]) / CLOSE[:- 1, :]
# define training set and target:
trainX = np.reshape(price_data, (price_data.shape[0], 1, price_data.shape[1]))
trainY = return_data
# create and fit the LSTM network:
model = Sequential()
model.add(LSTM(4, input_dim=1))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=100, batch_size=1, verbose=0)
settings['mean'] = average
settings['std'] = std_dev
settings['model'] = model
return
def myTradingSystem(DATE, CLOSE, exposure, equity, settings):
lookBack = settings['lookback']
if 'model' not in settings:
createAndTrain(DATE[:lookBack - 2], CLOSE[:lookBack - 2], settings)
model = settings['model']
average = settings['mean']
std_dev = settings['std']
testX = (CLOSE[lookBack-1:] - average) / std_dev
testX = np.reshape(testX, (testX.shape[0], 1, testX.shape[1]))
testY = model.predict(testX)
newDelta = testY[0]
nMarkets = CLOSE.shape[1]
pos = np.ones((1, nMarkets))
if newDelta >= 0:
pos[0] = 1
else:
pos[0] = -1
return pos, settings
def mySettings():
settings = {}
settings['markets'] = ['F_ES']
settings['slippage'] = 0.05
settings['budget'] = 1000000
settings['lookback'] = 504
settings['beginInSample'] = '20140101'
settings['endInSample'] = '20170101'
return settings
if __name__ == '__main__':Quantiacs
from quantiacsToolbox import runts
inter_op_parallelism_threads = 1
tf.random.set_seed(1)
results = runts(__file__)
Quantiacs