Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 11 additions & 20 deletions .github/workflows/test-and-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,24 @@ on:
concurrency: deploy-numerai-cli-${{ github.ref }}

jobs:
build-python36:
name: Build Python 3.6
runs-on: ubuntu-20.04
build-python:
name: Build Python ${{ matrix.python-version }}
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v4
with:
python-version: "3.6.15"
- run: pip install .
- run: numerai copy-example
- run: test -e tournament-python3/predict.py

build-python37:
name: Build Python 3.7
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v4
with:
python-version: "3.7.9"
python-version: ${{ matrix.python-version }}
- run: pip install .
- run: numerai copy-example
- run: test -e tournament-python3/predict.py

build-docker:
name: Build Docker
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: |
Expand All @@ -44,14 +35,14 @@ jobs:

pypi-release:
name: PyPI Release
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
needs: [build-python36, build-python37, build-docker]
needs: [build-python, build-docker]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v4
with:
python-version: "3.7.9"
python-version: "3.12"
- run: pip install twine wheel
- run: python setup.py sdist bdist_wheel
- run: |
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,7 @@ terraform.tfstate*

.idea/
.DS_STORE

tournament-python*/
signals-python*/
crypto-python*/
2 changes: 1 addition & 1 deletion numerai/cli/destroy_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def destroy_all(ctx, verbose, preserve_node_config):
verbose,
provider,
env_vars=provider_keys,
inputs={"node_config_file": "nodes.json"},
inputs={"node_config_file": "../nodes.json"},
)

except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion numerai/cli/node/destroy.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def destroy(ctx, preserve_node_config, verbose):
verbose,
provider,
env_vars=provider_keys,
inputs={"node_config_file": "nodes.json"},
inputs={"node_config_file": "../nodes.json"},
)

except Exception as e:
Expand Down
2 changes: 1 addition & 1 deletion numerai/cli/uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def uninstall():
provider=provider,
verbose=True,
env_vars=provider_keys,
inputs={"node_config_file": "nodes.json"},
inputs={"node_config_file": "../nodes.json"},
)

click.secho("cleaning up docker images...")
Expand Down
2 changes: 1 addition & 1 deletion numerai/cli/upgrade.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def upgrade(verbose):
verbose,
provider="aws",
env_vars=load_or_init_keys("aws"),
inputs={"node_config_file": "nodes.json"},
inputs={"node_config_file": "../nodes.json"},
)

click.secho("Upgrade complete!", fg="green")
Expand Down
12 changes: 12 additions & 0 deletions numerai/cli/util/debug.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,18 @@ def root_cause(std_out, err_msg):
"mode: https://docs.docker.com/engine/security/rootless/"
)

if (
"RepositoryAlreadyExistsException" in all_logs
or "EntityAlreadyExists" in all_logs
or "ResourceAlreadyExistsException" in all_logs
):
raise exception_with_msg(
"AWS resources with the names this node expects already exist in your account, "
"but they are not tracked in the current local Terraform state. "
"This usually happens after a partial previous apply. "
"Delete or import the existing AWS resources shown above, then retry."
)

