예제 #1
0
def get_simulation_results(c):
    df = run_simulation(c)
    df_final = df[df.substep.eq(2)]
    random_func = new_random_number_func(None)

    last_network = df_final.iloc[-1, 0]
    candidates = len(
        get_proposals(last_network, status=ProposalStatus.CANDIDATE))
    actives = len(get_proposals(last_network, status=ProposalStatus.ACTIVE))
    completed = len(
        get_proposals(last_network, status=ProposalStatus.COMPLETED))
    failed = len(get_proposals(last_network, status=ProposalStatus.FAILED))
    participants = len(get_participants(last_network))

    score = CommonsScore(params=c, df_final=df_final)

    result = {
        "timestep": list(df_final["timestep"]),
        "funding_pool": list(df_final["funding_pool"]),
        "token_price": list(df_final["token_price"]),
        "sentiment": list(df_final["sentiment"]),
        "score": score.eval(),
        "participants": participants,
        "proposals": {
            "candidates": candidates,
            "actives": actives,
            "completed": completed,
            "failed": failed,
            "total": candidates + actives + completed + failed
        }
    }
    return result, df_final
예제 #2
0
    def su_update_participants_token_batch_age(params, step, sL, s, _input, **kwargs):
        network = s["network"]
        participants = get_participants(network)
        for i, participant in participants:
            participant.update_token_batch_age()

        return "network", network
예제 #3
0
    def test_p_participant_decides_if_he_wants_to_exit(self):
        participants = get_participants(self.network)
        for i, participant in participants:
            participant.sentiment = 0.1

        self.params["probability_func"] = always
        ans = ParticipantExits.p_participant_decides_if_he_wants_to_exit(
            self.params, 0, 0, self.default_state)

        self.assertEqual(len(ans["defectors"]), 2)
예제 #4
0
    def p_decide_to_buy_tokens_bulk(params, step, sL, s, **kwargs):
        network = s["network"]
        commons = s["commons"]
        participants = get_participants(network)
        ans = {}
        total_dai = 0
        for i, participant in participants:
            # If a participant decides to buy, it will be specified in units of DAI.
            # If a participant decides to sell, it will be specified in units of tokens.
            x = participant.buy()
            if x > 0:
                total_dai += x
                ans[i] = x

        # Now that we have the sum of DAI, ask the Commons object how many
        # tokens this would be minted as a result. This will be inaccurate due
        # to slippage, and we need the result of this policy to be final to
        # avoid chaining 2 state update functions, so we run the deposit on a
        # throwaway copy of Commons
        if total_dai == 0:
            if params.get("debug"):
                print(
                    "ParticipantBuysTokens: No Participants bought tokens in timestep {}"
                    .format(step))
            return {
                "participant_decisions": ans,
                "total_dai": 0,
                "tokens": 0,
                "token_price": 0,
                "final_token_distribution": {}
            }

        else:
            commons2 = copy.copy(commons)
            tokens, token_price = commons2.deposit(total_dai)

            final_token_distribution = {}
            for i in ans:
                final_token_distribution[i] = ans[i] / total_dai

            if params.get("debug"):
                print(
                    "ParticipantBuysTokens: These Participants have decided to buy tokens with this amount of DAI: {}"
                    .format(ans))
                print(
                    "ParticipantBuysTokens: A total of {} DAI will be deposited. {} tokens should be minted as a result at a price of {} DAI/token"
                    .format(total_dai, tokens, token_price))

            return {
                "participant_decisions": ans,
                "total_dai": total_dai,
                "tokens": tokens,
                "token_price": token_price,
                "final_token_distribution": final_token_distribution
            }
예제 #5
0
    def test_p_participant_decides_if_he_wants_to_exit(self):
        participants = get_participants(self.network)
        for i, participant in participants:
            participant.sentiment = 0.1

        with patch("entities.probability") as p:
            p.return_value = True
            ans = ParticipantExits.p_participant_decides_if_he_wants_to_exit(
                self.params, 0, 0, self.default_state)

            self.assertEqual(len(ans["defectors"]), 4)
