numerai-cli 1.0.3__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/PKG-INFO +2 -1
  2. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/README.md +1 -0
  3. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/constants.py +1 -7
  4. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/node/__init__.py +20 -16
  5. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/node/config.py +17 -6
  6. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/node/test.py +2 -3
  7. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/util/docker.py +37 -12
  8. {numerai-cli-1.0.3/numerai/examples/tournament-python3 → numerai-cli-1.1.0/numerai/examples/crypto-python3}/Dockerfile +3 -3
  9. numerai-cli-1.1.0/numerai/examples/crypto-python3/predict.py +105 -0
  10. numerai-cli-1.1.0/numerai/examples/crypto-python3/requirements.txt +5 -0
  11. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/examples/signals-python3/Dockerfile +4 -4
  12. numerai-cli-1.1.0/numerai/examples/signals-python3/predict.py +104 -0
  13. numerai-cli-1.1.0/numerai/examples/signals-python3/requirements.txt +5 -0
  14. numerai-cli-1.1.0/numerai/examples/tournament-python3/Dockerfile +35 -0
  15. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/examples/tournament-python3/predict.py +17 -7
  16. numerai-cli-1.1.0/numerai/examples/tournament-python3/requirements.txt +5 -0
  17. numerai-cli-1.1.0/numerai/examples/tournament-python3/train.py +10 -0
  18. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/-inputs.tf +6 -0
  19. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/-main.tf +1 -0
  20. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/aws/-inputs.tf +6 -0
  21. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/aws/cluster.tf +50 -5
  22. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai_cli.egg-info/PKG-INFO +2 -1
  23. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai_cli.egg-info/SOURCES.txt +3 -1
  24. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/setup.py +1 -1
  25. numerai-cli-1.0.3/numerai/examples/signals-python3/data.py +0 -164
  26. numerai-cli-1.0.3/numerai/examples/signals-python3/predict.py +0 -160
  27. numerai-cli-1.0.3/numerai/examples/signals-python3/requirements.txt +0 -8
  28. numerai-cli-1.0.3/numerai/examples/signals-python3/train.py +0 -6
  29. numerai-cli-1.0.3/numerai/examples/tournament-python3/requirements.txt +0 -5
  30. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/MANIFEST.in +0 -0
  31. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/__init__.py +0 -0
  32. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/__init__.py +0 -0
  33. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/destroy_all.py +0 -0
  34. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/doctor.py +0 -0
  35. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/misc.py +0 -0
  36. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/node/deploy.py +0 -0
  37. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/node/destroy.py +0 -0
  38. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/setup.py +0 -0
  39. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/uninstall.py +0 -0
  40. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/upgrade.py +0 -0
  41. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/util/__init__.py +0 -0
  42. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/util/debug.py +0 -0
  43. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/util/files.py +0 -0
  44. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/cli/util/keys.py +0 -0
  45. {numerai-cli-1.0.3/numerai/examples/tournament-python3 → numerai-cli-1.1.0/numerai/examples/signals-python3}/train.py +0 -0
  46. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/examples/tournament-rlang/Dockerfile +0 -0
  47. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/examples/tournament-rlang/install_packages.R +0 -0
  48. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/examples/tournament-rlang/main.R +0 -0
  49. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/-outputs.tf +0 -0
  50. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/aws/-locals.tf +0 -0
  51. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/aws/-outputs.tf +0 -0
  52. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/aws/main.zip +0 -0
  53. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/aws/network.tf +0 -0
  54. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/aws/aws/webhook.tf +0 -0
  55. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/azure/cluster.tf +0 -0
  56. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/azure/input.tf +0 -0
  57. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/azure/locals.tf +0 -0
  58. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/azure/outputs.tf +0 -0
  59. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/azure/webhook.tf +0 -0
  60. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/azure_cron_trigger.zip +0 -0
  61. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/azure_trigger.zip +0 -0
  62. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/input.tf +0 -0
  63. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/main.tf +0 -0
  64. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/outputs.tf +0 -0
  65. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/azure/registry.tf +0 -0
  66. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/-inputs.tf +0 -0
  67. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/-main.tf +0 -0
  68. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/-outputs.tf +0 -0
  69. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/cloud-function.zip +0 -0
  70. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/gcp/-inputs.tf +0 -0
  71. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/gcp/-locals.tf +0 -0
  72. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/gcp/-outputs.tf +0 -0
  73. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/gcp/cluster.tf +0 -0
  74. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/gcp/webhook.tf +0 -0
  75. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/gcp/workflow-source.yaml +0 -0
  76. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/registry.tf +0 -0
  77. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai/terraform/gcp/services.tf +0 -0
  78. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai_cli.egg-info/dependency_links.txt +0 -0
  79. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai_cli.egg-info/entry_points.txt +0 -0
  80. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai_cli.egg-info/requires.txt +0 -0
  81. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/numerai_cli.egg-info/top_level.txt +0 -0
  82. {numerai-cli-1.0.3 → numerai-cli-1.1.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: numerai-cli
3
- Version: 1.0.3
3
+ Version: 1.1.0
4
4
  Summary: A library for deploying Numer.ai Prediction Nodes.
5
5
  Home-page: https://github.com/numerai/numerai-cli
6
6
  Author: Numer.ai
@@ -11,6 +11,7 @@ Description: # numerai-cli
11
11
  [![PyPI](https://img.shields.io/pypi/v/numerai-cli.svg?color=brightgreen)](https://pypi.org/project/numerai-cli/)
12
12
 
13
13
  Welcome to the Numerai CLI for the [Numerai Tournament](https://docs.numer.ai/tournament/learn).
14
+ Numerai CLI (aka Compute Heavy) is a tool to help you set up cloud automation for your Numerai predictions.
14
15
  This README is designed to have EVERYTHING you need to setup and maintain a Numerai Compute Heavy node.
15
16
 
16
17
  This CLI runs on your local computer to configure a Numerai Prediction Node in the cloud.
@@ -3,6 +3,7 @@
3
3
  [![PyPI](https://img.shields.io/pypi/v/numerai-cli.svg?color=brightgreen)](https://pypi.org/project/numerai-cli/)
4
4
 
5
5
  Welcome to the Numerai CLI for the [Numerai Tournament](https://docs.numer.ai/tournament/learn).
6
+ Numerai CLI (aka Compute Heavy) is a tool to help you set up cloud automation for your Numerai predictions.
6
7
  This README is designed to have EVERYTHING you need to setup and maintain a Numerai Compute Heavy node.
7
8
 
8
9
  This CLI runs on your local computer to configure a Numerai Prediction Node in the cloud.
@@ -1,10 +1,9 @@
1
1
  """Constants for Numerai CLI"""
2
+
2
3
  import os
3
4
  import json
4
5
  from pathlib import Path
5
6
 
6
- TOURNAMENT_NUMERAI = 8
7
- TOURNAMENT_SIGNALS = 11
8
7
  PACKAGE_PATH = os.path.dirname(__file__)
9
8
  CONFIG_PATH = os.path.join(str(Path.home()), ".numerai")
10
9
  KEYS_PATH = os.path.join(CONFIG_PATH, ".keys")
@@ -65,11 +64,6 @@ DEFAULT_SETTINGS = {
65
64
  }
66
65
 
67
66
  CONSTANTS_STR = f"""Default values (not your configured node values):
68
-
69
- ---Tournament Numbers---
70
- TOURNAMENT_NUMERAI: {TOURNAMENT_NUMERAI}
71
- TOURNAMENT_SIGNALS: {TOURNAMENT_SIGNALS}
72
-
73
67
  ---Paths---
74
68
  PACKAGE_PATH: {PACKAGE_PATH}
75
69
  CONFIG_PATH: {CONFIG_PATH}
@@ -1,4 +1,5 @@
1
1
  """Init for node"""
2
+
2
3
  import json
3
4
  import logging
4
5
  import click
@@ -15,22 +16,23 @@ from numerai.cli.util.keys import get_numerai_keys
15
16
  # Setting azure's logging level "ERROR" to avoid spamming the terminal
16
17
 
17
18
 
18
- def get_models(signals):
19
- if signals:
20
- tournament = TOURNAMENT_SIGNALS
21
- name_prefix = "signals"
22
- else:
23
- tournament = TOURNAMENT_NUMERAI
24
- name_prefix = "numerai"
19
+ def tournaments_dict():
20
+ napi = base_api.Api()
21
+ tournaments = napi.raw_query('query { tournaments { name tournament } }')
22
+ return {t["tournament"]: t["name"] for t in tournaments["data"]["tournaments"]}
23
+
24
+
25
+ def get_models(tournament):
25
26
  napi = base_api.Api(*get_numerai_keys())
26
27
  models = napi.get_models(tournament)
27
-
28
+ tournaments = napi.raw_query('query { tournaments { name tournament } }')
29
+ name_prefix = tournaments_dict()[tournament]
28
30
  model_dict = {}
29
31
  for model_name, model_id in models.items():
30
32
  model_dict[model_name] = {
31
33
  "id": model_id,
32
34
  "name": f"{name_prefix}-{model_name}",
33
- "is_signals": signals,
35
+ "tournament": tournament,
34
36
  }
35
37
  return model_dict
36
38
 
@@ -43,16 +45,18 @@ def get_models(signals):
43
45
  type=str,
44
46
  prompt=True,
45
47
  help="The name of one of your models to configure the Prediction Node for."
46
- "It defaults to the first model returned from your account.",
48
+ " It defaults to the first model returned from your account.",
47
49
  )
48
50
  @click.option(
49
- "--signals",
50
- "-s",
51
- is_flag=True,
52
- help="Target a signals model with this name. Defaults to false.",
51
+ "--tournament",
52
+ "-t",
53
+ default=8,
54
+ help="Target a specific tournament number."
55
+ " Defaults to Numerai Tournament/Classic."
56
+ f" Available tournaments: {json.dumps(tournaments_dict(), indent=2)}",
53
57
  )
54
58
  @click.pass_context
55
- def node(ctx, verbose, model_name, signals):
59
+ def node(ctx, verbose, model_name, tournament):
56
60
  """
57
61
  Commands to manage and test Prediction Nodes.
58
62
  """
@@ -68,7 +72,7 @@ def node(ctx, verbose, model_name, signals):
68
72
  else:
69
73
  logger.setLevel(logging.ERROR)
70
74
 
71
- models = get_models(signals)
75
+ models = get_models(tournament)
72
76
 
73
77
  try:
74
78
  ctx.ensure_object(dict)
@@ -1,4 +1,5 @@
1
1
  """Config command for Numerai CLI"""
2
+
2
3
  import json
3
4
  import os
4
5
  import click
@@ -94,6 +95,12 @@ from numerai.cli.util.keys import get_provider_keys, get_numerai_keys, load_or_i
94
95
  help="Forces your webhook to register with Numerai. "
95
96
  "Use in conjunction with options that prevent webhook auto-registering.",
96
97
  )
98
+ @click.option(
99
+ "--volume",
100
+ "-v",
101
+ type=int,
102
+ help="Specify additional block storage in GB. Currently only supported in AWS.",
103
+ )
97
104
  @click.pass_context
98
105
  def config(
99
106
  ctx,
@@ -107,6 +114,7 @@ def config(
107
114
  cron,
108
115
  timeout_minutes,
109
116
  register_webhook,
117
+ volume,
110
118
  ):
111
119
  """
112
120
  Uses Terraform to create a full Numerai Compute cluster in your desired provider.
@@ -262,12 +270,12 @@ def config(
262
270
  provider_registry_conf = create_gcp_registry(provider, verbose=verbose)
263
271
  node_conf.update(provider_registry_conf)
264
272
  registry_parts = node_conf["registry_id"].split("/")
265
- node_conf[
266
- "artifact_registry_login_url"
267
- ] = f"https://{registry_parts[3]}-docker.pkg.dev/"
268
- node_conf[
269
- "docker_repo"
270
- ] = f"{registry_parts[3]}-docker.pkg.dev/{registry_parts[1]}/numerai-container-registry/{node}:latest"
273
+ node_conf["artifact_registry_login_url"] = (
274
+ f"https://{registry_parts[3]}-docker.pkg.dev/"
275
+ )
276
+ node_conf["docker_repo"] = (
277
+ f"{registry_parts[3]}-docker.pkg.dev/{registry_parts[1]}/numerai-container-registry/{node}:latest"
278
+ )
271
279
  docker.login(node_conf, verbose)
272
280
  try:
273
281
  docker.manifest_inspect(node_conf["docker_repo"], verbose)
@@ -276,6 +284,9 @@ def config(
276
284
  docker.tag("hello-world:linux", node_conf["docker_repo"], verbose)
277
285
  docker.push(node_conf["docker_repo"], verbose)
278
286
  nodes_config[node] = node_conf
287
+ elif provider == "aws":
288
+ if volume is not None:
289
+ node_conf["volume"] = volume
279
290
 
280
291
  store_config(NODES_PATH, nodes_config)
281
292
 
@@ -61,7 +61,7 @@ def test(ctx, local, command, verbose):
61
61
  ctx.ensure_object(dict)
62
62
  model = ctx.obj["model"]
63
63
  node = model["name"]
64
- is_signals = model["is_signals"]
64
+ tournament = model["tournament"]
65
65
  node_config = load_or_init_nodes(node)
66
66
  provider = node_config["provider"]
67
67
 
@@ -143,7 +143,6 @@ def test(ctx, local, command, verbose):
143
143
  variables={"modelId": node_config["model_id"]},
144
144
  authorization=True,
145
145
  )
146
- tournament = TOURNAMENT_SIGNALS if is_signals else TOURNAMENT_NUMERAI
147
146
  curr_round = api.get_current_round(tournament)
148
147
  latest_subs = sorted(
149
148
  filter(
@@ -338,7 +337,7 @@ def get_recent_task_status_aws(cluster_arn, ecs_client, node, trigger_id):
338
337
  "red",
339
338
  )
340
339
  elif matched_task["lastStatus"] in stopped_codes:
341
- return matched_task, True, "Job execution succeeded!\r", "green"
340
+ return matched_task, True, "Job execution finished!\r", "green"
342
341
  elif matched_task["lastStatus"] in pending_codes:
343
342
  return matched_task, False, "Waiting for job to start...", "yellow"
344
343
  elif matched_task["lastStatus"] in running_codes:
@@ -166,9 +166,16 @@ def build(node_config, node, verbose):
166
166
  build_arg_str += f" --build-arg NODE={node}"
167
167
 
168
168
  cmd = (
169
- f'docker build --platform=linux/amd64 -t {node_config["docker_repo"]}' f"{build_arg_str} -f {path}/Dockerfile ."
169
+ f'docker build --platform=linux/amd64 --load -t {node_config["docker_repo"]}'
170
+ f"{build_arg_str} -f {path}/Dockerfile ."
170
171
  )
171
- execute(cmd, verbose)
172
+ stdout, stderr = execute(cmd, verbose)
173
+ if "unknown flag: --load" in (stdout.decode() + stderr.decode()):
174
+ click.secho(
175
+ "Docker version too old, please upgrade to at least 18.09",
176
+ fg="red",
177
+ )
178
+ exit(1)
172
179
 
173
180
 
174
181
  def run(node_config, verbose, command=""):
@@ -181,7 +188,9 @@ def login(node_config, verbose):
181
188
  username, password = login_aws()
182
189
  login_url = node_config['docker_repo']
183
190
  elif node_config["provider"] == PROVIDER_AZURE:
184
- username, password = login_azure(node_config["registry_rg_name"], node_config["registry_name"])
191
+ username, password = login_azure(
192
+ node_config["registry_rg_name"], node_config["registry_name"]
193
+ )
185
194
  login_url = node_config['docker_repo']
186
195
  elif node_config["provider"] == PROVIDER_GCP:
187
196
  username, password = login_gcp()
@@ -214,17 +223,23 @@ def login_aws():
214
223
  )
215
224
 
216
225
  token = ecr_client.get_authorization_token() # TODO: use registryIds
217
- username, password = base64.b64decode(token["authorizationData"][0]["authorizationToken"]).decode().split(":")
226
+ username, password = (
227
+ base64.b64decode(token["authorizationData"][0]["authorizationToken"])
228
+ .decode()
229
+ .split(":")
230
+ )
218
231
 
219
232
  return username, password
220
233
 
221
234
 
222
235
  def login_azure(resource_group_name, registry_name):
223
236
  azure_subs_id, azure_client, azure_tenant, azure_secret = get_azure_keys()
224
- credentials = ClientSecretCredential(client_id=azure_client, tenant_id=azure_tenant, client_secret=azure_secret)
225
- username_password = ContainerRegistryManagementClient(credentials, azure_subs_id).registries.list_credentials(
226
- resource_group_name, registry_name
237
+ credentials = ClientSecretCredential(
238
+ client_id=azure_client, tenant_id=azure_tenant, client_secret=azure_secret
227
239
  )
240
+ username_password = ContainerRegistryManagementClient(
241
+ credentials, azure_subs_id
242
+ ).registries.list_credentials(resource_group_name, registry_name)
228
243
  username = username_password.username
229
244
  password = username_password.passwords[0].value
230
245
  return username, password
@@ -288,24 +303,32 @@ def cleanup_aws(docker_repo):
288
303
 
289
304
  docker_repo_name = docker_repo.split("/")[-1]
290
305
 
291
- resp = ecr_client.list_images(repositoryName=docker_repo_name, filter={"tagStatus": "UNTAGGED"})
306
+ resp = ecr_client.list_images(
307
+ repositoryName=docker_repo_name, filter={"tagStatus": "UNTAGGED"}
308
+ )
292
309
 
293
310
  imageIds = resp["imageIds"]
294
311
  if len(imageIds) == 0:
295
312
  return []
296
313
 
297
- resp = ecr_client.batch_delete_image(repositoryName=docker_repo_name, imageIds=imageIds)
314
+ resp = ecr_client.batch_delete_image(
315
+ repositoryName=docker_repo_name, imageIds=imageIds
316
+ )
298
317
 
299
318
  return resp["imageIds"]
300
319
 
301
320
 
302
321
  def cleanup_azure(node_config):
303
322
  _, azure_client, azure_tenant, azure_secret = get_azure_keys()
304
- credentials = ClientSecretCredential(client_id=azure_client, tenant_id=azure_tenant, client_secret=azure_secret)
323
+ credentials = ClientSecretCredential(
324
+ client_id=azure_client, tenant_id=azure_tenant, client_secret=azure_secret
325
+ )
305
326
  acr_client = ContainerRegistryClient(node_config["acr_login_server"], credentials)
306
327
  docker_repo = node_config["docker_repo"]
307
328
  node_repo_name = [
308
- repo_name for repo_name in acr_client.list_repository_names() if repo_name == docker_repo.split("/")[-1]
329
+ repo_name
330
+ for repo_name in acr_client.list_repository_names()
331
+ if repo_name == docker_repo.split("/")[-1]
309
332
  ][0]
310
333
 
311
334
  # get all manifests, ordered by last update time
@@ -318,7 +341,9 @@ def cleanup_azure(node_config):
318
341
  # Remove all but the latest manifest
319
342
  removed_manifests = []
320
343
  for manifest in manifest_list[1:]:
321
- acr_client.update_manifest_properties(node_repo_name, manifest.digest, can_write=True, can_delete=True)
344
+ acr_client.update_manifest_properties(
345
+ node_repo_name, manifest.digest, can_write=True, can_delete=True
346
+ )
322
347
  removed_manifests.append(manifest.digest)
323
348
  acr_client.delete_manifest(node_repo_name, manifest.digest)
324
349
  return removed_manifests
@@ -4,9 +4,9 @@ FROM python:3.9
4
4
  # These are docker arguments that `numerai node deploy/test` will always pass into docker.
5
5
  # They are then set in your environment so that numerapi can access them when uploading submissions.
6
6
  # You can also access them from your script like so:
7
- # import os
8
- # public_id = os.environ["NUMERAI_PUBLIC_ID"]
9
- # secret_key = os.environ["NUMERAI_SECRET_KEY"]
7
+ # import os
8
+ # public_id = os.environ["NUMERAI_PUBLIC_ID"]
9
+ # secret_key = os.environ["NUMERAI_SECRET_KEY"]
10
10
  ARG NUMERAI_PUBLIC_ID
11
11
  ENV NUMERAI_PUBLIC_ID=$NUMERAI_PUBLIC_ID
12
12
 
@@ -0,0 +1,105 @@
1
+ """ Sample tournament model in python 3 """
2
+
3
+ import os
4
+ import json
5
+ import logging
6
+ import joblib
7
+ import numerapi
8
+ import pandas as pd
9
+ import lightgbm as lgbm
10
+
11
+ logging.basicConfig(filename="log.txt", filemode="a")
12
+
13
+ TOURNAMENT = 12
14
+ DATA_VERSION = "crypto/v1.0"
15
+ TRAINED_MODEL_PREFIX = "./trained_model"
16
+
17
+ DEFAULT_MODEL_ID = None
18
+ DEFAULT_PUBLIC_ID = None
19
+ DEFAULT_SECRET_KEY = None
20
+
21
+ # Read model id and initialize API client with api keys
22
+ # these are set by the docker image that you deploy after training,
23
+ # but you can also set them manually above for local testing
24
+ MODEL_ID = os.getenv("MODEL_ID", DEFAULT_MODEL_ID)
25
+ napi = numerapi.NumerAPI(
26
+ public_id=os.getenv("NUMERAI_PUBLIC_ID", DEFAULT_PUBLIC_ID),
27
+ secret_key=os.getenv("NUMERAI_SECRET_KEY", DEFAULT_SECRET_KEY),
28
+ )
29
+
30
+
31
+ def train(napi, model_id, force_training=False):
32
+ model_name = TRAINED_MODEL_PREFIX
33
+ if model_id:
34
+ model_name += f"_{model_id}"
35
+
36
+ # load a model if we have a trained model already and we aren't forcing a training session
37
+ if os.path.exists(model_name) and not force_training:
38
+ logging.info("loading existing trained model")
39
+ model = joblib.load(model_name)
40
+ return model
41
+
42
+ logging.info("reading training data")
43
+ napi.download_dataset(f"{DATA_VERSION}/train_targets.parquet")
44
+ target = pd.read_parquet(f"{DATA_VERSION}/train_targets.parquet")
45
+
46
+ # TODO: implement get_features and train a model
47
+ # This will take a few minutes 🍵
48
+ # logging.info("training model")
49
+ # model = lgbm.LGBMRegressor(
50
+ # n_estimators=2000,
51
+ # learning_rate=0.01,
52
+ # max_depth=5,
53
+ # num_leaves=2**5-1,
54
+ # colsample_bytree=0.1
55
+ # )
56
+ # model.fit(
57
+ # train_data[feature_cols],
58
+ # train_data["target"]
59
+ # )
60
+
61
+ # logging.info("saving model")
62
+ # joblib.dump(model, model_name)
63
+ # return model
64
+
65
+ # just return the target for now
66
+ return target
67
+
68
+
69
+ def predict(napi, model):
70
+ logging.info("reading prediction data")
71
+ napi.download_dataset(f"{DATA_VERSION}/live_universe.parquet")
72
+ live_universe = pd.read_parquet(f"{DATA_VERSION}/live_universe.parquet")
73
+
74
+ # TODO: implement get_features and predict the target
75
+ # logging.info("generating predictions")
76
+ # predictions = model.predict(get_features(live_universe))
77
+ # predictions = pd.DataFrame(
78
+ # predictions, columns=["prediction"], index=predict_data.index
79
+ # )
80
+ # return predictions
81
+
82
+ # just return the latest target for now
83
+ napi.download_dataset(f"{DATA_VERSION}/train_targets.parquet")
84
+ target = pd.read_parquet(f"{DATA_VERSION}/train_targets.parquet")
85
+ return (
86
+ target[target.date == target.date.max()]
87
+ .drop(columns=["date"])
88
+ .rename(columns={"target": "prediction"})
89
+ .set_index("symbol")
90
+ )
91
+
92
+
93
+ def submit(predictions, predict_output_path="predictions.csv", model_id=None):
94
+ logging.info("writing predictions to file and submitting")
95
+ include_index = predictions.index.name is not None
96
+ predictions.to_csv(predict_output_path, index=include_index)
97
+ napi.upload_predictions(
98
+ predict_output_path, model_id=model_id, tournament=TOURNAMENT
99
+ )
100
+
101
+
102
+ if __name__ == "__main__":
103
+ trained_model = train(napi, MODEL_ID)
104
+ predictions = predict(napi, trained_model)
105
+ submit(predictions, model_id=MODEL_ID)
@@ -0,0 +1,5 @@
1
+ numerapi==2.14.0
2
+ pandas==2.1.3
3
+ pyarrow==7.0.0
4
+ joblib==1.2.0
5
+ lightgbm==3.3.1
@@ -1,12 +1,12 @@
1
1
  # Provides us a working Python 3 environment.
2
- FROM python:3.7
2
+ FROM python:3.9
3
3
 
4
4
  # These are docker arguments that `numerai node deploy/test` will always pass into docker.
5
5
  # They are then set in your environment so that numerapi can access them when uploading submissions.
6
6
  # You can also access them from your script like so:
7
- # import os
8
- # public_id = os.environ["NUMERAI_PUBLIC_ID"]
9
- # secret_key = os.environ["NUMERAI_SECRET_KEY"]
7
+ # import os
8
+ # public_id = os.environ["NUMERAI_PUBLIC_ID"]
9
+ # secret_key = os.environ["NUMERAI_SECRET_KEY"]
10
10
  ARG NUMERAI_PUBLIC_ID
11
11
  ENV NUMERAI_PUBLIC_ID=$NUMERAI_PUBLIC_ID
12
12
 
@@ -0,0 +1,104 @@
1
+ """ Sample tournament model in python 3 """
2
+
3
+ import os
4
+ import json
5
+ import logging
6
+ import joblib
7
+ import numerapi
8
+ import pandas as pd
9
+ import lightgbm as lgbm
10
+
11
+ logging.basicConfig(filename="log.txt", filemode="a")
12
+
13
+ TOURNAMENT = 11
14
+ DATA_VERSION = "signals/v1.0"
15
+ TARGET_COL = "target"
16
+ TRAINED_MODEL_PREFIX = "./trained_model"
17
+
18
+ DEFAULT_MODEL_ID = None
19
+ DEFAULT_PUBLIC_ID = None
20
+ DEFAULT_SECRET_KEY = None
21
+
22
+ # Read model id and initialize API client with api keys
23
+ # these are set by the docker image that you deploy after training,
24
+ # but you can also set them manually above for local testing
25
+ MODEL_ID = os.getenv("MODEL_ID", DEFAULT_MODEL_ID)
26
+ napi = numerapi.NumerAPI(
27
+ public_id=os.getenv("NUMERAI_PUBLIC_ID", DEFAULT_PUBLIC_ID),
28
+ secret_key=os.getenv("NUMERAI_SECRET_KEY", DEFAULT_SECRET_KEY),
29
+ )
30
+
31
+
32
+ def train(napi, model_id, force_training=False):
33
+ model_name = TRAINED_MODEL_PREFIX
34
+ if model_id:
35
+ model_name += f"_{model_id}"
36
+
37
+ # load a model if we have a trained model already and we aren't forcing a training session
38
+ if os.path.exists(model_name) and not force_training:
39
+ logging.info("loading existing trained model")
40
+ model = joblib.load(model_name)
41
+ return model
42
+
43
+ logging.info("reading training data")
44
+ napi.download_dataset(f"{DATA_VERSION}/train.parquet")
45
+ train_data = pd.read_parquet(f"{DATA_VERSION}/train.parquet")
46
+ feature_cols = [
47
+ col
48
+ for col in train_data.columns
49
+ if col.startswith('feature_')
50
+ and col not in ("feature_country", "feature_exchange_code")
51
+ ]
52
+
53
+ # This will take a few minutes 🍵
54
+ logging.info("training model")
55
+ model = lgbm.LGBMRegressor(
56
+ n_estimators=2000,
57
+ learning_rate=0.01,
58
+ max_depth=5,
59
+ num_leaves=2**5 - 1,
60
+ colsample_bytree=0.1,
61
+ )
62
+ model.fit(train_data[feature_cols], train_data["target"])
63
+
64
+ logging.info("saving model")
65
+ joblib.dump(model, model_name)
66
+ return model
67
+
68
+
69
+ def predict(napi, model):
70
+ logging.info("reading prediction data")
71
+ napi.download_dataset(f"{DATA_VERSION}/live.parquet")
72
+ predict_data = pd.read_parquet(f"{DATA_VERSION}/live.parquet").set_index(
73
+ 'numerai_ticker'
74
+ )
75
+ feature_cols = [
76
+ col
77
+ for col in predict_data.columns
78
+ if col.startswith('feature_')
79
+ and col not in ("feature_country", "feature_exchange_code")
80
+ ]
81
+ print(predict_data)
82
+
83
+ logging.info("generating predictions")
84
+ predictions = model.predict(predict_data[feature_cols])
85
+ predictions = pd.DataFrame(
86
+ predictions, columns=["prediction"], index=predict_data.index
87
+ )
88
+ return predictions
89
+
90
+
91
+ def submit(predictions, predict_output_path="predictions.csv", model_id=None):
92
+ logging.info("writing predictions to file and submitting")
93
+ include_index = predictions.index.name is not None
94
+ predictions.to_csv(predict_output_path, index=include_index)
95
+ print(predictions)
96
+ napi.upload_predictions(
97
+ predict_output_path, model_id=model_id, tournament=TOURNAMENT
98
+ )
99
+
100
+
101
+ if __name__ == "__main__":
102
+ trained_model = train(napi, MODEL_ID)
103
+ predictions = predict(napi, trained_model)
104
+ submit(predictions, model_id=MODEL_ID)
@@ -0,0 +1,5 @@
1
+ numerapi==2.14.0
2
+ pandas==2.1.3
3
+ pyarrow==7.0.0
4
+ joblib==1.2.0
5
+ lightgbm==3.3.1
@@ -0,0 +1,35 @@
1
+ # Provides us a working Python 3 environment.
2
+ FROM python:3.9
3
+
4
+ # These are docker arguments that `numerai node deploy/test` will always pass into docker.
5
+ # They are then set in your environment so that numerapi can access them when uploading submissions.
6
+ # You can also access them from your script like so:
7
+ # import os
8
+ # public_id = os.environ["NUMERAI_PUBLIC_ID"]
9
+ # secret_key = os.environ["NUMERAI_SECRET_KEY"]
10
+ ARG NUMERAI_PUBLIC_ID
11
+ ENV NUMERAI_PUBLIC_ID=$NUMERAI_PUBLIC_ID
12
+
13
+ ARG NUMERAI_SECRET_KEY
14
+ ENV NUMERAI_SECRET_KEY=$NUMERAI_SECRET_KEY
15
+
16
+ ARG MODEL_ID
17
+ ENV MODEL_ID=$MODEL_ID
18
+
19
+ ARG SRC_PATH
20
+ ENV SRC_PATH=$SRC_PATH
21
+
22
+ # We then add the requirements.txt file, and pip install every requirement from it.
23
+ # The `ADD [source] [destination]` command will take a file from the source directory on your computer
24
+ # and copy it over to the destination directory in the Docker container.
25
+ ADD $SRC_PATH/requirements.txt .
26
+ RUN pip install -r requirements.txt --no-cache-dir
27
+
28
+ # Now, add everything in the source code directory.
29
+ # (including your code, compiled files, serialized models, everything...)
30
+ ADD $SRC_PATH .
31
+
32
+ # This sets the default command to run your docker container.
33
+ # It runs by default in the cloud and when running `numerai node test`.
34
+ # This is overridden when using `numerai node test --command [COMMAND]`.
35
+ CMD [ "python", "./predict.py" ]
@@ -6,10 +6,11 @@ import logging
6
6
  import joblib
7
7
  import numerapi
8
8
  import pandas as pd
9
- from sklearn.linear_model import LinearRegression
9
+ import lightgbm as lgbm
10
10
 
11
11
  logging.basicConfig(filename="log.txt", filemode="a")
12
12
 
13
+ TOURNAMENT = 8
13
14
  DATA_VERSION = "v4.1"
14
15
  ERA_COL = "era"
15
16
  DATA_TYPE_COL = "data_type"
@@ -52,18 +53,24 @@ def train(napi, model_id, force_training=False):
52
53
  model = joblib.load(model_name)
53
54
  return model
54
55
 
55
- model = LinearRegression()
56
-
57
56
  logging.info("reading training data")
58
57
  napi.download_dataset(f"{DATA_VERSION}/train.parquet")
59
58
  train_data = pd.read_parquet(
60
59
  f"{DATA_VERSION}/train.parquet", columns=get_features(napi)
61
60
  )
62
61
 
62
+ # This will take a few minutes 🍵
63
63
  logging.info("training model")
64
+ model = lgbm.LGBMRegressor(
65
+ n_estimators=2000,
66
+ learning_rate=0.01,
67
+ max_depth=5,
68
+ num_leaves=2**5 - 1,
69
+ colsample_bytree=0.1,
70
+ )
64
71
  model.fit(
65
- X=train_data.filter(like="feature_", axis="columns"),
66
- y=train_data[TARGET_COL],
72
+ train_data.filter(like="feature_", axis="columns"),
73
+ train_data[TARGET_COL],
67
74
  )
68
75
 
69
76
  logging.info("saving model")
@@ -88,8 +95,11 @@ def predict(napi, model):
88
95
 
89
96
  def submit(predictions, predict_output_path="predictions.csv", model_id=None):
90
97
  logging.info("writing predictions to file and submitting")
91
- predictions.to_csv(predict_output_path)
92
- napi.upload_predictions(predict_output_path, model_id=model_id)
98
+ include_index = predictions.index.name is not None
99
+ predictions.to_csv(predict_output_path, index=include_index)
100
+ napi.upload_predictions(
101
+ predict_output_path, model_id=model_id, tournament=TOURNAMENT
102
+ )
93
103
 
94
104
 
95
105
  if __name__ == "__main__":
@@ -0,0 +1,5 @@
1
+ numerapi==2.14.0
2
+ pandas==2.1.3
3
+ pyarrow==7.0.0
4
+ joblib==1.2.0
5
+ lightgbm==3.3.1
@@ -0,0 +1,10 @@
1
+ """ An extra entry point specifically for training. Used when running locally """
2
+
3
+ import predict
4
+
5
+ train_data_path, predict_data_path, predict_output_path = predict.download_data()
6
+
7
+ model_id = predict.MODEL_ID
8
+ model_type = predict.MODEL
9
+
10
+ predict.train(train_data_path, model_id, model_type, force_training=True)