Update bot config on front and back

This commit is contained in:
2025-06-04 15:42:21 +07:00
parent f41af96406
commit 756cd5fb11
14 changed files with 422 additions and 369 deletions

View File

@@ -5,12 +5,11 @@ import {useQuery} from '@tanstack/react-query'
import useApiUrlStore from '../../../app/store/apiStore'
import type {
Backtest,
MoneyManagement,
RunBacktestRequest,
StartBotRequest,
Ticker,
TradingBotConfig
Backtest,
MoneyManagement,
RunBacktestRequest,
StartBotRequest,
TradingBotConfig
} from '../../../generated/ManagingApi'
import {BacktestClient, BotClient, MoneyManagementClient} from '../../../generated/ManagingApi'
import type {IBacktestCards} from '../../../global/type'
@@ -90,23 +89,39 @@ const BacktestCards: React.FC<IBacktestCards> = ({ list, setBacktests }) => {
moneyManagementName.toLowerCase() === 'custom' ||
moneyManagementName.toLowerCase().includes('custom');
const request: StartBotRequest = {
// Create TradingBotConfig from the backtest configuration
const tradingBotConfig: TradingBotConfig = {
accountName: backtest.config.accountName,
name: botName,
botType: backtest.config.botType,
isForWatchOnly: isForWatchOnly,
// Only use the money management name if it's not a custom money management, otherwise use optimized
moneyManagementName: isCustomMoneyManagement ?
(backtest.optimizedMoneyManagement?.name || backtest.config.moneyManagement?.name) :
moneyManagementName,
scenario: backtest.config.scenarioName,
ticker: backtest.config.ticker as Ticker,
ticker: backtest.config.ticker,
scenarioName: backtest.config.scenarioName,
timeframe: backtest.config.timeframe,
initialTradingBalance: initialTradingBalance,
botType: backtest.config.botType,
isForWatchingOnly: isForWatchOnly,
isForBacktest: false, // This is for running a live bot
cooldownPeriod: backtest.config.cooldownPeriod,
maxLossStreak: backtest.config.maxLossStreak,
maxPositionTimeHours: backtest.config.maxPositionTimeHours,
flipOnlyWhenInProfit: backtest.config.flipOnlyWhenInProfit
flipOnlyWhenInProfit: backtest.config.flipOnlyWhenInProfit,
flipPosition: backtest.config.flipPosition,
name: botName,
botTradingBalance: initialTradingBalance,
// Use the optimized or original money management from backtest if it's custom
moneyManagement: isCustomMoneyManagement ?
(backtest.optimizedMoneyManagement || backtest.config.moneyManagement || {
name: 'default',
leverage: 1,
stopLoss: 0.01,
takeProfit: 0.02,
timeframe: backtest.config.timeframe
}) :
backtest.config.moneyManagement, // Always provide a valid MoneyManagement object
closeEarlyWhenProfitable: backtest.config.closeEarlyWhenProfitable || false
};
const request: StartBotRequest = {
config: tradingBotConfig,
// Only use the money management name if it's not a custom money management
moneyManagementName: isCustomMoneyManagement ? undefined : moneyManagementName
}
await client

View File

@@ -47,7 +47,9 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
cooldownPeriod: 10, // Default cooldown period of 10 minutes
maxLossStreak: 0, // Default max loss streak of 0 (no limit)
maxPositionTimeHours: null, // Default to null (disabled)
flipOnlyWhenInProfit: true // Default to true
flipOnlyWhenInProfit: true, // Default to true
balance: 10000, // Default balance
closeEarlyWhenProfitable: false // Default to false
}
});
const [selectedAccount, setSelectedAccount] = useState<string>('')
@@ -123,14 +125,15 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
flipOnlyWhenInProfit: form.flipOnlyWhenInProfit ?? true,
flipPosition: form.botType === BotType.FlippingBot, // Set based on bot type
name: `Backtest-${scenarioName}-${ticker}-${new Date().toISOString()}`,
botTradingBalance: 0, // Will be set in the request
botTradingBalance: form.balance,
moneyManagement: customMoneyManagement || moneyManagements?.find(m => m.name === selectedMoneyManagement) || moneyManagements?.[0] || {
name: 'placeholder',
leverage: 1,
stopLoss: 0.01,
takeProfit: 0.02,
timeframe: form.timeframe
}
},
closeEarlyWhenProfitable: form.closeEarlyWhenProfitable ?? false
};
// Create the RunBacktestRequest
@@ -138,7 +141,7 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
config: tradingBotConfig,
startDate: new Date(form.startDate),
endDate: new Date(form.endDate),
balance: balance,
balance: form.balance,
watchOnly: false,
save: form.save || false,
moneyManagementName: customMoneyManagement ? undefined : selectedMoneyManagement,
@@ -335,8 +338,8 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
} else if (selectedMoneyManagement) {
mm = moneyManagements.find((m) => m.name === selectedMoneyManagement);
}
// Use actual initial balance and a minimum threshold
const initialBalance = balance;
// Use form balance if available, otherwise fall back to state balance
const initialBalance = balance; // This state is kept in sync with form
const minBalance = 10; // You can make this configurable if needed
if (mm && mm.leverage && mm.stopLoss && initialBalance > minBalance) {
const perLoss = mm.leverage * mm.stopLoss;
@@ -400,8 +403,11 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
<input
type="number"
className="input input-bordered w-full"
value={balance}
onChange={(e) => setBalance(Number(e.target.value))}
{...register('balance', { valueAsNumber: true })}
onChange={(e) => {
setValue('balance', Number(e.target.value));
setBalance(Number(e.target.value)); // Keep state in sync for UI calculations
}}
/>
</FormInput>
@@ -443,7 +449,7 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
</FormInput>
</div>
{/* Sixth Row: Flip Only When In Profit & Save */}
{/* Sixth Row: Flip Only When In Profit & Close Early When Profitable */}
<div className="grid grid-cols-2 gap-4">
<FormInput label="Flip Only When In Profit" htmlFor="flipOnlyWhenInProfit">
<input
@@ -456,6 +462,20 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
</div>
</FormInput>
<FormInput label="Close Early When Profitable" htmlFor="closeEarlyWhenProfitable">
<input
type="checkbox"
className="toggle toggle-primary"
{...register('closeEarlyWhenProfitable')}
/>
<div className="text-xs text-gray-500 mt-1">
If enabled, positions will close early when they become profitable
</div>
</FormInput>
</div>
{/* Seventh Row: Save */}
<div className="grid grid-cols-1 gap-4">
<FormInput label="Save" htmlFor="save">
<input
type="checkbox"
@@ -465,7 +485,7 @@ const BacktestModal: React.FC<BacktestModalProps> = ({
</FormInput>
</div>
{/* Seventh Row: Start Date & End Date */}
{/* Eighth Row: Start Date & End Date */}
<div className="grid grid-cols-2 gap-4">
<FormInput label="Start Date" htmlFor="startDate">
<input

View File

@@ -226,6 +226,25 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
const cooldownRecommendations = getCooldownRecommendations();
// Calculate average trades per day
const getAverageTradesPerDay = () => {
if (positions.length === 0) return "0.00";
// Get all trade dates and sort them
const tradeDates = positions.map(position => new Date(position.open.date)).sort((a, b) => a.getTime() - b.getTime());
if (tradeDates.length < 2) return positions.length.toString();
// Calculate the date range in days
const firstTradeDate = tradeDates[0];
const lastTradeDate = tradeDates[tradeDates.length - 1];
const diffInMs = lastTradeDate.getTime() - firstTradeDate.getTime();
const diffInDays = Math.max(1, diffInMs / (1000 * 60 * 60 * 24)); // Ensure at least 1 day
const averageTradesPerDay = positions.length / diffInDays;
return averageTradesPerDay.toFixed(2);
};
return (
<>
<div className="grid grid-flow-row">
@@ -325,6 +344,10 @@ const BacktestRowDetails: React.FC<IBacktestRowDetailsProps> = ({
title="Median Cooldown"
content={cooldownRecommendations.median + " candles"}
></CardText>
<CardText
title="Avg Trades Per Day"
content={getAverageTradesPerDay() + " trades/day"}
></CardText>
</div>
<div>
<figure>

View File

@@ -3,7 +3,7 @@ import React, {useEffect, useState} from 'react'
import {useQuery} from '@tanstack/react-query'
import useApiUrlStore from '../../../app/store/apiStore'
import type {Backtest, StartBotRequest, Ticker,} from '../../../generated/ManagingApi'
import type {Backtest, StartBotRequest, Ticker, TradingBotConfig} from '../../../generated/ManagingApi'
import {BacktestClient, BotClient, MoneyManagementClient} from '../../../generated/ManagingApi'
import type {IBacktestCards} from '../../../global/type'
import {CardText, SelectColumnFilter, Table, Toast} from '../../mollecules'
@@ -58,19 +58,39 @@ const BacktestTable: React.FC<IBacktestCards> = ({ list, isFetching, setBacktest
moneyManagementName.toLowerCase() === 'custom' ||
moneyManagementName.toLowerCase().includes('custom');
const request: StartBotRequest = {
// Create TradingBotConfig from the backtest configuration
const tradingBotConfig: TradingBotConfig = {
accountName: backtest.config.accountName,
botType: backtest.config.botType,
isForWatchOnly: isForWatchOnly,
// Only use the money management name if it's not a custom money management
moneyManagementName: isCustomMoneyManagement ? '' : moneyManagementName,
scenario: backtest.config.scenarioName,
ticker: backtest.config.ticker as Ticker,
ticker: backtest.config.ticker,
scenarioName: backtest.config.scenarioName,
timeframe: backtest.config.timeframe,
initialTradingBalance: initialTradingBalance,
botType: backtest.config.botType,
isForWatchingOnly: isForWatchOnly,
isForBacktest: false, // This is for running a live bot
cooldownPeriod: backtest.config.cooldownPeriod,
maxLossStreak: backtest.config.maxLossStreak,
maxPositionTimeHours: backtest.config.maxPositionTimeHours,
flipOnlyWhenInProfit: backtest.config.flipOnlyWhenInProfit,
flipPosition: backtest.config.flipPosition,
name: botName,
botTradingBalance: initialTradingBalance,
// Use the money management from backtest if it's custom, otherwise leave null and use moneyManagementName
moneyManagement: isCustomMoneyManagement ?
(backtest.config.moneyManagement || {
name: 'default',
leverage: 1,
stopLoss: 0.01,
takeProfit: 0.02,
timeframe: backtest.config.timeframe
}) :
backtest.config.moneyManagement, // Always provide a valid MoneyManagement object
closeEarlyWhenProfitable: backtest.config.closeEarlyWhenProfitable || false
};
const request: StartBotRequest = {
config: tradingBotConfig,
// Only use the money management name if it's not a custom money management
moneyManagementName: isCustomMoneyManagement ? undefined : moneyManagementName
}
await client

View File

@@ -2699,6 +2699,7 @@ export interface TradingBotConfig {
flipPosition: boolean;
name: string;
maxPositionTimeHours?: number | null;
closeEarlyWhenProfitable?: boolean;
flipOnlyWhenInProfit: boolean;
}
@@ -3113,20 +3114,8 @@ export interface RunBacktestRequest {
}
export interface StartBotRequest {
botType?: BotType;
identifier?: string | null;
ticker?: Ticker;
scenario?: string | null;
timeframe?: Timeframe;
accountName?: string | null;
config?: TradingBotConfig | null;
moneyManagementName?: string | null;
isForWatchOnly?: boolean;
initialTradingBalance?: number;
cooldownPeriod?: number;
maxLossStreak?: number;
name?: string | null;
maxPositionTimeHours?: number | null;
flipOnlyWhenInProfit?: boolean;
}
export interface TradingBot {

View File

@@ -116,6 +116,7 @@ export type IBacktestsFormInput = {
maxLossStreak: number
maxPositionTimeHours?: number | null
flipOnlyWhenInProfit?: boolean
closeEarlyWhenProfitable?: boolean
}
export type IBacktestCards = {