def load_keras_sequential(relative_path: str, file_name_without_extension: str) -> Sequential: """ Loads a Keras Sequential neural network from file system Args: relative_path : relative path in project file_name_without_extension : file name without extension, will be used for json with models and h5 with weights. Returns: Sequential, or None if nothing found or error """ model_filename_with_path = os.path.join(ROOT_DIR, relative_path, file_name_without_extension + '.json') weights_filename_with_path = os.path.join(ROOT_DIR, relative_path, file_name_without_extension + '.h5') if os.path.exists(model_filename_with_path) and os.path.exists(weights_filename_with_path): try: json_file = open(model_filename_with_path, 'r') loaded_model_json = json_file.read() json_file.close() model = model_from_json(loaded_model_json) model.load_weights(weights_filename_with_path) logger.debug(f"load_keras_sequential: Loaded Sequential from {model_filename_with_path} " f"and {weights_filename_with_path}!") return model except: logger.error(f"load_keras_sequential: Loading of Sequential {model_filename_with_path} failed!") return None else: logger.error(f"load_keras_sequential: model File {model_filename_with_path} " f"or weights file {weights_filename_with_path} not found!") return None
def make_order(self, company: Company, orderTyp: OrderType, percentage, portfolio: Portfolio, stock_market_data: StockMarketData) -> Order: """ creates an Order Args: company: the company for the order orderTyp: the OrderTyp (as Vote instance) percentage: an integer indicating how much percent should be bought or sold Returns an order for one company of instance Order """ if orderTyp == OrderType.BUY: stock_price = stock_market_data.get_most_recent_price(company) port = portfolio.cash * percentage amount_to_buy = int(port // stock_price) logger.debug( f"{self.get_name()}: Got best action to buy {company}: and bought {amount_to_buy}" ) return Order(OrderType.BUY, company, amount_to_buy) if amount_to_buy > 0 else None elif orderTyp == OrderType.SELL: amount_to_sell = portfolio.get_stock(company) amount_to_sell *= percentage logger.debug( f"{self.get_name()}: Got best action to sell {company}: and sold {amount_to_sell}" ) return Order(OrderType.SELL, company, amount_to_sell) if amount_to_sell > 0 else None else: assert False
def save_keras_sequential(model: Sequential, relative_path: str, file_name_without_extension: str) -> bool: """ Saves a Keras Sequential in File System Args: model : Sequential to save relative_path : relative path in project file_name_without_extension : file name without extension, will be used for json with models and h5 with weights. Returns: True if successful, False otherwise, never None """ if model.model is None: logger.error(f"save_keras_sequential: Cannot write an empty model as file") return False try: model_as_json = model.to_json() model_filename_with_path = os.path.join(ROOT_DIR, relative_path, file_name_without_extension + '.json') weights_filename_with_path = os.path.join(ROOT_DIR, relative_path, file_name_without_extension + '.h5') json_file = open(model_filename_with_path, "w") json_file.write(model_as_json) json_file.close() model.save_weights(weights_filename_with_path) logger.debug(f"save_keras_sequential: Saved Sequential from {model_filename_with_path} " f"and {weights_filename_with_path}!") return True except: logger.error(f"save_keras_sequential: Writing of Sequential as file failed") return False
def run(self, data: StockMarketData, traders: List[ITrader], offset: int = 0) -> Dict[ITrader, Dict[Date, Portfolio]]: """ Runs the stock exchange over the given stock market data for the given traders. :param data: The complete stock market data :param traders: A list of all traders :param offset: The number of trading days which a will be skipped before (!) trading starts :return: The main data structure, which stores one portfolio per trade day, for each traders """ assert data is not None assert traders is not None # initialize the main data structure: Dictionary over traders, that stores each traders's portfolio per day # data structure type is Dict[ITrader, Dict[Date, Portfolio]] trade_dates = data.get_trade_days() assert trade_dates # must not be empty assert 0 <= offset < len(trade_dates) # offset must be feasible self.__complete_stock_market_data = data self.__trader_portfolios = { trader: { trade_dates[offset]: Portfolio(self.__cash) } for trader in traders } # iterate over all trade days minus 1, because we don't trade on the last day for tick in range(offset, len(trade_dates) - 1): logger.debug( f"Stock Exchange: Current tick '{tick}' means today is '{trade_dates[tick]}'" ) if tick % 365 == 1: print(trade_dates[tick]) # build stock market data until today current_stock_market_data = data.deepcopy_first_n_items(tick + 1) # iterate over all traders for trader in traders: # get the traders's order list by giving him a copy (to prevent cheating) of today's portfolio todays_portfolio = self.__trader_portfolios[trader][ trade_dates[tick]] current_order_list = trader.trade( copy.deepcopy(todays_portfolio), current_stock_market_data) # execute order list and save the result as tomorrow's portfolio tomorrows_portfolio = copy.deepcopy(todays_portfolio) tomorrows_portfolio.update_with_order_list( current_stock_market_data, current_order_list) self.__trader_portfolios[trader][trade_dates[ tick + 1]] = tomorrows_portfolio return self.__trader_portfolios
def follow_orders(orders): order_list = [] company_list = stock_market_data.get_companies() for company, order in zip(company_list, orders): stock_data = stock_market_data[company] if order.type == OrderType.BUY: # buy as many stocks as possible stock_price = stock_data.get_last()[-1] amount_to_buy = int(portfolio.cash // stock_price) logger.debug(f"{self.get_name()}: Got order to buy {company}: {amount_to_buy} shares a {stock_price}") if amount_to_buy > 0: order_list.append(Order(OrderType.BUY, company, amount_to_buy)) elif order.type == OrderType.SELL: # sell as many stocks as possible amount_to_sell = portfolio.get_stock(company) logger.debug(f"{self.get_name()}: Got order to sell {company}: {amount_to_sell} shares available") if amount_to_sell > 0: order_list.append(Order(OrderType.SELL, Company.A, amount_to_sell)) return order_list
def __follow_expert_vote(self, company: Company, stock_data: StockData, vote: Vote, buy_weight: float, portfolio: Portfolio, order_list: List[Order]): assert company is not None assert stock_data is not None assert vote is not None assert portfolio is not None assert order_list is not None if vote is Vote.BUY or vote is Vote.HOLD: assert buy_weight is not None and 0 < buy_weight <= 1.0 stock_price = stock_data.get_last()[-1] amount_to_buy = int(buy_weight * portfolio.cash // stock_price) logger.debug( f"{self.get_name()}: Got vote to buy {company}: {amount_to_buy} shares a {stock_price}" ) if amount_to_buy > 0: order_list.append(Order(OrderType.BUY, company, amount_to_buy)) elif vote == Vote.SELL: # sell as many stocks as possible amount_to_sell = portfolio.get_stock(company) logger.debug( f"{self.get_name()}: Got vote to sell {company}: {amount_to_sell} shares available" ) if amount_to_sell > 0: order_list.append( Order(OrderType.SELL, company, amount_to_sell)) else: # do nothing assert vote == Vote.HOLD logger.debug(f"{self.get_name()}: Got vote to hold {company}")
def __follow_action(self, company: Company, stock_data: StockData, vote: Vote, portfolio: Portfolio, order_list: List[Order]): """ Protected helper method to calculate amount of stocks to be bought and sold. :param company: Company :param stock_data: StockData :param vote: Vote :param portfolio: Portfolio :param order_list: List[Order] :return: None (writes result to order_list) """ assert company is not None assert stock_data is not None assert vote is not None assert portfolio is not None assert order_list is not None if vote == Vote.BUY: # buy as many stocks as possible stock_price = stock_data.get_last()[-1] amount_to_buy = int(portfolio.cash // stock_price) logger.debug( f"{self.get_name()}: Got vote to buy {company}: {amount_to_buy} shares a {stock_price}" ) if amount_to_buy > 0: order_list.append(Order(OrderType.BUY, company, amount_to_buy)) elif vote == Vote.SELL: # sell as many stocks as possible amount_to_sell = portfolio.get_stock(company) logger.debug( f"{self.get_name()}: Got vote to sell {company}: {amount_to_sell} shares available" ) if amount_to_sell > 0: order_list.append( Order(OrderType.SELL, company, amount_to_sell)) else: # do nothing assert vote == Vote.HOLD logger.debug(f"{self.get_name()}: Got vote to hold {company}")
def update_with_order_list(self, stock_market_data: StockMarketData, orders: List[Order]): """ Update the portfolio by executing all given stock orders simultaneously. Executing simultaneously means: 1) The order in which the stock orders are executed does not matter. 2) Cash from selling stocks today is only available for buying stocks tomorrow. If a stock order couldn't be executed (e.g., not enough cash/stocks available), then that order is skipped. :param stock_market_data: Information about all stock prices :param orders: The list of all stock orders :return: """ assert stock_market_data is not None assert orders is not None if len(orders) == 0: logger.debug("The order list is empty. No portfolio update this time") return available_cash = self.cash current_date = stock_market_data.get_most_recent_trade_day() logger.debug(f"Updating portfolio {self}: Available cash on {current_date} is {available_cash}") for order in orders: # get the infos about the order and the existing stock company = order.company current_price = stock_market_data.get_most_recent_price(company) amount = order.amount trade_volume = amount * current_price existing_amount = self.get_stock(company) if order.type is OrderType.BUY: logger.debug(f"Buying {amount} stocks of '{company}' at {current_price} (total {trade_volume})") if trade_volume <= available_cash: self.stocks[company] = existing_amount + amount self.cash -= trade_volume available_cash -= trade_volume else: logger.debug(f"Not enough cash ({available_cash}) for transaction with volume of {trade_volume}") elif order.type is OrderType.SELL: logger.debug(f"Selling {amount} stocks of '{company}' at {current_price} (total {trade_volume})") if existing_amount >= amount: self.stocks[company] = existing_amount - amount self.cash += trade_volume else: logger.debug(f"Not enough stocks ({existing_amount}) for selling {amount} of them") else: assert False logger.debug(f"Resulting available cash after trade: {self.cash}")
def get_title(self): current_title = self.driver.title logger.debug(f'get current title: {current_title}') return current_title
def get_url(self): current_url = self.driver.current_url logger.debug(f'get current url: {current_url}') return current_url
def choose_actions(self, stock_data_a: StockData, stock_data_b: StockData, portfolio: Portfolio, order_list: List[Order], epsilon=None, model_choice=None): assert epsilon is not None assert model_choice is not None action_a = None action_b = None if random.random() < self.epsilon: action_comb = random.randrange(10) else: action_comb = model_choice potential_buy_a = int(portfolio.cash // stock_data_a.get_last()[-1]) potential_buy_b = int(portfolio.cash // stock_data_b.get_last()[-1]) potential_sell_a = portfolio.get_stock(Company.A) potential_sell_b = portfolio.get_stock(Company.B) """10 action combinations: - buy 100% A, buy 0% B # buy only A completely - buy 100% A, sell 100% B # sell all B, buy all A - buy 50% A, buy 50% B # buy both - buy 0% A, buy 100% B # buy only B completely - sell 100% A, sell 0% B # sell only A completely - sell 100% A, sell 100% B # sell both completely - sell 100% A, buy 100% B # sell all A, buy all B - sell 50% A, sell 50% B # sell both half - sell 0% A, sell 100% B # sell only B completely - hold # do nothing """ logger.debug(f"{self.get_name()}: chooses action comb {action_comb}") if action_comb == 0: # buy 100% A, buy 0% B # buy only A completely action_a = OrderType.BUY.value action_b = 0 order_list.append(Order(OrderType.BUY, Company.A, potential_buy_a)) elif action_comb == 1: # buy 100% A, sell 100% B # sell all B, buy all A action_a = OrderType.BUY.value action_b = OrderType.SELL.value order_list.append(Order(OrderType.BUY, Company.A, potential_buy_a)) order_list.append( Order(OrderType.SELL, Company.B, potential_sell_b)) elif action_comb == 2: # buy 50% A, buy 50% B # buy both action_a = OrderType.BUY.value action_b = OrderType.SELL.value order_list.append( Order(OrderType.BUY, Company.A, potential_buy_a // 2)) remaining_cash = portfolio.cash - (potential_buy_a // 2) * stock_data_a.get_last()[-1] potential_buy_b = int(remaining_cash // stock_data_b.get_last()[-1]) order_list.append(Order(OrderType.SELL, Company.B, potential_buy_b)) elif action_comb == 3: # buy 0% A, buy 100% B # buy only B completely action_a = 0 action_b = OrderType.BUY.value order_list.append(Order(OrderType.BUY, Company.B, potential_buy_b)) elif action_comb == 4: # sell 100% A, sell 0% B # sell only A completely action_a = OrderType.SELL.value action_b = 0 order_list.append( Order(OrderType.SELL, Company.A, potential_sell_a)) elif action_comb == 5: # sell 100% A, sell 100% B # sell both completely action_a = OrderType.SELL.value action_b = OrderType.SELL.value order_list.append( Order(OrderType.SELL, Company.A, potential_sell_a)) order_list.append( Order(OrderType.SELL, Company.B, potential_sell_b)) elif action_comb == 6: # sell 100% A, buy 100% B # sell all A, buy all B action_a = OrderType.SELL.value action_b = OrderType.BUY.value order_list.append( Order(OrderType.SELL, Company.A, potential_sell_a)) order_list.append(Order(OrderType.BUY, Company.B, potential_buy_b)) elif action_comb == 7: # sell 50% A, sell 50% B # sell both half action_a = OrderType.SELL.value action_b = OrderType.SELL.value order_list.append( Order(OrderType.SELL, Company.A, potential_sell_a // 2)) order_list.append( Order(OrderType.SELL, Company.B, potential_sell_b // 2)) elif action_comb == 8: # sell 0% A, sell 100% B # sell only B completely action_a = 0 action_b = OrderType.SELL.value order_list.append( Order(OrderType.SELL, Company.B, potential_sell_b)) elif action_comb == 9: # hold # do nothing action_a = 0 action_b = 0 return action_a, action_b, order_list