class SymbolList(object):
class Symbol(object):
    def __init__(self, symbols):
    def get(self, symbol):
    def __repr__(self):
    def __str__(self):
    def __iter__(self):
    def __init__(self, symbol):
    def __repr__(self):
    def __str__(self):
    def __hash__(self):
    def __eq__(self, other):
    def custom(self, name): class YahooConnection(DataConnection):
    """
    Utilizes Pandas' Remote Data Access methods to fetch
    symbol data from Yahoo.
    """
    def get_data(self, symbol, start, end):
        """
        @type symbol: string
        @type start: datetime
        @type end: datetime
        @return: Returns a pandas DataFrame of the requested symbol
        @rtype: pandas.DataFrame
        """
        ret = web.DataReader(str(symbol).upper(), 'yahoo', start, end)
        ret.rename(columns=lambda name: '%s_%s' %(symbol, name), inplace=True)
        return ret class Dataset(object):
    """
    The Dataset object utilizes the pandas DataFrame as a backend for all
    the data handling.
    """
    def __init__(self, symbol_list, data_connection, start_datetime=None, \
                 end_datetime=None, periods=None, granularity=None):
        self.symbol_list = symbol_list
        # Either specify a start and end date or a number of periods since now
        assert periods != None or start_datetime != None
        self.start_datetime = start_datetime
        self.end_datetime = end_datetime
        self.periods = periods
        self.granularity = granularity
        self.data_connection = data_connection
        self.data_frame = pd.DataFrame()
        self.technical_indicators = []
        self.logger = logger.Logger(self.__class__.__name__)
        self.logger.info('symbol_list: %s  \
                          data_connection: %s  \
                          start_datetime: %s  \
                          end_datetime: %s  \
                          periods: %s  \
                          granularity: %s'
                         %(symbol_list, \
                           data_connection, \
                           start_datetime, \
                           end_datetime, \
                           periods, \
                           granularity))
    def __str__(self):
        return 'Dataset(symbol_list=%s, data_connection=%s, start_datetime=%s, \
end_datetime=%s, periods=%s, granularity=%s)' \
                       %(self.symbol_list, \
                         self.data_connection, \
                         self.start_datetime, \
                         self.end_datetime, \
                         self.periods, \
                         self.granularity)
    def __repr__(self):
        return 'Dataset(symbol_list=%s, data_connection=%s, start_datetime=%s, \
end_datetime=%s, periods=%s, granularity=%s)' \
                       %(self.symbol_list, \
                         self.data_connection, \
                         self.start_datetime, \
                         self.end_datetime, \
                         self.periods, \
                         self.granularity)

    def load_data(self, realtime=False, **kwargs):
        """
        Does the actual fetching and storage of the data in the
        dataframe attribute.
        """
        for symbol in self.symbol_list:
            self.logger.info('Loading data for %s (realtime=%s)' %(symbol, realtime))
            if self.periods:
                dataframe = self.data_connection.get_data(symbol, \
                                                          self.granularity, \
                                                          self.periods, \
                                                          realtime=realtime,
                                                          **kwargs)
            else:
                dataframe = self.data_connection.get_data(symbol, \
                                                          self.start_datetime, \
                                                          self.end_datetime,
                                                          **kwargs)
            self.data_frame = self.data_frame.combine_first(dataframe)

    def resample(self, timeframe, volume=True, adjusted_close=False, symbol=None):
        """
        Resamples data to fit another time frame.
        @type timeframe: string
        @param timeframe: The new timeframe to use; see pandas documentation.
        @type volume: boolean
        @param volume: True if volume should also be resampled.
        @type adjusted_close: boolean
        @param adjusted_close: True if Adj Close should also be resampled.
        @type symbol: Symbol
        @param symbol: The symbol to resample or None for all symbols.
        """
        assert len(self.data_frame) > 0, 'No data loaded yet'
        self.logger.info('Resampling data to %s' %timeframe)
        if symbol:
            self._resample(timeframe, volume, adjusted_close, symbol)
        else: # Do all symbols in symbol list
            for symbol in self.symbol_list:
                self._resample(timeframe, volume, adjusted_close, str(symbol))
            # Drop rows that have all NaN's
            self.data_frame = self.data_frame.dropna(how='all') # Only when ALL columns are NaN
        self.logger.debug('Resampling result: %s' %self.data_frame)

    def _resample(self, timeframe, volume, adjusted_close, symbol):
        """
        Should not use this directly.  Use resample() instead.
        """
        how = {'%s_Open' %symbol: 'first', '%s_High' %symbol: 'max',
               '%s_Low' %symbol: 'min', '%s_Close' %symbol: 'last'}
        if volume:
            how['%s_Volume' %symbol] = 'sum'
        if adjusted_close:
            how['%s_AdjClose' %symbol] = 'last'
        out = self.data_frame.resample(timeframe, how=how)
        self.data_frame['%s_Open' %symbol] = out['%s_Open' %symbol]
        self.data_frame['%s_High' %symbol] = out['%s_High' %symbol]
        self.data_frame['%s_Low' %symbol] = out['%s_Low' %symbol]
        self.data_frame['%s_Close' %symbol] = out['%s_Close' %symbol]
        if volume:
            self.data_frame['%s_Volume' %symbol] = out['%s_Volume' %symbol]
        if adjusted_close:
            self.data_frame['%s_AdjClose' %symbol] = out['%s_AdjClose' %symbol]

    def add_technical_indicator(self, technical_indicator):
        """
        Add the technical indicator to the dataset.
        Must be performed before refering a technical indicator in a
        running strategy.
        """
        self.logger.info('Adding technical indicator: %s' %technical_indicator)
        technical_indicator.results(self.data_frame)
        self.technical_indicators.append(technical_indicator)

    def update_technical_indicators(self):
        """
        Loops through each TI and brings it's values up to the latest time slice
        """
        pass class SMA(TechnicalIndicator):
    """
    A technical indicator that returns the simple moving average of a
    series/technical indicator.
    """
    def __init__(self, data, period):
        TechnicalIndicator.__init__(self)
        self.data = data
        self.period = period
        self.value = 'SMA_%s_%s' %(data, period)
        self.logger.info('Initialized - %s' %self)
    def __str__(self):
        return 'SMA(data=%s, period=%s)' %(self.data, self.period)
    def __repr__(self):
        return self.value
    def results(self, data_frame):
        data_frame[self.value] = pd.rolling_mean(data_frame[self.data], self.period) class CrossingAbove(Criteria):
    """
    Criteria used to determine if a technical indicator or symbol OHLCV is
    in the process of crossing above another technical indicator, symbol
    OHLCV, or value.
    """
    def __init__(self, param1, param2):
        Criteria.__init__(self)
        if isinstance(param1, TechnicalIndicator):
            param1 = param1.value
        if isinstance(param2, TechnicalIndicator):
            param2 = param2.value
        self.param1 = param1
        self.param2 = param2
        self.num_bars_required = 2
        self.logger.info('Initialized - %s' %self)
    def __repr__(self):
        return 'CrossingAbove(param1=%s, param2=%s)' \
               %(self.param1, self.param2)
    def __str__(self):
        return 'CrossingAbove(param1=%s, param2=%s)' \
               %(self.param1, self.param2)
    def apply(self, data_frame):
        """
        Apply the CrossingAbove criteria to the data_frame provided.
        @return Series(bool) The criteria status
        """
        if len(data_frame) < self.num_bars_required:
            return False
        value1_now = data_frame[self.param1][-1]
        value1_previous = data_frame[self.param1][-2]
        if isinstance(self.param2, (int, long, float)):
            if value1_previous <= self.param2 and value1_now > self.param2:
                return True
        else:
            value2_now = data_frame[self.param2][-1]
            value2_previous = data_frame[self.param2][-2]
            if value1_previous <= value2_previous and value1_now > value2_now:
                return True
        return False class TrailingStop(Criteria):
    """
    Criteria used to apply a trailing stop exit rule to a strategy.
    """
    def __init__(self, symbol, value, short=False, percent=False):
        Criteria.__init__(self)
        self.symbol = symbol
        self.value = abs(value)
        self.short = short
        self.percent = percent
        # Keep track of the trailing stop.
        if self.short:
            self.stop = self.value
        else:
            self.stop = -self.value
        self.label = 'TrailingStop_%s_%s_%s_%s' %(symbol, value, short, percent)
        self.num_bars_required = 1
        self.logger.info('Initialized - %s' %self)
    def __str__(self):
        return 'TrailingStop(symbol=%s, value=%s, short=%s, percent=%s)' \
                %(self.symbol, self.value, self.short, self.percent)
    def __repr__(self):
        return self.label
    def apply(self, data_frame):
        """
        Apply the TrailingStop criteria to the data_frame provided.
        @return Series(bool) The criteria status
        """
        if self.percent:
            current_value = data_frame['CHANGE_PERCENT_%s' %self.symbol][-1]
        else:
            current_value = data_frame['CHANGE_VALUE_%s' %self.symbol][-1]
        if not np.isnan(current_value):
            if self.short:
                if current_value > self.stop:
                    return True
                else:
                    # Update the trailing stop if needed.
                    if current_value + self.value < self.stop:
                        self.stop = current_value + self.value
            else:
                if current_value < self.stop:
                    return True
                else:
                    # Update the trailing stop if needed.
                    if current_value - self.value > self.stop:
                        self.stop = current_value - self.value
        return False class CriteriaGroup(object):
    """
    For now, since we haven't implemented adding to positions,
    the default is InMarket, NotInMarket, IsLong, IsShort gets
    added automatically to criteria groups as needed.
    """
    def __init__(self, criteria_list, action, symbol):
        self.criteria_list = criteria_list
        self.action = action
        self._action = 0
        self.symbol = str(symbol)
        # Add Actions Criteria Automatically
        if self.action == Long():
            self.criteria_list.append(Not(InMarket(self.symbol)))
            self._action = LONG
        elif self.action == LongExit():
            self.criteria_list.append(IsLong(self.symbol))
            self._action = LONG_EXIT
        elif self.action == Short():
            self.criteria_list.append(Not(InMarket(self.symbol)))
            self._action = SHORT
        elif self.action == ShortExit():
            self.criteria_list.append(IsShort(self.symbol))
            self._action = SHORT_EXIT
        else: raise InvalidAction()
        self.logger = logger.Logger(self.__class__.__name__)
        self.logger.info('New Criteria Group - %s for %s (%s)' \
                         %(str(action).upper(), symbol, criteria_list))

    def __str__(self):
        return 'CriteriaGroup(criteria_list=%s, action=%s, symbol=%s)' \
                              %(self.criteria_list, self.action, self.symbol)
    def __repr__(self):
        return 'CriteriaGroup(criteria_list=%s, action=%s, symbol=%s)' \
                              %(self.criteria_list, self.action, self.symbol)

    def get_result(self, data_frame):
        """
        Get the results of this criteria group based on the data_frame
        provided. If all criteria are True, return the action.
        """
        results = []
        for criteria in self.criteria_list:
            result = None
            if criteria.num_bars_required is not None:
                result = criteria.apply(data_frame[-criteria.num_bars_required:])
            else: result = criteria.apply(data_frame)
            results.append(result)
            self.logger.debug('Criteria - %s: %s' %(criteria, result))
        if False in results:
            return NO_ACTION
        else: return self._action class Long(Action):
    """
    Long Action represents going long in the market.
    """
    def __init__(self):
        Action.__init__(self, 'long')
    def raw(self):
        """
        A raw (int) representation of the action.
        """
        return LONG class LongExit(Action):
    """
    Long Exit Action represents exiting a long position from the market.
    """
    def __init__(self):
        Action.__init__(self, 'longexit')
    def __eq__(self, other):
        other = str(other).replace(' ', '').replace('_', '').replace('-', '').lower()
        return other == 'longexit' or other == 'exitlong'
    def raw(self):
        """
        A raw (int) representation of the action.
        """
        return LONG_EXIT class TradingProfile(object):
    """
    Simple trading profile object that holds information pertraining to a
    user's trading resources and constraints in the market.
    """
    def __init__(self, capital, trading_amount, trading_fee, slippage=0.0):
        self.capital = capital
        self.trading_amount = trading_amount
        self.trading_fee = trading_fee
        self.slippage = slippage
        self.logger = logger.Logger(self.__class__.__name__)
        self.logger.info('Initialized - %s' %self)
    def __str__(self):
        return 'TradingProfile(capital=%s, trading_amount=%s, trading_fee=%s, slippage=%s' \
                              %(self.capital, self.trading_amount, self.trading_fee, self.slippage)
    def __repr__(self):
        return 'TradingProfile(capital=%s, trading_amount=%s, trading_fee=%s, slippage=%s' \
                              %(self.capital, self.trading_amount, self.trading_fee, self.slippage) class StaticAmount(TradingAmount):
    """
    A TradingAmount that always returns the number of shares to most closely
    approximate a certain amount in dollars to be put in a trade.
    """
    def __init__(self, amount, round_up=False):
        TradingAmount.__init__(self)
        self.amount = amount
        self.round_up = round_up
        self.logger.info('Initialized - %s' %self)
    def __str__(self):
        return 'StaticAmount(amount=%s, round_up=%s)' %(self.amount, self.round_up)
    def __repr__(self):
        return 'StaticAmount(amount=%s, round_up=%s)' %(self.amount, self.round_up)
    def get_shares(self, price, available_money): # pylint: disable=unused-argument
        """
        Return the number of shares to purchase based on the current symbol
        price and the amount of capital available to your trading profile.
        """
        if self.round_up:
            shares = ceil(self.amount / price)
        else:
            shares = round(self.amount / price)
        return shares class StaticFee(TradingFee):
    """
    The StaticFee simply applies the same static fee to all entry/exit trades.
    """
    def __init__(self, fee):
        TradingFee.__init__(self)
        self.fee = fee
        self.logger.info('Initialized - %s' %self)
    def __str__(self):
        return 'StaticFee(fee=%s)' %self.fee
    def __repr__(self):
        return 'StaticFee(fee=%s)' %self.fee
    def get_fee(self, price, shares): # pylint: disable=unused-argument
        """
        Given a symbol price and the amount of shares purchased, this method
        will return the fees incurred for the trade.
        """
        return self.fee class Strategy(object):
    """
    All strategies perform the enter and exit actions on the OPEN of the bar.
    On every day, criterias are checked, and actions are queued up for the next
    open. This prevents lookahead bias.
    """
    def __init__(self, dataset, criteria_groups, trading_profile):
        self.dataset = dataset
        self.criteria_groups = criteria_groups
        self.trading_profile = trading_profile
        self.name = 'Strategy'
        self.report = report.Report(self, self.trading_profile)
        self.realtime_data_frame = pd.DataFrame() # Used for backtesting
        self.first_pass = True # Flag to execute certain actions on first bar of backtest
        self.upcoming_actions = {}
        self.logger = logger.Logger(self.__class__.__name__)
        self.logger.info('Initialized - %s' %self)

    def __str__(self):
        return 'Strategy(dataset=%s, criteria_groups=%s, trading_profile=%s)' \
                %(self.dataset, self.criteria_groups, self.trading_profile)
    def __repr__(self):
        return 'Strategy(dataset=%s, criteria_groups=%s, trading_profile=%s)' \
                %(self.dataset, self.criteria_groups, self.trading_profile)

    def simulate(self):
        """
        The entry point to start the strategy simulation.
        """
        self.logger.info('Simulating strategy...')
        self.realtime_data_frame = pd.DataFrame()
        for row_data in self.dataset.data_frame.iterrows():
            data = row_data[1].to_frame().T
            self.process_new_data(data)

    def process_new_data(self, data):
        """
        Here we're assuming the data parameter holds all the symbol data
        we'll need for the whole time slice.
        @type data: pandas.DataFrame
        @param data: Needs to have at least the OHLC for the new time slice
        of data. There is no limit as to how many time slices of data can be
        contained in data. However, more data means more computationally
        intensive.
        """
        self.logger.debug(data.index[-1])
        self.realtime_data_frame = self.realtime_data_frame.combine_first(data)
        # Process Standard Metrics
        for symbol in self.dataset.symbol_list:
            if self.first_pass:
                self._create_actions_status_columns(self.realtime_data_frame, symbol)
            # Add previous action and status to dataset
            # Keep track of market actions for each symbol
            try:
                self.realtime_data_frame['ACTIONS_%s' %symbol][-1] = self.upcoming_actions[symbol]
            except KeyError:
                self.realtime_data_frame['ACTIONS_%s' %symbol][-1] = NO_ACTION
            # Keep track of market position for each symbol
            self.realtime_data_frame['STATUS_%s' %symbol][-1] = self._get_status(symbol)
            # Update the PL's
            self.report.add_preprocess_metrics(str(symbol), self.realtime_data_frame)
            # Update Report
            self.report.handle_action(symbol, self.realtime_data_frame)
        self.first_pass = False
        # Process criteria
        cg_data = {}
        for crit_group in self.criteria_groups:
            if crit_group.symbol not in cg_data:
                cg_data[crit_group.symbol] = []
            cg_result = crit_group.get_result(self.realtime_data_frame)
            cg_data[crit_group.symbol].append(cg_result)
        self.logger.debug('Criteria Group Data: %s' %cg_data)
        # Determine action based on all criteria group results
        for symbol in cg_data:
            symbol_action = self._determine_action(cg_data[symbol])
            self.logger.debug('Upcoming Action for %s: %s' %(symbol, symbol_action))
            # Do the action on the Open of the next bar
            self.upcoming_actions[symbol] = symbol_action
        self.logger.debug('New data:\n%s' %self.realtime_data_frame.tail(1).to_string())

    def get_next_action(self):
        """
        Estimated shares and money required is based on the Close of the last bar.
        The action should always be executed on the Open of the next bar.
        """
        actions = {}
        for symbol in self.upcoming_actions:
            action = self.upcoming_actions[symbol]
            estimated_enter_value = self.realtime_data_frame['%s_Open' %symbol][-1]
            estimated_shares = self.trading_profile.trading_amount.get_shares(\
                               estimated_enter_value, self.report.available_money)
            actions[symbol] = {'action': action,
                               'action_name': ACTIONS_MAP[action],
                               'enter_on': 'OPEN',
                               'estimated_enter_value': estimated_enter_value,
                               'estimated_shares': estimated_shares,
                               'estimated_fees': self.trading_profile.trading_fee.get_fee(\
                                                 estimated_enter_value, estimated_shares),
                               'estimated_money_required': estimated_enter_value * estimated_shares}
        return actions

    def _determine_action(self, values):
        """
        Handles any conflicting actions based on multiple criteria groups.
        """
        # Can supply a pd.Series or a list
        try:
            values = values.values
        except AttributeError:
            pass
        if LONG in values and SHORT in values or \
           LONG_EXIT in values and SHORT_EXIT in values:
            return NO_ACTION
        if LONG_EXIT in values:
            return LONG_EXIT
        if SHORT_EXIT in values:
            return SHORT_EXIT
        if LONG in values:
            return LONG
        if SHORT in values:
            return SHORT
        return NO_ACTION

    def _get_status(self, symbol):
        """
        Helper method to get the current symbol status based the last action.
        """
        action = self.realtime_data_frame['ACTIONS_%s' %symbol][-1]
        # Replace SHORT with -1 and SHORT_EXIT with 1
        if action == SHORT:
            action = -1
        elif action == SHORT_EXIT:
            action = 1
        if len(self.realtime_data_frame) < 2:
            return action
        else:
            return self.realtime_data_frame['STATUS_%s' %symbol][-2] + action

    def _create_actions_status_columns(self, data_frame, symbol):
        """
        Helper method to create the symbol's actions and status column in
        the data_frame.
        """
        cols = data_frame.columns
        try:
            cols.get_loc('ACTIONS_%s' %symbol)
        except KeyError:
            data_frame['ACTIONS_%s' %symbol] = NO_ACTION
        try:
            cols.get_loc('STATUS_%s' %symbol)
        except KeyError:
            data_frame['STATUS_%s' %symbol] = NO_ACTION class Figure(object):
    """
    @param dataset: A Dataset or Strategy object.
    """
    def __init__(self, dataset, rows=1, grid=True):
        # We need to handle a strategy being passed
        if isinstance(dataset, strategy.Strategy):
            self.strategy = dataset
            self.data_frame = self.strategy.dataset.data_frame
            self.realtime_data_frame = dataset.realtime_data_frame
        else: # Assume a dataset was passed
            self.strategy = None
            self.data_frame = dataset.data_frame
            self.realtime_data_frame = None
        self.data_frame.reset_index(inplace=True)
        date_conversion = lambda date: date2num(date.to_pydatetime())
        self.data_frame['DATE'] = self.data_frame['Date'].apply(date_conversion)
        self.rows = rows
        if grid:
            plt.rc('axes', grid=True)
            plt.rc('grid', color='0.75', linestyle='-', linewidth='0.2')
        self.current_figure = None
        self.figure_first_ax = None
        self.figure_rows = 1
        self.legend = []
        self.legend_labels = []
        self.add_figure(self.rows)
        self.logger = logger.Logger(self.__class__.__name__)
        self.logger.info('dataset: %s  rows: %s  grid: %s' %(dataset, rows, grid))

    def add_figure(self, rows=1):
        """
        This function adds a figure to the plotting instance.
        """
        self.figure_rows = rows
        self.current_figure = plt.figure()
        self.current_figure.subplots_adjust(hspace=0)
        self.figure_first_ax = None

    def add_chart(self, technical_indicator, row=1, plot_type='line', color='blue'):
        """
        This function adds a chart to the current figure.
        """
        axes = self.current_figure.add_subplot(self.figure_rows,
                                               1,
                                               row,
                                               sharex=self.figure_first_ax)
        if self.figure_first_ax is None:
            self.figure_first_ax = axes
        try:
            # Only works with ScalarFormatter
            axes.ticklabel_format(style='plain')
        except AttributeError:
            # Ignore on error
            pass
        if isinstance(technical_indicator, symbol_list.Symbol): # Candlesticks
            axes.set_title(str(technical_indicator))
            axes.set_ylabel('Price')
            cols = ['DATE',
                    technical_indicator.open,
                    technical_indicator.close,
                    technical_indicator.high,
                    technical_indicator.low]
            candlestick_ochl(axes, self.data_frame[cols].values, colorup=u'g')
            self.add_actions(technical_indicator, axes)
        else:
            if not isinstance(technical_indicator, str):
                # Probably forgot to submit the TI value
                technical_indicator = technical_indicator.value
            values = self.data_frame[str(technical_indicator)]
            axes.set_title(technical_indicator)
            axes.set_ylabel('Value')
            if plot_type == 'line':
                line, = axes.plot(self.data_frame['DATE'], values, color=color)
                self.legend.append(line)
            else:
                bars = axes.bar(self.data_frame['DATE'], values, color=color, width=0.3)
                self.legend.append(bars)
            self.legend_labels.append(technical_indicator)
        axes.xaxis_date()
        axes.autoscale_view()

    def add_capital_chart(self, row=1, color='green'):
        """
        This helper method will add a capital history chart to the current
        figure.
        """
        assert self.strategy is not None, \
            'You must initialize this figure with a strategy to use this functionality'
        axes = self.current_figure.add_subplot(self.figure_rows,
                                               1,
                                               row,
                                               sharex=self.figure_first_ax)
        if self.figure_first_ax is None:
            self.figure_first_ax = axes
        try:
            # Only works with ScalarFormatter
            axes.ticklabel_format(style='plain')
        except AttributeError:
            # Ignore on error
            pass
        axes.set_title('Capital')
        axes.set_ylabel('Money')
        capital_history = self.strategy.report.available_capital_history
        dates = pd.Series(capital_history.index).apply(lambda date: date2num(date.to_pydatetime()))
        values = capital_history.fillna(method='ffill')
        line, = axes.plot(dates, values, color=color)
        self.legend.append(line)
        self.legend_labels.append('Capital')
        axes.xaxis_date()
        axes.autoscale_view()

    def plot(self):
        """
        Actually does the plotting/displaying of the new figure.
        """
        plt.legend(self.legend, self.legend_labels, loc=0, shadow=True, fancybox=True)
        plt.setp(plt.gca().get_xticklabels(), rotation=45, horizontalalignment='right')
        plt.setp([a.get_xticklabels() for a in self.current_figure.axes[:-1]], visible=False)
        #move_id = self.current_figure.canvas.mpl_connect('motion_notify_event', self.on_move)
        plt.show()
    def show(self):
        """
        Alias to plot().
        """
        self.plot()

    def add_actions(self, symbol, axes):
        """
        This function will take care of adding all entry/exit actions on
        the candlestick chart.
        """
        actions_label = 'ACTIONS_%s' %symbol
        if self.realtime_data_frame is None or \
           actions_label not in self.realtime_data_frame.columns:
            return
        actions = self.realtime_data_frame[actions_label]
        actions = actions[actions != 0]
        for datetime, action in actions.iteritems():
            row = self.data_frame.loc[self.data_frame['Date'] == datetime]
            enter_value = row['%s_Open' %symbol]
            exit_value = row['%s_Open' %symbol]
            if action == LONG:
                axes.annotate('Long', xy=(datetime, enter_value),
                              xytext=(datetime, enter_value + 0.1),
                              arrowprops=dict(facecolor='green'))
            elif action == LONG_EXIT:
                axes.annotate('LongExit', xy=(datetime, exit_value),
                              xytext=(datetime, exit_value + 0.1),
                              arrowprops=dict(facecolor='green'))
            elif action == SHORT:
                axes.annotate('Short', xy=(datetime, enter_value),
                              xytext=(datetime, enter_value + 0.1),
                              arrowprops=dict(facecolor='red'))
            elif action == SHORT_EXIT:
                axes.annotate('ShortExit', xy=(datetime, exit_value),
                              xytext=(datetime, exit_value + 0.1),
                              arrowprops=dict(facecolor='red'))

    #def on_move(self, event):
        #"""
        #@todo: Speed up annotations.
        #"""
        #ax = event.inaxes
        #if ax is not None:
            #date_ordinal = round(event.xdata)
            #if date_ordinal == self.currentDateOrdinal: return
            #self.current_date_ordinal = date_ordinal
            #for ax in self.labels:
                #if date_ordinal in self.labels[ax]:
                    #self.textObjects[ax].set_text(self.labels[ax][dateOrdinal])
            #event.canvas.draw()
