{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nsns.set_theme(style=\"whitegrid\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-11-07T04:41:08.759908Z","iopub.execute_input":"2021-11-07T04:41:08.760909Z","iopub.status.idle":"2021-11-07T04:41:09.712442Z","shell.execute_reply.started":"2021-11-07T04:41:08.760777Z","shell.execute_reply":"2021-11-07T04:41:09.711733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df=pd.read_csv('../input/g-research-crypto-forecasting/train.csv')\ndf.replace([np.inf, -np.inf], np.nan, inplace=True)","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:41:09.714067Z","iopub.execute_input":"2021-11-07T04:41:09.714288Z","iopub.status.idle":"2021-11-07T04:42:03.943433Z","shell.execute_reply.started":"2021-11-07T04:41:09.714258Z","shell.execute_reply":"2021-11-07T04:42:03.942650Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset=pd.read_csv('../input/g-research-crypto-forecasting/asset_details.csv')","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:03.944656Z","iopub.execute_input":"2021-11-07T04:42:03.944919Z","iopub.status.idle":"2021-11-07T04:42:03.957839Z","shell.execute_reply.started":"2021-11-07T04:42:03.944885Z","shell.execute_reply":"2021-11-07T04:42:03.957052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset_map=lambda x : asset[asset.Asset_ID==x].Asset_Name.tolist()[0]","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:03.959732Z","iopub.execute_input":"2021-11-07T04:42:03.960047Z","iopub.status.idle":"2021-11-07T04:42:03.964186Z","shell.execute_reply.started":"2021-11-07T04:42:03.959995Z","shell.execute_reply":"2021-11-07T04:42:03.963381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dfs={}\nfor i in np.unique(df.Asset_ID):\n    dfs[i]=df[df.Asset_ID==i].reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:03.965536Z","iopub.execute_input":"2021-11-07T04:42:03.965839Z","iopub.status.idle":"2021-11-07T04:42:08.633451Z","shell.execute_reply.started":"2021-11-07T04:42:03.965805Z","shell.execute_reply":"2021-11-07T04:42:08.632719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(12,8))\nfor i in range(0,2):\n    sns.lineplot(x='timestamp',y='Target',data=dfs[i][:500],\n                 label=asset_map(i))\n    \nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:08.634848Z","iopub.execute_input":"2021-11-07T04:42:08.635108Z","iopub.status.idle":"2021-11-07T04:42:09.011076Z","shell.execute_reply.started":"2021-11-07T04:42:08.635075Z","shell.execute_reply":"2021-11-07T04:42:09.010335Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Feature Enginearing","metadata":{}},{"cell_type":"markdown","source":"# Missing Data","metadata":{}},{"cell_type":"code","source":"df.isna().value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:09.012104Z","iopub.execute_input":"2021-11-07T04:42:09.012332Z","iopub.status.idle":"2021-11-07T04:42:13.631846Z","shell.execute_reply.started":"2021-11-07T04:42:09.012302Z","shell.execute_reply":"2021-11-07T04:42:13.631149Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#check Target nan\nmiss_idx={}\nmiss=[]\nsample_size=[]\nfor k,v in dfs.items():\n    #print(f'----asset---- : {asset_map(k)}')\n    #print(f'#missing : {v.Target.isna().sum()*100/v.shape[0]}%')\n    #print()\n    #print()\n    miss.append(v.Target.isna().sum()*100/v.shape[0])\n    miss_idx[k]=v[v.Target.isna()].index\n    sample_size.append(v[v.isna()==False].shape[0])\n    \nmiss=pd.DataFrame(miss,index=list(map(asset_map,dfs.keys()))).T\n\nsample_size=pd.DataFrame(sample_size,index=list(map(asset_map,dfs.keys()))).T","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:13.633136Z","iopub.execute_input":"2021-11-07T04:42:13.633541Z","iopub.status.idle":"2021-11-07T04:42:15.990558Z","shell.execute_reply.started":"2021-11-07T04:42:13.633503Z","shell.execute_reply":"2021-11-07T04:42:15.989819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(20,8))\nsns.barplot(data=miss)\nplt.xlabel('Cryptocurrency')\nplt.ylabel('% of missing')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:15.991873Z","iopub.execute_input":"2021-11-07T04:42:15.992135Z","iopub.status.idle":"2021-11-07T04:42:16.322471Z","shell.execute_reply.started":"2021-11-07T04:42:15.992101Z","shell.execute_reply":"2021-11-07T04:42:16.321811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* We can see that Degecoin, IOTA, Maker, Monero, Stellar have large amount of missing data , so I drop them ","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(20,8))\nsns.barplot(data=sample_size)\nplt.xlabel('Cryptocurrency')\nplt.ylabel('sample size')\nplt.title('sample size(not consider NaN)')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:16.324746Z","iopub.execute_input":"2021-11-07T04:42:16.325091Z","iopub.status.idle":"2021-11-07T04:42:16.657465Z","shell.execute_reply.started":"2021-11-07T04:42:16.325055Z","shell.execute_reply":"2021-11-07T04:42:16.656840Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Linear Search","metadata":{}},{"cell_type":"code","source":"def nan_linear_search(idx,inv=False):        \n    if inv:\n        i=-1\n        j=-2\n    else:\n        i=0\n        j=1\n    last=miss_idx[idx][i]\n    temp=miss_idx[idx][j]\n    target=last\n    if inv:\n        if (dfs[idx].tail(1).index!=target)[0]: #if NaN series not appear in the tail , then return \n            return\n    else:\n        if (dfs[idx].head(1).index!=target)[0]: #if NaN series not appear in the tail , then return \n            return\n        \n    while np.abs(last-temp)==1:\n        if inv:\n            i-=1\n            j-=1\n        else:\n            i+=1\n            j+=1\n        last=miss_idx[idx][i]\n        temp=miss_idx[idx][j]\n        \n    return list(range(last,target+1)) if inv else list(range(target,last+1))\n","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:16.658550Z","iopub.execute_input":"2021-11-07T04:42:16.659231Z","iopub.status.idle":"2021-11-07T04:42:16.667468Z","shell.execute_reply.started":"2021-11-07T04:42:16.659194Z","shell.execute_reply":"2021-11-07T04:42:16.666855Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Drop=['Degecoin', 'IOTA', 'Maker', 'Monero','Stellar']","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:16.668830Z","iopub.execute_input":"2021-11-07T04:42:16.669086Z","iopub.status.idle":"2021-11-07T04:42:16.680398Z","shell.execute_reply.started":"2021-11-07T04:42:16.669050Z","shell.execute_reply":"2021-11-07T04:42:16.679703Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for k,v in dfs.items():\n    if asset_map(k) in Drop:\n        dfs[k]=dfs[k].dropna()\n    else:\n        for bool_ in [True,False]:\n            nan_idx=nan_linear_search(k,bool_)\n            try:\n                dfs[k]=dfs[k].drop(nan_idx)\n            except:\n                pass\n        dfs[k]['Target']=dfs[k]['Target'].interpolate(method='cubic',order=2)\n        dfs[k]['VWAP']=dfs[k]['VWAP'].interpolate(method='cubic',order=2)","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:36.797909Z","iopub.execute_input":"2021-11-07T04:42:36.798550Z","iopub.status.idle":"2021-11-07T04:42:37.331136Z","shell.execute_reply.started":"2021-11-07T04:42:36.798513Z","shell.execute_reply":"2021-11-07T04:42:37.330386Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for k,v in dfs.items():\n    print(f'asset id : {k}')\n    print(v.isna().value_counts())\n    dfs[k]=dfs[k].drop(['Asset_ID'],axis=1)","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:42.145948Z","iopub.execute_input":"2021-11-07T04:42:42.146652Z","iopub.status.idle":"2021-11-07T04:42:45.970489Z","shell.execute_reply.started":"2021-11-07T04:42:42.146614Z","shell.execute_reply":"2021-11-07T04:42:45.969719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Tutorial Features","metadata":{}},{"cell_type":"code","source":"\ndef upper_shadow(df):\n    return df['High'] - np.maximum(df['Close'], df['Open'])\n\n\n\ndef lower_shadow(df):\n    return np.minimum(df['Close'], df['Open']) - df['Low']\n\ndef get_features(df, row=False):\n    df_feat = df[['Count', 'Open', 'High', 'Low', 'Close', 'Volume', 'VWAP']].copy()\n    df_feat['Upper_Shadow'] = upper_shadow(df_feat)\n    df_feat['Lower_Shadow'] = lower_shadow(df_feat)\n    \n    \n    df_feat[\"Close/Open\"] = df_feat[\"Close\"] / df_feat[\"Open\"] \n    df_feat[\"Close-Open\"] = df_feat[\"Close\"] - df_feat[\"Open\"] \n    df_feat[\"High-Low\"] = df_feat[\"High\"] - df_feat[\"Low\"] \n    df_feat[\"High/Low\"] = df_feat[\"High\"] / df_feat[\"Low\"]\n    if row:\n        df_feat['Mean'] = df_feat[['Open', 'High', 'Low', 'Close']].mean()\n    else:\n        df_feat['Mean'] = df_feat[['Open', 'High', 'Low', 'Close']].mean(axis=1)\n    \n    df_feat['High/Mean'] = df_feat['High'] / df_feat['Mean']\n    df_feat['Low/Mean'] = df_feat['Low'] / df_feat['Mean']\n    df_feat['Volume/Count'] = df_feat['Volume'] / (df_feat['Count'] + 1)\n    \n    \n    #I observe that if adding time info to series , the model will hard to train\n    \n    df_feat=df_feat.drop(['Count','Volume'],axis=1)\n    \n    df_feat['Target']=df.Target\n    \n    df_feat['timestamp']=df['timestamp']\n    \n\n    return df_feat","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:57.221304Z","iopub.execute_input":"2021-11-07T04:42:57.221573Z","iopub.status.idle":"2021-11-07T04:42:57.232570Z","shell.execute_reply.started":"2021-11-07T04:42:57.221545Z","shell.execute_reply":"2021-11-07T04:42:57.231872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for k,v in dfs.items():\n    dfs[k]=get_features(dfs[k])","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:42:58.167189Z","iopub.execute_input":"2021-11-07T04:42:58.167573Z","iopub.status.idle":"2021-11-07T04:43:05.235864Z","shell.execute_reply.started":"2021-11-07T04:42:58.167541Z","shell.execute_reply":"2021-11-07T04:43:05.235027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# KD Values","metadata":{}},{"cell_type":"code","source":"K=0\ndef KValue(rsv):\n    global K\n    K = (2/3) * K + (1/3) * rsv\n    return K\n\nD=0\ndef DValue(k):\n    global D\n    D = (2/3) * D + (1/3) * k\n    return D\n\ndef kd_value(df):\n    \n    df['date']=pd.to_datetime(df.timestamp,unit='s')\n    df=df.set_index('date')\n                              \n    #highest price in recent 9 days\n    df['9DAYMAX']=df['High'].rolling('9D').max()\n                              \n    #lowest price in recent 9 days \n    df['9DAYMIN']=df['Low'].rolling('9D').min()\n                              \n                              \n    #RSV value\n    df['RSV'] = 100 *\\\n        (df['Close'] - df['9DAYMIN']) / (df['9DAYMAX'] - df['9DAYMIN']+1) #prevent 0 divided\n                              \n    df['K'] = df['RSV'].apply(KValue)\n                              \n    df['D'] = df['K'].apply(DValue)\n    \n    df=df.drop(['9DAYMAX','9DAYMIN','Open','High','Low','Close','RSV'],axis=1)\n    \n    return df","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:43:10.569455Z","iopub.execute_input":"2021-11-07T04:43:10.570226Z","iopub.status.idle":"2021-11-07T04:43:10.579802Z","shell.execute_reply.started":"2021-11-07T04:43:10.570178Z","shell.execute_reply":"2021-11-07T04:43:10.578980Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for k,v in dfs.items():\n    dfs[k]=kd_value(dfs[k])","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:43:11.177755Z","iopub.execute_input":"2021-11-07T04:43:11.178331Z","iopub.status.idle":"2021-11-07T04:43:43.911178Z","shell.execute_reply.started":"2021-11-07T04:43:11.178296Z","shell.execute_reply":"2021-11-07T04:43:43.910393Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for k,v in dfs.items():\n    fig,ax=plt.subplots(ncols=2,figsize=(25,8))\n    sns.lineplot(x=v[:1000].index,y='K',data=v[:1000],label='K',ax=ax[0])\n    sns.lineplot(x=v[:1000].index,y='D',data=v[:1000],label='D',ax=ax[0])\n    ax[0].set_ylabel('value')\n    \n    sns.lineplot(x=v[:1000].index,y='Target',data=v[:1000],label='Target',ax=ax[1])\n    ax[0].set_title(asset_map(k))\n    ax[1].set_title(asset_map(k))\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:43:43.912873Z","iopub.execute_input":"2021-11-07T04:43:43.913130Z","iopub.status.idle":"2021-11-07T04:43:55.655467Z","shell.execute_reply.started":"2021-11-07T04:43:43.913096Z","shell.execute_reply":"2021-11-07T04:43:55.654853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Spliting","metadata":{}},{"cell_type":"markdown","source":"* Train:0.7\n\n* Val : 0.2\n\n* Test : 0.1\n","metadata":{}},{"cell_type":"code","source":"train={}\nval={}\ntest={}\n\n\nstats={}\nfor k,v in dfs.items():\n    n=len(dfs[k])\n    \n    timestamp=dfs[k].timestamp\n    train_df=dfs[k][:int(n*0.7)].drop(['timestamp'],axis=1)\n    val_df=dfs[k][int(n*0.7):int(n*0.9)].drop(['timestamp'],axis=1)\n    test_df=dfs[k][int(n*0.9):].drop(['timestamp'],axis=1)\n    \n    \n    #to ensure data is unseen , we can't use vali or test statistics to do normalization\n    train_mean=train_df.mean()\n    train_std=train_df.std()\n    \n    stats[k]=(train_mean,train_std)\n    \n    #normalization\n    train_df=(train_df-train_mean)/(train_std)\n    val_df=(val_df-train_mean)/(train_std)\n    test_df=(test_df-train_mean)/(train_std)\n    \n    train[k]=train_df.set_index(timestamp[:int(n*0.7)])\n    val[k]=val_df.set_index(timestamp[int(n*0.7):int(n*0.9)])\n    test[k]=test_df.set_index(timestamp[int(n*0.9):])\n","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:44:04.441081Z","iopub.execute_input":"2021-11-07T04:44:04.441864Z","iopub.status.idle":"2021-11-07T04:44:09.564680Z","shell.execute_reply.started":"2021-11-07T04:44:04.441826Z","shell.execute_reply":"2021-11-07T04:44:09.563825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for k,v in train.items():\n    temp=v[:1000].melt(var_name='column',value_name='normalized')\n    plt.figure(figsize=(25,8))\n    plt.title(asset_map(k))\n    sns.violinplot(x='column',y='normalized',data=temp)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:44:39.238052Z","iopub.execute_input":"2021-11-07T04:44:39.238548Z","iopub.status.idle":"2021-11-07T04:44:47.135510Z","shell.execute_reply.started":"2021-11-07T04:44:39.238513Z","shell.execute_reply":"2021-11-07T04:44:47.134861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* In prediction step :\n\n    $$Target=Target*\\sigma+\\mu$$","metadata":{}},{"cell_type":"markdown","source":"# Modeling","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.losses import MeanSquaredError,MeanAbsoluteError\nfrom tensorflow.keras.optimizers import Adam","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:45:31.337975Z","iopub.execute_input":"2021-11-07T04:45:31.338738Z","iopub.status.idle":"2021-11-07T04:45:36.237701Z","shell.execute_reply.started":"2021-11-07T04:45:31.338690Z","shell.execute_reply":"2021-11-07T04:45:36.236986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class WindowGenerator:\n    def __init__(self,input_width,label_width,offset,\n                train_df,val_df,test_df,label_columns=None,batch_size=32,drop_label=True):\n        self.train_df=train_df\n        self.val_df=val_df\n        self.test_df=test_df\n        self.batch_size=batch_size\n        self.drop_label=drop_label\n    \n        \n        #if we want to predict Target、Volumns ,label columns=['Target','Volumns']\n        self.label_columns=label_columns \n        if label_columns!=None:\n            self.label_columns_indices={name:i for i,name in enumerate(label_columns)}\n        self.column_indices={name:i for i,name in enumerate(train_df.columns)}\n        \n        #label idx\n        self.label_idx=[train_df.columns.to_list().index(name) \n                            for i,name in enumerate(label_columns)]\n        \n        self.select_idx=list(set(range(train_df.shape[-1]))-set(self.label_idx))\n        \n        \n        #manage indexes\n        self.input_width=input_width\n        self.label_width=label_width\n        self.offset=offset\n        \n        self.total_window_size=input_width+offset\n        \n        #input\n        self.input_slice=slice(0,input_width)\n        self.input_indices=np.arange(self.total_window_size)[self.input_slice]\n        \n        #label\n        self.label_start=self.total_window_size-self.label_width\n        self.label_slice=slice(self.label_start,None)\n        self.label_indices=np.arange(self.total_window_size)[self.label_slice]\n    \n    def split_window(self,features):\n        inputs=features[:,self.input_slice,:]\n        labels=features[:,self.label_slice,:]\n        \n        if self.label_columns!=None:\n            labels = tf.stack(\n                [labels[:, :, self.column_indices[name]] for name in self.label_columns],axis=-1)\n        \n            \n        inputs.set_shape([None,self.input_width,None])\n        labels.set_shape([None,self.label_width,None])\n        \n        if self.drop_label:\n            inputs=tf.gather(inputs,self.select_idx,axis=-1)\n        \n        return inputs,labels\n    \n    def make_dataset(self,data):\n        data = np.array(data, dtype=np.float32)\n        \n        \n        #split :  each window --> [input width , offset]\n        ds = tf.keras.preprocessing.timeseries_dataset_from_array(\n            data=data,\n            targets=None,\n            sequence_length=self.total_window_size,\n            sequence_stride=15,\n            shuffle=True,\n            batch_size=self.batch_size)\n        ds = ds.map(self.split_window)\n        \n        return ds\n    \n    @property\n    def train(self):\n        return self.make_dataset(self.train_df)\n    \n    @property\n    def val(self):\n        return self.make_dataset(self.val_df)\n    @property\n    def test(self):\n        return self.make_dataset(self.test_df)\n\n        \n    #if print object , this function will be called\n    def __repr__(self): \n        return '\\n'.join([\n        f'Total window size: {self.total_window_size}',\n        f'Input indices: {self.input_indices}',\n        f'Label indices: {self.label_indices}',\n        f'Label column name(s): {self.label_columns}'])","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:45:36.240401Z","iopub.execute_input":"2021-11-07T04:45:36.241094Z","iopub.status.idle":"2021-11-07T04:45:36.258896Z","shell.execute_reply.started":"2021-11-07T04:45:36.241054Z","shell.execute_reply":"2021-11-07T04:45:36.257186Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Hyperparameters","metadata":{}},{"cell_type":"code","source":"input_width=256\nlabel_width=256\noffset=0\nbatch_size=256\n\n\n#model\nunits=512\nlr=1e-5\nepochs=2","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:47:23.056829Z","iopub.execute_input":"2021-11-07T04:47:23.057358Z","iopub.status.idle":"2021-11-07T04:47:23.061245Z","shell.execute_reply.started":"2021-11-07T04:47:23.057322Z","shell.execute_reply":"2021-11-07T04:47:23.060530Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Model","metadata":{}},{"cell_type":"code","source":"class Model(tf.keras.Model):\n    def __init__(self, units, num_features=1,dropout=0.3):\n        super().__init__()\n        \n        self.units = units\n        self.lstm_cell = layers.LSTMCell(units,dropout=dropout)\n        self.lstm_rnn = layers.RNN(self.lstm_cell, return_state=True,return_sequences=True)\n        self.dense = layers.Dense(num_features,activation=None)  #the return is between -1~1\n        \n    def call(self,x,training=False):\n        x,*state=self.lstm_rnn(x,training=training)\n        x=self.dense(x)\n        return x\n    \n    def one_step_forecast(self,x,state=None):\n        #input : (1,features)\n        if state==None:\n            state=[tf.zeros((1,self.units)),tf.zeros((1,self.units))]\n        x,state=self.lstm_cell(x,states=state,training=False)\n        x=self.dense(x)\n        return x,state","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:47:26.028864Z","iopub.execute_input":"2021-11-07T04:47:26.029516Z","iopub.status.idle":"2021-11-07T04:47:26.039146Z","shell.execute_reply.started":"2021-11-07T04:47:26.029478Z","shell.execute_reply":"2021-11-07T04:47:26.038160Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* Train","metadata":{}},{"cell_type":"code","source":"def compile_and_fit(model, window, EPOCHS,patience=2):\n    early_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_loss',\n                                                    patience=patience,\n                                                    mode='min')\n    model.compile(loss=tf.losses.MeanSquaredError(),\n                optimizer=tf.optimizers.Adam(learning_rate=lr),\n                metrics=[tf.metrics.MeanAbsoluteError()])\n    \n    history = model.fit(window.train, epochs=EPOCHS,\n                      validation_data=window.val,\n                      callbacks=[early_stopping])\n    return history","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:47:27.179759Z","iopub.execute_input":"2021-11-07T04:47:27.180589Z","iopub.status.idle":"2021-11-07T04:47:27.186944Z","shell.execute_reply.started":"2021-11-07T04:47:27.180545Z","shell.execute_reply":"2021-11-07T04:47:27.186202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def main():\n    models={}\n    for k,v in dfs.items():\n        print(f'Asset {k}')\n        w=WindowGenerator(input_width,\n                  label_width,\n                  offset,\n                  train[k],\n                  val[k],\n                  test[k],\n                  ['Target'],\n                  batch_size)\n        models[k]= Model(units)\n        \n        hist=compile_and_fit(models[k], w, epochs,patience=2)\n        tf.keras.models.save_model(models[k],f'model_{k}.pt')\n        \n    return models","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:47:28.008878Z","iopub.execute_input":"2021-11-07T04:47:28.009493Z","iopub.status.idle":"2021-11-07T04:47:28.015762Z","shell.execute_reply.started":"2021-11-07T04:47:28.009456Z","shell.execute_reply":"2021-11-07T04:47:28.014671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models=main()","metadata":{"execution":{"iopub.status.busy":"2021-11-07T04:47:29.298732Z","iopub.execute_input":"2021-11-07T04:47:29.300159Z","iopub.status.idle":"2021-11-07T06:10:18.148587Z","shell.execute_reply.started":"2021-11-07T04:47:29.300111Z","shell.execute_reply":"2021-11-07T06:10:18.147813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Show Forecasting","metadata":{}},{"cell_type":"code","source":"target_idx=-3","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def inv_norm(target):\n    return target*train_std[target_idx]+train_mean[target_idx]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for k,v in train.items():\n    w=WindowGenerator(1000,\n                  1000,\n                  0,\n                  train[k],\n                  val[k],\n                  test[k],\n                  ['Target'],\n                  batch_size=1)\n    plt.figure()\n    plt.title(asset_map(k))\n    for x,y in w.test.take(1):\n        y_pred=models[k](x)[0,:,0].numpy()\n        plt.plot(range(1000),inv_norm(y_pred),label='predict')\n        plt.plot(range(1000),inv_norm(y[0,:,0].numpy()),label='ground_truth')\n    plt.legend()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2021-11-07T06:17:21.998896Z","iopub.execute_input":"2021-11-07T06:17:21.999645Z","iopub.status.idle":"2021-11-07T06:17:46.658525Z","shell.execute_reply.started":"2021-11-07T06:17:21.999607Z","shell.execute_reply":"2021-11-07T06:17:46.657843Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submit","metadata":{}},{"cell_type":"code","source":"import gresearch_crypto\n\nenv = gresearch_crypto.make_env()   \niter_test = env.iter_test() ","metadata":{"execution":{"iopub.status.busy":"2021-11-07T06:11:44.198143Z","iopub.execute_input":"2021-11-07T06:11:44.198927Z","iopub.status.idle":"2021-11-07T06:11:44.227749Z","shell.execute_reply.started":"2021-11-07T06:11:44.198886Z","shell.execute_reply":"2021-11-07T06:11:44.226826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"states={}\nfor k,(test_df, sample_prediction_df) in enumerate(iter_test):\n    t=np.unique(test_df.timestamp)[0]\n    \n    for i,idx in enumerate(test_df['Asset_ID']):\n        try:\n            if t in np.unique(train[idx].index):\n                x=train[idx].loc[t]\n            \n            elif t in np.unique(val[idx].index):\n                x=val[idx].loc[t]\n            else:\n                x=test[idx].loc[t]\n            \n            \n            x=x.drop(['Target'])\n            x=tf.convert_to_tensor(x)\n            x=tf.expand_dims(x,axis=0)\n        \n            pred,state=models[idx].one_step_forecast(x,state=None if k==0 else states[idx])\n        \n            states[idx]=state\n        \n            pred=inv_norm(pred)\n            sample_prediction_df['Target'].iloc[i]=pred.numpy()[0][0]\n        except:\n            sample_prediction_df['Target'].iloc[i]=0\n    env.predict(sample_prediction_df)","metadata":{"execution":{"iopub.status.busy":"2021-11-07T06:11:51.126674Z","iopub.execute_input":"2021-11-07T06:11:51.127166Z","iopub.status.idle":"2021-11-07T06:11:52.434636Z","shell.execute_reply.started":"2021-11-07T06:11:51.127127Z","shell.execute_reply":"2021-11-07T06:11:52.433867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}