import datetime as dt
import pandas as pd
import util
import indicators
from RTLearner import RTLearner


class StrategyLearner(object):

    def __init__(self, verbose=False, impact=0.0, commission=0.0, testing=False):
        self.verbose = verbose
        self.impact = impact
        self.commission = commission
        self.testing = testing

    def _get_volume(self):
        """For reference."""
        volume_all = ut.get_data(syms, dates, colname="Volume")
        volume = volume_all[syms]  # only portfolio symbols
        # volume_SPY = volume_all['SPY']  # only SPY, for comparison later
        if self.verbose:
            print(volume)

    def _add_indicators(self, df, symbol):
        """Add indicators for learning to DataFrame."""
        df.drop(columns=["SPY"], inplace=True)
        indicators.macd(df, symbol)
        indicators.rsi(df, symbol)
        indicators.price_sma(df, symbol, [8])
        indicators.price_delta(df, symbol, 3)
        df.dropna(inplace=True)

    def addEvidence(self, symbol="IBM",
                    sd=dt.datetime(2008, 1, 1),
                    ed=dt.datetime(2009, 1, 1),
                    sv=10000):

        self.y_threshold = 0.2
        self.indicators = ['macd_diff', 'rsi', 'price_sma_8']
        df = util.get_data([symbol], pd.date_range(sd, ed))
        self._add_indicators(df, symbol)

        def classify_y(row):
            if row > self.y_threshold:
                return 1
            elif row < -self.y_threshold:
                return -1
            else:
                pass
            return 0

        def set_y_threshold(pct):
            if max(pct) < 0.2:
                self.y_threshold = 0.02

        self.learner = RTLearner(leaf_size = 5)
        # self.learner = BagLearner(RTLearner, 3, {'leaf_size': 5})
        data_x = df[self.indicators].to_numpy()
        pct = df['pct_3']

        # This is a hack to get a low enough buy/sell threshold for the
        # cyclic the test 'ML4T-220' where the max pct_3 is 0.0268.
        set_y_threshold(pct)
        y = pct.apply(classify_y)

        self.learner.addEvidence(data_x, y.to_numpy())
        return y

    def strat(self, data_y, orders):
        self.holding = 0

        def strat(row):
            y = int(data_y.loc[row.name][0])
            shares = 0
            if self.holding == 0 and y == 1:
                shares = 1000
            elif self.holding == -1000 and y == 1:
                shares = 2000
            elif self.holding == 0 and y == -1:
                shares = -1000
            elif self.holding == 1000 and y == -1:
                shares = -2000
            self.holding += shares
            return shares

        orders["Shares"] = orders.apply(strat, axis=1)

    def testPolicy(self, symbol="IBM",
                   sd=dt.datetime(2009, 1, 1),
                   ed=dt.datetime(2010, 1, 1),
                   sv=10000):
        df = util.get_data([symbol], pd.date_range(sd, ed))
        self._add_indicators(df, symbol)
        data_x = df[self.indicators].to_numpy()
        data_y = pd.DataFrame(index=df.index, data=self.learner.query(data_x))

        orders = pd.DataFrame(index=df.index)
        orders["Symbol"] = symbol
        orders["Order"] = ""
        orders["Shares"] = 0
        self.strat(data_y, orders)
        if self.testing:
            return orders
        else:
            return orders[["Shares"]]

