def whatif(lb, users, s, c): """ Profit if `users` had staked `s` and `c` in every tournament. Earnings are left in NMR instead of splitting the NMR earnings into NMR and USD. """ if isinstance(users, list): pass elif nx.isstring(users): users = [users] else: raise ValueError("`users` must be str or list (of str)") cols = ['nmr_staked', 'nmr_burn', 'nmr_earn', 'nmr_net'] df = pd.DataFrame(columns=cols) lb.insert(0, 'pass', lb['live'] < LOGLOSS_BENCHMARK) rounds = np.sort(lb['round'].unique()) for r in rounds: d = lb[lb['round'] == r] if r > 112: staked = 0 burn = 0 earn = 0 for t in nx.tournament_all(as_str=False): dt = d[d.tournament == t] if dt.shape[0] > 0: cutoff, ignore = calc_cutoff(dt) if c >= cutoff: idx = dt.user.isin(users) dti = dt[idx] idx = dti['pass'] nwin = idx.sum() nlos = (~idx & (dti['live'].notna())).sum() p = (1.0 - cutoff) / cutoff burn += nlos * s earn += nwin * s * p staked += idx.size * s net = earn - burn df.loc[r] = [staked, burn, earn, net] else: raise ValueError("`round1` must start at at least 113") df.loc['total'] = df.sum() return df
def cutoff(lb): "Independent calculation of confidence cutoff" cols = nx.tournament_all(as_str=True) df = pd.DataFrame(columns=cols) rounds = np.sort(lb['round'].unique()) for r in rounds: d = lb[lb['round'] == r] if r > 112: cut = [] for t in nx.tournament_all(as_str=False): dt = d[d.tournament == t] cutoff, ignore = calc_cutoff(dt) cut.append(cutoff) else: cut = [np.nan] * 5 df.loc[r] = cut df['mean'] = df.mean(axis=1) df.loc['mean'] = df.mean() return df
def pass_rate(lb): "Fraction of users who beat benchmark in each round" cols = ['all', 'stakers', 'nonstakers', 'above_cutoff', 'below_cutoff'] df = pd.DataFrame(columns=cols) rounds = np.sort(lb['round'].unique()) for r in rounds: d = lb[(lb['round'] == r) & (lb.live.notna())] d.insert(0, 'pass', d['live'] < LOGLOSS_BENCHMARK) pr_all = d['pass'].mean() pr_stakers = d[d['s'] > 0]['pass'].mean() pr_nonstakers = d[d['s'] == 0]['pass'].mean() if r > 112: nabove = 0 nbelow = 0 pabove = 0 pbelow = 0 for t in nx.tournament_all(as_str=False): dt = d[d.tournament == t] cutoff, ignore = calc_cutoff(dt) nabove += dt[dt.c > cutoff].shape[0] nbelow += dt[dt.c < cutoff].shape[0] pabove += dt[(dt.c > cutoff) & (dt['pass'])].shape[0] pbelow += dt[(dt.c < cutoff) & (dt['pass'])].shape[0] if nabove == 0: pr_above = np.nan else: pr_above = 1.0 * pabove / nabove if nbelow == 0: pr_below = np.nan else: pr_below = 1.0 * pbelow / nbelow else: pr_above = np.nan pr_below = np.nan df.loc[r] = [pr_all, pr_stakers, pr_nonstakers, pr_above, pr_below] df.loc['mean'] = df.mean() return df
def payout(lb): "NMR and USD payouts per round" cols = [ 'staked_nmr', 'staked_above_cutoff', 'burned_nmr', 'nmr_payout', 'usd_payout', 'total_payout_in_nmr' ] df = pd.DataFrame(columns=cols) rounds = np.sort(lb['round'].unique()) lb.insert(0, 'pass', lb['live'] < LOGLOSS_BENCHMARK) for r in rounds: d = lb[lb['round'] == r] if r > 112: nmr_cut = 0 nmr_cut_pass = 0 for t in nx.tournament_all(as_str=False): dt = d[d.tournament == t] cutoff, ignore = calc_cutoff(dt) nmr_cut += dt[dt.c >= cutoff].sum()['s'] nmr_cut_pass += dt[(dt.c >= cutoff) & (dt['pass'])].sum()['s'] else: nmr_cut = np.nan if cutoff == 0: total = np.nan else: total = nmr_cut_pass * (1.0 - cutoff) / cutoff ds = d.sum() pay = [ ds['s'], nmr_cut, ds['nmr_burn'], ds['nmr_stake'], ds['usd_stake'], total ] df.loc[r] = pay fraction = df['burned_nmr'] / df['staked_above_cutoff'] df.insert(3, 'fraction_burned', fraction) df.loc['mean'] = df.mean() df = df.round(2) return df