feat: volatility targets, CZAR loss, and testnet topic examples - #42
feat: volatility targets, CZAR loss, and testnet topic examples#42jefferythewind wants to merge 26 commits into
Conversation
Core library changes: - workflow.py: Add target_type parameter (log_return | volatility) and compute_volatility_target_polars() for std of 1-min log returns - czar_loss.py (new): CZAR directional loss with gradient/hessian for custom LightGBM training — penalizes wrong-sign predictions, softens near-zero returns, normalizes by local volatility - __init__.py: Export czar_loss, czar_gradient, czar_hessian, make_czar_objective Tests: - test_volatility_target.py: 8 tests for volatility target computation Notebooks (example/illustration code): - Reorganize all topic scripts under notebooks/testnet/topic_*/ - Add example scripts for all testnet topics: 38, 41, 42 (8h price), 57, 83, 84 (8h log-return), 61, 62, 63 (24h log-return), 71 (NEAR 8h), 79-82 (15m volatility) - Add CZAR V1 model scripts for 8h price topics (38, 41, 42) - Add dashboard.sh convenience script - Remove notebooks/shared/ — keep deploy scripts at top level Docs: - README: Add topic reference tables, volatility workflow example - AGENTS.md: Fix paths for testnet/ subfolder - .gitignore: Add **/runs/ for training artifacts
The reputer's ground truth applies standardization_ratio = √(timeframe/frequency) to convert per-bar std to horizon volatility. Our compute_volatility_target_polars() was missing this scaling, causing workers to submit values ~√15 ≈ 3.87× too low on 15-minute volatility topics. Fix: multiply rolling std by √target_bars in the target computation. Tests updated to verify the scaling.
Replace 14 separate model variant scripts (model_a through model_e, walkthroughs) with 1 model_grid_retrain.py per volatility topic. The grid retrain script does a systematic search over objectives (MSE, Huber) × log-space × LightGBM hyperparams and saves the top 5 models for deployment. Net reduction: -4,450 lines across vol topics (79, 80, 81, 82).
…lots Replace row-by-row df.apply with vectorized numpy operations for vol feature engineering. 1.15M rows: 40 min → 6 seconds. Also adds scatter plot of predictions vs true values at the end of each grid retrain script to visually confirm predictions are on the correct √T-scaled magnitude.
- model_grid_retrain.py: grid search over objectives × LightGBM hyperparams - model_importance_groups.py: importance-based feature group diversity search - 960 input bars (16h lookback), 240 target bars (4h horizon) - README: add topic 85 to testnet topic reference table
…definitions Move the topic tables from a subsection of "Zero to deploy → Step 5" into a dedicated top-level "## Topic reference" section linked from the TOC. Add a brief definition of log-return, price, and volatility target types above the tables so readers understand what each topic requires before choosing one to work on. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 31 files
Architecture diagram
sequenceDiagram
participant User as Researcher/Dev
participant API as AlloraMLWorkflow API
participant DM as DataManager
participant DF as Polars DataFrame
participant LGB as LightGBM
participant CZAR as CZAR Loss Module
participant WM as WorkerManager
participant ALL as Allora Network
Note over User,ALL: Core Training Flow (Volatility & Log-Return)
User->>API: Initialize with target_type & config
API->>API: Validate target_type (log_return/volatility)
API->>DM: backfill(days, interval)
DM-->>API: Historical OHLCV data
API->>DM: get_full_feature_target_dataframe()
DM->>DF: Build base features + engineered features
alt target_type = "volatility"
DF->>DF: compute_volatility_target_polars()
Note over DF: Shift log returns, forward rolling std<br/>scale by sqrt(target_bars) - matches reputer
DF-->>API: DataFrame with volatility target (non-negative)
else target_type = "log_return"
DF->>DF: compute_target_polars()
Note over DF: log(future_close / current_close)
DF-->>API: DataFrame with log-return target
end
API-->>User: Training-ready DataFrame
Note over User,LGB: Model Training with CZAR Support
User->>CZAR: make_czar_objective(std, alpha)
CZAR->>CZAR: z-score by local volatility
CZAR-->>User: Custom LightGBM objective (grad + hess)
User->>LGB: LGBMRegressor(objective=czar_obj)
LGB->>DF: Fit (features, target)
DF-->>LGB: Trained model
Note over User,WM: Deployment & Live Inference
User->>WM: deploy_worker(topic_id, artifact_path)
WM-->>User: Worker deployed
User->>ALL: Submit predictions (live loop)
ALL->>User: Topic ground truth (for volatility: std of<br/>1-min log returns over horizon)
Note over User,ALL: New topic resources
Note over User: Topic example scripts for price (38/41/42),<br/>log-return (57/61-63/71/83/84),<br/>volatility (79-82/85) topics
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
- Cat B: remove _wf=wf default arg from _make_predict closures in all vol scripts and topic_61; predict() now reconstructs AlloraMLWorkflow from os.environ["ALLORA_API_KEY"] so the API key is not embedded in .pkl artifacts - Cat D: re-indent evaluate/store/print block inside for n_est loop in topic_41 and topic_42 examples (was evaluating only last checkpoint) - Cat H: leave DAYS_OF_HISTORY unchanged (intentional; users can reduce) - Cat I: subtract TARGET_BARS from train split end in all 5 vol grid retrain scripts to add a purge gap and avoid target contamination - Cat J: add missing regularization params (subsample, colsample_bytree, min_child_samples, reg_alpha, reg_lambda) to topic_38 final_model so it matches the CV training configuration - Cat K: no fix — design decision (select on val, evaluate on test, deploy on live) - Cat L: deduplicate by model_num before head(TOP_K_DEPLOY) in topic_79 - Cat M: raise ValueError if current_price is not finite or <= 0 before price multiplication in topic_38 model_v3_methodology - Cat N: no fix — false positive (topic_83 uses 1h bars; closes[-7] = 6h is correct) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 23 files (changes from recent commits).
Tip: instead of fixing issues one by one fix them all with cubic
Re-trigger cubic
The Category B fix made predict() closures reconstruct AlloraMLWorkflow
from os.environ["ALLORA_API_KEY"] at inference time. Training scripts
load the key from .allora_api_key into a local variable but never set
the env var, so the live test call at the end of each script failed
with KeyError. Add os.environ.setdefault("ALLORA_API_KEY", api_key)
immediately after get_api_key() in all 21 affected scripts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add sequential runner script for all 21 testnet example scripts. Ignore generated scatter plots, worker_secrets.json.lock, and one-off continuation runner scripts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 23 files (changes from recent commits).
Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
- README: collapse two-track install banner into a single command now that mainnet has completed the v9 → v10 upgrade - README: remove "testnet" qualifier from faucet description - WorkerManager, WorkerMonitor, AlloraTopicDiscovery, worker_runtime: default network to ALLORA_NETWORK env var (fallback "testnet") so users can deploy to mainnet with ALLORA_NETWORK=mainnet without modifying code - worker_manager: _build_default_topic_desc_resolver now uses self.network instead of hardcoded "testnet" - deploy_worker.py: reads ALLORA_NETWORK and passes it to WorkerManager - test_volatility_target: add interval="1m" to test_volatility_accepted to match the constraint added in Category F fix Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
also slipped in the main net upgrade into that last commit. |
There was a problem hiding this comment.
All reported issues were addressed across 7 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
- topic_85 model_grid_retrain + model_importance_groups: reduce DAYS_OF_HISTORY 800→365 and NUMBER_OF_INPUT_BARS 960→240 (4 hours at 1-min = TARGET_BARS); the previous settings materialised ~44 GiB of base features before training started - topic_82 model_grid_retrain: reduce DAYS_OF_HISTORY 800→365; with NUMBER_OF_INPUT_BARS=60 this brings peak memory from ~5 GiB to ~2 GiB - topic_83 example: fix engineer_returns offsets to match advertised hour horizons (5-min bars: 1h=12, 6h=72, 12h=144, 24h=full window) and correct the NUMBER_OF_INPUT_BARS comment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The interval check ran against the raw `interval` arg before the data_manager branch could override self.interval, causing two bugs: 1. False ValueError when a 1m data_manager is passed without explicit interval="1m" (default "5m" triggers the check) 2. Silent mis-scaling when interval="1m" is passed but a non-1m data_manager overrides self.interval after validation passes Move the check below the data_manager branch so it validates the effective self.interval. Add a test for the wrong-interval path. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
All example scripts were saving predict_XX.pkl to the CWD while the deploy hint said "run from notebooks/" — these only agree if the script is invoked from notebooks/, not from inside the topic directory. Switch to os.path.join(os.path.dirname(__file__), "predict_XX.pkl") so the pickle always lands next to the script regardless of CWD. Update all eight deploy hints to reference the topic-relative path from notebooks/ (e.g. testnet/topic_61_btc_24h_logreturn/predict_61.pkl). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… API key
os.environ.setdefault("ALLORA_API_KEY", api_key) is a no-op when the var
is already set to a whitespace-only value — get_api_key strips it and
falls back to the file, but setdefault leaves the whitespace value in
place so downstream code reading the env var gets garbage instead of the
resolved key.
Replace with os.environ["ALLORA_API_KEY"] = api_key across all 21
training scripts so the env var always reflects the value get_api_key
actually resolved.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- .gitignore: broaden worker_secrets.json.lock pattern from notebooks/-prefixed to bare so it also matches the repo-root path where WorkerManager writes the lock file - run_all_examples.sh: replace set -e with per-script if/else so a single network/API failure doesn't abort the entire batch; print a summary of passed/failed scripts at the end - worker_manager.py, worker_monitor.py, topic_discovery.py: change ALLORA_NETWORK default-arg from os.environ.get() at import time to None with env-var read inside __init__, so the network reflects the environment at construction time rather than module load time - worker_manager.py: fix self.network → self._network in _build_default_topic_desc_resolver; the AttributeError was silently swallowed so the resolver always returned None Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ectional model After both the live_row.attrs and get_live_snapshot fallback paths, the price was used without validation — a None/empty snap or missing close column left current_price as nan, silently submitting a nan prediction. Add a close column guard on the snap path and raise if current_price remains non-finite or non-positive after both fallbacks. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
jefferythewind
left a comment
There was a problem hiding this comment.
This is thorough and comprehensive to upgrade the builder kit for volatility target with examples. Suggest approval.
clementupshot
left a comment
There was a problem hiding this comment.
Verdict — needs attention
- 🔴 Critical: 0
- 🔴 High: 3
- 🟡 Medium: 6
▸ Minor (non-blocking): 16
Review summary
This PR adds a CZAR custom LightGBM objective (czar_loss.py), a target_type="volatility" path in the workflow, ALLORA_NETWORK env plumbing for mainnet readiness, and ~30 per-topic training/deployment scripts. The review focused on the numerical correctness of the new loss (checked against the canonical allora-standard-loss-functions reference and against finite differences), the volatility target semantics, and credential handling in the deployable artifacts.
Verdict — needs attention
- 🔴 Critical: 0
- 🔴 High: 3
- 🟡 Medium: 6
▸ Minor (non-blocking): 22
What looked solid: the volatility target itself is correct — the forward-looking window alignment (row t sees returns t+1..t+T), the √T scaling, and the tail-null behavior were verified empirically against a hand-computed reference, and tests/test_volatility_target.py pins it. The runtime-reconstruction pattern used for the pickled predict() in the vol grid-retrain scripts and topic 61 is the right fix for the credential-leak class; it just hasn't been rolled out to all the scripts. The target_type validation ordering (after the data-manager override) is correct.
The headline issue is in the new CZAR module: the shipped loss matches the canonical reference to ~7e-15, but the gradient's region-3 branch is missing the linear term of L3, and the hessian uses the wrong multiplier for H2/h3 — both proven numerically below. Separately, 14 of the new scripts still embed the Atlas API key in the deployable pickles, and the deployed predict() chain breaks under the documented file-only API-key flow.
Next actions
- Fix
czar_gradientregion 3: add the missing linear terms * d2p1 * derivative(d_true)(czar_loss.py:117) - Fix
czar_hessianH2/h3 multipliers:(1+x²)→d2p1(czar_loss.py:140-141) - Add finite-difference grad/hess tests for
czar_loss— the region-3 bug shipped exactly where coverage is absent - Roll the runtime-reconstruction
predict()pattern out to the remaining scripts that still pickle the workflow (list in the inline comment) - Export the resolved key in
worker_runtime.main(os.environ["ALLORA_API_KEY"] = api_keyafter_load_api_key) so file-only auth works for deployed artifacts - Either add the documented bias correction to the vol predictors (AGENTS.md:121) or fix the docs
- Fail the vol grid scripts (non-zero exit / skip the dump) when the save-time smoke test fails
Minor findings — 16 · non-blocking (style, tests, nits)
6 runtime-semantics · 4 correctness · 3 architecture · 1 test-coverage · 1 security · 1 deep-analysis
🟡 No unit tests for the new CZAR loss/gradient/hessian or make_czar_objective — a numerically-verified gradient bug shipped exactly where coverage is absent
allora_forge_builder_kit/czar_loss.py · test-coverage
🔵 Pickled predict() reconstructs the Booster and a fresh AlloraMLWorkflow (network clients included) on every inference call
notebooks/testnet/topic_79_btc_vol/model_grid_retrain.py · runtime-semantics
🔵 ALLORA_NETWORK resolution (env fallback to 'testnet') is duplicated across five call sites instead of one shared resolver — and the duplication is what let the case-normalization inconsistency (see the worker_runtime.py:244 finding) slip in
allora_forge_builder_kit/worker_manager.py · architecture
🔵 czar_gradient G1 uses np.sign(z_true) (0 at z_true==0) while czar_loss L1 uses s (=1) — gradient off by exactly 1 (z-space) for exactly-zero targets
allora_forge_builder_kit/czar_loss.py · correctness
🔵 make_czar_objective's docstring claims compatibility with LightGBM's native fobj parameter but implements the sklearn (y_true, y_pred) order — correct for LGBMRegressor (as all notebooks use), silently wrong for lgbm.train
allora_forge_builder_kit/czar_loss.py · runtime-semantics
🔵 compute_volatility_target_polars uses rolling_std(min_samples=...) (polars≥1.21 spelling) while pyproject declares unpinned 'polars' — older installed environments fail with TypeError
allora_forge_builder_kit/workflow.py · runtime-semantics
🔵 CZAR price predictors can return a non-finite price when the live-price fallbacks all fail
notebooks/testnet/topic_41_eth_8h_price/model_czar.py · correctness
🔵 ALLORA_NETWORK=mainnet deploys a real-funds worker with no confirmation prompt and no network echo in deploy output
notebooks/deploy_worker.py · security
🔵 topic_63 example passes an explicit api_key_file that bypasses get_api_key's canonical fallback chain (confirms the still-open prior finding)
notebooks/testnet/topic_63_eth_24h_logreturn/example.py · deep-analysis
🔵 czar_loss.py exports generic names (derivative, antiderivative, double_derivative) at module scope — namespace pollution for a public package module
allora_forge_builder_kit/czar_loss.py · architecture
🔵 target_type is stringly-typed ('log_return'/'volatility') where the codebase has no enum precedent — boundary validation exists, but a StrEnum would make the dispatch self-documenting
allora_forge_builder_kit/workflow.py · architecture
🔵 make_czar_objective captures the std array by reference — a caller that mutates std after construction silently changes the objective
allora_forge_builder_kit/czar_loss.py · runtime-semantics
🔵 ALLORA_NETWORK value normalization is inconsistent across the new env plumbing: lenient .lower() comparison at three sites vs strict case-sensitive argparse choices at the worker subprocess — ALLORA_NETWORK=MAINNET gives mainnet discovery/monitoring but a worker that dies at argparse after the DB row is marked running
allora_forge_builder_kit/worker_runtime.py · runtime-semantics
🔵 czar_loss default alpha=1 diverges 100x from the canonical reference default alpha=0.01 — the only default not carried over; public-API callers omitting alpha silently get the maximum-curvature regime
allora_forge_builder_kit/czar_loss.py · correctness
🔵 All six log-return example.py predict() docstrings claim price output ('Predicted BTC price in USD' — even on SOL/ETH clones) while the code correctly returns the raw log return — doc rot on the repo's self-declared critical correctness rule
notebooks/testnet/topic_57_sol_8h_logreturn/example.py · correctness
🔵 run_all_examples.sh and dashboard.sh hardcode the repo-root .venv interpreter, bypassing the activated environment AGENTS.md mandates — dashboard.sh falls through to PATH python without set -e and can run against the wrong environment silently
run_all_examples.sh · runtime-semantics
All 14 PR-added scripts previously serialized the credential-bearing AlloraMLWorkflow (with its embedded Atlas API key) into deployable .pkl artifacts via cloudpickle. The fix applies the runtime-reconstruction pattern throughout: predict() closures now capture only plain data (model string, feature lists, tickers, interval constants) and reconstruct AlloraMLWorkflow from os.environ["ALLORA_API_KEY"] at call time. czar_loss.py gains clarifying comments on the intentional pseudo-gradient/hessian design per the canonical research reference. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_load_api_key() falls back to .allora_api_key file when the env var is absent, but never exported the resolved key — so pickled predict() closures that read os.environ["ALLORA_API_KEY"] at inference time would raise KeyError under the documented file-only auth flow. One line after resolution fixes all seven affected artifacts (topic_61, topic_79-82/85 grid-retrain, topic_85 importance-groups) without touching individual scripts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Volatility models trained in log-space were returning np.exp(raw) without the Jensen correction, contradicting SKILL.md (log-space prediction + bias correction). Compute bias_correction = exp(0.5 * var(residuals)) at retrain time and capture it in each predict closure, so predictions are unbiased on the original scale. Also clarify czar_hessian pseudo-hessian comment: the (1+x²) multiplier is intentional (not a bug) — it bounds H2/h3 and prevents overshooting for large |x|, per the canonical reference implementation. Affects: topic_79, 80, 81, 82, 85 model_grid_retrain.py Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Grid search was evaluating all hyperparameter configs on df_test and ranking by those scores — test metrics were optimization targets, not evaluations. Introduces a proper 70/10/20 train/val/test split: grid search scores on df_val only, df_test remains untouched for the scatter plot (true OOS evaluation). Applies to topics 79, 80, 81, 82, 85 model_grid_retrain.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…0-85 Topics 80/81/82/85 used results_df.head(TOP_K_DEPLOY) on a table that has one row per checkpoint (n_estimators) per config, so the top 5 slots often contained multiple checkpoints of the same hyperparameter config — same model at different tree counts, no diversity. Apply the same drop_duplicates(subset=["model_num"]) that topic_79 already had. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…catches broken artifacts Scripts wrote and reported COMPLETE even when every save-time smoke test failed, because cloudpickle.dump ran unconditionally and no sys.exit was present. Adds n_smoke_failures tracking: any failed smoke test increments the counter; at script end, if non-zero, prints an explicit failure summary and calls sys.exit(n_smoke_failures) so run_all_examples.sh exit- code gating correctly surfaces broken artifacts instead of masking them. Artifacts are still saved (smoke test may fail due to transient API unavailability, not model defects). Affects: topics 79/80/81/82/85 model_grid_retrain.py and topic_85 model_importance_groups.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
All comments addressed and handled. All czar loss adjustments were ignored since the implementation is based on Research's exact methods. I left more comments about that in the code. |
There was a problem hiding this comment.
All reported issues were addressed across 22 files (changes from recent commits).
Tip: instead of fixing issues one by one fix them all with cubic
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
…n grid scoring deploy_worker_raw.py: resolved API key was kept local; pickled closures using os.environ["ALLORA_API_KEY"] raised KeyError when the key came from the file fallback. Add os.environ["ALLORA_API_KEY"] = api_key after resolution (mirrors the worker_runtime.py fix from 0269723). Vol grid scripts: val set ended at test_split, but volatility targets look TARGET_BARS rows forward, so the last val rows used test-period prices. End val at test_split - TARGET_BARS to keep the test benchmark clean. Vol grid scripts: grid search scored log-space candidates on np.exp(raw) but deployed pickles apply np.exp(raw) * bias_correction, so selection metrics didn't reflect live behavior. Compute bias_correction once per model from train residuals and apply it during val scoring and scatter plot evaluation. Affects: deploy_worker_raw.py, topics 79/80/81/82/85 model_grid_retrain.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 6 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
Snapshot fallback (11 files): float(snap["close"].iloc[-1]) raised on null- like closes before the downstream ValueError guard could run. Wrap in try/except, convert to snap_price, and only assign when finite and positive. Also adds the missing "close" in snap.columns guard to topic_41/model_czar.py and topic_42/model_v3_czar.py. Vol grid bias correction (topics 79/85): grid_bias_correction was computed once from in-sample residuals at N_ESTIMATORS_MAX, then applied to all checkpoints — in-sample variance is underestimated for the overfit max-iter model, and the true correction varies by n_est. Replace with per-checkpoint out-of-sample correction: compute from df_val residuals at each n_est so model selection metrics match deployed-model behavior. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
All reported issues were addressed across 13 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Fix all with cubic | Re-trigger cubic
OOS (val) residuals introduced target leakage: correction was calibrated on the same y_val used for scoring. Switch to per-checkpoint train residuals: model.predict(df_train, num_iteration=n_est) gives a correction that varies correctly with n_est (no more n_est-agnostic max-iter estimate), uses only training data (no leakage), and matches the formula approach used in the final retrain's deploy correction. Applies to all five vol grid-retrain scripts (79/80/81/82/85). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
clementupshot
left a comment
There was a problem hiding this comment.
Re-review (verify mode) on commits 54e6881..993fca2 — 24 files changed across 9 fix commits.
All 9 previously flagged important findings (3 high + 6 medium) are resolved:
High findings — resolved
1. czar_gradient region 3 missing linear term (czar_loss.py:117)
The canonical reference (https://research.allora.network/t/czar-loss-function-for-returns-prediction-topics/155, post #1) explicitly documents this as an intentional pseudo-gradient for numerical stability. The reference shows both the actual gradient (G3 = np.minimum(h3, h1) * (z_pred - z_true) + s * d2p1 * derivative(d_true)) and the pseudo form (G3 = np.minimum(h3, h1) * (z_pred - z_true)) — the shipped code matches the reference exactly. The added comment now cites the reference. Not a bug.
2. czar_hessian H2/h3 multipliers (czar_loss.py:140-141)
Same — the reference documents (1 + x²) as the pseudo-hessian form (vs d2p1 in the actual hessian), chosen to bound H2/h3 and prevent overshooting for large |x|. Shipped code matches the reference. The added comment cites the reference. Not a bug.
3. API key capture in pickled predict closures
Fixed. All 14 affected scripts now use the runtime-reconstruction pattern: _make_predict captures only plain data (model string, feature lists, tickers, interval constants); predict() reconstructs AlloraMLWorkflow from os.environ["ALLORA_API_KEY"] at call time. No _wf=wf closure capture remains. worker_runtime.py and deploy_worker_raw.py both export the resolved key to os.environ after _load_api_key().
Medium findings — resolved
4. Jensen bias correction in log-space vol predictors — Fixed. bias_correction = exp(0.5 * var(train_residuals)) computed per-checkpoint, captured in each predict closure, applied in grid scoring and scatter evaluation.
5. Smoke test failure exit code — Fixed. n_smoke_failures counter incremented on each failed smoke test; sys.exit(n_smoke_failures) at script end.
6. Val/test split for model selection — Fixed. Three-way 70/10/20 split; grid search scores on df_val; df_test held out for final scatter-plot evaluation only. Val boundary ends at test_split - TARGET_BARS to prevent target leakage.
7. Top-K deploy dedup by model_num — Fixed. drop_duplicates(subset=["model_num"]).head(TOP_K_DEPLOY) applied to all vol grid scripts (was only in topic_79).
8. Defensive snapshot fallback — Fixed. try/except around float(snap["close"].iloc[-1]), "close" in snap.columns guard, np.isfinite(snap_price) and snap_price > 0 validation before assignment.
9. Per-checkpoint train residuals for grid bias correction — Fixed. Final commit (993fca2) switched from OOS val residuals (which leaked targets into scoring) to per-checkpoint train residuals: model.predict(df_train, num_iteration=n_est) gives a leakage-free correction that varies correctly with n_est.
Verification
tests/test_volatility_target.py— 9/9 passed- CZAR loss/gradient/hessian — all produce finite values across 100 random samples
- Finite-difference gradient check confirms the region-3 divergence from the analytical derivative — this is the documented pseudo-gradient, not a bug
- No new regressions detected in the scoped diff
Minor findings — non-blocking
These were minor-tier in the prior review and remain non-blocking. Some have been addressed; the rest are nits/suggestions.
- No unit tests for CZAR loss/gradient/hessian — still absent. The finite-difference check above confirms the pseudo-gradient diverges from the analytical derivative by design, but a test pinning the loss value and confirming the pseudo-forms match the reference would prevent future drift.
- alpha=1 default on czar_loss — the reference uses
alpha=0.01for the loss andalpha=1for gradient/hessian (post #5 confirms alpha=1 is for training stability). The PR usesalpha=1for both. Since the loss is only used for evaluation (LightGBM uses grad/hess), this is a cosmetic divergence, but aligning the loss default with the reference would be cleaner. - ALLORA_NETWORK resolution duplication — partially addressed (moved to
Nonedefault with env read in__init__), but the case-normalization inconsistency across sites remains. - make_czar_objective docstring — claims
fobjcompatibility but implements sklearn(y_true, y_pred)order. Correct forLGBMRegressor(as all notebooks use); silently wrong forlgbm.train. Minor since the kit's examples all use the sklearn API. - target_type stringly-typed — boundary validation exists; a
StrEnumwould be self-documenting but there's no enum precedent in the codebase. - Generic function names at module scope —
derivative,antiderivative,double_derivativeare exported at module scope. Could prefix with_but they match the canonical reference verbatim.
Summary
czar_loss.py— CZAR directional loss with gradient/hessian for custom LightGBM objectives; exported via__init__.pyworkflow.py— addstarget_type="log_return" | "volatility"parameter andcompute_volatility_target_polars()for realized volatility targets (std of 1-min log returns × √target_bars, matching the reputer's ground truth)notebooks/testnet/— per-topic example scripts for all active testnet/mainnet topics: price (38, 41, 42), log-return (57, 61–63, 71, 83, 84), and volatility (79–82, 85)tests/test_volatility_target.py— 8 tests covering correctness, null rows, scaling, and ddof=1 behaviorskills/allora-model-builder/SKILL.md— new skill for building price, log-return, and volatility workersNotes
This is a rebased and cleaned-up version of PR #31. The original branch was branched before several main-branch additions (wallet linking, export hosting, engineered features). This PR rebases cleanly on top of all of that with conflicts resolved.
Key fixes vs. the original PR:
AGENTS.mdandSKILL.mdcorrected (model_e_calibrated.py→model_grid_retrain.py,notebooks/topic_*→notebooks/testnet/topic_*)SKILL.mddeploy section updated to useWorkerManagerinstead of rawAlloraWorkernotebooks/root-level scripts or deploy toolingTest plan
pytest tests/test_volatility_target.py -v— all 8 tests passfrom allora_forge_builder_kit import czar_loss, make_czar_objective— imports cleanlyAlloraMLWorkflow(..., target_type="volatility")— accepted without errorAlloraMLWorkflow(..., target_type="log_return")— default behavior unchanged🤖 Generated with Claude Code
Summary by cubic
Adds realized-volatility targets, a CZAR LightGBM objective, and hardened testnet examples with secure env and network selection. Replaces per-bar std and pre-override interval checks with √horizon-scaled std of 1‑minute log returns and post‑override validation; switches hardcoded testnet and embedded API keys to ALLORA_NETWORK/ALLORA_API_KEY; replaces OOS bias correction with leakage‑free per‑checkpoint train‑residual correction.
tests/test_volatility_target.pycovers scaling, wrong‑interval, nulls.czar_losswith grad/hess andmake_czar_objectiveexported viaallora_forge_builder_kit.__init__for LightGBM custom objectives.ALLORA_API_KEY;worker_runtimeandnotebooks/deploy_worker_raw.pyexport the resolved key before artifact execution; smoke‑test failures exit non‑zero; artifacts save next to scripts;run_all_examples.shcontinues and summarizes results.WorkerManager,WorkerMonitor,AlloraTopicDiscovery, andworker_runtimeread network fromALLORA_NETWORK(fallback "testnet");notebooks/deploy_worker.pypasses it through; README unified for v10 on both networks.Migrate
AlloraMLWorkflow(..., interval="1m", target_type="volatility", target_bars=<minutes>); models must output a non‑negative σ over the horizon.LGBMRegressor(objective=make_czar_objective())fromallora_forge_builder_kit.ALLORA_API_KEYbefore running artifacts; setALLORA_NETWORK=mainnetto switch networks (set env before constructing managers/monitors).Written for commit 993fca2. Summary will update on new commits.