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"); return BadRequest("scoreMin must be between 0 and 100");
} }
if (scoreMax.HasValue && (scoreMax < 0 || scoreMax > 100)) if (scoreMax.HasValue && (scoreMax < 0 || scoreMax > 100))
{ {
return BadRequest("scoreMax must be between 0 and 100"); return BadRequest("scoreMax must be between 0 and 100");
} }
if (winrateMin.HasValue && (winrateMin < 0 || winrateMin > 100)) if (winrateMin.HasValue && (winrateMin < 0 || winrateMin > 100))
{ {
return BadRequest("winrateMin must be between 0 and 100"); return BadRequest("winrateMin must be between 0 and 100");
} }
if (winrateMax.HasValue && (winrateMax < 0 || winrateMax > 100)) if (winrateMax.HasValue && (winrateMax < 0 || winrateMax > 100))
{ {
return BadRequest("winrateMax must be between 0 and 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"); return BadRequest("scoreMin must be less than or equal to scoreMax");
} }
if (winrateMin.HasValue && winrateMax.HasValue && winrateMin > winrateMax) if (winrateMin.HasValue && winrateMax.HasValue && winrateMin > winrateMax)
{ {
return BadRequest("winrateMin must be less than or equal to winrateMax"); return BadRequest("winrateMin must be less than or equal to winrateMax");
} }
if (maxDrawdownMax.HasValue && maxDrawdownMax < 0) if (maxDrawdownMax.HasValue && maxDrawdownMax < 0)
{ {
return BadRequest("maxDrawdownMax must be greater than or equal to 0"); return BadRequest("maxDrawdownMax must be greater than or equal to 0");
@@ -364,14 +369,17 @@ public class BacktestController : BaseController
{ {
return BadRequest("scoreMin must be between 0 and 100"); return BadRequest("scoreMin must be between 0 and 100");
} }
if (scoreMax.HasValue && (scoreMax < 0 || scoreMax > 100)) if (scoreMax.HasValue && (scoreMax < 0 || scoreMax > 100))
{ {
return BadRequest("scoreMax must be between 0 and 100"); return BadRequest("scoreMax must be between 0 and 100");
} }
if (winrateMin.HasValue && (winrateMin < 0 || winrateMin > 100)) if (winrateMin.HasValue && (winrateMin < 0 || winrateMin > 100))
{ {
return BadRequest("winrateMin must be between 0 and 100"); return BadRequest("winrateMin must be between 0 and 100");
} }
if (winrateMax.HasValue && (winrateMax < 0 || winrateMax > 100)) if (winrateMax.HasValue && (winrateMax < 0 || winrateMax > 100))
{ {
return BadRequest("winrateMax must be between 0 and 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"); return BadRequest("scoreMin must be less than or equal to scoreMax");
} }
if (winrateMin.HasValue && winrateMax.HasValue && winrateMin > winrateMax) if (winrateMin.HasValue && winrateMax.HasValue && winrateMin > winrateMax)
{ {
return BadRequest("winrateMin must be less than or equal to winrateMax"); return BadRequest("winrateMin must be less than or equal to winrateMax");
} }
if (maxDrawdownMax.HasValue && maxDrawdownMax < 0) if (maxDrawdownMax.HasValue && maxDrawdownMax < 0)
{ {
return BadRequest("maxDrawdownMax must be greater than or equal to 0"); return BadRequest("maxDrawdownMax must be greater than or equal to 0");
@@ -619,7 +629,8 @@ public class BacktestController : BaseController
} }
// Calculate total number of backtests // 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 try
{ {
@@ -651,7 +662,9 @@ public class BacktestController : BaseController
TotalBacktests = totalBacktests, TotalBacktests = totalBacktests,
CompletedBacktests = 0, CompletedBacktests = 0,
FailedBacktests = 0, FailedBacktests = 0,
Status = BundleBacktestRequestStatus.Pending, Status = request.SaveAsTemplate
? BundleBacktestRequestStatus.Saved
: BundleBacktestRequestStatus.Pending,
Name = request.Name Name = request.Name
}; };
@@ -687,7 +700,8 @@ public class BacktestController : BaseController
Timeframe = request.UniversalConfig.Timeframe, Timeframe = request.UniversalConfig.Timeframe,
IsForWatchingOnly = request.UniversalConfig.IsForWatchingOnly, IsForWatchingOnly = request.UniversalConfig.IsForWatchingOnly,
BotTradingBalance = request.UniversalConfig.BotTradingBalance, 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, FlipPosition = request.UniversalConfig.FlipPosition,
CooldownPeriod = request.UniversalConfig.CooldownPeriod, CooldownPeriod = request.UniversalConfig.CooldownPeriod,
MaxLossStreak = request.UniversalConfig.MaxLossStreak, MaxLossStreak = request.UniversalConfig.MaxLossStreak,
@@ -712,15 +726,16 @@ public class BacktestController : BaseController
WatchOnly = request.UniversalConfig.WatchOnly, WatchOnly = request.UniversalConfig.WatchOnly,
Save = request.UniversalConfig.Save, Save = request.UniversalConfig.Save,
WithCandles = request.UniversalConfig.WithCandles, WithCandles = request.UniversalConfig.WithCandles,
MoneyManagement = mmVariant.MoneyManagement != null ? MoneyManagement = mmVariant.MoneyManagement != null
new MoneyManagement ? new MoneyManagement
{ {
Name = mmVariant.MoneyManagement.Name, Name = mmVariant.MoneyManagement.Name,
Timeframe = mmVariant.MoneyManagement.Timeframe, Timeframe = mmVariant.MoneyManagement.Timeframe,
StopLoss = mmVariant.MoneyManagement.StopLoss, StopLoss = mmVariant.MoneyManagement.StopLoss,
TakeProfit = mmVariant.MoneyManagement.TakeProfit, TakeProfit = mmVariant.MoneyManagement.TakeProfit,
Leverage = mmVariant.MoneyManagement.Leverage Leverage = mmVariant.MoneyManagement.Leverage
} : null }
: null
}; };
backtestRequests.Add(backtestRequest); backtestRequests.Add(backtestRequest);

