Fix genetic backend

This commit is contained in:
2025-07-11 14:11:41 +07:00
parent d04d8f310d
commit e43a1af5ef
15 changed files with 542 additions and 205 deletions

View File

@@ -498,6 +498,44 @@ export class BacktestClient extends AuthorizedApiBase {
return Promise.resolve<Backtest>(null as any);
}
backtest_GetBacktestsByRequestId(requestId: string): Promise<Backtest[]> {
let url_ = this.baseUrl + "/Backtest/ByRequestId/{requestId}";
if (requestId === undefined || requestId === null)
throw new Error("The parameter 'requestId' must be defined.");
url_ = url_.replace("{requestId}", encodeURIComponent("" + requestId));
url_ = url_.replace(/[?&]$/, "");
let options_: RequestInit = {
method: "GET",
headers: {
"Accept": "application/json"
}
};
return this.transformOptions(options_).then(transformedOptions_ => {
return this.http.fetch(url_, transformedOptions_);
}).then((_response: Response) => {
return this.processBacktest_GetBacktestsByRequestId(_response);
});
}
protected processBacktest_GetBacktestsByRequestId(response: Response): Promise<Backtest[]> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
let result200: any = null;
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as Backtest[];
return result200;
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<Backtest[]>(null as any);
}
backtest_Run(request: RunBacktestRequest): Promise<Backtest> {
let url_ = this.baseUrl + "/Backtest/Run";
url_ = url_.replace(/[?&]$/, "");
@@ -3251,6 +3289,7 @@ export interface Backtest {
user: User;
indicatorsValues: { [key in keyof typeof IndicatorType]?: IndicatorsResultBase; };
score: number;
requestId?: string | null;
}
export interface TradingBotConfig {
@@ -3691,6 +3730,9 @@ export interface GeneticRequest {
bestIndividual?: string | null;
errorMessage?: string | null;
progressInfo?: string | null;
bestChromosome?: string | null;
currentGeneration?: number;
bestFitnessSoFar?: number | null;
}
export enum GeneticRequestStatus {

View File

@@ -236,6 +236,7 @@ export interface Backtest {
user: User;
indicatorsValues: { [key in keyof typeof IndicatorType]?: IndicatorsResultBase; };
score: number;
requestId?: string | null;
}
export interface TradingBotConfig {
@@ -676,6 +677,9 @@ export interface GeneticRequest {
bestIndividual?: string | null;
errorMessage?: string | null;
progressInfo?: string | null;
bestChromosome?: string | null;
currentGeneration?: number;
bestFitnessSoFar?: number | null;
}
export enum GeneticRequestStatus {

View File

@@ -4,6 +4,7 @@ import {useQuery} from '@tanstack/react-query'
import useApiUrlStore from '../../app/store/apiStore'
import {
type Backtest,
BacktestClient,
type GeneticRequest,
IndicatorType,
@@ -55,6 +56,10 @@ const BacktestGeneticBundle: React.FC = () => {
const [isSubmitting, setIsSubmitting] = useState(false)
const [selectedIndicators, setSelectedIndicators] = useState<IndicatorType[]>(ALL_INDICATORS)
const [geneticRequests, setGeneticRequests] = useState<GeneticRequest[]>([])
const [selectedRequest, setSelectedRequest] = useState<GeneticRequest | null>(null)
const [isViewModalOpen, setIsViewModalOpen] = useState(false)
const [backtests, setBacktests] = useState<Backtest[]>([])
const [isLoadingBacktests, setIsLoadingBacktests] = useState(false)
// Form setup
const {register, handleSubmit, watch, setValue, formState: {errors}} = useForm<GeneticBundleFormData>({
@@ -187,6 +192,30 @@ const BacktestGeneticBundle: React.FC = () => {
}
}
// Handle view details
const handleViewDetails = async (request: GeneticRequest) => {
setSelectedRequest(request)
setIsViewModalOpen(true)
setIsLoadingBacktests(true)
try {
const backtestsData = await backtestClient.backtest_GetBacktestsByRequestId(request.requestId)
setBacktests(backtestsData)
} catch (error) {
console.error('Error fetching backtests:', error)
new Toast('Failed to load backtest details', false)
} finally {
setIsLoadingBacktests(false)
}
}
// Close view modal
const closeViewModal = () => {
setIsViewModalOpen(false)
setSelectedRequest(null)
setBacktests([])
}
return (
<div className="space-y-6">
<div className="card bg-base-100 shadow-xl">
@@ -433,10 +462,7 @@ const BacktestGeneticBundle: React.FC = () => {
<td>
<div className="flex gap-2">
<button
onClick={() => {
// TODO: Implement view details
new Toast('View details not implemented yet', false)
}}
onClick={() => handleViewDetails(request)}
className="btn btn-sm btn-outline"
>
View
@@ -465,6 +491,92 @@ const BacktestGeneticBundle: React.FC = () => {
</div>
</div>
)}
{/* View Details Modal */}
{isViewModalOpen && selectedRequest && (
<div className="modal modal-open">
<div className="modal-box w-11/12 max-w-6xl">
<h3 className="font-bold text-lg mb-4">
Genetic Request Details - {selectedRequest.requestId.slice(0, 8)}...
</h3>
<div className="grid grid-cols-2 gap-4 mb-6">
<div>
<strong>Ticker:</strong> {selectedRequest.ticker}
</div>
<div>
<strong>Timeframe:</strong> {selectedRequest.timeframe}
</div>
<div>
<strong>Status:</strong>
<span className={`badge ${getStatusBadgeColor(selectedRequest.status)} ml-2`}>
{selectedRequest.status}
</span>
</div>
<div>
<strong>Created:</strong> {new Date(selectedRequest.createdAt).toLocaleString()}
</div>
{selectedRequest.completedAt && (
<div>
<strong>Completed:</strong> {new Date(selectedRequest.completedAt).toLocaleString()}
</div>
)}
</div>
<div className="mb-6">
<h4 className="font-semibold mb-2">Backtest Results ({backtests.length})</h4>
{isLoadingBacktests ? (
<div className="flex justify-center">
<span className="loading loading-spinner loading-md"></span>
</div>
) : backtests.length > 0 ? (
<div className="overflow-x-auto">
<table className="table table-zebra">
<thead>
<tr>
<th>ID</th>
<th>Final PnL</th>
<th>Win Rate</th>
<th>Growth %</th>
<th>Score</th>
<th>Positions</th>
<th>Created</th>
</tr>
</thead>
<tbody>
{backtests.map((backtest) => (
<tr key={backtest.id}>
<td className="font-mono text-xs">{backtest.id.slice(0, 8)}...</td>
<td className={backtest.finalPnl >= 0 ? 'text-success' : 'text-error'}>
${backtest.finalPnl.toFixed(2)}
</td>
<td>{backtest.winRate}%</td>
<td className={backtest.growthPercentage >= 0 ? 'text-success' : 'text-error'}>
{backtest.growthPercentage.toFixed(2)}%
</td>
<td>{backtest.score.toFixed(2)}</td>
<td>{backtest.positions?.length || 0}</td>
<td>{new Date(backtest.startDate).toLocaleDateString()}</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div className="text-center text-gray-500 py-8">
No backtest results found for this request.
</div>
)}
</div>
<div className="modal-action">
<button onClick={closeViewModal} className="btn">
Close
</button>
</div>
</div>
</div>
)}
</div>
)
}