def print_industry_coer(fund_ts, ostream): """ @summary prints standard deviation of returns for a fund @param fund_ts: pandas fund time series @param years: list of years to print out @param ostream: stream to print to """ industries = [['$DJUSBM', 'Materials'], ['$DJUSNC', 'Goods'], ['$DJUSCY', 'Services'], ['$DJUSFN', 'Financials'], ['$DJUSHC', 'Health'], ['$DJUSIN', 'Industrial'], ['$DJUSEN', 'Oil & Gas'], ['$DJUSTC', 'Technology'], ['$DJUSTL', 'TeleComm'], ['$DJUSUT', 'Utilities']] for i in range(0, len(industries)): if (i % 2 == 0): ostream.write("\n") #load data norObj = de.DataAccess('mysql') ldtTimestamps = du.getNYSEdays(fund_ts.index[0], fund_ts.index[-1], dt.timedelta(hours=16)) ldfData = norObj.get_data(ldtTimestamps, [industries[i][0]], ['close']) #get corelation ldfData[0] = ldfData[0].fillna(method='pad') ldfData[0] = ldfData[0].fillna(method='bfill') a = np.corrcoef(np.ravel(tsu.daily(ldfData[0][industries[i][0]])), np.ravel(tsu.daily(fund_ts.values))) b = np.ravel(tsu.daily(ldfData[0][industries[i][0]])) f = np.ravel(tsu.daily(fund_ts)) fBeta, unused = np.polyfit(b, f, 1) ostream.write("%10s(%s):%+6.2f, %+6.2f " % (industries[i][1], industries[i][0], a[0, 1], fBeta))
def print_other_coer(fund_ts, ostream): """ @summary prints standard deviation of returns for a fund @param fund_ts: pandas fund time series @param years: list of years to print out @param ostream: stream to print to """ industries = [['$SPX', ' S&P Index'], ['$DJI', ' Dow Jones'], ['$DJUSEN', 'Oil & Gas'], ['$DJGSP', ' Metals']] for i in range(0, len(industries)): if (i % 2 == 0): ostream.write("\n") #load data norObj = de.DataAccess('mysql') ldtTimestamps = du.getNYSEdays(fund_ts.index[0], fund_ts.index[-1], dt.timedelta(hours=16)) ldfData = norObj.get_data(ldtTimestamps, [industries[i][0]], ['close']) #get corelation ldfData[0] = ldfData[0].fillna(method='pad') ldfData[0] = ldfData[0].fillna(method='bfill') a = np.corrcoef(np.ravel(tsu.daily(ldfData[0][industries[i][0]])), np.ravel(tsu.daily(fund_ts.values))) b = np.ravel(tsu.daily(ldfData[0][industries[i][0]])) f = np.ravel(tsu.daily(fund_ts)) fBeta, unused = np.polyfit(b, f, 1) ostream.write("%10s(%s):%+6.2f, %+6.2f " % (industries[i][1], industries[i][0], a[0, 1], fBeta))
def speedTest(lfcFeature, ldArgs): ''' @Author: Tingyu Zhu @summary: Function to test the runtime for a list of features, and output them by speed @param lfcFeature: a list of features that will be sorted by runtime @param dArgs: Arguments to pass into feature function @return: A list of sorted tuples of format (time, function name/param string) ''' '''pulling out 2 years data to run test''' daData = de.DataAccess('mysql') dtStart = dt.datetime(2010, 1, 1) dtEnd = dt.datetime(2011, 12, 31) dtTimeofday = dt.timedelta(hours=16) lsSym = ['AAPL', 'GOOG', 'XOM', 'AMZN', 'BA', 'GILD', '$SPX'] #print lsSym '''set up variables for applyFeatures''' lsKeys = ['open', 'high', 'low', 'close', 'volume', 'actual_close'] ldtTimestamps = du.getNYSEdays(dtStart, dtEnd, dtTimeofday) ldfData = daData.get_data(ldtTimestamps, lsSym, lsKeys) dData = dict(zip(lsKeys, ldfData)) '''loop through features''' ltResults = [] for i in range(len(lfcFeature)): dtFuncStart = dt.datetime.now() ldfFeatures = applyFeatures(dData, [lfcFeature[i]], [ldArgs[i]], sMarketRel='$SPX') ltResults.append((dt.datetime.now() - dtFuncStart, lfcFeature[i].__name__ + ' : ' + str(ldArgs[i]))) ltResults.sort() '''print out result''' for tResult in ltResults: print tResult[1], ':', tResult[0] return ltResults
def share_table2fund(share_table): """ @summary converts data frame of shares into fund values @param share_table: data frame containing shares on days transactions occured @return fund : time series containing fund value over time @return leverage : time series containing fund value over time """ # Get the data from the data store dataobj = de.DataAccess('mysql') startday = share_table.index[0] endday = share_table.index[-1] symbols = list(share_table.columns) symbols.remove('_CASH') # print symbols # Get desired timestamps timeofday = dt.timedelta(hours=16) timestamps = du.getNYSEdays(startday - dt.timedelta(days=5), endday + dt.timedelta(days=1), timeofday) historic = dataobj.get_data(timestamps, symbols, ["close"])[0] historic["_CASH"] = 1 closest = historic[historic.index <= share_table.index[0]].ix[:] ts_leverage = pandas.Series(0, index=[closest.index[-1]]) # start shares/fund out as 100% cash first_val = closest.ix[-1] * share_table.ix[0] fund_ts = pandas.Series([first_val.sum(axis=1)], index=[closest.index[-1]]) prev_row = share_table.ix[0] for row_index, row in share_table.iterrows(): # print row_index trade_price = historic.ix[row_index:].ix[0:1] trade_date = trade_price.index[0] # print trade_date # get stock prices on all the days up until this trade to_calculate = historic[(historic.index <= trade_date) & (historic.index > fund_ts.index[-1])] # multiply prices by our current shares values_by_stock = to_calculate * prev_row # for date, sym in values_by_stock.iteritems(): # print date,sym # print values_by_stock prev_row = row #update leverage ts_leverage = _calculate_leverage(values_by_stock, ts_leverage) # calculate total value and append to our fund history fund_ts = fund_ts.append([values_by_stock.sum(axis=1)]) return [fund_ts, ts_leverage]
def generate_report(funds_list, graph_names, out_file, i_start_cash=10000): """ @summary generates a report given a list of fund time series """ html_file = open("report.html", "w") print_header(html_file, out_file) html_file.write("<IMG SRC = \'./funds.png\' width = 400/>\n") html_file.write("<BR/>\n\n") i = 0 pyplot.clf() #load spx for time frame symbol = ["$SPX"] start_date = 0 end_date = 0 for fund in funds_list: if (type(fund) != type(list())): if (start_date == 0 or start_date > fund.index[0]): start_date = fund.index[0] if (end_date == 0 or end_date < fund.index[-1]): end_date = fund.index[-1] mult = i_start_cash / fund.values[0] pyplot.plot(fund.index, fund.values * mult, label = \ path.basename(graph_names[i])) else: if (start_date == 0 or start_date > fund[0].index[0]): start_date = fund[0].index[0] if (end_date == 0 or end_date < fund[0].index[-1]): end_date = fund[0].index[-1] mult = i_start_cash / fund[0].values[0] pyplot.plot(fund[0].index, fund[0].values * mult, label = \ path.basename(graph_names[i])) i += 1 timeofday = dt.timedelta(hours=16) timestamps = du.getNYSEdays(start_date, end_date, timeofday) dataobj = de.DataAccess('mysql') benchmark_close = dataobj.get_data(timestamps, symbol, ["close"], \ verbose = False)[0] mult = i_start_cash / benchmark_close.values[0] i = 0 for fund in funds_list: if (type(fund) != type(list())): print_stats(fund, ["$SPX"], graph_names[i]) else: print_stats(fund[0], ["$SPX"], graph_names[i]) i += 1 pyplot.plot(benchmark_close.index, \ benchmark_close.values*mult, label = "SSPX") pyplot.ylabel('Fund Value') pyplot.xlabel('Date') pyplot.legend() savefig('funds.png', format='png') print_footer(html_file)
def testFeature(fcFeature, dArgs): ''' @summary: Quick function to run a feature on some data and plot it to see if it works. @param fcFeature: Feature function to test @param dArgs: Arguments to pass into feature function @return: Void ''' ''' Get Train data for 2009-2010 ''' dtStart = dt.datetime(2011, 7, 1) dtEnd = dt.datetime(2011, 12, 31) ''' Pull in current training data and test data ''' norObj = de.DataAccess('mysql') ''' Get 2 extra months for moving averages and future returns ''' ldtTimestamps = du.getNYSEdays(dtStart, dtEnd, dt.timedelta(hours=16)) lsSym = ['GOOG'] lsSym.append('WMT') lsSym.append('$SPX') lsSym.append('$VIX') lsSym.sort() lsKeys = ['open', 'high', 'low', 'close', 'volume', 'actual_close'] ldfData = norObj.get_data(ldtTimestamps, lsSym, lsKeys) dData = dict(zip(lsKeys, ldfData)) dfPrice = dData['close'] #print dfPrice.values ''' Generate a list of DataFrames, one for each feature, with the same index/column structure as price data ''' dtStart = dt.datetime.now() ldfFeatures = applyFeatures(dData, [fcFeature], [dArgs], sMarketRel='$SPX') print 'Runtime:', dt.datetime.now() - dtStart ''' Use last 3 months of index, to avoid lookback nans ''' dfPrint = ldfFeatures[0]['GOOG'] print 'GOOG values:', dfPrint.values print 'GOOG Sum:', dfPrint.ix[dfPrint.notnull()].sum() for sSym in lsSym: plt.subplot(211) plt.plot(ldfFeatures[0].index[-60:], dfPrice[sSym].values[-60:]) plt.plot( ldfFeatures[0].index[-60:], dfPrice['$SPX'].values[-60:] * dfPrice[sSym].values[-60] / dfPrice['$SPX'].values[-60]) plt.legend((sSym, '$SPX')) plt.title(sSym) plt.subplot(212) plt.plot(ldfFeatures[0].index[-60:], ldfFeatures[0][sSym].values[-60:]) plt.title('%s-%s' % (fcFeature.__name__, str(dArgs))) plt.show()
def calculate_efficiency(dt_start_date, dt_end_date, s_stock): """ @summary calculates the exit-entry/high-low trade efficiency of a stock from historical data @param start_date: entry point for the trade @param end_date: exit point for the trade @param stock: stock to compute efficiency for @return: float representing efficiency """ # Get the data from the data store dataobj = de.DataAccess('mysql') # Get desired timestamps timeofday=dt.timedelta(hours=16) timestamps = du.getNYSEdays(dt_start_date,dt_end_date+dt.timedelta(days=1),timeofday) historic = dataobj.get_data( timestamps, [s_stock] ,["close"] )[0] # print "######" # print historic hi=numpy.max(historic.values) low=numpy.min(historic.values) entry=historic.values[0] exit_price=historic.values[-1] return (((exit_price-entry)/(hi-low))[0])
def get_data(ls_symbols, ls_keys): ''' @summary: Gets a data chunk for backtesting @param dt_start: Start time @param dt_end: End time @param ls_symbols: symbols to use @note: More data will be pulled from before and after the limits to ensure valid data on the start/enddates which requires lookback/forward @return: data dictionry ''' print "Getting Data from MySQL" # Modify dates to ensure enough data for all features dt_start = dt.datetime(2005,1,1) dt_end = dt.datetime(2012, 8, 31) ldt_timestamps = du.getNYSEdays( dt_start, dt_end, dt.timedelta(hours=16) ) c_da = de.DataAccess('mysql') ldf_data = c_da.get_data(ldt_timestamps, ls_symbols, ls_keys) d_data = dict(zip(ls_keys, ldf_data)) return d_data
def print_html(fund_ts, benchmark, name, lf_dividend_rets=0.0, original="", s_fund_name="Fund", s_original_name="Original", d_trading_params="", d_hedge_params="", s_comments="", directory=False, leverage=False, commissions=0, slippage=0, borrowcost=0, ostream=sys.stdout, i_start_cash=1000000): """ @summary prints stats of a provided fund and benchmark @param fund_ts: fund value in pandas timeseries @param benchmark: benchmark symbol to compare fund to @param name: name to associate with the fund in the report @param directory: parameter to specify printing to a directory @param leverage: time series to plot with report @param commissions: value to print with report @param slippage: value to print with report @param ostream: stream to print stats to, defaults to stdout """ #Set locale for currency conversions locale.setlocale(locale.LC_ALL, '') #make names length independent for alignment s_formatted_original_name = "%15s" % s_original_name s_formatted_fund_name = "%15s" % s_fund_name fund_ts = fund_ts.fillna(method='pad') if directory != False: if not path.exists(directory): makedirs(directory) sfile = path.join(directory, "report-%s.html" % name) splot = "plot-%s.png" % name splot_dir = path.join(directory, splot) ostream = open(sfile, "wb") print "writing to ", sfile if type(original) == type("str"): if type(leverage) != type(False): print_plot(fund_ts, benchmark, name, splot_dir, lf_dividend_rets, leverage=leverage, i_start_cash=i_start_cash) else: print_plot(fund_ts, benchmark, name, splot_dir, lf_dividend_rets, i_start_cash=i_start_cash) else: if type(leverage) != type(False): print_plot([fund_ts, original], benchmark, name, splot_dir, s_original_name, lf_dividend_rets, leverage=leverage, i_start_cash=i_start_cash) else: print_plot([fund_ts, original], benchmark, name, splot_dir, s_original_name, lf_dividend_rets, i_start_cash=i_start_cash) print_header(ostream, name) start_date = fund_ts.index[0].strftime("%m/%d/%Y") end_date = fund_ts.index[-1].strftime("%m/%d/%Y") ostream.write("Performance Summary for "\ + str(path.basename(name)) + " Backtest\n") ostream.write("For the dates " + str(start_date) + " to "\ + str(end_date) + "") #paramater section if d_trading_params != "": ostream.write("\n\nTrading Paramaters\n\n") for var in d_trading_params: print_line(var, d_trading_params[var], ostream=ostream) if d_hedge_params != "": ostream.write("\nHedging Paramaters\n\n") if type(d_hedge_params['Weight of Hedge']) == type(float): d_hedge_params['Weight of Hedge'] = str( int(d_hedge_params['Weight of Hedge'] * 100)) + '%' for var in d_hedge_params: print_line(var, d_hedge_params[var], ostream=ostream) #comment section if s_comments != "": ostream.write("\nComments\n\n%s" % s_comments) if directory != False: ostream.write("\n\n<img src=" + splot + " width=600 />\n\n") mult = i_start_cash / fund_ts.values[0] timeofday = dt.timedelta(hours=16) timestamps = du.getNYSEdays(fund_ts.index[0], fund_ts.index[-1], timeofday) dataobj = de.DataAccess('mysql') years = du.getYears(fund_ts) benchmark_close = dataobj.get_data(timestamps, benchmark, ["close"]) benchmark_close = benchmark_close[0] for bench_sym in benchmark: benchmark_close[bench_sym] = benchmark_close[bench_sym].fillna( method='pad') if type(lf_dividend_rets) != type(0.0): for i, sym in enumerate(benchmark): benchmark_close[sym] = _dividend_rets_funds( benchmark_close[sym], lf_dividend_rets[i]) ostream.write("Resulting Values in $ with an initial investment of " + locale.currency(int(round(i_start_cash)), grouping=True) + "\n") print_line(s_formatted_fund_name + " Resulting Value", (locale.currency(int(round(fund_ts.values[-1] * mult)), grouping=True)), i_spacing=3, ostream=ostream) if type(original) != type("str"): mult3 = i_start_cash / original.values[0] print_line(s_formatted_original_name + " Resulting Value", (locale.currency(int(round(original.values[-1] * mult3)), grouping=True)), i_spacing=3, ostream=ostream) for bench_sym in benchmark: mult2 = i_start_cash / benchmark_close[bench_sym].values[0] print_line(bench_sym + " Resulting Value", locale.currency(int( round(benchmark_close[bench_sym].values[-1] * mult2)), grouping=True), i_spacing=3, ostream=ostream) ostream.write("\n") if len(years) > 1: print_line(s_formatted_fund_name + " Sharpe Ratio", "%10.3f" % fu.get_sharpe_ratio(fund_ts.values)[0], i_spacing=4, ostream=ostream) if type(original) != type("str"): print_line(s_formatted_original_name + " Sharpe Ratio", "%10.3f" % fu.get_sharpe_ratio(original.values)[0], i_spacing=4, ostream=ostream) for bench_sym in benchmark: print_line( bench_sym + " Sharpe Ratio", "%10.3f" % fu.get_sharpe_ratio(benchmark_close[bench_sym].values)[0], i_spacing=4, ostream=ostream) ostream.write("\n") ostream.write("Transaction Costs\n") print_line("Total Commissions"," %15s, %10.2f%%" % (locale.currency(int(round(commissions)), grouping=True), \ float((round(commissions)*100)/(fund_ts.values[-1]*mult))), i_spacing=4, ostream=ostream) print_line("Total Slippage"," %15s, %10.2f%%" % (locale.currency(int(round(slippage)), grouping=True), \ float((round(slippage)*100)/(fund_ts.values[-1]*mult))), i_spacing=4, ostream=ostream) print_line("Total Short Borrowing Cost"," %15s, %10.2f%%" % (locale.currency(int(round(borrowcost)), grouping=True), \ float((round(borrowcost)*100)/(fund_ts.values[-1]*mult))), i_spacing=4, ostream=ostream) print_line("Total Costs"," %15s, %10.2f%%" % (locale.currency(int(round(borrowcost+slippage+commissions)), grouping=True), \ float((round(borrowcost+slippage+commissions)*100)/(fund_ts.values[-1]*mult))), i_spacing=4, ostream=ostream) ostream.write("\n") print_line(s_formatted_fund_name + " Std Dev of Returns", get_std_dev(fund_ts), i_spacing=8, ostream=ostream) if type(original) != type("str"): print_line(s_formatted_original_name + " Std Dev of Returns", get_std_dev(original), i_spacing=8, ostream=ostream) for bench_sym in benchmark: print_line(bench_sym + " Std Dev of Returns", get_std_dev(benchmark_close[bench_sym]), i_spacing=8, ostream=ostream) ostream.write("\n") for bench_sym in benchmark: print_benchmark_coer(fund_ts, benchmark_close[bench_sym], str(bench_sym), ostream) ostream.write("\n") ostream.write("\nYearly Performance Metrics") print_years(years, ostream) s_line = "" for f_token in get_annual_return(fund_ts, years): s_line += " %+8.2f%%" % f_token print_line(s_formatted_fund_name + " Annualized Return", s_line, i_spacing=4, ostream=ostream) lf_vals = [get_annual_return(fund_ts, years)] ls_labels = [name] if type(original) != type("str"): s_line = "" for f_token in get_annual_return(original, years): s_line += " %+8.2f%%" % f_token print_line(s_formatted_original_name + " Annualized Return", s_line, i_spacing=4, ostream=ostream) lf_vals.append(get_annual_return(original, years)) ls_labels.append(s_original_name) for bench_sym in benchmark: s_line = "" for f_token in get_annual_return(benchmark_close[bench_sym], years): s_line += " %+8.2f%%" % f_token print_line(bench_sym + " Annualized Return", s_line, i_spacing=4, ostream=ostream) lf_vals.append(get_annual_return(benchmark_close[bench_sym], years)) ls_labels.append(bench_sym) print lf_vals print ls_labels ls_year_labels = [] for i in range(0, len(years)): ls_year_labels.append(str(years[i])) print_bar_chart(lf_vals, ls_labels, ls_year_labels, directory + "/annual_rets.png") print_years(years, ostream) print_line(s_formatted_fund_name + " Winning Days", get_winning_days(fund_ts, years), i_spacing=4, ostream=ostream) if type(original) != type("str"): print_line(s_formatted_original_name + " Winning Days", get_winning_days(original, years), i_spacing=4, ostream=ostream) for bench_sym in benchmark: print_line(bench_sym + " Winning Days", get_winning_days(benchmark_close[bench_sym], years), i_spacing=4, ostream=ostream) print_years(years, ostream) print_line(s_formatted_fund_name + " Max Draw Down", get_max_draw_down(fund_ts, years), i_spacing=4, ostream=ostream) if type(original) != type("str"): print_line(s_formatted_original_name + " Max Draw Down", get_max_draw_down(original, years), i_spacing=4, ostream=ostream) for bench_sym in benchmark: print_line(bench_sym + " Max Draw Down", get_max_draw_down(benchmark_close[bench_sym], years), i_spacing=4, ostream=ostream) print_years(years, ostream) print_line(s_formatted_fund_name + " Daily Sharpe Ratio", get_daily_sharpe(fund_ts, years), i_spacing=4, ostream=ostream) if type(original) != type("str"): print_line(s_formatted_original_name + " Daily Sharpe Ratio", get_daily_sharpe(original, years), i_spacing=4, ostream=ostream) for bench_sym in benchmark: print_line(bench_sym + " Daily Sharpe Ratio", get_daily_sharpe(benchmark_close[bench_sym], years), i_spacing=4, ostream=ostream) print_years(years, ostream) print_line(s_formatted_fund_name + " Daily Sortino Ratio", get_daily_sortino(fund_ts, years), i_spacing=4, ostream=ostream) if type(original) != type("str"): print_line(s_formatted_original_name + " Daily Sortino Ratio", get_daily_sortino(original, years), i_spacing=4, ostream=ostream) for bench_sym in benchmark: print_line(bench_sym + " Daily Sortino Ratio", get_daily_sortino(benchmark_close[bench_sym], years), i_spacing=4, ostream=ostream) ostream.write( "\n\n\nCorrelation and Beta with DJ Industries for the Fund ") print_industry_coer(fund_ts, ostream) ostream.write("\n\nCorrelation and Beta with Other Indices for the Fund ") print_other_coer(fund_ts, ostream) ostream.write("\n\n\nMonthly Returns for the Fund %\n") print_monthly_returns(fund_ts, years, ostream) print_footer(ostream)
def print_plot(fund, benchmark, graph_name, filename, s_original_name="", lf_dividend_rets=0.0, leverage=False, i_start_cash=1000000): """ @summary prints a plot of a provided fund and benchmark @param fund: fund value in pandas timeseries @param benchmark: benchmark symbol to compare fund to @param graph_name: name to associate with the fund in the report @param filename: file location to store plot1 """ pyplot.clf() if type(leverage) != type(False): gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1]) pyplot.subplot(gs[0]) start_date = 0 end_date = 0 if (type(fund) != type(list())): if (start_date == 0 or start_date > fund.index[0]): start_date = fund.index[0] if (end_date == 0 or end_date < fund.index[-1]): end_date = fund.index[-1] mult = i_start_cash / fund.values[0] pyplot.plot(fund.index, fund.values * mult, label = \ path.basename(graph_name)) else: i = 0 for entity in fund: if (start_date == 0 or start_date > entity.index[0]): start_date = entity.index[0] if (end_date == 0 or end_date < entity.index[-1]): end_date = entity.index[-1] mult = i_start_cash / entity.values[0] if i == 1 and len(fund) != 1: pyplot.plot(entity.index, entity.values * mult, label = \ s_original_name) else: pyplot.plot(entity.index, entity.values * mult, label = \ path.basename(graph_name)) i = i + 1 timeofday = dt.timedelta(hours=16) timestamps = du.getNYSEdays(start_date, end_date, timeofday) dataobj = de.DataAccess('mysql') benchmark_close = dataobj.get_data(timestamps, benchmark, ["close"]) benchmark_close = benchmark_close[0] benchmark_close = benchmark_close.fillna(method='pad') benchmark_close = benchmark_close.fillna(method='bfill') benchmark_close = benchmark_close.fillna(1.0) if type(lf_dividend_rets) != type(0.0): for i, sym in enumerate(benchmark): benchmark_close[sym] = _dividend_rets_funds( benchmark_close[sym], lf_dividend_rets[i]) for sym in benchmark: mult = i_start_cash / benchmark_close[sym].values[0] pyplot.plot(benchmark_close[sym].index, \ benchmark_close[sym].values*mult, label = sym) pyplot.gcf().autofmt_xdate() pyplot.gca().fmt_xdata = mdates.DateFormatter('%m-%d-%Y') pyplot.gca().xaxis.set_major_formatter(mdates.DateFormatter('%b %d %Y')) pyplot.xlabel('Date') pyplot.ylabel('Fund Value') pyplot.legend(loc="best") if type(leverage) != type(False): pyplot.subplot(gs[1]) pyplot.plot(leverage.index, leverage.values, label="Leverage") pyplot.gcf().autofmt_xdate() pyplot.gca().fmt_xdata = mdates.DateFormatter('%m-%d-%Y') pyplot.gca().xaxis.set_major_formatter( mdates.DateFormatter('%b %d %Y')) labels = [] max_label = max(leverage.values) min_label = min(leverage.values) rounder = -1 * (round(log10(max_label)) - 1) labels.append(round(min_label * 0.9, int(rounder))) labels.append(round((max_label + min_label) / 2, int(rounder))) labels.append(round(max_label * 1.1, int(rounder))) pyplot.yticks(labels) pyplot.legend(loc="best") pyplot.title(graph_name + " Leverage") pyplot.xlabel('Date') pyplot.legend() savefig(filename, format='png')