コード例 #1
0
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given Momemnt
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """
        if self.bought_stocks:
            return OrderList()
        else:
            self.bought_stocks = True
            order_list = OrderList()

            # Calculate how many cash to spend per company
            available_cash_per_stock = portfolio.cash / stock_market_data.get_number_of_companies()

            # Invest (100 // `len(companies)`)% of cash into each stock
            for company in list(CompanyEnum):
                most_recent_price = stock_market_data.get_most_recent_price(company)
                if most_recent_price is not None:
                    amount_to_buy = available_cash_per_stock // most_recent_price
                    order_list.buy(company, amount_to_buy)

        return order_list
コード例 #2
0
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given Momemnt
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """

        y_a = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A)
        y_b = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B)

        p_a = self.stock_a_predictor.doPredict(
            stock_market_data[CompanyEnum.COMPANY_A])
        p_b = self.stock_b_predictor.doPredict(
            stock_market_data[CompanyEnum.COMPANY_B])

        r_a = (p_a - y_a) / y_a * 100
        r_b = (p_b - y_b) / y_b * 100

        result = OrderList()

        if (r_a < 0 and portfolio.get_amount(CompanyEnum.COMPANY_A) > 0):
            result.sell(CompanyEnum.COMPANY_A,
                        portfolio.get_amount(CompanyEnum.COMPANY_A))

        if (r_b < 0 and portfolio.get_amount(CompanyEnum.COMPANY_B) > 0):
            result.sell(CompanyEnum.COMPANY_B,
                        portfolio.get_amount(CompanyEnum.COMPANY_B))

        if (r_a <= 0 and r_b <= 0):
            return result

        company = CompanyEnum.COMPANY_A

        if (r_b > r_a):
            company = CompanyEnum.COMPANY_B

        buy_amount = math.floor(
            portfolio.cash / stock_market_data.get_most_recent_price(company))

        if (portfolio.cash > 0 and buy_amount > 0):
            result.buy(company, buy_amount)

        print("Portfolio: " + str(
            portfolio.total_value(
                stock_market_data.get_most_recent_trade_day(),
                stock_market_data)))

        # TODO: implement trading logic

        return result
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given Momemnt
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """

        result = OrderList()

        predictions = {
            CompanyEnum.COMPANY_A: self.stock_a_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_A]),
            CompanyEnum.COMPANY_B: self.stock_b_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_B])
        }

        zuwachs = {}

        # sell companies which get worse
        for company in CompanyEnum:
            prediction = predictions[company]
            anzahl = portfolio.get_amount(company)
            current = stock_market_data.get_most_recent_price(company)

            zuwachs[company] = prediction / current

            # sell if getting worse
            if anzahl > 0:
                if current > prediction:
                    result.sell(company, anzahl)

        best = sorted(zuwachs, key=zuwachs.__getitem__)[::-1]

        currentCash = portfolio.cash

        for b in best:
            prediction = predictions[b]
            current = stock_market_data.get_most_recent_price(b)
            wachstum = (prediction / current)
            vola = self.isVolatile(stock_market_data[b].get_values())

            if wachstum > 1:
                if vola or wachstum > 1.001:
                    count = math.floor(currentCash / current)
                    result.buy(b, count)
                    currentCash -= count * current
                else:
                    result.sell(b, portfolio.get_amount(b))

        return result
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given Momemnt
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """
        result = OrderList()

        predictions = {
            CompanyEnum.COMPANY_A: self.stock_a_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_A]),
            CompanyEnum.COMPANY_B: self.stock_b_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_B])
        }

        zuwachs = {}

        # sell companies which get worse
        for company in CompanyEnum:
            prediction = predictions[company]
            anzahl = portfolio.get_amount(company)
            current = stock_market_data.get_most_recent_price(company)

            zuwachs[company] = prediction / current

            # sell if getting worse
            if anzahl > 0:
                if current > prediction:
                    result.sell(company, anzahl)

        bestCompany = None
        bestZuwachs = 1
        for company in CompanyEnum:
            if zuwachs[company] > bestZuwachs:
                bestZuwachs = zuwachs[company]
                bestCompany = company

        if bestCompany:
            current = stock_market_data.get_most_recent_price(company)
            count = math.floor(portfolio.cash / current)
            result.buy(bestCompany, count)



        # TODO: implement trading logic

        return result
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given Momemnt
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """

        order_list = OrderList()

        pred_a_value = self.stock_a_predictor.doPredict(
            stock_market_data[CompanyEnum.COMPANY_A])
        pred_b_value = self.stock_b_predictor.doPredict(
            stock_market_data[CompanyEnum.COMPANY_B])

        stock_a = portfolio.get_amount(CompanyEnum.COMPANY_A)
        stock_a_value = stock_market_data.get_most_recent_price(
            CompanyEnum.COMPANY_A)
        stock_b = portfolio.get_amount(CompanyEnum.COMPANY_B)
        stock_b_value = stock_market_data.get_most_recent_price(
            CompanyEnum.COMPANY_B)

        increase_a = pred_a_value - stock_a_value
        increase_b = pred_b_value - stock_b_value

        new_cash = 0.0

        if stock_a > 0 and increase_a < 0.0:
            order_list.sell(CompanyEnum.COMPANY_A, stock_a)

        if stock_b > 0 and increase_b < 0.0:
            order_list.sell(CompanyEnum.COMPANY_B, stock_b)

        if increase_a > increase_b and increase_a > 0.0:
            count_a = portfolio.cash / stock_a_value
            if count_a > 0:
                order_list.buy(CompanyEnum.COMPANY_A, int(count_a))
        elif increase_b > increase_a and increase_b > 0.0:
            count_b = portfolio.cash / stock_b_value
            if count_b > 0:
                order_list.buy(CompanyEnum.COMPANY_B, int(count_b))

        # TODO: implement trading logic

        return order_list
コード例 #6
0
    def test_update__sufficient_cash_reserve(self):
        """
        Tests: Portfolio#update

        Flavour: Enough cash in the portfolio, so the trades should be applied

        Creates a portfolio, a stock market data object and a arbitrary `OrderList` and executes these orders on the
        portfolio. Checks if those are applied correctly
        """
        cash_reserve = 20000.0

        data = StockData([(date(2017, 1, 1), 150.0)])
        stock_market_data = StockMarketData({CompanyEnum.COMPANY_A: data})

        portfolio = Portfolio(cash_reserve,
                              [SharesOfCompany(CompanyEnum.COMPANY_A, 200)])

        order_list = OrderList()
        order_list.buy(CompanyEnum.COMPANY_A, 100)

        updated_portfolio = portfolio.update(stock_market_data, order_list)

        # Current cash reserve is sufficient for trade volume. Trade should happen
        assert updated_portfolio.cash < cash_reserve
        assert updated_portfolio.cash < portfolio.cash
        assert updated_portfolio.shares[
            0].company_enum == CompanyEnum.COMPANY_A
        assert updated_portfolio.shares[0].amount == 300
コード例 #7
0
    def test_update__do_not_drop_below_cash_0(self):
        """
        Tests: Portfolio#update

        Flavour: When receiving two BUY orders the `#update` method should regard the available cash and NEVER drop
         below 0

        Creates a portfolio, a stock market data object and a arbitrary `OrderList` and executes these orders on the
        portfolio. Checks if those are applied correctly
        """
        cash_reserve = 16000.0

        data = StockData([(date(2017, 1, 1), 150.0)])
        stock_market_data = StockMarketData({CompanyEnum.COMPANY_A: data})

        portfolio = Portfolio(cash_reserve, [])

        # Create a order list whose individual actions are within the limit but in sum are over the limit
        # Stock price: 150.0, quantity: 100 -> trade volume: 15000.0; cash: 16000.0
        order_list = OrderList()
        order_list.buy(CompanyEnum.COMPANY_A, 100)
        order_list.buy(CompanyEnum.COMPANY_A, 100)

        updated_portfolio = portfolio.update(stock_market_data, order_list)

        assert updated_portfolio.cash >= 0
コード例 #8
0
ファイル: utils.py プロジェクト: Asteur/traderAI
def read_stock_market_data(stocks: StockList,
                           periods: PeriodList) -> StockMarketData:
    """
    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 `CompanyEnum` 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()

    # Read *all* available data
    for stock in stocks:
        filename = stock.value
        if len(periods) is 0:
            data[stock] = StockData(
                __read_stock_market_data([[stock, filename]])[stock])
        else:
            period_data = list()
            for period in periods:
                period_data.append(
                    __read_stock_market_data(
                        [[stock, ('%s_%s' % (filename, period))]]))
            data[stock] = StockData([
                item for period_dict in period_data if period_dict is not None
                for item in period_dict[stock]
            ])

    return StockMarketData(data)
