Il nostro algoritmo per le quotazioni fantaclub e' completamente
aperto e trasparente. Basta numeri misteriosi calati dall'alto! Il
nostro e' il primo algoritmo open source per le quotazioni del fantacalcio.
Prova direttamente il nostro algoritmo, inserisci i dati di input nel calcolatore
in questa pagina e verifica in anteprima come funziona.
L'algoritmo e' disponibile in due versioni: • standard:
le quotazioni variano fino a 1-2 crediti a settimana, per chi
preferisce la tradizione • fast: le quotazioni
variano fino a 3-4 crediti a settimana, per chi preferisce plusvalenze
piu' spinte.
I 6 di ufficio delle partite rinviate
sono ignorati e non sono usati per il calcolo della quotazione.
Fai tutte le prove che desideri
mediante il calcolatore online delle quotazioni ed inviaci il tuo
feedback. Ogni contributo e' importante per far evolvere l'algoritmo.
Calcola quotazione
Ruolo del calciatore:
Quotazione iniziale:
Voti separati da spazio (per senza voto scrivere "sv", per infortunio
"inf"):
Versione algoritmo:
Risultato: -
Descrizione dell'algoritmo
Dati di input
le variabili di ingresso per il
calcolo della quotazione sono: quotazione iniziale, ruolo del
calciatore (por, dif, cen, att), elenco dei voti (incluso SV) per tutte
le giornate di campionato inclusivi di tutti i bonus/malus. Il
risultato dell'algoritmo sara' la quotazione corrente del calciatore.
La fonte dei voti utilizzata e' la redazione Fantaclub doppia
precisione.
Come avviene il calcolo
L'algoritmo e' eseguito in maniera
iterativa per ogni giornata di campionato.
Ad ogni giornata si calcola il valore corrente della quotazione
partendo da: - quotazione corrente precedente (quotazione
iniziale se prima giornata) - media voto considerando tutte le
giornate precedenti - voto ultima giornata
Il calcolo della quotazione corrente e' effettuato in due
passaggi: prima si determina il valore target della quotazione,
determinato da media, ultimo voto e numero assenze.
Poi per evitare che vi possano essere sbalzi eccessivi tra una
giornata e l'altra e' determinato l'intervallo massimo di variazione
mediante una formula. Tale intervallo ha come valore massimo 3.5,
pertanto la quotazione di un calciatore puo' cambiare al massimo di 3-4
crediti da una giornata all'altra.
Se la distanza tra la quotazione target e la quotazione al passo
precedente supera l'intervallo massimo di variazione allora il
risultato sara' limitato a quotazione precedente +- intervallo di
variazione.
Tutti i calcoli giornata per giornata a partire dalla quotazione
iniziale in poi avvengono in numeri con virgola, il risultato finale e'
poi convertito in un numero intero, pari al valore della quotazione.
Il codice
Per chi desidera approfondire nei minimi dettagli, riportiamo per
intero il codice sorgente dell'algoritmo:
/**
* Algoritmo quotazioni fantaclub.
*
* Versione 1.0.0 Ultima modifica: 24/06/2017
*
* @author Marco Alessandretti - www.fantaclub.it
*/
public class AlgoritmoQuotazioni {
public static final double SV = 99;
private static final double OSCILLAZIONE_GIORNATA_SV = 0.05;
private static final double[] K1 = { 8.4, 12.5180, 10.8140, 9.5261 };
private static final double[] K2 = { -24.7, -63.8561, -53.8023, -41.1423 };
/**
* Calcola quotazione iterando su tutte le giornate.
*/
public static final int calcolaQuotazione(int quotazioneIniziale, List voti, Ruolo ruolo) {
// itera algoritmo giornata per giornata
double current = nextGiornata(2, quotazioneIniziale, ruolo, voti);
for (int i = 2; i <= voti.size(); i++) {
current = nextGiornata(i + 1, current, ruolo, voti);
}
// arrotonda ad intero
int result = (int) Math.round(current);
// quotazione minima 1
if (result <= 0) {
result = 1;
}
return result;
}
/**
* Calcola quotazione giornata successiva
*/
private static final double nextGiornata(int giornata, double quotazionePrecedente, Ruolo ruolo,
List listaVoti) {
int i;
// se non ci sono voti, mantieni quotazione
if (listaVoti.size() == 0) {
return quotazionePrecedente;
}
// costruisci array voti
double[] voti = new double[giornata - 1];
for (i = 0; i < voti.length; i++) {
voti[i] = listaVoti.get(i);
}
// se l'ultimo voto e' un sv non consecutivo allora mantieni quotazione
// ultima
double ultimoVoto = voti[voti.length - 1];
double penultimoVoto = SV;
if (voti.length > 1) {
penultimoVoto = voti[voti.length - 2];
}
if (ultimoVoto == SV && voti.length <= 1) {
return quotazionePrecedente;
}
if (penultimoVoto != SV && ultimoVoto == SV) {
return quotazionePrecedente;
}
// determina numero di assenze
int assenzeCount = assenzeCount(voti);
// calcola media escludendo gli sv (se sono tutti sv usa media attesa)
int presenze = 0;
double somma = 0;
for (i = 0; i < voti.length; i++) {
if (voti[i] != SV) {
presenze++;
somma += voti[i];
}
}
double media;
double mediaVoto;
if (presenze > 0) {
media = somma / presenze;
mediaVoto = media;
// dai peso maggiore ultimo voto
if (giornata >= 2 && ultimoVoto != SV) {
media = (media * 5 + ultimoVoto) / 6;
}
} else {
media = mediaAttesa(quotazionePrecedente, ruolo);
mediaVoto = media;
}
// calcola quotazione target
double result = quotazioneTarget(media, ruolo, assenzeCount);
// calcola scostamento massimo
double absDiff = Math.abs(quotazionePrecedente - result);
double maxDiff = maxDiffFunction(absDiff, ruolo);
//System.out.println("target " + result + " maxDiff " + maxDiff + " absDiff " + absDiff);
double diff = result - quotazionePrecedente;
if (diff < 0) {
// la quotazione e' diminuita
diff = -diff;
if (diff > maxDiff) {
result = quotazionePrecedente - maxDiff;
}
} else {
// la quotazione e' aumentata
if (diff > maxDiff) {
result = quotazionePrecedente + maxDiff;
}
}
// se e' senza voto puo' solo diminuire
if (ultimoVoto == SV && result > quotazionePrecedente) {
return quotazionePrecedente;
}
// impedisci aumenti in caso di brutti voti oppure diminuizioni in caso
// di voto alto
if (ultimoVoto != SV && presenze > 1) {
if (ultimoVoto >= 7 && ultimoVoto >= mediaVoto + 1.5 && result < quotazionePrecedente) {
result = quotazionePrecedente;
} else if (ultimoVoto < 7 && ultimoVoto <= mediaVoto - 1.5 && result > quotazionePrecedente) {
result = quotazionePrecedente;
}
}
return result;
}
/**
* Determina quotazione target per una data media.
*/
private static final double quotazioneTarget(double media, Ruolo ruolo, int numeroAssenze) {
double result = media * K1[ruolo.ordinal()] + K2[ruolo.ordinal()];
// calcola frazione da togliere dovuta alle assenze
double percentuale = 1 - (OSCILLAZIONE_GIORNATA_SV * numeroAssenze);
if (percentuale < 0) {
percentuale = 0;
}
result = result * percentuale;
return result;
}
/**
* Stima la media che dovrebbe avere un calciatore con una data quotazione.
*/
private static final double mediaAttesa(double quotazione, Ruolo ruolo) {
double mediaAttesa = (quotazione - K2[ruolo.ordinal()]) / K1[ruolo.ordinal()];
return mediaAttesa;
}
/**
* Determina scostamento massimo da una giornata all'altra.
*/
public static final double maxDiffFunction(double interval, Ruolo ruolo) {
int expansion = 12;
if (ruolo == Ruolo.PORTIERE) {
// per il portiere limita ulteriormente variazione quotazione
expansion = 20;
}
double result = -Math.expm1(-interval / expansion) * 3.5;
return result;
}
/**
* Contatore numero assenze per il calcolo della quotazione target.
*/
public static final int assenzeCount(double[] voti) {
int assenzeCount = 0;
for (int i = 0; i < voti.length; i++) {
if (voti[i] == SV) {
assenzeCount++;
} else {
// la presenza dimezza il contatore assenze per un rapido
// recupero
assenzeCount = assenzeCount / 2;
}
}
return assenzeCount;
}
}