def __init__(self, companies: List[Company] = None, periods: List[Period] = None): """ TODO refactor comment Reads the "cross product" from `stocks` and `periods` from CSV files and creates a `StockMarketData` object from this. For each defined stock in `stocks` the corresponding value from `Company` is used as logical name. If there are `periods` provided those are each read. Args: stocks: The company names for which to read the stock data. *Important:* These values need to be stated in `CompanyEnum` periods: The periods to read. If not empty each period is appended to the filename like this: `[stock_name]_[period].csv` Returns: The created `StockMarketData` object Examples: * Preface: Provided stock names are supposed to be part to `CompanyEnum`. They are stated plaintext-ish here to show the point: * `(['stock_a', 'stock_b'], ['1962-2011', '2012-2017'])` reads: * 'stock_a_1962-2011.csv' * 'stock_a_2012-2015.csv' * 'stock_b_1962-2011.csv' * 'stock_b_2012-2015.csv' into a dict with keys `CompanyEnum.COMPANY_A` and `CompanyEnum.COMPANY_B` respectively * `(['stock_a'], ['1962-2011', '2012-2017'])` reads: * 'stock_a_1962-2011.csv' * 'stock_a_2012-2015.csv' into a dict with a key `CompanyEnum.COMPANY_A` * `(['stock_a', 'stock_b'], ['1962-2011'])` reads: * 'stock_a_1962-2011.csv' * 'stock_b_1962-2011.csv' into a dict with keys `CompanyEnum.COMPANY_A` and `CompanyEnum.COMPANY_B` respectively * `(['stock_a', 'stock_b'], [])` reads: * 'stock_a.csv' * 'stock_b.csv' into a dict with keys `CompanyEnum.COMPANY_A` and `CompanyEnum.COMPANY_B` respectively """ data = dict() if companies is not None and periods is not None: # Read *all* available data for company in companies: filename = company.value if len(periods) is 0: data[company] = StockData(self.__read_stock_market_data([[company, filename]])[company]) else: period_data = list() for period in periods: period_data.append(self.__read_stock_market_data([[company, ('%s_%s' % (filename, period.value))]])) data[company] = StockData( [item for period_dict in period_data if period_dict is not None for item in period_dict[company]]) self.__market_data = data
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 vote(self, stock_data: StockData) -> Vote: """ Vote based on the stock's historic prices. :param stock_data: StockData object capturing the past stock prices :return: """ assert stock_data is not None try: (current_date, _) = stock_data.get_last() return self.__answers[self.__company][current_date] except (ValueError, IndexError): assert False
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 get_test_data(): return StockData([(Date(2017, 1, 1), 150.0), (Date(2017, 1, 2), 200.0)])
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