diff --git a/README.md b/README.md
index 1d48e1d..a6cdb44 100644
--- a/README.md
+++ b/README.md
@@ -94,8 +94,11 @@ python -m quant_research_starter.cli compute-factors -d data_sample/sample_price
# run a backtest
python -m quant_research_starter.cli backtest -d data_sample/sample_prices.csv -s output/factors.csv -o output/backtest_results.json
-# optional: start the Streamlit dashboard
+# DISCLAIMER: OLD VERSION
+# optional: start the Streamlit dashboard, if on main stream
streamlit run src/quant_research_starter/dashboard/streamlit_app.py
+# NEW VERSION: if streamlit is in legacy folder
+streamlit run legacy/streamlit/streamlit_app.py
```
---
diff --git a/src/quant_research_starter/frontend/cauweb/package.json b/src/quant_research_starter/frontend/cauweb/package.json
new file mode 100644
index 0000000..9f5cbe5
--- /dev/null
+++ b/src/quant_research_starter/frontend/cauweb/package.json
@@ -0,0 +1,32 @@
+{
+ "name": "@qrs/cauweb",
+ "version": "1.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview",
+ "lint": "eslint src --ext .ts,.tsx"
+ },
+ "dependencies": {
+ "@tailwindcss/vite": "^4.1.17",
+ "chart.js": "^4.5.1",
+ "lucide-react": "^0.263.1",
+ "react": "^18.2.0",
+ "react-chartjs-2": "^5.3.1",
+ "react-dom": "^18.2.0",
+ "react-router-dom": "^6.8.0"
+ },
+ "devDependencies": {
+ "@tailwindcss/cli": "^4.1.17",
+ "@tailwindcss/postcss": "^4.1.17",
+ "@types/react": "^18.3.26",
+ "@types/react-dom": "^18.3.7",
+ "@vitejs/plugin-react": "^4.1.0",
+ "autoprefixer": "^10.4.21",
+ "postcss": "^8.5.6",
+ "tailwindcss": "^4.1.17",
+ "typescript": "^5.9.3",
+ "vite": "^5.0.0"
+ }
+}
diff --git a/src/quant_research_starter/frontend/cauweb/src/pages/BacktestStudio.tsx b/src/quant_research_starter/frontend/cauweb/src/pages/BacktestStudio.tsx
new file mode 100644
index 0000000..a72e675
--- /dev/null
+++ b/src/quant_research_starter/frontend/cauweb/src/pages/BacktestStudio.tsx
@@ -0,0 +1,457 @@
+import React, { useState } from 'react';
+import { Play, TrendingUp, TrendingDown, Target, DollarSign, Calendar, BarChart3, Activity } from 'lucide-react';
+import { PerformanceChart } from '../components/PerformanceChart';
+
+interface BacktestMetrics {
+ totalReturn: number;
+ annualizedReturn: number;
+ volatility: number;
+ sharpeRatio: number;
+ maxDrawdown: number;
+ winRate: number;
+ turnover: number;
+ profitFactor: number;
+ sortinoRatio: number;
+ calmarRatio: number;
+}
+
+interface Trade {
+ symbol: string;
+ quantity: number;
+ price: number;
+ timestamp: string;
+ side: 'BUY' | 'SELL';
+ pnl: number;
+}
+
+export const BacktestStudio: React.FC = () => {
+ const [loading, setLoading] = useState(false);
+ const [backtestResults, setBacktestResults] = useState<{
+ metrics: BacktestMetrics;
+ trades: Trade[];
+ portfolioHistory: { date: string; value: number }[];
+ benchmarkHistory: { date: string; value: number }[];
+ } | null>(null);
+
+ const [config, setConfig] = useState({
+ initialCapital: 100000,
+ startDate: '2020-01-01',
+ endDate: '2023-12-31',
+ rebalanceFrequency: 'monthly',
+ strategy: 'momentum',
+ symbols: ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA', 'META', 'NFLX', 'NVDA']
+ });
+
+ const handleRunBacktest = async () => {
+ setLoading(true);
+
+ // Simulate API call with realistic delay
+ await new Promise(resolve => setTimeout(resolve, 2500));
+
+ // Generate mock data
+ const mockResults = {
+ metrics: {
+ totalReturn: 0.2345,
+ annualizedReturn: 0.0876,
+ volatility: 0.1567,
+ sharpeRatio: 1.234,
+ maxDrawdown: 0.1234,
+ winRate: 0.645,
+ turnover: 2.34,
+ profitFactor: 1.89,
+ sortinoRatio: 1.567,
+ calmarRatio: 0.707
+ },
+ trades: generateMockTrades(),
+ portfolioHistory: generatePortfolioHistory(),
+ benchmarkHistory: generateBenchmarkHistory()
+ };
+
+ setBacktestResults(mockResults);
+ setLoading(false);
+ };
+
+ const getMetrics = () => {
+ if (!backtestResults?.metrics) return [];
+
+ const metrics = backtestResults.metrics;
+ return [
+ {
+ key: 'Total Return',
+ value: `${(metrics.totalReturn * 100).toFixed(2)}%`,
+ change: `${(metrics.annualizedReturn * 100).toFixed(2)}% annualized`,
+ icon: TrendingUp,
+ trend: metrics.totalReturn > 0 ? 'positive' : 'negative',
+ description: 'Overall strategy performance'
+ },
+ {
+ key: 'Sharpe Ratio',
+ value: metrics.sharpeRatio.toFixed(3),
+ change: 'Risk-adjusted returns',
+ icon: Activity,
+ trend: metrics.sharpeRatio > 1 ? 'positive' : 'negative',
+ description: 'Higher is better'
+ },
+ {
+ key: 'Max Drawdown',
+ value: `${(metrics.maxDrawdown * 100).toFixed(2)}%`,
+ change: 'Worst peak-to-trough decline',
+ icon: TrendingDown,
+ trend: metrics.maxDrawdown < 0.1 ? 'positive' : 'negative',
+ description: 'Lower is better'
+ },
+ {
+ key: 'Win Rate',
+ value: `${(metrics.winRate * 100).toFixed(2)}%`,
+ change: 'Successful trade percentage',
+ icon: Target,
+ trend: metrics.winRate > 0.5 ? 'positive' : 'negative',
+ description: 'Trade success frequency'
+ },
+ {
+ key: 'Volatility',
+ value: `${(metrics.volatility * 100).toFixed(2)}%`,
+ change: 'Portfolio risk measure',
+ icon: BarChart3,
+ trend: metrics.volatility < 0.15 ? 'positive' : 'negative',
+ description: 'Annualized standard deviation'
+ },
+ {
+ key: 'Profit Factor',
+ value: metrics.profitFactor.toFixed(2),
+ change: 'Gross profit vs gross loss',
+ icon: DollarSign,
+ trend: metrics.profitFactor > 1.5 ? 'positive' : 'negative',
+ description: 'Higher is better'
+ }
+ ];
+ };
+
+ const getRecentTrades = () => {
+ if (!backtestResults?.trades) return [];
+ return backtestResults.trades.slice(0, 5); // Last 5 trades
+ };
+
+ return (
+
+
+
Backtest Studio
+
Test and optimize your trading strategies with advanced analytics
+
+
+
+ {/* Configuration Panel */}
+
+
+
+
+ Strategy Configuration
+
+
Configure your backtest parameters
+
+
+
+
+
+ setConfig({...config, initialCapital: Number(e.target.value)})}
+ className="form-input"
+ min="1000"
+ step="1000"
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ setConfig({...config, symbols: e.target.value.split(',').map(s => s.trim())})}
+ className="form-input"
+ placeholder="AAPL, MSFT, GOOGL, AMZN"
+ />
+
+
+
+
+
+
+ {/* Results Panel */}
+
+
+
Backtest Results
+
+ {backtestResults ? 'Strategy performance analysis' : 'Configure and run backtest to see results'}
+
+
+
+ {loading ? (
+
+
+
Running Backtest Analysis
+
Simulating trades and calculating performance metrics...
+
+
+
+
+
+
+ ) : backtestResults ? (
+
+ {/* Key Metrics */}
+
+
Performance Metrics
+
+ {getMetrics().map((metric) => {
+ const Icon = metric.icon;
+ return (
+
+
+
+
+
+
+ {metric.change}
+
+
+
+
{metric.key}
+
{metric.value}
+
{metric.description}
+
+
+ );
+ })}
+
+
+
+ {/* Performance Chart */}
+
+
Portfolio Performance
+
+
+
+ {/* Additional Metrics & Trades */}
+
+
+
Recent Trades
+
+ {getRecentTrades().map((trade, index) => (
+
+
{trade.symbol}
+
+ {trade.side}
+
+
{trade.quantity} shares
+
${trade.price.toFixed(2)}
+
= 0 ? 'positive' : 'negative'}`}>
+ {trade.pnl >= 0 ? '+' : ''}${trade.pnl.toFixed(2)}
+
+
+ ))}
+
+
+
+
+
Strategy Statistics
+
+
+ Total Trades
+ {backtestResults.trades.length}
+
+
+ Win Rate
+
+ {(backtestResults.metrics.winRate * 100).toFixed(1)}%
+
+
+
+ Avg. Trade Duration
+ 5.2 days
+
+
+ Largest Gain
+ +12.4%
+
+
+ Largest Loss
+ -8.7%
+
+
+ Profit Factor
+
+ {backtestResults.metrics.profitFactor.toFixed(2)}
+
+
+
+
+
+
+ ) : (
+
+
+
No Backtest Results
+
Configure your strategy parameters and run a backtest to see performance analytics
+
+ )}
+
+
+
+ );
+};
+
+// Mock data generators
+function generateMockTrades(): Trade[] {
+ const trades: Trade[] = [];
+ const symbols = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA', 'META'];
+
+ for (let i = 0; i < 25; i++) {
+ trades.push({
+ symbol: symbols[Math.floor(Math.random() * symbols.length)],
+ quantity: Math.floor(Math.random() * 100) + 10,
+ price: Math.random() * 500 + 50,
+ timestamp: `2023-${String(Math.floor(Math.random() * 12) + 1).padStart(2, '0')}-${String(Math.floor(Math.random() * 28) + 1).padStart(2, '0')}`,
+ side: Math.random() > 0.5 ? 'BUY' : 'SELL',
+ pnl: (Math.random() - 0.3) * 2000
+ });
+ }
+
+ return trades;
+}
+
+// Replace the existing generatePortfolioHistory and generateBenchmarkHistory functions:
+
+function generatePortfolioHistory() {
+ const history = [];
+ let value = 100000;
+ const startDate = new Date('2020-01-01');
+
+ // Create more realistic market data with trends and volatility
+ let trend = 0.002; // Slight upward trend
+ let volatility = 0.08;
+
+ for (let i = 0; i < 48; i++) { // 4 years of monthly data
+ const date = new Date(startDate);
+ date.setMonth(date.getMonth() + i);
+
+ // Realistic market simulation with momentum
+ const randomChange = (Math.random() - 0.5) * volatility;
+ const monthlyReturn = trend + randomChange;
+
+ // Add some momentum effect
+ if (i > 0) {
+ const prevReturn = (history[i-1].value / (i > 1 ? history[i-2].value : 100000)) - 1;
+ if (prevReturn > 0.02) {
+ trend = 0.003; // Positive momentum
+ } else if (prevReturn < -0.02) {
+ trend = 0.001; // Negative momentum
+ }
+ }
+
+ value *= (1 + monthlyReturn);
+
+ // Ensure minimum value
+ value = Math.max(value, 80000);
+
+ history.push({
+ date: date.toISOString().split('T')[0],
+ value: Math.round(value)
+ });
+ }
+
+ return history;
+}
+
+function generateBenchmarkHistory() {
+ const history = [];
+ let value = 100000;
+ const startDate = new Date('2020-01-01');
+
+ // Benchmark (SPY-like) with less volatility
+ let trend = 0.0015;
+ let volatility = 0.05;
+
+ for (let i = 0; i < 48; i++) {
+ const date = new Date(startDate);
+ date.setMonth(date.getMonth() + i);
+
+ const randomChange = (Math.random() - 0.5) * volatility;
+ const monthlyReturn = trend + randomChange;
+
+ value *= (1 + monthlyReturn);
+ value = Math.max(value, 85000);
+
+ history.push({
+ date: date.toISOString().split('T')[0],
+ value: Math.round(value)
+ });
+ }
+
+ return history;
+}
\ No newline at end of file
diff --git a/src/quant_research_starter/frontend/cauweb/src/pages/Dashboard.js b/src/quant_research_starter/frontend/cauweb/src/pages/Dashboard.js
new file mode 100644
index 0000000..f2feb89
--- /dev/null
+++ b/src/quant_research_starter/frontend/cauweb/src/pages/Dashboard.js
@@ -0,0 +1,20 @@
+import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
+import { TrendingUp, TrendingDown, Target } from 'lucide-react';
+export const Dashboard = () => {
+ const metrics = [
+ { title: 'Total Return', value: '+23.45%', change: '+2.1%', icon: TrendingUp, trend: 'up' },
+ { title: 'Sharpe Ratio', value: '1.234', change: '+0.12', icon: TrendingUp, trend: 'up' },
+ { title: 'Max Drawdown', value: '-12.34%', change: '-1.2%', icon: TrendingDown, trend: 'down' },
+ { title: 'Win Rate', value: '64.50%', change: '+3.2%', icon: Target, trend: 'up' }
+ ];
+ return (_jsxs("div", { className: "p-8", children: [_jsxs("div", { className: "mb-8", children: [_jsx("h1", { className: "text-3xl font-bold text-gray-900", children: "Dashboard" }), _jsx("p", { className: "text-gray-600 mt-2", children: "Welcome to your quantitative research workspace" })] }), _jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8", children: metrics.map((metric, index) => {
+ const Icon = metric.icon;
+ return (_jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-200 p-6", children: [_jsxs("div", { className: "flex items-center justify-between mb-4", children: [_jsx("div", { className: "p-2 bg-blue-50 rounded-lg", children: _jsx(Icon, { className: `w-6 h-6 ${metric.trend === 'up' ? 'text-green-600' : 'text-red-600'}` }) }), _jsx("span", { className: `text-sm font-medium ${metric.trend === 'up' ? 'text-green-600' : 'text-red-600'}`, children: metric.change })] }), _jsx("h3", { className: "text-gray-600 text-sm font-medium mb-1", children: metric.title }), _jsx("div", { className: `text-2xl font-bold ${metric.trend === 'up' ? 'text-green-600' : 'text-red-600'}`, children: metric.value })] }, index));
+ }) }), _jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-8", children: [_jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-200 p-6", children: [_jsx("h3", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Recent Backtests" }), _jsx("div", { className: "space-y-4", children: [
+ { name: 'Momentum Strategy', date: '2 hours ago', status: 'Completed' },
+ { name: 'Mean Reversion', date: '5 hours ago', status: 'Completed' },
+ { name: 'Sector Rotation', date: '1 day ago', status: 'Running' }
+ ].map((test, index) => (_jsxs("div", { className: "flex items-center justify-between p-3 bg-gray-50 rounded-lg", children: [_jsxs("div", { children: [_jsx("div", { className: "font-medium text-gray-900", children: test.name }), _jsx("div", { className: "text-sm text-gray-500", children: test.date })] }), _jsx("span", { className: `px-2 py-1 rounded-full text-xs font-medium ${test.status === 'Completed'
+ ? 'bg-green-100 text-green-800'
+ : 'bg-blue-100 text-blue-800'}`, children: test.status })] }, index))) })] }), _jsxs("div", { className: "bg-white rounded-xl shadow-sm border border-gray-200 p-6", children: [_jsx("h3", { className: "text-lg font-semibold text-gray-900 mb-4", children: "Quick Actions" }), _jsxs("div", { className: "space-y-3", children: [_jsxs("button", { className: "w-full text-left p-4 bg-blue-50 border border-blue-200 rounded-lg hover:bg-blue-100 transition-colors", children: [_jsx("div", { className: "font-medium text-blue-900", children: "Run New Backtest" }), _jsx("div", { className: "text-sm text-blue-700", children: "Test a new trading strategy" })] }), _jsxs("button", { className: "w-full text-left p-4 bg-green-50 border border-green-200 rounded-lg hover:bg-green-100 transition-colors", children: [_jsx("div", { className: "font-medium text-green-900", children: "Analyze Portfolio" }), _jsx("div", { className: "text-sm text-green-700", children: "Deep dive into performance metrics" })] }), _jsxs("button", { className: "w-full text-left p-4 bg-purple-50 border border-purple-200 rounded-lg hover:bg-purple-100 transition-colors", children: [_jsx("div", { className: "font-medium text-purple-900", children: "Research Factors" }), _jsx("div", { className: "text-sm text-purple-700", children: "Explore alpha factors" })] })] })] })] })] }));
+};
diff --git a/src/quant_research_starter/frontend/cauweb/src/pages/Dashboard.tsx b/src/quant_research_starter/frontend/cauweb/src/pages/Dashboard.tsx
new file mode 100644
index 0000000..91757a3
--- /dev/null
+++ b/src/quant_research_starter/frontend/cauweb/src/pages/Dashboard.tsx
@@ -0,0 +1,95 @@
+import React from 'react';
+import { TrendingUp, TrendingDown, DollarSign, Target } from 'lucide-react';
+
+export const Dashboard: React.FC = () => {
+ const metrics = [
+ { title: 'Total Return', value: '+23.45%', change: '+2.1%', icon: TrendingUp, trend: 'up' },
+ { title: 'Sharpe Ratio', value: '1.234', change: '+0.12', icon: TrendingUp, trend: 'up' },
+ { title: 'Max Drawdown', value: '-12.34%', change: '-1.2%', icon: TrendingDown, trend: 'down' },
+ { title: 'Win Rate', value: '64.50%', change: '+3.2%', icon: Target, trend: 'up' }
+ ];
+
+ return (
+
+
+
Dashboard
+
Welcome to your quantitative research workspace
+
+
+ {/* Metrics Grid */}
+
+ {metrics.map((metric, index) => {
+ const Icon = metric.icon;
+ return (
+
+
+
+
+
+
+ {metric.change}
+
+
+
{metric.title}
+
+ {metric.value}
+
+
+ );
+ })}
+
+
+ {/* Recent Activity */}
+
+
+
Recent Backtests
+
+ {[
+ { name: 'Momentum Strategy', date: '2 hours ago', status: 'Completed' },
+ { name: 'Mean Reversion', date: '5 hours ago', status: 'Completed' },
+ { name: 'Sector Rotation', date: '1 day ago', status: 'Running' }
+ ].map((test, index) => (
+
+
+
{test.name}
+
{test.date}
+
+
+ {test.status}
+
+
+ ))}
+
+
+
+
+
Quick Actions
+
+
+
+
+
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/src/quant_research_starter/frontend/readme.md b/src/quant_research_starter/frontend/readme.md
new file mode 100644
index 0000000..990ed99
--- /dev/null
+++ b/src/quant_research_starter/frontend/readme.md
@@ -0,0 +1,50 @@
+frontend/
+│
+├── core/ # Shared logic library
+│ ├── src/
+│ │ ├── components/ # Shared React components
+│ │ ├── hooks/ # Shared React hooks (fetch, state mgmt)
+│ │ ├── utils/ # Reusable helper functions
+│ │ ├── types/ # Shared TypeScript types
+│ │ └── index.ts # Export all shared modules
+│ ├── package.json
+│ ├── tsconfig.json
+│ └── README.md
+
+│
+├── cauweb/ # Main Web UI App
+│ ├── src/
+│ │ ├── pages/ # UI Screens (Home, Dashboard, About)
+│ │ ├── layouts/ # Shared layouts (Navbar, Sidebar)
+│ │ ├── features/ # Domain features (Logs, Trading UI)
+│ │ ├── assets/ # Images, icons, fonts
+│ │ ├── styles/ # Global CSS/Tailwind configs
+│ │ └── main.tsx # App entry point
+│ ├── public/
+│ ├── package.json
+│ ├── tsconfig.json
+│ └── README.md
+
+│
+├── cli/ # Terminal UI (Node/React Ink CLI)
+│ ├── src/
+│ │ └── index.ts
+│ ├── package.json
+│ └── tsconfig.json
+
+│
+├── metrics/ # Data visual charts + API metrics
+│ ├── src/
+│ │ ├── charts/
+│ │ ├── analytics/
+│ │ └── index.ts
+│ ├── package.json
+│ └── tsconfig.json
+
+│
+├── node_modules/ # Shared dependencies root install
+│
+├── package.json # root scripts + global deps
+├── pnpm-workspace.yaml # defines workspace packages
+├── tsconfig.base.json # shared TS config
+└── README.md