PINE LIBRARY
已更新

ICOptimizerLib

183
Library "ICOptimizerLib"
ICOptimizerLib v2 — IC-based parameter optimization with 4 Bayesian strategies.
Publish target: ICOptimizer/2 (hard break from v1 — see §A below).
Layer 1: primitive IC estimators (Pearson, Spearman, Kendall, Partial).
Layer 2: Optimizer UDT with 4 strategies: argmax | ucb | thompson | bayesian.
Layer 3: RegimeGate, ObjectiveWeights, composite scoring, serialize/restore.
Layer 4: diagnostics table and panel.
L2 library — depends only on NumLib.

─── §A v1 BACKWARD-COMPAT DECISION (follow-up 1) ────────────────────────

HARD BREAK. v1 (ICOptimizer/1) used bare strings ("argmax", "ucb", …).
v2 uses the OptimizerKind enum. Reason: Pine v6 enums are type-safe and
produce CE10 errors at compile time if a caller passes an invalid string,
whereas bare strings fail silently at runtime. The compat shim route
(string→enum dispatch wrapper) was considered and rejected: it would
re-introduce series-string branching inside a hot method, defeating the
purpose of the enum migration.

Migration for v1 callers:
OLD: f_find_optimal_param(params, ics, cur, 0.2) ← v1 API
NEW: opt = f_optimizer_new(OptimizerKind.ARGMAX, …) ← v2 API
idx = opt.propose()
opt.observe(idx, ic)
The free function f_find_optimal_param() is retained in §4 as a one-line
compat wrapper producing identical output to v1 findOptimalParam() for
callers that only used ARGMAX and do not need the UDT.

Publish target: ICOptimizer/2 (same publisher namespace as kNNLib/28,
LearningLib/1, etc. Parallel to v1, not a rename.)

─── §B UDT INDEPENDENCE AUDIT (follow-up 2) ─────────────────────────────

All 4 UDTs are independently constructable with no required coupling:

UDT Constructor Depends on
─────────────── ─────────────────────────── ────────────────────────────
Optimizer f_optimizer_new(…) nothing (grid is caller-owned)
RollingIC f_rolling_ic_new(capacity) nothing
RegimeGate f_regime_gate_new(…) nothing
ObjectiveWeights f_obj_weights_new(…) nothing

Valid combinations:
• Optimizer alone — minimal usage (ARGMAX strategy, no IC classification)
• Optimizer + RollingIC — IC classification per bar, classify() method
• Optimizer + ObjectiveWeights — composite scoring for multi-objective grids
• Optimizer + RegimeGate — gate-filtered observe() calls
• All 4 — full stack

Initialization order: any order; there are no cross-UDT init dependencies.
The caller is responsible for pushing IC values into RollingIC before
calling classify(); a fresh buffer returns 0.0 thresholds (safe default).

─── §C GP MATH VERIFICATION (follow-up 3) ───────────────────────────────

Jacobi solver convergence domain: guaranteed for diagonally dominant K.
K is diagonally dominant when kernel_noise > 0 (K[i,i] = kernel(xi,xi) +
noise ≥ 1 + noise > Σ_{j≠i} kernel(xi,xj) for RBF/Matern52 with ls > 0).
NaN propagation guard: f_optimizer_new() enforces noise ≥ 1e-6 at
construction (see implementation below). NaN in ic_sample is gated by
the na(ic_sample) check in observe() before any array writes.

Grid size constraints (enforced at f_optimizer_new):
grid_size == 1 → runtime.error (BAYESIAN is undefined for a single cell)
grid_size > 30 → runtime.error for BAYESIAN only (Jacobi O(n²×20) budget)
grid_size ≥ 2 → all strategies valid
ARGMAX/UCB/THOMPSON have no upper grid-size constraint.

Unit test specification (see test_icoptimizer_v2_unit.pine):
T1: grid=[1.0] + BAYESIAN → should hit error log (na guard)
T2: grid=[1.0,2.0] + BAYESIAN, 50 observe() calls → ic_var shrinks
T3: grid size=30 + BAYESIAN → no silent NaN on bar 500 / 1000
T4: rising IC synthetic trajectory → propose() returns idx 6 after warmup
T5: peak-in-middle IC → propose() converges to idx 3 (center)

─── §D v5→v6 DELTA (Phase E-2a) ─────────────────────────────────────────

1. //version=5 → //version=6
2. type ICOptimizer → decomposed to 4 independent UDTs (§B)
3. `series float` qualifiers explicit; `simple int` for all ta.* lengths (CE10297)
4. Enum OptimizerKind / KernelKind / ReturnMode replaces bare strings
5. classifyIC scalar bug → RollingIC ring buffer + sort-based percentile
6. detectAndAdjustDomination orphan → method check_domination on Optimizer
7. Monotonic counter → reset_decay(decay) method
8. S9: all multi-line ternaries collapsed to single lines
9. f_ma_for_idx() dispatch in demo for simple-int ta.sma constraint
10. Nested array.get() in f_build_gram / observe() split to locals (COMMA_STATEMENTS)


