def discretize(self, symbol="IBM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 12, 31)): syms = [symbol] dates = pd.date_range(sd, ed) indicator_dates = pd.date_range(sd - dt.timedelta(days=28), ed) prices_all = ut.get_data(syms, dates) # automatically adds SPY prices = prices_all[syms] # only portfolio symbols indicator_prices_all = ut.get_data( syms, indicator_dates ) #will this be the same size as the number of days traded? indicator_prices = indicator_prices_all[syms] prices_SPY = prices_all["SPY"] # only SPY, for comparison later #get 3 indicators using passed in start date minus window required for each rm = ind.get_rolling_mean(indicator_prices[symbol], window=20) percent_bb = ind.get_rolling_std(indicator_prices[symbol], window=20) #aka rstd upper_band, lower_band = ind.get_bollinger_bands(rm, percent_bb) percent_bb = percent_bb.iloc[19:] rm = rm.iloc[19:] upper_band = upper_band.iloc[19:] lower_band = lower_band.iloc[19:] for x in range(rm.size): #did i format that right?? #print(prices.iloc[x]) #print(type(rm.iloc[x])) if (prices.iloc[x][0] == rm.iloc[x]): percent_bb.iloc[x] = 0.0 elif (prices.iloc[x][0] > rm.iloc[x]): percent_bb.iloc[x] = (prices.iloc[x][0] - rm.iloc[x]) / ( upper_band.iloc[x] - rm.iloc[x]) elif (prices.iloc[x][0] < rm.iloc[x]): percent_bb.iloc[x] = (rm.iloc[x] - prices.iloc[x][0]) / ( lower_band.iloc[x] - rm.iloc[x]) percent_bb = pd.Series(percent_bb) #print(percent_bb) indicator_prices = indicator_prices.iloc[9:] #print(indicator_prices) momentum = pd.Series( ind.get_momentum(indicator_prices[symbol], window=10)) momentum = momentum.iloc[10:] #print(momentum) volatility = pd.Series( ind.get_volatility(indicator_prices[symbol], window=10)) volatility = volatility.iloc[10:] #print(volatility.values.shape) uglystupidnobodylikesyouvol, vol = pd.qcut(volatility.values, 10, retbins=True) esrfergs, momnt = pd.qcut(momentum.values, 10, retbins=True) rgefsegrf, bb = pd.qcut(percent_bb.values, 10, retbins=True) vol = vol[1:-1] momnt = momnt[1:-1] bb = bb[1:-1] return vol, momnt, bb
def get_features(self, prices): """Compute technical indicators and use them as features to be fed into a Q-learner. Parameters: prices: Adjusted close prices of the given symbol Returns: df_features: A pandas dataframe of the technical indicators """ window = 10 # Compute rolling mean rolling_mean = prices.rolling(window=window).mean() # Compute_rolling_std rolling_std = prices.rolling(window=window).std() # Compute momentum momentum = get_momentum(prices, window) # Compute SMA indicator sma_indicator = get_sma_indicator(prices, rolling_mean) # Compute Bollinger value bollinger_val = compute_bollinger_value(prices, rolling_mean, rolling_std) # Create a dataframe with three features df_features = pd.concat([momentum, sma_indicator], axis=1) df_features = pd.concat([df_features, bollinger_val], axis=1) df_features.columns = ["ind{}".format(i) for i in range(len(df_features.columns))] df_features.dropna(inplace=True) return df_features
def get_features(self, prices): """ Compute the technical features of a position and feed that into the Q-Learning process TODO: Try different parameters to see if you can improve the portfolio Try out different window sizes (right now set to 10 trading days) prices: Adjusted close prices of the given symbol df_features: A pandas dataframe of the technical indicators """ rolling_mean = prices.rolling(window=self.window_size).mean() rolling_std = prices.rolling(window=self.window_size).std() momentum = get_momentum(prices, self.window_size) sma_indicator = get_sma_indicator(prices, rolling_mean) bollinger_val = compute_bollinger_value(prices, rolling_mean, rolling_std) df_features = pd.concat([momentum, sma_indicator], axis=1) df_features = pd.concat([df_features, bollinger_val], axis=1) df_features.columns = ["ind{}".format(i) for i in range(len(df_features.columns))] # Perhaps you can come up with a different feature? # Try it! df_features.dropna(inplace=True) return df_features
def testPolicy(self, symbol="JPM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 1, 31), sv=100000): df_prices = get_data([symbol], pd.date_range(sd, ed)).ffill().bfill() df_prices_symbol = df_prices[[symbol]] momentum = get_momentum(df_prices_symbol) sma_r = get_sma_r(df_prices_symbol) bbp = get_bbp(df_prices_symbol) df_trades = df_prices_symbol.copy() df_trades[symbol] = 0 impact = 0.005 commission = 9.95 current_holding = 0 for i in range(df_prices_symbol.shape[0] - 1): price = df_prices_symbol.iloc[i, 0] sign = 0 if (bbp.iloc[i, 0] <= 0.6 and sma_r.iloc[i, 0] < 1) or \ (sma_r.iloc[i, 0] < 1 and momentum.iloc[i, 0] > 0.1) or \ (bbp.iloc[i, 0] <= 0.6 and momentum.iloc[i, 0] > 0.1): sign = 1 price = price * (1 + impact * sign) if (bbp.iloc[i, 0] >= 0.8 and sma_r.iloc[i, 0] > 1) or \ (sma_r.iloc[i, 0] > 1 and momentum.iloc[i, 0] < 0) or \ (bbp.iloc[i, 0] >= 0.8 and momentum.iloc[i, 0] < 0): sign = -1 price = price * (1 + impact * sign) if sign != 0: if current_holding == 0: sv -= commission sv = sv - price * 1000 * sign current_holding = 1000 * sign df_trades.iloc[i, 0] = 1000 * sign elif current_holding == -1000 * sign: sv -= commission sv = sv - price * 2000 * sign current_holding = 1000 * sign df_trades.iloc[i, 0] = 2000 * sign else: pass df_trades.index.names = ['Date'] df_trades.columns = ['Shares'] df_trades["Symbol"] = "JPM" df_trades["Order"] = [ "BUY" if x > 0 else "SELL" if x < 0 else "NA" for x in df_trades['Shares'] ] df_trades.drop(df_trades[df_trades['Shares'] == 0].index, inplace=True) df_trades['Shares'] = df_trades['Shares'].abs() df_trades = df_trades.reindex(columns=['Symbol', 'Order', 'Shares']) return df_trades
def testPolicy(self, symbol = "IBM", \ sd=dt.datetime(2009,1,1), \ ed=dt.datetime(2010,1,1), \ sv = 10000): syms = [symbol] # here we build a fake set of trades # your code should return the same sort of data syms = [symbol] dates = pd.date_range(sd, ed) prices, prices_SPY = id.get_price(syms, dates) if self.verbose: print prices daily_returns = (prices / prices.shift(1)) - 1 daily_returns = daily_returns[1:] # get indicators and combine them into as a feature data_frame lookback = 14 _, PSR = id.get_SMA(prices, lookback) _, _, bb_indicator = id.get_BB(prices, lookback) momentum = id.get_momentum(prices, lookback) indices = prices.index holdings = pd.DataFrame(np.nan, index=indices, columns=['Holdings']) holdings.iloc[0] = 0 for i in range(1, daily_returns.shape[0]): state = self.indicators_to_state(PSR.iloc[i], bb_indicator.iloc[i], momentum.iloc[i]) # Get action by Query learner with current state and reward to get action action = self.learner.querysetstate(state) #print("SL 286 action is ", action) # Get holdings with the new action. holdings.iloc[i], _ = self.apply_action(holdings.iloc[i - 1][0], action, 0) holdings.ffill(inplace=True) holdings.fillna(0, inplace=True) trades = holdings.diff() trades.iloc[0] = 0 # buy and sell happens when the difference change direction df_trades = pd.DataFrame(data=trades.values, index=trades.index, columns=['Trades']) #print("293: ", df_trades) if self.verbose: print type(df_trades) # it better be a DataFrame! if self.verbose: print trades if self.verbose: print prices return df_trades
def addEvidence(self, symbol = "IBM", \ sd=dt.datetime(2008,1,1), \ ed=dt.datetime(2009,1,1), \ sv = 10000): # add your code to do learning here # example usage of the old backward compatible util function syms = [symbol] dates = pd.date_range(sd, ed) prices_all = ut.get_data(syms, dates) # automatically adds SPY prices = prices_all[syms] # only portfolio symbols prices_SPY = prices_all['SPY'] # only SPY, for comparison later if self.verbose: print prices # example use with new colname volume_all = ut.get_data(syms, dates, colname="Volume") # automatically adds SPY volume = volume_all[syms] # only portfolio symbols volume_SPY = volume_all['SPY'] # only SPY, for comparison later if self.verbose: print volume bb_val, upper, lower, rm, rs = get_bb(prices) sma = get_sma(prices) mom = get_momentum(prices) x_train = np.zeros(shape=(len(prices), 7)) for i in range(20, len(prices) - self.N): x_train[i][0] = bb_val[i] x_train[i][1] = upper[i] x_train[i][2] = lower[i] x_train[i][3] = rm[i] x_train[i][4] = rs[i] x_train[i][5] = sma[i] x_train[i][6] = mom[i] x_train = pd.DataFrame(x_train) x_train = x_train[:-self.N] x_train.fillna(0, inplace=True) x_train = x_train.values y = [] for i in range(0, len(prices) - self.N): if (prices.ix[i + self.N, symbol] / prices.ix[i, symbol]) > 1.0009 + self.impact: y.append(1) elif (prices.ix[i + self.N, symbol] / prices.ix[i, symbol]) < 0.9991 - self.impact: y.append(-1) else: y.append(0) y_train = np.array(y) #print y_train self.learner.addEvidence(x_train, y_train)
def trading_strategy(self, sym_price): """Create a dataframe of order signals that maximizes portfolio's return. This function has been optimized for the symbol and training period in the main function Parameters: sym_price: The price series of a stock symbol of interest Returns: df_order_signals: A series that contains 1 for buy, 0 for hold and -1 for sell """ # Get momentum indicator and generate signals momentum = get_momentum(sym_price, 40) mom_signal = -1 * (momentum < -0.07) + 1 * (momentum > 0.14) # Get RSI indicator and generate signals rsi_indicator = get_RSI(sym_price) rsi_signal = 1 * (rsi_indicator < 50) + -1 * (rsi_indicator > 50) # Get SMA indicator and generate signals sma_indicator = get_sma_indicator(sym_price, sym_price.rolling(window=30).mean()) sma_signal = 1 * (sma_indicator < 0.0) + -1 * (sma_indicator > 0.0) # Combine individual signals signal = 1 * ((sma_signal == 1) & (rsi_signal == 1) & (mom_signal == 1)) \ + -1 * ((sma_signal == -1) & (rsi_signal == -1) & (mom_signal == -1)) # Create an order series with 0 as default values self.df_order_signals = signal * 0 # Keep track of net signals which are constrained to -1, 0, and 1 net_signals = 0 for date in self.df_order_signals.index: net_signals = self.df_order_signals.loc[:date].sum() # If net_signals is not long and signal is to buy if (net_signals < 1) and (signal.loc[date] == 1): self.df_order_signals.loc[date] = 1 # If net_signals is not short and signal is to sell elif (net_signals > -1) and (signal.loc[date] == -1): self.df_order_signals.loc[date] = -1 # On the last day, close any open positions if self.df_order_signals.sum() == -1: self.df_order_signals[-1] = 1 elif self.df_order_signals.sum() == 1: self.df_order_signals[-1] = -1 return self.df_order_signals
def testPolicyMomentum(n_days_bb=20, n_days_mtum=20, n_days_std=20, tresh_bb=1, tresh_mmtum=0.2, tresh_std_low=1, tresh_std_high=1, symbol="JPM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 12, 31), sv=100000): df_prices_all = get_data([symbol], pd.date_range(sd, ed)) df_prices = df_prices_all[symbol] df_trades = pd.DataFrame(data=np.zeros(len(df_prices)), index=df_prices.index, columns=['trades']) rstd = idc.get_rolling_stdev( pd.DataFrame(df_prices, index=df_prices.index, columns=[symbol]), n_days_std) bband = idc.get_bbands( pd.DataFrame(df_prices, index=df_prices.index, columns=[symbol]), n_days_bb) momentum = idc.get_momentum( pd.DataFrame(df_prices, index=df_prices.index, columns=[symbol]), n_days_mtum) abs_momentum = momentum.abs() # use momentum to confirm sell & buy signal: # confirmed if small enough momentum # (changes in prices is slowing - time to take action) for t in range(1, len(df_prices)): df_net_holdings = df_trades.cumsum(axis=0) net_holdings = df_net_holdings.values[t] if (net_holdings > 1000) | (net_holdings < -1000): print("ERROR") #if rstd[t] >= tresh_std: # buy signal if (bband[t - 1] <= -tresh_bb) & (bband[t] > -tresh_bb): if (abs_momentum[t] <= tresh_mmtum): if (net_holdings == 0): df_trades.iloc[t] = 1000 elif (net_holdings == -1000): df_trades.iloc[t] = 2000 # sell signal if (bband[t - 1] >= tresh_bb) & (bband[t] < tresh_bb): if (abs_momentum[t] <= tresh_mmtum): if (net_holdings == 0): df_trades.iloc[t] = -1000 elif (net_holdings == 1000): df_trades.iloc[t] = -2000 return df_trades, momentum
def testPolicy(self, symbol, sd, ed, sv=100000): # this policy is like this: buy when the price will go up the next day, sell when the price will do down the next day # get price data dates = pd.date_range(sd, ed) prices_all = get_data([symbol], dates, addSPY=True, colname='Adj Close') prices = prices_all[symbol] # only portfolio symbols # get indicators lookback = 14 _, PSR = id.get_SMA(prices, lookback) _, _, bb_indicator = id.get_BB(prices, lookback) momentum = id.get_momentum(prices, lookback) holdings = pd.DataFrame(np.nan, index=prices.index, columns=['Holdings']) # make sure when PSR (= price / SMA -1) >0.05 and bb_indicator > 1 and momentum > 0.05 SELL or hold -1000 # when PSR (= price / SMA -1) < -0.05 and bb_indicator < -1 and momentum < -0.05 Buy or hold -1000 #print("PSR: ", PSR) #print("momentum: ", momentum) #print("bb_indicator: ", bb_indicator) for t in range(prices.shape[0]): if PSR.iloc[t] < -0.02 and bb_indicator.iloc[ t] < -0.8 and momentum.iloc[t] < -0.03: holdings.iloc[t] = 1000 elif PSR.iloc[t] > 0.02 and bb_indicator.iloc[ t] > 0.8 and momentum.iloc[t] > 0.03: holdings.iloc[t] = -1000 # fill the NAN data holdings.ffill(inplace=True) holdings.fillna(0, inplace=True) trades = holdings.diff() trades.iloc[0] = 0 #trades.iloc[-1] = 0 #trades.columns = 'Trades' # buy and sell happens when the difference change direction df_trades = pd.DataFrame(data=trades.values, index=trades.index, columns=['Trades']) return df_trades
def testPolicy(self, symbol="JPM", sd=dt.datetime(2010, 1, 1), ed=dt.datetime(2011, 12, 31), sv=100000): df_prices = ut.get_data([symbol], pd.date_range(sd, ed)).ffill().bfill() df_prices = df_prices[[symbol]] # Make indicators df indicator_details = df_prices.copy() indicator_details.drop([symbol], axis=1, inplace=True) indicator_details[self.momentum] = idc.get_momentum(df_prices) indicator_details[self.sma_ratio] = idc.get_sma_r(df_prices) indicator_details[self.bollinger_percent] = idc.get_bbp(df_prices) df_trades = df_prices.copy() df_trades[symbol] = 0 current_holding = 0 indicators = indicator_details.iloc[self.window - 1] s = self.serialize(indicators) a = self.learner.querysetstate(s) prices_len = df_prices.shape[0] for i in range(self.window, prices_len - 1): s = self.serialize(indicator_details.iloc[i]) if a == 1: pass elif a == 0 and current_holding == 0: current_holding = -1000 df_trades.iloc[i, 0] = current_holding elif a == 0 and current_holding == 1000: current_holding = -1000 df_trades.iloc[i, 0] = current_holding * 2 elif a == 2 and current_holding == 0: current_holding = 1000 df_trades.iloc[i, 0] = current_holding elif a == 2 and current_holding == -1000: current_holding = 1000 df_trades.iloc[i, 0] = current_holding * 2 a = self.learner.querysetstate(s) return df_trades
def buildIndicators(self, df_prices, symbol="IBM"): """ Build (panda Series) indicators from the prices dataframe @params df_prices: the prices dataframe @params symbol: the asset's symbol 5,10,20,30 """ # rolling bollinger band self.bband = idc.get_bbands(pd.DataFrame(df_prices, index=df_prices.index, columns=[symbol]), self.window_size, symbol=symbol).dropna() # fixing treshold for consistencies before normalization self.bband[self.bband < -1] = -1 self.bband[self.bband > 1] = 1 self.discretize_bband = self.normalizeIndicators(self.bband) # rolling momentum abs self.momentum = idc.get_momentum(pd.DataFrame(df_prices, index=df_prices.index, columns=[symbol]), self.window_size, symbol=symbol).dropna() self.momentum[self.momentum < -0.3] = -0.3 self.momentum[self.momentum > 0.3] = 0.3 self.discretize_momentum = self.normalizeIndicators(self.momentum) # rolling standard deviation self.rstd = pd.Series(pd.rolling_std(df_prices, window=2), name='rstd').dropna() self.rstd[self.rstd < 0.5] = 0.5 self.rstd[self.rstd > 4] = 4 self.discretize_rstd = self.normalizeIndicators(self.rstd) # rolling rsi self.rsi = idc.get_rsi(df_prices, self.window_size).dropna() self.rsi[self.rsi < 40] = 40 self.rsi[self.rsi > 70] = 70 self.discretize_rsi = self.normalizeIndicators(self.rsi) self.discretize_holding = {0: 0, -1000: 1, 1000: 2} self.n_states = int(3 * 10**4)
def prepare_indicators(self, symbol="JPM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 12, 31)): dates = pd.date_range(sd, ed) prices = ut.get_data([symbol], dates) prices.fillna(method='ffill', inplace=True) prices.fillna(method='bfill', inplace=True) prices = prices[[symbol]] indicators = prices.copy() indicators.drop([symbol], axis=1, inplace=True) indicators["momentum"] = ind.get_momentum(prices, self.window) indicators["sma_ratio"] = ind.get_SMA_ratio(prices, symbol, self.window) indicators["bollinger_value"] = ind.get_bollinger_band( prices, symbol, self.window) return prices, indicators
def testPolicy(symbol, sd, ed, sv): symbols = ['JPM'] dates = pd.date_range(sd, ed) benchmark = get_data(symbols, dates, addSPY=False).dropna() prices = benchmark['JPM'].values trades = pd.DataFrame(data=np.zeros(len(prices)), index=benchmark.index, columns=['JPM']) print benchmark sma = get_sma(benchmark) mom = get_momentum(benchmark) bbval, upper, lower, rolling_m, rolling_s = get_bb(benchmark) holding = 0 benchmark = pd.DataFrame({'Date': dt.datetime(2008, 1, 2), 'JPM': [1000]}) benchmark.set_index("Date", inplace=True) for i in range(12, len(prices)): if sma[i] < 0.95 and bbval[i] < 0: trades['JPM'].iloc[i] = 1000 - holding holding = 1000 elif sma[i] > 1.05 and bbval[i] > 1: trades['JPM'].iloc[i] = -holding - 1000 holding = -1000 return trades, benchmark
def get_features1(self, prices, symbol, print=False): ''' Compute technical indicators and use them as features to be fed into a Q-learner. :param: prices: Adj Close prices dataframe :param: Whether adding data for printing to dataframe or not :return: Normalize Features dataframe ''' # Fill NAN values if any prices.fillna(method="ffill", inplace=True) prices.fillna(method="bfill", inplace=True) prices.fillna(1.0, inplace=True) # Price adj_close = prices[symbol] # Compute Momentum mom = get_momentum(adj_close, window=10) # Compute RSI rsi = get_RSI(adj_close) # Compute rolling mean rm = get_rolling_mean(adj_close, window=10) # Compute rolling standard deviation rstd = get_rolling_std(adj_close, window=10) # Compute upper and lower bands upper_band, lower_band = get_bollinger_bands(rm, rstd) # Compute SMA sma = get_sma_indicator(adj_close, rm) df = prices.copy() df['Momentum'] = mom df['Adj. Close/SMA'] = adj_close/sma df['middle_band'] = rm # Delete 'Adj Close' column del df[symbol] if set(['cash']).issubset(df.columns): del df['cash'] # Normalize dataframe df_norm = normalize_data(df) # Add Adj Close, Bollinrt Bands and RSY if printing if print: df_norm['Adj Close'] = prices[symbol] df_norm['upper_band'] = upper_band df_norm['lower_band'] = lower_band df_norm['middle_band'] = rm df_norm['RSI'] = rsi # Drop NaN df_norm.dropna(inplace=True) return df_norm
def testPolicy(self, symbol="JPM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 1, 31), sv=100000): # get data dates = pd.date_range(sd, ed) prices_all = get_data([symbol], dates) # automatically adds SPY prices_all.fillna(method='ffill', inplace=True) prices_all.fillna(method='bfill', inplace=True) prices = prices_all[[symbol]] prices_SPY = prices_all['SPY'] lookback = 7 momentum = get_momentum(prices, lookback=lookback) sma_r = get_sma_r(prices, lookback=lookback) bbp = get_bbp(prices, lookback=lookback) commission = 9.95 impact = 0.005 holding = 0 cash = sv #print(bbp) df_trades = prices.copy() df_trades[symbol] = 0 for i in range(lookback - 1, prices.shape[0] - 1): price = prices.iloc[i, 0] # BUY if (bbp.iloc[i,0] <= 0.6 and sma_r.iloc[i,0] < 1) or \ (sma_r.iloc[i,0] < 1 and momentum.iloc[i,0] > 0.1) or \ (bbp.iloc[i,0] <= 0.6 and momentum.iloc[i,0] > 0.1): price = price * (1 + impact) if holding == 0: cash = cash - price * 1000 - commission holding = 1000 df_trades.iloc[i, 0] = 1000 elif holding == -1000: cash = cash - price * 2000 - commission holding = 1000 df_trades.iloc[i, 0] = 2000 else: pass # SELL elif (bbp.iloc[i,0] >= 0.8 and sma_r.iloc[i,0] > 1) or \ (sma_r.iloc[i,0] > 1 and momentum.iloc[i,0] < 0) or \ (bbp.iloc[i,0] >= 0.8 and momentum.iloc[i,0] < 0): price = price * (1 - impact) if holding == 0: cash = cash + price * 1000 - commission holding = -1000 df_trades.iloc[i, 0] = -1000 elif holding == 1000: cash = cash + price * 2000 - commission holding = -1000 df_trades.iloc[i, 0] = -2000 else: pass else: pass return df_trades
def experiment1(): ms = ManualStrategy.ManualStrategy() sl = StrategyLearner.StrategyLearner() commission = 9.95 impact = 0.005 # in sample start_date = dt.datetime(2008, 1, 1) end_date = dt.datetime(2009, 12, 31) # dates = pd.date_range(start_date, end_date) symbol = 'JPM' sl.addEvidence(symbol=symbol, sd=start_date, ed=end_date, sv=100000, n_bins=5) df_trades_ms = ms.testPolicy(symbol=symbol, sd=start_date, ed=end_date, sv=100000) df_trades_sl = sl.testPolicy(symbol=symbol, sd=start_date, ed=end_date, sv=100000) # generate orders based on trades df_orders_ms, benchmark_orders = ManualStrategy.generate_orders( df_trades_ms, symbol) df_orders_sl, _ = ManualStrategy.generate_orders(df_trades_sl, symbol) port_vals_ms = ManualStrategy.compute_portvals(df_orders_ms, start_val=100000, sd=start_date, ed=end_date, commission=commission, impact=impact) port_vals_sl = ManualStrategy.compute_portvals(df_orders_sl, start_val=100000, sd=start_date, ed=end_date, commission=commission, impact=impact) #benchmark_orders.loc[benchmark_orders.index[1], 'Shares'] = 0 benchmark_vals = ManualStrategy.compute_portvals(benchmark_orders, sd=start_date, ed=end_date, start_val=100000, commission=commission, impact=impact) normed_port_ms = port_vals_ms / port_vals_ms.ix[0] normed_port_sl = port_vals_sl / port_vals_sl.ix[0] normed_bench = benchmark_vals / benchmark_vals.ix[0] dates = pd.date_range(start_date, end_date) prices_all = get_data([symbol], dates, addSPY=True, colname='Adj Close') prices = prices_all[symbol] # only portfolio symbols # get indicators lookback = 14 _, PSR = id.get_SMA(prices, lookback) _, _, bb_indicator = id.get_BB(prices, lookback) momentum = id.get_momentum(prices, lookback) # figure 5. plt.figure(figsize=(12, 6.5)) top = plt.subplot2grid((5, 1), (0, 0), rowspan=3, colspan=1) bottom = plt.subplot2grid((5, 1), (3, 0), rowspan=2, colspan=1, sharex=top) # plot the Long or short action for index, marks in df_trades_sl.iterrows(): if marks['Trades'] > 0: plt.axvline(x=index, color='blue', linestyle='dashed', alpha=.9) elif marks['Trades'] < 0: plt.axvline(x=index, color='black', linestyle='dashed', alpha=.9) else: pass top.xaxis_date() top.grid(True) top.plot(normed_port_sl, lw=2, color='red', label='Q-Learning Strategy') top.plot(normed_port_ms, lw=1.5, color='black', label='Manual Strategy') top.plot(normed_bench, lw=1.2, color='green', label='Benchmark') top.set_title( 'Machine Learning Strategy (MLS), Manual Strategy (MS) - In Sample Analysis' ) top.set_ylabel('Normalized Value') for index, marks in df_trades_sl.iterrows(): if marks['Trades'] > 0: top.axvline(x=index, color='blue', linestyle='dashed', alpha=.9) elif marks['Trades'] < 0: top.axvline(x=index, color='black', linestyle='dashed', alpha=.9) else: pass bottom.plot(momentum, color='olive', lw=1, label="momentum") bottom.plot(PSR, color='purple', lw=1, label="PSR") #bottom.plot(bb_indicator, color='blue', lw=1, label="Bollinger") bottom.set_title('Indicators') bottom.axhline(y=-0.2, color='grey', linestyle='--', alpha=0.5) bottom.axhline(y=0, color='grey', linestyle='--', alpha=0.5) bottom.axhline(y=0.2, color='grey', linestyle='--', alpha=0.5) bottom.legend() top.legend() top.axes.get_xaxis().set_visible(False) plt.xlim(start_date, end_date) filename = '01_MLS_insample.png' plt.savefig(filename) plt.close() port_cr_sl, port_adr_sl, port_stddr_sl, port_sr_sl = ManualStrategy.get_portfolio_stats( port_vals_sl) port_cr_ms, port_adr_ms, port_stddr_ms, port_sr_ms = ManualStrategy.get_portfolio_stats( port_vals_ms) bench_cr, bench_adr, bench_stddr, bench_sr = ManualStrategy.get_portfolio_stats( benchmark_vals) # Compare portfolio against benchmark print "=== Machine Learning Strategy (MLS) V.S. Manual Strategy (MS) In Sample ===" print "Date Range: {} to {}".format(start_date, end_date) print print "Sharpe Ratio of MLS: {}".format(port_sr_sl) print "Sharpe Ratio of MS: {}".format(port_sr_ms) print "Sharpe Ratio of BenchMark : {}".format(bench_sr) print print "Cumulative Return of MLS: {}".format(port_cr_sl) print "Cumulative Return of MS: {}".format(port_cr_ms) print "Cumulative Return of Benchmark : {}".format(bench_cr) print print "Standard Deviation of MLS: {}".format(port_stddr_sl) print "Standard Deviation of MS: {}".format(port_stddr_ms) print "Standard Deviation of Benchmark : {}".format(bench_stddr) print print "Average Daily Return of MLS: {}".format(port_adr_sl) print "Average Daily Return of MS: {}".format(port_adr_ms) print "Average Daily Return of BenchMark : {}".format(bench_adr) print print "Final MLS Portfolio Value: {}".format(port_vals_sl[-1]) print "Final MS Portfolio Value: {}".format(port_vals_ms[-1]) print "Final Benchmark Portfolio Value: {}".format(benchmark_vals[-1]) print # ======================== # OUT OF SAMPLE Analysis # ======================== start_date = dt.datetime(2010, 1, 1) end_date = dt.datetime(2011, 12, 31) # dates = pd.date_range(start_date, end_date) symbol = 'JPM' df_trades_ms = ms.testPolicy(symbol=symbol, sd=start_date, ed=end_date, sv=100000) df_trades_sl = sl.testPolicy(symbol=symbol, sd=start_date, ed=end_date, sv=100000) # generate orders based on trades df_orders_ms, benchmark_orders = ManualStrategy.generate_orders( df_trades_ms, symbol) df_orders_sl, _ = ManualStrategy.generate_orders(df_trades_sl, symbol) port_vals_ms = ManualStrategy.compute_portvals(df_orders_ms, start_val=100000, sd=start_date, ed=end_date, commission=commission, impact=impact) port_vals_sl = ManualStrategy.compute_portvals(df_orders_sl, start_val=100000, sd=start_date, ed=end_date, commission=commission, impact=impact) #benchmark_orders.loc[benchmark_orders.index[1], 'Shares'] = 0 benchmark_vals = ManualStrategy.compute_portvals(benchmark_orders, sd=start_date, ed=end_date, start_val=100000, commission=commission, impact=impact) normed_port_ms = port_vals_ms / port_vals_ms.ix[0] normed_port_sl = port_vals_sl / port_vals_sl.ix[0] normed_bench = benchmark_vals / benchmark_vals.ix[0] dates = pd.date_range(start_date, end_date) prices_all = get_data([symbol], dates, addSPY=True, colname='Adj Close') prices = prices_all[symbol] # only portfolio symbols # get indicators lookback = 14 _, PSR = id.get_SMA(prices, lookback) _, _, bb_indicator = id.get_BB(prices, lookback) momentum = id.get_momentum(prices, lookback) # figure 5. plt.figure(figsize=(12, 6.5)) top = plt.subplot2grid((5, 1), (0, 0), rowspan=3, colspan=1) bottom = plt.subplot2grid((5, 1), (3, 0), rowspan=2, colspan=1, sharex=top) # plot the Long or short action for index, marks in df_trades_sl.iterrows(): if marks['Trades'] > 0: plt.axvline(x=index, color='blue', linestyle='dashed', alpha=.9) elif marks['Trades'] < 0: plt.axvline(x=index, color='black', linestyle='dashed', alpha=.9) else: pass top.xaxis_date() top.grid(True) top.plot(normed_port_sl, lw=2, color='red', label='Q-Learning Strategy') top.plot(normed_port_ms, lw=1.5, color='black', label='Manual Strategy') top.plot(normed_bench, lw=1.2, color='green', label='Benchmark') top.set_title( 'Machine Learning Strategy (MLS) V.S. Manual Strategy (MS) - Out Sample Analysis' ) top.set_ylabel('Normalized Value') for index, marks in df_trades_sl.iterrows(): if marks['Trades'] > 0: top.axvline(x=index, color='blue', linestyle='dashed', alpha=.9) elif marks['Trades'] < 0: top.axvline(x=index, color='black', linestyle='dashed', alpha=.9) else: pass bottom.plot(momentum, color='olive', lw=1, label="momentum") bottom.plot(PSR, color='purple', lw=1, label="PSR") #bottom.plot(bb_indicator, color='blue', lw=1, label="Bollinger") bottom.set_title('Indicators') bottom.axhline(y=-0.2, color='grey', linestyle='--', alpha=0.5) bottom.axhline(y=0, color='grey', linestyle='--', alpha=0.5) bottom.axhline(y=0.2, color='grey', linestyle='--', alpha=0.5) bottom.legend() top.legend() top.axes.get_xaxis().set_visible(False) plt.xlim(start_date, end_date) filename = '02_MLS_outsample.png' plt.savefig(filename) plt.close() port_cr_sl, port_adr_sl, port_stddr_sl, port_sr_sl = ManualStrategy.get_portfolio_stats( port_vals_sl) port_cr_ms, port_adr_ms, port_stddr_ms, port_sr_ms = ManualStrategy.get_portfolio_stats( port_vals_ms) bench_cr, bench_adr, bench_stddr, bench_sr = ManualStrategy.get_portfolio_stats( benchmark_vals) # Compare portfolio against benchmark print "=== Machine Learning Strategy (MLS) V.S. Manual Strategy (MS) OUT Sample ===" print "Date Range: {} to {}".format(start_date, end_date) print print "Sharpe Ratio of MLS: {}".format(port_sr_sl) print "Sharpe Ratio of MS: {}".format(port_sr_ms) print "Sharpe Ratio of BenchMark : {}".format(bench_sr) print print "Cumulative Return of MLS: {}".format(port_cr_sl) print "Cumulative Return of MS: {}".format(port_cr_ms) print "Cumulative Return of Benchmark : {}".format(bench_cr) print print "Standard Deviation of MLS: {}".format(port_stddr_sl) print "Standard Deviation of MS: {}".format(port_stddr_ms) print "Standard Deviation of Benchmark : {}".format(bench_stddr) print print "Average Daily Return of MLS: {}".format(port_adr_sl) print "Average Daily Return of MS: {}".format(port_adr_ms) print "Average Daily Return of BenchMark : {}".format(bench_adr) print print "Final MLS Portfolio Value: {}".format(port_vals_sl[-1]) print "Final MS Portfolio Value: {}".format(port_vals_ms[-1]) print "Final Benchmark Portfolio Value: {}".format(benchmark_vals[-1]) print
def testPolicy( self, symbol="IBM", sd=dt.datetime(2009, 1, 1), ed=dt.datetime(2010, 1, 1), sv=10000, ): """ Tests your learner using data outside of the training data :param symbol: The stock symbol that you trained on on :type symbol: str :param sd: A datetime object that represents the start date, defaults to 1/1/2008 :type sd: datetime :param ed: A datetime object that represents the end date, defaults to 1/1/2009 :type ed: datetime :param sv: The starting value of the portfolio :type sv: int :return: A DataFrame with values representing trades for each day. Legal values are +1000.0 indicating a BUY of 1000 shares, -1000.0 indicating a SELL of 1000 shares, and 0.0 indicating NOTHING. Values of +2000 and -2000 for trades are also legal when switching from long to short or short to long so long as net holdings are constrained to -1000, 0, and 1000. :rtype: pandas.DataFrame """ dates = pd.date_range(sd,ed) df_prices = ind.get_price(symbol, dates) daily_rets = (df_prices / df_prices.shift(1)) - 1 daily_rets = daily_rets[1:] sd_older = sd - dt.timedelta(days=365) dates_older = pd.date_range(sd_older,ed) df_prices_older = ind.get_price(symbol, dates_older) sd_key = df_prices.index[0] sd_index = df_prices_older.index.get_loc(sd_key) df_holdings = df_prices.copy() df_holdings['Holdings'] = np.nan del df_holdings[symbol] # print(df_holdings) # Get Indicator Values _,_,ind1 = ind.get_BB(df_prices_older, self.lookback) ind2 = ind.get_CCI(df_prices_older, self.lookback) _,_,ind3 = ind.get_SMA_Cross(self.lookback, 100, df_prices_older) ind4 = ind.get_momentum(df_prices_older, self.lookback) _,_,ind5 = ind.get_MACD(df_prices_older) BB = ind1.iloc[sd_index:].values CCI = ind2.iloc[sd_index:].values SMA_Cross = ind3.iloc[sd_index:].values Momentum = ind4.iloc[sd_index:].values MACD = ind5.iloc[sd_index:].values df_holdings.iloc[0]['Holdings'] = 0 action = 2 # BB_threshold = 1.0 # MACD_threshold = 0.15 # Momentum_threshold = 0.1 # BB_threshold = 0. BB_threshold = 0.0 MACD_threshold = 0.0 Momentum_threshold = 0 for day_idx in range(1,daily_rets.shape[0]): # BB Logic BB_sell = BB[day_idx-1] >= 1-BB_threshold and BB[day_idx] < 1-BB_threshold BB_buy = BB[day_idx-1] <= BB_threshold and BB[day_idx] > BB_threshold # MACD Logic # MACD_sell = MACD[day_idx] > MACD[day_idx-1] and MACD[day_idx] > 0 and MACD[day_idx] < MACD_threshold # MACD_buy = MACD[day_idx] < MACD[day_idx-1] and MACD[day_idx] < 0 and MACD[day_idx] > -1*MACD_threshold MACD_sell = MACD[day_idx] >= 0 and MACD[day_idx-1] < 0 MACD_buy = MACD[day_idx] <= 0 and MACD[day_idx-1] > 0 # Momentum Logic Momentum_sell = Momentum[day_idx] > Momentum_threshold Momentum_buy = Momentum[day_idx] < -1*Momentum_threshold # SMA Cross Logic SMA_sell = SMA_Cross[day_idx] <= 0 and SMA_Cross[day_idx-1] > 0 SMA_buy = SMA_Cross[day_idx] >= 0 and SMA_Cross[day_idx-1] < 0 # Momentum_sell = True # Momentum_buy = True # Momentum_buy = Momentum[day_idx] > Momentum_threshold # Momentum_sell = Momentum[day_idx] < -1*Momentum_threshold action = 2 if (BB_sell and Momentum_sell) or (MACD_sell and Momentum_sell): action = 1 # Sell signal if (BB_buy and Momentum_buy) or (MACD_buy and Momentum_buy): action = 0 # Buy Signal df_holdings.iloc[day_idx]['Holdings'] = self.take_action(df_holdings.iloc[day_idx-1]['Holdings'], action) df_holdings.iloc[-1]['Holdings'] = 0 df_trades = df_holdings.diff() df_trades['Trades'] = df_trades['Holdings'] del df_trades['Holdings'] df_trades.iloc[0]['Trades'] = 0 return df_trades
def addEvidence(self, symbol = "IBM", \ sd=dt.datetime(2008,1,1), \ ed=dt.datetime(2009,1,1), \ sv = 10000,n_bins=6): # this method should create a QLearner, and train it for trading syms = [symbol] dates = pd.date_range(sd, ed) prices, prices_SPY = id.get_price(syms, dates) if self.verbose: print prices daily_returns = (prices / prices.shift(1)) - 1 daily_returns = daily_returns[1:] # get indicators and combine them into as a feature data_frame lookback = 14 _, PSR = id.get_SMA(prices, lookback) _, _, bb_indicator = id.get_BB(prices, lookback) momentum = id.get_momentum(prices, lookback) _, self.pbins = pd.qcut(PSR, n_bins, labels=False, retbins=True) _, self.bbins = pd.qcut(bb_indicator, n_bins, labels=False, retbins=True) _, self.mbins = pd.qcut(momentum, n_bins, labels=False, retbins=True) self.pbins = self.pbins[1:-1] self.bbins = self.bbins[1:-1] self.mbins = self.mbins[1:-1] # start training converged = False df_trades = None count = 0 old_cum_ret = 0.0 converge_count = 0 converged_prev = False #print "Total number of states is:", total_states # Initialize QLearner, self.learner = ql.QLearner(num_states=100 * n_bins, num_actions=self.num_actions, alpha=0.5, gamma=0.9, rar=0.0, radr=0.0, dyna=0, verbose=self.verbose) while (not converged) and (count < 100): # Set first state to the first data point (first day) indices = daily_returns.index holdings = pd.DataFrame(np.nan, index=indices, columns=['Holdings']) #first_state = self.indicators_to_state(PSR.iloc[0], bb_indicator.iloc[0], momentum.iloc[0]) #print("SL 152: holdings.iloc[0] = ", holdings.iloc[0][0], "; daily_rets.iloc[1] = ", daily_returns.iloc[1][0]) holdings.iloc[0] = 0. #print("SL 153") #df_prices = prices.copy() #df_prices['Cash'] = pd.Series(1.0, index=indices) #df_trades = df_prices.copy() #df_trades[:] = 0.0 state = self.indicators_to_state(PSR.iloc[0], bb_indicator.iloc[0], momentum.iloc[0]) action = self.learner.querysetstate(state) holdings.iloc[0], reward = self.apply_action( holdings.iloc[0][0], action, daily_returns.iloc[1][0]) #print("SL 171: PSR.shape[0] = ",PSR.shape[0],"; daily_returns.shape[0] = ",daily_returns.shape[0]) # Cycle through dates for j in range(1, daily_returns.shape[0]): state = self.indicators_to_state(PSR.iloc[j], bb_indicator.iloc[j], momentum.iloc[j]) # Get action by Query learner with current state and reward to get action action = self.learner.query(state, reward) # update reward and holdings with the new action. holdings.iloc[j], reward = self.apply_action( holdings.iloc[j - 1][0], action, daily_returns.iloc[j][0]) #print("SL 183: holdings.iloc[j][0] = ",holdings.iloc[j][0]) # Implement action returned by learner and update portfolio #print("SL 206: one learning is done.") #print("SL 215, holdings.iloc[0]",holdings.iloc[0]) holdings.iloc[-1] = 0 holdings.ffill(inplace=True) holdings.fillna(0, inplace=True) #print("SL 216 holdings = ",holdings) trades = holdings.diff() trades.iloc[0] = 0 # buy and sell happens when the difference change direction df_trades = pd.DataFrame(data=trades.values, index=indices, columns=['Trades']) df_orders, _ = generate_orders(df_trades, symbol) port_vals = compute_portvals(df_orders, sd=sd, ed=ed, impact=self.impact, start_val=sv, commission=self.commission) cum_ret, _, _, _ = get_portfolio_stats(port_vals) count += 1 old_cum_ret,converged_prev,converge_count,converged = \ check_convergence(old_cum_ret,cum_ret,converged_prev,converge_count) # check if converge #if converged: #print("SL 212: converged at iteration # ",count, "cum_ret is: ", cum_ret) return df_trades # example use with new colname volume_all = ut.get_data(syms, dates, colname="Volume") # automatically adds SPY volume = volume_all[syms] # only portfolio symbols volume_SPY = volume_all['SPY'] # only SPY, for comparison later if self.verbose: print volume
def testPolicy(self, symbol = "JPM", \ sd=dt.datetime(2010,1,1), \ ed=dt.datetime(2011,12,31), \ sv = 100000): rand.seed(5) LOOKBACK = 10 # example usage of the old backward compatible util function syms = [symbol] dates = pd.date_range(sd, ed) prices_all = ut.get_data(syms, dates) # automatically adds SPY prices = prices_all[syms] # only portfolio symbols prices.fillna(method='ffill', inplace=True) prices.fillna(method='bfill', inplace=True) prices_SPY = prices_all['SPY'] # only SPY, for comparison later if self.verbose: print(prices) # Make indicators df X = prices.copy() X.drop([symbol], axis=1, inplace=True) X['mmt'] = idc.get_momentum(prices) X['smar'] = idc.get_sma_r(prices) X['bbp'] = idc.get_bbp(prices) df_trades = prices.copy() df_trades[symbol] = 0 holding = 0 # Get initial state indicators = X.iloc[LOOKBACK - 1] s = self.serialize(indicators) a = self.learner.querysetstate(s) df_len = prices.shape[0] for i in range(LOOKBACK, df_len - 1): s = self.serialize(X.iloc[i]) if a == 2: # LONG if holding == 0: holding = 1000 df_trades.iloc[i, 0] = 1000 elif holding == -1000: holding = 1000 df_trades.iloc[i, 0] = 2000 elif a == 1: pass elif a == 0: # SHORT if holding == 0: holding = -1000 df_trades.iloc[i, 0] = -1000 elif holding == 1000: holding = -1000 df_trades.iloc[i, 0] = -2000 else: raise Exception("ERROR: INVALID ACTION") a = self.learner.querysetstate(s) # por_vals = ms.compute_portvals(df_trades, start_val = sv, commission=0.0, impact=self.impact) # cum_ret = por_vals[-1]/por_vals[0] - 1 return df_trades if self.verbose: print(type(trades)) # it better be a DataFrame! if self.verbose: print(trades) if self.verbose: print(prices_all)
def showvalues(): # Specify the start and end dates for this period. start_d = dt.date(2008, 1, 1) #end_d = dt.datetime(2018, 10, 30) yesterday = dt.date.today() - dt.timedelta(1) # Get portfolio values from Yahoo symbol = request.form['symbol'] portf_value = fetchOnlineData(start_d, yesterday, symbol) # ****Stock prices chart**** plot_prices = plot_stock_prices(portf_value.index, portf_value['Adj Close'], symbol) # ****Momentum chart**** # Normalize the prices Dataframe normed = pd.DataFrame() normed['Adj Close'] = portf_value['Adj Close'].values / portf_value[ 'Adj Close'].iloc[0] # Compute momentum sym_mom = get_momentum(normed['Adj Close'], window=10) # Create momentum chart plot_mom = plot_momentum(portf_value.index, normed['Adj Close'], sym_mom, "Momentum Indicator", (12, 8)) # ****Bollinger Bands**** # Compute rolling mean rm_JPM = get_rolling_mean(portf_value['Adj Close'], window=10) # Compute rolling standard deviation rstd_JPM = get_rolling_std(portf_value['Adj Close'], window=10) # Compute upper and lower bands upper_band, lower_band = get_bollinger_bands(rm_JPM, rstd_JPM) # Plot raw symbol values, rolling mean and Bollinger Bands dates = pd.date_range(start_d, yesterday) plot_boll = plot_bollinger(dates, portf_value.index, portf_value['Adj Close'], symbol, upper_band, lower_band, rm_JPM, num_std=1, title="Bollinger Indicator", fig_size=(12, 6)) # ****Simple moving average (SMA)**** # Compute SMA sma_JPM, q = get_sma(normed['Adj Close'], window=10) # Plot symbol values, SMA and SMA quality plot_sma = plot_sma_indicator(dates, portf_value.index, normed['Adj Close'], symbol, sma_JPM, q, "Simple Moving Average (SMA)") # ****Relative Strength Index (RSI)**** # Compute RSI rsi_value = get_RSI(portf_value['Adj Close']) # Plot RSI plot_rsi = plot_rsi_indicator(dates, portf_value.index, portf_value['Adj Close'], symbol, rsi_value, window=14, title="RSI Indicator", fig_size=(12, 6)) # Session variables session['start_val'] = request.form['start_val'] session['symbol'] = request.form['symbol'] session['start_d'] = start_d.strftime('%Y/%m/%d') session['num_shares'] = request.form['num_shares'] session['commission'] = request.form['commission'] session['impact'] = request.form['impact'] return render_template( # name of template "stockpriceschart.html", # now we pass in our variables into the template start_val=request.form['start_val'], symbol=request.form['symbol'], commission=request.form['commission'], impact=request.form['impact'], num_shares=request.form['num_shares'], start_date=start_d, end_date=yesterday, tables=[portf_value.to_html(classes=symbol)], titles=['na', 'Stock Prices '], div_placeholder_stock_prices=Markup(plot_prices), div_placeholder_momentum=Markup(plot_mom), div_placeholder_bollinger=Markup(plot_boll), div_placeholder_sma=Markup(plot_sma), div_placeholder_rsi=Markup(plot_rsi))
def addEvidence(self, symbol = "JPM", \ sd=dt.datetime(2008,1,1), \ ed=dt.datetime(2009,12,31), \ sv = 100000): rand.seed(5) LOOKBACK = 10 randomrate = 0.0 # Getting data syms = [symbol] dates = pd.date_range(sd, ed) prices_all = ut.get_data(syms, dates) # automatically adds SPY prices = prices_all[syms] # only portfolio symbols prices.fillna(method='ffill', inplace=True) prices.fillna(method='bfill', inplace=True) prices_SPY = prices_all['SPY'] # only SPY, for comparison later # Make indicators df X = prices.copy() X.drop([symbol], axis=1, inplace=True) X['mmt'] = idc.get_momentum(prices) X['smar'] = idc.get_sma_r(prices) X['bbp'] = idc.get_bbp(prices) # Get thresholds for 3 indicators # Momentum sorted_vals = X['mmt'].sort_values() sorted_vals = sorted_vals.dropna() stepsize = math.floor(sorted_vals.shape[0] / 10) for i in range(0, 10): self.threshold_mmt.append(sorted_vals[(i + 1) * stepsize]) # Simple moving average ratio sorted_vals = X['smar'].sort_values() sorted_vals = sorted_vals.dropna() stepsize = math.floor(sorted_vals.shape[0] / 10) for i in range(0, 10): self.threshold_smar.append(sorted_vals[(i + 1) * stepsize]) # Bollinger band percentage sorted_vals = X['bbp'].sort_values() sorted_vals = sorted_vals.dropna() stepsize = math.floor(sorted_vals.shape[0] / 10) for i in range(0, 10): self.threshold_bbp.append(sorted_vals[(i + 1) * stepsize]) # Get initial state indicators = X.iloc[LOOKBACK - 1] s = self.serialize(indicators) a = self.learner.querysetstate(s) df_len = prices.shape[0] run_i = 0 run_results = [] MAX_RUNS = 50 while run_i < MAX_RUNS: if len(run_results) > 10: # Check for convergence if (round(run_results[-1], 4) == round(run_results[-2], 4)): break run_i += 1 holding = 0 df_trades = prices.copy() df_trades[symbol] = 0 for i in range(LOOKBACK, df_len - 1): s = self.serialize(X.iloc[i]) price = prices.iloc[i, 0] next_price = prices.iloc[i + 1, 0] if rand.uniform(0.0, 1.0) <= randomrate: # going rogue a = rand.randint(0, 2) # choose the random direction # Calculate reward r = 0 if a == 2: # LONG if holding == 0: holding = 1000 df_trades.iloc[i, 0] = 1000 r = -self.impact * (price + next_price) * 1000 elif holding == -1000: holding = 1000 df_trades.iloc[i, 0] = 2000 r = -self.impact * (price + next_price) * 2000 else: pass elif a == 1: # do nothing pass elif a == 0: # SHORT if holding == 0: holding = -1000 df_trades.iloc[i, 0] = -1000 r = -self.impact * (price + next_price) * 1000 elif holding == 1000: holding = -1000 df_trades.iloc[i, 0] = -2000 r = -self.impact * (price + next_price) * 2000 else: pass else: raise Exception("ERROR: INVALID ACTION") r += (next_price - price) * holding a = self.learner.query(s, r) por_vals = ms.compute_portvals(df_trades, start_val=sv, commission=0.0, impact=self.impact) cum_ret = por_vals[-1] / por_vals[0] - 1 run_results.append(cum_ret)
def testPolicy( self, symbol="IBM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 1, 31), sv=10000, ): """ Tests your learner using data outside of the training data :param symbol: The stock symbol that you trained on on :type symbol: str :param sd: A datetime object that represents the start date, defaults to 1/1/2008 :type sd: datetime :param ed: A datetime object that represents the end date, defaults to 1/1/2009 :type ed: datetime :param sv: The starting value of the portfolio :type sv: int :return: A DataFrame with values representing trades for each day. Legal values are +1000.0 indicating a BUY of 1000 shares, -1000.0 indicating a SELL of 1000 shares, and 0.0 indicating NOTHING. Values of +2000 and -2000 for trades are also legal when switching from long to short or short to long so long as net holdings are constrained to -1000, 0, and 1000. :rtype: pandas.DataFrame """ syms = [symbol] dates = pd.date_range(sd, ed) indicator_dates = pd.date_range(sd - dt.timedelta(days=28), ed) prices_all = ut.get_data(syms, dates) # automatically adds SPY prices = prices_all[syms] # only portfolio symbols indicator_prices_all = ut.get_data( syms, indicator_dates ) #will this be the same size as the number of days traded? indicator_prices = indicator_prices_all[syms] prices_SPY = prices_all["SPY"] # only SPY, for comparison later rm = ind.get_rolling_mean(indicator_prices[symbol], window=20) percent_bb = ind.get_rolling_std(indicator_prices[symbol], window=20) #aka rstd upper_band, lower_band = ind.get_bollinger_bands(rm, percent_bb) percent_bb = percent_bb.iloc[19:] rm = rm.iloc[19:] upper_band = upper_band.iloc[19:] lower_band = lower_band.iloc[19:] for x in range(rm.size): #did i format that right?? #print(prices.iloc[x]) #print(type(rm.iloc[x])) if (prices.iloc[x][0] == rm.iloc[x]): percent_bb.iloc[x] = 0.0 elif (prices.iloc[x][0] > rm.iloc[x]): percent_bb.iloc[x] = (prices.iloc[x][0] - rm.iloc[x]) / ( upper_band.iloc[x] - rm.iloc[x]) elif (prices.iloc[x][0] < rm.iloc[x]): percent_bb.iloc[x] = (rm.iloc[x] - prices.iloc[x][0]) / ( lower_band.iloc[x] - rm.iloc[x]) percent_bb = pd.Series(percent_bb) #print(percent_bb) indicator_prices = indicator_prices.iloc[9:] #print(indicator_prices) momentum = pd.Series( ind.get_momentum(indicator_prices[symbol], window=10)) momentum = momentum.iloc[10:] #print(momentum) volatility = pd.Series( ind.get_volatility(indicator_prices[symbol], window=10)) volatility = volatility.iloc[10:] # here we build a fake set of trades # your code should return the same sort of data dates = pd.date_range(sd, ed) prices_all = ut.get_data([symbol], dates) # automatically adds SPY trades = prices_all[[ symbol, ]] # only portfolio symbols trades_SPY = prices_all["SPY"] # only SPY, for comparison later trades.values[:, :] = 0 # set them all to nothing vol, momnt, bb = self.discretize(symbol) #print(volatility.iloc[0]) #print(vol) vol_bin = "" mo_bin = "" bb_bin = "" holdings = 0 for x in range(trades.size): vol_set = False mo_set = False bb_set = False for y in range(vol.size): if (volatility.iloc[x] <= vol[y] and vol_set == False): #print(x) vol_bin = str(y) vol_set = True elif (y == vol.size - 1 and vol_set == False): vol_bin = str(y + 1) vol_set = True if (momentum.iloc[x] <= momnt[y] and mo_set == False): mo_bin = str(y) mo_set = True elif (y == momnt.size - 1 and mo_set == False): mo_bin = str(y + 1) mo_set = True if (percent_bb.iloc[x] <= bb[y] and bb_set == False): bb_bin = str(y) bb_set = True elif (y == bb.size - 1 and bb_set == False): bb_bin = str(y + 1) bb_set = True state = int(vol_bin + mo_bin + bb_bin) #print(state) action = self.learner.querysetstate(state) - 1 #print(action) if (action == 1): if (holdings == 0): trades.values[x, :] = 1000 elif (holdings == -1000): trades.values[x, :] = 2000 elif (holdings == 1000): trades.values[x, :] = 0 holdings = 1000 elif (action == 0): if (holdings == 0): trades.values[x, :] = 0 elif (holdings == -1000): trades.values[x, :] = 1000 elif (holdings == 1000): trades.values[x, :] = -1000 holdings = 0 elif (action == -1): if (holdings == 0): trades.values[x, :] = -1000 elif (holdings == -1000): trades.values[x, :] = 0 elif (holdings == 1000): trades.values[x, :] = -2000 holdings = -1000 #print(trades) if self.verbose: print(type(trades)) # it better be a DataFrame! if self.verbose: print(trades) if self.verbose: print(prices_all) #print(trades) return trades
def testPolicy(self, symbol="JPM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 12, 31), sv=100000): ''' The input parameters are: symbol: the stock symbol to act on sd: A datetime object that represents the start date ed: A datetime object that represents the end date sv: Start value of the portfolio The output df_trades in form: Date | Symbol | Order | Shares ''' # window = 10 dates = pd.date_range(sd, ed) symbols = symbol prices = ut.get_data([symbol], dates) prices.fillna(method='ffill', inplace=True) prices.fillna(method='bfill', inplace=True) # print("prices[:20]") # print(prices[:20]) # print(len(prices)) # 1. compute the 3 indicators from indicator.py # note: first 10 days might be no tradings since they are within the window time frame and 3 indicators rerturns N/A SMA = ind.get_SMA(prices, symbols, self.window) price_SMA_ratio = ind.get_SMA_ratio(prices, symbols, self.window) momentum = ind.get_momentum(prices, self.window) bb_value = ind.get_bollinger_band(prices, symbols, self.window) # print('Price/SMA ratio print here:') # print(price_SMA_ratio[:20]) # print(len(price_SMA_ratio)) # print('================') # print('momentum print here:') # print(momentum[:20]) # print(len(momentum)) # print('================') # print('bb_value print here:') # print(bb_value[:20]) # print('================') #This is for creating the dataframe for df_trades symbol_list = [] date_range = [] price_of_day = [] order = [] share = [] current_shares = 0 net_hold = 0 #net_hold = 0 no share, net_hold = 1: long position, net_hold = -1 shorted position buy_date = [] sell_date = [] #for SMA_ratio: small should buy, large should sell #for momemtum: negative should sell, positive should buy #for bb_value: small should buy, large should sell for i in range(len(prices.index) - 1): # for i in 0 - 504 symbol_list.append(symbol) date_range.append(prices.index[i]) price_of_day.append(prices[symbol][i]) #when you should buy if price_SMA_ratio['Price/SMA ratio'][i] < 0.95 or momentum[symbol][ i] > 0.3 or bb_value[i] <= 0.6 and current_shares == 0: order.append("BUY") share.append(1000) current_shares += 1000 elif price_SMA_ratio['Price/SMA ratio'][i] < 0.95 or momentum[ symbol][ i] > 0.3 or bb_value[i] <= 0.6 and current_shares < 0: order.append("BUY") share.append(2000) current_shares += 2000 #when you should sell elif price_SMA_ratio['Price/SMA ratio'][i] > 1.0 or momentum[ symbol][i] < -0.15 or bb_value[ i] > 0.9 and current_shares == 0: order.append("SELL") share.append(-1000) current_shares += -1000 elif price_SMA_ratio['Price/SMA ratio'][i] > 1.0 or momentum[ symbol][ i] < -0.15 or bb_value[i] > 0.9 and current_shares > 0: order.append("SELL") share.append(-2000) current_shares += -2000 else: order.append("HOLD") share.append(0) current_shares += 0 #create the dataframe to store the result df_trades = pd.DataFrame( index=date_range, columns=['Symbol', 'Prices', 'Order', 'Shares']) df_trades['Symbol'] = symbol_list df_trades['Prices'] = price_of_day df_trades['Order'] = order df_trades['Shares'] = share # print("df_trades[:20]") # print(df_trades[:20]) # print(len(df_trades)) return df_trades
def add_evidence( #this is where you could use the inspiration for the grading function from project 7 self, symbol="JPM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 1, 1), sv=10000, ): """ Trains your strategy learner over a given time frame. :param symbol: The stock symbol to train on :type symbol: str :param sd: A datetime object that represents the start date, defaults to 1/1/2008 :type sd: datetime :param ed: A datetime object that represents the end date, defaults to 1/1/2009 :type ed: datetime :param sv: The starting value of the portfolio :type sv: int """ # add your code to do learning here syms = [symbol] dates = pd.date_range(sd, ed) indicator_dates = pd.date_range(sd - dt.timedelta(days=28), ed) prices_all = ut.get_data(syms, dates) # automatically adds SPY prices = prices_all[syms] # only portfolio symbols indicator_prices_all = ut.get_data( syms, indicator_dates ) #will this be the same size as the number of days traded? indicator_prices = indicator_prices_all[syms] prices_SPY = prices_all["SPY"] # only SPY, for comparison later #get 3 indicators using passed in start date minus window required for each rm = ind.get_rolling_mean(indicator_prices[symbol], window=20) percent_bb = ind.get_rolling_std(indicator_prices[symbol], window=20) #aka rstd upper_band, lower_band = ind.get_bollinger_bands(rm, percent_bb) percent_bb = percent_bb.iloc[19:] rm = rm.iloc[19:] upper_band = upper_band.iloc[19:] lower_band = lower_band.iloc[19:] for x in range(rm.size): #did i format that right?? #print(prices.iloc[x]) #print(type(rm.iloc[x])) if (prices.iloc[x][0] == rm.iloc[x]): percent_bb.iloc[x] = 0.0 elif (prices.iloc[x][0] > rm.iloc[x]): percent_bb.iloc[x] = (prices.iloc[x][0] - rm.iloc[x]) / ( upper_band.iloc[x] - rm.iloc[x]) elif (prices.iloc[x][0] < rm.iloc[x]): percent_bb.iloc[x] = (rm.iloc[x] - prices.iloc[x][0]) / ( lower_band.iloc[x] - rm.iloc[x]) percent_bb = pd.Series(percent_bb) #print(percent_bb) indicator_prices = indicator_prices.iloc[9:] #print(indicator_prices) momentum = pd.Series( ind.get_momentum(indicator_prices[symbol], window=10)) momentum = momentum.iloc[10:] #print(momentum) volatility = pd.Series( ind.get_volatility(indicator_prices[symbol], window=10)) volatility = volatility.iloc[10:] #print(volatility.values.shape) uglystupidnobodylikesyouvol, vol = pd.qcut(volatility.values, 10, retbins=True) esrfergs, momnt = pd.qcut(momentum.values, 10, retbins=True) rgefsegrf, bb = pd.qcut(percent_bb.values, 10, retbins=True) vol = vol[1:-1] momnt = momnt[1:-1] bb = bb[1:-1] #print(volatility.iloc[0]) #print(vol) #print(volatility.iloc[0] in vol[0]) total_reward = 0 performance_list = np.zeros(10) for z in range(10): cash_value = float(sv) stock_value = 0.0 portfolio_value = cash_value + stock_value #figure out state vol_set = False mo_set = False bb_set = False vol_bin = "" mo_bin = "" bb_bin = "" for x in range(vol.size): if (volatility.iloc[0] <= vol[x] and vol_set == False): vol_bin = str(x) vol_set = True elif (x == vol.size - 1 and vol_set == False): vol_bin = str(x + 1) vol_set = True if (momentum.iloc[0] <= momnt[x] and mo_set == False): mo_bin = str(x) mo_set = True elif (x == momnt.size - 1 and mo_set == False): mo_bin = str(x + 1) mo_set = True if (percent_bb.iloc[0] <= bb[x] and bb_set == False): bb_bin = str(x) bb_set = True elif (x == bb.size - 1 and bb_set == False): bb_bin = str(x + 1) bb_set = True #print(volatility.iloc[0]) #position = 0 actually this could be action variable below final_str = vol_bin + mo_bin + bb_bin state = int(final_str) #print(state) action = self.learner.querysetstate(state) - 1 old_action = action same_action = False count = 0 stock_value = action * 1000.0 * prices.iloc[0] cash_value -= stock_value #print("Daily Value for end of Day 1" + ": " + str(portfolio_value)) for x in range( 1, prices.size ): #while the trading simualtion hasnt reached last day #at this point assume day 1 or x is over and now calculate the reward of the prior day's #decision to pass in next action call as r. also calculate the # holdings of the bot(maybe just check the action variable for this) daily_gain = (prices.values[x, 0] - prices.values[x - 1, 0] ) / prices.values[x - 1, 0] #daily percentage gain #print(type(daily_gain)) portfolio_value = ( (1.0 + daily_gain) * stock_value) + cash_value #print(portfolio_value) if (action == 1): if (daily_gain - self.impact > 0.02): reward = 35.0 elif (daily_gain - self.impact > 0.012): reward = 20.0 elif (daily_gain - self.impact > 0.004): reward = 7.5 elif (daily_gain - self.impact < -0.019): reward = -25.0 elif (daily_gain - self.impact < -0.009): reward = -10.0 else: reward = daily_gain * 10.0 elif (action == 0): reward = abs(daily_gain - self.impact) * 3.5 elif (action == -1): if (daily_gain - self.impact < -0.026): reward = 35.0 elif (daily_gain - self.impact < -0.015): reward = 20.0 elif (daily_gain - self.impact < -0.004): reward = 7.5 elif (daily_gain - self.impact > 0.019): reward = -25.0 elif (daily_gain - self.impact > 0.007): reward = -10.0 else: reward = daily_gain * -10.0 if (same_action == True): reward += (7.5 + self.impact) #determine state vol_set = False mo_set = False bb_set = False vol_bin = "" mo_bin = "" bb_bin = "" for y in range(vol.size): if (volatility.iloc[x] <= vol[y] and vol_set == False): #print(x) vol_bin = str(y) vol_set = True elif (y == vol.size - 1 and vol_set == False): vol_bin = str(y + 1) vol_set = True if (momentum.iloc[x] <= momnt[y] and mo_set == False): mo_bin = str(y) mo_set = True elif (y == momnt.size - 1 and mo_set == False): mo_bin = str(y + 1) mo_set = True if (percent_bb.iloc[x] <= bb[y] and bb_set == False): bb_bin = str(y) bb_set = True elif (y == bb.size - 1 and bb_set == False): bb_bin = str(y + 1) bb_set = True state = int(vol_bin + mo_bin + bb_bin) old_action = action action = self.learner.query(state, reward) - 1 same_action = False if (old_action == action and reward > 0.0): same_action = True stock_value = action * 1000.0 * prices.iloc[x] cash_value = portfolio_value - stock_value total_reward += reward #print("Daily Value for end of Day " + str(x+1) + ": " + str(portfolio_value)) #print("Ending value for test phase " + str(z+1) + ": " + str(portfolio_value)) performance_list[z] = portfolio_value mat.pyplot.plot(performance_list)
def testPolicy(self, symbol = "IBM", \ sd=dt.datetime(2009,1,1), \ ed=dt.datetime(2010,1,1), \ sv = 10000): # here we build a fake set of trades # your code should return the same sort of data dates = pd.date_range(sd, ed) prices_all = ut.get_data([symbol], dates) # automatically adds SPY prices = prices_all[[ symbol, ]] # only portfolio symbols trades_SPY = prices_all['SPY'] # only SPY, for comparison later bb_val, upper, lower, rm, rs = get_bb(prices) sma = get_sma(prices) mom = get_momentum(prices) x_test = np.zeros(shape=(len(prices), 7)) for i in range(20, len(prices) - self.N): x_test[i][0] = bb_val[i] x_test[i][1] = upper[i] x_test[i][2] = lower[i] x_test[i][3] = rm[i] x_test[i][4] = rs[i] x_test[i][5] = sma[i] x_test[i][6] = mom[i] x_test = pd.DataFrame(x_test) x_test = x_test[:-self.N] x_test = x_test.values y_test = self.learner.query(x_test) trades = pd.DataFrame(0, columns=prices.columns, index=prices.index) flag = 0 for i in range(0, len(prices) - self.N): if y_test[i] == 1: if flag == 0: flag = 1000 trades[symbol].iloc[i] = 1000 elif flag == -1000: flag = 1000 trades.iloc[i, 0] = 2000 if y_test[i] == -1: if flag == 0: flag = -1000 trades[symbol].iloc[i] = -1000 elif flag == 1000: flag = -1000 trades[symbol].iloc[i] = -2000 # trades.values[:,:] = 0 # set them all to nothing # trades.values[0,:] = 1000 # add a BUY at the start # trades.values[40,:] = -1000 # add a SELL # trades.values[41,:] = 1000 # add a BUY # trades.values[60,:] = -2000 # go short from long # trades.values[61,:] = 2000 # go long from short # trades.values[-1,:] = -1000 #exit on the last day # if self.verbose: print type(trades) # it better be a DataFrame! # if self.verbose: print trades # if self.verbose: print prices_all return trades
def addEvidence(self, symbol="JPM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 12, 31), sv=100000): df_prices = ut.get_data([symbol], pd.date_range(sd, ed)).ffill().bfill() df_prices = df_prices[[symbol]] indicator_details = df_prices.copy() indicator_details.drop([symbol], axis=1, inplace=True) indicator_details[self.momentum] = idc.get_momentum(df_prices) indicator_details[self.sma_ratio] = idc.get_sma_r(df_prices) indicator_details[self.bollinger_percent] = idc.get_bbp(df_prices) self.add_indicator_details(indicator_details) indicators = indicator_details.iloc[self.window - 1] s = self.serialize(indicators) a = self.learner.querysetstate(s) df_prices_len = df_prices.shape[0] ith_run = 0 run_results = [] while ith_run < self.max_runs: if len(run_results) > 10 and round(run_results[-1], 4) == round( run_results[-2], 4): break ith_run = ith_run + 1 holding = 0 df_trades = df_prices.copy() df_trades[symbol] = 0 for i in range(self.window, df_prices_len - 1): reward = 0 s = self.serialize(indicator_details.iloc[i]) current_price = df_prices.iloc[i, 0] next_price = df_prices.iloc[i + 1, 0] if rand.uniform(0.0, 1.0) <= 0: a = rand.randint(0, 2) if a == 1: pass elif a == 2 and holding == 0: holding = 1000 df_trades.iloc[i, 0] = holding reward = -self.impact * (current_price + next_price) * holding elif a == 2 and holding == -1000: holding = 1000 df_trades.iloc[i, 0] = 2 * holding reward = -self.impact * (current_price + next_price) * 2 * holding elif a == 0 and holding == 0: holding = -1000 df_trades.iloc[i, 0] = holding reward = -self.impact * (current_price + next_price) * 1000 elif a == 0 and holding == 1000: holding = -1000 df_trades.iloc[i, 0] = 2 * holding reward = -self.impact * (current_price + next_price) * 2000 reward += (next_price - current_price) * holding a = self.learner.query(s, reward) df_trades.index.names = ['Date'] df_trades.columns = ['Shares'] df_trades["Symbol"] = "JPM" df_trades["Order"] = [ "BUY" if x > 0 else "SELL" if x < 0 else "NA" for x in df_trades['Shares'] ] df_trades.drop(df_trades[df_trades['Shares'] == 0].index, inplace=True) df_trades['Shares'] = df_trades['Shares'].abs() df_trades = df_trades.reindex( columns=['Symbol', 'Order', 'Shares']) df_trades.to_csv('orders.csv') port_values = ms.compute_portvals('./orders.csv', start_val=sv, commission=0.0, impact=self.impact) cumulative_return = port_values[-1] / port_values[0] - 1 run_results.append(cumulative_return)
def add_evidence( self, symbol="IBM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 1, 1), sv=10000, ): """ Trains your strategy learner over a given time frame. :param symbol: The stock symbol to train on :type symbol: str :param sd: A datetime object that represents the start date, defaults to 1/1/2008 :type sd: datetime :param ed: A datetime object that represents the end date, defaults to 1/1/2009 :type ed: datetime :param sv: The starting value of the portfolio :type sv: int """ # add your code to do learning here converged = False x = np.zeros((3, 1)) dates = pd.date_range(sd, ed) df_prices = ind.get_price(symbol, dates) daily_rets = (df_prices / df_prices.shift(1)) - 1 daily_rets = daily_rets[1:] sd_older = sd - dt.timedelta(days=365) dates_older = pd.date_range(sd_older, ed) df_prices_older = ind.get_price(symbol, dates_older) sd_key = df_prices.index[0] sd_index = df_prices_older.index.get_loc(sd_key) num_bins = len(self.bins) max_state_idx = num_bins + num_bins * 10 + num_bins * 100 # Call Q-Learner Constructor self.learner = QLearner( num_states=(max_state_idx + 1), num_actions=3, alpha=0.01, gamma=0.0, rar=0.98, radr=0.9995, dyna=0, verbose=False, ) # df_trades = df_prices.copy() df_holdings = df_prices.copy() df_holdings['Holdings'] = np.nan del df_holdings[symbol] # print(df_holdings) # Initlialize Vars cum_ret_prev = 0 iters = 0 conv_counter = 0 Q_prev = np.copy(self.learner.Q) # Get Indicator Values _, _, ind1 = ind.get_BB(df_prices_older, self.lookback) ind2 = ind.get_CCI(df_prices_older, self.lookback) _, _, ind3 = ind.get_SMA_Cross(self.lookback, 100, df_prices_older) ind4 = ind.get_momentum(df_prices_older, self.lookback) _, _, ind5 = ind.get_MACD(df_prices_older) BB = ind1.iloc[sd_index:].values CCI = ind2.iloc[sd_index:].values SMA_Cross = ind3.iloc[sd_index:].values Momentum = ind4.iloc[sd_index:].values MACD = ind5.iloc[sd_index:].values _, self.x0bins = pd.qcut(BB[:, 0], num_bins, labels=False, retbins=True) _, self.x1bins = pd.qcut(CCI[:, 0], num_bins, labels=False, retbins=True) _, self.x2bins = pd.qcut(SMA_Cross[:, 0], num_bins, labels=False, retbins=True) _, self.x3bins = pd.qcut(Momentum[:, 0], num_bins, labels=False, retbins=True) _, self.x4bins = pd.qcut(MACD[:, 0], num_bins, labels=False, retbins=True) x_0 = np.digitize(BB[:, 0], self.x0bins[1:-1]) x_1 = np.digitize(CCI[:, 0], self.x1bins[1:-1]) x_2 = np.digitize(SMA_Cross[:, 0], self.x2bins[1:-1]) x_3 = np.digitize(Momentum[:, 0], self.x3bins[1:-1]) x_4 = np.digitize(MACD[:, 0], self.x4bins[1:-1]) state = x_0 + x_3 * 10 + x_4 * 100 while not converged: action = self.learner.querysetstate(state[0]) daily_return = daily_rets.iloc[0][symbol] cur_price = df_prices.iloc[0][symbol] next_price = df_prices.iloc[1][symbol] df_holdings.iloc[0]['Holdings'], reward = self.take_action( 0, action, cur_price, next_price) for day_idx in range(1, daily_rets.shape[0]): daily_return = daily_rets.iloc[day_idx][symbol] cur_price = df_prices.iloc[day_idx - 1][symbol] next_price = df_prices.iloc[day_idx][symbol] df_holdings.iloc[day_idx][ 'Holdings'], reward = self.take_action( df_holdings.iloc[day_idx - 1]['Holdings'], action, cur_price, next_price) action = self.learner.query(state[day_idx], reward) df_holdings.iloc[-1]['Holdings'] = 0 df_trades = df_holdings.diff() df_trades['Trades'] = df_trades['Holdings'] del df_trades['Holdings'] df_trades.iloc[0]['Trades'] = 0 portvals = msc.compute_portvals( df_trades, symbol, sv, self.commission, self.impact, ) cum_ret = (portvals[-1] / portvals[0]) - 1 Q_diff = np.abs(self.learner.Q - Q_prev) Q_max_diff = Q_diff.max() if iters > 20: # if abs(cum_ret - cum_ret_prev) < 0.0001: if Q_max_diff < 0.001: conv_counter += 1 else: conv_counter = 0 if conv_counter > 5 or iters > 20000: converged = True # if iters > 100: # if iters % 100 == 0: # print("Iteration #", iters) print("----------------------------------------------") print("-- --") print("Iteration #", iters) print("Error = ", abs(cum_ret - cum_ret_prev)) print("Q Diff: ", Q_max_diff) print("Epsilon: ", self.learner.rar) cum_ret_prev = cum_ret Q_prev = np.copy(self.learner.Q) iters += 1 self.learner.rar *= self.learner.radr # print("Iters = ", iters) print("Mode Trained in ", iters, " iterations!") np.savetxt('Q_Table.csv', self.learner.Q, delimiter=',')
def testPolicy( self, symbol="jpm", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 12, 31), sv=10000, ): """ Tests your learner using data outside of the training data :param symbol: The stock symbol that you trained on on :type symbol: str :param sd: A datetime object that represents the start date, defaults to 1/1/2008 :type sd: datetime :param ed: A datetime object that represents the end date, defaults to 1/1/2009 :type ed: datetime :param sv: The starting value of the portfolio :type sv: int :return: A DataFrame with values representing trades for each day. Legal values are +1000.0 indicating a BUY of 1000 shares, -1000.0 indicating a SELL of 1000 shares, and 0.0 indicating NOTHING. Values of +2000 and -2000 for trades are also legal when switching from long to short or short to long so long as net holdings are constrained to -1000, 0, and 1000. :rtype: pandas.DataFrame """ dates = pd.date_range(sd, ed) df_prices = ind.get_price(symbol, dates) daily_rets = (df_prices / df_prices.shift(1)) - 1 daily_rets = daily_rets[1:] sd_older = sd - dt.timedelta(days=365) dates_older = pd.date_range(sd_older, ed) df_prices_older = ind.get_price(symbol, dates_older) sd_key = df_prices.index[0] sd_index = df_prices_older.index.get_loc(sd_key) df_holdings = df_prices.copy() df_holdings['Holdings'] = np.nan del df_holdings[symbol] # print(df_holdings) cum_ret_prev = 0 iters = 0 num_bins = len(self.bins) _, _, ind1 = ind.get_BB(df_prices_older, self.lookback) ind2 = ind.get_CCI(df_prices_older, self.lookback) _, _, ind3 = ind.get_SMA_Cross(self.lookback, 100, df_prices_older) ind4 = ind.get_momentum(df_prices_older, self.lookback) _, _, ind5 = ind.get_MACD(df_prices_older) BB = ind1.iloc[sd_index:].values CCI = ind2.iloc[sd_index:].values SMA_Cross = ind3.iloc[sd_index:].values Momentum = ind4.iloc[sd_index:].values MACD = ind5.iloc[sd_index:].values _, self.x0bins = pd.qcut(BB[:, 0], num_bins, labels=False, retbins=True) _, self.x1bins = pd.qcut(CCI[:, 0], num_bins, labels=False, retbins=True) _, self.x2bins = pd.qcut(SMA_Cross[:, 0], num_bins, labels=False, retbins=True) _, self.x3bins = pd.qcut(Momentum[:, 0], num_bins, labels=False, retbins=True) _, self.x4bins = pd.qcut(MACD[:, 0], num_bins, labels=False, retbins=True) x_0 = np.digitize(BB[:, 0], self.x0bins[1:-1]) x_1 = np.digitize(CCI[:, 0], self.x1bins[1:-1]) x_2 = np.digitize(SMA_Cross[:, 0], self.x2bins[1:-1]) x_3 = np.digitize(Momentum[:, 0], self.x3bins[1:-1]) x_4 = np.digitize(MACD[:, 0], self.x4bins[1:-1]) state = x_0 + x_3 * 10 + x_4 * 100 self.learner.rar = 0 action = self.learner.querysetstate(state[0]) daily_return = daily_rets.iloc[0][symbol] df_holdings.iloc[0]['Holdings'] = 0 for day_idx in range(1, daily_rets.shape[0]): # implement action cur_price = df_prices.iloc[day_idx - 1][symbol] next_price = df_prices.iloc[day_idx][symbol] action = self.learner.querysetstate(state[day_idx]) df_holdings.iloc[day_idx]['Holdings'], _ = self.take_action( df_holdings.iloc[day_idx - 1]['Holdings'], action, cur_price, next_price) df_holdings.iloc[-1]['Holdings'] = 0 df_trades = df_holdings.diff() df_trades['Trades'] = df_trades['Holdings'] del df_trades['Holdings'] df_trades.iloc[0]['Trades'] = 0 return df_trades
def testPolicyMixed(n_days_bb=20, n_days_mtum=20, n_days_std=20, n_days_rsi=20, tresh_bb=1, tresh_mmtum=0.2, tresh_std_low=1, tresh_std_high=1, symbol="JPM", sd=dt.datetime(2008, 1, 1), ed=dt.datetime(2009, 12, 31), sv=100000): df_prices_all = get_data([symbol], pd.date_range(sd, ed)) df_prices = df_prices_all[symbol] df_trades = pd.DataFrame(data=np.zeros(len(df_prices)), index=df_prices.index, columns=['trades']) #rstd = idc.get_rolling_stdev(pd.DataFrame(df_prices, index = df_prices.index, columns = [symbol]), n_days_std) rstd = pd.rolling_std(df_prices, window=n_days_std) bband = idc.get_bbands( pd.DataFrame(df_prices, index=df_prices.index, columns=[symbol]), n_days_bb) momentum = idc.get_momentum( pd.DataFrame(df_prices, index=df_prices.index, columns=[symbol]), n_days_mtum) abs_momentum = momentum.abs() rsi = idc.get_rsi(df_prices, n_days_rsi) # use rsi to generat sell & buy signal: # > 70 : overbought : should sell # < 30 : oversold : should buy #use volatility as a filter: # if std to low, time to buy, std will increase soon, # maybe make a cross over on the rmean of std ? # if std to high, means the growth was strong but will back to the mean # use momentum to confirm sell & buy signal: # confirmed if small enough momentum # (changes in prices is slowing - time to take action) for t in range(1, len(df_prices) - 1): df_net_holdings = df_trades.cumsum(axis=0) net_holdings = df_net_holdings.values[t] if (net_holdings > 1000) | (net_holdings < -1000): print("ERROR") # buy signal if ((bband[t - 1] <= -tresh_bb) & (bband[t] > -tresh_bb)) | (rsi.iloc[t] < 30): if (abs_momentum[t] <= tresh_mmtum): if rstd[t] <= tresh_std_low: if (net_holdings == 0): df_trades.iloc[t] = 1000 elif (net_holdings == -1000): df_trades.iloc[t] = 2000 # sell signal if ((bband[t - 1] >= tresh_bb) & (bband[t] < tresh_bb)) | (rsi.iloc[t] > 70): if (abs_momentum[t] <= tresh_mmtum): if rstd[t] >= tresh_std_high: # could be remove since thresh = 0 if (net_holdings == 0): df_trades.iloc[t] = -1000 elif (net_holdings == 1000): df_trades.iloc[t] = -2000 return df_trades, rstd