コード例 #1
0
ファイル: pos.py プロジェクト: hartreepartners/external_tia
    def plot_rets(self, ls=1, ax=None):
        """Plot each of the position returns

        :param ls: True, if positions should be broken into long/short
        :param ax: Axes
        :param regr: True, if regression line is shown
        """
        import matplotlib.pyplot as plt
        from tia.util.mplot import AxesFormat

        if ax is None:
            ax = plt.gca()

        frame = self.frame

        if not ls:
            ax.scatter(frame.index, frame.ret, c="k", marker="o", label="All")
        else:
            if len(self.long_pids) > 0:
                lframe = frame.ix[frame.index.isin(self.long_pids)]
                ax.scatter(lframe.index, lframe.ret, c="k", marker="o", label="Long")
            if len(self.short_pids) > 0:
                sframe = frame.ix[frame.index.isin(self.short_pids)]
                ax.scatter(sframe.index, sframe.ret, c="r", marker="o", label="Short")

        # set some boundaries
        AxesFormat().Y.percent().apply()
        ax.set_xlim(0, frame.index.max() + 3)
        ax.set_xlabel("pid")
        ax.set_ylabel("return")
        ax.legend(loc="upper left")
        return ax
コード例 #2
0
ファイル: ret.py プロジェクト: xie3ge/tia
    def plot_ltd(self, ax=None, style='k', label='ltd', show_dd=1, title=True, legend=1):
        ltd = self.ltd_rets
        ax = ltd.plot(ax=ax, style=style, label=label)
        if show_dd:
            dd = self.drawdowns
            dd.plot(style='r', label='drawdowns', alpha=.5, ax=ax)
            ax.fill_between(dd.index, 0, dd.values, facecolor='red', alpha=.25)
            fmt = PercentFormatter

            AxesFormat().Y.percent().X.label("").apply(ax)
            legend and ax.legend(loc='upper left', prop={'size': 12})

            # show the actualy date and value
            mdt, mdd = self.maxdd_dt, self.maxdd
            bbox_props = dict(boxstyle="round", fc="w", ec="0.5", alpha=0.25)
            try:
                dtstr = '{0}'.format(mdt.to_period())
            except:
                # assume daily
                dtstr = '{0}'.format(hasattr(mdt, 'date') and mdt.date() or mdt)
            ax.text(mdt, dd[mdt], "{1} \n {0}".format(fmt(mdd), dtstr).strip(), ha="center", va="top", size=8,
                    bbox=bbox_props)

        if title is True:
            pf = new_percent_formatter(1, parens=False, trunc_dot_zeros=True)
            ff = new_float_formatter(precision=1, parens=False, trunc_dot_zeros=True)
            total = pf(self.ltd_ann)
            vol = pf(self.std_ann)
            sh = ff(self.sharpe_ann)
            mdd = pf(self.maxdd)
            title = 'ret$\mathregular{_{ann}}$ %s     vol$\mathregular{_{ann}}$ %s     sharpe %s     maxdd %s' % (
            total, vol, sh, mdd)

        title and ax.set_title(title, fontdict=dict(fontsize=10, fontweight='bold'))
        return ax
コード例 #3
0
    def plot_hist(self, ax=None, **histplot_kwargs):
        pf = new_percent_formatter(precision=1,
                                   parens=False,
                                   trunc_dot_zeros=1)
        ff = new_float_formatter(precision=1, parens=False, trunc_dot_zeros=1)

        ax = self.rets.hist(ax=ax, **histplot_kwargs)
        AxesFormat().X.percent(1).apply(ax)
        m, s, sk, ku = pf(self.mean), pf(self.std), ff(self.skew), ff(
            self.kurtosis)
        txt = (
            "$\mathregular{\mu}$=%s   $\mathregular{\sigma}$=%s   skew=%s   kurt=%s"
            % (m, s, sk, ku))
        bbox = dict(facecolor="white", alpha=0.5)
        ax.text(
            0,
            1,
            txt,
            fontdict={"fontweight": "bold"},
            bbox=bbox,
            ha="left",
            va="top",
            transform=ax.transAxes,
        )
        return ax
