def test_stock_market_data_one_company_one_period(self): stock_market_data = StockMarketData([Company.A], [Period.TRAINING]) self.assertIsNotNone(stock_market_data) self.assertEqual(stock_market_data.get_number_of_companies(), 1) self.assertEqual(stock_market_data.get_row_count(), 12588) self.assertEqual(stock_market_data.get_most_recent_trade_day(), Date(2011, 12, 30)) self.assertEqual(stock_market_data.get_most_recent_price(Company.A), 34.802376) self.assertIsNone(stock_market_data.get_most_recent_price(Company.B))
def test_stock_market_data_one_company_two_periods(self): stock_market_data = StockMarketData([Company.A], [Period.TRAINING, Period.TESTING]) self.assertIsNotNone(stock_market_data) self.assertEqual(stock_market_data.get_number_of_companies(), 1) self.assertEqual(stock_market_data.get_row_count(), 13594) self.assertEqual(stock_market_data.get_most_recent_trade_day(), Date(2015, 12, 31)) self.assertEqual(stock_market_data.get_most_recent_price(Company.A), 102.759895) self.assertIsNone(stock_market_data.get_most_recent_price(Company.B))
def trade(self, portfolio: Portfolio, stock_market_data: StockMarketData) -> List[Order]: """ Generate actions to be taken on the "stock market" Args: portfolio : current Portfolio of this traders stock_market_data : StockMarketData for evaluation Returns: A OrderList instance, may be empty never None """ assert portfolio is not None assert stock_market_data is not None if self.__bought_stocks: return [] else: self.__bought_stocks = True # Calculate how many cash to spend per company company_list = stock_market_data.get_companies() # Invest (100 // `len(companies)`)% of cash into each stock order_list = [] for company in company_list: available_cash_per_stock = portfolio.cash / len(company_list) most_recent_price = stock_market_data.get_most_recent_price( company) amount_to_buy = available_cash_per_stock // most_recent_price order_list.append(Order(OrderType.BUY, company, amount_to_buy)) return order_list
def __init__(self, expert_a, expert_b, stock_market_data: StockMarketData, portfolio: Portfolio): """ Constructor Args: expert_a : expert opinion from analyst A expert_b : expert opinion from analyst B portfolio : current Portfolio of this traders stock_market_data : StockMarketData for evaluation """ # get composition of current portfolio self.noStockA = portfolio.get_stock(Company.A) self.noStockB = portfolio.get_stock(Company.B) self.Cash = portfolio.cash # most important information: minimum cash neccessary to buy one addtional share: if set to 100 or any fixed value,the zig zag curve in the evalution set is occuring # when set to max no zigzag can be seen self.min_cash_to_buy = max( stock_market_data.get_most_recent_price(Company.A), stock_market_data.get_most_recent_price(Company.B)) # get votes from experts opinions company_list = stock_market_data.get_companies() for company in company_list: if company == Company.A: stock_data_a = stock_market_data[Company.A] vote_a = expert_a.vote(stock_data_a) elif company == Company.B: stock_data_b = stock_market_data[Company.B] vote_b = expert_b.vote(stock_data_b) else: assert False self.expertOpinionA = vote_a self.expertOpinionB = vote_b
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 test_get_most_recent_price(self): """ Tests: StockMarketData#get_most_recent_price Read the stock market data and check if the last available stock price is determined correctly """ stock_market_data = StockMarketData([Company.A, Company.B], [Period.TRAINING, Period.TESTING]) self.assertEqual(stock_market_data.get_most_recent_price(Company.A), stock_market_data[Company.A].get_last()[1])
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_value(self, stock_market_data: StockMarketData, date: Date = None) -> float: """ Return the value of this portfolio: It is the contained ash plus the value of all contained stocks. If no date is given, the most recent trade day from stock market data is used. :param stock_market_data: Information about all stock prices :param date: The day we want the portfolio value for :return: The portfolio value """ assert stock_market_data is not None result = self.cash for company in self.stocks.keys(): if date is None: price = stock_market_data.get_most_recent_price(company) else: stock_data = stock_market_data.__getitem__(company) price = stock_data.get_price(date) result += self.stocks[company] * price return result
def __create_order_for_company( self, company: Company, portfolio: Portfolio, vote: Vote, stock_market_data: StockMarketData) -> Order: order = None if vote == Vote.SELL: amount = portfolio.get_stock(company) if amount > 0: order = Order(OrderType.SELL, company, amount) elif vote == Vote.BUY: stock_price = stock_market_data.get_most_recent_price(company) amount = 0 if (self.type_a == self.type_b): # buy both - half portfolio value for each amount = int((portfolio.cash // 2) // stock_price) else: amount = int(portfolio.cash // stock_price) if amount > 0: order = Order(OrderType.BUY, company, amount) return order
def trade(self, portfolio: Portfolio, stock_market_data: StockMarketData) -> List[Order]: """ Generate action to be taken on the "stock market" Args: portfolio : current Portfolio of this traders stock_market_data : StockMarketData for evaluation Returns: A OrderList instance, may be empty never None """ assert portfolio is not None assert stock_market_data is not None assert stock_market_data.get_companies() == [Company.A, Company.B] # INPUT layer: 1 (buy or sell A?) # output layer: 2 ([buy_A, sell_A]) # TODO Compute the current state stock_data_A = stock_market_data[Company.A] expertA_voteA = self.expert_a.vote(stock_data_A) stock_data_B = stock_market_data[Company.B] expertB_voteB = self.expert_b.vote(stock_data_B) state = np.array([[ self.vote_map[expertA_voteA], self.vote_map[expertB_voteB], ]]) # do action 0 or 1? predictions = self.model.predict(state) # TODO Create actions for current state and decrease epsilon for fewer random actions if random.random() < self.epsilon: # use random actions for A and B action_A = random.randrange(2) action_B = random.randrange(2) else: # use prediction actions action_A = np.argmax(predictions[0][0:2]) action_B = np.argmax(predictions[0][2:4]) if self.epsilon > self.epsilon_min: self.epsilon *= self.epsilon_decay current_price_a = stock_market_data.get_most_recent_price(Company.A) current_price_b = stock_market_data.get_most_recent_price(Company.B) money_to_spend = portfolio.cash order_list = [] # do stuff for A if action_A == 0: # buy all A amount_to_buy = money_to_spend // current_price_a if amount_to_buy > 0: money_to_spend -= amount_to_buy * current_price_a order_list.append( Order(OrderType.BUY, Company.A, amount_to_buy)) elif action_A == 1: # sell all A amount_to_sell = portfolio.get_stock(Company.A) if amount_to_sell > 0: order_list.append( Order(OrderType.SELL, Company.A, amount_to_sell)) else: assert False # do stuff for B if action_B == 0: # buy all B amount_to_buy = money_to_spend // current_price_b if amount_to_buy > 0: order_list.append( Order(OrderType.BUY, Company.B, amount_to_buy)) elif action_B == 1: # sell all B amount_to_sell = portfolio.get_stock(Company.B) if amount_to_sell > 0: order_list.append( Order(OrderType.SELL, Company.B, amount_to_sell)) else: assert False # TODO train the neural network only if trade() was called before at least once if self.last_state is not None: # train diff_a = (current_price_a / self.last_price_a - 1) diff_b = (current_price_b / self.last_price_b - 1) fut_reward_a = np.max(predictions[0][0:2]) fut_reward_b = np.max(predictions[0][2:4]) reward_vec = np.array([[ diff_a + self.gamma * fut_reward_a, -diff_a + self.gamma * fut_reward_a, diff_b + self.gamma * fut_reward_b, -diff_b + self.gamma * fut_reward_b ]]) # TODO Store state as experience (memory) and replay # slides: <s, a, r, s'> # mine: <s, r> if self.min_size_of_memory_before_training <= len(self.memory): # take self.batch_size - 1 from memory batch = random.sample(self.memory, self.batch_size - 1) # append current state, reward batch.append((self.last_state, reward_vec)) for x, y in batch: self.model.fit(x, y, batch_size=self.batch_size, verbose=0) else: # only train with current (state, reward) self.model.fit(self.last_state, reward_vec, batch_size=1, verbose=0) self.memory.append((self.last_state, reward_vec)) # TODO Save created state, actions and portfolio value for the next call of trade() self.last_state = state self.last_action_a = action_A self.last_action_b = action_B self.last_portfolio_value = portfolio.get_value(stock_market_data) self.last_price_a = current_price_a self.last_price_b = current_price_b return order_list
def trade(self, portfolio: Portfolio, stock_market_data: StockMarketData) -> List[Order]: """ Generate action to be taken on the "stock market" Args: portfolio : current Portfolio of this traders stock_market_data : StockMarketData for evaluation Returns: A OrderList instance, may be empty never None """ assert portfolio is not None assert stock_market_data is not None assert stock_market_data.get_companies() == [Company.A, Company.B] # INPUT layer: 1 (buy or sell A?) # output layer: 2 ([buy_A, sell_A]) # TODO Compute the current state stock_data_A = stock_market_data[Company.A] expertA_voteA = self.expert_a.vote(stock_data_A) expertB_voteA = self.expert_b.vote(stock_data_A) stock_data_B = stock_market_data[Company.B] expertA_voteB = self.expert_a.vote(stock_data_B) expertB_voteB = self.expert_b.vote(stock_data_B) state = np.array([[ self.vote_map[expertA_voteA] + self.vote_map[expertB_voteA], self.vote_map[expertA_voteB] + self.vote_map[expertB_voteB], ]]) # do action 0 or 1? predictions = self.model.predict(state) ''' if random.random() < self.epsilon: # use random actions for A and B action_A = random.randrange(2) action_B = random.randrange(2) else: # use prediction actions action_A = np.argmax(predictions[0][0:2]) action_B = np.argmax(predictions[0][2:4]) ''' action_A = np.argmax(predictions[0][0:2]) action_B = np.argmax(predictions[0][2:4]) current_price_a = stock_market_data.get_most_recent_price(Company.A) current_price_b = stock_market_data.get_most_recent_price(Company.B) money_to_spend = portfolio.cash order_list = [] # do stuff for A if action_A == 0: # buy all A amount_to_buy = money_to_spend // current_price_a if amount_to_buy > 0: money_to_spend -= amount_to_buy * current_price_a order_list.append(Order(OrderType.BUY, Company.A, amount_to_buy)) elif action_A == 1: # sell all A amount_to_sell = portfolio.get_stock(Company.A) if amount_to_sell > 0: order_list.append(Order(OrderType.SELL, Company.A, amount_to_sell)) else: assert False # do stuff for B if action_B == 0: # buy all B amount_to_buy = money_to_spend // current_price_b if amount_to_buy > 0: order_list.append(Order(OrderType.BUY, Company.B, amount_to_buy)) elif action_B == 1: # sell all B amount_to_sell = portfolio.get_stock(Company.B) if amount_to_sell > 0: order_list.append(Order(OrderType.SELL, Company.B, amount_to_sell)) else: assert False if self.last_state is not None: # train diff_a = (current_price_a / self.last_price_a - 1) diff_b = (current_price_b / self.last_price_b - 1) fut_reward_a_buy = np.max(predictions[0][0]) fut_reward_a_buy = fut_reward_a_buy if fut_reward_a_buy > 0 else 0 fut_reward_a_sell = np.max(predictions[0][1]) fut_reward_a_sell = fut_reward_a_sell if fut_reward_a_sell > 0 else 0 fut_reward_b_buy = np.max(predictions[0][2]) fut_reward_b_buy = fut_reward_b_buy if fut_reward_b_buy > 0 else 0 fut_reward_b_sell = np.max(predictions[0][3]) fut_reward_b_sell = fut_reward_b_sell if fut_reward_b_sell > 0 else 0 reward_vec = np.array([[ diff_a + self.gamma * fut_reward_a_buy, -diff_a + self.gamma * fut_reward_a_sell, diff_b + self.gamma * fut_reward_b_buy, -diff_b + self.gamma * fut_reward_b_sell ]]) #reward_vec = np.array([[portfolio.get_value(stock_market_data)]]) self.model.fit(self.last_state, reward_vec, verbose=0) self.last_state = state self.last_action_a = action_A self.last_action_b = action_B self.last_portfolio_value = portfolio.get_value(stock_market_data) self.last_price_a = current_price_a self.last_price_b = current_price_b return order_list
def trade(self, portfolio: Portfolio, stock_market_data: StockMarketData) -> List[Order]: """ Generate action to be taken on the "stock market" Args: portfolio : current Portfolio of this traders stock_market_data : StockMarketData for evaluation Returns: A OrderList instance, may be empty never None """ assert portfolio is not None assert stock_market_data is not None assert stock_market_data.get_companies() == [Company.A, Company.B] # INPUT layer: 1 (buy or sell A?) # output layer: 2 ([buy_A, sell_A]) # TODO Compute the current state stock_data_A = stock_market_data[Company.A] expertA_voteA = self.expert_a.vote(stock_data_A) expertB_voteA = self.expert_b.vote(stock_data_A) stock_data_B = stock_market_data[Company.B] expertA_voteB = self.expert_a.vote(stock_data_B) expertB_voteB = self.expert_b.vote(stock_data_B) state = np.array([[ self.vote_map[expertA_voteA] + self.vote_map[expertB_voteA], self.vote_map[expertA_voteB] + self.vote_map[expertB_voteB], ]]) # do action 0 or 1? predictions = self.model.predict(state) #print(f'predictions:{predictions}') #input() action_A = np.argmax(predictions[0][0:2]) action_B = np.argmax(predictions[0][2:4]) most_recent_price_A = stock_market_data.get_most_recent_price( Company.A) most_recent_price_B = stock_market_data.get_most_recent_price( Company.B) order_list = [] money_to_spend = portfolio.cash # do stuff for A if action_A == 0: # buy all A amount_to_buy = money_to_spend // most_recent_price_A if amount_to_buy > 0: money_to_spend -= amount_to_buy * most_recent_price_A order_list.append( Order(OrderType.BUY, Company.A, amount_to_buy)) elif action_A == 1: # sell all A amount_to_sell = portfolio.get_stock(Company.A) if amount_to_sell > 0: order_list.append( Order(OrderType.SELL, Company.A, amount_to_sell)) else: assert False # do stuff for B if action_B == 0: # buy all B amount_to_buy = money_to_spend // most_recent_price_B if amount_to_buy > 0: order_list.append( Order(OrderType.BUY, Company.B, amount_to_buy)) elif action_B == 1: # sell all B amount_to_sell = portfolio.get_stock(Company.B) if amount_to_sell > 0: order_list.append( Order(OrderType.SELL, Company.B, amount_to_sell)) else: assert False if self.last_state is not None: # train diff = (portfolio.get_value(stock_market_data) / self.last_portfolio_value - 1) rec_vec = np.array([[-diff, -diff, -diff, -diff]]) rec_vec[0][self.last_action_a] = diff rec_vec[0][2 + self.last_action_b] = diff #reward_vec = np.array([[portfolio.get_value(stock_market_data)]]) self.model.fit(self.last_state, rec_vec) self.last_state = state self.last_action_a = action_A self.last_action_b = action_B self.last_portfolio_value = portfolio.get_value(stock_market_data) return order_list
def trade(self, portfolio: Portfolio, stock_market_data: StockMarketData) -> List[Order]: """ Generate action to be taken on the "stock market" Args: portfolio : current Portfolio of this traders stock_market_data : StockMarketData for evaluation Returns: A OrderList instance, may be empty never None """ assert portfolio is not None assert stock_market_data is not None assert stock_market_data.get_companies() == [Company.A, Company.B] self.day += 1 # TODO Compute the current state order_list = [] stock_data_a = stock_market_data[Company.A] stock_data_b = stock_market_data[Company.B] # Expert A expert_a = self.expert_a.vote(stock_data_a) # Expert B expert_b = self.expert_b.vote(stock_data_b) state = np.array([[ self.vote_num[expert_a], self.vote_num[expert_b], ]]) action = self.decide_action(state) # TODO Store state as experience (memory) and train the neural network only if trade() was called before at least once if self.last_state is not None: reward = (portfolio.get_value(stock_market_data) - self.last_portfolio_value) / self.last_portfolio_value self.memory.append((self.last_state, self.last_action, reward, state)) self.train_network(self.batch_size) # TODO Create actions for current state and decrease epsilon for fewer random actions act0 = 0 act1 = 0 act2 = 0 act3 = 0 act4 = 0 act5 = 0 act6 = 0 act7 = 0 act8 = 0 # What amount of the stocks should be bought or sold percent_buy = 1 percent_sell = 1 if action == 0: # Buy A stock_price_a = stock_market_data.get_most_recent_price(Company.A) amount_to_buy_a = int((portfolio.cash*percent_buy/2) // stock_price_a) if amount_to_buy_a > 0: order_list.append(Order(OrderType.BUY, Company.A, amount_to_buy_a)) # Buy B stock_price_b = stock_market_data.get_most_recent_price(Company.B) amount_to_buy_b = int((portfolio.cash*percent_buy/2) // stock_price_b) if amount_to_buy_b > 0: order_list.append(Order(OrderType.BUY, Company.B, amount_to_buy_b)) act0 += 1 elif action == 1: # Buy A stock_price_a = stock_market_data.get_most_recent_price(Company.A) amount_to_buy_a = int(portfolio.cash *percent_buy// stock_price_a) if amount_to_buy_a > 0: order_list.append(Order(OrderType.BUY, Company.A, amount_to_buy_a)) # Sell B amount_to_sell_b = int(portfolio.get_stock(Company.B)*percent_sell) if amount_to_sell_b > 0: order_list.append(Order(OrderType.SELL, Company.B, amount_to_sell_b)) act1 += 1 elif action == 2: # Sell A amount_to_sell_a = int(portfolio.get_stock(Company.A)*percent_sell) if amount_to_sell_a > 0: order_list.append(Order(OrderType.SELL, Company.A, amount_to_sell_a)) # Buy B stock_price_b = stock_market_data.get_most_recent_price(Company.B) amount_to_buy_b = int(portfolio.cash*percent_buy // stock_price_b) if amount_to_buy_b > 0: order_list.append(Order(OrderType.BUY, Company.B, amount_to_buy_b)) act2 += 1 elif action == 3: # Sell A amount_to_sell_a = int(portfolio.get_stock(Company.A)*percent_sell) if amount_to_sell_a > 0: order_list.append(Order(OrderType.SELL, Company.A, amount_to_sell_a)) # Sell B amount_to_sell_b = int(portfolio.get_stock(Company.B)*percent_sell) if amount_to_sell_b > 0: order_list.append(Order(OrderType.SELL, Company.B, amount_to_sell_b)) act3 += 1 elif action == 4: # Sell A amount_to_sell_a = int(portfolio.get_stock(Company.A)*percent_sell) if amount_to_sell_a > 0: order_list.append(Order(OrderType.SELL, Company.A, amount_to_sell_a)) # Hold B act4 += 1 elif action == 5: # Hold A # Sell B amount_to_sell_b = int(portfolio.get_stock(Company.B)*percent_sell) if amount_to_sell_b > 0: order_list.append(Order(OrderType.SELL, Company.B, amount_to_sell_b)) act5 += 1 elif action == 6: # Buy A stock_price_a = stock_market_data.get_most_recent_price(Company.A) amount_to_buy_a = int((portfolio.cash*percent_buy) // stock_price_a) if amount_to_buy_a > 0: order_list.append(Order(OrderType.BUY, Company.A, amount_to_buy_a)) # Hold B act6 += 1 elif action == 7: # Hold A # Buy B stock_price_b = stock_market_data.get_most_recent_price(Company.B) amount_to_buy_b = int((portfolio.cash*percent_buy) // stock_price_b) if amount_to_buy_b > 0: order_list.append(Order(OrderType.BUY, Company.B, amount_to_buy_b)) act7 += 1 elif action == 8: # Hold A # Hold B order_list.append(Order(OrderType.BUY, Company.B, 0)) act8 += 1 else: print("undefined action called"+str(action)) # Decrease the epsilon for fewer random actions if self.epsilon > self.epsilon_min: self.epsilon *= self.epsilon_decay # TODO Save created state, actions and portfolio value for the next call of trade() self.last_state = state self.last_action = action self.last_portfolio_value = portfolio.get_value(stock_market_data) return order_list
def trade(self, portfolio: Portfolio, stock_market_data: StockMarketData) -> List[Order]: """ Generate action to be taken on the "stock market" Args: portfolio : current Portfolio of this traders stock_market_data : StockMarketData for evaluation Returns: A OrderList instance, may be empty never None """ assert portfolio is not None assert stock_market_data is not None assert stock_market_data.get_companies() == [Company.A, Company.B] # INPUT layer: 1 (buy or sell A?) # output layer: 2 ([buy_A, sell_A]) # TODO Compute the current state stock_data_a = stock_market_data[Company.A] vote_a_for_a = self.expert_a.vote(stock_data_a) vote_b_for_a = self.expert_b.vote(stock_data_a) #stock_data_b = stock_market_data[Company.B] #vote_b = self.expert_a.vote(stock_data_b) state = np.array([[ self.vote_map[vote_a_for_a] + self.vote_map[vote_b_for_a] ]]) #, self.vote_map[vote_b]]) # do action 0 or 1? predictions = self.model.predict(state) action = np.argmax(predictions) current_price_a = stock_market_data.get_most_recent_price(Company.A) order_list = [] if action == 0: # buy all A amount_to_buy = portfolio.cash // current_price_a if amount_to_buy > 0: order_list.append( Order(OrderType.BUY, Company.A, amount_to_buy)) elif action == 1: # sell all A amount_to_sell = portfolio.get_stock(Company.A) if amount_to_sell > 0: order_list.append( Order(OrderType.SELL, Company.A, amount_to_sell)) else: assert False if self.last_state is not None: # train diff_a = (current_price_a / self.last_price_a - 1) if self.last_action_a == 0: rec_vec = np.array([[diff_a, -diff_a]]) elif self.last_action_a == 1: rec_vec = np.array([[diff_a, -diff_a]]) else: assert False # wtf #reward_vec = np.array([[portfolio.get_value(stock_market_data)]]) self.model.fit(self.last_state, rec_vec) self.last_state = state self.last_action_a = action self.last_portfolio_value = portfolio.get_value(stock_market_data) self.last_price_a = current_price_a return order_list