From 85fcbe133037236a291b6f66f359c8fd87aa0847 Mon Sep 17 00:00:00 2001 From: Tim Olson Date: Sun, 26 Apr 2026 11:51:29 -0400 Subject: [PATCH] indicator validation looks for all NaN's and all zeroes --- doc/plan.md | 7 ++---- sandbox/dexorder/tools/indicator_harness.py | 28 +++++++++++++++++++-- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/doc/plan.md b/doc/plan.md index c02aa58c..af36c8b3 100644 --- a/doc/plan.md +++ b/doc/plan.md @@ -1,7 +1,5 @@ # Development Plan -* Wiki memory -* Agent unification & spawn tool * Realtime data * Triggers * Strategy UI @@ -13,6 +11,5 @@ * Chat channels * MCP channel (with or without images) * TradingView indicator import tool -* Trader preferences tool -* Results persistence: research analysis, backtests, strategy performance metrics, etc. -* \ No newline at end of file +* Results persistence: ~~research analysis~~, backtests, strategy performance metrics, etc. +* Free tier with token limits and sandbox shutdown diff --git a/sandbox/dexorder/tools/indicator_harness.py b/sandbox/dexorder/tools/indicator_harness.py index b63993b4..e0447f19 100644 --- a/sandbox/dexorder/tools/indicator_harness.py +++ b/sandbox/dexorder/tools/indicator_harness.py @@ -61,14 +61,33 @@ def make_synthetic_ohlcv(n: int = 200): def summarize(result, n: int) -> str: import pandas as pd + warnings = [] + + def _check_series_warnings(s: "pd.Series", label: str = "") -> None: + valid = s.dropna() + prefix = f"Column '{label}': " if label else "" + if len(valid) == 0: + warnings.append( + f"⚠ WARNING: {prefix}All {n} output values are NaN. " + "The indicator produced no usable data — check for NaN propagation bugs " + "(e.g. uninitialized recursive filter, division by zero, insufficient warmup)." + ) + elif (valid == 0).all(): + warnings.append( + f"⚠ WARNING: {prefix}All non-NaN output values are zero. " + "The indicator may have a computation bug " + "(e.g. log(1) always being 0, constant input, or a formula that cancels out)." + ) + if isinstance(result, pd.Series): nan_count = int(result.isna().sum()) valid = result.dropna() sample = [round(float(v), 4) for v in valid.tail(5).values] if len(valid) else [] - return ( + summary = ( f"Series({n} bars), NaN: {nan_count}/{n}, " f"last 5 valid values: {sample}" ) + _check_series_warnings(result) elif isinstance(result, pd.DataFrame): cols = list(result.columns) nan_counts = {c: int(result[c].isna().sum()) for c in cols} @@ -77,13 +96,18 @@ def summarize(result, n: int) -> str: valid = result[col].dropna() if len(valid): sample[col] = [round(float(v), 4) for v in valid.tail(3).values] - return ( + _check_series_warnings(result[col], label=col) + summary = ( f"DataFrame({n} bars × {len(cols)} cols {cols}), " f"NaN counts: {nan_counts}, last 3 valid per col: {sample}" ) else: return f"Unexpected return type: {type(result).__name__}" + if warnings: + return summary + "\n" + "\n".join(warnings) + return summary + def run(impl_path: Path, metadata_path: Path) -> dict: """