コード例 #4
0
    def plot_ltd(self,
                 ax=None,
                 style="k",
                 label="ltd",
                 show_dd=1,
                 guess_xlabel=1,
                 title=True):
        ltd = self.ltd_frame.pl
        ax = ltd.plot(ax=ax, style=style, label=label)
        if show_dd:
            dd = self.drawdowns
            dd.plot(style="r", label="drawdowns", alpha=0.5)
            ax.fill_between(dd.index,
                            0,
                            dd.values,
                            facecolor="red",
                            alpha=0.25)
            fmt = lambda x: x
            # guess the formatter
            if guess_xlabel:
                from tia.util.fmt import guess_formatter
                from tia.util.mplot import AxesFormat

                fmt = guess_formatter(ltd.abs().max(), precision=1)
                AxesFormat().Y.apply_format(fmt).apply(ax)
                ax.legend(loc="upper left", prop={"size": 12})

            # show the actualy date and value
            mdt, mdd = self.maxdd_dt, self.maxdd
            bbox_props = dict(boxstyle="round", fc="w", ec="0.5", alpha=0.25)
            try:
                dtstr = "{0}".format(mdt.to_period())
            except:
                # assume daily
                dtstr = "{0}".format(
                    hasattr(mdt, "date") and mdt.date() or mdt)
            ax.text(
                mdt,
                dd[mdt],
                "{1} \n {0}".format(fmt(mdd), dtstr).strip(),
                ha="center",
                va="top",
                size=8,
                bbox=bbox_props,
            )

        if title is True:
            df = new_dynamic_formatter(precision=1,
                                       parens=False,
                                       trunc_dot_zeros=True)
            total = df(ltd.iloc[-1])
            vol = df(self.std)
            mdd = df(self.maxdd)
            title = "pnl %s     vol %s     maxdd %s" % (total, vol, mdd)

        title and ax.set_title(title,
                               fontdict=dict(fontsize=10, fontweight="bold"))
        return ax
コード例 #5
0
ファイル: pos.py プロジェクト: hartreepartners/external_tia
    def plot_ret_range(self, ax=None, ls=0, dur=0):
        """Plot the return range for each position

        :param ax: Axes
        """
        import matplotlib.pyplot as plt
        from tia.util.mplot import AxesFormat

        if ax is None:
            ax = plt.gca()

        frame = self.frame
        pids = frame.index

        min_rets = pd.Series(
            [self[pid].performance.ltd_txn.min() for pid in pids], index=pids
        )
        max_rets = pd.Series(
            [self[pid].performance.ltd_txn.max() for pid in pids], index=pids
        )

        if not ls:
            s = frame.duration + 20 if dur else 20
            ax.scatter(frame.index, frame.ret, s=s, c="k", marker="o", label="All")
            ax.vlines(pids, min_rets, max_rets)
        else:
            if len(self.long_pids) > 0:
                lframe = frame.ix[frame.index.isin(self.long_pids)]
                s = lframe.duration + 20 if dur else 20
                ax.scatter(
                    lframe.index, lframe.ret, s=s, c="k", marker="o", label="Long"
                )
                ax.vlines(lframe.index, min_rets[lframe.index], max_rets[frame.index])
            if len(self.short_pids) > 0:
                sframe = frame.ix[frame.index.isin(self.short_pids)]
                s = sframe.duration + 20 if dur else 20
                ax.scatter(
                    sframe.index, sframe.ret, s=s, c="r", marker="o", label="Short"
                )
                ax.vlines(sframe.index, min_rets[sframe.index], max_rets[sframe.index])

        AxesFormat().Y.percent().apply()
        ax.axhline(color="k", linestyle="--")
        ax.set_xlim(0, frame.index.max() + 3)
        ax.set_xlabel("pid")
        ax.set_ylabel("return")
        ax.legend(loc="upper left")
        return ax
