Skip to content

Commit

Permalink
- split +ve and -ve contributions
Browse files Browse the repository at this point in the history
- update code to ensure -ve voting is taken into account
  • Loading branch information
thelostone-mc committed Mar 21, 2020
1 parent 662b7f9 commit fa94d09
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 51 deletions.
146 changes: 97 additions & 49 deletions app/grants/clr.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,12 @@ def calculate_new_clr(aggregated_contributions, pair_totals, threshold=0.0, tota
'''
def calculate_new_clr_final(totals_pos, totals_neg, total_pot=0.0):
# calculate final totals
totals = [{'id': x['id'], 'clr_amount': (math.sqrt(x['clr_amount']) - math.sqrt(y['clr_amount']))**2} for x in totals_pos for y in totals_neg if x['id'] == y['id']]

if len(totals_neg) == 0:
totals = totals_pos
else:
totals = [{'id': x['id'], 'clr_amount': (math.sqrt(x['clr_amount']) - math.sqrt(y['clr_amount']))**2} for x in totals_pos for y in totals_neg if x['id'] == y['id']]

for x in totals:
if x['clr_amount'] < 0:
x['clr_amount'] = 0
Expand All @@ -171,7 +176,6 @@ def calculate_new_clr_final(totals_pos, totals_neg, total_pot=0.0):
return bigtot, totals



'''
Clubbed function that intakes grant data, calculates necessary intermediate calculations, and spits out clr calculations. This function is re-used for positive and negative contributions
Expand Down Expand Up @@ -224,20 +228,18 @@ def grants_clr_calculate_pos_neg(pos_totals, neg_totals, total_pot=0.0):
return final_bigtot, final_totals


def calculate_clr_for_donation(grant, amount, grant_contributions, total_pot, threshold):

### ADD NEW GRANT CONTRIBUTIONS MODEL IS UPDATED AND PULL SEPARATE POSITIVE AND NEGATIVE CONTRIBUTIONS, INPUT VARIABLES IN THE METHOD grants_clr_calculate LINES 292 AND ON WILL NEED TO BE CHANGED
def calculate_clr_for_donation(grant, amount, positive_grant_contributions, negative_grant_contributions, total_pot, threshold):

_grant_contributions = copy.deepcopy(grant_contributions)
_positive_grant_contributions = copy.deepcopy(positive_grant_contributions)
# find grant in contributions list and add donation
if amount != 0:
for grant_contribution in _grant_contributions:
for grant_contribution in _positive_grant_contributions:
if grant_contribution['id'] == grant.id:
# add this donation with a new profile (id 99999999999) to get impact
grant_contribution['contributions'].append({'999999999999': amount})

pos_totals = grants_clr_calculate(_grant_contributions, total_pot=total_pot, threshold=threshold, positive=True)
neg_totals = grants_clr_calculate(_grant_contributions, total_pot=total_pot, threshold=threshold, positive=False)
pos_totals = grants_clr_calculate(_positive_grant_contributions, total_pot=total_pot, threshold=threshold, positive=True)
neg_totals = grants_clr_calculate(negative_grant_contributions, total_pot=total_pot, threshold=threshold, positive=False)
_, grants_clr = grants_clr_calculate_pos_neg(pos_totals, neg_totals, total_pot=total_pot)

# find grant we added the contribution to and get the new clr amount
Expand All @@ -258,7 +260,8 @@ def calculate_clr_for_donation(grant, amount, grant_contributions, total_pot, th
Returns:
grants: list of grants based on clr_type
contrib_data: [{'id': <int>, 'contributions': <Object>}]
positive_contrib_data: [{'id': <int>, 'contributions': <Object>}]
negative_contrib_data: [{'id': <int>, 'contributions': <Object>}]
total_pot: float
threshold : int
'''
Expand All @@ -285,44 +288,70 @@ def populate_data_for_clr(clr_type=None, network='mainnet'):
return None, None, None, None

# set up data to load contributions for each grant
contrib_data = []
positive_contrib_data = []
negative_contrib_data = []

for grant in grants:
# go through all the individual contributions for each grant
g_contributions = copy.deepcopy(contributions).filter(subscription__grant_id=grant.id)

# put in correct format
phantom_funding_profiles = PhantomFunding.objects.filter(grant_id=grant.id, created_on__gte=CLR_START_DATE, created_on__lte=from_date)
all_contributing_profile_ids = list(set([c.subscription.contributor_profile.id for c in g_contributions] + [p.profile_id for p in phantom_funding_profiles]))
all_summed_contributions = []
grant_id = grant.defer_clr_to.pk if grant.defer_clr_to else grant.id

for profile_id in all_contributing_profile_ids:
# get sum of contributions per grant for each profile
profile_g_contributions = g_contributions.filter(subscription__contributor_profile_id=profile_id)
sum_of_each_profiles_contributions = float(sum([c.subscription.get_converted_monthly_amount() for c in profile_g_contributions]))
# Get the +ve and -ve contributions
positive_contributions = copy.deepcopy(contributions).filter(subscription__grant_id=grant.id, subscription__match_direction='+')
negative_contributions = copy.deepcopy(contributions).filter(subscription__grant_id=grant.id, subscription__match_direction='-')

phantom_funding = PhantomFunding.objects.filter(created_on__gte=CLR_START_DATE, grant_id=grant.id, profile_id=profile_id, created_on__lte=from_date)
if phantom_funding.exists():
sum_of_each_profiles_contributions = sum_of_each_profiles_contributions + phantom_funding.first().value
# Generate list of profiles who've made +ve and -ve contributions to the grant
phantom_funding_profiles = PhantomFunding.objects.filter(grant_id=grant.id, created_on__gte=CLR_START_DATE, created_on__lte=from_date)
positive_contributing_profile_ids = list(set([c.subscription.contributor_profile.id for c in positive_contributions] + [p.profile_id for p in phantom_funding_profiles]))
negative_contributing_profile_ids = list(set([c.subscription.contributor_profile.id for c in negative_contributions]))

# print(f'positive contrib profiles : {positive_contributing_profile_ids}')
# print(f'negative contrib profiles : {negative_contributing_profile_ids}')
# print(f'positive contributions : {positive_contributions}')
# print(f'negative contributions : {negative_contributions}')

positive_summed_contributions = []
negative_summed_contributions = []

# POSITIVE CONTRIBUTIONS
if len(positive_contributing_profile_ids) > 0:
for profile_id in positive_contributing_profile_ids:
# get sum of contributions per grant for each profile
profile_positive_contributions = positive_contributions.filter(subscription__contributor_profile_id=profile_id)
sum_of_each_profiles_contributions = float(sum([c.subscription.get_converted_monthly_amount() for c in profile_positive_contributions]))

phantom_funding = PhantomFunding.objects.filter(created_on__gte=CLR_START_DATE, grant_id=grant.id, profile_id=profile_id, created_on__lte=from_date)
if phantom_funding.exists():
sum_of_each_profiles_contributions = sum_of_each_profiles_contributions + phantom_funding.first().value

positive_summed_contributions.append({str(profile_id): sum_of_each_profiles_contributions})

# for each grant, list the contributions in key value pairs like {'profile id': sum of contributions}
positive_contrib_data.append({
'id': grant_id,
'contributions': positive_summed_contributions
})

all_summed_contributions.append({str(profile_id): sum_of_each_profiles_contributions})
# NEGATIVE CONTRIBUTIONS
if len(negative_contributing_profile_ids) > 0:
for profile_id in negative_contributing_profile_ids:
profile_negative_contributions = negative_contributions.filter(subscription__contributor_profile_id=profile_id)
sum_of_each_negative_contributions = float(sum([c.subscription.get_converted_monthly_amount() for c in profile_negative_contributions]))
negative_summed_contributions.append({str(profile_id): sum_of_each_negative_contributions})

# for each grant, list the contributions in key value pairs like {'profile id': sum of contributions}
grant_id = grant.defer_clr_to.pk if grant.defer_clr_to else grant.id
contrib_data.append({
'id': grant_id,
'contributions': all_summed_contributions
})
negative_contrib_data.append({
'id': grant_id,
'contributions': negative_summed_contributions
})

#print(f'\n contributions data: {contrib_data} \n')
return (grants, contrib_data, total_pot, threshold)
# print(f'\n positive contributions data: {positive_contrib_data} \n')
# print(f'\n negative contributions data: {negative_contrib_data} \n')
return (grants, positive_contrib_data, negative_contrib_data, total_pot, threshold)


def predict_clr(save_to_db=False, from_date=None, clr_type=None, network='mainnet'):
# setup
clr_calc_start_time = timezone.now()
debug_output = []
grants, contrib_data, total_pot, threshold = populate_data_for_clr(clr_type, network)
grants, positive_contrib_data, negative_contrib_data, total_pot, threshold = populate_data_for_clr(clr_type, network)

# calculate clr given additional donations
for grant in grants:
Expand All @@ -332,7 +361,14 @@ def predict_clr(save_to_db=False, from_date=None, clr_type=None, network='mainne

for amount in potential_donations:
# calculate clr with each additional donation and save to grants model
predicted_clr, grants_clr = calculate_clr_for_donation(grant, amount, contrib_data, total_pot, threshold)
predicted_clr, grants_clr = calculate_clr_for_donation(
grant,
amount,
positive_contrib_data,
negative_contrib_data,
total_pot,
threshold
)
potential_clr.append(predicted_clr)

if save_to_db:
Expand Down Expand Up @@ -372,29 +408,40 @@ def predict_clr(save_to_db=False, from_date=None, clr_type=None, network='mainne
grant: <Grant> - grant to be funded
contributor: <Profile> - contributor making a contribution
amount: <float> - amount with which is grant is to be funded
grant_contributions: [Object]
match_direction: <char> + , -
positive_grant_contributions: [Object]
negative_grant_contributions: [Object]
total_pot: <float>
threshold: <float>
Returns:
clr_amount
'''
def calculate_clr_for_donation_live(grant, contributor, amount, grant_contributions, total_pot, threshold):
def calculate_clr_for_donation_live(grant, contributor, amount, match_direction, positive_grant_contributions, negative_grant_contributions, total_pot, threshold):

if amount == 0:
return 0

_grant_contributions = copy.deepcopy(grant_contributions)
_positive_grant_contributions = copy.deepcopy(positive_grant_contributions)
_negative_grant_contributions = copy.deepcopy(negative_grant_contributions)

profile_id = str(contributor.pk)

for grant_contribution in _grant_contributions:
if grant_contribution['id'] == grant.id:
grant_contribution['contributions'].append({
profile_id: amount
})
if match_direction == '+':
for grant_contribution in _positive_grant_contributions:
if grant_contribution['id'] == grant.id:
grant_contribution['contributions'].append({
profile_id: amount
})
else:
for grant_contribution in _negative_grant_contributions:
if grant_contribution['id'] == grant.id:
grant_contribution['contributions'].append({
profile_id: amount
})

pos_totals = grants_clr_calculate(_grant_contributions, total_pot=total_pot, threshold=threshold, positive=True)
neg_totals = grants_clr_calculate(_grant_contributions, total_pot=total_pot, threshold=threshold, positive=False)
pos_totals = grants_clr_calculate(_positive_grant_contributions, total_pot=total_pot, threshold=threshold, positive=True)
neg_totals = grants_clr_calculate(_negative_grant_contributions, total_pot=total_pot, threshold=threshold, positive=False)
_, grants_clr = grants_clr_calculate_pos_neg(pos_totals, neg_totals, total_pot=total_pot)

# find grant we added the contribution to and get the new clr amount
Expand All @@ -414,11 +461,12 @@ def calculate_clr_for_donation_live(grant, contributor, amount, grant_contributi
grant: <Grant>
contributor: <Profile>
amount: <float>
match_direction: <char> + , -
Returns:
predicted_clr_match
'''
def predict_clr_live(grant, contributor, amount):
def predict_clr_live(grant, contributor, amount, match_direction='+'):

if not grant or not contributor:
print('error: predict_clr_live - missing parameters')
Expand All @@ -429,10 +477,10 @@ def predict_clr_live(grant, contributor, amount):

clr_type = grant.grant_type
network = grant.network
_, contrib_data, total_pot, threshold = populate_data_for_clr(clr_type, network)
_, positive_contrib_data, negative_contrib_data , total_pot, threshold = populate_data_for_clr(clr_type, network)

predicted_clr_match = calculate_clr_for_donation_live(
grant, contributor, amount, contrib_data, total_pot, threshold
grant, contributor, amount, match_direction, positive_contrib_data, negative_contrib_data, total_pot, threshold
)

return predicted_clr_match
13 changes: 11 additions & 2 deletions app/grants/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,8 @@ def grant_categories(request):
def predict_clr_v1(request, grant_id):
'''
{
amount: <float>
amount: <float>,
match_direction: <char> +, -
}
'''
response = {
Expand Down Expand Up @@ -1092,7 +1093,15 @@ def predict_clr_v1(request, grant_id):
response['message'] = 'error: missing parameter amount'
return JsonResponse(response)

predicted_clr_match = predict_clr_live(grant, profile, float(amount))

match_direction = request.GET.get('match_direction', '+')

predicted_clr_match = predict_clr_live(
grant,
profile,
float(amount),
match_direction
)

response = {
'status': 200,
Expand Down

0 comments on commit fa94d09

Please sign in to comment.