feat: 回测任务支持价格区间过滤
- 后端: - BacktestTask 实体类添加 minPrice 和 maxPrice 字段 - BacktestDto 添加价格区间参数和配置字段 - BacktestService 支持创建和查询价格区间配置 - BacktestExecutionService 在 taskToCopyTrading 中设置价格区间 - 添加数据库迁移脚本 V32__add_backtest_price_range_filter.sql - 前端: - BacktestList 添加价格区间输入表单(最低价、最高价) - 详情页面显示价格区间配置 - 一键创建跟单配置时包含价格区间 - 添加中英繁三语言翻译 - 修复价格输入框精度显示问题(0.4 不再显示为 0.40000000) 功能说明: - 价格区间过滤与跟单配置保持一致,确保回测结果能准确反映实际跟单效果 - 支持只设置最低价、只设置最高价、或同时设置两者 - 留空表示不限制价格 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1363,6 +1363,10 @@
|
||||
"fixedAmountRequired": "Please enter fixed amount",
|
||||
"fixedAmountInvalid": "Fixed amount must be greater than 0",
|
||||
"priceFilters": "Price Filters",
|
||||
"priceRange": "Price Range",
|
||||
"priceRangeTooltip": "Only copy Leader orders with price within the specified range. Leave empty to disable. Example: Enter 0.11 and 0.89 to only copy orders with price between 0.11 and 0.89; enter only max price 0.89 to only copy orders with price below 0.89; enter only min price 0.11 to only copy orders with price above 0.11.",
|
||||
"minPricePlaceholder": "Min price (leave empty to disable)",
|
||||
"maxPricePlaceholder": "Max price (leave empty to disable)",
|
||||
"keywordsPlaceholder": "Please enter keywords, press Enter to add",
|
||||
"maxPositionValuePlaceholder": "Leave empty to disable max position limit",
|
||||
"delaySecondsHint": "Delay execution to simulate real copy trading delay",
|
||||
|
||||
@@ -1363,6 +1363,10 @@
|
||||
"fixedAmountRequired": "请输入固定金额",
|
||||
"fixedAmountInvalid": "固定金额必须大于 0",
|
||||
"priceFilters": "价格过滤",
|
||||
"priceRange": "价格区间",
|
||||
"priceRangeTooltip": "仅跟单 Leader 交易价格在指定区间内的订单。不填写表示不限制。示例:填写 0.11 和 0.89 表示仅跟单价格在 0.11 到 0.89 之间的订单;只填写最高价 0.89 表示仅跟单价格在 0.89 以下的订单;只填写最低价 0.11 表示仅跟单价格在 0.11 以上的订单。",
|
||||
"minPricePlaceholder": "最低价(留空不限制)",
|
||||
"maxPricePlaceholder": "最高价(留空不限制)",
|
||||
"keywordsPlaceholder": "请输入关键字,按回车添加",
|
||||
"maxPositionValuePlaceholder": "留空表示不启用最大仓位限制",
|
||||
"delaySecondsHint": "延迟执行模拟真实跟单延迟",
|
||||
|
||||
@@ -1363,6 +1363,10 @@
|
||||
"fixedAmountRequired": "請輸入固定金額",
|
||||
"fixedAmountInvalid": "固定金額必須大於 0",
|
||||
"priceFilters": "價格過濾",
|
||||
"priceRange": "價格區間",
|
||||
"priceRangeTooltip": "僅跟單 Leader 交易價格在指定區間內的訂單。不填寫表示不限制。示例:填寫 0.11 和 0.89 表示僅跟單價格在 0.11 到 0.89 之間的訂單;只填寫最高價 0.89 表示僅跟單價格在 0.89 以下的訂單;只填寫最低價 0.11 表示僅跟單價格在 0.11 以上的訂單。",
|
||||
"minPricePlaceholder": "最低價(留空不限制)",
|
||||
"maxPricePlaceholder": "最高價(留空不限制)",
|
||||
"keywordsPlaceholder": "請輸入關鍵字,按回車添加",
|
||||
"maxPositionValuePlaceholder": "留空表示不啟用最大倉位限制",
|
||||
"delaySecondsHint": "延遲執行模擬真實跟單延遲",
|
||||
|
||||
@@ -272,7 +272,9 @@ const BacktestList: React.FC = () => {
|
||||
supportSell: values.supportSell,
|
||||
keywordFilterMode: values.keywordFilterMode,
|
||||
keywords: values.keywords,
|
||||
maxPositionValue: values.maxPositionValue
|
||||
maxPositionValue: values.maxPositionValue,
|
||||
minPrice: values.minPrice,
|
||||
maxPrice: values.maxPrice
|
||||
}
|
||||
|
||||
const response = await backtestService.create(request)
|
||||
@@ -324,6 +326,8 @@ const BacktestList: React.FC = () => {
|
||||
keywordFilterMode: taskConfig.keywordFilterMode || 'DISABLED',
|
||||
keywords: taskConfig.keywords || [],
|
||||
maxPositionValue: taskConfig.maxPositionValue,
|
||||
minPrice: taskConfig.minPrice,
|
||||
maxPrice: taskConfig.maxPrice,
|
||||
configName: `回测任务-${taskDetail.taskName}`
|
||||
}
|
||||
|
||||
@@ -992,6 +996,50 @@ const BacktestList: React.FC = () => {
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('backtest.priceRange')}
|
||||
tooltip={t('backtest.priceRangeTooltip')}
|
||||
>
|
||||
<Row gutter={12}>
|
||||
<Col span={12}>
|
||||
<Form.Item name="minPrice" noStyle>
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
placeholder={t('backtest.minPricePlaceholder') || '最低价(留空不限制)'}
|
||||
min={0.01}
|
||||
max={0.99}
|
||||
step={0.0001}
|
||||
precision={4}
|
||||
formatter={(value) => {
|
||||
if (!value && value !== 0) return ''
|
||||
const num = parseFloat(value.toString())
|
||||
if (isNaN(num)) return ''
|
||||
return num.toString().replace(/\.0+$/, '')
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item name="maxPrice" noStyle>
|
||||
<InputNumber
|
||||
style={{ width: '100%' }}
|
||||
placeholder={t('backtest.maxPricePlaceholder') || '最高价(留空不限制)'}
|
||||
min={0.01}
|
||||
max={0.99}
|
||||
step={0.0001}
|
||||
precision={4}
|
||||
formatter={(value) => {
|
||||
if (!value && value !== 0) return ''
|
||||
const num = parseFloat(value.toString())
|
||||
if (isNaN(num)) return ''
|
||||
return num.toString().replace(/\.0+$/, '')
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t('backtest.supportSell')}
|
||||
name="supportSell"
|
||||
@@ -1078,6 +1126,8 @@ const BacktestList: React.FC = () => {
|
||||
keywordFilterMode: detailConfig.keywordFilterMode,
|
||||
keywords: detailConfig.keywords || [],
|
||||
maxPositionValue: detailConfig.maxPositionValue,
|
||||
minPrice: detailConfig.minPrice,
|
||||
maxPrice: detailConfig.maxPrice,
|
||||
configName: `回测任务-${detailTask.taskName}`
|
||||
}
|
||||
setPreFilledConfig(preFilled)
|
||||
@@ -1268,6 +1318,20 @@ const BacktestList: React.FC = () => {
|
||||
{formatUSDC(detailConfig.maxPositionValue)} USDC
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
{(detailConfig.minPrice || detailConfig.maxPrice) && (
|
||||
<Descriptions.Item label={t('backtest.priceRange')}>
|
||||
{detailConfig.minPrice !== undefined && detailConfig.minPrice !== null && detailConfig.minPrice !== ''
|
||||
? `≥ ${parseFloat(detailConfig.minPrice).toFixed(4)}`
|
||||
: ''}
|
||||
{(detailConfig.minPrice !== undefined && detailConfig.minPrice !== null && detailConfig.minPrice !== '') &&
|
||||
(detailConfig.maxPrice !== undefined && detailConfig.maxPrice !== null && detailConfig.maxPrice !== '')
|
||||
? ' ~ '
|
||||
: ''}
|
||||
{detailConfig.maxPrice !== undefined && detailConfig.maxPrice !== null && detailConfig.maxPrice !== ''
|
||||
? `≤ ${parseFloat(detailConfig.maxPrice).toFixed(4)}`
|
||||
: ''}
|
||||
</Descriptions.Item>
|
||||
)}
|
||||
</Descriptions>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user