|
import numerapi |
|
from numerapi import utils |
|
from project_tools import project_config, project_utils |
|
from typing import List, Dict |
|
import pandas as pd |
|
import numpy as np |
|
|
|
napi = numerapi.NumerAPI() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_portfolio_overview(models, onlylatest=True): |
|
res_df = [] |
|
for m in models: |
|
|
|
print(f'extracting information for model {m}') |
|
if onlylatest: |
|
mdf = get_model_history_v3(m).loc[0:0] |
|
else: |
|
mdf = get_model_history_v3(m) |
|
res_df.append(mdf) |
|
|
|
|
|
if len(res_df)>0: |
|
res_df = pd.concat(res_df, axis=0) |
|
|
|
if onlylatest: |
|
return res_df.sort_values(by='floating_pl', ascending=False).reset_index(drop=True) |
|
else: |
|
return res_df.reset_index(drop=True) |
|
else: |
|
return None |
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_competitions(tournament=8): |
|
"""Retrieves information about all competitions |
|
Args: |
|
tournament (int, optional): ID of the tournament, defaults to 8 |
|
-- DEPRECATED there is only one tournament nowadays |
|
Returns: |
|
list of dicts: list of rounds |
|
Each round's dict contains the following items: |
|
* datasetId (`str`) |
|
* number (`int`) |
|
* openTime (`datetime`) |
|
* resolveTime (`datetime`) |
|
* participants (`int`): number of participants |
|
* prizePoolNmr (`decimal.Decimal`) |
|
* prizePoolUsd (`decimal.Decimal`) |
|
* resolvedGeneral (`bool`) |
|
* resolvedStaking (`bool`) |
|
* ruleset (`string`) |
|
Example: |
|
>>> NumerAPI().get_competitions() |
|
[ |
|
{'datasetId': '59a70840ca11173c8b2906ac', |
|
'number': 71, |
|
'openTime': datetime.datetime(2017, 8, 31, 0, 0), |
|
'resolveTime': datetime.datetime(2017, 9, 27, 21, 0), |
|
'participants': 1287, |
|
'prizePoolNmr': Decimal('0.00'), |
|
'prizePoolUsd': Decimal('6000.00'), |
|
'resolvedGeneral': True, |
|
'resolvedStaking': True, |
|
'ruleset': 'p_auction' |
|
}, |
|
.. |
|
] |
|
""" |
|
|
|
|
|
query = ''' |
|
query($tournament: Int!) { |
|
rounds(tournament: $tournament) { |
|
number |
|
resolveTime |
|
openTime |
|
resolvedGeneral |
|
resolvedStaking |
|
} |
|
} |
|
''' |
|
arguments = {'tournament': tournament} |
|
result = napi.raw_query(query, arguments) |
|
rounds = result['data']['rounds'] |
|
|
|
for r in rounds: |
|
utils.replace(r, "openTime", utils.parse_datetime_string) |
|
utils.replace(r, "resolveTime", utils.parse_datetime_string) |
|
utils.replace(r, "prizePoolNmr", utils.parse_float_string) |
|
utils.replace(r, "prizePoolUsd", utils.parse_float_string) |
|
return rounds |
|
|
|
|
|
def daily_submissions_performances(username: str) -> List[Dict]: |
|
"""Fetch daily performance of a user's submissions. |
|
Args: |
|
username (str) |
|
Returns: |
|
list of dicts: list of daily submission performance entries |
|
For each entry in the list, there is a dict with the following |
|
content: |
|
* date (`datetime`) |
|
* correlation (`float`) |
|
* roundNumber (`int`) |
|
* mmc (`float`): metamodel contribution |
|
* fnc (`float`): feature neutral correlation |
|
* correlationWithMetamodel (`float`) |
|
Example: |
|
>>> api = NumerAPI() |
|
>>> api.daily_user_performances("uuazed") |
|
[{'roundNumber': 181, |
|
'correlation': -0.011765912, |
|
'date': datetime.datetime(2019, 10, 16, 0, 0), |
|
'mmc': 0.3, |
|
'fnc': 0.1, |
|
'correlationWithMetamodel': 0.87}, |
|
... |
|
] |
|
""" |
|
query = """ |
|
query($username: String!) { |
|
v2UserProfile(username: $username) { |
|
dailySubmissionPerformances { |
|
date |
|
correlation |
|
corrPercentile |
|
roundNumber |
|
mmc |
|
mmcPercentile |
|
fnc |
|
fncPercentile |
|
correlationWithMetamodel |
|
} |
|
} |
|
} |
|
""" |
|
arguments = {'username': username} |
|
data = napi.raw_query(query, arguments)['data']['v2UserProfile'] |
|
performances = data['dailySubmissionPerformances'] |
|
|
|
for perf in performances: |
|
utils.replace(perf, "date", utils.parse_datetime_string) |
|
|
|
performances = [p for p in performances |
|
if any([p['correlation'], p['fnc'], p['mmc']])] |
|
return performances |
|
|
|
|
|
def daily_submissions_performances_V3(modelname: str) -> List[Dict]: |
|
query = """ |
|
query($modelName: String!) { |
|
v3UserProfile(modelName: $modelName) { |
|
roundModelPerformances{ |
|
roundNumber |
|
roundResolveTime |
|
corr |
|
corrPercentile |
|
mmc |
|
mmcMultiplier |
|
mmcPercentile |
|
tc |
|
tcPercentile |
|
tcMultiplier |
|
fncV3 |
|
fncV3Percentile |
|
corrWMetamodel |
|
payout |
|
roundResolved |
|
roundResolveTime |
|
corrMultiplier |
|
mmcMultiplier |
|
selectedStakeValue |
|
} |
|
stakeValue |
|
nmrStaked |
|
} |
|
} |
|
""" |
|
arguments = {'modelName': modelname} |
|
data = napi.raw_query(query, arguments)['data']['v3UserProfile'] |
|
performances = data['roundModelPerformances'] |
|
|
|
for perf in performances: |
|
utils.replace(perf, "date", utils.parse_datetime_string) |
|
|
|
performances = [p for p in performances |
|
if any([p['corr'], p['tc'], p['mmc']])] |
|
return performances |
|
|
|
|
|
def get_lb_models(limit=20000, offset=0): |
|
query = """ |
|
query($limit: Int, $offset: Int){ |
|
v2Leaderboard(limit:$limit, offset:$offset){ |
|
username |
|
} |
|
} |
|
""" |
|
arguments = {'limit':limit, 'offset':offset} |
|
data = napi.raw_query(query, arguments)['data']['v2Leaderboard'] |
|
model_list = [i['username'] for i in data] |
|
return model_list |
|
|
|
|
|
|
|
def get_round_model_performance(roundNumber: int, model: str): |
|
query = """ |
|
query($roundNumber: Int!, $username: String!) { |
|
roundSubmissionPerformance(roundNumber: $roundNumber, username: $username) { |
|
corrMultiplier |
|
mmcMultiplier |
|
roundDailyPerformances{ |
|
correlation |
|
mmc |
|
corrPercentile |
|
mmcPercentile |
|
payoutPending |
|
} |
|
selectedStakeValue |
|
} |
|
} |
|
""" |
|
arguments = {'roundNumber': roundNumber,'username': model} |
|
data = napi.raw_query(query, arguments)['data']['roundSubmissionPerformance'] |
|
latest_performance = data['roundDailyPerformances'][-1] |
|
res = {} |
|
res['model'] = model |
|
res['roundNumber'] = roundNumber |
|
res['corrMultiplier'] = data['corrMultiplier'] |
|
res['mmcMultiplier'] = data['mmcMultiplier'] |
|
res['selectedStakeValue'] = data['selectedStakeValue'] |
|
for key in latest_performance.keys(): |
|
res[key] = latest_performance[key] |
|
return res |
|
|
|
|
|
|
|
|
|
def get_user_profile(username: str) -> List[Dict]: |
|
"""Fetch daily performance of a user's submissions. |
|
Args: |
|
username (str) |
|
Returns: |
|
list of dicts: list of daily submission performance entries |
|
For each entry in the list, there is a dict with the following |
|
content: |
|
* date (`datetime`) |
|
* correlation (`float`) |
|
* roundNumber (`int`) |
|
* mmc (`float`): metamodel contribution |
|
* fnc (`float`): feature neutral correlation |
|
* correlationWithMetamodel (`float`) |
|
Example: |
|
>>> api = NumerAPI() |
|
>>> api.daily_user_performances("uuazed") |
|
[{'roundNumber': 181, |
|
'correlation': -0.011765912, |
|
'date': datetime.datetime(2019, 10, 16, 0, 0), |
|
'mmc': 0.3, |
|
'fnc': 0.1, |
|
'correlationWithMetamodel': 0.87}, |
|
... |
|
] |
|
""" |
|
query = """ |
|
query($username: String!) { |
|
v2UserProfile(username: $username) { |
|
dailySubmissionPerformances { |
|
date |
|
correlation |
|
corrPercentile |
|
roundNumber |
|
mmc |
|
mmcPercentile |
|
fnc |
|
fncPercentile |
|
correlationWithMetamodel |
|
} |
|
} |
|
} |
|
""" |
|
arguments = {'username': username} |
|
data = napi.raw_query(query, arguments)['data'] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return data |
|
|
|
|
|
def download_dataset(filename: str, dest_path: str = None, |
|
round_num: int = None) -> None: |
|
""" Download specified file for the current active round. |
|
|
|
Args: |
|
filename (str): file to be downloaded |
|
dest_path (str, optional): complate path where the file should be |
|
stored, defaults to the same name as the source file |
|
round_num (int, optional): tournament round you are interested in. |
|
defaults to the current round |
|
tournament (int, optional): ID of the tournament, defaults to 8 |
|
|
|
Example: |
|
>>> filenames = NumerAPI().list_datasets() |
|
>>> NumerAPI().download_dataset(filenames[0]}") |
|
""" |
|
if dest_path is None: |
|
dest_path = filename |
|
|
|
query = """ |
|
query ($filename: String! |
|
$round: Int) { |
|
dataset(filename: $filename |
|
round: $round) |
|
} |
|
""" |
|
args = {'filename': filename, "round": round_num} |
|
|
|
dataset_url = napi.raw_query(query, args)['data']['dataset'] |
|
utils.download_file(dataset_url, dest_path, show_progress_bars=True) |
|
|
|
|
|
|
|
|
|
|
|
def model_payout_history(model): |
|
napi = numerapi.NumerAPI() |
|
query = """ |
|
query($model: String!) { |
|
v3UserProfile(modelName: $model) { |
|
roundModelPerformances{ |
|
payout |
|
roundNumber |
|
roundResolved |
|
roundResolveTime |
|
corrMultiplier |
|
mmcMultiplier |
|
selectedStakeValue |
|
} |
|
stakeValue |
|
nmrStaked |
|
} |
|
} |
|
""" |
|
arguments = {'model': model} |
|
payout_info = napi.raw_query(query, arguments)['data']['v3UserProfile']['roundModelPerformances'] |
|
payout_info = pd.DataFrame.from_dict(payout_info) |
|
payout_info = payout_info[~pd.isnull(payout_info['payout'])].reset_index(drop=True) |
|
return payout_info |
|
|
|
|
|
def get_model_history_v3(model): |
|
res = model_payout_history(model) |
|
res = pd.DataFrame.from_dict(res) |
|
res['payout'] = res['payout'].astype(np.float64) |
|
res['current_stake'] = res['selectedStakeValue'].astype(np.float64) |
|
res['payout_cumsum'] = project_utils.series_reverse_cumsum(res['payout']) |
|
res['date'] = pd.to_datetime(res['roundResolveTime']).dt.date |
|
|
|
res['realised_pl'] = res['payout_cumsum'] |
|
latest_realised_pl = res[res['roundResolved'] == True]['payout_cumsum'].values[0] |
|
res.loc[res['roundResolved'] == False, 'realised_pl'] = latest_realised_pl |
|
|
|
res['floating_pl'] = 0 |
|
payoutPending_values = res[res['roundResolved'] == False]['payout'].values |
|
payoutPending_cumsum = payoutPending_values[::-1].cumsum()[::-1] |
|
res.loc[res['roundResolved'] == False, 'floating_pl'] = payoutPending_cumsum |
|
|
|
res['model'] = model |
|
|
|
res['floating_stake'] = res['current_stake'] + res['floating_pl'] |
|
cols = ['model', 'date', 'current_stake', 'floating_stake', 'payout', 'floating_pl', 'realised_pl', 'roundResolved', |
|
'roundNumber'] |
|
res = res[cols] |
|
return res |
|
|
|
|
|
|
|
|
|
|
|
|
|
|