pagination for backtest and optimization

This commit is contained in:
2025-07-16 14:27:07 +07:00
parent 11778aa2a4
commit f51fd5a5f7
15 changed files with 287 additions and 9 deletions

View File

@@ -580,6 +580,52 @@ export class BacktestClient extends AuthorizedApiBase {
return Promise.resolve<Backtest[]>(null as any);
}
backtest_GetBacktestsByRequestIdPaginated(requestId: string, page: number | undefined, pageSize: number | undefined): Promise<PaginatedBacktestsResponse> {
let url_ = this.baseUrl + "/Backtest/ByRequestId/{requestId}/Paginated?";
if (requestId === undefined || requestId === null)
throw new Error("The parameter 'requestId' must be defined.");
url_ = url_.replace("{requestId}", encodeURIComponent("" + requestId));
if (page === null)
throw new Error("The parameter 'page' cannot be null.");
else if (page !== undefined)
url_ += "page=" + encodeURIComponent("" + page) + "&";
if (pageSize === null)
throw new Error("The parameter 'pageSize' cannot be null.");
else if (pageSize !== undefined)
url_ += "pageSize=" + encodeURIComponent("" + pageSize) + "&";
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_GetBacktestsByRequestIdPaginated(_response);
});
}
protected processBacktest_GetBacktestsByRequestIdPaginated(response: Response): Promise<PaginatedBacktestsResponse> {
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 PaginatedBacktestsResponse;
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<PaginatedBacktestsResponse>(null as any);
}
backtest_Run(request: RunBacktestRequest): Promise<Backtest> {
let url_ = this.baseUrl + "/Backtest/Run";
url_ = url_.replace(/[?&]$/, "");
@@ -3696,6 +3742,16 @@ export interface DeleteBacktestsRequest {
backtestIds: string[];
}
export interface PaginatedBacktestsResponse {
backtests?: Backtest[] | null;
totalCount?: number;
currentPage?: number;
pageSize?: number;
totalPages?: number;
hasNextPage?: boolean;
hasPreviousPage?: boolean;
}
export interface RunBacktestRequest {
config?: TradingBotConfigRequest | null;
startDate?: Date;

View File

@@ -599,6 +599,16 @@ export interface DeleteBacktestsRequest {
backtestIds: string[];
}
export interface PaginatedBacktestsResponse {
backtests?: Backtest[] | null;
totalCount?: number;
currentPage?: number;
pageSize?: number;
totalPages?: number;
hasNextPage?: boolean;
hasPreviousPage?: boolean;
}
export interface RunBacktestRequest {
config?: TradingBotConfigRequest | null;
startDate?: Date;

View File

@@ -11,6 +11,7 @@ import {
type GeneticRequest,
GeneticSelectionMethod,
IndicatorType,
type PaginatedBacktestsResponse,
type RunGeneticRequest,
Ticker,
Timeframe,
@@ -75,6 +76,12 @@ const BacktestGeneticBundle: React.FC = () => {
const [backtests, setBacktests] = useState<Backtest[]>([])
const [isLoadingBacktests, setIsLoadingBacktests] = useState(false)
const [isFormCollapsed, setIsFormCollapsed] = useState(false)
// Pagination state
const [currentPage, setCurrentPage] = useState(1)
const [pageSize, setPageSize] = useState(50)
const [totalBacktests, setTotalBacktests] = useState(0)
const [totalPages, setTotalPages] = useState(0)
// Form setup
const {register, handleSubmit, watch, setValue, formState: {errors}} = useForm<GeneticBundleFormData>({
@@ -218,10 +225,21 @@ const BacktestGeneticBundle: React.FC = () => {
setSelectedRequest(request)
setIsViewModalOpen(true)
setIsLoadingBacktests(true)
// Reset pagination state
setCurrentPage(1)
setTotalBacktests(0)
setTotalPages(0)
try {
const backtestsData = await backtestClient.backtest_GetBacktestsByRequestId(request.requestId)
setBacktests(backtestsData)
const response: PaginatedBacktestsResponse = await backtestClient.backtest_GetBacktestsByRequestIdPaginated(
request.requestId,
1,
pageSize
)
setBacktests(response.backtests || [])
setTotalBacktests(response.totalCount || 0)
setTotalPages(response.totalPages || 0)
} catch (error) {
console.error('Error fetching backtests:', error)
new Toast('Failed to load backtest details', false)
@@ -235,6 +253,31 @@ const BacktestGeneticBundle: React.FC = () => {
setIsViewModalOpen(false)
setSelectedRequest(null)
setBacktests([])
setCurrentPage(1)
setTotalBacktests(0)
setTotalPages(0)
}
// Handle page change
const handlePageChange = async (newPage: number) => {
if (!selectedRequest || newPage < 1 || newPage > totalPages) return
setIsLoadingBacktests(true)
setCurrentPage(newPage)
try {
const response: PaginatedBacktestsResponse = await backtestClient.backtest_GetBacktestsByRequestIdPaginated(
selectedRequest.requestId,
newPage,
pageSize
)
setBacktests(response.backtests || [])
} catch (error) {
console.error('Error fetching backtests:', error)
new Toast('Failed to load backtest details', false)
} finally {
setIsLoadingBacktests(false)
}
}
// Table columns for genetic requests
@@ -698,7 +741,32 @@ const BacktestGeneticBundle: React.FC = () => {
</div>
<div className="mb-6">
<h4 className="font-semibold mb-2">Backtest Results ({backtests.length})</h4>
<div className="flex justify-between items-center mb-4">
<h4 className="font-semibold">Backtest Results ({totalBacktests} total)</h4>
{totalPages > 1 && (
<div className="flex items-center gap-2">
<span className="text-sm text-gray-600">
Page {currentPage} of {totalPages}
</span>
<div className="join">
<button
className="join-item btn btn-sm"
onClick={() => handlePageChange(currentPage - 1)}
disabled={currentPage <= 1 || isLoadingBacktests}
>
«
</button>
<button
className="join-item btn btn-sm"
onClick={() => handlePageChange(currentPage + 1)}
disabled={currentPage >= totalPages || isLoadingBacktests}
>
»
</button>
</div>
</div>
)}
</div>
{isLoadingBacktests ? (
<div className="flex justify-center">
<span className="loading loading-spinner loading-md"></span>