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 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)
                )
            )
        )
    )
Beispiel #3
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)
def test_compute_budget_factor_already_overran_budget():
    phi = sentence.Atom("ϕ")
    psi = sentence.Atom("Ψ")

    # there was one previous observation, which was "phi OR psi"
    past_observations = [sentence.Disjunction(phi, psi)]

    # on our one previous update, our credences were as follows
    past_credences = credence.History([{
        phi: .6,
        psi: .7,
    }])

    # on the previous update we purchased one token of psi
    past_trading_formulas = [{
        psi: formula.Constant(10),
    }]

    # we observe psi in our most recent update
    latest_observation = sentence.Disjunction(phi, psi)

    # our trading formula says to always purchase 10 tokens of phi
    latest_trading_formulas = {
        phi: formula.Constant(10),
    }

    # our budget is $2, which means we can lose up to $2, or, in other words,
    # the value of our holdings is allowed to go as low as -$2
    budget = 2

    # compute the budget factor
    budget_factor = inductor.compute_budget_factor(budget, past_observations,
                                                   latest_observation,
                                                   past_trading_formulas,
                                                   latest_trading_formulas,
                                                   past_credences)

    # on our previous update we purchased one token of PSI for $7 without being
    # able to rule out the possibility that PHI could turn out to be false, in
    # which case we would have lost $7, which is more than our budget of $2, so
    # our budget factor should be the constant 0 which eliminates all further
    # trading
    assert_is_instance(budget_factor, formula.Constant)
    assert_equal(budget_factor.k, 0)
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 test_compute_budget_factor_simple():
    phi = sentence.Atom("ϕ")

    # we are on the first update; our history is all empty
    past_credences = credence.History([])  # no past credences
    past_trading_formulas = []  # no past trading formulas
    past_observations = []  # no past observations

    # we observed phi in our most recent update
    latest_observation = phi

    # our trading formula says to always purchase 10 tokens of phi
    latest_trading_formulas = {
        phi: formula.Constant(10),
    }

    # our budget is $2, which means we can lose up to $2, or, in other words,
    # the value of our holdings is allowed to go as low as -$2
    budget = 2

    # compute the budget factor
    budget_factor = inductor.compute_budget_factor(budget, past_observations,
                                                   latest_observation,
                                                   past_trading_formulas,
                                                   latest_trading_formulas,
                                                   past_credences)

    assert_is_instance(budget_factor, formula.SafeReciprocal)

    # our world consists of only one base fact (phi), and we observed phi, so
    # the world where phi=true is only one world propositionally consistent with
    # our observations, and in this world we purchase 10 tokens of phi, which
    # could cost anywhere from $0 to $10 depending on the as-yet-unknown
    # credence for phi, and will have a value of exactly $10 in this world. In
    # no case will the value of our holdings drop below -$2, so we expect a
    # budget factor that evaluates to 1 for all credences in [0, 1].
    assert_equal(
        budget_factor.evaluate(past_credences.with_next_update({phi: 0.})), 1.)
    assert_equal(
        budget_factor.evaluate(past_credences.with_next_update({phi: .2})), 1.)
    assert_equal(
        budget_factor.evaluate(past_credences.with_next_update({phi: .6})), 1.)
    assert_equal(
        budget_factor.evaluate(past_credences.with_next_update({phi: 1.})), 1.)
def test_combine_trading_algorithms_simple():
    phi = sentence.Atom("ϕ")
    psi = sentence.Atom("Ψ")

    # in this test we are on the first update, so there is one trading
    # algorithm, one observation, and no historical credences
    trading_formula = {phi: formula.Constant(1)}
    trading_histories = [[trading_formula]]
    observation_history = [psi]
    credence_history = credence.History([])

    # create the compound trader, which just has one internal trader
    compound_trader = inductor.combine_trading_algorithms(
        trading_histories,
        observation_history,
        credence_history,
    )

    assert_equal(len(compound_trader), 1)
    assert_is_instance(compound_trader[phi], formula.Sum)
    assert_equal(len(compound_trader[phi].terms), 3)
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()
    }
Beispiel #10
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
 def trading_algorithm(sentence, start=1, step=1):
     for quantity in enumerator.integers(start=start, step=step):
         yield {sentence: formula.Constant(quantity)}
def test_compute_budget_factor_two_base_facts():
    phi = sentence.Atom("ϕ")
    psi = sentence.Atom("Ψ")

    # we are on the first update; our history is all empty
    past_credences = credence.History([])  # no past credences
    past_trading_formulas = []  # no past trading formulas
    past_observations = []  # no past observations

    # we observe psi in our most recent update
    latest_observation = sentence.Disjunction(phi, psi)

    # our trading formula says to always purchase 10 tokens of phi
    latest_trading_formulas = {
        phi: formula.Constant(10),
    }

    # our budget is $2, which means we can lose up to $2, or, in other words,
    # the value of our holdings is allowed to go as low as -$2
    budget = 2

    # compute the budget factor
    budget_factor = inductor.compute_budget_factor(budget, past_observations,
                                                   latest_observation,
                                                   past_trading_formulas,
                                                   latest_trading_formulas,
                                                   past_credences)

    assert_is_instance(budget_factor, formula.SafeReciprocal)

    print()
    print(budget_factor.tree())

    # Our world consists of two base facts, phi and psi, and we observed "phi OR psi", so
    # there are three worlds consistent with this observation:
    #   phi=True   psi=True
    #   phi=True   psi=False
    #   phi=False  psi=True
    #
    # Our trading formula says to purchase 10 tokens of phi no matter what. This
    # could cost us between $0 and $10 depending on the credence for phi. The
    # value of these 10 tokens could turn out to be either $0 if phi=False or $10
    # if phi=True:
    #   phi=True   psi=True    -> value of 10 tokens of phi = $10, so net worth between $0 and $10
    #   phi=True   psi=False   -> value of 10 tokens of phi = $10, so net worth between $0 and $10
    #   phi=False  psi=True    -> value of 10 tokens of phi = $0, so net worth between -$10 and $0
    #
    # In the third world, our net worth could drop below our budget for some
    # possible credences, so:

    # if the credence for phi were 1 then in the third world we would end up with a
    # net worth of -$10, so we should multiply our trading volume by 0.2
    assert_almost_equal(
        budget_factor.evaluate(past_credences.with_next_update({phi: 1.})), .2)

    # if the credence for phi were 0.4 then in the third world we would end up with a
    # net worth of -$4, so we should multiply our trading volume by 0.5
    assert_almost_equal(
        budget_factor.evaluate(past_credences.with_next_update({phi: .4})), .5)

    # if the credence for phi were 0.2 then in the third world we would end up with a
    # net worth of -$2, which is right on budget, so our scaling factor should be 1
    assert_almost_equal(
        budget_factor.evaluate(past_credences.with_next_update({phi: .2})), 1.)

    # if the credence for phi were 0 then in the third world we would end up with a
    # net worth of $0, which is above budget, so our scaling factor should be 1
    assert_almost_equal(
        budget_factor.evaluate(past_credences.with_next_update({phi: 0.})), 1.)