Revision: 6988
          http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6988&view=rev
Author:   jdh2358
Date:     2009-03-18 15:22:41 +0000 (Wed, 18 Mar 2009)

Log Message:
-----------
updated finance_work2.py demo

Modified Paths:
--------------
    trunk/matplotlib/examples/pylab_examples/finance_work2.py
    trunk/matplotlib/examples/pylab_examples/legend_demo3.py

Modified: trunk/matplotlib/examples/pylab_examples/finance_work2.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/finance_work2.py   2009-03-18 
07:39:43 UTC (rev 6987)
+++ trunk/matplotlib/examples/pylab_examples/finance_work2.py   2009-03-18 
15:22:41 UTC (rev 6988)
@@ -1,278 +1,221 @@
-"""
-You need a additional files to run this example.  Save the following
-in the same dir as this file
+## Plot the stock price with some technical indicators
+## Example usage::
+##     python stocks2.py --ticker=GE --startdate=2003
+##
+import datetime, os, urllib, optparse
+import numpy as np
+import dateutil.parser
+import matplotlib.colors as colors
+import matplotlib.finance as finance
+import matplotlib.dates as mdates
+import matplotlib.ticker as mticker
+import matplotlib.mlab as mlab
+import matplotlib.pyplot as plt
+import matplotlib.font_manager as font_manager
 
-  http://matplotlib.sourceforge.net/screenshots/helpers.py
+today = datetime.date.today()
 
-  http://matplotlib.sourceforge.net/screenshots/msft_nasdaq_d.csv
+optionparser = optparse.OptionParser()
 
-  http://matplotlib.sourceforge.net/screenshots/__init__.py
+optionparser.add_option('-t', '--ticker',
+                        dest='ticker',
+                        help='a stock market ticker',
+                        default='SPY')
 
-"""
+optionparser.add_option('-s', '--startdate',
+                        dest='startdate',
+                        help='the start date',
+                        
default=(today-datetime.timedelta(days=365*2)).strftime('%Y-%m-%d'))
 
-import time, os, sys, datetime
+optionparser.add_option('-e', '--enddate',
+                        dest='enddate',
+                        help='the end date',
+                        default=today.strftime('%Y-%m-%d'))
 
-from matplotlib import rcParams
-from matplotlib.ticker import  IndexLocator, FuncFormatter, NullFormatter, 
MultipleLocator
-from matplotlib.dates import IndexDateFormatter, date2num
-from matplotlib.finance import candlestick2, plot_day_summary2, \
-     volume_overlay, index_bar
-from pylab import *
 
-rcParams['timezone'] = 'US/Eastern'
-rc('grid', color='0.75', linestyle='-', linewidth=0.5)
+(commandoptions, commandargs) = optionparser.parse_args()
 
-def ema(s, n):
-    """
-    returns an n period exponential moving average for
-    the time series s
 
-    s is a list ordered from oldest (index 0) to most recent (index
-    -1) n is an integer
+startdate = dateutil.parser.parse(commandoptions.startdate)
+enddate = dateutil.parser.parse(commandoptions.enddate)
+ticker = commandoptions.ticker
 
-    returns a numeric array of the exponential moving average
-    """
-    s = array(s)
-    ema = []
-    j = 1
-    #get n sma first and calculate the next n period ema
-    sma = sum(s[:n]) / n
-    multiplier = 2 / float(1 + n)
-    ema.append(sma)
-    #EMA(current) = ( (Price(current) - EMA(prev) ) xMultiplier) + EMA(prev)
-    ema.append(( (s[n] - sma) * multiplier) + sma)
-    #now calculate the rest of the values
-    for i in s[n+1:]:
-        tmp = ( (i - ema[j]) * multiplier) + ema[j]
-        j = j + 1
-        ema.append(tmp)
-    return ema
 
