Supervised learning example

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.

exampl

16 Likes

@empottasch ... is there some way to message u directly? i thought i saw this once but can't find it again

hi @yellowslug , yes just using personal message on this forum. You mean the other example I gave?

that 1 can be found here:

The source code I use is given in the code.

I have not yet finished examples on Reinforcement learning. Did not start with this yet but from what I read there are professional traders who use this. The examples I gave use "supervised learning". Here we try to forecast the exact price. From what I understand when using "reinforcement learning" you teach the model to trade successfully rather than make an exact forecast of the price.

@yellowslug - your forum trust level is too low to have private messaging enabled. Private messages are enabled only for level-3 because private messaging was abused in the past to harass people. This is public forum, not private email system. If you have a question post on the forum.

I’d recommend to read some papers/blogs from EP Chan and Marcos Lopez de Prado about ML and trading.

1 Like