unrip/archive/implementation/20260402T230445Z-first-non-mocked-tradeable-loop-for-one-pair-implementation.md
philipp 54dc05a94c Archive first live trade loop and open funding visibility turn
Proof: Preserve the completed first live BTC/EURe trade loop and establish the next approved implementation proof around pre-credit funding visibility and operator alerts.
Assumptions: The live-trade loop is sufficiently proven by the recorded deposits, withdrawals, durable command/result chain, and successful mainnet quote responses; the next highest-value slice is operational visibility rather than new execution breadth.
Still fake: The newly opened funding-visibility and alert turn is planning only; no pre-credit watcher or durable alert evaluator is implemented yet.
2026-04-03 01:07:02 +02:00

16 KiB

Implementation Turn: first non-mocked tradeable loop for one pair

Status: open Opened: 2026-04-01

Goal

Build the first full live vertical slice that can actually attempt a trade:

  1. observe a real NEAR Intents quote
  2. enrich it with live external reference pricing
  3. synchronize spendable inventory already credited inside NEAR Intents
  4. evaluate it in a real strategy service
  5. gate it by inventory and arm state
  6. submit it through a real Near Intents executor
  7. persist the full chain in PostgreSQL

This turn is explicitly not a storage side-quest. Storage, control surfaces, analytics support, and treasury funding visibility are included because they are required to make the trade loop trustworthy.

Selected backlog items

  • [I001] Hybrid reference-price service using Kraken stream and CoinGecko poll or fallback for the active pair inputs.
  • [I002] PostgreSQL event store plus history writer for quotes, reference prices, decisions, commands, and execution results.
  • [I003] Strategy engine that consumes norm.swap_demand plus reference prices and emits auditable decisions.
  • [I004] Real Near Intents executor service using pre-funded internal inventory, with explicit arming and idempotent result reporting.
  • [I006] Decision-to-command safety gate with explicit arm or disarm state, notional caps, and inventory freshness checks.
  • [I007] Inventory-aware execution rule: implement both directions, but only fire the side backed by credited internal source-asset inventory.
  • [I008] Inventory-sync service for NEAR Intents internal balances and pending funding state.
  • [I009] Liquidity-manager service for deposit addresses, funding actions, and treasury visibility.
  • [B002] No reference price source exists, so the system cannot estimate edge.
  • [B003] Dummy reactor and dummy executor prevent a non-mocked trade path.
  • [B004] The current plan assumed external hot wallets were on the hot trade path instead of pre-funded internal inventory.

Architectural shape

Event backbone

Kafka or Redpanda remains the backbone between services.

Required topic set for this turn:

  • raw.near_intents.quote
  • norm.swap_demand
  • ref.market_price
  • state.intent_inventory
  • ops.liquidity_action
  • decision.trade_decision
  • cmd.execute_trade
  • exec.trade_result

Durable store

PostgreSQL is the first durable analytics and audit layer.

Why:

  • enough write throughput for current scope
  • strong queryability for replay, inspection, and debugging
  • simple to operate
  • better fit than inventing a warehouse right now

Service split

The first real loop should be seven services:

  • near-intents-ingest
  • market-reference-ingest
  • inventory-sync
  • liquidity-manager
  • history-writer
  • strategy-engine
  • trade-executor

Service-by-service responsibilities

1. near-intents-ingest

Responsibilities:

  • connect to the NEAR Intents quote stream
  • filter or classify the active pair
  • emit raw and normalized events
  • expose runtime state

Inputs:

  • NEAR Intents websocket
  • pair filter config and runtime override

Outputs:

  • raw.near_intents.quote
  • norm.swap_demand

Control surface:

  • GET /healthz
  • GET /state
  • GET /pair-filter
  • PUT /pair-filter
  • POST /pair-filter/reset

Important edge cases:

  • websocket disconnect
  • reconnect storm
  • invalid JSON
  • pair silent but connection healthy

