def calculate_rating_delta(self, tournament_result, rating_date, tournament, player): """ Determine player delta and tournament properties """ tournament_coefficient = self.tournament_coefficient(tournament) tournament_coefficient = get_tournament_coefficient(self.IS_EMA, tournament.id, player, tournament_coefficient) base_rank = self.calculate_base_rank(tournament_result, tournament) # for ema we had to round base rank if self.IS_EMA: base_rank = round(base_rank) tournament_age = self.tournament_age(tournament.end_date, rating_date) delta = tournament_coefficient * base_rank delta = self._calculate_percentage(delta, tournament_age) return delta, base_rank
def calculate_players_rating_rank(self, rating, rating_date, is_last): results = [] two_years_ago = self.get_date(rating_date) # it is important to save rating updates time rating.updated_on = timezone.now() rating.save() base_query = self.get_base_query(rating, two_years_ago, rating_date) tournament_ids = base_query.values_list('tournament_id', flat=True).distinct() coefficient_temp = TournamentCoefficients.objects.filter( tournament_id__in=tournament_ids, rating=rating, date=rating_date) coefficients_cache = {} coefficients = [] for coefficient in coefficient_temp: coefficients_cache[coefficient.tournament_id] = coefficient c = self._calculate_percentage(float(coefficient.coefficient), coefficient.age) coefficients.append(c) # TODO: Remove these hardcoded values when tournaments with stages will be implemented if not rating.is_online() and AGARI_TOURNAMENT_ID in tournament_ids: tournament = Tournament.objects.get(id=AGARI_TOURNAMENT_ID) if tournament.end_date >= rating_date: age = self.tournament_age(tournament.end_date, rating_date) coefficients.append( self._calculate_percentage(AGARI_SECOND_STAGE_COEFFICIENT, age)) coefficients.append( self._calculate_percentage(AGARI_FIRST_STAGE_COEFFICIENT, age)) coefficients = sorted(coefficients, reverse=True) max_coefficient = sum(coefficients[:self.SECOND_PART_MIN_TOURNAMENTS]) if len(coefficients) < self.SECOND_PART_MIN_TOURNAMENTS: max_coefficient += self.SECOND_PART_MIN_TOURNAMENTS - len( coefficients) for player in self.players: first_part_numerator_calculation = [] first_part_denominator_calculation = [] second_part_numerator_calculation = [] # we need to reduce SQL queries with this filter deltas = [] for x in base_query: if x.player_id == player.id: deltas.append(x) total_tournaments = len(deltas) if total_tournaments < self.MIN_TOURNAMENTS_NUMBER: continue if total_tournaments <= self.FIRST_PART_MIN_TOURNAMENTS: tournaments_results = deltas else: limit = self._determine_tournaments_number(total_tournaments) tournaments_results = sorted(deltas, key=lambda x: x.base_rank, reverse=True)[:limit] if is_last: RatingDelta.objects.filter( id__in=[x.id for x in tournaments_results]).update( is_active=True) first_part_numerator = 0 first_part_denominator = 0 for result in tournaments_results: coefficient_obj = coefficients_cache[result.tournament_id] coefficient = get_tournament_coefficient( coefficient_obj.tournament_id, player, coefficient_obj.coefficient) first_part_numerator += float(result.delta) first_part_denominator += float( self._calculate_percentage(float(coefficient), coefficient_obj.age)) if is_last: first_part_numerator_calculation.append( '{} * {} * {}'.format( floatformat(result.base_rank, -2), floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2))) first_part_denominator_calculation.append('{} * {}'.format( floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2))) if len(tournaments_results) < self.FIRST_PART_MIN_TOURNAMENTS: fill_missed_data = self.FIRST_PART_MIN_TOURNAMENTS - len( tournaments_results) first_part_denominator += fill_missed_data if is_last: for x in range(0, fill_missed_data): first_part_numerator_calculation.append('0') first_part_denominator_calculation.append('1') first_part = first_part_numerator / first_part_denominator second_part_numerator = 0 second_part_denominator = max_coefficient best_results = sorted( deltas, key=lambda x: x.delta, reverse=True)[:self.SECOND_PART_MIN_TOURNAMENTS] for result in best_results: coefficient_obj = coefficients_cache[result.tournament_id] coefficient = get_tournament_coefficient( coefficient_obj.tournament_id, player, coefficient_obj.coefficient) second_part_numerator += float(result.delta) if is_last: second_part_numerator_calculation.append( '{} * {} * {}'.format( floatformat(result.base_rank, -2), floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2))) second_part = second_part_numerator / second_part_denominator score = self._calculate_percentage( first_part, self.FIRST_PART_WEIGHT) + self._calculate_percentage( second_part, self.SECOND_PART_WEIGHT) rating_calculation = '' if is_last: first_part_calculation = '({}) / ({})'.format( ' + '.join(first_part_numerator_calculation), ' + '.join(first_part_denominator_calculation)) second_part_calculation = '({}) / {}'.format( ' + '.join(second_part_numerator_calculation), max_coefficient) rating_calculation = '({}) * {} + ({}) * {}'.format( first_part_calculation, self.FIRST_PART_WEIGHT / 100, second_part_calculation, self.SECOND_PART_WEIGHT / 100) results.append( RatingResult(rating=rating, player=player, score=score, place=0, rating_calculation=rating_calculation, date=rating_date, is_last=is_last)) place = 1 results = sorted(results, key=lambda x: x.score, reverse=True) for result in results: result.place = place place += 1 RatingResult.objects.bulk_create(results)
def coefficient_value(self): coefficient_obj = self.coefficient_obj return get_tournament_coefficient(self.rating.type == Rating.EMA, self.tournament_id, self.player, coefficient_obj.coefficient)
def _calculate_player_rating( self, player, tournaments_results, deltas, coefficients_cache, max_coefficient, selected_coefficients ): first_part_numerator_calculation = [] first_part_denominator_calculation = [] second_part_numerator_calculation = [] first_part_numerator = 0 first_part_denominator = 0 for result in tournaments_results: coefficient_obj = coefficients_cache[result.tournament_id] coefficient = get_tournament_coefficient( self.IS_EMA, coefficient_obj.tournament_id, player, coefficient_obj.coefficient ) first_part_numerator += float(result.delta) first_part_denominator += float(self._calculate_percentage(float(coefficient), coefficient_obj.age)) first_part_numerator_calculation.append( "{} * {} * {}".format( floatformat(result.base_rank, -2), floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2), ) ) first_part_denominator_calculation.append( "{} * {}".format(floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2)) ) if len(tournaments_results) < self.FIRST_PART_MIN_TOURNAMENTS: fill_missed_data = self.FIRST_PART_MIN_TOURNAMENTS - len(tournaments_results) first_part_denominator += fill_missed_data for _ in range(0, fill_missed_data): first_part_numerator_calculation.append("0") first_part_denominator_calculation.append("1") first_part = first_part_numerator / first_part_denominator second_part_numerator = 0 second_part_denominator = max_coefficient best_results = sorted(deltas, key=lambda x: x.delta, reverse=True)[: self.SECOND_PART_MIN_TOURNAMENTS] for result in best_results: coefficient_obj = coefficients_cache[result.tournament_id] coefficient = get_tournament_coefficient( self.IS_EMA, coefficient_obj.tournament_id, player, coefficient_obj.coefficient ) second_part_numerator += float(result.delta) second_part_numerator_calculation.append( "{} * {} * {}".format( floatformat(result.base_rank, -2), floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2), ) ) second_part = second_part_numerator / second_part_denominator score = self._calculate_percentage(first_part, self.FIRST_PART_WEIGHT) + self._calculate_percentage( second_part, self.SECOND_PART_WEIGHT ) max_coefficient_calculation = [] for x in selected_coefficients: max_coefficient_calculation.append( "{} * {}".format(floatformat(x["coefficient"], -2), floatformat(x["age"] / 100, -2)) ) max_coefficient_template = "max_coefficients = ({}) = {}".format( " + ".join(max_coefficient_calculation), max_coefficient ) first_part_calculation = "p1 = ({}) / ({}) = {}".format( " + ".join(first_part_numerator_calculation), " + ".join(first_part_denominator_calculation), first_part ) second_part_calculation = "p2 = ({}) / max_coefficients = {}".format( " + ".join(second_part_numerator_calculation), second_part ) total_calculation = "score = {} * {} + {} * {} = {}".format( first_part, self.FIRST_PART_WEIGHT / 100, second_part, self.SECOND_PART_WEIGHT / 100, score ) rating_calculation = "\n\n".join( (max_coefficient_template, first_part_calculation, second_part_calculation, total_calculation) ) return rating_calculation, score
def _calculate_player_rating(self, player, tournaments_results, deltas, coefficients_cache, max_coefficient, is_last): first_part_numerator_calculation = [] first_part_denominator_calculation = [] second_part_numerator_calculation = [] first_part_numerator = 0 first_part_denominator = 0 for result in tournaments_results: coefficient_obj = coefficients_cache[result.tournament_id] coefficient = get_tournament_coefficient(coefficient_obj.tournament_id, player, coefficient_obj.coefficient) first_part_numerator += float(result.delta) first_part_denominator += float(self._calculate_percentage(float(coefficient), coefficient_obj.age)) if is_last: first_part_numerator_calculation.append('{} * {} * {}'.format( floatformat(result.base_rank, -2), floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2) )) first_part_denominator_calculation.append('{} * {}'.format( floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2) )) if len(tournaments_results) < self.FIRST_PART_MIN_TOURNAMENTS: fill_missed_data = self.FIRST_PART_MIN_TOURNAMENTS - len(tournaments_results) first_part_denominator += fill_missed_data if is_last: for x in range(0, fill_missed_data): first_part_numerator_calculation.append('0') first_part_denominator_calculation.append('1') first_part = first_part_numerator / first_part_denominator second_part_numerator = 0 second_part_denominator = max_coefficient best_results = sorted(deltas, key=lambda x: x.delta, reverse=True)[:self.SECOND_PART_MIN_TOURNAMENTS] for result in best_results: coefficient_obj = coefficients_cache[result.tournament_id] coefficient = get_tournament_coefficient(coefficient_obj.tournament_id, player, coefficient_obj.coefficient) second_part_numerator += float(result.delta) if is_last: second_part_numerator_calculation.append('{} * {} * {}'.format( floatformat(result.base_rank, -2), floatformat(coefficient, -2), floatformat(coefficient_obj.age / 100, -2) )) second_part = second_part_numerator / second_part_denominator score = self._calculate_percentage(first_part, self.FIRST_PART_WEIGHT) + self._calculate_percentage(second_part, self.SECOND_PART_WEIGHT) rating_calculation = '' if is_last: first_part_calculation = '({}) / ({})'.format( ' + '.join(first_part_numerator_calculation), ' + '.join(first_part_denominator_calculation) ) second_part_calculation = '({}) / {}'.format( ' + '.join(second_part_numerator_calculation), max_coefficient ) rating_calculation = '({}) * {} + ({}) * {}'.format( first_part_calculation, self.FIRST_PART_WEIGHT / 100, second_part_calculation, self.SECOND_PART_WEIGHT / 100 ) return rating_calculation, score
def coefficient_value(self): coefficient_obj = self.coefficient_obj return get_tournament_coefficient(self.tournament_id, self.player, coefficient_obj.coefficient)