コード例 #6
0
def plot_return_on_dollar(rets, title='Return on $1', show_maxdd=0, figsize=None, ax=None, append=0, label=None, **plot_args):
    """ Show the cumulative return of specified rets and max drawdowns if selected."""
    crets = (1. + returns_cumulative(rets, expanding=1))
    if isinstance(crets, pd.DataFrame):
        tmp = crets.copy()
        for c in tmp.columns:
            s = tmp[c]
            fv = s.first_valid_index()
            fi = s.index.get_loc(fv)
            if fi != 0:
                tmp.ix[fi - 1, c] = 1.
            else:
                if not s.index.freq:
                    # no frequency set
                    freq = guess_freq(s.index)
                    s = s.asfreq(freq)
                first = s.index.shift(-1)[0]
                tmp = pd.concat([pd.DataFrame({c: [1.]}, index=[first]), tmp])
        crets = tmp
        if append:
            toadd = crets.index.shift(1)[-1]
            crets = pd.concat([crets, pd.DataFrame(np.nan, columns=crets.columns, index=[toadd])])
    else:
        fv = crets.first_valid_index()
        fi = crets.index.get_loc(fv)
        if fi != 0:
            crets = crets.copy()
            crets.iloc[fi - 1] = 1.
        else:
            if not crets.index.freq:
                first = crets.asfreq(guess_freq(crets.index)).index.shift(-1)[0]
            else:
                first = crets.index.shift(-1)[0]
            tmp = pd.Series([1.], index=[first])
            tmp = tmp.append(crets)
            crets = tmp

        if append:
            toadd = pd.Series(np.nan, index=[crets.index.shift(1)[-1]])
            crets = crets.append(toadd)

    ax = crets.plot(figsize=figsize, title=title, ax=ax, label=label, **plot_args)
    AxesFormat().Y.apply_format(new_float_formatter()).X.label("").apply(ax)
    #ax.tick_params(labelsize=14)
    if show_maxdd:
        # find the max drawdown available by using original rets
        if isinstance(rets, pd.DataFrame):
            iterator = rets.iteritems()
        else:
            iterator = iter([('', rets)])

        for c, col in iterator:
            dd, dt = max_drawdown(col, inc_date=1)
            lbl = c and c + ' maxdd' or 'maxdd'
            # get cret to place annotation correctly
            if isinstance(crets, pd.DataFrame):
                amt = crets.ix[dt, c]
            else:
                amt = crets[dt]

            bbox_props = dict(boxstyle="round", fc="w", ec="0.5", alpha=0.7)
            # sub = lambda c: c and len(c) > 2 and c[:2] or c
            try:
                dtstr = '{0}'.format(dt.to_period())
            except:
                dtstr = '{0}'.format(dt)

            ax.text(dt, amt, "mdd {0}".format(dtstr).strip(), ha="center",
                    va="center", size=10, bbox=bbox_props)
    plt.tight_layout()
