Update get backtests

This commit is contained in:
2025-07-17 04:40:18 +07:00
parent e4de01211d
commit 6a634eafaa
3 changed files with 52 additions and 29 deletions

View File

@@ -153,7 +153,7 @@ public class BacktestRepository : IBacktestRepository
public Backtest GetBacktestByIdForUser(User user, string id) public Backtest GetBacktestByIdForUser(User user, string id)
{ {
var backtest = _backtestRepository.FindById(id); var backtest = _backtestRepository.FindOne(b => b.Identifier == id);
// Check if backtest exists and belongs to the user // Check if backtest exists and belongs to the user
if (backtest != null && backtest.User != null && backtest.User.Name == user.Name) if (backtest != null && backtest.User != null && backtest.User.Name == user.Name)

View File

@@ -40,7 +40,7 @@ public class KaigenService : IKaigenService
// Check if credits are enabled via environment variable // Check if credits are enabled via environment variable
var creditsEnabledEnv = Environment.GetEnvironmentVariable("KAIGEN_CREDITS_ENABLED"); var creditsEnabledEnv = Environment.GetEnvironmentVariable("KAIGEN_CREDITS_ENABLED");
_creditsEnabled = string.IsNullOrEmpty(creditsEnabledEnv) || creditsEnabledEnv.ToLower() == "true"; _creditsEnabled = !string.IsNullOrEmpty(creditsEnabledEnv) && creditsEnabledEnv.ToLower() == "true";
if (!_creditsEnabled) if (!_creditsEnabled)
{ {
@@ -59,7 +59,8 @@ public class KaigenService : IKaigenService
// Validate required settings only if credits are enabled // Validate required settings only if credits are enabled
if (string.IsNullOrEmpty(_settings.PrivateKey)) if (string.IsNullOrEmpty(_settings.PrivateKey))
{ {
throw new InvalidOperationException("Kaigen PrivateKey is not configured. Please set the KAIGEN_PRIVATE_KEY environment variable."); throw new InvalidOperationException(
"Kaigen PrivateKey is not configured. Please set the KAIGEN_PRIVATE_KEY environment variable.");
} }
if (string.IsNullOrEmpty(_settings.BaseUrl)) if (string.IsNullOrEmpty(_settings.BaseUrl))
@@ -74,7 +75,8 @@ public class KaigenService : IKaigenService
if (!_creditsEnabled) if (!_creditsEnabled)
{ {
var dummyRequestId = Guid.NewGuid().ToString(); var dummyRequestId = Guid.NewGuid().ToString();
_logger.LogInformation("Credits disabled - skipping debit for user {UserName}. Returning dummy request ID {RequestId}", _logger.LogInformation(
"Credits disabled - skipping debit for user {UserName}. Returning dummy request ID {RequestId}",
user.Name, dummyRequestId); user.Name, dummyRequestId);
return dummyRequestId; return dummyRequestId;
} }
@@ -99,7 +101,8 @@ public class KaigenService : IKaigenService
signature = signature signature = signature
}; };
_logger.LogInformation("Debiting {Amount} credits for user {UserName} (wallet: {WalletAddress}) with request ID {RequestId}", _logger.LogInformation(
"Debiting {Amount} credits for user {UserName} (wallet: {WalletAddress}) with request ID {RequestId}",
debitAmount, user.Name, walletAddress, requestId); debitAmount, user.Name, walletAddress, requestId);
var response = await _httpClient.PutAsJsonAsync( var response = await _httpClient.PutAsJsonAsync(
@@ -116,7 +119,8 @@ public class KaigenService : IKaigenService
} }
var result = await response.Content.ReadFromJsonAsync<KaigenResponse>(_jsonOptions); var result = await response.Content.ReadFromJsonAsync<KaigenResponse>(_jsonOptions);
_logger.LogInformation("Successfully debited {Amount} credits for user {UserName} (wallet: {WalletAddress})", _logger.LogInformation(
"Successfully debited {Amount} credits for user {UserName} (wallet: {WalletAddress})",
debitAmount, user.Name, walletAddress); debitAmount, user.Name, walletAddress);
return requestId; return requestId;
@@ -156,7 +160,8 @@ public class KaigenService : IKaigenService
signature = signature signature = signature
}; };
_logger.LogInformation("Refunding credits for user {UserName} (wallet: {WalletAddress}) with request ID {RequestId}", _logger.LogInformation(
"Refunding credits for user {UserName} (wallet: {WalletAddress}) with request ID {RequestId}",
user.Name, walletAddress, requestId); user.Name, walletAddress, requestId);
var response = await _httpClient.PutAsJsonAsync( var response = await _httpClient.PutAsJsonAsync(
@@ -172,7 +177,8 @@ public class KaigenService : IKaigenService
return false; return false;
} }
_logger.LogInformation("Successfully refunded credits for user {UserName} (wallet: {WalletAddress})", user.Name, walletAddress); _logger.LogInformation("Successfully refunded credits for user {UserName} (wallet: {WalletAddress})",
user.Name, walletAddress);
return true; return true;
} }
catch (Exception ex) catch (Exception ex)