-def movavg(s, n):
-    """
-    returns an n period moving average for the time series s
+fh = finance.fetch_historical_yahoo(ticker, startdate, enddate)
+# a numpy record array with fields: date, open, high, low, close, volume, 
adj_close)
 
-    s is a list ordered from oldest (index 0) to most recent (index -1)
-    n is an integer
+r = mlab.csv2rec(fh); fh.close()
+r.sort()
 
-        returns a numeric array of the moving average
 
-    See also ema in this module for the exponential moving average.
+def moving_average(x, n, type='simple'):
     """
-    s = array(s)
-    c = cumsum(s)
-    return (c[n-1:] - c[:-n+1]) / float(n-1)
+    compute an n period moving average.
 
-def fill_over(ax, x, y, val, color, over=True):
+    type is 'simple' | 'exponential'
+
     """
-    Plot filled x,y for all y over val
-    if over = False, fill all areas < val
-    """
-    ybase = asarray(y)-val
-    crossings = nonzero(less(ybase[:-1] * ybase[1:],0))
+    x = np.asarray(x)
+    if type=='simple':
+        weights = np.ones(n)
+    else:
+        weights = np.exp(np.linspace(-1., 0., n))
 
-    if ybase[0]>=0: fillon = over
-    else:           fillon = not over
+    weights /= weights.sum()
 
+    a =  np.convolve(x, weights, mode='full')[:len(x)]
+    a[:n] = a[n]
+    return a
 
-    indLast = 0
-    for ind in crossings:
-        if fillon:
-            thisX = x[indLast:ind+1]
-            thisY = y[indLast:ind+1]
-            thisY[0] = val
-            thisY[-1] = val
-            ax.fill(thisX, thisY, facecolor=color)
-        fillon = not fillon
-        indLast = ind
+def relative_strength(prices, n=14):
+    """
+    compute the n period relative strength indicator
+    
http://stockcharts.com/school/doku.php?id=chart_school:glossary_r#relativestrengthindex
+    http://www.investopedia.com/terms/r/rsi.asp
+    """
 
+    deltas = np.diff(prices)
+    seed = deltas[:n+1]
+    up = seed[seed>=0].sum()/n
+    down = -seed[seed<0].sum()/n
+    rs = up/down
+    rsi = np.zeros_like(r.adj_close)
+    rsi[:n] = 100. - 100./(1.+rs)
 
-def random_signal(N, tau):
-    'generate a length N  random signal with time constant tau'
-    t = arange(float(N))
-    filter = exp(-t/tau)
-    return convolve( randn(N), filter, mode=2)[:len(t)]
+    for i in range(n, len(prices)):
+        delta = deltas[i-1] # cause the diff is 1 shorter
 
+        if delta>0:
+            upval = delta
+            downval = 0.
+        else:
+            upval = 0.
+            downval = -delta
 
-# load a numpy record array from yahoo csv data with fields date,
-# open, close, volume, adj_close from the mpl-data/example directory.
-# The record array stores python datetime.date as an object array in
-# the date column
-datafile = matplotlib.get_example_data('goog.npy')
-r = np.load(datafile).view(np.recarray)
-r = r[-250:]
+        up = (up*(n-1) + upval)/n
+        down = (down*(n-1) + downval)/n
 
-N = len(r)
+        rs = up/down
+        rsi[i] = 100. - 100./(1.+rs)
 
-vind = np.arange(N)
+    return rsi
 
-figBG   = 'w'        # the figure background color
-axesBG  = '#f6f6f6'  # the axies background color
-textsize = 8        # size for axes text
-
-# the demo data are intc from (2003, 9, 1) to (2004, 4, 12 ) with
-# dates as epoch; I saved these to a file for ease of debugginh
-ticker = 'MSFT'
-
-
-figure(1, facecolor=figBG)
-
-def get_locator():
+def moving_average_convergence(x, nslow=26, nfast=12):
     """
-    the axes cannot share the same locator, so this is a helper
-    function to generate locators that have identical functionality
+    compute the MACD (Moving Average Convergence/Divergence) using a fast and 
slow exponential moving avg'
+    return value is emaslow, emafast, macd which are len(x) arrays
     """
+    emaslow = moving_average(x, nslow, type='exponential')
+    emafast = moving_average(x, nfast, type='exponential')
+    return emaslow, emafast, emafast - emaslow
 
