def compute(self, txns):
        """Compute the long/short live-to-date transaction level profit and loss. Uses an open average calculation"""
        txndata = txns.frame
        mktdata = txns.pricer.get_eod_frame()
        if not isinstance(mktdata.index, pd.DatetimeIndex):
            mktdata.to_timestamp(freq='B')

        # get the set of all txn dts and mkt data dts
        pl = pd.merge(txndata, mktdata.reset_index(), how='outer', on=TPL.DT)
        if pl[TC.PID].isnull().all():
            ltd_frame = pd.DataFrame(index=pl.index)
            ltd_frame[TPL.DT] = pl[PL.DT]
            ltd_frame[TPL.POS] = 0
            ltd_frame[TPL.PID] = 0
            ltd_frame[TPL.TID] = 0
            ltd_frame[TPL.TXN_QTY] = np.nan
            ltd_frame[TPL.TXN_PX] = np.nan
            ltd_frame[TPL.TXN_FEES] = 0
            ltd_frame[TPL.TXN_PREMIUM] = 0
            ltd_frame[TPL.TXN_INTENT] = 0
            ltd_frame[TPL.TXN_ACTION] = 0
            ltd_frame[TPL.CLOSE_PX] = pl[TPL.CLOSE_PX]
            ltd_frame[TPL.OPEN_VAL] = 0
            ltd_frame[TPL.MKT_VAL] = 0
            ltd_frame[TPL.TOT_VAL] = 0
            ltd_frame[TPL.DVDS] = 0
            ltd_frame[TPL.FEES] = 0
            ltd_frame[TPL.RPL_GROSS] = 0
            ltd_frame[TPL.RPL] = 0
            ltd_frame[TPL.UPL] = 0
            ltd_frame[TPL.PL] = 0
            return ltd_frame
        else:
            pl.sort([TC.DT, TC.PID, TC.TID], inplace=1)
            pl.reset_index(inplace=1, drop=1)
            # check that all days can be priced
            has_position = pl[TC.PID] > 0
            missing_pxs = pl[MC.CLOSE].isnull()
            missing = pl[TC.DT][has_position & missing_pxs]
            if len(missing) > 0:
                msg = 'insufficient price data: {0} prices missing for dates {1}'
                mdates = ','.join([_.strftime('%Y-%m-%d') for _ in set(missing[:5])])
                mdates += (len(missing) > 5 and '...' or '')
                raise Exception(msg.format(len(missing), mdates))

            # Now there is a row for every timestamp. Now compute the pl and fill in where missing data should be
            cols = [TC.DT, TC.POS, TC.PID, TC.TID, TC.INTENT, TC.ACTION, TC.FEES, TC.QTY, TC.PX, TC.PREMIUM,
                    TC.OPEN_VAL]
            dts, pos_qtys, pids, tids, intents, sides, txn_fees, txn_qtys, txn_pxs, premiums, open_vals = [pl[c] for c
                                                                                                           in
                                                                                                           cols]

            dvds, closing_pxs, mkt_vals = [pl[c] for c in [MC.DVDS, MC.CLOSE, MC.MKT_VAL]]
            # Ensure only end of day is kept for dividends (join will match dvd to any transaction during day
            dvds = dvds.where(dts != dts.shift(-1), 0)
            # fill in pl dates
            open_vals.ffill(inplace=1)
            open_vals.fillna(0, inplace=1)
            pos_qtys.ffill(inplace=1)
            pos_qtys.fillna(0, inplace=1)
            # pid is the only tricky one, copy only while position is open
            inpos = intents.notnull() | (pos_qtys != 0)
            pids = np.where(inpos, pids.ffill(), 0)
            pl['pid'] = pids.astype(int)
            # Zero fill missing
            dvds.fillna(0, inplace=1)
            tids.fillna(0, inplace=1)
            tids = tids.astype(int)
            intents.fillna(0, inplace=1)
            intents = intents.astype(int)
            sides.fillna(0, inplace=1)
            sides = sides.astype(int)
            txn_fees.fillna(0, inplace=1)
            premiums.fillna(0, inplace=1)
            # LTD p/l calculation
            fees = txn_fees.cumsum()
            total_vals = premiums.cumsum()
            mkt_vals *= pos_qtys
            dvds = (dvds * pos_qtys).cumsum()
            rpl_gross = total_vals - open_vals
            rpl = rpl_gross + fees + dvds
            upl = mkt_vals + open_vals
            tpl = upl + rpl
            # build the result
            data = OrderedDict()
            data[TPL.DT] = dts
            data[TPL.POS] = pos_qtys
            data[TPL.PID] = pids
            data[TPL.TID] = tids
            data[TPL.TXN_QTY] = txn_qtys
            data[TPL.TXN_PX] = txn_pxs
            data[TPL.TXN_FEES] = txn_fees
            data[TPL.TXN_PREMIUM] = premiums
            data[TPL.TXN_INTENT] = intents
            data[TPL.TXN_ACTION] = sides
            data[TPL.CLOSE_PX] = closing_pxs
            data[TPL.OPEN_VAL] = open_vals
            data[TPL.MKT_VAL] = mkt_vals
            data[TPL.TOT_VAL] = total_vals
            data[TPL.DVDS] = dvds
            data[TPL.FEES] = fees
            data[TPL.RPL_GROSS] = rpl_gross
            data[TPL.RPL] = rpl
            data[TPL.UPL] = upl
            data[TPL.PL] = tpl
            ltd_frame = pd.DataFrame(data, columns=data.keys())
            return ltd_frame
Compute the long/short live-to-date transaction level profit and loss. Uses an open average calculation