コード例 #9
0
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:

        orders = OrderList()

        cheapest_company = min(
            list(CompanyEnum),
            key=lambda c: stock_market_data.get_most_recent_price(c))

        cash_per_comp = portfolio.cash / stock_market_data.get_number_of_companies(
        )

        price = stock_market_data.get_most_recent_price(cheapest_company)
        num_shares_to_buy = cash_per_comp // price
        if num_shares_to_buy > 0:
            orders.buy(cheapest_company, num_shares_to_buy)
            logger.info("Bought {0} shares.".format(num_shares_to_buy))

        return orders
コード例 #10
0
def get_data_up_to_offset(stock_market_data: StockMarketData, offset: int):
    """
    Removes all data items *behind* the given `offset` - this emulates going through history in a list of
    date->price items

    Args:
        stock_market_data: The `market_data` to step through
        offset: The offset to apply

    Returns:
        A copied `StockMarketData` object which only reaches from start to `offset`
    """
    if offset == 0:
        return stock_market_data

    offset_data = {}
    for company in stock_market_data.get_companies():
        offset_data[company] = stock_market_data[company].copy_to_offset(offset)

    return StockMarketData(offset_data)
コード例 #11
0
    def create_order_list(self, action_a: float, action_b: float,
                          portfolio: Portfolio, stock_market_data: StockMarketData) -> OrderList:
        """
        Take two floats between -1.0 and +1.0 (one for stock A and one for stock B) and convert them into corresponding
        orders.

        Args:
            action_a: float between -1.0 and 1.0, representing buy(positive) / sell(negative) for Company A
            action_b: float between -1.0 and 1.0, representing buy(positive) / sell(negative) for Company B
            portfolio: current portfolio of this trader
            stock_market_data: current stock market data

        Returns:
            List of corresponding orders
        """
        assert -1.0 <= action_a <= +1.0 and -1.0 <= action_b <= +1.0
        assert portfolio is not None and stock_market_data is not None
        order_list = OrderList()

        # Create orders for stock A
        owned_amount_a = portfolio.get_amount(CompanyEnum.COMPANY_A)
        if action_a > 0.0:
            current_price = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A)
            amount_to_buy = int(action_a * (portfolio.cash // current_price))
            order_list.buy(CompanyEnum.COMPANY_A, amount_to_buy)
        if action_a < 0.0 and owned_amount_a > 0:
            amount_to_sell = int(abs(action_a) * owned_amount_a)
            order_list.sell(CompanyEnum.COMPANY_A, amount_to_sell)

        # Create orders for stock B
        owned_amount_b = portfolio.get_amount(CompanyEnum.COMPANY_B)
        if action_b > 0.0:
            current_price = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B)
            amount_to_buy = int(action_b * (portfolio.cash // current_price))
            order_list.buy(CompanyEnum.COMPANY_B, amount_to_buy)
        if action_b < 0.0 and owned_amount_b > 0:
            amount_to_sell = int(abs(action_b) * owned_amount_b)
            order_list.sell(CompanyEnum.COMPANY_B, amount_to_sell)
        return order_list
コード例 #12
0
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given moment
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """
        
        current_price_a = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A)
        current_price_b = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B)
        
        predicted_price_a = self.stock_a_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_A])
        predicted_price_b = self.stock_b_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_B])
        
        portfolio_value = portfolio.total_value(
            stock_market_data.get_most_recent_trade_day(), 
            stock_market_data)

        state = State(portfolio_value,
            current_price_a, predicted_price_a, 
            current_price_b, predicted_price_b)

        if self.last_state and self.train_while_trading:
            self.train_model(state, self.last_state)

        action = self.decide_action(state, self.last_state)
        orders = self.create_orders(action, portfolio, stock_market_data)

        self.last_state = state

        # log_orders(orders)

        return orders
コード例 #13
0
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given moment
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """
        # build current state object
        stock_a_data = stock_market_data[CompanyEnum.COMPANY_A]
        stock_b_data = stock_market_data[CompanyEnum.COMPANY_B]
        predicted_stock_a = self.stock_a_predictor.doPredict(stock_a_data)
        predicted_stock_b = self.stock_b_predictor.doPredict(stock_b_data)
        current_state = State(portfolio.cash,
                              portfolio.get_amount(CompanyEnum.COMPANY_A),
                              portfolio.get_amount(CompanyEnum.COMPANY_B),
                              stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A),
                              stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B),
                              predicted_stock_a,
                              predicted_stock_b)
        logger.debug(f"DQL Trader: Current state: {current_state}")

        # Store experience and train the neural network only if doTrade was called before at least once
        if self.train_while_trading and self.last_state is not None:
            reward = self.calculate_reward(self.last_portfolio_value, current_portfolio_value)
            memory_tuple = (self.last_state, self.last_action_a, self.last_action_b, reward, current_state)
            self.memory.append(memory_tuple)
            if len(self.memory) > self.batch_size + self.min_size_of_memory_before_training:
                self.train_model()

        # Create actions for current state and decrease epsilon for fewer random actions
        (action_a, action_b) = self.get_action(current_state)
        self.epsilon = max([self.epsilon_min, self.epsilon * self.epsilon_decay])
        logger.debug(f"DQL Trader: Computed orders {action_a} and {action_b} with epsilon {self.epsilon}")

        # Save created state, actions and portfolio value for the next call of doTrade
        self.last_state, self.last_action_a, self.last_action_b = current_state, action_a, action_b
        self.last_portfolio_value = current_portfolio_value
        return self.create_order_list(action_a, action_b, portfolio, stock_market_data)
コード例 #14
0
    def test_update__action_order_does_not_matter(self):
        """
        Tests: Portfolio#update

        Flavour: It shouldn't matter which order the orders are in, the result should always look the same. In
         this case the portfolio's cash reserve is too low to execute a BUY action. However, it shouldn't matter if we
         execute a SELL action first, because the updated cash reserve after a SELL action shouldn't affect the
         available cash reserve for a subsequent BUY action

        Creates a portfolio, a stock market data object and a arbitrary `OrderList` and executes these orders on the
        portfolio. Checks if those are applied correctly
        """
        cash_reserve = 10.0

        data = StockData([(date(2017, 1, 1), 150.0)])
        stock_market_data = StockMarketData({CompanyEnum.COMPANY_A: data})

        # Create two equal designed portfolios
        portfolio1 = Portfolio(cash_reserve,
                               [SharesOfCompany(CompanyEnum.COMPANY_A, 200)])
        portfolio2 = Portfolio(cash_reserve,
                               [SharesOfCompany(CompanyEnum.COMPANY_A, 200)])

        assert portfolio1 == portfolio2

        # Create two order lists with the same entries, however in different order
        order_list_1 = OrderList()
        order_list_1.buy(CompanyEnum.COMPANY_A, 100)
        order_list_1.sell(CompanyEnum.COMPANY_A, 100)

        order_list_2 = OrderList()
        order_list_2.sell(CompanyEnum.COMPANY_A, 100)
        order_list_2.buy(CompanyEnum.COMPANY_A, 100)

        # Execute the trade action lists on the two portfolios
        updated_portfolio_order1 = portfolio1.update(stock_market_data,
                                                     order_list_1)
        updated_portfolio_order2 = portfolio2.update(stock_market_data,
                                                     order_list_2)

        # The portfolios should still be equal after applying the actions
        assert updated_portfolio_order1 == updated_portfolio_order2
コード例 #15
0
    def test_inspect__date_offset(self):
        """
        Tests: Evaluator#inspect_over_time

        Flavour: Test with an date offset
        """
        data = StockData([(date(2017, 1, 1), 150.0), (date(2017, 1, 2), 200.0),
                          (date(2017, 1, 3), 250.0)])
        stock_market_data = StockMarketData({CompanyEnum.COMPANY_A: data})

        portfolio = Portfolio(20000,
                              [SharesOfCompany(CompanyEnum.COMPANY_A, 200)])

        evaluator = PortfolioEvaluator(
            [SimpleTrader(RandomPredictor(), RandomPredictor())])

        portfolio_over_time: dict = \
            evaluator.inspect_over_time(stock_market_data, [portfolio], date_offset=date(2017, 1, 2))['nameless']

        assert date(2016, 12, 31) not in portfolio_over_time.keys()
        assert date(2017, 1, 1) in portfolio_over_time.keys()
        assert date(2017, 1, 2) in portfolio_over_time.keys()
        assert date(2017, 1, 3) not in portfolio_over_time.keys()
コード例 #16
0
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given moment
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """

        # TODO: Store experience and train the neural network only if doTrade was called before at least once

        # TODO: Create actions for current state and decrease epsilon for fewer random actions

        # TODO: Save created state, actions and portfolio value for the next call of doTrade

        deltaA = self.stock_a_predictor.doPredict(
            stock_market_data[CompanyEnum.COMPANY_A]) / stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A)
        deltaB = self.stock_b_predictor.doPredict(
            stock_market_data[CompanyEnum.COMPANY_B]) / stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B)

        INPUT = numpy.asarray([[
            (deltaA - 1.0) / 0.04,
            (deltaB - 1.0) / 0.04,
        ]])
        qualities = self.model.predict(INPUT)[0]

        qmax = max(qualities[0], qualities[1], qualities[2])

        currentValue = portfolio.total_value(stock_market_data.get_most_recent_trade_day(), stock_market_data)

        if self.lastValue and self.train_while_trading:
            lastReward = min(1, max(-1, (currentValue / self.lastValue - 1) / 0.04))
            shouldBeQ = lastReward + GAMMA * qmax

            self.lastOutput[self.lastAmax] = shouldBeQ

            xtrain = [self.lastInput[0]]
            ytrain = [self.lastOutput]
            for m in self.memory:
                xtrain.append(m[0][0])
                qs = self.model.predict(m[0])[0]
                qs[m[1]] = m[2] + GAMMA * qs[m[1]]
                ytrain.append(qs)

            self.model.fit(numpy.asarray(xtrain), numpy.asarray(ytrain))

            self.memory.append([self.lastInput, self.lastAmax, lastReward])
            if len(self.memory) > MEMOMRY_SIZE:
                self.memory.pop(0)

        self.lastValue = currentValue
        self.lastInput = INPUT
        self.lastOutput = qualities

        result = OrderList()

        actions = ["BUY_A__SELL_B", "BUY_A", "BUY_B__SELL_A", "BUY_B", "SELL_ALL"]

        nextAction = None
        if random.random() < self.epsilon and self.train_while_trading:
            nextAction = actions[random.randint(0, self.action_size - 1)]
        else:
            i = 0 if qualities[0] > qualities[1] else 1
            i = 2 if qualities[2] > qualities[i] else i
            i = 3 if qualities[3] > qualities[i] else i
            i = 4 if qualities[4] > qualities[i] else i
            nextAction = actions[i]

        self.epsilon = max(self.epsilon_decay * self.epsilon, self.epsilon_min)

        if nextAction == "BUY_A__SELL_B":
            result.sell(CompanyEnum.COMPANY_B, portfolio.get_amount(CompanyEnum.COMPANY_B))
            count = math.floor(portfolio.cash / stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A))
            result.buy(CompanyEnum.COMPANY_A, count)
            self.lastAmax = 0
        elif nextAction == "BUY_A":
            count = math.floor(portfolio.cash / stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A))
            result.buy(CompanyEnum.COMPANY_A, count)
            self.lastAmax = 1
        elif nextAction == "BUY_B__SELL_A":
            result.sell(CompanyEnum.COMPANY_A, portfolio.get_amount(CompanyEnum.COMPANY_A))
            count = math.floor(portfolio.cash / stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B))
            result.buy(CompanyEnum.COMPANY_B, count)
            self.lastAmax = 2
        elif nextAction == "BUY_B":
            count = math.floor(portfolio.cash / stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B))
            result.buy(CompanyEnum.COMPANY_B, count)
            self.lastAmax = 3
        elif nextAction == "SELL_ALL":
            result.sell(CompanyEnum.COMPANY_A, portfolio.get_amount(CompanyEnum.COMPANY_A))
            result.sell(CompanyEnum.COMPANY_B, portfolio.get_amount(CompanyEnum.COMPANY_B))
            self.lastAmax = 4

        return result
コード例 #17
0
    def inspect_over_time_with_mapping(
            self,
            market_data: StockMarketData,
            portfolio_trader_mapping: PortfolioTraderMappingList,
            evaluation_offset: int = -1,
            date_offset: datetime.date = None):
        """
        Behaves exactly as `#inspect_over_time *except* for the parameter `portfolio_trader_mapping`:
        While `#inspect_over_time` uses the traders provided to the constructor of this class, this method uses the
        provided list of trader-portfolio mappings. This allows for an fixed association between portfolios and their
        traders

        Args:
            market_data:
            portfolio_trader_mapping: A mapping between portfolios and traders.
             Structure: `List[Tuple[Portfolio, ITrader]]`
            evaluation_offset:
            date_offset:

        Returns:

        """
        # Map that holds all portfolios in the course of time. Structure: {portfolio_name => {date => portfolio}}
        all_portfolios = {}

        # Cache that holds the latest object of each portfolio. Structure: {portfolio_name => portfolio}
        portfolio_cache = {}

        # Map that holds the drawing colors for each portfolio
        colors = {}

        if not market_data.check_data_length():
            # Checks whether all data series are of the same length (i.e. have an equal count of date->price items)
            return

        if evaluation_offset == -1 and date_offset is None:
            # `evaluation_offset` has the 'disabled' value, so we calculate it based on the underlying data
            evaluation_offset = market_data.get_row_count()

        if date_offset is not None:
            # `date_offset` is set, so the `evaluation_offset` is calculated based on the given date
            first_company = next(iter(market_data.get_companies()))
            market_data_for_company = market_data[first_company]
            index = market_data_for_company.get_dates().index(date_offset)
            evaluation_offset = market_data.get_row_count() - index

        # Reading should start one day later, because we also save the initial portfolio value in our return data.
        # Therefore the return data contains `evaluation_offset` rows which includes `evaluation_offset`-1 trades
        evaluation_offset = evaluation_offset - 1

        # And now the clock ticks
        # We start at -`evaluation_offset` and roll through the `market_data` in forward direction until the
        # second-to-last item
        for current_tick in range(-evaluation_offset, 0):

            # Retrieve the stock market data up the current day, i.e. move one tick further in `market_data`
            current_market_data = get_data_up_to_offset(
                market_data, current_tick)

            # Retrieve the current date
            current_date = current_market_data.get_most_recent_trade_day()

            portfolio_list = [p_t[0] for p_t in portfolio_trader_mapping]
            logger.debug(
                f"Start updating portfolios {portfolio_list} on {current_date} (tick {current_tick})"
            )

            for portfolio, trader, color in portfolio_trader_mapping:
                if current_tick == -evaluation_offset:
                    # Save the starting state of this portfolio
                    yesterday = current_date - datetime.timedelta(days=1)
                    all_portfolios.update(
                        {portfolio.name: {
                            yesterday: portfolio
                        }})
                    portfolio_cache.update({portfolio.name: portfolio})

                # Retrieve latest portfolio object from cache
                portfolio_to_update = portfolio_cache[portfolio.name]

                # Determine the total portfolio value at this time
                current_total_portfolio_value = portfolio_to_update.total_value(
                    current_date, current_market_data)

                # Ask the trader for its action
                update = trader.doTrade(portfolio_to_update,
                                        current_total_portfolio_value,
                                        current_market_data)

                # Update the portfolio that is saved at ILSE - The InnovationLab Stock Exchange ;-)
                updated_portfolio = portfolio_to_update.update(
                    current_market_data, update)

                # Save the updated portfolio in our dict under the current date as key
                all_portfolios[
                    updated_portfolio.name][current_date] = updated_portfolio
                portfolio_cache.update({portfolio.name: updated_portfolio})

                colors[portfolio.name] = color

            logger.debug(
                f"End updating portfolios {portfolio_list} on {current_date} (tick {current_tick})\n"
            )

        # Draw a diagram of the portfolios' changes over time - if we're not unit testing
        if self.draw_results:
            draw(all_portfolios, market_data, colors)

        return all_portfolios
コード例 #18
0
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given moment
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """
        # TODO: Build and store current state object
        s_a_current = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A)
        s_b_current = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B)

        pct_a = round((s_a_current * portfolio.get_amount(CompanyEnum.COMPANY_A))/portfolio.total_value(stock_market_data.get_most_recent_trade_day(), stock_market_data), 2)
        pct_b = round((s_b_current * portfolio.get_amount(CompanyEnum.COMPANY_B))/portfolio.total_value(stock_market_data.get_most_recent_trade_day(), stock_market_data), 2)
        pct_cash = 1 - pct_a - pct_b;


        s_a_next = self.stock_a_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_A]);
        s_b_next = self.stock_b_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_B]);

        pct_a_diff = round((s_a_next - s_a_current) / s_a_current, 2);
        pct_b_diff = round((s_b_next - s_b_current) / s_b_current, 2);

        portfolio_value = portfolio.total_value(stock_market_data.get_most_recent_trade_day(), stock_market_data);
        portfolio_diff = round((self.portfolio_value_prev - portfolio_value) / self.portfolio_value_prev, 2);




        #r = -1;
        #if (portfolio_diff < 0):
        #    r = 1;
        #elif (portfolio_diff == 0):
        #    r = 0;

        if (portfolio_diff < 0):
            self.y_prev[0][self.idx_prev] = 1;
        elif (portfolio_diff >= 0):
            self.y_prev[0][self.idx_prev] = -1;




        # TODO: Store experience and train the neural network only if doTrade was called before at least once
        if (self.loop_value > 0):
            self.model.fit(np.array([[self.pct_a_prev, self.pct_b_prev, self.pct_cash_prev, self.diff_a_prev, self.diff_b_prev]]), self.y_prev, epochs=1, batch_size=1)

        # TODO: Create actions for current state and decrease epsilon for fewer random actions

        res = self.model.predict(np.array([[pct_a, pct_b, pct_cash, pct_a_diff, pct_b_diff]])) # [0, 0, 1, 0]
        idx = np.argmax(res);

        ret = OrderList()


        if (idx == 0):
            ret.buy(CompanyEnum.COMPANY_A, math.floor(portfolio.cash / stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A)))
        elif (idx == 1):
            ret.buy(CompanyEnum.COMPANY_B, math.floor(portfolio.cash / stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B)))
        elif (idx == 2):
            ret.sell(CompanyEnum.COMPANY_A, portfolio.get_amount(CompanyEnum.COMPANY_A))     
        else:
            ret.sell(CompanyEnum.COMPANY_B, portfolio.get_amount(CompanyEnum.COMPANY_B))



        # TODO: Save created state, actions and portfolio value for the next call of doTrade
        self.portfolio_value_prev = portfolio_value;
        self.pct_a_prev = pct_a;
        self.pct_b_prev = pct_b;
        self.pct_cash_prev = pct_cash;
        self.diff_a_prev = pct_a_diff;
        self.diff_b_prev = pct_a_diff;
        self.idx_prev = idx;
        self.y_prev = res;

        self.loop_value = self.loop_value + 1;

        return ret