コード例 #7
0
    def add_position_page(self, result):
        def dofmt(t):
            t.apply_basic_style(cmap=self.table_style)
            [
                row.guess_format(pcts=1, trunc_dot_zeros=1)
                for row in t.cells.iter_rows()
            ]
            ncols = len(t.formatted_values.columns)
            t.set_col_widths(pcts=[1. / ncols] * ncols)
            return t

        def do_rename(df):
            d = {
                'consecutive_win_cnt_max': 'win_streak',
                'consecutive_loss_cnt_max': 'lose_streak'
            }
            return df.rename(index=lambda c: d.get(c, c))

        pdf = self.pdf
        figures = self.figures
        port = result.port
        buyhold = result.buyhold

        sframe = pd.DataFrame({
            'all': port.positions.stats.series,
            'long': port.long.positions.stats.series,
            'short': port.short.positions.stats.series
        })
        tf = pdf.table_formatter(insert_level(sframe, 'Position', copy=True))
        stable = dofmt(tf).build()

        s = PortfolioSummary()
        s.include_long_short().include_win_loss()
        dframe = s(port, PortfolioSummary.analyze_returns).T.ix['pos']
        tf = pdf.table_formatter(
            do_rename(insert_level(dframe, 'Position', copy=True)))
        dtable = dofmt(tf).build()

        # Plot Position Returns
        f, ax = self.create_ax()
        port.positions.plot_rets(ax=ax)
        plt.tight_layout()
        figures.savefig(key='pos_ls', clear=1)
        # Plot Position Ranges
        f, ax = self.create_ax(figsize=(8, 3))
        port.positions.plot_ret_range(ls=1, dur=1, ax=ax)
        plt.tight_layout()
        figures.savefig(key='pos_rng', clear=1)
        # Plot Long Short Positions with regression line
        tmp = port.position_frame[['side', 'ret']].reset_index()
        g = sns.lmplot("pid", "ret", col="side", hue="side", data=tmp, size=3)
        AxesFormat().Y.percent().apply()
        figures.savefig(key='pos_ls', clear=1)
        # Plot Return vs Duration
        tmp = port.position_frame[['ret', 'duration', 'side']]
        diag_kws = {}
        if len(port.position_frame.index) <= 1:
            diag_kws = {'range': (-100, 100)}
        sns.pairplot(tmp, hue="side", size=3, diag_kws=diag_kws)
        figures.savefig(key='pos_pair', clear=1)

        toimg = lambda path: rlab.new_dynamic_image(path)
        itms = {
            'F1':
            toimg(figures['pos_rng']),
            'F3':
            toimg(figures['pos_ls']),
            'F2':
            toimg(figures['pos_pair']),
            'F5':
            stable,
            'F6':
            dtable,
            'HDR':
            self.title_bar('{0} - {1} - position summary'.format(
                result.sid, result.desc))
        }
        pdf.build_page('positions', itms)
