class GDAXOrderBookBacktest: """ """ def __init__(self): self.data = None self.strategies = [] self.broker = Broker() def add_strategy(self, strategy): strategy.add_broker(self.broker) self.strategies.append(strategy) def load_csv_directory(self, directory): """ """ logger.info('Loading CSV data from {}...'.format(directory)) directory_enc = os.fsencode(directory) csv_names = ('datetime', 'type', 'price', 'size', 'num-orders') filenames = sorted(os.listdir(directory_enc)) data_list = [] for filename in filenames: file_path_enc = os.path.join(directory_enc, filename) file_path = os.fsdecode(file_path_enc) data = pd.read_csv(file_path, header=None, names=csv_names) data_list.append(data) logger.info('Read {}'.format(filename)) self.data = pd.concat(data_list, ignore_index=True) def run(self): """ """ # Group data so strategies see the full order book in a give moment grouped_data = self.data.groupby('datetime') logger.info('Running strategies...') # Run strategies on data for key, item in grouped_data: data = grouped_data.get_group(key) self.broker.next(key, data) for strategy in self.strategies: strategy.next(key, data) logger.info('Calculating metrics...') # Calculate strategy metrics for strategy in self.strategies: strategy.metrics() def plot(self): """ """ data_plot = self.data data_plot_b = data_plot.loc[data_plot['type'] == 'b'] data_plot_b = data_plot_b.groupby('datetime')['price'].max() data_plot_b = data_plot_b.to_frame('Best Bid') data_plot = data_plot_b account_df = pd.DataFrame.from_records( self.broker.account_value, index='datetime', columns=['datetime', 'Account Value'] ) data_plot = data_plot.join(account_df, how='left') data_plot = data_plot.interpolate(method='time') fig, axes = plt.subplots(nrows=2) data_plot['Best Bid'].plot(ax=axes[0]) data_plot['Account Value'].plot(ax=axes[1]) first_best_bid = data_plot['Best Bid'].head(1) first_best_bid_xy = (first_best_bid.index[0], first_best_bid[0],) axes[0].annotate('{}'.format(first_best_bid[0]), first_best_bid_xy) last_best_bid = data_plot['Best Bid'].tail(1) last_best_bid_xy = (last_best_bid.index[0], last_best_bid[0],) axes[0].annotate('{}'.format(last_best_bid[0]), last_best_bid_xy) first_account = data_plot['Account Value'].head(1) first_account_xy = (first_account.index[0], first_account[0],) axes[1].annotate('{}'.format(first_account[0]), first_account_xy) last_account = data_plot['Account Value'].tail(1) last_account_xy = (last_account.index[0], last_account[0],) axes[1].annotate('{}'.format(last_account[0]), last_account_xy) plt.show()
class SAMGameGym(gym.Env): metadata = {'render.modes': ['human']} def __init__(self, env_config): account = Account(000000, env_config['initial_cash'], 0, env_config['initial_cash'], env_config['initial_cash'], dict(), False) max_limit = env_config['window'] self.resized_image_width = 100 self.resized_image_height = 100 image_channel = 4 self.log_every = env_config['log_every'] self.broker = Broker(account, max_limit=max_limit) self.all_tickers = self.broker.all_tickers self.n_symbols = env_config['n_symbols'] self.tech_indicators = env_config['tech_indicators'] length = OHCLVV + len(self.tech_indicators.split()) self.use_image = env_config['use_image'] if self.use_image: self.observation_space = gym.spaces.Dict({ 'data': gym.spaces.Box(-np.inf, np.inf, (self.n_symbols, max_limit, length)), 'images': gym.spaces.Box(-np.inf, np.inf, (self.n_symbols, self.resized_image_height, self.resized_image_width, image_channel)), 'privates': gym.spaces.Box(-np.inf, np.inf, (5 + self.n_symbols * 2, )) }) else: self.observation_space = gym.spaces.Dict({ 'data': gym.spaces.Box(-np.inf, np.inf, (self.n_symbols, max_limit, length)), 'privates': gym.spaces.Box(-np.inf, np.inf, (5 + self.n_symbols * 2, )) }) self.action_space = gym.spaces.MultiDiscrete([env_config['bins']] * self.n_symbols) self.current_tickers = None self.qty_val = np.linspace(-env_config['max_shares'], env_config['max_shares'], env_config['bins']) self.images = None self.refresh_data = True def extract_data(self, df_dict, t, statuses, images=None): columns = ['open', 'high', 'low', 'close', 'volume', 'vwap'] columns.extend(self.tech_indicators.split()) dfs = [df_dict[tick][columns] for tick in t] frame = np.array(dfs) privates = self.broker.account.flat() # fix privates.extend(statuses) # if images is not None: # images = np.array(list( # self.broker.get_view(frame=df_dict, # resize=(self.resized_image_width, self.resized_image_height)).values())) # # self.images = images[0, :, :, :3] # return frame, images, privates # else: return frame, privates def render(self, mode='rgb_array'): if self.use_image: assert self.images is not None plt.imshow(self.images) # plt.pause(0.1) plt.show(block=False) def reset(self): if self.refresh_data: t = np.random.choice(self.all_tickers, self.n_symbols) self.current_tickers = t self.broker.account.stocks_owned = {tick: 0 for tick in t} df_dict = self.broker.start(t, self.use_image, self.tech_indicators) self.refresh_data = False else: df_dict = self.broker.next(use_image=False)[0] # if self.use_image: # frame, images, privates = self.extract_data(df_dict, t, [1] * self.n_symbols) # return {'data': frame, 'images': images, 'privates': np.array(privates, dtype=np.float)} # else: frame, privates = self.extract_data(df_dict, self.current_tickers, [1] * self.n_symbols) return {'data': frame, 'privates': np.array(privates, dtype=np.float)} def step(self, action): res = self.broker.next(self.use_image) orders = make_orders(self.current_tickers, action, res[0], self.qty_val) statuses = self.broker.place_orders(orders) reward = self.broker.equity - self.broker.last_equity done = self.broker.done() self.refresh_data = done # print(res[-1], flush=True, end='\r') if res[2]: # 2 - new week #todo: bug here print(ERASELINE, self.broker.account, '\norders:', orders, '\nstatuses:', statuses, flush=True) weekly_df = pd.DataFrame( self.broker.daily_account_balances).set_index('timestamp') weekly_perf = bt.weekly_backtest_with( weekly_df, [bt.BTMetrics.SHARPE_RATIO, bt.BTMetrics.MAX_DRAWDOWN]) reward += sum(weekly_perf.values()) done = True if self.use_image: next_frame, next_images, next_privates = self.extract_data( res[0], self.current_tickers, statuses) # todo: add order statuses to observation private variables return dict(data=next_frame, images=next_images, privates=np.array(next_privates, dtype=np.float)), \ reward, done, {} else: next_frame, next_privates = self.extract_data( res[0], self.current_tickers, statuses) # todo: add order statuses to observation private variables return dict(data=next_frame, privates=np.array(next_privates, dtype=np.float)), \ reward, done, {}