2. market-reference-ingest

Responsibilities:

  • subscribe to Kraken BTC/EUR pricing
  • poll CoinGecko for fallback or cross-check pricing
  • derive fair BTC/EURe price for both trade directions
  • publish reference-price events
  • expose latest source state and freshness

Inputs:

  • Kraken stream
  • CoinGecko HTTP API

Outputs:

  • ref.market_price

Control surface:

  • GET /healthz
  • GET /state
  • POST /refresh
  • POST /pause
  • POST /resume

Required state:

  • latest Kraken price
  • latest CoinGecko price
  • derived fair rate
  • freshness age
  • source health flags

Important edge cases:

  • Kraken disconnect
  • CoinGecko timeout or rate limit
  • both sources stale
  • conflicting sources beyond tolerance

Required behavior:

  • if Kraken is down but CoinGecko is fresh, degrade according to policy and record fallback usage
  • if both are stale, mark the service unhealthy for decisioning
  • the first implementation must make the EURe/EUR pricing assumption explicit:
    • either treat EURe as 1:1 with EUR and record that plainly
    • or use a separate sanity source and record the mapping logic

3. inventory-sync

Responsibilities:

  • read current credited spendable inventory from NEAR Intents internal state
  • distinguish credited balances from pending deposits and pending withdrawals
  • publish current internal inventory state
  • expose freshness and reconciliation state

Inputs:

  • NEAR Intents inventory or verifier surfaces
  • liquidity-manager state when relevant

Outputs:

  • state.intent_inventory

Control surface:

  • GET /healthz
  • GET /state
  • POST /refresh
  • POST /pause
  • POST /resume

Required state:

  • spendable balances by asset
  • pending inbound funding by asset
  • pending outbound withdrawal by asset
  • last sync time
  • reconciliation status

Important edge cases:

  • internal inventory surface unavailable
  • external deposit seen but not yet credited internally
  • credited balance lower than expected after funding
  • stale inventory snapshot

Required behavior:

  • only credited internal inventory counts as spendable
  • pending treasury movements must remain non-spendable
  • stale inventory state must be visible and actionable

4. liquidity-manager

Responsibilities:

  • request and track deposit addresses or equivalent funding handles for treasury assets
  • track treasury funding actions from external wallets into NEAR Intents
  • track withdrawals and rebalance actions
  • expose current funding pipeline state
  • publish auditable liquidity action records

Inputs:

  • treasury configuration
  • external funding wallets
  • NEAR Intents deposit or withdrawal surfaces

Outputs:

  • ops.liquidity_action

Control surface:

  • GET /healthz
  • GET /state
  • POST /refresh
  • POST /pause
  • POST /resume
  • POST /freeze-withdrawals

Required state:

  • active deposit addresses or funding handles
  • recent funding attempts
  • pending credits
  • recent withdrawals
  • rebalance state

Important edge cases:

  • deposit address request failure
  • external wallet funded but NEAR Intents credit delayed
  • duplicate funding detection
  • unsupported asset or chain mapping

Required behavior:

  • treasury actions must remain visible and auditable
  • funding must be decoupled from the per-trade hot path

5. history-writer

Responsibilities:

  • consume the core topics
  • write append-only rows into PostgreSQL
  • preserve causality across quote, decision, and execution records
  • expose lag and write state

Inputs:

  • all core Kafka topics

Outputs:

  • PostgreSQL rows

Control surface:

  • GET /healthz
  • GET /state
  • POST /pause
  • POST /resume
  • POST /drain

Required stored record families:

  • raw quotes
  • normalized demand
  • reference prices
  • inventory snapshots
  • liquidity actions
  • trade decisions
  • execute commands
  • execution results

Important edge cases:

  • PostgreSQL unavailable
  • duplicate deliveries from Kafka
  • offset commit mismatch after partial write

Required behavior:

  • never claim success before the write is durable
  • surface last committed offsets and last successful write time