コード例 #8
0
    def add_portfolio_page(self, result):
        def alpha_beta(p, bm):
            model = pd.ols(x=bm.rets, y=p.rets)
            beta = model.beta[0]
            alpha = p.total_ann - beta * bm.total_ann
            s = pd.Series({'alpha': alpha, 'beta': beta})
            return s

        def rs(port1, port2, kind='dly_ret_stats'):
            stats = getattr(port1, kind)
            ab = alpha_beta(stats, getattr(port2, kind))
            tmp = stats.series.append(ab)
            tmp.name = stats.series.name
            return tmp

        def dofmt(t):
            t.apply_basic_style(cmap=self.table_style)
            [
                row.guess_format(pcts=1, trunc_dot_zeros=1)
                for row in t.cells.iter_rows()
            ]
            ncols = len(t.formatted_values.columns)
            t.set_col_widths(pcts=[1. / ncols] * ncols)

        def do_rename(df):
            d = {
                'consecutive_win_cnt_max': 'win_streak',
                'consecutive_loss_cnt_max': 'lose_streak'
            }
            return df.rename(index=lambda c: d.get(c, c))

        # Build the pdf tables
        pdf = self.pdf
        figures = self.figures
        port = result.port
        buyhold = result.buyhold
        sframe = pd.DataFrame([
            rs(port, buyhold, 'dly_ret_stats'),
            rs(port, buyhold, 'weekly_ret_stats'),
            rs(port, buyhold, 'monthly_ret_stats'),
            rs(port, buyhold, 'quarterly_ret_stats')
        ]).T

        tf = pdf.table_formatter(insert_level(sframe, 'Portfolio', copy=True))
        dofmt(tf)
        stable = tf.build()

        s = PortfolioSummary()
        s.include_long_short().include_win_loss()
        dframe = s(port, PortfolioSummary.analyze_returns).T
        tf = pdf.table_formatter(
            do_rename(insert_level(dframe.ix['port'], 'Portfolio', copy=True)))
        dofmt(tf)
        dtable = tf.build()

        # Return on $1 image
        f, ax = self.create_ax()
        buyhold.plot_ret_on_dollar('B', label='Buy & Hold', ax=ax)
        port.plot_ret_on_dollar('B', label=result.desc, ax=ax, color='k')
        ax.legend(loc='upper left')
        ax.set_title('vs Buy & Hold')
        plt.tight_layout()
        figures.savefig(key='buyhold', clear=1)
        # Drawdown image
        f, ax = self.create_ax()
        port.dly_ret_stats.plot_ltd(ax=ax)
        plt.tight_layout()
        figures.savefig(key='dd', clear=1)
        # Long / Short Returns
        f, ax = self.create_ax()
        port.plot_ret_on_dollar('B', label='All', color='k', ax=ax)
        port.long.plot_ret_on_dollar('B', label='Long', ax=ax)
        port.short.plot_ret_on_dollar('B', label='Short', ax=ax)
        ax.legend(loc='upper left')
        figures.savefig(key='ls', clear=1)
        # Sharpe / Ann Vol
        f, ax = self.create_ax()
        perf.sharpe_annualized(port.monthly_rets,
                               expanding=1).iloc[3:].plot(ax=ax,
                                                          color='k',
                                                          label='sharpe')
        ax.set_ylabel('sharpe ann', color='k')
        ax2 = ax.twinx()
        perf.std_annualized(port.monthly_rets,
                            expanding=1).iloc[3:].plot(ax=ax2,
                                                       label='vol',
                                                       color='b',
                                                       alpha=1)
        ax2.set_ylabel('vol ann', color='b')
        plt.tight_layout()
        figures.savefig(key='sharpe', clear=1)
        # Monthly Returns Bar Chart
        f, ax = self.create_ax()
        tmp = pd.DataFrame({
            'All': port.monthly_rets.to_period('M'),
            'Long': port.long.monthly_rets.to_period('M'),
            'Short': port.short.monthly_rets.to_period('M')
        })
        tmp.plot(kind='bar',
                 ax=ax,
                 color=['k', self.long_color, self.short_color])
        AxesFormat().Y.percent().X.rotate().apply()
        plt.tight_layout()
        ax.set_title('Monthly Returns')
        figures.savefig(key='mrets', clear=1)
        # Monthly Returns Box Plot
        f, ax = self.create_ax()
        sns.boxplot(tmp,
                    ax=ax,
                    color=['gray', self.long_color, self.short_color])
        ax.set_title('Monthly Returns')
        AxesFormat().Y.percent().apply()
        plt.tight_layout()
        figures.savefig(key='mrets_box', clear=1)
        # Build the PDF Page
        toimg = lambda path: rlab.new_dynamic_image(path)
        itms = {
            'F1':
            toimg(figures['buyhold']),
            'F2':
            toimg(figures['dd']),
            'F3':
            toimg(figures['ls']),
            'F4':
            toimg(figures['mrets']),
            'F5':
            toimg(figures['sharpe']),
            'F6':
            toimg(figures['mrets_box']),
            'F7':
            stable,
            'F8':
            dtable,
            'HDR':
            self.title_bar('{0} - {1} - portfolio summary'.format(
                result.sid, result.desc))
        }
        pdf.build_page('portfolio', itms)
