End-to-end user journey from algorithm creation through backtesting, paper trading, and graduation to live.
journey
title Algorithm Trading User Journey
section Create Algorithm
Navigate to /admin/algorithms: 5: User
Click "New Algorithm": 5: User
Choose: From English or Manual DSL: 4: User
Describe strategy in natural language: 4: User
Review translated DSL: 4: User
Save algorithm: 5: User
section Configure & Backtest
Click "Backtest" on algorithm card: 5: User
Select lookback period (90/180/365/730): 5: User
Optionally select dataset: 4: User
Click "Tune" for risk overrides: 3: User
Click "Run Backtest": 5: User
View loading spinner: 3: User
section Analyze Results
Review equity curve chart: 5: User
Check 13 metrics in grid: 5: User
Examine drawdown chart: 4: User
View trades table: 4: User
Check guardrail kills: 4: User
Review factor attribution: 3: User
section Paper Trading
Click "Paper Trade" button: 5: User
Algorithm starts in paper mode: 5: User
Monitor daily equity updates: 4: User
Check EOD critic reports: 3: User
Complete 30 days + 50 trades: 4: User
section Graduation
Verify Sharpe >= 1.0: 4: User
Verify Max DD <= 15%: 4: User
Verify PSR >= 0.95: 4: User
Verify Walk-Forward >= 0.70: 4: User
Complete MFA + Risk Ack: 5: User
section Live Trading
Click "Go Live": 5: User
Algorithm executes on broker: 5: User
Daily EOD critic reviews: 4: User
Monitor via dashboard: 5: User
2. UI Component Hierarchy
React component tree for the algorithms page and all modals.
Natural language to DSL translation with anti-hallucination defenses.
sequenceDiagram
participant U as User
participant UI as FromEnglishModal
participant API as /from-english endpoint
participant LLM as Claude (translate.ts)
participant Parser as DSL Parser
participant DB as algorithm_llm_rejections
U->>UI: Enter: "Buy NVDA when RSI<30, sell when RSI>70"
UI->>API: POST { description }
API->>LLM: Translate to StrategyAST
LLM-->>API: Return JSON AST
API->>Parser: Validate AST structure
alt Parse Success
Parser-->>API: Valid AST
API->>Parser: Check primitives against whitelist
Parser-->>API: All primitives valid
API-->>UI: { ast, dsl }
UI->>U: Show DSL preview
else Unknown Primitive
Parser-->>API: Error: "unknown_primitive" not in registry
API->>DB: Log rejection
API->>LLM: Retry with specific error
Note over LLM: Max 3 attempts
LLM-->>API: Corrected AST
else Syntax Error
Parser-->>API: Parse error
API->>DB: Log rejection
API-->>UI: { error }
UI->>U: Show error, suggest fixes
end
9 Anti-Hallucination Defenses
#
Defense
Implementation
1
Zod Schema Validation
All LLM output validated against strict Zod schemas
2
Primitive Whitelist
375 primitives in PRIMITIVES registry, reject unknown
3
Cite-or-Refuse
Critiques must name specific primitive or metric
4
Deterministic Cross-Validation
Sharpe/DD/return gates before accepting modifications
5
LLM-Jury
Proposer/Critic/Judge pattern for modifications
6
Confidence Threshold
0.85 threshold forces human escalation
7
Rejection Audit Log
All rejections persisted to algorithm_llm_rejections
8
asOf-Frozen Context
Evaluator context locked to bar timestamp, no look-ahead
9
Adversarial Review
Explicit "find what's wrong" prompt in critic phase
6. DSL Primitive Categories
375 primitives organized into 13 categories for signal generation and strategy construction.
How the DSL evaluator processes expressions with no-look-ahead guarantee.
flowchart TB
subgraph Input["Input (per bar)"]
AST["Expression AST"]
Bar["Current OHLCV Bar"]
History["Historical bars[0..idx]"]
AsOf["asOf timestamp"]
end
subgraph BuildContext["Build EvalContext"]
Prices["prices: Record"]
Indicators["IndicatorBundle"]
Position["Current position state"]
Macro["Macro overlays (VIX, yields)"]
Sentiment["Sentiment scores"]
end
subgraph Evaluate["evaluate(expr, ctx)"]
Switch{"expr.type?"}
Literal["Return expr.value"]
Identifier["Look up in ctx.prices"]
subgraph FunctionCall["Function Call"]
Lookup["PRIMITIVES[expr.name]"]
Args["Evaluate args recursively"]
Dispatch["Dispatch to handler"]
end
subgraph BinaryOp["Binary Operation"]
Left["evaluate(expr.left)"]
Right["evaluate(expr.right)"]
Apply["Apply operator"]
end
end
subgraph Handlers["Primitive Handlers"]
Tech["Technical: ctx.indicators.rsi(14)"]
Macro2["Macro: ctx.vix()"]
Pos["Position: ctx.position.*"]
Pattern["Pattern: detectFVG(ctx.bars)"]
end
AST --> Switch
Bar --> BuildContext
History --> BuildContext
AsOf --> BuildContext
BuildContext --> Indicators
BuildContext --> Position
BuildContext --> Macro
Switch -->|"literal"| Literal
Switch -->|"identifier"| Identifier
Switch -->|"call"| FunctionCall
Switch -->|"binop"| BinaryOp
FunctionCall --> Handlers
Handlers --> Result["boolean | number"]
No-Look-Ahead Guarantee: The evaluator only has access to bars[0..idx] where idx is the current bar index. All indicators compute against historical data only. The asOf timestamp is used to filter overlays and macro data.
9. Risk Management Pipeline
Multi-layer risk checks from entry signal to execution.
flowchart TB
subgraph EntrySignal["Entry Signal Generated"]
Signal["entry.when == true"]
Size["Calculate size via kelly/fixed"]
end
subgraph PreTradeChecks["Pre-Trade Risk Checks"]
MaxPos["max_position_usd check"]
DailyLoss["max_daily_loss_pct check"]
Drawdown["max_drawdown_pct check"]
Correlation["Portfolio correlation check"]
Slippage["Slippage-aware sizing"]
end
subgraph Execution["Trade Execution"]
SlippageCalc["Almgren-Chriss slippage"]
Execute["Execute trade"]
Record["Record to algorithm_trades"]
end
subgraph PostTradeMonitor["Post-Trade Monitoring"]
StopLoss["stop_loss_pct monitoring"]
TrailingStop["trailing_stop_pct tracking"]
HoldingPeriod["Holding period checks"]
EODCritic["EOD LLM critic (live only)"]
end
subgraph ExitTriggers["Exit Triggers"]
SignalExit["exit.when == true"]
StopHit["Stop loss hit"]
TrailingHit["Trailing stop hit"]
GuardrailKill["Guardrail kill"]
Liquidation["Leverage liquidation"]
end
Signal --> Size --> MaxPos
MaxPos -->|"Pass"| DailyLoss
MaxPos -->|"Fail"| Reject["Reject trade"]
DailyLoss -->|"Pass"| Drawdown
DailyLoss -->|"Fail"| Reject
Drawdown -->|"Pass"| Correlation
Correlation -->|"Pass"| Slippage
Slippage --> Execute --> Record
Record --> StopLoss
StopLoss --> TrailingStop
TrailingStop --> HoldingPeriod
SignalExit --> Exit["Close position"]
StopHit --> Exit
TrailingHit --> Exit
GuardrailKill --> Exit
Liquidation --> Exit
10. Graduation Gates
Requirements for promoting algorithms from paper to live trading.
flowchart LR
subgraph BacktestPhase["Backtest Phase"]
BT["Run backtest"]
BTMetrics["Calculate metrics"]
BTPass{"Sharpe >= 0.5?"}
end
subgraph PaperPhase["Paper Trading Phase"]
Paper["Paper trade 30 days"]
Trades["Complete 50+ trades"]
PaperMetrics["Real-time metrics"]
end
subgraph GraduationGates["Graduation Gates"]
G1["Sharpe >= 1.0"]
G2["Max DD <= 15%"]
G3["PSR >= 0.95"]
G4["Walk-Forward OOS/IS >= 0.70"]
G5["MFA Verification"]
G6["Risk Acknowledgement"]
end
subgraph LivePhase["Live Trading"]
Live["Execute on broker"]
EOD["Daily EOD critic"]
Monitor["Real-time monitoring"]
end
BT --> BTMetrics --> BTPass
BTPass -->|"Yes"| Paper
BTPass -->|"No"| Iterate["Iterate strategy"]
Paper --> Trades --> PaperMetrics
PaperMetrics --> G1 --> G2 --> G3 --> G4 --> G5 --> G6
G6 -->|"All Pass"| Live
G1 -->|"Fail"| Continue["Continue paper trading"]
Live --> EOD --> Monitor
Key tables for algorithm storage and execution tracking.
erDiagram
user_algorithms ||--o{ algorithm_versions : has
user_algorithms ||--o{ algorithm_runs : executes
algorithm_runs ||--o{ algorithm_trades : generates
algorithm_runs ||--o{ algorithm_telemetry : records
algorithm_runs ||--o| algorithm_run_status : has_current
user_algorithms ||--o{ algorithm_llm_rejections : logs
user_algorithms ||--o{ algorithm_llm_jury : decides
algorithm_runs ||--o{ algorithm_eod_critic : reviewed_by
user_algorithms {
uuid id PK
uuid user_id FK
string name
jsonb ast
string mode
string status
timestamp created_at
}
algorithm_versions {
uuid id PK
uuid algorithm_id FK
jsonb ast
string change_reason
timestamp created_at
}
algorithm_runs {
uuid id PK
uuid algorithm_id FK
string mode "backtest|paper|live"
string status "running|stopped|killed"
numeric starting_equity
numeric current_equity
jsonb metrics
timestamp started_at
timestamp ended_at
}
algorithm_trades {
uuid id PK
uuid run_id FK
string symbol
string side "buy|sell"
numeric requested_price
numeric executed_price
numeric executed_qty
numeric pnl
numeric slippage_bps
string exit_reason
timestamp ts
}
algorithm_telemetry {
uuid id PK
uuid run_id FK
numeric equity
numeric drawdown_pct
jsonb positions
timestamp ts
}
algorithm_run_status {
uuid run_id PK
numeric current_equity
jsonb positions
timestamp last_tick_at
}
algorithm_eod_critic {
uuid id PK
uuid run_id FK
date critic_date UK
string verdict "continue|warn|escalate|kill"
text reasoning
timestamp created_at
}
19. API Routes
Algorithm-related API endpoints.
Route
Method
Handler
Purpose
/algorithms
GET
handleListAlgorithms
List user's algorithms
/algorithms
POST
handleCreateAlgorithm
Create new algorithm
/algorithms/from-english
POST
handleFromEnglish
NL to DSL translation
/algorithms/:id/backtest
POST
handleBacktestAlgorithm
Run backtest
/algorithms/:id/walk-forward
POST
handleWalkForwardBacktest
Walk-forward optimization
/algorithms/:id/monte-carlo
POST
handleMonteCarloBacktest
Bootstrap simulation
/algorithms/:id/stress-test
POST
handleStressTestAlgorithm
Regime stress test
/algorithms/:id/critique
POST
handleCritique
LLM critique
/algorithms/:id/paper/start
POST
handleStartPaperRun
Start paper trading
/algorithms/:id/paper/stop
POST
handleStopPaperRun
Stop paper trading
/algorithms/:id/live/start
POST
handleStartLiveRun
Start live trading (gated)
/ai-kill-switch/activate
POST
handleActivateKillSwitch
Emergency stop all trading
20. Credits System
Trading credits lifecycle for paper and live trading.
sequenceDiagram
participant User
participant StartRun as startRun()
participant Credits as user_credits
participant Executor as Paper Executor
participant StopRun as stopRun()
User->>StartRun: Start paper trading
StartRun->>Credits: Check available credits
Credits-->>StartRun: Available: $100,000
StartRun->>Credits: Reserve $10,000 for run
Note over Credits: available: $90,000 reserved: $10,000
StartRun-->>Executor: Run started
loop Every Tick
Executor->>Executor: Calculate equity
Executor->>Credits: Sync reserved with equity
Note over Credits: If equity = $10,500 reserved syncs to $10,500
end
User->>StopRun: Stop run
StopRun->>Executor: flattenAllPositions()
Executor->>Executor: Close all positions at market
StopRun->>Credits: Release credits + P/L
Note over Credits: available: $100,500 reserved: $0 (+$500 profit applied)
Credits Table Structure
Column
Type
Description
user_id
UUID
User reference
available_credits
NUMERIC
Credits available for new runs
reserved_credits
NUMERIC
Credits locked in active runs
total_pnl
NUMERIC
Lifetime P&L across all runs
updated_at
TIMESTAMP
Last update time
Primitives Requiring Data Sources
Some DSL primitives require external data feeds that may not be fully configured.
Note: The following primitives may return default/stubbed values if the required data source is not configured: