This package implements the isolated trader contract in designs/trader-api-design.md. It never
turns a locally entered balance into broker money. Bound traders use an owner-registered Agent
Portfolio and copy mirror. Explicit standalone traders execute directly in the credential's broker
account, with a virtual strategy-only cap and no owner mirror.
The local dbzero 0.6.10 wheel is installed from /dbzero-data/lib and requires
regular CPython 3.14 (3.14+gil in uv).
uv sync --all-extras --python 3.14+gil
chmod 600 .env_demo
./server.sh
.venv/bin/trader --help
.venv/bin/trader-admin --helpAll service commands require a signed trader key. Obtain a local token and export it before running CLI examples below:
export TRADER_KEY="$(.venv/bin/python -m trader_api.trader_keys issue --trader alpha --environment demo)"
./trader --config .env_demo --expected-environment demo status
# An explicit --trader_key VALUE overrides TRADER_KEY.Tokens embed the trader and demo/real environment, are verified using the public
key, and expire after 24 hours. The CLI no longer accepts --trader. Existing
profile credentials and broker permissions remain required. RPC rejects trader
requests without a signed token; owner-admin authentication is separate.
The three workflow scripts still take --trader NAME, issue and export a fresh
key at startup, and pass it to agent shell commands. Agents need neither trader
nor key flags. Tokens are excluded from prompts and journal command prefixes.
Signing keys live in .trader-server/keys/ and are generated once under a lock.
The directory is mode 0700 and private.pem is mode 0600. Access to the private
key grants local issuance authority. To invalidate all tokens, stop servers and
UI processes, remove the entire signing-key directory, and restart the servers
to generate a new pair. Restart clients and reissue tokens. Incomplete or corrupt
keypairs fail rather than being replaced automatically. Update clients and
servers together and restart both demo and real servers after this upgrade.
Profiles are fixed project-root filenames and are never merged with ambient variables. Remove the
obsolete TRADER_ENV; only broker/owner-verified scopes establish an environment. The committed
.env_demo.example contains supported full demo URLs. Never commit an actual profile.
The server owns writable prefixes, broker connections, and refresh workers. UI, CLI, and the public
Python TraderService facade open read-only prefixes and send service calls through db0-rpc.
Start it explicitly before opening clients:
./server.sh # background demo server, RPC on 127.0.0.1:8002
./server.sh --catalog traders.toml # use the same catalog as the UI
./server.sh --real # separate real server, RPC on 127.0.0.1:8003
./server.sh --stop # stop demo; add --real to stop realStarts/stops are idempotent. --port overrides the selected RPC port; clients discover the endpoint
from prefix metadata. Logs and private authentication/process files live in .trader-server/{environment}.
RPC is loopback-only and authenticates the local token plus trader/owner credential proofs.
Trader/profile selections must match the server catalog. --owner-config selects the server's owner
profile (default .env_demo or .env_real). Existing owner operations remain demo-only.
After provisioning, add the child profile to the server/UI catalog and restart the server before using it.
The native RPC wheel must match regular CPython 3.14. If it is missing from /dbzero-data/lib, build
it from the available upstream sources before syncing:
uv run --no-project --python 3.14+gil --with setuptools --with wheel python scripts/build_rpc.py
uv sync --all-extras --python 3.14+gilFor direct demo trading, explicitly set TRADER_TRADING_MODE=standalone in a mode-0600 profile,
use direct-account credentials, and configure identity/P&L, eligibility, quote, cost, and execution
routes for the same environment. Startup authenticates the broker read, binds ordinary-account identity
to a one-way fingerprint of the authenticated user key (or explicit broker IDs when returned), and probes
ETH eligibility before any command is enabled. No Agent Portfolio or copy relationship is created. Broker write access
remains authoritative at dispatch; a successful read does not guarantee that an order will be accepted.
The init amount is strategy capital only, not a broker deposit. No agent binding or copy is created.
trader --config .env_demo --expected-environment demo \
smoke-demo --expected-investment 1000 --symbol ETH --strategy-notional-usd 100Repeating the same smoke command reports its durable outcome without a second broker dispatch.
If it reports an unknown or pending execution, explicitly repeat with --reconcile to look up the
same order; do not place a replacement trade. The smoke command refuses REAL and bound profiles.
REAL standalone accounts require an explicit profile and catalog opt-in; there is no automatic smoke.
OwnerAdminService is a separate authenticated surface. Its register_existing method consumes
issuance/owner evidence bound to the exact child token. Trader init only asserts an existing owner
investment and activates that binding.
Bootstrap local owner/vault secrets once, then provision through the separate admin entry point. The child profile is created with mode 0600 and the one-time broker token is also encrypted in the fixed demo storage root. Reusing the administrative key never sends a second provisioning request.
.venv/bin/trader-admin --config .env_demo bootstrap
./server.sh --owner-config .env_demo
.venv/bin/trader-admin --config .env_demo provision \
--trader <immutable-trader-id> --investment-usd 1000 \
--portfolio-name <6-to-10-char-name> --token-name <token-name> \
--administrative-request-key <durable-key> --child-config .env_demo_child
export TRADER_KEY="$(.venv/bin/python -m trader_api.trader_keys issue --trader <immutable-trader-id> --environment demo)"
.venv/bin/trader --config .env_demo_child \
--expected-environment demo init --expected-investment 1000The current broker create contract has no resting limit order. limit_ioc executes immediately or
cancels immediately and its rate must be within 10% of market. market_if_touched may rest at a
remote trigger but becomes a market order when triggered. Callers must choose explicitly between
those semantics; the CLI does not relabel MIT as a limit order.
The database server is the sole writer for its environment, including owner provisioning and mirror
reconciliation. The optional trader-worker compatibility entry point uses a read-only RPC client;
its Unix socket remains mode 0600, HMAC-authenticated, and allowlisted. Broker adapters and native
write-side services remain server-local.
All deployments use /dbzero-data/trader. Trader prefixes are demo/{trader_name} or
real/{trader_name}; shared prefixes are {environment}/control and
{environment}/market-events. Prefix names have no leading slash. Trader names retain
spelling and case, must be safe single path components, and cannot use the reserved names
control, market-events, or credential-vault. Vault files live in
{environment}/credential-vault. Tests use isolated directories under
/dbzero-data/trader/tests; no dotenv, environment variable, or CLI option redirects the production root.
Persistent models use plain names (Intent, Preview, etc.) and store related memo objects
directly. Trader owns the immutable name in its trader prefix; TraderState,
PortfolioBinding, and the control-side TraderRegistration reference that instance.
String trader names are resolved during registration/authentication and retained in API values.
Models use dataclass constructors without prefix arguments; storage operations
select the active prefix with db0.open before constructing objects, including singletons.
Monetary amounts, position units, and protection rates are stored as Decimal values;
JSON/API output serializes them as strings.
Parameters and audit facts use native dictionaries, and broker outcomes retain native
numeric values. Timestamps use timezone-aware datetime values; audit hashing uses UTC
at dbzero's millisecond precision. Operations, lifecycle states, execution states, sides,
and ledger categories use dbzero enums. Absent optional values use None.
UUIDs are serialized only for API responses and exports; incoming API IDs are
resolved to instances with type and trader-prefix checks. Internal links, comparisons, and
relationship queries use instances, with no UUID lookup tags. tag_fields indexes relationships and broker IDs,
with object-tag queries using db0.as_tag(instance). Broker/request IDs and opaque trader
storage keys retain their external identity and routing roles.
Audit hashes bind the referenced intent's command digest.
This storage schema replaces the former *Memo classes and ID fields. Existing databases
require migration before use; no automatic migration is included. Prefix startup disables
dbzero declaration auto-migration (no_auto_migrate=True); loading an existing workspace
must not backfill or rewrite historical records. Schema/index upgrades require explicit
migration against a verified backup.
Submission records trader intent/reservation, control reservation, control outcome, and trader
projection in sequence. Updates use db0.atomic() with default dbzero autocommit; these stages
do not force disk commits before broker dispatch. An ambiguous broker mutation stays UNKNOWN and holds reservations.
Recovery looks up opens by their committed request UUID and never treats a miss as non-execution.
A strategy fill makes mirror state pending until the owner reader records the actual mirror outcome. The proportional estimate is only a conservative admission bound and never becomes an owner fill.
DbzeroStore.backup_prefix creates a per-prefix dbzero copy beneath the selected environment
directory. Restore into a new isolated child directory, verify the audit chain, and reconcile before
allowing exposure. Back up the control prefix separately. Retiring broker portfolios remains an
explicit owner operation and is not performed by disable, restore, or local cleanup.
.venv/bin/ruff check .
.venv/bin/mypy trader_api
.venv/bin/pytest -m 'not external_demo'
.venv/bin/pytest -m external_demo
.venv/bin/pytest --cov=trader_api --cov-report=term-missing
graphify update .The external demo suite is opt-in. It uses dedicated portfolios, no more than USD 2,000 initial investment, leverage one, and the smallest eligible size. Missing owner/child binding evidence is a blocked test, not a pass. Every external resource is tracked; ambiguous mutations are never blindly retried and portfolio deletion requires separate explicit authorization.
Run ./server.sh, then ./start_ui.sh and open http://localhost:8001. The UI launcher restarts
an existing trader UI on the requested port (default 8001), leaves unrelated services untouched,
and syncs dependencies, including the local dbzero wheel, into the project environment.
The UI uses NiceGUI 3.18.0, which removes the older vbuild dependency incompatible
with Python 3.14. Trader initialization and dashboard reads run in worker threads so dbzero transactions stay outside NiceGUI asyncio tasks.
The page loads before its server connection is ready. Previously verified traders open their local
portfolio, history, approvals, budgets, and cached prices even without connectivity. Local
approval edits remain available; opening, closing, cancellation, and reconciliation are
disabled while offline. Cached access requires the same local credentials, broker user key,
trader, and environment. A new trader without a verified local record waits for its first
successful connection.
Connectivity is checked in the background every 15 seconds, including after failed startup; Reconnect now requests an earlier check. Recovery verifies the broker identity again, resumes price refresh and reconciliation, and enables trading in the existing workspace. It never resubmits orders. Offline prices retain their original timestamps and become stale normally. Startup and background failures are logged; the UI shows connection status without blocking the page.
The browser regression test uses an isolated database and simulated broker without external
trading. Install playwright with uv pip install --python .venv/bin/python playwright and run .venv/bin/python -m playwright install chromium,
then .venv/bin/python -m pytest tests/test_web_ui.py. NiceGUI must also be installed.
The workspace shows only the selected trader’s durable local positions, pending orders, and execution history. Account cash, external positions, and old account-wide valuation snapshots do not enter its dashboard. Allocated capital is strategy capital, not a broker deposit; Available strategy budget follows the existing admission rules. Uninitialized traders can initialize their allocation in the workspace.
Use Add approved instrument, type a symbol (such as BTC) or a numeric instrument ID,
and click Add instrument. This saves the approval locally without contacting eToro;
Find instrument is optional. Symbols are normalized and persist immediately. The broker
validates the instrument through trading eligibility when preparing an order, then its
canonical ID is saved. An unresolved symbol shows Waiting for market data until that
ID is known. Removing approval still blocks opening by either symbol or resolved ID. Approval lists start empty, including for existing
databases. Every opening path (UI, Python API, CLI, and demo smoke command) requires
approval. Removing approval blocks new openings and invalidates earlier opening reviews;
existing positions and pending orders remain available for closing or cancellation.
Approvals persist per trader and changes appear in the local audit log.
Instrument lookup and previous-close data use the standard eToro read-only endpoints
by default, including for existing profiles. ETORO_INSTRUMENTS_URL and
ETORO_CLOSING_PRICES_URL can be explicitly configured as shown in .env_demo.example;
configured values still undergo strict host and path validation. Missing previous-close
data displays Waiting for daily change.
Approval never bypasses the broker’s eligibility, permission, or budget checks.
Place order opens a dedicated draft/review dialog containing only approved instruments. Dismissing the dialog invalidates its review. Open orders default to market and leverage one. Market-if-touched and limit IOC are available when supported by the configured broker. Review the trader, environment, instrument, size, estimated costs, and budget impact before submitting. Positions support full or partial closing (default 100%); owned pending orders support cancellation when the corresponding broker route is configured. Editing a draft or switching workspaces invalidates its review. Repeated submission uses the same idempotency key. Pending or unknown executions are reconciled through their existing records, without replacement orders, and dispatched work continues if the browser disconnects.
P/L uses confirmed fills and costs. Realized P/L is gross confirmed close profit minus confirmed execution costs, including opening fees once. Unrealized P/L uses remaining confirmed units and bid for longs or ask for shorts; leverage is not applied again. Missing required execution, cost, or price data displays Waiting. An initialized trader with no executions has an empty portfolio and zero P/L.
Portfolio equity and cash also include broker-reported overnight fees and dividends
and outstanding estimated overnight charges. eToro reports these adjustments together
in position totalFees: positive amounts are charges, negative amounts are refunds.
Reported amounts reduce settled strategy P/L; positive unreported estimates reserve
trading capacity separately from entry capital. Estimated refunds do not expand capacity.
Broker snapshots replace covered estimates, and closed-trade net settlement replaces
provisional accounting without deducting fees again.
Configure charging calendars per trader and instrument through the CLI:
trader --config .env_demo fees schedule set --instrument-id 1001 \
--timezone Europe/London --rollover-time 22:00 --weekdays mon,tue,wed,thu,fri --weekend-day fri
trader --config .env_demo fees schedule show --instrument-id 1001
trader --config .env_demo fees refresh
trader --config .env_demo fees schedule remove --instrument-id 1001The calendar above is an example; configure the instrument's actual charging calendar. Estimates accrue only after rollover, using the cost API's overnight or weekend amount and confirmed units held at that event. Rates refresh at most hourly and expire for estimation after two hours. Missing schedules/rates and stale fee snapshots are flagged; known reported fees remain included. No historical estimates are invented before the first fee snapshot. Fee data and schedules persist across restarts.
The workspace uses Portfolio, Approved instruments, Strategy, Market events, Pending orders, and History tabs. Portfolio boxes group all owned positions by instrument. Their area represents remaining allocated strategy capital plus unrealized P/L, relative to this trader's total worth (initial allocation plus confirmed realized and unrealized P/L). A neutral Cash box includes cash reserved for pending orders; Available strategy budget remains the separate admission limit. Partial closes prorate invested capital using confirmed remaining units, and leverage is not applied again. Green/red indicates the instrument's change since the broker's previous daily close, even for short positions. Indicative price is the bid/ask midpoint.
The Approved instruments tab includes held and unheld approvals. Position and instrument actions appear as tool buttons on hover or keyboard focus and remain visible on touch devices. Closing a position opens a percentage dialog before the trade review. Missing accounting or valuation displays Waiting, with no chart until complete. Negative components or nonpositive worth are displayed in text without a misleading treemap. Details remain accessible for tiny holdings.
Prices for both held and approved instruments refresh every 60 seconds, after executions or approval additions, and on manual request (subject to broker retry backoff). Cached prices survive errors and restarts. Each position shows its last successful quote timestamp; it turns red only after 90 seconds. Aggregate P/L uses the oldest contributing price timestamp. Reloading the page does not refresh that timestamp. Confirmed fills and prices use separate persisted records, preserving existing databases; execution backfill looks up only locally recorded orders.
Commands serialize per trader, with broker I/O outside database critical sections. Persistent model classes use empty Python slots to avoid inheriting managed instance dictionaries and weakrefs into dbzero's native memory layout on CPython 3.14. This preserves stored fields and existing databases. Database critical sections also defer automatic cyclic garbage collection while the pinned native extension releases the GIL, restoring the previous GC setting immediately afterward. Trading tests use simulated brokers, including two traders sharing an account and unrelated external positions.
Historical validation limitation with dbzero 0.6.8: layout, registration, authentication,
news, and shared-calendar checks pass, but the full non-external suite aborts
inside native immutable-object cleanup during database close. The quarantined
test_dbzero_repro.py also fails when enabled. Existing model-layout and GC
safeguards remain in place; native trading and restart stability is unresolved.
Queries requiring declaration migration raise dbzero.MigrateError when startup
migration is disabled. Explicit migration remains covered by a regression test;
that test failed to recover the historical record with the 0.6.8 build.
The project now uses the local dbzero 0.6.10 wheel. Storage/CLI upgrade checks pass,
but the existing explicit declaration-migration regression still fails to recover
the historical record after db0.migrate(Legacy) with 0.6.10. Existing GC and model
layout safeguards and the native-crash quarantine remain in place.
Trading descriptions can be published as immutable trader-local strategy versions.
Use trader --config .env_demo strategy show, export with
strategy show --text, then publish your edited UTF-8 file with
strategy publish --file strategy.txt --expected-version N (0 for the first
publication). The Strategy UI tab provides the same workflow. Transactions retain
whichever version was current at submission. See the
versioned strategy documentation.
Each environment has a local calendar shared by its traders. Use the Market events tab to browse the next 14 days, filter by range/instrument/category/importance, group by day or category, and inspect expectations and outcomes. Populate through the API or offline-first CLI:
./trader --config .env_demo events list --days 14
./trader --config .env_demo events put --file event.json --expected-revision 0
./trader --config .env_demo events import --file events.json
./trader --config .env_demo events show --key us-employment-2026-11Imports are atomic and revision checked. CLI listing collects all pages and retries when the calendar changes. Events can reference multiple instrument IDs without changing trading approvals. See the calendar API and CLI reference for the JSON format, all-day schedules, outcome timing, permissions, and limits.
Each trader has a private local news library, isolated by environment. Collect supplied articles or notes through the News tab, API, or offline-first CLI. News starts empty; adding a URL stores the link without fetching it. Instrument cards provide a News action that opens the library filtered to that asset. The UI supports search, add/edit, archive/restore, and revision conflict handling.
./trader --config .env_demo news add --symbol AAPL \
--title 'Article title' --body 'Your summary or note' --source-url https://example.org/article
./trader --config .env_demo news list --symbol AAPL
./trader --config .env_demo news list --search earnings --all --json
./trader --config .env_demo news show --key <saved-key>News commands print readable output by default; --json returns the standard CLI envelope.
Symbols and instrument IDs need no trading approval. See the news API and CLI reference
for stdin imports, edits, revisions, filters, and limits.
market_research.sh starts one unattended Codex session using gpt-6.1-sol with
high reasoning effort, live web search, and --yolo. Run it inside your externally
managed safe sandbox with an already authenticated Codex CLI on PATH, flock,
and the project dependencies installed. It asks no questions and exits when done.
./market_research.sh --trader alpha # demo, .env_demo
./market_research.sh --trader alpha --real # real, .env_real
./market_research.sh --trader alpha --demo --config .env_demo_child
./trader --config .env_demo --expected-environment demo --json instruments listResearch covers locally approved instruments, including unresolved symbol approvals, rather than the full broker catalog. The agent reviews existing News records, strategy, and upcoming events, then saves missing, refreshed, or deeper research in the trader's News library with sources and observation times. Its instructions permit research and verified calendar writes; they prohibit trades and changes to approvals, strategies, or project code. There is no research-specific enforcement layer around the YOLO agent.
Profiles must be project-root filenames with mode 0600. Demo is the default;
--demo and --real are mutually exclusive. Every trader command asserts the selected
environment. Concurrent runs for the same environment/trader skip successfully;
locks live in ignored .market-research/. Codex output streams to the caller and its
exit status propagates. Review its final summary for partial research failures.
Schedule externally, using the same OS account and Codex authentication as your manual
run. For example, this cron entry runs hourly; ensure cron's PATH includes Codex:
0 * * * * /src/dev/market_research.sh --trader alpha >> /path/to/market-research.log 2>&1Adjust the schedule to the relevant exchanges' market hours and timezone. The script does not filter market hours or impose a timeout; an active session prevents overlap with the next invocation for that trader/environment.
update_strategy.sh runs an unattended Codex session with the same model, high
reasoning effort, live search, and YOLO mode. Supply the trader's investment goal
on its first run using --goal-file goal.json for a structured objective or
--goal for a legacy text goal; later invocations reuse the latest saved goal when both are
omitted. A supplied goal is saved before Codex starts, even if the agent ultimately
leaves the strategy unchanged or fails. Goal versions are private to the selected
trader/environment and retain their exact text.
./update_strategy.sh --trader alpha \
--goal="Super aggressive short term investor. Expected gains: 10% MoM, maximum allowed drawdown -25% MoM"
./update_strategy.sh --trader alpha --goal-file goal.json # structured registration
./update_strategy.sh --trader alpha # reuse saved goal
./update_strategy.sh --trader alpha --real --config .env_real_child --goal='Your real-account objective'
./trader --config .env_demo goal show
./trader --config .env_demo goal history
./trader --config .env_demo performance summary --period month
./trader --config .env_demo performance operations --limit 100The agent reviews current/historical strategies, approved instruments, news, market events, portfolio exposure, stored equity observations, and operation outcomes attributed to their original strategy versions. It publishes an initial strategy or a justified new version automatically; an adequate strategy stays unchanged. Publications record the goal version and declared approved instruments. The API rejects a changed goal or an instrument removed before publication. This validates the declared universe; free-form strategy text is not mechanically parsed for instrument mentions. Existing trading approval checks still apply to orders.
Targets are free-form objectives. Performance tools report stored observations,
coverage gaps, staleness, percentage returns and sampled absolute/percentage
drawdown for the fixed local strategy allocation. Broker deposits and unrelated
holdings are excluded. These tools do not provide backtests. The agent must acknowledge
missing evidence rather than claim verified target achievement. These reads use
existing collected data and do not refresh execution details or start a collector.
Portfolio refreshes (one-shot and the UI's existing collector) persist local equity
samples. A recorded activation supplies the initial cash-allocation baseline when
no samples exist. return_percent measures change from the first period sample;
maximum_drawdown_percent measures each decline against its preceding peak.
coverage_complete and missing_intervals expose unobserved history.
net_accounting_complete distinguishes settled net outcomes from unavailable
execution-cost breakdowns. Earlier unobserved market values are never invented.
The agent writes a Markdown playbook targeting 300–500 words, with short executable rules under Objective and universe, Entries, Sizing and exposure, Exits and risk, Monitoring and catalysts, and References. Converting a verbose strategy into this format justifies a new version while preserving useful rules. Supporting research stays in News; tooling diagnostics go to Tool requests. The word target is prompt guidance, with no additional publication validation.
Current strategies, published history, trade-linked dialogs and conflict comparisons render sanitized Markdown with responsive document styling. The editor and API retain exact raw UTF-8 text; historical versions are unchanged.
The agent's instructions allow strategy publication, calendar upkeep, source
recommendations and tool-request reports, and prohibit trading or changes to goals,
News, approvals or code. Research performs primary calendar upkeep; strategy updates
reconcile missing or changed catalysts before publication. Both workflows check the
next 14 days, preceding 30 days and any dated catalyst used in their rules. Empty
calendars trigger catalog checks, including official macro schedules. Agents preserve
existing content, verify schedules and past outcomes, record source URLs and UTC
verification times, reuse keys, write with expected revisions and read back every
calendar write. Macro events can have no instrument assignments. Unverified records
cannot support date-specific execution rules; failures appear in run summaries.
As with market research,
YOLO isolation is supplied externally. Strategy updates use separate per-trader
locks, so research may run concurrently; final strategy/goal checks resolve races.
Invoke this script from your scheduler with the same authentication and PATH as
your manual run. No timeout or market-hour filter is imposed.
rebalance.sh executes justified portfolio changes using the saved goal and the
current strategy linked to that goal version. It uses gpt-6.1-sol with high
reasoning effort, live search, YOLO mode, no questions, and automatic exit.
./rebalance.sh --trader alpha # demo, .env_demo
./rebalance.sh --trader alpha --real --config .env_real_childThe launcher works from any directory, checks both documents and account readiness through the scoped CLI, and takes a separate nonblocking lock per trader/environment. An overlapping rebalance exits successfully without starting another session. Scheduling remains external; research and strategy runs use independent locks. Goal overrides and strategy publication are unavailable in this workflow.
Each invocation retains a private directory under ignored .market-research/ with
journal.json, streamed output.log, and Codex's final summary.txt. The journal
captures configuration snapshots and the agent records plans, previews, stable
idempotency keys, intent IDs, outcomes, and bounded recovery attempts. Later runs
inspect earlier unresolved actions before trading. An interrupted run must be
reconciled with its original preview/key rather than replaced. The script preserves
Codex's exit status; that status alone does not establish trade completion.
Journal durable mutation plans and outcomes; keep read observations compact and
reuse helpers instead of regenerating them per command. Recovery waits 5/10/20
seconds before at most three refresh/status checks. Refresh already reconciles
pending executions, so each attempt needs no additional reconcile call. Confirm
both the original intent and remaining units: fresh quotes do not prove a fill.
All three launchers batch independent reads, reuse results, and bound research
for unavailable facts rather than repeating searches indefinitely.
The agent refreshes owned holdings, considers approvals, news, events, performance, costs, financing, pending exposure, and budgets, then executes reductions before dependent openings. Every submission carries both expected configuration versions. A changed document stops new submissions without undoing completed actions. Missing compliance evidence prevents new exposure while permitting clearly justified risk reductions consistent with the current documents. Free-form financial objectives are assessed by the agent; the API enforces versions, declared scope, ownership, budgets, and existing admission rules. Targets are objectives, not guarantees.
Like the other unattended launchers, this requires an externally managed safe sandbox. Workflow restrictions on journal writes and configuration changes are agent instructions; YOLO mode does not impose a command allowlist.
The rebalance agent must choose, save, and verify next_rebalance_at before
finishing, including runs where it makes no trades or stops on a configuration
conflict. It uses the strategy horizon, market hours, catalysts, evidence gaps,
and uncertain execution outcomes to choose the time, and records its rationale
and verified timestamp in the journal and final summary.
./trader --config .env_demo --json rebalance-schedule show
./trader --config .env_demo --json rebalance-schedule set \
--at '2026-10-12T14:00:00+00:00' --expected-version 0
./trader --config .env_demo --json statusUse the current version from show when setting a future, timezone-aware time.
The field is private to the trader/environment and also appears in status.
The workspace displays Next rebalance below its summary metrics, in UTC, and
updates it on the existing five-second poll. An unset time shows Not planned.
It records the intended rebalance time only. External scheduling, including
preceding market research and strategy review, is handled separately; recording
this field does not create a job or prevent manual rebalances before it is due.
Authenticated research uses the same scoped CLI and JSON envelope as other reads:
./trader --config .env_demo --json instruments lookup ETH
./trader --config .env_demo --json market-data snapshot --symbol ETH
./trader --config .env_demo --json market-data candles --instrument-id 1001 --interval OneDay --count 100
./trader --config .env_demo --json sources list --symbol ETH
./trader --config .env_demo --json sources show --key etoro-market-data
./trader --config .env_demo --json sources put --file source.json --expected-revision 0
./trader --config .env_demo --json sources archive --key my-source --expected-revision 1
./trader --config .env_demo --json tool-requests list --status open
./trader --config .env_demo --json tool-requests report --file request.json
./trader --config .env_demo --json tool-requests show --key broker-fundamentalsSupply TRADER_KEY as usual. Lookup returns broker metadata and does not approve
instruments. Snapshot/candle reads require local approval, reject ambiguous symbols,
and never call trade previews, costs, eligibility, or execution. A snapshot includes
instrument metadata, bid/ask/spread, latest daily close, observation timestamps, and
explicit reasons for unavailable components. Authentication failures stop the read.
Quotes parse the broker date field, with legacy timestamp compatibility, and
expose UTC broker_timestamp, timestamp_source, timestamp_basis, quote_type,
clock_skew_seconds, and timestamp_age_seconds. Age uses response receipt time.
Up to five seconds of future broker skew is accepted with age zero; larger skew
and malformed timestamps produce sanitized per-instrument diagnostics. Missing
timestamps retain unknown age. The demo uses eToro's v2 rates feed; explicitly
configured v1 routes remain supported, without fallback after v2 failures.
Timezone-less v2 dates use UTC. Missing, null, or blank eToro currencies default
to USD with currency_source=etoro_default; explicit currencies use broker.
Other brokers keep unknown currency behavior. Existing News keys remain symbol based.
portfolio-refresh --wait --timeout-seconds 60 queues through the server's
existing collector and polls once per second in the caller. Without an active
worker, it collects synchronously. Requests during collection schedule a further
pass. Inspect completed and completion_state; fresh cached values or changed
generation do not establish completion. Poll an existing request with
portfolio-refresh --status-only --requested-at TIMESTAMP. Collection failures
and REFRESH_TIMEOUT include sanitized status; broker backoff remains in effect.
Strategy freshness requirements and intent-level trade verification remain unchanged.
Candles default to 100 OneDay observations, with counts 1–1000. Supported intervals:
OneMinute, FiveMinutes, TenMinutes, FifteenMinutes, ThirtyMinutes, OneHour,
FourHours, OneDay, OneWeek. The optional ETORO_CANDLES_URL profile route is
https://public-api.etoro.com/api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}.
The adapter requests newest observations and returns them chronologically with UTC
timestamps, decimal strings, optional volume, and incomplete-candle flags. Coverage
shows shortfalls and gaps without synthesizing observations; gaps may include market
closures. See the eToro candle contract.
research-sources and tool-requests are shared by all authenticated traders in one
environment, isolated between demo and real, and reserved against trader registration.
The catalog seeds curated recommendations once without overwriting edits. Source
JSON contains key, name, url, coverage and topics (text arrays), symbols
(text array), category, rationale, limitations, and optional archived.
Agent additions become visible immediately. Authenticated authorship, timestamps,
origin, and edit provenance are server generated. Catalog records are descriptive;
they cannot add executable commands, broker routes, or authenticated HTTP targets.
Broker access information comes from the selected profile. Other documented eToro
research APIs are labeled as requiring integration. Farside is a specialist
aggregator, distinct from issuer and protocol primary sources.
Source writes require the current --expected-revision (0 for creation); --file -
accepts stdin. Tool report JSON contains key, workflow, run_id,
missing_capability, attempted_command, error, evidence, desired_inputs,
desired_outputs, workaround, and kind (missing_integration,
configuration_access, insufficient_data, bug_report, or feature_request).
Use bug_report for suspected defects with exact scoped commands, relevant observed
results, expected behavior in desired_outputs, and a workaround. Describe unconfirmed
discrepancies as suspected bugs after a bounded reproducibility check. Use
feature_request for absent capabilities; ordinary market uncertainty remains research.
Reports deduplicate by stable key and retain all traders and occurrences. Repeated
reports from the same trader/workflow/run are idempotent. Reports preserve review
status and notes. The workspace Sources and Tool requests tabs expose
coverage, provenance, profile access, evidence, and filters, and poll shared
generations. Request reviews use revision checks, support open, planned,
implemented, and declined, and display new reports received since the last review.
Review tickets through the authenticated CLI, preserving occurrence history:
./trader --config .env_demo tool-requests review --key KEY --expected-revision REV \
--status implemented --review-note 'Acceptance checks and evidence'The local quota is 60 requests per rolling minute per user credential, shared by
server transports, including at most 16 execution requests and 20 heavy reads
(candles and trade history). Rate-limit errors identify quota_origin and
retry_after_seconds; broker Retry-After blocks that credential until its deadline.
Wait before retrying reads. Trade mutations are never automatically retried.
Performance charts use stored bucket resolution even when historical tags are
missing. coverage_complete, reasons, expected_bucket_count,
returned_bucket_count, and last_observed_at describe historical coverage.
stale describes collector freshness independently. Boundary buckets contain their
whole stored interval; historical gaps remain gaps. The workspace chart displays
these coverage and freshness values separately.
All three launchers discover catalog sources, reuse News and macro evidence, and check supported broker reads before reporting data unavailable. Their permissions include source recommendations and concrete tool reports in addition to each workflow's existing writes. Bounded temporary Python orchestration/analysis helpers remain allowed when they preserve authentication and scope. Agents must not add broker integrations themselves. Unconfirmed external facts remain uncertainties; unavailable data is never an entry signal. Fallback searches are limited to two per instrument after checking recommended sources; News changes require substantive new evidence and permission from the active workflow.