예제 #6
0
 def test_su_update_participants_token_batch_age(self):
     """
     Test that after running the state update function the participants'
     token batch age in days are incremented by one
     """
     _input = {}
     _, network = GenerateNewParticipant.su_update_participants_token_batch_age(
         self.params, 0, 0, {"network": self.network.copy()}, _input)
     participants = get_participants(network)
     for i, participant in participants:
         self.assertEqual(participant.holdings.age_days, 1)
예제 #7
0
    def su_update_sentiment_decay(params, step, sL, s, _input, **kwargs):
        network = s["network"]

        participants = get_participants(network)
        for participant_idx, participant in participants:
            sentiment_old = network.nodes[participant_idx]["item"].sentiment
            sentiment_new = sentiment_old - config.sentiment_decay
            sentiment_new = 0 if sentiment_new < 0 else sentiment_new
            network.nodes[participant_idx]["item"].sentiment = sentiment_new

        return "network", network
예제 #8
0
    def p_decide_to_sell_tokens_bulk(params, step, sL, s, **kwargs):
        network = s["network"]
        commons = s["commons"]
        participants = get_participants(network)
        ans = {}
        total_tokens = 0
        for i, participant in participants:
            # If a participant decides to buy, it will be specified in units of DAI.
            # If a participant decides to sell, it will be specified in units of tokens.
            x = participant.sell()
            if x > 0:
                total_tokens += x
                ans[i] = x

        # Now that we have the sum of tokens, ask the Commons object how many
        # DAI would be redeemed as a result. This will be inaccurate due
        # to slippage, and we need the result of this policy to be final to
        # avoid chaining 2 state update functions, so we run the operation on a
        # throwaway copy of Commons
        if total_tokens == 0:
            if params.get("debug"):
                print(
                    "ParticipantSellsTokens: No Participants sold tokens in timestep {}"
                    .format(step))
            return {
                "participant_decisions": ans,
                "total_tokens": 0,
                "dai_returned": 0,
                "realized_price": 0
            }
        else:
            commons2 = copy.copy(commons)
            dai_returned, realized_price = commons2.burn(total_tokens)

            final_dai_distribution = {}
            for i, participant in participants:
                final_dai_distribution[i] = ans[i] / total_tokens

            if params.get("debug"):
                print(
                    "ParticipantSellsTokens: These Participants have decided to sell this many  tokens: {}"
                    .format(ans))
                print(
                    "ParticipantSellsTokens: A total of {} tokens will be burned. {} DAI should be returned as a result, at a price of {} DAI/token"
                    .format(total_tokens, dai_returned, realized_price))
            return {
                "participant_decisions": ans,
                "total_tokens": total_tokens,
                "dai_returned": dai_returned,
                "realized_price": realized_price
            }
    def test_bootstrap_network(self):
        """
        Tests that the network was created and that the subcomponents work too.
        """
        token_batches = [TokenBatch(1000, VestingOptions(10, 30))
                         for _ in range(4)]
        network = bootstrap_network(token_batches, 1, 3000, 4e6, 0.2)

        edges = list(network.edges(data="type"))
        _, _, edge_types = list(zip(*edges))

        self.assertEqual(edge_types.count('support'), 4)
        self.assertEqual(len(get_participants(network)), 4)
        self.assertEqual(len(get_proposals(network)), 1)
예제 #10
0
    def p_randomly(params, step, sL, s):
        """
        Randomly picks a Participant from the network and asks him if he wants
        to create a Proposal.
        """
        funding_pool = s["funding_pool"]
        network = s["network"]

        participants = get_participants(network)
        i, participant = random.sample(participants, 1)[0]

        wants_to_create_proposal = participant.create_proposal(calc_total_funds_requested(
            network), calc_median_affinity(network), funding_pool)

        return {"new_proposal": wants_to_create_proposal, "proposed_by_participant": i}