コード例 #19
0
    def doTrade(self, portfolio: Portfolio, current_portfolio_value: float,
                stock_market_data: StockMarketData) -> OrderList:
        """
        Generate action to be taken on the "stock market"
    
        Args:
          portfolio : current Portfolio of this trader
          current_portfolio_value : value of Portfolio at given moment
          stock_market_data : StockMarketData for evaluation

        Returns:
          A OrderList instance, may be empty never None
        """
        # TODO: Build and store current state object

        ## cash %, portfolio a value %, portfolio b %, pred a, pred b

        account_value = portfolio.cash + current_portfolio_value
        a_value = portfolio.get_amount(CompanyEnum.COMPANY_A) * stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A)
        b_value = portfolio.get_amount(CompanyEnum.COMPANY_B) * stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B)

        a_value_percent = a_value / account_value
        b_value_percent = b_value / account_value
        cash_percent = portfolio.cash / account_value

        pred_a_value = self.stock_a_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_A])
        pred_b_value = self.stock_b_predictor.doPredict(stock_market_data[CompanyEnum.COMPANY_B])

        stock_a_value = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_A)
        stock_b_value = stock_market_data.get_most_recent_price(CompanyEnum.COMPANY_B)

        increase_a = (pred_a_value - stock_a_value) / stock_a_value
        increase_b = (pred_b_value - stock_b_value) / stock_b_value

        current_status = [[cash_percent, a_value_percent, b_value_percent, increase_a, increase_b]]

        np_current_status = np.array(current_status)

        # TODO: Store experience and train the neural network only if doTrade was called before at least once

        ## calc rewards = was cash + portfolio - (old cash + old portfolio), map auf 1 0 -1, now simple:
        if self.stored_action >= 0:

            if current_portfolio_value > self.stored_portfolio_value:
                reward = 1.0
            elif current_portfolio_value < self.stored_portfolio_value:
                reward = -1.0
            else:
                reward = 0

            reward_array = [0, 0, 0]

            reward_array[self.stored_action] = reward

            np_reward_array = np.array([reward_array])

            ## train again

            # print(np_reward_array)


            if self.train_while_trading:
                self.model.fit(self.np_previous_status, np_reward_array, epochs=1, batch_size=1, verbose=0)

        # TODO: Create actions for current state and decrease epsilon for fewer random actions

        action = -1

        random_value = uniform(0.0, 1.0)
        if random_value > self.epsilon:
            action = randint(0, 2)
        else:
            pred = self.model.predict(np_current_status)
            prediction = pred[0]

            if len(prediction) != 3:
                print("komische prediction")

            action = 2
            max = prediction[action]

            for i in range(3):
                if prediction[i] > max:
                    action = i


        self.count[action] = self.count[action] + 1
        # print("actions")
        # print(self.count)

        self.epsilon = self.epsilon * self.epsilon_decay
        if self.epsilon < self.epsilon_min:
            self.epsilon = self.epsilon_min

        order_list = OrderList()

        if action < 0 or action > 2:
            print("komische action")
            print(action)
        else:

            stock_a = portfolio.get_amount(CompanyEnum.COMPANY_A)
            stock_b = portfolio.get_amount(CompanyEnum.COMPANY_B)

            if action == 0:
                # sell a
                if stock_a > 0:
                    order_list.sell(CompanyEnum.COMPANY_A, stock_a)
                # buy b
                count_b = portfolio.cash / stock_b_value
                if count_b > 0:
                    order_list.buy(CompanyEnum.COMPANY_B, int(count_b))
            if action == 1:
                # sell b
                if stock_b > 0:
                    order_list.sell(CompanyEnum.COMPANY_B, stock_b)
                # boy a
                count_a = portfolio.cash / stock_a_value
                if count_a > 0:
                    order_list.buy(CompanyEnum.COMPANY_A, int(count_a))

        # TODO: Save created state, actions and portfolio value for the next call of

        self.stored_action = action
        self.stored_portfolio_value = current_portfolio_value
        self.np_previous_status = np_current_status

        ## save current state as laststate, current portfolio and cash

        return order_list