Test Formula
test_formulaInvent a formula over EnsoTrade's data, and get back whether it actually predicts
forward returns — validated on a holdout split, not just fit to the whole window.
formula is a math expression combining any of the fields listed in fetch_series'
docstring (for the same timeframe) with +, -, *, /, **, %, unary +/-, and abs/min/max/
sqrt/log/log1p/exp/sign/clip/mean/std, e.g. "ofi1 * vpin - dofi / 2" or
"sign(qi) * sqrt(abs(obi))". No other Python is executed — this runs through a restricted,
default-deny expression evaluator, not eval().
timeframe="scalp" (default, WDE order-flow, second-scale): horizon is which forward
return to correlate against — ret_1s_bp, ret_5s_bp, ret_30s_bp, or ret_60s_bp. hours max
720 (30 days).
timeframe = "15m"/"1h"/"4h"/"1d" for day/swing strategies (real OKX candles, always
available): use horizon_bars instead of horizon — the forward % return N candles
ahead (e.g. horizon_bars=4 on timeframe="1h" = predicting the move 4 hours out). hours
max ~1500 bars worth; a small hours still fetches at least 150 bars (the minimum needed
for a meaningful 70/30 split) rather than failing outright, so the actual window tested
can be wider than requested for a small hours value.
Either mode needs enough rows that a 70/30 split leaves >=150 total. Returns train (first 70% chronologically) and holdout (untouched final 30%) Spearman/Pearson correlations plus a verdict: 'validated' only if holdout |spearman| >= 0.15 AND same-signed as train — this guards against keeping a formula that only looked good by chance on one slice of data.
ALSO returns, computed on the holdout portion only:
net: risk-adjusted performance AFTER trading costs — sharpe, sortino, max_drawdown_pct, calmar, ann_return_pct, ann_volatility_pct, win_rate_pct, profit_factor. Sharpe is annualized and corrected for overlapping horizons (a horizon spanning N bars sampled every bar is subsampled to non-overlapping periods first, which removes the ~sqrt(N) inflation naive Sharpe would show).gross: the same metrics before costs, so the cost drag is visible.costs: fee/slippage assumptions, position_changes (turnover), total_cost_pct. Costs are charged on position CHANGES only, not per bar — holding one side is cheap, flipping every bar is not.cost_verdict: survives_costs / marginal_after_costs / killed_by_costs / unknown. IMPORTANT:verdictis a correlation test and says nothing about profitability; a formula can be 'validated' and still be killed_by_costs. Check both.walk_forward: the same formula re-scored on 5 consecutive time blocks, with consistency_pct (share of blocks agreeing on direction) and astableflag. An edge that passes one holdout but flips sign between blocks is usually noise.
fee_bp/slippage_bp are per side, defaulting to 5bp taker + 2bp slippage; raise
them for illiquid coins or a worse fee tier. Iterate: call this repeatedly with
different formulas, keep what validates AND survives costs, discard what doesn't.
Requires an EnsoTrade Pro API key.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| hours | No | ||
| fee_bp | No | ||
| symbol | Yes | ||
| formula | Yes | ||
| horizon | No | ret_30s_bp | |
| timeframe | No | scalp | |
| slippage_bp | No | ||
| horizon_bars | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||