An MCP server that provides on-demand skill loading for AI coding assistants.
BY modbenderUPDATED Oct 28, 2026
INTENDED FOR◈OpenClawInstall in a listed agent.
instructions.md
---
name: numerai-tournament-762d71de587a
description: Autonomous Numerai tournament participation — train models, submit predictions, and earn NMR cryptocurrency.
tags:
- finance
- machine-learning
- cryptocurrency
- trading
- numerai
- lightgbm
- data-science
metadata:
clawdbot:
requires:
env:
- NUMERAI_PUBLIC_ID
- NUMERAI_SECRET_KEY
bins:
- python3
- pip
primaryEnv: NUMERAI_SECRET_KEY
---
# Numerai Tournament
Participate autonomously in the [Numerai](https://numer.ai) data science tournament. Numerai is a hedge fund that crowdsources stock market predictions from data scientists. You submit predictions on obfuscated financial data and earn (or lose) NMR cryptocurrency based on performance.
## Overview
- **What**: Predict stock market returns using obfuscated tabular features
- **How**: Download data, train a model, submit predictions each round
- **Reward**: Stake NMR on predictions; earn or lose based on correlation with targets
- **Frequency**: New rounds open Tue–Sat at 13:00 UTC; scores resolve ~31 days later
## Setup
### 1. Create a Numerai Account
```bash
# Visit https://numer.ai to sign up
# Then create API keys at https://numer.ai/account
# Store credentials:
mkdir -p ~/.numerai
cat > ~/.numerai/credentials.json << 'CREDS'
{
"public_id": "YOUR_PUBLIC_ID",
"secret_key": "YOUR_SECRET_KEY"
}
CREDS
chmod 600 ~/.numerai/credentials.json
```
Alternatively, set environment variables:
```bash
export NUMERAI_PUBLIC_ID="YOUR_PUBLIC_ID"
export NUMERAI_SECRET_KEY="YOUR_SECRET_KEY"
```
### 2. Install Dependencies
```bash
python3 -m venv venv && source venv/bin/activate
pip install numerapi lightgbm pandas numpy cloudpickle scikit-learn
```
On macOS ARM (Apple Silicon), LightGBM also requires:
```bash
brew install libomp
```
### 3. Download Tournament Data
```python
from numerapi import NumerAPI
from pathlib import Path
napi = NumerAPI() # No auth needed for data download
data_dir = Path("data")
data_dir.mkdir(exist_ok=True)
# Current dataset version is v5.2
napi.download_dataset("v5.2/train.parquet", dest_path=str(data_dir / "train.parquet"))
napi.download_dataset("v5.2/validation.parquet", dest_path=str(data_dir / "validation.parquet"))
napi.download_dataset("v5.2/live.parquet", dest_path=str(data_dir / "live.parquet"))
napi.download_dataset("v5.2/features.json", dest_path=str(data_dir / "features.json"))
napi.download_dataset("v5.2/live_benchmark_models.parquet", dest_path=str(data_dir / "live_benchmark_models.parquet"))
```
**Note**: Training data is ~8GB. Only `live.parquet` and `features.json` are needed for prediction.
## Training a Model
The recommended approach is a LightGBM ensemble trained on multiple targets. This provides strong and stable performance.
### Feature Selection
```python
import json
with open("data/features.json") as f:
feature_metadata = json.load(f)
# Three feature set sizes:
# "small" — ~42 features (fast iteration)
# "medium" — ~780 features (good tradeoff)
# "all" — ~2748 features (maximum signal, slow)
features = feature_metadata["feature_sets"]["medium"]
```
### Target Selection
The main target is `target`. Additional targets improve ensemble diversity:
| Target | Description |
|--------|-------------|
| `target` | Primary tournament target |
| `target_teager2b_20` | Current payout-correlated target |
| `target_cyrusd_20` | Complementary target for ensemble diversity |
### LightGBM Training
```python
import lightgbm as lgb
import pandas as pd
import pickle
train = pd.read_parquet("data/train.parquet", columns=["era"] + features + targets)
lgbm_params = {
"n_estimators": 5000, # Use 20000 for production quality
"learning_rate": 0.005,
"max_depth": 6,
"num_leaves": 64,
"min_child_samples": 5000,
"colsample_bytree": 0.1,
"subsample": 0.8,
"subsample_freq": 1,
"reg_alpha": 0.1,
"reg_lambda": 1.0,
"verbose": -1,
"n_jobs": -1,
}
models = {}
for target in targets:
X = train[features]
y = train[target]
mask = y.notna()
model = lgb.LGBMRegressor(**lgbm_params)
model.fit(X[mask], y[mask])
models[target] = model
with open("models/ensemble_models.pkl", "wb") as f:
pickle.dump(models, f)
```
### Validation
Evaluate per-era correlation and Sharpe ratio:
```python
val = pd.read_parquet("data/validation.parquet", columns=["era"] + features + targets)
predictions = pd.DataFrame(index=val.index)
for target, model in models.items():
raw = model.predict(val[features])
predictions[target] = pd.Series(raw, index=val.index).rank(pct=True)
ensemble = predictions.mean(axis=1).rank(pct=True)
corrs = []
for era in val["era"].unique():
m = val["era"] == era
pred_era = ensemble[m]
tgt = val.loc[m, "target"]
if tgt.notna().sum() >= 10:
corrs.append(pred_era.corr(tgt))
corrs = pd.Series(corrs)
print(f"Mean Corr: {corrs.mean():.4f}")
print(f"Sharpe: {corrs.mean() / corrs.std():.2f}")
print(f"% Positive: {(corrs > 0).mean() * 100:.1f}%")
```
Target validation performance: Mean Corr > 0.02, Sharpe > 1.0, >90% positive eras.
## Submitting Predictions
### Option A: Upload a Predictions CSV (Manual)
```python
import json
from numerapi import NumerAPI
with open("~/.numerai/credentials.json") as f:
creds = json.load(f)
napi = NumerAPI(creds["public_id"], creds["secret_key"])
# Check round status
current_round = napi.get_current_round()
is_open = napi.check_round_open()
print(f"Round {current_round}, Open: {is_open}")
if is_open:
# Download live data
napi.download_dataset("v5.2/live.parquet", dest_path="data/live.parquet")
live = pd.read_parquet("data/live.parquet")
# Generate predictions (same ensemble logic as validation)
predictions = pd.DataFrame(index=live.index)
for target, model in models.items():
raw = model.predict(live[features])
predictions[target] = pd.Series(raw, index=live.index).rank(pct=True)
ensemble = predictions.mean(axis=1).rank(pct=True)
# Save and submit
submission = ensemble.to_frame("prediction")
submission.to_csv("predictions.csv")
napi.upload_predictions("predictions.csv", model_id="YOUR_MODEL_ID")
```
### Option B: Upload a Model Pickle (Zero-Maintenance)
Upload a pickled function and Numerai runs it daily — no cron, no server.
**Critical constraints for model upload:**
- Must be a **pickled function** (not a class), loaded via `pd.read_pickle()`
- Must use **Python 3.12** (Numerai's max supported version)
- Must match Numerai runtime packages: `lightgbm==4.5.0`, `numpy==2.1.3`, `pandas==2.3.1`
- Runtime limits: 1 CPU, 4GB RAM, 10 minute timeout
- Use **native LightGBM Boosters** (not sklearn wrappers) to avoid dependency issues
```python
# Build the upload pickle (run with Python 3.12!)
import cloudpickle
import lightgbm as lgb
import pandas as pd
import pickle
# Load trained sklearn models and extract native boosters
with open("models/ensemble_models.pkl", "rb") as f:
sklearn_models = pickle.load(f)
boosters = {}
for name, model in sklearn_models.items():
bstr = model.booster_.model_to_string()
boosters[name] = lgb.Booster(model_str=bstr)
feature_cols = features # medium feature set list
models = boosters
def predict(live_features: pd.DataFrame, live_benchmark_models: pd.DataFrame = None) -> pd.DataFrame:
predictions = pd.DataFrame(index=live_features.index)
for target, booster in models.items():
raw = booster.predict(live_features[feature_cols])
predictions[target] = pd.Series(raw, index=live_features.index).rank(pct=True)
ensemble = predictions.mean(axis=1).rank(pct=True)
return ensemble.to_frame("prediction")
with open("models/model_upload.pkl", "wb") as f:
cloudpickle.dump(predict, f)
```
Then upload via the Numerai web UI at https://numer.ai or via API:
```python
napi.upload_model("models/model_upload.pkl", model_id="YOUR_MODEL_ID")
```
## Checking Performance
```python
from numerapi import NumerAPI
napi = NumerAPI(public_id, secret_key)
# Round status
print(f"Current round: {napi.get_current_round()}")
# Get model performance (scores resolve after ~31 days)
# Check via https://numer.ai/models/YOUR_USERNAME
```
## Tournament Rules & Key Facts
- **Dataset**: v5.2 — obfuscated financial features, ~2748 total features
- **Rounds**: Open Tue–Sat at 13:00 UTC. Weekday windows: ~1hr. Saturday: ~49hrs.
- **Scoring**: 20D2L framework, ~31 day resolution
- **Payout formula**: `stake * clip(payout_factor * (0.75*CORR + 2.25*MMC), -0.05, +0.05)`
- CORR = correlation of predictions with target
- MMC = meta-model contribution (originality bonus)
- **Staking**: Optional — stake NMR to earn/lose based on performance. Start with 0 stake until the model proves consistent.
- **Current payout target**: Resembles `target_teager2b_20`
## Tips for Strong Performance
1. **Ensemble multiple targets** — reduces variance, improves Sharpe
2. **Rank-normalize predictions** — use `.rank(pct=True)` before averaging and after
3. **Use early stopping** — prevent overfitting with `lgb.early_stopping(300)`
4. **Feature neutralization** — improves MMC by decorrelating from common factors
5. **Era-aware validation** — always evaluate per-era, never row-level metrics
6. **Don't overfit to validation** — Numerai data is non-stationary; keep models simple
## External Endpoints
This skill interacts with the following external services:
- `api.numer.ai` — Numerai GraphQL API for round status, submissions, and scores
- `numer.ai` — Data downloads (tournament datasets)
## Security & Privacy
- Your `NUMERAI_PUBLIC_ID` and `NUMERAI_SECRET_KEY` are sent to `api.numer.ai` for authentication
- Predictions (stock return rankings) are uploaded to Numerai's servers
- No other data leaves your machine
- Store credentials in `~/.numerai/credentials.json` with `chmod 600` permissions
---
name: numerai-tournament-762d71de587a
description: Autonomous Numerai tournament participation — train models, submit predictions, and earn NMR cryptocurrency.
tags:
- finance
- machine-learning
- cryptocurrency
- trading
- numerai
- lightgbm
- data-science
metadata:
clawdbot:
requires:
env:
- NUMERAI_PUBLIC_ID
- NUMERAI_SECRET_KEY
bins:
- python3
- pip
primaryEnv: NUMERAI_SECRET_KEY
---
# Numerai Tournament
Participate autonomously in the [Numerai](https://numer.ai) data science tournament. Numerai is a hedge fund that crowdsources stock market predictions from data scientists. You submit predictions on obfuscated financial data and earn (or lose) NMR cryptocurrency based on performance.
## Overview
- **What**: Predict stock market returns using obfuscated tabular features
- **How**: Download data, train a model, submit predictions each round
- **Reward**: Stake NMR on predictions; earn or lose based on correlation with targets
- **Frequency**: New rounds open Tue–Sat at 13:00 UTC; scores resolve ~31 days later
## Setup
### 1. Create a Numerai Account
```bash
# Visit https://numer.ai to sign up
# Then create API keys at https://numer.ai/account
# Store credentials:
mkdir -p ~/.numerai
cat > ~/.numerai/credentials.json << 'CREDS'
{
"public_id": "YOUR_PUBLIC_ID",
"secret_key": "YOUR_SECRET_KEY"
}
CREDS
chmod 600 ~/.numerai/credentials.json
```
Alternatively, set environment variables:
```bash
export NUMERAI_PUBLIC_ID="YOUR_PUBLIC_ID"
export NUMERAI_SECRET_KEY="YOUR_SECRET_KEY"
```
### 2. Install Dependencies
```bash
python3 -m venv venv && source venv/bin/activate
pip install numerapi lightgbm pandas numpy cloudpickle scikit-learn
```
On macOS ARM (Apple Silicon), LightGBM also requires:
```bash
brew install libomp
```
### 3. Download Tournament Data
```python
from numerapi import NumerAPI
from pathlib import Path
napi = NumerAPI() # No auth needed for data download
data_dir = Path("data")
data_dir.mkdir(exist_ok=True)
# Current dataset version is v5.2
napi.download_dataset("v5.2/train.parquet", dest_path=str(data_dir / "train.parquet"))
napi.download_dataset("v5.2/validation.parquet", dest_path=str(data_dir / "validation.parquet"))
napi.download_dataset("v5.2/live.parquet", dest_path=str(data_dir / "live.parquet"))
napi.download_dataset("v5.2/features.json", dest_path=str(data_dir / "features.json"))
napi.download_dataset("v5.2/live_benchmark_models.parquet", dest_path=str(data_dir / "live_benchmark_models.parquet"))
```
**Note**: Training data is ~8GB. Only `live.parquet` and `features.json` are needed for prediction.
## Training a Model
The recommended approach is a LightGBM ensemble trained on multiple targets. This provides strong and stable performance.
### Feature Selection
```python
import json
with open("data/features.json") as f:
feature_metadata = json.load(f)
# Three feature set sizes:
# "small" — ~42 features (fast iteration)
# "medium" — ~780 features (good tradeoff)
# "all" — ~2748 features (maximum signal, slow)
features = feature_metadata["feature_sets"]["medium"]
```
### Target Selection
The main target is `target`. Additional targets improve ensemble diversity:
| Target | Description |
|--------|-------------|
| `target` | Primary tournament target |
| `target_teager2b_20` | Current payout-correlated target |
| `target_cyrusd_20` | Complementary target for ensemble diversity |
### LightGBM Training
```python
import lightgbm as lgb
import pandas as pd
import pickle
train = pd.read_parquet("data/train.parquet", columns=["era"] + features + targets)
lgbm_params = {
"n_estimators": 5000, # Use 20000 for production quality
"learning_rate": 0.005,
"max_depth": 6,
"num_leaves": 64,
"min_child_samples": 5000,
"colsample_bytree": 0.1,
"subsample": 0.8,
"subsample_freq": 1,
"reg_alpha": 0.1,
"reg_lambda": 1.0,
"verbose": -1,
"n_jobs": -1,
}
models = {}
for target in targets:
X = train[features]
y = train[target]
mask = y.notna()
model = lgb.LGBMRegressor(**lgbm_params)
model.fit(X[mask], y[mask])
models[target] = model
with open("models/ensemble_models.pkl", "wb") as f:
pickle.dump(models, f)
```
### Validation
Evaluate per-era correlation and Sharpe ratio:
```python
val = pd.read_parquet("data/validation.parquet", columns=["era"] + features + targets)
predictions = pd.DataFrame(index=val.index)
for target, model in models.items():
raw = model.predict(val[features])
predictions[target] = pd.Series(raw, index=val.index).rank(pct=True)
ensemble = predictions.mean(axis=1).rank(pct=True)
corrs = []
for era in val["era"].unique():
m = val["era"] == era
pred_era = ensemble[m]
tgt = val.loc[m, "target"]
if tgt.notna().sum() >= 10:
corrs.append(pred_era.corr(tgt))
corrs = pd.Series(corrs)
print(f"Mean Corr: {corrs.mean():.4f}")
print(f"Sharpe: {corrs.mean() / corrs.std():.2f}")
print(f"% Positive: {(corrs > 0).mean() * 100:.1f}%")
```
Target validation performance: Mean Corr > 0.02, Sharpe > 1.0, >90% positive eras.
## Submitting Predictions
### Option A: Upload a Predictions CSV (Manual)
```python
import json
from numerapi import NumerAPI
with open("~/.numerai/credentials.json") as f:
creds = json.load(f)
napi = NumerAPI(creds["public_id"], creds["secret_key"])
# Check round status
current_round = napi.get_current_round()
is_open = napi.check_round_open()
print(f"Round {current_round}, Open: {is_open}")
if is_open:
# Download live data
napi.download_dataset("v5.2/live.parquet", dest_path="data/live.parquet")
live = pd.read_parquet("data/live.parquet")
# Generate predictions (same ensemble logic as validation)
predictions = pd.DataFrame(index=live.index)
for target, model in models.items():
raw = model.predict(live[features])
predictions[target] = pd.Series(raw, index=live.index).rank(pct=True)
ensemble = predictions.mean(axis=1).rank(pct=True)
# Save and submit
submission = ensemble.to_frame("prediction")
submission.to_csv("predictions.csv")
napi.upload_predictions("predictions.csv", model_id="YOUR_MODEL_ID")
```
### Option B: Upload a Model Pickle (Zero-Maintenance)
Upload a pickled function and Numerai runs it daily — no cron, no server.
**Critical constraints for model upload:**
- Must be a **pickled function** (not a class), loaded via `pd.read_pickle()`
- Must use **Python 3.12** (Numerai's max supported version)
- Must match Numerai runtime packages: `lightgbm==4.5.0`, `numpy==2.1.3`, `pandas==2.3.1`
- Runtime limits: 1 CPU, 4GB RAM, 10 minute timeout
- Use **native LightGBM Boosters** (not sklearn wrappers) to avoid dependency issues
```python
# Build the upload pickle (run with Python 3.12!)
import cloudpickle
import lightgbm as lgb
import pandas as pd
import pickle
# Load trained sklearn models and extract native boosters
with open("models/ensemble_models.pkl", "rb") as f:
sklearn_models = pickle.load(f)
boosters = {}
for name, model in sklearn_models.items():
bstr = model.booster_.model_to_string()
boosters[name] = lgb.Booster(model_str=bstr)
feature_cols = features # medium feature set list
models = boosters
def predict(live_features: pd.DataFrame, live_benchmark_models: pd.DataFrame = None) -> pd.DataFrame:
predictions = pd.DataFrame(index=live_features.index)
for target, booster in models.items():
raw = booster.predict(live_features[feature_cols])
predictions[target] = pd.Series(raw, index=live_features.index).rank(pct=True)
ensemble = predictions.mean(axis=1).rank(pct=True)
return ensemble.to_frame("prediction")
with open("models/model_upload.pkl", "wb") as f:
cloudpickle.dump(predict, f)
```
Then upload via the Numerai web UI at https://numer.ai or via API:
```python
napi.upload_model("models/model_upload.pkl", model_id="YOUR_MODEL_ID")
```
## Checking Performance
```python
from numerapi import NumerAPI
napi = NumerAPI(public_id, secret_key)
# Round status
print(f"Current round: {napi.get_current_round()}")
# Get model performance (scores resolve after ~31 days)
# Check via https://numer.ai/models/YOUR_USERNAME
```
## Tournament Rules & Key Facts
- **Dataset**: v5.2 — obfuscated financial features, ~2748 total features
- **Rounds**: Open Tue–Sat at 13:00 UTC. Weekday windows: ~1hr. Saturday: ~49hrs.
- **Scoring**: 20D2L framework, ~31 day resolution
- **Payout formula**: `stake * clip(payout_factor * (0.75*CORR + 2.25*MMC), -0.05, +0.05)`
- CORR = correlation of predictions with target
- MMC = meta-model contribution (originality bonus)
- **Staking**: Optional — stake NMR to earn/lose based on performance. Start with 0 stake until the model proves consistent.
- **Current payout target**: Resembles `target_teager2b_20`
## Tips for Strong Performance
1. **Ensemble multiple targets** — reduces variance, improves Sharpe
2. **Rank-normalize predictions** — use `.rank(pct=True)` before averaging and after
3. **Use early stopping** — prevent overfitting with `lgb.early_stopping(300)`
4. **Feature neutralization** — improves MMC by decorrelating from common factors
5. **Era-aware validation** — always evaluate per-era, never row-level metrics
6. **Don't overfit to validation** — Numerai data is non-stationary; keep models simple
## External Endpoints
This skill interacts with the following external services:
- `api.numer.ai` — Numerai GraphQL API for round status, submissions, and scores
- `numer.ai` — Data downloads (tournament datasets)
## Security & Privacy
- Your `NUMERAI_PUBLIC_ID` and `NUMERAI_SECRET_KEY` are sent to `api.numer.ai` for authentication
- Predictions (stock return rankings) are uploaded to Numerai's servers
- No other data leaves your machine
- Store credentials in `~/.numerai/credentials.json` with `chmod 600` permissions
COMPATIBILITY & REFERENCES
Platform guidance
Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.
Database schema design and data modeling patterns including normalization principles (1NF-5NF), denormalization trade-offs, entity relationship design, indexing strategies, schema evolution, and domain-driven design patterns. Activates when designing new database schemas, refactoring data models,...
SQL Server index design and optimization strategies. Use this skill when: (1) User needs help designing indexes, (2) User asks about clustered vs nonclustered indexes, (3) User wants to optimize columnstore indexes, (4) User needs filtered or covering indexes, (5) User asks about index maintenanc...