Fix managing with good backtest return

This commit is contained in:
2025-11-14 14:28:13 +07:00
parent 61ade29d4e
commit 0cfc30598b
7 changed files with 44 additions and 56 deletions

View File

@@ -233,7 +233,7 @@ public class BacktestController : BaseController
/// <returns>A list of backtests associated with the specified request ID.</returns> /// <returns>A list of backtests associated with the specified request ID.</returns>
[HttpGet] [HttpGet]
[Route("ByRequestId/{requestId}")] [Route("ByRequestId/{requestId}")]
public async Task<ActionResult<IEnumerable<Backtest>>> GetBacktestsByRequestId(string requestId) public async Task<ActionResult<IEnumerable<LightBacktestResponse>>> GetBacktestsByRequestId(string requestId)
{ {
if (string.IsNullOrEmpty(requestId)) if (string.IsNullOrEmpty(requestId))
{ {
@@ -246,7 +246,7 @@ public class BacktestController : BaseController
} }
var backtests = await _backtester.GetBacktestsByRequestIdAsync(requestGuid); var backtests = await _backtester.GetBacktestsByRequestIdAsync(requestGuid);
return Ok(backtests); return Ok(backtests.Select(b => LightBacktestResponseMapper.MapFromDomain(b)));
} }
/// <summary> /// <summary>

View File

