|
| 1 | +''' |
| 2 | +Created on Dec 3, 2014 |
| 3 | +
|
| 4 | +@author: Aleksey Kramer |
| 5 | +''' |
| 6 | +import numpy as np |
| 7 | +import matplotlib |
| 8 | +import matplotlib.pyplot as plt |
| 9 | +import matplotlib.ticker as mticker |
| 10 | +import matplotlib.dates as mdates |
| 11 | +from matplotlib.finance import candlestick |
| 12 | +import pylab |
| 13 | + |
| 14 | +# adjusted font size for the plots |
| 15 | +matplotlib.rcParams.update({"font.size": 10}) |
| 16 | + |
| 17 | + |
| 18 | +# define RSI function |
| 19 | +def rsiFunc(prices, n=14): |
| 20 | + deltas = np.diff(prices) |
| 21 | + seed = deltas[:n+1] |
| 22 | + up = seed[seed >= 0].sum() / n |
| 23 | + down = -seed[seed<0].sum() / n |
| 24 | + rs = up/down |
| 25 | + rsi = np.zeros_like(prices) |
| 26 | + rsi[:n] = 100. - 100./(1. + rs) |
| 27 | + for i in range(n, len(prices)): |
| 28 | + delta = deltas[i-1] |
| 29 | + if delta > 0: |
| 30 | + upval = delta |
| 31 | + downval = 0. |
| 32 | + else: |
| 33 | + upval = 0. |
| 34 | + downval = -delta |
| 35 | + up = (up * (n-1) +upval) / n |
| 36 | + down = (down*(n-1) + downval) / n |
| 37 | + rs = up/down |
| 38 | + rsi[i] = 100. - 100. / (1. + rs) |
| 39 | + return rsi |
| 40 | + |
| 41 | +# define moving average function |
| 42 | +def movingaverage(values, window): |
| 43 | + weights = np.repeat(1.0, window) / window |
| 44 | + smas = np.convolve(values, weights, 'valid') |
| 45 | + return smas # numpy array |
| 46 | + |
| 47 | +def graphData(stock, MA1=12, MA2=26): |
| 48 | + try: |
| 49 | + # define the data file |
| 50 | + stockFile = "./data/" + stock + ".txt" |
| 51 | + |
| 52 | + # Load data into numpy arrays |
| 53 | + date, closep, highp, lowp, openp, volume = np.loadtxt(stockFile, delimiter=",", |
| 54 | + unpack=True, converters = {0: mdates.strpdate2num("%Y%m%d")}) |
| 55 | + |
| 56 | + #----------------------------------------------------------------------------------------------- |
| 57 | + # building data for drawing plotting candlestick chart. Basically, a an array of comma separated |
| 58 | + # values. The order of elements is very specific, so check the documentation for candlestick |
| 59 | + x = 0 |
| 60 | + y = len(date) |
| 61 | + candleArray = [] |
| 62 | + while x < y: |
| 63 | + # order of elements matters!!! - used for candlestick charting |
| 64 | + appendLine = date[x], openp[x], closep[x], highp[x], lowp[x], volume[x] |
| 65 | + candleArray.append(appendLine) |
| 66 | + x += 1 |
| 67 | + |
| 68 | + # moving averages for 12 and 26 days |
| 69 | + Av1 = movingaverage(closep, MA1) |
| 70 | + Av2 = movingaverage(closep, MA2) |
| 71 | + # Starting point for graphs |
| 72 | + SP = len(date[MA2-1:]) |
| 73 | + # Creating Moving Average labels |
| 74 | + label1=str(MA1) + " SMA" |
| 75 | + label2=str(MA2) + " SMA" |
| 76 | + |
| 77 | + |
| 78 | + # changing the face color of the graphics |
| 79 | + fig = plt.figure(facecolor="#07000D") |
| 80 | + |
| 81 | + # create room and plot candlestick chart |
| 82 | + ax1 = plt.subplot2grid((5,4), (1,0), rowspan=4, colspan=4, axisbg="#07000D") |
| 83 | + candlestick(ax1, candleArray[-SP:], width=0.75, colorup="#9EFF15", colordown="#FF1717") |
| 84 | + # plot moving averages |
| 85 | + ax1.plot(date[-SP:], Av1[-SP:], "#5998FF", label=label1, linewidth=1.5) |
| 86 | + ax1.plot(date[-SP:], Av2[-SP:], "#E1EDF9", label=label2, linewidth=1.5) |
| 87 | + # Set grid color to white |
| 88 | + ax1.grid(True, color="white") |
| 89 | + # Set number of tickers on x-axis |
| 90 | + ax1.xaxis.set_major_locator(mticker.MaxNLocator(10)) |
| 91 | + # Format date for presentation |
| 92 | + ax1.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d")) |
| 93 | + # Change label and border colors |
| 94 | + ax1.yaxis.label.set_color("white") |
| 95 | + ax1.spines["bottom"].set_color("#5998FF") |
| 96 | + ax1.spines["top"].set_color("#5998FF") |
| 97 | + ax1.spines["left"].set_color("#5998FF") |
| 98 | + ax1.spines["right"].set_color("#5998FF") |
| 99 | + # Change tick color to white |
| 100 | + ax1.tick_params(axis="y", colors="white") |
| 101 | + ax1.tick_params(axis="x", colors="white") |
| 102 | + plt.ylabel("Stock Price and Volume") |
| 103 | + # display legend and set size of font to 7 |
| 104 | + maLeg = plt.legend(loc=9, ncol=2, prop={"size":7}, fancybox=True) |
| 105 | + # update label transparency |
| 106 | + maLeg.get_frame().set_alpha(0.4) |
| 107 | + textEd = pylab.gca().get_legend().get_texts() |
| 108 | + # set label color |
| 109 | + pylab.setp(textEd[0:5], color = "white") |
| 110 | + # Tilt the labels to 45 degrees |
| 111 | + for label in ax1.xaxis.get_ticklabels(): |
| 112 | + label.set_rotation(45) |
| 113 | + |
| 114 | + |
| 115 | + # set up RSI area |
| 116 | + ax0 = plt.subplot2grid((5,4), (0,0), sharex=ax1, rowspan=1, colspan=4, axisbg="#07000d") |
| 117 | + #plot RSI |
| 118 | + rsi = rsiFunc(closep) |
| 119 | + rsiCol = "#00FFE8" |
| 120 | + ax0.plot(date[-SP:],rsi[-SP:], rsiCol, linewidth=1.5) |
| 121 | + ax0.axhline(70, color = rsiCol) |
| 122 | + ax0.axhline(30, color = rsiCol) |
| 123 | + # color the spaces between the horizontal lines and the RSI line |
| 124 | + ax0.fill_between(date[-SP:],rsi[-SP:], 70, where=(rsi[-SP:] >= 70), facecolor=rsiCol, edgecolor=rsiCol) |
| 125 | + ax0.fill_between(date[-SP:],rsi[-SP:], 30, where=(rsi[-SP:] <= 30), facecolor=rsiCol, edgecolor=rsiCol) |
| 126 | + # Change label and border colors |
| 127 | + ax0.spines["bottom"].set_color("#5998FF") |
| 128 | + ax0.spines["top"].set_color("#5998FF") |
| 129 | + ax0.spines["left"].set_color("#5998FF") |
| 130 | + ax0.spines["right"].set_color("#5998FF") |
| 131 | + # Change tick color to white |
| 132 | + ax0.tick_params(axis="x", colors="white") |
| 133 | + ax0.tick_params(axis="y", colors="white") |
| 134 | + ax0.set_yticks([30,70]) |
| 135 | + ax0.yaxis.label.set_color("white") |
| 136 | + plt.ylabel("RSI") |
| 137 | + |
| 138 | + |
| 139 | + # Plot volume on the same range as ax1 |
| 140 | + volumeMin = 0 |
| 141 | + ax1v = ax1.twinx() |
| 142 | + # subtract moving average calculations |
| 143 | + ax1v.fill_between(date[-SP:], volumeMin, volume[-SP:], facecolor="#00FFE8", alpha=.5) |
| 144 | + ax1v.axes.yaxis.set_ticklabels([]) |
| 145 | + # hide grid |
| 146 | + ax1v.grid(False) |
| 147 | + # Change label and border colors |
| 148 | + ax1v.spines["bottom"].set_color("#5998FF") |
| 149 | + ax1v.spines["top"].set_color("#5998FF") |
| 150 | + ax1v.spines["left"].set_color("#5998FF") |
| 151 | + ax1v.spines["right"].set_color("#5998FF") |
| 152 | + # update the height of the volume part |
| 153 | + ax1v.set_ylim(0,3*volume.max()) |
| 154 | + # Change axis color |
| 155 | + ax1v.tick_params(axis="x", colors="white") |
| 156 | + ax1v.tick_params(axis="y", colors="white") |
| 157 | + |
| 158 | + |
| 159 | + # Setting up the overall appearance of the plot |
| 160 | + plt.subplots_adjust(left=.08, bottom=.14, right=.95, top=.95, wspace=.20, hspace=0) |
| 161 | + plt.suptitle(stock, color="white") |
| 162 | + plt.setp(ax0.get_xticklabels(), visible=False) |
| 163 | + plt.show() |
| 164 | + fig.savefig("./data/" + stock + ".png", facecolor=fig.get_facecolor()) |
| 165 | + |
| 166 | + except Exception, e: |
| 167 | + print "main loop", str(e) |
| 168 | + |
| 169 | +if __name__ == "__main__": |
| 170 | + # testing the calls |
| 171 | + # a list of stocks to process (for testing) |
| 172 | + stocksToPull = 'AAPL', 'GOOG', 'AMZN', 'EBAY', 'CMG', 'MSFT', 'C', 'BA', 'TSLA' |
| 173 | + |
| 174 | + graphData(stocksToPull[3]) |
| 175 | + |
| 176 | + |
0 commit comments