import { useState } from 'react'; import { useAppContext } from '../context/AppContext'; import { SignalsTab } from '../tabs/SignalsTab'; import { BacktestTab } from '../tabs/BacktestTab'; import { MyStrategiesTab } from '../tabs/MyStrategiesTab'; import { VisualRuleBuilder, type VisualRule } from '../components/strategy/VisualRuleBuilder'; import { CodeStrategyEditor } from '../components/strategy/CodeStrategyEditor'; import { createTradeProfile } from '../lib/profileApi'; type ResearchTab = 'Strategies' | 'Visual Builder' | 'Code Editor' | 'Signals' | 'Backtesting'; // Sub-tab pill styles function SubTab({ label, active, onClick, }: { label: string; active: boolean; onClick: () => void }) { return ( ); } export function ResearchView() { const { botState, connected, showBacktestTab, isAdmin, activeSymbol } = useAppContext(); const [tab, setTab] = useState('Strategies'); const tabs: ResearchTab[] = [ 'Strategies', 'Visual Builder', 'Code Editor', ...(isAdmin ? ['Signals' as ResearchTab] : []), ...(showBacktestTab ? ['Backtesting' as ResearchTab] : []), ]; // Save a visual-builder strategy via the canonical createTradeProfile helper. // Backend `saveTradeProfileForUser` expects the TradeProfilePayload shape: // { name, symbols, allocated_capital, risk_per_trade_percent, is_active, // strategy_config: { ... } } // Visual rules go inside strategy_config.rules so the strategy engine can // route to the visual interpreter (alongside the existing rule-based engine). const handleSaveVisualStrategy = async (name: string, rules: VisualRule[]) => { const fallbackSymbol = Object.keys(botState.symbols)[0] ?? 'SPY'; const symbol = activeSymbol || fallbackSymbol; const totalCapital = botState.settings?.totalCapital ?? 1000; const riskPct = botState.settings?.riskPerTrade ?? 1; await createTradeProfile({ name, symbols: symbol, allocated_capital: totalCapital, risk_per_trade_percent: riskPct, is_active: false, // user activates explicitly from MyStrategiesTab strategy_config: { type: 'visual', version: 1, rules: rules.map(r => ({ indicator: r.indicator, condition: r.condition, value: r.value, action: r.action, quantity: r.quantity, quantityType: r.quantityType, })), }, }); }; return (

Research

{tabs.map(t => ( setTab(t)} /> ))}
{tab === 'Strategies' && ( )} {tab === 'Visual Builder' && (
Visual Rule Builder
Build a trading strategy by composing IF/THEN rules. Drag rows to reorder. Click "Save Strategy" to store it.
)} {tab === 'Code Editor' && (
Code Strategy Editor
Write a custom strategy function in JavaScript. Click "Run Backtest" to test it against historical data.
)} {tab === 'Signals' && ( )} {tab === 'Backtesting' && ( )}
); }