def __init__(self, rsiPeriod, streakrsiPeriod, percentRankPeriod): MultiMetricMetric.__init__(self) self.close = AdjustedClose() self.rsi = RSI(metric=self.close, period=rsiPeriod) self.streak = Streak(metric=self.close) self.streakrsi = RSI(period=streakrsiPeriod, metric=self.streak) self.percentRank = PercentRank(metric=self.close, period=percentRankPeriod) self.average = AverageMetric(self.rsi, self.streakrsi, self.percentRank) self._addMetric(self.close) self._addMetric(self.rsi) self._addMetric(self.streak) self._addMetric(self.streakrsi) self._addMetric(self.percentRank) self._addMetric(self.average)
def __init__(self, period, rsiPeriod): MultiMetricMetric.__init__(self) self.rsis = list() rsi = RSI(rsiPeriod) self.rsis.append(rsi) self._addMetric(rsi) for i in range(1, period): hist = HistoricMetric(metric=rsi, period=i) self._addMetric(hist) self.rsis.append(hist)
def features(data, target): """ Given a standard yfinance data dataframe, add features that will help the balanced scorecard to recognize buy and sell signals in the data. The features are added as columns in the data dataframe. The original hist dataframe from yfinance is provided, so we can copy the target to the data dataframe. The data dataframe with the extra features is returned. The target argument contains the name of the column that contains the the target. """ # windows = [3, 5, 10, 15, 20, 30] #, 45, 60] windows = [ 10, 20, 30 ] for i in windows: ma = data.Close.rolling(i).mean() if 'MACD' in comb: data[f'MACD_{i}'] = ma - data.Close if 'PctDiff' in comb: data[f'PctDiff_{i}'] = data.Close.diff(i) if 'StdDev' in comb: data[f'StdDev_{i}'] = data.Close.rolling(i).std() # exclude_cols = [target, 'smooth', 'Close', 'Date', 'Volume', 'Dividends', 'Stock Splits'] exclude_cols = [target, 'smooth', 'Close', 'Low', 'High', 'Open', 'Date', 'Volume', 'Dividends', 'Stock Splits'] factor = data.Close.copy() for c in data.columns.tolist(): if c in exclude_cols: continue data[c] = data[c] / factor for i in windows: if 'RSI' in comb: data[f'RSI_{i}'] = RSI(data, i) / 100 if 'WPR' in comb: data[f'WPR_{i}'] = WPR(data, i) / 100 if 'MFI' in comb: data[f'MFI_{i}'] = MFI(data, i) / 100 if 'BBP' in comb: data[f'BBP_{i}'] = BBP(data, i) if 'P/E Ratio' in data.columns: if 'P/E Ratio' not in comb: log(f'Deleting P/E Ratio feature: comb={comb}') del data['P/E Ratio'] else: log(f'Keeping P/E Ratio feature: comb={comb}') data = data.dropna() return data
def compute_data(token): global one_hour_rsi #enddate = datetime.datetime(2020, 5, 4, 15,30,0,0) enddate = datetime.datetime.today() startdate = enddate - datetime.timedelta(3) try: df = historical_data.get(kite, token, startdate, enddate, candlesize) df = SuperTrend.calc(df, supertrend_period, supertrend_multiplier) df = MACD.calc(df) rsi = historical_data.get(kite, token, startdate, enddate, "60minute") rsi = RSI.calc(rsi) one_hour_rsi = rsi.RSI_14.values[-1] except Exception as e: print("******* ERROR Computing Historical Data ********", token, e) return df
def compute_data(token): global one_hour_rsi #enddate = datetime.datetime(2020, 5, 4, 15,30,0,0) enddate = datetime.datetime.today() startdate = enddate - datetime.timedelta(15) try: df = historical_data.get(kite, token, startdate, enddate, candlesize) df = EMA.calc(df, 'close', 'ema_5', 5) df = EMA.calc(df, 'close', 'ema_20', 20) df = MACD.calc(df) df = MFI.calc(df) df = VWAP.calc(df) rsi = historical_data.get(kite, token, startdate, enddate, "60minute") rsi = RSI.calc(rsi) one_hour_rsi = rsi.RSI_14.values[-2] except Exception as e: print("******* ERROR Computing Historical Data ********", token, e) return df
def __init__(self, close, rsi: indicators.RSI, fee=0.0): Strategy.__init__(self, close.index, fee=0.0) lowthreshpassed = False lowlowthreshpassed = False hithreshpassed = False hihithreshpassed = False hasbought = False close['rsi'] = rsi.data() for index, row in close.iterrows(): # achat en fonction du RSI if row['rsi'] < 33: lowthreshpassed = True if row['rsi'] < 20: lowlowthreshpassed = True if row['rsi'] > 66: hithreshpassed = True if row['rsi'] > 80: hihithreshpassed = True if row['rsi'] > 20 and lowlowthreshpassed == True: lowlowthreshpassed = False if hasbought == False: hasbought = True if row['rsi'] > 33 and lowthreshpassed == True: lowthreshpassed = False if hasbought == False: hasbought = True # on revend par RSI seulement si c'est le seul signal qui a généré l'achat if row['rsi'] < 80 and hihithreshpassed == True: hihithreshpassed = False if hasbought == True: hasbought = False if row['rsi'] < 66 and hithreshpassed == True: hithreshpassed = False if hasbought == True: hasbought = False if hasbought == True: self.signals['signal'].loc[index] = 1.0 self.signals['positions'] = self.signals['signal'].diff()
def test_run(): Traindates = pd.date_range('2008-1-1', '2009-12-31') TestDates = pd.date_range('2010-1-1', '2011-12-31') syms = ['AAPL'] prices_train = get_data(syms, Traindates) prices_test = get_data(syms, TestDates) prices_train = prices_train[syms] prices_test = prices_test[syms] bb_train = BB(prices_train, lookback=20) bb_train = bb_train.fillna(method='bfill') bb_test = BB(prices_test, lookback=20) bb_test = bb_test.fillna(method='bfill') macd_train = MACD(prices_train) macd_test = MACD(prices_test) rsi_train = RSI(prices_train, lookback=14) rsi_test = RSI(prices_test, lookback=14) df_train = pd.concat([prices_train, bb_train, macd_train, rsi_train], axis=1) df_train = df_train.fillna(method='bfill') df_test = pd.concat([prices_test, bb_test, macd_test, rsi_test], axis=1) df_test = df_test.fillna(method='bfill') indicators_train = pd.DataFrame(columns=[ 'MACD_ZERO', 'MACD_SIGNAL', 'ACROSS_BAND', 'BB_value', 'RSI', 'Decision' ]) indicators_test = pd.DataFrame(columns=[ 'MACD_ZERO', 'MACD_SIGNAL', 'ACROSS_BAND', 'BB_value', 'RSI', 'Decision' ]) indicators_train['BB_value'] = (df_train[syms[0]] - bb_train['Middle Band'] ) / (bb_train['Upper Band'] - bb_train['Middle Band']) indicators_train['MACD_ZERO'] = macd_train['MACD Line'] indicators_train['MACD_SIGNAL'] = macd_train['Signal Line'] indicators_train['ACROSS_BAND'] = bb_train['Middle Band'] indicators_train['RSI'] = rsi_train['RSI'] indicators_train = (indicators_train - indicators_train.mean(axis=0) ) / indicators_train.std(axis=0) indicators_test['BB_value'] = ( df_test[syms[0]] - bb_test['Middle Band']) / (bb_test['Upper Band'] - bb_test['Middle Band']) indicators_test['MACD_ZERO'] = macd_test['MACD Line'] indicators_test['MACD_SIGNAL'] = macd_test['Signal Line'] indicators_test['ACROSS_BAND'] = bb_test['Middle Band'] indicators_test['RSI'] = rsi_test['RSI'] indicators_test = (indicators_test - indicators_test.mean(axis=0) ) / indicators_test.std(axis=0) YBUY = 0.05 YSELL = -0.05 for (i_row, row), (i_future, future) in zip(df_train.iterrows(), df_train.shift(-21).iterrows()): if (future[syms[0]] / row[syms[0]] - 1 ) > YBUY: # if 21 days return exceed YBUY, then BUY Decision=1 indicators_train.ix[i_row, 'Decision'] = 1 if ( future[syms[0]] / row[syms[0]] - 1 ) < YSELL: # if 21 days return less than YSELL, then SELL Decision=-1 indicators_train.ix[i_row, 'Decision'] = -1 indicators_train = indicators_train.fillna(0) for (i_row, row), (i_future, future) in zip(df_test.iterrows(), df_test.shift(-21).iterrows()): if (future[syms[0]] / row[syms[0]] - 1 ) > YBUY: # if 21 days return exceed YBUY, then BUY Decision=1 indicators_test.ix[i_row, 'Decision'] = 1 if ( future[syms[0]] / row[syms[0]] - 1 ) < YSELL: # if 21 days return less than YSELL, then SELL Decision=-1 indicators_test.ix[i_row, 'Decision'] = -1 indicators_test = indicators_test.fillna(0) #print indicators file_dir_train = os.path.join('orders', 'indicators_train.csv') file_dir_test = os.path.join('orders', 'indicators_test.csv') indicators_train.to_csv(file_dir_train, header=False, index=False) indicators_test.to_csv(file_dir_test, header=False, index=False) inf_train = open('orders/indicators_train.csv') inf_test = open('orders/indicators_test.csv') data_train = np.array( [map(float, s.strip().split(',')) for s in inf_train.readlines()]) data_test = np.array( [map(float, s.strip().split(',')) for s in inf_test.readlines()]) predY_list = [0] * data_test.shape[0] for i in range(10): # bag 10 times learner = dt.DTclass(leaf_size=5, verbose=False) train_rows = int(round(1.0 * data_train.shape[0])) test_rows = int(round(1.0 * data_test.shape[0])) Xtrain = data_train[:train_rows, 0:-1] Ytrain = data_train[:train_rows, -1] Xtest = data_test[:train_rows, 0:-1] Ytest = data_test[:train_rows, -1] learner.addEvidence(Xtrain, Ytrain) # training step predY = learner.query(Xtest) # query predY_list = predY_list + predY predY = predY_list / 10.0 prices_test['decision'] = predY #print prices_port orders = pd.DataFrame(columns=['Date', 'Symbol', 'Order', 'Shares']) holding = 0 # holding =200 long; holding=-200 short window = date.datetime(2008, 1, 1) # window should more than 21 for (i_row, row) in prices_test.iterrows(): if row['decision'] < 0 and (i_row - window).days > 21 and holding > -200: orders.loc[len(orders)] = [ i_row, syms[0], 'SELL', str(200 + holding) ] holding -= 200 + holding window = i_row plt.axvline(i_row, color='r') if row['decision'] > 0 and (i_row - window).days > 21 and holding < 200: orders.loc[len(orders)] = [ i_row, syms[0], 'BUY', str(200 - holding) ] # max buy holding += 200 - holding window = i_row plt.axvline(i_row, color='g') file_dir = os.path.join('orders', 'orders_ML_test.csv') orders.to_csv(file_dir) of_ML_test = "./orders/orders_ML_test.csv" #of = "./orders/orders.csv" sv = 100000 #calculate benchmark of testing data dfprices = pd.DataFrame(prices_test) dfprices['Cash'] = sv - 200 * dfprices.ix[0, 'AAPL'] dfprices['Holding'] = 200 dfprices['Stock values'] = dfprices['Holding'] * dfprices['AAPL'] dfprices['Port_val'] = dfprices['Cash'] + dfprices['Stock values'] dfprices['Benchmark'] = dfprices['Port_val'] / dfprices['Port_val'].ix[ 0, :] benchmark = dfprices['Benchmark'] #calculate rule based on test period orders_test = pd.DataFrame(columns=['Date', 'Symbol', 'Order', 'Shares']) holding_RB = 0 # holding =200 long; holding=-200 short window_RB = date.datetime(2010, 1, 1) # window should more than 21 for (i_row, row), (i_prev, prev) in zip(df_test.iterrows(), df_test.shift(1).iterrows()): if prev['MACD Line'] >= 0 and row['MACD Line'] < 0 and ( i_row - window_RB).days > 21 and holding_RB > -200: orders_test.loc[len(orders_test)] = [ i_row, syms[0], 'SELL', str(200 + holding_RB) ] holding_RB -= 200 + holding_RB window_RB = i_row if prev['MACD Line'] <= 0 and row['MACD Line'] > 0 and ( i_row - window_RB).days > 21 and holding_RB < 200: orders_test.loc[len(orders_test)] = [ i_row, syms[0], 'BUY', str(200 - holding_RB) ] # max buy holding_RB += 200 - holding_RB window_RB = i_row if prev['MACD Line'] >= prev['Signal Line'] and row['MACD Line'] < row[ 'Signal Line'] and ( i_row - window_RB ).days > 21 and holding_RB > -200 and row['RSI'] > 70: orders_test.loc[len(orders_test)] = [ i_row, syms[0], 'SELL', str(200 + holding_RB) ] holding_RB -= 200 + holding_RB window_RB = i_row if prev['MACD Line'] <= prev['Signal Line'] and row['MACD Line'] > row[ 'Signal Line'] and (i_row - window_RB).days > 21 and holding_RB < 200: orders_test.loc[len(orders_test)] = [ i_row, syms[0], 'BUY', str(200 - holding_RB) ] # max buy holding_RB += 200 - holding_RB window_RB = i_row if prev[syms[0]] <= prev['Lower Band'] and row[ syms[0]] > row['Lower Band'] and ( i_row - window_RB ).days > 21 and holding_RB < 200: # cross up Lower Band orders_test.loc[len(orders_test)] = [ i_row, syms[0], 'BUY', str(200 - holding_RB) ] # max buy holding_RB += 200 - holding_RB window_RB = i_row if prev[syms[0]] <= prev['Middle Band'] and row[ syms[0]] > row['Middle Band'] and ( i_row - window_RB).days > 21 and holding_RB > -200 and row[ 'RSI'] > 70: # cross up Middle Band orders_test.loc[len(orders_test)] = [ i_row, syms[0], 'SELL', str(200 + holding_RB) ] holding_RB -= 200 + holding_RB window_RB = i_row # if prev[syms[0]] >= prev['Upper Band'] and row[syms[0]] < row['Upper Band'] and (i_row-window).days>21 and holding>-200 and row['RSI']>70: # cross down Upper Band # orders.loc[len(orders)] = [i_row, syms[0], 'SELL', str(200+holding)] # holding -= 200+holding # window = i_row # plt.axvline(i_row, color='r') if prev[syms[0]] >= prev['Middle Band'] and row[ syms[0]] < row['Middle Band'] and ( i_row - window_RB ).days > 21 and holding_RB < 200: # cross down Middle Band orders_test.loc[len(orders_test)] = [ i_row, syms[0], 'BUY', str(200 - holding_RB) ] holding_RB += 200 - holding_RB window_RB = i_row file_dir_RB_test = os.path.join('orders', 'orders_RB_test.csv') orders_test.to_csv(file_dir_RB_test) portvals_RB = compute_portvals(start_date=date.datetime(2010, 1, 1), end_date=date.datetime(2011, 12, 31), orders_file=file_dir_RB_test, start_val=sv) portvals_RB = portvals_RB / portvals_RB.ix[0, :] benchmark = benchmark / benchmark.ix[0, :] portvals_ML = compute_portvals(start_date=date.datetime(2010, 1, 1), end_date=date.datetime(2011, 12, 31), orders_file=of_ML_test, start_val=sv) portvals_ML = portvals_ML / portvals_ML.ix[0, :] prices_test = prices_test / prices_test.ix[0, :] plt.plot(prices_test.index, portvals_RB, label='Rule-based portfolio', color='b') plt.plot(prices_test.index, portvals_ML, label='ML-based portfolio Out of Sample', color='g') #plt.plot(prices_port.index, prices_port, label='APPL', color='m') plt.plot(benchmark.index, benchmark, label='Benchmark', color='k') plt.xlabel('Date') plt.ylabel('Price') plt.legend(loc='upper left') plt.show()
investor = Investor(models=[mr], world=w, live=False) # livetrade with investor investor.routine() ''' # --- workflow 3 --- # build base world from indicators import Moving_Average, RSI from world import world_from_live w = world_from_live( basket, cash=10000, indicators=[Moving_Average(n=200), Moving_Average(n=10), RSI(2)]) # get model from models import Mean_Reversion mr = Mean_Reversion('Mean Reversion', 200, 10, 2) # build investor from investor import Investor i = Investor(models=[mr], world=w, live=False) # set up backtest from backtest import Backtest b = Backtest(name='mean_reversion_backtest_000', investor=i, base_world=w) # show/export results b.do_backtest() b.export_history(path='backtests/') # --- workflow 4 ---
def test_run(): # Read data dates = pd.date_range('2008-1-1', '2009-12-31') syms = ['AAPL'] prices_all = get_data(syms, dates) prices_port = prices_all[syms] # only price of each stock in portfolio prices_SPY = prices_all['SPY'] # only SPY, for comparison later bb = BB(prices_port, lookback=20) macd = MACD(prices_port) rsi = RSI(prices_port, lookback=14) df = pd.concat([prices_port, bb, macd, rsi], axis=1) df = df.fillna(method='bfill') #print df #plot_data(df, title="Bollinger Bands and stock price", ylabel="Stock price", xlabel="Date") orders = pd.DataFrame(columns=['Date', 'Symbol', 'Order', 'Shares']) holding = 0 #holding =200 long; holding=-200 short window = dt.datetime(2008, 1, 1) # window should more than 21 for (i_row, row), (i_prev, prev) in zip(df.iterrows(), df.shift(1).iterrows()): if prev['MACD Line'] >= 0 and row['MACD Line'] < 0 and ( i_row - window).days > 21 and holding > -200: orders.loc[len(orders)] = [ i_row, syms[0], 'SELL', str(200 + holding) ] holding -= 200 + holding window = i_row plt.axvline(i_row, color='r') if prev['MACD Line'] <= 0 and row['MACD Line'] > 0 and ( i_row - window).days > 21 and holding < 200: orders.loc[len(orders)] = [ i_row, syms[0], 'BUY', str(200 - holding) ] #max buy holding += 200 - holding window = i_row plt.axvline(i_row, color='g') if prev['MACD Line'] >= prev['Signal Line'] and row['MACD Line'] < row[ 'Signal Line'] and ( i_row - window).days > 21 and holding > -200 and row['RSI'] > 70: orders.loc[len(orders)] = [ i_row, syms[0], 'SELL', str(200 + holding) ] holding -= 200 + holding window = i_row plt.axvline(i_row, color='r') if prev['MACD Line'] <= prev['Signal Line'] and row['MACD Line'] > row[ 'Signal Line'] and (i_row - window).days > 21 and holding < 200: orders.loc[len(orders)] = [ i_row, syms[0], 'BUY', str(200 - holding) ] #max buy holding += 200 - holding window = i_row plt.axvline(i_row, color='g') if prev[syms[0]] <= prev['Lower Band'] and row[ syms[0]] > row['Lower Band'] and ( i_row - window).days > 21 and holding < 200: # cross up Lower Band orders.loc[len(orders)] = [ i_row, syms[0], 'BUY', str(200 - holding) ] #max buy holding += 200 - holding window = i_row plt.axvline(i_row, color='g') if prev[syms[0]] <= prev['Middle Band'] and row[ syms[0]] > row['Middle Band'] and ( i_row - window).days > 21 and holding > -200 and row[ 'RSI'] > 70: # cross up Middle Band orders.loc[len(orders)] = [ i_row, syms[0], 'SELL', str(200 + holding) ] holding -= 200 + holding window = i_row plt.axvline(i_row, color='r') # if prev[syms[0]] >= prev['Upper Band'] and row[syms[0]] < row['Upper Band'] and (i_row-window).days>21 and holding>-200 and row['RSI']>70: # cross down Upper Band # orders.loc[len(orders)] = [i_row, syms[0], 'SELL', str(200+holding)] # holding -= 200+holding # window = i_row # plt.axvline(i_row, color='r') if prev[syms[0]] >= prev['Middle Band'] and row[ syms[0]] < row['Middle Band'] and ( i_row - window ).days > 21 and holding < 200: # cross down Middle Band orders.loc[len(orders)] = [ i_row, syms[0], 'BUY', str(200 - holding) ] holding += 200 - holding window = i_row plt.axvline(i_row, color='g') file_dir = os.path.join('orders', 'orders.csv') orders.to_csv(file_dir) Compare_df = BestPossible() benchmark = Compare_df['Benchmark'] of = "./orders/orders.csv" sv = 100000 portvals = compute_portvals(orders_file=of, start_val=sv) portvals = portvals / portvals.ix[0, :] benchmark = benchmark / benchmark.ix[0, :] #plot_data(plot_df, title="Benchmark vs. Rule-based portfolio", ylabel="Normalized price", xlabel="Date") prices_port = prices_port / prices_port.ix[0, :] plt.plot(prices_port.index, portvals, label='Rule-based portfolio', color='b') plt.plot(prices_port.index, prices_port, label='APPL', color='m') plt.plot(benchmark.index, benchmark, label='Benchmark', color='k') plt.title('Benchmark vs. Rule-based portfolio') plt.xlabel('Date') plt.ylabel('Price') plt.legend(loc='lower right') plt.show()
def __init__(self, fitting_file='BTC-USD_2019-04-07.csv.xz', testing_file='BTC-USD_2019-04-08.csv.xz', step_size=1, max_position=5, window_size=10, seed=1, action_repeats=10, training=True, format_3d=True, z_score=True, reward_type='default', scale_rewards=True, ema_alpha=EMA_ALPHA): """ Base class for creating environments extending OpenAI's GYM framework. :param fitting_file: historical data used to fit environment data (i.e., previous trading day) :param testing_file: historical data used in environment :param step_size: increment size for steps (NOTE: leave a 1, otherwise market transaction data will be overlooked) :param max_position: maximum number of positions able to hold in inventory :param window_size: number of lags to include in observation space :param seed: random seed number :param action_repeats: number of steps to take in environment after a given action :param training: if TRUE, then randomize starting point in environment :param format_3d: if TRUE, reshape observation space from matrix to tensor :param z_score: if TRUE, normalize data set with Z-Score, otherwise use Min-Max (i.e., range of 0 to 1) :param reward_type: method for calculating the environment's reward: 1) 'trade_completion' --> reward is generated per trade's round trip 2) 'continuous_total_pnl' --> change in realized & unrealized pnl between time steps 3) 'continuous_realized_pnl' --> change in realized pnl between time steps 4) 'continuous_unrealized_pnl' --> change in unrealized pnl between time steps 5) 'normed' --> refer to https://arxiv.org/abs/1804.04216v1 6) 'div' --> reward is generated per trade's round trip divided by inventory count (again, refer to https://arxiv.org/abs/1804.04216v1) 7) 'asymmetrical' --> extended version of *default* and enhanced with a reward for being filled above/below midpoint, and returns only negative rewards for Unrealized PnL to discourage long-term speculation. 8) 'asymmetrical_adj' --> extended version of *default* and enhanced with a reward for being filled above/below midpoint, and weighted up/down unrealized returns. 9) 'default' --> Pct change in Unrealized PnL + Realized PnL of respective time step. :param ema_alpha: decay factor for EMA, usually between 0.9 and 0.9999; if NONE, raw values are returned in place of smoothed values """ # properties required for instantiation self.action_repeats = action_repeats self._seed = seed self._random_state = np.random.RandomState(seed=self._seed) self.training = training self.step_size = step_size self.max_position = max_position self.window_size = window_size self.reward_type = reward_type self.format_3d = format_3d # e.g., [window, features, *NEW_AXIS*] self.sym = testing_file[:7] # slice the CCY from the filename self.scale_rewards = scale_rewards # properties that get reset() self.reward = 0.0 self.done = False self.local_step_number = 0 self.midpoint = 0.0 self.observation = None self.action = 0 self.last_pnl = 0. self.last_midpoint = None self.midpoint_change = None # properties to override in sub-classes self.actions = None self.broker = None self.action_space = None self.observation_space = None # get historical data for simulations self.sim = Sim(z_score=z_score, alpha=ema_alpha) self.prices_, self.data, self.normalized_data = self.sim.load_environment_data( fitting_file=fitting_file, testing_file=testing_file, include_imbalances=True, as_pandas=False) self.best_bid = self.best_ask = None self.max_steps = self.data.shape[ 0] - self.step_size * self.action_repeats - 1 # load indicators into the indicator manager self.tns = IndicatorManager() self.rsi = IndicatorManager() for window in INDICATOR_WINDOW: self.tns.add( ('tns_{}'.format(window), TnS(window=window, alpha=ema_alpha))) self.rsi.add( ('rsi_{}'.format(window), RSI(window=window, alpha=ema_alpha))) # conditionally load PnlNorm, since it calculates in O(n) time complexity self.pnl_norm = PnlNorm( window=INDICATOR_WINDOW[0], alpha=None) if self.reward_type == 'normed' else None # rendering class self._render = TradingGraph(sym=self.sym) # graph midpoint prices self._render.reset_render_data( y_vec=self.prices_[:np.shape(self._render.x_vec)[0]]) # buffer for appending lags self.data_buffer = list()
def myTradingSystem( DATE, OPEN, HIGH, LOW, CLOSE, VOL, USA_ADP, USA_EARN, USA_HRS, USA_BOT, USA_BC, USA_BI, USA_CU, USA_CF, USA_CHJC, USA_CFNAI, USA_CP, USA_CCR, USA_CPI, USA_CCPI, USA_CINF, USA_DFMI, USA_DUR, USA_DURET, USA_EXPX, USA_EXVOL, USA_FRET, USA_FBI, USA_GBVL, USA_GPAY, USA_HI, USA_IMPX, USA_IMVOL, USA_IP, USA_IPMOM, USA_CPIC, USA_CPICM, USA_JBO, USA_LFPR, USA_LEI, USA_MPAY, USA_MP, USA_NAHB, USA_NLTTF, USA_NFIB, USA_NFP, USA_NMPMI, USA_NPP, USA_EMPST, USA_PHS, USA_PFED, USA_PP, USA_PPIC, USA_RSM, USA_RSY, USA_RSEA, USA_RFMI, USA_TVS, USA_UNR, USA_WINV, exposure, equity, settings): nMarkets = CLOSE.shape[1] lookback = settings['lookback'] pos = np.zeros(nMarkets) markets = settings['markets'] w = settings['market_factor_weights'] lweights, sweights = econ_long_short_allocation( markets, DATE[0], DATE[-1], w, activate=settings['dynamic_portfolio_allocation']) sentiment_data = settings['sentiment_data'] covid_data = settings['covid_data'] # to understand how this system works print("Using data from {} onwards to predict/take position in {}".format( DATE[0], DATE[-1])) OPEN = np.transpose(OPEN)[1:] HIGH = np.transpose(HIGH)[1:] LOW = np.transpose(LOW)[1:] CLOSE = np.transpose(CLOSE)[1:] VOL = np.transpose(VOL)[1:] if settings['model'] == 'TA': ''' Based on factors from https://www.investing.com/technical/us-spx-500-futures-technical-analysis ################ TREND FOLOWING ################ Simple Moving Average (SMA) crosses, period 5,10,20,50,100,200 ''' # indicators SMA5s = [SMA(close, 5) for close in CLOSE] SMA10s = [SMA(close, 10) for close in CLOSE] SMA20s = [SMA(close, 20) for close in CLOSE] SMA50s = [SMA(close, 50) for close in CLOSE] SMA100s = [SMA(close, 100) for close in CLOSE] SMA200s = [SMA(close, 200) for close in CLOSE] # signals def buy_condition(close, sma): return (close[-1] > sma[-1]) and (close[-2] <= sma[-2]) def sell_condition(close, sma): return (close[-1] < sma[-1]) and (close[-2] >= sma[-2]) SMA5_cross_buys = [ True if buy_condition(close, sma) else False for close, sma in zip(CLOSE, SMA5s) ] SMA5_cross_sells = [ True if sell_condition(close, sma) else False for close, sma in zip(CLOSE, SMA5s) ] SMA10_cross_buys = [ True if buy_condition(close, sma) else False for close, sma in zip(CLOSE, SMA10s) ] SMA10_cross_sells = [ True if sell_condition(close, sma) else False for close, sma in zip(CLOSE, SMA10s) ] SMA20_cross_buys = [ True if buy_condition(close, sma) else False for close, sma in zip(CLOSE, SMA20s) ] SMA20_cross_sells = [ True if sell_condition(close, sma) else False for close, sma in zip(CLOSE, SMA20s) ] SMA50_cross_buys = [ True if buy_condition(close, sma) else False for close, sma in zip(CLOSE, SMA50s) ] SMA50_cross_sells = [ True if sell_condition(close, sma) else False for close, sma in zip(CLOSE, SMA50s) ] SMA100_cross_buys = [ True if buy_condition(close, sma) else False for close, sma in zip(CLOSE, SMA100s) ] SMA100_cross_sells = [ True if sell_condition(close, sma) else False for close, sma in zip(CLOSE, SMA100s) ] SMA200_cross_buys = [ True if buy_condition(close, sma) else False for close, sma in zip(CLOSE, SMA200s) ] SMA200_cross_sells = [ True if sell_condition(close, sma) else False for close, sma in zip(CLOSE, SMA200s) ] ''' Exponential Moving Average (EMA) crosses, period 5,10,20,50,100,200 ''' # indicators EMA5s = [EMA(close, 5) for close in CLOSE] EMA10s = [EMA(close, 10) for close in CLOSE] EMA20s = [EMA(close, 20) for close in CLOSE] EMA50s = [EMA(close, 50) for close in CLOSE] EMA100s = [EMA(close, 100) for close in CLOSE] EMA200s = [EMA(close, 200) for close in CLOSE] # signals # def condition(close, ema): # return (close[-1] > ema[-1]) and (close[-2] <= ema[-2]) def buy_condition(close, ema): return (close[-1] > ema[-1]) and (close[-2] <= ema[-2]) def sell_condition(close, ema): return (close[-1] < ema[-1]) and (close[-2] >= ema[-2]) EMA5_cross_buys = [ True if buy_condition(close, ema) else False for close, ema in zip(CLOSE, EMA5s) ] EMA5_cross_sells = [ True if sell_condition(close, ema) else False for close, ema in zip(CLOSE, EMA5s) ] EMA10_cross_buys = [ True if buy_condition(close, ema) else False for close, ema in zip(CLOSE, EMA10s) ] EMA10_cross_sells = [ True if sell_condition(close, ema) else False for close, ema in zip(CLOSE, EMA10s) ] EMA20_cross_buys = [ True if buy_condition(close, ema) else False for close, ema in zip(CLOSE, EMA20s) ] EMA20_cross_sells = [ True if sell_condition(close, ema) else False for close, ema in zip(CLOSE, EMA20s) ] EMA50_cross_buys = [ True if buy_condition(close, ema) else False for close, ema in zip(CLOSE, EMA50s) ] EMA50_cross_sells = [ True if sell_condition(close, ema) else False for close, ema in zip(CLOSE, EMA50s) ] EMA100_cross_buys = [ True if buy_condition(close, ema) else False for close, ema in zip(CLOSE, EMA100s) ] EMA100_cross_sells = [ True if sell_condition(close, ema) else False for close, ema in zip(CLOSE, EMA100s) ] EMA200_cross_buys = [ True if buy_condition(close, ema) else False for close, ema in zip(CLOSE, EMA200s) ] EMA200_cross_sells = [ True if sell_condition(close, ema) else False for close, ema in zip(CLOSE, EMA200s) ] ''' Average Directional Movement Index (ADX), period 14 ''' # indicators ADXs = [ ADX(high, low, close, 14) for high, low, close in zip(HIGH, LOW, CLOSE) ] # signals # adx[0] is mDI, adx[1] is pDI, adx[2] is actual ADX def bullish_condition(adx): # Bullish strong trend cross return (adx[2][-1] > 20) and (adx[1][-1] > adx[0][-1]) and ( adx[1][-2] <= adx[0][-2]) def bearish_condition(adx): # Bearish strong trend cross return (adx[2][-1] > 20) and (adx[1][-1] < adx[0][-1]) and ( adx[1][-2] >= adx[0][-2]) ADX_bullish_crosses = [ True if bullish_condition(adx) else False for adx in ADXs ] ADX_bearish_crosses = [ True if bearish_condition(adx) else False for adx in ADXs ] ''' Moving Average Convergence Divergence (MACD) fast=12, slow=26 ''' # indicator EMA12s = [EMA(close, 12) for close in CLOSE] EMA26s = [EMA(close, 26) for close in CLOSE] MACDs = [[(a - b) if b is not None else None for a, b in zip(EMA12, EMA26)] for EMA12, EMA26 in zip(EMA12s, EMA26s)] # signals def bullish_condition(MACD): # Bullish zero cross which sustains for 2 days (reduce false signals) return (MACD[-3] <= 0) and (MACD[-2] > 0) and (MACD[-1] > 0) def bearish_condition(MACD): # Bearish zero cross return (MACD[-3] >= 0) and (MACD[-2] < 0) and (MACD[-1] < 0) MACD_bullish_zero_cross = [ True if bullish_condition(MACD) else False for MACD in MACDs ] MACD_bearish_zero_cross = [ True if bearish_condition(MACD) else False for MACD in MACDs ] ''' Commodity Channel Index (CCI), period 14 ''' # indicator CCIs = [ CCI(high, low, close, 14) for high, low, close in zip(HIGH, LOW, CLOSE) ] # signals def bullish_condition(CCI): return (CCI[-1] > 100) and (CCI[-2] <= 100) def bearish_condition(CCI): return (CCI[-1] < -100) and (CCI[-2] >= -100) CCI_emerging_bulls = [ True if bullish_condition(CCI) else False for CCI in CCIs ] CCI_emerging_bears = [ True if bearish_condition(CCI) else False for CCI in CCIs ] ''' ################ MOMENTUM ################ Relative Strength Index (RSI), period 14 ''' # indicator RSIs = [RSI(close) for close in CLOSE] # signals def bullish_reversal(rsi, sma200, close): # Uptrend and cross 30 to become oversold (Bullish) return (close[-1] > sma200[-1]) and (rsi[-2] >= 30) and (rsi[-1] < 30) def bearish_reversal(rsi, sma200, close): # Downtrend and cross 70 to become overbought (Bearish) return (close[-1] < sma200[-1]) and (rsi[-2] <= 70) and (rsi[-1] > 70) def underbought_uptrend(rsi, sma200, close): # Uptrend and underbought return (close[-1] > sma200[-1]) and (rsi[-1] < 50) def undersold_downtrend(rsi, sma200, close): # Downtrend and undersold return (close[-1] < sma200[-1]) and (rsi[-1] > 50) RSI_bullish_reversal = [ True if bullish_reversal(rsi, sma200, close) else False for rsi, sma200, close in zip(RSIs, SMA200s, CLOSE) ] RSI_bearish_reversal = [ True if bearish_reversal(rsi, sma200, close) else False for rsi, sma200, close in zip(RSIs, SMA200s, CLOSE) ] RSI_underbought_uptrend = [ True if underbought_uptrend(rsi, sma200, close) else False for rsi, sma200, close in zip(RSIs, SMA200s, CLOSE) ] RSI_undersold_downtrend = [ True if undersold_downtrend(rsi, sma200, close) else False for rsi, sma200, close in zip(RSIs, SMA200s, CLOSE) ] ''' Stochastic Oscillator, fast 14, slow 3 ''' # indicators StochOscs = [ StochOsc(close, high, low, 14, 3) for close, high, low in zip(CLOSE, HIGH, LOW) ] # signals # stochosc[0] is Ks, stochosc[1] is Ds def bullish_cross(stochosc): # K (fast) cross D (slow) from below return (stochosc[0][-2] <= stochosc[1][-2]) and (stochosc[0][-1] > stochosc[1][-1]) def bearish_cross(stochosc): # K (fast) cross D (slow) from above return (stochosc[0][-2] >= stochosc[1][-2]) and (stochosc[0][-1] < stochosc[1][-1]) StochOsc_bullish_cross = [ True if bullish_cross(stochosc) else False for stochosc in StochOscs ] StochOsc_bearish_cross = [ True if bearish_cross(stochosc) else False for stochosc in StochOscs ] ''' Williams %R, 14 period ''' # indicator WilliamsRs = [ WilliamsR(high, low, close) for high, low, close in zip(HIGH, LOW, CLOSE) ] # signals def bullish(wr, close, sma100): # Overbought price action return (wr[-1] > -20) and (close[-1] > sma100[-1]) and ( close[-2] <= sma100[-2]) def bearish(wr, close, sma100): # Oversold price action return (wr[-1] < -80) and (close[-1] < sma100[-1]) and ( close[-2] >= sma100[-2]) WilliamsR_uptrend = [ True if bullish(wr, close, sma100) else False for wr, close, sma100 in zip(WilliamsRs, CLOSE, SMA100s) ] WilliamsR_downtrend = [ True if bearish(wr, close, sma100) else False for wr, close, sma100 in zip(WilliamsRs, CLOSE, SMA100s) ] ''' Ultimate Oscillator, periods 20,40,80 ''' # indicator UltiOscs = [ UltiOsc(high, low, close, 20, 40, 80) for high, low, close in zip(HIGH, LOW, CLOSE) ] # signals def bullish_cross(ultiosc): # Bullish center cross return (ultiosc[-1] > 50) and (ultiosc[-2] <= 50) def bearish_cross(ultiosc): # Bearish center cross return (ultiosc[-1] < 50) and (ultiosc[-2] >= 50) def bullish_reversal(ultiosc): # Bullish reversal from oversold return (ultiosc[-1] < 30) and (ultiosc[-2] >= 30) def bearish_reversal(ultiosc): # Bearish reversal from overbought return (ultiosc[-1] > 70) and (ultiosc[-2] >= 70) UltiOsc_bullish_cross = [ True if bullish_cross(ultiosc) else False for ultiosc in UltiOscs ] UltiOsc_bearish_cross = [ True if bearish_cross(ultiosc) else False for ultiosc in UltiOscs ] UltiOsc_bullish_reversal = [ True if bullish_reversal(ultiosc) else False for ultiosc in UltiOscs ] UltiOsc_bearish_reversal = [ True if bearish_reversal(ultiosc) else False for ultiosc in UltiOscs ] ''' ################ VOLUME ################ Accumulation / Distribution Index (ADI) ''' # indicator ADIs = [ ADI(high, low, close, vol) for high, low, close, vol in zip(HIGH, LOW, CLOSE, VOL) ] def bullish_trend(close, adi, sma200): # bullish trend confirmation return (close[-1] > sma200[-1]) and (close[-2] <= sma200[-2]) and ( adi[-1] > adi[-2]) def bearish_trend(close, adi, sma200): # bearish trend confirmation return (close[-1] < sma200[-1]) and (close[-2] >= sma200[-2]) and ( adi[-1] < adi[-2]) ADI_bullish_trend_confo = [ True if bullish_trend(close, adi, sma200) else False for close, adi, sma200 in zip(CLOSE, ADIs, SMA200s) ] ADI_bearish_trend_confo = [ True if bearish_trend(close, adi, sma200) else False for close, adi, sma200 in zip(CLOSE, ADIs, SMA200s) ] ''' On-Balance Volume (OBV) ''' # indicator OBVs = [OBV(close, vol) for close, vol in zip(CLOSE, VOL)] # signals def bullish_trend(obv): return (obv[-1] > obv[-2]) and (obv[-2] > obv[-3]) def bearish_trend(obv): return (obv[-1] < obv[-2]) and (obv[-2] < obv[-3]) OBV_bullish_trend_confo = [ True if bullish_trend(obv) else False for obv in OBVs ] OBV_bearish_trend_confo = [ True if bearish_trend(obv) else False for obv in OBVs ] ''' ################ VOLATILITY ################ Bollinger Bands (BB), 20 period ''' # indicator + signal BBs = [BB(close, 20) for close in CLOSE] BB_bullish_reversal = [True if bb[1][-1] == 1 else False for bb in BBs] BB_bearish_reversal = [True if bb[0][-1] == 1 else False for bb in BBs] ''' Execution ''' for i in range(0, nMarkets - 1): future_name = markets[i + 1] # # Trend following # if (SMA5_cross_buys[i] == True) or (SMA10_cross_buys[i] == True) or (SMA20_cross_buys[i] == True) or (SMA50_cross_buys[i] == True) or (SMA100_cross_buys[i] == True) or (SMA200_cross_buys == True): # pos[i+1] = 1 # if (SMA5_cross_sells[i] == True) or (SMA10_cross_sells[i] == True) or (SMA20_cross_sells[i] == True) or (SMA50_cross_sells[i] == True) or (SMA100_cross_sells[i] == True) or (SMA200_cross_sells == True): # pos[i+1] = -1 # Mean reverting # if (SMA5_cross_buys[i] == True) or (SMA10_cross_buys[i] == True) or (SMA20_cross_buys[i] == True) or (SMA50_cross_buys[i] == True) or (SMA100_cross_buys[i] == True) or (SMA200_cross_buys == True): # pos[i+1] = -1 # if (SMA5_cross_sells[i] == True) or (SMA10_cross_sells[i] == True) or (SMA20_cross_sells[i] == True) or (SMA50_cross_sells[i] == True) or (SMA100_cross_sells[i] == True) or (SMA200_cross_sells == True): # pos[i+1] = 1 # # Trend following # if (EMA5_cross_buys[i] == True) or (EMA10_cross_buys[i] == True) or (EMA20_cross_buys[i] == True) or (EMA50_cross_buys[i] == True) or (EMA100_cross_buys[i] == True) or (EMA200_cross_buys == True): # pos[i+1] = 1 # if (EMA5_cross_sells[i] == True) or (EMA10_cross_sells[i] == True) or (EMA20_cross_sells[i] == True) or (EMA50_cross_sells[i] == True) or (EMA100_cross_sells[i] == True) or (EMA200_cross_sells == True): # pos[i+1] = -1 # # Mean-reverting # if (EMA5_cross_buys[i] == True) or (EMA10_cross_buys[i] == True) or (EMA20_cross_buys[i] == True) or (EMA50_cross_buys[i] == True) or (EMA100_cross_buys[i] == True) or (EMA200_cross_buys == True): # pos[i+1] = -1 # if (EMA5_cross_sells[i] == True) or (EMA10_cross_sells[i] == True) or (EMA20_cross_sells[i] == True) or (EMA50_cross_sells[i] == True) or (EMA100_cross_sells[i] == True) or (EMA200_cross_sells == True): # pos[i+1] = 1 # if ADX_bullish_crosses[i] == True: # pos[i+1] = 1 # elif ADX_bearish_crosses[i] == True: # pos[i+1] = -1 # if MACD_bullish_zero_cross[i] == True: # pos[i+1] = 1 # elif MACD_bearish_zero_cross[i] == True: # pos[i+1] = -1 # if CCI_emerging_bulls[i] == True: # pos[i+1] = 1 # elif CCI_emerging_bears[i] == True: # pos[i+1] = -1 # if RSI_bullish_reversal[i] == True: # pos[i+1] = 1 # elif RSI_bearish_reversal[i] == True: # pos[i+1] = -1 # if StochOsc_bullish_cross[i] == True: # pos[i+1] = 1 # elif StochOsc_bearish_cross[i] == True: # pos[i+1] = -1 # if WilliamsR_uptrend[i] == True: # pos[i+1] = 1 # elif WilliamsR_downtrend[i] == True: # pos[i+1] = -1 # if UltiOsc_bullish_cross[i] == True: # pos[i+1] = 1 # elif UltiOsc_bearish_cross[i] == True: # pos[i+1] = -1 # if UltiOsc_bullish_reversal[i] == True: # pos[i+1] = 1 # elif UltiOsc_bearish_reversal[i] == True: # pos[i+1] = -1 # if ADI_bullish_trend_confo[i] == True: # pos[i+1] = lweights[future_name] # elif ADI_bearish_trend_confo[i] == True: # pos[i+1] = sweights[future_name] # if OBV_bullish_trend_confo[i] == True: # pos[i+1] = 1 # elif OBV_bearish_trend_confo[i] == True: # pos[i+1] = -1 # # Mean-reverting # if BB_bullish_reversal[i] == True: # pos[i+1] = 1 # elif BB_bearish_reversal[i] == True: # pos[i+1] = -1 # # Trend-following if BB_bullish_reversal[i] == True: pos[i + 1] = sweights[future_name] elif BB_bearish_reversal[i] == True: pos[i + 1] = lweights[future_name] elif settings['model'] == 'LIGHTGBM': for i in range(0, nMarkets - 1): future_name = markets[i + 1] if future_name in [ "CASH", "F_ED", "F_UZ", "F_SS", "F_ZQ", "F_EB", "F_VW", "F_F" ]: feature_ADI = ADI(HIGH[i], LOW[i], CLOSE[i], VOL[i]) feature_WilliamsR = WilliamsR(HIGH[i], LOW[i], CLOSE[i]) feature_BB_high_crosses, feature_BB_low_crosses = BB( CLOSE[i], 10) feature_CCI = CCI(LOW[i], CLOSE[i], VOL[i], 10) features = np.array([[ OPEN[i][-1], HIGH[i][-1], LOW[i][-1], CLOSE[i][-1], VOL[i][-1], feature_ADI[-1], feature_WilliamsR[-1], feature_BB_high_crosses[-1], feature_BB_low_crosses[-1], feature_CCI[-1], CLOSE[i][-2], CLOSE[i][-3], ]]) model_dir = f"./data/lgb_models/{markets[i+1]}_model" prediction = get_lgb_prediction(model_dir, features)[0] if prediction == 1: pos[i + 1] = lweights[future_name] elif prediction == -1: pos[i + 1] = sweights[future_name] elif settings['model'] == 'sentiment': ''' How sentiment of tweets from Bloomberg/Trump affect VIX, Gold and Treasuries ''' for i in range(0, nMarkets - 1): future_name = markets[i + 1] if future_name in ['F_GC']: #'F_VX','F_GC','F_TU' sentiment = sentiment_data[future_name] today = datetime.strptime(str(DATE[-1]), '%Y%m%d').date() if (today - sentiment['DATE'].tolist()[0] ).days > 30: # at least 30 days for training train = sentiment[sentiment['DATE'] < today] test = sentiment[sentiment['DATE'] == today] trainY = train['CLOSE'] del train['DATE'], train['CLOSE'] trainX = train del test['DATE'], test['CLOSE'] model = RandomForestRegressor() model.fit(trainX, trainY) pred_CLOSE = model.predict(test)[0] if pred_CLOSE > CLOSE[i][-2]: pos[i + 1] = 1 else: pos[i + 1] = -1 elif settings['model'] == 'covid': ''' How no. of covid cases in each country affects their overall markets 'sharpe': 1.3048, 'sortino': 2.3477, avg longs per day: 1.35 , avg shorts per day: 6.6 ''' for i in range(0, nMarkets - 1): country = None future_name = markets[i + 1] if future_name in ['F_ES', 'F_MD', 'F_NQ', 'F_RU', 'F_XX', 'F_YM']: country = 'US' elif future_name in ['F_AX', 'F_DM', 'F_DZ']: country = 'Germany' elif future_name == 'F_CA': country = 'France' elif future_name == 'F_LX': country = 'United Kingdom' elif future_name == 'F_FP': country = 'Finland' elif future_name == 'F_NY': country = 'Japan' elif future_name == 'F_PQ': country = 'Portugal' elif future_name in ['F_SH', 'F_SX']: country = 'Switzerland' if country: df = covid_data[covid_data['Country/Region'] == country].T.sum( axis=1).reset_index() df = df.iloc[1:] df['index'] = df['index'].apply(lambda x: x + "20") df['index'] = df['index'].apply( lambda x: datetime.strptime(x, '%m/%d/%Y').date()) future = pd.DataFrame({'DATE': DATE, 'CLOSE': CLOSE[i]}) future['CLOSE'] = future['CLOSE'].shift(-1) future['DATE'] = future['DATE'].apply( lambda x: datetime.strptime(str(x), '%Y%m%d').date()) df = pd.merge(df, future, left_on='index', right_on='DATE') df = df[df[0] != 0][[0, 'CLOSE']].rename(columns={0: "count"}) if len(df) > 10: reg = LinearRegression().fit( np.array(df['count'].values[:-1]).reshape(-1, 1), df['CLOSE'].values[:-1]) pred_CLOSE = reg.predict( np.array(df['count'].values[-1]).reshape(1, -1))[0] if pred_CLOSE > CLOSE[i][-2]: pos[i + 1] = 1 else: pos[i + 1] = -1 elif settings['model'] == 'ARIMA': for i in range(0, nMarkets - 1): try: if markets[i + 1] not in ARIMA_MODELS: model = auto_arima(np.log(CLOSE[i][:-1]), trace=False, error_action='ignore', suppress_warnings=True) ARIMA_MODELS[markets[i + 1]] = model.fit( np.log(CLOSE[i][:-1])) model = ARIMA_MODELS[markets[i + 1]].fit(np.log(CLOSE[i][:-1])) pred = model.predict(n_periods=1)[0] # print(markets[i+1],pred, np.log(CLOSE[i][-1])) pos[i + 1] = 1 if pred > np.log(CLOSE[i][-1]) else -1 except: pos[i + 1] = 0 print(f"Today's position in the {len(markets)} futures: {pos}") elif settings['model'] == 'GARCH': # Log return of the closing data #Prameters bound1 = 1 bound2 = 1 cor_dir = f'./data/garch_models/correlation.txt' with open(cor_dir) as f: cor_dict = json.load(f) log_return = np.diff(np.log(CLOSE)) #print(log_return) #log_return = log_return[~np.isnan(log_return)] #print(log_return[1]) for i in range(0, nMarkets - 1): train_Xs = log_return[i][:-1] #test_Xs = log_return[i][-1] sd = np.var(train_Xs) # define model model_dir = f'./data/garch_models/{markets[i+1]}_garch_model.txt' with open(model_dir) as f: params_dict = json.load(f) p = params_dict['order'][0] q = params_dict['order'][1] model = arch_model(train_Xs, p=p, q=q) model_fixed = model.fix(params_dict['params']) # forecast the test set forecasts = model_fixed.forecast() #expected = forecasts.mean.iloc[-1:]['h.1'] var = forecasts.variance.iloc[-1:]['h.1'] #print(type(variance)) if (cor_dict[markets[i + 1]] > 0.03): if (float(np.sqrt(var)) > bound1 * np.std(train_Xs)): pos[i] = 1 elif (float(np.sqrt(var)) < bound2 * np.std(train_Xs)): pos[i] = -1 else: pos[i] = 0 elif (cor_dict[markets[i + 1]] < -0.03): if (float(np.sqrt(var)) > bound1 * np.std(train_Xs)): pos[i] = -1 elif (float(np.sqrt(var)) < bound2 * np.std(train_Xs)): pos[i] = 1 else: pos[i] = 0 else: pos[i] = 0 # With the estimated return and variance, we can apply portfolio optimization #print((np.array(result) * np.array(truth)).sum() / len(result)) elif settings['model'] == 'fourier': #Parameters that filter the signal with specific range of signals #Note that the lower bound should be larger than 0 and upper bound smaller than 1 filter_type = 'customed' my_frequency_bound = [0.05, 0.2] filter_type = 'low' #Specify high/mid/low/customed for weekly signals, weekly to monthly signals, above monthly signals or customed frequency range if filter_type == 'high': frequency_bound = [0.2, 1] elif filter_type == 'mid': frequency_bound = [0.05, 0.2] elif filter_type == 'low': frequency_bound = [0, 0.05] elif filter_type == 'customed': frequency_bound = my_frequency_bound #Transform the close data by fourier filtering, only signals within the specific range remains transformed_close = [] for i in range(0, nMarkets - 1): signal = CLOSE[i][:-1] fft = np.fft.rfft(signal) T = 1 # sampling interval N = len(signal) f = np.linspace(0, 1 / T, N) fft_filtered = [] for j in range(int(N / 2)): if f[j] > frequency_bound[0] and f[j] < frequency_bound[1]: fft_filtered.append(fft[j]) else: fft_filtered.append(0) signal_filtered = np.fft.irfft(fft_filtered) transformed_close.append(list(signal_filtered)) periodLonger = 200 periodShorter = 40 smaLongerPeriod = np.nansum( np.array(transformed_close)[:, -periodLonger:], axis=1) / periodLonger smaShorterPeriod = np.nansum( np.array(transformed_close)[:, -periodShorter:], axis=1) / periodShorter longEquity = smaShorterPeriod > smaLongerPeriod shortEquity = ~longEquity pos_1 = np.zeros(nMarkets - 1) pos_1[longEquity] = 1 pos_1[shortEquity] = -1 pos = np.array([0] + list(pos_1)) elif settings['model'] == 'pearson': ''' Pairwise correlation, taking position based on the greatest variation from average of the past 50 periods of 50 days ''' #'sharpe': 0.57939, 'sortino': 0.9027189, 'returnYearly': 0.076509, 'volaYearly': 0.13205 # with allocation #avg longs per day: 6.343 , avg shorts per day: 6.746 d = {} ##Name of future : Close of all 88 futures names = [] ##names of all 88 future for i in range(0, nMarkets - 1): n = markets[i + 1] names.append(n) d[n] = (CLOSE[i]) d_corr = settings['historic_corr'] ## key = tuple of name of 2 futures, value = position to take for ((future1,future2),difference) d_position = {} for i in list(d_corr.keys()): f = i[0] s = i[1] tup = d_corr[i] l1 = d[f][-49:-1] ##take last 50 close l2 = d[s][-49:-1] ##take last 50 close corr, _ = pearsonr(l1, l2) change_f = d[f][-2] - d[f][-49] change_s = d[s][-2] - d[s][-49] diff = tup - corr if diff > 0.3: if change_f > change_s: d_position[i] = ( (-1, 1), diff ) ##assuming -1 means short while 1 means long else: d_position[i] = ((1, -1), diff) for i in range( len(names)): ##find position based on greatest variation diff = 0 pair = tuple() name = names[i] counter = 0 for k in list(d_position.keys()): if name in k: counter += 1 pair = k if counter == 1: if name == k[0]: if d_position[k][0][0] > 0: pos[i + 1] = lweights[name] else: pos[i + 1] = sweights[name] else: if d_position[k][0][1] > 0: pos[i + 1] = lweights[name] else: pos[i + 1] = sweights[name] elif settings['model'] == 'FASTDTW': #'sharpe': 4.8632971, 'sortino': 17.09129, 'returnYearly': 1.216714, 'volaYearly': 0.25018 # no allocation # avg longs per day: 0.328 , avg shorts per day: 0.281 d = {} ##Name of future : Close of all 88 futures names = [] ##names of all 88 future for i in range(0, nMarkets - 1): n = markets[i + 1] names.append(n) d[n] = (CLOSE[i]) d_dist = settings[ 'historic_dist'] ## key = tuple of name of 2 futures, value = average distance d_position = {} for i in list(d_dist.keys()): f = i[0] s = i[1] tup = d_dist[i] l1 = d[f][-49:-1] ##take last 50 close l2 = d[s][-49:-1] ##take last 50 close distance, _ = fastdtw(l1, l2) distance = distance / 50 change_f = d[f][-2] - d[f][-49] change_s = d[s][-2] - d[s][-49] diff = distance - tup threshold = 16 * tup if distance > threshold: if change_f > change_s: d_position[i] = ( (-1, 1), diff ) ##assuming -1 means short while 1 means long else: d_position[i] = ((1, -1), diff) for i in range( len(names)): ##find position based on greatest variation diff = 0 name = names[i] for k in list(d_position.keys()): if name in k: if d_position[k][1] > diff: diff = d_position[k][1] if name == k[0]: if d_position[k][0][0] > 0: pos[i + 1] = lweights[name] else: pos[i + 1] = sweights[name] else: if d_position[k][0][1] > 0: pos[i + 1] = lweights[name] else: pos[i + 1] = sweights[name] # check if latest economic data suggests downturn then activate short only strats print("Positions:", pos) if np.nansum(pos) > 0: pos = pos / np.nansum(abs(pos)) settings['longs'] = settings['longs'] + sum(1 for x in pos if x > 0) settings['shorts'] = settings['shorts'] + sum(1 for x in pos if x < 0) settings['days'] = settings['days'] + 1 return pos, settings
def application(): if request.method == 'POST': new_request = request.get_json(force=True) new_ticker = get_ticker(new_request) private_client = AuthenticatedClient(Data.API_Public_Key, Data.API_Secret_Key, Data.Passphrase) new_order = Order(private_client) position = OpenPosition(new_order) funds = Capital(private_client) indicator = Indicator() macd = MACD() candle_ticker: str stop_time: int candle_gra = int if position.get_position() and last_instance(): candle_ticker = new_order.get_key("product_id") stop_time = get_time(27976) candle_gra = 300 writer = open(Data.Time, "w") writer.write(str(time.time() + 5.0)) writer.close() elif position.get_position() is False: candle_ticker = new_ticker stop_time = get_time(83925) candle_gra = 900 try: indicator.set_candles(product=candle_ticker, callback=stop_time, begin=get_time(0), granularity=candle_gra) except ValueError as ve: print(ve.with_traceback()) except NameError as ne: print(ne.with_traceback()) indicator_list = [indicator, macd] try: for value in indicator_list: value.candles = indicator.candles value.set_indicator() value.set_dates() except Exception as e: print(e.with_traceback()) indicator_5m = Indicator() macd_5m = MACD() if position.get_position() is False: if macd.hist[-1] > macd.hist[-2]: try: indicator_5m.set_candles(product=new_ticker, callback=get_time(27976), begin=get_time(0), granularity=900) except ValueError as ve: print(ve.with_traceback()) else: indicator_5m = indicator macd_5m = macd volume_5m = VolSMA(timeperiod=20) bands2dev_5m = BB() bands1dev_5m = BB(ndbevup=1, nbdevdn=1) rsi_5m = RSI() ema_5m = EMA() momentum_5m = Momentum() indicators = [ indicator_5m, macd_5m, volume_5m, bands1dev_5m, bands2dev_5m, rsi_5m, ema_5m, momentum_5m ] try: for value in indicators: value.candles = indicator_5m.candles value.set_indicator() value.set_dates() except Exception as e: print(e.with_traceback()) strategy_5m = Strategy(indicator_5m, macd_5m, bands1dev_5m, bands2dev_5m, volume_5m, rsi_5m, ema_5m, new_order) try: strategy_5m.strategy(-1) except Exception as e: print(e.with_traceback()) trade_side: str trade_product: str trade_funds: str if (new_order.is_bottom()) and (position.get_position() is False): trade_side = "buy" trade_product = new_ticker trade_funds = funds.get_capital() elif (new_order.is_top()) and (position.get_position()): trade_side = "sell" trade_product = new_order.get_key("product_id") trade_funds = get_size(trade_product, new_order.get_key("filled_size")) try: new_trade = private_client.place_market_order( product_id=trade_product, side=trade_side, funds=trade_funds) writer = open(Data.Path, "w") writer.write(new_trade['id']) writer.close() writer = open(Data.Time, "w") writer.write(new_trade['done_at']) writer.close() except NameError as ne: print(ne.with_traceback()) except KeyError as ke: print(ke.with_traceback()) return 'success', 200 elif request.method == 'GET': return redirect('http://3.218.228.129/login') else: abort(400)
def __init__(self, rsi=RSI(), order=Order()): super(RSISTrategy, self).__init__(rsi=rsi, order=order)
bbp = BBP(pdf, lookback) print('BBP:') print("====") print('') print(bbp.tail(30)) print('') plot_BBP(sym, bbp, pdf) # rsi = RSI_indicator_v1(pdf, lookback) # rsi = RSI_indicator_v2(pdf, lookback) # rsi = RSI_indicator_v3(pdf, lookback) # rsi = RSI_indicator_v4(pdf, lookback) # rsi = RSI_indicator_v5(pdf, lookback) # rsi = RSI_indicator_v6(pdf, lookback) rsi = RSI(pdf, lookback) print('RSI:') print("====") print('') print(rsi.tail(30)) print('') plot_RSI(sym, rsi, pdf) mfi = MFI(vdf, hdf, ldf, pdf, lookback) print('MFI:') print("====") print('') print(mfi.tail(30)) print('') plot_MFI(sym, mfi, pdf)
def test_run(): #construct indicator and decision dates = pd.date_range('2008-1-1', '2009-12-31') syms = ['AAPL'] prices_all = get_data(syms, dates) prices_port = prices_all[syms] # only price of each stock in portfolio bb = BB(prices_port, lookback=20) bb=bb.fillna(method='bfill') macd = MACD(prices_port) rsi = RSI(prices_port, lookback=14) df = pd.concat([prices_port, bb, macd, rsi], axis=1) df = df.fillna(method='bfill') indicators = pd.DataFrame(columns=['MACD_ZERO', 'MACD_SIGNAL', 'ACROSS_BAND', 'BB_value', 'RSI','Decision']) indicators['BB_value'] = (df[syms[0]] - bb['Middle Band']) / (bb['Upper Band'] - bb['Middle Band']) indicators['MACD_ZERO']=macd['MACD Line'] indicators['MACD_SIGNAL'] = macd['Signal Line'] indicators['ACROSS_BAND'] = bb['Middle Band'] indicators['RSI'] = rsi['RSI'] indicators2 = indicators[['MACD_SIGNAL', 'MACD_ZERO']] indicators2 = (indicators2 - indicators2.mean(axis=0)) / indicators2.std(axis=0) indicators2['Color']='k' # construct indicators # for (i_row, row), (i_prev, prev) in zip(df.iterrows(), df.shift(1).iterrows()): # if prev['MACD Line'] >= 0 and row['MACD Line'] < 0: # MACD prev>0,now<0, SELL MACD_ZERO=-1 # indicators.ix[i_row,'MACD_ZERO']=-1 # if prev['MACD Line'] <= 0 and row['MACD Line'] > 0: # MACD prev<0,now>0, BUY MACD_ZERO=1 # indicators.ix[i_row, 'MACD_ZERO'] = 1 # if prev['MACD Line'] >= prev['Signal Line'] and row['MACD Line'] < row['Signal Line']: # MACD prev>Signal Line,now<Signal line, SELL MACD_Signal=-1 # indicators.ix[i_row,'MACD_SIGNAL']=-1 # if prev['MACD Line'] <= prev['Signal Line'] and row['MACD Line'] > row['Signal Line']: # MACD prev<Signal Line,now>Signal line, BUY MACD_Signal=1 # indicators.ix[i_row, 'MACD_SIGNAL'] = 1 # if prev[syms[0]] <= prev['Lower Band'] and row[syms[0]] > row['Lower Band']: # cross up Lower Band, BUY Acroo_band=1 # indicators.ix[i_row, 'ACROSS_BAND'] = 1 # if prev[syms[0]] >= prev['Upper Band'] and row[syms[0]] < row['Upper Band']: # cross down Upper Band SELL Acroo_band=-1 # indicators.ix[i_row, 'ACROSS_BAND'] = -1 # if row['RSI']>70: #RSI>70 overbought, likely to sell it # indicators.ix[i_row, 'RSI'] = -1 # if row['RSI'] < 30: #RSI<30, oversold, likely to buy it. # indicators.ix[i_row, 'RSI'] = 1 # construct decision indicators = (indicators - indicators.mean(axis=0)) / indicators.std(axis=0) YBUY=0.05 YSELL=-0.05 for (i_row, row), (i_future, future) in zip(df.iterrows(), df.shift(-21).iterrows()): if (future[syms[0]]/row[syms[0]]-1)> YBUY: # if 21 days return exceed YBUY, then BUY Decision=1 indicators.ix[i_row, 'Decision'] = 1 indicators2.ix[i_row, 'Color'] = 'g' if (future[syms[0]] / row[syms[0]] - 1) < YSELL: # if 21 days return less than YSELL, then SELL Decision=-1 indicators.ix[i_row, 'Decision'] = -1 indicators2.ix[i_row, 'Color'] = 'r' indicators=indicators.fillna(0) #print indicators file_dir = os.path.join('orders', 'indicators.csv') file_dir2 = os.path.join('orders', 'Training data.csv') indicators.to_csv(file_dir, header=False, index=False) indicators2.to_csv(file_dir2)
def __init__(self, symbol: str, fitting_file: str, testing_file: str, max_position: int = 10, window_size: int = 100, seed: int = 1, action_repeats: int = 5, training: bool = True, format_3d: bool = False, reward_type: str = 'default', transaction_fee: bool = True, ema_alpha: list or float or None = EMA_ALPHA): """ Base class for creating environments extending OpenAI's GYM framework. :param symbol: currency pair to trade / experiment :param fitting_file: prior trading day (e.g., T-1) :param testing_file: current trading day (e.g., T) :param max_position: maximum number of positions able to hold in inventory :param window_size: number of lags to include in observation space :param seed: random seed number :param action_repeats: number of steps to take in environment after a given action :param training: if TRUE, then randomize starting point in environment :param format_3d: if TRUE, reshape observation space from matrix to tensor :param reward_type: method for calculating the environment's reward: 1) 'default' --> inventory count * change in midpoint price returns 2) 'default_with_fills' --> inventory count * change in midpoint price returns + closed trade PnL 3) 'realized_pnl' --> change in realized pnl between time steps 4) 'differential_sharpe_ratio' --> http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.1.7210&rep=rep1&type=pdf 5) 'asymmetrical' --> extended version of *default* and enhanced with a reward for being filled above or below midpoint, and returns only negative rewards for Unrealized PnL to discourage long-term speculation. 6) 'trade_completion' --> reward is generated per trade's round trip :param ema_alpha: decay factor for EMA, usually between 0.9 and 0.9999; if NONE, raw values are returned in place of smoothed values """ assert reward_type in VALID_REWARD_TYPES, \ 'Error: {} is not a valid reward type. Value must be in:\n{}'.format( reward_type, VALID_REWARD_TYPES) self.viz = Visualize( columns=['midpoint', 'buys', 'sells', 'inventory', 'realized_pnl'], store_historical_observations=True) # get Broker class to keep track of PnL and orders self.broker = Broker(max_position=max_position, transaction_fee=transaction_fee) # properties required for instantiation self.symbol = symbol self.action_repeats = action_repeats self._seed = seed self._random_state = np.random.RandomState(seed=self._seed) self.training = training self.max_position = max_position self.window_size = window_size self.reward_type = reward_type self.format_3d = format_3d # e.g., [window, features, *NEW_AXIS*] self.testing_file = testing_file # properties that get reset() self.reward = np.array([0.0], dtype=np.float32) self.step_reward = np.array([0.0], dtype=np.float32) self.done = False self.local_step_number = 0 self.midpoint = 0.0 self.observation = None self.action = 0 self.last_pnl = 0. self.last_midpoint = None self.midpoint_change = None self.A_t, self.B_t = 0., 0. # variables for Differential Sharpe Ratio self.episode_stats = ExperimentStatistics() self.best_bid = self.best_ask = None # properties to override in sub-classes self.actions = None self.action_space = None self.observation_space = None # get historical data for simulations self.data_pipeline = DataPipeline(alpha=ema_alpha) # three different data sets, for different purposes: # 1) midpoint_prices - midpoint prices that have not been transformed # 2) raw_data - raw limit order book data, not including imbalances # 3) normalized_data - z-scored limit order book and order flow imbalance # data, also midpoint price feature is replace by midpoint log price change self._midpoint_prices, self._raw_data, self._normalized_data = \ self.data_pipeline.load_environment_data( fitting_file=fitting_file, testing_file=testing_file, include_imbalances=True, as_pandas=True, ) # derive best bid and offer self._best_bids = self._raw_data['midpoint'] - ( self._raw_data['spread'] / 2) self._best_asks = self._raw_data['midpoint'] + ( self._raw_data['spread'] / 2) self.max_steps = self._raw_data.shape[0] - self.action_repeats - 1 # load indicators into the indicator manager self.tns = IndicatorManager() self.rsi = IndicatorManager() for window in INDICATOR_WINDOW: self.tns.add( ('tns_{}'.format(window), TnS(window=window, alpha=ema_alpha))) self.rsi.add( ('rsi_{}'.format(window), RSI(window=window, alpha=ema_alpha))) # buffer for appending lags self.data_buffer = deque(maxlen=self.window_size) # Index of specific data points used to generate the observation space features = self._raw_data.columns.tolist() self.best_bid_index = features.index('bids_distance_0') self.best_ask_index = features.index('asks_distance_0') self.notional_bid_index = features.index('bids_notional_0') self.notional_ask_index = features.index('asks_notional_0') self.buy_trade_index = features.index('buys') self.sell_trade_index = features.index('sells') # typecast all data sets to numpy self._raw_data = self._raw_data.to_numpy(dtype=np.float32) self._normalized_data = self._normalized_data.to_numpy( dtype=np.float32) self._midpoint_prices = self._midpoint_prices.to_numpy( dtype=np.float64) self._best_bids = self._best_bids.to_numpy(dtype=np.float32) self._best_asks = self._best_asks.to_numpy(dtype=np.float32) # rendering class self._render = TradingGraph(sym=self.symbol) # graph midpoint prices self._render.reset_render_data( y_vec=self._midpoint_prices[:np.shape(self._render.x_vec)[0]])
def __init__(self, close, rsi: indicators.RSI, macd: indicators.MACD, fee=0.0): Strategy.__init__(self, close.index, fee=0.0) # indique le signal en cours sachant que MACD > RSI buysignalstrat = None macdcrossedfromdown = False macdcrossedfromtop = False lowthreshpassed = False lowlowthreshpassed = False hithreshpassed = False hihithreshpassed = False hasbought = False self.signals['rsi'] = rsi.data() self.signals['macd'], self.signals['macd_signal'] = macd.data() for index, row in self.signals.iterrows(): # achat en fonction du RSI if row['rsi'] < 33: lowthreshpassed = True if row['rsi'] < 20: lowlowthreshpassed = True if row['rsi'] > 66: hithreshpassed = True if row['rsi'] > 80: hihithreshpassed = True if row['rsi'] > 20 and lowlowthreshpassed == True: lowlowthreshpassed = False if hasbought == False: hasbought = True buysignalstrat = "RSI" if row['rsi'] > 33 and lowthreshpassed == True: lowthreshpassed = False if hasbought == False: hasbought = True buysignalstrat = "RSI" # on revend par RSI seulement si c'est le seul signal qui a généré l'achat if row['rsi'] < 80 and hihithreshpassed == True: hihithreshpassed = False if hasbought == True and buysignalstrat == "RSI": hasbought = False buysignalstrat = None if row['rsi'] < 66 and hithreshpassed == True: hithreshpassed = False if hasbought == True and buysignalstrat == "RSI": hasbought = False buysignalstrat = None # achat en fonction de la MACD # TODO : lorsque le marché stagne, la MACD génère beaucoup de faux signaux, comment les éviter ? if row['macd'] > row[ 'macd_signal'] and macdcrossedfromdown == False: macdcrossedfromdown = True macdcrossedfromtop = False if hasbought == False: hasbought = True # même si nous avions acheté avec le RSI, si le signal est confirmé par la MACD # il sera considéré comme étant prévalant buysignalstrat = "MACD" if row['macd'] < row['macd_signal'] and macdcrossedfromtop == False: macdcrossedfromtop = True macdcrossedfromdown = False if hasbought == True: hasbought = False buysignalstrat = None if hasbought == True: self.signals['signal'].loc[index] = 1.0 self.signals['positions'] = self.signals['signal'].diff()
windowSize = 2 #Get full dataset dfPrices = get_data_google( stockSym, pd.date_range(before_start_date, end_sample_date)) dfSPY = dfPrices[['SPY']] dfPrices = dfPrices[stockSym] #Normalize Price priceNormed = dfPrices / dfPrices.ix[0] SPYNormed = dfSPY / dfSPY.ix[0] #Call indicators topBand, bottomBand, bbValue, bbp = Bollinger_Bands( stockSym, dfPrices, windowSize) RSIValueSMA, RSIValueEWM = RSI(stockSym, dfPrices, windowSize) MACDValue, signal, MACDIndicator = MACD(stockSym, dfPrices) SPYInd = SPYIndicator(dfSPY) #Standardize bbp = (bbp - bbp.mean()) / (bbp.std()) RSIValueEWM = (RSIValueEWM - RSIValueEWM.mean()) / (RSIValueEWM.std()) MACDValue = (MACDValue - MACDValue.mean()) / (MACDValue.std()) signal = (signal - signal.mean()) / (signal.std()) MACDIndicator = (MACDIndicator - MACDIndicator.mean()) / (MACDIndicator.std()) #5 Day Future Returns futureReturn = (dfPrices / dfPrices.shift(windowSize)) - 1.0 futureReturn = futureReturn.shift(-windowSize)