Update bot config on front and back
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -116,6 +116,7 @@ export type IBacktestsFormInput = {
|
||||
maxLossStreak: number
|
||||
maxPositionTimeHours?: number | null
|
||||
flipOnlyWhenInProfit?: boolean
|
||||
closeEarlyWhenProfitable?: boolean
|
||||
}
|
||||
|
||||
export type IBacktestCards = {
|
||||
|
||||
Reference in New Issue
Block a user