2021-11-16 10:00:26 +01:00
#%%
import pytorch_lightning as pl
from pytorch_lightning.callbacks import EarlyStopping , LearningRateMonitor
from pytorch_forecasting import TimeSeriesDataSet , TemporalFusionTransformer
from pytorch_forecasting.data import GroupNormalizer
from pytorch_forecasting.metrics import QuantileLoss
import sys
sys . path . insert ( 0 , '..' )
2022-01-26 23:22:43 +01:00
from data_loader import load_files
2021-11-16 10:00:26 +01:00
print ( "success" )
#%%
# load data
2021-11-16 10:20:35 +01:00
data = load_files ( '../data/' , add_features = True , log_returns = False , narrow_format = True )
2021-11-16 10:00:26 +01:00
# need to treat time as an independent column
data = data . reset_index () . rename ({ 'index' : 'time' }, axis = 'columns' )
# we need a `time_idx` column for pytorch-forecasting, so we convert the time column to a time index by encoding the dates as consecutive days from the first date.
data [ 'time_idx' ] = ( data [ 'time' ] - data [ 'time' ] . min ()) . astype ( 'timedelta64[D]' ) . astype ( int ) + 1
# volume needs some love before we can use it
data . drop ( columns = [ 'volume' ], inplace = True )
data [ 'month' ] = data [ 'month' ] . astype ( str )
data [ 'day_month' ] = data [ 'day_month' ] . astype ( str )
data [ 'day_week' ] = data [ 'day_week' ] . astype ( str )
#%%
# define dataset
max_encoder_length = 36 # this is the look-back window, see https://github.com/jdb78/pytorch-forecasting/issues/448
max_prediction_length = 6
# training_cutoff = "YYYY-MM-DD" # day for cutoff
# training_cutoff = data["time_idx"].max() - max_prediction_length
2021-11-16 10:20:35 +01:00
#%%
data . head ()
data . describe ()
#%%
2021-11-16 10:00:26 +01:00
training = TimeSeriesDataSet (
data , # data[lambda x: x.date < training_cutoff],
time_idx = 'time_idx' ,
target = 'returns' ,
# weight="weight",
group_ids = [ 'ticker' ],
min_encoder_length = max_encoder_length , ##max_encoder_length//2,
max_encoder_length = max_encoder_length ,
min_prediction_length = 1 ,
max_prediction_length = 1 , #max_prediction_length,
static_categoricals = [ ],
static_reals = [ ],
time_varying_known_categoricals = [ 'day_month' , 'day_week' , 'month' ],
time_varying_known_reals = [ 'vol_10' , 'vol_20' , 'vol_30' , 'vol_60' , 'mom_10' , 'mom_20' , 'mom_30' , 'mom_60' , 'mom_90' ],
time_varying_unknown_categoricals = [ ],
time_varying_unknown_reals = [ 'returns' ],
allow_missing_timesteps = True ,
2021-11-16 10:20:35 +01:00
target_normalizer = GroupNormalizer (
groups = [ 'ticker' ], transformation = "softplus" )
2021-11-16 10:00:26 +01:00
)
#%%
print ( training . index . time )
print ( training . index . time . max ())
#%%
# create validation and training dataset
validation = TimeSeriesDataSet . from_dataset ( training , data , predict = True , stop_randomization = True )
batch_size = 128
2021-11-16 10:20:35 +01:00
train_dataloader = training . to_dataloader ( train = True , batch_size = batch_size , num_workers = 0 )
val_dataloader = validation . to_dataloader ( train = False , batch_size = batch_size , num_workers = 0 )
2021-11-16 10:00:26 +01:00
# define trainer with early stopping
early_stop_callback = EarlyStopping ( monitor = "val_loss" , min_delta = 1e-4 , patience = 1 , verbose = False , mode = "min" )
lr_logger = LearningRateMonitor ()
trainer = pl . Trainer (
max_epochs = 100 ,
gpus = 0 ,
gradient_clip_val = 0.1 ,
limit_train_batches = 30 ,
callbacks = [ lr_logger , early_stop_callback ],
)
# create the model
tft = TemporalFusionTransformer . from_dataset (
training ,
learning_rate = 0.03 ,
hidden_size = 32 ,
attention_head_size = 1 ,
dropout = 0.1 ,
hidden_continuous_size = 16 ,
output_size = 7 ,
loss = QuantileLoss (),
log_interval = 2 ,
reduce_on_plateau_patience = 4
)
print ( f "Number of parameters in network: { tft . size () / 1e3 : .1f } k" )
# find optimal learning rate (set limit_train_batches to 1.0 and log_interval = -1)
res = trainer . tuner . lr_find (
tft , train_dataloader = train_dataloader , val_dataloaders = val_dataloader , early_stop_threshold = 1000.0 , max_lr = 0.3 ,
)
print ( f "suggested learning rate: { res . suggestion () } " )
fig = res . plot ( show = True , suggest = True )
fig . show ()
# fit the model
trainer . fit (
tft , train_dataloader = train_dataloader , val_dataloaders = val_dataloader ,
)
# %%