View File

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

View File

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

View File

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

View File

@@ -201,7 +201,7 @@ const BundleRequestModal: React.FC<BundleRequestModalProps> = ({
}; };
// Create bundle backtest request // Create bundle backtest request
const handleCreateBundle = async () => { const handleCreateBundle = async (asTemplate: boolean = false) => {
if (!strategyName || selectedTickers.length === 0) { if (!strategyName || selectedTickers.length === 0) {
new Toast('Please fill in all required fields', false); new Toast('Please fill in all required fields', false);
return; return;
@@ -254,15 +254,22 @@ const BundleRequestModal: React.FC<BundleRequestModalProps> = ({
universalConfig, universalConfig,
dateTimeRanges, dateTimeRanges,
moneyManagementVariants, moneyManagementVariants,
tickerVariants: selectedTickers tickerVariants: selectedTickers,
saveAsTemplate: asTemplate
}; };
try { try {
await onCreateBundle?.(request); 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(); onClose();
} catch (error) { } 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 <button
className="btn btn-primary w-full mb-4" className="btn btn-primary w-full mb-4"
onClick={handleCreateBundle} onClick={() => handleCreateBundle(false)}
disabled={!strategyName || selectedTickers.length === 0 || !scenario} disabled={!strategyName || selectedTickers.length === 0 || !scenario}
> >
Run Backtest Run Backtest
</button> </button>
<div className="flex justify-between"> <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"> <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" /> <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> </svg>
Save this backtest Save as template
</button> </button>
<button className="btn btn-ghost btn-sm"> <button className="btn btn-ghost btn-sm">
Clear all Clear all