예제 #11
0
    def p_participant_decides_if_he_wants_to_exit(params, step, sL, s, **kwargs):
        network = s["network"]
        participants = get_participants(network)
        defectors = {}
        for i, participant in participants:
            e = participant.wants_to_exit()
            if e:
                defectors[i] = {
                    "sentiment": participant.sentiment,
                    "holdings": participant.holdings.total,
                }

        if params.get("debug"):
            print("ParticipantExits: Participants {} (2nd number is their sentiment) want to exit".format(
                defectors))
        return {"defectors": defectors}
예제 #12
0
    def p_participant_votes_on_proposal_according_to_affinity(
            params, step, sL, s, **kwargs):
        """
        This policy collects data from the DiGraph to tell the Participant class
        which candidate proposals it supports, and
        Participant.vote_on_candidate_proposals() will decide which proposals it
        will take action on.

        Then, Participant.stake_across_all_supported_proposals() will tell us
        how much it will stake on each of them.
        """
        network = s["network"]
        participants = get_participants(network)

        participants_stakes = {}
        for participant_idx, participant in participants:
            proposal_idx_affinity = {}  # {4: 0.9, 5: 0.9}
            candidate_proposals = get_proposals_by_participant_and_status(
                network,
                participant_idx=participant_idx,
                status_filter=[ProposalStatus.CANDIDATE])
            for proposal_idx, proposal in candidate_proposals.items():
                proposal_idx_affinity[proposal_idx] = proposal[
                    "support"].affinity
            proposals_that_participant_cares_enough_to_vote_on = participant.vote_on_candidate_proposals(
                proposal_idx_affinity)

            stake_across_all_supported_proposals_input = []
            for proposal_idx, affinity in proposals_that_participant_cares_enough_to_vote_on.items(
            ):
                stake_across_all_supported_proposals_input.append(
                    (affinity, proposal_idx))
            stakes = participant.stake_across_all_supported_proposals(
                stake_across_all_supported_proposals_input)

            participants_stakes[participant_idx] = stakes

            if params.get("debug"):
                if proposals_that_participant_cares_enough_to_vote_on:
                    print(
                        "ParticipantVoting: Participant {} was given Proposals with corresponding affinities {} and he decided to vote on {}, distributing his tokens thusly {}"
                        .format(
                            participant_idx, proposal_idx_affinity,
                            proposals_that_participant_cares_enough_to_vote_on,
                            stakes))

        return {"participants_stake_on_proposals": participants_stakes}
    def test_calc_avg_sentiment(self):
        """
        Ensure that the average sentiment was calculated correctly
        """
        participants = get_participants(self.network)

        for _, p in participants:
            p.sentiment = 0.5
        self.assertEqual(0.5, calc_avg_sentiment(self.network))

        for _, p in participants:
            p.sentiment = 1
        self.assertEqual(1, calc_avg_sentiment(self.network))

        for _, p in participants:
            p.sentiment = 1
        self.network.nodes[8]["item"].sentiment = 0.5
        self.assertEqual(0.9, calc_avg_sentiment(self.network))
예제 #14
0
    def p_randomly(params, step, sL, s, **kwargs):
        """
        Randomly picks a Participant from the network and asks him if he wants
        to create a Proposal.
        """
        funding_pool = s["funding_pool"]
        network = s["network"]
        choice_func = params["choice_func"]

        participants = get_participants(network)
        participants_dict = dict(participants)
        i = choice_func(list(participants_dict))
        participant = participants_dict[i]

        wants_to_create_proposal = participant.create_proposal(calc_total_funds_requested(
            network), calc_median_affinity(network), funding_pool)

        return {"new_proposal": wants_to_create_proposal, "proposed_by_participant": i}