コード例 #9
0
    def add_position_page(self, result):
        def dofmt(t):
            t.apply_basic_style(cmap=self.table_style)
            [
                row.guess_format(pcts=1, trunc_dot_zeros=1)
                for row in t.cells.iter_rows()
            ]
            ncols = len(t.formatted_values.columns)
            t.set_col_widths(pcts=[1.0 / ncols] * ncols)
            return t

        def do_rename(df):
            d = {
                "consecutive_win_cnt_max": "win_streak",
                "consecutive_loss_cnt_max": "lose_streak",
            }
            return df.rename(index=lambda c: d.get(c, c))

        pdf = self.pdf
        figures = self.figures
        port = result.port
        buyhold = result.buyhold

        sframe = pd.DataFrame({
            "all": port.positions.stats.series,
            "long": port.long.positions.stats.series,
            "short": port.short.positions.stats.series,
        })
        tf = pdf.table_formatter(insert_level(sframe, "Position", copy=True))
        stable = dofmt(tf).build()

        s = PortfolioSummary()
        s.include_long_short().include_win_loss()
        dframe = s(port, PortfolioSummary.analyze_returns).T.ix["pos"]
        tf = pdf.table_formatter(
            do_rename(insert_level(dframe, "Position", copy=True)))
        dtable = dofmt(tf).build()

        # Plot Position Returns
        f, ax = self.create_ax()
        port.positions.plot_rets(ax=ax)
        plt.tight_layout()
        figures.savefig(key="pos_ls", clear=1)
        # Plot Position Ranges
        f, ax = self.create_ax(figsize=(8, 3))
        port.positions.plot_ret_range(ls=1, dur=1, ax=ax)
        plt.tight_layout()
        figures.savefig(key="pos_rng", clear=1)
        # Plot Long Short Positions with regression line
        tmp = port.position_frame[["side", "ret"]].reset_index()
        g = sns.lmplot("pid", "ret", col="side", hue="side", data=tmp, size=3)
        AxesFormat().Y.percent().apply()
        figures.savefig(key="pos_ls", clear=1)
        # Plot Return vs Duration
        tmp = port.position_frame[["ret", "duration", "side"]]
        diag_kws = {}
        if len(port.position_frame.index) <= 1:
            diag_kws = {"range": (-100, 100)}
        sns.pairplot(tmp, hue="side", size=3, diag_kws=diag_kws)
        figures.savefig(key="pos_pair", clear=1)

        toimg = lambda path: rlab.new_dynamic_image(path)
        itms = {
            "F1":
            toimg(figures["pos_rng"]),
            "F3":
            toimg(figures["pos_ls"]),
            "F2":
            toimg(figures["pos_pair"]),
            "F5":
            stable,
            "F6":
            dtable,
            "HDR":
            self.title_bar("{0} - {1} - position summary".format(
                result.sid, result.desc)),
        }
        pdf.build_page("positions", itms)