6. strategy-engine

Responsibilities:

  • join latest demand with latest price and inventory state
  • compute implied quote rate
  • compare it to fair rate
  • apply freshness thresholds
  • apply the initial 2% gross edge threshold
  • apply max-notional and inventory checks
  • emit auditable decision events
  • emit cmd.execute_trade only when all gates pass and the system is armed

Inputs:

  • norm.swap_demand
  • ref.market_price
  • state.intent_inventory

Outputs:

  • decision.trade_decision
  • cmd.execute_trade

Control surface:

  • GET /healthz
  • GET /state
  • POST /arm
  • POST /disarm
  • POST /pause
  • POST /resume
  • PUT /threshold
  • PUT /limits

Required decision state:

  • arm state
  • current threshold
  • current notional cap
  • latest decision
  • latest rejected decision reason
  • per-reason skip counters

Required decision record fields:

  • decision_id
  • quote_id
  • pair
  • direction
  • implied_rate
  • reference_rate
  • gross_edge_pct
  • price_freshness_ms
  • inventory_snapshot
  • decision
  • decision_reason

Important edge cases:

  • stale prices
  • no price yet
  • no inventory yet
  • insufficient spendable inventory
  • pending deposit exists but is not yet credited
  • quote already expired
  • repeated quote IDs
  • one direction affordable and the other not
  • fresh deploy starts armed by mistake

7. trade-executor

Responsibilities:

  • consume cmd.execute_trade
  • load the correct Near Intents signing authority
  • perform the real Near Intents submission using pre-funded internal inventory
  • preserve idempotency across retries and restarts
  • emit exec.trade_result

Inputs:

  • cmd.execute_trade
  • signing secrets
  • optional latest inventory state

Outputs:

  • exec.trade_result

Control surface:

  • GET /healthz
  • GET /state
  • POST /arm
  • POST /disarm
  • POST /pause
  • POST /resume
  • POST /drain

Required state:

  • arm state
  • last command seen
  • last request sent
  • last venue response
  • in-flight command count
  • completed command count
  • error counters

Important edge cases:

  • duplicate command delivery
  • crash after submission but before result publish
  • venue reject
  • timeout with unknown outcome
  • insufficient internal inventory detected late
  • secret missing or invalid
  • signer not authorized for the intended NEAR Intents account

Required behavior:

  • never silently swallow a venue error
  • always publish a result record for attempted commands
  • make duplicate suppression durable
  • never try to bridge or top up inventory during trade execution
  • start disarmed by default on fresh deploy

Persistence design

Why PostgreSQL now

  • current scale does not require a special time-series database
  • rows are easier to inspect than a custom file format for this phase
  • joins across decision, command, and result matter more right now than raw ingestion throughput
  • treasury, inventory, and execution joins matter more than raw bus throughput at this stage

Minimum tables or equivalent record families

  • raw_near_intents_quotes
  • swap_demand_events
  • market_price_events
  • intent_inventory_snapshots
  • liquidity_actions
  • trade_decisions
  • execute_trade_commands
  • trade_execution_results

Query requirements

Must be able to answer:

  • what was the latest fair price when this decision was made
  • what spendable inventory existed when this decision was made
  • what treasury funding actions were still pending
  • why was this quote skipped
  • what command was emitted for this quote
  • what happened when the executor submitted it
  • what credited internal inventory existed at the time

Control and stop semantics

Every service must support inspection.

State endpoints must be sufficient to answer:

  • is it healthy
  • is it connected
  • what is it currently using as input state
  • what was the last successful action
  • why is it blocked, if blocked
  • whether the state is authoritative or stale

Stopping must be explicit:

  • pause means stop taking new work but keep process alive
  • drain means finish in-flight work then stop cleanly
  • disarm means remain live and observable but refuse side effects

This matters because the operator must be able to halt strategy or execution without destroying the whole pipeline.