예제 #15
0
    def test_su_update_sentiment_decay(self):
        """
        Test that the participants' sentiment is decreased by the value defined
        on config.sentiment_decay after executing the state update function
        su_update_sentiment_decay.
        """
        participants_old_sentiment = []
        participants = get_participants(self.network)

        for _, participant in participants:
            participants_old_sentiment.append(participant.sentiment)

        network = ParticipantSentiment.su_update_sentiment_decay(
            self.params, 0, 0, {"network": self.network.copy()}, {})

        for i, participant in participants:
            old_sentiment = participants_old_sentiment[i]
            sentiment_decay = old_sentiment - participant.sentiment
            self.assertAlmostEqual(sentiment_decay, config.sentiment_decay)
예제 #16
0
    def test_participant_token_batch_age_is_updated_every_timestep(self):
        """
        Test that the age of the Participants' token batch is updated every
        timestep. The test checks if the older token batch age has the same
        age
        of the simulation (timestep). It considers that at least one
        participant stays in the commons from the beginning to the end of the
        simulation.
        """
        for index, row in self.df_final.iterrows():
            timestep = row["timestep"]
            network = row["network"]
            participants = get_participants(network)

            participants_token_batch_ages = []
            for i, participant in participants:
                participants_token_batch_ages.append(
                    participant.holdings.age_days)
            # Check if the older token batch has the same age of the simulation
            self.assertEqual(max(participants_token_batch_ages), timestep)
예제 #17
0
    def test_p_participant_votes_on_proposal_according_to_affinity_vesting_nonvesting(
            self):
        """
        Ensure that when a Participant with vesting and nonvesting tokens votes
        on 2 Proposals of equal affinity, all of his tokens will be split 50-50
        between them.
        """
        participants = get_participants(self.network)
        for _, participant in participants:
            participant.holdings = TokenBatch(1000, 1000)

        with patch("entities.probability") as p:
            p.return_value = True
            ans = ParticipantVoting.p_participant_votes_on_proposal_according_to_affinity(
                self.params, 0, 0, {
                    "network": copy.copy(self.network),
                    "funding_pool": 1000,
                    "token_supply": 1000
                })

            reference = {
                'participants_stake_on_proposals': {
                    0: {
                        4: 1000.0,
                        5: 1000.0
                    },
                    1: {
                        4: 1000.0,
                        5: 1000.0
                    },
                    2: {
                        4: 1000.0,
                        5: 1000.0
                    },
                    3: {
                        4: 1000.0,
                        5: 1000.0
                    }
                }
            }
            self.assertEqual(ans, reference)
예제 #18
0
    def eval(self) -> float:
        '''
            Calculates the final score using all the defined metrics methods in this class
        '''
        last_network = self.df_final.iloc[-1, 0]
        p_candidates = get_proposals(last_network,
                                     status=ProposalStatus.CANDIDATE)
        candidates = len(p_candidates)
        p_actives = get_proposals(last_network, status=ProposalStatus.ACTIVE)
        actives = len(p_actives)
        p_completed = get_proposals(last_network,
                                    status=ProposalStatus.COMPLETED)
        completed = len(p_completed)
        p_failed = get_proposals(last_network, status=ProposalStatus.FAILED)
        failed = len(p_failed)
        participants = len(get_participants(last_network))

        funds_candidates = sum([p.funds_requested for _, p in p_candidates])
        funds_actives = sum([p.funds_requested for _, p in p_actives])
        funds_completed = sum([p.funds_requested for _, p in p_completed])
        funds_failed = sum([p.funds_requested for _, p in p_failed])

        self.metrics = Metrics(participants=participants,
                               candidates=candidates,
                               funds_candidates=funds_candidates,
                               actives=actives,
                               funds_actives=funds_actives,
                               completed=completed,
                               funds_completed=funds_completed,
                               failed=failed,
                               funds_failed=funds_failed)
        methods = [
            attr for attr in dir(self)
            if callable(getattr(self, attr)) and attr.startswith('calc_')
        ]
        return min(
            round(
                sum([getattr(self, method)()
                     for method in methods]) * self.sigma), 1000)
 def test_get_participants(self):
     res = get_participants(self.network)
     self.assertEqual(len(res), 5)