コード例 #10
0
    def add_portfolio_page(self, result):
        def alpha_beta(p, bm):
            model = pd.ols(x=bm.rets, y=p.rets)
            beta = model.beta[0]
            alpha = p.total_ann - beta * bm.total_ann
            s = pd.Series({"alpha": alpha, "beta": beta})
            return s

        def rs(port1, port2, kind="dly_ret_stats"):
            stats = getattr(port1, kind)
            ab = alpha_beta(stats, getattr(port2, kind))
            tmp = stats.series.append(ab)
            tmp.name = stats.series.name
            return tmp

        def dofmt(t):
            t.apply_basic_style(cmap=self.table_style)
            [
                row.guess_format(pcts=1, trunc_dot_zeros=1)
                for row in t.cells.iter_rows()
            ]
            ncols = len(t.formatted_values.columns)
            t.set_col_widths(pcts=[1.0 / ncols] * ncols)

        def do_rename(df):
            d = {
                "consecutive_win_cnt_max": "win_streak",
                "consecutive_loss_cnt_max": "lose_streak",
            }
            return df.rename(index=lambda c: d.get(c, c))

        # Build the pdf tables
        pdf = self.pdf
        figures = self.figures
        port = result.port
        buyhold = result.buyhold
        sframe = pd.DataFrame([
            rs(port, buyhold, "dly_ret_stats"),
            rs(port, buyhold, "weekly_ret_stats"),
            rs(port, buyhold, "monthly_ret_stats"),
            rs(port, buyhold, "quarterly_ret_stats"),
        ]).T

        tf = pdf.table_formatter(insert_level(sframe, "Portfolio", copy=True))
        dofmt(tf)
        stable = tf.build()

        s = PortfolioSummary()
        s.include_long_short().include_win_loss()
        dframe = s(port, PortfolioSummary.analyze_returns).T
        tf = pdf.table_formatter(
            do_rename(insert_level(dframe.ix["port"], "Portfolio", copy=True)))
        dofmt(tf)
        dtable = tf.build()

        # Return on $1 image
        f, ax = self.create_ax()
        buyhold.plot_ret_on_dollar("B", label="Buy & Hold", ax=ax)
        port.plot_ret_on_dollar("B", label=result.desc, ax=ax, color="k")
        ax.legend(loc="upper left")
        ax.set_title("vs Buy & Hold")
        plt.tight_layout()
        figures.savefig(key="buyhold", clear=1)
        # Drawdown image
        f, ax = self.create_ax()
        port.dly_ret_stats.plot_ltd(ax=ax)
        plt.tight_layout()
        figures.savefig(key="dd", clear=1)
        # Long / Short Returns
        f, ax = self.create_ax()
        port.plot_ret_on_dollar("B", label="All", color="k", ax=ax)
        port.long.plot_ret_on_dollar("B", label="Long", ax=ax)
        port.short.plot_ret_on_dollar("B", label="Short", ax=ax)
        ax.legend(loc="upper left")
        figures.savefig(key="ls", clear=1)
        # Sharpe / Ann Vol
        f, ax = self.create_ax()
        perf.sharpe_annualized(port.monthly_rets,
                               expanding=1).iloc[3:].plot(ax=ax,
                                                          color="k",
                                                          label="sharpe")
        ax.set_ylabel("sharpe ann", color="k")
        ax2 = ax.twinx()
        perf.std_annualized(port.monthly_rets,
                            expanding=1).iloc[3:].plot(ax=ax2,
                                                       label="vol",
                                                       color="b",
                                                       alpha=1)
        ax2.set_ylabel("vol ann", color="b")
        plt.tight_layout()
        figures.savefig(key="sharpe", clear=1)
        # Monthly Returns Bar Chart
        f, ax = self.create_ax()
        tmp = pd.DataFrame({
            "All": port.monthly_rets.to_period("M"),
            "Long": port.long.monthly_rets.to_period("M"),
            "Short": port.short.monthly_rets.to_period("M"),
        })
        tmp.plot(kind="bar",
                 ax=ax,
                 color=["k", self.long_color, self.short_color])
        AxesFormat().Y.percent().X.rotate().apply()
        plt.tight_layout()
        ax.set_title("Monthly Returns")
        figures.savefig(key="mrets", clear=1)
        # Monthly Returns Box Plot
        f, ax = self.create_ax()
        sns.boxplot(tmp,
                    ax=ax,
                    color=["gray", self.long_color, self.short_color])
        ax.set_title("Monthly Returns")
        AxesFormat().Y.percent().apply()
        plt.tight_layout()
        figures.savefig(key="mrets_box", clear=1)
        # Build the PDF Page
        toimg = lambda path: rlab.new_dynamic_image(path)
        itms = {
            "F1":
            toimg(figures["buyhold"]),
            "F2":
            toimg(figures["dd"]),
            "F3":
            toimg(figures["ls"]),
            "F4":
            toimg(figures["mrets"]),
            "F5":
            toimg(figures["sharpe"]),
            "F6":
            toimg(figures["mrets_box"]),
            "F7":
            stable,
            "F8":
            dtable,
            "HDR":
            self.title_bar("{0} - {1} - portfolio summary".format(
                result.sid, result.desc)),
        }
        pdf.build_page("portfolio", itms)