Logging requirements

All services use structured JSON logs.

Stable top-level fields:

  • level
  • service
  • component
  • event
  • namespace
  • venue
  • topic
  • pair

Additional body fields when relevant:

  • quote_id
  • decision_id
  • command_id
  • execution_id
  • inventory_id
  • liquidity_action_id
  • gross_edge_pct
  • price_freshness_ms

Log when:

  • source connection is lost or reestablished
  • price source becomes stale
  • inventory state becomes stale or recovers
  • funding action is requested, seen, credited, delayed, failed, or frozen
  • strategy rejects with a meaningful reason
  • strategy arms or disarms
  • executor arms or disarms
  • command is submitted
  • venue rejects or times out
  • PostgreSQL disconnects or recovers
  • control API changes state

Do not log every healthy message by default.

Failure and failover behavior

Reference pricing

  • Kraken failure with fresh CoinGecko:
    • allowed only if fallback policy says yes
    • decision records must note fallback source use
  • both sources stale:
    • strategy blocks all execution

Inventory state

  • missing or stale inventory state:
    • strategy may still emit a non-actionable rejected decision
    • strategy must not emit cmd.execute_trade
  • pending funding action:
    • remains non-spendable
    • must be visible in control state and durable records
  • treasury action service down:
    • already funded trading may continue if inventory-sync is fresh
    • new funding or withdrawal operations must be blocked visibly

Persistence

  • PostgreSQL unavailable:
    • history-writer unhealthy
    • system must surface that audit history is impaired
    • if the user wants strict mode, strategy or executor may be blocked until persistence returns

Execution

  • timeout with unknown venue outcome:
    • emit explicit uncertain result
    • preserve idempotency state for recovery
  • restart after partial submission:
    • executor must not blindly resubmit without checking prior state
  • executor sees lower real inventory than strategy snapshot:
    • emit explicit failure result
    • do not attempt fallback treasury movement

Testing and validation plan

Unit tests

  • implied-rate calculation for both directions
  • explicit EURe/EUR pricing-basis test
  • threshold checks
  • stale-price blocking
  • insufficient-inventory blocking
  • pending-deposit-not-spendable blocking
  • command emission only when armed
  • idempotency transitions in executor

Integration tests

  • pricing service emits canonical reference-price events
  • inventory-sync emits credited vs pending inventory state correctly
  • liquidity-manager records funding actions and status transitions
  • strategy consumes demand, pricing, and inventory and emits decision plus command as expected
  • history-writer persists linked records across topics
  • executor publishes result records for success and failure paths

Runtime validation in cluster

  • inspect each service /state
  • verify live reference pricing updates
  • verify live internal inventory state
  • verify one treasury funding path from request or deposit tracking to credited inventory
  • verify strategy and executor start disarmed on a fresh deploy
  • observe a rejected decision due to block condition
  • arm strategy and executor
  • keep the first live max notional tiny, on the order of a few EURe, before any larger cap
  • observe one command emission
  • observe one real Near Intents execution attempt
  • verify PostgreSQL contains the full linked chain

Deliberately rejected for this turn

  • dashboards
  • broad multi-pair abstractions
  • ML training infrastructure
  • broad backtest framework
  • polished operator UI
  • warehouse or lakehouse design

Expected deliverables

  • market-reference-ingest
  • inventory-sync
  • liquidity-manager
  • history-writer
  • strategy-engine
  • trade-executor
  • PostgreSQL schema and migrations or equivalent setup
  • updated Kafka topic creation and config
  • shared control API pattern for all long-running services
  • tests for strategy, inventory, persistence, and executor behavior
  • docs for operations, arm or disarm flow, and inspection commands

Validation target

This turn is only complete when the deployed system can, through repo-controlled services alone, take one live active-pair quote, price it, verify credited internal inventory, decide on it, gate it, submit a real Near Intents execution attempt, and preserve the full record chain in PostgreSQL.