-    return IndexLocator(10, 1)
 
+plt.rc('axes', grid=True)
+plt.rc('grid', color='0.75', linestyle='-', linewidth=0.5)
 
-formatter =  IndexDateFormatter(date2num(r.date), '%b %d %y')
-
-nullfmt   = NullFormatter()         # no labels
-
-def fmt_vol(x,pos):
-    if pos>3: return ''  # only label the first 3 ticks
-    return '%dM' % int(x*1e-6)
-
-volumeFmt = FuncFormatter(fmt_vol)
-
+textsize = 9
 left, width = 0.1, 0.8
 rect1 = [left, 0.7, width, 0.2]
 rect2 = [left, 0.3, width, 0.4]
 rect3 = [left, 0.1, width, 0.2]
-axUpper      = axes(rect1, axisbg=axesBG)  #left, bottom, width, height
-axMiddle     = axes(rect2, axisbg=axesBG, sharex=axUpper)
-axMiddleVol  = axMiddle.twinx()
-axLower      = axes(rect3, axisbg=axesBG, sharex=axUpper)
 
 
-axUpper.xaxis.set_major_locator( get_locator() )
-axUpper.xaxis.set_major_formatter(nullfmt)
-axUpper.grid(True)
+fig = plt.figure(facecolor='white')
+axescolor  = '#f6f6f6'  # the axies background color
 
-# set up two scales on middle axes with left and right ticks
-axMiddle.yaxis.tick_left()
-axMiddle.xaxis.set_major_formatter(nullfmt)
+ax1 = fig.add_axes(rect1, axisbg=axescolor)  #left, bottom, width, height
+ax2 = fig.add_axes(rect2, axisbg=axescolor, sharex=ax1)
+ax2t = ax2.twinx()
+ax3  = fig.add_axes(rect3, axisbg=axescolor, sharex=ax1)
 
-axMiddleVol.yaxis.set_major_formatter(volumeFmt)
-axMiddle.grid(True)
+### plot the relative strength indicator
+prices = r.adj_close
+rsi = relative_strength(prices)
+fillcolor = 'darkgoldenrod'
 
-axLower.xaxis.set_major_locator( get_locator() )
-axLower.xaxis.set_major_formatter( formatter )
-axLower.grid(True)
+ax1.plot(r.date, rsi, color=fillcolor)
+ax1.axhline(70, color=fillcolor)
+ax1.axhline(30, color=fillcolor)
+ax1.fill_between(r.date, rsi, 70, facecolor=fillcolor, where=(rsi>=70))
+ax1.fill_between(r.date, rsi, 30, facecolor=fillcolor, where=(rsi<=30))
+ax1.text(0.6, 0.9, '>70 = overbought', va='top', transform=ax1.transAxes, 
fontsize=textsize)
+ax1.text(0.6, 0.1, '<30 = oversold', transform=ax1.transAxes, 
fontsize=textsize)
+ax1.set_ylim(0, 100)
+ax1.set_yticks([30,70])
+ax1.text(0.025, 0.95, 'RSI (14)', va='top', transform=ax1.transAxes, 
fontsize=textsize)
+ax1.set_title('%s daily'%ticker)
 
-if 1: ############### Upper axes #################
+### plot the price and volume data
+deltas = np.zeros_like(prices)
+deltas[1:] = np.diff(prices)
+up = deltas>0
+ax2.vlines(r.date[up], r.low[up], r.high[up], color='black', 
label='_nolegend_')
+ax2.vlines(r.date[~up], r.low[~up], r.high[~up], color='black', 
label='_nolegend_')
+ma20 = moving_average(prices, 20, type='simple')
+ma200 = moving_average(prices, 200, type='simple')
 