import datetime
from nowtrade.symbol_list import StockList
from nowtrade.data_connection import YahooConnection
from nowtrade.dataset import Dataset
from nowtrade.technical_indicator import SMA
from nowtrade.criteria import CrossingAbove, TrailingStop
from nowtrade.criteria_group import CriteriaGroup
from nowtrade.action import Long, LongExit
from nowtrade.trading_profile import TradingProfile
from nowtrade.trading_amount import StaticAmount
from nowtrade.trading_fee import StaticFee
from nowtrade.strategy import Strategy
from nowtrade.figures import Figure

# This is a standard crossover strategy that we won't get into here
stocks = StockList(['GOOGL'])
googl = stocks.get('GOOGL')
start = datetime.datetime(2013, 01, 01)
end = datetime.datetime(2015, 01, 01)
stock_data = Dataset(stocks, YahooConnection(), start, end)
stock_data.load_data()
sma10 = SMA(googl.close, 10)
sma25 = SMA(googl.close, 25)
stock_data.add_technical_indicator(sma10)
stock_data.add_technical_indicator(sma25)
enter_crit_long = CrossingAbove(sma10, sma25)
exit_crit_long = TrailingStop(googl, 0.05, percent=True)
enter_crit_group = CriteriaGroup([enter_crit_long], Long(), googl)
exit_crit_group = CriteriaGroup([exit_crit_long], LongExit(), googl)

profile = TradingProfile(100000, StaticAmount(10000), StaticFee(5))