def trading_algorithm_2():
     yield {
         b:
         formula.Constant(3.5),
         b_or_g:
         formula.Product(formula.Constant(2), formula.Price(if_g_then_r,
                                                            2)),
     }
     yield {
         b: formula.Constant(-1),
         if_g_then_r: formula.Max(formula.Price(b, 1), formula.Price(g, 2)),
     }
def test_find_credences_multiple():
    credence_history = credence.History(
        [])  # empty history; we are on the first update
    trading_formulas = {
        # purchase sentence 1 in quantity max(credence-of-sentence-1, credence-of-sentence-2)
        1:
        formula.Max(formula.Price(1, 1), formula.Price(2, 1)),
        # purchase sentence 2 in quantity 1 - credence-of-sentence-1 - credence-of-sentence-2
        2:
        formula.Sum(
            formula.Constant(1),
            formula.Sum(
                formula.Product(formula.Constant(-1), formula.Price(1, 1)),
                formula.Product(formula.Constant(-1), formula.Price(2, 1))))
    }

    new_credences = inductor.find_credences(trading_formulas, credence_history,
                                            1e-5)

    # setting credence[1] to 1 and credence[2] to 0 satisfies the conditions
    assert_almost_equal(new_credences[1], 1)
    assert_almost_equal(new_credences[2], 0)
def trade_on_probability(sentence, day, p, slope=10):
    return formula.Min(
        formula.Constant(1),
        formula.Max(
            formula.Constant(-1),
            formula.Sum(
                formula.Constant(slope * p),
                formula.Product(
                    formula.Constant(-slope),
                    formula.Price(sentence, day)
                )
            )
        )
    )
Example #4
0
def make_s_curve(f, intercept, slope):
    return formula.Min(
        formula.Constant(1),
        formula.Max(
            formula.Constant(-1),
            formula.Sum(
                formula.Constant(slope * intercept),
                formula.Product(
                    formula.Constant(-slope),
                    f
                )
            )
        )
    )
def test_find_credences_single():
    credence_history = credence.History([])  # empty history
    trading_formulas = {
        # purchase sentence 1 in quantity 1 - 3 * credence
        1:
        formula.Sum(formula.Constant(1),
                    formula.Product(formula.Constant(-3), formula.Price(1,
                                                                        1))),
    }

    new_credences = inductor.find_credences(trading_formulas, credence_history,
                                            1e-5)

    # setting credence to 1/3 yields a trade quantity of zero, which satisfies
    assert_almost_equal(new_credences[1], 1 / 3)
Example #6
0
def combine_trading_algorithms(trading_histories, observation_history,
                               credence_history):
    """
    Given:
     * A sequence of N generators over trading formulas (trading_algorithms)
     * A sequence of N sentences (observation_history)
     * A sequence of N-1 belief states (credence_history)
    Returns:
     * A single trading formula for day N that incorporates the wisdom from 
       the N trading algorithms. The returned trading formula exploits any
       market that any of the N constituent trading algorithms exploits.

    This function implements TradingFirm as defined in 5.3.2 in the logical
    induction paper.
    """
    n = len(credence_history) + 1
    assert len(observation_history) == n
    assert len(trading_histories) == n

    # compute the terms that should be added together to produce the final
    # trading formula
    terms_by_sentence = collections.defaultdict(list)
    for k, trading_history in enumerate(
            trading_histories):  # this is the loop over \Sum_{k<=n}
        # zero out the first k entries
        clipped_trading_history = []
        for i, trading_formula in enumerate(trading_history):
            if i < k:
                clipped_trading_history.append({})
            else:
                clipped_trading_history.append(trading_formula)

        # compute an upper bound on the net value for this trading history
        net_value_bound = 0
        for trading_formula in clipped_trading_history:
            for sentence, trading_expr in trading_formula.items():
                # compute an upper bound on the absolute value of trading_expr,
                # which is the quantity that we will purchase of this sentence
                quantity_bound = trading_expr.bound()

                # Let C = quantity_bound. We might spend up to $C purchasing
                # these tokens, and they might later be worth up to $C, so their
                # net value could be between -$C and $2C. We technically only
                # need a lower bound for the sum below but here we follow the
                # paper and compute a formal bound on the net value of this
                # trade by including the constant 2 below. See the last
                # paragraph of proof of 5.3.2 in the paper.
                net_value_bound += 2 * quantity_bound

        net_value_bound = math.ceil(net_value_bound)

        # TODO: we can compute a better bound by using the N-1 belief states
        # that we have already observed in credence_history

        for budget in range(1, net_value_bound + 1):
            budget_factor = compute_budget_factor(budget,
                                                  observation_history[:-1],
                                                  observation_history[-1],
                                                  clipped_trading_history[:-1],
                                                  clipped_trading_history[-1],
                                                  credence_history)

            for sentence, trading_expr in clipped_trading_history[-1].items():
                weight = 2**(-k - 1 - budget)
                terms_by_sentence[sentence].append(
                    formula.Product(formula.Constant(weight), budget_factor,
                                    trading_expr))

        for sentence, trading_expr in clipped_trading_history[-1].items():
            weight = 2**(-k - 1 - net_value_bound)
            terms_by_sentence[sentence].append(
                formula.Product(formula.Constant(weight), trading_expr))

    # create a trading formula for each sentence that is a sum of the terms
    # computed above
    return {
        sentence: formula.Sum(*terms)
        for sentence, terms in terms_by_sentence.items()
    }
