Open the app
Architecture

Multi-profile extensibility

The seams frozen now so adding Forex or commodities is a new profile, not a rewrite.

Today there is one profile: crypto new listings. The goal is that adding a new business brick — Forex, commodities — is a new profile reusing the whole infrastructure, not a rewrite. The cost is naming the seams today versus a painful refactor later.

Generic infrastructure vs business brick

Two things with different lifetimes, kept separate:

  • Generic infrastructure (knows nothing about crypto or forex): the multi-agent system, SQLite memory, trade journal, scoring engine, guardrail framework, notifications, CI/CD, Docker images.
  • A profile (specific to an asset class): a data source, an execution adapter, a strategy, and a risk profile.

Interfaces to freeze now

Four seams, frozen even with a single implementation behind each:

InterfaceResponsibilityTodayLater
MarketDataSourceFetch history + subscribe to live dataExchanges + feedsForex broker
ExecutionAdapterPlace / cancel / reconcile an order (restricted surface)Crypto exchangesForex broker
StrategyConsume normalized candles + flags, emit signalsNew listingsOther
RiskProfileCaps and rules specific to the asset classCrypto spotForex (margin)
The seam already exists
The normalized candle schema (timestamp, OHLCV, symbol, timeframe, UTC) is the join. As long as Forex enters through that same format, the engine, backtest and journal do not see the difference. That is what prevents the “rewrite everything”.

Data & deployment consequences

  • A profile discriminator on every domain record so profiles share one Convex backend without colliding.
  • One runtime container per profile, same image, different config (runtime-crypto, later runtime-forex ). Deploy, restart or break Forex without touching crypto.
  • SQLite memory per profile (separate volume), so each profile’s cognition stays isolated.

The real catch: Forex is not “crypto with other symbols”

Three differences hit the risk layer directly — which is why it must be parameterized per asset class:

Leverage / margin

Forex is almost always traded on margin. Current guardrails assume spot with no leverage. Guardrails must read leverage from the RiskProfile, never assume spot = no leverage in code.

Market hours

Forex closes on weekends (crypto is 24/7), creating open-gap risk. The data and execution abstractions must not assume always-on markets.

Broker APIs

Forex broker APIs are often less clean than crypto exchange APIs, so the adapter abstraction must not bake in crypto-exchange semantics.

Technical vs risk extensibility
Technical extensibility is easy to guarantee by naming the seams now. Risk extensibility is the one trap — avoided by keeping the guardrail layer parameterized per profile rather than hard-coding the spot, no-leverage assumption.