f_ic_pearson(signal, ret, n)
  Pearson IC: correlation of signal with forward return
  Parameters:
    signal (float): Signal series (e.g. z-score oscillator)
    ret (float): Forward return series (aligned: ret[0] = realized return for signal[horizon])
    n (simple int): Rolling window (simple int — required by ta.correlation)

f_ic_spearman(signal, ret, n)
  Spearman IC via rank correlation approximation
  Parameters:
    signal (float): Signal series
    ret (float): Forward return series
    n (simple int): Rolling window
  Returns: Spearman rank-correlation approximation

f_ic_kendall(signal, ret, n)
  Kendall IC approximation (via concordant/discordant sign correlation)
  Parameters:
    signal (float): Signal series
    ret (float): Forward return series
    n (simple int): Rolling window
  Returns: Kendall tau approximation

f_ic_partial(signal, ret, control, n)
  Partial IC: correlation of signal with ret after removing control variable
  Parameters:
    signal (float): Signal series
    ret (float): Forward return series
    control (float): Control variable to partial out
    n (simple int): Rolling window
  Returns: Partial Pearson IC

f_forward_return(src, horizon, mode, benchmark)
  Compute forward return from source series
  Parameters:
    src (float): Source price series
    horizon (simple int): Look-forward bars
    mode (series ReturnMode): ReturnMode enum
    benchmark (float): Optional benchmark (used only in EXCESS mode; pass na otherwise)

f_label_from_signal(sig, ret, eps)
  Label from signal × return sign match
  Parameters:
    sig (float): Signal value
    ret (float): Realized return
    eps (float): Dead-zone threshold (returns within ±eps labelled 0)
  Returns: 1 = correct direction, -1 = wrong direction, 0 = inside dead-zone

f_rolling_ic_new(capacity)
  Create a new RollingIC buffer
  Parameters:
    capacity (simple int): Number of IC samples to retain

method push(self, ic_val)
  Push a new IC observation into the ring buffer
  Namespace types: RollingIC
  Parameters:
    self (RollingIC)
    ic_val (float)

method classify(self, ic_val, good_pct, bad_pct)
  Classify current IC against ring buffer distribution
  Namespace types: RollingIC
  Parameters:
    self (RollingIC): RollingIC buffer (must have been pushed at least once)
    ic_val (float): Current IC to classify
    good_pct (float): Percentile above which IC is "good" (0–100)
    bad_pct (float): Percentile below which IC is "bad" (0–100)
  Returns: [is_good, is_bad, good_thresh, bad_thresh]

f_optimizer_new(kind, grid, lr, c_ucb, cooldown, kernel_kind, kernel_ls, kernel_noise)
  Create a new Optimizer
  Parameters:
    kind (series OptimizerKind): Strategy
    grid (array<float>): Parameter grid (array<float>, size ≤ 30 for BAYESIAN)
    lr (float): EWM learning rate for ic_ema / ic_var updates (0–1)
    c_ucb (float): UCB exploration constant (ignored for non-UCB)
    cooldown (simple int): Minimum bars between switches
    kernel_kind (series KernelKind): Kernel for BAYESIAN (ignored otherwise)
    kernel_ls (float): Kernel lengthscale (ignored otherwise)
    kernel_noise (float): Observation noise (ignored otherwise)

method propose(self)
  Propose next parameter index to try
  Namespace types: Optimizer
  Parameters:
    self (Optimizer)
  Returns: Selected grid index

method observe(self, idx, ic_sample)
  Record observed IC for a grid cell and update posterior
  Namespace types: Optimizer
  Parameters:
    self (Optimizer)
    idx (int): Grid index that was evaluated
    ic_sample (float): Observed IC value

method reset_decay(self, decay)
  Apply exponential decay to ic_ema and ic_var (prevents monotonic drift)
  Namespace types: Optimizer
  Parameters:
    self (Optimizer)
    decay (float): Decay factor 0..1 (e.g. 0.95 = retain 95% of past)

method check_domination(self, long_n, short_n, ratio_threshold)
  Detect directional signal domination and bump current grid index
  Namespace types: Optimizer
  Parameters:
    self (Optimizer)
    long_n (int): Count of long signals in evaluation window
    short_n (int): Count of short signals in evaluation window
    ratio_threshold (float): Domination ratio (e.g. 4 = 4:1 imbalance)
  Returns: [was_dominated, direction_str] direction_str = "long" | "short" | "none"

method current_param(self)
  Get current parameter value from grid
  Namespace types: Optimizer
  Parameters:
    self (Optimizer)

f_find_optimal_param(testParams, icValues, currentParam, smoothing)
  Find optimal parameter from arrays (v1-compatible, wraps Optimizer.propose)
  Parameters:
    testParams (array<float>): Grid array
    icValues (array<float>): IC values for each grid cell (same size)
    currentParam (float): Current param (for EWM smoothing)
    smoothing (simple float): EWM lr (0–1)
  Returns: [newParam, bestIC, bestIdx]

f_regime_gate_new(mode, threshold, confirm_bars)
  Create RegimeGate
  Parameters:
    mode (string)
    threshold (float)
    confirm_bars (simple int)

method is_open(self, ic_val, bars_above)
  Check if gate is open given current IC and a rolling counter
  Namespace types: RegimeGate
  Parameters:
    self (RegimeGate): RegimeGate
    ic_val (float): Current IC
    bars_above (int): Rolling bars-above-threshold counter (caller maintains)
  Returns: bool gate_open

f_obj_weights_new(w_ic, w_hitrate, w_freq_penalty, w_drawdown_penalty)
  Create ObjectiveWeights
  Parameters:
    w_ic (float)
    w_hitrate (float)
    w_freq_penalty (float)
    w_drawdown_penalty (float)

f_composite_score(w, ic, hitrate, freq, drawdown)
  Compute composite score for a grid cell
  Parameters:
    w (ObjectiveWeights): ObjectiveWeights
    ic (float): IC value for cell
    hitrate (float): Hit rate 0..1 for cell
    freq (float): Signal frequency 0..1 (higher = more signals = penalized)
    drawdown (float): Max drawdown magnitude (positive float)
  Returns: Composite score (higher = better)

f_optimizer_serialize(self)
  Serialize Optimizer state to a compact CSV string
  Parameters:
    self (Optimizer): Optimizer to serialize
  Returns: string blob (pass to f_optimizer_restore to reconstruct ic_ema/ic_var)

f_optimizer_restore(self, blob)
  Restore ic_ema/ic_var/visits from serialized blob into an existing Optimizer
  Parameters:
    self (Optimizer): Optimizer (grid must already be initialized with correct size)
    blob (string): String from f_optimizer_serialize
  Returns: self (mutated in place)

f_diag_table(self, gate, weights, pos, max_rows)
  Render diagnostics table for Optimizer state
  Parameters:
    self (Optimizer): Optimizer
    gate (RegimeGate): RegimeGate (pass na if unused)
    weights (ObjectiveWeights): ObjectiveWeights (pass na if unused)
    pos (string): Table position (e.g. position.bottom_right)
    max_rows (simple int): Maximum grid rows to display (capped at array.size(grid))
  Returns: table reference

f_diag_panel(self, height)
  Render sparkline-style panel (one plot bar per grid cell, height = ic_ema)
  Parameters:
    self (Optimizer): Optimizer
    height (float): Panel height in price units (caller scales)
  Returns: label(na) (renders labels directly)

f_kind_str(k)
  Parameters:
    k (series OptimizerKind)

f_kernel_str(k)
  Parameters:
    k (series KernelKind)

f_return_mode_str(m)
  Parameters:
    m (series ReturnMode)

RollingIC
  Rolling IC ring buffer for proper percentile computation
  Fields:
    samples (array<float>): Circular buffer of IC observations
    head (series int): Write head (mod capacity)
    capacity (series int): Max samples to retain

Optimizer
  Optimizer — unified UDT for all 4 strategies
  Fields:
    kind (series OptimizerKind): Strategy: ARGMAX | UCB | THOMPSON | BAYESIAN
    grid (array<float>): Discrete parameter grid (size ≤ 30 for BAYESIAN)
    ic_ema (array<float>): Posterior mean per cell (EWM updated)
    ic_var (array<float>): Posterior variance per cell (UCB/Thompson/Bayes)
    visits (array<int>): Visit count per cell
    lr (series float): EWM learning rate for ic_ema / ic_var updates
    c_ucb (series float): Exploration coefficient (UCB only)
    cooldown (series int): Minimum bars between parameter changes
    last_change_bar (series int): Bar index of last change
    current_idx (series int): Currently selected grid index
    kernel_matrix (array<float>): Flattened len(grid)² Gram matrix (BAYESIAN only)
    kernel_kind (series KernelKind): RBF | MATERN52 (BAYESIAN only)
    kernel_ls (series float): Kernel lengthscale (BAYESIAN only)
    kernel_noise (series float): Observation noise σ² (BAYESIAN only)
    total_visits (series int): Cumulative visit count (for UCB log normalizer)
    decay_factor (series float): EWM decay applied by reset_decay (0..1; 1=no decay)

RegimeGate
  RegimeGate — IC regime filter
  Fields:
    mode (series string): "positive" | "any" | "top_pct"
    threshold (series float): IC threshold for "positive" or percentile for "top_pct"
    confirm_bars (series int): Bars IC must stay above threshold before gate opens

ObjectiveWeights
  ObjectiveWeights — composite scoring weights
  Fields:
    w_ic (series float): Weight on IC component
    w_hitrate (series float): Weight on hit-rate component
    w_freq_penalty (series float): Penalty for excessive signal frequency
    w_drawdown_penalty (series float): Penalty for drawdown
版本注释
v2

免责声明

这些信息和出版物并非旨在提供,也不构成TradingView提供或认可的任何形式的财务、投资、交易或其他类型的建议或推荐。请阅读使用条款了解更多信息。