├── Images ├── AAPL.png ├── AAPL_sr.png ├── AAPL_locals.png ├── AAPL_smooth.png ├── AAPL_smooth_sr.png └── AAPL_normal_smooth.png ├── requirements.txt ├── support_resistance.py └── README.md /Images/AAPL.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sohandillikar/SupportResistance/HEAD/Images/AAPL.png -------------------------------------------------------------------------------- /Images/AAPL_sr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sohandillikar/SupportResistance/HEAD/Images/AAPL_sr.png -------------------------------------------------------------------------------- /Images/AAPL_locals.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sohandillikar/SupportResistance/HEAD/Images/AAPL_locals.png -------------------------------------------------------------------------------- /Images/AAPL_smooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sohandillikar/SupportResistance/HEAD/Images/AAPL_smooth.png -------------------------------------------------------------------------------- /Images/AAPL_smooth_sr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sohandillikar/SupportResistance/HEAD/Images/AAPL_smooth_sr.png -------------------------------------------------------------------------------- /Images/AAPL_normal_smooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sohandillikar/SupportResistance/HEAD/Images/AAPL_normal_smooth.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | scipy==1.5.4 2 | numpy==1.19.4 3 | pandas==1.1.4 4 | matplotlib==3.3.3 5 | scikit-learn==0.23.2 6 | pandas-datareader==0.9.0 7 | -------------------------------------------------------------------------------- /support_resistance.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from math import sqrt 4 | import matplotlib.pyplot as plt 5 | import pandas_datareader as web 6 | from scipy.signal import savgol_filter 7 | from sklearn.linear_model import LinearRegression 8 | 9 | def pythag(pt1, pt2): 10 | a_sq = (pt2[0] - pt1[0]) ** 2 11 | b_sq = (pt2[1] - pt1[1]) ** 2 12 | return sqrt(a_sq + b_sq) 13 | 14 | def regression_ceof(pts): 15 | X = np.array([pt[0] for pt in pts]).reshape(-1, 1) 16 | y = np.array([pt[1] for pt in pts]) 17 | model = LinearRegression() 18 | model.fit(X, y) 19 | return model.coef_[0], model.intercept_ 20 | 21 | def local_min_max(pts): 22 | local_min = [] 23 | local_max = [] 24 | prev_pts = [(0, pts[0]), (1, pts[1])] 25 | for i in range(1, len(pts) - 1): 26 | append_to = '' 27 | if pts[i-1] > pts[i] < pts[i+1]: 28 | append_to = 'min' 29 | elif pts[i-1] < pts[i] > pts[i+1]: 30 | append_to = 'max' 31 | if append_to: 32 | if local_min or local_max: 33 | prev_distance = pythag(prev_pts[0], prev_pts[1]) * 0.5 34 | curr_distance = pythag(prev_pts[1], (i, pts[i])) 35 | if curr_distance >= prev_distance: 36 | prev_pts[0] = prev_pts[1] 37 | prev_pts[1] = (i, pts[i]) 38 | if append_to == 'min': 39 | local_min.append((i, pts[i])) 40 | else: 41 | local_max.append((i, pts[i])) 42 | else: 43 | prev_pts[0] = prev_pts[1] 44 | prev_pts[1] = (i, pts[i]) 45 | if append_to == 'min': 46 | local_min.append((i, pts[i])) 47 | else: 48 | local_max.append((i, pts[i])) 49 | return local_min, local_max 50 | 51 | symbol = 'AAPL' 52 | df = web.DataReader(symbol, 'yahoo', '2019-01-01', '2019-04-01') 53 | series = df['Close'] 54 | series.index = np.arange(series.shape[0]) 55 | 56 | month_diff = series.shape[0] // 30 57 | if month_diff == 0: 58 | month_diff = 1 59 | 60 | smooth = int(2 * month_diff + 3) 61 | 62 | pts = savgol_filter(series, smooth, 3) 63 | 64 | local_min, local_max = local_min_max(pts) 65 | 66 | local_min_slope, local_min_int = regression_ceof(local_min) 67 | local_max_slope, local_max_int = regression_ceof(local_max) 68 | support = (local_min_slope * np.array(series.index)) + local_min_int 69 | resistance = (local_max_slope * np.array(series.index)) + local_max_int 70 | 71 | plt.title(symbol) 72 | plt.xlabel('Days') 73 | plt.ylabel('Prices') 74 | plt.plot(series, label=symbol) 75 | plt.plot(support, label='Support', c='r') 76 | plt.plot(resistance, label='Resistance', c='g') 77 | plt.legend() 78 | plt.show() 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SupportResistance 2 | A python script that estimates the support and resistance lines of a stock's prices or a period 3 | ## Prerequisites 4 | 1. Have `Python3` and `pip` installed on PC. (Install from https://python.org) 5 | 2. Have `git` installed. (Install from https://git-scm.com/downloads) 6 | 7 | ## Setup 8 | 1. `git clone` the repository 9 | ```sh 10 | git clone https://github.com/lil-zohee/SupportResistance.git 11 | ``` 12 | 2. Move in the new directory 13 | ```sh 14 | cd SupportResistance/ 15 | ``` 16 | 3. Install all necessary modules 17 | ```sh 18 | pip3 install -r requirements.txt 19 | ``` 20 | 4. Now you can run the program 21 | ```sh 22 | python3 support_resistance.py 23 | ``` 24 | In the python script, I tried to predict the support and resistance for AAPL stock from the dates of January 1, 2019 to April 1, 2019. However, you can change that in lines 51 and 52 of the program. 25 | ```python 26 | symbol = 'AAPL' 27 | df = web.DataReader(symbol, 'yahoo', '2019-01-01', '2019-04-01') 28 | ``` 29 | 30 | ## How it works 31 | The closing prices of the Bank Of America stock from January 1, 2019 to April 1, 2019 look like this. 32 |

