├── Contributing.md ├── README.md ├── Trading_Using_CNN.ipynb ├── WMT.csv └── finalrsiupdated.ipynb /Contributing.md: -------------------------------------------------------------------------------- 1 | There is a folder with the raw dataset in it. Firstly you will have to label the data set as per the algorithm given in the paper. 2 | 3 | After that you will need to define the technical indicators as columns for the ticker. 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Algorthmic-Trading-Using-CNN 2 | This project is essentially the implementation of the paper “Algorithmic Financial Trading with Deep Convolutional Neural Networks: Time Series to Image Conversion Approach” . 3 | Here is the link to the paper: https://www.researchgate.net/publication/324802031_Algorithmic_Financial_Trading_with_Deep_Convolutional_Neural_Networks_Time_Series_to_Image_Conversion_Approach 4 | 5 | The idea is to make a trading system which buys, sells or holds the stock based on a list of technical indicators. These technical indicators shall be fed to a CNN in the form of images to generate labels. 6 | 7 | Pre Requisites include basic Python knowledge and a grasp of how financial markets work. Besides this, you should be keen to implement simple Deep Learning algorithms using Tensorflow. 8 | -------------------------------------------------------------------------------- /Trading_Using_CNN.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 5, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pandas as pd\n", 10 | "import numpy as np\n", 11 | "from pandas import DataFrame # specify datatype while passing df object" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 6, 17 | "metadata": {}, 18 | "outputs": [], 19 | "source": [ 20 | " #df = pd.read_csv('WMT.csv')\n", 21 | " #Uncomment this and read the WMT csv file wherever its stored on your local device" 22 | ] 23 | }, 24 | { 25 | "cell_type": "code", 26 | "execution_count": 8, 27 | "metadata": {}, 28 | "outputs": [ 29 | { 30 | "ename": "IndentationError", 31 | "evalue": "unindent does not match any outer indentation level (, line 92)", 32 | "output_type": "error", 33 | "traceback": [ 34 | "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m92\u001b[0m\n\u001b[1;33m return df\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mIndentationError\u001b[0m\u001b[1;31m:\u001b[0m unindent does not match any outer indentation level\n" 35 | ] 36 | } 37 | ], 38 | "source": [ 39 | "#This is where you will code up the technical indicators and add as columns in the original dataframe\n", 40 | "\n", 41 | "def rsi(df):\n", 42 | " Difference = pd.Series(df['Close'].diff())\n", 43 | " Gain = pd.Series(np.where(Difference>0,Difference,0))\n", 44 | " Loss = pd.Series(np.where(Difference<0,-Difference,0))\n", 45 | " for period in range(6,26):\n", 46 | " AvgGain = pd.Series(Gain.rolling(window=period).mean())\n", 47 | " AvgLoss = pd.Series(Loss.rolling(window=period).mean())\n", 48 | " RS=pd.Series(AvgGain/AvgLoss)\n", 49 | " df[f'RSI_{period}']=pd.Series(100-100/(1+RS))\n", 50 | " return df\n", 51 | " \n", 52 | "def cmo(df):\n", 53 | " Difference = pd.Series(df[\"Close\"] - df[\"Close\"].shift(1))\n", 54 | " Sum=pd.Series(Difference.abs())\n", 55 | " for period in range(6, 21): \n", 56 | " diff = Difference.rolling(window=period).sum() \n", 57 | " sum = Sum.rolling(window=period).sum()\n", 58 | " df[f'cmo_{period}'] = (diff/sum) * 100 \n", 59 | " return df\n", 60 | " \n", 61 | "def williams(df):\n", 62 | " for period in range(6,21):\n", 63 | " lowest_low=pd.Series(df[\"Low\"].rolling(window = period).min())\n", 64 | " highest_high=pd.Series(df[\"High\"].rolling(window = period).max()) \n", 65 | " df[f'Williams_{period}']=pd.Series(((highest_high-df['Close'])/(highest_high-lowest_low))*-100)\n", 66 | " return df\n", 67 | " \n", 68 | "def sma(df: DataFrame):\n", 69 | " '''\n", 70 | " SMA: Simple Moving Average; computes the average of a selected\n", 71 | " range of prices, over periods 6 through 30(both inclusive).\n", 72 | " \n", 73 | " Arguement: \n", 74 | " df: DataFrame object initialised from the csv data\n", 75 | " Returns:\n", 76 | " df: Modified DataFrame object\n", 77 | " '''\n", 78 | " \n", 79 | " for period in range(6, 31):\n", 80 | " col_name = f'sma_{period}'\n", 81 | " df[col_name] = df[\"Adj Close\"].rolling(window=period).mean()\n", 82 | " \n", 83 | " return df \n", 84 | " \n", 85 | "def wma(df: DataFrame):\n", 86 | " '''\n", 87 | " WMA: Weighted Moving Average; places a greater weight on the more recent\n", 88 | " datapoints. Calculated over periods 6 through 20(both inclusive).\n", 89 | " \n", 90 | " Arguement: \n", 91 | " df: DataFrame object initialised from the csv data\n", 92 | " Returns:\n", 93 | " df: Modified DataFrame object\n", 94 | " '''\n", 95 | " for period in range(6, 21):\n", 96 | " col_name = f'wma_{period}'\n", 97 | " weights = np.arange(1, period+1)\n", 98 | " denominator = np.sum(weights)\n", 99 | "\n", 100 | " df[col_name] = df[\"Adj Close\"].rolling(window=period).apply(\n", 101 | " lambda x: np.sum(weights*x)/denominator)\n", 102 | " \n", 103 | " return df\n", 104 | " \n", 105 | "def ppo(df):\n", 106 | " for period in range(6, 21):\n", 107 | " ema_lower = df[\"Adj Close\"].ewm(span = period).mean()\n", 108 | " ema_higher = df[\"Adj Close\"].ewm(span = period + 14).mean()\n", 109 | " df[f'ppo_{period}'] = (ema_lower - ema_higher)*100/ema_higher\n", 110 | " df[f'ppo_signal_{period}'] = df[f'ppo_{period}'].ewm(span=period - 3).mean()\n", 111 | " \n", 112 | " return df\n", 113 | " \n", 114 | "def ema(df: DataFrame):\n", 115 | " '''\n", 116 | " EMA: Exponential Moving Average; similar to WMA, it places a greater weight on the recent\n", 117 | " datapoints and hence reacts more significantly to price changes than SMA.\n", 118 | " Calculated over periods 6 through 20(both inclusive).\n", 119 | " \n", 120 | " Arguement: \n", 121 | " df: DataFrame object initialised from the csv data\n", 122 | " Returns:\n", 123 | " df: Modified DataFrame object\n", 124 | " '''\n", 125 | " for period in range(6, 21):\n", 126 | " col_name = f'ema_{period}'\n", 127 | " df[col_name] = df[\"Adj Close\"].ewm(span=period, adjust=True).mean()\n", 128 | "\n", 129 | " return df\n", 130 | " \n", 131 | "def roc(df):\n", 132 | " for n in range(6,21):\n", 133 | " col_name=f'roc_{n}'\n", 134 | " D = df['Adj Close'].diff(n)\n", 135 | " N= df['Adj Close'].shift(n)\n", 136 | " df[col_name] = (D/N)*100\n", 137 | " return df\n", 138 | " \n", 139 | "def cmfi(df):\n", 140 | " MFM = ((df['Close']-df['Low']) - (df['High']-df['Close']))/(df['High']-df['Low']) #Calculating Multiplier\n", 141 | " MFV = MFM * df['Volume'] \n", 142 | " for period in range(6,21):\n", 143 | " df[f'cmfi_{period}'] = (MFV.rolling(window = period).sum())/(df['Volume'].rolling(window = period).sum())\n", 144 | " return df\n", 145 | "\n", 146 | "def hma(df):\n", 147 | " for len in range(6,21):\n", 148 | " col_name = f'hma_{len}'\n", 149 | " half_len = len//2\n", 150 | " k = int(np.sqrt(len))\n", 151 | " half_weights = np.arange(1, half_len+1)\n", 152 | " weights = np.arange(1, len+1)\n", 153 | " half_wma = df['Adj Close'].rolling(half_len).apply(lambda x: np.dot(x, half_weights)/half_weights.sum(), raw=True)\n", 154 | " full_wma = df['Adj Close'].rolling(len).apply(lambda x: np.dot(x, weights)/weights.sum(), raw=True)\n", 155 | " diff = (2*half_wma) - full_wma\n", 156 | " w = np.arange(1, k+1)\n", 157 | " df[col_name] = diff.rolling(k).apply(lambda x: np.dot(x, w)/w.sum(), raw=True)\n", 158 | " return df\n", 159 | " \n", 160 | "def tripleema(df):\n", 161 | " for period in range(6,21):\n", 162 | " ema1 = df['Adj Close'].ewm(span=period).mean()\n", 163 | " ema2 = ema1.ewm(span=period).mean()\n", 164 | " ema3 = ema2.ewm(span=period).mean()\n", 165 | " df[f'tripleema_{period}'] = ((3*ema1) - (3*ema2) + ema3)\n", 166 | " return df\n", 167 | " \n", 168 | "def psi(df): #Psychology Line Index Indicator\n", 169 | " movement = pd.Series(np.where(df['Close']-df['Close'].shift(1) > 0 ,'UP',None))\n", 170 | " for period in range(6,21):\n", 171 | " df[f'psi_{period}']=((movement.rolling(window=period).count())/period)*100\n", 172 | " return df\n", 173 | " \n", 174 | "def cci(df): \n", 175 | " TP = (df['High'] + df['Low'] + df['Close']) / 3 \n", 176 | " for period in range(6,21):\n", 177 | " df[f'cci_{period}']= pd.Series((TP - TP.rolling(window = period).mean()) / (0.015 * TP.rolling(window = period).std()))\n", 178 | " return df\n", 179 | "\n", 180 | " \n" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": null, 186 | "metadata": {}, 187 | "outputs": [], 188 | "source": [ 189 | "def label_data(df):\n", 190 | " \"\"\"\n", 191 | " Research Paper Algorithm's of Labelling Method is simply telling us to take Window Size of 11 period and check,\n", 192 | " whether the middle number is maximum in the window, then Label it as \"Sell\", or\n", 193 | " if the middle number is minimum in the window, then Label it as \"Buy\",\n", 194 | " else Label it as \"Hold\", and then Slide the Window by 1 Period\n", 195 | " \"\"\"\n", 196 | " \"\"\"\n", 197 | " Parameter : df ==> Dataframe with OHLCV data.\n", 198 | " Returns : df ==> Dataframe with 1 added column of \"Label\".\n", 199 | " \"\"\"\n", 200 | " df['Label'] = ''\n", 201 | " WindowSize = 11\n", 202 | " counter_row = 0\n", 203 | "\n", 204 | " while counter_row < len(df):\n", 205 | " if counter_row >= WindowSize:\n", 206 | " \n", 207 | " #Creating the Window\n", 208 | " WindowBeginIndex = counter_row - WindowSize \n", 209 | " WindowEndIndex = WindowBeginIndex + WindowSize - 1\n", 210 | " WindowMidIndex = (WindowBeginIndex + WindowEndIndex)/2\n", 211 | " min = np.inf\n", 212 | " max = 0\n", 213 | " min_index = -1\n", 214 | " max_index = -1\n", 215 | " \n", 216 | " #Finding Maximum and minimum in the Window \n", 217 | " for i in range (WindowBeginIndex, WindowEndIndex +1): \n", 218 | " number = df['Close'][i]\n", 219 | " if number < min:\n", 220 | " min = number\n", 221 | " min_index = i\n", 222 | " if number > max:\n", 223 | " max = number\n", 224 | " max_index = i\n", 225 | " \n", 226 | " #Checking if the Middle number of Window is Max or Min and classifying them as \"SELL\",\"BUY\",\"HOLD\"\n", 227 | " if max_index == WindowMidIndex: \n", 228 | " df['Label'][WindowMidIndex] = 0 #SELL\n", 229 | " elif min_index == WindowMidIndex:\n", 230 | " df['Label'][WindowMidIndex] = 1 #BUY\n", 231 | " else :\n", 232 | " df['Label'][WindowMidIndex] = 2 #HOLD\n", 233 | " counter_row = counter_row + 1\n", 234 | " return df" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "metadata": {}, 241 | "outputs": [], 242 | "source": [ 243 | "#Important - Before running normalizing function make sure to first run the label_algorithm and then the indicator functions, to avoid errors.\n", 244 | "#And also run the rsi, sma, ppo functions at the last to get the better results (because of the unequal periods).\n", 245 | "def normalizing(df):\n", 246 | " list_features = df.iloc[:, 8:233].columns\n", 247 | " min_max_scaler = preprocessing.MinMaxScaler()\n", 248 | " df[list_features] = min_max_scaler.fit_transform(df[list_features])\n", 249 | " return df" 250 | ] 251 | } 252 | ], 253 | "metadata": { 254 | "kernelspec": { 255 | "display_name": "PyCharm (Algorthmic-Trading-Using-CNN)", 256 | "language": "python", 257 | "name": "pycharm-f070fd36" 258 | }, 259 | "language_info": { 260 | "codemirror_mode": { 261 | "name": "ipython", 262 | "version": 3 263 | }, 264 | "file_extension": ".py", 265 | "mimetype": "text/x-python", 266 | "name": "python", 267 | "nbconvert_exporter": "python", 268 | "pygments_lexer": "ipython3", 269 | "version": "3.7.6" 270 | } 271 | }, 272 | "nbformat": 4, 273 | "nbformat_minor": 4 274 | } -------------------------------------------------------------------------------- /finalrsiupdated.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 26, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import pandas as pd\n", 10 | "import talib\n", 11 | "\n", 12 | "import numpy as np" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 27, 18 | "metadata": {}, 19 | "outputs": [], 20 | "source": [ 21 | " df = pd.read_csv('WMT.csv')\n", 22 | " #Uncomment this and read the WMT csv file wherever its stored on your local device" 23 | ] 24 | }, 25 | { 26 | "cell_type": "code", 27 | "execution_count": 28, 28 | "metadata": {}, 29 | "outputs": [], 30 | "source": [ 31 | "#This is where you will code up the technical indicators and add as columns in the original dataframe\n", 32 | "\n", 33 | "def rsi(dataset):\n", 34 | " for i in range(6,26):\n", 35 | " RSI = talib.RSI(dataset.Close, timeperiod=i)\n", 36 | " srs = pd.Series(data=RSI)\n", 37 | " srs = srs.rename('RSI' + str(i))\n", 38 | " dataset=pd.concat([dataset,srs],axis=1)\n", 39 | " return dataset\n", 40 | " #code rsi 6 to 25\n", 41 | " \n", 42 | "def cmo():\n", 43 | " \n", 44 | "def williams():\n", 45 | " \n", 46 | "def sma(): #code sma 6 to 30 \n", 47 | " \n", 48 | "def wma():\n", 49 | " \n", 50 | "def ppo():\n", 51 | " \n", 52 | "def ema():\n", 53 | " \n", 54 | "def roc():\n", 55 | " \n", 56 | "def cmfi():\n", 57 | "\n", 58 | "def hma():\n", 59 | " \n", 60 | "def dmi():\n", 61 | " \n", 62 | "def tripleema():\n", 63 | " \n", 64 | "def psi():\n", 65 | " \n", 66 | "def cci():\n", 67 | " \n" 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": null, 73 | "metadata": {}, 74 | "outputs": [], 75 | "source": [ 76 | "def label_data():" 77 | ] 78 | } 79 | ], 80 | "metadata": { 81 | "kernelspec": { 82 | "display_name": "Python 3", 83 | "language": "python", 84 | "name": "python3" 85 | }, 86 | "language_info": { 87 | "codemirror_mode": { 88 | "name": "ipython", 89 | "version": 3 90 | }, 91 | "file_extension": ".py", 92 | "mimetype": "text/x-python", 93 | "name": "python", 94 | "nbconvert_exporter": "python", 95 | "pygments_lexer": "ipython3", 96 | "version": "3.7.6" 97 | } 98 | }, 99 | "nbformat": 4, 100 | "nbformat_minor": 4 101 | } 102 | --------------------------------------------------------------------------------