A Kraken spot microstructure engine. Live market data is written once into a shared DMT tree as datura.Artifact rows. Signal systems Measure by seeking tree prefixes and running composed nomagique pipelines; each emits categorized readings with finite confidence and temporal surprise. The trader queries those measurements, walks YAML playbooks in logic/rules/tree.yml, and allocates capital proportional to edge across the live cross-section. A paper wallet (β¬200 default) records fills against Kraken WebSocket v2.
Category semantics and design rationale: DECISION.md.
Agent and architecture contract: AGENTS.md Β§8.
Migration tasks and acceptance: spec/SPEC.md.
- Architecture
- The data pipeline
- Boot sequence
- Core types
- Playbooks
- Signal systems
- Trader mechanics
- Sizing
- UI and telemetry
- nomagique layer
- Build and run
- Configuration reference
- Repository map
Canonical contract (AGENTS.md Β§8): one tree, write at ingest, query everywhere else. If wiring beyond websocket β tree β Seek β FlipFlop β nomagique.Number seems necessary, fix nomagique, artifact schema, or ingest prefixes β do not grow relay layers in the trader or signals.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Kraken WebSocket v2 β kraken/public, kraken/paper, kraken/user β
β trade Β· ticker Β· book Β· instrument Β· ohlc β
β parse frame β datura.Artifact β tree.Insert(prefix, wire) β
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β dmt.Tree (shared process bus) β
β ingest: role/scope/origin/β¦ (e.g. book/BTC-USD) β
β measure: measurement/<scope>/<origin>/β¦ β
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β tree.Seek(prefix) β signal Measure / explicit packed frames
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β signal/* β Measure only (reference: signal/toxicity/signal.go) β
β pumpdump Β· depthflow Β· hawkes Β· leadlag Β· liquidity Β· sentiment β
β correlation Β· fluid Β· causal Β· cvd Β· exhaust Β· toxicity Β· β¦ β
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β logic.Measurement {Source, Category, Confidence, Surprise}
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β logic.Tree β embedded logic/rules/tree.yml β
β Walk() β deepest reachable leaf wins; exits before entries β
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ActionEnter / ActionStopLoss / ActionTakeProfit
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β trader.Crypto β desk β
β latest readings per (symbol, source); edge-proportional sizing β
β broker β paper fills or live orders β
ββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββ
βΌ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ui.Hub β ws://127.0.0.1:8765/ws β React dashboard β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
SYMM is a fleet of classifiers plus a playbook layer and a desk. Signals do not call each other; they read the same tree the websockets write.
Migration note: The
curiousbranch is mid-migration. Legacy relay paths (trader/crypto.goβupdateSignalsβsignal.Update,signal/replay/,signal/codec/,signal/buffer/) are debt to remove, not targets to restore. Seespec/SPEC.mdPhase 1β2.
Kraken WS βββΊ tree.Insert (raw JSON artifacts)
β
βΌ
signal.Measure βββΊ measurement artifacts
β
βΌ
trader: latest reading per (symbol, source)
β
βΌ
logic.Tree.Walk
β
βββββββββββββ΄βββββββββββββ
βΌ βΌ
flat β consider entry held β manage exit
β β
βββββ broker fill ββββββββ
β
βΌ
wallet + ui audit
Four properties:
-
Single ingress. Market data enters once at the websocket. No duplicate fan-out through trader book/trade/ticker types or per-signal
Update. -
Measure-only signals. Each signal seeks ingest prefixes on the shared tree, runs one
nomagique.Numberpipeline, and writes measurement artifacts. Reference:signal/toxicity/signal.go. -
Signal trust before the desk. Publishable measurements carry finite
Confidenceβ (0, 1] and temporalSurprise(playbook YAML may still saySNR; the Go field islogic.Measurement.Surprise). Playbook branches gate on explicitvalue:thresholds. -
Forward feedback.
market.Storyrecords per-source forward movement labels; calibrated scales sharpen or soften feature scoring before category evidence is derived.
Current entry point: cmd/root.go β four concurrent roles:
cmd.Execute()
ββ rootCmd.Run
ββ qpool.NewQ (workers from runtime.NumCPU())
ββ go public.NewWebSocket(...).Run(WebSocketURL)
ββ go paper.NewWebSocket(...).Run()
ββ go trader.NewCrypto(...).Run()
ββ trader.PublishDecisionTreeSnapshot(pool)
ββ ui.NewHub(...).Run() // blocks; serves ws://127.0.0.1:8765/ws
Config loads from cmd/cfg/config.yml (embedded default), overridable via --config or $HOME/.symm/config.yml.
Paper mode uses kraken/paper for simulated private channel responses. Live desk requires SYMM_KRAKEN_API_KEY, SYMM_KRAKEN_API_SECRET, and SYMM_LIVE=1.
One signal's classified reading on one symbol at one moment (logic/measurement.go):
type Measurement struct {
Symbol string
Source SourceType
Category CategoryType
Strength float64 // raw fused strength (dashboard gauges)
Confidence float64 // finite selection trust β (0, 1]
Surprise float64 // temporal category surprise (playbook gating)
Price float64
ObservedAt time.Time
// β¦
}
Confidenceexact0means no publishable evidence; above1is invalid signal math.Surpriseis how unexpected the selected category is against that symbol's recent category prior β not a win rate. Playbook branches often gate onsurprise > 1.
Bridge from tree artifacts: logic.MeasurementFromArtifact. Each signal emits exactly one category at a time.
Output of a playbook walk (logic/action.go). logic.Tree evaluates embedded rules/tree.yml; deepest reachable leaf wins. Exits are evaluated before entries.
Actions: ActionEnter, ActionDeny, ActionWait, ActionStopLoss, ActionTakeProfit, ActionShort.
Canonical source: logic/rules/tree.yml (embedded via logic/tree.go). Not market/perspectives/ β that package is removed.
| Priority | Playbook | Thesis (summary) |
|---|---|---|
| 1 | trend |
Breadth + endogenous alpha + laminar/frenzy + aggressive drive |
| 2 | drive |
Aggressive drive or hidden absorption |
| 3 | leadlag |
Breadth + inefficient lag |
| 4 | scarcity |
Extreme scarcity + ignition cue |
| 5 | pump |
Coiled compression or spoof trap entry |
Tree walking: branches gate on category, observation, or metric. Category branches compare Surprise (or confidence when configured) to explicit YAML value: thresholds. Metric branches read trader context (thesis_score, spread_bps, fee_pct, etc.).
Builtin deny categories (ToxicBluff, LiquidityVacuum, Turbulent, Saturation, SystemicHerd, LiquidityShock) appear in the embedded tree. Full mappings: logic/category.go and DECISION.md.
Each signal package:
- Composes one
nomagique.NumberinNewSignal(schema on adatura.Artifact, not hardcoded Go params) - Implements
Measure(query)βtree.Seek(query.Prefix()), explicit artifact frame decode, pipeline evaluate where used - Does not ingest feeds, hold
Update, or switch on category index insideMeasure
| Signal | Package | Categories (examples) | Ingest prefix |
|---|---|---|---|
| PumpDump | signal/pumpdump |
vertical_ignition, coiled_compression, organic_trend, faded_exhaustion |
trade |
| DepthFlow | signal/depthflow |
loaded_imbalance, spoof_trap, book_thinning, dense_neutrality |
book |
| Hawkes | signal/hawkes |
frenzy, saturation, organic, exhaustion |
trade |
| LeadLag | signal/leadlag |
inefficient_lag, synchronized_drift, decoupled_move, anchor_stall |
trade, ticker |
| Liquidity | signal/liquidity |
extreme_scarcity, median_depth, robust_liquidity |
trade |
| Sentiment | signal/sentiment |
risk_on_surge, divergent_move, systemic_slump |
trade |
| Correlation | signal/correlation |
decoupled_alpha, stochastic_noise, divergent_stress, systemic_herd |
trade |
| Fluid | signal/fluid |
laminar, turbulent, inertial, viscous |
book, trade |
| Causal | signal/causal |
endogenous_alpha, systemic_beta, liquidity_shock, causal_noise |
trade, book |
| CVD | signal/cvd |
hidden_absorption, aggressive_drive, stochastic_balance, volume_starvation |
trade |
| Toxicity | signal/toxicity |
toxic_bluff, liquidity_vacuum, hard_support |
book, trade |
| Exhaust | signal/exhaust |
mechanical_collapse, thermal_exhaustion, active_reversal, fragile_expansion |
book, trade |
Per-signal narratives below remain valid product descriptions; wiring must follow the Measure-only tree contract above.
Hunts verticality: volume-relative-to-baseline (RVOL) and price precursor across rolling windows, self-scaled against per-symbol EMA baselines. Three detection windows: 10 s fast, 5 m medium, hourly against a 14-day median.
Distance-decayed book imbalance with anti-spoof filtering. Bid and ask volumes weighted by exponential decay from the touch; fake near-touch walls excluded before imbalance is computed.
Bivariate self-exciting point process on the trade stream. MLE refit throttled per symbol on thin markets.
BTC/EUR anchor lag vs follower universe. Hayashi-Yoshida cross-correlation over per-symbol history; InefficientLag when the anchor moved and followers lag.
Cross-section rank by daily quote volume; ExtremeScarcity for illiquid outliers.
Breadth of positive returns across the universe; macro overlay.
Pearson cross-symbol return correlation; SystemicHerd as deny, DecoupledAlpha as entry cue.
Book depth field dynamics: Reynolds number, divergence, vorticity. Laminar confirms trend; Turbulent is a universal deny.
Pearl's causal ladder on a microstructure DAG with Hayashi-Yoshida covariance and contagion-gated regime switching. EndogenousAlpha required in trend playbook.
Cumulative volume delta from the trade tape. AggressiveDrive and HiddenAbsorption drive drive-playbook entries.
Cancel-vs-fill asymmetry on book updates. ToxicBluff, LiquidityVacuum, HardSupport. Reference implementation for signal shape: signal/toxicity/signal.go.
Microstructure decay modes; exit timing via playbook leaves (ActionStopLoss, ActionTakeProfit), not a separate exit channel.
trader.Crypto scores through playbooks, not by re-deriving signal math.
Target ingestion: query measurement artifacts from the shared tree (or consolidated story readings) β not measurements broadcast fan-out from per-signal Update.
Entry path (summary):
- Collect playbook entries authorizing
ActionEnter - Thesis score β RMS of playbook-relevant surprises
- Friction and economics gates
- Cross-section edge calibration
- Edge-proportional size β
brokerfill
Exit path: pump peak trail, perspective TTL, then exit branches with ObservationHolding. Stops before take-profits when both fire.
Paper / live parity: broker.QuoteCache, SlippageFill, PreflightGates, Kraken fee schedule from AssetPairs, latency profile in runs/network_latency.json. Live: SYMM_LIVE=1 + API credentials; boot fails closed if live session cannot start.
Forward truth: market.Story records per-signal forward labels independent of fills; scales feed back into signal feature scoring.
Edge-proportional across the live cross-section:
thesisScore(s) = RMS(playbook-relevant surprises) Γ βconfirmations
edge(s) = thesisScore(s) β median(all scores) β MAD(all scores)
share(s) = edge(s) / (thesisScore(s) + Ξ£ positive scores)
notional(s) = free_cash Γ share(s)
MinCostEUR remains the exchange-cost floor.
ui.Hub serves ws://127.0.0.1:8765/ws (default 127.0.0.1:8765; set ui.addr or SYMM_UI_ADDR to :8765 for all interfaces).
On connect, the hub sends a snapshot from trader.ConnectSnapshotFrames (wallet, decision tree, layout). Live frames arrive via ui.Publish* from trader and signals.
| Event / frame | Typical source | Contents |
|---|---|---|
layout |
ui.Hub | dashboard schema |
confidence |
measurements | per-source confidence and surprise |
wallet |
trader | balance, inventory, marks |
audit |
trader | conviction, edge, playbook |
ohlc |
kraken/public | anchor / open-position candles |
decision_tree |
trader | embedded playbook snapshot |
heartbeat |
ui.Hub | seq, queue depth |
Frontend: cd frontend && pnpm install && pnpm dev. Override WS URL with VITE_SYMM_WS_URL.
Signal math lives in github.com/theapemachine/nomagique, composed in each signal's NewSignal:
nomagique.Number(
vector.NewFeatureExtractor(schemaArtifact),
probability.NewClassifier(
logic.NewCircuit(/* rules */),
logic.NewCircuit(/* rules */),
),
probability.NewTransitionSurprise(/* β¦ */),
)- FeatureExtractor β reads payload JSON using schema artifact attributes
- Classifier β score source order is the category index; no symm-side
switch - Circuit β priority-ordered rules (
Match/Then) - Transport β
datura/transport.FlipFlopbetween tree seek and pipeline
Do not add domain types to nomagique; do not hardcode thresholds in Go β declare transforms and keys on schema artifacts (AGENTS.md Β§8).
qpool uses go:linkname hooks. Use the Makefile (exports GOFLAGS=-ldflags=-checklinkname=0):
make build # β bin/symm (includes capnp-ts codegen)
make run # paper defaults; UI at ws://127.0.0.1:8765/ws
make test-go # full Go suite
make test-frontend # tsc + Vitest
make bench # package benchmarks
make test-cover # β runs/coverage.outBare
go test ./...withoutGOFLAGSfails at link time. Usemake test-goorexport GOFLAGS=-ldflags=-checklinkname=0.
Profile while running: make run-profile β http://127.0.0.1:6060/debug/pprof/
CLI tuning / replay eval (symm tune, symm eval, make record) are deferred until the tree + Measure path is stable (spec/SPEC.md Phase 5). Offline tests insert artifacts directly into the tree or use package-level websocket harnesses β not a signal/replay relay package.
| Variable | Effect |
|---|---|
SYMM_KRAKEN_API_KEY |
Live desk + L3 when paired with secret |
SYMM_KRAKEN_API_SECRET |
Base64-encoded API secret |
SYMM_LIVE |
1 or true for live desk |
SYMM_UI_ADDR |
WebSocket listen address |
SYMM_WALLET_EUR |
Paper starting capital (default 200) |
SYMM_QUOTE_CURRENCY |
Symbol discovery quote (config default EUR) |
Full wiring: cmd/cfg/config.yml and viper SYMM_* overrides.
π Wallet and desk
| Field | Default | Description |
|---|---|---|
WalletEUR |
200.0 |
Paper capital |
MinCostEUR |
0.45 |
Minimum trade notional |
PerspectiveTTL |
30s |
Position binding horizon |
EntryEdgeMultiple |
2.0 |
Thesis vs round-trip friction |
π Execution economics
| Field | Default | Description |
|---|---|---|
ExecutionEconomicsEnabled |
true |
Post-fee return ledger |
ForwardReturnMinSamples |
30 |
Warm playbook threshold |
ForwardReturnSignificanceZ |
1.96 |
Economics gate z-score |
π Exit and trail parameters
| Field | Default | Description |
|---|---|---|
TakeProfitR |
2.0 |
Return multiple vs stop |
StopVolMultiple |
8.0 |
Stop = NΓ tick volatility |
PumpTrailPct |
0.08 |
Fast pump trail |
PumpHardStopPct |
0.12 |
Pump hard floor |
π Market data and connectivity
| Field | Default | Description |
|---|---|---|
QuoteCurrency |
EUR |
Discovery filter |
BookDepthLevels |
5 |
Book depth maintained locally |
π Signal-specific parameters
| Field | Default | Description |
|---|---|---|
HawkesFitCooldown |
5s |
MLE refit interval |
BookDepthDecayLambda |
1000 |
DepthFlow decay (ms) |
FluidGridSize |
32 |
Fluid grid NΓN |
CausalContagionBreak |
0.9 |
Regime break threshold |
See cmd/cfg/config.yml for the full set.
π UI and infrastructure
| Field | Default | Description |
|---|---|---|
UIAddr |
127.0.0.1:8765 |
Dashboard WebSocket |
UITelemetryBuffer |
512 |
Lossy client ring |
| Path | Contents |
|---|---|
cmd/ |
Cobra entry, embedded cfg/config.yml, boot |
spec/SPEC.md |
Migration spec (tasks, acceptance) |
logic/ |
Playbooks (rules/tree.yml), Measurement, tree walk |
signal/ |
Measure-only classifiers |
trader/ |
Desk, economics, cognitive memory |
market/ |
Story, forward feedback (not playbooks) |
kraken/public/ |
Public REST + WebSocket β tree ingest |
kraken/paper/ |
Paper private WebSocket |
kraken/user/ |
Authenticated user streams |
kraken/market/ |
Kraken frame helpers / tree ingest (thin; no feed multiplexer) |
broker/ |
Paper and live execution, quote cache |
ui/ |
WebSocket hub, publish helpers |
frontend/ |
React dashboard |
datura/, nomagique/, qpool/, errnie/ |
External libs (see go.mod) |
DECISION.md |
Category semantics |
AGENTS.md |
Agent contract; Β§8 = architecture |
Removed / do not restore: market/perspectives/, signal/replay/, signal/codec/, signal/buffer/, trader updateSignals relay.
Adding a signal:
- Compose one
nomagique.NumberinNewSignalfrom schema artifact attributes. - Implement
Measure(query)β seek ingest prefix on the shared tree,FlipFlop, return measurement artifacts. - Do not add
Update, feed subscriptions, or category switches inMeasure. - Register measurement prefixes consistent with
logic.SourceTypeandDECISION.md. - Extend
logic/rules/tree.ymlif new categories should authorize or deny trades.
See signal/toxicity/signal.go and AGENTS.md Β§8.