Example #7
0
def compute_budget_factor(budget, observation_history, next_observation,
                          trading_history, next_trading_formulas,
                          credence_history):
    """
    Returns a trading formula representing a weight that can be multiplied with
    each formula in next_trading_formulas in order to guarantee that the
    trader's value-of-holdings will not fall below the given budget in any
    world.

    The worlds considered are those that are propositionally consistent with the
    sentences in observation_history and next_observation.

    The lists observation_history, trading_history, and credence_history all
    have the same length.

    next_observation is the most recently observed sentence.

    next_trading_formulas is a list of (sentence, formula) pairs that will be
    evaluated on whatever credences the logical inductor outputs when it updates
    its credences in light of next_observation. We do not get to see these
    credences when computing the budget factor because the budget factor is an
    input to the process by which the logical inductor updates its credences.
    """
    assert budget > 0

    history_length = len(observation_history)

    # compute the support for all trading formulas over all days
    support = union(
        set(trading_formulas.keys()) for trading_formulas in trading_history)

    # evaluate the "if" clause in (5.2.1)
    for i in range(history_length):
        observations_up_to_i = set(observation_history[:i + 1])

        # go over the worlds consistent with the first N observations
        for world in worlds_consistent_with(observations_up_to_i, support):

            # calculate the accumulated value of the trader up to update N
            accumulated_value = 0
            for cur_trading_formulas in trading_history[:i + 1]:
                accumulated_value += evaluate(cur_trading_formulas,
                                              credence_history, world)

                # if we have exceeded our budget on a previous update then we
                # have no more money to trade now
                if accumulated_value < -budget + 1e-7:
                    return formula.Constant(0)

    # create a set of observations up to and including the most recent
    observations = set(observation_history)
    observations.add(next_observation)

    # add atoms for next_trading_formula to the support set
    support.update(set(next_trading_formulas.keys()))

    # if we got this far then we have not already exceeded our budget, so now
    # compute the budget factor
    budget_divisors = []
    for world in worlds_consistent_with(observations, support):
        # compute our accumulated value in this world
        accumulated_value = 0
        for cur_trading_formulas in trading_history:
            accumulated_value += evaluate(cur_trading_formulas,
                                          credence_history, world)

        # the money we have left to trade now is our original budget, plus
        # (resp. minus) any money we made (resp. lost) since the beginning of
        # time
        remaining_budget = budget + accumulated_value

        # this value should be positive given the check that we did above
        assert remaining_budget > 1e-8
        remaining_budget_recip = 1. / remaining_budget

        # construct a trading formula representing the value of
        # next_trading_formulas in this world, as a function of the
        # yet-to-be-determined credences for the latest update
        value_of_holdings_terms = []
        for sentence, trading_formula in next_trading_formulas.items():
            # construct a trading formula that looks up the price of tokens for this sentence
            price = formula.Price(sentence, history_length + 1)

            # construct a trading formula that computes the value that this
            # sentence pays out in this world
            payout = formula.Constant(float(world[sentence]))

            # construct a trading formula that computes the net value of
            # purchasing one token of this sentence, which is the payout from the
            # token minus the price paid to purchase the token
            value = formula.Sum(payout,
                                formula.Product(formula.Constant(-1), price))

            # construct a trading formula that multiplies the number of tokens that we
            # purchase by their profitability
            value_of_holdings_terms.append(
                formula.Product(trading_formula, value))

        # construct a trading formula representing the value of the trades
        # executed on this update in this world
        value_of_holdings = formula.Sum(*value_of_holdings_terms)

        # construct a trading formula representing the negation of the above
        neg_value_of_holdings = formula.Product(formula.Constant(-1),
                                                value_of_holdings)

        # construct a trading formula representing the value we would need to
        # divide our trades by in this world in order to make sure we do not
        # exceed our remaining budget
        divisor_in_this_world = formula.Product(
            formula.Constant(remaining_budget_recip), neg_value_of_holdings)

        # add the budget factor for this world to the list of terms
        budget_divisors.append(divisor_in_this_world)

    # the final budget divisor is the max of all the possible budget divisors.
    budget_divisor = formula.Max(*budget_divisors)

    # now take the safe reciprocal of the divisor, which turns it into a
    # multiplicative factor and also clips it to 1, so that we only scale
    # traders down, not up. This is what we want because if a trader is below
    # its budget then there is no need to scale it up until it uses all of its
    # remaining budget.
    budget_factor = formula.SafeReciprocal(budget_divisor)

    # and we are done!
    return budget_factor