Skip to content

Architecture

Proposed data model

Status: logical design, no migrations implemented. Audience and market may still change cardinalities and precision.

Implementation update: see the ROADMAP, ADR-0011, ADR-0012 and ADR-0013 for the effective state. The text below preserves the original requirements/designs, not a statement that all infrastructure or external validation details have already occurred.

Status: logical design, no migrations implemented. Audience and market may still change cardinalities and precision.

Entities#

TableMain fields and constraints
usersid, name, verified email, status, timestamps
social_accountsuser_id, provider, subject; UNIQUE(provider, subject)
sessionsrevocable session, expiration, user; without unnecessary Google token
trading_accountsowner_id, broker, external_id, mode, currency, status
instrumentsmarket, symbol, currency, tick_size, qty_step, timezone, status
candlesinstrument_id, feed, timeframe, open_time, OHLCV, closed, revision
strategy_versionsstrategy_id, version, schema_version, JSONB parameters, hash
strategy_runsaccount_id, version, mode, status, start/end and dataset
signalsrun_id, candle/event, direction, reason; dedupe_key UNIQUE
risk_policy_versionsaccount, version, currency, limits and validity
risk_decisionssignal, version, snapshot, reason, approved/rejected
risk_reservationsaccount, intent, reserved exposure, status
order_intentsaccount, signal, idempotency_key, client_order_id, state
broker_ordersaccount, broker_order_id UNIQUE per account, intent, status
fillsaccount, broker_execution_id UNIQUE per account, qty, price, fees
ledger_entriescash/position entries, referenced fill and reversal
position_snapshotsaccount/instrument, qty, cost and mark; recoverable projection
outbox_eventstype, version, payload, attempts, available_at, claim and generation
engine_controlsaccount, halted, reason, generation, heartbeat and leader
reconciliation_runsaccount, result, divergences, cursor and time
backtest_runscode, dataset/hash, parameters, seeds, costs and metrics
audit_eventsactor, account, action, previous/new version, request_id and time

Precision and units#

Proposed: PostgreSQL NUMERIC and explicit decimal in Go; decimal strings in the JSON contracts and display conversion in React. Final scales depend on the instruments; do not assume two decimal places for price, quantity or crypto. Round quantity down according to lot/step when opening risk, price according to tick and side; validate the broker's minimums and maximums. Do not use floats for ledger or limits. Statistical indicators may use float with tolerances and finite inputs.

Every amount carries a currency. Do not add USD and BRL without an FX rate, instant and FX source. Without a reliable source, show values separately. Store UTC (timestamptz), keep the market timezone and use the official calendar for holidays and DST.

Integrity and concurrency#

  • FKs preserve account/execution/version; external IDs are unique in the correct scope.
  • Candles: UNIQUE(instrument_id, feed, timeframe, open_time, revision); an explicit current revision prevents mixing revisions in the same backtest.
  • Risk reservations and intents are created atomically with the outbox. Include partially filled orders and orders in unknown state in the conservative calculation.
  • Fill events are deduplicated before changing the ledger. Corrections are adjustment/reversal entries, never silent deletion of financial evidence.
  • Real and paper accounts, synthetic and historical datasets use explicit namespaces.
  • Indexes by account+status+time on orders and account+instrument on positions.
  • Retention/partitioning of candles only after budget and volume; do not discard data that supports results without recording the dataset's unavailability.

Risk and sizing#

For a purchase without leverage: budget = equity * risk_fraction; risk_per_unit = entry - stop + estimated_costs_per_unit + slippage_buffer; qty = floor_to_step(min(budget/risk_per_unit, cash_limit/entry, exposure_limit/entry)). Reject stop >= entry, negative costs, non-positive denominator, non-finite values or quantity below the minimum. The reservation uses the conservative execution scenario, not the expected profit. Stops do not limit maximum guaranteed loss.

Realized P&L comes from fills, cost policy and fees; unrealized requires a recent marked price and source. Result before costs, after costs and tax estimate are distinct fields; tax calculation is not defined in the MVP.

Confirmed adjustment: two markets, personal use#

The model must distinguish Brazil and the US and preserve separate paper accounts. An owner may have several trading_accounts; owner_id serves authorization, without introducing organizations, billing or SaaS tenancy in the MVP. Instrument uniqueness uses market/venue/symbol, not the isolated symbol. Separate BRL and USD in the ledger; FX policy and aggregated limits still depend on a decision. Synthetic data needs a visible flag and source, including in the internal simulator.