-    # make up a pseudo signal
-    purple = '#660033'
-    s = random_signal(N, tau=20)
-    thresh = 4
-    axUpper.plot(s, color=purple)
-    # upper horiz line
+linema20, = ax2.plot(r.date, ma20, color='blue', lw=2, label='MA (20)')
+linema200, = ax2.plot(r.date, ma200, color='red', lw=2, label='MA (200)')
 
 
+last = r[-1]
+s = '%s O:%1.2f H:%1.2f L:%1.2f C:%1.2f, V:%1.1fM Chg:%+1.2f' % (
+    today.strftime('%d-%b-%Y'),
+    last.open, last.high,
+    last.low, last.close,
+    last.volume*1e-6,
+    last.close-last.open )
+t4 = ax2.text(0.3, 0.9, s, transform=ax2.transAxes, fontsize=textsize)
 
-    axUpper.plot( (0, N), [thresh, thresh], color=purple, linewidth=1)
-    # lower horiz line
-    axUpper.plot( (0, N), [-thresh, -thresh], color=purple, linewidth=1)
+props = font_manager.FontProperties(size=10)
+leg = ax2.legend(loc='center left', shadow=True, fancybox=True, prop=props)
+leg.get_frame().set_alpha(0.5)
 
+vmax = r.volume.max()/1e6
+poly = ax2t.fill_between(r.date, r.volume/1e6, 0, facecolor=fillcolor, 
label='Volume')
+ax2t.set_ylim(0, 5*vmax)
+ymax = np.int(vmax)
+yticks = [vmax/2., vmax]
+ax2t.set_yticks(yticks)
+ax2t.set_yticklabels(['%d M'%val for val in yticks])
 
-    # fill above threshold
-    fill_over(axUpper, vind, s,  thresh,  purple, over=True)
-    fill_over(axUpper, vind, s, -thresh,  purple,  over=False)
+### compute the MACD indicator
+fillcolor = 'darkslategrey'
+nslow = 26
+nfast = 12
+nema = 9
+emaslow, emafast, macd = moving_average_convergence(prices, nslow=nslow, 
nfast=nfast)
+ema9 = moving_average(macd, nema, type='exponential')
+ax3.plot(r.date, macd, color='black', lw=2)
+ax3.plot(r.date, ema9, color='blue', lw=1)
+ax3.fill_between(r.date, macd-ema9, 0, facecolor=fillcolor, alpha=0.5)
 
-    t = axUpper.set_title('Google (GOOG)',  fontsize=12)
-    t.set_y(1.05)  # move it up a bit higher than the default
-    t.set_x(0)  # align the title left, axes coords
-    t.set_horizontalalignment('left')  # align the title left, axes coords
-    axUpper.yaxis.set_major_locator( MultipleLocator(5) )
 
+ax3.text(0.025, 0.95, 'MACD (%d, %d, %d)'%(nfast, nslow, nema), va='top',
+         transform=ax3.transAxes, fontsize=textsize)
 
+ax3.set_yticks([])
+# turn off tick labels, rorate them, etc
+for ax in ax1, ax2, ax2t, ax3:
+    if ax!=ax3:
+        for label in ax.get_xticklabels():
+            label.set_visible(False)
+    else:
+        for label in ax.get_xticklabels():
+            label.set_rotation(30)
+            label.set_horizontalalignment('right')
 
-    # now add some text
-    left, height, top = 0.025, 0.06, 0.85
-    t = axUpper.text(left, top, 'RSI(14) 51.0', fontsize=textsize,
-                     transform=axUpper.transAxes)
+    ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')
 
+class PriceFormatter(mticker.FormatStrFormatter):
+    'suppress the lowest tick label to prevent overlap'
+    def __call__(self, x, pos=None):
+        if pos==0:
+            return ''
+        else:
+            return mticker.FormatStrFormatter.__call__(self, x, pos=None)
 