33 | AAPL 2019-01-01 to 2019-04-01 34 |

35 | 36 | ### Step 1: Smoothen the graph 37 | We can use the `savgol_filter` function from the `scipy.signal` module, to make the graph smoother. I have created a simple algorithm to determine how much we should smoothen a graph. All the closing prices of a stock are stored in a `pd.Series` object. To determine the level of smoothness we want in our graph, we have to find the difference in months of the 2 dates. Then we multiply it with 2 and add it with 3. 38 | ```python 39 | month_diff = series.shape[0] // 30 40 | if month_diff == 0: # If we have 0 months worth of prices, edit the variable to = 1 41 | month_diff = 1 42 | smooth = int(2 * month_diff + 3) # Level of smoothness in our graph 43 | ``` 44 | Now lets smoothen our graph 45 | ```python 46 | pts = savgol_filter(series, smooth, 3) # 3 is the order of the polynomials 47 | ``` 48 | Here's the result of plotting `pts`. 49 |

50 | AAPL smooth 51 |

52 | Here's what the two graphs look like in comparison. 53 |

54 | AAPL normal smooth 55 |

56 | 57 | ### Step 2: Finding the local maximum and minimum points 58 | To find the local maximum and local minimum, I have created a function, which takes up lines 21 - 49 in the `support_resistance.py`. Essentially, this function loops through the given `pts` from indexes `1` to `-1`. If the point is less than the point behind it and less than the point ahead of it, then it is a local minimum. Similarly, if the point in greater than the point behind it and greater than the point ahead of it, it is a local maximum. However, if we simply do this, then the algorithm will detect many local minimums and maximums. Therefore, I have used the Pythagorean theorem to determine the distance between the previous point and current point, as well as the distance between the current point and next point. I made sure to only consider a point as a local maximum or minimum if the distance between it and the next point was greater than half of the distance between it and the previous point. Here is the result of plotting the local maximum and minimum points. 59 |

60 | AAPL locals 61 |

62 | 63 | ### Step 3: Line of best fit between local minimum and maximum 64 | To find the line of best fit between the local minimum and maximum points, I used the `sklean.linear_model.LinearRegression` model. I have created a function on lines 14 - 19 in the `support_resistance.py`. 65 | ```python 66 | def regression_ceof(pts): 67 | """ 68 | Uses LinearRegression model to determine 69 | the best fit slope and y-intercept of 70 | the given points. 71 | """ 72 | return slope, y_int 73 | 74 | local_min_slope, local_min_int = regression_ceof(local_min) 75 | local_max_slope, local_max_int = regression_ceof(local_max) 76 | ``` 77 | 78 | ### Step 4: Creating support and resistance lines 79 | Now that we have the slope and y-intercept of the local minimum and maximum, we can easily draw the support and resistance lines using the linear equation `y = mx + b`. `m` is the slope and `b` is the y-intercept. 80 | ```python 81 | support = (local_min_slope * np.array(series.index)) + local_min_int 82 | resistance = (local_max_slope * np.array(series.index)) + local_max_int 83 | ``` 84 | After plotting the support and resistance lines, we get this. 85 |

86 | AAPL smooth sr 87 |

88 | This is what it looks like on the normal graph. 89 |

90 | AAPL sr 91 |

92 | --------------------------------------------------------------------------------