def __getitem__(self, index): "Index by round number, list (or tuple), or slice" if isinstance(index, slice): if index.step is not None: raise ValueError("slice step size must be 1") r1, r2 = self.rounds_to_ints(index.start, index.stop) rs = list(range(r1, r2 + 1)) ts = nx.tournament_all(as_str=False) elif nx.isint(index): rs = [index] ts = nx.tournament_all(as_str=False) elif isinstance(index, list): rs, ts = zip(*index) ts = [nx.tournament_int(i) for i in ts] elif isinstance(index, tuple): if len(index) != 2: raise IndexError("tuple index must have length 2") r, t = index if not nx.isint(r): raise IndexError("first element of tuple index must be int") if not (nx.isint(t) or nx.isstring(t)): msg = "second element of tuple index must be int or str" raise IndexError(msg) rs = [r] ts = [nx.tournament_int(t)] else: raise IndexError("indexing method not supported") self.gets(rs, ts) ridx = self.df['round'].isin(rs) tidx = self.df['tournament'].isin(ts) idx = ridx & tidx df = self.df[idx] return df
def test_tournament_int(): """test tournament_int""" for t_int, t_str in nx.tournament_iter(): t_int2 = nx.tournament_int(t_int) ok_(t_int2 == t_int, "tournament int do not agree") t_int2 = nx.tournament_int(t_str) ok_(t_int2 == t_int, "tournament int do not agree") assert_raises(ValueError, nx.tournament_int, 0) assert_raises(ValueError, nx.tournament_int, 'burn') assert_raises(ValueError, nx.tournament_int, None)
def upload(filename, tournament, public_id, secret_key, block=True, n_tries=100, sleep_seconds=60, verbose=False): """ Upload tournament submission (csv file) to Numerai. If upload fails then retry upload `n_tries` times, pausing `sleep_seconds` between each try. If block is True (default) then the scope of your token must be both upload_submission and read_submission_info. If block is False then only upload_submission is needed. """ tournament = nx.tournament_int(tournament) count = 0 while count < n_tries: try: napi = NumerAPI(public_id=public_id, secret_key=secret_key, verbosity='warning') upload_id = napi.upload_predictions(filename, tournament=tournament) if block: status = status_block(upload_id, public_id, secret_key) else: status = upload_status(upload_id, public_id, secret_key) break except: # noqa print('upload failed') time.sleep(sleep_seconds) count += 1 return upload_id, status
def pairs_with_tournament(self, tournament, as_str=True): """List of pairs; `tournament` can be int, str, or list""" if isinstance(tournament, list): tournaments = [nx.tournament_int(t) for t in tournament] elif nx.isstring(tournament): tournaments = [nx.tournament_int(tournament)] elif nx.isint(tournament): tournaments = [tournament] else: raise ValueError('`tournament` must be int, str or list') prs = self.pairs(as_str=False) pairs = [] for pr in prs: if pr[1] in tournaments: if as_str: pr = (pr[0], nx.tournament_str(pr[1])) pairs.append(pr) return pairs
def __contains__(self, round_tournament_tuple): "Has (round, torunament) tuple already been downloaded? True or False" if len(round_tournament_tuple) != 2: raise ValueError("`round_tournament_tuple` must have length 2") if self.df is None: return False r, t = round_tournament_tuple t = nx.tournament_int(t) idx = (self.df['round'] == r) & (self.df['tournament'] == t) if idx.sum() > 0: return True return False
def load_prediction_csv(filename, name=None): "Load prediction object from a Numerai csv (text) tournament file" df = pd.read_csv(filename, index_col='id') if df.shape[1] != 1: raise ValueError("csv file must contain one column of predictions") tournament = nx.tournament_int(df.columns[0].split('_')[-1]) if name is None: name = os.path.split(filename)[-1] if name.endswith('.csv'): name = name[:-4] df.columns = [(name, tournament)] return Prediction(df)
def round_resolution_date(tournament=1): "The date each round was resolved as a Dataframe." tournament = nx.tournament_int(tournament) napi = NumerAPI(verbosity='warn') dates = napi.get_competitions(tournament=tournament) dates = pd.DataFrame(dates)[['number', 'resolveTime']] rename_map = {'number': 'round', 'resolveTime': 'date'} dates = dates.rename(rename_map, axis=1) date = dates['date'].tolist() date = [d.date() for d in date] dates['date'] = date dates = dates.set_index('round') dates = dates.sort_index() return dates
def download_leaderboard(round_number=None, tournament=1): """ Download leaderboard for specified tournament and round. Default is to download current round. """ tournament = nx.tournament_int(tournament) if round_number is None: napi = NumerAPI(verbosity='warn') num = napi.get_current_round(tournament=tournament) else: num = round_number df = download_raw_leaderboard(round_number=num, tournament=tournament) df = raw_leaderboard_to_df(df, num) return df
def get(self, round_number, tournament): "Download, if missing, a single round/tournament pair" r = round_number t = nx.tournament_int(tournament) if (r, t) not in self: if self.verbose: print("downloading ({:d}, {})".format(r, t)) b = download_leaderboard(r, t) if self.verbose: if b['resolved'].all(): print("({:d}, {}) is resolved".format(r, t)) else: print("({:d}, {}) is not resolved".format(r, t)) self.df = pd.concat([self.df, b]) else: if self.verbose: print("({:d}, {}) already downloaded".format(r, t))
def __getitem__(self, index): "Prediction indexing is by model pair(s)" if isinstance(index, tuple): if len(index) != 2: raise IndexError("When indexing by tuple must be length 2") if isinstance(index[0], slice): if not is_none_slice(index[0]): raise IndexError("Slces must be slice(None, None, None,)") pairs1 = self.pairs(as_str=False) elif nx.isstring(index[0]): pairs1 = self.pairs_with_name(index[0], as_str=False) else: raise IndexError("indexing method not recognized") if isinstance(index[1], slice): if not is_none_slice(index[1]): raise IndexError("Slces must be slice(None, None, None,)") pairs2 = self.pairs(as_str=False) elif nx.isint(index[1]): pairs2 = self.pairs_with_tournament(index[1], as_str=False) elif nx.isstring(index[1]): pairs2 = self.pairs_with_tournament(index[1], as_str=False) else: raise IndexError("indexing method not recognized") pairs = [] for pair in pairs1: if pair in pairs2: pairs.append(pair) p = Prediction(pd.DataFrame(data=self.df[pairs])) elif nx.isstring(index): pairs = self.pairs_with_name(index, as_str=False) p = Prediction(self.df[pairs]) else: # assume an iterable of tuple pairs idx = [] for ix in index: if len(ix) != 2: msg = "Expecting list of tuple pairs with length 2" raise IndexError(msg) idx.append((ix[0], nx.tournament_int(ix[1]))) p = Prediction(self.df[idx]) return p
def download_raw_leaderboard(round_number=None, tournament=1): "Download leaderboard for given round number" tournament = nx.tournament_int(tournament) query = ''' query($number: Int! $tournament: Int!) { rounds(number: $number tournament: $tournament) { leaderboard { username LiveLogloss ValidationLogloss Consistency paymentGeneral { nmrAmount usdAmount } paymentStaking { nmrAmount usdAmount } stake { value confidence soc } stakeResolution { destroyed } } } } ''' napi = NumerAPI(verbosity='warn') if round_number is None: round_number = get_current_round_number(tournament) arguments = {'number': round_number, 'tournament': tournament} leaderboard = napi.raw_query(query, arguments) leaderboard = leaderboard['data']['rounds'][0]['leaderboard'] return leaderboard
def download_leaderboard(round_number=None, tournament=1): """ Download leaderboard for specified tournament and round. Default is to download current round. """ tournament = nx.tournament_int(tournament) if round_number is None: napi = NumerAPI(verbosity='warn') num = napi.get_current_round() else: num = round_number df = download_raw_leaderboard(round_number=num, tournament=tournament) df = raw_leaderboard_to_df(df, num) df.insert(1, 'tournament', tournament) cols = ['usd_main', 'usd_stake', 'nmr_main', 'nmr_stake', 'nmr_burn'] d = df[cols] total = d.abs().sum().sum() if total == 0: resolved = False else: resolved = True df.insert(2, 'resolved', resolved) return df
def make_pair(self, name, tournament): """Combine `name` and `tournament` into a pair (dataframe column name)""" if not nx.isstring(name): raise ValueError("`name` must be a string") return (name, nx.tournament_int(tournament))
def tournament_isin(self, tournament): """Is tournament in Prediction object? True or False.""" tournaments = self.tournaments(as_str=False) tournament = nx.tournament_int(tournament) return tournament in tournaments
def get_stakes_minimal(round_number=None, tournament=1, mark_user=None): "Download stakes, modify it to make it more useful, return as dataframe." tournament = nx.tournament_int(tournament) # get raw stakes napi = NumerAPI() query = ''' query stakes($number: Int! $tournament: Int!){ rounds(number: $number tournament: $tournament){ leaderboard { username stake { insertedAt soc confidence value } } } } ''' if round_number is None: round_number = 0 elif round_number < 61: raise ValueError('First staking was in round 61') arguments = {'number': round_number, 'tournament': tournament} stakes = napi.raw_query(query, arguments) # massage raw stakes stakes = stakes['data']['rounds'][0]['leaderboard'] stakes2 = [] strptime = datetime.datetime.strptime now = datetime.datetime.utcnow() secperday = 24 * 60 * 60 micperday = 1000000 * secperday for s in stakes: user = s['username'] s = s['stake'] if s['value'] is not None: s2 = {} s2['user'] = user s2['s'] = float(s['value']) s2['c'] = decimal.Decimal(s['confidence']) s2['soc'] = float(s['soc']) t = now - strptime(s['insertedAt'], '%Y-%m-%dT%H:%M:%S.%fZ') d = t.days d += 1.0 * t.seconds / secperday d += 1.0 * t.microseconds / micperday s2['days'] = d stakes2.append(s2) stakes = stakes2 # jam stakes into a dataframe stakes = pd.DataFrame(stakes) stakes = stakes[['days', 's', 'soc', 'c', 'user']] # index by user stakes = stakes.set_index('user') # sort in prize pool order stakes = stakes.sort_values(['c', 'days'], axis=0, ascending=[False, False]) # mark user if mark_user is not None and mark_user in stakes.index: stakes['mark'] = '' me = stakes.loc[mark_user]['days'] idx = stakes.days < me stakes.loc[idx, 'mark'] = 'new' stakes.loc[mark_user, 'mark'] = '<<<<' return stakes
def __init__(self, tournament=1, verbose=False): self.tournament = nx.tournament_int(tournament) self.verbose = verbose self.df = None self.unresolved_rounds = [] self.current_round = None
def upload(filename, tournament, public_id, secret_key, block=True, n_tries=100, sleep_seconds=60, verbose=False, model_id=None): """ Upload tournament submission (csv file) to Numerai. Accounts with multiple models must specify model_id If upload fails then retry upload `n_tries` times, pausing `sleep_seconds` between each try. If block is True (default) then the scope of your token must be both upload_submission and read_submission_info. If block is False then only upload_submission is needed. """ tournament = nx.tournament_int(tournament) count = 0 napi = NumerAPI(public_id=public_id, secret_key=secret_key, verbosity='warning') models = napi.get_models() if len(models) > 1 and model_id is None: raise Exception( f"Account has multiple models - you must specify model_id from {models}" ) elif model_id and model_id not in models.values(): raise Exception( f"Specified model_id {model_id} not found in account models {models}" ) while count < n_tries: try: upload_id = napi.upload_predictions(filename, tournament=tournament, model_id=model_id) if block: status = status_block(upload_id, public_id, secret_key, model_id=model_id) else: status = upload_status(upload_id, public_id, secret_key, model_id=model_id) break except Exception as e: # noqa if str(e).startswith("Can't update submission after deadline"): # Bailout with error message and do not retry uploads raise Exception(e) else: print('Upload exception - %s' % e) time.sleep(sleep_seconds) count += 1 else: raise Exception('Upload failed after reaching max retries') return upload_id, status
def get_current_round_number(tournament): "Current round number as an integer." tournament = nx.tournament_int(tournament) napi = NumerAPI(verbosity='warn') cr = napi.get_current_round(tournament=tournament) return cr