initial charts / backtest
This commit is contained in:
parent
11c24b2280
commit
1b9010ebf4
37 changed files with 3888 additions and 23 deletions
1
apps/stock/web-app/src/features/backtest/hooks/index.ts
Normal file
1
apps/stock/web-app/src/features/backtest/hooks/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { useBacktest } from './useBacktest';
|
||||
169
apps/stock/web-app/src/features/backtest/hooks/useBacktest.ts
Normal file
169
apps/stock/web-app/src/features/backtest/hooks/useBacktest.ts
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { BacktestService } from '../services/backtestService';
|
||||
import type { BacktestConfig, BacktestResult, BacktestStatus } from '../types';
|
||||
|
||||
export function useBacktest() {
|
||||
const [backtestId, setBacktestId] = useState<string | null>(null);
|
||||
const [config, setConfig] = useState<BacktestConfig | null>(null);
|
||||
const [status, setStatus] = useState<BacktestStatus>('idle');
|
||||
const [results, setResults] = useState<BacktestResult | null>(null);
|
||||
const [currentTime, setCurrentTime] = useState<number | null>(null);
|
||||
const [progress, setProgress] = useState<number>(0);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const cleanupRef = useRef<(() => void) | null>(null);
|
||||
|
||||
const handleConfigSubmit = useCallback(async (newConfig: BacktestConfig) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
// Create backtest
|
||||
const { id } = await BacktestService.createBacktest(newConfig);
|
||||
|
||||
setBacktestId(id);
|
||||
setConfig(newConfig);
|
||||
setStatus('configured');
|
||||
setResults(null);
|
||||
setCurrentTime(null);
|
||||
setProgress(0);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to create backtest');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleStart = useCallback(async () => {
|
||||
if (!backtestId) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
await BacktestService.startBacktest(backtestId);
|
||||
setStatus('running');
|
||||
|
||||
// Start polling for updates
|
||||
cleanupRef.current = await BacktestService.pollBacktestUpdates(
|
||||
backtestId,
|
||||
(newStatus, newProgress, newTime) => {
|
||||
setStatus(newStatus);
|
||||
if (newProgress !== undefined) setProgress(newProgress);
|
||||
if (newTime !== undefined) setCurrentTime(newTime);
|
||||
|
||||
// Fetch full results when completed
|
||||
if (newStatus === 'completed') {
|
||||
BacktestService.getBacktestResults(backtestId).then(setResults);
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to start backtest');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [backtestId]);
|
||||
|
||||
const handlePause = useCallback(async () => {
|
||||
if (!backtestId) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
await BacktestService.pauseBacktest(backtestId);
|
||||
setStatus('paused');
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to pause backtest');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [backtestId]);
|
||||
|
||||
const handleResume = useCallback(async () => {
|
||||
if (!backtestId) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
await BacktestService.resumeBacktest(backtestId);
|
||||
setStatus('running');
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to resume backtest');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [backtestId]);
|
||||
|
||||
const handleStop = useCallback(async () => {
|
||||
if (!backtestId) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
await BacktestService.stopBacktest(backtestId);
|
||||
setStatus('stopped');
|
||||
|
||||
// Stop polling
|
||||
if (cleanupRef.current) {
|
||||
cleanupRef.current();
|
||||
cleanupRef.current = null;
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to stop backtest');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [backtestId]);
|
||||
|
||||
const handleStep = useCallback(async () => {
|
||||
if (!backtestId) return;
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
setError(null);
|
||||
|
||||
await BacktestService.stepBacktest(backtestId);
|
||||
|
||||
// Get updated status
|
||||
const statusUpdate = await BacktestService.getBacktestStatus(backtestId);
|
||||
setStatus(statusUpdate.status);
|
||||
if (statusUpdate.progress !== undefined) setProgress(statusUpdate.progress);
|
||||
if (statusUpdate.currentTime !== undefined) setCurrentTime(statusUpdate.currentTime);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'Failed to step backtest');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [backtestId]);
|
||||
|
||||
// Cleanup on unmount
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (cleanupRef.current) {
|
||||
cleanupRef.current();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
backtestId,
|
||||
config,
|
||||
status,
|
||||
results,
|
||||
currentTime,
|
||||
progress,
|
||||
error,
|
||||
isLoading,
|
||||
handleConfigSubmit,
|
||||
handleStart,
|
||||
handlePause,
|
||||
handleResume,
|
||||
handleStop,
|
||||
handleStep,
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue