Add saved bundle status

This commit is contained in:
2025-10-22 16:45:49 +07:00
parent 6ffe9ae9c4
commit a1fe7ed3b3
5 changed files with 46 additions and 18 deletions

View File

@@ -153,14 +153,17 @@ public class BacktestController : BaseController
{
return BadRequest("scoreMin must be between 0 and 100");
}
if (scoreMax.HasValue && (scoreMax < 0 || scoreMax > 100))
{
return BadRequest("scoreMax must be between 0 and 100");
}
if (winrateMin.HasValue && (winrateMin < 0 || winrateMin > 100))
{
return BadRequest("winrateMin must be between 0 and 100");
}
if (winrateMax.HasValue && (winrateMax < 0 || winrateMax > 100))
{
return BadRequest("winrateMax must be between 0 and 100");
@@ -170,10 +173,12 @@ public class BacktestController : BaseController
{
return BadRequest("scoreMin must be less than or equal to scoreMax");
}
if (winrateMin.HasValue && winrateMax.HasValue && winrateMin > winrateMax)
{
return BadRequest("winrateMin must be less than or equal to winrateMax");
}
if (maxDrawdownMax.HasValue && maxDrawdownMax < 0)
{
return BadRequest("maxDrawdownMax must be greater than or equal to 0");
@@ -186,7 +191,7 @@ public class BacktestController : BaseController
var indicatorList = string.IsNullOrWhiteSpace(indicators)
? Array.Empty<string>()
: indicators.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var filter = new BacktestsFilter
{
NameContains = string.IsNullOrWhiteSpace(name) ? null : name.Trim(),
@@ -364,14 +369,17 @@ public class BacktestController : BaseController
{
return BadRequest("scoreMin must be between 0 and 100");
}
if (scoreMax.HasValue && (scoreMax < 0 || scoreMax > 100))
{
return BadRequest("scoreMax must be between 0 and 100");
}
if (winrateMin.HasValue && (winrateMin < 0 || winrateMin > 100))
{
return BadRequest("winrateMin must be between 0 and 100");
}
if (winrateMax.HasValue && (winrateMax < 0 || winrateMax > 100))
{
return BadRequest("winrateMax must be between 0 and 100");
@@ -381,10 +389,12 @@ public class BacktestController : BaseController
{
return BadRequest("scoreMin must be less than or equal to scoreMax");
}
if (winrateMin.HasValue && winrateMax.HasValue && winrateMin > winrateMax)
{
return BadRequest("winrateMin must be less than or equal to winrateMax");
}
if (maxDrawdownMax.HasValue && maxDrawdownMax < 0)
{
return BadRequest("maxDrawdownMax must be greater than or equal to 0");
@@ -619,8 +629,9 @@ public class BacktestController : BaseController
}
// Calculate total number of backtests
var totalBacktests = request.DateTimeRanges.Count * request.MoneyManagementVariants.Count * request.TickerVariants.Count;
var totalBacktests = request.DateTimeRanges.Count * request.MoneyManagementVariants.Count *
request.TickerVariants.Count;
try
{
var user = await GetUser();
@@ -651,7 +662,9 @@ public class BacktestController : BaseController
TotalBacktests = totalBacktests,
CompletedBacktests = 0,
FailedBacktests = 0,
Status = BundleBacktestRequestStatus.Pending,
Status = request.SaveAsTemplate
? BundleBacktestRequestStatus.Saved
: BundleBacktestRequestStatus.Pending,
Name = request.Name
};
@@ -687,7 +700,8 @@ public class BacktestController : BaseController
Timeframe = request.UniversalConfig.Timeframe,
IsForWatchingOnly = request.UniversalConfig.IsForWatchingOnly,
BotTradingBalance = request.UniversalConfig.BotTradingBalance,
Name = $"{request.UniversalConfig.BotName}_{ticker}_{dateRange.StartDate:yyyyMMdd}_{dateRange.EndDate:yyyyMMdd}",
Name =
$"{request.UniversalConfig.BotName}_{ticker}_{dateRange.StartDate:yyyyMMdd}_{dateRange.EndDate:yyyyMMdd}",
FlipPosition = request.UniversalConfig.FlipPosition,
CooldownPeriod = request.UniversalConfig.CooldownPeriod,
MaxLossStreak = request.UniversalConfig.MaxLossStreak,
@@ -712,15 +726,16 @@ public class BacktestController : BaseController
WatchOnly = request.UniversalConfig.WatchOnly,
Save = request.UniversalConfig.Save,
WithCandles = request.UniversalConfig.WithCandles,
MoneyManagement = mmVariant.MoneyManagement != null ?
new MoneyManagement
MoneyManagement = mmVariant.MoneyManagement != null
? new MoneyManagement
{
Name = mmVariant.MoneyManagement.Name,
Timeframe = mmVariant.MoneyManagement.Timeframe,
StopLoss = mmVariant.MoneyManagement.StopLoss,
TakeProfit = mmVariant.MoneyManagement.TakeProfit,
Leverage = mmVariant.MoneyManagement.Leverage
} : null
}
: null
};
backtestRequests.Add(backtestRequest);
@@ -980,4 +995,4 @@ public class BacktestController : BaseController
Timeframe = moneyManagementRequest.Timeframe
};
}
}
}

View File

@@ -143,7 +143,6 @@ public class BundleBacktestRequest
/// Estimated time remaining in seconds
/// </summary>
public int? EstimatedTimeRemainingSeconds { get; set; }
}
/// <summary>
@@ -174,5 +173,6 @@ public enum BundleBacktestRequestStatus
/// <summary>
/// Request was cancelled
/// </summary>
Cancelled
Cancelled,
Saved
}

View File

@@ -4493,6 +4493,7 @@ export enum BundleBacktestRequestStatus {
Completed = "Completed",
Failed = "Failed",
Cancelled = "Cancelled",
Saved = "Saved",
}
export interface RunBundleBacktestRequest {

View File

@@ -668,6 +668,7 @@ export enum BundleBacktestRequestStatus {
Completed = "Completed",
Failed = "Failed",
Cancelled = "Cancelled",
Saved = "Saved",
}
export interface RunBundleBacktestRequest {

View File

@@ -201,7 +201,7 @@ const BundleRequestModal: React.FC<BundleRequestModalProps> = ({
};
// Create bundle backtest request
const handleCreateBundle = async () => {
const handleCreateBundle = async (asTemplate: boolean = false) => {
if (!strategyName || selectedTickers.length === 0) {
new Toast('Please fill in all required fields', false);
return;
@@ -254,15 +254,22 @@ const BundleRequestModal: React.FC<BundleRequestModalProps> = ({
universalConfig,
dateTimeRanges,
moneyManagementVariants,
tickerVariants: selectedTickers
tickerVariants: selectedTickers,
saveAsTemplate: asTemplate
};
try {
await onCreateBundle?.(request);
new Toast('Bundle backtest request created successfully!', true);
const successMessage = asTemplate
? 'Template saved successfully!'
: 'Bundle backtest request created successfully!';
new Toast(successMessage, true);
onClose();
} catch (error) {
new Toast('Failed to create bundle backtest request', false);
const errorMessage = asTemplate
? 'Failed to save template'
: 'Failed to create bundle backtest request';
new Toast(errorMessage, false);
}
};
@@ -809,18 +816,22 @@ const BundleRequestModal: React.FC<BundleRequestModalProps> = ({
<button
className="btn btn-primary w-full mb-4"
onClick={handleCreateBundle}
onClick={() => handleCreateBundle(false)}
disabled={!strategyName || selectedTickers.length === 0 || !scenario}
>
Run Backtest
</button>
<div className="flex justify-between">
<button className="btn btn-outline btn-sm">
<button
className="btn btn-outline btn-sm"
onClick={() => handleCreateBundle(true)}
disabled={!strategyName || selectedTickers.length === 0 || !scenario}
>
<svg className="w-4 h-4 mr-2" fill="currentColor" viewBox="0 0 20 20">
<path fillRule="evenodd" d="M4 4a2 2 0 00-2 2v8a2 2 0 002 2h12a2 2 0 002-2V6a2 2 0 00-2-2H4zm12 12V6H4v10h12zM8 8a1 1 0 000 2h4a1 1 0 100-2H8z" clipRule="evenodd" />
</svg>
Save this backtest
Save as template
</button>
<button className="btn btn-ghost btn-sm">
Clear all