fieldtest: milestone verb-dissolution — 3 scenarios, 8 findings
Milestone-close fieldtest for "Verb dissolution" (#210), authored from the public interface only. Three end-to-end scenarios over the real GER40/USDJPY 2025 archive: 1. all four dissolved verbs on the r-sma real path (sweep via blueprint; generalize/walkforward/mc via --strategy) — correct + deterministic; 2. reach-through — `aura generalize` auto-registers a campaign+process document and `aura campaign run <id>` reproduces worst_case byte-for-byte; 3. a hand-authored 2-instrument × 2-window × 2-regime matrix (8 cells → 4 generalizations) no verb can express — regimes compared, never argmax'd. Result: 0 bugs; the core promise holds empirically (behaviour preservation, campaign-substrate reach-through, and the risk-regime axis all confirmed). Residual findings are discoverability/ergonomics follow-ups, filed as #216 (risk-axis discoverability), #217 (verb knob asymmetry), #218 (no-project store litter). The friction-and-bug spec stays a git-ignored working file.
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
{"family_id":"c9051499-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["graph.fast.length",{"I64":3}],["graph.slow.length",{"I64":12}],["graph.bias.scale",{"F64":0.5}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"window":[1735776899999000000,1751313479999000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"597d719b7ac607158cda3e68cd497387620397a5e93087e23da512876dafba9a"},"metrics":{"total_pips":-2862699.999994523,"max_drawdown":54231416.66667029,"bias_sign_flips":15891,"r":{"expectancy_r":-0.003094165573522419,"n_trades":17257,"win_rate":0.3358057599814568,"avg_win_r":1.7935292472072515,"avg_loss_r":-0.911437620211857,"profit_factor":0.9948888162507548,"max_r_drawdown":566.4995211761315,"n_open_at_end":1,"sqn":-0.1783787608960865,"sqn_normalized":-0.013578771907835513,"net_expectancy_r":-0.003094165573522419,"conviction_terciles_r":[-0.014644128985305857,0.031101557818235325,-0.02573598921419908]}}}}
|
||||
{"family_id":"c9051499-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["graph.fast.length",{"I64":3}],["graph.slow.length",{"I64":20}],["graph.bias.scale",{"F64":0.5}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"window":[1735776899999000000,1751313479999000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"597d719b7ac607158cda3e68cd497387620397a5e93087e23da512876dafba9a"},"metrics":{"total_pips":35241319.999987476,"max_drawdown":31772746.666658945,"bias_sign_flips":11235,"r":{"expectancy_r":0.03257206096854835,"n_trades":12715,"win_rate":0.3163979551710578,"avg_win_r":2.1158491102262986,"avg_loss_r":-0.9316506230125727,"profit_factor":1.0511433070554879,"max_r_drawdown":266.5859374316973,"n_open_at_end":1,"sqn":1.4521422112547406,"sqn_normalized":0.12878075519133622,"net_expectancy_r":0.03257206096854835,"conviction_terciles_r":[0.04920222689976142,0.06716125374424935,-0.018635214851196506]}}}}
|
||||
{"family_id":"c9051499-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["graph.fast.length",{"I64":5}],["graph.slow.length",{"I64":12}],["graph.bias.scale",{"F64":0.5}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"window":[1735776899999000000,1751313479999000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"597d719b7ac607158cda3e68cd497387620397a5e93087e23da512876dafba9a"},"metrics":{"total_pips":20785143.333291434,"max_drawdown":30654553.33336261,"bias_sign_flips":13848,"r":{"expectancy_r":0.019526291202329023,"n_trades":17215,"win_rate":0.35817600929422017,"avg_win_r":1.777196624871446,"avg_loss_r":-0.961358429351912,"profit_factor":1.03164597470791,"max_r_drawdown":373.7780277379172,"n_open_at_end":1,"sqn":1.0889084897621863,"sqn_normalized":0.08299231333366146,"net_expectancy_r":0.019526291202329023,"conviction_terciles_r":[0.004667062062864069,0.03749828968851462,0.01641406424441263]}}}}
|
||||
{"family_id":"c9051499-0-GER40-w0-r0-s0-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["graph.fast.length",{"I64":5}],["graph.slow.length",{"I64":20}],["graph.bias.scale",{"F64":0.5}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"window":[1735776899999000000,1751313479999000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"597d719b7ac607158cda3e68cd497387620397a5e93087e23da512876dafba9a"},"metrics":{"total_pips":18233000.000000946,"max_drawdown":31101689.99998994,"bias_sign_flips":9458,"r":{"expectancy_r":0.039703430408155306,"n_trades":12266,"win_rate":0.3287135170389695,"avg_win_r":2.163314792457502,"avg_loss_r":-1.0001801027206976,"profit_factor":1.0591346347759685,"max_r_drawdown":224.30257453649057,"n_open_at_end":1,"sqn":1.6764291413616224,"sqn_normalized":0.15136787755392725,"net_expectancy_r":0.039703430408155306,"conviction_terciles_r":[0.019293894904215347,0.09570496525941728,0.004106439733979929]}}}}
|
||||
@@ -0,0 +1,2 @@
|
||||
{"generalize":{"metric":"expectancy_r","n_instruments":2,"per_instrument":[["GER40",0.020714763278940063],["USDJPY",-0.02015289368686083]],"sign_agreement":1,"worst_case":-0.02015289368686083}}
|
||||
{"family_id":"generalize-0"}
|
||||
@@ -0,0 +1 @@
|
||||
{"mc_r_bootstrap":{"block_len":5,"e_r":{"mean":-0.0244452745179496,"p25":-0.049478856865015644,"p5":-0.08954647176285867,"p50":-0.02478708119746579,"p75":0.0025705255279945957,"p95":0.04095084752967499},"n_resamples":1000,"n_trades":4188,"prob_le_zero":0.725}}
|
||||
@@ -0,0 +1,4 @@
|
||||
{"family_id":"sweep-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["fast.length",{"I64":3}],["slow.length",{"I64":12}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}],["bias_scale",{"F64":0.5}]],"window":[1735776899999000000,1740775980000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)"},"metrics":{"total_pips":14651566.666678049,"max_drawdown":18136499.999995403,"bias_sign_flips":5517,"r":{"expectancy_r":0.018859228268604623,"n_trades":5933,"win_rate":0.3313669307264453,"avg_win_r":1.8426756303388427,"avg_loss_r":-0.8850034000323995,"profit_factor":1.0318706650340974,"max_r_drawdown":225.25426571034052,"n_open_at_end":1,"sqn":0.6974423376927421,"sqn_normalized":0.09054638856123323,"net_expectancy_r":0.018859228268604623,"conviction_terciles_r":[0.0387351724780272,-0.06440452791147729,0.082257088744931]}}}}
|
||||
{"family_id":"sweep-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["fast.length",{"I64":3}],["slow.length",{"I64":20}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}],["bias_scale",{"F64":0.5}]],"window":[1735776899999000000,1740775980000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)"},"metrics":{"total_pips":19555223.33332326,"max_drawdown":12253393.333338382,"bias_sign_flips":3883,"r":{"expectancy_r":0.024628978003358875,"n_trades":4329,"win_rate":0.30723030723030725,"avg_win_r":2.1545138422487486,"avg_loss_r":-0.9199348330824573,"profit_factor":1.038645634961237,"max_r_drawdown":251.9859393421582,"n_open_at_end":1,"sqn":0.6914750359042567,"sqn_normalized":0.1050951592554701,"net_expectancy_r":0.024628978003358875,"conviction_terciles_r":[0.006462585142108019,0.024349095590771613,0.04307525327719716]}}}}
|
||||
{"family_id":"sweep-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["fast.length",{"I64":5}],["slow.length",{"I64":12}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}],["bias_scale",{"F64":0.5}]],"window":[1735776899999000000,1740775980000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)"},"metrics":{"total_pips":19312446.66667577,"max_drawdown":15871903.333339252,"bias_sign_flips":4750,"r":{"expectancy_r":0.04700233450737109,"n_trades":5894,"win_rate":0.3556158805564981,"avg_win_r":1.8525578436029042,"avg_loss_r":-0.9494285099013277,"profit_factor":1.0768267269441847,"max_r_drawdown":179.24653306247404,"n_open_at_end":1,"sqn":1.5560523190981717,"sqn_normalized":0.2026838426485038,"net_expectancy_r":0.04700233450737109,"conviction_terciles_r":[0.03190319926750814,0.0280326242500623,0.08106349596625315]}}}}
|
||||
{"family_id":"sweep-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["fast.length",{"I64":5}],["slow.length",{"I64":20}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}],["bias_scale",{"F64":0.5}]],"window":[1735776899999000000,1740775980000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)"},"metrics":{"total_pips":18328560.000000566,"max_drawdown":9906540.000002608,"bias_sign_flips":3287,"r":{"expectancy_r":0.04859274367149766,"n_trades":4219,"win_rate":0.3211661531168523,"avg_win_r":2.2340448422497614,"avg_loss_r":-0.9853763881628382,"profit_factor":1.072645008931395,"max_r_drawdown":190.26165498821445,"n_open_at_end":1,"sqn":1.2371118790190263,"sqn_normalized":0.1904601905171822,"net_expectancy_r":0.04859274367149766,"conviction_terciles_r":[0.016145802052213384,0.027383921029859034,0.10221037306087778]}}}}
|
||||
@@ -0,0 +1,3 @@
|
||||
{"family_id":"cdb926b9-0-GER40-w0-r0-s1-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["sma_signal.fast.length",{"I64":3}],["sma_signal.slow.length",{"I64":20}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"window":[1743552899999000000,1746144899998000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","selection":{"selection_metric":"sqn_normalized","n_trials":4,"raw_winner_metric":0.23380026821855684,"mode":"Argmax","deflated_score":-0.02109631640973328,"overfit_probability":0.08691308691308691,"n_resamples":1000,"block_len":5,"seed":0},"instrument":"GER40","topology_hash":"546f4838aca6b0bf67140b5868b4aba18fdc53be57e6cca28bf23588fbf68027"},"metrics":{"total_pips":8183056.666656338,"max_drawdown":18858563.333333366,"bias_sign_flips":1719,"r":{"expectancy_r":-0.01920789380675256,"n_trades":1965,"win_rate":0.3282442748091603,"avg_win_r":1.8618888639654576,"avg_loss_r":-0.9383801731727207,"profit_factor":0.9695288007919832,"max_r_drawdown":137.77315046127524,"n_open_at_end":1,"sqn":-0.3748009115721454,"sqn_normalized":-0.08455111928160124,"net_expectancy_r":-0.01920789380675256,"conviction_terciles_r":[0.10598506453251073,-0.05626494177857611,-0.10734380417419227]}}}}
|
||||
{"family_id":"cdb926b9-0-GER40-w0-r0-s1-0","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["sma_signal.fast.length",{"I64":3}],["sma_signal.slow.length",{"I64":20}],["stop_length",{"I64":3}],["stop_k",{"F64":2.0}]],"window":[1746144899999000000,1748736899998000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","selection":{"selection_metric":"sqn_normalized","n_trials":4,"raw_winner_metric":0.26435292869838395,"mode":"Argmax","deflated_score":0.008500161995362798,"overfit_probability":0.04095904095904096,"n_resamples":1000,"block_len":5,"seed":0},"instrument":"GER40","topology_hash":"546f4838aca6b0bf67140b5868b4aba18fdc53be57e6cca28bf23588fbf68027"},"metrics":{"total_pips":-3961950.0000006165,"max_drawdown":10036766.666671904,"bias_sign_flips":1936,"r":{"expectancy_r":-0.03037327584427613,"n_trades":2223,"win_rate":0.3076923076923077,"avg_win_r":2.0821474859350597,"avg_loss_r":-0.9692713921906461,"profit_factor":0.954736609471486,"max_r_drawdown":115.63656595781805,"n_open_at_end":1,"sqn":-0.5299548162533878,"sqn_normalized":-0.11240072488255289,"net_expectancy_r":-0.03037327584427613,"conviction_terciles_r":[-0.017453577620605926,-0.14329709342399838,0.06963084351177566]}}}}
|
||||
{"walkforward":{"oos_r":{"avg_loss_r":-0.9550089196115396,"avg_win_r":1.9752499605999214,"conviction_terciles_r":[0.0,0.0,0.0],"expectancy_r":-0.025134504186269092,"max_r_drawdown":182.12945308117088,"n_open_at_end":0,"n_trades":4188,"net_expectancy_r":-0.025134504186269092,"profit_factor":0.9614472455342553,"sqn":-0.6482501288192202,"sqn_normalized":-0.10017036937879212,"win_rate":0.3173352435530086},"param_stability":[{"mean":3.0,"p25":3.0,"p5":3.0,"p50":3.0,"p75":3.0,"p95":3.0},{"mean":20.0,"p25":20.0,"p5":20.0,"p50":20.0,"p75":20.0,"p95":20.0},{"mean":3.0,"p25":3.0,"p5":3.0,"p50":3.0,"p75":3.0,"p95":3.0},{"mean":2.0,"p25":2.0,"p5":2.0,"p50":2.0,"p75":2.0,"p95":2.0}],"stitched_total_pips":4221106.666655721,"windows":2}}
|
||||
@@ -0,0 +1,3 @@
|
||||
{"family_id":"18844db5-0-GER40-w0-r0-s0-1","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["sma_signal.fast.length",{"I64":5}],["sma_signal.slow.length",{"I64":20}],["stop_length",{"I64":14}],["stop_k",{"F64":2.0}]],"window":[1735689600000000000,1751328000000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=1)","instrument":"GER40","topology_hash":"546f4838aca6b0bf67140b5868b4aba18fdc53be57e6cca28bf23588fbf68027","project":{"namespace":"mvd_lab","dylib_sha256":"5d344b782a69518e1dcdaec3dc7de1c674f0a4cc8b381b3200f22b20681107c5","commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34-dirty"}},"metrics":{"total_pips":18233000.000000946,"max_drawdown":31101689.99998994,"bias_sign_flips":9458,"r":{"expectancy_r":0.020714763278940063,"n_trades":11954,"win_rate":0.3347833361218002,"avg_win_r":1.9163637943202063,"avg_loss_r":-0.9333077998784003,"profit_factor":1.0333650637863112,"max_r_drawdown":275.50659414385825,"n_open_at_end":1,"sqn":1.0064752069572405,"sqn_normalized":0.09205480352174625,"net_expectancy_r":0.020714763278940063,"conviction_terciles_r":[0.021638082552302703,0.05122661182958574,-0.010720172846380115]}}}}
|
||||
{"family_id":"18844db5-0-USDJPY-w0-r0-s0-1","report":{"manifest":{"commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34","params":[["sma_signal.fast.length",{"I64":5}],["sma_signal.slow.length",{"I64":20}],["stop_length",{"I64":14}],["stop_k",{"F64":2.0}]],"window":[1735689600000000000,1751328000000000000],"seed":0,"broker":"sim-optimal+risk-executor(pip_size=0.01)","instrument":"USDJPY","topology_hash":"546f4838aca6b0bf67140b5868b4aba18fdc53be57e6cca28bf23588fbf68027","project":{"namespace":"mvd_lab","dylib_sha256":"5d344b782a69518e1dcdaec3dc7de1c674f0a4cc8b381b3200f22b20681107c5","commit":"2a7caa6e38bbd7768ad8ef1a4bc5a745f1122e34-dirty"}},"metrics":{"total_pips":-54188.85299999609,"max_drawdown":58066.20499999583,"bias_sign_flips":11638,"r":{"expectancy_r":-0.02015289368686083,"n_trades":14927,"win_rate":0.34353855429758157,"avg_win_r":1.7575394349373088,"avg_loss_r":-0.9504525427515395,"profit_factor":0.9677003547760925,"max_r_drawdown":397.3583054736529,"n_open_at_end":1,"sqn":-1.0814412470315609,"sqn_normalized":-0.08851495715635345,"net_expectancy_r":-0.02015289368686083,"conviction_terciles_r":[0.02290410840773472,-0.028150331805494457,-0.0552038047283186]}}}}
|
||||
{"campaign_run":{"campaign":"18844db5ee31af117fa9f3ed405a11e62f8d99f9795097d22e4f8b4002c4317e","process":"87851fd8c2fd1a42fe48f921c44db6026b67d67a50d3a708783e454552f677ce","run":1,"seed":0,"cells":[{"strategy":"546f4838aca6b0bf67140b5868b4aba18fdc53be57e6cca28bf23588fbf68027","instrument":"GER40","window_ms":[1735689600000,1751328000000],"stages":[{"block":"std::sweep","family_id":"18844db5-0-GER40-w0-r0-s0-1","selection":{"winner_ordinal":0,"params":[["fast.length",{"I64":5}],["slow.length",{"I64":20}]],"selection":{"selection_metric":"expectancy_r","n_trials":1,"raw_winner_metric":0.020714763278940063,"mode":"Argmax"}}}]},{"strategy":"546f4838aca6b0bf67140b5868b4aba18fdc53be57e6cca28bf23588fbf68027","instrument":"USDJPY","window_ms":[1735689600000,1751328000000],"stages":[{"block":"std::sweep","family_id":"18844db5-0-USDJPY-w0-r0-s0-1","selection":{"winner_ordinal":0,"params":[["fast.length",{"I64":5}],["slow.length",{"I64":20}]],"selection":{"selection_metric":"expectancy_r","n_trials":1,"raw_winner_metric":-0.02015289368686083,"mode":"Argmax"}}}]}],"generalizations":[{"strategy_ordinal":0,"window_ordinal":0,"regime_ordinal":0,"generalization":{"selection_metric":"expectancy_r","n_instruments":2,"worst_case":-0.02015289368686083,"sign_agreement":1,"per_instrument":[["GER40",0.020714763278940063],["USDJPY",-0.02015289368686083]]},"winners":[["GER40",[["fast.length",{"I64":5}],["slow.length",{"I64":20}]]],["USDJPY",[["fast.length",{"I64":5}],["slow.length",{"I64":20}]]]]}]}}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
|
||||
{"generalize":{"metric":"expectancy_r","n_instruments":2,"per_instrument":[["GER40",0.020714763278940063],["USDJPY",-0.02015289368686083]],"sign_agreement":1,"worst_case":-0.02015289368686083}}
|
||||
{"family_id":"generalize-0"}
|
||||
@@ -0,0 +1 @@
|
||||
{"format_version":1,"kind":"campaign","name":"generalize","data":{"instruments":["GER40","USDJPY"],"windows":[{"from_ms":1735689600000,"to_ms":1751328000000}]},"risk":[{"vol":{"length":14,"k":2.0}}],"strategies":[{"ref":{"content_id":"546f4838aca6b0bf67140b5868b4aba18fdc53be57e6cca28bf23588fbf68027"},"axes":{"fast.length":{"kind":"I64","values":[5]},"slow.length":{"kind":"I64","values":[20]}}}],"process":{"ref":{"content_id":"87851fd8c2fd1a42fe48f921c44db6026b67d67a50d3a708783e454552f677ce"}},"seed":0,"presentation":{"persist_taps":[],"emit":["family_table"]}}
|
||||
@@ -0,0 +1 @@
|
||||
{"format_version":1,"kind":"process","name":"generalize","pipeline":[{"block":"std::sweep","metric":"expectancy_r","select":"argmax"},{"block":"std::generalize","metric":"expectancy_r"}]}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"format_version": 1,
|
||||
"kind": "campaign",
|
||||
"name": "mvd-regime-window-matrix",
|
||||
"seed": 42,
|
||||
"data": {
|
||||
"instruments": ["GER40", "USDJPY"],
|
||||
"windows": [
|
||||
{ "from_ms": 1735689600000, "to_ms": 1751328000000 },
|
||||
{ "from_ms": 1719792000000, "to_ms": 1735689600000 }
|
||||
]
|
||||
},
|
||||
"risk": [
|
||||
{ "vol": { "length": 14, "k": 2.0 } },
|
||||
{ "vol": { "length": 20, "k": 3.0 } }
|
||||
],
|
||||
"strategies": [
|
||||
{
|
||||
"ref": { "content_id": "546f4838aca6b0bf67140b5868b4aba18fdc53be57e6cca28bf23588fbf68027" },
|
||||
"axes": {
|
||||
"fast.length": { "kind": "I64", "values": [3, 5] },
|
||||
"slow.length": { "kind": "I64", "values": [12, 20] }
|
||||
}
|
||||
}
|
||||
],
|
||||
"process": { "ref": { "content_id": "d68e747465a7e0ccde2fc1ea425119bd2f2bc26c43a3001a71c7ee0b6ac6a901" } },
|
||||
"presentation": { "persist_taps": [], "emit": ["family_table", "selection_report"] }
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"format_version": 1,
|
||||
"kind": "process",
|
||||
"name": "mvd-sweep-deflate-generalize",
|
||||
"description": "Anti-false-discovery sweep (deflated argmax) then a cross-instrument worst-case floor, run once per (window, risk regime) cell.",
|
||||
"pipeline": [
|
||||
{ "block": "std::sweep", "metric": "sqn_normalized", "select": "argmax", "deflate": true },
|
||||
{ "block": "std::generalize", "metric": "expectancy_r" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{}
|
||||
@@ -0,0 +1,3 @@
|
||||
/target
|
||||
Cargo.lock
|
||||
/runs
|
||||
@@ -0,0 +1,4 @@
|
||||
# Static project context only (C17); paths only.
|
||||
[paths]
|
||||
runs = "runs"
|
||||
# data = "/path/to/archive" # the recorded-data root; defaults to the built-in path
|
||||
@@ -0,0 +1,10 @@
|
||||
# mvd_lab — an aura research project
|
||||
|
||||
This crate is an aura project: a cdylib of node/strategy blueprints the
|
||||
`aura` host loads during research (see the engine's docs/project-layout.md).
|
||||
|
||||
- Build: `cargo build` (the next `aura` invocation loads the fresh dylib)
|
||||
- Run: `aura run blueprints/signal.json` (from anywhere inside this dir)
|
||||
- Nodes live in `src/`; each is registered in `vocabulary()`/`type_ids()`
|
||||
under the `mvd_lab::` namespace prefix.
|
||||
- Topology is data (`blueprints/*.json`), node logic is Rust.
|
||||
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "mvd_lab"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies]
|
||||
aura-core = { path = "/home/brummel/dev/aura/crates/aura-core" }
|
||||
|
||||
# Standalone workspace root: never a member of an enclosing workspace.
|
||||
[workspace]
|
||||
@@ -0,0 +1 @@
|
||||
{"format_version":1,"blueprint":{"name":"mvd_lab_signal","nodes":[{"primitive":{"type":"SMA","name":"fast","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":2}}]}},{"primitive":{"type":"SMA","name":"slow","bound":[{"pos":0,"name":"length","kind":"I64","value":{"I64":4}}]}},{"primitive":{"type":"Sub"}},{"primitive":{"type":"Bias","name":"bias","bound":[{"pos":0,"name":"scale","kind":"F64","value":{"F64":0.5}}]}},{"primitive":{"type":"mvd_lab::Identity"}}],"edges":[{"from":0,"to":2,"slot":0,"from_field":0},{"from":1,"to":2,"slot":1,"from_field":0},{"from":2,"to":3,"slot":0,"from_field":0},{"from":3,"to":4,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0}],"source":"F64"}],"output":[{"node":4,"field":0,"name":"bias"}]}}
|
||||
@@ -0,0 +1,76 @@
|
||||
//! mvd_lab — an aura research project: node logic + the exported vocabulary.
|
||||
//!
|
||||
//! Every node type this crate provides is registered in `vocabulary()` /
|
||||
//! `type_ids()` under the `mvd_lab::` namespace prefix; the `aura` host loads
|
||||
//! this cdylib per invocation and merges it with the std vocabulary.
|
||||
|
||||
use aura_core::{
|
||||
Cell, Ctx, FieldSpec, Firing, Node, NodeSchema, PortSpec, PrimitiveBuilder,
|
||||
ScalarKind,
|
||||
};
|
||||
|
||||
/// One-input f64 pass-through. Emits `None` until its input has a value.
|
||||
pub struct Identity {
|
||||
out: [Cell; 1],
|
||||
}
|
||||
|
||||
impl Identity {
|
||||
pub fn new() -> Self {
|
||||
Self { out: [Cell::from_f64(0.0)] }
|
||||
}
|
||||
pub fn builder() -> PrimitiveBuilder {
|
||||
PrimitiveBuilder::new(
|
||||
"mvd_lab::Identity",
|
||||
NodeSchema {
|
||||
inputs: vec![PortSpec {
|
||||
kind: ScalarKind::F64,
|
||||
firing: Firing::Any,
|
||||
name: "value".into(),
|
||||
}],
|
||||
output: vec![FieldSpec { name: "value".into(), kind: ScalarKind::F64 }],
|
||||
params: vec![],
|
||||
},
|
||||
|_| Box::new(Identity::new()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Identity {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Node for Identity {
|
||||
fn lookbacks(&self) -> Vec<usize> {
|
||||
vec![1]
|
||||
}
|
||||
fn eval(&mut self, ctx: Ctx<'_>) -> Option<&[Cell]> {
|
||||
let w = ctx.f64_in(0);
|
||||
if w.is_empty() {
|
||||
return None;
|
||||
}
|
||||
self.out[0] = Cell::from_f64(w[0]);
|
||||
Some(&self.out)
|
||||
}
|
||||
fn label(&self) -> String {
|
||||
"mvd_lab::Identity".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn vocabulary(type_id: &str) -> Option<PrimitiveBuilder> {
|
||||
match type_id {
|
||||
"mvd_lab::Identity" => Some(Identity::builder()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn type_ids() -> &'static [&'static str] {
|
||||
&["mvd_lab::Identity"]
|
||||
}
|
||||
|
||||
aura_core::aura_project! {
|
||||
namespace: "mvd_lab",
|
||||
vocabulary: vocabulary,
|
||||
type_ids: type_ids,
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"format_version":1,"blueprint":{"name":"graph","nodes":[{"primitive":{"type":"SMA","name":"fast"}},{"primitive":{"type":"SMA","name":"slow"}},{"primitive":{"type":"Sub","name":"sub"}},{"primitive":{"type":"Bias","name":"bias"}}],"edges":[{"from":0,"to":2,"slot":0,"from_field":0},{"from":1,"to":2,"slot":1,"from_field":0},{"from":2,"to":3,"slot":0,"from_field":0}],"input_roles":[{"name":"price","targets":[{"node":0,"slot":0},{"node":1,"slot":0}],"source":"F64"}],"output":[{"node":3,"field":0,"name":"bias"}]}}
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{"op": "source", "role": "price", "kind": "F64"},
|
||||
{"op": "add", "type": "SMA", "name": "fast"},
|
||||
{"op": "add", "type": "SMA", "name": "slow"},
|
||||
{"op": "feed", "role": "price", "into": ["fast.series", "slow.series"]},
|
||||
{"op": "add", "type": "Sub", "name": "sub"},
|
||||
{"op": "connect", "from": "fast.value", "to": "sub.lhs"},
|
||||
{"op": "connect", "from": "slow.value", "to": "sub.rhs"},
|
||||
{"op": "add", "type": "Bias", "name": "bias"},
|
||||
{"op": "connect", "from": "sub.value", "to": "bias.signal"},
|
||||
{"op": "expose", "from": "bias.bias", "as": "bias"}
|
||||
]
|
||||
Reference in New Issue
Block a user