View File

@@ -1,6 +1,7 @@
import {CardPositionItem, TradeChart} from '..' import {CardPositionItem, TradeChart} from '..'
import { import {
Backtest, Backtest,
BacktestClient,
CandlesWithIndicatorsResponse, CandlesWithIndicatorsResponse,
DataClient, DataClient,
GetCandlesWithIndicatorsRequest, GetCandlesWithIndicatorsRequest,
@@ -20,6 +21,17 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
}) => { }) => {
const {apiUrl} = useApiUrlStore(); const {apiUrl} = useApiUrlStore();
const dataClient = new DataClient({}, apiUrl); const dataClient = new DataClient({}, apiUrl);
const backtestClient = new BacktestClient({}, apiUrl);
// Use TanStack Query to load full backtest data
const {data: fullBacktestData, isLoading: isLoadingFullBacktest, error: fullBacktestError} = useQuery({
queryKey: ['fullBacktest', backtest.id],
queryFn: async (): Promise<Backtest> => {
return await backtestClient.backtest_Backtest(backtest.id);
},
staleTime: 5 * 60 * 1000, // 5 minutes
gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
});
// Use TanStack Query to load candles with indicators // Use TanStack Query to load candles with indicators
const {data: candlesData, isLoading: isLoadingCandles, error} = useQuery({ const {data: candlesData, isLoading: isLoadingCandles, error} = useQuery({
@@ -65,9 +77,12 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime) gcTime: 10 * 60 * 1000, // 10 minutes (formerly cacheTime)
}); });
// Use the full backtest data if available, otherwise fallback to the original backtest
const currentBacktest = fullBacktestData || backtest;
// Use the data from query or fallback to backtest data // Use the data from query or fallback to backtest data
const candles = candlesData?.candles || backtest.candles || []; const candles = candlesData?.candles || currentBacktest.candles || [];
const indicatorsValues = candlesData?.indicatorsValues || backtest.indicatorsValues || {}; const indicatorsValues = candlesData?.indicatorsValues || currentBacktest.indicatorsValues || {};
const { const {
positions, positions,
@@ -75,7 +90,7 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
signals, signals,
statistics, statistics,
config config
} = backtest; } = currentBacktest;
// Helper function to calculate position open time in hours // Helper function to calculate position open time in hours
const calculateOpenTimeInHours = (position: any) => { const calculateOpenTimeInHours = (position: any) => {
@@ -301,10 +316,12 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
return ( return (
<> <>
<div className="grid grid-flow-row"> <div className="grid grid-flow-row">
{isLoadingCandles && ( {(isLoadingCandles || isLoadingFullBacktest) && (
<div className="flex justify-center items-center p-4"> <div className="flex justify-center items-center p-4">
<div className="loading loading-spinner loading-lg"></div> <div className="loading loading-spinner loading-lg"></div>
<span className="ml-2">Loading candles with indicators...</span> <span className="ml-2">
{isLoadingFullBacktest ? "Loading backtest data..." : "Loading candles with indicators..."}
</span>
</div> </div>
)} )}
<div className="grid grid-cols-4 p-5"> <div className="grid grid-cols-4 p-5">
@@ -358,7 +375,7 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
<CardText <CardText
title="Optimized Money Management" title="Optimized Money Management"
content={ content={
"SL: " + backtest.optimizedMoneyManagement?.stopLoss.toFixed(2) + "% TP: " + backtest.optimizedMoneyManagement?.takeProfit.toFixed(2) + "%" "SL: " + currentBacktest.optimizedMoneyManagement?.stopLoss.toFixed(2) + "% TP: " + currentBacktest.optimizedMoneyManagement?.takeProfit.toFixed(2) + "%"
} }
></CardText> ></CardText>
<CardText <CardText
@@ -393,7 +410,7 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
></CardText> ></CardText>
<CardText <CardText
title="Total Fees" title="Total Fees"
content={"$" + backtest.fees.toLocaleString('en-US', { content={"$" + currentBacktest.fees.toLocaleString('en-US', {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2 maximumFractionDigits: 2
})} })}
@@ -415,7 +432,7 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
content={getAverageTradesPerDay() + " trades/day"} content={getAverageTradesPerDay() + " trades/day"}
></CardText> ></CardText>
</div> </div>
{!isLoadingCandles && ( {!isLoadingCandles && !isLoadingFullBacktest && (
<div className="w-full"> <div className="w-full">
<figure className="w-full"> <figure className="w-full">
<TradeChart <TradeChart