Synth api (#28)
* Add synthApi * Put confidence for Synth proba * Update the code * Update readme * Fix bootstraping * fix github build * Update the endpoints for scenario * Add scenario and update backtest modal * Update bot modal * Update interfaces for synth * add synth to backtest * Add Kelly criterion and better signal * Update signal confidence * update doc * save leaderboard and prediction * Update nswag to generate ApiClient in the correct path * Unify the trading modal * Save miner and prediction * Update messaging and block new signal until position not close when flipping off * Rename strategies to indicators * Update doc * Update chart + add signal name * Fix signal direction * Update docker webui * remove crypto npm * Clean * Fix mobile a bit
This commit is contained in:
@@ -3,7 +3,7 @@ import { create } from 'zustand'
|
||||
import type {MoneyManagement} from '../../generated/ManagingApi'
|
||||
|
||||
type CustomMoneyManagementStore = {
|
||||
setCustomMoneyManagement: (custom: MoneyManagement) => void
|
||||
setCustomMoneyManagement: (custom: MoneyManagement | null) => void
|
||||
moneyManagement: MoneyManagement | null
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import {create} from 'zustand'
|
||||
import type {Scenario} from '../../generated/ManagingApi'
|
||||
|
||||
type CustomScenarioStore = {
|
||||
setCustomScenario: (custom: Scenario) => void
|
||||
setCustomScenario: (custom: Scenario | null) => void
|
||||
scenario: Scenario | null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
|
||||
import type {IModalProps} from '../../../global/type'
|
||||
import type {IModalProps} from '../../../global/type.tsx'
|
||||
|
||||
import ModalHeader from './ModalHeader'
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { IModalProps } from '../../../global/type'
|
||||
import type {IModalProps} from '../../../global/type.tsx'
|
||||
|
||||
const ModalHeader: React.FC<IModalProps> = ({ onClose, titleHeader }: any) => {
|
||||
return (
|
||||
|
||||
@@ -9,10 +9,11 @@ import type {
|
||||
MoneyManagement,
|
||||
RunBacktestRequest,
|
||||
StartBotRequest,
|
||||
TradingBotConfig
|
||||
TradingBotConfig,
|
||||
TradingBotConfigRequest
|
||||
} from '../../../generated/ManagingApi'
|
||||
import {BacktestClient, BotClient, MoneyManagementClient} from '../../../generated/ManagingApi'
|
||||
import type {IBacktestCards} from '../../../global/type'
|
||||
import type {IBacktestCards} from '../../../global/type.tsx'
|
||||
import MoneyManagementModal from '../../../pages/settingsPage/moneymanagement/moneyManagementModal'
|
||||
import {CardPosition, CardText, Toast} from '../../mollecules'
|
||||
import CardPositionItem from '../Trading/CardPositionItem'
|
||||
@@ -119,9 +120,7 @@ const BacktestCards: React.FC<IBacktestCards> = ({ list, setBacktests }) => {
|
||||
};
|
||||
|
||||
const request: StartBotRequest = {
|
||||
config: tradingBotConfig,
|
||||
// Only use the money management name if it's not a custom money management
|
||||
moneyManagementName: isCustomMoneyManagement ? undefined : moneyManagementName
|
||||
config: tradingBotConfig as unknown as TradingBotConfigRequest,
|
||||
}
|
||||
|
||||
await client
|
||||
@@ -165,21 +164,19 @@ const BacktestCards: React.FC<IBacktestCards> = ({ list, setBacktests }) => {
|
||||
}
|
||||
|
||||
const request: RunBacktestRequest = {
|
||||
config: optimizedConfig,
|
||||
config: optimizedConfig as unknown as TradingBotConfigRequest,
|
||||
startDate: startDate,
|
||||
endDate: endDate,
|
||||
balance: backtest.walletBalances[0].value,
|
||||
watchOnly: false,
|
||||
save: false,
|
||||
moneyManagementName: undefined, // We're passing the moneyManagement object directly
|
||||
moneyManagement: optimizedConfig.moneyManagement
|
||||
}
|
||||
|
||||
await client
|
||||
.backtest_Run(request)
|
||||
.then((backtest: Backtest) => {
|
||||
t.update('success', `${backtest.config.ticker} Backtest Succeeded`)
|
||||
setBacktests((arr) => [...arr, backtest])
|
||||
setBacktests((arr: Backtest[]) => [...arr, backtest])
|
||||
})
|
||||
.catch((err) => {
|
||||
t.update('error', 'Error :' + err)
|
||||
@@ -193,7 +190,7 @@ const BacktestCards: React.FC<IBacktestCards> = ({ list, setBacktests }) => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap m-4 -mx-4">
|
||||
{list?.map((backtest: Backtest, index) => (
|
||||
{list?.map((backtest: Backtest, index: number) => (
|
||||
<div
|
||||
key={index.toString()}
|
||||
className="sm:w-1/2 md:w-1/2 xl:w-1/2 w-full p-2"
|
||||
@@ -213,7 +210,7 @@ const BacktestCards: React.FC<IBacktestCards> = ({ list, setBacktests }) => {
|
||||
positions={backtest.positions}
|
||||
walletBalances={backtest.walletBalances}
|
||||
signals={backtest.signals}
|
||||
strategiesValues={backtest.strategiesValues}
|
||||
indicatorsValues={backtest.indicatorsValues}
|
||||
width={720}
|
||||
height={512}
|
||||
></TradeChart>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, {useEffect, useState} from 'react'
|
||||
|
||||
import type {Backtest, MoneyManagement} from '../../../generated/ManagingApi'
|
||||
import type {IModalProps} from '../../../global/type'
|
||||
import {Modal} from '../../mollecules'
|
||||
import type {IModalProps} from '../../../global/type.tsx'
|
||||
|
||||
interface IBotNameModalProps extends IModalProps {
|
||||
backtest: Backtest
|
||||
|
||||
@@ -258,7 +258,7 @@ const CustomScenario: React.FC<ICustomScenario> = ({
|
||||
</div>
|
||||
|
||||
{/* Dynamic parameter inputs based on indicator type */}
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-3">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-3">
|
||||
{getRequiredParams(indicator.type || indicatorTypes[0].type).map((param) => (
|
||||
<FormInput key={param} label={param.charAt(0).toUpperCase() + param.slice(1)} htmlFor={`${param}-${index}`} inline={false}>
|
||||
<input
|
||||
|
||||
@@ -3,6 +3,8 @@ import React, {useEffect, useState} from 'react'
|
||||
import {type SubmitHandler, useForm} from 'react-hook-form'
|
||||
|
||||
import useApiUrlStore from '../../../app/store/apiStore'
|
||||
import {useCustomMoneyManagement} from '../../../app/store/customMoneyManagement'
|
||||
import {useCustomScenario} from '../../../app/store/customScenario'
|
||||
import {
|
||||
AccountClient,
|
||||
BacktestClient,
|
||||
@@ -136,6 +138,8 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
const [selectedTicker, setSelectedTicker] = useState<Ticker | undefined>(undefined);
|
||||
|
||||
const { apiUrl } = useApiUrlStore();
|
||||
const { setCustomMoneyManagement: setGlobalCustomMoneyManagement } = useCustomMoneyManagement();
|
||||
const { setCustomScenario: setGlobalCustomScenario } = useCustomScenario();
|
||||
|
||||
// API clients
|
||||
const scenarioClient = new ScenarioClient({}, apiUrl);
|
||||
@@ -185,6 +189,18 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
setSelectedTicker(backtest.config.ticker);
|
||||
}
|
||||
setValue('scenarioName', backtest.config.scenarioName || '');
|
||||
|
||||
// Handle custom scenario from backtest
|
||||
if ((backtest.config as any).scenario) {
|
||||
setShowCustomScenario(true);
|
||||
setCustomScenario((backtest.config as any).scenario);
|
||||
setGlobalCustomScenario((backtest.config as any).scenario); // Also update global store for prefilling
|
||||
setSelectedScenario('custom');
|
||||
} else if (backtest.config.scenarioName) {
|
||||
setSelectedScenario(backtest.config.scenarioName);
|
||||
setShowCustomScenario(false);
|
||||
}
|
||||
|
||||
setValue('timeframe', backtest.config.timeframe);
|
||||
setValue('botType', backtest.config.botType);
|
||||
setValue('cooldownPeriod', backtest.config.cooldownPeriod);
|
||||
@@ -203,11 +219,31 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
if (backtest.config.moneyManagement) {
|
||||
setShowCustomMoneyManagement(true);
|
||||
setCustomMoneyManagement(backtest.config.moneyManagement);
|
||||
|
||||
// Convert decimal values to percentages for UI display
|
||||
const formattedMoneyManagement = {
|
||||
...backtest.config.moneyManagement,
|
||||
stopLoss: backtest.config.moneyManagement.stopLoss * 100,
|
||||
takeProfit: backtest.config.moneyManagement.takeProfit * 100,
|
||||
};
|
||||
setGlobalCustomMoneyManagement(formattedMoneyManagement);
|
||||
}
|
||||
} else if (mode === 'backtest' && backtest) {
|
||||
// Initialize from existing backtest for re-running
|
||||
setValue('accountName', backtest.config.accountName);
|
||||
setValue('scenarioName', backtest.config.scenarioName || '');
|
||||
|
||||
// Handle custom scenario from backtest
|
||||
if ((backtest.config as any).scenario) {
|
||||
setShowCustomScenario(true);
|
||||
setCustomScenario((backtest.config as any).scenario);
|
||||
setGlobalCustomScenario((backtest.config as any).scenario); // Also update global store for prefilling
|
||||
setSelectedScenario('custom');
|
||||
} else if (backtest.config.scenarioName) {
|
||||
setSelectedScenario(backtest.config.scenarioName);
|
||||
setShowCustomScenario(false);
|
||||
}
|
||||
|
||||
setValue('timeframe', backtest.config.timeframe);
|
||||
setValue('botType', backtest.config.botType);
|
||||
setValue('cooldownPeriod', backtest.config.cooldownPeriod);
|
||||
@@ -243,6 +279,14 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
if (backtest.config.moneyManagement) {
|
||||
setShowCustomMoneyManagement(true);
|
||||
setCustomMoneyManagement(backtest.config.moneyManagement);
|
||||
|
||||
// Convert decimal values to percentages for UI display
|
||||
const formattedMoneyManagement = {
|
||||
...backtest.config.moneyManagement,
|
||||
stopLoss: backtest.config.moneyManagement.stopLoss * 100,
|
||||
takeProfit: backtest.config.moneyManagement.takeProfit * 100,
|
||||
};
|
||||
setGlobalCustomMoneyManagement(formattedMoneyManagement);
|
||||
}
|
||||
|
||||
// Handle risk management
|
||||
@@ -274,6 +318,33 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
setValue('useForSignalFiltering', config.useForSignalFiltering ?? true);
|
||||
setValue('useForDynamicStopLoss', config.useForDynamicStopLoss ?? true);
|
||||
|
||||
// Handle money management - if it exists, treat as custom for update mode
|
||||
if (config.moneyManagement) {
|
||||
setShowCustomMoneyManagement(true);
|
||||
setCustomMoneyManagement(config.moneyManagement);
|
||||
|
||||
// Convert decimal values to percentages for UI display
|
||||
const formattedMoneyManagement = {
|
||||
...config.moneyManagement,
|
||||
stopLoss: config.moneyManagement.stopLoss * 100,
|
||||
takeProfit: config.moneyManagement.takeProfit * 100,
|
||||
};
|
||||
setGlobalCustomMoneyManagement(formattedMoneyManagement);
|
||||
setSelectedMoneyManagement('custom'); // Set dropdown to show "custom"
|
||||
}
|
||||
|
||||
// Handle scenario - check if we have scenario data or just a name reference
|
||||
if ((config as any).scenario) {
|
||||
setShowCustomScenario(true);
|
||||
setCustomScenario((config as any).scenario);
|
||||
setGlobalCustomScenario((config as any).scenario); // Also update global store for prefilling
|
||||
setSelectedScenario('custom'); // Set dropdown to show "custom"
|
||||
} else if (config.scenarioName) {
|
||||
setValue('scenarioName', config.scenarioName);
|
||||
setSelectedScenario(config.scenarioName);
|
||||
setShowCustomScenario(false);
|
||||
}
|
||||
|
||||
// Handle risk management
|
||||
if (config.riskManagement) {
|
||||
setValue('useCustomRiskManagement', true);
|
||||
@@ -373,9 +444,11 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
if (e.target.value === 'custom') {
|
||||
setShowCustomMoneyManagement(true);
|
||||
setCustomMoneyManagement(undefined);
|
||||
setGlobalCustomMoneyManagement(null); // Clear global store when creating new custom
|
||||
} else {
|
||||
setShowCustomMoneyManagement(false);
|
||||
setCustomMoneyManagement(undefined);
|
||||
setGlobalCustomMoneyManagement(null); // Clear global store when switching away from custom
|
||||
setSelectedMoneyManagement(e.target.value);
|
||||
}
|
||||
};
|
||||
@@ -384,9 +457,11 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
if (e.target.value === 'custom') {
|
||||
setShowCustomScenario(true);
|
||||
setCustomScenario(undefined);
|
||||
setGlobalCustomScenario(null); // Clear global store when creating new custom
|
||||
} else {
|
||||
setShowCustomScenario(false);
|
||||
setCustomScenario(undefined);
|
||||
setGlobalCustomScenario(null); // Clear global store when switching away from custom
|
||||
setSelectedScenario(e.target.value);
|
||||
setValue('scenarioName', e.target.value);
|
||||
}
|
||||
@@ -612,7 +687,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
)}
|
||||
|
||||
{/* First Row: Account & Timeframe */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<FormInput label="Account" htmlFor="accountName">
|
||||
<select
|
||||
className="select select-bordered w-full"
|
||||
@@ -650,10 +725,11 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
</div>
|
||||
|
||||
{/* Second Row: Money Management & Bot Type */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<FormInput label="Money Management" htmlFor="moneyManagement">
|
||||
<select
|
||||
className="select select-bordered w-full"
|
||||
value={selectedMoneyManagement || (showCustomMoneyManagement ? 'custom' : '')}
|
||||
onChange={onMoneyManagementChange}
|
||||
>
|
||||
{moneyManagements.length === 0 ? (
|
||||
@@ -704,6 +780,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
<select
|
||||
className="select select-bordered w-full"
|
||||
{...register('scenarioName')}
|
||||
value={selectedScenario || (showCustomScenario ? 'custom' : '')}
|
||||
onChange={onScenarioChange}
|
||||
>
|
||||
{scenarios.length === 0 ? (
|
||||
@@ -854,7 +931,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
|
||||
{/* Dates for backtests */}
|
||||
{mode === 'backtest' && (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<FormInput label="Start Date" htmlFor="startDate">
|
||||
<input
|
||||
type="date"
|
||||
@@ -899,13 +976,13 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
min="1"
|
||||
max="10"
|
||||
value={selectedLoopQuantity.toString()}
|
||||
onChange={(e) => setLoopQuantity(Number(e.target.value))}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setLoopQuantity(Number(e.target.value))}
|
||||
/>
|
||||
</FormInput>
|
||||
)}
|
||||
|
||||
{/* Max Loss Streak & Max Position Time */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<FormInput
|
||||
label={
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -949,7 +1026,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
</div>
|
||||
|
||||
{/* Trading Options */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<FormInput
|
||||
label={
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -1179,7 +1256,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
</FormInput>
|
||||
|
||||
{/* Risk Management Parameters Grid */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<FormInput
|
||||
label={
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -1350,7 +1427,7 @@ const UnifiedTradingModal: React.FC<UnifiedTradingModalProps> = ({
|
||||
</div>
|
||||
|
||||
{/* Checkboxes for Kelly and Expected Utility */}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<FormInput
|
||||
label={
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
@@ -133,7 +133,7 @@ export type IFormInput = {
|
||||
}
|
||||
|
||||
export type IModalProps = {
|
||||
showModal?: boolean | undefined
|
||||
showModal: boolean
|
||||
onSubmit?: React.FormEventHandler
|
||||
onClose?: React.FormEventHandler
|
||||
titleHeader?: string
|
||||
|
||||
@@ -8,11 +8,11 @@ import TradesModal from '../../components/mollecules/TradesModal/TradesModal'
|
||||
import {TradeChart, UnifiedTradingModal} from '../../components/organism'
|
||||
import type {BotType, MoneyManagement, Position, TradingBotResponse} from '../../generated/ManagingApi'
|
||||
import {BotClient} from '../../generated/ManagingApi'
|
||||
import type {IBotList} from '../../global/type'
|
||||
import type {IBotList} from '../../global/type.tsx'
|
||||
import MoneyManagementModal from '../settingsPage/moneymanagement/moneyManagementModal'
|
||||
|
||||
function baseBadgeClass(isOutlined = false) {
|
||||
let classes = 'text-xs badge '
|
||||
let classes = 'text-xs badge badge-sm transition-all duration-200 hover:scale-105 '
|
||||
|
||||
if (isOutlined) {
|
||||
classes += 'badge-outline '
|
||||
@@ -240,7 +240,7 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{list.map((bot: TradingBotResponse, index) => (
|
||||
{list.map((bot: TradingBotResponse, index: number) => (
|
||||
<div
|
||||
key={index.toString()}
|
||||
className="sm:w-1 md:w-1/2 xl:w-1/2 w-full p-2"
|
||||
@@ -258,23 +258,36 @@ const BotList: React.FC<IBotList> = ({ list }) => {
|
||||
}
|
||||
</figure>
|
||||
<div className="card-body">
|
||||
<h2 className="card-title text-sm">
|
||||
<div className="mb-4">
|
||||
{/* Bot Name - Always on its own line */}
|
||||
<h2 className="card-title text-sm mb-3">
|
||||
{bot.config.ticker}
|
||||
</h2>
|
||||
|
||||
{/* Badge Container - Responsive */}
|
||||
<div className="flex flex-wrap gap-1 sm:gap-2">
|
||||
{/* Info Badges */}
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{getMoneyManagementBadge(bot.config.moneyManagement)}
|
||||
{getIsForWatchingBadge(bot.config.isForWatchingOnly, bot.identifier)}
|
||||
</div>
|
||||
|
||||
{/* Action Badges */}
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{getToggleBotStatusBadge(bot.status, bot.identifier, bot.config.botType)}
|
||||
{getUpdateBotBadge(bot)}
|
||||
{getManualPositionBadge(bot.identifier)}
|
||||
{getDeleteBadge(bot.identifier)}
|
||||
</h2>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="columns-2">
|
||||
<div>
|
||||
<div>
|
||||
<CardText
|
||||
title="Scenario"
|
||||
content={bot.config.scenarioName}
|
||||
content={bot.config.scenarioName ?? bot.config.scenario?.name}
|
||||
></CardText>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -5,12 +5,8 @@ import { useForm } from 'react-hook-form'
|
||||
import useApiUrlStore from '../../../app/store/apiStore'
|
||||
import {Modal, Toast} from '../../../components/mollecules'
|
||||
import type {Account} from '../../../generated/ManagingApi'
|
||||
import {
|
||||
AccountType,
|
||||
AccountClient,
|
||||
TradingExchanges,
|
||||
} from '../../../generated/ManagingApi'
|
||||
import type { IAccountFormInput, IModalProps } from '../../../global/type'
|
||||
import {AccountClient, AccountType, TradingExchanges,} from '../../../generated/ManagingApi'
|
||||
import type {IAccountFormInput, IModalProps} from '../../../global/type.tsx'
|
||||
|
||||
const AccountModal: React.FC<IModalProps> = ({ showModal, toggleModal }) => {
|
||||
const [selectedExchange, setSelectedExchange] = useState<TradingExchanges>()
|
||||
|
||||
Reference in New Issue
Block a user