Add paper trading mode with Finnhub data fallback#1
Open
smshapiro85 wants to merge 21 commits into
Open
Conversation
Implement test account / paper trading mode for experiments that don't require Schwab connectivity. Experiments can now run on real market data from Finnhub API as a fallback. Changes: - Add finnhubQuotes.ts for real-time stock quotes from Finnhub API - Create unified marketDataService.ts with fallback chain: Schwab → Finnhub → Mock - Add paper_trading and data_source columns to experiments table - Update seed.ts to ensure experiments table exists - Strategy executor now uses unified market data service - Status API reports available data sources API accepts paperTrading, dataSource, and startBalance params when generating experiments. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Set up comprehensive testing infrastructure: API Tests (Vitest): - Configure Vitest with test utilities and mock factories - Add market data service tests (14 tests) covering fallback chain - Add experiments API tests (11 tests) for paper trading flows - Create test helpers for mocking database and Finnhub API E2E Tests (Playwright): - Configure Playwright with auto-start for frontend/backend - Add experiment flow tests (generate, display, navigation) - Add dashboard and strategies page tests Test commands: npm run test, npm run test:e2e Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use .first() to handle pages with multiple "Generate Experiments" buttons. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move all /experiments routes before /:id routes to prevent 'experiments' from being matched as a strategy ID parameter. Express matches routes in order, so the wildcard /:id on line 108 was intercepting requests to /experiments before they could reach the actual experiment endpoints on line 308. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
UI fixes: - Remove .slice(0, 5) limit to show ALL today's experiments - Add delete button to individual experiments in historical list - Add "Clear Date" button to delete all experiments for selected date - Show experiment count in "Today's Experiments" header Backend changes: - Add deleteExperiment and deleteExperimentsByDate to strategyLibrary - Add DELETE /experiments/:id endpoint for single experiment - Add DELETE /experiments?date=YYYY-MM-DD endpoint for bulk delete Frontend API: - Add experimentsApi.delete() method - Add experimentsApi.deleteByDate() method Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New architecture ensures experiments use IDENTICAL execution logic as live trading: Shared Components: - tradeExecutionContext.ts: Abstraction layer for position/trade tracking - Can route to live positions table or experiment-specific tracking - Provides consistent interface for balance, positions, and trade recording - signalProcessor.ts: Shared signal execution logic - processBuySignal(): Same VIX adjustment, position sizing, risk checks - processSellSignal(): Same P&L calculation, position closing - closePositionAtMarket(): Same EOD close logic - updatePositionsAndCheckStopLoss(): Same stop-loss monitoring Experiment Runner: - Uses executeStrategy() from strategyExecutor (same YAML parsing) - Uses signalProcessor for trade execution (same execution logic) - Only differences are: - Virtual balance per experiment (paper trading) - Trades stored in experiment_trades table - Positions tracked per-experiment Scheduler Integration: - 9:35 AM ET: Start PENDING experiments -> RUNNING - Every 30 sec (market hours): Run experiment analysis cycles - 3:45 PM ET: Complete experiments -> COMPLETED with P&L - Startup recovery: Loads running experiments if app was restarted Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Addresses all 3 error-level issues from Codex review: 1. Quote source mismatch (issue-3): - Changed from marketDataService.getQuote to mockBroker.getQuote - Now uses SAME quote source as live trading engine 2. Double VIX adjustment / position sizing (issue-1): - Removed signal.quantity-based sizing - Now uses tradingSettings.maxPositionSize * portfolioValue (SAME as live) - VIX adjustment applied ONCE via getVIXAdjustedPositionSize() 3. Stop-loss logic mismatch (issue-2): - Removed fixed percent stopLossPct parameter - Now uses calculateStopLossPrice() from riskManager (SAME as live) - Config-driven stop-loss from trading settings Also addresses warning-level issues: - Added concurrency guard (cycleInProgress flag) to prevent overlapping cycles - Fixed position resume logic to properly net buy/sell quantities per symbol - Removed unused dataSource field from TradeExecutionContext The only differences between experiments and live trading are now: - Virtual balance tracking per experiment - Trades stored in experiment_trades table (not trades table) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
New endpoints: - POST /api/strategies/experiments/start-all Manually triggers startTodaysExperiments() to start all PENDING experiments for today. Useful for testing on weekends/off-hours. - POST /api/strategies/experiments/run-cycle Manually runs one experiment analysis cycle. Useful for testing signal processing and trade execution. - GET /api/strategies/experiments/running-status Returns the count and IDs of currently running experiments. All endpoints are placed before /:id routes to avoid route matching issues. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create e2eTestUtils.ts with 10 test scenarios per experiment: 1. Winning Trade - verify profit calculation 2. Losing Trade (Stop Loss) - verify stop loss execution 3. Max Daily Trades - verify trade limit enforcement 4. Max Daily Loss - verify loss limit enforcement 5. Position Sizing - verify position size limits 6. Schedule End - verify time-based termination 7. Manual Disable - verify manual stop functionality 8. Negative News Threshold - placeholder for sentiment-based pausing 9. Global Risk Limit - verify global loss limit 10. Experiment Completion - verify proper status transitions - Add test API endpoints: - POST /experiments/test/force-trade - force a trade for testing - POST /experiments/test/simulate-cycle - simulate complete trade cycle - POST /experiments/test/run-e2e-suite - run full test suite - GET /experiments/test/termination-paths - list all termination paths - POST /experiments/test/cleanup - identify test trades for cleanup - Add gap analysis for test coverage of termination paths - Add comprehensive documentation in docs/E2E-TESTING.md Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Shorten test symbols to fit VARCHAR(10) constraint: TEST_WIN → T_WIN, TEST_LOSS → T_LOSS, etc. - Make max_daily_trades test idempotent with unique run IDs - Update cleanup function to match new symbol prefixes Test results: 220/220 scenarios passing (100%) - 22 experiments tested - 10 scenarios per experiment - 66.7% termination path coverage (10/15 paths) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Audit confirms E2E tests work as designed: - Playwright tests call real services (OpenRouter, Finnhub) when configured - Backend test utilities use synthetic data for offline/weekend testing - Market data fallback to mocks is intentional for after-hours testing No code changes needed - architecture is sound. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Ran full E2E test suite confirming all tests pass: - Experiments page display and generation - Paper trading mode status - Dashboard navigation - Strategies page display Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add dist/, playwright-report/, and test-results/ to .gitignore. These are build/test artifacts that should not be version controlled. All E2E tests verified passing (7/7). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The route resolution issue was already fixed. Removed TODOs and it.skip() wrappers - all 27 backend tests now pass. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The ActivityLog page was hardcoded to port 3001 but the backend runs on port 3005, causing "Error loading activity log" message. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use relative '/api' path to go through Vite's proxy configuration, avoiding CORS issues with direct cross-origin requests. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Historical experiments should NEVER be in RUNNING state. This adds multiple layers of protection: 1. updateExperimentStatus() - Blocks attempts to set past-day experiments to RUNNING status 2. getExperiments() - Auto-completes orphaned RUNNING experiments when querying by past date 3. getExperimentsByDate() - Same auto-completion for date queries 4. getExperimentById() - Auto-completes if fetching an orphaned RUNNING experiment from a past day Combined with the startup auto-complete from the previous commit, this ensures orphaned experiments are cleaned up at multiple points: - On application startup - When querying experiments for display - When attempting status updates Note: An ARCHIVED status was considered but deemed unnecessary - the existing COMPLETED status adequately represents finished experiments regardless of age. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Changes
finnhubQuotes.ts- Real-time stock quotes from Finnhub API with cachingmarketDataService.ts- Unified market data interface with fallback chainpaper_tradinganddata_sourcecolumns to experimentsHow Paper Trading Works
paperTrading: trueanddataSource: 'finnhub'Test plan
npm run db:seedto ensure experiments table is createdFINNHUB_API_KEYin.envand verify quotes are fetched/api/statusshows data source availabilitystartBalanceanddataSourceparams🤖 Generated with Claude Code