POJO-like class in Python
When reading


  An alternative (non-OOP) solution would do something like list_of_MOCS = [{'symbol_1':(bars_1,signals_1)},...,{'symbol_N':(bars_N,signals_N)}] so basically a list containing a map with the key being the ticker and value being a tuple of the two dataframes.


I thought, that a better alternative would be:

MOCS = {
    'symbol_1': (bars_1, signals_1),
    'symbol_2': (bars_2, signals_2),
    ...
    'symbol_N': (bars_N, signals_N),
}


Especially given the fact that pd.DataFrame(MOCS) would yield a valid structure.

However, reading at your usage in generate_positions and expected usage in backtest_portfolio; and especially the fact that you will need to explode the data-structure anyway, I would keep the class approach and use collections.namedtuple as largely suggested in the comments. It provides both the advantages of a class (attributes access) and a tuple (immutable + index access).

I would however change generate_positions to create a dictionnary that will hold the structure of the resulting dataframe before building said dataframe. And incorporate that method directly into the constructor as it does not provide much added value on its own:

from collections import namedtuple


MarketOnCloseSecurity = namedtuple('MarketOnCloseSecurity', 'symbol bars signals')


class MarketOnClosePortfolio(Portfolio):
    """Encapsulates the notion of a portfolio of positions based
    on a set of signals as provided by a Strategy.

    Requires:
    market_on_close_securities
    initial_capital - The amount in cash at the start of the portfolio."""

    def __init__(self, market_on_close_securities, initial_capital=100000.0):
        self.market_on_close_securities = market_on_close_securities
        self.initial_capital = float(initial_capital)

        #loop through each MOCS (market_on_close_security) to calculate positions
        securities = {
            security.symbol: 100 * security.signals['signal'] # This strategy buys 100 shares
            for security in market_on_close_securities
        }
        self.positions = pd.DataFrame(securities)

    def backtest_portfolio(self):
        ...


I would also extend the namedtuple to provide extra utilities methods:

class MarketOnCloseSecurity(namedtuple('MarketOnCloseSecurity', 'symbol bars signals')):
    def buy_shares(self, amount):
        return amount * self.signals['signal']

    def close_price(self):
        return self.bars['close_price'].astype(float)


So that you can have more meaningful actions in MarketOnClosePortfolio:

class MarketOnClosePortfolio(Portfolio):
    """Encapsulates the notion of a portfolio of positions based
    on a set of signals as provided by a Strategy.

    Requires:
    market_on_close_securities
    initial_capital - The amount in cash at the start of the portfolio."""

    def __init__(self, market_on_close_securities, initial_capital=100000.0):
        self.market_on_close_securities = market_on_close_securities
        self.initial_capital = float(initial_capital)

        securities = {
            security.symbol: security.buy_shares(100)
            for security in market_on_close_securities
        }
        self.positions = pd.DataFrame(securities)

    def backtest_portfolio(self):
        # use security.close_price() for any security in self.marke_on_close_securities if you need to
        ...