Add bundle version number on the backtest name
This commit is contained in:
@@ -616,6 +616,11 @@ public class BacktestController : BaseController
|
||||
return BadRequest("Universal configuration is required");
|
||||
}
|
||||
|
||||
if (request.UniversalConfig.Scenario == null)
|
||||
{
|
||||
return BadRequest("Scenario object must be provided in universal configuration for bundle backtest");
|
||||
}
|
||||
|
||||
if (request.DateTimeRanges == null || !request.DateTimeRanges.Any())
|
||||
{
|
||||
return BadRequest("At least one DateTime range is required");
|
||||
@@ -705,7 +710,8 @@ public class BacktestController : BaseController
|
||||
return;
|
||||
}
|
||||
|
||||
var savedBundleRequest = backtester.GetBundleBacktestRequestByIdForUser(reloadedUser, bundleRequestId);
|
||||
var savedBundleRequest =
|
||||
backtester.GetBundleBacktestRequestByIdForUser(reloadedUser, bundleRequestId);
|
||||
if (savedBundleRequest != null)
|
||||
{
|
||||
await backtester.CreateJobsForBundleRequestAsync(savedBundleRequest);
|
||||
|
||||
@@ -195,7 +195,7 @@ public class JobService
|
||||
MaxPositionTimeHours = backtestRequest.Config.MaxPositionTimeHours,
|
||||
FlipOnlyWhenInProfit = backtestRequest.Config.FlipOnlyWhenInProfit,
|
||||
FlipPosition = backtestRequest.Config.FlipPosition,
|
||||
Name = $"{bundleRequest.Name} #{i + 1}",
|
||||
Name = $"{bundleRequest.Name} v{bundleRequest.Version} #{i + 1}",
|
||||
CloseEarlyWhenProfitable = backtestRequest.Config.CloseEarlyWhenProfitable,
|
||||
UseSynthApi = backtestRequest.Config.UseSynthApi,
|
||||
UseForPositionSizing = backtestRequest.Config.UseForPositionSizing,
|
||||
@@ -233,7 +233,8 @@ public class JobService
|
||||
{
|
||||
try
|
||||
{
|
||||
var refundSuccess = await _kaigenService.RefundUserCreditsAsync(creditRequestId, bundleRequest.User);
|
||||
var refundSuccess =
|
||||
await _kaigenService.RefundUserCreditsAsync(creditRequestId, bundleRequest.User);
|
||||
if (refundSuccess)
|
||||
{
|
||||
_logger.LogInformation(
|
||||
@@ -243,7 +244,8 @@ public class JobService
|
||||
}
|
||||
catch (Exception refundEx)
|
||||
{
|
||||
_logger.LogError(refundEx, "Error during refund attempt for user {UserName}", bundleRequest.User.Name);
|
||||
_logger.LogError(refundEx, "Error during refund attempt for user {UserName}",
|
||||
bundleRequest.User.Name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +272,8 @@ public class JobService
|
||||
// Running jobs should be handled by stale job recovery, not manual retry
|
||||
if (job.Status != JobStatus.Failed && job.Status != JobStatus.Cancelled)
|
||||
{
|
||||
throw new InvalidOperationException($"Cannot retry job with status {job.Status}. Only Failed or Cancelled jobs can be retried.");
|
||||
throw new InvalidOperationException(
|
||||
$"Cannot retry job with status {job.Status}. Only Failed or Cancelled jobs can be retried.");
|
||||
}
|
||||
|
||||
// Reset job to pending state
|
||||
@@ -304,4 +307,3 @@ public class JobService
|
||||
_logger.LogInformation("Deleted job {JobId}", jobId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,6 @@ import {
|
||||
import useApiUrlStore from '../../app/store/apiStore';
|
||||
import Toast from '../../components/mollecules/Toast/Toast';
|
||||
import {useQuery} from '@tanstack/react-query';
|
||||
import * as signalR from '@microsoft/signalr';
|
||||
import AuthorizedApiBase from '../../generated/AuthorizedApiBase';
|
||||
import BacktestTable from '../../components/organism/Backtest/backtestTable';
|
||||
import FormInput from '../../components/mollecules/FormInput/FormInput';
|
||||
import CustomScenario from '../../components/organism/CustomScenario/CustomScenario';
|
||||
@@ -337,73 +335,6 @@ const BundleRequestModal: React.FC<BundleRequestModalProps> = ({
|
||||
if (queryBacktests) setBacktests(queryBacktests);
|
||||
}, [queryBacktests]);
|
||||
|
||||
// SignalR live updates for existing bundles
|
||||
useEffect(() => {
|
||||
if (!open || !bundle) return;
|
||||
if (bundle.status !== 'Pending' && bundle.status !== 'Running') return;
|
||||
let connection: any = null;
|
||||
let connectionId: string = '';
|
||||
let unsubscribed = false;
|
||||
(async () => {
|
||||
try {
|
||||
connection = new signalR.HubConnectionBuilder()
|
||||
.withUrl(`${apiUrl.replace(/\/$/, '')}/backtestHub`)
|
||||
.withAutomaticReconnect()
|
||||
.build();
|
||||
await connection.start();
|
||||
connectionId = connection.connectionId;
|
||||
// Subscribe to bundle updates
|
||||
const authBase = new AuthorizedApiBase({} as any);
|
||||
let fetchOptions: any = {
|
||||
method: 'POST',
|
||||
headers: { 'X-SignalR-ConnectionId': connectionId },
|
||||
};
|
||||
fetchOptions = await authBase.transformOptions(fetchOptions);
|
||||
await fetch(`${apiUrl}/backtest/Bundle/Subscribe?requestId=${bundle.requestId}`, fetchOptions);
|
||||
connection.on('BundleBacktestUpdate', (result: LightBacktestResponse) => {
|
||||
// Map enums if needed
|
||||
if (result.config) {
|
||||
if (typeof result.config.ticker === 'number') {
|
||||
result.config.ticker = Ticker[result.config.ticker as keyof typeof Ticker];
|
||||
} else if (typeof result.config.ticker === 'string' && Ticker[result.config.ticker as keyof typeof Ticker]) {
|
||||
result.config.ticker = Ticker[result.config.ticker as keyof typeof Ticker];
|
||||
}
|
||||
if (typeof result.config.timeframe === 'number') {
|
||||
result.config.timeframe = Timeframe[result.config.timeframe as keyof typeof Timeframe];
|
||||
} else if (typeof result.config.timeframe === 'string' && Timeframe[result.config.timeframe as keyof typeof Timeframe]) {
|
||||
result.config.timeframe = Timeframe[result.config.timeframe as keyof typeof Timeframe];
|
||||
}
|
||||
}
|
||||
setBacktests((prev) => {
|
||||
if (prev.some((b) => b.id === result.id)) return prev;
|
||||
return [...prev, result];
|
||||
});
|
||||
});
|
||||
signalRRef.current = connection;
|
||||
} catch (e: any) {
|
||||
new Toast('Failed to subscribe to live updates', false);
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
unsubscribed = true;
|
||||
if (connection && connectionId) {
|
||||
(async () => {
|
||||
const authBase = new AuthorizedApiBase({} as any);
|
||||
let fetchOptions: any = {
|
||||
method: 'POST',
|
||||
headers: { 'X-SignalR-ConnectionId': connectionId },
|
||||
};
|
||||
fetchOptions = await authBase.transformOptions(fetchOptions);
|
||||
await fetch(`${apiUrl}/backtest/Bundle/Unsubscribe?requestId=${bundle.requestId}`, fetchOptions);
|
||||
})();
|
||||
}
|
||||
if (signalRRef.current) {
|
||||
signalRRef.current.stop();
|
||||
signalRRef.current = null;
|
||||
}
|
||||
};
|
||||
}, [open, bundle, apiUrl]);
|
||||
|
||||
if (!open) return null;
|
||||
|
||||
// If viewing an existing bundle
|
||||
|
||||
Reference in New Issue
Block a user