███████╗██╗ ██╗ ██████╗ ██╗ ██╗ ██╗██╗ ██╗
██╔════╝██║ ██║██╔═══██╗██║ ██║ ██║╚██╗██╔╝
█████╗ ██║ ██║██║ ██║██║ ██║ ██║ ╚███╔╝
██╔══╝ ╚██╗ ██╔╝██║ ██║██║ ╚██╗ ██╔╝ ██╔██╗
███████╗ ╚████╔╝ ╚██████╔╝███████╗ ╚████╔╝ ██╔╝ ██╗
╚══════╝ ╚═══╝ ╚═════╝ ╚══════╝ ╚═══╝ ╚═╝ ╚═╝
Built on the shoulders of NOFX · Forged into a production trading system
EvolvX transforms NOFX from a brilliant prompt-driven trading app into a disciplined,
testable, self-improving trading platform — without breaking a single existing feature.
What's New · Architecture · Getting Started · API Reference · Credits
NOFX is an extraordinary piece of software. A 10,000+ star open-source AI trading system that lets multiple AI models compete to make trading decisions in real-time. If you haven't seen it — go look at it now. It's genuinely impressive.
But after running it in production, a pattern emerges:
❓ "Did my strategy get better, or did I just get lucky?"
❓ "Which parameter change improved returns?"
❓ "What did the AI decide last Tuesday at 2am and why?"
❓ "If I backtest version 3 of my config, will it match what ran live?"
❓ "How do I prove the AI isn't overfitting?"
The core issue: NOFX is a prompt-first system. The AI is the foundation, and everything else is wired around it. Backtest, paper trade, and live trade use different code paths. Strategies are mutable config blobs. Decision history is raw AI text. There's no learning loop grounded in measured outcomes.
EvolvX is the answer to those questions. It takes NOFX's excellent AI trading machinery and places it on top of four new layers that make the system provably comparable, reproducible, and self-improving.
EvolvX adds four architectural layers on top of NOFX. Every existing feature continues to work. Nothing is removed.
BEFORE (NOFX) AFTER (EvolvX)
───────────────────────────── ──────────────────────────────────────
Backtest: backtest/engine.go ┐
Paper: (not implemented) ├──► ALL THREE → engine/pipeline/pipeline.go
Live: trader/auto_trader.go ┘
MarketEvent
Three divergent code paths → StrategyEvaluator (AI call)
No shared fill model → RiskChecker (same rules)
No shared risk logic → ExecutionAdapter (sim or live)
No replay capability → Fill + EventLogger
→ MetricsCollector
Same schema. Always.
Every market event, signal, order, fill, and metric passes through the same processCycle() function regardless of mode. Backtest results are mathematically comparable to paper results because they use the same fill model, same fee assumptions, same slippage model, same risk checks.
BEFORE (NOFX) AFTER (EvolvX)
───────────────────────────── ──────────────────────────────────────
StrategyConfig { ... } StrategyRecord {
↕ mutable ID: "uuid-stable-across-versions"
↕ no history Version: "1.3.0" ← semver
↕ no lineage Status: "paper" ← lifecycle
↕ no performance tracking Parameters: { ... } ← immutable
} Performance: [...] ← accumulated
ParentID: "..." ← lineage
}
NewVersion() → new row, old row unchanged
SetStatus("approved", "j.peetz69@gmail.com") → human gate
Strategies are versioned artifacts, not mutable config. A change to any parameter creates a new version. The original version is preserved forever. Backtests and live runs always reference a specific ID + Version tuple — you can reproduce any historical run exactly.
BEFORE (NOFX) AFTER (EvolvX)
───────────────────────────── ──────────────────────────────────────
decision_records table: journal.DecisionEntry {
system_prompt: "You are a..." timestamp, symbol, strategy_version
input_prompt: "Market data..." market_snapshot ← price, OI, indicators
raw_response: "<reasoning>..." signal_inputs ← what the AI saw
cot_trace: "Step 1..." reasoning ← why it decided
execution_log: "Filled at..." risk_state ← margin, positions
✗ no market snapshot position_state ← what was open
✗ no risk state outcome ← what actually happened
✗ no outcome review_notes ← human annotation
✗ not queryable by outcome }
✗ lost on restart
Queryable by: strategy, symbol,
date range, outcome class.
Survives restarts. Compactable.
Read before next decision (memory).
The AI now reads its own history before acting. The last 5 decisions for each symbol are injected into the user prompt as structured context. The system knows what it did, what the outcome was, and can avoid repeating mistakes.
BEFORE (NOFX) AFTER (EvolvX)
───────────────────────────── ──────────────────────────────────────
"Learning" = editing prompts Learning = measured outcome → candidate
generation → walk-forward
Ad hoc parameter tweaks validation → threshold filter → human
approval → new version
No overfitting protection
No version lineage Parent v1.0.0
No promotion rules ↓ GenerateCandidates() [~20 mutations]
No human gate ↓ EvaluateCandidate() [train split]
↓ EvaluateCandidate() [val split]
↓ checkThresholds()
↓ Promote() → StatusPaper
↓ Human: SetStatus("approved", "you")
↓ Live
Child v1.0.1 (lineage tracked)
Candidates are scored on out-of-sample validation data only. An overfitting guard rejects candidates where the validation return is less than 40% of the training return. A human approval gate prevents any strategy from going live without explicit confirmation.
┌─────────────────────────────────────────────────────────────────────────────┐
│ EvolvX Pipeline │
│ (identical for all three modes) │
└──────────────────────────────────┬──────────────────────────────────────────┘
│
┌────────────────────▼────────────────────┐
│ MarketFeed │
│ ┌──────────────┐ ┌───────────────────┐│
│ │ Historical │ │ ChannelFeed ││
│ │ (SQLite bars)│ │ (live/paper) ││
│ └──────────────┘ └───────────────────┘│
└────────────────────┬────────────────────┘
│ MarketEvent
▼
┌────────────────────────────────────────┐
│ StrategyEvaluator │
│ │
│ 1. Read prior decisions (journal) │
│ 2. BuildSystemPrompt(params) │
│ 3. BuildUserPrompt(context) │
│ 4. CallAI() → raw response │
│ 5. ParseResponse() → []Signal │
└────────────────────┬───────────────────┘
│ []Signal
▼
┌────────────────────────────────────────┐
│ RiskChecker │
│ │
│ • Max positions │
│ • Leverage caps (BTC/ETH vs altcoin) │
│ • Margin usage enforcement │
│ • Position value ratio caps │
│ • Min position size │
└────────────────────┬───────────────────┘
│ Order (approved / adjusted)
▼
┌────────────────────────────────────────┐
│ ExecutionAdapter │
│ │
│ ┌─────────────────┐ ┌─────────────┐ │
│ │ SimulatedAdapter│ │ LiveAdapter │ │
│ │ (backtest+paper)│ │ (live) │ │
│ │ • Slippage 0.05%│ │ • Real │ │
│ │ • Fee 0.06% │ │ exchange │ │
│ │ • Deterministic │ │ • Poll for │ │
│ │ fill │ │ fills │ │
│ └─────────────────┘ └─────────────┘ │
└────────────────────┬───────────────────┘
│ Fill
┌─────────────┴──────────────┐
▼ ▼
┌─────────────────────┐ ┌──────────────────────┐
│ EventLogger │ │ JournalRecorder │
│ (append-only log) │ │ (decision memory) │
└─────────────────────┘ └──────────────────────┘
│
▼
┌──────────────────────┐
│ MetricsCollector │
│ Sharpe, Sortino, │
│ Drawdown, Win Rate │
└──────────────────────┘
DRAFT ──────► PAPER ──────► APPROVED ──────► DEPRECATED
│ │ │ │
│ │ │ ▼
│ │ │ DISABLED
│ ▼ │
│ (optimizer can │
│ promote here │
│ automatically) │
│ │
└──────────────────────────────┘
Human required
(SetStatus needs changedBy)
Every transition creates a NEW VERSION.
No row is ever overwritten.
Parent Strategy v1.0.0
│
▼
GenerateCandidates()
┌──────────────────────────────────────────────────────┐
│ RSI period variants [7, 9, 14, 21] │
│ EMA period variants [10, 20, 50, 100] │
│ Leverage variants [2, 3, 5, 7, 10] │
│ Confidence variants [65, 70, 75, 80, 85] │
│ Margin usage variants [50%, 60%, 70%, 80%, 90%] │
│ Trading mode variants [aggressive, conservative, │
│ scalping] │
│ Max position variants [2, 3, 4, 5] │
└──────────────────────────────────────────────────────┘
│ ~20 candidates
▼
EvaluateCandidate() × N (parallel workers)
┌──────────────────────────────────────────────────────┐
│ Train split [months -4 to -2] ← fit │
│ Val split [months -2 to now] ← score │
│ │
│ Metrics on VAL split only: │
│ net_return, max_drawdown, sharpe, sortino │
│ win_rate, profit_factor, trade_count │
│ val/train ratio (overfitting guard) │
└──────────────────────────────────────────────────────┘
│
▼
checkThresholds() ← conservative defaults
┌──────────────────────────────────────────────────────┐
│ val_return ≥ 3% │
│ |val_drawdown| ≤ 15% │
│ val_sharpe ≥ 0.5 │
│ val_win_rate ≥ 45% │
│ val_profit_factor ≥ 1.1 │
│ val_trades ≥ 10 │
│ val/train ratio ≥ 0.4 ← no overfit │
└──────────────────────────────────────────────────────┘
│ passing candidates
▼
Promote() → registry v1.0.1, StatusPaper
│
▼
✋ Human gate: SetStatus("approved", "j.peetz69@gmail.com")
│
▼
Live trading
nofx.db (existing — untouched)
auto_traders ← existing strategy configs
decision_logs ← existing AI decision logs
klines ← existing market data
registry.db (new)
strategies ← versioned, immutable strategy records
lineage ← parent → child evolution graph
journal.db (new)
decisions ← per-decision memory with outcomes
summaries ← compacted history for large datasets
optimizer.db (new)
opt_jobs ← optimization job state
event_log.db (new, per session)
event_log ← append-only pipeline audit trail
Same as NOFX:
# macOS
brew install go ta-lib node
# Ubuntu/Debian
sudo apt-get install golang libta-lib0-dev nodejs npm# Clone EvolvX
git clone https://github.com/JPeetz/EvolvX.git
cd EvolvX
# Install dependencies
go mod download
# Build
go build -o evolvx ./...If you already have NOFX running, migration is a single command. It is 100% safe — it reads your existing database and writes to new files. Nothing is modified.
# One-time migration (idempotent — safe to run multiple times)
go run ./cmd/migrate/main.go \
--legacy-db ./nofx.db \
--registry-db ./registry.db \
--journal-db ./journal.db \
--import-decisions # also imports your existing decision logs
# Output:
# migrate: imported 4 strategies, skipped 0
# migrate: imported 1,247 legacy decision records
# migration complete.After migration, start the server normally:
./evolvx
# or with Docker:
docker compose up -dAccess the UI at http://localhost:3000 — all existing features continue to work identically.
# Start fresh (same as NOFX)
curl -fsSL https://raw.githubusercontent.com/JPeetz/EvolvX/main/install.sh | bash
open http://localhost:3000# List all versions of a strategy
curl http://localhost:3000/api/v1/registry/strategies/{id}/versions
# Create a new version (old version preserved)
curl -X POST http://localhost:3000/api/v1/registry/strategies/{id}/versions \
-H "Content-Type: application/json" \
-d '{
"parent_version": "1.0.0",
"bump_type": "patch",
"author": "j.peetz69@gmail.com",
"mutation_summary": "Raised min_confidence from 75 to 80",
"parameters": { "min_confidence": 80, ... }
}'
# Approve a strategy for live trading (human gate)
curl -X PUT http://localhost:3000/api/v1/registry/strategies/{id}/versions/{ver}/status \
-d '{ "status": "approved", "changed_by": "j.peetz69@gmail.com" }'
# Returns 400 if changed_by is empty — the human gate is enforced server-side.
# Export a strategy for sharing / backup
curl http://localhost:3000/api/v1/registry/strategies/{id}/export/{version} > strategy-v1.0.0.json
# View strategy lineage
curl http://localhost:3000/api/v1/registry/strategies/{id}/lineage# Query decisions by strategy + outcome
curl "http://localhost:3000/api/v1/journal/decisions?strategy_id={id}&outcome=win&limit=20"
# Query a specific symbol's history
curl "http://localhost:3000/api/v1/journal/decisions?symbol=BTCUSDT&from=2024-01-01T00:00:00Z"
# Record an outcome after a position closes
curl -X POST http://localhost:3000/api/v1/journal/decisions/{decision_id}/outcome \
-d '{
"closed_at": "2024-03-15T14:30:00Z",
"close_price": 72400.0,
"realized_pnl": 48.50,
"return_pct": 0.048,
"class": "win",
"exit_reason": "take_profit"
}'
# Add a human review note
curl -X POST http://localhost:3000/api/v1/journal/decisions/{id}/review \
-d '{ "note": "Good entry — RSI was oversold and OI was rising. Keep this pattern.", "reviewer": "joerg" }'
# Get compacted summary (for large history)
curl http://localhost:3000/api/v1/journal/summaries/{strategy_id}/{version}# Submit an optimization job
curl -X POST http://localhost:3000/api/v1/optimizer/jobs \
-d '{
"strategy_id": "{id}",
"strategy_version": "1.0.0",
"created_by": "j.peetz69@gmail.com",
"train_from": "2023-01-01T00:00:00Z",
"train_to": "2024-01-01T00:00:00Z",
"val_from": "2024-01-01T00:00:00Z",
"val_to": "2024-06-01T00:00:00Z",
"max_candidates": 20
}'
# Returns: { "job_id": "uuid", "status": "pending" }
# Run the job (async)
curl -X POST http://localhost:3000/api/v1/optimizer/jobs/{job_id}/run
# Returns: { "status": "running" }
# Check results
curl http://localhost:3000/api/v1/optimizer/jobs/{job_id}
# Returns full job with all candidates, scores, and promotion decisions
# List all jobs for a strategy
curl "http://localhost:3000/api/v1/optimizer/jobs?strategy_id={id}"Six test suites verify the core invariants:
go test ./... -v✅ engine/pipeline TestModeParityBacktestVsPaper
Same strategy + same events → identical fills in backtest and paper.
Proves the unified pipeline works.
✅ engine/pipeline TestAllFillsPassThroughPipeline
Every order carries StrategyID + Mode, proving no bypass exists.
✅ engine/adapters TestAdapterInterfaceContract
Compile-time: both SimulatedAdapter and LiveAdapter satisfy
ExecutionAdapter. Swapping modes requires zero business logic changes.
✅ engine/adapters TestRiskCheckerEnforcementRules
All 6 risk rules tested: max positions, min size, leverage caps,
margin usage, position value ratio, clean order passthrough.
✅ registry TestStrategyVersionImmutability
NewVersion() preserves original. Creates new row. Never overwrites.
✅ registry TestStatusTransitions
Human gate enforced. Invalid transitions rejected. Semver correct.
✅ journal TestDecisionPersistsAcrossRestart
Decisions survive db close/reopen. Memory is durable.
✅ journal TestDecisionQueryFilters
Query by strategy, symbol, date range, outcome class all verified.
✅ journal TestCompaction
Old entries summarised and archived. Recent entries unaffected.
✅ optimizer TestPromotionRequiresAllThresholds
5 failure modes tested individually. Only perfect candidate promoted.
✅ optimizer TestOptimizerNeverMutatesLiveStrategy
Promoted version is StatusPaper. Original approved version untouched.
✅ optimizer TestOptimizerJobLifecycle
Full submit → run → done lifecycle verified with mock runner.
NOFX has 10,000+ stars for good reason. The AI prompt machinery, exchange adapters, market data assembly, and UI are all excellent. EvolvX wraps the existing decision.StrategyEngine behind the StrategyEvaluator interface — the AI call and prompt builder are unchanged. Only the lifecycle around them is new.
NOFX already uses SQLite. Same deployment story — single binary, no external database. The new databases (registry.db, journal.db, optimizer.db) are separate files so they can be backed up independently and never corrupt the existing nofx.db.
Semantic versioning gives you a clear signal: a patch bump (1.0.0 → 1.0.1) is a status change or performance update. A minor bump (1.0.0 → 1.1.0) is a parameter change. A major bump (1.0.0 → 2.0.0) is a structural change. This convention makes GetLatest() unambiguous and lineage graphs readable.
The optimizer promotes candidates to StatusPaper automatically. Transitioning to StatusApproved (live) requires a non-empty changed_by field. This is not just a config flag — it's enforced server-side in the registry. No amount of automation can skip the human sign-off.
SimulatedAdapter is used for both backtest and paper modes. The only thing that differs is the Mode field on the fills. This means a strategy that shows drawdown in backtest will show the same drawdown in paper — because it's the same code. No more "it worked in backtest but not in paper" surprises.
EvolvX/
├── engine/
│ ├── core/
│ │ └── types.go ← shared vocabulary (events, orders, fills)
│ ├── adapters/
│ │ ├── interface.go ← ExecutionAdapter, MarketFeed, EventLogger
│ │ ├── simulated.go ← deterministic fill model (backtest + paper)
│ │ └── live.go ← thin wrapper over existing exchange clients
│ ├── pipeline/
│ │ ├── pipeline.go ← unified processing loop
│ │ ├── evaluator.go ← AI call wrapper + journal injection
│ │ ├── risk.go ← ported risk enforcement rules
│ │ ├── metrics.go ← running Sharpe, Sortino, drawdown
│ │ └── logger.go ← append-only SQLite event log
│ └── feeds/
│ └── feeds.go ← SQLiteHistoricalFeed, ChannelFeed, SliceReplayFeed
│
├── registry/
│ ├── types.go ← StrategyRecord, Parameters, PerformanceSummary
│ ├── service.go ← CRUD, versioning, immutability, human gate
│ └── migrate.go ← one-time import from existing auto_traders table
│
├── journal/
│ ├── types.go ← DecisionEntry, Outcome, StrategySummary
│ └── service.go ← Record, RecordOutcome, Query, Compact
│
├── optimizer/
│ ├── types.go ← Candidate, EvalResult, PromotionThresholds
│ ├── generator.go ← systematic parameter mutation grid
│ ├── evaluator.go ← walk-forward scoring + promoter
│ └── service.go ← job orchestration, parallel workers
│
├── trader/
│ └── auto_trader_pipeline.go ← PipelineRunner shim (minimal change to existing)
│
├── api/
│ ├── registry_handlers.go ← HTTP handlers for registry, journal, optimizer
│ └── services.go ← service construction + migration entry point
│
├── cmd/
│ └── migrate/
│ └── main.go ← one-time CLI migration tool
│
├── outcome/
│ ├── types.go ← OpenPosition, CloseEvent, ComputeOutcome
│ └── recorder.go ← automatic fill→journal outcome recording
│
├── regime/
│ └── detector.go ← bull/bear/sideways/volatile classifier + time windows
│
├── ensemble/
│ └── voter.go ← weighted signal voting across strategy versions
│
├── observability/
│ ├── metrics.go ← 25 Prometheus metrics across all subsystems
│ ├── server.go ← /metrics + /health + /info HTTP server (port 9090)
│ └── instrument.go ← typed helpers called by pipeline/registry/journal/etc
│
├── notifications/
│ └── service.go ← Slack + Telegram webhook alerts with rate limiting
│
├── dashboards/
│ ├── evolvx_overview.json ← Grafana dashboard (import directly)
│ └── README.md ← setup guide: Prometheus scraping, Grafana provisioning
│
├── multitrader/
│ └── hub.go ← SharedJournalHub — routes N traders into one journal
│
├── memory/
│ └── symbol_store.go ← cross-strategy symbol memory with prompt injection
│
├── attribution/
│ └── engine.go ← PnL attribution by strategy/symbol/regime
│
├── compaction/
│ ├── worker.go ← auto-compaction scheduler
│ └── export_test.go ← test exports
│
├── web/src/ ← UI additions (drop into existing NOFX web/)
│ ├── lib/
│ │ └── evolvx-api.ts ← typed API client for all EvolvX endpoints
│ ├── components/evolvx/
│ │ ├── ui.tsx ← shared primitives: badges, cards, buttons, modals
│ │ ├── LineageGraph.tsx ← SVG strategy evolution tree
│ │ ├── OutcomeHeatmap.tsx ← GitHub-style outcome calendar heatmap
│ │ └── StrategyDiff.tsx ← side-by-side parameter diff modal
│ ├── pages/
│ │ ├── Registry.tsx ← version history + lineage + approve/deprecate
│ │ ├── Journal.tsx ← heatmap + timeline + decision table + detail modal
│ │ ├── Optimizer.tsx ← job runner + candidate comparison + score chart
│ │ ├── Intelligence.tsx ← regime map + multi-symbol + ensemble (v1.2)
│ │ ├── AuditLog.tsx ← full event stream, session inspector (v1.3)
│ │ └── Attribution.tsx ← cross-strategy PnL, symbol memory, regime (v2.0)
│ └── router-additions.tsx ← route + nav integration guide (6 routes total)
│
├── [existing NOFX packages] ← UNCHANGED
│ ├── trader/
│ ├── decision/
│ ├── market/
│ ├── mcp/
│ ├── store/
│ ├── backtest/
│ └── web/
│
└── docs/
├── ARCHITECTURE.md
├── MIGRATION.md
└── API.md
| Capability | NOFX | v1.0 | v1.1 | v1.2 | v1.3 | v2.0 |
|---|---|---|---|---|---|---|
| AI trading (multi-model) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Multi-exchange support | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Strategy Studio UI | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| AI Debate Arena | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Real-time dashboard | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Paper trading | ❌ | ✅ new | ✅ | ✅ | ✅ | ✅ |
| Unified execution layer | ❌ | ✅ new | ✅ | ✅ | ✅ | ✅ |
| Strategy versioning + immutability | ❌ | ✅ new | ✅ | ✅ | ✅ | ✅ |
| Decision memory + journal | ❌ | ✅ new | ✅ | ✅ | ✅ | ✅ |
| Human approval gate | ❌ | ✅ new | ✅ | ✅ | ✅ | ✅ |
| Walk-forward optimization | ❌ | ✅ new | ✅ | ✅ | ✅ | ✅ |
| Overfitting protection | ❌ | ✅ new | ✅ | ✅ | ✅ | ✅ |
| Strategy lineage graph | ❌ | API only | ✅ UI | ✅ | ✅ | ✅ |
| Registry UI (history, diff, export) | ❌ | ❌ | ✅ new | ✅ | ✅ | ✅ |
| Journal dashboard (heatmap, timeline) | ❌ | ❌ | ✅ new | ✅ | ✅ | ✅ |
| Optimizer job UI + candidate table | ❌ | ❌ | ✅ new | ✅ | ✅ | ✅ |
| Strategy diff viewer | ❌ | ❌ | ✅ new | ✅ | ✅ | ✅ |
| Automatic outcome recording | ❌ | ❌ | ❌ | ✅ new | ✅ | ✅ |
| Multi-symbol walk-forward | ❌ | ❌ | ❌ | ✅ new | ✅ | ✅ |
| Regime detection (bull/bear/sideways/volatile) | ❌ | ❌ | ❌ | ✅ new | ✅ | ✅ |
| Ensemble voting across versions | ❌ | ❌ | ❌ | ✅ new | ✅ | ✅ |
| Intelligence dashboard (UI) | ❌ | ❌ | ❌ | ✅ new | ✅ | ✅ |
| Prometheus metrics (25 metrics) | ❌ | ❌ | ❌ | ❌ | ✅ new | ✅ |
| Grafana dashboard templates | ❌ | ❌ | ❌ | ❌ | ✅ new | ✅ |
| Slack / Telegram alerts | ❌ | ❌ | ❌ | ❌ | ✅ new | ✅ |
| Audit log viewer (UI) | ❌ | ❌ | ❌ | ❌ | ✅ new | ✅ |
| Shared journal hub (multi-trader) | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ new |
| Cross-strategy attribution | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ new |
| Symbol memory consolidation | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ new |
| Auto-compaction with policy | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ new |
v1.0 ─── Foundation (released)
✅ Unified pipeline (backtest + paper + live share one code path)
✅ Strategy registry with semver versioning and immutability enforcement
✅ Decision journal with durable per-decision memory and outcome tracking
✅ Walk-forward optimizer with overfitting protection and human approval gate
✅ One-time migration tool from existing NOFX databases
✅ 12 test suites verifying all core invariants
v1.1 ─── UI Integration (released)
✅ Registry panel — version history timeline, approve/deprecate actions, export
✅ Lineage graph — interactive SVG tree showing parent→child strategy evolution
✅ Journal dashboard — outcome heatmap, win/loss bars, cumulative equity curve
✅ Decision table — filterable by strategy/symbol/outcome, full detail modal
✅ Optimizer UI — job submission, candidate score chart, comparison table
✅ Strategy diff viewer — side-by-side parameter comparison with delta highlighting
v1.2 ─── Advanced Learning (released)
✅ Automatic outcome recording — fills matched to journal decisions in real-time
✅ Multi-symbol walk-forward — evaluate candidates across all configured symbols
✅ Regime-aware backtesting — bull/bear/sideways/volatile detection and per-regime scoring
✅ Ensemble strategy support — weighted voting across approved versions with quorum gate
✅ Intelligence dashboard — regime map, multi-symbol view, ensemble status UI
v1.3 ─── Observability (released)
✅ Prometheus metrics — 25 metrics across pipeline, registry, journal, optimizer, regime, ensemble
✅ Grafana dashboard — overview dashboard with strategy/mode/symbol variables + alerting rules
✅ Slack / Telegram alerts — promotion, approval, deprecation, job completion, large win/loss
✅ Audit log viewer — full pipeline event stream, session inspector, kind/mode/date filters
v2.0 ─── Multi-Trader Memory (released)
✅ Shared journal hub — all traders write to one journal, event broadcasting to subscribers
✅ Cross-strategy attribution — PnL/WR breakdown by strategy version, symbol, and regime
✅ Symbol memory consolidation — cross-strategy knowledge per symbol with prompt injection
✅ Auto-compaction worker — scheduled retention policy enforcement per strategy status
EvolvX would not exist without NOFX.
The entire AI trading machinery — multi-model AI clients, exchange adapters for Binance/Bybit/OKX/Hyperliquid/Aster/Lighter, the strategy prompt builder, the indicator pipeline, the Debate Arena, the AI500 integration, the React dashboard — is the work of the NoFxAiOS team and the NOFX community.
Original Repository: https://github.com/NoFxAiOS/nofx
Original Stars: 10,000+
Original Forks: 2,700+
Original License: AGPL-3.0
EvolvX contributes: Unified pipeline, strategy registry, decision journal,
optimization loop, and all associated tests.
EvolvX modifies: Nothing in the original packages.
EvolvX license: AGPL-3.0 (same as original, as required)
If you find EvolvX useful, please star the original NOFX repository at github.com/NoFxAiOS/nofx. Every star helps the original authors continue their work.
Joerg Peetz
Senior Technical Support Engineer, Trend AI (formerly Trend Micro)
Based in Ireland
GitHub: https://github.com/JPeetz
X/Twitter: https://x.com/joerg_peetz
LinkedIn: https://linkedin.com/in/joerg-peetz
Medium: https://medium.com/@jpeetz
Email: j.peetz69@gmail.com
Also the author of NeuralLog — AI-powered log analysis for technical support operations, and various projects in the OpenClaw/AutoNovelClaw ecosystem.
EvolvX follows NOFX's contribution model. All contributions are tracked and rewarded.
# Fork, branch, change, test, PR
git checkout -b feature/my-improvement
go test ./... # all tests must pass
git push origin feature/my-improvement
# Open PR against mainGood first issues: Look for the good-first-issue label. All planned versions through v2.0 are shipped. Good starting points for new contributors: the two missing API handlers (/api/v1/attribution/report and /api/v1/memory/symbols), the prometheus/client_golang dependency declaration in go.mod, and Grafana alerting rule templates for drawdown and stalled-fills scenarios.
Architecture questions: Open a Discussion rather than an Issue.
Bug reports: Include the strategy version, the mode (backtest/paper/live), and the relevant section of the event log.
EvolvX is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0), the same license as NOFX. See LICENSE for the full text.
EvolvX: because "did the AI get better or did I get lucky?" deserves an answer.