From 14c43474ab01224ab22aef39bf6813c4578a06e7 Mon Sep 17 00:00:00 2001 From: claude Date: Fri, 24 Jul 2026 22:05:34 +0200 Subject: [PATCH] =?UTF-8?q?fieldtest:=20construction-args=20=E2=80=94=204?= =?UTF-8?q?=20examples,=200=20bugs=20/=201=20friction=20/=202=20spec-gap?= =?UTF-8?q?=20/=204=20working?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Source-blind consumer run over the #271 surface: a NY first-bar- momentum Session authored purely as data and run e2e over --real US500; a LinComb{arity:3} blend binding the arity-unlocked weights with the Session period swept (4 members, reproduced 4/4 bit-identically); eight strict-form refusal probes (all exit 1, actionable prose); an args composite registered and use-spliced into a consumer (v2 propagates, ids stable, C29 doc gate holds). Findings routed: Count lexical form + asymmetry ratified into glossary/guide (follow-up commit); introspect dead-end on arg-bearing ports and the missing CostSum wiring path absorbed into #341. refs #271 --- fieldtests/construction-args/TRANSCRIPT.md | 217 ++++++++++++++++++ .../construction-args/ca_1_ny_session.bp.json | 1 + .../ca_1_ny_session.build.err | 0 .../ca_1_ny_session.ops.json | 28 +++ .../ca_1_ny_session.run.json | 65 ++++++ .../ca_2_lincomb_blend.bp.json | 1 + .../ca_2_lincomb_blend.build.err | 0 .../ca_2_lincomb_blend.ops.json | 33 +++ .../ca_2_lincomb_blend.sweep.jsonl | 4 + .../ca_2b_costsum_arity.ops.json | 3 + .../construction-args/ca_3a_bad_tz.ops.json | 8 + .../ca_3b_unpadded_time.ops.json | 8 + .../ca_3c_zero_count.ops.json | 7 + .../ca_3d_garbage_count.ops.json | 5 + .../ca_3e_missing_arg.ops.json | 7 + .../ca_3f_args_on_argless.ops.json | 8 + .../ca_3g_unknown_arg_key.ops.json | 8 + .../ca_3h_partial_args.ops.json | 8 + .../construction-args/ca_4_consumer.bp.json | 1 + .../construction-args/ca_4_consumer.ops.json | 19 ++ .../construction-args/ca_4_consumer.run.json | 71 ++++++ .../ca_4_ny_anchor_pattern.bp.json | 1 + .../ca_4_ny_anchor_pattern.ops.json | 9 + .../construction-args/ca_4_pattern.build.err | 0 24 files changed, 512 insertions(+) create mode 100644 fieldtests/construction-args/TRANSCRIPT.md create mode 100644 fieldtests/construction-args/ca_1_ny_session.bp.json create mode 100644 fieldtests/construction-args/ca_1_ny_session.build.err create mode 100644 fieldtests/construction-args/ca_1_ny_session.ops.json create mode 100644 fieldtests/construction-args/ca_1_ny_session.run.json create mode 100644 fieldtests/construction-args/ca_2_lincomb_blend.bp.json create mode 100644 fieldtests/construction-args/ca_2_lincomb_blend.build.err create mode 100644 fieldtests/construction-args/ca_2_lincomb_blend.ops.json create mode 100644 fieldtests/construction-args/ca_2_lincomb_blend.sweep.jsonl create mode 100644 fieldtests/construction-args/ca_2b_costsum_arity.ops.json create mode 100644 fieldtests/construction-args/ca_3a_bad_tz.ops.json create mode 100644 fieldtests/construction-args/ca_3b_unpadded_time.ops.json create mode 100644 fieldtests/construction-args/ca_3c_zero_count.ops.json create mode 100644 fieldtests/construction-args/ca_3d_garbage_count.ops.json create mode 100644 fieldtests/construction-args/ca_3e_missing_arg.ops.json create mode 100644 fieldtests/construction-args/ca_3f_args_on_argless.ops.json create mode 100644 fieldtests/construction-args/ca_3g_unknown_arg_key.ops.json create mode 100644 fieldtests/construction-args/ca_3h_partial_args.ops.json create mode 100644 fieldtests/construction-args/ca_4_consumer.bp.json create mode 100644 fieldtests/construction-args/ca_4_consumer.ops.json create mode 100644 fieldtests/construction-args/ca_4_consumer.run.json create mode 100644 fieldtests/construction-args/ca_4_ny_anchor_pattern.bp.json create mode 100644 fieldtests/construction-args/ca_4_ny_anchor_pattern.ops.json create mode 100644 fieldtests/construction-args/ca_4_pattern.build.err diff --git a/fieldtests/construction-args/TRANSCRIPT.md b/fieldtests/construction-args/TRANSCRIPT.md new file mode 100644 index 0000000..5f304bc --- /dev/null +++ b/fieldtests/construction-args/TRANSCRIPT.md @@ -0,0 +1,217 @@ +# Fieldtest transcript — cycle #271 (typed construction args) + +Verbatim command/output capture for the `fieldtests/construction-args/` fixtures. +Binary: `target/debug/aura` built from HEAD `6ca359a` via `cargo build --workspace` +(debug profile). Runs used a scratch project `aura new ca_lab` (in `/tmp/ca_lab`); +real data resolved from the built-in archive (`/mnt/tickdata/Pepperstone`). All +op-scripts authored from the public interface only (README, authoring guide, +glossary, design ledger C24, `aura graph introspect`). + +Public interface only — no crate source read. + +--- + +## Discovery loop (axis 3) — is the args grammar learnable from the binary? + +``` +$ aura graph introspect --vocabulary | wc -l +36 + +$ aura graph introspect --node Session +Session — bars elapsed since the session open, from the configured open time and timezone + arg tz: Tz (IANA timezone name, e.g. Europe/Berlin) + arg open: TimeOfDay (local wall-clock HH:MM) + note ports and params form at construction; args are required + +$ aura graph introspect --node LinComb +LinComb — linear combination of its inputs with constant weights + arg arity: Count (positive integer count) + note ports and params form at construction; args are required + +$ aura graph introspect --node CostSum +CostSum — sums cost-model contributions into one cost-in-R stream + arg n_costs: Count (positive integer count) + note ports and params form at construction; args are required +``` + +The arg *grammar* (name, kind, hint) is fully self-describing. But `--node ` +stops at the note — it does NOT reveal the post-construction ports/params. To +learn the port names you must author a partial op-list carrying the args and pipe +it through `--unwired`; to learn the param names you must build and `--list-axes`. +Nothing on the `--node` surface names those follow-up steps. First naive guess at +LinComb's input port was `lc.in0` — wrong: + +``` +$ echo '[{"op":"add","type":"LinComb","name":"lc","args":{"arity":"3"}}]' \ + | aura graph introspect --unwired +lc.term[0]:F64 +lc.term[1]:F64 +lc.term[2]:F64 + +$ echo '[{"op":"add","type":"CostSum","name":"cs","args":{"n_costs":"3"}}]' \ + | aura graph introspect --unwired +cs.cost[0].cost_in_r:F64 +cs.cost[0].cum_cost_in_r:F64 +cs.cost[0].open_cost_in_r:F64 +cs.cost[1].cost_in_r:F64 (… ×3 slots, 3 fields each) +``` + +Weight param names, discovered only after a build: + +``` +$ aura graph build < lc_probe.ops.json > lc_probe.bp.json +$ aura sweep lc_probe.bp.json --list-axes +graph.lc.weights[0]:F64 # open by default → sweepable (C24) +graph.lc.weights[1]:F64 +... +``` + +--- + +## Example 1 — `ca_1_ny_session` (axis 1: non-Frankfurt Session as data) + +``` +$ aura graph build < ca_1_ny_session.ops.json > ca_1_ny_session.bp.json +$ head -c 25 ca_1_ny_session.bp.json +{"format_version":2,"blue # arg-bearing → v2 + +$ aura graph introspect --content-id --identity-id < ca_1_ny_session.ops.json +5b085a5b3f411072e48d4b54717b3d09e88be50b0bd797d345c2ee90baa41c37 # content id +4bf0513a4d2e852ab580fd8846737f57c1825b944ff9df1a48040a07fe92446b # identity id + +# --- inside ca_lab/ --- +$ aura run ca_1_ny_session.bp.json --real US500 --from 1725148800000 --to 1725580800000 +{"manifest":{... "topology_hash":"5b085a5b...b40d95cf"? -> 5b085a5b... (== content id) ...}, + "metrics":{... "expectancy_r":0.7853745294474523,"n_trades":18 ...}} (exit 0) + +# synthetic refuses cleanly (OHLC strategy, close-only synthetic stream): +$ aura run ca_1_ny_session.bp.json +aura: strategy "graph" consumes columns beyond close (open, high, low) — + synthetic data generates a close series only; run with --real +``` + +Full report captured in `ca_1_ny_session.run.json`. + +--- + +## Example 2 — `ca_2_lincomb_blend` (axis 2: LinComb arity + weights + swept period) + +Three SMA spreads blended through `LinComb(arity 3)` with bound `weights[i]`, +NY-session-gated, `Session.period_minutes` left OPEN (sweepable). + +``` +$ aura graph build < ca_2_lincomb_blend.ops.json > ca_2_lincomb_blend.bp.json +$ head -c 25 ca_2_lincomb_blend.bp.json +{"format_version":2,"blue + +$ aura sweep ca_2_lincomb_blend.bp.json --list-axes +graph.sess.period_minutes:I64 # open +graph.lc.weights[0]:F64 default=0.5 # bound (re-openable by --axis) +graph.lc.weights[1]:F64 default=0.3 +graph.lc.weights[2]:F64 default=0.2 +... + +# --- inside ca_lab/ --- sweep the arity-unlocked weight AND the period param: +$ aura sweep ca_2_lincomb_blend.bp.json --real US500 --from 1725148800000 --to 1725580800000 \ + --axis graph.sess.period_minutes=15,30 --axis 'graph.lc.weights[0]=0.3,0.5' --name ca2_blend +{"family_id":"caa3508a-0-US500-w0-r0-s0-0", ... 4 members ...} (exit 0) + +$ aura reproduce caa3508a-0-US500-w0-r0-s0-0 +... member graph.lc.weights[0]=0.3, graph.sess.period_minutes=15 ... reproduced: bit-identical +... (×4) +reproduced 4/4 members bit-identically +``` + +Sweep output in `ca_2_lincomb_blend.sweep.jsonl`. NB: at this gating, the two +`weights[0]` values yield identical member metrics (the gated blend's sign is +weight-insensitive here) — a semantic property of the strategy, not the arg +channel; the params bound and swept correctly. + +CostSum arity probe: `ca_2b_costsum_arity.ops.json` → `--unwired` shows +`cost[i].{cost_in_r,cum_cost_in_r,open_cost_in_r}` (3 slots × 3 fields). Wiring +CostSum end to end needs the RiskExecutor context (cost nodes take +`closed/open/entry_price/stop_price`) — no op-script path for that exists in the +public corpus (see finding SG2). + +--- + +## Example 3 — refusal battery (axis 4: strict-form refusal prose) + +Every case: `aura graph build < FIXTURE`, stderr + exit code. + +``` +ca_3a_bad_tz aura: op 1 (add): node sess arg "tz" expects Tz (IANA timezone name, e.g. Europe/Berlin) — got "berlin" exit 1 +ca_3b_unpadded_time aura: op 1 (add): node sess arg "open" expects TimeOfDay (local wall-clock HH:MM) — got "9:30" exit 1 +ca_3c_zero_count aura: op 2 (add): node lc arg "arity" expects Count (positive integer count) — got "0" exit 1 +ca_3d_garbage_count aura: op 1 (add): node lc arg "arity" expects Count (positive integer count) — got "three" exit 1 +ca_3e_missing_arg aura: op 1 (add): node sess is missing required arg "tz" exit 1 +ca_3f_args_on_argless aura: op 1 (add): node a takes no construction args exit 1 +ca_3g_unknown_arg_key aura: op 1 (add): node sess has no construction arg "region" exit 1 +ca_3h_partial_args aura: op 1 (add): node sess is missing required arg "open" exit 1 +``` + +Edge-form strictness (ad-hoc, `--unwired`): + +``` +Count arity: "3"→ok "03"→refuse "+3"→refuse "3.0"→refuse "1e1"→refuse "-2"→refuse " 3"→refuse "0x3"→refuse +Time open: "09:30"→ok "00:00"→ok "23:59"→ok "24:00"→refuse "09:60"→refuse "9:05"→refuse "09:5"→refuse "09:30:00"→refuse "0930"→refuse +``` + +Note the padding asymmetry: `open` REQUIRES a zero-padded hour (`09:05`), but +`arity` REFUSES a leading zero (`03`). See finding SG1. + +--- + +## Example 4 — `ca_4` register → use (axis 5: #317 interplay) + +``` +$ aura graph build < ca_4_ny_anchor_pattern.ops.json > ca_4_ny_anchor_pattern.bp.json +$ head -c 25 ca_4_ny_anchor_pattern.bp.json +{"format_version":2,"blue +$ aura graph introspect --content-id --identity-id < ca_4_ny_anchor_pattern.ops.json +d51132463b2d1780b3ed9b83dc9f9a229a9d6b93fce3e15c7c0572970e2e4564 +863c89ddeaa2dfe7d79c7e55944263145399c67397a27c0955bdd768cc6ed72e + +# --- inside ca_lab/ --- +$ aura graph register .../ca_4_ny_anchor_pattern.bp.json --name ny_anchor +registered blueprint d51132463b2d... (.../runs/blueprints/d51132463b2d....json) +label "ny_anchor" -> d51132463b2d... + +$ aura graph introspect --registered +ny_anchor d51132463b2d NY cash-open session anchor: bars elapsed since the 09:30 America/New_York open + +$ aura graph build < ca_4_consumer.ops.json > consumer.bp.json +# stderr: aura: note: use "anchor": ny_anchor -> d51132463b2d... +$ head -c 25 consumer.bp.json +{"format_version":2,"blue # v2 propagates THROUGH the splice +$ aura graph introspect --content-id --identity-id < ca_4_consumer.ops.json +985991f62cc6b92895018312c5ea86e493ef1c09dd53cf6e0813551baa97b671 +bbe7060f4136255e594e1b01242ae80c3f5decfc543f23198d66adff6ce52a7b + +$ aura run consumer.bp.json --real US500 --from 1725148800000 --to 1725580800000 +{"manifest":{... "topology_hash":"985991f6..." (== content id), + "defaults":[["graph.anchor.sess.period_minutes",{"I64":15}], ...] ...}, + "metrics":{... "n_trades":8 ...}} (exit 0) + +# doc gate on the args-bearing composite (doc stripped): +$ aura graph register ca4_docless.bp.json --name ny_docless +aura: blueprint: composite `graph` carries no doc — a registered composite + describes itself (C29); add a doc line (...) before register exit 1 +``` + +Consumer report captured in `ca_4_consumer.run.json`. + +--- + +## Cross-cutting confirmations + +``` +# args-free document stays format_version 1 (byte-stability invariant, C18): +$ echo '[{"op":"source",...},{"op":"add","type":"SMA",...},...]' | aura graph build | head -c 25 +{"format_version":1,"blue + +# content id deterministic across builds: +$ aura graph introspect --content-id < ca_1_ny_session.ops.json (×2) -> identical +5b085a5b3f411072e48d4b54717b3d09e88be50b0bd797d345c2ee90baa41c37 +5b085a5b3f411072e48d4b54717b3d09e88be50b0bd797d345c2ee90baa41c37 +``` diff --git a/fieldtests/construction-args/ca_1_ny_session.bp.json b/fieldtests/construction-args/ca_1_ny_session.bp.json new file mode 100644 index 0000000..649127a --- /dev/null +++ b/fieldtests/construction-args/ca_1_ny_session.bp.json @@ -0,0 +1 @@ +{"format_version":2,"blueprint":{"name":"graph","nodes":[{"primitive":{"type":"Resample","name":"c15","bound":[{"pos":0,"name":"period_minutes","kind":"I64","value":{"I64":15}}]}},{"primitive":{"type":"Sub","name":"body"}},{"primitive":{"type":"Sign","name":"dir"}},{"primitive":{"type":"Session","name":"sess","args":[{"name":"tz","value":"America/New_York"},{"name":"open","value":"09:30"}],"bound":[{"pos":0,"name":"period_minutes","kind":"I64","value":{"I64":15}}]}},{"primitive":{"type":"EqConst","name":"isfirst","bound":[{"pos":0,"name":"target","kind":"I64","value":{"I64":1}}]}},{"primitive":{"type":"When","name":"firstmom"}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":1.0}}]}}],"edges":[{"from":0,"to":1,"slot":0,"from_field":3},{"from":0,"to":1,"slot":1,"from_field":0},{"from":1,"to":2,"slot":0,"from_field":0},{"from":0,"to":3,"slot":0,"from_field":3},{"from":3,"to":4,"slot":0,"from_field":0},{"from":2,"to":5,"slot":0,"from_field":0},{"from":4,"to":5,"slot":1,"from_field":0},{"from":5,"to":6,"slot":0,"from_field":0}],"input_roles":[{"name":"open","targets":[{"node":0,"slot":0}],"source":"F64"},{"name":"high","targets":[{"node":0,"slot":1}],"source":"F64"},{"name":"low","targets":[{"node":0,"slot":2}],"source":"F64"},{"name":"close","targets":[{"node":0,"slot":3}],"source":"F64"}],"output":[{"node":6,"field":0,"name":"bias"}]}} \ No newline at end of file diff --git a/fieldtests/construction-args/ca_1_ny_session.build.err b/fieldtests/construction-args/ca_1_ny_session.build.err new file mode 100644 index 0000000..e69de29 diff --git a/fieldtests/construction-args/ca_1_ny_session.ops.json b/fieldtests/construction-args/ca_1_ny_session.ops.json new file mode 100644 index 0000000..6578c8e --- /dev/null +++ b/fieldtests/construction-args/ca_1_ny_session.ops.json @@ -0,0 +1,28 @@ +[ + {"op": "source", "role": "open", "kind": "F64"}, + {"op": "source", "role": "high", "kind": "F64"}, + {"op": "source", "role": "low", "kind": "F64"}, + {"op": "source", "role": "close", "kind": "F64"}, + {"op": "add", "type": "Resample", "name": "c15", "bind": {"period_minutes": {"I64": 15}}}, + {"op": "feed", "role": "open", "into": ["c15.open"]}, + {"op": "feed", "role": "high", "into": ["c15.high"]}, + {"op": "feed", "role": "low", "into": ["c15.low"]}, + {"op": "feed", "role": "close", "into": ["c15.close"]}, + {"op": "add", "type": "Sub", "name": "body"}, + {"op": "connect", "from": "c15.close", "to": "body.lhs"}, + {"op": "connect", "from": "c15.open", "to": "body.rhs"}, + {"op": "add", "type": "Sign", "name": "dir"}, + {"op": "connect", "from": "body.value", "to": "dir.value"}, + {"op": "add", "type": "Session", "name": "sess", + "args": {"tz": "America/New_York", "open": "09:30"}, + "bind": {"period_minutes": {"I64": 15}}}, + {"op": "connect", "from": "c15.close", "to": "sess.trigger"}, + {"op": "add", "type": "EqConst", "name": "isfirst", "bind": {"target": {"I64": 1}}}, + {"op": "connect", "from": "sess.bars_since_open", "to": "isfirst.value"}, + {"op": "add", "type": "When", "name": "firstmom"}, + {"op": "connect", "from": "dir.value", "to": "firstmom.value"}, + {"op": "connect", "from": "isfirst.value", "to": "firstmom.gate"}, + {"op": "add", "type": "Bias", "name": "bias", "bind": {"scale": {"F64": 1.0}}}, + {"op": "connect", "from": "firstmom.value", "to": "bias.signal"}, + {"op": "expose", "from": "bias.bias", "as": "bias"} +] diff --git a/fieldtests/construction-args/ca_1_ny_session.run.json b/fieldtests/construction-args/ca_1_ny_session.run.json new file mode 100644 index 0000000..9717824 --- /dev/null +++ b/fieldtests/construction-args/ca_1_ny_session.run.json @@ -0,0 +1,65 @@ +{ + "manifest": { + "commit": "6ca359ae00e8e7921f08557be383bc2d0a2ce199", + "params": [], + "defaults": [ + [ + "graph.c15.period_minutes", + { + "I64": 15 + } + ], + [ + "graph.sess.period_minutes", + { + "I64": 15 + } + ], + [ + "graph.isfirst.target", + { + "I64": 1 + } + ], + [ + "graph.bias.scale", + { + "F64": 1.0 + } + ] + ], + "window": [ + 1725235200000000000, + 1725580800000000000 + ], + "seed": 0, + "broker": "sim-optimal+risk-executor(pip_size=1)", + "topology_hash": "5b085a5b3f411072e48d4b54717b3d09e88be50b0bd797d345c2ee90baa41c37", + "project": { + "commit": "d7e3a8f39881cc8eba42a906fa846676bfbb1010" + } + }, + "metrics": { + "total_pips": 8.700000000000728, + "max_drawdown": 77.0, + "bias_sign_flips": 2, + "r": { + "expectancy_r": 0.7853745294474523, + "n_trades": 18, + "win_rate": 0.1111111111111111, + "avg_win_r": 17.115118267387366, + "avg_loss_r": -1.2558434377950367, + "profit_factor": 1.7035481645543986, + "max_r_drawdown": 16.041140339815094, + "n_open_at_end": 1, + "sqn": 0.4343599983483773, + "sqn_normalized": 0.4343599983483773, + "net_expectancy_r": 0.7853745294474523, + "conviction_terciles_r": [ + -1.3650686711197901, + -1.2338202185443914, + 4.955012478006539 + ] + } + } +} diff --git a/fieldtests/construction-args/ca_2_lincomb_blend.bp.json b/fieldtests/construction-args/ca_2_lincomb_blend.bp.json new file mode 100644 index 0000000..9556335 --- /dev/null +++ b/fieldtests/construction-args/ca_2_lincomb_blend.bp.json @@ -0,0 +1 @@ +{"format_version":2,"blueprint":{"name":"graph","doc":"NY-session-gated blend of three SMA spreads via a LinComb(arity 3); sweepable session period","nodes":[{"primitive":{"type":"SMA","name":"a","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":2}}]}},{"primitive":{"type":"SMA","name":"b","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":5}}]}},{"primitive":{"type":"SMA","name":"c","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":10}}]}},{"primitive":{"type":"Sub","name":"sA"}},{"primitive":{"type":"Sub","name":"sB"}},{"primitive":{"type":"Sub","name":"sC"}},{"primitive":{"type":"LinComb","name":"lc","args":[{"name":"arity","value":"3"}],"bound":[{"pos":0,"name":"weights[0]","kind":"F64","value":{"F64":0.5}},{"pos":1,"name":"weights[1]","kind":"F64","value":{"F64":0.3}},{"pos":2,"name":"weights[2]","kind":"F64","value":{"F64":0.2}}]}},{"primitive":{"type":"Session","name":"sess","args":[{"name":"tz","value":"America/New_York"},{"name":"open","value":"09:30"}]}},{"primitive":{"type":"EqConst","name":"insession","bound":[{"pos":0,"name":"target","kind":"I64","value":{"I64":1}}]}},{"primitive":{"type":"When","name":"gated"}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":1.0}}]}}],"edges":[{"from":0,"to":3,"slot":0,"from_field":0},{"from":2,"to":3,"slot":1,"from_field":0},{"from":1,"to":4,"slot":0,"from_field":0},{"from":2,"to":4,"slot":1,"from_field":0},{"from":0,"to":5,"slot":0,"from_field":0},{"from":1,"to":5,"slot":1,"from_field":0},{"from":3,"to":6,"slot":0,"from_field":0},{"from":4,"to":6,"slot":1,"from_field":0},{"from":5,"to":6,"slot":2,"from_field":0},{"from":7,"to":8,"slot":0,"from_field":0},{"from":6,"to":9,"slot":0,"from_field":0},{"from":8,"to":9,"slot":1,"from_field":0},{"from":9,"to":10,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0},{"node":2,"slot":0},{"node":7,"slot":0}],"source":"F64"}],"output":[{"node":10,"field":0,"name":"bias"}]}} \ No newline at end of file diff --git a/fieldtests/construction-args/ca_2_lincomb_blend.build.err b/fieldtests/construction-args/ca_2_lincomb_blend.build.err new file mode 100644 index 0000000..e69de29 diff --git a/fieldtests/construction-args/ca_2_lincomb_blend.ops.json b/fieldtests/construction-args/ca_2_lincomb_blend.ops.json new file mode 100644 index 0000000..42acb4d --- /dev/null +++ b/fieldtests/construction-args/ca_2_lincomb_blend.ops.json @@ -0,0 +1,33 @@ +[ + {"op": "doc", "text": "NY-session-gated blend of three SMA spreads via a LinComb(arity 3); sweepable session period"}, + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "SMA", "name": "a", "bind": {"length": {"I64": 2}}}, + {"op": "add", "type": "SMA", "name": "b", "bind": {"length": {"I64": 5}}}, + {"op": "add", "type": "SMA", "name": "c", "bind": {"length": {"I64": 10}}}, + {"op": "feed", "role": "price", "into": ["a.series", "b.series", "c.series"]}, + {"op": "add", "type": "Sub", "name": "sA"}, + {"op": "connect", "from": "a.value", "to": "sA.lhs"}, + {"op": "connect", "from": "c.value", "to": "sA.rhs"}, + {"op": "add", "type": "Sub", "name": "sB"}, + {"op": "connect", "from": "b.value", "to": "sB.lhs"}, + {"op": "connect", "from": "c.value", "to": "sB.rhs"}, + {"op": "add", "type": "Sub", "name": "sC"}, + {"op": "connect", "from": "a.value", "to": "sC.lhs"}, + {"op": "connect", "from": "b.value", "to": "sC.rhs"}, + {"op": "add", "type": "LinComb", "name": "lc", "args": {"arity": "3"}, + "bind": {"weights[0]": {"F64": 0.5}, "weights[1]": {"F64": 0.3}, "weights[2]": {"F64": 0.2}}}, + {"op": "connect", "from": "sA.value", "to": "lc.term[0]"}, + {"op": "connect", "from": "sB.value", "to": "lc.term[1]"}, + {"op": "connect", "from": "sC.value", "to": "lc.term[2]"}, + {"op": "add", "type": "Session", "name": "sess", + "args": {"tz": "America/New_York", "open": "09:30"}}, + {"op": "feed", "role": "price", "into": ["sess.trigger"]}, + {"op": "add", "type": "EqConst", "name": "insession", "bind": {"target": {"I64": 1}}}, + {"op": "connect", "from": "sess.bars_since_open", "to": "insession.value"}, + {"op": "add", "type": "When", "name": "gated"}, + {"op": "connect", "from": "lc.value", "to": "gated.value"}, + {"op": "connect", "from": "insession.value", "to": "gated.gate"}, + {"op": "add", "type": "Bias", "name": "bias", "bind": {"scale": {"F64": 1.0}}}, + {"op": "connect", "from": "gated.value", "to": "bias.signal"}, + {"op": "expose", "from": "bias.bias", "as": "bias"} +] diff --git a/fieldtests/construction-args/ca_2_lincomb_blend.sweep.jsonl b/fieldtests/construction-args/ca_2_lincomb_blend.sweep.jsonl new file mode 100644 index 0000000..f857b89 --- /dev/null +++ b/fieldtests/construction-args/ca_2_lincomb_blend.sweep.jsonl @@ -0,0 +1,4 @@ +{"family_id":"a457bcb1-0-US500-w0-r0-s0-0","report":{"manifest":{"commit":"6ca359ae00e8e7921f08557be383bc2d0a2ce199","params":[["graph.lc.weights[0]",{"F64":0.3}],["graph.sess.period_minutes",{"I64":15}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["graph.a.length",{"I64":2}],["graph.b.length",{"I64":5}],["graph.c.length",{"I64":10}],["graph.lc.weights[1]",{"F64":0.3}],["graph.lc.weights[2]",{"F64":0.2}],["graph.insession.target",{"I64":1}],["graph.bias.scale",{"F64":1.0}]],"window":[1725235200000000000,1725580800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"US500","topology_hash":"ef8e0a4eb23bda78ae3914bb3bcc742314750827498e841fb2a2a7f9aea4c864","project":{"commit":"d7e3a8f39881cc8eba42a906fa846676bfbb1010"}},"metrics":{"total_pips":-96.06109999999117,"max_drawdown":137.94459999999816,"bias_sign_flips":10,"r":{"expectancy_r":-0.709681826087026,"n_trades":37,"win_rate":0.13513513513513514,"avg_win_r":3.454890860540305,"avg_loss_r":-1.3603963083725465,"profit_factor":0.3968157614344175,"max_r_drawdown":28.676655116297415,"n_open_at_end":1,"sqn":-1.7501753655158518,"sqn_normalized":-1.7501753655158518,"net_expectancy_r":-0.709681826087026,"conviction_terciles_r":[0.010138828240044861,-1.4112281254600723,-0.7265504614292024]}}}} +{"family_id":"a457bcb1-0-US500-w0-r0-s0-0","report":{"manifest":{"commit":"6ca359ae00e8e7921f08557be383bc2d0a2ce199","params":[["graph.lc.weights[0]",{"F64":0.3}],["graph.sess.period_minutes",{"I64":30}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["graph.a.length",{"I64":2}],["graph.b.length",{"I64":5}],["graph.c.length",{"I64":10}],["graph.lc.weights[1]",{"F64":0.3}],["graph.lc.weights[2]",{"F64":0.2}],["graph.insession.target",{"I64":1}],["graph.bias.scale",{"F64":1.0}]],"window":[1725235200000000000,1725580800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"US500","topology_hash":"ef8e0a4eb23bda78ae3914bb3bcc742314750827498e841fb2a2a7f9aea4c864","project":{"commit":"d7e3a8f39881cc8eba42a906fa846676bfbb1010"}},"metrics":{"total_pips":-53.55989999998029,"max_drawdown":120.4151999999832,"bias_sign_flips":18,"r":{"expectancy_r":-0.05940492516372425,"n_trades":34,"win_rate":0.23529411764705882,"avg_win_r":3.3843995517241234,"avg_loss_r":-1.1190370718984466,"profit_factor":0.9305801696597508,"max_r_drawdown":18.95335695076066,"n_open_at_end":1,"sqn":-0.13880221854288846,"sqn_normalized":-0.13880221854288846,"net_expectancy_r":-0.05940492516372425,"conviction_terciles_r":[0.92760843970395,-1.1133959931000275,0.001991302649185419]}}}} +{"family_id":"a457bcb1-0-US500-w0-r0-s0-0","report":{"manifest":{"commit":"6ca359ae00e8e7921f08557be383bc2d0a2ce199","params":[["graph.lc.weights[0]",{"F64":0.5}],["graph.sess.period_minutes",{"I64":15}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["graph.a.length",{"I64":2}],["graph.b.length",{"I64":5}],["graph.c.length",{"I64":10}],["graph.lc.weights[1]",{"F64":0.3}],["graph.lc.weights[2]",{"F64":0.2}],["graph.insession.target",{"I64":1}],["graph.bias.scale",{"F64":1.0}]],"window":[1725235200000000000,1725580800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"US500","topology_hash":"ef8e0a4eb23bda78ae3914bb3bcc742314750827498e841fb2a2a7f9aea4c864","project":{"commit":"d7e3a8f39881cc8eba42a906fa846676bfbb1010"}},"metrics":{"total_pips":-90.72209999998813,"max_drawdown":138.7875999999975,"bias_sign_flips":10,"r":{"expectancy_r":-0.709681826087026,"n_trades":37,"win_rate":0.13513513513513514,"avg_win_r":3.454890860540305,"avg_loss_r":-1.3603963083725465,"profit_factor":0.3968157614344175,"max_r_drawdown":28.676655116297415,"n_open_at_end":1,"sqn":-1.7501753655158518,"sqn_normalized":-1.7501753655158518,"net_expectancy_r":-0.709681826087026,"conviction_terciles_r":[0.010138828240044861,-1.294302553607114,-0.8344817585242409]}}}} +{"family_id":"a457bcb1-0-US500-w0-r0-s0-0","report":{"manifest":{"commit":"6ca359ae00e8e7921f08557be383bc2d0a2ce199","params":[["graph.lc.weights[0]",{"F64":0.5}],["graph.sess.period_minutes",{"I64":30}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"defaults":[["graph.a.length",{"I64":2}],["graph.b.length",{"I64":5}],["graph.c.length",{"I64":10}],["graph.lc.weights[1]",{"F64":0.3}],["graph.lc.weights[2]",{"F64":0.2}],["graph.insession.target",{"I64":1}],["graph.bias.scale",{"F64":1.0}]],"window":[1725235200000000000,1725580800000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"US500","topology_hash":"ef8e0a4eb23bda78ae3914bb3bcc742314750827498e841fb2a2a7f9aea4c864","project":{"commit":"d7e3a8f39881cc8eba42a906fa846676bfbb1010"}},"metrics":{"total_pips":-49.96429999999597,"max_drawdown":125.2664000000041,"bias_sign_flips":18,"r":{"expectancy_r":-0.05940492516372425,"n_trades":34,"win_rate":0.23529411764705882,"avg_win_r":3.3843995517241234,"avg_loss_r":-1.1190370718984466,"profit_factor":0.9305801696597508,"max_r_drawdown":18.95335695076066,"n_open_at_end":1,"sqn":-0.13880221854288846,"sqn_normalized":-0.13880221854288846,"net_expectancy_r":-0.05940492516372425,"conviction_terciles_r":[0.92760843970395,-0.9291244696270301,-0.16692426053439502]}}}} diff --git a/fieldtests/construction-args/ca_2b_costsum_arity.ops.json b/fieldtests/construction-args/ca_2b_costsum_arity.ops.json new file mode 100644 index 0000000..3795e13 --- /dev/null +++ b/fieldtests/construction-args/ca_2b_costsum_arity.ops.json @@ -0,0 +1,3 @@ +[ + {"op": "add", "type": "CostSum", "name": "cs", "args": {"n_costs": "3"}} +] diff --git a/fieldtests/construction-args/ca_3a_bad_tz.ops.json b/fieldtests/construction-args/ca_3a_bad_tz.ops.json new file mode 100644 index 0000000..66db09f --- /dev/null +++ b/fieldtests/construction-args/ca_3a_bad_tz.ops.json @@ -0,0 +1,8 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "Session", "name": "sess", + "args": {"tz": "berlin", "open": "09:30"}, + "bind": {"period_minutes": {"I64": 15}}}, + {"op": "feed", "role": "price", "into": ["sess.trigger"]}, + {"op": "expose", "from": "sess.bars_since_open", "as": "bars"} +] diff --git a/fieldtests/construction-args/ca_3b_unpadded_time.ops.json b/fieldtests/construction-args/ca_3b_unpadded_time.ops.json new file mode 100644 index 0000000..5aad6ab --- /dev/null +++ b/fieldtests/construction-args/ca_3b_unpadded_time.ops.json @@ -0,0 +1,8 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "Session", "name": "sess", + "args": {"tz": "America/New_York", "open": "9:30"}, + "bind": {"period_minutes": {"I64": 15}}}, + {"op": "feed", "role": "price", "into": ["sess.trigger"]}, + {"op": "expose", "from": "sess.bars_since_open", "as": "bars"} +] diff --git a/fieldtests/construction-args/ca_3c_zero_count.ops.json b/fieldtests/construction-args/ca_3c_zero_count.ops.json new file mode 100644 index 0000000..132aaf1 --- /dev/null +++ b/fieldtests/construction-args/ca_3c_zero_count.ops.json @@ -0,0 +1,7 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "SMA", "name": "a", "bind": {"length": {"I64": 2}}}, + {"op": "add", "type": "LinComb", "name": "lc", "args": {"arity": "0"}}, + {"op": "feed", "role": "price", "into": ["a.series"]}, + {"op": "expose", "from": "lc.value", "as": "out"} +] diff --git a/fieldtests/construction-args/ca_3d_garbage_count.ops.json b/fieldtests/construction-args/ca_3d_garbage_count.ops.json new file mode 100644 index 0000000..66b65f6 --- /dev/null +++ b/fieldtests/construction-args/ca_3d_garbage_count.ops.json @@ -0,0 +1,5 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "LinComb", "name": "lc", "args": {"arity": "three"}}, + {"op": "expose", "from": "lc.value", "as": "out"} +] diff --git a/fieldtests/construction-args/ca_3e_missing_arg.ops.json b/fieldtests/construction-args/ca_3e_missing_arg.ops.json new file mode 100644 index 0000000..a58bedd --- /dev/null +++ b/fieldtests/construction-args/ca_3e_missing_arg.ops.json @@ -0,0 +1,7 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "Session", "name": "sess", + "bind": {"period_minutes": {"I64": 15}}}, + {"op": "feed", "role": "price", "into": ["sess.trigger"]}, + {"op": "expose", "from": "sess.bars_since_open", "as": "bars"} +] diff --git a/fieldtests/construction-args/ca_3f_args_on_argless.ops.json b/fieldtests/construction-args/ca_3f_args_on_argless.ops.json new file mode 100644 index 0000000..8c0e8f0 --- /dev/null +++ b/fieldtests/construction-args/ca_3f_args_on_argless.ops.json @@ -0,0 +1,8 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "SMA", "name": "a", + "args": {"window": "3"}, + "bind": {"length": {"I64": 2}}}, + {"op": "feed", "role": "price", "into": ["a.series"]}, + {"op": "expose", "from": "a.value", "as": "out"} +] diff --git a/fieldtests/construction-args/ca_3g_unknown_arg_key.ops.json b/fieldtests/construction-args/ca_3g_unknown_arg_key.ops.json new file mode 100644 index 0000000..77178ef --- /dev/null +++ b/fieldtests/construction-args/ca_3g_unknown_arg_key.ops.json @@ -0,0 +1,8 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "Session", "name": "sess", + "args": {"tz": "America/New_York", "open": "09:30", "region": "east"}, + "bind": {"period_minutes": {"I64": 15}}}, + {"op": "feed", "role": "price", "into": ["sess.trigger"]}, + {"op": "expose", "from": "sess.bars_since_open", "as": "bars"} +] diff --git a/fieldtests/construction-args/ca_3h_partial_args.ops.json b/fieldtests/construction-args/ca_3h_partial_args.ops.json new file mode 100644 index 0000000..7874708 --- /dev/null +++ b/fieldtests/construction-args/ca_3h_partial_args.ops.json @@ -0,0 +1,8 @@ +[ + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "add", "type": "Session", "name": "sess", + "args": {"tz": "America/New_York"}, + "bind": {"period_minutes": {"I64": 15}}}, + {"op": "feed", "role": "price", "into": ["sess.trigger"]}, + {"op": "expose", "from": "sess.bars_since_open", "as": "bars"} +] diff --git a/fieldtests/construction-args/ca_4_consumer.bp.json b/fieldtests/construction-args/ca_4_consumer.bp.json new file mode 100644 index 0000000..97afd62 --- /dev/null +++ b/fieldtests/construction-args/ca_4_consumer.bp.json @@ -0,0 +1 @@ +{"format_version":2,"blueprint":{"name":"graph","doc":"consumer: splice the NY session anchor by name, go long 1.0 on the first session bar, flat otherwise","nodes":[{"composite":{"name":"anchor","doc":"NY cash-open session anchor: bars elapsed since the 09:30 America/New_York open","nodes":[{"primitive":{"type":"Session","name":"sess","args":[{"name":"tz","value":"America/New_York"},{"name":"open","value":"09:30"}],"bound":[{"pos":0,"name":"period_minutes","kind":"I64","value":{"I64":15}}]}}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0}]}],"output":[{"node":0,"field":0,"name":"bars"}]}},{"primitive":{"type":"EqConst","name":"isfirst","bound":[{"pos":0,"name":"target","kind":"I64","value":{"I64":1}}]}},{"primitive":{"type":"Const","name":"one","bound":[{"pos":0,"name":"value","kind":"F64","value":{"F64":1.0}}]}},{"primitive":{"type":"Const","name":"zero","bound":[{"pos":0,"name":"value","kind":"F64","value":{"F64":0.0}}]}},{"primitive":{"type":"Select","name":"sel"}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":1.0}}]}}],"edges":[{"from":0,"to":1,"slot":0,"from_field":0},{"from":1,"to":4,"slot":0,"from_field":0},{"from":2,"to":4,"slot":1,"from_field":0},{"from":3,"to":4,"slot":2,"from_field":0},{"from":4,"to":5,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":2,"slot":0},{"node":3,"slot":0}],"source":"F64"}],"output":[{"node":5,"field":0,"name":"bias"}]}} \ No newline at end of file diff --git a/fieldtests/construction-args/ca_4_consumer.ops.json b/fieldtests/construction-args/ca_4_consumer.ops.json new file mode 100644 index 0000000..04e9a49 --- /dev/null +++ b/fieldtests/construction-args/ca_4_consumer.ops.json @@ -0,0 +1,19 @@ +[ + {"op": "doc", "text": "consumer: splice the NY session anchor by name, go long 1.0 on the first session bar, flat otherwise"}, + {"op": "source", "role": "price", "kind": "F64"}, + {"op": "use", "ref": {"name": "ny_anchor"}, "name": "anchor"}, + {"op": "feed", "role": "price", "into": ["anchor.price"]}, + {"op": "add", "type": "EqConst", "name": "isfirst", "bind": {"target": {"I64": 1}}}, + {"op": "connect", "from": "anchor.bars", "to": "isfirst.value"}, + {"op": "add", "type": "Const", "name": "one", "bind": {"value": {"F64": 1.0}}}, + {"op": "feed", "role": "price", "into": ["one.clock"]}, + {"op": "add", "type": "Const", "name": "zero", "bind": {"value": {"F64": 0.0}}}, + {"op": "feed", "role": "price", "into": ["zero.clock"]}, + {"op": "add", "type": "Select", "name": "sel"}, + {"op": "connect", "from": "isfirst.value", "to": "sel.cond"}, + {"op": "connect", "from": "one.value", "to": "sel.then"}, + {"op": "connect", "from": "zero.value", "to": "sel.otherwise"}, + {"op": "add", "type": "Bias", "name": "bias", "bind": {"scale": {"F64": 1.0}}}, + {"op": "connect", "from": "sel.value", "to": "bias.signal"}, + {"op": "expose", "from": "bias.bias", "as": "bias"} +] diff --git a/fieldtests/construction-args/ca_4_consumer.run.json b/fieldtests/construction-args/ca_4_consumer.run.json new file mode 100644 index 0000000..4cd6bcf --- /dev/null +++ b/fieldtests/construction-args/ca_4_consumer.run.json @@ -0,0 +1,71 @@ +{ + "manifest": { + "commit": "6ca359ae00e8e7921f08557be383bc2d0a2ce199", + "params": [], + "defaults": [ + [ + "graph.anchor.sess.period_minutes", + { + "I64": 15 + } + ], + [ + "graph.isfirst.target", + { + "I64": 1 + } + ], + [ + "graph.one.value", + { + "F64": 1.0 + } + ], + [ + "graph.zero.value", + { + "F64": 0.0 + } + ], + [ + "graph.bias.scale", + { + "F64": 1.0 + } + ] + ], + "window": [ + 1725235200000000000, + 1725580800000000000 + ], + "seed": 0, + "broker": "sim-optimal+risk-executor(pip_size=1)", + "topology_hash": "985991f62cc6b92895018312c5ea86e493ef1c09dd53cf6e0813551baa97b671", + "project": { + "commit": "d7e3a8f39881cc8eba42a906fa846676bfbb1010" + } + }, + "metrics": { + "total_pips": -19.5, + "max_drawdown": 35.5, + "bias_sign_flips": 8, + "r": { + "expectancy_r": -0.7143093152455215, + "n_trades": 8, + "win_rate": 0.125, + "avg_win_r": 2.704952265814223, + "avg_loss_r": -1.2027752553969135, + "profit_factor": 0.32127510981397456, + "max_r_drawdown": 7.371844351604779, + "n_open_at_end": 0, + "sqn": -1.3625154866298599, + "sqn_normalized": -1.3625154866298599, + "net_expectancy_r": -0.7143093152455215, + "conviction_terciles_r": [ + -1.0191864862283455, + -1.1307276003565727, + -0.09463958281258789 + ] + } + } +} diff --git a/fieldtests/construction-args/ca_4_ny_anchor_pattern.bp.json b/fieldtests/construction-args/ca_4_ny_anchor_pattern.bp.json new file mode 100644 index 0000000..3a92d35 --- /dev/null +++ b/fieldtests/construction-args/ca_4_ny_anchor_pattern.bp.json @@ -0,0 +1 @@ +{"format_version":2,"blueprint":{"name":"graph","doc":"NY cash-open session anchor: bars elapsed since the 09:30 America/New_York open","nodes":[{"primitive":{"type":"Session","name":"sess","args":[{"name":"tz","value":"America/New_York"},{"name":"open","value":"09:30"}],"bound":[{"pos":0,"name":"period_minutes","kind":"I64","value":{"I64":15}}]}}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0}]}],"output":[{"node":0,"field":0,"name":"bars"}]}} \ No newline at end of file diff --git a/fieldtests/construction-args/ca_4_ny_anchor_pattern.ops.json b/fieldtests/construction-args/ca_4_ny_anchor_pattern.ops.json new file mode 100644 index 0000000..14e71f6 --- /dev/null +++ b/fieldtests/construction-args/ca_4_ny_anchor_pattern.ops.json @@ -0,0 +1,9 @@ +[ + {"op": "doc", "text": "NY cash-open session anchor: bars elapsed since the 09:30 America/New_York open"}, + {"op": "input", "role": "price"}, + {"op": "add", "type": "Session", "name": "sess", + "args": {"tz": "America/New_York", "open": "09:30"}, + "bind": {"period_minutes": {"I64": 15}}}, + {"op": "feed", "role": "price", "into": ["sess.trigger"]}, + {"op": "expose", "from": "sess.bars_since_open", "as": "bars"} +] diff --git a/fieldtests/construction-args/ca_4_pattern.build.err b/fieldtests/construction-args/ca_4_pattern.build.err new file mode 100644 index 0000000..e69de29