-if 1:  ############### Middle axes #################
+ax2.yaxis.set_major_formatter(PriceFormatter('%d'))
+plt.show()
 
 
-    candlestick2(axMiddle, r.open, r.close, r.high, r.low, width=0.9)
-
-    # specify the text in axes (0,1) coords.  0,0 is lower left and 1,1 is
-    # upper right
-
-    left, height, top = 0.025, 0.06, 0.9
-    t1 = axMiddle.text(left, top, '%s daily'%ticker, fontsize=textsize,
-                       transform=axMiddle.transAxes)
-    t2 = axMiddle.text(left, top-height, 'MA(5)', color='b', fontsize=textsize,
-                       transform=axMiddle.transAxes)
-    t3 = axMiddle.text(left, top-2*height, 'MA(20)', color='r', 
fontsize=textsize,
-                       transform=axMiddle.transAxes)
-
-    s = '%s O:%1.2f H:%1.2f L:%1.2f C:%1.2f, V:%1.1fM Chg:%+1.2f' %(
-        time.strftime('%d-%b-%Y'),
-        r.open[-1], r.high[-1],
-        r.low[-1], r.close[-1],
-        r.volume[-1]*1e-6,
-        r.close[-1]-r.open[-1])
-    t4 = axMiddle.text(0.4, top, s, fontsize=textsize,
-                       transform=axMiddle.transAxes)
-
-
-    # now do the moviing average.  I'll use a convolution to simulate a
-    # real moving average
-    ma5  = movavg(r.adj_close, 5)
-    ma20 = movavg(r.adj_close, 20)
-    axMiddle.plot(vind[5-1:], ma5,   'b', linewidth=1)
-    axMiddle.plot(vind[20-1:], ma20, 'r', linewidth=1)
-
-    axMiddle.set_ylim((300, 800))
-    axMiddle.set_yticks(np.arange(800, 800, 100))
-
-    # Now do the volume overlay
-
-    # todo - this is broken
-    bars = volume_overlay(axMiddleVol, r.open, r.close, r.volume, alpha=0.5)
-    #axMiddleVol.set_ylim(0, 3*r.volume.max())  # use only a third of the 
viewlim
-
-
-if 1:  ############### Lower axes #################
-
-    # make up two signals; I don't know what the signals are in real life
-    # so I'll just illustrate the plotting stuff
-    s1 = random_signal(N, 10)
-    s2 = random_signal(N, 20)
-
-    axLower.plot(vind, s1, color=purple)
-    axLower.plot(vind, s2, color='k', linewidth=1.0)
-    s3 = s2-s1
-    axLower.plot(vind, s3, color='#cccc99')  # wheat
-    bars = index_bar(axLower, s3, width=2, alpha=0.5,
-                     facecolor='#3087c7', edgecolor='#cccc99')
-    axLower.yaxis.set_major_locator(MultipleLocator(5))
-
-
-    # now add some text
-    left, height, top = 0.025, 0.06, 0.85
-
-    t = axLower.text(left, top, 'MACD(12,26,9) -0.26', fontsize=textsize,
-                     transform=axLower.transAxes)
-
-    # make sure everyone has the same axes limits
-
-    setp(axLower.get_xticklabels(), 'rotation', 45,
-        'horizontalalignment', 'right', fontsize=8)
-
-# force all the axes to have the same x data limits
-allAxes = (axUpper, axMiddle, axMiddleVol, axLower)
-xlim = 0, N
-for a in allAxes:
-    a.set_xlim(xlim)
-
-for ax in axUpper, axMiddle, axMiddleVol:
-    for ticklabel in ax.get_xticklabels():
-        ticklabel.set_visible(False)
-
-show()

Modified: trunk/matplotlib/examples/pylab_examples/legend_demo3.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/legend_demo3.py    2009-03-18 
07:39:43 UTC (rev 6987)
+++ trunk/matplotlib/examples/pylab_examples/legend_demo3.py    2009-03-18 
15:22:41 UTC (rev 6988)
@@ -23,7 +23,7 @@
 
 ax3 = plt.subplot(3,1,3)
 myplot(ax3)
-ax3.legend(loc=1, ncol=4, mode="expand", shadow=True)
+ax3.legend(shadow=True, fancybox=True)
 
 
 plt.draw()


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Apps built with the Adobe(R) Flex(R) framework and Flex Builder(TM) are
powering Web 2.0 with engaging, cross-platform capabilities. Quickly and
easily build your RIAs with Flex Builder, the Eclipse(TM)based development
software that enables intelligent coding and step-through debugging.
Download the free 60 day trial. http://p.sf.net/sfu/www-adobe-com
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins

Reply via email to