@@ -511,6 +511,7 @@ public static class Enums
{ {
Score, Score,
FinalPnl, FinalPnl,
NetPnl,
WinRate, WinRate,
GrowthPercentage, GrowthPercentage,
HodlPercentage, HodlPercentage,

View File

@@ -518,6 +518,9 @@ public class PostgreSqlBacktestRepository : IBacktestRepository
BacktestSortableColumn.FinalPnl => sortOrder == "desc" BacktestSortableColumn.FinalPnl => sortOrder == "desc"
? baseQuery.OrderByDescending(b => b.FinalPnl) ? baseQuery.OrderByDescending(b => b.FinalPnl)
: baseQuery.OrderBy(b => b.FinalPnl), : baseQuery.OrderBy(b => b.FinalPnl),
BacktestSortableColumn.NetPnl => sortOrder == "desc"
? baseQuery.OrderByDescending(b => b.NetPnl)
: baseQuery.OrderBy(b => b.NetPnl),
BacktestSortableColumn.WinRate => sortOrder == "desc" BacktestSortableColumn.WinRate => sortOrder == "desc"
? baseQuery.OrderByDescending(b => b.WinRate) ? baseQuery.OrderByDescending(b => b.WinRate)
: baseQuery.OrderBy(b => b.WinRate), : baseQuery.OrderBy(b => b.WinRate),
@@ -654,6 +657,9 @@ public class PostgreSqlBacktestRepository : IBacktestRepository
BacktestSortableColumn.FinalPnl => sortOrder == "desc" BacktestSortableColumn.FinalPnl => sortOrder == "desc"
? baseQuery.OrderByDescending(b => b.FinalPnl) ? baseQuery.OrderByDescending(b => b.FinalPnl)
: baseQuery.OrderBy(b => b.FinalPnl), : baseQuery.OrderBy(b => b.FinalPnl),
BacktestSortableColumn.NetPnl => sortOrder == "desc"
? baseQuery.OrderByDescending(b => b.NetPnl)
: baseQuery.OrderBy(b => b.NetPnl),
BacktestSortableColumn.WinRate => sortOrder == "desc" BacktestSortableColumn.WinRate => sortOrder == "desc"
? baseQuery.OrderByDescending(b => b.WinRate) ? baseQuery.OrderByDescending(b => b.WinRate)
: baseQuery.OrderBy(b => b.WinRate), : baseQuery.OrderBy(b => b.WinRate),

View File

@@ -76,6 +76,7 @@ const ServerSortableTable = ({
const enumToColumnMapping: { [key in BacktestSortableColumn]?: string } = { const enumToColumnMapping: { [key in BacktestSortableColumn]?: string } = {
[BacktestSortableColumn.Score]: 'score', [BacktestSortableColumn.Score]: 'score',
[BacktestSortableColumn.FinalPnl]: 'finalPnl', [BacktestSortableColumn.FinalPnl]: 'finalPnl',
[BacktestSortableColumn.NetPnl]: 'netPnl',
[BacktestSortableColumn.WinRate]: 'winRate', [BacktestSortableColumn.WinRate]: 'winRate',
[BacktestSortableColumn.GrowthPercentage]: 'growthPercentage', [BacktestSortableColumn.GrowthPercentage]: 'growthPercentage',
[BacktestSortableColumn.HodlPercentage]: 'hodlPercentage', [BacktestSortableColumn.HodlPercentage]: 'hodlPercentage',
@@ -169,6 +170,7 @@ const BacktestTable: React.FC<BacktestTableProps> = ({list, isFetching, onSortCh
const [rows, setRows] = useState<LightBacktestResponse[]>([]) const [rows, setRows] = useState<LightBacktestResponse[]>([])
const {apiUrl} = useApiUrlStore() const {apiUrl} = useApiUrlStore()
const {removeBacktest} = useBacktestStore() const {removeBacktest} = useBacktestStore()
console.log('list', list)
// Bot configuration modal state // Bot configuration modal state
const [showBotConfigModal, setShowBotConfigModal] = useState(false) const [showBotConfigModal, setShowBotConfigModal] = useState(false)
@@ -350,6 +352,7 @@ const BacktestTable: React.FC<BacktestTableProps> = ({list, isFetching, onSortCh
const sortByMapping: { [key: string]: BacktestSortableColumn } = { const sortByMapping: { [key: string]: BacktestSortableColumn } = {
'score': BacktestSortableColumn.Score, 'score': BacktestSortableColumn.Score,
'finalPnl': BacktestSortableColumn.FinalPnl, 'finalPnl': BacktestSortableColumn.FinalPnl,
'netPnl': BacktestSortableColumn.NetPnl,
'winRate': BacktestSortableColumn.WinRate, 'winRate': BacktestSortableColumn.WinRate,
'growthPercentage': BacktestSortableColumn.GrowthPercentage, 'growthPercentage': BacktestSortableColumn.GrowthPercentage,
'hodlPercentage': BacktestSortableColumn.HodlPercentage, 'hodlPercentage': BacktestSortableColumn.HodlPercentage,
@@ -525,10 +528,10 @@ const BacktestTable: React.FC<BacktestTableProps> = ({list, isFetching, onSortCh
columns: [ columns: [
{ {
Cell: ({cell}: any) => ( Cell: ({cell}: any) => (
<>{cell.row.values.finalPnl.toFixed(2)} $</> <>{cell.row.values.netPnl.toFixed(2)} $</>
), ),
Header: 'Pnl $', Header: 'Pnl $',
accessor: 'finalPnl', accessor: 'netPnl',
disableFilters: true, disableFilters: true,
disableSortBy: false, disableSortBy: false,
sortType: 'basic', sortType: 'basic',

View File

@@ -800,7 +800,7 @@ export class BacktestClient extends AuthorizedApiBase {
return Promise.resolve<FileResponse>(null as any); return Promise.resolve<FileResponse>(null as any);
} }
backtest_GetBacktestsByRequestId(requestId: string): Promise<Backtest[]> { backtest_GetBacktestsByRequestId(requestId: string): Promise<LightBacktestResponse[]> {
let url_ = this.baseUrl + "/Backtest/ByRequestId/{requestId}"; let url_ = this.baseUrl + "/Backtest/ByRequestId/{requestId}";
if (requestId === undefined || requestId === null) if (requestId === undefined || requestId === null)
throw new Error("The parameter 'requestId' must be defined."); throw new Error("The parameter 'requestId' must be defined.");
@@ -821,13 +821,13 @@ export class BacktestClient extends AuthorizedApiBase {
}); });
} }
protected processBacktest_GetBacktestsByRequestId(response: Response): Promise<Backtest[]> { protected processBacktest_GetBacktestsByRequestId(response: Response): Promise<LightBacktestResponse[]> {
const status = response.status; const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); }; let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) { if (status === 200) {
return response.text().then((_responseText) => { return response.text().then((_responseText) => {
let result200: any = null; let result200: any = null;
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as Backtest[]; result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as LightBacktestResponse[];
return result200; return result200;
}); });
} else if (status !== 200 && status !== 204) { } else if (status !== 200 && status !== 204) {
@@ -835,7 +835,7 @@ export class BacktestClient extends AuthorizedApiBase {
return throwException("An unexpected server error occurred.", status, _responseText, _headers); return throwException("An unexpected server error occurred.", status, _responseText, _headers);
}); });
} }
return Promise.resolve<Backtest[]>(null as any); return Promise.resolve<LightBacktestResponse[]>(null as any);
} }
backtest_GetBacktestsByRequestIdPaginated(requestId: string, page: number | undefined, pageSize: number | undefined, sortBy: string | null | undefined, sortOrder: string | null | undefined): Promise<PaginatedBacktestsResponse> { backtest_GetBacktestsByRequestIdPaginated(requestId: string, page: number | undefined, pageSize: number | undefined, sortBy: string | null | undefined, sortOrder: string | null | undefined): Promise<PaginatedBacktestsResponse> {
@@ -5010,16 +5010,6 @@ export interface DeleteBacktestsRequest {
backtestIds: string[]; backtestIds: string[];
} }
export interface PaginatedBacktestsResponse {
backtests?: LightBacktestResponse[] | null;
totalCount?: number;
currentPage?: number;
pageSize?: number;
totalPages?: number;
hasNextPage?: boolean;
hasPreviousPage?: boolean;
}
export interface LightBacktestResponse { export interface LightBacktestResponse {
id: string; id: string;
config: TradingBotConfig; config: TradingBotConfig;
@@ -5038,9 +5028,20 @@ export interface LightBacktestResponse {
netPnl: number; netPnl: number;
} }
export interface PaginatedBacktestsResponse {
backtests?: LightBacktestResponse[] | null;
totalCount?: number;
currentPage?: number;
pageSize?: number;
totalPages?: number;
hasNextPage?: boolean;
hasPreviousPage?: boolean;
}
export enum BacktestSortableColumn { export enum BacktestSortableColumn {
Score = "Score", Score = "Score",
FinalPnl = "FinalPnl", FinalPnl = "FinalPnl",
NetPnl = "NetPnl",
WinRate = "WinRate", WinRate = "WinRate",
GrowthPercentage = "GrowthPercentage", GrowthPercentage = "GrowthPercentage",
HodlPercentage = "HodlPercentage", HodlPercentage = "HodlPercentage",

View File

@@ -572,16 +572,6 @@ export interface DeleteBacktestsRequest {
backtestIds: string[]; backtestIds: string[];
} }
export interface PaginatedBacktestsResponse {
backtests?: LightBacktestResponse[] | null;
totalCount?: number;
currentPage?: number;
pageSize?: number;
totalPages?: number;
hasNextPage?: boolean;
hasPreviousPage?: boolean;
}
export interface LightBacktestResponse { export interface LightBacktestResponse {
id: string; id: string;
config: TradingBotConfig; config: TradingBotConfig;
@@ -600,9 +590,20 @@ export interface LightBacktestResponse {
netPnl: number; netPnl: number;
} }
export interface PaginatedBacktestsResponse {
backtests?: LightBacktestResponse[] | null;
totalCount?: number;
currentPage?: number;
pageSize?: number;
totalPages?: number;
hasNextPage?: boolean;
hasPreviousPage?: boolean;
}
export enum BacktestSortableColumn { export enum BacktestSortableColumn {
Score = "Score", Score = "Score",
FinalPnl = "FinalPnl", FinalPnl = "FinalPnl",
NetPnl = "NetPnl",
WinRate = "WinRate", WinRate = "WinRate",
GrowthPercentage = "GrowthPercentage", GrowthPercentage = "GrowthPercentage",
HodlPercentage = "HodlPercentage", HodlPercentage = "HodlPercentage",

View File

@@ -299,40 +299,16 @@ const BundleRequestModal: React.FC<BundleRequestModalProps> = ({
queryFn: async () => { queryFn: async () => {
if (!open || !bundle) return []; if (!open || !bundle) return [];
const res = await backtestClient.backtest_GetBacktestsByRequestId(bundle.requestId); const res = await backtestClient.backtest_GetBacktestsByRequestId(bundle.requestId);
if (!res) return []; if (!res) return [] as LightBacktestResponse[];
return res.map((b: any) => { console.log('res', res)
// Map enums for ticker and timeframe return res as LightBacktestResponse[];
if (b.config) {
if (typeof b.config.ticker === 'number') {
b.config.ticker = Ticker[b.config.ticker as keyof typeof Ticker];
}
if (typeof b.config.timeframe === 'number') {
b.config.timeframe = Timeframe[b.config.timeframe as keyof typeof Timeframe];
}
}
return {
id: b.id,
config: b.config,
finalPnl: b.finalPnl,
winRate: b.winRate,
growthPercentage: b.growthPercentage,
hodlPercentage: b.hodlPercentage,
startDate: b.startDate,
endDate: b.endDate,
maxDrawdown: b.maxDrawdown ?? null,
fees: b.fees,
sharpeRatio: b.sharpeRatio ?? null,
score: b.score ?? 0,
scoreMessage: b.scoreMessage ?? '',
};
});
}, },
enabled: !!open && !!bundle, enabled: !!open && !!bundle,
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
}); });
useEffect(() => { useEffect(() => {
if (queryBacktests) setBacktests(queryBacktests); if (queryBacktests) setBacktests(queryBacktests as LightBacktestResponse[]);
}, [queryBacktests]); }, [queryBacktests]);
if (!open) return null; if (!open) return null;