# these are non-errors that either shouldn't be handled or are handled elsewhere
if b"Can't update submission after deadline" in err_msg:
return
Expand Down
1 change: 0 additions & 1 deletion numerai/cli/util/docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ def execute(command, verbose, censor_substr=None):
shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=1,
close_fds=on_posix,
)
stdout_q = Queue()
Expand Down
8 changes: 4 additions & 4 deletions numerai/cli/util/terraform.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def apply_terraform(nodes_config, affected_providers, provider, verbose):
verbose,
affected_provider,
env_vars=load_or_init_keys(affected_provider),
inputs={"node_config_file": "nodes.json"},
inputs={"node_config_file": "../nodes.json"},
)
else:
click.secho(f"provider {affected_provider} not supported", fg="red")
Expand Down Expand Up @@ -51,7 +51,7 @@ def create_azure_registry(provider, provider_keys, verbose):
verbose,
"azure",
env_vars=provider_keys,
inputs={"node_config_file": "nodes.json"},
inputs={"node_config_file": "../nodes.json"},
)
res = terraform("output -json acr_repo_details", True, provider).decode("utf-8")
return json.loads(res)
Expand All @@ -64,13 +64,13 @@ def create_gcp_registry(provider, verbose):
'apply -target="google_project_service.cloud_resource_manager" -auto-approve ',
verbose,
"gcp",
inputs={"node_config_file": "nodes.json"},
inputs={"node_config_file": "../nodes.json"},
)
terraform(
'apply -target="google_artifact_registry_repository.registry[0]" -auto-approve ',
verbose,
"gcp",
inputs={"node_config_file": "nodes.json"},
inputs={"node_config_file": "../nodes.json"},
)
res = terraform("output -json artifact_registry_details", True, provider).decode(
"utf-8"
Expand Down
2 changes: 1 addition & 1 deletion numerai/examples/crypto-python3/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Provides us a working Python 3 environment.
FROM python:3.9
FROM python:3.13

# These are docker arguments that `numerai node deploy/test` will always pass into docker.
# They are then set in your environment so that numerapi can access them when uploading submissions.
Expand Down
78 changes: 30 additions & 48 deletions numerai/examples/crypto-python3/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
logging.basicConfig(filename="log.txt", filemode="a")

TOURNAMENT = 12
DATA_VERSION = "crypto/v1.0"
DATA_VERSION = "crypto/v2.0"
TARGET_COL = "target_binned_return_20"
TRAINED_MODEL_PREFIX = "./trained_model"

DEFAULT_MODEL_ID = None
Expand All @@ -22,7 +23,7 @@
# these are set by the docker image that you deploy after training,
# but you can also set them manually above for local testing
MODEL_ID = os.getenv("MODEL_ID", DEFAULT_MODEL_ID)
napi = numerapi.NumerAPI(
napi = numerapi.CryptoAPI(
public_id=os.getenv("NUMERAI_PUBLIC_ID", DEFAULT_PUBLIC_ID),
secret_key=os.getenv("NUMERAI_SECRET_KEY", DEFAULT_SECRET_KEY),
)
Expand All @@ -40,63 +41,44 @@ def train(napi, model_id, force_training=False):
return model

logging.info("reading training data")
napi.download_dataset(f"{DATA_VERSION}/train_targets.parquet")
target = pd.read_parquet(f"{DATA_VERSION}/train_targets.parquet")

# TODO: implement get_features and train a model
# This will take a few minutes 🍵
# logging.info("training model")
# model = lgbm.LGBMRegressor(
# n_estimators=2000,
# learning_rate=0.01,
# max_depth=5,
# num_leaves=2**5-1,
# colsample_bytree=0.1
# )
# model.fit(
# train_data[feature_cols],
# train_data["target"]
# )

# logging.info("saving model")
# joblib.dump(model, model_name)
# return model

# just return the target for now
return target
napi.download_dataset(f"{DATA_VERSION}/train.parquet")
train_data = pd.read_parquet(f"{DATA_VERSION}/train.parquet")
feature_cols = [col for col in train_data.columns if col.startswith("feature_")]

logging.info("training model")
model = lgbm.LGBMRegressor(
n_estimators=2000,
learning_rate=0.01,
max_depth=5,
num_leaves=2**5 - 1,
colsample_bytree=0.1,
)
model.fit(train_data[feature_cols], train_data[TARGET_COL])

logging.info("saving model")
joblib.dump(model, model_name)
return model


def predict(napi, model):
logging.info("reading prediction data")
napi.download_dataset(f"{DATA_VERSION}/live_universe.parquet")
live_universe = pd.read_parquet(f"{DATA_VERSION}/live_universe.parquet")

# TODO: implement get_features and predict the target
# logging.info("generating predictions")
# predictions = model.predict(get_features(live_universe))
# predictions = pd.DataFrame(
# predictions, columns=["prediction"], index=predict_data.index
# )
# return predictions

# just return the latest target for now
napi.download_dataset(f"{DATA_VERSION}/train_targets.parquet")
target = pd.read_parquet(f"{DATA_VERSION}/train_targets.parquet")
return (
target[target.date == target.date.max()]
.drop(columns=["date"])
.rename(columns={"target": "prediction"})
.set_index("symbol")
napi.download_dataset(f"{DATA_VERSION}/live.parquet")
predict_data = pd.read_parquet(f"{DATA_VERSION}/live.parquet")
feature_cols = [col for col in predict_data.columns if col.startswith("feature_")]

logging.info("generating predictions")
predictions = model.predict(predict_data[feature_cols])
predictions = pd.DataFrame(
predictions, columns=["prediction"], index=predict_data.index
)
return predictions


def submit(predictions, predict_output_path="predictions.csv", model_id=None):
logging.info("writing predictions to file and submitting")
include_index = predictions.index.name is not None
predictions.to_csv(predict_output_path, index=include_index)
napi.upload_predictions(
predict_output_path, model_id=model_id, tournament=TOURNAMENT
)
napi.upload_predictions(predict_output_path, model_id=model_id)


if __name__ == "__main__":
Expand Down
11 changes: 6 additions & 5 deletions numerai/examples/crypto-python3/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
numerapi==2.14.0
pandas==2.1.3
pyarrow==7.0.0
joblib==1.2.0
lightgbm==3.3.1
numerapi==2.22.0
pandas==2.3.3
pyarrow==18.1.0
joblib==1.5.3
lightgbm==4.5.0
scikit-learn==1.6.1
2 changes: 1 addition & 1 deletion numerai/examples/signals-python3/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Provides us a working Python 3 environment.
FROM python:3.9
FROM python:3.13

# These are docker arguments that `numerai node deploy/test` will always pass into docker.
# They are then set in your environment so that numerapi can access them when uploading submissions.
Expand Down
8 changes: 3 additions & 5 deletions numerai/examples/signals-python3/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
logging.basicConfig(filename="log.txt", filemode="a")

TOURNAMENT = 11
DATA_VERSION = "signals/v1.0"
DATA_VERSION = "signals/v2.0"
TARGET_COL = "target"
TRAINED_MODEL_PREFIX = "./trained_model"

Expand All @@ -23,7 +23,7 @@
# these are set by the docker image that you deploy after training,
# but you can also set them manually above for local testing
MODEL_ID = os.getenv("MODEL_ID", DEFAULT_MODEL_ID)
napi = numerapi.NumerAPI(
napi = numerapi.SignalsAPI(
public_id=os.getenv("NUMERAI_PUBLIC_ID", DEFAULT_PUBLIC_ID),
secret_key=os.getenv("NUMERAI_SECRET_KEY", DEFAULT_SECRET_KEY),
)
Expand Down Expand Up @@ -93,9 +93,7 @@ def submit(predictions, predict_output_path="predictions.csv", model_id=None):
include_index = predictions.index.name is not None
predictions.to_csv(predict_output_path, index=include_index)
print(predictions)
napi.upload_predictions(
predict_output_path, model_id=model_id, tournament=TOURNAMENT
)
napi.upload_predictions(predict_output_path, model_id=model_id)


if __name__ == "__main__":
Expand Down
11 changes: 6 additions & 5 deletions numerai/examples/signals-python3/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
numerapi==2.14.0
pandas==2.1.3
pyarrow==7.0.0
joblib==1.2.0
lightgbm==3.3.1
numerapi==2.22.0
pandas==2.3.3
pyarrow==18.1.0
joblib==1.5.3
lightgbm==4.5.0
scikit-learn==1.6.1
2 changes: 1 addition & 1 deletion numerai/examples/tournament-python3/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Provides us a working Python 3 environment.
FROM python:3.9
FROM python:3.13

# These are docker arguments that `numerai node deploy/test` will always pass into docker.
# They are then set in your environment so that numerapi can access them when uploading submissions.
Expand Down
18 changes: 6 additions & 12 deletions numerai/examples/tournament-python3/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,9 @@
logging.basicConfig(filename="log.txt", filemode="a")

TOURNAMENT = 8
DATA_VERSION = "v4.1"
DATA_VERSION = "v5.2"
ERA_COL = "era"
DATA_TYPE_COL = "data_type"
TARGET_COL = "target_nomi_v4_20"
TARGET_COL = "target"
TRAINED_MODEL_PREFIX = "./trained_model"

DEFAULT_MODEL_ID = None
Expand All @@ -35,11 +34,7 @@ def get_features(napi):
napi.download_dataset(f"{DATA_VERSION}/features.json")
with open(f"{DATA_VERSION}/features.json", "r") as f:
feature_metadata = json.load(f)
return feature_metadata["feature_sets"]["small"] + [
ERA_COL,
DATA_TYPE_COL,
TARGET_COL,
]
return feature_metadata["feature_sets"]["small"]


def train(napi, model_id, force_training=False):
Expand All @@ -56,7 +51,8 @@ def train(napi, model_id, force_training=False):
logging.info("reading training data")
napi.download_dataset(f"{DATA_VERSION}/train.parquet")
train_data = pd.read_parquet(
f"{DATA_VERSION}/train.parquet", columns=get_features(napi)
f"{DATA_VERSION}/train.parquet",
columns=[ERA_COL] + get_features(napi) + [TARGET_COL],
)

# This will take a few minutes 🍵
Expand Down Expand Up @@ -97,9 +93,7 @@ def submit(predictions, predict_output_path="predictions.csv", model_id=None):
logging.info("writing predictions to file and submitting")
include_index = predictions.index.name is not None
predictions.to_csv(predict_output_path, index=include_index)
napi.upload_predictions(
predict_output_path, model_id=model_id, tournament=TOURNAMENT
)
napi.upload_predictions(predict_output_path, model_id=model_id)


if __name__ == "__main__":
Expand Down
Loading
Loading