here an example using the Python plugin. I installed Python just like is explained in the main Python thread. You will have to also install a bunch of libraries (see Python code import).
This is an example of "supervised learning". Which means that you control the input and output. It works good for "synthetic" data or for instance real data that shows clear periodicities. But for stock or futures price data I have not found something that works. But I am just a novice at this.
I understand that "reinforcement learning' might give better results. With reinforcement learning (if I understood it correctly) you learn the NN to trade rather than predict the exact price. But I have not yet worked on that a lot yet.
Python code below I found on the net. Source is shown in the Python code (top)
AFL code:
SetBarsRequired( sbrAll, sbrAll );
_N( pythonpath = "C:\\Users\\win 10\\AppData\\Local\\Programs\\Python\\Python38\\mypython\\neural\\relataly\\" );
_N( pythonfile = "MultivariateDatesSaveLoad3.py" );
PyLoadFromFile( "Excersize6", pythonpath + pythonfile );
trainmodel = ParamTrigger( "Train Model", "Start Training Model" );
calculateforecast = ParamTrigger( "Calculate Forecast", "Start Forecast Calculation" );
trainfactor = Param( "Train Factor", 0.8, 0.1, 1, 0.01 );
sequence_length = Param( "Sequence Length", 50, 1, 250, 1 );
nfut = Param( "Forecast bar Nbars into the future", 1, 1, 10, 1 );
_N( startDate = ParamDate( "Start Date", "1-1-2021", 1 ) );
_N( endDate = ParamDate( "End Date", "7-28-2022", 1 ) );
datatype = ParamToggle( "Data Type", "Real|Synthetic", 1 );
resetstaticvariables = ParamTrigger( "Reset Static Variables", "Reset" );
showsignals = ParamToggle( "Show possible Trading Signals", "No|Yes", 0 );
SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
if( resetstaticvariables )
{
StaticVarRemove( "prediction" );
StaticVarRemove( "forecast" );
}
yearArray = Year();
monthArray = Month();
dayArray = Day();
hourArray = Hour();
minuteArray = Minute();
secondArray = Second();
if( datatype )
{
pi = 3.14159265359;
//sinusFunctionArray = 0.02 * Cum( 1 ) + sin( 0.125 * pi * Cum( 1 ) );
sinusFunctionArray = 0.02 * Cum( 1 ) + sin( 2 * pi * Cum( 1 ) / 20 ) + sin( 2 * pi * Cum( 1 ) / 40 ) + sin( 2 * pi * Cum( 1 ) / 500 );
C = H = L = O = V = sinusFunctionArray;
openArray = sinusFunctionArray;
highArray = sinusFunctionArray;
lowArray = sinusFunctionArray;
closeArray = sinusFunctionArray;
volumeArray = sinusFunctionArray;
ema20Array = MA( C, 20 );
ema100Array = EMA( C, 100 );
bbandTopArray = BBandTop( C, 20, 2 );
bbandBotArray = BBandBot( C, 20, 2 );
rsiArray = RSIa( C, 14 );
// the features
Plot( C, "Close Price", ColorRGB( 3, 157, 252 ), styleDots, Null, Null, 0, 0, 2 );
Plot( ema20Array, "EMA20", colorYellow, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );
Plot( ema100Array, "EMA100", colorAqua, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );
Plot( bbandTopArray, "BBANDTOP", colorViolet, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );
Plot( bbandBotArray, "BBANDBOT", colorViolet, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );
}
else
{
openArray = Open;
highArray = High;
lowArray = Low;
closeArray = MA( Close, 5 );
volumeArray = Volume;
ema20Array = EMA( C, 5 );
ema100Array = EMA( C, 100 );
bbandTopArray = BBandTop( C, 20, 2 );
bbandBotArray = BBandBot( C, 20, 2 );
rsiArray = RSIa( C, 14 );
// the features
Plot( C, "Close Price", ColorRGB( 3, 157, 252 ), styleCandle, Null, Null, 0, 0, 2 );
Plot( ema20Array, "EMA20", colorYellow, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );
Plot( ema100Array, "EMA100", colorAqua, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );
Plot( bbandTopArray, "BBANDTOP", colorViolet, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );
Plot( bbandBotArray, "BBANDBOT", colorViolet, styleLine | styleNoRescale, Null, Null, 0, 0, 1 );
}
if( trainmodel )
{
Say( "start training model" );
PyEvalFunction( "Excersize6", "getDataFromAmibroker", yearArray, monthArray, dayArray,
hourArray, minuteArray, secondArray,
openArray, highArray, lowArray, closeArray, volumeArray, ema20Array,
bbandTopArray, bbandBotArray, rsiArray,
startDate, endDate, nfut, sequence_length, trainfactor );
PyEvalFunction( "Excersize6", "trainModelUsingPython" );
predictionFromPython = PyEvalFunction( "Excersize6", "getPredictionFromPython" );
StaticVarSet( "prediction", Ref( predictionFromPython, -( nfut - 1 ) ) );
Say( "finished" );
}
if( calculateforecast )
{
Say( "calculate forecast" );
PyEvalFunction( "Excersize6", "getDataFromAmibroker", yearArray, monthArray, dayArray,
hourArray, minuteArray, secondArray,
openArray, highArray, lowArray, closeArray, volumeArray, ema20Array,
bbandTopArray, bbandBotArray, rsiArray,
startDate, endDate, nfut, sequence_length, trainfactor );
PyEvalFunction( "Excersize6", "calculateForecastUsingPython" );
forecastFromPython = PyEvalFunction( "Excersize6", "getForecastFromPython" );
StaticVarSet( "forecast", forecastFromPython );
Say( "finished" );
}
Plot( IIf( Nz( StaticVarGet( "prediction" ) ) == 0, Null, Nz( StaticVarGet( "prediction" ) ) ), "Prediction", ColorRGB( 249, 160, 72 ), styleDots | styleNoRescale | styleNoLabel, Null, Null, 0, 1, 4 );
Plot( IIf( Nz( StaticVarGet( "forecast" ) ) == 0, Null, Nz( StaticVarGet( "forecast" ) ) ), "Forecast", ColorRGB( 243, 50, 230 ), styleDots | styleNoRescale, Null, Null, ( nfut ), -1, 8 );
mask = DateTime() >= StrToDateTime( startDate ) AND DateTime() <= StrToDateTime( endDate );
startmask = mask AND !Ref( mask, -1 );
endmask = !mask AND Ref( mask, -1 );
Plot( mask, "", ColorRGB( 0, 0, 40 ), styleArea | styleOwnScale | styleNoLabel, 0, 1, 0, -3, 1 );
Plot( startMask, "", ColorGold, styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -2, 1 );
Plot( endMask, "", ColorGold, styleHistogram | styleOwnScale | styleNoLabel, 0, 1, 0, -2, 1 );
if( showsignals )
{
pred = Nz( StaticVarGet( "prediction" ) );
Buy = pred < Ref( pred, nfut ) && pred != 0;
Sell = pred > Ref( pred, nfut ) && pred != 0;
BuyPrice = C;
SellPrice = C;
Buy = ExRem( Buy, Sell );
Sell = ExRem( Sell, Buy );
Short = Sell;
Cover = Buy;
ShortPrice = C;
CoverPrice = C;
bi = BarIndex();
if( LastValue( ValueWhen( Buy, bi ) ) > LastValue( ValueWhen( Short, bi ) ) )
{
Sell[BarCount - 1] = 1;
}
else
if( LastValue( ValueWhen( Buy, bi ) ) < LastValue( ValueWhen( Short, bi ) ) )
{
Cover[BarCount - 1] = 1;
}
PlotShapes( IIf( Buy, shapeUpArrow, shapeNone ), colorDarkGreen, 0, L, -15 );
PlotShapes( IIf( Buy, shapeSmallCircle, shapeNone ), colorWhite, 0, BuyPrice, 0 );
PlotShapes( IIf( Sell, shapeDownArrow, shapeNone ), colorRed, 0, H, -15 );
PlotShapes( IIf( Sell, shapeSmallCircle, shapeNone ), colorWhite, 0, SellPrice, 0 );
PlotShapes( IIf( Short, shapeSmallDownTriangle, shapeNone ), colorRed, 0, H, IIf( Short AND Sell, -30, -15 ) );
PlotShapes( IIf( Short, shapeSmallCircle, shapeNone ), colorWhite, 0, ShortPrice, 0 );
PlotShapes( IIf( Cover, shapeSmallUpTriangle, shapeNone ), colorDarkGreen, 0, L, IIf( Cover AND Buy, -30, -15 ) );
PlotShapes( IIf( Cover, shapeSmallCircle, shapeNone ), colorWhite, 0, CoverPrice, 0 );
longResult = Prec( IIf( Sell, SellPrice - ValueWhen( Buy, BuyPrice ), 0 ), 2 );
shortResult = Prec( IIf( Cover, ValueWhen( Short, ShortPrice ) - CoverPrice, 0 ), 2 );
longResult = LastValue( Cum( IIf( longResult, longResult, 0 ) ) ) * PointValue;
shortResult = LastValue( Cum( IIf( shortResult, shortResult, 0 ) ) ) * PointValue;
//"longResult: " + longResult;
//"shortResult: "+ shortResult;
Title = "Result: " + ( longResult + shortResult );
}
Python code
'''
https://www.relataly.com/feature-engineering-for-multivariate-time-series-models-with-python/1813/
https://www.relataly.com/stock-market-prediction-using-multivariate-time-series-in-python/1815/
https://www.relataly.com/time-series-forecasting-changing-prediction-horizon/169/
https://github.com/thushv89/datacamp_tutorials/blob/master/tensorboard_tutorial/Tensorboard%20Tutorial.ipynb
https://github.com/ninja3697/Stocks-Price-Prediction-using-Multivariate-Analysis/blob/master/Multivatiate-LSTM/Multivariate-3-LSTM.ipynb
https://www.thepythoncode.com/article/stock-price-prediction-in-python-using-tensorflow-2-and-keras
'''
import sys
sys.path.append('C:/Users/win 10/AppData/Roaming/Python/Python38/site-packages')
sys.path.append('C:/Users/win 10/AppData/Local/Programs/Python/Python38/Lib/site-packages')
import tensorflow as tf
import math
import numpy as np
import pandas as pd
from datetime import date, timedelta, datetime
from pandas.plotting import register_matplotlib_converters
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from sklearn.metrics import mean_absolute_error, mean_squared_error
from keras.models import Sequential
from tensorflow.keras.models import load_model
from keras.layers import LSTM, Dense, Dropout
from keras.callbacks import EarlyStopping
from sklearn.preprocessing import RobustScaler, MinMaxScaler
import seaborn as sns
from joblib import dump, load
import random
import AmiPy
'''
# set seed, so we can get the same results after rerunning several times
np.random.seed(314)
tf.random.set_seed(314)
random.seed(314)
'''
def getDataFromAmibroker(year_arr, month_arr, day_arr, hour_arr, minute_arr, second_arr,
open_arr, high_arr, low_arr, close_arr, volume_arr,ema20_arr,
bbandtop_arr, bbandbot_arr, rsi_arr,
startdate, enddate, fut, sl, tf):
global df
global df1
global sequence_length
global trainfactor
global mask
global nfut
start_date = startdate
end_date = enddate
df = pd.DataFrame()
data_filtered = pd.DataFrame()
df['Year'] = year_arr.astype(int)
df['Month'] = month_arr.astype(int)
df['Day'] = day_arr.astype(int)
df['Hour'] = hour_arr.astype(int)
df['Minute'] = minute_arr.astype(int)
df['Second'] = second_arr.astype(int)
df['Date'] = pd.to_datetime(df[['Month', 'Day', 'Year']], format='%m%d%Y')
df['Datetime'] = pd.to_datetime(df[['Year', 'Month', 'Day', 'Hour', 'Minute','Second']])
df['Open'] = open_arr
df['High'] = high_arr
df['Low'] = low_arr
df['Close'] = close_arr
df['Volume'] = volume_arr
df['EMA20'] = ema20_arr
#df['EMA100'] = ema100_arr
df['Bollinger_Upper'] = bbandtop_arr
df['Bollinger_Lower'] = bbandbot_arr
df['RSI'] = rsi_arr
df['Predict'] = close_arr # fill with data array to overwrite later
df['Forecast'] = close_arr # fill with data array to overwrite later
sequence_length = int(sl)
trainfactor = tf
nfut = int(fut)
mask = (df['Date'] >= start_date) & (df['Date'] <= end_date)
df1 = df.loc[mask]
df['Predict'] = 0.0
df1['Predict'] = 0.0
df['Forecast'] = 0.0
df1['Forecast'] = 0.0
def getListWithFeatures():
# List of considered Features
FEATURES = [
# 'High',
# 'Low',
# 'Open',
'Close',
# 'Volume',
'EMA20',
# 'EMA100',
# 'Date',
# 'Day',
# 'Month',
# 'Year',
# 'Adj Close',
# 'close_shift-1',
# 'close_shift-2',
# 'MACD',
# 'RSI',
# 'MA200',
# 'MA200_high',
# 'MA200_low',
'Bollinger_Upper',
'Bollinger_Lower',
# 'MA100',
# 'MA50',
# 'MA26',
# 'MA14_low',
# 'MA14_high',
# 'MA12',
# 'EMA20',
# 'EMA100',
# 'EMA200',
# 'DIFF-MA200-MA50',
# 'DIFF-MA200-MA10',
# 'DIFF-MA200-CLOSE',
# 'DIFF-MA100-CLOSE',
# 'DIFF-MA50-CLOSE'
]
return FEATURES
def trainModelUsingPython():
# Indexing Batches
train_df1 = df1.sort_values(by=['Datetime']).copy()
# AmiPy.Print(str(train_df1) +'\n')
# We safe a copy of the dates index, before we need to reset it to numbers
date_index = train_df1.index
# We reset the index, so we can convert the date-index to a number-index
train_df1 = train_df1.reset_index(drop=True).copy()
FEATURES = getListWithFeatures()
dump(FEATURES, 'FEATURES.joblib') # save features list to disk
# Create the dataset with features and filter the data to the list of FEATURES
data = pd.DataFrame(train_df1)
data_filtered = data[FEATURES]
# We add a prediction column and set dummy values to prepare the data for scaling
data_filtered_ext = data_filtered.copy()
# Get the number of rows in the data
nrows = data_filtered.shape[0]
# Convert the data to numpy values
np_data_unscaled = np.array(data_filtered)
# np_data_unscaled = np.reshape(np_data_unscaled, (nrows, -1))
# Transform the data by scaling each feature to a range between 0 and 1
scaler = MinMaxScaler(feature_range=(0, 1))
np_data_scaled = scaler.fit_transform(np_data_unscaled)
dump(scaler, 'scaler.joblib') # save scale to disk
# Creating a separate scaler that works on a single column for scaling predictions
scaler_pred = MinMaxScaler()
df1_Close = pd.DataFrame(data_filtered_ext['Close'])
np_Close_scaled = scaler_pred.fit_transform(df1_Close)
dump(scaler_pred, 'scaler_pred.joblib') # save scaler to disk
# Prediction Index
index_Close = data_filtered.columns.get_loc("Close")
# Split the training data into train and train data sets
# As a first step, we get the number of rows to train the model on 80% of the data
train_data_len = math.ceil(np_data_scaled.shape[0] * trainfactor)
# Create the training and test data
train_data = np_data_scaled[0:train_data_len, :]
test_data = np_data_scaled[train_data_len - sequence_length:, :]
# The RNN needs data with the format of [samples, time steps, features]
# Here, we create N samples, sequence_length time steps per sample, and 6 features
def partition_dataset(sequence_length, data):
x, y = [], []
data_len = data.shape[0]
for i in range(sequence_length, data_len - nfut + 1):
x.append(data[i-sequence_length:i,:]) #contains sequence_length values 0-sequence_length * columsn
y.append(data[i + nfut - 1, index_Close]) #contains the prediction values for validation, for single-step prediction
# Convert the x and y to numpy arrays
x = np.array(x)
y = np.array(y)
return x, y
# Generate training data and test data
x_train, y_train = partition_dataset(sequence_length, train_data)
x_test, y_test = partition_dataset(sequence_length, test_data)
# AmiPy.Print(str(train_data.shape) +'\n')
# AmiPy.Print(str(test_data.shape) +'\n')
# Configure the neural network model
model = Sequential()
# Model with n_neurons = inputshape Timestamps, each with x_train.shape[2] variables
# AmiPy.Print(str(x_train.shape[0]) +'\n') # total length of training data
# AmiPy.Print(str(x_train.shape[1]) +'\n') # sequence length
# AmiPy.Print(str(x_train.shape[2]) +'\n') # number of features
n_neurons = x_train.shape[1] * x_train.shape[2]
#AmiPy.Print(str(n_neurons) +'\n')
model.add(LSTM(n_neurons, return_sequences=True, input_shape=(x_train.shape[1], x_train.shape[2])))
#model.add(Dropout(0.2))
model.add(LSTM(n_neurons, return_sequences=True))
#model.add(Dropout(0.2))
#model.add(LSTM(n_neurons, return_sequences=True))
#model.add(Dropout(0.2))
model.add(LSTM(n_neurons))
#model.add(Dropout(0.2))
#model.add(Dense(5))
#model.add(Dense(25, activation="sigmoid"))
model.add(Dense(1))
# Compile the model
model.compile(optimizer='adam', loss='mse')
# Training the model
epochs = 100
batch_size = 32
early_stop = EarlyStopping(monitor='loss', patience=5, verbose=0)
history = model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
validation_data=(x_test, y_test),
callbacks = [early_stop],
verbose=0
)
# Get the predicted values
y_pred_scaled = model.predict(x_test)
# Unscale the predicted values
y_pred = scaler_pred.inverse_transform(y_pred_scaled)
y_test_unscaled = scaler_pred.inverse_transform(y_test.reshape(-1, 1))
# AmiPy.Print(str(len(y_pred)) +'\n')
'''
plt.plot(y_pred, 'gp-',)
plt.plot(y_test_unscaled,'bo-' )
plt.show()
'''
# store prediction
offset1 = df1.index[0]
# AmiPy.Print(str(train_data_len + offset1) +'\n')
# AmiPy.Print(str(df1['Predict'].size + offset1 - nfut) +'\n')
df1.at[train_data_len + offset1:df1['Predict'].size + offset1 - nfut,'Predict'] = y_pred
df['Predict'].loc[mask] = df1['Predict']
# save the model to disk
model.save('myModel.h5')
def calculateForecastUsingPython():
scaler = load('scaler.joblib')
scaler_pred = load('scaler_pred.joblib')
saved_model = load_model('myModel.h5')
# FEATURES = getListWithFeatures()
FEATURES = load('FEATURES.joblib')
offset1 = df1.index[0]
df1_temp = df1[-sequence_length:]
new_df1 = df1_temp.filter(FEATURES)
# Get the last N day closing price values and scale the data to be values between 0 and 1
last_N_days = new_df1[-sequence_length:].values
last_N_days_scaled = scaler.transform(last_N_days)
# Create an empty list and Append past N days
X_test_new = []
X_test_new.append(last_N_days_scaled)
# Convert the X_test data set to a numpy array and reshape the data
pred_price_scaled = saved_model.predict(np.array(X_test_new))
pred_price_unscaled = scaler_pred.inverse_transform(pred_price_scaled.reshape(-1, 1))
# Print last price and predicted price for the next day
predicted_price = pred_price_unscaled.ravel()[0]
sz = df1['Forecast'].size + offset1
df1.loc[sz-1,'Forecast'] = predicted_price
df['Forecast'].loc[mask] = df1['Forecast']
def getPredictionFromPython():
return df['Predict'].to_numpy()
def getForecastFromPython():
return df['Forecast'].to_numpy()
here is how it looks like for the "synthetic data". So in the code I posted I use 4 "features", close, EMA20 and Bollinger_Upper + Lower, see Python code. The orange line is the predicted price. The violet dot is the forcast.